From ce2d2f07cdb0ba8232a43d9e35d814b14b7d0d67 Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Wed, 3 Mar 2021 18:11:32 +0000 Subject: [PATCH 01/25] vuepress site --- docs/.vuepress/config.js | 61 +++++ docs/README.md | 531 +++++++++++++++++++++++++++++++++++++++ docs/json-schema.md | 2 +- package.json | 7 +- 4 files changed, 598 insertions(+), 3 deletions(-) create mode 100644 docs/.vuepress/config.js create mode 100644 docs/README.md diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js new file mode 100644 index 000000000..7a425c034 --- /dev/null +++ b/docs/.vuepress/config.js @@ -0,0 +1,61 @@ +module.exports = { + title: "Ajv: Another JSON validator", + description: "Just playing around", + themeConfig: { + logo: "https://ajv.js.org/images/ajv_logo.png", + nav: [ + {text: "Home", link: "/"}, + { + text: "Validation", + items: [ + {text: "Validating data", link: "/validation"}, + {text: "Strict mode", link: "/strict-mode"}, + {text: "JSON Schema", link: "/json-schema"}, + {text: "JSON Type Definition", link: "/json-type-definition"}, + {text: "Type coercion", link: "/coercion"}, + ], + }, + { + text: "API", + items: [ + {text: "Methods & options", link: "/api"}, + {text: "Define keywords", link: "/keywords"}, + ], + }, + {text: "Security", link: "/security"}, + {text: "FAQ", link: "/faq"}, + ], + sidebar: [ + "/", + "/faq", + "/security", + { + title: "Validation", + collapsable: false, + children: [ + "/validation", + "/strict-mode", + "/json-schema", + "/json-type-definition", + "/api", + "/keywords", + "/coercion" + ] + }, + { + title: "Code generation & design", + collapsable: false, + children: [ + "/standalone", + "/codegen", + "/components", + ] + }, + ], + nextLinks: false, + prevLinks: false, + repo: 'ajv-validator/ajv', + docsDir: 'docs', + editLinks: true, + }, +} diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 000000000..051aab899 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,531 @@ +# Ajv: Another JSON validator + +Ajv logo + +The fastest JSON schema validator for Node.js and browser. + +Supports JSON Schema draft-06/07/2019-09 (draft-04 is supported in [version 6](https://github.com/ajv-validator/ajv/tree/v6)) and JSON Type Definition [RFC8927](https://datatracker.ietf.org/doc/rfc8927/). + +[![build](https://github.com/ajv-validator/ajv/workflows/build/badge.svg)](https://github.com/ajv-validator/ajv/actions?query=workflow%3Abuild) +[![npm](https://img.shields.io/npm/v/ajv.svg)](https://www.npmjs.com/package/ajv) +[![npm downloads](https://img.shields.io/npm/dm/ajv.svg)](https://www.npmjs.com/package/ajv) +[![Coverage Status](https://coveralls.io/repos/github/ajv-validator/ajv/badge.svg?branch=master)](https://coveralls.io/github/ajv-validator/ajv?branch=master) +[![Gitter](https://img.shields.io/gitter/room/ajv-validator/ajv.svg)](https://gitter.im/ajv-validator/ajv) +[![GitHub Sponsors](https://img.shields.io/badge/$-sponsors-brightgreen)](https://github.com/sponsors/epoberezkin) + +## Platinum sponsors + +[](https://www.mozilla.org)[](https://opencollective.com/ajv)[](https://opencollective.com/ajv) + +## Using version 7 + +Ajv version 7 has these new features: + +- NEW: support of JSON Type Definition [RFC8927](https://datatracker.ietf.org/doc/rfc8927/) (from [v7.1.0](https://github.com/ajv-validator/ajv-keywords/releases/tag/v7.1.0)), including generation of [serializers](./docs/api.md#jtd-serialize) and [parsers](./docs/api.md#jtd-parse) from JTD schemas that are more efficient than native JSON serialization/parsing, combining JSON string parsing and validation in one function. +- support of JSON Schema draft-2019-09 features: [`unevaluatedProperties`](./docs/json-schema.md#unevaluatedproperties) and [`unevaluatedItems`](./docs/json-schema.md#unevaluateditems), [dynamic recursive references](./docs/validation.md#extending-recursive-schemas) and other [additional keywords](./docs/json-schema.md#json-schema-draft-2019-09). +- to reduce the mistakes in JSON schemas and unexpected validation results, [strict mode](./docs/strict-mode.md) is added - it prohibits ignored or ambiguous JSON Schema elements. +- to make code injection from untrusted schemas impossible, [code generation](./docs/codegen.md) is fully re-written to be safe and to allow code optimization (compiled schema code size is reduced by more than 10%). +- to simplify Ajv extensions, the new keyword API that is used by pre-defined keywords is available to user-defined keywords - it is much easier to define any keywords now, especially with subschemas. [ajv-keywords](https://github.com/ajv-validator/ajv-keywords) package was updated to use the new API (in [v4.0.0](https://github.com/ajv-validator/ajv-keywords/releases/tag/v4.0.0)) +- schemas are compiled to ES6 code (ES5 code generation is also supported with an option). +- to improve reliability and maintainability the code is migrated to TypeScript. + +**Please note**: + +- the support for JSON-Schema draft-04 is removed - if you have schemas using "id" attributes you have to replace them with "\$id" (or continue using [Ajv v6](https://github.com/ajv-validator/ajv/tree/v6) that will be supported until 02/28/2021). +- all formats are separated to ajv-formats package - they have to be explicitly added if you use them. + +See [release notes](https://github.com/ajv-validator/ajv/releases/tag/v7.0.0) for the details. + +To install the new version: + +```bash +npm install ajv +``` + +See [Getting started](#usage) for code example. + +## Contributing + +100+ people contributed to Ajv. You are very welcome to join by implementing new features that are valuable to many users and by improving documentation. + +Please do not be disappointed if your suggestion is not accepted - it is important to maintain the balance between the library size, performance and functionality. If it seems that a feature would benefit only a small number of users, its addition may be delayed until there is more support from the users community - so please submit the issue first to explain why this feature is important. + +Please include documentation and test coverage with any new feature implementations. + +To run tests: + +```bash +npm install +git submodule update --init +npm test +``` + +`npm run build` - compiles typescript to `dist` folder. + +Please review [Contributing guidelines](./CONTRIBUTING.md) and [Code components](./docs/components.md). + +## Contents + +- [Platinum sponsors](#platinum-sponsors) +- [Using version 7](#using-version-7) +- [Contributing](#contributing) +- [Mozilla MOSS grant and OpenJS Foundation](#mozilla-moss-grant-and-openjs-foundation) +- [Sponsors](#sponsors) +- [Performance](#performance) +- [Features](#features) +- [Getting started](#usage) +- [Choosing schema language](#choosing-schema-language) + - [JSON Schema](#json-schema) + - [JSON Type Definition](#json-type-definition) +- [Frequently Asked Questions](./docs/faq.md) +- [Using in browser](#using-in-browser) + - [Content Security Policy](./docs/security.md#content-security-policy) +- [Using in ES5 environment](#using-in-es5-environment) +- [Command line interface](#command-line-interface) +- [API reference](./docs/api.md) + - [Methods](./docs/api.md#ajv-constructor-and-methods) + - [Options](./docs/api.md#options) + - [Validation errors](./docs/api.md#validation-errors) +- NEW: [Strict mode](./docs/strict-mode.md#strict-mode) + - [Prohibit ignored keywords](./docs/strict-mode.md#prohibit-ignored-keywords) + - [Prevent unexpected validation](./docs/strict-mode.md#prevent-unexpected-validation) + - [Strict types](./docs/strict-mode.md#strict-types) + - [Strict number validation](./docs/strict-mode.md#strict-number-validation) +- [Data validation](./docs/validation.md) + - [Validation basics](./docs/validation.md#validation-basics): [JSON Schema keywords](./docs/validation.md#validation-keywords), [annotations](./docs/validation.md#annotation-keywords), [formats](./docs/validation.md#formats) + - [Modular schemas](./docs/validation.md#modular-schemas): [combining with \$ref](./docs/validation.md#ref), [\$data reference](./docs/validation.md#data-reference), [$merge and $patch](./docs/validation.md#merge-and-patch-keywords) + - [Asynchronous schema compilation](./docs/validation.md#asynchronous-schema-compilation) + - [Standalone validation code](./docs/standalone.md) + - [Asynchronous validation](./docs/validation.md#asynchronous-validation) + - [Modifying data](./docs/validation.md#modifying-data-during-validation): [additional properties](./docs/validation.md#removing-additional-properties), [defaults](./docs/validation.md#assigning-defaults), [type coercion](./docs/validation.md#coercing-data-types) +- [Extending Ajv](#extending-ajv) + - User-defined keywords: + - [basics](./docs/validation.md#user-defined-keywords) + - [guide](./docs/keywords.md) + - [Plugins](#plugins) + - [Related packages](#related-packages) +- [Security considerations](./docs/security.md) + - [Security contact](./docs/security.md#security-contact) + - [Untrusted schemas](./docs/security.md#untrusted-schemas) + - [Circular references in objects](./docs/security.md#circular-references-in-javascript-objects) + - [Trusted schemas](./docs/security.md#security-risks-of-trusted-schemas) + - [ReDoS attack](./docs/security.md#redos-attack) + - [Content Security Policy](./docs/security.md#content-security-policy) +- [Some packages using Ajv](#some-packages-using-ajv) +- [Changes history](#changes-history) +- [Support, Code of conduct, Contacts, License](#open-source-software-support) + +## Mozilla MOSS grant and OpenJS Foundation + +[](https://www.mozilla.org/en-US/moss/)     [](https://openjsf.org/blog/2020/08/14/ajv-joins-openjs-foundation-as-an-incubation-project/) + +Ajv has been awarded a grant from Mozilla’s [Open Source Support (MOSS) program](https://www.mozilla.org/en-US/moss/) in the “Foundational Technology” track! It will sponsor the development of Ajv support of [JSON Schema version 2019-09](https://tools.ietf.org/html/draft-handrews-json-schema-02) and of [JSON Type Definition (RFC8927)](https://datatracker.ietf.org/doc/rfc8927/). + +Ajv also joined [OpenJS Foundation](https://openjsf.org/) – having this support will help ensure the longevity and stability of Ajv for all its users. + +This [blog post](https://www.poberezkin.com/posts/2020-08-14-ajv-json-validator-mozilla-open-source-grant-openjs-foundation.html) has more details. + +I am looking for the long term maintainers of Ajv – working with [ReadySet](https://www.thereadyset.co/), also sponsored by Mozilla, to establish clear guidelines for the role of a "maintainer" and the contribution standards, and to encourage a wider, more inclusive, contribution from the community. + +## Please [sponsor Ajv development](https://github.com/sponsors/epoberezkin) + +Since I asked to support Ajv development 40 people and 6 organizations contributed via GitHub and OpenCollective - this support helped receiving the MOSS grant! + +Your continuing support is very important - the funds will be used to develop and maintain Ajv once the next major version is released. + +Please sponsor Ajv via: + +- [GitHub sponsors page](https://github.com/sponsors/epoberezkin) (GitHub will match it) +- [Ajv Open Collective️](https://opencollective.com/ajv) + +Thank you. + +#### Open Collective sponsors + + + + + + + + + + + + + + +## Performance + +Ajv generates code to turn JSON Schemas into super-fast validation functions that are efficient for v8 optimization. + +Currently Ajv is the fastest and the most standard compliant validator according to these benchmarks: + +- [json-schema-benchmark](https://github.com/ebdrup/json-schema-benchmark) - 50% faster than the second place +- [jsck benchmark](https://github.com/pandastrike/jsck#benchmarks) - 20-190% faster +- [z-schema benchmark](https://rawgit.com/zaggino/z-schema/master/benchmark/results.html) +- [themis benchmark](https://cdn.rawgit.com/playlyfe/themis/master/benchmark/results.html) + +Performance of different validators by [json-schema-benchmark](https://github.com/ebdrup/json-schema-benchmark): + +[![performance](https://chart.googleapis.com/chart?chxt=x,y&cht=bhs&chco=76A4FB&chls=2.0&chbh=32,4,1&chs=600x416&chxl=-1:|djv|ajv|json-schema-validator-generator|jsen|is-my-json-valid|themis|z-schema|jsck|skeemas|json-schema-library|tv4&chd=t:100,98,72.1,66.8,50.1,15.1,6.1,3.8,1.2,0.7,0.2)](https://github.com/ebdrup/json-schema-benchmark/blob/master/README.md#performance) + +## Features + +- Ajv implements JSON Schema [draft-06/07/2019-09](http://json-schema.org/) standards (draft-04 is supported in v6): + - all validation keywords (see [JSON Schema validation keywords](./docs/json-schema.md)) + - keyword "nullable" from [Open API 3 specification](https://swagger.io/docs/specification/data-models/data-types/). + - full support of remote references (remote schemas have to be added with `addSchema` or compiled to be available) + - support of circular references between schemas + - correct string lengths for strings with unicode pairs + - [formats](#formats) defined by JSON Schema draft-07 standard (with [ajv-formats](https://github.com/ajv-validator/ajv-formats) plugin) and additional formats (can be turned off) + - [validates schemas against meta-schema](./docs/api.md#api-validateschema) +- NEW: supports [JSON Type Definition](https://datatracker.ietf.org/doc/rfc8927/): + - all forms (see [JSON Type Definition schema forms](./docs/json-type-definition.md)) + - meta-schema for JTD schemas + - "union" keyword and user-defined keywords (can be used inside "metadata" member of the schema) +- supports [browsers](#using-in-browser) and Node.js 0.10-14.x +- [asynchronous loading](./docs/validation.md#asynchronous-schema-compilation) of referenced schemas during compilation +- "All errors" validation mode with [option allErrors](./docs/api.md#options) +- [error messages with parameters](./docs/api.md#validation-errors) describing error reasons to allow error message generation +- i18n error messages support with [ajv-i18n](https://github.com/ajv-validator/ajv-i18n) package +- [removing-additional-properties](./docs/validation.md#removing-additional-properties) +- [assigning defaults](./docs/validation.md#assigning-defaults) to missing properties and items +- [coercing data](./docs/validation.md#coercing-data-types) to the types specified in `type` keywords +- [user-defined keywords](#user-defined-keywords) +- draft-06/07 keywords `const`, `contains`, `propertyNames` and `if/then/else` +- draft-06 boolean schemas (`true`/`false` as a schema to always pass/fail). +- additional extension keywords with [ajv-keywords](https://github.com/ajv-validator/ajv-keywords) package +- [\$data reference](./docs/validation.md#data-reference) to use values from the validated data as values for the schema keywords +- [asynchronous validation](./docs/api.md#asynchronous-validation) of user-defined formats and keywords + +## Install + +To install version 7: + +``` +npm install ajv +``` + +## Getting started + +Try it in the Node.js REPL: https://runkit.com/npm/ajv + +In JavaScript: + +```javascript +// or ESM/TypeScript import +import Ajv from "ajv" +// Node.js require: +const Ajv = require("ajv").default + +const ajv = new Ajv() // options can be passed, e.g. {allErrors: true} +const validate = ajv.compile(schema) +const valid = validate(data) +if (!valid) console.log(validate.errors) +``` + +In TypeScript: + +```typescript +import Ajv, {JSONSchemaType, DefinedError} from "ajv" + +const ajv = new Ajv() + +type MyData = {foo: number} + +// Optional schema type annotation for schema to match MyData type. +// To use JSONSchemaType set `strictNullChecks: true` in tsconfig `compilerOptions`. +const schema: JSONSchemaType = { + type: "object", + properties: { + foo: {type: "number", minimum: 0}, + }, + required: ["foo"], + additionalProperties: false, +} + +// validate is a type guard for MyData - type is inferred from schema type +const validate = ajv.compile(schema) + +// or, if you did not use type annotation for the schema, +// type parameter can be used to make it type guard: +// const validate = ajv.compile(schema) + +const data: any = {foo: 1} + +if (validate(data)) { + // data is MyData here + console.log(data.foo) +} else { + // The type cast is needed to allow user-defined keywords and errors + // You can extend this type to include your error types as needed. + for (const err of validate.errors as DefinedError[]) { + switch (err.keyword) { + case "minimum": + // err type is narrowed here to have "minimum" error params properties + console.log(err.params.limit) + break + // ... + } + } +} +``` + +With JSON Type Definition schema: + +In JavaScript: + +```javascript +const Ajv = require("ajv").default + +const ajv = new Ajv() // options can be passed, e.g. {allErrors: true} +const schema = { + properties: { + foo: {type: "float64"}, + }, +} +const validate = ajv.compile(schema) +const valid = validate({foo: 1}) // true +if (!valid) console.log(validate.errors) +// Unlike JSON Schema: +const valid1 = validate(1) // false, bot an object +const valid2 = validate({}) // false, foo is required +const valid3 = validate({foo: 1, bar: 2}) // false, bar is additional +``` + +In TypeScript: + +```typescript +import {JTDSchemaType} from "ajv" + +type MyData = {foo: number} + +// Optional schema type annotation for schema to match MyData type. +// To use JTDSchemaType set `strictNullChecks: true` in tsconfig `compilerOptions`. +const schema: JTDSchemaType = { + properties: { + foo: {type: "float64"}, + }, +} +``` + +See [this test](./spec/types/json-schema.spec.ts) for an advanced example, [API reference](./docs/api.md) and [Options](./docs/api.md#options) for more details. + +Ajv compiles schemas to functions and caches them in all cases (using schema itself as a key for Map) or another function passed via options), so that the next time the same schema is used (not necessarily the same object instance) it won't be compiled again. + +The best performance is achieved when using compiled functions returned by `compile` or `getSchema` methods (there is no additional function call). + +**Please note**: every time a validation function or `ajv.validate` are called `errors` property is overwritten. You need to copy `errors` array reference to another variable if you want to use it later (e.g., in the callback). See [Validation errors](./docs/api.md#validation-errors) + +## Using in browser + +See [Content Security Policy](./docs/security.md#content-security-policy) to decide the best approach how to use Ajv in the browser. + +Whether you use Ajv or compiled schemas, it is recommended that you bundle them together with your code. + +If you need to use Ajv in several bundles you can create a separate UMD bundles using `npm run bundle` script. + +Then you need to load Ajv with support of JSON Schema draft-07 in the browser: + +```html + + +``` + +To load the bundle that supports JSON Schema draft-2019-09: + +```html + + +``` + +To load the bundle that supports JSON Type Definition: + +```html + + +``` + +This bundle can be used with different module systems; it creates global `ajv` (or `ajv2019`) if no module system is found. + +The browser bundle is available on [cdnjs](https://cdnjs.com/libraries/ajv). + +**Please note**: some frameworks, e.g. Dojo, may redefine global require in a way that is not compatible with CommonJS module format. In this case Ajv bundle has to be loaded before the framework and then you can use global `ajv` (see issue [#234](https://github.com/ajv-validator/ajv/issues/234)). + +## Choosing schema language + +Both JSON Schema and JSON Type Definition are cross-platform specifications with implementations in multiple programming languages that help you define the shape and requirements to your JSON data. + +This section compares their pros/cons to help decide which specification fits your application better. + +### JSON Schema + +- Pros + - Wide specification adoption. + - Used as part of OpenAPI specification. + - Support of complex validation scenarios: + - untagged unions and boolean logic + - conditional schemas and dependencies + - restrictions on the number ranges and the size of strings, arrays and objects + - semantic validation with formats, patterns and content keywords + - distribute strict record definitions across multiple schemas (with unevaluatedProperties) + - Can be effectively used for validation of any JavaScript objects and configuration files. +- Cons + - Defines the collection of restrictions on the data, rather than the shape of the data. + - No standard support for tagged unions. + - Complex and error prone for the new users (Ajv has [strict mode](./docs/strict-mode) to compensate for it, but it is not cross-platform). + - Some parts of specification are difficult to implement, creating the risk of implementations divergence: + - reference resolution model + - unevaluatedProperties/unevaluatedItems + - dynamic recursive references + - Internet draft status (rather than RFC) + +See [JSON Schema](./docs/json-schema.md) for the list of defined keywords. + +### JSON Type Definition + +- Pros: + - Aligned with type systems of many languages - can be used to generate type definitions and efficient parsers and serializers to/from these types. + - Very simple, enforcing the best practices for cross-platform JSON API modelling. + - Simple to implement, ensuring consistency across implementations. + - Defines the shape of JSON data via strictly defined schema forms (rather than the collection of restrictions). + - Effective support for tagged unions. + - Designed to protect against user mistakes. + - Approved as [RFC8927](https://datatracker.ietf.org/doc/rfc8927/) +- Cons: + - Limited, compared with JSON Schema - no support for untagged unions\*, conditionals, references between different schema files\*\*, etc. + - No meta-schema in the specification\*. + - Brand new - limited industry adoption (as of January 2021). + +\* Ajv defines meta-schema for JTD schemas and non-standard keyword "union" that can be used inside "metadata" object. + +\*\* You can still combine schemas from multiple files in the application code. + +See [JSON Type Definition](./docs/json-type-definition.md) for the list of defined schema forms. + +## Using in ES5 environment + +You need to: + +- recompile Typescript to ES5 target - it is set to 2018 in the bundled compiled code. +- generate ES5 validation code: + +```javascript +const ajv = new Ajv({code: {es5: true}}) +``` + +See [Advanced options](https://github.com/ajv-validator/ajv/blob/master/docs/api.md#advanced-options). + +## Command line interface + +CLI is available as a separate npm package [ajv-cli](https://github.com/ajv-validator/ajv-cli). It supports: + +- compiling JSON Schemas to test their validity +- generating [standalone validation code](./docs/standalone.md) that exports validation function(s) to be used without Ajv +- migrating schemas to draft-07 and draft-2019-09 (using [json-schema-migrate](https://github.com/epoberezkin/json-schema-migrate)) +- validating data file(s) against JSON Schema +- testing expected validity of data against JSON Schema +- referenced schemas +- user-defined meta-schemas, validation keywords and formats +- files in JSON, JSON5, YAML, and JavaScript format +- all Ajv options +- reporting changes in data after validation in [JSON-patch](https://datatracker.ietf.org/doc/rfc6902/) format + +## Extending Ajv + +### User defined keywords + +See section in [data validation](./docs/validation.md#user-defined-keywords) and the [detailed guide](./docs/keywords.md). + +### Plugins + +Ajv can be extended with plugins that add keywords, formats or functions to process generated code. When such plugin is published as npm package it is recommended that it follows these conventions: + +- it exports a function that accepts ajv instance as the first parameter - it allows using plugins with [ajv-cli](#command-line-interface). +- this function returns the same instance to allow chaining. +- this function can accept an optional configuration as the second parameter. + +You can import `Plugin` interface from ajv if you use Typescript. + +If you have published a useful plugin please submit a PR to add it to the next section. + +### Related packages + +- [ajv-bsontype](https://github.com/BoLaMN/ajv-bsontype) - plugin to validate mongodb's bsonType formats +- [ajv-cli](https://github.com/jessedc/ajv-cli) - command line interface +- [ajv-formats](https://github.com/ajv-validator/ajv-formats) - formats defined in JSON Schema specification +- [ajv-errors](https://github.com/ajv-validator/ajv-errors) - plugin for defining error messages in the schema +- [ajv-i18n](https://github.com/ajv-validator/ajv-i18n) - internationalised error messages +- [ajv-istanbul](https://github.com/ajv-validator/ajv-istanbul) - plugin to instrument generated validation code to measure test coverage of your schemas +- [ajv-keywords](https://github.com/ajv-validator/ajv-keywords) - plugin with additional validation keywords (select, typeof, etc.) +- [ajv-merge-patch](https://github.com/ajv-validator/ajv-merge-patch) - plugin with keywords $merge and $patch +- [ajv-formats-draft2019](https://github.com/luzlab/ajv-formats-draft2019) - format validators for draft2019 that aren't included in [ajv-formats](https://github.com/ajv-validator/ajv-formats) (ie. `idn-hostname`, `idn-email`, `iri`, `iri-reference` and `duration`) + +## Some packages using Ajv + +- [webpack](https://github.com/webpack/webpack) - a module bundler. Its main purpose is to bundle JavaScript files for usage in a browser +- [jsonscript-js](https://github.com/JSONScript/jsonscript-js) - the interpreter for [JSONScript](http://www.jsonscript.org) - scripted processing of existing endpoints and services +- [osprey-method-handler](https://github.com/mulesoft-labs/osprey-method-handler) - Express middleware for validating requests and responses based on a RAML method object, used in [osprey](https://github.com/mulesoft/osprey) - validating API proxy generated from a RAML definition +- [har-validator](https://github.com/ahmadnassri/har-validator) - HTTP Archive (HAR) validator +- [jsoneditor](https://github.com/josdejong/jsoneditor) - a web-based tool to view, edit, format, and validate JSON http://jsoneditoronline.org +- [JSON Schema Lint](https://github.com/nickcmaynard/jsonschemalint) - a web tool to validate JSON/YAML document against a single JSON Schema http://jsonschemalint.com +- [objection](https://github.com/vincit/objection.js) - SQL-friendly ORM for Node.js +- [table](https://github.com/gajus/table) - formats data into a string table +- [ripple-lib](https://github.com/ripple/ripple-lib) - a JavaScript API for interacting with [Ripple](https://ripple.com) in Node.js and the browser +- [restbase](https://github.com/wikimedia/restbase) - distributed storage with REST API & dispatcher for backend services built to provide a low-latency & high-throughput API for Wikipedia / Wikimedia content +- [hippie-swagger](https://github.com/CacheControl/hippie-swagger) - [Hippie](https://github.com/vesln/hippie) wrapper that provides end to end API testing with swagger validation +- [react-form-controlled](https://github.com/seeden/react-form-controlled) - React controlled form components with validation +- [rabbitmq-schema](https://github.com/tjmehta/rabbitmq-schema) - a schema definition module for RabbitMQ graphs and messages +- [@query/schema](https://www.npmjs.com/package/@query/schema) - stream filtering with a URI-safe query syntax parsing to JSON Schema +- [chai-ajv-json-schema](https://github.com/peon374/chai-ajv-json-schema) - chai plugin to us JSON Schema with expect in mocha tests +- [grunt-jsonschema-ajv](https://github.com/SignpostMarv/grunt-jsonschema-ajv) - Grunt plugin for validating files against JSON Schema +- [extract-text-webpack-plugin](https://github.com/webpack-contrib/extract-text-webpack-plugin) - extract text from bundle into a file +- [electron-builder](https://github.com/electron-userland/electron-builder) - a solution to package and build a ready for distribution Electron app +- [addons-linter](https://github.com/mozilla/addons-linter) - Mozilla Add-ons Linter +- [gh-pages-generator](https://github.com/epoberezkin/gh-pages-generator) - multi-page site generator converting markdown files to GitHub pages +- [ESLint](https://github.com/eslint/eslint) - the pluggable linting utility for JavaScript and JSX +- [Spectral](https://github.com/stoplightio/spectral) - the customizable linting utility for JSON/YAML, OpenAPI, AsyncAPI, and JSON Schema + +## Changes history + +See https://github.com/ajv-validator/ajv/releases + +**Please note**: [Changes in version 7.0.0](https://github.com/ajv-validator/ajv/releases/tag/v7.0.0) + +[Version 6.0.0](https://github.com/ajv-validator/ajv/releases/tag/v6.0.0). + +## Code of conduct + +Please review and follow the [Code of conduct](./CODE_OF_CONDUCT.md). + +Please report any unacceptable behaviour to ajv.validator@gmail.com - it will be reviewed by the project team. + +## Security contact + +To report a security vulnerability, please use the +[Tidelift security contact](https://tidelift.com/security). +Tidelift will coordinate the fix and disclosure. Please do NOT report security vulnerabilities via GitHub issues. + +## Open-source software support + +Ajv is a part of [Tidelift subscription](https://tidelift.com/subscription/pkg/npm-ajv?utm_source=npm-ajv&utm_medium=referral&utm_campaign=readme) - it provides a centralised support to open-source software users, in addition to the support provided by software maintainers. + +## License + +[MIT](./LICENSE) diff --git a/docs/json-schema.md b/docs/json-schema.md index d6abf6e86..6a5492883 100644 --- a/docs/json-schema.md +++ b/docs/json-schema.md @@ -1,4 +1,4 @@ -# JSON Schema validation keywords +# JSON Schema keywords In a simple way, JSON Schema is an object with validation keywords. diff --git a/package.json b/package.json index e8071d67f..ef5b49c57 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,9 @@ "test": "npm link && npm link ajv && npm run json-tests && npm run eslint && npm run test-cov", "test-ci": "AJV_FULL_TEST=true npm test", "prepublish": "npm run build", - "benchmark": "npm i && npm run build && npm link && cd ./benchmark && npm link ajv && npm i && node ./jtd" + "benchmark": "npm i && npm run build && npm link && cd ./benchmark && npm link ajv && npm i && node ./jtd", + "docs:dev": "vuepress dev docs", + "docs:build": "vuepress build docs" }, "nyc": { "exclude": [ @@ -96,7 +98,8 @@ "terser": "^5.2.1", "ts-node": "^9.0.0", "tsify": "^5.0.2", - "typescript": "^4.0.0" + "typescript": "^4.0.0", + "vuepress": "^1.8.2" }, "collective": { "type": "opencollective", From c385312282234c6e213ab15df9a3a386ab330873 Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Wed, 3 Mar 2021 20:53:41 +0000 Subject: [PATCH 02/25] site: generate tables of content in pages --- docs/.vuepress/config.js | 20 ++++++------ docs/.vuepress/public/favicon.ico | Bin 0 -> 1150 bytes docs/codegen.md | 2 ++ docs/components.md | 4 +++ docs/faq.md | 2 ++ docs/json-schema.md | 51 ++++-------------------------- docs/json-type-definition.md | 38 ++++++++-------------- docs/keywords.md | 16 ++-------- docs/security.md | 7 +--- docs/standalone.md | 2 ++ docs/strict-mode.md | 43 ++++++++----------------- docs/validation.md | 24 ++------------ package.json | 1 + 13 files changed, 62 insertions(+), 148 deletions(-) create mode 100644 docs/.vuepress/public/favicon.ico diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index 7a425c034..28affd1e3 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -1,6 +1,12 @@ +const {slugify} = require("@vuepress/shared-utils") + module.exports = { title: "Ajv: Another JSON validator", description: "Just playing around", + markdown: { + slugify: (str) => slugify(str.replace(/]*\/>/, "")), + toc: {includeLevel: [2, 3, 4]} + }, themeConfig: { logo: "https://ajv.js.org/images/ajv_logo.png", nav: [ @@ -39,23 +45,19 @@ module.exports = { "/json-type-definition", "/api", "/keywords", - "/coercion" - ] + "/coercion", + ], }, { title: "Code generation & design", collapsable: false, - children: [ - "/standalone", - "/codegen", - "/components", - ] + children: ["/standalone", "/codegen", "/components"], }, ], nextLinks: false, prevLinks: false, - repo: 'ajv-validator/ajv', - docsDir: 'docs', + repo: "ajv-validator/ajv", + docsDir: "docs", editLinks: true, }, } diff --git a/docs/.vuepress/public/favicon.ico b/docs/.vuepress/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..f19dfab7eb065463c7275fce7468ba201848ad5a GIT binary patch literal 1150 zcmd^8+e;L26#jOdT`zc9V@WF6G?NS@qiuGS!rOXnA)*ipdWaIKRZ=vejPN&_So9D@ z5C#?W&|WgpHw9yRupkK^d}@6Non04F3Lz>ec1~w@+1fuL=r^4C4&OQ7xy%JH@ny4t z?0owsourb9o*B9VzaVoCb?vu!W7+0k&8ZzI)d})!_SNiqJ40wMkliiWc z>edaC8zZlrU6klY!4BSAdPCz9@h*$H$oi(MW}VLF@5S`C&VHZ$hgibSid|b{O6%H6 zO;faw^-VIFRC1+$iYu7cUO?zNy zc#g2EDe~-(UgTBKuqDj1KaG!MF4Lf;6LYBS^Oe!iYc%JB+FdQ0uDGKOhQ{TN+&Sdtpj{0P`Hk;1 The value of this keyword is a JSON Schema (can be a boolean). @@ -542,7 +505,7 @@ If the value is a schema for the data object to be valid the values in all "addi _invalid_: `{bar: 2}`, `{baz: 3}`, `{foo: 1, bar: 2}`, etc. -### `dependencies` +### `dependencies` This keyword is deprecated. The same functionality is available with keywords `dependentRequired` and `dependentSchemas`. @@ -588,7 +551,7 @@ For schema dependency, if the data object contains a property that is a key in t _invalid_: `{foo: 1, bar: "a"}` -### `dependentRequired` +### `dependentRequired` The value of this keyword should be a map with keys equal to data object properties. Each value in the map should be an array of unique property names. @@ -611,7 +574,7 @@ _valid_: `{foo: 1, bar: 2, baz: 3}`, `{}`, `{a: 1}` _invalid_: `{foo: 1}`, `{foo: 1, bar: 2}`, `{foo: 1, baz: 3}` -### `dependentSchemas` +### `dependentSchemas` The value of the keyword should be a map with keys equal to data object properties. Each value in the map should be a JSON Schema. @@ -661,7 +624,7 @@ _valid_: `{"foo@bar.com": "any", "bar@bar.com": "any"}` _invalid_: `{foo: "any value"}` -### `unevaluatedProperties` +### `unevaluatedProperties` The value of this keyword is a JSON Schema (can be a boolean). diff --git a/docs/json-type-definition.md b/docs/json-type-definition.md index 2f4c8da3f..3c3666388 100644 --- a/docs/json-type-definition.md +++ b/docs/json-type-definition.md @@ -11,23 +11,7 @@ const AjvJTD = require("ajv/dist/jtd").default const ajv = new AjvJTD() ``` -## Contents - -- [JTD schema forms](#jtd-schema-forms): - - [type](#type-schema-form) (for primitive values) - - [enum](#enum-schema-form) - - [elements](#elements-schema-form) (for arrays) - - [properties](#properties-schema-form) (for records) - - [discriminator](#discriminator-schema-form) (for tagged union of records) - - [values](#values-schema-form) (for dictionary) - - [ref](#ref-schema-form) (to reference a schema in definitions) - - [empty](#empty-schema-form) (for any data) -- [JTDSchemaType](#jtdschematype) -- [Extending JTD](#extending-jtd) - - [metadata](#metadata-schema-member) - - [union](#union-keyword) - - [user-defined keywords](#user-defined-keywords) -- [Validation errors](#validation-errors) +[[toc]] ## JTD schema forms @@ -42,7 +26,7 @@ All forms require that: Root schema can have member `definitions` that has a dictionary of schemas that can be references from any other schemas using form `ref` -### Type schema form +### Type form This form defines a primitive value. @@ -74,7 +58,7 @@ Unlike JSON Schema, JTD does not allow defining values that can take one of seve } ``` -### Enum schema form +### Enum form This form defines a string that can take one of the values from the list (the values in the list must be unique). @@ -90,7 +74,7 @@ Unlike JSON Schema, JTD does not allow defining `enum` with values of any other } ``` -### Elements schema form +### Elements form This form defines a homogenous array of any size (possibly empty) with the elements that satisfy a given schema. @@ -114,7 +98,7 @@ Valid data: `[]`, `["foo"]`, `["foo", "bar"]` Invalid data: `["foo", 1]`, any type other than array -### Properties schema form +### Properties form This form defines record (JSON object) that has defined required and optional properties. @@ -173,7 +157,7 @@ Invalid data: `{}`, `{foo: 1}`, `{foo: "bar", bar: "3"}`, any type other than ob } ``` -### Discriminator schema form +### Discriminator form This form defines discriminated (tagged) union of different record types. @@ -231,7 +215,7 @@ Invalid data: `{}`, `{foo: "1"}`, `{version: 1, foo: "1"}`, any type other than } ``` -### Values schema form +### Values form This form defines a homogenous dictionary where the values of members satisfy a given schema. @@ -255,7 +239,7 @@ Valid data: `{}`, `{"foo": 1}`, `{"foo": 1, "bar": 2}` Invalid data: `{"foo": "bar"}`, any type other than object -### Ref schema form +### Ref form This form defines a reference to the schema that is present in the corresponding key in the `definitions` member of the root schema. @@ -310,7 +294,7 @@ Unlike JSON Schema, JTD does not allow to reference: } ``` -### Empty schema form +### Empty form Empty JTD schema defines the data instance that can be of any type, including JSON `null` (even if `nullable` member is not present). It cannot have any member other than `nullable` and `metadata`. @@ -416,3 +400,7 @@ This keyword can be used only inside `metadata` schema member. Any user-defined keywords that can be used in JSON Schema schemas can also be used in JTD schemas, including the keywords in [ajv-keywords](https://github.com/ajv-validator/ajv-keywords) package. **Please note**: It is strongly recommended to only use it to simplify migration from JSON Schema to JTD and not to use non-standard keywords in the new schemas, as these keywords are not supported by any other tools. + +## Validation errors + +TODO diff --git a/docs/keywords.md b/docs/keywords.md index d8d3272f4..20a0fa1e4 100644 --- a/docs/keywords.md +++ b/docs/keywords.md @@ -1,18 +1,8 @@ # User defined keywords -## Contents +[[toc]] -- Define keyword with: - - [code generation function](#define-keyword-with-code-generation-function) - used by all pre-defined keywords - - [validation function](#define-keyword-with-validation-function) - - [compilation function](#define-keyword-with-compilation-function) - - [macro function](#define-keyword-with-macro-function) -- [Schema compilation context](#schema-compilation-context) -- [Validation time variables](#validation-time-variables) -- [Ajv utilities](#ajv-utilities) -- [Defining keyword errors](#defining-keyword-errors) - -### Common attributes of keyword definitions +## Common attributes of keyword definitions The usual interface to define all keywords has these properties: @@ -31,7 +21,7 @@ interface _KeywordDef { Keyword definitions may have additional optional properties - see [types](../lib/types/index.ts) and [KeywordCxt](../lib/compile/context.ts). -### Define keyword with code generation function +### Define keyword with code generation function Starting from v7 Ajv uses [CodeGen module](../lib/compile/codegen/index.ts) for all pre-defined keywords - see [codegen.md](./codegen.md) for details. diff --git a/docs/security.md b/docs/security.md index 94b32b61f..9ae9761da 100644 --- a/docs/security.md +++ b/docs/security.md @@ -2,12 +2,7 @@ JSON Schema, if properly used, can replace data sanitisation. It doesn't replace other API security considerations. It also introduces additional security aspects to consider. -- [Security contact](#security-contact) -- [Untrusted schemas](#untrusted-schemas) -- [Circular references in objects](#circular-references-in-javascript-objects) -- [Trusted schemas](#security-risks-of-trusted-schemas) -- [ReDoS attack](#redos-attack) -- [Content Security Policy](#content-security-policy) +[[toc]] ## Security contact diff --git a/docs/standalone.md b/docs/standalone.md index c2facb7b2..1f8a0360c 100644 --- a/docs/standalone.md +++ b/docs/standalone.md @@ -1,5 +1,7 @@ # Standalone validation code +[[toc]] + Ajv supports generating standalone modules with exported validation function(s), with one default export or multiple named exports, that are pre-compiled and can be used without Ajv. It is useful for several reasons: - to reduce the browser bundle size - Ajv is not included in the bundle (although if you have a large number of schemas the bundle can become bigger - when the total size of generated validation code is bigger than Ajv code). diff --git a/docs/strict-mode.md b/docs/strict-mode.md index b6be34593..dacaa4b62 100644 --- a/docs/strict-mode.md +++ b/docs/strict-mode.md @@ -4,24 +4,7 @@ Strict mode intends to prevent any unexpected behaviours or silently ignored mis To disable all strict mode restrictions use option `strict: false`. Some of the restrictions can be changed with their own options -- [JSON Type Definition schemas](#json-type-definition-schemas) -- [JSON Schema schemas](#json-schema-schemas) - - [Prohibit ignored keywords](#prohibit-ignored-keywords) - - unknown keywords - - ignored "additionalItems" keyword - - ignored "if", "then", "else" keywords - - ignored "contains", "maxContains" and "minContains" keywords - - unknown formats - - ignored defaults - - [Prevent unexpected validation](#prevent-unexpected-validation) - - overlap between "properties" and "patternProperties" keywords (also `allowMatchingProperties` option) - - required properties have to be present in properties [Strict required](#strict-required) - - unconstrained tuples (also `strictTuples` option) - - [Strict types](#strict-types) (also `strictTypes` option) - - union types (also `allowUnionTypes` option) - - contradictory types - - require applicable types - - [Strict number validation](#strict-number-validation) +[[toc]] ## JSON Type Definition schemas @@ -42,7 +25,7 @@ JSON Schema specification is very permissive and allows many elements in the sch ### Prohibit ignored keywords -#### Prohibit unknown keywords +#### Unknown keywords JSON Schema [section 6.5](https://tools.ietf.org/html/draft-handrews-json-schema-02#section-6.5) requires to ignore unknown keywords. The motivation is to increase cross-platform portability of schemas, so that implementations that do not support certain keywords can still do partial validation. @@ -63,19 +46,19 @@ or ajv.addVocabulary(["allowed1", "allowed2"]) ``` -#### Prohibit ignored "additionalItems" keyword +#### Ignored "additionalItems" keyword JSON Schema section [9.3.1.2](https://tools.ietf.org/html/draft-handrews-json-schema-02#section-9.3.1.2) requires to ignore "additionalItems" keyword if "items" keyword is absent or if it is not an array of items. This is inconsistent with the interaction of "additionalProperties" and "properties", and may cause unexpected results. By default Ajv fails schema compilation when "additionalItems" is used without "items" (or if "items" is not an array). -#### Prohibit ignored "if", "then", "else" keywords +#### Ignored "if", "then", "else" keywords JSON Schema section [9.2.2](https://tools.ietf.org/html/draft-handrews-json-schema-02#section-9.2.2) requires to ignore "if" (only annotations are collected) if both "then" and "else" are absent, and ignore "then"/"else" if "if" is absent. By default Ajv fails schema compilation in these cases. -#### Prohibit ignored "contains", "maxContains" and "minContains" keywords +#### Ignored "contains", "maxContains" and "minContains" keywords JSON Schema sections [6.4.4, 6.4.5](https://json-schema.org/draft/2019-09/json-schema-validation.html#rfc.section.6.4.4) require to ignore keywords "maxContains" and "minContains" if "contains" keyword is absent. @@ -83,7 +66,7 @@ It is also implied that when "minContains" is 0 and "maxContains" is absent, "co By default Ajv fails schema compilation in these cases. -#### Prohibit unknown formats +#### Unknown formats By default unknown formats throw exception during schema compilation (and fail validation in case format keyword value is [\$data reference](./validation.md#data-reference)). It is possible to opt out of format validation completely with options `validateFormats: false`. You can define all known formats with `addFormat` method or `formats` option - to have some format ignored pass `true` as its definition: @@ -95,13 +78,13 @@ const ajv = new Ajv({formats: { Standard JSON Schema formats are provided in [ajv-formats](https://github.com/ajv-validator/ajv-formats) package - see [Formats](./validation.md#formats) section. -#### Prohibit ignored defaults +#### Ignored defaults With `useDefaults` option Ajv modifies validated data by assigning defaults from the schema, but there are different limitations when the defaults can be ignored (see [Assigning defaults](./validation.md#assigning-defaults)). In strict mode Ajv fails schema compilation if such defaults are used in the schema. ### Prevent unexpected validation -#### Prohibit overlap between "properties" and "patternProperties" keywords +#### Overlap between "properties" and "patternProperties" keywords The expectation of users (see #196, #286) is that "patternProperties" only apply to properties not already defined in "properties" keyword, but JSON Schema section [9.3.2](https://tools.ietf.org/html/draft-handrews-json-schema-02#section-9.3.2) defines these two keywords as independent. It means that to some properties two subschemas can be applied - one defined in "properties" keyword and another defined in "patternProperties" for the pattern matching this property. @@ -111,7 +94,7 @@ In addition to allowing such patterns by using option `strict: false`, there is To reiterate, neither this nor other strict mode restrictions change the validation results - they only restrict which schemas are valid. -#### Strict required +#### Defined required properties With option `strictRequired` set to `"log"` or `true` Ajv logs warning or throws exception if the property used in "required" keyword is not defined in "properties" keyword in the same or some parent schema relating to the same object (data instance). @@ -119,7 +102,7 @@ By default this option is disabled. **Please note** there are certain scenarios when property defined in the parent schema will not be taken into account. -#### Prohibit unconstrained tuples +#### Unconstrained tuples Ajv also logs a warning if "items" is an array (for schema that defines a tuple) but neither "minItems" nor "additionalItems"/"maxItems" keyword is present (or have a wrong value): @@ -149,11 +132,11 @@ Use `strictTuples` option to suppress this warning (`false`) or turn it into exc If you use `JSONSchemaType` this mistake will also be prevented on a type level. -### Strict types +### Strict types An additional option `strictTypes` ("log" by default) imposes additional restrictions on how type keyword is used: -#### Prohibit union types +#### Union types With `strictTypes` option "type" keywords with multiple types (other than with "null") are prohibited. @@ -239,7 +222,7 @@ It also can be refactored: This restriction can be lifted separately from other `strictTypes` restrictions with `allowUnionTypes: true` option. -#### Prohibit contradictory types +#### Contradictory types Subschemas can apply to the same data instance, and it is possible to have contradictory type keywords - it usually indicate some mistake. For example: diff --git a/docs/validation.md b/docs/validation.md index 1a43c374f..9d0f08f2c 100644 --- a/docs/validation.md +++ b/docs/validation.md @@ -1,24 +1,6 @@ # Data validation -- [Data validation](#data-validation) - - [JSON Schema draft-2019-09](#json-schema-draft-2019-09) - - [Validation basics](#validation-basics) - - [JSON Schema validation keywords](#json-schema-validation-keywords) - - [Annotation keywords](#annotation-keywords) - - [Formats](#formats) - - [Modular schemas](#modular-schemas) - - [Combining schemas with \$ref](#combining-schemas-with-ref) - - [Extending recursive schemas](#extending-recursive-schemas) - - [\$data reference](#data-reference) - - [$merge and $patch keywords](#merge-and-patch-keywords) - - [User-defined keywords](#user-defined-keywords) - - [Asynchronous schema compilation](#asynchronous-schema-compilation) - - [Asynchronous validation](#asynchronous-validation) - - [Using transpilers](#using-transpilers) - - [Modifying data during validation](#modifying-data-during-validation) - - [Removing additional properties](#removing-additional-properties) - - [Assigning defaults](#assigning-defaults) - - [Coercing data types](#coercing-data-types) +[[toc]] ## JSON Schema draft-2019-09 @@ -150,7 +132,7 @@ You can add and replace any formats using [addFormat](./api.md#api-addformat) me ## Modular schemas -### Combining schemas with \$ref +### Combining schemas with $ref You can structure your validation logic across multiple schema files and have schemas reference each other using `$ref` keyword. @@ -269,7 +251,7 @@ At the moment Ajv implements the spec for dynamic recursive references with thes Ajv also does not support dynamic references in [asynchronous schemas](#asynchronous-validation) (Ajv extension) - it is assumed that the referenced schema is synchronous, and there is no validation-time check for it. -### \$data reference +### $data reference With `$data` option you can use values from the validated data as the values for the schema keywords. See [proposal](https://github.com/json-schema-org/json-schema-spec/issues/51) for more information about how it works. diff --git a/package.json b/package.json index ef5b49c57..6a719ca9e 100644 --- a/package.json +++ b/package.json @@ -77,6 +77,7 @@ "@types/require-from-string": "^1.2.0", "@typescript-eslint/eslint-plugin": "^3.8.0", "@typescript-eslint/parser": "^3.8.0", + "@vuepress/shared-utils": "^1.8.2", "ajv-formats": "^1.5.0", "browserify": "^17.0.0", "chai": "^4.0.1", From 3ac2f9f00bb4bc88f65919d91207a46a64ab833f Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Wed, 3 Mar 2021 21:35:35 +0000 Subject: [PATCH 03/25] site: using custom blocks --- docs/api.md | 32 +++++++++++++++++++-------- docs/codegen.md | 8 +++++-- docs/json-schema.md | 12 +++++++---- docs/json-type-definition.md | 12 ++++++++--- docs/keywords.md | 4 +++- docs/security.md | 18 ++++++++++++---- docs/strict-mode.md | 8 +++++-- docs/validation.md | 42 ++++++++++++++++++++++++++---------- 8 files changed, 100 insertions(+), 36 deletions(-) diff --git a/docs/api.md b/docs/api.md index 9bdee479c..cd94f85ad 100644 --- a/docs/api.md +++ b/docs/api.md @@ -50,7 +50,7 @@ if (validate(data)) { See more advanced example in [the test](../spec/types/json-schema.spec.ts). -#### ajv.compileSerializer(schema: object): (data: any) =\> string (NEW) +#### ajv.compileSerializer(schema: object): (data: any) =\> string Generate serializing function based on the [JTD schema](./json-type-definition.md) (caches the schema) - only in JTD instance of Ajv (see example below). @@ -84,9 +84,11 @@ const serializeMyData = ajv.compileSerializer(mySchema) // it prevents you from accidentally passing the wrong type ``` -**Please note**: Compiled serializers do NOT validate passed data, it is assumed that the data is valid according to the schema. In the future there may be an option added that would make serializers also validate the data. +::: warning Please note +Compiled serializers do NOT validate passed data, it is assumed that the data is valid according to the schema. In the future there may be an option added that would make serializers also validate the data. +::: -#### ajv.compileParser(schema: object): (json: string) =\> any (NEW) +#### ajv.compileParser(schema: object): (json: string) =\> any Generate parsing function based on the [JTD schema](./json-type-definition.md) (caches the schema) - only in JTD instance of Ajv (see example below). @@ -109,7 +111,9 @@ console.log(parseMyData.position) // 4 console.log(parseMyData.message) // property x not allowed ``` -**Please note**: generated parsers is a NEW Ajv functionality (as of March 2021), there can be some edge cases that are not handled correctly - please report any issues/submit fixes. +::: warning Please note +Generated parsers is a NEW Ajv functionality (as of March 2021), there can be some edge cases that are not handled correctly - please report any issues/submit fixes. +::: \* As long as empty schema `{}` is not used - there is a possibility to improve performance in this case. Also, the performance of parsing `discriminator` schemas depends on the position of discriminator tag in the schema - the best parsing performance will be achieved if the tag is the first property - this is how compiled JTD serializers generate JSON in case of discriminator schemas. @@ -139,7 +143,9 @@ Validation errors will be available in the `errors` property of Ajv instance (`n In typescript this method can act as a type guard (similarly to function returned by `compile` method - see example there). -**Please note**: every time this method is called the errors are overwritten so you need to copy them to another variable if you want to use them later. +::: warning Please note +Every time this method is called the errors are overwritten so you need to copy them to another variable if you want to use them later. +::: If the schema is asynchronous (has `$async` keyword on the top level) this method returns a Promise. See [Asynchronous validation](./validation.md#asynchronous-validation). @@ -157,11 +163,13 @@ Although `addSchema` does not compile schemas, explicit compilation is not requi By default the schema is validated against meta-schema before it is added, and if the schema does not pass validation the exception is thrown. This behaviour is controlled by `validateSchema` option. -**Please note**: Ajv return it instance for method chaining from all methods with the prefix `add*` and `remove*`: +::: tip Please note +Ajv return it instance for method chaining from all methods with the prefix `add*` and `remove*`: ```javascript const validate = new Ajv().addSchema(schema).addFormat(name, regex).getSchema(uri) ``` +::: #### ajv.addMetaSchema(schema: object | object[], key?: string): Ajv @@ -283,7 +291,9 @@ interface KeywordDefinition { `compile`, `macro` and `code` are mutually exclusive, only one should be used at a time. `validate` can be used separately or in addition to `compile` or `macro` to support [\$data reference](./validation.md#data-reference). -**Please note**: If the keyword is validating data type that is different from the type(s) in its definition, the validation function will not be called (and expanded macro will not be used), so there is no need to check for data type inside validation function or inside schema returned by macro function (unless you want to enforce a specific type and for some reason do not want to use a separate `type` keyword for that). In the same way as standard keywords work, if the keyword does not apply to the data type being validated, the validation of this keyword will succeed. +::: tip Please note +If the keyword is validating data type that is different from the type(s) in its definition, the validation function will not be called (and expanded macro will not be used), so there is no need to check for data type inside validation function or inside schema returned by macro function (unless you want to enforce a specific type and for some reason do not want to use a separate `type` keyword for that). In the same way as standard keywords work, if the keyword does not apply to the data type being validated, the validation of this keyword will succeed. +::: See [User defined keywords](./keywords.md) for more details. @@ -297,7 +307,9 @@ Removes added or pre-defined keyword so you can redefine them. While this method can be used to extend pre-defined keywords, it can also be used to completely change their meaning - it may lead to unexpected results. -**Please note**: schemas compiled before the keyword is removed will continue to work without changes. To recompile schemas use `removeSchema` method and compile them again. +::: warning Please note +The schemas compiled before the keyword is removed will continue to work without changes. To recompile schemas use `removeSchema` method and compile them again. +::: #### ajv.errorsText(errors?: object[], options?: object): string @@ -496,7 +508,9 @@ interface JTDErrorObject { This error format is used when using JTD schemas. To simplify usage, you may still generate Ajv error objects using `ajvErrors` option. You can also add a human-readable error message to error objects using option `messages`. -**Please note**: Ajv is not fully consistent with JTD regarding the error objects in some scenarios - it will be consistent by the time Ajv version 8 is released. Therefore it is not recommended yet to use error objects for any advanced application logic. +::: warning Please note +Ajv is not fully consistent with JTD regarding the error objects in some scenarios - it will be consistent by the time Ajv version 8 is released. Therefore it is not recommended yet to use error objects for any advanced application logic. +::: ### Error parameters diff --git a/docs/codegen.md b/docs/codegen.md index e11dcce75..353da3c0e 100644 --- a/docs/codegen.md +++ b/docs/codegen.md @@ -68,7 +68,9 @@ CodeGen class generates code trees and performs several optimizations before the 2. removes unused variable declarations. 3. replaces variables that are used only once and assigned expressions that are explicitly marked as "constant" (i.e. having referential transparency) with the expressions themselves. -**Please note**: These optimizations assume that the expressions in `if` conditions, `for` statement headers and assigned expressions are free of any side effects - this is the case for all pre-defined validation keywords. +::: warning Please note +These optimizations assume that the expressions in `if` conditions, `for` statement headers and assigned expressions are free of any side effects - this is the case for all pre-defined validation keywords. +::: See [these tests](../spec/codegen.spec.ts) for examples. @@ -85,4 +87,6 @@ While tagged template literals wrap passed strings based on their run-time value It is strongly recommended to define additional keywords only with Typescript - using plain JavaScript would still allow passing unsafe strings to code generation methods. -**Please note**: If your user-defined keywords need to have side-effects that are removed by optimization (see above), you may need to disable it. +::: warning Please note +If your user-defined keywords need to have side-effects that are removed by optimization (see above), you may need to disable it. +::: diff --git a/docs/json-schema.md b/docs/json-schema.md index 6fad14a16..d1d789d1c 100644 --- a/docs/json-schema.md +++ b/docs/json-schema.md @@ -59,7 +59,9 @@ The value of keyword `maximum` (`minimum`) should be a number. This value is the The value of keyword `exclusiveMaximum` (`exclusiveMinimum`) should be a number. This value is the exclusive maximum (minimum) allowed value for the data to be valid (the data equal to this keyword value is invalid). -**Please note**: Boolean value for keywords `exclusiveMaximum` (`exclusiveMinimum`) is no longer supported. +::: warning Please note +Boolean value for keywords `exclusiveMaximum` (`exclusiveMinimum`) is no longer supported. +::: **Examples** @@ -375,7 +377,9 @@ _invalid_: `{}`, `{a: 1}`, `{c: 3, d: 4}` The value of the keyword should be a map with keys equal to data object properties. Each value in the map should be a JSON Schema. For data object to be valid the corresponding values in data object properties should be valid according to these schemas. -**Please note**: `properties` keyword does not require that the properties mentioned in it are present in the object (see examples). +::: warning Please note +`properties` keyword does not require that the properties mentioned in it are present in the object (see examples). +::: **Example** @@ -404,10 +408,10 @@ The value of this keyword should be a map where keys should be regular expressio When the value in data object property matches multiple regular expressions it should be valid according to all the schemas for all matched regular expressions. -**Please note**: - +::: warning Please note 1. `patternProperties` keyword does not require that properties matching patterns are present in the object (see examples). 2. By default, Ajv does not allow schemas where patterns in `patternProperties` match any property name in `properties` keyword - that leads to unexpected validation results. It can be allowed with option `allowMatchingProperties`. See [Strict mode](./strict-mode.md) +::: **Example** diff --git a/docs/json-type-definition.md b/docs/json-type-definition.md index 3c3666388..68db841d5 100644 --- a/docs/json-type-definition.md +++ b/docs/json-type-definition.md @@ -380,7 +380,9 @@ Each schema form may have an optional member `metadata` that JTD reserves for im - any user-defined keywords, for example keywords defined in [ajv-keywords](https://github.com/ajv-validator/ajv-keywords) package - JSON Schema keywords, as long as their names are different from standard JTD keywords. It can be used to enable a gradual migration from JSON Schema to JTD, should it be required. -**Please note**: Ajv-specific extension to JTD are likely to be unsupported by other tools, so while it may simplify adoption, it undermines the cross-platform objective of using JTD. While it is ok to put some human readable information in `metadata` member, it is recommended not to add any validation logic there (even if it is supported by Ajv). +::: warning Please note +Ajv-specific extension to JTD are likely to be unsupported by other tools, so while it may simplify adoption, it undermines the cross-platform objective of using JTD. While it is ok to put some human readable information in `metadata` member, it is recommended not to add any validation logic there (even if it is supported by Ajv). +::: Additional restrictions that Ajv enforces on `metadata` schema member: @@ -393,13 +395,17 @@ Ajv defines `union` keyword that is used in the schema that validates JTD schema This keyword can be used only inside `metadata` schema member. -**Please note**: This keyword is non-standard and it is not supported in other JTD tools, so it is recommended NOT to use this keyword in schemas for your data if you want them to be cross-platform. +::: warning Please note +This keyword is non-standard and it is not supported in other JTD tools, so it is recommended NOT to use this keyword in schemas for your data if you want them to be cross-platform. +::: ### User-defined keywords Any user-defined keywords that can be used in JSON Schema schemas can also be used in JTD schemas, including the keywords in [ajv-keywords](https://github.com/ajv-validator/ajv-keywords) package. -**Please note**: It is strongly recommended to only use it to simplify migration from JSON Schema to JTD and not to use non-standard keywords in the new schemas, as these keywords are not supported by any other tools. +::: warning Please note +It is strongly recommended to only use it to simplify migration from JSON Schema to JTD and not to use non-standard keywords in the new schemas, as these keywords are not supported by any other tools. +::: ## Validation errors diff --git a/docs/keywords.md b/docs/keywords.md index 20a0fa1e4..740367ecd 100644 --- a/docs/keywords.md +++ b/docs/keywords.md @@ -155,7 +155,9 @@ console.log(validate({foo: "baz"})) // false `const` keyword is already available in Ajv. -**Please note:** If the keyword does not define errors (see [Reporting errors](./api.md#reporting-errors)) pass `errors: false` in its definition; it will make generated code more efficient. +::: tip Please note +If the keyword does not define errors (see [Reporting errors](./api.md#reporting-errors)) pass `errors: false` in its definition; it will make generated code more efficient. +::: To add asynchronous keyword pass `async: true` in its definition. diff --git a/docs/security.md b/docs/security.md index 9ae9761da..49cd3518f 100644 --- a/docs/security.md +++ b/docs/security.md @@ -38,7 +38,9 @@ Some keywords in JSON Schemas can lead to very slow validation for certain data. - `patternProperties` for large property names - use `propertyNames` to mitigate, but some regular expressions can have exponential evaluation time as well. - `uniqueItems` for large non-scalar arrays - use `maxItems` to mitigate -**Please note**: The suggestions above to prevent slow validation would only work if you do NOT use `allErrors: true` in production code (using it would continue validation after validation errors). +::: danger Please note +The suggestions above to prevent slow validation would only work if you do NOT use `allErrors: true` in production code (using it would continue validation after validation errors). +::: You can validate your JSON schemas against [this meta-schema](../lib/refs/json-schema-secure.json) to check that these recommendations are followed: @@ -53,7 +55,9 @@ const schema2 = {format: "email", maxLength: MAX_LENGTH} isSchemaSecure(schema2) // true ``` -**Please note**: following all these recommendation is not a guarantee that validation of untrusted data is safe - it can still lead to some undesirable results. +::: danger Please note +Following all these recommendation is not a guarantee that validation using of untrusted data is safe - it can still lead to some undesirable results. +::: ## ReDoS attack @@ -61,7 +65,11 @@ Certain regular expressions can lead to the exponential evaluation time even wit Please assess the regular expressions you use in the schemas on their vulnerability to this attack - see [safe-regex](https://github.com/substack/safe-regex), for example. -**Please note**: some formats that [ajv-formats](https://github.com/ajv-validator/ajv-formats) package implements use [regular expressions](https://github.com/ajv-validator/ajv-formats/blob/master/src/formats.ts) that can be vulnerable to ReDoS attack, so if you use Ajv to validate data from untrusted sources **it is strongly recommended** to consider the following: +::: warning Please note +Some formats that [ajv-formats](https://github.com/ajv-validator/ajv-formats) package implements use [regular expressions](https://github.com/ajv-validator/ajv-formats/blob/master/src/formats.ts) that can be vulnerable to ReDoS attack. +::: + +If you use Ajv to validate data from untrusted sources **it is strongly recommended** to consider the following: - making assessment of "format" implementations in [ajv-formats](https://github.com/ajv-validator/ajv-formats). - passing `"fast"` option to ajv-formats plugin (see its docs) that simplifies some of the regular expressions (although it does not guarantee that they are safe). @@ -74,6 +82,8 @@ Whatever mitigation you choose, please assume all formats provided by ajv-format When using Ajv in a browser page with enabled Content Security Policy (CSP), `script-src` directive must include `'unsafe-eval'`. -**Please note**: `unsafe-eval` is NOT recommended in a secure CSP[[1]](https://developer.chrome.com/extensions/contentSecurityPolicy#relaxing-eval), as it has the potential to open the document to cross-site scripting (XSS) attacks. +::: warning Please note +`unsafe-eval` is NOT recommended in a secure CSP[[1]](https://developer.chrome.com/extensions/contentSecurityPolicy#relaxing-eval), as it has the potential to open the document to cross-site scripting (XSS) attacks. +::: In order to use Ajv without relaxing CSP, you can [compile the schemas using CLI](https://github.com/ajv-validator/ajv-cli#compile-schemas) or programmatically in your build code - see [Standalone validation code](./standalone.md). Compiled JavaScript file can export one or several validation functions that have the same code as the schemas compiled at runtime. diff --git a/docs/strict-mode.md b/docs/strict-mode.md index dacaa4b62..a9d35c44e 100644 --- a/docs/strict-mode.md +++ b/docs/strict-mode.md @@ -100,7 +100,9 @@ With option `strictRequired` set to `"log"` or `true` Ajv logs warning or throws By default this option is disabled. -**Please note** there are certain scenarios when property defined in the parent schema will not be taken into account. +::: warning Please note +there are certain scenarios when property defined in the parent schema will not be taken into account. +::: #### Unconstrained tuples @@ -248,7 +250,9 @@ The schema above violates `strictTypes` as "array" type is not compatible with o } ``` -**Please note**: type "number" can be narrowed to "integer", the opposite would violate `strictTypes`. +::: warning Please note +Type "number" can be narrowed to "integer", the opposite would violate `strictTypes`. +::: #### Require applicable types diff --git a/docs/validation.md b/docs/validation.md index 9d0f08f2c..f66bbf8ca 100644 --- a/docs/validation.md +++ b/docs/validation.md @@ -36,7 +36,9 @@ With this import Ajv supports the following features: - dynamic recursive references with [`recursiveAnchor`/`recursiveReference`] - see [Extending recursive schemas](#extending-recursive-schemas) - draft-2019-09 meta-schema is the default. -**Please note**: Supporting dynamic recursive references and `unevaluatedProperties/Items` adds additional generated code even to the validation functions where these features are not used (when possible, Ajv determines which properties/items are "unevaluated" at compilation time, but support for dynamic references always adds additional generated code). If you are not using these features in your schemas it is recommended to use default Ajv export with JSON-Schema draft-07 support. +::: warning Please note +Supporting dynamic recursive references and `unevaluatedProperties/Items` adds additional generated code even to the validation functions where these features are not used (when possible, Ajv determines which properties/items are "unevaluated" at compilation time, but support for dynamic references always adds additional generated code). If you are not using these features in your schemas it is recommended to use default Ajv export with JSON-Schema draft-07 support. +::: You can also use individual draft-2019-09 features to Ajv with the advanced options `dynamicRef`, `next` and `unevaluated`. These options are changing how the code is generated for draft-07 keywords to support the new features of draft-2019-09, but they do not add the new keywords - they should be added separately. The code examples below shows how to enable individual draft-2019-09 features: @@ -85,7 +87,9 @@ JSON Schema specification defines several metadata keywords that describe the sc - `contentEncoding`: [RFC 2045](https://tools.ietf.org/html/rfc2045#section-6.1), e.g., "base64". - `contentMediaType`: [RFC 2046](https://datatracker.ietf.org/doc/rfc2046/), e.g., "image/png". -**Please note**: Ajv does not implement validation of the keywords `examples`, `contentEncoding` and `contentMediaType` but it reserves them. If you want to create a plugin that implements any of them, it should remove these keywords from the instance. +::: warning Please note +Ajv does not implement validation of the keywords `examples`, `contentEncoding` and `contentMediaType` but it reserves them. If you want to create a plugin that implements any of them, it should remove these keywords from the instance. +::: ### Formats @@ -105,7 +109,9 @@ See ajv-formats documentation for further details. It is recommended NOT to use "format" keyword implementations with untrusted data, as they may use potentially unsafe regular expressions (even though known issues are fixed) - see [ReDoS attack](./security.md#redos-attack). -**Please note**: if you need to use "format" keyword to validate untrusted data, you MUST assess their suitability and safety for your validation scenarios. +::: danger Please note +If you need to use "format" keyword to validate untrusted data, you MUST assess their suitability and safety for your validation scenarios. +::: The following formats are defined in [ajv-formats](https://github.com/ajv-validator/ajv-formats) for string validation with "format" keyword: @@ -126,7 +132,9 @@ The following formats are defined in [ajv-formats](https://github.com/ajv-valida - _json-pointer_: JSON-pointer according to [RFC6901](https://datatracker.ietf.org/doc/rfc6901/). - _relative-json-pointer_: relative JSON-pointer according to [this draft](http://tools.ietf.org/html/draft-luff-relative-json-pointer-00). -**Please note**: JSON Schema draft-07 also defines formats `iri`, `iri-reference`, `idn-hostname` and `idn-email` for URLs, hostnames and emails with international characters. These formats are available in [ajv-formats-draft2019](https://github.com/luzlab/ajv-formats-draft2019) plugin. +::: warning Please note +JSON Schema draft-07 also defines formats `iri`, `iri-reference`, `idn-hostname` and `idn-email` for URLs, hostnames and emails with international characters. These formats are available in [ajv-formats-draft2019](https://github.com/luzlab/ajv-formats-draft2019) plugin. +::: You can add and replace any formats using [addFormat](./api.md#api-addformat) method. @@ -173,8 +181,7 @@ const validate = ajv.addSchema(defsSchema).compile(schema) See [Options](./api.md#options) and [addSchema](./api.md#add-schema) method. -**Please note**: - +::: tip Please note - `$ref` is resolved as the uri-reference using schema \$id as the base URI (see the example). - References can be recursive (and mutually recursive) to implement the schemas for different data structures (such as linked lists, trees, graphs, etc.). - You don't have to host your schema files at the URIs that you use as schema \$id. These URIs are only used to identify the schemas, and according to JSON Schema specification validators should not expect to be able to download the schemas from these URIs. @@ -182,6 +189,7 @@ See [Options](./api.md#options) and [addSchema](./api.md#add-schema) method. - You can pass the identifier of the schema as the second parameter of `addSchema` method or as a property name in `schemas` option. This identifier can be used instead of (or in addition to) schema \$id. - You cannot have the same \$id (or the schema identifier) used for more than one schema - the exception will be thrown. - You can implement dynamic resolution of the referenced schemas using `compileAsync` method. In this way you can store schemas in any system (files, web, database, etc.) and reference them without explicitly adding to Ajv instance. See [Asynchronous schema compilation](./validation.md#asynchronous-schema-compilation). +::: ### Extending recursive schemas @@ -434,7 +442,9 @@ function loadSchema(uri) { } ``` -**Please note**: [Option](./api.md#options) `missingRefs` should NOT be set to `"ignore"` or `"fail"` for asynchronous compilation to work. +::: warning Please note +[Option](./api.md#options) `missingRefs` should NOT be set to `"ignore"` or `"fail"` for asynchronous compilation to work. +::: ## Asynchronous validation @@ -444,7 +454,9 @@ You can define formats and keywords that perform validation asynchronously by ac If your schema uses asynchronous formats/keywords or refers to some schema that contains them it should have `"$async": true` keyword so that Ajv can compile it correctly. If asynchronous format/keyword or reference to asynchronous schema is used in the schema without `$async` keyword Ajv will throw an exception during schema compilation. -**Please note**: all asynchronous subschemas that are referenced from the current or other schemas should have `"$async": true` keyword as well, otherwise the schema compilation will fail. +::: warning Please note +All asynchronous subschemas that are referenced from the current or other schemas should have `"$async": true` keyword as well, otherwise the schema compilation will fail. +::: Validation function for an asynchronous format/keyword should return a promise that resolves with `true` or `false` (or rejects with `new Ajv.ValidationError(errors)` if you want to return errors from the keyword function). @@ -556,7 +568,11 @@ If `removeAdditional` option in the example above were `"all"` then both `additi If the option were `"failing"` then property `additional1` would have been removed regardless of its value and property `additional2` would have been removed only if its value were failing the schema in the inner `additionalProperties` (so in the example above it would have stayed because it passes the schema, but any non-number would have been removed). -**Please note**: If you use `removeAdditional` option with `additionalProperties` keyword inside `anyOf`/`oneOf` keywords your validation can fail with this schema, for example: +::: warning Please note +If you use `removeAdditional` option with `additionalProperties` keyword inside `anyOf`/`oneOf` keywords your validation can fail with this schema +::: + +For example: ```javascript { @@ -608,7 +624,9 @@ With the option value `"empty"` properties and items equal to `null` or `""` (em This option modifies original data. -**Please note**: the default value is inserted in the generated validation code as a literal, so the value inserted in the data will be the deep clone of the default in the schema. +::: warning Please note +The default value is inserted in the generated validation code as a literal, so the value inserted in the data will be the deep clone of the default in the schema. +::: Example 1 (`default` in `properties`): @@ -664,7 +682,9 @@ When you are validating user inputs all your data properties are usually strings This option modifies original data. -**Please note**: if you pass a scalar value to the validating function its type will be coerced and it will pass the validation, but the value of the variable you pass won't be updated because scalars are passed by value. +::: warning Please note +If you pass a scalar value to the validating function its type will be coerced and it will pass the validation, but the value of the variable you pass won't be updated because scalars are passed by value. +::: Example 1: From 4f258ea18aecd85b14f2b876ede64668658cfe03 Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Wed, 3 Mar 2021 22:06:14 +0000 Subject: [PATCH 04/25] site: use local images --- docs/.vuepress/config.js | 2 +- docs/.vuepress/public/ajv.svg | 3 +++ docs/README.md | 12 +++++++++--- docs/codegen.md | 2 +- docs/coercion.md | 2 +- docs/faq.md | 4 ++-- docs/img/gap.svg | 5 +++++ docs/img/mozilla.svg | 1 + docs/img/openjs.png | Bin 0 -> 41494 bytes docs/img/reserved.svg | 3 +++ docs/json-schema.md | 2 +- 11 files changed, 27 insertions(+), 9 deletions(-) create mode 100644 docs/.vuepress/public/ajv.svg create mode 100644 docs/img/gap.svg create mode 100644 docs/img/mozilla.svg create mode 100644 docs/img/openjs.png create mode 100644 docs/img/reserved.svg diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index 28affd1e3..b872f9364 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -8,7 +8,7 @@ module.exports = { toc: {includeLevel: [2, 3, 4]} }, themeConfig: { - logo: "https://ajv.js.org/images/ajv_logo.png", + logo: "/ajv.svg", nav: [ {text: "Home", link: "/"}, { diff --git a/docs/.vuepress/public/ajv.svg b/docs/.vuepress/public/ajv.svg new file mode 100644 index 000000000..f6f89e097 --- /dev/null +++ b/docs/.vuepress/public/ajv.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/docs/README.md b/docs/README.md index 051aab899..60ef492a0 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,21 +1,25 @@ # Ajv: Another JSON validator -Ajv logo +Ajv logo The fastest JSON schema validator for Node.js and browser. Supports JSON Schema draft-06/07/2019-09 (draft-04 is supported in [version 6](https://github.com/ajv-validator/ajv/tree/v6)) and JSON Type Definition [RFC8927](https://datatracker.ietf.org/doc/rfc8927/). +::: v-pre [![build](https://github.com/ajv-validator/ajv/workflows/build/badge.svg)](https://github.com/ajv-validator/ajv/actions?query=workflow%3Abuild) [![npm](https://img.shields.io/npm/v/ajv.svg)](https://www.npmjs.com/package/ajv) [![npm downloads](https://img.shields.io/npm/dm/ajv.svg)](https://www.npmjs.com/package/ajv) [![Coverage Status](https://coveralls.io/repos/github/ajv-validator/ajv/badge.svg?branch=master)](https://coveralls.io/github/ajv-validator/ajv?branch=master) [![Gitter](https://img.shields.io/gitter/room/ajv-validator/ajv.svg)](https://gitter.im/ajv-validator/ajv) [![GitHub Sponsors](https://img.shields.io/badge/$-sponsors-brightgreen)](https://github.com/sponsors/epoberezkin) +::: ## Platinum sponsors -[](https://www.mozilla.org)[](https://opencollective.com/ajv)[](https://opencollective.com/ajv) +::: v-pre +[](https://www.mozilla.org)[](https://opencollective.com/ajv) +::: ## Using version 7 @@ -117,7 +121,9 @@ Please review [Contributing guidelines](./CONTRIBUTING.md) and [Code components] ## Mozilla MOSS grant and OpenJS Foundation -[](https://www.mozilla.org/en-US/moss/)     [](https://openjsf.org/blog/2020/08/14/ajv-joins-openjs-foundation-as-an-incubation-project/) +::: v-pre +[](https://www.mozilla.org/en-US/moss/) [](https://openjsf.org/blog/2020/08/14/ajv-joins-openjs-foundation-as-an-incubation-project/) +::: Ajv has been awarded a grant from Mozilla’s [Open Source Support (MOSS) program](https://www.mozilla.org/en-US/moss/) in the “Foundational Technology” track! It will sponsor the development of Ajv support of [JSON Schema version 2019-09](https://tools.ietf.org/html/draft-handrews-json-schema-02) and of [JSON Type Definition (RFC8927)](https://datatracker.ietf.org/doc/rfc8927/). diff --git a/docs/codegen.md b/docs/codegen.md index 353da3c0e..3f5f77faa 100644 --- a/docs/codegen.md +++ b/docs/codegen.md @@ -1,4 +1,4 @@ -# Code generation +# Code generation design [[toc]] diff --git a/docs/coercion.md b/docs/coercion.md index 288577ece..4bb0cce70 100644 --- a/docs/coercion.md +++ b/docs/coercion.md @@ -1,4 +1,4 @@ -# Ajv type coercion rules +# Type coercion rules To enable type coercion pass option `coerceTypes` to Ajv with `true` or `array` (it is `false` by default). See [example](./validation.md#coercing-data-types). diff --git a/docs/faq.md b/docs/faq.md index 5394f4520..f83a8118b 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -78,11 +78,11 @@ This problem is related to the problem explained above - properties treated as a See the example in [Filtering Data](https://github.com/ajv-validator/ajv#filtering-data) section of readme. -## Generating schemas with resolved references (\$ref) +## Generating schemas with resolved references ($ref) See [#22](https://github.com/ajv-validator/ajv/issues/22), [#125](https://github.com/ajv-validator/ajv/issues/125), [#146](https://github.com/ajv-validator/ajv/issues/146), [#228](https://github.com/ajv-validator/ajv/issues/228), [#336](https://github.com/ajv-validator/ajv/issues/336), [#454](https://github.com/ajv-validator/ajv/issues/454). -#### Why Ajv does not replace references (\$ref) with the actual referenced schemas as some validators do? +#### Why Ajv does not replace references ($ref) with the actual referenced schemas as some validators do? 1. The scope of Ajv is validating data against JSON Schemas; inlining referenced schemas is not necessary for validation. When Ajv generates code for validation it either inlines the code of referenced schema or uses function calls. Doing schema manipulation is more complex and out of scope. 2. When schemas are recursive (or mutually recursive) resolving references would result in self-referencing recursive data-structures that can be difficult to process. diff --git a/docs/img/gap.svg b/docs/img/gap.svg new file mode 100644 index 000000000..7a634f80e --- /dev/null +++ b/docs/img/gap.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/docs/img/mozilla.svg b/docs/img/mozilla.svg new file mode 100644 index 000000000..daaf128de --- /dev/null +++ b/docs/img/mozilla.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/img/openjs.png b/docs/img/openjs.png new file mode 100644 index 0000000000000000000000000000000000000000..cd91d83265c8fa7145043e1ca0d2de1b8be52173 GIT binary patch literal 41494 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 IM6N<$f~WvRm;e9( literal 0 HcmV?d00001 diff --git a/docs/img/reserved.svg b/docs/img/reserved.svg new file mode 100644 index 000000000..529135e09 --- /dev/null +++ b/docs/img/reserved.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/docs/json-schema.md b/docs/json-schema.md index d1d789d1c..c8689f04d 100644 --- a/docs/json-schema.md +++ b/docs/json-schema.md @@ -1,4 +1,4 @@ -# JSON Schema keywords +# JSON Schema In a simple way, JSON Schema is an object with validation keywords. From e493e0ff749b43450627683f4ac8457616886d1a Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Thu, 4 Mar 2021 22:17:25 +0000 Subject: [PATCH 05/25] vuepress site: guide --- .gitignore | 5 +- .tonic_example.js | 10 +- CODE_OF_CONDUCT.md | 4 + CONTRIBUTING.md | 4 + benchmark/jtd.js | 10 + docs/.vuepress/config.js | 35 ++- docs/LICENSE.md | 21 ++ docs/OLD_README.md | 281 +++++++++++++++++ docs/README.md | 538 ++------------------------------- docs/api.md | 1 + docs/guide/environments.md | 120 ++++++++ docs/guide/getting-started.md | 164 ++++++++++ docs/guide/managing-schemas.md | 60 ++++ docs/guide/modular-schemas.md | 233 ++++++++++++++ docs/guide/schema-language.md | 54 ++++ docs/guide/typescript.md | 205 +++++++++++++ docs/json-schema.md | 3 +- docs/validation.md | 259 ---------------- scripts/publish-site | 9 + 19 files changed, 1227 insertions(+), 789 deletions(-) create mode 100644 docs/LICENSE.md create mode 100644 docs/OLD_README.md create mode 100644 docs/guide/environments.md create mode 100644 docs/guide/getting-started.md create mode 100644 docs/guide/managing-schemas.md create mode 100644 docs/guide/modular-schemas.md create mode 100644 docs/guide/schema-language.md create mode 100644 docs/guide/typescript.md create mode 100755 scripts/publish-site diff --git a/.gitignore b/.gitignore index 8fc84d941..9b3f4a121 100644 --- a/.gitignore +++ b/.gitignore @@ -40,4 +40,7 @@ bundle/ package-lock.json -spec/_json/*.js \ No newline at end of file +spec/_json/*.js + +docs/CODE_OF_CONDUCT.md +docs/CONTRIBUTING.md diff --git a/.tonic_example.js b/.tonic_example.js index 2b0d6683e..7579d21c5 100644 --- a/.tonic_example.js +++ b/.tonic_example.js @@ -1,20 +1,20 @@ -var Ajv = require("ajv") -var ajv = new Ajv({allErrors: true}) +const Ajv = require("ajv").default +const ajv = new Ajv({allErrors: true}) -var schema = { +const schema = { properties: { foo: {type: "string"}, bar: {type: "number", maximum: 3}, }, } -var validate = ajv.compile(schema) +const validate = ajv.compile(schema) test({foo: "abc", bar: 2}) test({foo: 2, bar: 4}) function test(data) { - var valid = validate(data) + const valid = validate(data) if (valid) console.log("Valid!") else console.log("Invalid: " + ajv.errorsText(validate.errors)) } diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index b8026a2cf..c96b8e5dc 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,3 +1,7 @@ +--- +permalink: /code_of_conduct +--- + # Contributor Covenant Code of Conduct ## Our Pledge diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b105d2f8a..a4aa54052 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,3 +1,7 @@ +--- +permalink: /contributing +--- + # Contributing Thank you for your help making Ajv better! Every contribution is appreciated. If you plan to implement a new feature or some other change please create an issue first, to make sure that your work is not lost. diff --git a/benchmark/jtd.js b/benchmark/jtd.js index 88c2a5ae2..0127fdf5b 100644 --- a/benchmark/jtd.js +++ b/benchmark/jtd.js @@ -13,6 +13,7 @@ for (const testName in jtdValidationTests) { const valid = errors.length === 0 if (!valid) continue tests.push({ + validate: ajv.compile(schema), serialize: ajv.compileSerializer(schema), parse: ajv.compileParser(schema), data: instance, @@ -77,6 +78,12 @@ suite.add("JTD test suite: JSON.parse", () => { } }) +suite.add("JTD test suite: JSON.parse + validate", () => { + for (const test of tests) { + JSON.parse(test.json) + } +}) + const validTestData = JSON.stringify(testData) const invalidTestData = JSON.stringify({ @@ -91,11 +98,14 @@ const invalidTestData = JSON.stringify({ }) const parse = ajv.compileParser(testSchema) +const validate = ajv.compile(testSchema) suite.add("valid test data: compiled JTD parser", () => parse(validTestData)) suite.add("valid test data: JSON.parse", () => JSON.parse(validTestData)) +suite.add("valid test data: JSON.parse + validate", () => validate(JSON.parse(validTestData))) suite.add("invalid test data: compiled JTD parser", () => parse(invalidTestData)) suite.add("invalid test data: JSON.parse", () => JSON.parse(invalidTestData)) +suite.add("invalid test data: JSON.parse + validate", () => validate(JSON.parse(invalidTestData))) console.log() diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index b872f9364..1cf1a3379 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -5,7 +5,7 @@ module.exports = { description: "Just playing around", markdown: { slugify: (str) => slugify(str.replace(/]*\/>/, "")), - toc: {includeLevel: [2, 3, 4]} + toc: {includeLevel: [2, 3, 4]}, }, themeConfig: { logo: "/ajv.svg", @@ -33,17 +33,27 @@ module.exports = { ], sidebar: [ "/", - "/faq", - "/security", { - title: "Validation", + title: "Guide", + collapsable: false, + children: [ + "/guide/getting-started", + "/guide/typescript", + "/guide/schema-language", + "/guide/managing-schemas", + "/guide/modular-schemas", + "/guide/environments", + ] + }, + { + title: "Reference", collapsable: false, children: [ "/validation", - "/strict-mode", + "/api", "/json-schema", "/json-type-definition", - "/api", + "/strict-mode", "/keywords", "/coercion", ], @@ -53,9 +63,18 @@ module.exports = { collapsable: false, children: ["/standalone", "/codegen", "/components"], }, + { + title: "Information", + collapsable: false, + children: [ + "/faq", + "/security", + "/CONTRIBUTING", + ["/CODE_OF_CONDUCT", "Code of conduct"], + ["/LICENSE", "License"] + ], + }, ], - nextLinks: false, - prevLinks: false, repo: "ajv-validator/ajv", docsDir: "docs", editLinks: true, diff --git a/docs/LICENSE.md b/docs/LICENSE.md new file mode 100644 index 000000000..a0f827cbd --- /dev/null +++ b/docs/LICENSE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015-2017 Evgeny Poberezkin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/docs/OLD_README.md b/docs/OLD_README.md new file mode 100644 index 000000000..8e50db426 --- /dev/null +++ b/docs/OLD_README.md @@ -0,0 +1,281 @@ +# Ajv: Another JSON validator + +Ajv logo + +The fastest JSON schema validator for Node.js and browser. + +Supports JSON Schema draft-06/07/2019-09 (draft-04 is supported in [version 6](https://github.com/ajv-validator/ajv/tree/v6)) and JSON Type Definition [RFC8927](https://datatracker.ietf.org/doc/rfc8927/). + +::: v-pre +[![build](https://github.com/ajv-validator/ajv/workflows/build/badge.svg)](https://github.com/ajv-validator/ajv/actions?query=workflow%3Abuild) +[![npm](https://img.shields.io/npm/v/ajv.svg)](https://www.npmjs.com/package/ajv) +[![npm downloads](https://img.shields.io/npm/dm/ajv.svg)](https://www.npmjs.com/package/ajv) +[![Coverage Status](https://coveralls.io/repos/github/ajv-validator/ajv/badge.svg?branch=master)](https://coveralls.io/github/ajv-validator/ajv?branch=master) +[![Gitter](https://img.shields.io/gitter/room/ajv-validator/ajv.svg)](https://gitter.im/ajv-validator/ajv) +[![GitHub Sponsors](https://img.shields.io/badge/$-sponsors-brightgreen)](https://github.com/sponsors/epoberezkin) +::: + +## Platinum sponsors + +::: v-pre +[](https://www.mozilla.org)[](https://opencollective.com/ajv) +::: + +## Using version 7 + +Ajv version 7 has these new features: + +- NEW: support of JSON Type Definition [RFC8927](https://datatracker.ietf.org/doc/rfc8927/) (from [v7.1.0](https://github.com/ajv-validator/ajv-keywords/releases/tag/v7.1.0)), including generation of [serializers](./docs/api.md#jtd-serialize) and [parsers](./docs/api.md#jtd-parse) from JTD schemas that are more efficient than native JSON serialization/parsing, combining JSON string parsing and validation in one function. +- support of JSON Schema draft-2019-09 features: [`unevaluatedProperties`](./docs/json-schema.md#unevaluatedproperties) and [`unevaluatedItems`](./docs/json-schema.md#unevaluateditems), [dynamic recursive references](./docs/validation.md#extending-recursive-schemas) and other [additional keywords](./docs/json-schema.md#json-schema-draft-2019-09). +- to reduce the mistakes in JSON schemas and unexpected validation results, [strict mode](./docs/strict-mode.md) is added - it prohibits ignored or ambiguous JSON Schema elements. +- to make code injection from untrusted schemas impossible, [code generation](./docs/codegen.md) is fully re-written to be safe and to allow code optimization (compiled schema code size is reduced by more than 10%). +- to simplify Ajv extensions, the new keyword API that is used by pre-defined keywords is available to user-defined keywords - it is much easier to define any keywords now, especially with subschemas. [ajv-keywords](https://github.com/ajv-validator/ajv-keywords) package was updated to use the new API (in [v4.0.0](https://github.com/ajv-validator/ajv-keywords/releases/tag/v4.0.0)) +- schemas are compiled to ES6 code (ES5 code generation is also supported with an option). +- to improve reliability and maintainability the code is migrated to TypeScript. + +**Please note**: + +- the support for JSON-Schema draft-04 is removed - if you have schemas using "id" attributes you have to replace them with "\$id" (or continue using [Ajv v6](https://github.com/ajv-validator/ajv/tree/v6) that will be supported until 02/28/2021). +- all formats are separated to ajv-formats package - they have to be explicitly added if you use them. + +See [release notes](https://github.com/ajv-validator/ajv/releases/tag/v7.0.0) for the details. + +To install the new version: + +```bash +npm install ajv +``` + +See [Getting started](#usage) for code example. + +## Contributing + +100+ people contributed to Ajv. You are very welcome to join by implementing new features that are valuable to many users and by improving documentation. + +Please do not be disappointed if your suggestion is not accepted - it is important to maintain the balance between the library size, performance and functionality. If it seems that a feature would benefit only a small number of users, its addition may be delayed until there is more support from the users community - so please submit the issue first to explain why this feature is important. + +Please include documentation and test coverage with any new feature implementations. + +To run tests: + +```bash +npm install +git submodule update --init +npm test +``` + +`npm run build` - compiles typescript to `dist` folder. + +Please review [Contributing guidelines](./CONTRIBUTING.md) and [Code components](./docs/components.md). + +## Contents + +- [Platinum sponsors](#platinum-sponsors) +- [Using version 7](#using-version-7) +- [Contributing](#contributing) +- [Mozilla MOSS grant and OpenJS Foundation](#mozilla-moss-grant-and-openjs-foundation) +- [Sponsors](#sponsors) +- [Performance](#performance) +- [Features](#features) +- [Frequently Asked Questions](./docs/faq.md) +- [Using in browser](#using-in-browser) + - [Content Security Policy](./docs/security.md#content-security-policy) +- [Using in ES5 environment](#using-in-es5-environment) +- [Command line interface](#command-line-interface) +- [API reference](./docs/api.md) + - [Methods](./docs/api.md#ajv-constructor-and-methods) + - [Options](./docs/api.md#options) + - [Validation errors](./docs/api.md#validation-errors) +- NEW: [Strict mode](./docs/strict-mode.md#strict-mode) + - [Prohibit ignored keywords](./docs/strict-mode.md#prohibit-ignored-keywords) + - [Prevent unexpected validation](./docs/strict-mode.md#prevent-unexpected-validation) + - [Strict types](./docs/strict-mode.md#strict-types) + - [Strict number validation](./docs/strict-mode.md#strict-number-validation) +- [Data validation](./docs/validation.md) + - [Validation basics](./docs/validation.md#validation-basics): [JSON Schema keywords](./docs/validation.md#validation-keywords), [annotations](./docs/validation.md#annotation-keywords), [formats](./docs/validation.md#formats) + - [Modular schemas](./docs/validation.md#modular-schemas): [combining with \$ref](./docs/validation.md#ref), [\$data reference](./docs/validation.md#data-reference), [$merge and $patch](./docs/validation.md#merge-and-patch-keywords) + - [Asynchronous schema compilation](./docs/validation.md#asynchronous-schema-compilation) + - [Standalone validation code](./docs/standalone.md) + - [Asynchronous validation](./docs/validation.md#asynchronous-validation) + - [Modifying data](./docs/validation.md#modifying-data-during-validation): [additional properties](./docs/validation.md#removing-additional-properties), [defaults](./docs/validation.md#assigning-defaults), [type coercion](./docs/validation.md#coercing-data-types) +- [Extending Ajv](#extending-ajv) + - User-defined keywords: + - [basics](./docs/validation.md#user-defined-keywords) + - [guide](./docs/keywords.md) + - [Plugins](#plugins) + - [Related packages](#related-packages) +- [Security considerations](./docs/security.md) + - [Security contact](./docs/security.md#security-contact) + - [Untrusted schemas](./docs/security.md#untrusted-schemas) + - [Circular references in objects](./docs/security.md#circular-references-in-javascript-objects) + - [Trusted schemas](./docs/security.md#security-risks-of-trusted-schemas) + - [ReDoS attack](./docs/security.md#redos-attack) + - [Content Security Policy](./docs/security.md#content-security-policy) +- [Some packages using Ajv](#some-packages-using-ajv) +- [Changes history](#changes-history) +- [Support, Code of conduct, Contacts, License](#open-source-software-support) + +## Mozilla MOSS grant and OpenJS Foundation + +::: v-pre +[](https://www.mozilla.org/en-US/moss/) [](https://openjsf.org/blog/2020/08/14/ajv-joins-openjs-foundation-as-an-incubation-project/) +::: + +Ajv has been awarded a grant from Mozilla’s [Open Source Support (MOSS) program](https://www.mozilla.org/en-US/moss/) in the “Foundational Technology” track! It will sponsor the development of Ajv support of [JSON Schema version 2019-09](https://tools.ietf.org/html/draft-handrews-json-schema-02) and of [JSON Type Definition (RFC8927)](https://datatracker.ietf.org/doc/rfc8927/). + +Ajv also joined [OpenJS Foundation](https://openjsf.org/) – having this support will help ensure the longevity and stability of Ajv for all its users. + +This [blog post](https://www.poberezkin.com/posts/2020-08-14-ajv-json-validator-mozilla-open-source-grant-openjs-foundation.html) has more details. + +I am looking for the long term maintainers of Ajv – working with [ReadySet](https://www.thereadyset.co/), also sponsored by Mozilla, to establish clear guidelines for the role of a "maintainer" and the contribution standards, and to encourage a wider, more inclusive, contribution from the community. + +## Please [sponsor Ajv development](https://github.com/sponsors/epoberezkin) + +Since I asked to support Ajv development 40 people and 6 organizations contributed via GitHub and OpenCollective - this support helped receiving the MOSS grant! + +Your continuing support is very important - the funds will be used to develop and maintain Ajv once the next major version is released. + +Please sponsor Ajv via: + +- [GitHub sponsors page](https://github.com/sponsors/epoberezkin) (GitHub will match it) +- [Ajv Open Collective️](https://opencollective.com/ajv) + +Thank you. + +#### Open Collective sponsors + + + + + + + + + + + + + + +## Performance + +Ajv generates code to turn JSON Schemas into super-fast validation functions that are efficient for v8 optimization. + +Currently Ajv is the fastest and the most standard compliant validator according to these benchmarks: + +- [json-schema-benchmark](https://github.com/ebdrup/json-schema-benchmark) - 50% faster than the second place +- [jsck benchmark](https://github.com/pandastrike/jsck#benchmarks) - 20-190% faster +- [z-schema benchmark](https://rawgit.com/zaggino/z-schema/master/benchmark/results.html) +- [themis benchmark](https://cdn.rawgit.com/playlyfe/themis/master/benchmark/results.html) + +Performance of different validators by [json-schema-benchmark](https://github.com/ebdrup/json-schema-benchmark): + +[![performance](https://chart.googleapis.com/chart?chxt=x,y&cht=bhs&chco=76A4FB&chls=2.0&chbh=32,4,1&chs=600x416&chxl=-1:|djv|ajv|json-schema-validator-generator|jsen|is-my-json-valid|themis|z-schema|jsck|skeemas|json-schema-library|tv4&chd=t:100,98,72.1,66.8,50.1,15.1,6.1,3.8,1.2,0.7,0.2)](https://github.com/ebdrup/json-schema-benchmark/blob/master/README.md#performance) + +## Features + +- Ajv implements JSON Schema [draft-06/07/2019-09](http://json-schema.org/) standards (draft-04 is supported in v6): + - all validation keywords (see [JSON Schema validation keywords](./docs/json-schema.md)) + - keyword "nullable" from [Open API 3 specification](https://swagger.io/docs/specification/data-models/data-types/). + - full support of remote references (remote schemas have to be added with `addSchema` or compiled to be available) + - support of circular references between schemas + - correct string lengths for strings with unicode pairs + - [formats](#formats) defined by JSON Schema draft-07 standard (with [ajv-formats](https://github.com/ajv-validator/ajv-formats) plugin) and additional formats (can be turned off) + - [validates schemas against meta-schema](./docs/api.md#api-validateschema) +- NEW: supports [JSON Type Definition](https://datatracker.ietf.org/doc/rfc8927/): + - all forms (see [JSON Type Definition schema forms](./docs/json-type-definition.md)) + - meta-schema for JTD schemas + - "union" keyword and user-defined keywords (can be used inside "metadata" member of the schema) +- supports [browsers](#using-in-browser) and Node.js 0.10-14.x +- [asynchronous loading](./docs/validation.md#asynchronous-schema-compilation) of referenced schemas during compilation +- "All errors" validation mode with [option allErrors](./docs/api.md#options) +- [error messages with parameters](./docs/api.md#validation-errors) describing error reasons to allow error message generation +- i18n error messages support with [ajv-i18n](https://github.com/ajv-validator/ajv-i18n) package +- [removing-additional-properties](./docs/validation.md#removing-additional-properties) +- [assigning defaults](./docs/validation.md#assigning-defaults) to missing properties and items +- [coercing data](./docs/validation.md#coercing-data-types) to the types specified in `type` keywords +- [user-defined keywords](#user-defined-keywords) +- draft-06/07 keywords `const`, `contains`, `propertyNames` and `if/then/else` +- draft-06 boolean schemas (`true`/`false` as a schema to always pass/fail). +- additional extension keywords with [ajv-keywords](https://github.com/ajv-validator/ajv-keywords) package +- [\$data reference](./docs/validation.md#data-reference) to use values from the validated data as values for the schema keywords +- [asynchronous validation](./docs/api.md#asynchronous-validation) of user-defined formats and keywords + +## Extending Ajv + +### User defined keywords + +See section in [data validation](./docs/validation.md#user-defined-keywords) and the [detailed guide](./docs/keywords.md). + +### Plugins + +Ajv can be extended with plugins that add keywords, formats or functions to process generated code. When such plugin is published as npm package it is recommended that it follows these conventions: + +- it exports a function that accepts ajv instance as the first parameter - it allows using plugins with [ajv-cli](#command-line-interface). +- this function returns the same instance to allow chaining. +- this function can accept an optional configuration as the second parameter. + +You can import `Plugin` interface from ajv if you use Typescript. + +If you have published a useful plugin please submit a PR to add it to the next section. + +### Related packages + +- [ajv-bsontype](https://github.com/BoLaMN/ajv-bsontype) - plugin to validate mongodb's bsonType formats +- [ajv-cli](https://github.com/jessedc/ajv-cli) - command line interface +- [ajv-formats](https://github.com/ajv-validator/ajv-formats) - formats defined in JSON Schema specification +- [ajv-errors](https://github.com/ajv-validator/ajv-errors) - plugin for defining error messages in the schema +- [ajv-i18n](https://github.com/ajv-validator/ajv-i18n) - internationalised error messages +- [ajv-istanbul](https://github.com/ajv-validator/ajv-istanbul) - plugin to instrument generated validation code to measure test coverage of your schemas +- [ajv-keywords](https://github.com/ajv-validator/ajv-keywords) - plugin with additional validation keywords (select, typeof, etc.) +- [ajv-merge-patch](https://github.com/ajv-validator/ajv-merge-patch) - plugin with keywords $merge and $patch +- [ajv-formats-draft2019](https://github.com/luzlab/ajv-formats-draft2019) - format validators for draft2019 that aren't included in [ajv-formats](https://github.com/ajv-validator/ajv-formats) (ie. `idn-hostname`, `idn-email`, `iri`, `iri-reference` and `duration`) + +## Some packages using Ajv + +- [webpack](https://github.com/webpack/webpack) - a module bundler. Its main purpose is to bundle JavaScript files for usage in a browser +- [jsonscript-js](https://github.com/JSONScript/jsonscript-js) - the interpreter for [JSONScript](http://www.jsonscript.org) - scripted processing of existing endpoints and services +- [osprey-method-handler](https://github.com/mulesoft-labs/osprey-method-handler) - Express middleware for validating requests and responses based on a RAML method object, used in [osprey](https://github.com/mulesoft/osprey) - validating API proxy generated from a RAML definition +- [har-validator](https://github.com/ahmadnassri/har-validator) - HTTP Archive (HAR) validator +- [jsoneditor](https://github.com/josdejong/jsoneditor) - a web-based tool to view, edit, format, and validate JSON http://jsoneditoronline.org +- [JSON Schema Lint](https://github.com/nickcmaynard/jsonschemalint) - a web tool to validate JSON/YAML document against a single JSON Schema http://jsonschemalint.com +- [objection](https://github.com/vincit/objection.js) - SQL-friendly ORM for Node.js +- [table](https://github.com/gajus/table) - formats data into a string table +- [ripple-lib](https://github.com/ripple/ripple-lib) - a JavaScript API for interacting with [Ripple](https://ripple.com) in Node.js and the browser +- [restbase](https://github.com/wikimedia/restbase) - distributed storage with REST API & dispatcher for backend services built to provide a low-latency & high-throughput API for Wikipedia / Wikimedia content +- [hippie-swagger](https://github.com/CacheControl/hippie-swagger) - [Hippie](https://github.com/vesln/hippie) wrapper that provides end to end API testing with swagger validation +- [react-form-controlled](https://github.com/seeden/react-form-controlled) - React controlled form components with validation +- [rabbitmq-schema](https://github.com/tjmehta/rabbitmq-schema) - a schema definition module for RabbitMQ graphs and messages +- [@query/schema](https://www.npmjs.com/package/@query/schema) - stream filtering with a URI-safe query syntax parsing to JSON Schema +- [chai-ajv-json-schema](https://github.com/peon374/chai-ajv-json-schema) - chai plugin to us JSON Schema with expect in mocha tests +- [grunt-jsonschema-ajv](https://github.com/SignpostMarv/grunt-jsonschema-ajv) - Grunt plugin for validating files against JSON Schema +- [extract-text-webpack-plugin](https://github.com/webpack-contrib/extract-text-webpack-plugin) - extract text from bundle into a file +- [electron-builder](https://github.com/electron-userland/electron-builder) - a solution to package and build a ready for distribution Electron app +- [addons-linter](https://github.com/mozilla/addons-linter) - Mozilla Add-ons Linter +- [gh-pages-generator](https://github.com/epoberezkin/gh-pages-generator) - multi-page site generator converting markdown files to GitHub pages +- [ESLint](https://github.com/eslint/eslint) - the pluggable linting utility for JavaScript and JSX +- [Spectral](https://github.com/stoplightio/spectral) - the customizable linting utility for JSON/YAML, OpenAPI, AsyncAPI, and JSON Schema + +## Changes history + +See https://github.com/ajv-validator/ajv/releases + +**Please note**: [Changes in version 7.0.0](https://github.com/ajv-validator/ajv/releases/tag/v7.0.0) + +[Version 6.0.0](https://github.com/ajv-validator/ajv/releases/tag/v6.0.0). + +## Code of conduct + +Please review and follow the [Code of conduct](./CODE_OF_CONDUCT.md). + +Please report any unacceptable behaviour to ajv.validator@gmail.com - it will be reviewed by the project team. + +## Security contact + +To report a security vulnerability, please use the +[Tidelift security contact](https://tidelift.com/security). +Tidelift will coordinate the fix and disclosure. Please do NOT report security vulnerabilities via GitHub issues. + +## Open-source software support + +Ajv is a part of [Tidelift subscription](https://tidelift.com/subscription/pkg/npm-ajv?utm_source=npm-ajv&utm_medium=referral&utm_campaign=readme) - it provides a centralised support to open-source software users, in addition to the support provided by software maintainers. diff --git a/docs/README.md b/docs/README.md index 60ef492a0..1f03ab021 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,537 +1,45 @@ -# Ajv: Another JSON validator +# Ajv JSON Validator -Ajv logo +Safety, security and reliability for JavaScript applications -The fastest JSON schema validator for Node.js and browser. +## Ajv News -Supports JSON Schema draft-06/07/2019-09 (draft-04 is supported in [version 6](https://github.com/ajv-validator/ajv/tree/v6)) and JSON Type Definition [RFC8927](https://datatracker.ietf.org/doc/rfc8927/). +This section will include the last update and the headlines of several previous updates, e.g. these sections: -::: v-pre -[![build](https://github.com/ajv-validator/ajv/workflows/build/badge.svg)](https://github.com/ajv-validator/ajv/actions?query=workflow%3Abuild) -[![npm](https://img.shields.io/npm/v/ajv.svg)](https://www.npmjs.com/package/ajv) -[![npm downloads](https://img.shields.io/npm/dm/ajv.svg)](https://www.npmjs.com/package/ajv) -[![Coverage Status](https://coveralls.io/repos/github/ajv-validator/ajv/badge.svg?branch=master)](https://coveralls.io/github/ajv-validator/ajv?branch=master) -[![Gitter](https://img.shields.io/gitter/room/ajv-validator/ajv.svg)](https://gitter.im/ajv-validator/ajv) -[![GitHub Sponsors](https://img.shields.io/badge/$-sponsors-brightgreen)](https://github.com/sponsors/epoberezkin) -::: +https://github.com/ajv-validator/ajv#using-version-7 -## Platinum sponsors +https://github.com/ajv-validator/ajv#mozilla-moss-grant-and-openjs-foundation -::: v-pre -[](https://www.mozilla.org)[](https://opencollective.com/ajv) -::: +### Write less code -## Using version 7 +**Ensure your data is valid once it's received** -Ajv version 7 has these new features: +Instead of having your data validation and sanitization logic scattered around your code, you can express the requirements to your data with concise, easy to read and cross-platform [JSON Schema](https://json-schema.org) or [JSON Type Definition](https://jsontypedef.com) specifications and validate the data as soon as it arrives to your application. TypeScript users can use validation functions as type guards, having type level guarantee that if your data is validated - it is correct. -- NEW: support of JSON Type Definition [RFC8927](https://datatracker.ietf.org/doc/rfc8927/) (from [v7.1.0](https://github.com/ajv-validator/ajv-keywords/releases/tag/v7.1.0)), including generation of [serializers](./docs/api.md#jtd-serialize) and [parsers](./docs/api.md#jtd-parse) from JTD schemas that are more efficient than native JSON serialization/parsing, combining JSON string parsing and validation in one function. -- support of JSON Schema draft-2019-09 features: [`unevaluatedProperties`](./docs/json-schema.md#unevaluatedproperties) and [`unevaluatedItems`](./docs/json-schema.md#unevaluateditems), [dynamic recursive references](./docs/validation.md#extending-recursive-schemas) and other [additional keywords](./docs/json-schema.md#json-schema-draft-2019-09). -- to reduce the mistakes in JSON schemas and unexpected validation results, [strict mode](./docs/strict-mode.md) is added - it prohibits ignored or ambiguous JSON Schema elements. -- to make code injection from untrusted schemas impossible, [code generation](./docs/codegen.md) is fully re-written to be safe and to allow code optimization (compiled schema code size is reduced by more than 10%). -- to simplify Ajv extensions, the new keyword API that is used by pre-defined keywords is available to user-defined keywords - it is much easier to define any keywords now, especially with subschemas. [ajv-keywords](https://github.com/ajv-validator/ajv-keywords) package was updated to use the new API (in [v4.0.0](https://github.com/ajv-validator/ajv-keywords/releases/tag/v4.0.0)) -- schemas are compiled to ES6 code (ES5 code generation is also supported with an option). -- to improve reliability and maintainability the code is migrated to TypeScript. +### Super fast and secure -**Please note**: +**The fastest and the most secure JSON validator** -- the support for JSON-Schema draft-04 is removed - if you have schemas using "id" attributes you have to replace them with "\$id" (or continue using [Ajv v6](https://github.com/ajv-validator/ajv/tree/v6) that will be supported until 02/28/2021). -- all formats are separated to ajv-formats package - they have to be explicitly added if you use them. +Ajv was designed at the time when there were no validators fully complying with JSON Schema specification, aiming to achieve the best possibly validation performance via just-in-time compilation of JSON schemas to code. Ajv achieved both speed and rigour, but initially security was an afterthought - many security flaws have been fixed thanks to the reports from its users. Ajv version 7 was rebuilt to have secure code generation embedded in its design as the primary objective - even if you use untrusted schemas (which is still not recommended) there are type-level guarantees against remote code execution. -See [release notes](https://github.com/ajv-validator/ajv/releases/tag/v7.0.0) for the details. +### Multi-specification -To install the new version: +**Choose your JSON schema standard** -```bash -npm install ajv -``` +In addition to the latest JSON Schema draft 2020-12, Ajv version 8 added support for JSON Type Definition - a new [RFC8927](https://datatracker.ietf.org/doc/rfc8927/) that offers a much simpler and less error-prone alternative to JSON Schema. Designed to be well-aligned with type systems, JTD has tools for both validation and type code generation for multiple languages. -See [Getting started](#usage) for code example. +## Introduction (no section heading) -## Contributing +Ajv is a widely used library that provides reliability, safety and security to millions of JavaScript applications and other libraries. It can be used in all JavaScript environments - node.js, browsers, Electron apps, etc. If your environment or security policy prohibit run-time function construction you can compile your schemas during build time into a standalone validation code (it may still have dependencies on small parts of Ajv code, but doesn't use the whole library) - since version 7 it is fully supported for all JSON schemas. -100+ people contributed to Ajv. You are very welcome to join by implementing new features that are valuable to many users and by improving documentation. +Installation -Please do not be disappointed if your suggestion is not accepted - it is important to maintain the balance between the library size, performance and functionality. If it seems that a feature would benefit only a small number of users, its addition may be delayed until there is more support from the users community - so please submit the issue first to explain why this feature is important. +Usage example / or small playground -Please include documentation and test coverage with any new feature implementations. +Try in the playground (TBC) -To run tests: +## Who uses Ajv -```bash -npm install -git submodule update --init -npm test -``` +## Contributors -`npm run build` - compiles typescript to `dist` folder. - -Please review [Contributing guidelines](./CONTRIBUTING.md) and [Code components](./docs/components.md). - -## Contents - -- [Platinum sponsors](#platinum-sponsors) -- [Using version 7](#using-version-7) -- [Contributing](#contributing) -- [Mozilla MOSS grant and OpenJS Foundation](#mozilla-moss-grant-and-openjs-foundation) -- [Sponsors](#sponsors) -- [Performance](#performance) -- [Features](#features) -- [Getting started](#usage) -- [Choosing schema language](#choosing-schema-language) - - [JSON Schema](#json-schema) - - [JSON Type Definition](#json-type-definition) -- [Frequently Asked Questions](./docs/faq.md) -- [Using in browser](#using-in-browser) - - [Content Security Policy](./docs/security.md#content-security-policy) -- [Using in ES5 environment](#using-in-es5-environment) -- [Command line interface](#command-line-interface) -- [API reference](./docs/api.md) - - [Methods](./docs/api.md#ajv-constructor-and-methods) - - [Options](./docs/api.md#options) - - [Validation errors](./docs/api.md#validation-errors) -- NEW: [Strict mode](./docs/strict-mode.md#strict-mode) - - [Prohibit ignored keywords](./docs/strict-mode.md#prohibit-ignored-keywords) - - [Prevent unexpected validation](./docs/strict-mode.md#prevent-unexpected-validation) - - [Strict types](./docs/strict-mode.md#strict-types) - - [Strict number validation](./docs/strict-mode.md#strict-number-validation) -- [Data validation](./docs/validation.md) - - [Validation basics](./docs/validation.md#validation-basics): [JSON Schema keywords](./docs/validation.md#validation-keywords), [annotations](./docs/validation.md#annotation-keywords), [formats](./docs/validation.md#formats) - - [Modular schemas](./docs/validation.md#modular-schemas): [combining with \$ref](./docs/validation.md#ref), [\$data reference](./docs/validation.md#data-reference), [$merge and $patch](./docs/validation.md#merge-and-patch-keywords) - - [Asynchronous schema compilation](./docs/validation.md#asynchronous-schema-compilation) - - [Standalone validation code](./docs/standalone.md) - - [Asynchronous validation](./docs/validation.md#asynchronous-validation) - - [Modifying data](./docs/validation.md#modifying-data-during-validation): [additional properties](./docs/validation.md#removing-additional-properties), [defaults](./docs/validation.md#assigning-defaults), [type coercion](./docs/validation.md#coercing-data-types) -- [Extending Ajv](#extending-ajv) - - User-defined keywords: - - [basics](./docs/validation.md#user-defined-keywords) - - [guide](./docs/keywords.md) - - [Plugins](#plugins) - - [Related packages](#related-packages) -- [Security considerations](./docs/security.md) - - [Security contact](./docs/security.md#security-contact) - - [Untrusted schemas](./docs/security.md#untrusted-schemas) - - [Circular references in objects](./docs/security.md#circular-references-in-javascript-objects) - - [Trusted schemas](./docs/security.md#security-risks-of-trusted-schemas) - - [ReDoS attack](./docs/security.md#redos-attack) - - [Content Security Policy](./docs/security.md#content-security-policy) -- [Some packages using Ajv](#some-packages-using-ajv) -- [Changes history](#changes-history) -- [Support, Code of conduct, Contacts, License](#open-source-software-support) - -## Mozilla MOSS grant and OpenJS Foundation - -::: v-pre -[](https://www.mozilla.org/en-US/moss/) [](https://openjsf.org/blog/2020/08/14/ajv-joins-openjs-foundation-as-an-incubation-project/) -::: - -Ajv has been awarded a grant from Mozilla’s [Open Source Support (MOSS) program](https://www.mozilla.org/en-US/moss/) in the “Foundational Technology” track! It will sponsor the development of Ajv support of [JSON Schema version 2019-09](https://tools.ietf.org/html/draft-handrews-json-schema-02) and of [JSON Type Definition (RFC8927)](https://datatracker.ietf.org/doc/rfc8927/). - -Ajv also joined [OpenJS Foundation](https://openjsf.org/) – having this support will help ensure the longevity and stability of Ajv for all its users. - -This [blog post](https://www.poberezkin.com/posts/2020-08-14-ajv-json-validator-mozilla-open-source-grant-openjs-foundation.html) has more details. - -I am looking for the long term maintainers of Ajv – working with [ReadySet](https://www.thereadyset.co/), also sponsored by Mozilla, to establish clear guidelines for the role of a "maintainer" and the contribution standards, and to encourage a wider, more inclusive, contribution from the community. - -## Please [sponsor Ajv development](https://github.com/sponsors/epoberezkin) - -Since I asked to support Ajv development 40 people and 6 organizations contributed via GitHub and OpenCollective - this support helped receiving the MOSS grant! - -Your continuing support is very important - the funds will be used to develop and maintain Ajv once the next major version is released. - -Please sponsor Ajv via: - -- [GitHub sponsors page](https://github.com/sponsors/epoberezkin) (GitHub will match it) -- [Ajv Open Collective️](https://opencollective.com/ajv) - -Thank you. - -#### Open Collective sponsors - - - - - - - - - - - - - - -## Performance - -Ajv generates code to turn JSON Schemas into super-fast validation functions that are efficient for v8 optimization. - -Currently Ajv is the fastest and the most standard compliant validator according to these benchmarks: - -- [json-schema-benchmark](https://github.com/ebdrup/json-schema-benchmark) - 50% faster than the second place -- [jsck benchmark](https://github.com/pandastrike/jsck#benchmarks) - 20-190% faster -- [z-schema benchmark](https://rawgit.com/zaggino/z-schema/master/benchmark/results.html) -- [themis benchmark](https://cdn.rawgit.com/playlyfe/themis/master/benchmark/results.html) - -Performance of different validators by [json-schema-benchmark](https://github.com/ebdrup/json-schema-benchmark): - -[![performance](https://chart.googleapis.com/chart?chxt=x,y&cht=bhs&chco=76A4FB&chls=2.0&chbh=32,4,1&chs=600x416&chxl=-1:|djv|ajv|json-schema-validator-generator|jsen|is-my-json-valid|themis|z-schema|jsck|skeemas|json-schema-library|tv4&chd=t:100,98,72.1,66.8,50.1,15.1,6.1,3.8,1.2,0.7,0.2)](https://github.com/ebdrup/json-schema-benchmark/blob/master/README.md#performance) - -## Features - -- Ajv implements JSON Schema [draft-06/07/2019-09](http://json-schema.org/) standards (draft-04 is supported in v6): - - all validation keywords (see [JSON Schema validation keywords](./docs/json-schema.md)) - - keyword "nullable" from [Open API 3 specification](https://swagger.io/docs/specification/data-models/data-types/). - - full support of remote references (remote schemas have to be added with `addSchema` or compiled to be available) - - support of circular references between schemas - - correct string lengths for strings with unicode pairs - - [formats](#formats) defined by JSON Schema draft-07 standard (with [ajv-formats](https://github.com/ajv-validator/ajv-formats) plugin) and additional formats (can be turned off) - - [validates schemas against meta-schema](./docs/api.md#api-validateschema) -- NEW: supports [JSON Type Definition](https://datatracker.ietf.org/doc/rfc8927/): - - all forms (see [JSON Type Definition schema forms](./docs/json-type-definition.md)) - - meta-schema for JTD schemas - - "union" keyword and user-defined keywords (can be used inside "metadata" member of the schema) -- supports [browsers](#using-in-browser) and Node.js 0.10-14.x -- [asynchronous loading](./docs/validation.md#asynchronous-schema-compilation) of referenced schemas during compilation -- "All errors" validation mode with [option allErrors](./docs/api.md#options) -- [error messages with parameters](./docs/api.md#validation-errors) describing error reasons to allow error message generation -- i18n error messages support with [ajv-i18n](https://github.com/ajv-validator/ajv-i18n) package -- [removing-additional-properties](./docs/validation.md#removing-additional-properties) -- [assigning defaults](./docs/validation.md#assigning-defaults) to missing properties and items -- [coercing data](./docs/validation.md#coercing-data-types) to the types specified in `type` keywords -- [user-defined keywords](#user-defined-keywords) -- draft-06/07 keywords `const`, `contains`, `propertyNames` and `if/then/else` -- draft-06 boolean schemas (`true`/`false` as a schema to always pass/fail). -- additional extension keywords with [ajv-keywords](https://github.com/ajv-validator/ajv-keywords) package -- [\$data reference](./docs/validation.md#data-reference) to use values from the validated data as values for the schema keywords -- [asynchronous validation](./docs/api.md#asynchronous-validation) of user-defined formats and keywords - -## Install - -To install version 7: - -``` -npm install ajv -``` - -## Getting started - -Try it in the Node.js REPL: https://runkit.com/npm/ajv - -In JavaScript: - -```javascript -// or ESM/TypeScript import -import Ajv from "ajv" -// Node.js require: -const Ajv = require("ajv").default - -const ajv = new Ajv() // options can be passed, e.g. {allErrors: true} -const validate = ajv.compile(schema) -const valid = validate(data) -if (!valid) console.log(validate.errors) -``` - -In TypeScript: - -```typescript -import Ajv, {JSONSchemaType, DefinedError} from "ajv" - -const ajv = new Ajv() - -type MyData = {foo: number} - -// Optional schema type annotation for schema to match MyData type. -// To use JSONSchemaType set `strictNullChecks: true` in tsconfig `compilerOptions`. -const schema: JSONSchemaType = { - type: "object", - properties: { - foo: {type: "number", minimum: 0}, - }, - required: ["foo"], - additionalProperties: false, -} - -// validate is a type guard for MyData - type is inferred from schema type -const validate = ajv.compile(schema) - -// or, if you did not use type annotation for the schema, -// type parameter can be used to make it type guard: -// const validate = ajv.compile(schema) - -const data: any = {foo: 1} - -if (validate(data)) { - // data is MyData here - console.log(data.foo) -} else { - // The type cast is needed to allow user-defined keywords and errors - // You can extend this type to include your error types as needed. - for (const err of validate.errors as DefinedError[]) { - switch (err.keyword) { - case "minimum": - // err type is narrowed here to have "minimum" error params properties - console.log(err.params.limit) - break - // ... - } - } -} -``` - -With JSON Type Definition schema: - -In JavaScript: - -```javascript -const Ajv = require("ajv").default - -const ajv = new Ajv() // options can be passed, e.g. {allErrors: true} -const schema = { - properties: { - foo: {type: "float64"}, - }, -} -const validate = ajv.compile(schema) -const valid = validate({foo: 1}) // true -if (!valid) console.log(validate.errors) -// Unlike JSON Schema: -const valid1 = validate(1) // false, bot an object -const valid2 = validate({}) // false, foo is required -const valid3 = validate({foo: 1, bar: 2}) // false, bar is additional -``` - -In TypeScript: - -```typescript -import {JTDSchemaType} from "ajv" - -type MyData = {foo: number} - -// Optional schema type annotation for schema to match MyData type. -// To use JTDSchemaType set `strictNullChecks: true` in tsconfig `compilerOptions`. -const schema: JTDSchemaType = { - properties: { - foo: {type: "float64"}, - }, -} -``` - -See [this test](./spec/types/json-schema.spec.ts) for an advanced example, [API reference](./docs/api.md) and [Options](./docs/api.md#options) for more details. - -Ajv compiles schemas to functions and caches them in all cases (using schema itself as a key for Map) or another function passed via options), so that the next time the same schema is used (not necessarily the same object instance) it won't be compiled again. - -The best performance is achieved when using compiled functions returned by `compile` or `getSchema` methods (there is no additional function call). - -**Please note**: every time a validation function or `ajv.validate` are called `errors` property is overwritten. You need to copy `errors` array reference to another variable if you want to use it later (e.g., in the callback). See [Validation errors](./docs/api.md#validation-errors) - -## Using in browser - -See [Content Security Policy](./docs/security.md#content-security-policy) to decide the best approach how to use Ajv in the browser. - -Whether you use Ajv or compiled schemas, it is recommended that you bundle them together with your code. - -If you need to use Ajv in several bundles you can create a separate UMD bundles using `npm run bundle` script. - -Then you need to load Ajv with support of JSON Schema draft-07 in the browser: - -```html - - -``` - -To load the bundle that supports JSON Schema draft-2019-09: - -```html - - -``` - -To load the bundle that supports JSON Type Definition: - -```html - - -``` - -This bundle can be used with different module systems; it creates global `ajv` (or `ajv2019`) if no module system is found. - -The browser bundle is available on [cdnjs](https://cdnjs.com/libraries/ajv). - -**Please note**: some frameworks, e.g. Dojo, may redefine global require in a way that is not compatible with CommonJS module format. In this case Ajv bundle has to be loaded before the framework and then you can use global `ajv` (see issue [#234](https://github.com/ajv-validator/ajv/issues/234)). - -## Choosing schema language - -Both JSON Schema and JSON Type Definition are cross-platform specifications with implementations in multiple programming languages that help you define the shape and requirements to your JSON data. - -This section compares their pros/cons to help decide which specification fits your application better. - -### JSON Schema - -- Pros - - Wide specification adoption. - - Used as part of OpenAPI specification. - - Support of complex validation scenarios: - - untagged unions and boolean logic - - conditional schemas and dependencies - - restrictions on the number ranges and the size of strings, arrays and objects - - semantic validation with formats, patterns and content keywords - - distribute strict record definitions across multiple schemas (with unevaluatedProperties) - - Can be effectively used for validation of any JavaScript objects and configuration files. -- Cons - - Defines the collection of restrictions on the data, rather than the shape of the data. - - No standard support for tagged unions. - - Complex and error prone for the new users (Ajv has [strict mode](./docs/strict-mode) to compensate for it, but it is not cross-platform). - - Some parts of specification are difficult to implement, creating the risk of implementations divergence: - - reference resolution model - - unevaluatedProperties/unevaluatedItems - - dynamic recursive references - - Internet draft status (rather than RFC) - -See [JSON Schema](./docs/json-schema.md) for the list of defined keywords. - -### JSON Type Definition - -- Pros: - - Aligned with type systems of many languages - can be used to generate type definitions and efficient parsers and serializers to/from these types. - - Very simple, enforcing the best practices for cross-platform JSON API modelling. - - Simple to implement, ensuring consistency across implementations. - - Defines the shape of JSON data via strictly defined schema forms (rather than the collection of restrictions). - - Effective support for tagged unions. - - Designed to protect against user mistakes. - - Approved as [RFC8927](https://datatracker.ietf.org/doc/rfc8927/) -- Cons: - - Limited, compared with JSON Schema - no support for untagged unions\*, conditionals, references between different schema files\*\*, etc. - - No meta-schema in the specification\*. - - Brand new - limited industry adoption (as of January 2021). - -\* Ajv defines meta-schema for JTD schemas and non-standard keyword "union" that can be used inside "metadata" object. - -\*\* You can still combine schemas from multiple files in the application code. - -See [JSON Type Definition](./docs/json-type-definition.md) for the list of defined schema forms. - -## Using in ES5 environment - -You need to: - -- recompile Typescript to ES5 target - it is set to 2018 in the bundled compiled code. -- generate ES5 validation code: - -```javascript -const ajv = new Ajv({code: {es5: true}}) -``` - -See [Advanced options](https://github.com/ajv-validator/ajv/blob/master/docs/api.md#advanced-options). - -## Command line interface - -CLI is available as a separate npm package [ajv-cli](https://github.com/ajv-validator/ajv-cli). It supports: - -- compiling JSON Schemas to test their validity -- generating [standalone validation code](./docs/standalone.md) that exports validation function(s) to be used without Ajv -- migrating schemas to draft-07 and draft-2019-09 (using [json-schema-migrate](https://github.com/epoberezkin/json-schema-migrate)) -- validating data file(s) against JSON Schema -- testing expected validity of data against JSON Schema -- referenced schemas -- user-defined meta-schemas, validation keywords and formats -- files in JSON, JSON5, YAML, and JavaScript format -- all Ajv options -- reporting changes in data after validation in [JSON-patch](https://datatracker.ietf.org/doc/rfc6902/) format - -## Extending Ajv - -### User defined keywords - -See section in [data validation](./docs/validation.md#user-defined-keywords) and the [detailed guide](./docs/keywords.md). - -### Plugins - -Ajv can be extended with plugins that add keywords, formats or functions to process generated code. When such plugin is published as npm package it is recommended that it follows these conventions: - -- it exports a function that accepts ajv instance as the first parameter - it allows using plugins with [ajv-cli](#command-line-interface). -- this function returns the same instance to allow chaining. -- this function can accept an optional configuration as the second parameter. - -You can import `Plugin` interface from ajv if you use Typescript. - -If you have published a useful plugin please submit a PR to add it to the next section. - -### Related packages - -- [ajv-bsontype](https://github.com/BoLaMN/ajv-bsontype) - plugin to validate mongodb's bsonType formats -- [ajv-cli](https://github.com/jessedc/ajv-cli) - command line interface -- [ajv-formats](https://github.com/ajv-validator/ajv-formats) - formats defined in JSON Schema specification -- [ajv-errors](https://github.com/ajv-validator/ajv-errors) - plugin for defining error messages in the schema -- [ajv-i18n](https://github.com/ajv-validator/ajv-i18n) - internationalised error messages -- [ajv-istanbul](https://github.com/ajv-validator/ajv-istanbul) - plugin to instrument generated validation code to measure test coverage of your schemas -- [ajv-keywords](https://github.com/ajv-validator/ajv-keywords) - plugin with additional validation keywords (select, typeof, etc.) -- [ajv-merge-patch](https://github.com/ajv-validator/ajv-merge-patch) - plugin with keywords $merge and $patch -- [ajv-formats-draft2019](https://github.com/luzlab/ajv-formats-draft2019) - format validators for draft2019 that aren't included in [ajv-formats](https://github.com/ajv-validator/ajv-formats) (ie. `idn-hostname`, `idn-email`, `iri`, `iri-reference` and `duration`) - -## Some packages using Ajv - -- [webpack](https://github.com/webpack/webpack) - a module bundler. Its main purpose is to bundle JavaScript files for usage in a browser -- [jsonscript-js](https://github.com/JSONScript/jsonscript-js) - the interpreter for [JSONScript](http://www.jsonscript.org) - scripted processing of existing endpoints and services -- [osprey-method-handler](https://github.com/mulesoft-labs/osprey-method-handler) - Express middleware for validating requests and responses based on a RAML method object, used in [osprey](https://github.com/mulesoft/osprey) - validating API proxy generated from a RAML definition -- [har-validator](https://github.com/ahmadnassri/har-validator) - HTTP Archive (HAR) validator -- [jsoneditor](https://github.com/josdejong/jsoneditor) - a web-based tool to view, edit, format, and validate JSON http://jsoneditoronline.org -- [JSON Schema Lint](https://github.com/nickcmaynard/jsonschemalint) - a web tool to validate JSON/YAML document against a single JSON Schema http://jsonschemalint.com -- [objection](https://github.com/vincit/objection.js) - SQL-friendly ORM for Node.js -- [table](https://github.com/gajus/table) - formats data into a string table -- [ripple-lib](https://github.com/ripple/ripple-lib) - a JavaScript API for interacting with [Ripple](https://ripple.com) in Node.js and the browser -- [restbase](https://github.com/wikimedia/restbase) - distributed storage with REST API & dispatcher for backend services built to provide a low-latency & high-throughput API for Wikipedia / Wikimedia content -- [hippie-swagger](https://github.com/CacheControl/hippie-swagger) - [Hippie](https://github.com/vesln/hippie) wrapper that provides end to end API testing with swagger validation -- [react-form-controlled](https://github.com/seeden/react-form-controlled) - React controlled form components with validation -- [rabbitmq-schema](https://github.com/tjmehta/rabbitmq-schema) - a schema definition module for RabbitMQ graphs and messages -- [@query/schema](https://www.npmjs.com/package/@query/schema) - stream filtering with a URI-safe query syntax parsing to JSON Schema -- [chai-ajv-json-schema](https://github.com/peon374/chai-ajv-json-schema) - chai plugin to us JSON Schema with expect in mocha tests -- [grunt-jsonschema-ajv](https://github.com/SignpostMarv/grunt-jsonschema-ajv) - Grunt plugin for validating files against JSON Schema -- [extract-text-webpack-plugin](https://github.com/webpack-contrib/extract-text-webpack-plugin) - extract text from bundle into a file -- [electron-builder](https://github.com/electron-userland/electron-builder) - a solution to package and build a ready for distribution Electron app -- [addons-linter](https://github.com/mozilla/addons-linter) - Mozilla Add-ons Linter -- [gh-pages-generator](https://github.com/epoberezkin/gh-pages-generator) - multi-page site generator converting markdown files to GitHub pages -- [ESLint](https://github.com/eslint/eslint) - the pluggable linting utility for JavaScript and JSX -- [Spectral](https://github.com/stoplightio/spectral) - the customizable linting utility for JSON/YAML, OpenAPI, AsyncAPI, and JSON Schema - -## Changes history - -See https://github.com/ajv-validator/ajv/releases - -**Please note**: [Changes in version 7.0.0](https://github.com/ajv-validator/ajv/releases/tag/v7.0.0) - -[Version 6.0.0](https://github.com/ajv-validator/ajv/releases/tag/v6.0.0). - -## Code of conduct - -Please review and follow the [Code of conduct](./CODE_OF_CONDUCT.md). - -Please report any unacceptable behaviour to ajv.validator@gmail.com - it will be reviewed by the project team. - -## Security contact - -To report a security vulnerability, please use the -[Tidelift security contact](https://tidelift.com/security). -Tidelift will coordinate the fix and disclosure. Please do NOT report security vulnerabilities via GitHub issues. - -## Open-source software support - -Ajv is a part of [Tidelift subscription](https://tidelift.com/subscription/pkg/npm-ajv?utm_source=npm-ajv&utm_medium=referral&utm_campaign=readme) - it provides a centralised support to open-source software users, in addition to the support provided by software maintainers. - -## License - -[MIT](./LICENSE) +Ajv is free to use and open-source that many developers contributed to. Join us! diff --git a/docs/api.md b/docs/api.md index cd94f85ad..a6cf8da99 100644 --- a/docs/api.md +++ b/docs/api.md @@ -169,6 +169,7 @@ Ajv return it instance for method chaining from all methods with the prefix `add ```javascript const validate = new Ajv().addSchema(schema).addFormat(name, regex).getSchema(uri) ``` + ::: #### ajv.addMetaSchema(schema: object | object[], key?: string): Ajv diff --git a/docs/guide/environments.md b/docs/guide/environments.md new file mode 100644 index 000000000..550fed108 --- /dev/null +++ b/docs/guide/environments.md @@ -0,0 +1,120 @@ +# Execution environments + +[[toc]] + +## Server-side Node.js + +The main consideration for using Ajv server-side is to [manage compiled schemas](./managing-schemas) correctly, ensuring that the same schema is not compiled more than once. + +## Short-lived environments + +Depending on the life-time of the environments, the benefits from "compile once - validate many times" model can be limited - you can consider using [standalone validation code](../standalone). + +If you have a pre-defined set of schemas, you can: + +1. compile all schemas in the build step - you can either write your own script or use [ajv-cli](https://github.com/ajv-validator/ajv). +2. generate and beautify standalone validation code - you can have all your schemas exported from one file. +3. additionally, you can inline all dependencies on Ajv or ajv-formats using any bundling tools. +4. deploy compiled schemas as part of your application or library (with or without dependency on Ajv, depending on whether you did step 3 and which validation keywords are used in the schemas) + +Please see [gajus/table](https://github.com/gajus/table) package that pre-compiles schemas in this way. + +Even if your schemas need to be stored in the database, you can still compile schemas once and store your validation functions alongside schemas in the database as well, loading them on demand. + +## Browsers + +See [Content Security Policy](../security.md#content-security-policy) to decide how best to use Ajv in the browser for your use case. + +Whether you compile schemas in the browser or use [standalone validation code](../standalone), it is recommended that you bundle them together with your application code. + +If you need to use Ajv in several application bundles you can create a separate UMD bundles of Ajv using `npm run bundle` script. + +In this case you need to load Ajv using the correct bundle, depending on which schema language and which version you need to use: + + + +```html + + +``` + + + +```html + + +``` + + + +```html + + +``` + + + +This bundle can be used with different module systems; it creates global `ajv`/`ajv2019`/`ajvJTD` if no module system is found. + +The browser bundles are available on [cdnjs](https://cdnjs.com/libraries/ajv). + +::: warning Please note +Some frameworks, e.g. Dojo, may redefine global require in a way that is not compatible with CommonJS module format. In this case Ajv bundle has to be loaded before the framework and then you can use global `ajv` (see issue [#234](https://github.com/ajv-validator/ajv/issues/234)). +::: + +## ES5 environments + +You need to: + +- recompile Typescript to ES5 target - it is set to 2018 in the bundled compiled code. +- generate ES5 validation code: + +```javascript +const ajv = new Ajv({code: {es5: true}}) +``` + +See [Advanced options](https://github.com/ajv-validator/ajv/blob/master/docs/api.md#advanced-options). + +## Other JavaScript environments + +Ajv is used in other JavaScript environments, including Electron apps, WeChat mini-apps and many others, where the same considerations apply as above: + +- compilation performance +- restrictive content security policy +- bundle size + +If any of this is important, you may have better results with pre-compiled [standalone validation code](../standalone). + +## Command line interface + +Ajv can be used from the terminal in any operating system supported by Node.js + +CLI is available as a separate npm package [ajv-cli](https://github.com/ajv-validator/ajv-cli). + +It supports: + +- compiling JSON Schemas to test their validity +- generating [standalone validation code](./docs/standalone.md) that exports validation function(s) +- migrating schemas to draft-07 and draft-2019-09 (using [json-schema-migrate](https://github.com/epoberezkin/json-schema-migrate)) +- validating data file(s) against JSON Schema +- testing expected validity of data against JSON Schema +- referenced schemas +- user-defined meta-schemas, validation keywords and formats +- files in JSON, JSON5, YAML, and JavaScript format +- all Ajv options +- reporting changes in data after validation in [JSON-patch](https://datatracker.ietf.org/doc/rfc6902/) format diff --git a/docs/guide/getting-started.md b/docs/guide/getting-started.md new file mode 100644 index 000000000..fcb0b7ccd --- /dev/null +++ b/docs/guide/getting-started.md @@ -0,0 +1,164 @@ +# Getting started + +[[toc]] + +## Install + +::: tip Node REPL +You can try Ajv without installing it in the Node.js REPL: [https://runkit.com/npm/ajv](https://runkit.com/npm/ajv) +::: + +To install Ajv version 7: + +``` +npm install ajv +``` + +If you need to use Ajv with [JSON Schema draft-04](../json-schema#draft-04), you need to install version 6: + +``` +npm install ajv@6 +``` + +See [Contributing](../CONTRIBUTING.md) on how to run the tests locally + +## Basic data validation + +Ajv takes a schema for your JSON data and converts it into a very efficient JavaScript code +that validates your data according to the schema. To create schema you can use either +[JSON Schema](../json-schema) or [JSON Type Definition](../json-type-definition) - check out [Choosing schema language](./schema-language), they have +different advantages and disadvantages. + +For example, to validate an object that has a required property "foo" (an integer number), an optional property "bar" (a string) and no other properties: + + + +```javascript +const Ajv = require("ajv").default +const ajv = new Ajv() // options can be passed, e.g. {allErrors: true} + +const schema = { + type: "object", + properties: { + foo: {type: "integer"}, + bar: {type: "string"} + }, + required: ["foo"], + additionalProperties: false +} + +const validate = ajv.compile(schema) + +const validData = { + foo: 1, + bar: "abc" +} + +const valid = validate(data) +if (!valid) console.log(validate.errors) +``` + + + +```javascript +const Ajv = require("ajv/dist/jtd").default +const ajv = new Ajv() // options can be passed, e.g. {allErrors: true} + +const schema = { + properties: { + foo: {type: "int32"} + }, + optionalProperties: { + bar: {type: "string"} + } +} + + +const validate = ajv.compile(schema) + +const validData = { + foo: 1, + bar: "abc" +} + +const valid = validate(data) +if (!valid) console.log(validate.errors) +`````` + + + +Ajv compiles schemas to functions and caches them in all cases (using schema itself as a key for Map), so that the next time the same schema object is used it won't be compiled again. + +::: tip Please note +The best performance is achieved when using compiled functions returned by `compile` or `getSchema` methods. + +While execution of the compiled validation function is very fast, its compilation is +relatively slow, so you need to make sure that you compile schemas only once and +re-use compiled validation functions. See [Managing multiple schemas](./managing-schemas). +::: + +::: warning Please note +Every time a validation function (or `ajv.validate`) is called `errors` property is overwritten. You need to copy `errors` array reference to another variable if you want to use it later (e.g., in the callback). See [Validation errors](../api.md#validation-errors) +::: + +## Parsing and serializing JSON + +Ajv can compile efficient parsers and serializers from [JSON Type Definition](../json-type-definition) schemas. + +Serializing the data with a function specialized to your data shape can be more than 10x compared with `JSON.stringify`. + +Parsing the data replaces the need for a separate validation after generic parsing with `JSON.parse` (although validation itself is usually much faster than parsing). In case your JSON string is valid specialized parsing is as approximately fast as JSON.parse, but in case your JSON is invalid, specialized parsing would fail much faster - so it can be very efficient in some scenarios. + +For the same data structure, you can compile parser and serializer in this way: + + + +```javascript +const Ajv = require("ajv/dist/jtd").default +const ajv = new Ajv() // options can be passed, e.g. {allErrors: true} + +const schema = { + properties: { + foo: {type: "int32"} + }, + optionalProperties: { + bar: {type: "string"} + } +} + +const serialize = ajv.compileSerializer(schema) +console.log(serialize(data)) + +const parse = ajv.compileParser(schema) + +const data = { + foo: 1, + bar: "abc" +} + +const json = '{"foo": 1, "bar": "abc"}' +const invalidJson = '{"unknown": "abc"}' + +console.log(parseAndLog(json)) // logs {foo: 1, bar: "abc"} +console.log(parseAndLog(invalidJson)) // logs error and position + +function parseAndLog(json) { + const data = parse(json) + if (data === undefined) { + console.log(parse.message) // error message from the last parse call + console.log(parse.position) // error position in string + } else { + console.log(data) + } +} +``` + + + +::: tip Please note +You would have smaller performance benefits in case your schema contains some properties or other parts that are empty schemas (`{}`) - parser would call `JSON.parse` in this case. +::: + +::: warning Please note +Compiled parsers, unlike JSON.parse, do not throw the exception in case JSON string is not a valid JSON or in case data is invalid according to the schema. As soon as the parser determines that either JSON or data is invalid, it returns `undefined` and reports error and position via parsers properties `message` and `position`. +::: \ No newline at end of file diff --git a/docs/guide/managing-schemas.md b/docs/guide/managing-schemas.md new file mode 100644 index 000000000..16197ae31 --- /dev/null +++ b/docs/guide/managing-schemas.md @@ -0,0 +1,60 @@ +# Managing schemas + +[[toc]] + +## Re-using validation functions + +Ajv validation model is optimized for server side execution, when schema compilation happens only once and validation happens multiple times - this has a substantial performance benefit comparing with validators that interpret the schema in the process of validation. + +Transition from template-based code generation in Ajv v6 to the tree-based in v7 brought: +- type-level safety against code injection via untrusted schemas +- more efficient validation code (via [tree optimizations](../codegen.md#code-optimization)) +- smaller memory footprint of compiled functions (schemas are no longer serialized) +- smaller bundle size +- more maintainable code + +These improvements cost slower schema compilation, and increased chance of re-compilation in case you pass a different schema object (see [#1413](https://github.com/ajv-validator/ajv/issues/1413)), so it is very important to [manage schemas correctly](./managing-schemas), so they are only compiled once, or use standalone validation code. + +There are several approaches to manage compiled schemas. + +## Standalone validation code + +## Compiling during initialization + +## Using Ajv instance cache + +### Cache key: schema vs $id + +### Pre-adding all schemas + +### Adding schemas on-demand + +### Asynchronous schema loading + +TODO motivation + +During asynchronous compilation remote references are loaded using supplied function. See `compileAsync` [method](./api.md#api-compileAsync) and `loadSchema` [option](./api.md#options). + +Example: + +```javascript +const ajv = new Ajv({loadSchema: loadSchema}) + +ajv.compileAsync(schema).then(function (validate) { + const valid = validate(data) + // ... +}) + +function loadSchema(uri) { + return request.json(uri).then(function (res) { + if (res.statusCode >= 400) throw new Error("Loading error: " + res.statusCode) + return res.body + }) +} +``` + +::: warning Please note +[Option](./api.md#options) `missingRefs` should NOT be set to `"ignore"` or `"fail"` for asynchronous compilation to work. +::: + +## Caching in your applications diff --git a/docs/guide/modular-schemas.md b/docs/guide/modular-schemas.md new file mode 100644 index 000000000..d6b0e3c97 --- /dev/null +++ b/docs/guide/modular-schemas.md @@ -0,0 +1,233 @@ +# Modular schemas + +## Combining schemas with $ref + +You can structure your validation logic across multiple schema files and have schemas reference each other using `$ref` keyword. + +Example: + +```javascript +const schema = { + $id: "http://example.com/schemas/schema.json", + type: "object", + properties: { + foo: {$ref: "defs.json#/definitions/int"}, + bar: {$ref: "defs.json#/definitions/str"}, + }, +} + +const defsSchema = { + $id: "http://example.com/schemas/defs.json", + definitions: { + int: {type: "integer"}, + str: {type: "string"}, + }, +} +``` + +Now to compile your schema you can either pass all schemas to Ajv instance: + +```javascript +const ajv = new Ajv({schemas: [schema, defsSchema]}) +const validate = ajv.getSchema("http://example.com/schemas/schema.json") +``` + +or use `addSchema` method: + +```javascript +const ajv = new Ajv() +const validate = ajv.addSchema(defsSchema).compile(schema) +``` + +See [Options](./api.md#options) and [addSchema](./api.md#add-schema) method. + +::: tip Please note + +- `$ref` is resolved as the uri-reference using schema \$id as the base URI (see the example). +- References can be recursive (and mutually recursive) to implement the schemas for different data structures (such as linked lists, trees, graphs, etc.). +- You don't have to host your schema files at the URIs that you use as schema \$id. These URIs are only used to identify the schemas, and according to JSON Schema specification validators should not expect to be able to download the schemas from these URIs. +- The actual location of the schema file in the file system is not used. +- You can pass the identifier of the schema as the second parameter of `addSchema` method or as a property name in `schemas` option. This identifier can be used instead of (or in addition to) schema \$id. +- You cannot have the same \$id (or the schema identifier) used for more than one schema - the exception will be thrown. +- You can implement dynamic resolution of the referenced schemas using `compileAsync` method. In this way you can store schemas in any system (files, web, database, etc.) and reference them without explicitly adding to Ajv instance. See [Asynchronous schema compilation](./validation.md#asynchronous-schema-compilation). + ::: + +## Extending recursive schemas + +While statically defined `$ref` keyword allows to split schemas to multiple files, it is difficult to extend recursive schemas - the recursive reference(s) in the original schema points to the original schema, and not to the extended one. So in JSON Schema draft-07 the only available solution to extend the recursive schema was to redefine all sections of the original schema that have recursion. + +It was particularly repetitive when extending meta-schema, as it has many recursive references, but even in a schema with a single recursive reference extending it was very verbose. + +JSON Schema draft-2019-09 and the upcoming draft defined the mechanism for dynamic recursion using keywords `$recursiveRef`/`$recursiveAnchor` (draft-2019-09) or `$dynamicRef`/`$dynamicAnchor` (the next JSON Schema draft) that is somewhat similar to "open recursion" in functional programming. + +Consider this recursive schema with static recursion: + +```javascript +const treeSchema = { + $id: "https://example.com/tree", + type: "object", + required: ["data"], + properties: { + data: true, + children: { + type: "array", + items: {$ref: "#"}, + }, + }, +} +``` + +The only way to extend this schema to prohibit additional properties is by adding `additionalProperties` keyword right in the schema - this approach can be impossible if you do not control the source of the original schema. Ajv also provided the additional keywords in [ajv-merge-patch](https://github.com/ajv-validator/ajv-merge-patch) package to extend schemas by treating them as plain JSON data. While this approach may work for you, it is non-standard and therefore not portable. + +The new keywords for dynamic recursive references allow extending this schema without modifying it: + +```javascript +const treeSchema = { + $id: "https://example.com/tree", + $recursiveAnchor: true, + type: "object", + required: ["data"], + properties: { + data: true, + children: { + type: "array", + items: {$recursiveRef: "#"}, + }, + }, +} + +const strictTreeSchema = { + $id: "https://example.com/strict-tree", + $recursiveAnchor: true, + $ref: "tree", + unevaluatedProperties: false, +} + +import Ajv2019 from "ajv/dist/2019" +// const Ajv2019 = require("ajv/dist/2019").default +const ajv = new Ajv2019({ + schemas: [treeSchema, strictTreeSchema], +}) +const validate = ajv.getSchema("https://example.com/strict-tree") +``` + +See [dynamic-refs](../spec/dynamic-ref.spec.ts) test for the example using `$dynamicAnchor`/`$dynamicRef`. + +At the moment Ajv implements the spec for dynamic recursive references with these limitations: + +- `$recursiveAnchor`/`$dynamicAnchor` can only be used in the schema root. +- `$recursiveRef`/`$dynamicRef` can only be hash fragments, without URI. + +Ajv also does not support dynamic references in [asynchronous schemas](#asynchronous-validation) (Ajv extension) - it is assumed that the referenced schema is synchronous, and there is no validation-time check for it. + +## $data reference + +With `$data` option you can use values from the validated data as the values for the schema keywords. See [proposal](https://github.com/json-schema-org/json-schema-spec/issues/51) for more information about how it works. + +`$data` reference is supported in the keywords: const, enum, format, maximum/minimum, exclusiveMaximum / exclusiveMinimum, maxLength / minLength, maxItems / minItems, maxProperties / minProperties, formatMaximum / formatMinimum, formatExclusiveMaximum / formatExclusiveMinimum, multipleOf, pattern, required, uniqueItems. + +The value of "$data" should be a [JSON-pointer](https://datatracker.ietf.org/doc/rfc6901/) to the data (the root is always the top level data object, even if the $data reference is inside a referenced subschema) or a [relative JSON-pointer](http://tools.ietf.org/html/draft-luff-relative-json-pointer-00) (it is relative to the current point in data; if the \$data reference is inside a referenced subschema it cannot point to the data outside of the root level for this subschema). + +Examples. + +This schema requires that the value in property `smaller` is less or equal than the value in the property larger: + +```javascript +const ajv = new Ajv({$data: true}) + +const schema = { + properties: { + smaller: { + type: "number", + maximum: {$data: "1/larger"}, + }, + larger: {type: "number"}, + }, +} + +const validData = { + smaller: 5, + larger: 7, +} + +ajv.validate(schema, validData) // true +``` + +This schema requires that the properties have the same format as their field names: + +```javascript +const schema = { + additionalProperties: { + type: "string", + format: {$data: "0#"}, + }, +} + +const validData = { + "date-time": "1963-06-19T08:30:06.283185Z", + email: "joe.bloggs@example.com", +} +``` + +`$data` reference is resolved safely - it won't throw even if some property is undefined. If `$data` resolves to `undefined` the validation succeeds (with the exclusion of `const` keyword). If `$data` resolves to incorrect type (e.g. not "number" for maximum keyword) the validation fails. + +## $merge and $patch keywords + +With the package [ajv-merge-patch](https://github.com/ajv-validator/ajv-merge-patch) you can use the keywords `$merge` and `$patch` that allow extending JSON Schemas with patches using formats [JSON Merge Patch (RFC 7396)](https://datatracker.ietf.org/doc/rfc7396/) and [JSON Patch (RFC 6902)](https://datatracker.ietf.org/doc/rfc6902/). + +To add keywords `$merge` and `$patch` to Ajv instance use this code: + +```javascript +require("ajv-merge-patch")(ajv) +``` + +Examples. + +Using `$merge`: + +```javascript +{ + $merge: { + source: { + type: "object", + properties: {p: {type: "string"}}, + additionalProperties: false + }, + with: { + properties: {q: {type: "number"}} + } + } +} +``` + +Using `$patch`: + +```javascript +{ + $patch: { + source: { + type: "object", + properties: {p: {type: "string"}}, + additionalProperties: false + }, + with: [{op: "add", path: "/properties/q", value: {type: "number"}}] + } +} +``` + +The schemas above are equivalent to this schema: + +```javascript +{ + type: "object", + properties: { + p: {type: "string"}, + q: {type: "number"} + }, + additionalProperties: false +} +``` + +The properties `source` and `with` in the keywords `$merge` and `$patch` can use absolute or relative `$ref` to point to other schemas previously added to the Ajv instance or to the fragments of the current schema. + +See the package [ajv-merge-patch](https://github.com/ajv-validator/ajv-merge-patch) for more information. diff --git a/docs/guide/schema-language.md b/docs/guide/schema-language.md new file mode 100644 index 000000000..94d69c602 --- /dev/null +++ b/docs/guide/schema-language.md @@ -0,0 +1,54 @@ +# Choosing schema language + +[[toc]] + +Both [JSON Schema](../json-schema.md) and [JSON Type Definition](../json-type-definition.md) are cross-platform specifications with implementations in multiple programming languages that define the shape of your JSON data. + +You can see the difference between the two specifications in [Getting started](./getting-started) section examples. + +This section compares their pros/cons to help decide which specification fits your application better. + +## JSON Schema + +- Pros + - Wide specification adoption. + - Used as part of OpenAPI specification. + - Support of complex validation scenarios: + - untagged unions and boolean logic + - conditional schemas and dependencies + - restrictions on the number ranges and the size of strings, arrays and objects + - semantic validation with formats, patterns and content keywords + - distribute strict record definitions across multiple schemas (with unevaluatedProperties) + - Can be effectively used for validation of any JavaScript objects and configuration files. +- Cons + - Defines the collection of restrictions on the data, rather than the shape of the data. + - No standard support for tagged unions. + - Complex and error prone for the new users (Ajv has [strict mode](../strict-mode) enabled by default to compensate for it, but it is not cross-platform). + - Some parts of specification are difficult to implement, creating the risk of implementations divergence: + - reference resolution model + - unevaluatedProperties/unevaluatedItems + - dynamic recursive references + - Internet draft status (rather than RFC) + +See [JSON Schema](../json-schema.md) for more information and the list of defined keywords. + +## JSON Type Definition + +- Pros: + - Aligned with type systems of many languages - can be used to generate type definitions and efficient parsers and serializers to/from these types. + - Very simple, enforcing the best practices for cross-platform JSON API modelling. + - Simple to implement, ensuring consistency across implementations. + - Defines the shape of JSON data via strictly defined schema forms (rather than the collection of restrictions). + - Effective support for tagged unions. + - Designed to protect against user mistakes. + - Approved as [RFC8927](https://datatracker.ietf.org/doc/rfc8927/) +- Cons: + - Limited, compared with JSON Schema - no support for untagged unions\*, conditionals, references between different schema files\*\*, etc. + - No meta-schema in the specification\*. + - Brand new - limited industry adoption (as of January 2021). + +\* Ajv defines meta-schema for JTD schemas and non-standard keyword "union" that can be used inside "metadata" object. + +\*\* You can still combine schemas from multiple files in the application code. + +See [JSON Type Definition](../json-type-definition.md) for more information and the list of defined schema forms. diff --git a/docs/guide/typescript.md b/docs/guide/typescript.md new file mode 100644 index 000000000..a7a162dbd --- /dev/null +++ b/docs/guide/typescript.md @@ -0,0 +1,205 @@ +# Using with TypeScript + +[[toc]] + +## Additional functionality + +Ajv takes advantage of TypeScript type system to provide additional functionality that is not possible in JavaScript: + +- utility types `JSONSchemaType` and `JTDSchemaType` to convert data type into the schema type to simplify writing schemas, both for [JSON Schema](../json-schema.md) (but without union support) and for [JSON Type Definition](../json-type-definition) (with tagged unions support). +- compiled validation functions are type guards that narrow the type after successful validation. +- validation errors for JSON Schema are defined as tagged unions, for type-safe error handling. +- when utility type is used, compiled JTD serializers only accept data of correct type (as they do not validate that the data is valid) and compiled parsers return correct data type. + +## Utility types for schemas + +For the same example as in [Getting started](./getting-started): + + + +```typescript +import Ajv, {JSONSchemaType} from "ajv" +const ajv = new Ajv() // options can be passed, e.g. {allErrors: true} + +interface MyData { + foo: number + bar?: string +} + +const schema: JSONSchemaType = { + type: "object", + properties: { + foo: {type: "integer"}, + bar: {type: "string"} + }, + required: ["foo"], + additionalProperties: false +} + +// validate is a type guard for MyData - type is inferred from schema type +const validate = ajv.compile(schema) + +// or, if you did not use type annotation for the schema, +// type parameter can be used to make it type guard: +// const validate = ajv.compile(schema) + +const validData = { + foo: 1, + bar: "abc" +} + +if (validate(data)) { + // data is MyData here + console.log(data.foo) +} else { + console.log(validate.errors) +} +``` + + + +```typescript +import Ajv, {JTDSchemaType} from "ajv/dist/jtd" +const ajv = new Ajv() // options can be passed, e.g. {allErrors: true} + +interface MyData { + foo: number + bar?: string +} + +const schema: JTDSchemaType = { + properties: { + foo: {type: "int32"} + }, + optionalProperties: { + bar: {type: "string"} + } +} + + +// validate is a type guard for MyData - type is inferred from schema type +const validate = ajv.compile(schema) + +// or, if you did not use type annotation for the schema, +// type parameter can be used to make it type guard: +// const validate = ajv.compile(schema) + +const validData = { + foo: 1, + bar: "abc" +} + +if (validate(data)) { + // data is MyData here + console.log(data.foo) +} else { + console.log(validate.errors) +} +`````` + + + +See [this test](https://github.com/ajv-validator/ajv/tree/master/spec/types/json-schema.spec.ts) for an advanced example. + +## Type-safe error handling + +With [JSON Schema](../json-schema), the validation error type is an open union, but it can be cast to a tagged union (using validation keyword as tag) for easier error handling. + +This is not useful with [JSON Type Definition](../json-type-definition), as it defines errors for schema forms, not for keywords. + +Continuing the example above: + + + +```typescript +import {DefinedError} from "ajv" + +// ... + +if (validate(data)) { + // data is MyData here + console.log(data.foo) +} else { + // The type cast is needed, as Ajv uses a wider type to allow extension + // You can extend this type to include your error types as needed. + for (const err of validate.errors as DefinedError[]) { + switch (err.keyword) { + case "type": + // err type is narrowed here to have "type" error params properties + console.log(err.params.type) + break + // ... + } + } +} +``` + + + +## Type-safe parsers and serializers + +With typescript, your compiled parsers and serializers can be type-safe, either taking their type from schema type or from type parameter passed to compilation functions. + +This example uses the same data and schema types as above: + + + +```typescript +import Ajv, {JTDSchemaType} from "ajv/dist/jtd" +const ajv = new Ajv() // options can be passed, e.g. {allErrors: true} + +interface MyData { + foo: number + bar?: string +} + +const schema: JTDSchemaType = { + properties: { + foo: {type: "int32"} + }, + optionalProperties: { + bar: {type: "string"} + } +} + +// serialize will only accept data compatible with MyData +const serialize = ajv.compileSerializer(schema) + +// parse will return MyData or undefined +const parse = ajv.compileParser(schema) + +// types of parse and serialize are inferred from schema, +// they can also be defined explicitly: +// const parse = ajv.compileParser(schema) + +const data = { + foo: 1, + bar: "abc" +} + +const invalidData = { + unknown: "abc" +} + +console.log(serialize(data)) +console.log(serialize(invalidData)) // type error + +const json = '{"foo": 1, "bar": "abc"}' +const invalidJson = '{"unknown": "abc"}' + +console.log(parseAndLogFoo(json)) // logs property +console.log(parseAndLogFoo(invalidJson)) // logs error and position + +function parseAndLogFoo(json: string): void { + const data = parse(json) // MyData | undefined + if (data === undefined) { + console.log(parse.message) // error message from the last parse call + console.log(parse.position) // error position in string + } else { + // data is MyData here + console.log(data.foo) + } +} +``` + + diff --git a/docs/json-schema.md b/docs/json-schema.md index c8689f04d..db3037223 100644 --- a/docs/json-schema.md +++ b/docs/json-schema.md @@ -409,9 +409,10 @@ The value of this keyword should be a map where keys should be regular expressio When the value in data object property matches multiple regular expressions it should be valid according to all the schemas for all matched regular expressions. ::: warning Please note + 1. `patternProperties` keyword does not require that properties matching patterns are present in the object (see examples). 2. By default, Ajv does not allow schemas where patterns in `patternProperties` match any property name in `properties` keyword - that leads to unexpected validation results. It can be allowed with option `allowMatchingProperties`. See [Strict mode](./strict-mode.md) -::: + ::: **Example** diff --git a/docs/validation.md b/docs/validation.md index f66bbf8ca..ce568b7cf 100644 --- a/docs/validation.md +++ b/docs/validation.md @@ -138,239 +138,6 @@ JSON Schema draft-07 also defines formats `iri`, `iri-reference`, `idn-hostname` You can add and replace any formats using [addFormat](./api.md#api-addformat) method. -## Modular schemas - -### Combining schemas with $ref - -You can structure your validation logic across multiple schema files and have schemas reference each other using `$ref` keyword. - -Example: - -```javascript -const schema = { - $id: "http://example.com/schemas/schema.json", - type: "object", - properties: { - foo: {$ref: "defs.json#/definitions/int"}, - bar: {$ref: "defs.json#/definitions/str"}, - }, -} - -const defsSchema = { - $id: "http://example.com/schemas/defs.json", - definitions: { - int: {type: "integer"}, - str: {type: "string"}, - }, -} -``` - -Now to compile your schema you can either pass all schemas to Ajv instance: - -```javascript -const ajv = new Ajv({schemas: [schema, defsSchema]}) -const validate = ajv.getSchema("http://example.com/schemas/schema.json") -``` - -or use `addSchema` method: - -```javascript -const ajv = new Ajv() -const validate = ajv.addSchema(defsSchema).compile(schema) -``` - -See [Options](./api.md#options) and [addSchema](./api.md#add-schema) method. - -::: tip Please note -- `$ref` is resolved as the uri-reference using schema \$id as the base URI (see the example). -- References can be recursive (and mutually recursive) to implement the schemas for different data structures (such as linked lists, trees, graphs, etc.). -- You don't have to host your schema files at the URIs that you use as schema \$id. These URIs are only used to identify the schemas, and according to JSON Schema specification validators should not expect to be able to download the schemas from these URIs. -- The actual location of the schema file in the file system is not used. -- You can pass the identifier of the schema as the second parameter of `addSchema` method or as a property name in `schemas` option. This identifier can be used instead of (or in addition to) schema \$id. -- You cannot have the same \$id (or the schema identifier) used for more than one schema - the exception will be thrown. -- You can implement dynamic resolution of the referenced schemas using `compileAsync` method. In this way you can store schemas in any system (files, web, database, etc.) and reference them without explicitly adding to Ajv instance. See [Asynchronous schema compilation](./validation.md#asynchronous-schema-compilation). -::: - -### Extending recursive schemas - -While statically defined `$ref` keyword allows to split schemas to multiple files, it is difficult to extend recursive schemas - the recursive reference(s) in the original schema points to the original schema, and not to the extended one. So in JSON Schema draft-07 the only available solution to extend the recursive schema was to redefine all sections of the original schema that have recursion. - -It was particularly repetitive when extending meta-schema, as it has many recursive references, but even in a schema with a single recursive reference extending it was very verbose. - -JSON Schema draft-2019-09 and the upcoming draft defined the mechanism for dynamic recursion using keywords `$recursiveRef`/`$recursiveAnchor` (draft-2019-09) or `$dynamicRef`/`$dynamicAnchor` (the next JSON Schema draft) that is somewhat similar to "open recursion" in functional programming. - -Consider this recursive schema with static recursion: - -```javascript -const treeSchema = { - $id: "https://example.com/tree", - type: "object", - required: ["data"], - properties: { - data: true, - children: { - type: "array", - items: {$ref: "#"}, - }, - }, -} -``` - -The only way to extend this schema to prohibit additional properties is by adding `additionalProperties` keyword right in the schema - this approach can be impossible if you do not control the source of the original schema. Ajv also provided the additional keywords in [ajv-merge-patch](https://github.com/ajv-validator/ajv-merge-patch) package to extend schemas by treating them as plain JSON data. While this approach may work for you, it is non-standard and therefore not portable. - -The new keywords for dynamic recursive references allow extending this schema without modifying it: - -```javascript -const treeSchema = { - $id: "https://example.com/tree", - $recursiveAnchor: true, - type: "object", - required: ["data"], - properties: { - data: true, - children: { - type: "array", - items: {$recursiveRef: "#"}, - }, - }, -} - -const strictTreeSchema = { - $id: "https://example.com/strict-tree", - $recursiveAnchor: true, - $ref: "tree", - unevaluatedProperties: false, -} - -import Ajv2019 from "ajv/dist/2019" -// const Ajv2019 = require("ajv/dist/2019").default -const ajv = new Ajv2019({ - schemas: [treeSchema, strictTreeSchema], -}) -const validate = ajv.getSchema("https://example.com/strict-tree") -``` - -See [dynamic-refs](../spec/dynamic-ref.spec.ts) test for the example using `$dynamicAnchor`/`$dynamicRef`. - -At the moment Ajv implements the spec for dynamic recursive references with these limitations: - -- `$recursiveAnchor`/`$dynamicAnchor` can only be used in the schema root. -- `$recursiveRef`/`$dynamicRef` can only be hash fragments, without URI. - -Ajv also does not support dynamic references in [asynchronous schemas](#asynchronous-validation) (Ajv extension) - it is assumed that the referenced schema is synchronous, and there is no validation-time check for it. - -### $data reference - -With `$data` option you can use values from the validated data as the values for the schema keywords. See [proposal](https://github.com/json-schema-org/json-schema-spec/issues/51) for more information about how it works. - -`$data` reference is supported in the keywords: const, enum, format, maximum/minimum, exclusiveMaximum / exclusiveMinimum, maxLength / minLength, maxItems / minItems, maxProperties / minProperties, formatMaximum / formatMinimum, formatExclusiveMaximum / formatExclusiveMinimum, multipleOf, pattern, required, uniqueItems. - -The value of "$data" should be a [JSON-pointer](https://datatracker.ietf.org/doc/rfc6901/) to the data (the root is always the top level data object, even if the $data reference is inside a referenced subschema) or a [relative JSON-pointer](http://tools.ietf.org/html/draft-luff-relative-json-pointer-00) (it is relative to the current point in data; if the \$data reference is inside a referenced subschema it cannot point to the data outside of the root level for this subschema). - -Examples. - -This schema requires that the value in property `smaller` is less or equal than the value in the property larger: - -```javascript -const ajv = new Ajv({$data: true}) - -const schema = { - properties: { - smaller: { - type: "number", - maximum: {$data: "1/larger"}, - }, - larger: {type: "number"}, - }, -} - -const validData = { - smaller: 5, - larger: 7, -} - -ajv.validate(schema, validData) // true -``` - -This schema requires that the properties have the same format as their field names: - -```javascript -const schema = { - additionalProperties: { - type: "string", - format: {$data: "0#"}, - }, -} - -const validData = { - "date-time": "1963-06-19T08:30:06.283185Z", - email: "joe.bloggs@example.com", -} -``` - -`$data` reference is resolved safely - it won't throw even if some property is undefined. If `$data` resolves to `undefined` the validation succeeds (with the exclusion of `const` keyword). If `$data` resolves to incorrect type (e.g. not "number" for maximum keyword) the validation fails. - -### $merge and $patch keywords - -With the package [ajv-merge-patch](https://github.com/ajv-validator/ajv-merge-patch) you can use the keywords `$merge` and `$patch` that allow extending JSON Schemas with patches using formats [JSON Merge Patch (RFC 7396)](https://datatracker.ietf.org/doc/rfc7396/) and [JSON Patch (RFC 6902)](https://datatracker.ietf.org/doc/rfc6902/). - -To add keywords `$merge` and `$patch` to Ajv instance use this code: - -```javascript -require("ajv-merge-patch")(ajv) -``` - -Examples. - -Using `$merge`: - -```javascript -{ - $merge: { - source: { - type: "object", - properties: {p: {type: "string"}}, - additionalProperties: false - }, - with: { - properties: {q: {type: "number"}} - } - } -} -``` - -Using `$patch`: - -```javascript -{ - $patch: { - source: { - type: "object", - properties: {p: {type: "string"}}, - additionalProperties: false - }, - with: [{op: "add", path: "/properties/q", value: {type: "number"}}] - } -} -``` - -The schemas above are equivalent to this schema: - -```javascript -{ - type: "object", - properties: { - p: {type: "string"}, - q: {type: "number"} - }, - additionalProperties: false -} -``` - -The properties `source` and `with` in the keywords `$merge` and `$patch` can use absolute or relative `$ref` to point to other schemas previously added to the Ajv instance or to the fragments of the current schema. - -See the package [ajv-merge-patch](https://github.com/ajv-validator/ajv-merge-patch) for more information. - ## User-defined keywords The advantages of defining keywords are: @@ -420,32 +187,6 @@ Several keywords (typeof, instanceof, range and propertyNames) are defined in [a See [User-defined keywords](./keywords.md) for more details. -## Asynchronous schema compilation - -During asynchronous compilation remote references are loaded using supplied function. See `compileAsync` [method](./api.md#api-compileAsync) and `loadSchema` [option](./api.md#options). - -Example: - -```javascript -const ajv = new Ajv({loadSchema: loadSchema}) - -ajv.compileAsync(schema).then(function (validate) { - const valid = validate(data) - // ... -}) - -function loadSchema(uri) { - return request.json(uri).then(function (res) { - if (res.statusCode >= 400) throw new Error("Loading error: " + res.statusCode) - return res.body - }) -} -``` - -::: warning Please note -[Option](./api.md#options) `missingRefs` should NOT be set to `"ignore"` or `"fail"` for asynchronous compilation to work. -::: - ## Asynchronous validation Example in Node.js REPL: https://runkit.com/esp/ajv-asynchronous-validation diff --git a/scripts/publish-site b/scripts/publish-site new file mode 100755 index 000000000..51d9a2736 --- /dev/null +++ b/scripts/publish-site @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +set -ex + +echo "About to publish $GITHUB_REF to gh-pages..." + +cp CODE_OF_CONDUCT.md docs +cp CONTRIBUTING.md docs +cp LICENSE docs From a638a47624d05b8c56d1038867b85595e79ec7ab Mon Sep 17 00:00:00 2001 From: Erik Brinkman Date: Sun, 21 Feb 2021 19:23:38 -0500 Subject: [PATCH 06/25] fix null bug --- lib/types/jtd-schema.ts | 18 ++++++++---------- spec/types/jtd-schema.spec.ts | 30 ++++++++++++++---------------- 2 files changed, 22 insertions(+), 26 deletions(-) diff --git a/lib/types/jtd-schema.ts b/lib/types/jtd-schema.ts index aecf5b3b0..14dd5a83a 100644 --- a/lib/types/jtd-schema.ts +++ b/lib/types/jtd-schema.ts @@ -46,14 +46,20 @@ type StringType = "string" | "timestamp" /** actual schema */ export type JTDSchemaType = Record> = ( | // refs - where null wasn't specified, must match exactly - ({[K in keyof D]: [T] extends [D[K]] ? {ref: K} : never}[keyof D] & {nullable?: false}) + (null extends EnumString + ? never + : {[K in keyof D]: [T] extends [D[K]] ? {ref: K} : never}[keyof D] & {nullable?: false}) // nulled refs - if ref is nullable and nullable is specified, then it can // match either null or non-null definitions - | (null extends T + | (null extends EnumString + ? never + : null extends T ? { [K in keyof D]: [Exclude] extends [Exclude] ? {ref: K} : never }[keyof D] & {nullable: true} : never) + // empty - empty schemas also treat nullable differently in that it's now optional + | (unknown extends T ? {nullable?: true} : never) // all other types | (( | // numbers - only accepts the type number @@ -129,14 +135,6 @@ export type JTDSchemaType = Record] : never) - // empty schema - // NOTE there should only be one type that extends Record so unions - // shouldn't be a worry - | (T extends Record ? unknown : never) - // null - // NOTE we have to check this too because null as an exclusive type also - // qualifies for the empty schema - | (true extends TypeEquality ? unknown : never) ) & (null extends T ? { diff --git a/spec/types/jtd-schema.spec.ts b/spec/types/jtd-schema.spec.ts index a6f3c3dc3..daa82bba5 100644 --- a/spec/types/jtd-schema.spec.ts +++ b/spec/types/jtd-schema.spec.ts @@ -52,8 +52,10 @@ describe("JTDSchemaType", () => { // @ts-expect-error const nums: JTDSchemaType<1 | 2 | 3> = {type: "int32"} const numNull: JTDSchemaType = {type: "int32", nullable: true} + // @ts-expect-error + const numNotNull: JTDSchemaType = {type: "float32"} - void [numf, numi, numl, nums, numNull] + void [numf, numi, numl, nums, numNull, numNotNull] }) it("should typecheck boolean schemas", () => { @@ -258,14 +260,18 @@ describe("JTDSchemaType", () => { }) it("should typecheck empty schemas", () => { - const empty: JTDSchemaType> = {} + const empty: JTDSchemaType = {} + // unknown can be null + const emptyUnknown: JTDSchemaType = {nullable: true} // can only use empty for empty and null // @ts-expect-error const emptyButFull: JTDSchemaType<{a: string}> = {} - const emptyNull: JTDSchemaType = {nullable: true} - const emptyMeta: JTDSchemaType> = {metadata: {}} + const emptyMeta: JTDSchemaType = {metadata: {}} - void [empty, emptyButFull, emptyNull, emptyMeta] + // constant null not representable + const emptyNull: TypeEquality, never> = true + + void [empty, emptyUnknown, emptyButFull, emptyMeta, emptyNull] }) it("should typecheck ref schemas", () => { @@ -311,17 +317,9 @@ describe("JTDSchemaType", () => { it("should typecheck metadata schemas", () => { const meta: JTDSchemaType = {type: "float32", metadata: {key: "val"}} - const emptyMeta: JTDSchemaType> = {metadata: {key: "val"}} - const nullMeta: JTDSchemaType = {nullable: true, metadata: {key: "val"}} - - void [meta, emptyMeta, nullMeta] - }) - - it("should typecheck nullable schemas", () => { - const isNull: JTDSchemaType = {nullable: true} - // @ts-expect-error - const numNotNull: JTDSchemaType = {type: "float32"} + const emptyMeta: JTDSchemaType = {metadata: {key: "val"}} + const unknownMeta: JTDSchemaType = {nullable: true, metadata: {key: "val"}} - void [isNull, numNotNull] + void [meta, emptyMeta, unknownMeta] }) }) From 7347260f6fa977a96a6dfc5b9c3bf3ded122c294 Mon Sep 17 00:00:00 2001 From: Erik Brinkman Date: Mon, 22 Feb 2021 15:34:26 -0500 Subject: [PATCH 07/25] allow nullable: false for unknown --- lib/types/jtd-schema.ts | 4 ++-- spec/types/jtd-schema.spec.ts | 16 ++++------------ 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/lib/types/jtd-schema.ts b/lib/types/jtd-schema.ts index 14dd5a83a..1dc4e3fb9 100644 --- a/lib/types/jtd-schema.ts +++ b/lib/types/jtd-schema.ts @@ -58,8 +58,8 @@ export type JTDSchemaType = Record] extends [Exclude] ? {ref: K} : never }[keyof D] & {nullable: true} : never) - // empty - empty schemas also treat nullable differently in that it's now optional - | (unknown extends T ? {nullable?: true} : never) + // empty - empty schemas also treat nullable differently in that it's now fully ignored + | (unknown extends T ? {nullable?: boolean} : never) // all other types | (( | // numbers - only accepts the type number diff --git a/spec/types/jtd-schema.spec.ts b/spec/types/jtd-schema.spec.ts index daa82bba5..2b95630fa 100644 --- a/spec/types/jtd-schema.spec.ts +++ b/spec/types/jtd-schema.spec.ts @@ -177,17 +177,7 @@ describe("JTDSchemaType", () => { nullable: true, } - // can't use properties for any object (e.g. keyof = never) - const noProperties: TypeEquality, never> = true - - void [ - properties, - optionalProperties, - mixedProperties, - fewerProperties, - propertiesNull, - noProperties, - ] + void [properties, optionalProperties, mixedProperties, fewerProperties, propertiesNull] }) it("should typecheck discriminator schemas", () => { @@ -263,6 +253,8 @@ describe("JTDSchemaType", () => { const empty: JTDSchemaType = {} // unknown can be null const emptyUnknown: JTDSchemaType = {nullable: true} + // somewhat unintuitively, it can still have nullable: false even though it can be null + const falseUnknown: JTDSchemaType = {nullable: false} // can only use empty for empty and null // @ts-expect-error const emptyButFull: JTDSchemaType<{a: string}> = {} @@ -271,7 +263,7 @@ describe("JTDSchemaType", () => { // constant null not representable const emptyNull: TypeEquality, never> = true - void [empty, emptyUnknown, emptyButFull, emptyMeta, emptyNull] + void [empty, emptyUnknown, falseUnknown, emptyButFull, emptyMeta, emptyNull] }) it("should typecheck ref schemas", () => { From 9dab628d4364cd1cb2af1ab7c3b7d71459f65d28 Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Fri, 5 Mar 2021 22:53:32 +0000 Subject: [PATCH 08/25] site: improve guide --- docs/.vuepress/config.js | 3 +- docs/api.md | 54 +++-- ...odular-schemas.md => combining-schemas.md} | 2 +- docs/guide/managing-schemas.md | 220 +++++++++++++++++- docs/guide/schema-language.md | 6 +- docs/guide/user-keywords.md | 58 +++++ docs/json-schema.md | 16 ++ docs/validation.md | 65 ------ 8 files changed, 323 insertions(+), 101 deletions(-) rename docs/guide/{modular-schemas.md => combining-schemas.md} (99%) create mode 100644 docs/guide/user-keywords.md diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index 1cf1a3379..b745ae4ae 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -41,7 +41,8 @@ module.exports = { "/guide/typescript", "/guide/schema-language", "/guide/managing-schemas", - "/guide/modular-schemas", + "/guide/combining-schemas", + "/guide/user-keywords", "/guide/environments", ] }, diff --git a/docs/api.md b/docs/api.md index a6cf8da99..8eb493700 100644 --- a/docs/api.md +++ b/docs/api.md @@ -6,7 +6,7 @@ ## Ajv constructor and methods -#### new Ajv(options: object) +### `new Ajv(options: object)` Create Ajv instance: @@ -16,7 +16,7 @@ const ajv = new Ajv() See [Options](#options) -#### ajv.compile(schema: object): (data: any) =\> boolean | Promise\ +### `ajv.compile(schema: object): (data: any) => boolean | Promise` Generate validating function and cache the compiled schema for future use. @@ -50,7 +50,9 @@ if (validate(data)) { See more advanced example in [the test](../spec/types/json-schema.spec.ts). -#### ajv.compileSerializer(schema: object): (data: any) =\> string + + +### `ajv.compileSerializer(schema: object): (data: any) => string` Generate serializing function based on the [JTD schema](./json-type-definition.md) (caches the schema) - only in JTD instance of Ajv (see example below). @@ -88,7 +90,9 @@ const serializeMyData = ajv.compileSerializer(mySchema) Compiled serializers do NOT validate passed data, it is assumed that the data is valid according to the schema. In the future there may be an option added that would make serializers also validate the data. ::: -#### ajv.compileParser(schema: object): (json: string) =\> any + + +### `ajv.compileParser(schema: object): (json: string) => any` Generate parsing function based on the [JTD schema](./json-type-definition.md) (caches the schema) - only in JTD instance of Ajv (see example below). @@ -117,7 +121,9 @@ Generated parsers is a NEW Ajv functionality (as of March 2021), there can be so \* As long as empty schema `{}` is not used - there is a possibility to improve performance in this case. Also, the performance of parsing `discriminator` schemas depends on the position of discriminator tag in the schema - the best parsing performance will be achieved if the tag is the first property - this is how compiled JTD serializers generate JSON in case of discriminator schemas. -#### ajv.compileAsync(schema: object, meta?: boolean): Promise\ + + +### `ajv.compileAsync(schema: object, meta?: boolean): Promise` Asynchronous version of `compile` method that loads missing remote schemas using asynchronous function in `options.loadSchema`. This function returns a Promise that resolves to a validation function. An optional callback passed to `compileAsync` will be called with 2 parameters: error (or null) and validating function. The returned promise will reject (and the callback will be called with an error) when: @@ -133,7 +139,7 @@ Similarly to `compile`, it can return type guard in typescript. See example in [Asynchronous compilation](./validation.md#asynchronous-schema-compilation). -#### ajv.validate(schemaOrRef: object | string, data: any): boolean +### `ajv.validate(schemaOrRef: object | string, data: any): boolean` Validate data using passed schema (it will be compiled and cached). @@ -149,7 +155,9 @@ Every time this method is called the errors are overwritten so you need to copy If the schema is asynchronous (has `$async` keyword on the top level) this method returns a Promise. See [Asynchronous validation](./validation.md#asynchronous-validation). -#### ajv.addSchema(schema: object | object[], key?: string): Ajv + + +### `ajv.addSchema(schema: object | object[], key?: string): Ajv` Add schema(s) to validator instance. This method does not compile schemas (but it still validates them). Because of that dependencies can be added in any order and circular dependencies are supported. It also prevents unnecessary compilation of schemas that are containers for other schemas but not used as a whole. @@ -172,13 +180,15 @@ const validate = new Ajv().addSchema(schema).addFormat(name, regex).getSchema(ur ::: -#### ajv.addMetaSchema(schema: object | object[], key?: string): Ajv +### `ajv.addMetaSchema(schema: object | object[], key?: string): Ajv` Adds meta schema(s) that can be used to validate other schemas. That function should be used instead of `addSchema` because there may be instance options that would compile a meta schema incorrectly (at the moment it is `removeAdditional` option). There is no need to explicitly add draft-07 meta schema (http://json-schema.org/draft-07/schema) - it is added by default, unless option `meta` is set to `false`. You only need to use it if you have a changed meta-schema that you want to use to validate your schemas. See `validateSchema`. -#### ajv.validateSchema(schema: object): boolean + + +### `ajv.validateSchema(schema: object): boolean` Validates schema. This method should be used to validate schemas rather than `validate` due to the inconsistency of `uri` format in JSON Schema standard. @@ -190,11 +200,11 @@ If schema has `$schema` property, then the schema with this id (that should be p Errors will be available at `ajv.errors`. -#### ajv.getSchema(key: string): undefined | ((data: any) =\> boolean | Promise\) +### `ajv.getSchema(key: string): undefined | ((data: any) => boolean | Promise)` Retrieve compiled schema previously added with `addSchema` by the key passed to `addSchema` or by its full reference (id). The returned validating function has `schema` property with the reference to the original schema. -#### ajv.removeSchema(schemaOrRef: object | string | RegExp): Ajv +### `ajv.removeSchema(schemaOrRef: object | string | RegExp): Ajv` Remove added/cached schema. Even if schema is referenced by other schemas it can be safely removed as dependent schemas have local references. @@ -207,7 +217,9 @@ Schema can be removed using: If no parameter is passed all schemas but meta-schemas will be removed and the cache will be cleared. -#### ajv.addFormat(name: string, format: Format): Ajv + + +### `ajv.addFormat(name: string, format: Format): Ajv` ```typescript type Format = @@ -238,7 +250,9 @@ interface FormatDefinition { // actual type definition is more precise - see typ Formats can be also added via `formats` option. -#### ajv.addKeyword(definition: object):s Ajv + + +### `ajv.addKeyword(definition: object): Ajv` Add validation keyword to Ajv instance. @@ -298,11 +312,11 @@ If the keyword is validating data type that is different from the type(s) in its See [User defined keywords](./keywords.md) for more details. -#### ajv.getKeyword(keyword: string): object | boolean +### `ajv.getKeyword(keyword: string): object | boolean` Returns keyword definition, `false` if the keyword is unknown. -#### ajv.removeKeyword(keyword: string): Ajv +### `ajv.removeKeyword(keyword: string): Ajv` Removes added or pre-defined keyword so you can redefine them. @@ -312,7 +326,7 @@ While this method can be used to extend pre-defined keywords, it can also be use The schemas compiled before the keyword is removed will continue to work without changes. To recompile schemas use `removeSchema` method and compile them again. ::: -#### ajv.errorsText(errors?: object[], options?: object): string +### `ajv.errorsText(errors?: object[], options?: object): string` Returns the text with all errors in a String. @@ -372,7 +386,7 @@ const defaultOptions = { \* these options are not supported with JSON Type Definition schemas -#### Strict mode options (NEW in v7) +### Strict mode options (NEW in v7) - _strict_: By default Ajv executes in strict mode, that is designed to prevent any unexpected behaviours or silently ignored mistakes in schemas (see [Strict Mode](./strict-mode.md) for more details). It does not change any validation results, but it makes some schemas invalid that would be otherwise valid according to JSON Schema specification. Option values: - `true` (default) - use strict mode and throw an exception when any strict mode restriction is violated. @@ -396,7 +410,7 @@ const defaultOptions = { - `true` (default) - validate formats (see [Formats](./validation.md#formats)). In [strict mode](./strict-mode.md) unknown formats will throw exception during schema compilation (and fail validation in case format keyword value is [\$data reference](./validation.md#data-reference)). - `false` - do not validate any format keywords (TODO they will still collect annotations once supported). -#### Validation and reporting options +### Validation and reporting options - _\$data_: support [\$data references](./validation.md#data-reference). Draft 6 meta-schema that is added by default will be extended to allow them. If you want to use another meta-schema you need to use $dataMetaSchema method to add support for $data reference. See [API](#ajv-constructor-and-methods). - _allErrors_: check all rules collecting all errors. Default is to return after the first error. @@ -413,7 +427,7 @@ const defaultOptions = { - `false` - logging is disabled. - _loadSchema_: asynchronous function that will be used to load remote schemas when `compileAsync` [method](#api-compileAsync) is used and some reference is missing (option `missingRefs` should NOT be 'fail' or 'ignore'). This function should accept remote schema uri as a parameter and return a Promise that resolves to a schema. See example in [Asynchronous compilation](./validation.md#asynchronous-schema-compilation). -#### Options to modify validated data +### Options to modify validated data - _removeAdditional_: remove additional properties - see example in [Removing additional properties](./validation.md#removing-additional-properties). This option is not used if schema is added with `addMetaSchema` method. Option values: - `false` (default) - not to remove additional properties @@ -429,7 +443,7 @@ const defaultOptions = { - `true` - coerce scalar data types. - `"array"` - in addition to coercions between scalar types, coerce scalar data to an array with one element and vice versa (as required by the schema). -#### Advanced options +### Advanced options - _meta_: add [meta-schema](http://json-schema.org/documentation.html) so it can be used by other schemas (true by default). If an object is passed, it will be used as the default meta-schema for schemas that have no `$schema` keyword. This default meta-schema MUST have `$schema` keyword. - _validateSchema_: validate added/compiled schemas against meta-schema (true by default). `$schema` property in the schema can be http://json-schema.org/draft-07/schema or absent (draft-07 meta-schema will be used) or can be a reference to the schema previously added with `addMetaSchema` method. Option values: diff --git a/docs/guide/modular-schemas.md b/docs/guide/combining-schemas.md similarity index 99% rename from docs/guide/modular-schemas.md rename to docs/guide/combining-schemas.md index d6b0e3c97..d73733e39 100644 --- a/docs/guide/modular-schemas.md +++ b/docs/guide/combining-schemas.md @@ -1,4 +1,4 @@ -# Modular schemas +# Combining schemas ## Combining schemas with $ref diff --git a/docs/guide/managing-schemas.md b/docs/guide/managing-schemas.md index 16197ae31..4498a3dff 100644 --- a/docs/guide/managing-schemas.md +++ b/docs/guide/managing-schemas.md @@ -13,27 +13,217 @@ Transition from template-based code generation in Ajv v6 to the tree-based in v7 - smaller bundle size - more maintainable code -These improvements cost slower schema compilation, and increased chance of re-compilation in case you pass a different schema object (see [#1413](https://github.com/ajv-validator/ajv/issues/1413)), so it is very important to [manage schemas correctly](./managing-schemas), so they are only compiled once, or use standalone validation code. +These improvements cost slower schema compilation, and increased chance of re-compilation in case you pass a different schema object (see [#1413](https://github.com/ajv-validator/ajv/issues/1413)), so it is very important to manage schemas correctly, so they are only compiled once. There are several approaches to manage compiled schemas. ## Standalone validation code +The motivation to pre-compile schemas: +- faster startup times +- lower memory footprint/bundle size +- compatible with strict content security policies +- almost no risk to compile schema more than once +- better for short-lived environments + +See [Standalone validation code](../standalone) for the details. + +There are scenarios when it can be not possible or difficult: +- dynamic or user-provided schemas - while you can do caching, it can be either difficult to implement or inefficient. +- user-defined keywords that use closures that are difficult to serialize as code. + ## Compiling during initialization +The simplest approach is to compile all your schemas when the application starts, outside of the code that handles requests. It can be done simply in the module scope: + + + +```javascript +const Ajv = require("ajv").defalt +const schema_user = require("./schema_user.json") +const ajv = new Ajv() +const validate_user = ajv.compile(schema_user) + + + + + +// this is just some abstract API framework +app.post("/user", async (cxt) => { + if (validate_user(cxt.body)) { + // create user + } else { + // report error + cxt.status(400) + } +}) +``` + + + +```javascript +import Ajv from "ajv" +import * as schema_user from "./schema_user.json" +const ajv = new Ajv() +const validate_user = ajv.compile(schema_user) + +interface User { + username: string +} + +// this is just some abstract API framework +app.post("/user", async (cxt) => { + if (validate_user(cxt.body)) { + // create user + } else { + // report error + cxt.status(400) + } +}) +``` + + + +::: warning Please note +It recommended to use a single Ajv instance for the whole application, so if you use validation in more than one module, you should: +- require Ajv in a separate module responsible for validation +- compile all validators there +- export them to be used in multiple modules of your application +::: + ## Using Ajv instance cache -### Cache key: schema vs $id +Another, more effective approach, is to use Ajv instance cache to have all compiled validators available anywhere in your application from a single import. + +In this case you would have a separate module where you instantiate Ajv and use this instance in your application. + +You can load all schemas and add them to Ajv instance in a single `validation` module: + + + +```javascript +const Ajv = require("ajv").defalt +const schema_user = require("./schema_user.json") +const schema_document = require("./schema_document.json") +const ajv = exports.ajv = new Ajv() +ajv.addSchema(schema_user, "user") +ajv.addSchema(schema_document, "document") +``` + + + +```typescript +import Ajv from "ajv" +import * as schema_user from "./schema_user.json" +import * as schema_document from "./schema_document.json" +export const ajv = new Ajv() +ajv.addSchema(schema_user, "user") +ajv.addSchema(schema_document, "document") +``` + + + +And then you can import Ajv instance and access any schema in any application module, for example `user` module: + + + +```javascript +const {ajv} = require("./validation") + + + + + +// this is just some abstract API framework +app.post("/user", async (cxt) => { + const validate = ajv.getSchema("user") + if (validate(cxt.body)) { + // create user + } else { + // report error + cxt.status(400) + } +}) +``` + + + +```javascript +import ajv from "./validation" + +interface User { + username: string +} + +// this is just some abstract API framework +app.post("/user", async (cxt) => { + const validate = ajv.getSchema("user") + if (validate(cxt.body)) { + // create user + } else { + // report error + cxt.status(400) + } +}) +``` + + + +::: tip Please note +In the example above, schema compilation happens only once, on the first API call, not at the application start-up time. It means that the application would start a bit faster, but the first API call would be a bit slower. If this is undesirable, you could, for example, call `getSchema` for all added schemas after they are added, then when `getSchema` is called inside route handler it would simply get compiled validation function from the instance cache. +::: + +### Cache key: schema vs key vs $id -### Pre-adding all schemas +In the example above, the key passed to the `addSchema` method was used to retrieve schemas from the cache. Other options are: +- use schema root $id attribute. While it usually looks like URI, it does not mean Ajv downloads it from this URI - this is simply $id used to identify and access the schema. You can though configure Ajv to download schemas on demand - see [Asynchronous schema loading](#asynchronous-schema-loading) +- use schema object itself as a key to the cache (it is possible, because Ajv uses Map). This approach is not recommended, because it would only work if you pass the same instance of the schema object that was passed to `addSchema` method - it is easy to make a mistake that would result in schema being compiled every time it is used. -### Adding schemas on-demand +### Pre-adding all schemas vs adding on demand + +In the example above all schemas were added in advance. It is also possible, to add schemas as they are used - it can be helpful if there is many schemas. In this case, you need to check first whether the schema is already added by calling `getSchema` method - it would return `undefined` if not: + +```javascript +const schema_user = require("./schema_user.json") +let validate = ajv.getSchema("user") +if (!validate) { + ajv.addSchema(schema_user, "user") + validate = ajv.getSchema("user") +} +``` + +If your schema has `$id` attribute, for example: + + + +```json +{ + "$id": "https://example.com/user.json", + "type": "object", + "properties": { + "username": {"type": "string"} + }, + required: ["username"] +} +``` + + + +then the above logic can be simpler: + +```javascript +const schema_user = require("./schema_user.json") +const validate = ajv.getSchema("https://example.com/user.json") + || ajv.compile(schema_user) +``` + +The above is possible because when the schema has `$id` attribute `compile` method both compiles the schema (returning the validation function) and adds it to the Ajv instance cache at the same time. ### Asynchronous schema loading -TODO motivation +There are cases when you need to have a large collection of schemas stored in some database or on the remote server. In this case you are likely to use schema `$id` as some resource identifier to retrieve it - either network URI or database ID. -During asynchronous compilation remote references are loaded using supplied function. See `compileAsync` [method](./api.md#api-compileAsync) and `loadSchema` [option](./api.md#options). +You can use `compileAsync` [method](./api.md#api-compileAsync) to asynchronously load the schemas as they are compiled, loading the schemas that are referenced from compiled schemas on demand. Ajv itself does not do any IO operations, it uses the function you supply via `loadSchema` [option](./api.md#options) to load schema from the passed ID. This function should return `Promise` that resolves to the schema (you can use async function, as in the example). Example: @@ -45,11 +235,10 @@ ajv.compileAsync(schema).then(function (validate) { // ... }) -function loadSchema(uri) { - return request.json(uri).then(function (res) { - if (res.statusCode >= 400) throw new Error("Loading error: " + res.statusCode) - return res.body - }) +async function loadSchema(uri) { + const res = await request.json(uri) + if (res.statusCode >= 400) throw new Error("Loading error: " + res.statusCode) + return res.body } ``` @@ -57,4 +246,11 @@ function loadSchema(uri) { [Option](./api.md#options) `missingRefs` should NOT be set to `"ignore"` or `"fail"` for asynchronous compilation to work. ::: -## Caching in your applications +## Caching schemas in your code + +You can maintain cache of compiled schemas in your application independently from Ajv. It can be helpful in cases when you have multiple Ajv instances because, for example: +- you need to compile different schemas with different options +- you use both JSON Schema and JSON Type Definition schemas in one application +- you have $id conflicts between different third party schemas you do not control + +Whatever approach you use, you need to ensure that each schema is compiled only once. diff --git a/docs/guide/schema-language.md b/docs/guide/schema-language.md index 94d69c602..c79df328d 100644 --- a/docs/guide/schema-language.md +++ b/docs/guide/schema-language.md @@ -2,13 +2,15 @@ [[toc]] +## Comparison + Both [JSON Schema](../json-schema.md) and [JSON Type Definition](../json-type-definition.md) are cross-platform specifications with implementations in multiple programming languages that define the shape of your JSON data. You can see the difference between the two specifications in [Getting started](./getting-started) section examples. This section compares their pros/cons to help decide which specification fits your application better. -## JSON Schema +### JSON Schema - Pros - Wide specification adoption. @@ -32,7 +34,7 @@ This section compares their pros/cons to help decide which specification fits yo See [JSON Schema](../json-schema.md) for more information and the list of defined keywords. -## JSON Type Definition +### JSON Type Definition - Pros: - Aligned with type systems of many languages - can be used to generate type definitions and efficient parsers and serializers to/from these types. diff --git a/docs/guide/user-keywords.md b/docs/guide/user-keywords.md new file mode 100644 index 000000000..90557fab0 --- /dev/null +++ b/docs/guide/user-keywords.md @@ -0,0 +1,58 @@ +# User-defined keywords + +You can extend keyword available in Ajv by defining your own keywords. + +The advantages of defining keywords are: + +- allow creating validation scenarios that cannot be expressed using pre-defined keywords +- simplify your schemas +- help bringing a bigger part of the validation logic to your schemas +- make your schemas more expressive, less verbose and closer to your application domain +- implement data processors that modify your data (`modifying` option MUST be used in keyword definition) and/or create side effects while the data is being validated + +If a keyword is used only for side-effects and its validation result is pre-defined, use option `valid: true/false` in keyword definition to simplify both generated code (no error handling in case of `valid: true`) and your keyword functions (no need to return any validation result). + +::: warning Please note +When extending JSON Schema standard with additional keywords, you have several potential concerns to be aware of: +- portability of your schemas - they would only work with JavaScript or TypeScript applications where you can use Ajv. +- additional documentation required to maintain your schemas. +::: + +::: danger Please note +While it is possible to define additional keywords for JSON Type Definition schemas (these keywords can only be used in `metadata` member of the schema), it is strongly recommended not to do it - JTD is specifically designed for cross-platform APIs. +::: + +You can define keywords with [addKeyword](./api.md#api-addkeyword) method. Keywords are defined on the `ajv` instance level - new instances will not have previously defined keywords. + +Ajv allows defining keywords with: + +- code generation function (used by all pre-defined keywords) +- validation function +- compilation function +- macro function + +Example. `range` and `exclusiveRange` keywords using compiled schema: + +```javascript +ajv.addKeyword({ + keyword: "range", + type: "number", + schemaType: "array", + implements: "exclusiveRange", + compile: ([min, max], parentSchema) => + parentSchema.exclusiveRange === true + ? (data) => data > min && data < max + : (data) => data >= min && data <= max, +}) + +const schema = {range: [2, 4], exclusiveRange: true} +const validate = ajv.compile(schema) +console.log(validate(2.01)) // true +console.log(validate(3.99)) // true +console.log(validate(2)) // false +console.log(validate(4)) // false +``` + +Several keywords (typeof, instanceof, range and propertyNames) are defined in [ajv-keywords](https://github.com/ajv-validator/ajv-keywords) package - they can be used for your schemas and as a starting point for your own keywords. + +See [User-defined keywords](./keywords.md) reference for more details. diff --git a/docs/json-schema.md b/docs/json-schema.md index db3037223..4b98ff2ad 100644 --- a/docs/json-schema.md +++ b/docs/json-schema.md @@ -851,3 +851,19 @@ If the data is invalid against the sub-schema in `if` keyword, then the validati - `2000` (>1000) - `11`, `57`, `123` (any integer with more than one non-zero digit) - non-integers + +## Metadata keywords + +JSON Schema specification defines several metadata keywords that describe the schema itself but do not perform any validation. + +- `title` and `description`: information about the data represented by that schema +- `$comment`: information for developers. With option `$comment` Ajv logs or passes the comment string to the user-supplied function. See [Options](./api.md#options). +- `default`: a default value of the data instance, see [Assigning defaults](#assigning-defaults). +- `examples`: an array of data instances. Ajv does not check the validity of these instances against the schema. +- `readOnly` and `writeOnly`: marks data-instance as read-only or write-only in relation to the source of the data (database, api, etc.). +- `contentEncoding`: [RFC 2045](https://tools.ietf.org/html/rfc2045#section-6.1), e.g., "base64". +- `contentMediaType`: [RFC 2046](https://datatracker.ietf.org/doc/rfc2046/), e.g., "image/png". + +::: warning Please note +Ajv does not implement validation of the keywords `examples`, `contentEncoding` and `contentMediaType` but it reserves them. If you want to create a plugin that implements any of them, it should remove these keywords from the instance. +::: diff --git a/docs/validation.md b/docs/validation.md index ce568b7cf..b27580751 100644 --- a/docs/validation.md +++ b/docs/validation.md @@ -75,22 +75,6 @@ Ajv supports all validation keywords from draft-07 of JSON Schema standard - see [ajv-keywords](https://github.com/ajv-validator/ajv-keywords) package provides additional validation keywords that can be used with Ajv. -### Metadata keywords - -JSON Schema specification defines several metadata keywords that describe the schema itself but do not perform any validation. - -- `title` and `description`: information about the data represented by that schema -- `$comment` (NEW in draft-07): information for developers. With option `$comment` Ajv logs or passes the comment string to the user-supplied function. See [Options](./api.md#options). -- `default`: a default value of the data instance, see [Assigning defaults](#assigning-defaults). -- `examples` (NEW in draft-06): an array of data instances. Ajv does not check the validity of these instances against the schema. -- `readOnly` and `writeOnly` (NEW in draft-07): marks data-instance as read-only or write-only in relation to the source of the data (database, api, etc.). -- `contentEncoding`: [RFC 2045](https://tools.ietf.org/html/rfc2045#section-6.1), e.g., "base64". -- `contentMediaType`: [RFC 2046](https://datatracker.ietf.org/doc/rfc2046/), e.g., "image/png". - -::: warning Please note -Ajv does not implement validation of the keywords `examples`, `contentEncoding` and `contentMediaType` but it reserves them. If you want to create a plugin that implements any of them, it should remove these keywords from the instance. -::: - ### Formats From version 7 Ajv does not include formats defined by JSON Schema specification - these and several other formats are provided by [ajv-formats](https://github.com/ajv-validator/ajv-formats) plugin. @@ -138,55 +122,6 @@ JSON Schema draft-07 also defines formats `iri`, `iri-reference`, `idn-hostname` You can add and replace any formats using [addFormat](./api.md#api-addformat) method. -## User-defined keywords - -The advantages of defining keywords are: - -- allow creating validation scenarios that cannot be expressed using pre-defined keywords -- simplify your schemas -- help bringing a bigger part of the validation logic to your schemas -- make your schemas more expressive, less verbose and closer to your application domain -- implement data processors that modify your data (`modifying` option MUST be used in keyword definition) and/or create side effects while the data is being validated - -If a keyword is used only for side-effects and its validation result is pre-defined, use option `valid: true/false` in keyword definition to simplify both generated code (no error handling in case of `valid: true`) and your keyword functions (no need to return any validation result). - -The concerns you have to be aware of when extending JSON Schema standard with additional keywords are the portability and understanding of your schemas. You will have to support these keywords on other platforms and to properly document them so that everybody can understand and use your schemas. - -You can define keywords with [addKeyword](./api.md#api-addkeyword) method. Keywords are defined on the `ajv` instance level - new instances will not have previously defined keywords. - -Ajv allows defining keywords with: - -- code generation function (used by all pre-defined keywords) -- validation function -- compilation function -- macro function - -Example. `range` and `exclusiveRange` keywords using compiled schema: - -```javascript -ajv.addKeyword({ - keyword: "range", - type: "number", - schemaType: "array", - implements: "exclusiveRange", - compile: ([min, max], parentSchema) => - parentSchema.exclusiveRange === true - ? (data) => data > min && data < max - : (data) => data >= min && data <= max, -}) - -const schema = {range: [2, 4], exclusiveRange: true} -const validate = ajv.compile(schema) -console.log(validate(2.01)) // true -console.log(validate(3.99)) // true -console.log(validate(2)) // false -console.log(validate(4)) // false -``` - -Several keywords (typeof, instanceof, range and propertyNames) are defined in [ajv-keywords](https://github.com/ajv-validator/ajv-keywords) package - they can be used for your schemas and as a starting point for your own keywords. - -See [User-defined keywords](./keywords.md) for more details. - ## Asynchronous validation Example in Node.js REPL: https://runkit.com/esp/ajv-asynchronous-validation From 0b1378654d703d9fa3e3a195f601e36db67f42e5 Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Sat, 6 Mar 2021 12:11:30 +0000 Subject: [PATCH 09/25] site: restructure validation.md and guide --- CONTRIBUTING.md | 2 +- README.md | 4 +- docs/.vuepress/config.js | 75 ++++-- docs/OLD_README.md | 6 +- docs/api.md | 200 ++-------------- docs/codegen.md | 6 +- docs/components.md | 28 +-- docs/guide/async-validation.md | 72 ++++++ docs/guide/environments.md | 2 +- docs/guide/formats.md | 107 +++++++++ docs/guide/getting-started.md | 64 +++--- docs/guide/managing-schemas.md | 57 ++--- docs/guide/modifying-data.md | 235 +++++++++++++++++++ docs/guide/schema-language.md | 139 ++++++++--- docs/{ => guide}/standalone.md | 2 +- docs/guide/typescript.md | 68 +++--- docs/guide/user-keywords.md | 3 +- docs/json-schema.md | 6 +- docs/json-type-definition.md | 2 +- docs/keywords.md | 16 +- docs/options.md | 302 ++++++++++++++++++++++++ docs/security.md | 2 +- docs/strict-mode.md | 2 +- docs/validation.md | 407 --------------------------------- lib/types/index.ts | 2 +- 25 files changed, 1045 insertions(+), 764 deletions(-) create mode 100644 docs/guide/async-validation.md create mode 100644 docs/guide/formats.md create mode 100644 docs/guide/modifying-data.md rename docs/{ => guide}/standalone.md (97%) create mode 100644 docs/options.md delete mode 100644 docs/validation.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a4aa54052..d73b91781 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,7 +2,7 @@ permalink: /contributing --- -# Contributing +# Contributing guide Thank you for your help making Ajv better! Every contribution is appreciated. If you plan to implement a new feature or some other change please create an issue first, to make sure that your work is not lost. diff --git a/README.md b/README.md index df205f44e..745cdd634 100644 --- a/README.md +++ b/README.md @@ -93,7 +93,7 @@ Please review [Contributing guidelines](./CONTRIBUTING.md) and [Code components] - [Strict number validation](./docs/strict-mode.md#strict-number-validation) - [Data validation](./docs/validation.md) - [Validation basics](./docs/validation.md#validation-basics): [JSON Schema keywords](./docs/validation.md#validation-keywords), [annotations](./docs/validation.md#annotation-keywords), [formats](./docs/validation.md#formats) - - [Modular schemas](./docs/validation.md#modular-schemas): [combining with \$ref](./docs/validation.md#ref), [\$data reference](./docs/validation.md#data-reference), [$merge and $patch](./docs/validation.md#merge-and-patch-keywords) + - [Modular schemas](./docs/validation.md#modular-schemas): [combining with \$ref](./docs/validation.md#ref), [\$data reference](./docs/guide/combining-schemas.md#data-reference), [$merge and $patch](./docs/validation.md#merge-and-patch-keywords) - [Asynchronous schema compilation](./docs/validation.md#asynchronous-schema-compilation) - [Standalone validation code](./docs/standalone.md) - [Asynchronous validation](./docs/validation.md#asynchronous-validation) @@ -196,7 +196,7 @@ Performance of different validators by [json-schema-benchmark](https://github.co - draft-06/07 keywords `const`, `contains`, `propertyNames` and `if/then/else` - draft-06 boolean schemas (`true`/`false` as a schema to always pass/fail). - additional extension keywords with [ajv-keywords](https://github.com/ajv-validator/ajv-keywords) package -- [\$data reference](./docs/validation.md#data-reference) to use values from the validated data as values for the schema keywords +- [\$data reference](./docs/guide/combining-schemas.md#data-reference) to use values from the validated data as values for the schema keywords - [asynchronous validation](./docs/api.md#asynchronous-validation) of user-defined formats and keywords ## Install diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index b745ae4ae..ff533b384 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -12,24 +12,55 @@ module.exports = { nav: [ {text: "Home", link: "/"}, { - text: "Validation", + text: "Guide", items: [ - {text: "Validating data", link: "/validation"}, - {text: "Strict mode", link: "/strict-mode"}, - {text: "JSON Schema", link: "/json-schema"}, - {text: "JSON Type Definition", link: "/json-type-definition"}, - {text: "Type coercion", link: "/coercion"}, + {link: "/guide/getting-started", text: "Getting started"}, + {link: "/guide/typescript", text: "Using with TypeScript"}, + {link: "/guide/schema-language", text: "Choosing schema language"}, + {link: "/guide/managing-schemas", text: "Managing schemas"}, + {link: "/guide/combining-schemas", text: "Combining schemas"}, + {link: "/guide/formats", text: "Format validation"}, + {link: "/guide/modifying-data", text: "Modifying data"}, + {link: "/guide/user-keywords", text: "User-defined keywords"}, + {link: "/guide/async-validation", text: "Asynchronous validation"}, + {link: "/guide/standalone", text: "Standalone validation code"}, + {link: "/guide/environments", text: "Execution environments"}, ], }, { - text: "API", + text: "Learn more", items: [ - {text: "Methods & options", link: "/api"}, - {text: "Define keywords", link: "/keywords"}, + { + text: "Reference", + items: [ + {link: "/api", text: "API Reference"}, + {link: "/options", text: "Initialization options"}, + {link: "/json-schema", text: "JSON Schema"}, + {link: "/json-type-definition", text: "JSON Type Definition"}, + {link: "/strict-mode", text: "Strict mode"}, + {link: "/keywords", text: "User defined keywords"}, + {link: "/coercion", text: "Type coercion rules"}, + ], + }, + { + text: "Contributors", + items: [ + {link: "/CONTRIBUTING", text: "Contributing"}, + {link: "/codegen", text: "Code generation design"}, + {link: "/components", text: "Code components"}, + {link: "/CODE_OF_CONDUCT", text: "Code of Conduct"}, + ], + }, + { + text: "Information", + items: [ + {link: "/security", text: "Security"}, + {link: "/faq", text: "FAQ"}, + {link: "/LICENSE", text: "License"}, + ], + }, ], }, - {text: "Security", link: "/security"}, - {text: "FAQ", link: "/faq"}, ], sidebar: [ "/", @@ -42,16 +73,19 @@ module.exports = { "/guide/schema-language", "/guide/managing-schemas", "/guide/combining-schemas", + "/guide/formats", + "/guide/modifying-data", "/guide/user-keywords", + "/guide/async-validation", "/guide/environments", - ] + ], }, { title: "Reference", collapsable: false, children: [ - "/validation", "/api", + "/options", "/json-schema", "/json-type-definition", "/strict-mode", @@ -60,9 +94,14 @@ module.exports = { ], }, { - title: "Code generation & design", + title: "Contributors", collapsable: false, - children: ["/standalone", "/codegen", "/components"], + children: [ + "/CONTRIBUTING", + "/codegen", + "/components", + ["/CODE_OF_CONDUCT", "Code of conduct"], + ], }, { title: "Information", @@ -70,10 +109,8 @@ module.exports = { children: [ "/faq", "/security", - "/CONTRIBUTING", - ["/CODE_OF_CONDUCT", "Code of conduct"], - ["/LICENSE", "License"] - ], + ["/LICENSE", "License"], + ] }, ], repo: "ajv-validator/ajv", diff --git a/docs/OLD_README.md b/docs/OLD_README.md index 8e50db426..edd620a53 100644 --- a/docs/OLD_README.md +++ b/docs/OLD_README.md @@ -26,7 +26,7 @@ Supports JSON Schema draft-06/07/2019-09 (draft-04 is supported in [version 6](h Ajv version 7 has these new features: - NEW: support of JSON Type Definition [RFC8927](https://datatracker.ietf.org/doc/rfc8927/) (from [v7.1.0](https://github.com/ajv-validator/ajv-keywords/releases/tag/v7.1.0)), including generation of [serializers](./docs/api.md#jtd-serialize) and [parsers](./docs/api.md#jtd-parse) from JTD schemas that are more efficient than native JSON serialization/parsing, combining JSON string parsing and validation in one function. -- support of JSON Schema draft-2019-09 features: [`unevaluatedProperties`](./docs/json-schema.md#unevaluatedproperties) and [`unevaluatedItems`](./docs/json-schema.md#unevaluateditems), [dynamic recursive references](./docs/validation.md#extending-recursive-schemas) and other [additional keywords](./docs/json-schema.md#json-schema-draft-2019-09). +- support of JSON Schema draft-2019-09 features: [`unevaluatedProperties`](./docs/json-schema.md#unevaluatedproperties) and [`unevaluatedItems`](./docs/json-schema.md#unevaluateditems), [dynamic recursive references](./docs/guide/combining-schemas.md#extending-recursive-schemas) and other [additional keywords](./docs/json-schema.md#json-schema-draft-2019-09). - to reduce the mistakes in JSON schemas and unexpected validation results, [strict mode](./docs/strict-mode.md) is added - it prohibits ignored or ambiguous JSON Schema elements. - to make code injection from untrusted schemas impossible, [code generation](./docs/codegen.md) is fully re-written to be safe and to allow code optimization (compiled schema code size is reduced by more than 10%). - to simplify Ajv extensions, the new keyword API that is used by pre-defined keywords is available to user-defined keywords - it is much easier to define any keywords now, especially with subschemas. [ajv-keywords](https://github.com/ajv-validator/ajv-keywords) package was updated to use the new API (in [v4.0.0](https://github.com/ajv-validator/ajv-keywords/releases/tag/v4.0.0)) @@ -93,7 +93,7 @@ Please review [Contributing guidelines](./CONTRIBUTING.md) and [Code components] - [Strict number validation](./docs/strict-mode.md#strict-number-validation) - [Data validation](./docs/validation.md) - [Validation basics](./docs/validation.md#validation-basics): [JSON Schema keywords](./docs/validation.md#validation-keywords), [annotations](./docs/validation.md#annotation-keywords), [formats](./docs/validation.md#formats) - - [Modular schemas](./docs/validation.md#modular-schemas): [combining with \$ref](./docs/validation.md#ref), [\$data reference](./docs/validation.md#data-reference), [$merge and $patch](./docs/validation.md#merge-and-patch-keywords) + - [Modular schemas](./docs/validation.md#modular-schemas): [combining with \$ref](./docs/validation.md#ref), [\$data reference](./docs/guide/combining-schemas.md#data-reference), [$merge and $patch](./docs/validation.md#merge-and-patch-keywords) - [Asynchronous schema compilation](./docs/validation.md#asynchronous-schema-compilation) - [Standalone validation code](./docs/standalone.md) - [Asynchronous validation](./docs/validation.md#asynchronous-validation) @@ -198,7 +198,7 @@ Performance of different validators by [json-schema-benchmark](https://github.co - draft-06/07 keywords `const`, `contains`, `propertyNames` and `if/then/else` - draft-06 boolean schemas (`true`/`false` as a schema to always pass/fail). - additional extension keywords with [ajv-keywords](https://github.com/ajv-validator/ajv-keywords) package -- [\$data reference](./docs/validation.md#data-reference) to use values from the validated data as values for the schema keywords +- [\$data reference](./docs/guide/combining-schemas.md#data-reference) to use values from the validated data as values for the schema keywords - [asynchronous validation](./docs/api.md#asynchronous-validation) of user-defined formats and keywords ## Extending Ajv diff --git a/docs/api.md b/docs/api.md index 8eb493700..5b378130d 100644 --- a/docs/api.md +++ b/docs/api.md @@ -1,12 +1,10 @@ # API Reference -- [Ajv constructor and methods](#ajv-constructor-and-methods) -- [Options](#options) -- [Validation errors](#validation-errors) +[[toc]] ## Ajv constructor and methods -### `new Ajv(options: object)` +### new Ajv(options: object) Create Ajv instance: @@ -14,9 +12,9 @@ Create Ajv instance: const ajv = new Ajv() ``` -See [Options](#options) +See [Options](./options) -### `ajv.compile(schema: object): (data: any) => boolean | Promise` +### ajv.compile(schema: object): (data: any) => boolean | Promise < any > Generate validating function and cache the compiled schema for future use. @@ -52,7 +50,7 @@ See more advanced example in [the test](../spec/types/json-schema.spec.ts). -### `ajv.compileSerializer(schema: object): (data: any) => string` +### ajv.compileSerializer(schema: object): (data: any) => string Generate serializing function based on the [JTD schema](./json-type-definition.md) (caches the schema) - only in JTD instance of Ajv (see example below). @@ -92,7 +90,7 @@ Compiled serializers do NOT validate passed data, it is assumed that the data is -### `ajv.compileParser(schema: object): (json: string) => any` +### ajv.compileParser(schema: object): (json: string) => any Generate parsing function based on the [JTD schema](./json-type-definition.md) (caches the schema) - only in JTD instance of Ajv (see example below). @@ -123,7 +121,7 @@ Generated parsers is a NEW Ajv functionality (as of March 2021), there can be so -### `ajv.compileAsync(schema: object, meta?: boolean): Promise` +### ajv.compileAsync(schema: object, meta?: boolean): Promise < Function > Asynchronous version of `compile` method that loads missing remote schemas using asynchronous function in `options.loadSchema`. This function returns a Promise that resolves to a validation function. An optional callback passed to `compileAsync` will be called with 2 parameters: error (or null) and validating function. The returned promise will reject (and the callback will be called with an error) when: @@ -139,7 +137,7 @@ Similarly to `compile`, it can return type guard in typescript. See example in [Asynchronous compilation](./validation.md#asynchronous-schema-compilation). -### `ajv.validate(schemaOrRef: object | string, data: any): boolean` +### ajv.validate(schemaOrRef: object | string, data: any): boolean Validate data using passed schema (it will be compiled and cached). @@ -157,7 +155,7 @@ If the schema is asynchronous (has `$async` keyword on the top level) this metho -### `ajv.addSchema(schema: object | object[], key?: string): Ajv` +### ajv.addSchema(schema: object | object[], key?: string): Ajv Add schema(s) to validator instance. This method does not compile schemas (but it still validates them). Because of that dependencies can be added in any order and circular dependencies are supported. It also prevents unnecessary compilation of schemas that are containers for other schemas but not used as a whole. @@ -180,7 +178,7 @@ const validate = new Ajv().addSchema(schema).addFormat(name, regex).getSchema(ur ::: -### `ajv.addMetaSchema(schema: object | object[], key?: string): Ajv` +### ajv.addMetaSchema(schema: object | object[], key?: string): Ajv Adds meta schema(s) that can be used to validate other schemas. That function should be used instead of `addSchema` because there may be instance options that would compile a meta schema incorrectly (at the moment it is `removeAdditional` option). @@ -188,7 +186,7 @@ There is no need to explicitly add draft-07 meta schema (http://json-schema.org/ -### `ajv.validateSchema(schema: object): boolean` +### ajv.validateSchema(schema: object): boolean Validates schema. This method should be used to validate schemas rather than `validate` due to the inconsistency of `uri` format in JSON Schema standard. @@ -200,11 +198,11 @@ If schema has `$schema` property, then the schema with this id (that should be p Errors will be available at `ajv.errors`. -### `ajv.getSchema(key: string): undefined | ((data: any) => boolean | Promise)` +### ajv.getSchema(key: string): undefined | ((data: any) => boolean | Promise < any >) Retrieve compiled schema previously added with `addSchema` by the key passed to `addSchema` or by its full reference (id). The returned validating function has `schema` property with the reference to the original schema. -### `ajv.removeSchema(schemaOrRef: object | string | RegExp): Ajv` +### ajv.removeSchema(schemaOrRef: object | string | RegExp): Ajv Remove added/cached schema. Even if schema is referenced by other schemas it can be safely removed as dependent schemas have local references. @@ -219,7 +217,7 @@ If no parameter is passed all schemas but meta-schemas will be removed and the c -### `ajv.addFormat(name: string, format: Format): Ajv` +### ajv.addFormat(name: string, format: Format): Ajv ```typescript type Format = @@ -252,7 +250,7 @@ Formats can be also added via `formats` option. -### `ajv.addKeyword(definition: object): Ajv` +### ajv.addKeyword(definition: object): Ajv Add validation keyword to Ajv instance. @@ -288,7 +286,7 @@ interface KeywordDefinition { modifying?: true // MUST be passed if keyword modifies data valid?: boolean // to pre-define validation result, validation function result will be ignored - // this option MUST NOT be used with `macro` keywords. - $data?: true // to support [\$data reference](./validation.md#data-reference) as the value of keyword. + $data?: true // to support [\$data reference](./guide/combining-schemas.md#data-reference) as the value of keyword. // The reference will be resolved at validation time. If the keyword has meta-schema, // it would be extended to allow $data and it will be used to validate the resolved value. // Supporting $data reference requires that keyword has `code` or `validate` function @@ -304,7 +302,7 @@ interface KeywordDefinition { } ``` -`compile`, `macro` and `code` are mutually exclusive, only one should be used at a time. `validate` can be used separately or in addition to `compile` or `macro` to support [\$data reference](./validation.md#data-reference). +`compile`, `macro` and `code` are mutually exclusive, only one should be used at a time. `validate` can be used separately or in addition to `compile` or `macro` to support [\$data reference](./guide/combining-schemas.md#data-reference). ::: tip Please note If the keyword is validating data type that is different from the type(s) in its definition, the validation function will not be called (and expanded macro will not be used), so there is no need to check for data type inside validation function or inside schema returned by macro function (unless you want to enforce a specific type and for some reason do not want to use a separate `type` keyword for that). In the same way as standard keywords work, if the keyword does not apply to the data type being validated, the validation of this keyword will succeed. @@ -312,11 +310,11 @@ If the keyword is validating data type that is different from the type(s) in its See [User defined keywords](./keywords.md) for more details. -### `ajv.getKeyword(keyword: string): object | boolean` +### ajv.getKeyword(keyword: string): object | boolean Returns keyword definition, `false` if the keyword is unknown. -### `ajv.removeKeyword(keyword: string): Ajv` +### ajv.removeKeyword(keyword: string): Ajv Removes added or pre-defined keyword so you can redefine them. @@ -326,166 +324,12 @@ While this method can be used to extend pre-defined keywords, it can also be use The schemas compiled before the keyword is removed will continue to work without changes. To recompile schemas use `removeSchema` method and compile them again. ::: -### `ajv.errorsText(errors?: object[], options?: object): string` +### ajv.errorsText(errors?: object[], options?: object): string Returns the text with all errors in a String. Options can have properties `separator` (string used to separate errors, ", " by default) and `dataVar` (the variable name that dataPaths are prefixed with, "data" by default). -## Options - -Option defaults: - -```javascript -// see types/index.ts for actual types -const defaultOptions = { - // strict mode options (NEW) - strict: true, - strictTypes: "log", // * - strictTuples: "log", // * - strictRequired: false, // * - allowUnionTypes: false, // * - allowMatchingProperties: false, // * - validateFormats: true, // * - // validation and reporting options: - $data: false, // * - allErrors: false, - verbose: false, // * - $comment: false, // * - formats: {}, - keywords: {}, - schemas: {}, - logger: undefined, - loadSchema: undefined, // *, function(uri: string): Promise {} - // options to modify validated data: - removeAdditional: false, - useDefaults: false, // * - coerceTypes: false, // * - // advanced options: - meta: true, - validateSchema: true, - addUsedSchema: true, - inlineRefs: true, - passContext: false, - loopRequired: Infinity, // * - loopEnum: Infinity, // NEW - ownProperties: false, - multipleOfPrecision: undefined, // * - messages: true, // false with JTD - ajvErrors: false // only with JTD - code: { - // NEW - es5: false, - lines: false, - source: false, - process: undefined, // (code: string) => string - optimize: true, - }, -} -``` - -\* these options are not supported with JSON Type Definition schemas - -### Strict mode options (NEW in v7) - -- _strict_: By default Ajv executes in strict mode, that is designed to prevent any unexpected behaviours or silently ignored mistakes in schemas (see [Strict Mode](./strict-mode.md) for more details). It does not change any validation results, but it makes some schemas invalid that would be otherwise valid according to JSON Schema specification. Option values: - - `true` (default) - use strict mode and throw an exception when any strict mode restriction is violated. - - `"log"` - log warning when any strict mode restriction is violated. - - `false` - ignore all strict mode restrictions. Also ignores `strictTypes` restrictions unless it is explicitly passed. -- _strictTypes_: By default Ajv logs warning when "type" keyword is used in a way that may be incorrect or confusing to other people - see [Strict types](./strict-mode.md#strict-types) for more details. This option does not change validation results. Option values: - - `true` - throw exception when any strictTypes restriction is violated. - - `"log"` (default, unless option strict is `false`) - log warning when any strictTypes restriction is violated. - - `false` - ignore all strictTypes restrictions violations. -- _strictTuples_: By default Ajv logs warning when "items" is array and "minItems" and "maxItems"/"additionalItems" not present or different from the number of items. See [Strict mode](./strict-mode.md) for more details. This option does not change validation results. Option values: - - `true` - throw exception. - - `"log"` (default, unless option strict is `false`) - log warning. - - `false` - ignore strictTuples restriction violations. -- _strictRequired_: Ajv can log warning or throw exception when the property used in "required" keyword is not defined in "properties" keyword. See [Strict mode](./strict-mode.md) for more details. This option does not change validation results. Option values: - - `true` - throw exception. - - `"log"` - log warning. - - `false` (default) - ignore strictRequired restriction violations. -- _allowUnionTypes_: pass true to allow using multiple non-null types in "type" keyword (one of `strictTypes` restrictions). see [Strict types](./strict-mode.md#strict-types) -- _allowMatchingProperties_: pass true to allow overlap between "properties" and "patternProperties". Does not affect other strict mode restrictions. See [Strict Mode](./strict-mode.md). -- _validateFormats_: format validation. Option values: - - `true` (default) - validate formats (see [Formats](./validation.md#formats)). In [strict mode](./strict-mode.md) unknown formats will throw exception during schema compilation (and fail validation in case format keyword value is [\$data reference](./validation.md#data-reference)). - - `false` - do not validate any format keywords (TODO they will still collect annotations once supported). - -### Validation and reporting options - -- _\$data_: support [\$data references](./validation.md#data-reference). Draft 6 meta-schema that is added by default will be extended to allow them. If you want to use another meta-schema you need to use $dataMetaSchema method to add support for $data reference. See [API](#ajv-constructor-and-methods). -- _allErrors_: check all rules collecting all errors. Default is to return after the first error. -- _verbose_: include the reference to the part of the schema (`schema` and `parentSchema`) and validated data in errors (false by default). -- _\$comment_: log or pass the value of `$comment` keyword to a function. Option values: - - `false` (default): ignore \$comment keyword. - - `true`: log the keyword value to console. - - function: pass the keyword value, its schema path and root schema to the specified function -- _formats_: an object with format definitions. Keys and values will be passed to `addFormat` method. Pass `true` as format definition to ignore some formats. -- _keywords_: an array of keyword definitions or strings. Values will be passed to `addKeyword` method. -- _schemas_: an array or object of schemas that will be added to the instance. In case you pass the array the schemas must have IDs in them. When the object is passed the method `addSchema(value, key)` will be called for each schema in this object. -- _logger_: sets the logging method. Default is the global `console` object that should have methods `log`, `warn` and `error`. See [Error logging](#error-logging). Option values: - - logger instance - it should have methods `log`, `warn` and `error`. If any of these methods is missing an exception will be thrown. - - `false` - logging is disabled. -- _loadSchema_: asynchronous function that will be used to load remote schemas when `compileAsync` [method](#api-compileAsync) is used and some reference is missing (option `missingRefs` should NOT be 'fail' or 'ignore'). This function should accept remote schema uri as a parameter and return a Promise that resolves to a schema. See example in [Asynchronous compilation](./validation.md#asynchronous-schema-compilation). - -### Options to modify validated data - -- _removeAdditional_: remove additional properties - see example in [Removing additional properties](./validation.md#removing-additional-properties). This option is not used if schema is added with `addMetaSchema` method. Option values: - - `false` (default) - not to remove additional properties - - `"all"` - all additional properties are removed, regardless of `additionalProperties` keyword in schema (and no validation is made for them). - - `true` - only additional properties with `additionalProperties` keyword equal to `false` are removed. - - `"failing"` - additional properties that fail schema validation will be removed (where `additionalProperties` keyword is `false` or schema). -- _useDefaults_: replace missing or undefined properties and items with the values from corresponding `default` keywords. Default behaviour is to ignore `default` keywords. This option is not used if schema is added with `addMetaSchema` method. See examples in [Assigning defaults](./validation.md#assigning-defaults). Option values: - - `false` (default) - do not use defaults - - `true` - insert defaults by value (object literal is used). - - `"empty"` - in addition to missing or undefined, use defaults for properties and items that are equal to `null` or `""` (an empty string). -- _coerceTypes_: change data type of data to match `type` keyword. See the example in [Coercing data types](./validation.md#coercing-data-types) and [coercion rules](./coercion.md). Option values: - - `false` (default) - no type coercion. - - `true` - coerce scalar data types. - - `"array"` - in addition to coercions between scalar types, coerce scalar data to an array with one element and vice versa (as required by the schema). - -### Advanced options - -- _meta_: add [meta-schema](http://json-schema.org/documentation.html) so it can be used by other schemas (true by default). If an object is passed, it will be used as the default meta-schema for schemas that have no `$schema` keyword. This default meta-schema MUST have `$schema` keyword. -- _validateSchema_: validate added/compiled schemas against meta-schema (true by default). `$schema` property in the schema can be http://json-schema.org/draft-07/schema or absent (draft-07 meta-schema will be used) or can be a reference to the schema previously added with `addMetaSchema` method. Option values: - - `true` (default) - if the validation fails, throw the exception. - - `"log"` - if the validation fails, log error. - - `false` - skip schema validation. -- _addUsedSchema_: by default methods `compile` and `validate` add schemas to the instance if they have `$id` (or `id`) property that doesn't start with "#". If `$id` is present and it is not unique the exception will be thrown. Set this option to `false` to skip adding schemas to the instance and the `$id` uniqueness check when these methods are used. This option does not affect `addSchema` method. -- _inlineRefs_: Affects compilation of referenced schemas. Option values: - - `true` (default) - the referenced schemas that don't have refs in them are inlined, regardless of their size - it improves performance. - - `false` - to not inline referenced schemas (they will always be compiled as separate functions). - - integer number - to limit the maximum number of keywords of the schema that will be inlined (to balance the total size of compiled functions and performance). -- _passContext_: pass validation context to _compile_ and _validate_ keyword functions. If this option is `true` and you pass some context to the compiled validation function with `validate.call(context, data)`, the `context` will be available as `this` in your keywords. By default `this` is Ajv instance. -- _loopRequired_: by default `required` keyword is compiled into a single expression (or a sequence of statements in `allErrors` mode). In case of a very large number of properties in this keyword it may result in a very big validation function. Pass integer to set the number of properties above which `required` keyword will be validated in a loop - smaller validation function size but also worse performance. -- _loopEnum_ (NEW in v7): by default `enum` keyword is compiled into a single expression. In case of a very large number of allowed values it may result in a large validation function. Pass integer to set the number of values above which `enum` keyword will be validated in a loop. -- _ownProperties_: by default Ajv iterates over all enumerable object properties; when this option is `true` only own enumerable object properties (i.e. found directly on the object rather than on its prototype) are iterated. Contributed by @mbroadst. -- _multipleOfPrecision_: by default `multipleOf` keyword is validated by comparing the result of division with parseInt() of that result. It works for dividers that are bigger than 1. For small dividers such as 0.01 the result of the division is usually not integer (even when it should be integer, see issue [#84](https://github.com/ajv-validator/ajv/issues/84)). If you need to use fractional dividers set this option to some positive integer N to have `multipleOf` validated using this formula: `Math.abs(Math.round(division) - division) < 1e-N` (it is slower but allows for float arithmetic deviations). -- _messages_: Include human-readable messages in errors. `true` by default. `false` can be passed when messages are generated outside of Ajv code (e.g. with [ajv-i18n](https://github.com/ajv-validator/ajv-i18n)). -- _ajvErrors_: this option is only supported with JTD schemas to generate error objects with the properties described in the first part of [Validation errors](#validation-errors) section, otherwise JTD errors are generated when JTD schemas are used (see the second part of [the same section](#validation-errors)). -- _code_ (new in v7): code generation options: - -```typescript -type CodeOptions = { - es5?: boolean // to generate es5 code - by default code is es6, with "for-of" loops, "let" and "const" - lines?: boolean // add line-breaks to code - to simplify debugging of generated functions - source?: boolean // add `source` property (see Source below) to validating function. - process?: (code: string, schema?: SchemaEnv) => string // an optional function to process generated code - // before it is passed to Function constructor. - // It can be used to either beautify or to transpile code. - optimize?: boolean | number // code optimization flag or number of passes, 1 pass by default, - // code optimizations reduce the size of the generated code (bytes, based on the tests) by over 10%, - // the number of code tree nodes by nearly 17%. - // You would almost never need more than one optimization pass, unless you have some really complex schemas - - // the second pass in the tests (it has quite complex schemas) only improves optimization by less than 0.1%. - // See [Code optimization](./codegen.md#code-optimization) for details. -} - -type Source = { - code: string // unlike func.toString() it includes assignments external to function scope - scope: Scope // see Code generation (TODO) -} -``` - ## Validation errors In case of validation failure, Ajv assigns the array of errors to `errors` property of validation function (or to `errors` property of Ajv instance when `validate` or `validateSchema` methods were called). In case of [asynchronous validation](./validation.md#asynchronous-validation), the returned promise is rejected with exception `Ajv.ValidationError` that has `errors` property. @@ -653,3 +497,7 @@ const ajv = new Ajv({ }, }) ``` + +## Options + +This section is moved to [Initialization options](./options) page diff --git a/docs/codegen.md b/docs/codegen.md index 3f5f77faa..164a5caf5 100644 --- a/docs/codegen.md +++ b/docs/codegen.md @@ -2,7 +2,7 @@ [[toc]] -Starting from v7 Ajv uses [CodeGen module](../lib/compile/codegen/index.ts) that replaced [doT](https://github.com/olado/dot) templates used earlier. +Starting from v7 Ajv uses [CodeGen module](https://github.com/ajv-validator/ajv/blob/master/lib/compile/codegen/index.ts) that replaced [doT](https://github.com/olado/dot) templates used earlier. The motivations for this change: @@ -39,7 +39,7 @@ function log(comparison: string): void { // type Code = _Code | Name, _Code can only be constructed with template literals const msg: Code = str`${num} is ${comparison} than ${x}` // msg is _Code instance, so it will be inserted via another template without quotes - gen.code(_`console log(${msg})`) + gen.code(_`console.log(${msg})`) } ``` @@ -54,7 +54,7 @@ if (num0 > 0) { } ``` -`.const`, `.if` and `.code` above are methods of CodeGen class that generate code inside class instance `gen` - see [source code](../lib/compile/codegen/index.ts) for all available methods and [tests](../spec/codegen.spec.ts) for other code generation examples. +`.const`, `.if` and `.code` above are methods of CodeGen class that generate code inside class instance `gen` - see [source code](https://github.com/ajv-validator/ajv/blob/master/lib/compile/codegen/index.ts) for all available methods and [tests](../spec/codegen.spec.ts) for other code generation examples. These methods only accept instances of private class `_Code`, other values will be rejected by Typescript compiler - the risk to pass unsafe string is mitigated on type level. diff --git a/docs/components.md b/docs/components.md index ad0e96013..b3bc0c8c5 100644 --- a/docs/components.md +++ b/docs/components.md @@ -4,34 +4,34 @@ ## Ajv classes -[lib/core.ts](../lib/core.ts) - core Ajv class without any keywords. All Ajv methods for managing schemas and extensions are defined in this class. +[lib/core.ts](https://github.com/ajv-validator/ajv/blob/master/lib/core.ts) - core Ajv class without any keywords. All Ajv methods for managing schemas and extensions are defined in this class. -[lib/ajv.ts](../lib/ajv.ts) - subclass of Ajv core with JSON Schema draft-07 keywords. +[lib/ajv.ts](https://github.com/ajv-validator/ajv/blob/master/lib/ajv.ts) - subclass of Ajv core with JSON Schema draft-07 keywords. -[lib/2019.ts](../lib/2019.ts) - subclass of Ajv core with JSON Schema draft-2019-09 keywords. +[lib/2019.ts](https://github.com/ajv-validator/ajv/blob/master/lib/2019.ts) - subclass of Ajv core with JSON Schema draft-2019-09 keywords. -[lib/jtd.ts](../lib/jtd.ts) - subclass of Ajv core with JSON Type Definition support. +[lib/jtd.ts](https://github.com/ajv-validator/ajv/blob/master/lib/jtd.ts) - subclass of Ajv core with JSON Type Definition support. ## Schema compilation -[lib/compile](../lib/compile) - code for schema compilation +[lib/compile](https://github.com/ajv-validator/ajv/blob/master/lib/compile) - code for schema compilation -[lib/compile/index.ts](../lib/compile/index.ts) - the main recursive function code for schema compilation, functions for reference resolution, the interface for schema compilation context (`SchemaCxt`). +[lib/compile/index.ts](https://github.com/ajv-validator/ajv/blob/master/lib/compile/index.ts) - the main recursive function code for schema compilation, functions for reference resolution, the interface for schema compilation context (`SchemaCxt`). -[lib/compile/context.ts](../lib/compile/context.ts) - the class for keyword code generation `KeywordCxt`. All pre-defined keywords and user-defined keywords that use `code` function are passed an instance of this class. +[lib/compile/context.ts](https://github.com/ajv-validator/ajv/blob/master/lib/compile/context.ts) - the class for keyword code generation `KeywordCxt`. All pre-defined keywords and user-defined keywords that use `code` function are passed an instance of this class. -[lib/compile/rules.ts](../lib/compile/rules.ts) - data structure to store references to all all keyword definitions that were added to Ajv instance, organised by data type. +[lib/compile/rules.ts](https://github.com/ajv-validator/ajv/blob/master/lib/compile/rules.ts) - data structure to store references to all all keyword definitions that were added to Ajv instance, organised by data type. -[lib/compile/subschema.ts](../lib/compile/subschema.ts) - creates schema context (`SchemaCxt`) to generate code for subschemas - used by all applicator keywords in [lib/vocabularies/applicator](../lib/vocabularies/applicator). +[lib/compile/subschema.ts](https://github.com/ajv-validator/ajv/blob/master/lib/compile/subschema.ts) - creates schema context (`SchemaCxt`) to generate code for subschemas - used by all applicator keywords in [lib/vocabularies/applicator](https://github.com/ajv-validator/ajv/blob/master/lib/vocabularies/applicator). -[lib/compile/codegen](../lib/compile/codegen) - the api for [code generation](./codegen.md). +[lib/compile/codegen](https://github.com/ajv-validator/ajv/blob/master/lib/compile/codegen) - the api for [code generation](./codegen.md). -[lib/compile/validate](../lib/compile/validate) - code to iterate the schema to generate code of validation function. +[lib/compile/validate](https://github.com/ajv-validator/ajv/blob/master/lib/compile/validate) - code to iterate the schema to generate code of validation function. ## Other components -[lib/standalone](../lib/standalone) - module to generate [standalone validation code](./standalone.md). +[lib/standalone](https://github.com/ajv-validator/ajv/blob/master/lib/standalone) - module to generate [standalone validation code](./standalone.md). -[lib/vocabularies](../lib/vocabularies) - pre-defined validation keywords. +[lib/vocabularies](https://github.com/ajv-validator/ajv/blob/master/lib/vocabularies) - pre-defined validation keywords. -[lib/refs](../lib/refs) - JSON Schema meta-schemas. +[lib/refs](https://github.com/ajv-validator/ajv/blob/master/lib/refs) - JSON Schema meta-schemas. diff --git a/docs/guide/async-validation.md b/docs/guide/async-validation.md new file mode 100644 index 000000000..d5f432ecd --- /dev/null +++ b/docs/guide/async-validation.md @@ -0,0 +1,72 @@ +# Asynchronous validation + +You can define formats and keywords that perform validation asynchronously by accessing database or some other service. You should add `async: true` in the keyword or format definition (see [addFormat](./api.md#api-addformat), [addKeyword](./api.md#api-addkeyword) and [User-defined keywords](./keywords.md)). + +If your schema uses asynchronous formats/keywords or refers to some schema that contains them it should have `"$async": true` keyword so that Ajv can compile it correctly. If asynchronous format/keyword or reference to asynchronous schema is used in the schema without `$async` keyword Ajv will throw an exception during schema compilation. + +::: warning Please note +All asynchronous subschemas that are referenced from the current or other schemas should have `"$async": true` keyword as well, otherwise the schema compilation will fail. +::: + +Validation function for an asynchronous format/keyword should return a promise that resolves with `true` or `false` (or rejects with `new Ajv.ValidationError(errors)` if you want to return errors from the keyword function). + +Ajv compiles asynchronous schemas to [async functions](http://tc39.github.io/ecmascript-asyncawait/). Async functions are supported in Node.js 7+ and all modern browsers. You can supply a transpiler as a function via `processCode` option. See [Options](./api.md#options). + +The compiled validation function has `$async: true` property (if the schema is asynchronous), so you can differentiate these functions if you are using both synchronous and asynchronous schemas. + +Validation result will be a promise that resolves with validated data or rejects with an exception `Ajv.ValidationError` that contains the array of validation errors in `errors` property. + +Example: + +```javascript +const ajv = new Ajv() + +ajv.addKeyword({ + keyword: "idExists" + async: true, + type: "number", + validate: checkIdExists, +}) + +async function checkIdExists(schema, data) { + // this is just an example, you would want to avoid SQL injection in your code + const rows = await sql(`SELECT id FROM ${schema.table} WHERE id = ${data}`) + return !!rows.length // true if record is found +} + +const schema = { + $async: true, + properties: { + userId: { + type: "integer", + idExists: {table: "users"}, + }, + postId: { + type: "integer", + idExists: {table: "posts"}, + }, + }, +} + +const validate = ajv.compile(schema) + +validate({userId: 1, postId: 19}) + .then(function (data) { + console.log("Data is valid", data) // { userId: 1, postId: 19 } + }) + .catch(function (err) { + if (!(err instanceof Ajv.ValidationError)) throw err + // data is invalid + console.log("Validation errors:", err.errors) + }) +``` + +### Using transpilers + +```javascript +const ajv = new Ajv({processCode: transpileFunc}) +const validate = ajv.compile(schema) // transpiled es7 async function +validate(data).then(successFunc).catch(errorFunc) +``` + +See [Options](../options). diff --git a/docs/guide/environments.md b/docs/guide/environments.md index 550fed108..1b2267e9b 100644 --- a/docs/guide/environments.md +++ b/docs/guide/environments.md @@ -104,7 +104,7 @@ If any of this is important, you may have better results with pre-compiled [stan Ajv can be used from the terminal in any operating system supported by Node.js -CLI is available as a separate npm package [ajv-cli](https://github.com/ajv-validator/ajv-cli). +CLI is available as a separate npm package [ajv-cli](https://github.com/ajv-validator/ajv-cli). It supports: diff --git a/docs/guide/formats.md b/docs/guide/formats.md new file mode 100644 index 000000000..a8c39062f --- /dev/null +++ b/docs/guide/formats.md @@ -0,0 +1,107 @@ +# Format validation + +## String formats + +From version 7 Ajv does not include formats defined by JSON Schema specification - these and several other formats are provided by [ajv-formats](https://github.com/ajv-validator/ajv-formats) plugin. + +To add all formats from this plugin: + + + +```javascript +const Ajv = require("ajv").default +const addFormats = require("ajv-formats") + +const ajv = new Ajv() +addFormats(ajv) + +```` + + + +```typescript +import Ajv from "ajv" +import addFormats from "ajv-formats" + +const ajv = new Ajv() +addFormats(ajv) +```` + + + + +See [ajv-formats](https://github.com/ajv-validator/ajv-formats) documentation for further details. + +It is recommended NOT to use "format" keyword implementations with untrusted data, as they may use potentially unsafe regular expressions (even though known issues are fixed) - see [ReDoS attack](./security.md#redos-attack). + +::: danger Please note +If you need to use "format" keyword to validate untrusted data, you MUST assess their suitability and safety for your validation scenarios. +::: + +The following formats are defined in [ajv-formats](https://github.com/ajv-validator/ajv-formats) for string validation with "format" keyword: + +- _date_: full-date according to [RFC3339](http://tools.ietf.org/html/rfc3339#section-5.6). +- _time_: time with optional time-zone. +- _date-time_: date-time from the same source (time-zone is mandatory). +- _duration_: duration from [RFC3339](https://tools.ietf.org/html/rfc3339#appendix-A) +- _uri_: full URI. +- _uri-reference_: URI reference, including full and relative URIs. +- _uri-template_: URI template according to [RFC6570](https://datatracker.ietf.org/doc/rfc6570/) +- _url_ (deprecated): [URL record](https://url.spec.whatwg.org/#concept-url). +- _email_: email address. +- _hostname_: host name according to [RFC1034](http://tools.ietf.org/html/rfc1034#section-3.5). +- _ipv4_: IP address v4. +- _ipv6_: IP address v6. +- _regex_: tests whether a string is a valid regular expression by passing it to RegExp constructor. +- _uuid_: Universally Unique Identifier according to [RFC4122](https://datatracker.ietf.org/doc/rfc4122/). +- _json-pointer_: JSON-pointer according to [RFC6901](https://datatracker.ietf.org/doc/rfc6901/). +- _relative-json-pointer_: relative JSON-pointer according to [this draft](http://tools.ietf.org/html/draft-luff-relative-json-pointer-00). + +::: warning Please note +JSON Schema draft-07 also defines formats `iri`, `iri-reference`, `idn-hostname` and `idn-email` for URLs, hostnames and emails with international characters. These formats are available in [ajv-formats-draft2019](https://github.com/luzlab/ajv-formats-draft2019) plugin. +::: + +## User-defined formats + +You can add and replace any formats using [addFormat](./api.md#api-addformat) method: + +```javascript +ajv.addFormat("identifier", /^a-z\$_[a-zA-Z$_0-9]*$/) +``` + +Ajv also allows defining the formats that would be applied to numbers only: + +```javascript +ajv.addFormat("byte", { + type: "number", + validate: (x) => x >= 0 && x <= 255 && x % 1 == 0, +}) +``` + +## Formats and standalone validation code + +If you use formats from [ajv-formats](https://github.com/ajv-validator/ajv-formats) package, [standalone validation code](../standalone) will be supported out of the box. + +::: warning Please note +You need to make sure that ajv-formats imports the same version and the same code of ajv as the one you use in your application for standalone validation code to work (because of `instanceof` check that is currently used). + +`npm` and other package managers may not update the version of ajv dependency of ajv-formats when you update version of ajv in your application - the workaround is to use clean npm installation. +::: + +If you define your own formats, for standalone code generation to work you need to pass the code snippet that evaluates to an object with all defined formats to the option `code.formats`: + + + +```javascript +const {default: Ajv, _} = require("ajv") +const ajv = new Ajv({code: {formats: _`require("./my_formats")`}}) +``` + + + +```typescript +import Ajv, {_} from "ajv" +const ajv = new Ajv({code: {formats: _`require("./my_formats")`}}) +``` + + diff --git a/docs/guide/getting-started.md b/docs/guide/getting-started.md index fcb0b7ccd..dc64a4193 100644 --- a/docs/guide/getting-started.md +++ b/docs/guide/getting-started.md @@ -10,13 +10,13 @@ You can try Ajv without installing it in the Node.js REPL: [https://runkit.com/n To install Ajv version 7: -``` +```bash npm install ajv ``` -If you need to use Ajv with [JSON Schema draft-04](../json-schema#draft-04), you need to install version 6: +If you need to use Ajv with [JSON Schema draft-04](./schema-language#draft-04), you need to install Ajv version 6: -``` +```bash npm install ajv@6 ``` @@ -38,25 +38,26 @@ const Ajv = require("ajv").default const ajv = new Ajv() // options can be passed, e.g. {allErrors: true} const schema = { - type: "object", - properties: { - foo: {type: "integer"}, - bar: {type: "string"} - }, - required: ["foo"], - additionalProperties: false +type: "object", +properties: { +foo: {type: "integer"}, +bar: {type: "string"} +}, +required: ["foo"], +additionalProperties: false } const validate = ajv.compile(schema) const validData = { - foo: 1, - bar: "abc" +foo: 1, +bar: "abc" } const valid = validate(data) if (!valid) console.log(validate.errors) -``` + +```` @@ -83,7 +84,8 @@ const validData = { const valid = validate(data) if (!valid) console.log(validate.errors) -`````` +```` + @@ -118,12 +120,12 @@ const Ajv = require("ajv/dist/jtd").default const ajv = new Ajv() // options can be passed, e.g. {allErrors: true} const schema = { - properties: { - foo: {type: "int32"} - }, - optionalProperties: { - bar: {type: "string"} - } +properties: { +foo: {type: "int32"} +}, +optionalProperties: { +bar: {type: "string"} +} } const serialize = ajv.compileSerializer(schema) @@ -132,8 +134,8 @@ console.log(serialize(data)) const parse = ajv.compileParser(schema) const data = { - foo: 1, - bar: "abc" +foo: 1, +bar: "abc" } const json = '{"foo": 1, "bar": "abc"}' @@ -143,14 +145,15 @@ console.log(parseAndLog(json)) // logs {foo: 1, bar: "abc"} console.log(parseAndLog(invalidJson)) // logs error and position function parseAndLog(json) { - const data = parse(json) - if (data === undefined) { - console.log(parse.message) // error message from the last parse call - console.log(parse.position) // error position in string - } else { - console.log(data) - } +const data = parse(json) +if (data === undefined) { +console.log(parse.message) // error message from the last parse call +console.log(parse.position) // error position in string +} else { +console.log(data) +} } + ``` @@ -161,4 +164,5 @@ You would have smaller performance benefits in case your schema contains some pr ::: warning Please note Compiled parsers, unlike JSON.parse, do not throw the exception in case JSON string is not a valid JSON or in case data is invalid according to the schema. As soon as the parser determines that either JSON or data is invalid, it returns `undefined` and reports error and position via parsers properties `message` and `position`. -::: \ No newline at end of file +::: +``` diff --git a/docs/guide/managing-schemas.md b/docs/guide/managing-schemas.md index 4498a3dff..b442e1cc2 100644 --- a/docs/guide/managing-schemas.md +++ b/docs/guide/managing-schemas.md @@ -7,6 +7,7 @@ Ajv validation model is optimized for server side execution, when schema compilation happens only once and validation happens multiple times - this has a substantial performance benefit comparing with validators that interpret the schema in the process of validation. Transition from template-based code generation in Ajv v6 to the tree-based in v7 brought: + - type-level safety against code injection via untrusted schemas - more efficient validation code (via [tree optimizations](../codegen.md#code-optimization)) - smaller memory footprint of compiled functions (schemas are no longer serialized) @@ -20,6 +21,7 @@ There are several approaches to manage compiled schemas. ## Standalone validation code The motivation to pre-compile schemas: + - faster startup times - lower memory footprint/bundle size - compatible with strict content security policies @@ -29,6 +31,7 @@ The motivation to pre-compile schemas: See [Standalone validation code](../standalone) for the details. There are scenarios when it can be not possible or difficult: + - dynamic or user-provided schemas - while you can do caching, it can be either difficult to implement or inefficient. - user-defined keywords that use closures that are difficult to serialize as code. @@ -44,20 +47,17 @@ const schema_user = require("./schema_user.json") const ajv = new Ajv() const validate_user = ajv.compile(schema_user) - - - - // this is just some abstract API framework app.post("/user", async (cxt) => { - if (validate_user(cxt.body)) { - // create user - } else { - // report error - cxt.status(400) - } +if (validate_user(cxt.body)) { +// create user +} else { +// report error +cxt.status(400) +} }) -``` + +```` @@ -80,16 +80,18 @@ app.post("/user", async (cxt) => { cxt.status(400) } }) -``` +```` + ::: warning Please note It recommended to use a single Ajv instance for the whole application, so if you use validation in more than one module, you should: + - require Ajv in a separate module responsible for validation - compile all validators there - export them to be used in multiple modules of your application -::: + ::: ## Using Ajv instance cache @@ -130,21 +132,18 @@ And then you can import Ajv instance and access any schema in any application mo ```javascript const {ajv} = require("./validation") - - - - // this is just some abstract API framework app.post("/user", async (cxt) => { - const validate = ajv.getSchema("user") - if (validate(cxt.body)) { - // create user - } else { - // report error - cxt.status(400) - } +const validate = ajv.getSchema("user") +if (validate(cxt.body)) { +// create user +} else { +// report error +cxt.status(400) +} }) -``` + +```` @@ -165,7 +164,8 @@ app.post("/user", async (cxt) => { cxt.status(400) } }) -``` +```` + @@ -176,6 +176,7 @@ In the example above, schema compilation happens only once, on the first API cal ### Cache key: schema vs key vs $id In the example above, the key passed to the `addSchema` method was used to retrieve schemas from the cache. Other options are: + - use schema root $id attribute. While it usually looks like URI, it does not mean Ajv downloads it from this URI - this is simply $id used to identify and access the schema. You can though configure Ajv to download schemas on demand - see [Asynchronous schema loading](#asynchronous-schema-loading) - use schema object itself as a key to the cache (it is possible, because Ajv uses Map). This approach is not recommended, because it would only work if you pass the same instance of the schema object that was passed to `addSchema` method - it is easy to make a mistake that would result in schema being compiled every time it is used. @@ -213,8 +214,7 @@ then the above logic can be simpler: ```javascript const schema_user = require("./schema_user.json") -const validate = ajv.getSchema("https://example.com/user.json") - || ajv.compile(schema_user) +const validate = ajv.getSchema("https://example.com/user.json") || ajv.compile(schema_user) ``` The above is possible because when the schema has `$id` attribute `compile` method both compiles the schema (returning the validation function) and adds it to the Ajv instance cache at the same time. @@ -249,6 +249,7 @@ async function loadSchema(uri) { ## Caching schemas in your code You can maintain cache of compiled schemas in your application independently from Ajv. It can be helpful in cases when you have multiple Ajv instances because, for example: + - you need to compile different schemas with different options - you use both JSON Schema and JSON Type Definition schemas in one application - you have $id conflicts between different third party schemas you do not control diff --git a/docs/guide/modifying-data.md b/docs/guide/modifying-data.md new file mode 100644 index 000000000..0f95782ce --- /dev/null +++ b/docs/guide/modifying-data.md @@ -0,0 +1,235 @@ +# Modifying data during validation + +[[toc]] + +## General considerations + +Ajv has several options that allow to modify data during validation: + +- removeAdditional - to remove properties not defined in the schema object. +- useDefaults - to assign defaults from the schema to the validated data properties. +- coerceTypes - to change data type, when possible, to match the type(s) in the schema. + +You can also define keywords that modify data. + +::: tip Please note +It is not possible to modify the root data instance passed to the validation function, only data properties can be modified. This is related to how JavaScript passes parameters, and not a limitation of Ajv. +::: + +::: warning Please note +This functionality is non-standard - this is likely to be unsupported in other JSON Schema validator implementations. +::: + +::: danger Please note +While pure schema validation produces the results independent of the keywords and subschema order, enabling any feature that may modify the data makes validation impure and its results are likely to depend on the order of evaluation of keywords and subschemas. + +The order of evaluation of subschemas in keywords like `allOf` is always the same as the order of subschemas in the array. + +On another hand, the order of evaluation of keywords, while consistent between validations and not dependent on how schema object is created, is neither documented nor guaranteed, so it can change in the future major versions (and, in rare cases, it can change in minor version - e.g. when there is bug that needs to be fixed). + +It is strongly recommended to always put user-defined keywords that can mutate data in separate subschemas inside `allOf` keyword to make the order of evaluation unambiguous. The exceptions to this recommendation are pre-defined `default` and `type` keywords - they must remain in the same schema as other keywords. +::: + +## Removing additional properties + +With [option `removeAdditional`](./api.md#options) (added by [andyscott](https://github.com/andyscott)) you can filter data during the validation. + +This option modifies original data. + +Example: + +```javascript +const ajv = new Ajv({removeAdditional: true}) +const schema = { + additionalProperties: false, + properties: { + foo: {type: "number"}, + bar: { + additionalProperties: {type: "number"}, + properties: { + baz: {type: "string"}, + }, + }, + }, +} + +const data = { + foo: 0, + additional1: 1, // will be removed; `additionalProperties` == false + bar: { + baz: "abc", + additional2: 2, // will NOT be removed; `additionalProperties` != false + }, +} + +const validate = ajv.compile(schema) + +console.log(validate(data)) // true +console.log(data) // { "foo": 0, "bar": { "baz": "abc", "additional2": 2 } +``` + +If `removeAdditional` option in the example above were `"all"` then both `additional1` and `additional2` properties would have been removed. + +If the option were `"failing"` then property `additional1` would have been removed regardless of its value and property `additional2` would have been removed only if its value were failing the schema in the inner `additionalProperties` (so in the example above it would have stayed because it passes the schema, but any non-number would have been removed). + +::: warning Please note +If you use `removeAdditional` option with `additionalProperties` keyword inside `anyOf`/`oneOf` keywords your validation can fail with this schema +::: + +For example: + +```javascript +{ + type: "object", + oneOf: [ + { + properties: { + foo: {type: "string"} + }, + required: ["foo"], + additionalProperties: false + }, + { + properties: { + bar: {type: "integer"} + }, + required: ["bar"], + additionalProperties: false + } + ] +} +``` + +The intention of the schema above is to allow objects with either the string property "foo" or the integer property "bar", but not with both and not with any other properties. + +With the option `removeAdditional: true` the validation will pass for the object `{ "foo": "abc"}` but will fail for the object `{"bar": 1}`. It happens because while the first subschema in `oneOf` is validated, the property `bar` is removed because it is an additional property according to the standard (because it is not included in `properties` keyword in the same schema). + +While this behaviour is unexpected (issues [#129](https://github.com/ajv-validator/ajv/issues/129), [#134](https://github.com/ajv-validator/ajv/issues/134)), it is correct. To have the expected behaviour (both objects are allowed and additional properties are removed) the schema has to be refactored in this way: + +```javascript +{ + type: "object", + properties: { + foo: {type: "string"}, + bar: {type: "integer"} + }, + additionalProperties: false, + oneOf: [{required: ["foo"]}, {required: ["bar"]}] +} +``` + +The schema above is also more efficient - it will compile into a faster function. + +## Assigning defaults + +With [option `useDefaults`](./api.md#options) Ajv will assign values from `default` keyword in the schemas of `properties` and `items` (when it is the array of schemas) to the missing properties and items. + +With the option value `"empty"` properties and items equal to `null` or `""` (empty string) will be considered missing and assigned defaults. + +This option modifies original data. + +::: warning Please note +The default value is inserted in the generated validation code as a literal, so the value inserted in the data will be the deep clone of the default in the schema. +::: + +Example 1 (`default` in `properties`): + +```javascript +const ajv = new Ajv({useDefaults: true}) +const schema = { + type: "object", + properties: { + foo: {type: "number"}, + bar: {type: "string", default: "baz"}, + }, + required: ["foo", "bar"], +} + +const data = {foo: 1} + +const validate = ajv.compile(schema) + +console.log(validate(data)) // true +console.log(data) // { "foo": 1, "bar": "baz" } +``` + +Example 2 (`default` in `items`): + +```javascript +const schema = { + type: "array", + items: [{type: "number"}, {type: "string", default: "foo"}], +} + +const data = [1] + +const validate = ajv.compile(schema) + +console.log(validate(data)) // true +console.log(data) // [ 1, "foo" ] +``` + +With `useDefaults` option `default` keywords throws exception during schema compilation when used in: + +- not in `properties` or `items` subschemas +- in schemas inside `anyOf`, `oneOf` and `not` (see [#42](https://github.com/ajv-validator/ajv/issues/42)) +- in `if` schema +- in schemas generated by user-defined _macro_ keywords + +The strict mode option can change the behaviour for these unsupported defaults (`strict: false` to ignore them, `"log"` to log a warning). + +See [Strict mode](./strict-mode.md). + +## Coercing data types + +When you are validating user inputs all your data properties are usually strings. The option `coerceTypes` allows you to have your data types coerced to the types specified in your schema `type` keywords, both to pass the validation and to use the correctly typed data afterwards. + +This option modifies original data. + +::: warning Please note +If you pass a scalar value to the validating function its type will be coerced and it will pass the validation, but the value of the variable you pass won't be updated because scalars are passed by value. +::: + +Example 1: + +```javascript +const ajv = new Ajv({coerceTypes: true}) +const schema = { + type: "object", + properties: { + foo: {type: "number"}, + bar: {type: "boolean"}, + }, + required: ["foo", "bar"], +} + +const data = {foo: "1", bar: "false"} + +const validate = ajv.compile(schema) + +console.log(validate(data)) // true +console.log(data) // { "foo": 1, "bar": false } +``` + +Example 2 (array coercions): + +```javascript +const ajv = new Ajv({coerceTypes: "array"}) +const schema = { + properties: { + foo: {type: "array", items: {type: "number"}}, + bar: {type: "boolean"}, + }, +} + +const data = {foo: "1", bar: ["false"]} + +const validate = ajv.compile(schema) + +console.log(validate(data)) // true +console.log(data) // { "foo": [1], "bar": false } +``` + +The coercion rules, as you can see from the example, are different from JavaScript both to validate user input as expected and to have the coercion reversible (to correctly validate cases where different types are defined in subschemas of "anyOf" and other compound keywords). + +See [Type coercion rules](./coercion.md) for details. diff --git a/docs/guide/schema-language.md b/docs/guide/schema-language.md index c79df328d..335983705 100644 --- a/docs/guide/schema-language.md +++ b/docs/guide/schema-language.md @@ -2,6 +2,76 @@ [[toc]] +## JSON Type Definition + +Ajv supports the new specification focussed on defining cross-platform types of JSON messages/payloads - JSON Type Definition (JTD). See the informal reference of [JTD schema forms](../json-type-definition) and formal specification [RFC8927](https://datatracker.ietf.org/doc/rfc8927/). + +## JSON Schema + +Ajv supports most widely used drafts of JSON Schema specification. Please see the informal reference of available [JSON Schema validation keywords](../json-schema) and [specification drafts](https://json-schema.org/specification.html). + +### draft-04 + +Draft-04 is not included in Ajv v7, because of substantial differences it has with the following drafts: + +- different schema member for schema identifier (`id` in draft-04 instead of `$id`) +- different syntax of exclusiveMaximum/Minimum, that is difficult to support in one codebase, particularly with [$data reference](combining-schemas.md#data-reference) + +You can still use draft-04 schemas with Ajv v6 - while this is no longer actively developed, any security related issues would still be supported at least until 30/06/2021. To install: + +```bash +npm install ajv@6 +``` + +Migrating schemas from draft-04 to draft-07 is very easy with [ajv-cli](https://github.com/ajv-validator/ajv-cli) + +### draft-07 (and draft-06) + +These are the most widely used versions of JSON Schema specification, and they are supported with the main ajv export. + +```javascript +import Ajv from "ajv" +const ajv = new Ajv() +``` + +If you need to support draft-06 schemas you need to add additional meta-schema, but you may just change (or remove) `$schema` attribute in your schemas - no other changes are needed: + +```javascript +const draft6MetaSchema = require("ajv/dist/refs/json-schema-draft-06.json") +ajv.addMetaSchema(draft6MetaSchema) +``` + +### draft 2019-09 (and draft-2012-12) + +The main advantage of this JSON Schema version over draft-07 is the ability to spread the definition of records that do not allow additional properties across multiple schemas. If you do not need it, you might be better off with draft-07. + +To use Ajv with the support of all JSON Schema draft-2019-09/2020-12 features you need to use a different export: + +```javascript +import Ajv2019 from "ajv/dist/2019" +const ajv = new Ajv2019() +``` + +Optionally, you can add draft-07 meta-schema, to use both draft-07 and draft-2019-09 schemas in one Ajv instance: + +```javascript +const draft7MetaSchema = require("ajv/dist/refs/json-schema-draft-07.json") +ajv.addMetaSchema(draft7MetaSchema) +``` + +Draft-2019-09 support is provided via a separate export in order to avoid increasing the bundle and generated code size for draft-07 users. + +With this import Ajv supports the following features: + +- keywords [`unevaluatedProperties`](../json-schema.md#unevaluatedproperties) and [`unevaluatedItems`](../json-schema.md#unevaluateditems) +- keywords [`dependentRequired`](../json-schema.md#dependentrequired), [`dependentSchemas`](../json-schema.md#dependentschemas), [`maxContains`/`minContain`](../json-schema.md#maxcontains--mincontains) +- dynamic recursive references with [`recursiveAnchor`/`recursiveReference`] - see [Extending recursive schemas](./combining-schemas.md#extending-recursive-schemas) +- draft-2019-09 meta-schema is the default. + +::: warning Please note +Supporting dynamic recursive references and `unevaluatedProperties`/`unevaluatedItems` keywords adds additional generated code even to the validation functions where these features are not used (when possible, Ajv determines which properties/items are "unevaluated" at compilation time, but support for dynamic references always adds additional generated code). If you are not using these features in your schemas it is recommended to use default Ajv export with JSON-Schema draft-07 support. +::: + ## Comparison Both [JSON Schema](../json-schema.md) and [JSON Type Definition](../json-type-definition.md) are cross-platform specifications with implementations in multiple programming languages that define the shape of your JSON data. @@ -12,42 +82,49 @@ This section compares their pros/cons to help decide which specification fits yo ### JSON Schema -- Pros - - Wide specification adoption. - - Used as part of OpenAPI specification. - - Support of complex validation scenarios: - - untagged unions and boolean logic - - conditional schemas and dependencies - - restrictions on the number ranges and the size of strings, arrays and objects - - semantic validation with formats, patterns and content keywords - - distribute strict record definitions across multiple schemas (with unevaluatedProperties) - - Can be effectively used for validation of any JavaScript objects and configuration files. -- Cons - - Defines the collection of restrictions on the data, rather than the shape of the data. - - No standard support for tagged unions. - - Complex and error prone for the new users (Ajv has [strict mode](../strict-mode) enabled by default to compensate for it, but it is not cross-platform). - - Some parts of specification are difficult to implement, creating the risk of implementations divergence: - - reference resolution model - - unevaluatedProperties/unevaluatedItems - - dynamic recursive references - - Internet draft status (rather than RFC) +**Pros**: + +- Wide specification adoption. +- Used as part of OpenAPI specification. +- Support of complex validation scenarios: + - untagged unions and boolean logic + - conditional schemas and dependencies + - restrictions on the number ranges and the size of strings, arrays and objects + - semantic validation with formats, patterns and content keywords + - distribute strict record definitions across multiple schemas (with unevaluatedProperties) +- Can be effectively used for validation of any JavaScript objects and configuration files. + +**Cons**: + +- Defines the collection of restrictions on the data, rather than the shape of the data. +- No standard support for tagged unions. +- Complex and error prone for the new users (Ajv has [strict mode](../strict-mode) enabled by default to compensate for it, but it is not cross-platform). +- Some parts of specification are difficult to implement, creating the risk of implementations divergence: + - reference resolution model + - unevaluatedProperties/unevaluatedItems + - dynamic recursive references +- Internet draft status (rather than RFC) See [JSON Schema](../json-schema.md) for more information and the list of defined keywords. ### JSON Type Definition -- Pros: - - Aligned with type systems of many languages - can be used to generate type definitions and efficient parsers and serializers to/from these types. - - Very simple, enforcing the best practices for cross-platform JSON API modelling. - - Simple to implement, ensuring consistency across implementations. - - Defines the shape of JSON data via strictly defined schema forms (rather than the collection of restrictions). - - Effective support for tagged unions. - - Designed to protect against user mistakes. - - Approved as [RFC8927](https://datatracker.ietf.org/doc/rfc8927/) -- Cons: - - Limited, compared with JSON Schema - no support for untagged unions\*, conditionals, references between different schema files\*\*, etc. - - No meta-schema in the specification\*. - - Brand new - limited industry adoption (as of January 2021). +**Pros**: + +- Aligned with type systems of many languages - can be used to generate type definitions and efficient parsers and serializers to/from these types. +- Very simple, enforcing the best practices for cross-platform JSON API modelling. +- Simple to implement, ensuring consistency across implementations. +- Defines the shape of JSON data via strictly defined schema forms (rather than the collection of restrictions). +- Effective support for tagged unions. +- Designed to protect against user mistakes. +- Supports compilation of schemas to efficient [serializers and parsers](./getting-started.md#parsing-and-serializing-json) (no need to validate as a separate step) +- Approved as [RFC8927](https://datatracker.ietf.org/doc/rfc8927/) + +**Cons**: + +- Limited, compared with JSON Schema - no support for untagged unions\*, conditionals, references between different schema files\*\*, etc. +- No meta-schema in the specification\*. +- Brand new - limited industry adoption (as of January 2021). \* Ajv defines meta-schema for JTD schemas and non-standard keyword "union" that can be used inside "metadata" object. diff --git a/docs/standalone.md b/docs/guide/standalone.md similarity index 97% rename from docs/standalone.md rename to docs/guide/standalone.md index 1f8a0360c..7549286cd 100644 --- a/docs/standalone.md +++ b/docs/guide/standalone.md @@ -78,7 +78,7 @@ To support standalone code generation: - Ajv option `source.code` must be set to `true` - only `code` and `macro` user-defined keywords are supported (see [User defined keywords](./keywords.md)). -- when `code` keywords define variables in shared scope using `gen.scopeValue`, they must provide `code` property with the code snippet. See source code of pre-defined keywords for examples in [vocabularies folder](../lib/vocabularies). +- when `code` keywords define variables in shared scope using `gen.scopeValue`, they must provide `code` property with the code snippet. See source code of pre-defined keywords for examples in [vocabularies folder](https://github.com/ajv-validator/ajv/blob/master/lib/vocabularies). - if formats are used in standalone code, ajv option `code.formats` should contain the code snippet that will evaluate to an object with all used formats definition - it can be a call to `require("...")` with the correct path (relative to the location of saved module): ```javascript diff --git a/docs/guide/typescript.md b/docs/guide/typescript.md index a7a162dbd..5253f52c7 100644 --- a/docs/guide/typescript.md +++ b/docs/guide/typescript.md @@ -22,18 +22,18 @@ import Ajv, {JSONSchemaType} from "ajv" const ajv = new Ajv() // options can be passed, e.g. {allErrors: true} interface MyData { - foo: number - bar?: string +foo: number +bar?: string } const schema: JSONSchemaType = { - type: "object", - properties: { - foo: {type: "integer"}, - bar: {type: "string"} - }, - required: ["foo"], - additionalProperties: false +type: "object", +properties: { +foo: {type: "integer"}, +bar: {type: "string"} +}, +required: ["foo"], +additionalProperties: false } // validate is a type guard for MyData - type is inferred from schema type @@ -44,17 +44,18 @@ const validate = ajv.compile(schema) // const validate = ajv.compile(schema) const validData = { - foo: 1, - bar: "abc" +foo: 1, +bar: "abc" } if (validate(data)) { - // data is MyData here - console.log(data.foo) +// data is MyData here +console.log(data.foo) } else { - console.log(validate.errors) +console.log(validate.errors) } -``` + +```` @@ -95,7 +96,8 @@ if (validate(data)) { } else { console.log(validate.errors) } -`````` +```` + @@ -105,7 +107,7 @@ See [this test](https://github.com/ajv-validator/ajv/tree/master/spec/types/json With [JSON Schema](../json-schema), the validation error type is an open union, but it can be cast to a tagged union (using validation keyword as tag) for easier error handling. -This is not useful with [JSON Type Definition](../json-type-definition), as it defines errors for schema forms, not for keywords. +This is not useful with [JSON Type Definition](../json-type-definition), as it defines errors for schema forms, not for keywords. Continuing the example above: @@ -117,22 +119,23 @@ import {DefinedError} from "ajv" // ... if (validate(data)) { - // data is MyData here - console.log(data.foo) +// data is MyData here +console.log(data.foo) } else { - // The type cast is needed, as Ajv uses a wider type to allow extension - // You can extend this type to include your error types as needed. - for (const err of validate.errors as DefinedError[]) { - switch (err.keyword) { - case "type": - // err type is narrowed here to have "type" error params properties - console.log(err.params.type) - break - // ... - } - } +// The type cast is needed, as Ajv uses a wider type to allow extension +// You can extend this type to include your error types as needed. +for (const err of validate.errors as DefinedError[]) { +switch (err.keyword) { +case "type": +// err type is narrowed here to have "type" error params properties +console.log(err.params.type) +break +// ... +} +} } -``` + +```` @@ -200,6 +203,7 @@ function parseAndLogFoo(json: string): void { console.log(data.foo) } } -``` +```` + diff --git a/docs/guide/user-keywords.md b/docs/guide/user-keywords.md index 90557fab0..c178ecb15 100644 --- a/docs/guide/user-keywords.md +++ b/docs/guide/user-keywords.md @@ -14,9 +14,10 @@ If a keyword is used only for side-effects and its validation result is pre-defi ::: warning Please note When extending JSON Schema standard with additional keywords, you have several potential concerns to be aware of: + - portability of your schemas - they would only work with JavaScript or TypeScript applications where you can use Ajv. - additional documentation required to maintain your schemas. -::: + ::: ::: danger Please note While it is possible to define additional keywords for JSON Type Definition schemas (these keywords can only be used in `metadata` member of the schema), it is strongly recommended not to do it - JTD is specifically designed for cross-platform APIs. diff --git a/docs/json-schema.md b/docs/json-schema.md index 4b98ff2ad..2a5da20c2 100644 --- a/docs/json-schema.md +++ b/docs/json-schema.md @@ -15,9 +15,9 @@ v7 added support for all new keywords in draft-2019-09: - [dependentRequired](#dependentrequired) - [dependentSchemas](#dependentschemas) - [maxContains/minContains](#maxcontains--mincontains) -- [$recursiveAnchor/$recursiveRef](./validation.md#extending-recursive-schemas) +- [$recursiveAnchor/$recursiveRef](./guide/combining-schemas.md#extending-recursive-schemas) -There is also support for [$dynamicAnchor/$dynamicRef](./validation.md#extending-recursive-schemas) from the next version of JSON Schema draft that will replace `$recursiveAnchor`/`$recursiveRef`. +There is also support for [$dynamicAnchor/$dynamicRef](./guide/combining-schemas.md#extending-recursive-schemas) from the next version of JSON Schema draft that will replace `$recursiveAnchor`/`$recursiveRef`. ## `type` @@ -701,7 +701,7 @@ _valid_: `"foo"` _invalid_: any other value -The same can be achieved with `enum` keyword using the array with one item. But `const` keyword is more than just a syntax sugar for `enum`. In combination with the [\$data reference](./validation.md#data-reference) it allows to define equality relations between different parts of the data. This cannot be achieved with `enum` keyword even with `$data` reference because `$data` cannot be used in place of one item - it can only be used in place of the whole array in `enum` keyword. +The same can be achieved with `enum` keyword using the array with one item. But `const` keyword is more than just a syntax sugar for `enum`. In combination with the [$data reference](./guide/combining-schemas.md#data-reference) it allows to define equality relations between different parts of the data. This cannot be achieved with `enum` keyword even with `$data` reference because `$data` cannot be used in place of one item - it can only be used in place of the whole array in `enum` keyword. **Example** diff --git a/docs/json-type-definition.md b/docs/json-type-definition.md index 68db841d5..9cf260f84 100644 --- a/docs/json-type-definition.md +++ b/docs/json-type-definition.md @@ -391,7 +391,7 @@ Additional restrictions that Ajv enforces on `metadata` schema member: ### Union keyword -Ajv defines `union` keyword that is used in the schema that validates JTD schemas ([meta-schema](../lib/refs/jtd-schema.ts)). +Ajv defines `union` keyword that is used in the schema that validates JTD schemas ([meta-schema](https://github.com/ajv-validator/ajv/blob/master/lib/refs/jtd-schema.ts)). This keyword can be used only inside `metadata` schema member. diff --git a/docs/keywords.md b/docs/keywords.md index 740367ecd..834959871 100644 --- a/docs/keywords.md +++ b/docs/keywords.md @@ -19,11 +19,11 @@ interface _KeywordDef { } ``` -Keyword definitions may have additional optional properties - see [types](../lib/types/index.ts) and [KeywordCxt](../lib/compile/context.ts). +Keyword definitions may have additional optional properties - see [types](https://github.com/ajv-validator/ajv/blob/master/lib/types/index.ts) and [KeywordCxt](https://github.com/ajv-validator/ajv/blob/master/lib/compile/context.ts). ### Define keyword with code generation function -Starting from v7 Ajv uses [CodeGen module](../lib/compile/codegen/index.ts) for all pre-defined keywords - see [codegen.md](./codegen.md) for details. +Starting from v7 Ajv uses [CodeGen module](https://github.com/ajv-validator/ajv/blob/master/lib/compile/codegen/index.ts) for all pre-defined keywords - see [codegen.md](./codegen.md) for details. This is the best approach for user defined keywords: @@ -51,7 +51,7 @@ ajv.addKeyword({ keyword: "even", type: "number", schemaType: "boolean", - // $data: true // to support [$data reference](./validation.md#data-reference), ... + // $data: true // to support [$data reference](./guide/combining-schemas.md#data-reference), ... code(cxt: KeywordCxt) { const {data, schema} = cxt const op = schema ? _`!==` : _`===` @@ -88,9 +88,9 @@ ajv.addKeyword({ }) ``` -You can review pre-defined Ajv keywords in [validation](../lib/validation) folder for more advanced examples - it is much easier to define code generation keywords than it was in the previous version of Ajv. +You can review pre-defined Ajv keywords in [validation](https://github.com/ajv-validator/ajv/blob/master/lib/validation) folder for more advanced examples - it is much easier to define code generation keywords than it was in the previous version of Ajv. -See [KeywordCxt](../lib/compile/context.ts) and [SchemaCxt](../lib/compile/index.ts) type definitions for more information about properties you can use in your keywords. +See [KeywordCxt](https://github.com/ajv-validator/ajv/blob/master/lib/compile/context.ts) and [SchemaCxt](https://github.com/ajv-validator/ajv/blob/master/lib/compile/index.ts) type definitions for more information about properties you can use in your keywords. ### Define keyword with "validate" function @@ -126,7 +126,7 @@ The function should return validation result as boolean. It can return an array - testing your keywords before converting them to compiled/code keywords - defining keywords that do not depend on the schema value (e.g., when the value is always `true`). In this case you can add option `schema: false` to the keyword definition and the schemas won't be passed to the validation function, it will only receive the same parameters as compiled validation function. - defining keywords where the schema is a value used in some expression. -- defining keywords that support [\$data reference](./validation.md#data-reference) - in this case `validate` or `code` function is required, either as the only option or in addition to `compile` or `macro`. +- defining keywords that support [\$data reference](./guide/combining-schemas.md#data-reference) - in this case `validate` or `code` function is required, either as the only option or in addition to `compile` or `macro`. Example: `constant` keyword (a synonym for draft-06 keyword `const`, it is equivalent to `enum` keyword with one item): @@ -243,11 +243,11 @@ Macro keywords an be recursive - i.e. return schemas containing the same keyword ## Schema compilation context -Schema compilation context [SchemaCxt](../lib/compile/index.ts) is available in property `it` of [KeywordCxt](../lib/compile/context.ts) (and it is also the 3rd parameter of `compile` and `macro` keyword functions). See types in the source code on the properties you can use in this object. +Schema compilation context [SchemaCxt](https://github.com/ajv-validator/ajv/blob/master/lib/compile/index.ts) is available in property `it` of [KeywordCxt](https://github.com/ajv-validator/ajv/blob/master/lib/compile/context.ts) (and it is also the 3rd parameter of `compile` and `macro` keyword functions). See types in the source code on the properties you can use in this object. ## Validation time variables -All function scoped variables available during validation are defined in [names](../lib/compile/names.ts). +All function scoped variables available during validation are defined in [names](https://github.com/ajv-validator/ajv/blob/master/lib/compile/names.ts). ## Reporting errors diff --git a/docs/options.md b/docs/options.md new file mode 100644 index 000000000..59c43f124 --- /dev/null +++ b/docs/options.md @@ -0,0 +1,302 @@ +# Initialization options + +[[toc]] + +## Usage + +This page describes properties of the options object that can be passed to Ajv constructor. + +For example, to report all validation errors (rather than failing on the first errors) you should pass `allErrors` option to constructor: + +```javascript +const ajv = new Ajv({allErrors: true}) +``` + +## Option defaults + +::: tip Please note +Passing the value below for some of the options is equivalent to not passing this option at all. There is no need to pass default option values - it is recommended to only pass option values that are different from defaults. +::: + +```javascript +// see types/index.ts for actual types +const defaultOptions = { + // strict mode options (NEW) + strict: true, + strictTypes: "log", // * + strictTuples: "log", // * + strictRequired: false, // * + allowUnionTypes: false, // * + allowMatchingProperties: false, // * + validateFormats: true, // * + // validation and reporting options: + $data: false, // * + allErrors: false, + verbose: false, // * + $comment: false, // * + formats: {}, + keywords: {}, + schemas: {}, + logger: undefined, + loadSchema: undefined, // *, function(uri: string): Promise {} + // options to modify validated data: + removeAdditional: false, + useDefaults: false, // * + coerceTypes: false, // * + // advanced options: + meta: true, + validateSchema: true, + addUsedSchema: true, + inlineRefs: true, + passContext: false, + loopRequired: Infinity, // * + loopEnum: Infinity, // NEW + ownProperties: false, + multipleOfPrecision: undefined, // * + messages: true, // false with JTD + ajvErrors: false // only with JTD + code: { + // NEW + es5: false, + lines: false, + source: false, + process: undefined, // (code: string) => string + optimize: true, + }, +} +``` + +\* these options are not supported with JSON Type Definition schemas + +## Strict mode options + +### strict + +By default Ajv executes in strict mode, that is designed to prevent any unexpected behaviours or silently ignored mistakes in schemas (see [Strict Mode](./strict-mode.md) for more details). It does not change any validation results, but it makes some schemas invalid that would be otherwise valid according to JSON Schema specification. + +Option values: + +- `true` (default) - use strict mode and throw an exception when any strict mode restriction is violated. +- `"log"` - log warning when any strict mode restriction is violated. +- `false` - ignore all strict mode restrictions. Also ignores `strictTypes` restrictions unless it is explicitly passed. + +### strictTypes + +By default Ajv logs warning when "type" keyword is used in a way that may be incorrect or confusing to other people - see [Strict types](./strict-mode.md#strict-types) for more details. This option does not change validation results. + +Option values: + +- `true` - throw exception when any strictTypes restriction is violated. +- `"log"` (default, unless option strict is `false`) - log warning when any strictTypes restriction is violated. +- `false` - ignore all strictTypes restrictions violations. + +### strictTuples + +By default Ajv logs warning when "items" is array and "minItems" and "maxItems"/"additionalItems" not present or different from the number of items. See [Strict mode](./strict-mode.md) for more details. This option does not change validation results. + +Option values: + +- `true` - throw exception. +- `"log"` (default, unless option strict is `false`) - log warning. +- `false` - ignore strictTuples restriction violations. + +### strictRequired + +Ajv can log warning or throw exception when the property used in "required" keyword is not defined in "properties" keyword. See [Strict mode](./strict-mode.md) for more details. This option does not change validation results. + +Option values: + +- `true` - throw exception. +- `"log"` - log warning. +- `false` (default) - ignore strictRequired restriction violations. + +### allowUnionTypes + +Pass true to allow using multiple non-null types in "type" keyword (one of `strictTypes` restrictions). see [Strict types](./strict-mode.md#strict-types) + +### allowMatchingProperties + +Pass true to allow overlap between "properties" and "patternProperties". Does not affect other strict mode restrictions. See [Strict Mode](./strict-mode.md). + +### validateFormats + +Format validation. + +Option values: + +- `true` (default) - validate formats (see [Formats](./validation.md#formats)). In [strict mode](./strict-mode.md) unknown formats will throw exception during schema compilation (and fail validation in case format keyword value is [\$data reference](./guide/combining-schemas.md#data-reference)). +- `false` - do not validate any format keywords (TODO they will still collect annotations once supported). + +## Validation and reporting options + +### $data + +Support [\$data references](./guide/combining-schemas.md#data-reference). Draft 6 meta-schema that is added by default will be extended to allow them. If you want to use another meta-schema you need to use $dataMetaSchema method to add support for $data reference. See [API](#ajv-constructor-and-methods). + +### allErrors + +Check all rules collecting all errors. Default is to return after the first error. + +### verbose + +Include the reference to the part of the schema (`schema` and `parentSchema`) and validated data in errors (false by default). + +### $comment + +Log or pass the value of `$comment` keyword to a function. + +Option values: + +- `false` (default): ignore \$comment keyword. +- `true`: log the keyword value to console. +- function: pass the keyword value, its schema path and root schema to the specified function + +### formats + +An object with format definitions. Keys and values will be passed to `addFormat` method. Pass `true` as format definition to ignore some formats. + +### keywords + +An array of keyword definitions or strings. Values will be passed to `addKeyword` method. + +### schemas + +An array or object of schemas that will be added to the instance. In case you pass the array the schemas must have IDs in them. When the object is passed the method `addSchema(value, key)` will be called for each schema in this object. + +### logger + +Sets the logging method. Default is the global `console` object that should have methods `log`, `warn` and `error`. See [Error logging](#error-logging). + +Option values: + +- logger instance - it should have methods `log`, `warn` and `error`. If any of these methods is missing an exception will be thrown. +- `false` - logging is disabled. + +### loadSchema + +Asynchronous function that will be used to load remote schemas when `compileAsync` [method](#api-compileAsync) is used and some reference is missing (option `missingRefs` should NOT be 'fail' or 'ignore'). This function should accept remote schema uri as a parameter and return a Promise that resolves to a schema. See example in [Asynchronous compilation](./validation.md#asynchronous-schema-compilation). + +## Options to modify validated data + +### removeAdditional + +Remove additional properties - see example in [Removing additional properties](./validation.md#removing-additional-properties). + +This option is not used if schema is added with `addMetaSchema` method. + +Option values: + +- `false` (default) - not to remove additional properties +- `"all"` - all additional properties are removed, regardless of `additionalProperties` keyword in schema (and no validation is made for them). +- `true` - only additional properties with `additionalProperties` keyword equal to `false` are removed. +- `"failing"` - additional properties that fail schema validation will be removed (where `additionalProperties` keyword is `false` or schema). + +### useDefaults + +Replace missing or undefined properties and items with the values from corresponding `default` keywords. Default behaviour is to ignore `default` keywords. This option is not used if schema is added with `addMetaSchema` method. + +See examples in [Assigning defaults](./validation.md#assigning-defaults). + +Option values: + +- `false` (default) - do not use defaults +- `true` - insert defaults by value (object literal is used). +- `"empty"` - in addition to missing or undefined, use defaults for properties and items that are equal to `null` or `""` (an empty string). + +### coerceTypes + +Change data type of data to match `type` keyword. See the example in [Coercing data types](./validation.md#coercing-data-types) and [coercion rules](./coercion.md). + +Option values: + +- `false` (default) - no type coercion. +- `true` - coerce scalar data types. +- `"array"` - in addition to coercions between scalar types, coerce scalar data to an array with one element and vice versa (as required by the schema). + +## Advanced options + +### meta + +Add [meta-schema](http://json-schema.org/documentation.html) so it can be used by other schemas (true by default). If an object is passed, it will be used as the default meta-schema for schemas that have no `$schema` keyword. This default meta-schema MUST have `$schema` keyword. + +### validateSchema + +Validate added/compiled schemas against meta-schema (true by default). `$schema` property in the schema can be http://json-schema.org/draft-07/schema or absent (draft-07 meta-schema will be used) or can be a reference to the schema previously added with `addMetaSchema` method. + +Option values: + +- `true` (default) - if the validation fails, throw the exception. +- `"log"` - if the validation fails, log error. +- `false` - skip schema validation. + +### addUsedSchema + +By default methods `compile` and `validate` add schemas to the instance if they have `$id` (or `id`) property that doesn't start with "#". If `$id` is present and it is not unique the exception will be thrown. Set this option to `false` to skip adding schemas to the instance and the `$id` uniqueness check when these methods are used. This option does not affect `addSchema` method. + +### inlineRefs + +Affects compilation of referenced schemas. + +Option values: + +- `true` (default) - the referenced schemas that don't have refs in them are inlined, regardless of their size - it improves performance. +- `false` - to not inline referenced schemas (they will always be compiled as separate functions). +- integer number - to limit the maximum number of keywords of the schema that will be inlined (to balance the total size of compiled functions and performance). + +### passContext + +Pass validation context to _compile_ and _validate_ keyword functions. If this option is `true` and you pass some context to the compiled validation function with `validate.call(context, data)`, the `context` will be available as `this` in your keywords. By default `this` is Ajv instance. + +### loopRequired + +By default `required` keyword is compiled into a single expression (or a sequence of statements in `allErrors` mode). In case of a very large number of properties in this keyword it may result in a very big validation function. Pass integer to set the number of properties above which `required` keyword will be validated in a loop - smaller validation function size but also worse performance. + +### loopEnum + +By default `enum` keyword is compiled into a single expression. In case of a very large number of allowed values it may result in a large validation function. Pass integer to set the number of values above which `enum` keyword will be validated in a loop. + +### ownProperties + +By default Ajv iterates over all enumerable object properties; when this option is `true` only own enumerable object properties (i.e. found directly on the object rather than on its prototype) are iterated. Contributed by @mbroadst. + +### multipleOfPrecision + +By default `multipleOf` keyword is validated by comparing the result of division with `parseInt()` of that result. It works for dividers that are bigger than 1. For small dividers such as 0.01 the result of the division is usually not integer (even when it should be integer, see issue [#84](https://github.com/ajv-validator/ajv/issues/84)). If you need to use fractional dividers set this option to some positive integer N to have `multipleOf` validated using this formula: `Math.abs(Math.round(division) - division) < 1e-N` (it is slower but allows for float arithmetic deviations). + +### messages + +Include human-readable messages in errors. `true` by default. `false` can be passed when messages are generated outside of Ajv code (e.g. with [ajv-i18n](https://github.com/ajv-validator/ajv-i18n)). + +### ajvErrors + +This option is only supported with JTD schemas to generate error objects with the properties described in the first part of [Validation errors](#validation-errors) section, otherwise JTD errors are generated when JTD schemas are used (see the second part of [the same section](#validation-errors)). + +### code + +Code generation options: + +```typescript +type CodeOptions = { + es5?: boolean // to generate es5 code - by default code is es6, with "for-of" loops, "let" and "const" + lines?: boolean // add line-breaks to code - to simplify debugging of generated functions + source?: boolean // add `source` property (see Source below) to validating function. + process?: (code: string, schema?: SchemaEnv) => string // an optional function to process generated code + // before it is passed to Function constructor. + // It can be used to either beautify or to transpile code. + optimize?: boolean | number // code optimization flag or number of passes, 1 pass by default, + // code optimizations reduce the size of the generated code (bytes, based on the tests) by over 10%, + // the number of code tree nodes by nearly 17%. + // You would almost never need more than one optimization pass, unless you have some really complex schemas - + // the second pass in the tests (it has quite complex schemas) only improves optimization by less than 0.1%. + // See [Code optimization](./codegen.md#code-optimization) for details. + formats?: Code + // Code snippet created with `_` tagged template literal that contains all format definitions, + // it can be the code of actual definitions or `require` call: + // _`require("./my-formats")` +} + +type Source = { + code: string // unlike func.toString() it includes assignments external to function scope + scope: Scope // see Code generation (TODO) +} +``` diff --git a/docs/security.md b/docs/security.md index 49cd3518f..419fd90c1 100644 --- a/docs/security.md +++ b/docs/security.md @@ -42,7 +42,7 @@ Some keywords in JSON Schemas can lead to very slow validation for certain data. The suggestions above to prevent slow validation would only work if you do NOT use `allErrors: true` in production code (using it would continue validation after validation errors). ::: -You can validate your JSON schemas against [this meta-schema](../lib/refs/json-schema-secure.json) to check that these recommendations are followed: +You can validate your JSON schemas against [this meta-schema](https://github.com/ajv-validator/ajv/blob/master/lib/refs/json-schema-secure.json) to check that these recommendations are followed: ```javascript ajv = new Ajv({strictTypes: false}) // this option is required for this schema diff --git a/docs/strict-mode.md b/docs/strict-mode.md index a9d35c44e..493916ba7 100644 --- a/docs/strict-mode.md +++ b/docs/strict-mode.md @@ -68,7 +68,7 @@ By default Ajv fails schema compilation in these cases. #### Unknown formats -By default unknown formats throw exception during schema compilation (and fail validation in case format keyword value is [\$data reference](./validation.md#data-reference)). It is possible to opt out of format validation completely with options `validateFormats: false`. You can define all known formats with `addFormat` method or `formats` option - to have some format ignored pass `true` as its definition: +By default unknown formats throw exception during schema compilation (and fail validation in case format keyword value is [\$data reference](./guide/combining-schemas.md#data-reference)). It is possible to opt out of format validation completely with options `validateFormats: false`. You can define all known formats with `addFormat` method or `formats` option - to have some format ignored pass `true` as its definition: ```javascript const ajv = new Ajv({formats: { diff --git a/docs/validation.md b/docs/validation.md deleted file mode 100644 index b27580751..000000000 --- a/docs/validation.md +++ /dev/null @@ -1,407 +0,0 @@ -# Data validation - -[[toc]] - -## JSON Schema draft-2019-09 - -The default export of Ajv provides support of JSON-Schema draft-07, without any of draft-2019-09 features: - -```javascript -import Ajv from "ajv" -// const Ajv = require("ajv").default -const ajv = new Ajv() -``` - -To use Ajv with the support of all JSON Schema draft-2019-09 features you need to use a different export: - -```javascript -import Ajv from "ajv/dist/2019" -// const Ajv2019 = require("ajv/dist/2019").default -const ajv = new Ajv2019() -``` - -Optionally, you can add draft-07 meta-schema, to use both draft-07 and draft-2019-09 schemas in one Ajv instance: - -```javascript -const draft7MetaSchema = require("ajv/dist/refs/json-schema-draft-07.json") -ajv.addMetaSchema(draft7MetaSchema) -``` - -Draft-2019-09 support is provided via a separate export in order to avoid increasing the bundle and generated code size for draft-07 users. - -With this import Ajv supports the following features: - -- keywords [`unevaluatedProperties`](./json-schema.md#unevaluatedproperties) and [`unevaluatedItems`](./json-schema.md#unevaluateditems) -- keywords [`dependentRequired`](./json-schema.md#dependentrequired), [`dependentSchemas`](./json-schema.md#dependentschemas), [`maxContains`/`minContain`](./json-schema.md#maxcontains--mincontains) -- dynamic recursive references with [`recursiveAnchor`/`recursiveReference`] - see [Extending recursive schemas](#extending-recursive-schemas) -- draft-2019-09 meta-schema is the default. - -::: warning Please note -Supporting dynamic recursive references and `unevaluatedProperties/Items` adds additional generated code even to the validation functions where these features are not used (when possible, Ajv determines which properties/items are "unevaluated" at compilation time, but support for dynamic references always adds additional generated code). If you are not using these features in your schemas it is recommended to use default Ajv export with JSON-Schema draft-07 support. -::: - -You can also use individual draft-2019-09 features to Ajv with the advanced options `dynamicRef`, `next` and `unevaluated`. These options are changing how the code is generated for draft-07 keywords to support the new features of draft-2019-09, but they do not add the new keywords - they should be added separately. The code examples below shows how to enable individual draft-2019-09 features: - -```javascript -import Ajv from "ajv" -// const Ajv = require("ajv").default - -// add support for unevaluatedProperties and unevaluatedItems without other 2019-09 features -const ajv = new Ajv({unevaluated: true}) -import unevaluatedVocabulary from "ajv/dist/vocabularies/unevaluated" -// const unevaluatedVocabulary = require("ajv/dist/vocabularies/unevaluated").default -ajv.addVocabulary(unevaluatedVocabulary) - -// add support for dependentRequired, dependentSchemas, maxContains and minContains -const ajv = new Ajv({next: true}) -import nextVocabulary from "ajv/dist/vocabularies/next" -// const nextVocabulary = require("ajv/dist/vocabularies/next").default -ajv.addVocabulary(nextVocabulary) - -// add support for dynamic recursive references -const ajv = new Ajv({dynamicRef: true}) -import dynamicVocabulary from "ajv/dist/vocabularies/dynamic" -// const dynamicVocabulary = require("ajv/dist/vocabularies/dynamic").default -ajv.addVocabulary(dynamicVocabulary) -``` - -If you want to have support of all these features you should import Ajv from `"ajv/dist/2019"` as shown above. - -## Validation basics - -### JSON Schema validation keywords - -Ajv supports all validation keywords from draft-07 of JSON Schema standard - see [JSON Schema validation keywords](./json-schema.md) for more details. - -[ajv-keywords](https://github.com/ajv-validator/ajv-keywords) package provides additional validation keywords that can be used with Ajv. - -### Formats - -From version 7 Ajv does not include formats defined by JSON Schema specification - these and several other formats are provided by [ajv-formats](https://github.com/ajv-validator/ajv-formats) plugin. - -To add all formats from this plugin: - -```javascript -import Ajv from "ajv" -import addFormats from "ajv-formats" - -const ajv = new Ajv() -addFormats(ajv) -``` - -See ajv-formats documentation for further details. - -It is recommended NOT to use "format" keyword implementations with untrusted data, as they may use potentially unsafe regular expressions (even though known issues are fixed) - see [ReDoS attack](./security.md#redos-attack). - -::: danger Please note -If you need to use "format" keyword to validate untrusted data, you MUST assess their suitability and safety for your validation scenarios. -::: - -The following formats are defined in [ajv-formats](https://github.com/ajv-validator/ajv-formats) for string validation with "format" keyword: - -- _date_: full-date according to [RFC3339](http://tools.ietf.org/html/rfc3339#section-5.6). -- _time_: time with optional time-zone. -- _date-time_: date-time from the same source (time-zone is mandatory). -- _duration_: duration from [RFC3339](https://tools.ietf.org/html/rfc3339#appendix-A) -- _uri_: full URI. -- _uri-reference_: URI reference, including full and relative URIs. -- _uri-template_: URI template according to [RFC6570](https://datatracker.ietf.org/doc/rfc6570/) -- _url_ (deprecated): [URL record](https://url.spec.whatwg.org/#concept-url). -- _email_: email address. -- _hostname_: host name according to [RFC1034](http://tools.ietf.org/html/rfc1034#section-3.5). -- _ipv4_: IP address v4. -- _ipv6_: IP address v6. -- _regex_: tests whether a string is a valid regular expression by passing it to RegExp constructor. -- _uuid_: Universally Unique Identifier according to [RFC4122](https://datatracker.ietf.org/doc/rfc4122/). -- _json-pointer_: JSON-pointer according to [RFC6901](https://datatracker.ietf.org/doc/rfc6901/). -- _relative-json-pointer_: relative JSON-pointer according to [this draft](http://tools.ietf.org/html/draft-luff-relative-json-pointer-00). - -::: warning Please note -JSON Schema draft-07 also defines formats `iri`, `iri-reference`, `idn-hostname` and `idn-email` for URLs, hostnames and emails with international characters. These formats are available in [ajv-formats-draft2019](https://github.com/luzlab/ajv-formats-draft2019) plugin. -::: - -You can add and replace any formats using [addFormat](./api.md#api-addformat) method. - -## Asynchronous validation - -Example in Node.js REPL: https://runkit.com/esp/ajv-asynchronous-validation - -You can define formats and keywords that perform validation asynchronously by accessing database or some other service. You should add `async: true` in the keyword or format definition (see [addFormat](./api.md#api-addformat), [addKeyword](./api.md#api-addkeyword) and [User-defined keywords](./keywords.md)). - -If your schema uses asynchronous formats/keywords or refers to some schema that contains them it should have `"$async": true` keyword so that Ajv can compile it correctly. If asynchronous format/keyword or reference to asynchronous schema is used in the schema without `$async` keyword Ajv will throw an exception during schema compilation. - -::: warning Please note -All asynchronous subschemas that are referenced from the current or other schemas should have `"$async": true` keyword as well, otherwise the schema compilation will fail. -::: - -Validation function for an asynchronous format/keyword should return a promise that resolves with `true` or `false` (or rejects with `new Ajv.ValidationError(errors)` if you want to return errors from the keyword function). - -Ajv compiles asynchronous schemas to [async functions](http://tc39.github.io/ecmascript-asyncawait/). Async functions are supported in Node.js 7+ and all modern browsers. You can supply a transpiler as a function via `processCode` option. See [Options](./api.md#options). - -The compiled validation function has `$async: true` property (if the schema is asynchronous), so you can differentiate these functions if you are using both synchronous and asynchronous schemas. - -Validation result will be a promise that resolves with validated data or rejects with an exception `Ajv.ValidationError` that contains the array of validation errors in `errors` property. - -Example: - -```javascript -const ajv = new Ajv() - -ajv.addKeyword({ - keyword: "idExists" - async: true, - type: "number", - validate: checkIdExists, -}) - -function checkIdExists(schema, data) { - return knex(schema.table) - .select("id") - .where("id", data) - .then(function (rows) { - return !!rows.length // true if record is found - }) -} - -const schema = { - $async: true, - properties: { - userId: { - type: "integer", - idExists: {table: "users"}, - }, - postId: { - type: "integer", - idExists: {table: "posts"}, - }, - }, -} - -const validate = ajv.compile(schema) - -validate({userId: 1, postId: 19}) - .then(function (data) { - console.log("Data is valid", data) // { userId: 1, postId: 19 } - }) - .catch(function (err) { - if (!(err instanceof Ajv.ValidationError)) throw err - // data is invalid - console.log("Validation errors:", err.errors) - }) -``` - -### Using transpilers - -```javascript -const ajv = new Ajv({processCode: transpileFunc}) -const validate = ajv.compile(schema) // transpiled es7 async function -validate(data).then(successFunc).catch(errorFunc) -``` - -See [Options](./api.md#options). - -## Modifying data during validation - -### Removing additional properties - -With [option `removeAdditional`](./api.md#options) (added by [andyscott](https://github.com/andyscott)) you can filter data during the validation. - -This option modifies original data. - -Example: - -```javascript -const ajv = new Ajv({removeAdditional: true}) -const schema = { - additionalProperties: false, - properties: { - foo: {type: "number"}, - bar: { - additionalProperties: {type: "number"}, - properties: { - baz: {type: "string"}, - }, - }, - }, -} - -const data = { - foo: 0, - additional1: 1, // will be removed; `additionalProperties` == false - bar: { - baz: "abc", - additional2: 2, // will NOT be removed; `additionalProperties` != false - }, -} - -const validate = ajv.compile(schema) - -console.log(validate(data)) // true -console.log(data) // { "foo": 0, "bar": { "baz": "abc", "additional2": 2 } -``` - -If `removeAdditional` option in the example above were `"all"` then both `additional1` and `additional2` properties would have been removed. - -If the option were `"failing"` then property `additional1` would have been removed regardless of its value and property `additional2` would have been removed only if its value were failing the schema in the inner `additionalProperties` (so in the example above it would have stayed because it passes the schema, but any non-number would have been removed). - -::: warning Please note -If you use `removeAdditional` option with `additionalProperties` keyword inside `anyOf`/`oneOf` keywords your validation can fail with this schema -::: - -For example: - -```javascript -{ - type: "object", - oneOf: [ - { - properties: { - foo: {type: "string"} - }, - required: ["foo"], - additionalProperties: false - }, - { - properties: { - bar: {type: "integer"} - }, - required: ["bar"], - additionalProperties: false - } - ] -} -``` - -The intention of the schema above is to allow objects with either the string property "foo" or the integer property "bar", but not with both and not with any other properties. - -With the option `removeAdditional: true` the validation will pass for the object `{ "foo": "abc"}` but will fail for the object `{"bar": 1}`. It happens because while the first subschema in `oneOf` is validated, the property `bar` is removed because it is an additional property according to the standard (because it is not included in `properties` keyword in the same schema). - -While this behaviour is unexpected (issues [#129](https://github.com/ajv-validator/ajv/issues/129), [#134](https://github.com/ajv-validator/ajv/issues/134)), it is correct. To have the expected behaviour (both objects are allowed and additional properties are removed) the schema has to be refactored in this way: - -```javascript -{ - type: "object", - properties: { - foo: {type: "string"}, - bar: {type: "integer"} - }, - additionalProperties: false, - oneOf: [{required: ["foo"]}, {required: ["bar"]}] -} -``` - -The schema above is also more efficient - it will compile into a faster function. - -### Assigning defaults - -With [option `useDefaults`](./api.md#options) Ajv will assign values from `default` keyword in the schemas of `properties` and `items` (when it is the array of schemas) to the missing properties and items. - -With the option value `"empty"` properties and items equal to `null` or `""` (empty string) will be considered missing and assigned defaults. - -This option modifies original data. - -::: warning Please note -The default value is inserted in the generated validation code as a literal, so the value inserted in the data will be the deep clone of the default in the schema. -::: - -Example 1 (`default` in `properties`): - -```javascript -const ajv = new Ajv({useDefaults: true}) -const schema = { - type: "object", - properties: { - foo: {type: "number"}, - bar: {type: "string", default: "baz"}, - }, - required: ["foo", "bar"], -} - -const data = {foo: 1} - -const validate = ajv.compile(schema) - -console.log(validate(data)) // true -console.log(data) // { "foo": 1, "bar": "baz" } -``` - -Example 2 (`default` in `items`): - -```javascript -const schema = { - type: "array", - items: [{type: "number"}, {type: "string", default: "foo"}], -} - -const data = [1] - -const validate = ajv.compile(schema) - -console.log(validate(data)) // true -console.log(data) // [ 1, "foo" ] -``` - -With `useDefaults` option `default` keywords throws exception during schema compilation when used in: - -- not in `properties` or `items` subschemas -- in schemas inside `anyOf`, `oneOf` and `not` (see [#42](https://github.com/ajv-validator/ajv/issues/42)) -- in `if` schema -- in schemas generated by user-defined _macro_ keywords - -The strict mode option can change the behaviour for these unsupported defaults (`strict: false` to ignore them, `"log"` to log a warning). - -See [Strict mode](./strict-mode.md). - -### Coercing data types - -When you are validating user inputs all your data properties are usually strings. The option `coerceTypes` allows you to have your data types coerced to the types specified in your schema `type` keywords, both to pass the validation and to use the correctly typed data afterwards. - -This option modifies original data. - -::: warning Please note -If you pass a scalar value to the validating function its type will be coerced and it will pass the validation, but the value of the variable you pass won't be updated because scalars are passed by value. -::: - -Example 1: - -```javascript -const ajv = new Ajv({coerceTypes: true}) -const schema = { - type: "object", - properties: { - foo: {type: "number"}, - bar: {type: "boolean"}, - }, - required: ["foo", "bar"], -} - -const data = {foo: "1", bar: "false"} - -const validate = ajv.compile(schema) - -console.log(validate(data)) // true -console.log(data) // { "foo": 1, "bar": false } -``` - -Example 2 (array coercions): - -```javascript -const ajv = new Ajv({coerceTypes: "array"}) -const schema = { - properties: { - foo: {type: "array", items: {type: "number"}}, - bar: {type: "boolean"}, - }, -} - -const data = {foo: "1", bar: ["false"]} - -const validate = ajv.compile(schema) - -console.log(validate(data)) // true -console.log(data) // { "foo": [1], "bar": false } -``` - -The coercion rules, as you can see from the example, are different from JavaScript both to validate user input as expected and to have the coercion reversible (to correctly validate cases where different types are defined in subschemas of "anyOf" and other compound keywords). - -See [Coercion rules](./coercion.md) for details. diff --git a/lib/types/index.ts b/lib/types/index.ts index 79ffa12df..7aa1c32f6 100644 --- a/lib/types/index.ts +++ b/lib/types/index.ts @@ -102,7 +102,7 @@ interface _KeywordDef { type?: JSONType | JSONType[] // data types that keyword applies to schemaType?: JSONType | JSONType[] // allowed type(s) of keyword value in the schema allowUndefined?: boolean // used for keywords that can be invoked by other keywords, not being present in the schema - $data?: boolean // keyword supports [$data reference](../../docs/validation.md#data-reference) + $data?: boolean // keyword supports [$data reference](../../docs/guide/combining-schemas.md#data-reference) implements?: string[] // other schema keywords that this keyword implements before?: string // keyword should be executed before this keyword (should be applicable to the same type) post?: boolean // keyword should be executed after other keywords without post flag From 0aeb9b137eeae914cb1bbd91c63bbcfd32de8d11 Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Sat, 6 Mar 2021 12:49:39 +0000 Subject: [PATCH 10/25] site/docs: remove duplications from readme --- README.md | 232 +-------------------------- docs/.vuepress/config.js | 6 +- docs/OLD_README.md | 281 --------------------------------- docs/guide/schema-language.md | 10 +- docs/{guide => }/standalone.md | 0 5 files changed, 14 insertions(+), 515 deletions(-) delete mode 100644 docs/OLD_README.md rename docs/{guide => }/standalone.md (100%) diff --git a/README.md b/README.md index 745cdd634..7e981178d 100644 --- a/README.md +++ b/README.md @@ -74,14 +74,12 @@ Please review [Contributing guidelines](./CONTRIBUTING.md) and [Code components] - [Performance](#performance) - [Features](#features) - [Getting started](#usage) -- [Choosing schema language](#choosing-schema-language) - - [JSON Schema](#json-schema) - - [JSON Type Definition](#json-type-definition) +- [Choosing schema language: JSON Schema vs JSON Type Definition](./docs/guide/schema-language.md#comparison) - [Frequently Asked Questions](./docs/faq.md) -- [Using in browser](#using-in-browser) +- [Using in browser](./docs/guide/environments.md#browsers) - [Content Security Policy](./docs/security.md#content-security-policy) -- [Using in ES5 environment](#using-in-es5-environment) -- [Command line interface](#command-line-interface) +- [Using in ES5 environment](./docs/guide/environments.md#es5-environments) +- [Command line interface](./docs/guide/environments.md#command-line-interface) - [API reference](./docs/api.md) - [Methods](./docs/api.md#ajv-constructor-and-methods) - [Options](./docs/api.md#options) @@ -225,227 +223,7 @@ const valid = validate(data) if (!valid) console.log(validate.errors) ``` -In TypeScript: - -```typescript -import Ajv, {JSONSchemaType, DefinedError} from "ajv" - -const ajv = new Ajv() - -type MyData = {foo: number} - -// Optional schema type annotation for schema to match MyData type. -// To use JSONSchemaType set `strictNullChecks: true` in tsconfig `compilerOptions`. -const schema: JSONSchemaType = { - type: "object", - properties: { - foo: {type: "number", minimum: 0}, - }, - required: ["foo"], - additionalProperties: false, -} - -// validate is a type guard for MyData - type is inferred from schema type -const validate = ajv.compile(schema) - -// or, if you did not use type annotation for the schema, -// type parameter can be used to make it type guard: -// const validate = ajv.compile(schema) - -const data: any = {foo: 1} - -if (validate(data)) { - // data is MyData here - console.log(data.foo) -} else { - // The type cast is needed to allow user-defined keywords and errors - // You can extend this type to include your error types as needed. - for (const err of validate.errors as DefinedError[]) { - switch (err.keyword) { - case "minimum": - // err type is narrowed here to have "minimum" error params properties - console.log(err.params.limit) - break - // ... - } - } -} -``` - -With JSON Type Definition schema: - -In JavaScript: - -```javascript -const Ajv = require("ajv").default - -const ajv = new Ajv() // options can be passed, e.g. {allErrors: true} -const schema = { - properties: { - foo: {type: "float64"}, - }, -} -const validate = ajv.compile(schema) -const valid = validate({foo: 1}) // true -if (!valid) console.log(validate.errors) -// Unlike JSON Schema: -const valid1 = validate(1) // false, bot an object -const valid2 = validate({}) // false, foo is required -const valid3 = validate({foo: 1, bar: 2}) // false, bar is additional -``` - -In TypeScript: - -```typescript -import {JTDSchemaType} from "ajv" - -type MyData = {foo: number} - -// Optional schema type annotation for schema to match MyData type. -// To use JTDSchemaType set `strictNullChecks: true` in tsconfig `compilerOptions`. -const schema: JTDSchemaType = { - properties: { - foo: {type: "float64"}, - }, -} -``` - -See [this test](./spec/types/json-schema.spec.ts) for an advanced example, [API reference](./docs/api.md) and [Options](./docs/api.md#options) for more details. - -Ajv compiles schemas to functions and caches them in all cases (using schema itself as a key for Map) or another function passed via options), so that the next time the same schema is used (not necessarily the same object instance) it won't be compiled again. - -The best performance is achieved when using compiled functions returned by `compile` or `getSchema` methods (there is no additional function call). - -**Please note**: every time a validation function or `ajv.validate` are called `errors` property is overwritten. You need to copy `errors` array reference to another variable if you want to use it later (e.g., in the callback). See [Validation errors](./docs/api.md#validation-errors) - -## Using in browser - -See [Content Security Policy](./docs/security.md#content-security-policy) to decide the best approach how to use Ajv in the browser. - -Whether you use Ajv or compiled schemas, it is recommended that you bundle them together with your code. - -If you need to use Ajv in several bundles you can create a separate UMD bundles using `npm run bundle` script. - -Then you need to load Ajv with support of JSON Schema draft-07 in the browser: - -```html - - -``` - -To load the bundle that supports JSON Schema draft-2019-09: - -```html - - -``` - -To load the bundle that supports JSON Type Definition: - -```html - - -``` - -This bundle can be used with different module systems; it creates global `ajv` (or `ajv2019`) if no module system is found. - -The browser bundle is available on [cdnjs](https://cdnjs.com/libraries/ajv). - -**Please note**: some frameworks, e.g. Dojo, may redefine global require in a way that is not compatible with CommonJS module format. In this case Ajv bundle has to be loaded before the framework and then you can use global `ajv` (see issue [#234](https://github.com/ajv-validator/ajv/issues/234)). - -## Choosing schema language - -Both JSON Schema and JSON Type Definition are cross-platform specifications with implementations in multiple programming languages that help you define the shape and requirements to your JSON data. - -This section compares their pros/cons to help decide which specification fits your application better. - -### JSON Schema - -- Pros - - Wide specification adoption. - - Used as part of OpenAPI specification. - - Support of complex validation scenarios: - - untagged unions and boolean logic - - conditional schemas and dependencies - - restrictions on the number ranges and the size of strings, arrays and objects - - semantic validation with formats, patterns and content keywords - - distribute strict record definitions across multiple schemas (with unevaluatedProperties) - - Can be effectively used for validation of any JavaScript objects and configuration files. -- Cons - - Defines the collection of restrictions on the data, rather than the shape of the data. - - No standard support for tagged unions. - - Complex and error prone for the new users (Ajv has [strict mode](./docs/strict-mode) to compensate for it, but it is not cross-platform). - - Some parts of specification are difficult to implement, creating the risk of implementations divergence: - - reference resolution model - - unevaluatedProperties/unevaluatedItems - - dynamic recursive references - - Internet draft status (rather than RFC) - -See [JSON Schema](./docs/json-schema.md) for the list of defined keywords. - -### JSON Type Definition - -- Pros: - - Aligned with type systems of many languages - can be used to generate type definitions and efficient parsers and serializers to/from these types. - - Very simple, enforcing the best practices for cross-platform JSON API modelling. - - Simple to implement, ensuring consistency across implementations. - - Defines the shape of JSON data via strictly defined schema forms (rather than the collection of restrictions). - - Effective support for tagged unions. - - Designed to protect against user mistakes. - - Approved as [RFC8927](https://datatracker.ietf.org/doc/rfc8927/) -- Cons: - - Limited, compared with JSON Schema - no support for untagged unions\*, conditionals, references between different schema files\*\*, etc. - - No meta-schema in the specification\*. - - Brand new - limited industry adoption (as of January 2021). - -\* Ajv defines meta-schema for JTD schemas and non-standard keyword "union" that can be used inside "metadata" object. - -\*\* You can still combine schemas from multiple files in the application code. - -See [JSON Type Definition](./docs/json-type-definition.md) for the list of defined schema forms. - -## Using in ES5 environment - -You need to: - -- recompile Typescript to ES5 target - it is set to 2018 in the bundled compiled code. -- generate ES5 validation code: - -```javascript -const ajv = new Ajv({code: {es5: true}}) -``` - -See [Advanced options](https://github.com/ajv-validator/ajv/blob/master/docs/api.md#advanced-options). - -## Command line interface - -CLI is available as a separate npm package [ajv-cli](https://github.com/ajv-validator/ajv-cli). It supports: - -- compiling JSON Schemas to test their validity -- generating [standalone validation code](./docs/standalone.md) that exports validation function(s) to be used without Ajv -- migrating schemas to draft-07 and draft-2019-09 (using [json-schema-migrate](https://github.com/epoberezkin/json-schema-migrate)) -- validating data file(s) against JSON Schema -- testing expected validity of data against JSON Schema -- referenced schemas -- user-defined meta-schemas, validation keywords and formats -- files in JSON, JSON5, YAML, and JavaScript format -- all Ajv options -- reporting changes in data after validation in [JSON-patch](https://datatracker.ietf.org/doc/rfc6902/) format +See more examples in [Guide: getting started](./docs/guide/getting-started) ## Extending Ajv diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index ff533b384..8324111c0 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -23,7 +23,6 @@ module.exports = { {link: "/guide/modifying-data", text: "Modifying data"}, {link: "/guide/user-keywords", text: "User-defined keywords"}, {link: "/guide/async-validation", text: "Asynchronous validation"}, - {link: "/guide/standalone", text: "Standalone validation code"}, {link: "/guide/environments", text: "Execution environments"}, ], }, @@ -38,6 +37,7 @@ module.exports = { {link: "/json-schema", text: "JSON Schema"}, {link: "/json-type-definition", text: "JSON Type Definition"}, {link: "/strict-mode", text: "Strict mode"}, + {link: "/standalone", text: "Standalone validation code"}, {link: "/keywords", text: "User defined keywords"}, {link: "/coercion", text: "Type coercion rules"}, ], @@ -45,7 +45,7 @@ module.exports = { { text: "Contributors", items: [ - {link: "/CONTRIBUTING", text: "Contributing"}, + {link: "/CONTRIBUTING", text: "Contributing guide"}, {link: "/codegen", text: "Code generation design"}, {link: "/components", text: "Code components"}, {link: "/CODE_OF_CONDUCT", text: "Code of Conduct"}, @@ -63,7 +63,6 @@ module.exports = { }, ], sidebar: [ - "/", { title: "Guide", collapsable: false, @@ -89,6 +88,7 @@ module.exports = { "/json-schema", "/json-type-definition", "/strict-mode", + "/standalone", "/keywords", "/coercion", ], diff --git a/docs/OLD_README.md b/docs/OLD_README.md deleted file mode 100644 index edd620a53..000000000 --- a/docs/OLD_README.md +++ /dev/null @@ -1,281 +0,0 @@ -# Ajv: Another JSON validator - -Ajv logo - -The fastest JSON schema validator for Node.js and browser. - -Supports JSON Schema draft-06/07/2019-09 (draft-04 is supported in [version 6](https://github.com/ajv-validator/ajv/tree/v6)) and JSON Type Definition [RFC8927](https://datatracker.ietf.org/doc/rfc8927/). - -::: v-pre -[![build](https://github.com/ajv-validator/ajv/workflows/build/badge.svg)](https://github.com/ajv-validator/ajv/actions?query=workflow%3Abuild) -[![npm](https://img.shields.io/npm/v/ajv.svg)](https://www.npmjs.com/package/ajv) -[![npm downloads](https://img.shields.io/npm/dm/ajv.svg)](https://www.npmjs.com/package/ajv) -[![Coverage Status](https://coveralls.io/repos/github/ajv-validator/ajv/badge.svg?branch=master)](https://coveralls.io/github/ajv-validator/ajv?branch=master) -[![Gitter](https://img.shields.io/gitter/room/ajv-validator/ajv.svg)](https://gitter.im/ajv-validator/ajv) -[![GitHub Sponsors](https://img.shields.io/badge/$-sponsors-brightgreen)](https://github.com/sponsors/epoberezkin) -::: - -## Platinum sponsors - -::: v-pre -[](https://www.mozilla.org)[](https://opencollective.com/ajv) -::: - -## Using version 7 - -Ajv version 7 has these new features: - -- NEW: support of JSON Type Definition [RFC8927](https://datatracker.ietf.org/doc/rfc8927/) (from [v7.1.0](https://github.com/ajv-validator/ajv-keywords/releases/tag/v7.1.0)), including generation of [serializers](./docs/api.md#jtd-serialize) and [parsers](./docs/api.md#jtd-parse) from JTD schemas that are more efficient than native JSON serialization/parsing, combining JSON string parsing and validation in one function. -- support of JSON Schema draft-2019-09 features: [`unevaluatedProperties`](./docs/json-schema.md#unevaluatedproperties) and [`unevaluatedItems`](./docs/json-schema.md#unevaluateditems), [dynamic recursive references](./docs/guide/combining-schemas.md#extending-recursive-schemas) and other [additional keywords](./docs/json-schema.md#json-schema-draft-2019-09). -- to reduce the mistakes in JSON schemas and unexpected validation results, [strict mode](./docs/strict-mode.md) is added - it prohibits ignored or ambiguous JSON Schema elements. -- to make code injection from untrusted schemas impossible, [code generation](./docs/codegen.md) is fully re-written to be safe and to allow code optimization (compiled schema code size is reduced by more than 10%). -- to simplify Ajv extensions, the new keyword API that is used by pre-defined keywords is available to user-defined keywords - it is much easier to define any keywords now, especially with subschemas. [ajv-keywords](https://github.com/ajv-validator/ajv-keywords) package was updated to use the new API (in [v4.0.0](https://github.com/ajv-validator/ajv-keywords/releases/tag/v4.0.0)) -- schemas are compiled to ES6 code (ES5 code generation is also supported with an option). -- to improve reliability and maintainability the code is migrated to TypeScript. - -**Please note**: - -- the support for JSON-Schema draft-04 is removed - if you have schemas using "id" attributes you have to replace them with "\$id" (or continue using [Ajv v6](https://github.com/ajv-validator/ajv/tree/v6) that will be supported until 02/28/2021). -- all formats are separated to ajv-formats package - they have to be explicitly added if you use them. - -See [release notes](https://github.com/ajv-validator/ajv/releases/tag/v7.0.0) for the details. - -To install the new version: - -```bash -npm install ajv -``` - -See [Getting started](#usage) for code example. - -## Contributing - -100+ people contributed to Ajv. You are very welcome to join by implementing new features that are valuable to many users and by improving documentation. - -Please do not be disappointed if your suggestion is not accepted - it is important to maintain the balance between the library size, performance and functionality. If it seems that a feature would benefit only a small number of users, its addition may be delayed until there is more support from the users community - so please submit the issue first to explain why this feature is important. - -Please include documentation and test coverage with any new feature implementations. - -To run tests: - -```bash -npm install -git submodule update --init -npm test -``` - -`npm run build` - compiles typescript to `dist` folder. - -Please review [Contributing guidelines](./CONTRIBUTING.md) and [Code components](./docs/components.md). - -## Contents - -- [Platinum sponsors](#platinum-sponsors) -- [Using version 7](#using-version-7) -- [Contributing](#contributing) -- [Mozilla MOSS grant and OpenJS Foundation](#mozilla-moss-grant-and-openjs-foundation) -- [Sponsors](#sponsors) -- [Performance](#performance) -- [Features](#features) -- [Frequently Asked Questions](./docs/faq.md) -- [Using in browser](#using-in-browser) - - [Content Security Policy](./docs/security.md#content-security-policy) -- [Using in ES5 environment](#using-in-es5-environment) -- [Command line interface](#command-line-interface) -- [API reference](./docs/api.md) - - [Methods](./docs/api.md#ajv-constructor-and-methods) - - [Options](./docs/api.md#options) - - [Validation errors](./docs/api.md#validation-errors) -- NEW: [Strict mode](./docs/strict-mode.md#strict-mode) - - [Prohibit ignored keywords](./docs/strict-mode.md#prohibit-ignored-keywords) - - [Prevent unexpected validation](./docs/strict-mode.md#prevent-unexpected-validation) - - [Strict types](./docs/strict-mode.md#strict-types) - - [Strict number validation](./docs/strict-mode.md#strict-number-validation) -- [Data validation](./docs/validation.md) - - [Validation basics](./docs/validation.md#validation-basics): [JSON Schema keywords](./docs/validation.md#validation-keywords), [annotations](./docs/validation.md#annotation-keywords), [formats](./docs/validation.md#formats) - - [Modular schemas](./docs/validation.md#modular-schemas): [combining with \$ref](./docs/validation.md#ref), [\$data reference](./docs/guide/combining-schemas.md#data-reference), [$merge and $patch](./docs/validation.md#merge-and-patch-keywords) - - [Asynchronous schema compilation](./docs/validation.md#asynchronous-schema-compilation) - - [Standalone validation code](./docs/standalone.md) - - [Asynchronous validation](./docs/validation.md#asynchronous-validation) - - [Modifying data](./docs/validation.md#modifying-data-during-validation): [additional properties](./docs/validation.md#removing-additional-properties), [defaults](./docs/validation.md#assigning-defaults), [type coercion](./docs/validation.md#coercing-data-types) -- [Extending Ajv](#extending-ajv) - - User-defined keywords: - - [basics](./docs/validation.md#user-defined-keywords) - - [guide](./docs/keywords.md) - - [Plugins](#plugins) - - [Related packages](#related-packages) -- [Security considerations](./docs/security.md) - - [Security contact](./docs/security.md#security-contact) - - [Untrusted schemas](./docs/security.md#untrusted-schemas) - - [Circular references in objects](./docs/security.md#circular-references-in-javascript-objects) - - [Trusted schemas](./docs/security.md#security-risks-of-trusted-schemas) - - [ReDoS attack](./docs/security.md#redos-attack) - - [Content Security Policy](./docs/security.md#content-security-policy) -- [Some packages using Ajv](#some-packages-using-ajv) -- [Changes history](#changes-history) -- [Support, Code of conduct, Contacts, License](#open-source-software-support) - -## Mozilla MOSS grant and OpenJS Foundation - -::: v-pre -[](https://www.mozilla.org/en-US/moss/) [](https://openjsf.org/blog/2020/08/14/ajv-joins-openjs-foundation-as-an-incubation-project/) -::: - -Ajv has been awarded a grant from Mozilla’s [Open Source Support (MOSS) program](https://www.mozilla.org/en-US/moss/) in the “Foundational Technology” track! It will sponsor the development of Ajv support of [JSON Schema version 2019-09](https://tools.ietf.org/html/draft-handrews-json-schema-02) and of [JSON Type Definition (RFC8927)](https://datatracker.ietf.org/doc/rfc8927/). - -Ajv also joined [OpenJS Foundation](https://openjsf.org/) – having this support will help ensure the longevity and stability of Ajv for all its users. - -This [blog post](https://www.poberezkin.com/posts/2020-08-14-ajv-json-validator-mozilla-open-source-grant-openjs-foundation.html) has more details. - -I am looking for the long term maintainers of Ajv – working with [ReadySet](https://www.thereadyset.co/), also sponsored by Mozilla, to establish clear guidelines for the role of a "maintainer" and the contribution standards, and to encourage a wider, more inclusive, contribution from the community. - -## Please [sponsor Ajv development](https://github.com/sponsors/epoberezkin) - -Since I asked to support Ajv development 40 people and 6 organizations contributed via GitHub and OpenCollective - this support helped receiving the MOSS grant! - -Your continuing support is very important - the funds will be used to develop and maintain Ajv once the next major version is released. - -Please sponsor Ajv via: - -- [GitHub sponsors page](https://github.com/sponsors/epoberezkin) (GitHub will match it) -- [Ajv Open Collective️](https://opencollective.com/ajv) - -Thank you. - -#### Open Collective sponsors - - - - - - - - - - - - - - -## Performance - -Ajv generates code to turn JSON Schemas into super-fast validation functions that are efficient for v8 optimization. - -Currently Ajv is the fastest and the most standard compliant validator according to these benchmarks: - -- [json-schema-benchmark](https://github.com/ebdrup/json-schema-benchmark) - 50% faster than the second place -- [jsck benchmark](https://github.com/pandastrike/jsck#benchmarks) - 20-190% faster -- [z-schema benchmark](https://rawgit.com/zaggino/z-schema/master/benchmark/results.html) -- [themis benchmark](https://cdn.rawgit.com/playlyfe/themis/master/benchmark/results.html) - -Performance of different validators by [json-schema-benchmark](https://github.com/ebdrup/json-schema-benchmark): - -[![performance](https://chart.googleapis.com/chart?chxt=x,y&cht=bhs&chco=76A4FB&chls=2.0&chbh=32,4,1&chs=600x416&chxl=-1:|djv|ajv|json-schema-validator-generator|jsen|is-my-json-valid|themis|z-schema|jsck|skeemas|json-schema-library|tv4&chd=t:100,98,72.1,66.8,50.1,15.1,6.1,3.8,1.2,0.7,0.2)](https://github.com/ebdrup/json-schema-benchmark/blob/master/README.md#performance) - -## Features - -- Ajv implements JSON Schema [draft-06/07/2019-09](http://json-schema.org/) standards (draft-04 is supported in v6): - - all validation keywords (see [JSON Schema validation keywords](./docs/json-schema.md)) - - keyword "nullable" from [Open API 3 specification](https://swagger.io/docs/specification/data-models/data-types/). - - full support of remote references (remote schemas have to be added with `addSchema` or compiled to be available) - - support of circular references between schemas - - correct string lengths for strings with unicode pairs - - [formats](#formats) defined by JSON Schema draft-07 standard (with [ajv-formats](https://github.com/ajv-validator/ajv-formats) plugin) and additional formats (can be turned off) - - [validates schemas against meta-schema](./docs/api.md#api-validateschema) -- NEW: supports [JSON Type Definition](https://datatracker.ietf.org/doc/rfc8927/): - - all forms (see [JSON Type Definition schema forms](./docs/json-type-definition.md)) - - meta-schema for JTD schemas - - "union" keyword and user-defined keywords (can be used inside "metadata" member of the schema) -- supports [browsers](#using-in-browser) and Node.js 0.10-14.x -- [asynchronous loading](./docs/validation.md#asynchronous-schema-compilation) of referenced schemas during compilation -- "All errors" validation mode with [option allErrors](./docs/api.md#options) -- [error messages with parameters](./docs/api.md#validation-errors) describing error reasons to allow error message generation -- i18n error messages support with [ajv-i18n](https://github.com/ajv-validator/ajv-i18n) package -- [removing-additional-properties](./docs/validation.md#removing-additional-properties) -- [assigning defaults](./docs/validation.md#assigning-defaults) to missing properties and items -- [coercing data](./docs/validation.md#coercing-data-types) to the types specified in `type` keywords -- [user-defined keywords](#user-defined-keywords) -- draft-06/07 keywords `const`, `contains`, `propertyNames` and `if/then/else` -- draft-06 boolean schemas (`true`/`false` as a schema to always pass/fail). -- additional extension keywords with [ajv-keywords](https://github.com/ajv-validator/ajv-keywords) package -- [\$data reference](./docs/guide/combining-schemas.md#data-reference) to use values from the validated data as values for the schema keywords -- [asynchronous validation](./docs/api.md#asynchronous-validation) of user-defined formats and keywords - -## Extending Ajv - -### User defined keywords - -See section in [data validation](./docs/validation.md#user-defined-keywords) and the [detailed guide](./docs/keywords.md). - -### Plugins - -Ajv can be extended with plugins that add keywords, formats or functions to process generated code. When such plugin is published as npm package it is recommended that it follows these conventions: - -- it exports a function that accepts ajv instance as the first parameter - it allows using plugins with [ajv-cli](#command-line-interface). -- this function returns the same instance to allow chaining. -- this function can accept an optional configuration as the second parameter. - -You can import `Plugin` interface from ajv if you use Typescript. - -If you have published a useful plugin please submit a PR to add it to the next section. - -### Related packages - -- [ajv-bsontype](https://github.com/BoLaMN/ajv-bsontype) - plugin to validate mongodb's bsonType formats -- [ajv-cli](https://github.com/jessedc/ajv-cli) - command line interface -- [ajv-formats](https://github.com/ajv-validator/ajv-formats) - formats defined in JSON Schema specification -- [ajv-errors](https://github.com/ajv-validator/ajv-errors) - plugin for defining error messages in the schema -- [ajv-i18n](https://github.com/ajv-validator/ajv-i18n) - internationalised error messages -- [ajv-istanbul](https://github.com/ajv-validator/ajv-istanbul) - plugin to instrument generated validation code to measure test coverage of your schemas -- [ajv-keywords](https://github.com/ajv-validator/ajv-keywords) - plugin with additional validation keywords (select, typeof, etc.) -- [ajv-merge-patch](https://github.com/ajv-validator/ajv-merge-patch) - plugin with keywords $merge and $patch -- [ajv-formats-draft2019](https://github.com/luzlab/ajv-formats-draft2019) - format validators for draft2019 that aren't included in [ajv-formats](https://github.com/ajv-validator/ajv-formats) (ie. `idn-hostname`, `idn-email`, `iri`, `iri-reference` and `duration`) - -## Some packages using Ajv - -- [webpack](https://github.com/webpack/webpack) - a module bundler. Its main purpose is to bundle JavaScript files for usage in a browser -- [jsonscript-js](https://github.com/JSONScript/jsonscript-js) - the interpreter for [JSONScript](http://www.jsonscript.org) - scripted processing of existing endpoints and services -- [osprey-method-handler](https://github.com/mulesoft-labs/osprey-method-handler) - Express middleware for validating requests and responses based on a RAML method object, used in [osprey](https://github.com/mulesoft/osprey) - validating API proxy generated from a RAML definition -- [har-validator](https://github.com/ahmadnassri/har-validator) - HTTP Archive (HAR) validator -- [jsoneditor](https://github.com/josdejong/jsoneditor) - a web-based tool to view, edit, format, and validate JSON http://jsoneditoronline.org -- [JSON Schema Lint](https://github.com/nickcmaynard/jsonschemalint) - a web tool to validate JSON/YAML document against a single JSON Schema http://jsonschemalint.com -- [objection](https://github.com/vincit/objection.js) - SQL-friendly ORM for Node.js -- [table](https://github.com/gajus/table) - formats data into a string table -- [ripple-lib](https://github.com/ripple/ripple-lib) - a JavaScript API for interacting with [Ripple](https://ripple.com) in Node.js and the browser -- [restbase](https://github.com/wikimedia/restbase) - distributed storage with REST API & dispatcher for backend services built to provide a low-latency & high-throughput API for Wikipedia / Wikimedia content -- [hippie-swagger](https://github.com/CacheControl/hippie-swagger) - [Hippie](https://github.com/vesln/hippie) wrapper that provides end to end API testing with swagger validation -- [react-form-controlled](https://github.com/seeden/react-form-controlled) - React controlled form components with validation -- [rabbitmq-schema](https://github.com/tjmehta/rabbitmq-schema) - a schema definition module for RabbitMQ graphs and messages -- [@query/schema](https://www.npmjs.com/package/@query/schema) - stream filtering with a URI-safe query syntax parsing to JSON Schema -- [chai-ajv-json-schema](https://github.com/peon374/chai-ajv-json-schema) - chai plugin to us JSON Schema with expect in mocha tests -- [grunt-jsonschema-ajv](https://github.com/SignpostMarv/grunt-jsonschema-ajv) - Grunt plugin for validating files against JSON Schema -- [extract-text-webpack-plugin](https://github.com/webpack-contrib/extract-text-webpack-plugin) - extract text from bundle into a file -- [electron-builder](https://github.com/electron-userland/electron-builder) - a solution to package and build a ready for distribution Electron app -- [addons-linter](https://github.com/mozilla/addons-linter) - Mozilla Add-ons Linter -- [gh-pages-generator](https://github.com/epoberezkin/gh-pages-generator) - multi-page site generator converting markdown files to GitHub pages -- [ESLint](https://github.com/eslint/eslint) - the pluggable linting utility for JavaScript and JSX -- [Spectral](https://github.com/stoplightio/spectral) - the customizable linting utility for JSON/YAML, OpenAPI, AsyncAPI, and JSON Schema - -## Changes history - -See https://github.com/ajv-validator/ajv/releases - -**Please note**: [Changes in version 7.0.0](https://github.com/ajv-validator/ajv/releases/tag/v7.0.0) - -[Version 6.0.0](https://github.com/ajv-validator/ajv/releases/tag/v6.0.0). - -## Code of conduct - -Please review and follow the [Code of conduct](./CODE_OF_CONDUCT.md). - -Please report any unacceptable behaviour to ajv.validator@gmail.com - it will be reviewed by the project team. - -## Security contact - -To report a security vulnerability, please use the -[Tidelift security contact](https://tidelift.com/security). -Tidelift will coordinate the fix and disclosure. Please do NOT report security vulnerabilities via GitHub issues. - -## Open-source software support - -Ajv is a part of [Tidelift subscription](https://tidelift.com/subscription/pkg/npm-ajv?utm_source=npm-ajv&utm_medium=referral&utm_campaign=readme) - it provides a centralised support to open-source software users, in addition to the support provided by software maintainers. diff --git a/docs/guide/schema-language.md b/docs/guide/schema-language.md index 335983705..1a4fc914c 100644 --- a/docs/guide/schema-language.md +++ b/docs/guide/schema-language.md @@ -12,18 +12,20 @@ Ajv supports most widely used drafts of JSON Schema specification. Please see th ### draft-04 -Draft-04 is not included in Ajv v7, because of substantial differences it has with the following drafts: +Draft-04 is not included in Ajv v7, because of some differences it has with the following drafts: - different schema member for schema identifier (`id` in draft-04 instead of `$id`) -- different syntax of exclusiveMaximum/Minimum, that is difficult to support in one codebase, particularly with [$data reference](combining-schemas.md#data-reference) +- different syntax of exclusiveMaximum/Minimum -You can still use draft-04 schemas with Ajv v6 - while this is no longer actively developed, any security related issues would still be supported at least until 30/06/2021. To install: +You can still use draft-04 schemas with Ajv v6 - while this is no longer actively developed, any security related issues would still be supported at least until 30/06/2021. + +To install v6: ```bash npm install ajv@6 ``` -Migrating schemas from draft-04 to draft-07 is very easy with [ajv-cli](https://github.com/ajv-validator/ajv-cli) +You can migrate schemas from draft-04 to draft-07 using [ajv-cli](https://github.com/ajv-validator/ajv-cli). ### draft-07 (and draft-06) diff --git a/docs/guide/standalone.md b/docs/standalone.md similarity index 100% rename from docs/guide/standalone.md rename to docs/standalone.md From ddd79b65ae87d39bbe0dbd1d7235a78a2325be07 Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Sat, 6 Mar 2021 13:07:16 +0000 Subject: [PATCH 11/25] update CONTRIBUTING.md --- CONTRIBUTING.md | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d73b91781..4e39ab9b2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,7 +4,11 @@ permalink: /contributing # Contributing guide -Thank you for your help making Ajv better! Every contribution is appreciated. If you plan to implement a new feature or some other change please create an issue first, to make sure that your work is not lost. +Thank you for your help making Ajv better! Every contribution is appreciated. There are many areas where you can contribute. + +::: tip Please note +If you plan to implement a new feature or some other change please create an issue first, to make sure that your work is not lost. +::: - [Documentation](#documentation) - [Issues](#issues) @@ -22,26 +26,30 @@ Thank you for your help making Ajv better! Every contribution is appreciated. If ## Documentation -Ajv has a lot of features and maintaining documentation takes time. I appreciate the time you spend correcting or clarifying the documentation. +Ajv has a lot of features and maintaining documentation takes time. If anything is unclear, or could be explained better, we appreciate the time you spend correcting or clarifying it. ## Issues -Before submitting the issue please search the existing issues and also review [Frequently Asked Questions](./docs/faq.md). +Before submitting the issue: +- Search the existing issues +- Review [Frequently Asked Questions](./docs/faq.md). +- Provide all the relevant information, reducing both your schema and data to the smallest possible size when they still have the issue. -It is really important that you spend time to provide all the relevant information and to reduce both your schema and data to the smallest possible size when they still have the issue. Simplifying the issue also makes it more valuable for other users (in cases it turns out to be an incorrect usage rather than a bug). +We value simplicity - simplifying the example that shows the issue makes it more valuable for other users. This process helps us reduce situations where an error is occurring due to incorrect usage rather than a bug. #### Bug reports Please make sure to include the following information in the issue: -1. What version of Ajv are you using? Does the issue happen if you use the latest version? -2. Ajv options object (see https://github.com/ajv-validator/ajv/api.md#options). -3. JSON Schema and the data you are validating (please make it as small as possible to reproduce the issue). -4. Your code sample (please use `options`, `schema` and `data` as variables). -5. Validation result, data AFTER validation, error messages. -6. What results did you expect? +1. What version of Ajv are you using? +2. Does the issue happen if you use the latest version? +3. Ajv [options object](./docs/options) +4. Schema and the data you are validating (please make it as small as possible to reproduce the issue). +5. Your code sample (please use `options`, `schema` and `data` as variables). +6. Validation result, data AFTER validation, error messages. +7. What results did you expect? -Please include the link to the working code sample at Runkit.com (please clone https://runkit.com/esp/ajv-issue) - it will speed up investigation and fixing. +To speed up investigation and fixes, please include the link to the working code sample at runkit.com (please clone https://runkit.com/esp/ajv-issue). [Create bug report](https://github.com/ajv-validator/ajv/issues/new?template=bug-or-error-report.md). @@ -61,16 +69,16 @@ Please include this information: 1. The version of Ajv you are using. 2. The problem you want to solve. -3. What do you think is the correct solution to problem? -4. Will you be able to implement it? +3. Your solution to the problem. +4. Would you like to implement it? If you’re requesting a change, it would be helpful to include this as well: 1. What you did. -2. What you would like to happen. -3. What actually happened. +2. What happened. +3. What you would like to happen. -Please include as much details as possible. +Please include as much details as possible - the more information, the better. #### Browser and compatibility issues From 4850ec6d62a576d30b0a46f38e6dc5b4a6df769b Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Sat, 6 Mar 2021 14:58:48 +0000 Subject: [PATCH 12/25] update CODE_OF_CONDUCT of CONTRIBUTING --- .gitignore | 1 + CODE_OF_CONDUCT.md | 71 +++++++++++++++++--------------------------- CONTRIBUTING.md | 34 ++++++++++----------- docs/LICENSE.md | 21 ------------- scripts/publish-site | 2 +- 5 files changed, 47 insertions(+), 82 deletions(-) delete mode 100644 docs/LICENSE.md diff --git a/.gitignore b/.gitignore index 9b3f4a121..861174534 100644 --- a/.gitignore +++ b/.gitignore @@ -44,3 +44,4 @@ spec/_json/*.js docs/CODE_OF_CONDUCT.md docs/CONTRIBUTING.md +docs/LICENSE.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index c96b8e5dc..6f4bdd55f 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -6,75 +6,60 @@ permalink: /code_of_conduct ## Our Pledge -In the interest of fostering an open and welcoming environment, we as -contributors and maintainers pledge to making participation in our project and -our community a harassment-free experience for everyone, regardless of age, body -size, disability, ethnicity, sex characteristics, gender identity and expression, -level of experience, education, socio-economic status, nationality, personal -appearance, race, religion, or sexual identity and orientation. +We commit to creating and maintaining an open and welcoming environment. We, as contributors and maintainers, commit to building a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards -Examples of behavior that contributes to creating a positive environment -include: +**Behaviour that contributes to creating a positive environment include**: - Using welcoming and inclusive language -- Being respectful of differing viewpoints and experiences + - Consider when identity words like race or ethnicity matter + - Be conscious of language with discriminatory connotations (e.g. gendered, ableist, racialized phrases) + - Be open to being corrected if you make a mistake - it’s okay to mess up, what matters is your follow up - Gracefully accepting constructive criticism -- Focusing on what is best for the community - Showing empathy towards other community members +- Treat other community members and project team members with respect +- Report if you witness harassment or wrongdoing in our spaces -Examples of unacceptable behavior by participants include: +**Unacceptable behaviour by participants include**: -- The use of sexualized language or imagery and unwelcome sexual attention or - advances +- The use of sexualized language or imagery and unwelcome sexual attention or advances - Trolling, insulting/derogatory comments, and personal or political attacks - Public or private harassment -- Publishing others' private information, such as a physical or electronic - address, without explicit permission -- Other conduct which could reasonably be considered inappropriate in a - professional setting +- Publishing others' private information, such as a physical or electronic address, without explicit permission +- Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities -Project maintainers are responsible for clarifying the standards of acceptable -behavior and are expected to take appropriate and fair corrective action in -response to any instances of unacceptable behavior. +Project maintainers are responsible for clarifying the standards of acceptable behaviour and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behaviour. -Project maintainers have the right and responsibility to remove, edit, or -reject comments, commits, code, wiki edits, issues, and other contributions -that are not aligned to this Code of Conduct, or to ban temporarily or -permanently any contributor for other behaviors that they deem inappropriate, -threatening, offensive, or harmful. +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope -This Code of Conduct applies both within project spaces and in public spaces -when an individual is representing the project or its community. Examples of -representing a project or community include using an official project e-mail -address, posting via an official social media account, or acting as an appointed -representative at an online or offline event. Representation of a project may be -further defined and clarified by project maintainers. +The goal of this Code of Conduct is to set standards and expectations around how we interact within this community. It’s scope applies to all project participants and covers all interactions within the community associated with this project including, but not limited to, email communication, issue trackers, source code repositories, forums, and social media. + +Examples of representing a project or community include: +- Using an official project e-mail address +- Posting via an official social media account +- Acting as an appointed representative at an online or offline event + +Representation of a project may be further defined and clarified by project maintainers. ## Enforcement -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at ajv.validator@gmail.com. All -complaints will be reviewed and investigated and will result in a response that -is deemed necessary and appropriate to the circumstances. The project team is -obligated to maintain confidentiality with regard to the reporter of an incident. -Further details of specific enforcement policies may be posted separately. +We will not tolerate abuse, harassment, or any other unacceptable behaviour made against community members, project maintainers, or members of our project team, either online or offline. + +Violations of our Code of Conduct may be reported by contacting the project team at ajv.validator@gmail.com. The project team will review and investigate all complaints, to the best of our ability, and will respond in a way that it deems appropriate to the circumstances. -Project maintainers who do not follow or enforce the Code of Conduct in good -faith may face temporary or permanent repercussions as determined by other -members of the project's leadership. +Reports of violations will be investigated in a respectful, professional manner as promptly and confidentially as possible. We will have zero tolerance for intimidation or retaliation against anyone who raises a concern, makes a report or cooperates in an investigation around a violation of our code of conduct. Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions or removal as determined by other members of the project's leadership. ## Attribution -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +This Code of Conduct is adapted from the [Contributor Covenant][https://www.contributor-covenant.org], version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html -[homepage]: https://www.contributor-covenant.org - For answers to common questions about this code of conduct, see https://www.contributor-covenant.org/faq diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4e39ab9b2..96d461ff4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -82,7 +82,7 @@ Please include as much details as possible - the more information, the better. #### Browser and compatibility issues -[Create an issue](https://github.com/ajv-validator/ajv/issues/new?template=compatibility.md) to report a compatibility problem that only happens in a particular environment (when your code works correctly in node.js v8+ in linux systems but fails in some other environment). +[Create an issue](https://github.com/ajv-validator/ajv/issues/new?template=compatibility.md) to report a compatibility problem that only happens in a particular environment (when your code works correctly in the latest stable Node.js in linux systems but fails in some other environment). Please include this information: @@ -90,7 +90,7 @@ Please include this information: 2. The environment you have the problem with. 3. Your code (please make it as small as possible to reproduce the issue). 4. If your issue is in the browser, please list the other packages loaded in the page in the order they are loaded. Please check if the issue gets resolved (or results change) if you move Ajv bundle closer to the top. -5. Results in node.js v8+. +5. Results in the latest stable Node.js. 6. Results and error messages in your platform. #### Installation and dependency issues @@ -100,15 +100,15 @@ Please include this information: Before submitting the issue, please try the following: - use the latest stable Node.js and `npm` -- use `yarn` instead of `npm` - the issue can be related to https://github.com/npm/npm/issues/19877 -- remove `node_modules` and `package-lock.json` and run install again +- try using `yarn` instead of `npm` - the issue can be related to https://github.com/npm/npm/issues/19877 +- remove `node_modules` and `package-lock.json` and run `npm install` again If nothing helps, please submit: 1. The version of Ajv you are using -2. Operating system and node.js version +2. Operating system and Node.js version 3. Package manager and its version -4. Link to (or contents of) package.json +4. Link to (or contents of) package.json and package-lock.json 5. Error messages 6. The output of `npm ls` @@ -116,7 +116,7 @@ If nothing helps, please submit: Ajv implements JSON Schema standard draft-04 and draft-06/07. -If it is a general issue related to using the standard keywords included in JSON Schema or implementing some advanced validation logic please ask the question on [Stack Overflow](https://stackoverflow.com/questions/ask?tags=jsonschema,ajv) (my account is [esp](https://stackoverflow.com/users/1816503/esp)) or submitting the question to [JSON-Schema.org](https://github.com/json-schema-org/json-schema-spec/issues/new). Please mention @epoberezkin. +If it is a general issue related to using the standard keywords included in JSON Schema specification or implementing some advanced validation logic please ask the question on [Stack Overflow](https://stackoverflow.com/questions/ask?tags=jsonschema,ajv) (my account is [esp](https://stackoverflow.com/users/1816503/esp)) or submit the question to [json-schema.org](https://github.com/json-schema-org/json-schema-spec/issues/new). Please mention @epoberezkin. #### Ajv usage questions @@ -126,9 +126,9 @@ If the question is advanced, it can be submitted to [Stack Overflow](http://stac ## Code -Thanks a lot for considering contributing to Ajv. Many great features were created by its users. +Thanks a lot for considering contributing to Ajv! Our users have created many great features, and we look forward to your contributions. -Please review [Code components](./docs/components.md) document as well - it will help navigating the code. +For help navigating the code, please review the [Code components](./docs/components.md) document. #### Development @@ -142,20 +142,20 @@ npm test `npm run build` - compiles typescript to dist folder. -`npm run watch` - automatically compiles typescript when files in lib folder change +`npm run watch` - automatically compiles typescript when files on lib folder changes. #### Pull requests -To make accepting your changes faster please follow these steps: +We want to iterate on the code efficiently. To speed up the process, please follow these steps: 1. Submit an [issue with the bug](https://github.com/ajv-validator/ajv/issues/new) or with the proposed change (unless the contribution is to fix the documentation typos and mistakes). -2. Please describe the proposed api and implementation plan (unless the issue is a relatively simple bug and fixing it doesn't change any api). -3. Once agreed, please write as little code as possible to achieve the desired result. -4. Please add the tests both for the added feature and, in case the feature is some option, for the existing behaviour when this option is disabled. +2. Describe the proposed api and implementation plan (unless the issue is a relatively simple bug and fixing it doesn't change any api). +3. Once agreed, please write as little code as possible to achieve the desired result. We are passionate about keeping our library size optimized. +4. Please add the tests both for the added feature and, if you are submitting an option, for the existing behaviour when this option is turned off or not passed. 5. Please avoid unnecessary changes, refactoring or changing coding styles as part of your change (unless the change was proposed as refactoring). -6. Please follow the coding conventions even if they are not validated (and/or you use different conventions in your code). +6. Follow the coding conventions even if they are not validated. 7. Please run the tests before committing your code. -8. If tests fail in Travis after you make a PR please investigate and fix the issue. +8. If tests fail in CI build after you make a PR please investigate and fix the issue. #### Contributions license @@ -164,6 +164,6 @@ When contributing the code you confirm that: 1. Your contribution is created by you. 2. You have the right to submit it under the MIT license. 3. You understand and agree that your contribution is public, will be stored indefinitely, can be redistributed as the part of Ajv or another related package under MIT license, modified or completely removed from Ajv. -4. You grant irrevocable MIT license to use your contribution as part of Ajv or another related package. +4. You grant irrevocable MIT license to use your contribution as part of Ajv or any other package. 5. You waive all rights to your contribution. 6. Unless you request otherwise, you can be mentioned as the author of the contribution in the Ajv documentation and change log. diff --git a/docs/LICENSE.md b/docs/LICENSE.md deleted file mode 100644 index a0f827cbd..000000000 --- a/docs/LICENSE.md +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015-2017 Evgeny Poberezkin - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/scripts/publish-site b/scripts/publish-site index 51d9a2736..ef757b202 100755 --- a/scripts/publish-site +++ b/scripts/publish-site @@ -6,4 +6,4 @@ echo "About to publish $GITHUB_REF to gh-pages..." cp CODE_OF_CONDUCT.md docs cp CONTRIBUTING.md docs -cp LICENSE docs +cp LICENSE docs/LICENSE.md From eca24a6a9534efc43f80b908058c28a47f76fddb Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Sat, 6 Mar 2021 15:36:05 +0000 Subject: [PATCH 13/25] docs: rewrite Contributing, fix links --- CODE_OF_CONDUCT.md | 12 ++++----- CONTRIBUTING.md | 30 +++++++-------------- README.md | 47 ++++++++++++++++++++++----------- docs/api.md | 8 +++--- docs/coercion.md | 2 +- docs/guide/combining-schemas.md | 4 ++- docs/options.md | 10 +++---- docs/strict-mode.md | 4 +-- 8 files changed, 62 insertions(+), 55 deletions(-) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 6f4bdd55f..28a25baee 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -4,11 +4,11 @@ permalink: /code_of_conduct # Contributor Covenant Code of Conduct -## Our Pledge +### Our Pledge We commit to creating and maintaining an open and welcoming environment. We, as contributors and maintainers, commit to building a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. -## Our Standards +### Our Standards **Behaviour that contributes to creating a positive environment include**: @@ -29,13 +29,13 @@ We commit to creating and maintaining an open and welcoming environment. We, as - Publishing others' private information, such as a physical or electronic address, without explicit permission - Other conduct which could reasonably be considered inappropriate in a professional setting -## Our Responsibilities +### Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behaviour and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behaviour. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. -## Scope +### Scope The goal of this Code of Conduct is to set standards and expectations around how we interact within this community. It’s scope applies to all project participants and covers all interactions within the community associated with this project including, but not limited to, email communication, issue trackers, source code repositories, forums, and social media. @@ -46,7 +46,7 @@ Examples of representing a project or community include: Representation of a project may be further defined and clarified by project maintainers. -## Enforcement +### Enforcement We will not tolerate abuse, harassment, or any other unacceptable behaviour made against community members, project maintainers, or members of our project team, either online or offline. @@ -56,7 +56,7 @@ Reports of violations will be investigated in a respectful, professional manner Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions or removal as determined by other members of the project's leadership. -## Attribution +### Attribution This Code of Conduct is adapted from the [Contributor Covenant][https://www.contributor-covenant.org], version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 96d461ff4..fb1229aae 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,24 +10,14 @@ Thank you for your help making Ajv better! Every contribution is appreciated. Th If you plan to implement a new feature or some other change please create an issue first, to make sure that your work is not lost. ::: -- [Documentation](#documentation) -- [Issues](#issues) - - [Bug reports](#bug-reports) - - [Security vulnerabilities](#security-vulnerabilities) - - [Change proposals](#changes) - - [Browser and compatibility issues](#compatibility) - - [Installation and dependency issues](#installation) - - [JSON Schema standard](#json-schema) - - [Ajv usage questions](#usage) -- [Code](#code) - - [Development](#development) - - [Pull requests](#pull-requests) - - [Contributions license](#contributions-license) +[[toc]] ## Documentation Ajv has a lot of features and maintaining documentation takes time. If anything is unclear, or could be explained better, we appreciate the time you spend correcting or clarifying it. +There is a link in the bottom of each website page to quickly edit it. + ## Issues Before submitting the issue: @@ -37,7 +27,7 @@ Before submitting the issue: We value simplicity - simplifying the example that shows the issue makes it more valuable for other users. This process helps us reduce situations where an error is occurring due to incorrect usage rather than a bug. -#### Bug reports +### Bug reports Please make sure to include the following information in the issue: @@ -53,7 +43,7 @@ To speed up investigation and fixes, please include the link to the working code [Create bug report](https://github.com/ajv-validator/ajv/issues/new?template=bug-or-error-report.md). -#### Security vulnerabilities +### Security vulnerabilities To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security). @@ -61,7 +51,7 @@ Tidelift will coordinate the fix and disclosure. Please do NOT report security vulnerabilities via GitHub issues. -#### Change proposals +### Change proposals [Create a proposal](https://github.com/ajv-validator/ajv/issues/new?template=change.md) for a new feature, option or some other improvement. @@ -80,7 +70,7 @@ If you’re requesting a change, it would be helpful to include this as well: Please include as much details as possible - the more information, the better. -#### Browser and compatibility issues +### Browser and compatibility issues [Create an issue](https://github.com/ajv-validator/ajv/issues/new?template=compatibility.md) to report a compatibility problem that only happens in a particular environment (when your code works correctly in the latest stable Node.js in linux systems but fails in some other environment). @@ -93,7 +83,7 @@ Please include this information: 5. Results in the latest stable Node.js. 6. Results and error messages in your platform. -#### Installation and dependency issues +### Installation and dependency issues [Create an issue](https://github.com/ajv-validator/ajv/issues/new?template=installation.md) to report problems that happen during Ajv installation or when Ajv is missing some dependency. @@ -112,13 +102,13 @@ If nothing helps, please submit: 5. Error messages 6. The output of `npm ls` -#### Using JSON Schema standard +### Using JSON Schema standard Ajv implements JSON Schema standard draft-04 and draft-06/07. If it is a general issue related to using the standard keywords included in JSON Schema specification or implementing some advanced validation logic please ask the question on [Stack Overflow](https://stackoverflow.com/questions/ask?tags=jsonschema,ajv) (my account is [esp](https://stackoverflow.com/users/1816503/esp)) or submit the question to [json-schema.org](https://github.com/json-schema-org/json-schema-spec/issues/new). Please mention @epoberezkin. -#### Ajv usage questions +### Ajv usage questions The best place to ask a question about using Ajv is [Gitter chat](https://gitter.im/ajv-validator/ajv). diff --git a/README.md b/README.md index 7e981178d..2d2da61e0 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ Supports JSON Schema draft-06/07/2019-09 (draft-04 is supported in [version 6](h Ajv version 7 has these new features: - NEW: support of JSON Type Definition [RFC8927](https://datatracker.ietf.org/doc/rfc8927/) (from [v7.1.0](https://github.com/ajv-validator/ajv-keywords/releases/tag/v7.1.0)), including generation of [serializers](./docs/api.md#jtd-serialize) and [parsers](./docs/api.md#jtd-parse) from JTD schemas that are more efficient than native JSON serialization/parsing, combining JSON string parsing and validation in one function. -- support of JSON Schema draft-2019-09 features: [`unevaluatedProperties`](./docs/json-schema.md#unevaluatedproperties) and [`unevaluatedItems`](./docs/json-schema.md#unevaluateditems), [dynamic recursive references](./docs/validation.md#extending-recursive-schemas) and other [additional keywords](./docs/json-schema.md#json-schema-draft-2019-09). +- support of JSON Schema draft-2019-09 features: [`unevaluatedProperties`](./docs/json-schema.md#unevaluatedproperties) and [`unevaluatedItems`](./docs/json-schema.md#unevaluateditems), [dynamic recursive references](./docs/guide/combining-schemas.md#extending-recursive-schemas) and other [additional keywords](./docs/json-schema.md#json-schema-draft-2019-09). - to reduce the mistakes in JSON schemas and unexpected validation results, [strict mode](./docs/strict-mode.md) is added - it prohibits ignored or ambiguous JSON Schema elements. - to make code injection from untrusted schemas impossible, [code generation](./docs/codegen.md) is fully re-written to be safe and to allow code optimization (compiled schema code size is reduced by more than 10%). - to simplify Ajv extensions, the new keyword API that is used by pre-defined keywords is available to user-defined keywords - it is much easier to define any keywords now, especially with subschemas. [ajv-keywords](https://github.com/ajv-validator/ajv-keywords) package was updated to use the new API (in [v4.0.0](https://github.com/ajv-validator/ajv-keywords/releases/tag/v4.0.0)) @@ -46,9 +46,23 @@ See [Getting started](#usage) for code example. ## Contributing -100+ people contributed to Ajv. You are very welcome to join by implementing new features that are valuable to many users and by improving documentation. +More than 100 people contributed to Ajv, and we would love to have you join the development. We welcome implementing new features that will benefit many users and ideas to improve our documentation. -Please do not be disappointed if your suggestion is not accepted - it is important to maintain the balance between the library size, performance and functionality. If it seems that a feature would benefit only a small number of users, its addition may be delayed until there is more support from the users community - so please submit the issue first to explain why this feature is important. +At Ajv, we are committed to creating more equitable and inclusive spaces for our community and team members to contribute to discussions that affect both this project and our ongoing work in the open source ecosystem. + +We strive to create an environment of respect and healthy discourse by setting standards for our interactions and we expect it from all members of our community - from long term project member to first time visitor. For more information, review our [code of conduct](./CODE_OF_CONDUCT.md) and values. + +### How we make decisions + +We value conscious curation of our library size, and balancing performance and functionality. To that end, we cannot accept every suggestion. When evaluating pull requests we consider: +- Will this benefit many users or a niche use case? +- How will this impact the performance of Ajv? +- How will this expand our library size? + +To help us evaluate and understand, when you submit an issue and pull request: +- Explain why this feature is important to the user base +- Include documentation +- Include test coverage with any new feature implementations Please include documentation and test coverage with any new feature implementations. @@ -62,7 +76,7 @@ npm test `npm run build` - compiles typescript to `dist` folder. -Please review [Contributing guidelines](./CONTRIBUTING.md) and [Code components](./docs/components.md). +Please also review [Contributing guidelines](./CONTRIBUTING.md) and [Code components](./docs/components.md). ## Contents @@ -89,16 +103,17 @@ Please review [Contributing guidelines](./CONTRIBUTING.md) and [Code components] - [Prevent unexpected validation](./docs/strict-mode.md#prevent-unexpected-validation) - [Strict types](./docs/strict-mode.md#strict-types) - [Strict number validation](./docs/strict-mode.md#strict-number-validation) -- [Data validation](./docs/validation.md) - - [Validation basics](./docs/validation.md#validation-basics): [JSON Schema keywords](./docs/validation.md#validation-keywords), [annotations](./docs/validation.md#annotation-keywords), [formats](./docs/validation.md#formats) - - [Modular schemas](./docs/validation.md#modular-schemas): [combining with \$ref](./docs/validation.md#ref), [\$data reference](./docs/guide/combining-schemas.md#data-reference), [$merge and $patch](./docs/validation.md#merge-and-patch-keywords) - - [Asynchronous schema compilation](./docs/validation.md#asynchronous-schema-compilation) +- [Validation guide](./docs/guide/getting-started.md) + - [Getting started](./docs/guide/getting-started.md) + - [Validating formats](./docs/guide/formats.md) + - [Modular schemas](./docs/guide/combining-schemas.md): [combining with \$ref](./docs/guide/combining-schemas#ref), [\$data reference](./docs/guide/combining-schemas.md#data-reference), [$merge and $patch](./docs/guide/combining-schemas#merge-and-patch-keywords) + - [Asynchronous schema compilation](./docs/guide/managing-schemas.md#asynchronous-schema-compilation) - [Standalone validation code](./docs/standalone.md) - - [Asynchronous validation](./docs/validation.md#asynchronous-validation) - - [Modifying data](./docs/validation.md#modifying-data-during-validation): [additional properties](./docs/validation.md#removing-additional-properties), [defaults](./docs/validation.md#assigning-defaults), [type coercion](./docs/validation.md#coercing-data-types) + - [Asynchronous validation](./docs/guide/async-validation.md) + - [Modifying data](./docs/guide/modifying-data.md): [additional properties](./docs/guide/modifying-data.md#removing-additional-properties), [defaults](./docs/guide/modifying-data.md#assigning-defaults), [type coercion](./docs/guide/modifying-data.md#coercing-data-types) - [Extending Ajv](#extending-ajv) - User-defined keywords: - - [basics](./docs/validation.md#user-defined-keywords) + - [basics](./docs/guide/user-keywords.md) - [guide](./docs/keywords.md) - [Plugins](#plugins) - [Related packages](#related-packages) @@ -183,13 +198,13 @@ Performance of different validators by [json-schema-benchmark](https://github.co - meta-schema for JTD schemas - "union" keyword and user-defined keywords (can be used inside "metadata" member of the schema) - supports [browsers](#using-in-browser) and Node.js 0.10-14.x -- [asynchronous loading](./docs/validation.md#asynchronous-schema-compilation) of referenced schemas during compilation +- [asynchronous loading](./docs/guide/managing-schemas.md#asynchronous-schema-compilation) of referenced schemas during compilation - "All errors" validation mode with [option allErrors](./docs/api.md#options) - [error messages with parameters](./docs/api.md#validation-errors) describing error reasons to allow error message generation - i18n error messages support with [ajv-i18n](https://github.com/ajv-validator/ajv-i18n) package -- [removing-additional-properties](./docs/validation.md#removing-additional-properties) -- [assigning defaults](./docs/validation.md#assigning-defaults) to missing properties and items -- [coercing data](./docs/validation.md#coercing-data-types) to the types specified in `type` keywords +- [removing-additional-properties](./docs/guide/modifying-data.md#removing-additional-properties) +- [assigning defaults](./docs/guide/modifying-data.md#assigning-defaults) to missing properties and items +- [coercing data](./docs/guide/modifying-data.md#coercing-data-types) to the types specified in `type` keywords - [user-defined keywords](#user-defined-keywords) - draft-06/07 keywords `const`, `contains`, `propertyNames` and `if/then/else` - draft-06 boolean schemas (`true`/`false` as a schema to always pass/fail). @@ -229,7 +244,7 @@ See more examples in [Guide: getting started](./docs/guide/getting-started) ### User defined keywords -See section in [data validation](./docs/validation.md#user-defined-keywords) and the [detailed guide](./docs/keywords.md). +See section in [data validation](./docs/guide/user-keywords.md) and the [detailed guide](./docs/keywords.md). ### Plugins diff --git a/docs/api.md b/docs/api.md index 5b378130d..114ff39c7 100644 --- a/docs/api.md +++ b/docs/api.md @@ -18,7 +18,7 @@ See [Options](./options) Generate validating function and cache the compiled schema for future use. -Validating function returns a boolean value (or promise for async schemas that must have `$async: true` property - see [Asynchronous validation](./validation.md#asynchronous-validation)). This function has properties `errors` and `schema`. Errors encountered during the last validation are assigned to `errors` property (it is assigned `null` if there was no errors). `schema` property contains the reference to the original schema. +Validating function returns a boolean value (or promise for async schemas that must have `$async: true` property - see [Asynchronous validation](./guide/async-validation.md)). This function has properties `errors` and `schema`. Errors encountered during the last validation are assigned to `errors` property (it is assigned `null` if there was no errors). `schema` property contains the reference to the original schema. The schema passed to this method will be validated against meta-schema unless `validateSchema` option is false. If schema is invalid, an error will be thrown. See [options](#options). @@ -135,7 +135,7 @@ You can asynchronously compile meta-schema by passing `true` as the second param Similarly to `compile`, it can return type guard in typescript. -See example in [Asynchronous compilation](./validation.md#asynchronous-schema-compilation). +See example in [Asynchronous compilation](./guide/managing-schemas.md#asynchronous-schema-compilation). ### ajv.validate(schemaOrRef: object | string, data: any): boolean @@ -151,7 +151,7 @@ In typescript this method can act as a type guard (similarly to function returne Every time this method is called the errors are overwritten so you need to copy them to another variable if you want to use them later. ::: -If the schema is asynchronous (has `$async` keyword on the top level) this method returns a Promise. See [Asynchronous validation](./validation.md#asynchronous-validation). +If the schema is asynchronous (has `$async` keyword on the top level) this method returns a Promise. See [Asynchronous validation](./guide/async-validation.md). @@ -332,7 +332,7 @@ Options can have properties `separator` (string used to separate errors, ", " by ## Validation errors -In case of validation failure, Ajv assigns the array of errors to `errors` property of validation function (or to `errors` property of Ajv instance when `validate` or `validateSchema` methods were called). In case of [asynchronous validation](./validation.md#asynchronous-validation), the returned promise is rejected with exception `Ajv.ValidationError` that has `errors` property. +In case of validation failure, Ajv assigns the array of errors to `errors` property of validation function (or to `errors` property of Ajv instance when `validate` or `validateSchema` methods were called). In case of [asynchronous validation](./guide/async-validation.md), the returned promise is rejected with exception `Ajv.ValidationError` that has `errors` property. ### Error objects diff --git a/docs/coercion.md b/docs/coercion.md index 4bb0cce70..e4a0f595c 100644 --- a/docs/coercion.md +++ b/docs/coercion.md @@ -1,6 +1,6 @@ # Type coercion rules -To enable type coercion pass option `coerceTypes` to Ajv with `true` or `array` (it is `false` by default). See [example](./validation.md#coercing-data-types). +To enable type coercion pass option `coerceTypes` to Ajv with `true` or `array` (it is `false` by default). See [example](./guide/modifying-data.md#coercing-data-types). The coercion rules are different from JavaScript: diff --git a/docs/guide/combining-schemas.md b/docs/guide/combining-schemas.md index d73733e39..dc2995880 100644 --- a/docs/guide/combining-schemas.md +++ b/docs/guide/combining-schemas.md @@ -1,5 +1,7 @@ # Combining schemas +[[toc]] + ## Combining schemas with $ref You can structure your validation logic across multiple schema files and have schemas reference each other using `$ref` keyword. @@ -49,7 +51,7 @@ See [Options](./api.md#options) and [addSchema](./api.md#add-schema) method. - The actual location of the schema file in the file system is not used. - You can pass the identifier of the schema as the second parameter of `addSchema` method or as a property name in `schemas` option. This identifier can be used instead of (or in addition to) schema \$id. - You cannot have the same \$id (or the schema identifier) used for more than one schema - the exception will be thrown. -- You can implement dynamic resolution of the referenced schemas using `compileAsync` method. In this way you can store schemas in any system (files, web, database, etc.) and reference them without explicitly adding to Ajv instance. See [Asynchronous schema compilation](./validation.md#asynchronous-schema-compilation). +- You can implement dynamic resolution of the referenced schemas using `compileAsync` method. In this way you can store schemas in any system (files, web, database, etc.) and reference them without explicitly adding to Ajv instance. See [Asynchronous schema compilation](./managing-schemas.md#asynchronous-schema-compilation). ::: ## Extending recursive schemas diff --git a/docs/options.md b/docs/options.md index 59c43f124..4f0591f3d 100644 --- a/docs/options.md +++ b/docs/options.md @@ -124,7 +124,7 @@ Format validation. Option values: -- `true` (default) - validate formats (see [Formats](./validation.md#formats)). In [strict mode](./strict-mode.md) unknown formats will throw exception during schema compilation (and fail validation in case format keyword value is [\$data reference](./guide/combining-schemas.md#data-reference)). +- `true` (default) - validate formats (see [Formats](./guide/formats.md)). In [strict mode](./strict-mode.md) unknown formats will throw exception during schema compilation (and fail validation in case format keyword value is [\$data reference](./guide/combining-schemas.md#data-reference)). - `false` - do not validate any format keywords (TODO they will still collect annotations once supported). ## Validation and reporting options @@ -174,13 +174,13 @@ Option values: ### loadSchema -Asynchronous function that will be used to load remote schemas when `compileAsync` [method](#api-compileAsync) is used and some reference is missing (option `missingRefs` should NOT be 'fail' or 'ignore'). This function should accept remote schema uri as a parameter and return a Promise that resolves to a schema. See example in [Asynchronous compilation](./validation.md#asynchronous-schema-compilation). +Asynchronous function that will be used to load remote schemas when `compileAsync` [method](#api-compileAsync) is used and some reference is missing (option `missingRefs` should NOT be 'fail' or 'ignore'). This function should accept remote schema uri as a parameter and return a Promise that resolves to a schema. See example in [Asynchronous compilation](./guide/managing-schemas.md#asynchronous-schema-compilation). ## Options to modify validated data ### removeAdditional -Remove additional properties - see example in [Removing additional properties](./validation.md#removing-additional-properties). +Remove additional properties - see example in [Removing additional properties](./guide/modifying-data.md#removing-additional-properties). This option is not used if schema is added with `addMetaSchema` method. @@ -195,7 +195,7 @@ Option values: Replace missing or undefined properties and items with the values from corresponding `default` keywords. Default behaviour is to ignore `default` keywords. This option is not used if schema is added with `addMetaSchema` method. -See examples in [Assigning defaults](./validation.md#assigning-defaults). +See examples in [Assigning defaults](./guide/modifying-data.md#assigning-defaults). Option values: @@ -205,7 +205,7 @@ Option values: ### coerceTypes -Change data type of data to match `type` keyword. See the example in [Coercing data types](./validation.md#coercing-data-types) and [coercion rules](./coercion.md). +Change data type of data to match `type` keyword. See the example in [Coercing data types](./guide/modifying-data.md#coercing-data-types) and [coercion rules](./coercion.md). Option values: diff --git a/docs/strict-mode.md b/docs/strict-mode.md index 493916ba7..66dbe95cb 100644 --- a/docs/strict-mode.md +++ b/docs/strict-mode.md @@ -76,11 +76,11 @@ const ajv = new Ajv({formats: { }) ``` -Standard JSON Schema formats are provided in [ajv-formats](https://github.com/ajv-validator/ajv-formats) package - see [Formats](./validation.md#formats) section. +Standard JSON Schema formats are provided in [ajv-formats](https://github.com/ajv-validator/ajv-formats) package - see [Formats](./guide/formats) section. #### Ignored defaults -With `useDefaults` option Ajv modifies validated data by assigning defaults from the schema, but there are different limitations when the defaults can be ignored (see [Assigning defaults](./validation.md#assigning-defaults)). In strict mode Ajv fails schema compilation if such defaults are used in the schema. +With `useDefaults` option Ajv modifies validated data by assigning defaults from the schema, but there are different limitations when the defaults can be ignored (see [Assigning defaults](./guide/modifying-data.md#assigning-defaults)). In strict mode Ajv fails schema compilation if such defaults are used in the schema. ### Prevent unexpected validation From e8b71d820a9732f6557bce6f26fe987c4efa4c9a Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Sat, 6 Mar 2021 15:59:18 +0000 Subject: [PATCH 14/25] site: README -> HOME --- docs/{README.md => HOME.md} | 0 scripts/publish-site | 13 +++++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) rename docs/{README.md => HOME.md} (100%) diff --git a/docs/README.md b/docs/HOME.md similarity index 100% rename from docs/README.md rename to docs/HOME.md diff --git a/scripts/publish-site b/scripts/publish-site index ef757b202..c59629271 100755 --- a/scripts/publish-site +++ b/scripts/publish-site @@ -1,9 +1,14 @@ #!/usr/bin/env bash -set -ex +set -e echo "About to publish $GITHUB_REF to gh-pages..." -cp CODE_OF_CONDUCT.md docs -cp CONTRIBUTING.md docs -cp LICENSE docs/LICENSE.md +function copyReplace { + sed "s/](.\/docs\//](.\//" $1 > $2 +} + +copyReplace README.md docs/README.md +copyReplace CODE_OF_CONDUCT.md docs/CODE_OF_CONDUCT.md +copyReplace CONTRIBUTING.md docs/CONTRIBUTING.md +copyReplace LICENSE docs/LICENSE.md From 9f5b0511008ea0e902a85d03694f32682a69c69c Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Sat, 6 Mar 2021 16:12:49 +0000 Subject: [PATCH 15/25] site: replace links in copied files --- .gitignore | 1 + README.md | 14 ++++++++++---- scripts/publish-site | 2 +- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 861174534..6791d6c03 100644 --- a/.gitignore +++ b/.gitignore @@ -42,6 +42,7 @@ package-lock.json spec/_json/*.js +docs/README.md docs/CODE_OF_CONDUCT.md docs/CONTRIBUTING.md docs/LICENSE.md diff --git a/README.md b/README.md index 2d2da61e0..221e2ff2c 100644 --- a/README.md +++ b/README.md @@ -2,20 +2,24 @@ # Ajv: Another JSON schema validator -The fastest JSON schema validator for Node.js and browser. +Super fast JSON schema validator for Node.js and browser. Supports JSON Schema draft-06/07/2019-09 (draft-04 is supported in [version 6](https://github.com/ajv-validator/ajv/tree/v6)) and JSON Type Definition [RFC8927](https://datatracker.ietf.org/doc/rfc8927/). +::: v-pre [![build](https://github.com/ajv-validator/ajv/workflows/build/badge.svg)](https://github.com/ajv-validator/ajv/actions?query=workflow%3Abuild) [![npm](https://img.shields.io/npm/v/ajv.svg)](https://www.npmjs.com/package/ajv) [![npm downloads](https://img.shields.io/npm/dm/ajv.svg)](https://www.npmjs.com/package/ajv) [![Coverage Status](https://coveralls.io/repos/github/ajv-validator/ajv/badge.svg?branch=master)](https://coveralls.io/github/ajv-validator/ajv?branch=master) [![Gitter](https://img.shields.io/gitter/room/ajv-validator/ajv.svg)](https://gitter.im/ajv-validator/ajv) [![GitHub Sponsors](https://img.shields.io/badge/$-sponsors-brightgreen)](https://github.com/sponsors/epoberezkin) +::: ## Platinum sponsors -[](https://www.mozilla.org)[](https://opencollective.com/ajv)[](https://opencollective.com/ajv) +::: v-pre +[](https://www.mozilla.org)[](https://opencollective.com/ajv) +::: ## Using version 7 @@ -130,7 +134,9 @@ Please also review [Contributing guidelines](./CONTRIBUTING.md) and [Code compon ## Mozilla MOSS grant and OpenJS Foundation -[](https://www.mozilla.org/en-US/moss/)     [](https://openjsf.org/blog/2020/08/14/ajv-joins-openjs-foundation-as-an-incubation-project/) +::: v-pre +[](https://www.mozilla.org/en-US/moss/)[](https://openjsf.org/blog/2020/08/14/ajv-joins-openjs-foundation-as-an-incubation-project/) +::: Ajv has been awarded a grant from Mozilla’s [Open Source Support (MOSS) program](https://www.mozilla.org/en-US/moss/) in the “Foundational Technology” track! It will sponsor the development of Ajv support of [JSON Schema version 2019-09](https://tools.ietf.org/html/draft-handrews-json-schema-02) and of [JSON Type Definition (RFC8927)](https://datatracker.ietf.org/doc/rfc8927/). @@ -297,7 +303,7 @@ If you have published a useful plugin please submit a PR to add it to the next s ## Changes history -See https://github.com/ajv-validator/ajv/releases +See [https://github.com/ajv-validator/ajv/releases](https://github.com/ajv-validator/ajv/releases) **Please note**: [Changes in version 7.0.0](https://github.com/ajv-validator/ajv/releases/tag/v7.0.0) diff --git a/scripts/publish-site b/scripts/publish-site index c59629271..ab70d2542 100755 --- a/scripts/publish-site +++ b/scripts/publish-site @@ -5,7 +5,7 @@ set -e echo "About to publish $GITHUB_REF to gh-pages..." function copyReplace { - sed "s/](.\/docs\//](.\//" $1 > $2 + sed "s/](.\/docs\//](.\//g" $1 > $2 } copyReplace README.md docs/README.md From 593c0debcf43d1a4c96b7623032369a7aee1450a Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Sat, 6 Mar 2021 17:53:33 +0000 Subject: [PATCH 16/25] site: add github button, add links --- CODE_OF_CONDUCT.md | 11 +- CONTRIBUTING.md | 5 +- README.md | 4 +- docs/.vuepress/components/GitHub.vue | 29 ++ docs/.vuepress/config.js | 6 +- docs/.vuepress/theme/LICENSE | 21 ++ .../theme/components/AlgoliaSearchBox.vue | 172 ++++++++++++ .../theme/components/DropdownLink.vue | 252 ++++++++++++++++++ .../theme/components/DropdownTransition.vue | 33 +++ docs/.vuepress/theme/components/Home.vue | 175 ++++++++++++ docs/.vuepress/theme/components/NavLink.vue | 90 +++++++ docs/.vuepress/theme/components/NavLinks.vue | 147 ++++++++++ docs/.vuepress/theme/components/Navbar.vue | 140 ++++++++++ docs/.vuepress/theme/components/Page.vue | 31 +++ docs/.vuepress/theme/components/PageEdit.vue | 155 +++++++++++ docs/.vuepress/theme/components/PageNav.vue | 163 +++++++++++ docs/.vuepress/theme/components/Sidebar.vue | 64 +++++ .../theme/components/SidebarButton.vue | 40 +++ .../theme/components/SidebarGroup.vue | 141 ++++++++++ .../theme/components/SidebarLink.vue | 133 +++++++++ .../theme/components/SidebarLinks.vue | 106 ++++++++ .../theme/global-components/Badge.vue | 44 +++ .../theme/global-components/CodeBlock.vue | 41 +++ .../theme/global-components/CodeGroup.vue | 120 +++++++++ docs/.vuepress/theme/index.js | 71 +++++ docs/.vuepress/theme/layouts/404.vue | 30 +++ docs/.vuepress/theme/layouts/Layout.vue | 151 +++++++++++ docs/.vuepress/theme/noopModule.js | 1 + docs/.vuepress/theme/styles/arrow.styl | 22 ++ docs/.vuepress/theme/styles/code.styl | 137 ++++++++++ docs/.vuepress/theme/styles/config.styl | 1 + .../.vuepress/theme/styles/custom-blocks.styl | 44 +++ docs/.vuepress/theme/styles/index.styl | 202 ++++++++++++++ docs/.vuepress/theme/styles/mobile.styl | 37 +++ docs/.vuepress/theme/styles/toc.styl | 3 + docs/.vuepress/theme/styles/wrapper.styl | 9 + docs/.vuepress/theme/util/index.js | 239 +++++++++++++++++ docs/faq.md | 2 +- 38 files changed, 3058 insertions(+), 14 deletions(-) create mode 100644 docs/.vuepress/components/GitHub.vue create mode 100644 docs/.vuepress/theme/LICENSE create mode 100644 docs/.vuepress/theme/components/AlgoliaSearchBox.vue create mode 100644 docs/.vuepress/theme/components/DropdownLink.vue create mode 100644 docs/.vuepress/theme/components/DropdownTransition.vue create mode 100644 docs/.vuepress/theme/components/Home.vue create mode 100644 docs/.vuepress/theme/components/NavLink.vue create mode 100644 docs/.vuepress/theme/components/NavLinks.vue create mode 100644 docs/.vuepress/theme/components/Navbar.vue create mode 100644 docs/.vuepress/theme/components/Page.vue create mode 100644 docs/.vuepress/theme/components/PageEdit.vue create mode 100644 docs/.vuepress/theme/components/PageNav.vue create mode 100644 docs/.vuepress/theme/components/Sidebar.vue create mode 100644 docs/.vuepress/theme/components/SidebarButton.vue create mode 100644 docs/.vuepress/theme/components/SidebarGroup.vue create mode 100644 docs/.vuepress/theme/components/SidebarLink.vue create mode 100644 docs/.vuepress/theme/components/SidebarLinks.vue create mode 100644 docs/.vuepress/theme/global-components/Badge.vue create mode 100644 docs/.vuepress/theme/global-components/CodeBlock.vue create mode 100644 docs/.vuepress/theme/global-components/CodeGroup.vue create mode 100644 docs/.vuepress/theme/index.js create mode 100644 docs/.vuepress/theme/layouts/404.vue create mode 100644 docs/.vuepress/theme/layouts/Layout.vue create mode 100644 docs/.vuepress/theme/noopModule.js create mode 100644 docs/.vuepress/theme/styles/arrow.styl create mode 100644 docs/.vuepress/theme/styles/code.styl create mode 100644 docs/.vuepress/theme/styles/config.styl create mode 100644 docs/.vuepress/theme/styles/custom-blocks.styl create mode 100644 docs/.vuepress/theme/styles/index.styl create mode 100644 docs/.vuepress/theme/styles/mobile.styl create mode 100644 docs/.vuepress/theme/styles/toc.styl create mode 100644 docs/.vuepress/theme/styles/wrapper.styl create mode 100644 docs/.vuepress/theme/util/index.js diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 28a25baee..b3ceffd86 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -37,9 +37,10 @@ Project maintainers have the right and responsibility to remove, edit, or reject ### Scope -The goal of this Code of Conduct is to set standards and expectations around how we interact within this community. It’s scope applies to all project participants and covers all interactions within the community associated with this project including, but not limited to, email communication, issue trackers, source code repositories, forums, and social media. +The goal of this Code of Conduct is to set standards and expectations around how we interact within this community. It’s scope applies to all project participants and covers all interactions within the community associated with this project including, but not limited to, email communication, issue trackers, source code repositories, forums, and social media. Examples of representing a project or community include: + - Using an official project e-mail address - Posting via an official social media account - Acting as an appointed representative at an online or offline event @@ -50,7 +51,7 @@ Representation of a project may be further defined and clarified by project main We will not tolerate abuse, harassment, or any other unacceptable behaviour made against community members, project maintainers, or members of our project team, either online or offline. -Violations of our Code of Conduct may be reported by contacting the project team at ajv.validator@gmail.com. The project team will review and investigate all complaints, to the best of our ability, and will respond in a way that it deems appropriate to the circumstances. +Violations of our Code of Conduct may be reported by contacting the project team at [ajv.validator@gmail.com](mailto:ajv.validator@gmail.com). The project team will review and investigate all complaints, to the best of our ability, and will respond in a way that it deems appropriate to the circumstances. Reports of violations will be investigated in a respectful, professional manner as promptly and confidentially as possible. We will have zero tolerance for intimidation or retaliation against anyone who raises a concern, makes a report or cooperates in an investigation around a violation of our code of conduct. Further details of specific enforcement policies may be posted separately. @@ -58,8 +59,8 @@ Project maintainers who do not follow or enforce the Code of Conduct in good fai ### Attribution -This Code of Conduct is adapted from the [Contributor Covenant][https://www.contributor-covenant.org], version 1.4, -available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html +This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org), version 1.4, +available at [https://www.contributor-covenant.org/version/1/4/code-of-conduct.html](https://www.contributor-covenant.org/version/1/4/code-of-conduct.html) For answers to common questions about this code of conduct, see -https://www.contributor-covenant.org/faq +[https://www.contributor-covenant.org/faq](https://www.contributor-covenant.org/faq) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fb1229aae..3231428c9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,7 +4,7 @@ permalink: /contributing # Contributing guide -Thank you for your help making Ajv better! Every contribution is appreciated. There are many areas where you can contribute. +Thank you for your help making Ajv better! Every contribution is appreciated. There are many areas where you can contribute. ::: tip Please note If you plan to implement a new feature or some other change please create an issue first, to make sure that your work is not lost. @@ -21,9 +21,10 @@ There is a link in the bottom of each website page to quickly edit it. ## Issues Before submitting the issue: + - Search the existing issues - Review [Frequently Asked Questions](./docs/faq.md). -- Provide all the relevant information, reducing both your schema and data to the smallest possible size when they still have the issue. +- Provide all the relevant information, reducing both your schema and data to the smallest possible size when they still have the issue. We value simplicity - simplifying the example that shows the issue makes it more valuable for other users. This process helps us reduce situations where an error is occurring due to incorrect usage rather than a bug. diff --git a/README.md b/README.md index 221e2ff2c..872129360 100644 --- a/README.md +++ b/README.md @@ -54,16 +54,18 @@ More than 100 people contributed to Ajv, and we would love to have you join the At Ajv, we are committed to creating more equitable and inclusive spaces for our community and team members to contribute to discussions that affect both this project and our ongoing work in the open source ecosystem. -We strive to create an environment of respect and healthy discourse by setting standards for our interactions and we expect it from all members of our community - from long term project member to first time visitor. For more information, review our [code of conduct](./CODE_OF_CONDUCT.md) and values. +We strive to create an environment of respect and healthy discourse by setting standards for our interactions and we expect it from all members of our community - from long term project member to first time visitor. For more information, review our [code of conduct](./CODE_OF_CONDUCT.md) and values. ### How we make decisions We value conscious curation of our library size, and balancing performance and functionality. To that end, we cannot accept every suggestion. When evaluating pull requests we consider: + - Will this benefit many users or a niche use case? - How will this impact the performance of Ajv? - How will this expand our library size? To help us evaluate and understand, when you submit an issue and pull request: + - Explain why this feature is important to the user base - Include documentation - Include test coverage with any new feature implementations diff --git a/docs/.vuepress/components/GitHub.vue b/docs/.vuepress/components/GitHub.vue new file mode 100644 index 000000000..04b57f97f --- /dev/null +++ b/docs/.vuepress/components/GitHub.vue @@ -0,0 +1,29 @@ + + + + + diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index 8324111c0..451d20222 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -106,11 +106,7 @@ module.exports = { { title: "Information", collapsable: false, - children: [ - "/faq", - "/security", - ["/LICENSE", "License"], - ] + children: ["/faq", "/security", ["/LICENSE", "License"]], }, ], repo: "ajv-validator/ajv", diff --git a/docs/.vuepress/theme/LICENSE b/docs/.vuepress/theme/LICENSE new file mode 100644 index 000000000..15f1f7e7a --- /dev/null +++ b/docs/.vuepress/theme/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2018-present, Yuxi (Evan) You + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/docs/.vuepress/theme/components/AlgoliaSearchBox.vue b/docs/.vuepress/theme/components/AlgoliaSearchBox.vue new file mode 100644 index 000000000..7071fb8fb --- /dev/null +++ b/docs/.vuepress/theme/components/AlgoliaSearchBox.vue @@ -0,0 +1,172 @@ + + + + + diff --git a/docs/.vuepress/theme/components/DropdownLink.vue b/docs/.vuepress/theme/components/DropdownLink.vue new file mode 100644 index 000000000..be6563fae --- /dev/null +++ b/docs/.vuepress/theme/components/DropdownLink.vue @@ -0,0 +1,252 @@ + + + + + diff --git a/docs/.vuepress/theme/components/DropdownTransition.vue b/docs/.vuepress/theme/components/DropdownTransition.vue new file mode 100644 index 000000000..eeaf12b5c --- /dev/null +++ b/docs/.vuepress/theme/components/DropdownTransition.vue @@ -0,0 +1,33 @@ + + + + + diff --git a/docs/.vuepress/theme/components/Home.vue b/docs/.vuepress/theme/components/Home.vue new file mode 100644 index 000000000..acd87446d --- /dev/null +++ b/docs/.vuepress/theme/components/Home.vue @@ -0,0 +1,175 @@ + + + + + diff --git a/docs/.vuepress/theme/components/NavLink.vue b/docs/.vuepress/theme/components/NavLink.vue new file mode 100644 index 000000000..f7e65a445 --- /dev/null +++ b/docs/.vuepress/theme/components/NavLink.vue @@ -0,0 +1,90 @@ + + + diff --git a/docs/.vuepress/theme/components/NavLinks.vue b/docs/.vuepress/theme/components/NavLinks.vue new file mode 100644 index 000000000..75b2b7c45 --- /dev/null +++ b/docs/.vuepress/theme/components/NavLinks.vue @@ -0,0 +1,147 @@ + + + + + diff --git a/docs/.vuepress/theme/components/Navbar.vue b/docs/.vuepress/theme/components/Navbar.vue new file mode 100644 index 000000000..f8dd49ca6 --- /dev/null +++ b/docs/.vuepress/theme/components/Navbar.vue @@ -0,0 +1,140 @@ + + + + + diff --git a/docs/.vuepress/theme/components/Page.vue b/docs/.vuepress/theme/components/Page.vue new file mode 100644 index 000000000..04ec7cb33 --- /dev/null +++ b/docs/.vuepress/theme/components/Page.vue @@ -0,0 +1,31 @@ + + + + + diff --git a/docs/.vuepress/theme/components/PageEdit.vue b/docs/.vuepress/theme/components/PageEdit.vue new file mode 100644 index 000000000..cf9b2d25c --- /dev/null +++ b/docs/.vuepress/theme/components/PageEdit.vue @@ -0,0 +1,155 @@ + + + + + diff --git a/docs/.vuepress/theme/components/PageNav.vue b/docs/.vuepress/theme/components/PageNav.vue new file mode 100644 index 000000000..4c19aae5f --- /dev/null +++ b/docs/.vuepress/theme/components/PageNav.vue @@ -0,0 +1,163 @@ + + + + + diff --git a/docs/.vuepress/theme/components/Sidebar.vue b/docs/.vuepress/theme/components/Sidebar.vue new file mode 100644 index 000000000..e70e33367 --- /dev/null +++ b/docs/.vuepress/theme/components/Sidebar.vue @@ -0,0 +1,64 @@ + + + + + diff --git a/docs/.vuepress/theme/components/SidebarButton.vue b/docs/.vuepress/theme/components/SidebarButton.vue new file mode 100644 index 000000000..3f54afd55 --- /dev/null +++ b/docs/.vuepress/theme/components/SidebarButton.vue @@ -0,0 +1,40 @@ + + + diff --git a/docs/.vuepress/theme/components/SidebarGroup.vue b/docs/.vuepress/theme/components/SidebarGroup.vue new file mode 100644 index 000000000..d7f192946 --- /dev/null +++ b/docs/.vuepress/theme/components/SidebarGroup.vue @@ -0,0 +1,141 @@ + + + + + diff --git a/docs/.vuepress/theme/components/SidebarLink.vue b/docs/.vuepress/theme/components/SidebarLink.vue new file mode 100644 index 000000000..4cd7665ae --- /dev/null +++ b/docs/.vuepress/theme/components/SidebarLink.vue @@ -0,0 +1,133 @@ + + + diff --git a/docs/.vuepress/theme/components/SidebarLinks.vue b/docs/.vuepress/theme/components/SidebarLinks.vue new file mode 100644 index 000000000..55e62885e --- /dev/null +++ b/docs/.vuepress/theme/components/SidebarLinks.vue @@ -0,0 +1,106 @@ + + + diff --git a/docs/.vuepress/theme/global-components/Badge.vue b/docs/.vuepress/theme/global-components/Badge.vue new file mode 100644 index 000000000..53951f9d5 --- /dev/null +++ b/docs/.vuepress/theme/global-components/Badge.vue @@ -0,0 +1,44 @@ + + + diff --git a/docs/.vuepress/theme/global-components/CodeBlock.vue b/docs/.vuepress/theme/global-components/CodeBlock.vue new file mode 100644 index 000000000..d59d85b26 --- /dev/null +++ b/docs/.vuepress/theme/global-components/CodeBlock.vue @@ -0,0 +1,41 @@ + + + + + diff --git a/docs/.vuepress/theme/global-components/CodeGroup.vue b/docs/.vuepress/theme/global-components/CodeGroup.vue new file mode 100644 index 000000000..ac6ec5543 --- /dev/null +++ b/docs/.vuepress/theme/global-components/CodeGroup.vue @@ -0,0 +1,120 @@ + + + + + diff --git a/docs/.vuepress/theme/index.js b/docs/.vuepress/theme/index.js new file mode 100644 index 000000000..01958f462 --- /dev/null +++ b/docs/.vuepress/theme/index.js @@ -0,0 +1,71 @@ +const path = require("path") + +// Theme API. +module.exports = (options, ctx) => { + const {themeConfig, siteConfig} = ctx + + // resolve algolia + const isAlgoliaSearch = + themeConfig.algolia || + Object.keys((siteConfig.locales && themeConfig.locales) || {}).some( + (base) => themeConfig.locales[base].algolia + ) + + const enableSmoothScroll = themeConfig.smoothScroll === true + + return { + alias() { + return { + "@AlgoliaSearchBox": isAlgoliaSearch + ? path.resolve(__dirname, "components/AlgoliaSearchBox.vue") + : path.resolve(__dirname, "noopModule.js"), + } + }, + + plugins: [ + ["@vuepress/active-header-links", options.activeHeaderLinks], + "@vuepress/search", + "@vuepress/plugin-nprogress", + [ + "container", + { + type: "tip", + defaultTitle: { + "/": "TIP", + "/zh/": "提示", + }, + }, + ], + [ + "container", + { + type: "warning", + defaultTitle: { + "/": "WARNING", + "/zh/": "注意", + }, + }, + ], + [ + "container", + { + type: "danger", + defaultTitle: { + "/": "WARNING", + "/zh/": "警告", + }, + }, + ], + [ + "container", + { + type: "details", + before: (info) => + `
${info ? `${info}` : ""}\n`, + after: () => "
\n", + }, + ], + ["smooth-scroll", enableSmoothScroll], + ], + } +} diff --git a/docs/.vuepress/theme/layouts/404.vue b/docs/.vuepress/theme/layouts/404.vue new file mode 100644 index 000000000..2cbfa0f17 --- /dev/null +++ b/docs/.vuepress/theme/layouts/404.vue @@ -0,0 +1,30 @@ + + + diff --git a/docs/.vuepress/theme/layouts/Layout.vue b/docs/.vuepress/theme/layouts/Layout.vue new file mode 100644 index 000000000..329807099 --- /dev/null +++ b/docs/.vuepress/theme/layouts/Layout.vue @@ -0,0 +1,151 @@ + + + diff --git a/docs/.vuepress/theme/noopModule.js b/docs/.vuepress/theme/noopModule.js new file mode 100644 index 000000000..b1c6ea436 --- /dev/null +++ b/docs/.vuepress/theme/noopModule.js @@ -0,0 +1 @@ +export default {} diff --git a/docs/.vuepress/theme/styles/arrow.styl b/docs/.vuepress/theme/styles/arrow.styl new file mode 100644 index 000000000..20bffc0dc --- /dev/null +++ b/docs/.vuepress/theme/styles/arrow.styl @@ -0,0 +1,22 @@ +@require './config' + +.arrow + display inline-block + width 0 + height 0 + &.up + border-left 4px solid transparent + border-right 4px solid transparent + border-bottom 6px solid $arrowBgColor + &.down + border-left 4px solid transparent + border-right 4px solid transparent + border-top 6px solid $arrowBgColor + &.right + border-top 4px solid transparent + border-bottom 4px solid transparent + border-left 6px solid $arrowBgColor + &.left + border-top 4px solid transparent + border-bottom 4px solid transparent + border-right 6px solid $arrowBgColor diff --git a/docs/.vuepress/theme/styles/code.styl b/docs/.vuepress/theme/styles/code.styl new file mode 100644 index 000000000..9d3aa9a54 --- /dev/null +++ b/docs/.vuepress/theme/styles/code.styl @@ -0,0 +1,137 @@ +{$contentClass} + code + color lighten($textColor, 20%) + padding 0.25rem 0.5rem + margin 0 + font-size 0.85em + background-color rgba(27,31,35,0.05) + border-radius 3px + .token + &.deleted + color #EC5975 + &.inserted + color $accentColor + +{$contentClass} + pre, pre[class*="language-"] + line-height 1.4 + padding 1.25rem 1.5rem + margin 0.85rem 0 + background-color $codeBgColor + border-radius 6px + overflow auto + code + color #fff + padding 0 + background-color transparent + border-radius 0 + +div[class*="language-"] + position relative + background-color $codeBgColor + border-radius 6px + .highlight-lines + user-select none + padding-top 1.3rem + position absolute + top 0 + left 0 + width 100% + line-height 1.4 + .highlighted + background-color rgba(0, 0, 0, 66%) + pre, pre[class*="language-"] + background transparent + position relative + z-index 1 + &::before + position absolute + z-index 3 + top 0.8em + right 1em + font-size 0.75rem + color rgba(255, 255, 255, 0.4) + &:not(.line-numbers-mode) + .line-numbers-wrapper + display none + &.line-numbers-mode + .highlight-lines .highlighted + position relative + &:before + content ' ' + position absolute + z-index 3 + left 0 + top 0 + display block + width $lineNumbersWrapperWidth + height 100% + background-color rgba(0, 0, 0, 66%) + pre + padding-left $lineNumbersWrapperWidth + 1 rem + vertical-align middle + .line-numbers-wrapper + position absolute + top 0 + width $lineNumbersWrapperWidth + text-align center + color rgba(255, 255, 255, 0.3) + padding 1.25rem 0 + line-height 1.4 + br + user-select none + .line-number + position relative + z-index 4 + user-select none + font-size 0.85em + &::after + content '' + position absolute + z-index 2 + top 0 + left 0 + width $lineNumbersWrapperWidth + height 100% + border-radius 6px 0 0 6px + border-right 1px solid rgba(0, 0, 0, 66%) + background-color $codeBgColor + + +for lang in $codeLang + div{'[class~="language-' + lang + '"]'} + &:before + content ('' + lang) + +div[class~="language-javascript"] + &:before + content "js" + +div[class~="language-typescript"] + &:before + content "ts" + +div[class~="language-markup"] + &:before + content "html" + +div[class~="language-markdown"] + &:before + content "md" + +div[class~="language-json"]:before + content "json" + +div[class~="language-ruby"]:before + content "rb" + +div[class~="language-python"]:before + content "py" + +div[class~="language-bash"]:before + content "sh" + +div[class~="language-php"]:before + content "php" + +@import '~prismjs/themes/prism-tomorrow.css' diff --git a/docs/.vuepress/theme/styles/config.styl b/docs/.vuepress/theme/styles/config.styl new file mode 100644 index 000000000..9e403210f --- /dev/null +++ b/docs/.vuepress/theme/styles/config.styl @@ -0,0 +1 @@ +$contentClass = '.theme-default-content' diff --git a/docs/.vuepress/theme/styles/custom-blocks.styl b/docs/.vuepress/theme/styles/custom-blocks.styl new file mode 100644 index 000000000..5b868166a --- /dev/null +++ b/docs/.vuepress/theme/styles/custom-blocks.styl @@ -0,0 +1,44 @@ +.custom-block + .custom-block-title + font-weight 600 + margin-bottom -0.4rem + &.tip, &.warning, &.danger + padding .1rem 1.5rem + border-left-width .5rem + border-left-style solid + margin 1rem 0 + &.tip + background-color #f3f5f7 + border-color #42b983 + &.warning + background-color rgba(255,229,100,.3) + border-color darken(#ffe564, 35%) + color darken(#ffe564, 70%) + .custom-block-title + color darken(#ffe564, 50%) + a + color $textColor + &.danger + background-color #ffe6e6 + border-color darken(red, 20%) + color darken(red, 70%) + .custom-block-title + color darken(red, 40%) + a + color $textColor + &.details + display block + position relative + border-radius 2px + margin 1.6em 0 + padding 1.6em + background-color #eee + h4 + margin-top 0 + figure, p + &:last-child + margin-bottom 0 + padding-bottom 0 + summary + outline none + cursor pointer diff --git a/docs/.vuepress/theme/styles/index.styl b/docs/.vuepress/theme/styles/index.styl new file mode 100644 index 000000000..1b34f6022 --- /dev/null +++ b/docs/.vuepress/theme/styles/index.styl @@ -0,0 +1,202 @@ +@require './config' +@require './code' +@require './custom-blocks' +@require './arrow' +@require './wrapper' +@require './toc' + +html, body + padding 0 + margin 0 + background-color #fff + +body + font-family -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif + -webkit-font-smoothing antialiased + -moz-osx-font-smoothing grayscale + font-size 16px + color $textColor + +.page + padding-left $sidebarWidth + +.navbar + position fixed + z-index 20 + top 0 + left 0 + right 0 + height $navbarHeight + background-color #fff + box-sizing border-box + border-bottom 1px solid $borderColor + +.sidebar-mask + position fixed + z-index 9 + top 0 + left 0 + width 100vw + height 100vh + display none + +.sidebar + font-size 16px + background-color #fff + width $sidebarWidth + position fixed + z-index 10 + margin 0 + top $navbarHeight + left 0 + bottom 0 + box-sizing border-box + border-right 1px solid $borderColor + overflow-y auto + +{$contentClass}:not(.custom) + @extend $wrapper + > *:first-child + margin-top $navbarHeight + + a:hover + text-decoration underline + + p.demo + padding 1rem 1.5rem + border 1px solid #ddd + border-radius 4px + + img + max-width 100% + +{$contentClass}.custom + padding 0 + margin 0 + + img + max-width 100% + +a + font-weight 500 + color $accentColor + text-decoration none + +p a code + font-weight 400 + color $accentColor + +kbd + background #eee + border solid 0.15rem #ddd + border-bottom solid 0.25rem #ddd + border-radius 0.15rem + padding 0 0.15em + +blockquote + font-size 1rem + color #999; + border-left .2rem solid #dfe2e5 + margin 1rem 0 + padding .25rem 0 .25rem 1rem + + & > p + margin 0 + +ul, ol + padding-left 1.2em + +strong + font-weight 600 + +h1, h2, h3, h4, h5, h6 + font-weight 600 + line-height 1.25 + + {$contentClass}:not(.custom) > & + margin-top (0.5rem - $navbarHeight) + padding-top ($navbarHeight + 1rem) + margin-bottom 0 + + &:first-child + margin-top -1.5rem + margin-bottom 1rem + + + p, + pre, + .custom-block + margin-top 2rem + + &:focus .header-anchor, + &:hover .header-anchor + opacity: 1 + +h1 + font-size 2.2rem + +h2 + font-size 1.65rem + padding-bottom .3rem + border-bottom 1px solid $borderColor + +h3 + font-size 1.35rem + +a.header-anchor + font-size 0.85em + float left + margin-left -0.87em + padding-right 0.23em + margin-top 0.125em + opacity 0 + + &:focus, + &:hover + text-decoration none + +code, kbd, .line-number + font-family source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace + +p, ul, ol + line-height 1.7 + +hr + border 0 + border-top 1px solid $borderColor + +table + border-collapse collapse + margin 1rem 0 + display: block + overflow-x: auto + +tr + border-top 1px solid #dfe2e5 + + &:nth-child(2n) + background-color #f6f8fa + +th, td + border 1px solid #dfe2e5 + padding .6em 1em + +.theme-container + &.sidebar-open + .sidebar-mask + display: block + + &.no-navbar + {$contentClass}:not(.custom) > h1, h2, h3, h4, h5, h6 + margin-top 1.5rem + padding-top 0 + + .sidebar + top 0 + +@media (min-width: ($MQMobile + 1px)) + .theme-container.no-sidebar + .sidebar + display none + + .page + padding-left 0 + +@require 'mobile.styl' diff --git a/docs/.vuepress/theme/styles/mobile.styl b/docs/.vuepress/theme/styles/mobile.styl new file mode 100644 index 000000000..f5bd32739 --- /dev/null +++ b/docs/.vuepress/theme/styles/mobile.styl @@ -0,0 +1,37 @@ +@require './config' + +$mobileSidebarWidth = $sidebarWidth * 0.82 + +// narrow desktop / iPad +@media (max-width: $MQNarrow) + .sidebar + font-size 15px + width $mobileSidebarWidth + .page + padding-left $mobileSidebarWidth + +// wide mobile +@media (max-width: $MQMobile) + .sidebar + top 0 + padding-top $navbarHeight + transform translateX(-100%) + transition transform .2s ease + .page + padding-left 0 + .theme-container + &.sidebar-open + .sidebar + transform translateX(0) + &.no-navbar + .sidebar + padding-top: 0 + +// narrow mobile +@media (max-width: $MQMobileNarrow) + h1 + font-size 1.9rem + {$contentClass} + div[class*="language-"] + margin 0.85rem -1.5rem + border-radius 0 diff --git a/docs/.vuepress/theme/styles/toc.styl b/docs/.vuepress/theme/styles/toc.styl new file mode 100644 index 000000000..d3e71069b --- /dev/null +++ b/docs/.vuepress/theme/styles/toc.styl @@ -0,0 +1,3 @@ +.table-of-contents + .badge + vertical-align middle diff --git a/docs/.vuepress/theme/styles/wrapper.styl b/docs/.vuepress/theme/styles/wrapper.styl new file mode 100644 index 000000000..a99262c71 --- /dev/null +++ b/docs/.vuepress/theme/styles/wrapper.styl @@ -0,0 +1,9 @@ +$wrapper + max-width $contentWidth + margin 0 auto + padding 2rem 2.5rem + @media (max-width: $MQNarrow) + padding 2rem + @media (max-width: $MQMobileNarrow) + padding 1.5rem + diff --git a/docs/.vuepress/theme/util/index.js b/docs/.vuepress/theme/util/index.js new file mode 100644 index 000000000..8f018dd98 --- /dev/null +++ b/docs/.vuepress/theme/util/index.js @@ -0,0 +1,239 @@ +export const hashRE = /#.*$/ +export const extRE = /\.(md|html)$/ +export const endingSlashRE = /\/$/ +export const outboundRE = /^[a-z]+:/i + +export function normalize(path) { + return decodeURI(path).replace(hashRE, "").replace(extRE, "") +} + +export function getHash(path) { + const match = path.match(hashRE) + if (match) { + return match[0] + } +} + +export function isExternal(path) { + return outboundRE.test(path) +} + +export function isMailto(path) { + return /^mailto:/.test(path) +} + +export function isTel(path) { + return /^tel:/.test(path) +} + +export function ensureExt(path) { + if (isExternal(path)) { + return path + } + const hashMatch = path.match(hashRE) + const hash = hashMatch ? hashMatch[0] : "" + const normalized = normalize(path) + + if (endingSlashRE.test(normalized)) { + return path + } + return normalized + ".html" + hash +} + +export function isActive(route, path) { + const routeHash = decodeURIComponent(route.hash) + const linkHash = getHash(path) + if (linkHash && routeHash !== linkHash) { + return false + } + const routePath = normalize(route.path) + const pagePath = normalize(path) + return routePath === pagePath +} + +export function resolvePage(pages, rawPath, base) { + if (isExternal(rawPath)) { + return { + type: "external", + path: rawPath, + } + } + if (base) { + rawPath = resolvePath(rawPath, base) + } + const path = normalize(rawPath) + for (let i = 0; i < pages.length; i++) { + if (normalize(pages[i].regularPath) === path) { + return Object.assign({}, pages[i], { + type: "page", + path: ensureExt(pages[i].path), + }) + } + } + console.error(`[vuepress] No matching page found for sidebar item "${rawPath}"`) + return {} +} + +function resolvePath(relative, base, append) { + const firstChar = relative.charAt(0) + if (firstChar === "/") { + return relative + } + + if (firstChar === "?" || firstChar === "#") { + return base + relative + } + + const stack = base.split("/") + + // remove trailing segment if: + // - not appending + // - appending to trailing slash (last segment is empty) + if (!append || !stack[stack.length - 1]) { + stack.pop() + } + + // resolve relative path + const segments = relative.replace(/^\//, "").split("/") + for (let i = 0; i < segments.length; i++) { + const segment = segments[i] + if (segment === "..") { + stack.pop() + } else if (segment !== ".") { + stack.push(segment) + } + } + + // ensure leading slash + if (stack[0] !== "") { + stack.unshift("") + } + + return stack.join("/") +} + +/** + * @param { Page } page + * @param { string } regularPath + * @param { SiteData } site + * @param { string } localePath + * @returns { SidebarGroup } + */ +export function resolveSidebarItems(page, regularPath, site, localePath) { + const {pages, themeConfig} = site + + const localeConfig = + localePath && themeConfig.locales ? themeConfig.locales[localePath] || themeConfig : themeConfig + + const pageSidebarConfig = page.frontmatter.sidebar || localeConfig.sidebar || themeConfig.sidebar + if (pageSidebarConfig === "auto") { + return resolveHeaders(page) + } + + const sidebarConfig = localeConfig.sidebar || themeConfig.sidebar + if (!sidebarConfig) { + return [] + } else { + const {base, config} = resolveMatchingConfig(regularPath, sidebarConfig) + if (config === "auto") { + return resolveHeaders(page) + } + return config ? config.map((item) => resolveItem(item, pages, base)) : [] + } +} + +/** + * @param { Page } page + * @returns { SidebarGroup } + */ +function resolveHeaders(page) { + const headers = groupHeaders(page.headers || []) + return [ + { + type: "group", + collapsable: false, + title: page.title, + path: null, + children: headers.map((h) => ({ + type: "auto", + title: h.title, + basePath: page.path, + path: page.path + "#" + h.slug, + children: h.children || [], + })), + }, + ] +} + +export function groupHeaders(headers) { + // group h3s under h2 + headers = headers.map((h) => Object.assign({}, h)) + let lastH2 + headers.forEach((h) => { + if (h.level === 2) { + lastH2 = h + } else if (lastH2) { + ;(lastH2.children || (lastH2.children = [])).push(h) + } + }) + return headers.filter((h) => h.level === 2) +} + +export function resolveNavLinkItem(linkItem) { + return Object.assign(linkItem, { + type: linkItem.items && linkItem.items.length ? "links" : "link", + }) +} + +/** + * @param { Route } route + * @param { Array | Array | [link: string]: SidebarConfig } config + * @returns { base: string, config: SidebarConfig } + */ +export function resolveMatchingConfig(regularPath, config) { + if (Array.isArray(config)) { + return { + base: "/", + config: config, + } + } + for (const base in config) { + if (ensureEndingSlash(regularPath).indexOf(encodeURI(base)) === 0) { + return { + base, + config: config[base], + } + } + } + return {} +} + +function ensureEndingSlash(path) { + return /(\.html|\/)$/.test(path) ? path : path + "/" +} + +function resolveItem(item, pages, base, groupDepth = 1) { + if (typeof item === "string") { + return resolvePage(pages, item, base) + } else if (Array.isArray(item)) { + return Object.assign(resolvePage(pages, item[0], base), { + title: item[1], + }) + } else { + const children = item.children || [] + if (children.length === 0 && item.path) { + return Object.assign(resolvePage(pages, item.path, base), { + title: item.title, + }) + } + return { + type: "group", + path: item.path, + title: item.title, + sidebarDepth: item.sidebarDepth, + initialOpenGroupIndex: item.initialOpenGroupIndex, + children: children.map((child) => resolveItem(child, pages, base, groupDepth + 1)), + collapsable: item.collapsable !== false, + } + } +} diff --git a/docs/faq.md b/docs/faq.md index f83a8118b..b8535923e 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -9,7 +9,7 @@ The purpose of this document is to help find answers quicker. I am happy to cont Ajv implements JSON schema specification. Before submitting the issue about the behaviour of any validation keywords please review them in: - [JSON Schema specification](https://tools.ietf.org/html/draft-handrews-json-schema-validation-00) (draft-07) -- [Validation keywords](./json-schema.md) in Ajv documentation +- [JSON Schema reference](./json-schema.md) in Ajv documentation - [JSON Schema tutorial](https://spacetelescope.github.io/understanding-json-schema/) (for draft-04) #### Why Ajv validates empty object as valid? From 0e3caf2354899797bd882cfe21e73a578646fe1d Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Sat, 6 Mar 2021 17:56:25 +0000 Subject: [PATCH 17/25] update years --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 96ee71998..139162ad2 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2015-2017 Evgeny Poberezkin +Copyright (c) 2015-2021 Evgeny Poberezkin Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From d5f7f8cfaa272e30240eae18700893fc6e0e08a2 Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Sat, 6 Mar 2021 18:53:30 +0000 Subject: [PATCH 18/25] ci: publish site --- .github/workflows/build.yml | 4 ++-- .gitignore | 6 +++--- docs/.vuepress/config.js | 12 ++++++------ scripts/publish-site | 26 ++++++++++++++++++++++---- 4 files changed, 33 insertions(+), 15 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c6b50135a..d1ba022f0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,7 +2,7 @@ name: build on: push: - branches: [master] + branches: [master, vuepress] pull_request: branches: ["*"] @@ -30,7 +30,7 @@ jobs: github-token: ${{ secrets.GITHUB_TOKEN }} - name: update website if: ${{ github.event_name == 'push' && matrix.node-version == '14.x' }} - run: ./scripts/publish-gh-pages + run: ./scripts/publish-site env: GH_TOKEN_PUBLIC: ${{ secrets.GH_TOKEN_PUBLIC }} GIT_USER_EMAIL: ${{ secrets.GIT_USER_EMAIL }} diff --git a/.gitignore b/.gitignore index 6791d6c03..370ab2b27 100644 --- a/.gitignore +++ b/.gitignore @@ -43,6 +43,6 @@ package-lock.json spec/_json/*.js docs/README.md -docs/CODE_OF_CONDUCT.md -docs/CONTRIBUTING.md -docs/LICENSE.md +docs/code_of_conduct.md +docs/contributing.md +docs/license.md diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index 451d20222..18cc22dcf 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -45,10 +45,10 @@ module.exports = { { text: "Contributors", items: [ - {link: "/CONTRIBUTING", text: "Contributing guide"}, + {link: "/contributing", text: "Contributing guide"}, {link: "/codegen", text: "Code generation design"}, {link: "/components", text: "Code components"}, - {link: "/CODE_OF_CONDUCT", text: "Code of Conduct"}, + {link: "/code_of_conduct", text: "Code of Conduct"}, ], }, { @@ -56,7 +56,7 @@ module.exports = { items: [ {link: "/security", text: "Security"}, {link: "/faq", text: "FAQ"}, - {link: "/LICENSE", text: "License"}, + {link: "/license", text: "License"}, ], }, ], @@ -97,16 +97,16 @@ module.exports = { title: "Contributors", collapsable: false, children: [ - "/CONTRIBUTING", + "/contributing", "/codegen", "/components", - ["/CODE_OF_CONDUCT", "Code of conduct"], + ["/code_of_conduct", "Code of conduct"], ], }, { title: "Information", collapsable: false, - children: ["/faq", "/security", ["/LICENSE", "License"]], + children: ["/faq", "/security", ["/license", "License"]], }, ], repo: "ajv-validator/ajv", diff --git a/scripts/publish-site b/scripts/publish-site index ab70d2542..13e3bcded 100755 --- a/scripts/publish-site +++ b/scripts/publish-site @@ -1,6 +1,6 @@ #!/usr/bin/env bash -set -e +set -ex echo "About to publish $GITHUB_REF to gh-pages..." @@ -9,6 +9,24 @@ function copyReplace { } copyReplace README.md docs/README.md -copyReplace CODE_OF_CONDUCT.md docs/CODE_OF_CONDUCT.md -copyReplace CONTRIBUTING.md docs/CONTRIBUTING.md -copyReplace LICENSE docs/LICENSE.md +copyReplace CODE_OF_CONDUCT.md docs/code_of_conduct.md +copyReplace CONTRIBUTING.md docs/contributing.md +copyReplace LICENSE docs/license.md + +rm -rf ../gh-pages + +git config --global user.name "$GIT_USER_NAME" +git config --global user.email "$GIT_USER_EMAIL" +git clone -b gh-pages --single-branch https://"${GH_TOKEN_PUBLIC}"@github.com/ajv-validator/ajv.git ../gh-pages + +cp -R docs/.vuepress/dist/ ../gh-pages/docs +cd ../gh-pages + +if [[ $(git status --porcelain) ]]; then + echo "Changes detected. Updating gh-pages branch..." + git add -A + git commit -m "updated by ajv workflow https://github.com/ajv-validator/ajv/actions/runs/$GITHUB_RUN_ID" + git push --quiet origin gh-pages > /dev/null 2>&1 +fi + +echo "Done" From 3ad1e08a2026fc6c10aa6f00da4e9eff46dc5d3e Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Sat, 6 Mar 2021 18:58:30 +0000 Subject: [PATCH 19/25] site: fix publish script --- README.md | 2 ++ scripts/publish-site | 2 ++ 2 files changed, 4 insertions(+) diff --git a/README.md b/README.md index 872129360..48eda20f3 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ Ajv logo +  + # Ajv: Another JSON schema validator Super fast JSON schema validator for Node.js and browser. diff --git a/scripts/publish-site b/scripts/publish-site index 13e3bcded..6b18eab36 100755 --- a/scripts/publish-site +++ b/scripts/publish-site @@ -13,6 +13,8 @@ copyReplace CODE_OF_CONDUCT.md docs/code_of_conduct.md copyReplace CONTRIBUTING.md docs/contributing.md copyReplace LICENSE docs/license.md +npm run docs:build + rm -rf ../gh-pages git config --global user.name "$GIT_USER_NAME" From fff6917e21a6f159361c5bfb9bc5f6e6c809f3c0 Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Sat, 6 Mar 2021 19:34:03 +0000 Subject: [PATCH 20/25] site: debugging script --- .github/workflows/build.yml | 14 +++++++------- scripts/publish-site | 10 +++++++--- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d1ba022f0..caf1f90c2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -21,13 +21,13 @@ jobs: with: node-version: ${{ matrix.node-version }} - run: npm install - - run: git submodule update --init - - run: npm run build - - run: npm run test-ci - - name: coveralls - uses: coverallsapp/github-action@master - with: - github-token: ${{ secrets.GITHUB_TOKEN }} + # - run: git submodule update --init + # - run: npm run build + # - run: npm run test-ci + # - name: coveralls + # uses: coverallsapp/github-action@master + # with: + # github-token: ${{ secrets.GITHUB_TOKEN }} - name: update website if: ${{ github.event_name == 'push' && matrix.node-version == '14.x' }} run: ./scripts/publish-site diff --git a/scripts/publish-site b/scripts/publish-site index 6b18eab36..29bdeda35 100755 --- a/scripts/publish-site +++ b/scripts/publish-site @@ -3,6 +3,7 @@ set -ex echo "About to publish $GITHUB_REF to gh-pages..." +rm -rf ../gh-pages function copyReplace { sed "s/](.\/docs\//](.\//g" $1 > $2 @@ -15,15 +16,18 @@ copyReplace LICENSE docs/license.md npm run docs:build -rm -rf ../gh-pages - git config --global user.name "$GIT_USER_NAME" git config --global user.email "$GIT_USER_EMAIL" git clone -b gh-pages --single-branch https://"${GH_TOKEN_PUBLIC}"@github.com/ajv-validator/ajv.git ../gh-pages -cp -R docs/.vuepress/dist/ ../gh-pages/docs +rsync -a ./docs/.vuepress/dist/ ../gh-pages/docs +ls ../gh-pages/docs + cd ../gh-pages +ls docs +git status --porcelain + if [[ $(git status --porcelain) ]]; then echo "Changes detected. Updating gh-pages branch..." git add -A From 39d04ae13294eccc3145a70f756172f1a9bc71ba Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Sat, 6 Mar 2021 20:09:55 +0000 Subject: [PATCH 21/25] site: fix images --- README.md | 6 +++--- docs/.vuepress/config.js | 2 +- docs/.vuepress/public/{ => img}/ajv.svg | 0 docs/{ => .vuepress/public}/img/gap.svg | 0 docs/{ => .vuepress/public}/img/mozilla.svg | 0 docs/{ => .vuepress/public}/img/openjs.png | Bin docs/{ => .vuepress/public}/img/reserved.svg | 0 scripts/publish-site | 4 ---- 8 files changed, 4 insertions(+), 8 deletions(-) rename docs/.vuepress/public/{ => img}/ajv.svg (100%) rename docs/{ => .vuepress/public}/img/gap.svg (100%) rename docs/{ => .vuepress/public}/img/mozilla.svg (100%) rename docs/{ => .vuepress/public}/img/openjs.png (100%) rename docs/{ => .vuepress/public}/img/reserved.svg (100%) diff --git a/README.md b/README.md index 48eda20f3..297f6ae66 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -Ajv logo +Ajv logo   @@ -20,7 +20,7 @@ Supports JSON Schema draft-06/07/2019-09 (draft-04 is supported in [version 6](h ## Platinum sponsors ::: v-pre -[](https://www.mozilla.org)[](https://opencollective.com/ajv) +[](https://www.mozilla.org)[](https://opencollective.com/ajv) ::: ## Using version 7 @@ -139,7 +139,7 @@ Please also review [Contributing guidelines](./CONTRIBUTING.md) and [Code compon ## Mozilla MOSS grant and OpenJS Foundation ::: v-pre -[](https://www.mozilla.org/en-US/moss/)[](https://openjsf.org/blog/2020/08/14/ajv-joins-openjs-foundation-as-an-incubation-project/) +[](https://www.mozilla.org/en-US/moss/)[](https://openjsf.org/blog/2020/08/14/ajv-joins-openjs-foundation-as-an-incubation-project/) ::: Ajv has been awarded a grant from Mozilla’s [Open Source Support (MOSS) program](https://www.mozilla.org/en-US/moss/) in the “Foundational Technology” track! It will sponsor the development of Ajv support of [JSON Schema version 2019-09](https://tools.ietf.org/html/draft-handrews-json-schema-02) and of [JSON Type Definition (RFC8927)](https://datatracker.ietf.org/doc/rfc8927/). diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index 18cc22dcf..414561aa0 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -8,7 +8,7 @@ module.exports = { toc: {includeLevel: [2, 3, 4]}, }, themeConfig: { - logo: "/ajv.svg", + logo: "/img/ajv.svg", nav: [ {text: "Home", link: "/"}, { diff --git a/docs/.vuepress/public/ajv.svg b/docs/.vuepress/public/img/ajv.svg similarity index 100% rename from docs/.vuepress/public/ajv.svg rename to docs/.vuepress/public/img/ajv.svg diff --git a/docs/img/gap.svg b/docs/.vuepress/public/img/gap.svg similarity index 100% rename from docs/img/gap.svg rename to docs/.vuepress/public/img/gap.svg diff --git a/docs/img/mozilla.svg b/docs/.vuepress/public/img/mozilla.svg similarity index 100% rename from docs/img/mozilla.svg rename to docs/.vuepress/public/img/mozilla.svg diff --git a/docs/img/openjs.png b/docs/.vuepress/public/img/openjs.png similarity index 100% rename from docs/img/openjs.png rename to docs/.vuepress/public/img/openjs.png diff --git a/docs/img/reserved.svg b/docs/.vuepress/public/img/reserved.svg similarity index 100% rename from docs/img/reserved.svg rename to docs/.vuepress/public/img/reserved.svg diff --git a/scripts/publish-site b/scripts/publish-site index 29bdeda35..c09758432 100755 --- a/scripts/publish-site +++ b/scripts/publish-site @@ -21,13 +21,9 @@ git config --global user.email "$GIT_USER_EMAIL" git clone -b gh-pages --single-branch https://"${GH_TOKEN_PUBLIC}"@github.com/ajv-validator/ajv.git ../gh-pages rsync -a ./docs/.vuepress/dist/ ../gh-pages/docs -ls ../gh-pages/docs cd ../gh-pages -ls docs -git status --porcelain - if [[ $(git status --porcelain) ]]; then echo "Changes detected. Updating gh-pages branch..." git add -A From 50c7fde128c8d9486f679ad2d76c2a433e96dc93 Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Sat, 6 Mar 2021 20:14:59 +0000 Subject: [PATCH 22/25] readme: use images from the website --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 297f6ae66..fbd39e9e0 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -Ajv logo +Ajv logo   @@ -20,7 +20,7 @@ Supports JSON Schema draft-06/07/2019-09 (draft-04 is supported in [version 6](h ## Platinum sponsors ::: v-pre -[](https://www.mozilla.org)[](https://opencollective.com/ajv) +[](https://www.mozilla.org)[](https://opencollective.com/ajv) ::: ## Using version 7 @@ -139,7 +139,7 @@ Please also review [Contributing guidelines](./CONTRIBUTING.md) and [Code compon ## Mozilla MOSS grant and OpenJS Foundation ::: v-pre -[](https://www.mozilla.org/en-US/moss/)[](https://openjsf.org/blog/2020/08/14/ajv-joins-openjs-foundation-as-an-incubation-project/) +[](https://www.mozilla.org/en-US/moss/)[](https://openjsf.org/blog/2020/08/14/ajv-joins-openjs-foundation-as-an-incubation-project/) ::: Ajv has been awarded a grant from Mozilla’s [Open Source Support (MOSS) program](https://www.mozilla.org/en-US/moss/) in the “Foundational Technology” track! It will sponsor the development of Ajv support of [JSON Schema version 2019-09](https://tools.ietf.org/html/draft-handrews-json-schema-02) and of [JSON Type Definition (RFC8927)](https://datatracker.ietf.org/doc/rfc8927/). From f87c4f0eccd1e9a0cb25126934ec474bfb22a456 Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Sat, 6 Mar 2021 20:21:43 +0000 Subject: [PATCH 23/25] remove unused script --- .github/workflows/build.yml | 14 +++++++------- scripts/publish-gh-pages | 31 ------------------------------- 2 files changed, 7 insertions(+), 38 deletions(-) delete mode 100755 scripts/publish-gh-pages diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index caf1f90c2..d1ba022f0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -21,13 +21,13 @@ jobs: with: node-version: ${{ matrix.node-version }} - run: npm install - # - run: git submodule update --init - # - run: npm run build - # - run: npm run test-ci - # - name: coveralls - # uses: coverallsapp/github-action@master - # with: - # github-token: ${{ secrets.GITHUB_TOKEN }} + - run: git submodule update --init + - run: npm run build + - run: npm run test-ci + - name: coveralls + uses: coverallsapp/github-action@master + with: + github-token: ${{ secrets.GITHUB_TOKEN }} - name: update website if: ${{ github.event_name == 'push' && matrix.node-version == '14.x' }} run: ./scripts/publish-site diff --git a/scripts/publish-gh-pages b/scripts/publish-gh-pages deleted file mode 100755 index 6119ac45c..000000000 --- a/scripts/publish-gh-pages +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env bash - -set -ex - -echo "About to publish $GITHUB_REF to gh-pages..." - -rm -rf ../gh-pages - -git config --global user.name "$GIT_USER_NAME" -git config --global user.email "$GIT_USER_EMAIL" -git clone -b gh-pages --single-branch https://"${GH_TOKEN_PUBLIC}"@github.com/ajv-validator/ajv.git ../gh-pages -SOURCE=../gh-pages/_source -mkdir -p $SOURCE -cp *.md $SOURCE -cp -R docs $SOURCE -cp LICENSE $SOURCE -cd ../gh-pages -node ./generate - -# remove logo from README -sed -E "s/]+ajv_logo[^>]+>//" index.md > new-index.md -mv new-index.md index.md - -if [[ $(git status --porcelain) ]]; then - echo "Changes detected. Updating gh-pages branch..." - git add -A - git commit -m "updated by ajv workflow https://github.com/ajv-validator/ajv/actions/runs/$GITHUB_RUN_ID" - git push --quiet origin gh-pages > /dev/null 2>&1 -fi - -echo "Done" From dc48cc16f0941145c10845855c0e6e1932dd75b7 Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Sat, 6 Mar 2021 20:23:32 +0000 Subject: [PATCH 24/25] only build on master pushes --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d1ba022f0..ef9a0ef58 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,7 +2,7 @@ name: build on: push: - branches: [master, vuepress] + branches: [master] pull_request: branches: ["*"] From 67b57cab7297c724a69a9161e5b88b26738b51d2 Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Sat, 6 Mar 2021 20:34:11 +0000 Subject: [PATCH 25/25] readme: fix layout --- README.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index fbd39e9e0..a930b92b4 100644 --- a/README.md +++ b/README.md @@ -19,9 +19,7 @@ Supports JSON Schema draft-06/07/2019-09 (draft-04 is supported in [version 6](h ## Platinum sponsors -::: v-pre -[](https://www.mozilla.org)[](https://opencollective.com/ajv) -::: +[](https://www.mozilla.org)[](https://opencollective.com/ajv) ## Using version 7 @@ -139,7 +137,7 @@ Please also review [Contributing guidelines](./CONTRIBUTING.md) and [Code compon ## Mozilla MOSS grant and OpenJS Foundation ::: v-pre -[](https://www.mozilla.org/en-US/moss/)[](https://openjsf.org/blog/2020/08/14/ajv-joins-openjs-foundation-as-an-incubation-project/) +[](https://www.mozilla.org/en-US/moss/)[](https://openjsf.org/blog/2020/08/14/ajv-joins-openjs-foundation-as-an-incubation-project/) ::: Ajv has been awarded a grant from Mozilla’s [Open Source Support (MOSS) program](https://www.mozilla.org/en-US/moss/) in the “Foundational Technology” track! It will sponsor the development of Ajv support of [JSON Schema version 2019-09](https://tools.ietf.org/html/draft-handrews-json-schema-02) and of [JSON Type Definition (RFC8927)](https://datatracker.ietf.org/doc/rfc8927/).