$schema The document decides
A document is read at the version it names, whatever the argument says. The argument is the fallback for a document that names nothing — never an override of one that does.
Six versions, one walk
moonschema validates a JSON instance against a JSON Schema. You hand it a
Json tree; it answers yes or no, and when the answer is no it says where —
in the instance, and in the schema. Six versions of the specification, four output
formats, and no sockets.
In the browser, on the real engine
A schema on the left, an instance on the right. Edit either: the package compiled to JavaScript validates as you type, and prints every reason it had.
What it holds to
The specification is large and most of it is small print. These are the parts that decide whether a validator is useful or merely present.
A document is read at the version it names, whatever the argument says. The argument is the fallback for a document that names nothing — never an override of one that does.
A fault names the place in the instance and the keyword that refused it, so a message
can point at both. at is a JSON Pointer; so is schema_at.
A validator should not fetch. A $ref reaches a map of documents you fill
in; what is not handed over does not resolve, and that is a fault, not a pass.
What an applicator evaluated is passed to its neighbours, so
unevaluatedProperties sees the branches of an allOf — which
is the only way to close a composed object.
\d, \w, \s and \p{Letter} work as
the specification writes them, read by moonregex's ECMA-262 dialect with the
u flag; scripts and binary properties too, from Unicode 17.0.
A $schema naming a version this does not know is refused when the schema
is read — not read at a version of someone else's choosing.
date-time and its leap second, email down to a quoted local
part, idn-hostname through the tables of RFC 5892, uri by
component. An assertion when you ask for one, and by default from v1.
flag, basic, detailed, verbose.
Each unit carries the evaluation path that went through $ref and the
schema location that did not.
A pub(open) trait for a keyword and one for a vocabulary: a document that
names yours in $vocabulary gets it, and the library is not changed to
allow it.
The six
Six versions are in use, so six are here. The value on the left is the enum; the URI is
what a document writes in $schema.
| Draft | $schema | What it is |
|---|---|---|
| Draft4 | json-schema.org/draft-04/schema# |
What OpenAPI 3.0 profiles, and what much Java and Python tooling still emits. |
| Draft6 | json-schema.org/draft-06/schema# |
$id replaces id; exclusiveMinimum becomes a number. |
| Draft7 | json-schema.org/draft-07/schema# |
The most widely deployed version. |
| Draft2019 | json-schema.org/draft/2019-09/schema |
Vocabularies, $defs, $recursiveRef, unevaluatedProperties. |
| Draft2020 | json-schema.org/draft/2020-12/schema |
$dynamicRef, prefixItems — and what OpenAPI 3.1 is. |
| V1 | json-schema.org/v1 |
format asserts, propertyDependencies arrives. |
Both http and https spellings are accepted, with or without the trailing #.
Where the cloth ends
Four decisions, each with a reason, so that nobody has to discover them by finding the hole.
$refA validator that opens sockets is a validator that blocks, retries and fails. The seam is remotes: a map from URI to document, filled by the caller.
A schema is read for what it says, not checked for whether it should have said it. $schema picks the version; the rest is the schema author's business.
Links and media types are a different specification. This one is validation.
Interpretation first. If it measures slow, that is the time to argue about it — not before there is a number.
Runnable
Each is a small program with its real output, and runs with moon run src/examples/….