Current section
Files
Jump to
Current section
Files
src/glerd_valid.gleam
import gleam/dict
import gleam/list
import gleam/option.{Some}
import gleam/regex.{Match}
import gleam/string
import gleamyshell
import glerd/types
import justin
import simplifile
const safe_comma = "zqLFwXhSaN3MtHvpYbE6xA2UfmjW9PRduT7ksrZB5G4c8yQDJe"
pub fn generate(root, record_info) {
let imports =
record_info
|> list.map(fn(ri) {
let #(_, module_name, _, _) = ri
"import " <> module_name
})
|> list.unique
|> string.join("\n")
let gen_content =
list.fold(record_info, "// this file was generated via glerd_valid
import gleam/bool
import gleam/string
import gleam/list
" <> imports, fn(acc, rinfo) {
let #(record_name, module_name, fields, meta) = rinfo
let assert Ok(re) = "valid:(\\w+):(\\w+):'([^']+)'" |> regex.from_string
let validations = regex.scan(re, meta)
let field_type_by_name =
fields
|> list.fold(dict.new(), fn(acc, field) {
let #(field_name, typ) = field
dict.insert(acc, field_name, typ)
})
let validation_body =
{
use validation <- list.flat_map(validations)
let assert Match(
_,
[Some(field_name), Some(check_level), Some(rules)],
) = validation
let rules =
rules |> string.replace(",,", safe_comma) |> string.split(",")
use rule <- list.flat_map(rules)
let rule = rule |> string.replace(safe_comma, ",")
let assert Ok(re) = "(\\w+)=(.+)" |> regex.from_string
let assert [Match(_, [Some(key), Some(val)])] =
regex.scan(re, rule |> string.trim)
case key, dict.get(field_type_by_name, field_name), check_level {
"gte", Ok(types.IsInt), "self" | "min", Ok(types.IsInt), "self" -> [
"
use <- bool.guard({ x." <> field_name <> " >= " <> val <> " } |> bool.negate,
Error(\"" <> module_name <> "." <> record_name <> "." <> field_name <> " should be greater or equal than " <> val <> "\"))
",
]
"gte", Ok(types.IsFloat), "self" | "min", Ok(types.IsFloat), "self" -> [
"
use <- bool.guard({ x." <> field_name <> " >=. " <> val <> " } |> bool.negate,
Error(\"" <> module_name <> "." <> record_name <> "." <> field_name <> " should be greater or equal than " <> val <> "\"))
",
]
"gte", Ok(types.IsString), "length"
| "min", Ok(types.IsString), "length"
-> ["
use <- bool.guard({ string.length(x." <> field_name <> ") >= " <> val <> " } |> bool.negate,
Error(\"" <> module_name <> "." <> record_name <> "." <> field_name <> " length should be greater or equal than " <> val <> "\"))
"]
"gte", Ok(types.IsList(_)), "length"
| "min", Ok(types.IsList(_)), "length"
-> ["
use <- bool.guard({ list.length(x." <> field_name <> ") >= " <> val <> " } |> bool.negate,
Error(\"" <> module_name <> "." <> record_name <> "." <> field_name <> " length should be greater or equal than " <> val <> "\"))
"]
"gt", Ok(types.IsInt), "self" -> ["
use <- bool.guard({ x." <> field_name <> " > " <> val <> " } |> bool.negate,
Error(\"" <> module_name <> "." <> record_name <> "." <> field_name <> " should be greater than " <> val <> "\"))
"]
"gt", Ok(types.IsFloat), "self" -> ["
use <- bool.guard({ x." <> field_name <> " >. " <> val <> " } |> bool.negate,
Error(\"" <> module_name <> "." <> record_name <> "." <> field_name <> " should be greater than " <> val <> "\"))
"]
"gt", Ok(types.IsString), "length" -> ["
use <- bool.guard({ string.length(x." <> field_name <> ") > " <> val <> " } |> bool.negate,
Error(\"" <> module_name <> "." <> record_name <> "." <> field_name <> " length should be greater than " <> val <> "\"))
"]
"gt", Ok(types.IsList(_)), "length" -> ["
use <- bool.guard({ list.length(x." <> field_name <> ") > " <> val <> " } |> bool.negate,
Error(\"" <> module_name <> "." <> record_name <> "." <> field_name <> " length should be greater than " <> val <> "\"))
"]
"lte", Ok(types.IsInt), "self" | "max", Ok(types.IsInt), "self" -> [
"
use <- bool.guard({ x." <> field_name <> " <= " <> val <> " } |> bool.negate,
Error(\"" <> module_name <> "." <> record_name <> "." <> field_name <> " should be less or equal than " <> val <> "\"))
",
]
"lte", Ok(types.IsFloat), "self" | "max", Ok(types.IsFloat), "self" -> [
"
use <- bool.guard({ x." <> field_name <> " <=. " <> val <> " } |> bool.negate,
Error(\"" <> module_name <> "." <> record_name <> "." <> field_name <> " should be less or equal than " <> val <> "\"))
",
]
"lte", Ok(types.IsString), "length"
| "max", Ok(types.IsString), "length"
-> ["
use <- bool.guard({ string.length(x." <> field_name <> ") <= " <> val <> " } |> bool.negate,
Error(\"" <> module_name <> "." <> record_name <> "." <> field_name <> " length should be less or equal than " <> val <> "\"))
"]
"lte", Ok(types.IsList(_)), "length"
| "max", Ok(types.IsList(_)), "length"
-> ["
use <- bool.guard({ list.length(x." <> field_name <> ") <= " <> val <> " } |> bool.negate,
Error(\"" <> module_name <> "." <> record_name <> "." <> field_name <> " length should be less or equal than " <> val <> "\"))
"]
"lt", Ok(types.IsInt), "self" -> ["
use <- bool.guard({ x." <> field_name <> " < " <> val <> " } |> bool.negate,
Error(\"" <> module_name <> "." <> record_name <> "." <> field_name <> " should be less than " <> val <> "\"))
"]
"lt", Ok(types.IsFloat), "self" -> ["
use <- bool.guard({ x." <> field_name <> " <. " <> val <> " } |> bool.negate,
Error(\"" <> module_name <> "." <> record_name <> "." <> field_name <> " should be less than " <> val <> "\"))
"]
"lt", Ok(types.IsString), "length" -> ["
use <- bool.guard({ string.length(x." <> field_name <> ") < " <> val <> " } |> bool.negate,
Error(\"" <> module_name <> "." <> record_name <> "." <> field_name <> " length should be less than " <> val <> "\"))
"]
"lt", Ok(types.IsList(_)), "length" -> ["
use <- bool.guard({ list.length(x." <> field_name <> ") < " <> val <> " } |> bool.negate,
Error(\"" <> module_name <> "." <> record_name <> "." <> field_name <> " length should be less than " <> val <> "\"))
"]
"eq", Ok(types.IsInt), "self"
| "eq", Ok(types.IsFloat), "self"
| "eq", Ok(types.IsBool), "self"
-> ["
use <- bool.guard({ x." <> field_name <> " == " <> val <> " } |> bool.negate,
Error(\"" <> module_name <> "." <> record_name <> "." <> field_name <> " should be equal to " <> val <> "\"))
"]
"eq", Ok(types.IsString), "self" -> ["
use <- bool.guard({ x." <> field_name <> " == \"" <> val <> "\" } |> bool.negate,
Error(\"" <> module_name <> "." <> record_name <> "." <> field_name <> " should be equal to \\\"" <> val <> "\\\"\"))
"]
"eq", Ok(types.IsString), "length" -> ["
use <- bool.guard({ string.length(x." <> field_name <> ") == " <> val <> " } |> bool.negate,
Error(\"" <> module_name <> "." <> record_name <> "." <> field_name <> " length should be equal to " <> val <> "\"))
"]
"eq", Ok(types.IsList(_)), "self" -> ["
use <- bool.guard({ x." <> field_name <> " == " <> val <> " } |> bool.negate,
Error(\"" <> module_name <> "." <> record_name <> "." <> field_name <> " should be equal to " <> val
|> string.replace("\"", "\\\"") <> "\"))
"]
"eq", Ok(types.IsList(_)), "length" -> ["
use <- bool.guard({ list.length(x." <> field_name <> ") == " <> val <> " } |> bool.negate,
Error(\"" <> module_name <> "." <> record_name <> "." <> field_name <> " length should be equal to " <> val <> "\"))
"]
"ne", Ok(types.IsInt), "self"
| "ne", Ok(types.IsFloat), "self"
| "ne", Ok(types.IsBool), "self"
-> ["
use <- bool.guard({ x." <> field_name <> " != " <> val <> " } |> bool.negate,
Error(\"" <> module_name <> "." <> record_name <> "." <> field_name <> " should not be equal to " <> val <> "\"))
"]
"ne", Ok(types.IsString), "self" -> ["
use <- bool.guard({ x." <> field_name <> " != \"" <> val <> "\" } |> bool.negate,
Error(\"" <> module_name <> "." <> record_name <> "." <> field_name <> " should not be equal to \\\"" <> val <> "\\\"\"))
"]
"ne", Ok(types.IsString), "length" -> ["
use <- bool.guard({ string.length(x." <> field_name <> ") != " <> val <> " } |> bool.negate,
Error(\"" <> module_name <> "." <> record_name <> "." <> field_name <> " length should not be equal to " <> val <> "\"))
"]
"ne", Ok(types.IsList(_)), "self" -> ["
use <- bool.guard({ x." <> field_name <> " != " <> val <> " } |> bool.negate,
Error(\"" <> module_name <> "." <> record_name <> "." <> field_name <> " should not be equal to " <> val
|> string.replace("\"", "\\\"") <> "\"))
"]
"ne", Ok(types.IsList(_)), "length" -> ["
use <- bool.guard({ list.length(x." <> field_name <> ") != " <> val <> " } |> bool.negate,
Error(\"" <> module_name <> "." <> record_name <> "." <> field_name <> " length should not be equal to " <> val <> "\"))
"]
key, typ, check_level ->
panic as {
"Unknown rule for key: "
<> key
<> " , type: "
<> string.inspect(typ)
<> " , nested check: "
<> check_level
}
}
}
|> string.join("\n")
<> "\n Ok(Nil)"
acc <> "
pub fn " <> justin.snake_case(record_name) <> "_valid(x: " <> module_name <> "." <> record_name <> ") {
" <> validation_body <> "
}
"
})
let gen_file_path = "./" <> root <> "/glerd_valid_gen.gleam"
let assert Ok(_) = simplifile.write(gen_file_path, gen_content)
let assert Ok(_) =
gleamyshell.execute("gleam", ".", ["format", gen_file_path])
Nil
}