JSON Schema 2020-12 evaluation.
The evaluator answers ANNOTATIONS as well as errors, from the first line and
not as a later addition: unevaluatedProperties and unevaluatedItems are
defined in terms of what the ADJACENT keywords and the in-place applicators
already evaluated, so a validator that answers only true/false cannot grow
them without being rewritten. Every evaluation therefore returns
{:valid? :props :items :errors} - the property names and item indices that
were evaluated AT THIS INSTANCE LOCATION, plus every fault found underneath.
Two kinds of applicator, and the difference is the whole design:
$ref, $dynamicRef, allOf, anyOf, oneOf, if/then/
else, dependentSchemas) apply another schema to the SAME instance
location, so their annotations belong to this location and bubble up.properties, patternProperties, additionalProperties, items,
prefixItems, contains, propertyNames) apply to a location BELOW, so
their annotations stay there and this location records only which member
was covered.Identifiers are resolved once, when the schema is compiled: $id moves the
base URI, $anchor and $dynamicAnchor name a place inside it, and the
index that comes out is what $ref and $dynamicRef read. Nothing is
fetched over the network, ever - a schema that references a document the
caller did not supply is a compile error, not a silent pass.
JSON Schema 2020-12 evaluation.
The evaluator answers ANNOTATIONS as well as errors, from the first line and
not as a later addition: `unevaluatedProperties` and `unevaluatedItems` are
defined in terms of what the ADJACENT keywords and the in-place applicators
already evaluated, so a validator that answers only true/false cannot grow
them without being rewritten. Every evaluation therefore returns
`{:valid? :props :items :errors}` - the property names and item indices that
were evaluated AT THIS INSTANCE LOCATION, plus every fault found underneath.
Two kinds of applicator, and the difference is the whole design:
- IN PLACE (`$ref`, `$dynamicRef`, `allOf`, `anyOf`, `oneOf`, `if`/`then`/
`else`, `dependentSchemas`) apply another schema to the SAME instance
location, so their annotations belong to this location and bubble up.
- CHILD (`properties`, `patternProperties`, `additionalProperties`, `items`,
`prefixItems`, `contains`, `propertyNames`) apply to a location BELOW, so
their annotations stay there and this location records only which member
was covered.
Identifiers are resolved once, when the schema is compiled: `$id` moves the
base URI, `$anchor` and `$dynamicAnchor` name a place inside it, and the
index that comes out is what `$ref` and `$dynamicRef` read. Nothing is
fetched over the network, ever - a schema that references a document the
caller did not supply is a compile error, not a silent pass.What every format the 2020-12 specification names actually asserts.
format is an ANNOTATION by default and this namespace is only consulted
when a schema asks for the assertion - by declaring the format-assertion
vocabulary, or because the caller compiled with :format-assertion true.
An unknown format is not an error: it annotates and asserts nothing, which
is why known? is a question worth asking before valid? answers one.
Every check is the grammar of the specification that owns it, written out
rather than delegated: java.net.URI is RFC 2396 and accepts what RFC 3986
refuses, InetAddress resolves names, and DateTimeFormatter has no
opinion about a leap second, which RFC 3339 permits at exactly one instant
of the day.
What every `format` the 2020-12 specification names actually asserts. `format` is an ANNOTATION by default and this namespace is only consulted when a schema asks for the assertion - by declaring the format-assertion vocabulary, or because the caller compiled with `:format-assertion true`. An unknown format is not an error: it annotates and asserts nothing, which is why `known?` is a question worth asking before `valid?` answers one. Every check is the grammar of the specification that owns it, written out rather than delegated: `java.net.URI` is RFC 2396 and accepts what RFC 3986 refuses, `InetAddress` resolves names, and `DateTimeFormatter` has no opinion about a leap second, which RFC 3339 permits at exactly one instant of the day.
Internationalized domain names, as IDNA2008 and UTS 46 define them - what
format: idn-hostname asserts and what format: idn-email asks about the
part after the at sign.
A name is read the way a resolver reads it. First the whole string is
MAPPED: the characters Unicode discards in a domain name are dropped, the
compatibility forms are folded (so a fullwidth digit becomes an ASCII one)
and everything is lower-cased. Then it is split on the four characters that
separate labels - . and its ideographic, fullwidth and halfwidth twins.
Each label is then either an A-label, xn-- followed by Punycode, which is
decoded and must re-encode to exactly what arrived, or a U-label, whose
every code point must be PVALID by the derived property of RFC 5892 - and
the handful that are only CONTEXTUALLY valid must satisfy their rule: a
MIDDLE DOT between two ls, a Greek KERAIA before a Greek letter, a
KATAKANA MIDDLE DOT in a label that has Japanese in it, a ZERO WIDTH JOINER
after a virama, and Arabic-Indic digits that do not mix with their extended
cousins. Finally, a name with any right-to-left label answers to the Bidi
rule of RFC 5893, which is what makes 0a.<hebrew> invalid while
<arabic><extended-indic-digit> stays valid.
Two of the tables Unicode publishes have no Java API - the derived property
NFKC_CaseFold and Joining_Type - so the first is computed as
NFC(lower-case(NFKC(x))) and the second from the script and category of
the character, with the right-joining letters of the Arabic block written
out. Both agree with the published data on everything a domain name can
hold; neither is a substitute for the tables themselves.
Internationalized domain names, as IDNA2008 and UTS 46 define them - what `format: idn-hostname` asserts and what `format: idn-email` asks about the part after the at sign. A name is read the way a resolver reads it. First the whole string is MAPPED: the characters Unicode discards in a domain name are dropped, the compatibility forms are folded (so a fullwidth digit becomes an ASCII one) and everything is lower-cased. Then it is split on the four characters that separate labels - `.` and its ideographic, fullwidth and halfwidth twins. Each label is then either an A-label, `xn--` followed by Punycode, which is decoded and must re-encode to exactly what arrived, or a U-label, whose every code point must be PVALID by the derived property of RFC 5892 - and the handful that are only CONTEXTUALLY valid must satisfy their rule: a MIDDLE DOT between two `l`s, a Greek KERAIA before a Greek letter, a KATAKANA MIDDLE DOT in a label that has Japanese in it, a ZERO WIDTH JOINER after a virama, and Arabic-Indic digits that do not mix with their extended cousins. Finally, a name with any right-to-left label answers to the Bidi rule of RFC 5893, which is what makes `0a.<hebrew>` invalid while `<arabic><extended-indic-digit>` stays valid. Two of the tables Unicode publishes have no Java API - the derived property NFKC_CaseFold and Joining_Type - so the first is computed as `NFC(lower-case(NFKC(x)))` and the second from the script and category of the character, with the right-joining letters of the Arabic block written out. Both agree with the published data on everything a domain name can hold; neither is a substitute for the tables themselves.
ECMAScript regular expressions in the dialect java.util.regex speaks.
pattern and patternProperties hold ECMA-262 regular expressions, and
Java's are ALMOST the same language. Every difference between the two is
silent - the pattern compiles on both sides and matches different strings:
\s is six ASCII characters in Java; in ECMAScript it is every space
separator, both line terminators and the byte-order mark,\v is one vertical tab in ECMAScript and a whole class of vertical
whitespace in Java,\ca and \cA are the same control character in ECMAScript, which
takes the letter modulo 32; Java exclusive-ors with 64 and answers !,\b inside a character class is a backspace in ECMAScript,\0 is NUL in ECMAScript and the start of an octal escape in Java,\p{Letter} and \p{Script=Greek} are \p{L} and \p{IsGreek}.One scan answers both questions this library asks of a pattern: how Java
spells it, and whether it was ECMAScript in the first place - which is what
format: regex asserts, and why (?P<name>...), (?#comment) and the
inline flags (?i) are refused even though Java understands two of them.
ECMAScript regular expressions in the dialect java.util.regex speaks.
`pattern` and `patternProperties` hold ECMA-262 regular expressions, and
Java's are ALMOST the same language. Every difference between the two is
silent - the pattern compiles on both sides and matches different strings:
- `\s` is six ASCII characters in Java; in ECMAScript it is every space
separator, both line terminators and the byte-order mark,
- `\v` is one vertical tab in ECMAScript and a whole class of vertical
whitespace in Java,
- `\ca` and `\cA` are the same control character in ECMAScript, which
takes the letter modulo 32; Java exclusive-ors with 64 and answers `!`,
- `\b` inside a character class is a backspace in ECMAScript,
- `\0` is NUL in ECMAScript and the start of an octal escape in Java,
- `\p{Letter}` and `\p{Script=Greek}` are `\p{L}` and `\p{IsGreek}`.
One scan answers both questions this library asks of a pattern: how Java
spells it, and whether it was ECMAScript in the first place - which is what
`format: regex` asserts, and why `(?P<name>...)`, `(?#comment)` and the
inline flags `(?i)` are refused even though Java understands two of them.URI reference resolution and JSON Pointer tokens - the addressing half of JSON Schema.
Identifiers in a schema are URI REFERENCES: $id moves the base, $ref
resolves against whatever base encloses it, and a fragment is either an
anchor name or a JSON Pointer. Everything here is string work; nothing
fetches anything, because a validator that resolves a reference over the
network is a validator that fails differently on every machine.
URI reference resolution and JSON Pointer tokens - the addressing half of JSON Schema. Identifiers in a schema are URI REFERENCES: `$id` moves the base, `$ref` resolves against whatever base encloses it, and a fragment is either an anchor name or a JSON Pointer. Everything here is string work; nothing fetches anything, because a validator that resolves a reference over the network is a validator that fails differently on every machine.
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |