Batch / CI JSON Schema validation CLI with schema linting and JSON reports, built on mizchi/jsonschema.
Attribution. MoonCheck does not implement a JSON Schema validator. All schema compilation and data validation is done by mizchi/jsonschema (MIT), declared as a dependency in moon.mod. MoonCheck is an extension on top of it that adds what you need to run schema checks over many files in CI. Versions up to 0.1.0 shipped their own small validation engine; from 0.2.0 that engine was removed and replaced by mizchi/jsonschema.
| mizchi/jsonschema | MoonCheck adds | |
|---|---|---|
| Validate a value against a JSON Schema | ✅ (the engine) | uses it as is |
| Command line tool | – | mooncheck validate schema.json data/*.json |
| Many documents in one run, one bad file does not stop the run | – | ✅ |
| Machine-readable report for CI | – | --report json, stable error kinds |
| Stable exit codes | – | 0 valid / 1 invalid data / 2 usage, I/O or schema error |
| Schema linting | lenient: unknown nodes become "accept anything" | check-schema rejects typos such as "type": "int", "min", "required": true with a location and a hint |
| Error format | JsonPointer + message tree | flat errors with $.user.tags[0] paths and a kind (missing_required, type_mismatch, above_max, …) |
moon update # refresh the registry index
moon check # type-check
moon test # run the test suite
moon run examples/demo # run the demo (any backend)
moon build cmd/main --target native # build the `mooncheck` executable{
"type": "object",
"required": ["host", "port"],
"properties": {
"host": { "type": "string", "minLength": 1 },
"port": { "type": "integer", "minimum": 1, "maximum": 65535 },
"debug": { "type": "boolean" },
"timeout": { "type": "integer", "minimum": 0, "maximum": 600 }
}
}mooncheck validate examples/cli/config.schema.json examples/cli/configs/*.jsonok: examples/cli/configs/service_a.json
ok: examples/cli/configs/service_b.json
examples/cli/configs/service_c_broken.json: $.host: String length 0 is less than minimum 1
examples/cli/configs/service_c_broken.json: $.port: Value is greater than maximum 65535
examples/cli/configs/service_c_broken.json: $.timeout: Value is not a number
checked 3 document(s): 2 ok, 1 failed, 3 error(s)
error: 1 of 3 document(s) failed validation{
"schema": "examples/cli/config.schema.json",
"ok": false,
"summary": { "checked": 3, "failed": 1, "errors": 3 },
"documents": [
{ "path": "examples/cli/configs/service_a.json", "ok": true, "errors": [] },
{ "path": "examples/cli/configs/service_b.json", "ok": true, "errors": [] },
{
"path": "examples/cli/configs/service_c_broken.json",
"ok": false,
"errors": [
{ "path": "$.host", "kind": "too_short", "message": "String length 0 is less than minimum 1" },
{ "path": "$.port", "kind": "above_max", "message": "Value is greater than maximum 65535" },
{ "path": "$.timeout", "kind": "type_mismatch", "message": "Value is not a number" }
]
}
]
}mooncheck check-schema bad.schema.jsonerror: invalid schema "bad.schema.json": #/required: must be an array of property names, e.g. ["name"]; #/properties/age/type: unknown type "int" (did you mean "integer"?); #/properties/age: unknown keyword "min" (did you mean "minimum"?)| kind | produced by |
|---|---|
| missing_required | required |
| type_mismatch | type |
| below_min / above_max | minimum, exclusiveMinimum / maximum, exclusiveMaximum |
| too_short / too_long | minLength, minItems / maxLength, maxItems |
| not_in_enum | enum |
| constraint | any other keyword (const, anyOf, additionalProperties, …) |
| invalid_json | the data file is not JSON |
match @MoonCheck.validate_strings(schema_text, data_text) {
Ok(errors) if errors.is_empty() => println("valid")
Ok(errors) => for error in errors { println(@MoonCheck.to_string(error)) }
Err(reason) => println("could not validate: \{reason}")
}let schema = match @MoonCheck.parse_schema_text(schema_text) {
Ok(schema) => schema
Err(reason) => panic()
}
let report = @MoonCheck.RunReport::new("schema.json", [
@MoonCheck.FileResult::new("a.json", @MoonCheck.validate_text(schema, text_a)),
@MoonCheck.FileResult::new("b.json", @MoonCheck.validate_text(schema, text_b)),
])
println(@MoonCheck.render(report, @MoonCheck.ReportFormat::json(), false))moon testMoonCheck/
├── moon.mod # module metadata, depends on mizchi/jsonschema
├── schema.mbt # schema linter + compile via mizchi/jsonschema
├── validate.mbt # adapter: mizchi/jsonschema errors -> MoonCheck errors
├── error.mbt # stable ValidationError / ErrorKind
├── report.mbt # text and JSON reports
├── cli.mbt # command line parsing + usage text
├── *_test.mbt, *_wbtest.mbt # tests
├── cmd/main/ # CLI shell: reads files, prints, sets exit status
└── examples/
├── demo/ # runnable demo (moon run examples/demo)
└── cli/ # sample schemas + data (configs/ for batch runs)pub enum CliCommand {
Help
Version
Validate(ValidateOptions)
CheckSchema(CheckSchemaOptions)
Invalid(String)
} derive(Eq, Debug)pub struct ValidateOptions {
format : ReportFormat
quiet : Bool
schema : String
data : Array[String]
} derive(Eq, Debug){
"schema": "schema.json",
"ok": false,
"summary": { "checked": 2, "failed": 1, "errors": 2 },
"documents": [
{ "path": "a.json", "ok": true, "errors": [] },
{ "path": "b.json", "ok": false,
"errors": [ { "path": "$.age", "kind": "type_mismatch", "message": "..." } ] }
]
}fn validate_strings(schema_text : String, data_text : String) -> Result[Array[ValidationError], String]Install
Download zipBatch / CI JSON Schema validation CLI with schema linting and JSON reports, built on mizchi/jsonschema.