@jarenjs/formats
v0.56.0
Published
Jaren Formats for JSON Schema Validation
Readme
@jarenjs/formats
Format validators for the JSON Schema format keyword, built on the text validators of @jarenjs/core. Includes all standard string formats (date-time, date, time, duration, email, idn-email, hostname, idn-hostname, ipv4, ipv6, uri, uri-reference, uri-template, iri, iri-reference, uuid, regex) plus many extras (iregexp, isbn10, mac, base64, alpha, color, ...) and numeric formats (int8 ... uint64, float16 ... float64).
The JSON addressing formats are grouped separately in jsonFormats: json-pointer, json-pointer-uri-fragment and relative-json-pointer (RFC 6901), and json-path, which validates query strings against the complete RFC 9535 grammar using the parser of the JSONPath compiler in @jarenjs/json, plus json-path-segments for the variable-rooted path strings of the Jaren query format.
The geospatial formats are grouped in geoFormats: geohash, wkt and geojson, backed by the spatial kernel in @jarenjs/core/geo.
The name → predicate bindings live in one canonical table, exported as formatTesters (plus the per-group stringFormatTesters, jsonFormatTesters, geoFormatTesters, dateTimeFormatTesters, numberFormatTesters): bare synchronous predicates without validator coupling. The format compilers above wrap these testers in the validator contract, and @jarenjs/forms merges its rendering hints over the same table for per-keystroke field validation — one registry, so the two layers can never drift apart.
Usage
import { JarenValidator } from '@jarenjs/validate';
import * as formats from '@jarenjs/formats';
const jaren = new JarenValidator()
.addFormats(formats.stringFormats)
.addFormats(formats.numberFormats)
.addFormats(formats.dateTimeFormats)
.addFormats(formats.jsonFormats)
.addFormats(formats.geoFormats);
const validate = jaren.compile({ type: 'string', format: 'json-path' });
validate('$.store.book[[email protected] < 10]'); // trueFormat assertion follows the specification per draft: asserted through draft 2019-09, annotation-only from draft 2020-12 on unless enabled via the formatAssertion option (new JarenValidator({ formatAssertion: true })) or a metaschema that declares the format-assertion vocabulary.
Register the group before you use a name from it, and register the right one. The groups are split, so date-time lives in dateTimeFormats and not in stringFormats, and json-path lives in jsonFormats. Registering only stringFormats and then writing format: 'date-time' leaves the keyword accepting every value — per spec, an unregistered format is an annotation and asserts nothing, so nothing anywhere reports it. For schemas you own, compile with new JarenValidator({ unknownFormats: 'error' }): the missing registration then fails at compile time instead of silently. This repository does that for every schema it ships, gated by test/validate/our-schema-formats.test.js.
Register the compilers, not the testers. stringFormats and formatTesters are both objects full of functions, but only the compilers take (schemaObj, jsonSchema) and return the per-value validator; a tester registered in a compiler's place compiles to nothing. That one throws under either unknownFormats setting, because it is never intentional. Use formatTesters directly — as @jarenjs/forms does for per-keystroke field validation — rather than through addFormats.
✍ The complete format list
✍ Formats for strings
These format validators are based on the json-schema.org website. They are grouped in stringFormats (with the date/time formats also available separately as dateTimeFormats).
🗨 Formats for datetime
date-time| according to RFC3339, time-zone is mandatorydate| according to RFC3339, time-zone is mandatorytime| according to RFC3339, time-zone is mandatoryduration| duration from RFC3339iso-date-time| ISO 8601 date-time with optional timezoneiso-time| ISO 8601 time with optional timezone — the timezone offset is uniformly optional, so a zone-less time such as12:30:00validates
Note: All date time formats can use formatMinimum / formatMaximum and formatExclusiveMinimum and formatExclusiveMaximum. The bounds are folded to epoch milliseconds at compile time and string values compare as numbers, so a validation allocates no Date; a raw Date instance as the value is still accepted and compares numerically.
🗨 Formats for url's, hostnames and emails
url| http/https URL — aurinarrowed to the web schemes, so it must carry an authority and the RFC 3986 grammar still applies (http://localhost:8080andhttp://127.0.0.1/are URLs;http://x/a|bis not)uri| full URI according to RFC3986, parsed against the grammar by character code — an ASCII grammar throughout, so a string carrying non-ASCII characters is aniriand not auriuri-reference| URI reference, absolute or relative, according to RFC3986uri-template| URI template according to RFC6570iri| full URI with international characters, according to RFC3987 — parsed against the grammar by character code, so percent-encoding must be well formed andiprivateis accepted in the query onlyiri-reference| full IRI reference, absolute or relative, according to RFC3987email| email address according to RFC5321, including quoted-string local parts and[192.0.2.1]/[IPv6:::1]address literalshostname| host name according to RFC1034idn-hostname| host name with international charactersidn-email| email address with international characters
🗨 Formats for identifiers
uuid| Universally Unique IDentifier according to RFC4122guid| Globally Unique IDentifier according to Microsoftidentifier| C-type identifierhtml-identifier| html elementidattribute identifier according to RFC7992css-identifier| css class name identifier according to RFC7993mac| ethernet interface identifier (EUI-48) according to IEEE820ipv4| IP v4 address according to RFC791ipv6| IP v6 address according to RFC2460
🗨 Formats for json pointers and paths
These are grouped in jsonFormats.
json-pointer| JSON-pointer according to RFC6901json-pointer-uri-fragment| JSON-pointer fragment according to RFC6901relative-json-pointer| relative JSON-pointer according to draft-luff-relative-json-pointer-00json-path| JSONPath query according to RFC9535, checked against the complete grammar (including filter well-typedness) by the parser of the JSONPath compiler in@jarenjs/jsonjson-path-segments| a variable-rooted path string —$namefollowed by optional RFC9535 segments ($book.price[[email protected]]), the form the Jaren query format uses to address a bound variable. Not a valid RFC 9535 query on its own (the RFC's root identifier is$alone), sojson-pathrejects it; both formats recognize the five built-in function extensions and no others, because a format has to mean the same thing in every schema
🗨 Miscellaneous formats
alpha| allow only ASCII alpha characters (a-zA-Z)numeric| allow only numeric characters (0-9)alphanumeric| allow only ASCII alpha numeric charactershexadecimal| allow only hexadecimal characters (0-9a-fA-F)uppercase| allow only upper case alpha characterslowercase| allow only lower case alpha characterscolor| web color hex string (starts with #, must be 3 or 6 hax characters)regex| tests whether a string is a valid regular expressioniregexp| tests whether a string is a valid I-Regexp according to RFC9485 — the interoperable subset that means the same thing in every regexp dialect, so it is stricter thanregex: shorthand classes (\d,\w), lazy quantifiers, anchors and lookaround are all rejectedbase64| base64 encoded databyte| same asbase64formatisbn10| International Standard Book Number 10 digit numberisbn13| International Standard Book Number 13 digit numbercountry2| country code by alpha-2 according to ISO3166-1 — the 249 assigned codes plusXK, the user-assigned code for Kosovo; matched case-insensitivelyiban| International Bank Account Number according to ISO13616 — checks the country's registered length, the alphanumeric body and the ISO 7064 MOD 97-10 check digits, so a transposed digit is caught; accepts both the compact electronic format (NL91ABNA0417164300) and the print format grouped in fours (NL91 ABNA 0417 1643 00)
✍ Geospatial formats
These are grouped in geoFormats, backed by the spatial kernel in @jarenjs/core/geo.
geohash| a base-32 geohash cell name, any length (u173z); the alphabet is lowercase and deliberately omitsa,i,landowkt| a Well-Known Text geometry (ISO 19125 / OGC Simple Features): the seven tagged types with optionalZ/M/ZMmodifiers,EMPTY, consistent coordinate counts and closed polygon rings; an unmodified tag accepts 2 or 3 coordinates per point, as the field (PostGIS) doesgeojson| a structurally valid GeoJSON object per RFC 7946 — unlike every other format this one applies to objects, and it enforces the invariant JSON Schema provably cannot: every linear ring closed
geojson exists next to the GeoJSON meta-schema artifacts in @jarenjs/json, not instead of them, and the division of labour is deliberate: the format is the one-keyword annotation that answers yes or no in a single call, while the meta-schema locates the failure and (in the $query-extended variant) also checks ring winding. Reach for the schema when you want a diagnosis; reach for the format when you only want the gate.
✍ Formats for numbers
These are grouped in numberFormats. Formats for numbers validate both numbers and strings as number types; combine them with the type keyword (e.g. { "type": "integer", "format": "int32" }) when only real number types should be allowed.
🗨 Formats integer numbers
int8| signed 8 bit integeruint8| unsigned 8 bit integerint16| signed 16 bit integeruint16| unsigned 16 bit integerint32| signed 32 bit integeruint32| unsigned 32 integerint64| signed 64 integeruint64| unsigned 64 integer
🗨 Formats floating point numbers
float16| 16 bit floating point numberfloat32| 32 bit floating point numberfloat64| 64 bit floating point numberfloat| 32 bit floating point numberdouble| 64 bit floating point number
Development
Unit tests live in test/formats/ at the repository root; test/formats/testers.test.js enforces that every compiler registry's key set equals its tester group's, so the validator layer and the bare-predicate layer can never drift. The predicates themselves are implemented and tested in @jarenjs/core. See the repository README for the monorepo picture and the ROADMAP for planned formats.
