///|
/// MoonBit Schema Validator — Validate JSON data against a JSON Schema.
///
/// Usage:
/// moon run cmd/validate -- '' ''
/// moon run cmd/validate -- --schema '' ''
/// moon run cmd/validate -- --help
///
/// Examples:
/// moon run cmd/validate -- '{"name":"Alice"}' '{"name":"Bob"}'
/// moon run cmd/validate -- --schema '{"type":"string","minLength":1}' '"hello"'
fn print_help() -> Unit {
println("MoonBit Schema Validator")
println("")
println("Usage:")
println(" moon run cmd/validate -- '' ''")
println(" (infer schema from sample, validate data)")
println(" moon run cmd/validate -- --schema '' ''")
println(" (inline JSON Schema string, validate data)")
println("")
println("File input:")
println(" sh cmd/validate/cli.sh --file --file ")
println(
" sh cmd/validate/cli.sh --sample-file --file ",
)
println("")
println("Output:")
println(" PASS")
println(" FAIL with error details")
println(" ERROR for invalid arguments or JSON")
}
///|
fn main {
let args = @env.args()
if args.length() < 2 || args[1] == "--help" || args[1] == "-h" {
print_help()
return
}
// JSON Schema mode.
if args[1] == "--schema" {
if args.length() < 4 {
println("ERROR: --schema requires a JSON Schema and data JSON")
println(
"Usage: moon run cmd/validate -- --schema '' ''",
)
return
}
let schema_raw = args[2]
let data_raw = args[3]
let schema_json = @json.parse(schema_raw) catch {
_ => {
println("ERROR: invalid JSON Schema")
return
}
}
let schema = @moon_zod.json_schema_to_schema(schema_json)
println("Schema: \{@moon_zod.schema_to_moon_zod_code(schema)}")
let _ = validate(schema, data_raw)
return
}
// Default mode: infer from sample
if args.length() < 3 {
println("ERROR: missing arguments")
println("Usage: moon run cmd/validate -- '' ''")
return
}
let sample_raw = args[1]
let data_raw = args[2]
let sample_json = @json.parse(sample_raw) catch {
_ => {
println("ERROR: invalid sample JSON")
return
}
}
let schema = @moon_zod.json_infer_schema(sample_json)
println("Schema: \{@moon_zod.schema_to_moon_zod_code(schema)}")
let _ = validate(schema, data_raw)
}
///|
/// CLI 传入的 \n 是字面量反斜杠+n,替换为真正换行符以便分割。
fn normalize_sep(data : String) -> String {
data.replace(old="\\n", new="\n")
}
///|
fn validate(schema : @moon_zod.Schema, data_raw : String) -> Bool {
let data = normalize_sep(data_raw)
if data.contains("\n") {
validate_lines(schema, data)
} else {
validate_one(schema, data)
}
}
///|
fn validate_one(schema : @moon_zod.Schema, data : String) -> Bool {
let data_json = @json.parse(data) catch {
_ => {
println("ERROR: invalid data JSON")
return false
}
}
match schema.parse(data_json) {
Ok(_) => {
println("PASS")
true
}
Err(errors) => {
println("FAIL")
for e in errors {
println(" [\{e.path}] \{e.message} (got: \{@debug.to_string(e.got)})")
}
false
}
}
}
///|
fn validate_lines(schema : @moon_zod.Schema, data : String) -> Bool {
let lines = data.split("\n")
let mut pass_count = 0
let mut fail_count = 0
let mut line_num = 0
for line in lines {
line_num = line_num + 1
let trimmed = line.trim()
if trimmed.is_empty() {
continue
}
let data_json = @json.parse(trimmed) catch {
_ => {
println("FAIL: line \{line_num} — invalid JSON")
fail_count = fail_count + 1
continue
}
}
match schema.parse(data_json) {
Ok(_) => pass_count = pass_count + 1
Err(errors) => {
println("FAIL: line \{line_num}")
for e in errors {
println(
" [\{e.path}] \{e.message} (got: \{@debug.to_string(e.got)})",
)
}
fail_count = fail_count + 1
}
}
}
println("Results: \{pass_count} passed, \{fail_count} failed")
fail_count == 0
}