Jaren is a high-performance JSON Schema Validating Compiler written in vanilla JavaScript. It offers full support for draft6, draft7, and partial support for draft2019 and draft2020. Jaren is designed for speed and is under active development.
This library started as a personal merge of some useful javascript algorithms, functions, modules and classes, I programmed or snippits that I used over the years; stuff that I used and didn't want to forget about and wrapped them in an organized way into a monorepo as a JSON Schema validating compiler library that anyone can use.
Please read Understanding JSON Schema for a more comprehensive guide on what JSON Schema is (not Jaren!).
We recommend you clone this repository and install the dependencies with nodejs by just running the following command in the terminal at the root of the repository.
npm install
npm run build
npm run coverAt its current state, we recommend you use the @jarenjs/validate package, which is stable and will not change any of its public interfaces.
For format support please use the @jarenjs/formats package with it.
But for now its recommended you dive into the test folder and try to find your way from there.
Programming is like sex.
One mistake and you have to support it for the rest of your life.
Jaren supports a wide range of JSON Schema validation keywords. Here's a quick overview:
- JSON data type:
type,nullable,required - Numbers:
maximum,minimum,multipleOf - Strings:
maxLength,minLength,pattern - Arrays:
maxItems,minItems,uniqueItems,items,contains - Objects:
maxProperties,minProperties,required,properties,patternProperties - All types:
enum,const - Compound:
not,oneOf,anyOf,allOf,if/then/else - Meta:
$id,$ref,$anchor
π₯ For a complete list of supported keywords and their implementation status, click here
- type
- nullable | (OpenAPI)
- required | as boolean (OpenAPI)
- maximum / minimum
or exclusiveMaximum / exclusiveMinimum - multipleOf
- maxLength / minLength
- pattern
- format
- formatMinimum / formatMaximum
or formatExclusiveMinimum / formatExclusiveMaximum
- maxItems / minItems
- uniqueItems
- items
- items | as schema or tuple deprecated in
draft2020 - items | as schema only new
draft2020
- items | as schema or tuple deprecated in
- prefixItems | as tuple new
draft2020 - additionalItems | as schema deprecated in
draft2020 - contains
- maxContains / minContains | new
draft2019 - β unevaluatedItems | new
draft2019(in-progress)
- maxProperties / minProperties
- required | as array!
- properties
- patternProperties
- additionalProperties
- dependencies | deprecated in
draft2019 - dependentRequired | new
draft2019 - dependentSchemas | new
draft2019 - propertyNames
- β unevaluatedProperties | new
draft2019(in-progress) - β propertyDependencies
- enum
- const
- not
- oneOf
- anyOf
- allOf
- if / then / else
See also:
- β $schema
- $id
- $ref
- $anchor
- β $recursiveRef | new
draft2019& deprecated indraft2020 - β $recursiveAnchor | new
draft2019& deprecated indraft2020 - β $dynamicRef | new
draft2020 - β $dynamicAnchor | new
draft2020 - β $data | (Ajv specific)
- β $vocabulary | new
draft2020
- β strict
- strictFormat | used to enforce a specific format type like numbers and integers (in-progress)
- β strictTuple
- β errorMessage
- definitions | used by initial schema traversal deprecated in
draft2019 - $defs | used by initial schema traversal new
draft2019 - components | (OpenAPI)
Jaren supports various format validators for strings and numbers, including:
- Date and Time:
date-time,date,time - URLs and Emails:
url,email,hostname,ipv4,ipv6 - Identifiers:
uuid,guid,identifier - Numbers:
int8,uint8,int16,uint16,int32,uint32,float32,float64
But we have many more formats that are not listed here!
π₯ For a complete list of supported formats, click here
These format validators are based on the json-schema.org website.
-
date-time| according to RFC3339, time-zone is mandatory -
date| according to RFC3339, time-zone is mandatory -
time| according to RFC3339, time-zone is mandatory -
β
duration| duration from RFC3339 -
β
iso-date-time| date-time with optional time-zone -
β
iso-time| time with optional time-zone
Note: All date time formats can use formatMinimum / formatMaximum and formatExclusiveMinimum and formatExclusiveMaximum
-
url| full URL -
url--full| same asurl, but more comprehensive -
uri| full URI -
uri--full| same asuri, but more comprehensive -
uri-reference| URI reference, including full and relative URIs -
uri-reference--full| same asuri-reference, but more comprehensive -
uri-template| URI template according to RFC6570 -
iri| full URI with international characters -
iri-reference| full URI reference with with international characters -
email| email address -
email--full| same as email, but more comprehensive -
hostname| host name according to RFC1034 -
idn-hostname| host name with international characters -
idn-email| email address with international characters
-
uuid| Universally Unique IDentifier according to RFC4122 -
guid| Globally Unique IDentifier according to Microsoft -
identifier| C-type identifier -
html-identifier| html elementidattribute identifier according to RFC7992 -
css-identifier| css class name identifier according to RFC7993 -
mac| ethernet interface identifier (EUI-48) according to IEEE820 -
ipv4| IP v4 address according to RFC791 -
ipv6| IP v6 address according to RFC2460
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-00- β
json-path| JSONPath according to RFC9535
-
alpha| allow only ASCII alpha characters (a-zA-Z) -
numeric| allow only numeric characters (0-9) -
alphanumeric| allow only ASCII alpha numeric characters -
hexadecimal| allow only hexadecimal characters (0-9a-fA-F) -
uppercase| allow only upper case alpha characters -
lowercase| allow only lower case alpha characters -
color| web color hex string (starts with #, must be 3 or 6 hax characters) -
regex| tests whether a string is a valid regular expression -
base64| base64 encoded data -
byte| same asbase64format -
isbn10| International Standard Book Number 10 digit number -
isbn13| International Standard Book Number 13 digit number -
country2| Country code by alpha-2 according to ISO3166-1 !No tests exists! -
iban| International Bank Account Number !No tests exists!
Formats for numbers validate both numbers and strings as number types. If you want to strictly only allow number types, you can explicitly set the strictFormat keyword to boolean true to only allow strict number or integer types.
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
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
I manager tried to open that door before,
but it apparently was scheduled for the next release.
- 0.8
- current
- 0.9
- Jaren as a drop-in replacement for Ajv
- add benchmark test suite for
draft7 - Fixing JSON error schema output
- add error reporting tests
- π 1.0 Stable release for
draft7- add i18n
- add development documentation
- add examples
- 1.1
- Modelling Inheritance with JSON Schema
- Express array constraints more cleanly
- 1.2
- Using Dynamic References to Support Generic Types
- 1.3
- Runtime schema manipulation of constraints
- 1.4-1.9
- Fix bugs and/or add forgotten features for latest draft compliance
- 2.0 π Stable release for
draft2020
π₯ To get the full picture and details about what that roadmap entails, click here
You can trust that if I say I do something, I will definitely do it unless I don't!
Jaren is a mono-repo with multiple workspaces in the ./packages directory. Because of this, Jaren imports its core, validator, formats and in later versions its reviver (see JSON.parse) and replacer (see JSON.stringify) from its workspace packages. This has not been done yet and simply exports the available packages from its workspace imports, without wrapping them into a Jaren class that exposes a similar api as Ajv does.
On a extra note: Ajv compiles or a function or a promise. Jaren will NOT do this, instead it will expose an extra method for async compilers: compileAsync. Note also: that Jaren will NOT include a default meta schema, but has to be added separately by the caller.
See also:
From the blog post of the json-schema.org website. This feature needs to implement the following keywords in order for the proposed schema structure to work: errorMessage
See also:
From the blog post of the json-schema.org website. This feature needs to implement the following keywords in order for the proposed schema structure to work: unevaluatedProperties. Jaren has already implemented some code to make this feature work by introducing the ValidationResults class and the refactoring of the compileObjectSchema functions.
See also:
From the release notes of the 2020-12 draft, there has been proposed a way to handle items that where neither validated by the items or contains keyword of an array schema object. This feature needs to implement the keyword unevaluatedItems.
From the blog post of the json-schema.org website. This feature needs to implement the following keywords in order for the proposed schema structure to work: $dynamicAnchor, $dynamicRef. We might also support $recursiveAnchor and $recursiveRef to be backwards compatible with draft2019
See also:
- Understanding lexical dynamic scopes
- Improve/simplify "$recursiveAnchor" and "$recursiveRef"
- Lexical Scope and Dynamic Scope
- Keyword for extending a schema
- Recursive References with "$recursiveRef" and "$recursiveAnchor"
- $dynamicRef and $dynamicAnchor
The Ajv JSON Schema validator has implemented the $data keyword that can extend the otherwise constant schema values with dynamic runtime values for the following keywords: const, enum, format, minLength, maxLength, pattern, minimum, maximum, exclusiveMinimum, exclusiveMaximum, multipleOf, minProperties, maxProperties, required, minItems, maxItems, uniqueItems. This however has seen enough criticism from multiple developers claiming not to follow the json spec intention and or not being comprehensive enough for more radical manipulations. Besides those against the proposal, many developers and companies use the $data keyword, or other implementations like the data-ref proposal from json-everything, successfully.
See also:
Procrastination
I will look up what that means, later...
For detailed documentation on using Jaren, including API references and advanced usage examples, visit our official documentation. Which is the code itself.
Even though es2017 is becoming pretty cool, jaren includes an extensive set of additional extensions to common types found in @jarenjs/core. We have added functionality for Number, String, Date, Object and Array classes including a set of test and getters related to the javascript type system.
For object types @jarenjs/core has special functions to manipulate array and objects alike including types like Map. @jarenjs/core also added some additional classes to queue or traverse tree like data structures.
We've added some additional string and regex functionality to the @jarenjs/core/text package to make it more powerful and flexible. You will find a lot of functionality to validate your input with. You can do this without using json schema and its formats. It can be really useful in day to day usage like checking for country codes, zip codes, iban numbers, etc. The @jarenjs/formats package exposes all the validation functions for the @jarenjs/validate package if you want to make use of them in a schema kind of way.
There are 4 extensive math classes defined in @jarenjs/core/calc; int32, float64, vec2i32, vec2f64 and vec3f64. The Matrix class is not yet supported. @jarenjs/core/calc tries to encapsulate and group math functionality as much as possible. This with the idea to help the Javascript Runtime compiler determine what we are looking at. Each class has two types of operator groups; pure and impure. As the name suggests, pure operators are immutable and return a new structure, impure operators operates on the structure itself. The @jarenjs/formats package exposes some of these functions to make them available for the @jarenjs/validate package.
The int32 and float32 classes are mere helper functions to speed up your inner loops as some benchmarks suggests. However, these benchmarks are highly speculative and the results differ greatly between browser versions. I still implemented them for two reasons; 1) sometimes I like to be explicit. 2) sometimes it helps me to remember how stuff works. The int32 class also implements some complex operators like sin, cos and others too.
The vector classes vec2i32, vec2f64 and vec3f64 contain enough functionality to quickly do about any operation you want. The primitive pure operators (add, sub, mul, div) and impure operators (iadd, isub, imul, idiv) are supported for the vec2i32, vec2f64 and vec2f64 classes. They also contain product operators (mag2 - magnitude square, mag - magnitude, dot, crossABAB) and other more complex vector operators (unit, iunit).
Is it true that when computer software is designed,
a back door is left for the designer to enter at will?
We welcome contributions from the community! Here's how you can help:
- Report Issues: Found a bug or have a feature request? Open an issue.
- Improve Documentation: Help us make Jaren easier to use by improving our docs.
- Add Tests: Increase our test coverage, especially for draft2019 and draft2020 features.
- Implement New Features: Pick an item from our roadmap and submit a pull request.
So frequently asked
but never out spoken
what shadow arises
what hath thou awoken
I am aware of the excellent Ajv and zod validators, but I really needed to understand json schema in the first place and I wanted to do something else (see if I could beat its first place in speed). We as programmers work with validation all over the place, especially at the front-end, but also at the back-end and in the middle-ware. Since 2023 I started working a lot with LLM's and I believe that in order to work with them in a more natural way, we need to speak JSON, all the way down. So I decided to create a JSON Schema validator that is fully compliant with the JSON Schema specification and should be fast for the fun of it, but that is also easy to understand and easy to extend. Not by plugins perse, but by simply opening up the code and see what is going on.
Good question! I believe that vanilla javascript for a library like this is a little bit more straight forward to understand. And to be honest, I just like javascript. TypeScript is an excellent language but there is also a lot of boilerplate code that might be a bit too much for what we are trying to accomplish here. And I don't want to use a transpiler that might destroy my intentions of how it should be working, since I understand how the JIT compiler is working very well. Also I do use JSDoc to generate the documentation for the code and that should be enough for most of the users and TypeScript libraries when they want to make use of Jaren. Therefor I don't see the need for TypeScript here.
If you find bugs, or want to know what a function is doing, please don't hesitate to ask me by filing an issue. Off topic questions I'd rather not see, but any jaren related question is very welcome.
Please file an issue at the github jaren repository.
