Liking cljdoc? Tell your friends :D

com.blockether.skjema.core

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.

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.
raw docstring

com.blockether.skjema.format

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.
raw docstring

com.blockether.skjema.idn

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.
raw docstring

com.blockether.skjema.regex

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.
raw docstring

com.blockether.skjema.uri

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.
raw docstring

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close