Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: ajv-validator/ajv
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v6.12.6
Choose a base ref
...
head repository: ajv-validator/ajv
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v7.0.0
Choose a head ref

Commits on Jul 21, 2020

  1. Copy the full SHA
    75038f8 View commit details

Commits on Jul 22, 2020

  1. Copy the full SHA
    3025ab2 View commit details
  2. style: eslint

    epoberezkin committed Jul 22, 2020
    Copy the full SHA
    ffbb010 View commit details
  3. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    2a6d1a9 View commit details
  4. Copy the full SHA
    bac244e View commit details
  5. fix: browser tests

    epoberezkin committed Jul 22, 2020
    Copy the full SHA
    6fe3e5f View commit details
  6. Merge pull request #1249 from ajv-validator/v7-alpha-remove-formats

    move formats to ajv-formats
    epoberezkin authored Jul 22, 2020
    Copy the full SHA
    166d2df View commit details
  7. Copy the full SHA
    197a9e8 View commit details
  8. Copy the full SHA
    b1bb27e View commit details
  9. Copy the full SHA
    39055fb View commit details

Commits on Jul 26, 2020

  1. use dot v2

    epoberezkin committed Jul 26, 2020
    Copy the full SHA
    078ffa7 View commit details

Commits on Jul 27, 2020

  1. Revert "use dot v2"

    This reverts commit 078ffa7.
    epoberezkin committed Jul 27, 2020
    Copy the full SHA
    44e5d55 View commit details
  2. Merge pull request #1252 from ajv-validator/v7-alpha-remove-draft4

    v7 alpha - remove draft4
    epoberezkin authored Jul 27, 2020
    Copy the full SHA
    6cede7b View commit details

Commits on Aug 9, 2020

  1. Copy the full SHA
    64ebe88 View commit details
  2. Copy the full SHA
    99d7a5d View commit details
  3. Copy the full SHA
    669e0c1 View commit details
  4. Copy the full SHA
    971d9f9 View commit details
  5. Copy the full SHA
    43d80f6 View commit details
  6. Copy the full SHA
    ddca210 View commit details
  7. Copy the full SHA
    e8cb96f View commit details

Commits on Aug 10, 2020

  1. Copy the full SHA
    42319bf View commit details
  2. Copy the full SHA
    0c4f819 View commit details
  3. Copy the full SHA
    49b13dd View commit details
  4. Copy the full SHA
    883ecaf View commit details
  5. Copy the full SHA
    df6bcdd View commit details
  6. Copy the full SHA
    5283a86 View commit details
  7. refactor: util types

    epoberezkin committed Aug 10, 2020
    Copy the full SHA
    ed5972d View commit details
  8. Copy the full SHA
    9436ab2 View commit details
  9. Copy the full SHA
    8d77a1d View commit details
  10. Copy the full SHA
    0a1fa0f View commit details
  11. fix: ucs2length

    epoberezkin committed Aug 10, 2020
    Copy the full SHA
    7aea117 View commit details
  12. Copy the full SHA
    acfd737 View commit details
  13. Copy the full SHA
    de3d047 View commit details

Commits on Aug 11, 2020

  1. refactor: schemaType

    epoberezkin committed Aug 11, 2020
    Copy the full SHA
    08d1224 View commit details
  2. Copy the full SHA
    36f6177 View commit details
  3. loopEnum: test, docs

    epoberezkin committed Aug 11, 2020
    Copy the full SHA
    d36783c View commit details
  4. Copy the full SHA
    84f76cd View commit details
  5. style: curly

    epoberezkin committed Aug 11, 2020
    Copy the full SHA
    24ffbec View commit details
  6. Copy the full SHA
    99c2b28 View commit details
  7. style: eqeqeq

    epoberezkin committed Aug 11, 2020
    Copy the full SHA
    dd5a08b View commit details
  8. Copy the full SHA
    3918306 View commit details
  9. Copy the full SHA
    0720a49 View commit details

Commits on Aug 12, 2020

  1. Copy the full SHA
    3337b28 View commit details

Commits on Aug 13, 2020

  1. Copy the full SHA
    d02a257 View commit details

Commits on Aug 15, 2020

  1. Copy the full SHA
    8f9c1bf View commit details
  2. Copy the full SHA
    f938cc8 View commit details
  3. Copy the full SHA
    3b267b0 View commit details
  4. Copy the full SHA
    c974266 View commit details
  5. Copy the full SHA
    9765bcb View commit details
  6. Copy the full SHA
    822336c View commit details
Showing 394 changed files with 22,328 additions and 19,464 deletions.
2 changes: 0 additions & 2 deletions .codeclimate.yml

This file was deleted.

30 changes: 30 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
const jsConfig = require("@ajv-validator/config/.eslintrc_js")
const tsConfig = require("@ajv-validator/config/.eslintrc")

module.exports = {
env: {
es6: true,
node: true,
},
overrides: [
jsConfig,
{
...tsConfig,
files: ["*.ts"],
rules: {
...tsConfig.rules,
complexity: ["error", 17],
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-floating-promises": "off",
"@typescript-eslint/no-implied-eval": "off",
"@typescript-eslint/no-invalid-this": "off",
"@typescript-eslint/no-parameter-properties": "off",
"@typescript-eslint/no-unnecessary-condition": "warn",
"@typescript-eslint/no-unsafe-assignment": "off",
"@typescript-eslint/no-unsafe-member-access": "off",
"@typescript-eslint/restrict-template-expressions": "off",
},
},
],
}
29 changes: 0 additions & 29 deletions .eslintrc.yml

This file was deleted.

15 changes: 2 additions & 13 deletions .github/ISSUE_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<!--
Frequently Asked Questions: https://github.com/ajv-validator/ajv/blob/master/FAQ.md
Frequently Asked Questions: https://github.com/ajv-validator/ajv/blob/master/docs/faq.md
Please provide all info and reduce your schema and data to the smallest possible size.
This template is for bug or error reports. For other issues please use:
@@ -12,38 +12,30 @@ This template is for bug or error reports. For other issues please use:

**What version of Ajv are you using? Does the issue happen if you use the latest version?**



**Ajv options object**

<!-- See https://github.com/ajv-validator/ajv#options -->
<!-- See https://github.com/ajv-validator/ajv/api.md#options -->

```javascript


```


**JSON Schema**

<!-- Please make it as small as possible to reproduce the issue -->

```json


```


**Sample data**

<!-- Please make it as small as posssible to reproduce the issue -->

```json


```


**Your code**

<!--
@@ -59,10 +51,8 @@ Thank you!

```javascript


```


**Validation result, data AFTER validation, error messages**

```
@@ -72,5 +62,4 @@ Thank you!

**What results did you expect?**


**Are you going to resolve the issue?**
23 changes: 5 additions & 18 deletions .github/ISSUE_TEMPLATE/bug-or-error-report.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
---
name: Bug or error report
about: Please use for issues related to incorrect validation behaviour
title: ''
labels: 'bug report'
assignees: ''

title: ""
labels: "bug report"
assignees: ""
---

<!--
Frequently Asked Questions: https://github.com/ajv-validator/ajv/blob/master/FAQ.md
Frequently Asked Questions: https://github.com/ajv-validator/ajv/blob/master/docs/faq.md
Please provide all info and reduce your schema and data to the smallest possible size.
This template is for bug or error reports.
@@ -17,38 +16,30 @@ For other issues please see https://github.com/ajv-validator/ajv/blob/master/CON

**What version of Ajv are you using? Does the issue happen if you use the latest version?**



**Ajv options object**

<!-- See https://github.com/ajv-validator/ajv#options -->
<!-- See https://github.com/ajv-validator/ajv/api.md/api.md#options -->

```javascript


```


**JSON Schema**

<!-- Please make it as small as possible to reproduce the issue -->

```json


```


**Sample data**

<!-- Please make it as small as posssible to reproduce the issue -->

```json


```


**Your code**

<!--
@@ -64,18 +55,14 @@ Thank you!

```javascript


```


**Validation result, data AFTER validation, error messages**

```
```

**What results did you expect?**


**Are you going to resolve the issue?**
9 changes: 4 additions & 5 deletions .github/ISSUE_TEMPLATE/change.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
---
name: Feature or change proposal
about: For proposals of new features, options or some other improvements
title: ''
labels: 'enhancement'
assignees: ''

title: ""
labels: "enhancement"
assignees: ""
---

<!--
Frequently Asked Questions: https://github.com/ajv-validator/ajv/blob/master/FAQ.md
Frequently Asked Questions: https://github.com/ajv-validator/ajv/blob/master/docs/faq.md
Please provide all info and reduce your schema and data to the smallest possible size.
This template is for change proposals.
9 changes: 4 additions & 5 deletions .github/ISSUE_TEMPLATE/compatibility.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
---
name: Browser and compatibility issue
about: For issues that only happen in a specific environment
title: ''
labels: 'compatibility'
assignees: ''

title: ""
labels: "compatibility"
assignees: ""
---

<!--
Frequently Asked Questions: https://github.com/ajv-validator/ajv/blob/master/FAQ.md
Frequently Asked Questions: https://github.com/ajv-validator/ajv/blob/master/docs/faq.md
Please provide all info and reduce your schema and data to the smallest possible size.
This template is for compatibility issues.
9 changes: 4 additions & 5 deletions .github/ISSUE_TEMPLATE/installation.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
---
name: Installation and dependency issue
about: For issues that happen during installation
title: ''
labels: 'installation'
assignees: ''

title: ""
labels: "installation"
assignees: ""
---

<!--
Frequently Asked Questions: https://github.com/ajv-validator/ajv/blob/master/FAQ.md
Frequently Asked Questions: https://github.com/ajv-validator/ajv/blob/master/docs/faq.md
Please provide all info and reduce your schema and data to the smallest possible size.
This template is for installation and dependency issues.
14 changes: 4 additions & 10 deletions .github/ISSUE_TEMPLATE/typescript.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
---
name: Missing or incorrect type definition
about: Please use for issues related to typescript types
title: ''
labels: 'typescript'
assignees: ''

title: ""
labels: "typescript"
assignees: ""
---

<!--
Frequently Asked Questions: https://github.com/ajv-validator/ajv/blob/master/FAQ.md
Frequently Asked Questions: https://github.com/ajv-validator/ajv/blob/master/docs/faq.md
This template is for issues about missing or incorrect type definition and other typescript-related issues.
For other issues please see https://github.com/ajv-validator/ajv/blob/master/CONTRIBUTING.md
-->

**What version of Ajv are you using? Does the issue happen if you use the latest version?**


**Your typescript code**

<!--
@@ -25,18 +23,14 @@ Please make it as small as posssible to reproduce the issue

```typescript


```


**Typescript compiler error messages**

```
```

**Describe the change that should be made to address the issue?**


**Are you going to resolve the issue?**
2 changes: 0 additions & 2 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -11,8 +11,6 @@ Please answer the questions below.

**What issue does this pull request resolve?**


**What changes did you make?**


**Is there anything that requires more attention while reviewing?**
5 changes: 5 additions & 0 deletions .github/img/gap.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions .github/img/reserved.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
37 changes: 37 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: build

on:
push:
branches: [master]
pull_request:
branches: ["*"]

jobs:
build:
runs-on: ubuntu-latest

strategy:
matrix:
node-version: [10.x, 12.x, 14.x]

steps:
- uses: actions/checkout@v2
- name: use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
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 }}
- name: update website
if: ${{ matrix.node-version == '14.x' }}
run: ./scripts/publish-gh-pages
env:
GH_TOKEN_PUBLIC: ${{ secrets.GH_TOKEN_PUBLIC }}
GIT_USER_EMAIL: ${{ secrets.GIT_USER_EMAIL }}
GIT_USER_NAME: ${{ secrets.GIT_USER_NAME }}
34 changes: 34 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: publish

on:
release:
types: [published]

jobs:
publish-npm:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: 14
registry-url: https://registry.npmjs.org/
- run: npm install
- run: git submodule update --init
- run: npm run test-ci
- name: Publish beta version to npm
if: "github.event.release.prerelease"
run: npm publish --tag beta
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Publish to npm
if: "!github.event.release.prerelease"
run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Commit bundles to ajv-dist
run: ./scripts/publish-bundles
env:
GH_TOKEN_PUBLIC: ${{ secrets.GH_TOKEN_PUBLIC }}
GIT_USER_EMAIL: ${{ secrets.GIT_USER_EMAIL }}
GIT_USER_NAME: ${{ secrets.GIT_USER_NAME }}
10 changes: 6 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -29,13 +29,15 @@ node_modules

.DS_Store

# Compiled templates
lib/dotjs/*.js

# Browserified tests
.browser

# bundles
# compiled typescript
dist/

# browser bundles
bundle/

package-lock.json

spec/_json/*.js
9 changes: 0 additions & 9 deletions .jshintrc

This file was deleted.

7 changes: 7 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
spec/JSON-Schema-Test-Suite
.browser
coverage
dist
bundle
.nyc_output
spec/_json
28 changes: 14 additions & 14 deletions .tonic_example.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
var Ajv = require('ajv');
var ajv = new Ajv({allErrors: true});
var Ajv = require("ajv")
var ajv = new Ajv({allErrors: true})

var schema = {
"properties": {
"foo": { "type": "string" },
"bar": { "type": "number", "maximum": 3 }
}
};
properties: {
foo: {type: "string"},
bar: {type: "number", maximum: 3},
},
}

var validate = ajv.compile(schema);
var validate = ajv.compile(schema)

test({"foo": "abc", "bar": 2});
test({"foo": 2, "bar": 4});
test({foo: "abc", bar: 2})
test({foo: 2, bar: 4})

function test(data) {
var valid = validate(data);
if (valid) console.log('Valid!');
else console.log('Invalid: ' + ajv.errorsText(validate.errors));
}
var valid = validate(data)
if (valid) console.log("Valid!")
else console.log("Invalid: " + ajv.errorsText(validate.errors))
}
8 changes: 5 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
language: node_js
before_script:
- git submodule update --init
- npm install -g codeclimate-test-reporter
node_js:
- 10
- 12
- 14
before_script:
- git submodule update --init
- npm install -g codeclimate-test-reporter
script:
- npm run test-ci
after_script:
- codeclimate-test-reporter < coverage/lcov.info
- coveralls < coverage/lcov.info
26 changes: 13 additions & 13 deletions CODE_OF_CONDUCT.md
Original file line number Diff line number Diff line change
@@ -14,22 +14,22 @@ appearance, race, religion, or sexual identity and orientation.
Examples of behavior that contributes to creating a positive environment
include:

* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
- Using welcoming and inclusive language
- Being respectful of differing viewpoints and experiences
- Gracefully accepting constructive criticism
- Focusing on what is best for the community
- Showing empathy towards other community members

Examples of unacceptable behavior by participants include:

* 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
- 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

## Our Responsibilities

46 changes: 14 additions & 32 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -16,35 +16,31 @@ Thank you for your help making Ajv better! Every contribution is appreciated. If
- [Pull requests](#pull-requests)
- [Contributions license](#contributions-license)


## Documentation

Ajv has a lot of features and maintaining documentation takes time. I appreciate the time you spend correcting or clarifying the documentation.


## Issues

Before submitting the issue please search the existing issues and also review [Frequently Asked Questions](https://github.com/ajv-validator/ajv/blob/master/FAQ.md).

I would really appreciate the time you spend providing all the information and reducing 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).
Before submitting the issue please search the existing issues and also review [Frequently Asked Questions](./docs/faq.md).

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).

#### 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#options).
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 (please use `options`, `schema` and `data` as variables).
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?

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.

[Create bug report](https://github.com/ajv-validator/ajv/issues/new?template=bug-or-error-report.md).


#### Security vulnerabilities

To report a security vulnerability, please use the
@@ -53,7 +49,6 @@ Tidelift will coordinate the fix and disclosure.

Please do NOT report security vulnerabilities via GitHub issues.


#### <a name="changes"></a>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.
@@ -73,7 +68,6 @@ If you’re requesting a change, it would be helpful to include this as well:

Please include as much details as possible.


#### <a name="compatibility"></a>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).
@@ -87,12 +81,12 @@ Please include this information:
5. Results in node.js v8+.
6. Results and error messages in your platform.


#### <a name="installation"></a>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.

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
@@ -106,25 +100,23 @@ If nothing helps, please submit:
5. Error messages
6. The output of `npm ls`


#### <a name="json-schema"></a>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 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.


#### <a name="usage"></a>Ajv usage questions

The best place to ask a question about using Ajv is [Gitter chat](https://gitter.im/ajv-validator/ajv).

If the question is advanced, it can be submitted to [Stack Overflow](http://stackoverflow.com/questions/ask?tags=jsonschema,ajv).


## Code

Thanks a lot for considering contributing to Ajv. Many very useful features were created by its users.
Thanks a lot for considering contributing to Ajv. Many great features were created by its users.

Please review [Code components](./docs/components.md) document as well - it will help navigating the code.

#### Development

@@ -136,19 +128,9 @@ git submodule update --init
npm test
```

The full test suite runs for 3 minutes. If your change is trivial you can run quick test before committing (10 sec) and then disable pre-commit hook:

```bash
npm run test-fast
git commit -nm 'type: message'
```

All validation functions are generated using doT templates in [dot](https://github.com/ajv-validator/ajv/tree/master/lib/dot) folder. Templates are precompiled so doT is not a run-time dependency.

`npm run build` - compiles templates to [dotjs](https://github.com/ajv-validator/ajv/tree/master/lib/dotjs) folder.

`npm run watch` - automatically compiles templates when files in dot folder change
`npm run build` - compiles typescript to dist folder.

`npm run watch` - automatically compiles typescript when files in lib folder change

#### Pull requests

@@ -157,11 +139,11 @@ To make accepting your changes faster 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 avoid unnecessary changes, refactoring or changing coding styles as part of your change (unless the change was proposed as refactoring).
5. Please follow the coding conventions even if they are not validated (and/or you use different conventions in your code).
6. Please run the tests before committing your code.
7. If tests fail in Travis after you make a PR please investigate and fix the issue.

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.
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).
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.

#### Contributions license

463 changes: 0 additions & 463 deletions CUSTOM.md

This file was deleted.

857 changes: 0 additions & 857 deletions KEYWORDS.md

This file was deleted.

1,511 changes: 210 additions & 1,301 deletions README.md

Large diffs are not rendered by default.

24 changes: 5 additions & 19 deletions bower.json
Original file line number Diff line number Diff line change
@@ -1,25 +1,11 @@
{
"name": "ajv",
"description": "Another JSON Schema Validator",
"main": "dist/ajv.min.js",
"authors": [
"Evgeny Poberezkin"
],
"main": "bundle/ajv.min.js",
"authors": ["Evgeny Poberezkin"],
"license": "MIT",
"keywords": [
"JSON",
"schema",
"validator"
],
"keywords": ["JSON", "schema", "validator"],
"homepage": "https://github.com/ajv-validator/ajv",
"moduleType": [
"amd",
"globals",
"node"
],
"ignore": [
"node_modules",
"bower_components",
"spec"
]
"moduleType": ["amd", "globals", "node"],
"ignore": ["node_modules", "bower_components", "spec"]
}
31 changes: 0 additions & 31 deletions circle.yml

This file was deleted.

541 changes: 541 additions & 0 deletions docs/api.md

Large diffs are not rendered by default.

86 changes: 86 additions & 0 deletions docs/codegen.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# Code generation

Starting from v7 Ajv uses [CodeGen module](../lib/compile/codegen/index.ts) that replaced [doT](https://github.com/olado/dot) templates used earlier.

The motivations for this change:

- doT templates were difficult to maintain and to change, particularly for the occasional contributors.
- they discouraged modularity within validation keywords code and also led to implicit dependencies between different parts of code.
- they had risks of remote code execution in case untrusted schemas were used, even though all identified issues were patched.
- ES6 template literals that are now widely supported offer a great alternative to both ASTs and to plain string concatenation - this option was not available when Ajv started.

## Safe code generation

CodeGen module defines two tagged templates that should be passed to all code generation methods and used in other tagged templates:

- `_` - to create instances of private \_Code class that will not be escaped when used in code or other tagged templates.
- `str` - to create code for string expressions.

For example, this code:

```typescript
const x = 0
// Name is a subclass of _Code that can be safely used in code - it only allows valid identifiers
// gen.const creates a unique variable name with the prefix "num".
const num: Name = gen.const("num", 5)
gen.if(
// _`...` returns the instance of _Code with safe interpolation of `num` and `x`.
// if `x` was a string, it would be inserted into code as a quoted string value rather than as a code fragment,
// so if `x` contained some code, it would not be executed.
_`${num} > ${x}`,
() => log("greater"),
() => log("smaller or equal")
)

function log(comparison: string): void {
// msg creates a string expression with concatenation - see generated code below
// 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})`)
}
```

generates this javascript code:

```javascript
const num0 = 5
if (num0 > 0) {
console.log(num0 + " is greater than 0")
} else {
console.log(num0 + " is smaller or equal than 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.

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.

If a string variable were used in `_` template literal, its value would be safely wrapped in quotes - in many cases it is quite useful, as it allows to inject values that can be either string or number via the same template. In the worst case, the generated code could be invalid, but it will prevent the risk of code execution that attacker could pass via untrusted schema as a string value that should be inserted in code (e.g., instead of a number). Also see the comment in the example.

## Code optimization

CodeGen class generates code trees and performs several optimizations before the code is rendered:

1. removes empty and unreachable branches (e.g. `else` branch after `if(true)`, etc.).
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.

See [these tests](../spec/codegen.spec.ts) for examples.

By default Ajv does 1-pass optimization - based on the test suite it reduces the code size by 10.5% and the number of tree nodes by 16.7% (TODO benchmark the validation time). The second optimization pass changes it by less than 0.1%, so you won't need it unless you have really complex schemas or if you generate standalone code and want it to pass relevant eslint rules.

Optimization mode can be changed with [options](./api.md#options):

- `{code: {optimize: false}}` - to disable (e.g., when schema compilation time is more important),
- `{code: {optimize: 2}}` - 2-pass optimization.

## User-defined keywords

While tagged template literals wrap passed strings based on their run-time values, CodeGen class methods rely on types to ensure safety of passed parameters - there is no run-time checks that the passed value is an instance of \_Code class.

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.
39 changes: 14 additions & 25 deletions COERCION.md → docs/coercion.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# Ajv type coercion rules

To enable type coercion pass option `coerceTypes` to Ajv with `true` or `array` (it is `false` by default). See [example](https://github.com/ajv-validator/ajv#coercing-data-types).
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).

The coercion rules are different from JavaScript:

- to validate user input as expected
- to have the coercion reversible
- to correctly validate cases where different types are required in subschemas (e.g., in `anyOf`).
@@ -11,100 +12,88 @@ Type coercion only happens if there is `type` keyword and if without coercion th

If there are multiple types allowed in `type` keyword the coercion will only happen if none of the types match the data and some of the scalar types are present (coercion to/from `object`/`array` is not possible). In this case the validating function will try coercing the data to each type in order until some of them succeeds.

Application of these rules can have some unexpected consequences. Ajv may coerce the same value multiple times (this is why coercion reversibility is required) as needed at different points in the schema. This is particularly evident when using `oneOf`, which must test all of the subschemas. Ajv will coerce the type for each subschema, possibly resulting in unexpected failure if it can coerce to match more than one of the subschemas. Even if it succeeds, Ajv will not backtrack, so you'll get the type of the final coercion even if that's not the one that allowed the data to pass validation. If possible, structure your schema with `anyOf`, which won't validate subsequent subschemas as soon as it encounters one subschema that matches.
Application of these rules can have some unexpected consequences. Ajv may coerce the same value multiple times (this is why coercion reversibility is required) as needed at different points in the schema. This is particularly evident when using `oneOf`, which must test all of the subschemas. Ajv will coerce the type for each subschema, possibly resulting in unexpected failure if it can coerce to match more than one of the subschemas. Even if it succeeds, Ajv will not backtrack, so you'll get the type of the final coercion even if that's not the one that allowed the data to pass validation. If possible, structure your schema with `anyOf`, which won't validate subsequent subschemas as soon as it encounters one subschema that matches.

Possible type coercions:

|from&nbsp;type&nbsp;&rarr;<br>to&nbsp;type&nbsp;&darr;|string|number|boolean|null|array*|
|---|:-:|:-:|:-:|:-:|:-:|
|string |-|`x`&rarr;`""+x`|`false`&rarr;`"false"`<br>`true`&rarr;`"true"`|`null`&rarr;`""`|`[x]`&rarr;`x`|
|number /<br>integer|Valid number /<br>integer: `x`&rarr;`+x`<br>|-|`false`&rarr;`0`<br>`true`&rarr;`1`|`null`&rarr;`0`|`[x]`&rarr;`x`|
|boolean |`"false"`&rarr;`false`<br>`"true"`&rarr;`true`<br>`"abc"`&#8696;<br>`""`&#8696;|`0`&rarr;`false`<br>`1`&rarr;`true`<br>`x`&#8696;|-|`null`&rarr;`false`|`[false]`&rarr;`false`<br>`[true]`&rarr;`true`|
|null |`""`&rarr;`null`<br>`"null"`&#8696;<br>`"abc"`&#8696;|`0`&rarr;`null`<br>`x`&#8696;|`false`&rarr;`null`<br>`true`&#8696;|-|`[null]`&rarr;`null`|
|array* |`x`&rarr;`[x]`|`x`&rarr;`[x]`|`false`&rarr;`[false]`<br>`true`&rarr;`[true]`|`null`&rarr;`[null]`|-|

\* Requires option `{coerceTypes: 'array'}`
| from&nbsp;type&nbsp;&rarr;<br>to&nbsp;type&nbsp;&darr; | string | number | boolean | null | array\* |
| ------------------------------------------------------ | :-----------------------------------------------------------------------------: | :-----------------------------------------------: | :--------------------------------------------: | :------------------: | :--------------------------------------------: |
| string | - | `x`&rarr;`""+x` | `false`&rarr;`"false"`<br>`true`&rarr;`"true"` | `null`&rarr;`""` | `[x]`&rarr;`x` |
| number /<br>integer | Valid number /<br>integer: `x`&rarr;`+x`<br> | - | `false`&rarr;`0`<br>`true`&rarr;`1` | `null`&rarr;`0` | `[x]`&rarr;`x` |
| boolean | `"false"`&rarr;`false`<br>`"true"`&rarr;`true`<br>`"abc"`&#8696;<br>`""`&#8696; | `0`&rarr;`false`<br>`1`&rarr;`true`<br>`x`&#8696; | - | `null`&rarr;`false` | `[false]`&rarr;`false`<br>`[true]`&rarr;`true` |
| null | `""`&rarr;`null`<br>`"null"`&#8696;<br>`"abc"`&#8696; | `0`&rarr;`null`<br>`x`&#8696; | `false`&rarr;`null`<br>`true`&#8696; | - | `[null]`&rarr;`null` |
| array\* | `x`&rarr;`[x]` | `x`&rarr;`[x]` | `false`&rarr;`[false]`<br>`true`&rarr;`[true]` | `null`&rarr;`[null]` | - |

\* Requires option `{coerceTypes: "array"}`

## Coercion from string values

#### To number type

Coercion to `number` is possible if the string is a valid number, `+data` is used.


#### To integer type

Coercion to `integer` is possible if the string is a valid number without fractional part (`data % 1 === 0`).


#### To boolean type

Unlike JavaScript, only these strings can be coerced to `boolean`:

- `"true"` -> `true`
- `"false"` -> `false`


#### To null type

Empty string is coerced to `null`, other strings can't be coerced.


## Coercion from number values

#### To string type

Always possible, `'' + data` is used


#### To boolean type

Unlike JavaScript, only these numbers can be coerced to `boolean`:

- `1` -> `true`
- `0` -> `false`


#### To null type

`0` coerces to `null`, other numbers can't be coerced.


## Coercion from boolean values

#### To string type

- `true` -> `"true"`
- `false` -> `"false"`


#### To number/integer types

- `true` -> `1`
- `false` -> `0`


#### To null type

`false` coerces to `null`, `true` can't be coerced.


## Coercion from null

#### To string type

`null` coerses to the empty string.

`null` coerces to the empty string.

#### To number/integer types

`null` coerces to `0`


#### To boolean type

`null` coerces to `false`


## Coercion to and from array

These coercions require that the option `coerceTypes` is `"array"`.
33 changes: 33 additions & 0 deletions docs/components.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Code components

## 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/ajv.ts](../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.

## Schema compilation

[lib/compile](../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/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/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/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/codegen](../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.

## Other components

[lib/standalone](../lib/standalone) - module to generate [standalone validation code](./standalone.md).

[lib/vocabularies](../lib/vocabularies) - pre-defined validation keywords.

[lib/refs](../lib/refs) - JSON Schema meta-schemas.
75 changes: 30 additions & 45 deletions FAQ.md → docs/faq.md
Original file line number Diff line number Diff line change
@@ -2,110 +2,95 @@

The purpose of this document is to help find answers quicker. I am happy to continue the discussion about these issues, so please comment on some of the issues mentioned below or create a new issue if it seems more appropriate.



## Using JSON schema

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](https://github.com/ajv-validator/ajv/blob/master/KEYWORDS.md) in Ajv documentation
- [Validation keywords](./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?

##### Why Ajv validates empty object as valid?

"properties" keyword does not require the presence of any properties, you need to use "required" keyword. It also doesn't require that the data is an object, so any other type of data will also be valid. To require a specific type use "type" keyword.


##### Why Ajv validates only the first item of the array?
"properties" keyword does not require the presence of any properties, you need to use "required" keyword. It also doesn't require that the data is an object, so any other type of data will also be valid. To require a specific type use "type" keyword. [Strict types mode](./strict-mode.md#strict-types) introduced in v7 requires presence of "type" when "properties" are used, so the mistakes are less likely.

"items" keyword support [two syntaxes](https://github.com/ajv-validator/ajv/blob/master/KEYWORDS.md#items) - 1) when the schema applies to all items; 2) when there is a different schema for each item in the beginning of the array. This problem means you are using the second syntax.
#### Why Ajv validates only the first item of the array?

"items" keyword support [two syntaxes](./json-schema.md#items) - 1) when the schema applies to all items; 2) when there is a different schema for each item in the beginning of the array. This problem means you are using the second syntax.

In v7 with option `strictTuples` (`"log"` by default) this problem is less likely to happen, as Ajv would log warning about missing "minItems" and other keywords that are required to constrain tuple size.

## Ajv API for returning validation errors

See [#65](https://github.com/ajv-validator/ajv/issues/65), [#212](https://github.com/ajv-validator/ajv/issues/212), [#236](https://github.com/ajv-validator/ajv/issues/236), [#242](https://github.com/ajv-validator/ajv/issues/242), [#256](https://github.com/ajv-validator/ajv/issues/256).


##### Why Ajv assigns errors as a property of validation function (or instance) instead of returning an object with validation results and errors?
#### Why Ajv assigns errors as a property of validation function (or instance) instead of returning an object with validation results and errors?

The reasons are history (other fast validators with the same api) and performance (returning boolean is faster). Although more code is written to process errors than to handle successful results, almost all server-side validations pass. The existing API is more efficient from the performance point of view.

Ajv also supports asynchronous validation (with custom asynchronous formats and keywords) that returns a promise that either resolves to `true` or rejects with an error.


##### Would errors get overwritten in case of "concurrent" validations?

No. There is no concurrency in JavaScript - it is single-threaded. While a validation is run no other JavaScript code (that can access the same memory) can be executed. As long as the errors are used in the same execution block, the errors will not be overwritten.
Ajv also supports asynchronous validation (with asynchronous formats and keywords) that returns a promise that either resolves to `true` or rejects with an error.

#### Would errors get overwritten in case of "concurrent" validations?

##### Can we change / extend API to add a method that would return errors (rather than assign them to `errors` property)?
No. There is no parallel execution in JavaScript, and the cooperative concurrency model of javascript makes this pattern safe. While a validation is run, no other JavaScript code that can access the same memory can be executed. As long as the errors are used in the same execution block, the errors will not be overwritten.

No. In many cases there is a module responsible for the validation in the application, usually to load schemas and to process errors. This module is the right place to introduce any custom API. Convenience is a subjective thing, changing or extending API purely because of convenience would either break backward compatibility (even if it's done in a new major version it still complicates migration) or bloat API (making it more difficult to maintain).
#### Can we change / extend API to add a method that would return errors (rather than assign them to `errors` property)?

No. In many cases there is a module responsible for the validation in the application, usually to load schemas and to process errors. This module is the right place to introduce any user-defined API. Convenience is a subjective thing, changing or extending API purely because of convenience would either break backward compatibility (even if it's done in a new major version it still complicates migration) or bloat API (making it more difficult to maintain).

##### Why don't `"additionalProperties": false` errors display the property name?
#### Why don't `"additionalProperties": false` errors display the property name?

Doing this would create a precedent where validated data is used in error messages, creating a vulnerability (e.g., when ajv is used to validate API data/parameters and error messages are logged).

Since the property name is already in the params object, in an application you can modify messages in any way you need. ajv-errors package allows modifying messages as well.


Since the property name is already in the params object, in an application you can modify the messages in any way you need. ajv-errors package allows modifying messages as well.

## Additional properties inside compound keywords anyOf, oneOf, etc.

See [#127](https://github.com/ajv-validator/ajv/issues/127), [#129](https://github.com/ajv-validator/ajv/issues/129), [#134](https://github.com/ajv-validator/ajv/issues/134), [#140](https://github.com/ajv-validator/ajv/issues/140), [#193](https://github.com/ajv-validator/ajv/issues/193), [#205](https://github.com/ajv-validator/ajv/issues/205), [#238](https://github.com/ajv-validator/ajv/issues/238), [#264](https://github.com/ajv-validator/ajv/issues/264).


##### Why the keyword `additionalProperties: false` fails validation when some properties are "declared" inside a subschema in `anyOf`/etc.?
#### Why the keyword `additionalProperties: false` fails validation when some properties are "declared" inside a subschema in `anyOf`/etc.?

The keyword `additionalProperties` creates the restriction on validated data based on its own value (`false` or schema object) and on the keywords `properties` and `patternProperties` in the SAME schema object. JSON Schema validators must NOT take into account properties used in other schema objects.

While you can expect that the schema below would allow the objects either with properties `foo` and `bar` or with properties `foo` and `baz` and all other properties will be prohibited, this schema will only allow objects with one property `foo` (an empty object and any non-objects will also be valid):

```json
```javascript
{
"properties": { "foo": { "type": "number" } },
"additionalProperties": false,
"oneOf": [
{ "properties": { "bar": { "type": "number" } } },
{ "properties": { "baz": { "type": "number" } } }
type: "object",
properties: {foo: {type: "number"}},
additionalProperties: false,
oneOf: [
{properties: {bar: {type: "number"}}},
{properties: {baz: {type: "number"}}}
]
}
```

The reason for that is that `additionalProperties` keyword ignores properties inside `oneOf` keyword subschemas. That's not the limitation of Ajv or any other validator, that's how it must work according to the standard (and if you consider all the problems with the alternatives it is the only sensible way to define this keyword).
The reason for that is that `additionalProperties` keyword ignores properties inside `oneOf` keyword subschemas. That's not the limitation of Ajv or any other validator, that's how it must work according to the standard.

There are several ways to implement the described logic that would allow two properties, please see the suggestions in the issues mentioned above.


##### Why the validation fails when I use option `removeAdditional` with the keyword `anyOf`/etc.?
#### Why the validation fails when I use option `removeAdditional` with the keyword `anyOf`/etc.?

This problem is related to the problem explained above - properties treated as additional in the sense of `additionalProperties` keyword, based on `properties`/`patternProperties` keyword in the same schema object.

See the exemple in [Filtering Data](https://github.com/ajv-validator/ajv#filtering-data) section of readme.
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.
3. There are cases when such inlining would also require adding (or modyfing) `id` attribute in the inlined schema fragment to make the resulting schema equivalent.
3. There are cases when such inlining would also require adding (or modifying) `id` attribute in the inlined schema fragment to make the resulting schema equivalent.

There were many conversations about the meaning of `$ref` in [JSON Schema GitHub organisation](https://github.com/json-schema-org). The consensus is that while it is possible to treat `$ref` as schema inclusion with two caveats (above), this interpretation is unnecessary complex. A more efficient approach is to treat `$ref` as a delegation, i.e. a special keyword that validates the current data instance against the referenced schema. The analogy with programming languages is that `$ref` is a function call rather than a macro. See [here](https://github.com/json-schema-org/json-schema-spec/issues/279), for example.


##### How can I generate a schema where `$ref` keywords are replaced with referenced schemas?
#### How can I generate a schema where `$ref` keywords are replaced with referenced schemas?

There are two possible approaches:

1. Traverse schema (e.g. with json-schema-traverse) and replace every `$ref` with the referenced schema.
2. Use a specially constructed JSON Schema with a [custom keyword](https://github.com/ajv-validator/ajv/blob/master/CUSTOM.md) to traverse and modify your schema.
2. Use a specially constructed JSON Schema with a [user-defined keyword](./keywords.md) to traverse and modify your schema.
885 changes: 885 additions & 0 deletions docs/json-schema.md

Large diffs are not rendered by default.

277 changes: 277 additions & 0 deletions docs/keywords.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,277 @@
# User defined keywords

## Contents

- 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

The usual interface to define all keywords has these properties:

```typescript
interface _KeywordDef {
keyword: string | string[]
type?: JSONType | JSONType[] // data type(s) that keyword applies to,
// if defined, it is usually "string", "number", "object" or "array"
schemaType?: JSONType | JSONType[] // the allowed type(s) of value that keyword must have in the schema
error?: {
message: string | ((cxt: KeywordCxt) => Code)
params?: (cxt: KeywordCxt) => Code
}
}
```

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

Starting from v7 Ajv uses [CodeGen module](../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:

- safe against code injection
- best performance
- the precise control over validation process
- access to the parent data and the path to the currently validated data

While Ajv can be safely used with plain JavaScript, it is strongly recommended to use Typescript for user-defined keywords that generate code - the prevention against code injection via untrusted schemas is partially based on the type system, not only on runtime checks.

The usual keyword definition for keywords generating code extends common interface with "code" function:

```typescript
interface CodeKeywordDefinition extends _KeywordDef {
code: (cxt: KeywordCxt, ruleType?: string) => void // code generation function
}
```

Example `even` keyword:

```typescript
import {_, KeywordCxt} from Ajv

ajv.addKeyword({
keyword: "even",
type: "number",
schemaType: "boolean",
// $data: true // to support [$data reference](./validation.md#data-reference), ...
code(cxt: KeywordCxt) {
const {data, schema} = cxt
const op = schema ? _`!==` : _`===`
cxt.fail(_`${data} %2 ${op} 0`) // ... the only code change needed is to use `cxt.fail$data` here
},
})

const schema = {even: true}
const validate = ajv.compile(schema)
console.log(validate(2)) // true
console.log(validate(3)) // false
```

Example `range` keyword:

```typescript
import {_, nil, KeywordCxt} from Ajv

ajv.addKeyword({
keyword: "range",
type: "number",
code(cxt: KeywordCxt) {
const {schema, parentSchema, data} = cxt
const [min, max] = schema
const eq: Code = parentSchema.exclusiveRange ? _`=` : nil
gen.fail(_`${data} <${eq} ${min} || ${data} >${eq} ${max}`)
},
metaSchema: {
type: "array",
items: [{type: "number"}, {type: "number"}],
minItems: 2
additionalItems: false,
},
})
```

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.

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.

### Define keyword with "validate" function

Usual keyword definition for validation keywords:

```typescript
interface FuncKeywordDefinition extends _KeywordDef {
validate?: SchemaValidateFunction | DataValidateFunction // DataValidateFunction requires `schema: false` option
schema?: boolean // schema: false makes validate not to expect schema (DataValidateFunction)
modifying?: boolean
async?: boolean
valid?: boolean
errors?: boolean | "full"
}

interface SchemaValidateFunction {
(schema: any, data: any, parentSchema?: AnySchemaObject, dataCxt?: DataValidationCxt):
| boolean
| Promise<any>
errors?: Partial<ErrorObject>[]
}

interface DataValidateFunction {
(this: Ajv | any, data: any, dataCxt?: DataValidationCxt): boolean | Promise<any>
errors?: Partial<ErrorObject>[]
}
```

The function should return validation result as boolean. It can return an array of validation errors via `.errors` property of itself (otherwise a standard error will be used).

`validate` keywords are suitable for:

- 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`.

Example: `constant` keyword (a synonym for draft-06 keyword `const`, it is equivalent to `enum` keyword with one item):

```javascript
ajv.addKeyword({
keyword: "constant",
validate: (schema, data) =>
typeof schema == "object" && schema !== null ? deepEqual(schema, data) : schema === data,
errors: false,
})

const schema = {
constant: 2,
}
const validate = ajv.compile(schema)
console.log(validate(2)) // true
console.log(validate(3)) // false

const schema = {
constant: {foo: "bar"},
}
const validate = ajv.compile(schema)
console.log(validate({foo: "bar"})) // true
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.

To add asynchronous keyword pass `async: true` in its definition.

### Define keyword with "compile" function

The keyword is similar to "validate", with the difference that "compile" property has function that will be called during schema compilation and should return validation function:

```typescript
interface FuncKeywordDefinition extends _KeywordDef {
compile?: (schema: any, parentSchema: AnySchemaObject, it: SchemaObjCxt) => DataValidateFunction
schema?: boolean // schema: false makes validate not to expect schema (DataValidateFunction)
modifying?: boolean
async?: boolean
valid?: boolean
errors?: boolean | "full"
}
```

In some cases it is the best approach to define keywords, but it has the performance cost of an extra function call during validation. If keyword logic can be expressed via some other JSON Schema then `macro` keyword definition is more efficient (see below).

Example. `range` and `exclusiveRange` keywords using compiled schema:

```javascript
ajv.addKeyword({
keyword: "range",
type: "number",
compile([min, max], parentSchema) {
return parentSchema.exclusiveRange === true
? (data) => data > min && data < max
: (data) => data >= min && data <= max
},
errors: false,
metaSchema: {
// schema to validate keyword value
type: "array",
items: [{type: "number"}, {type: "number"}],
minItems: 2,
additionalItems: false,
},
})

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
```

See note on errors and asynchronous keywords in the previous section.

### Define keyword with "macro" function

Keyword definition:

```typescript
interface MacroKeywordDefinition extends FuncKeywordDefinition {
macro: (schema: any, parentSchema: AnySchemaObject, it: SchemaCxt) => AnySchema
}
```

"Macro" function is called during schema compilation. It is passed schema, parent schema and [schema compilation context](#schema-compilation-context) and it should return another schema that will be applied to the data in addition to the original schema.

It is an efficient approach (in cases when the keyword logic can be expressed with another JSON Schema), because it is usually easy to implement and there is no extra function call during validation.

In addition to the errors from the expanded schema macro keyword will add its own error in case validation fails.

Example. `range` and `exclusiveRange` keywords from the previous example defined with macro:

```javascript
ajv.addKeyword({
keyword: "range",
type: "number",
macro: ([minimum, maximum]) => ({minimum, maximum}), // schema with keywords minimum and maximum
// metaSchema: the same as in the example above
})
```

Macro keywords an be recursive - i.e. return schemas containing the same keyword. See the example of defining a recursive macro keyword `deepProperties` in the [test](../spec/keyword.spec.ts#L316).

## 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.

## Validation time variables

All function scoped variables available during validation are defined in [names](../lib/compile/names.ts).

## Reporting errors

All keywords can define error messages with `KeywordErrorDefinition` object passed as `error` property of keyword definition:

```typescript
interface KeywordErrorDefinition {
message: string | ((cxt: KeywordErrorCxt) => Code)
params?: (cxt: KeywordErrorCxt) => Code
}
```

`code` keywords can pass parameters to these functions via `cxt.setParams` (see implementations of pre-defined keywords), other keywords can only set a string message this way.

Another approach for reporting errors can be used for `validate` and `compile` keyword - they can define errors by assigning them to `.errors` property of the validation function. Asynchronous keywords can return promise that rejects with `new Ajv.ValidationError(errors)`, where `errors` is an array of validation errors (if you don't want to create errors in asynchronous keyword, its validation function can return the promise that resolves with `false`).

Each error object in `errors` array should at least have properties `keyword`, `message` and `params`, other properties will be added.

If keyword doesn't define or return errors, the default error will be created in case the keyword fails validation.
83 changes: 83 additions & 0 deletions docs/security.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# Security considerations

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)

## 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.

## Untrusted schemas

Ajv treats JSON schemas as trusted as your application code. This security model is based on the most common use case, when the schemas are static and bundled together with the application.

If your schemas are received from untrusted sources (or generated from untrusted data) there are several scenarios you need to prevent:

- compiling schemas can cause stack overflow (if they are too deep)
- compiling schemas can be slow (e.g. [#557](https://github.com/ajv-validator/ajv/issues/557))
- validating certain data can be slow

It is difficult to predict all the scenarios, but at the very least it may help to limit the size of untrusted schemas (e.g. limit JSON string length) and also the maximum schema object depth (that can be high for relatively small JSON strings). You also may want to mitigate slow regular expressions in `pattern` and `patternProperties` keywords.

Regardless the measures you take, using untrusted schemas increases security risks.

## Circular references in JavaScript objects

Ajv does not support schemas and validated data that have circular references in objects. See [issue #802](https://github.com/ajv-validator/ajv/issues/802).

An attempt to compile such schemas or validate such data would cause stack overflow (or will not complete in case of asynchronous validation). Depending on the parser you use, untrusted data can lead to circular references.

## Security risks of trusted schemas

Some keywords in JSON Schemas can lead to very slow validation for certain data. These keywords include (but may be not limited to):

- `pattern` and `format` for large strings - in some cases using `maxLength` can help mitigate it, but certain regular expressions can lead to exponential validation time even with relatively short strings (see [ReDoS attack](#redos-attack)).
- `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).

You can validate your JSON schemas against [this meta-schema](../lib/refs/json-schema-secure.json) to check that these recommendations are followed:

```javascript
const isSchemaSecure = ajv.compile(require("ajv/lib/refs/json-schema-secure.json"))

const schema1 = {format: "email"}
isSchemaSecure(schema1) // false

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.

## ReDoS attack

Certain regular expressions can lead to the exponential evaluation time even with relatively short strings.

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:

- 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).
- replacing format implementations provided by ajv-formats with your own implementations of "format" keyword that either use different regular expressions or another approach to format validation. Please see [addFormat](#api-addformat) method.
- disabling format validation by ignoring "format" keyword with option `format: false`

Whatever mitigation you choose, please assume all formats provided by ajv-formats as potentially unsafe and make your own assessment of their suitability for your validation scenarios.

## Content Security Policy

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.

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.
94 changes: 94 additions & 0 deletions docs/standalone.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# Standalone validation code

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).
- to reduce the start-up time - the validation and compilation of schemas will happen during build time.
- to avoid dynamic code evaluation with Function constructor (used for schema compilation) - when it is prohibited by the browser page [Content Security Policy](./security.md#content-security-policy).

This functionality in Ajv v7 supersedes deprecated package ajv-pack that can be used with Ajv v6. All schemas, including those with recursive references, formats and user-defined keywords are supported, with few [limitations](#configuration-and-limitations).

## Usage with CLI

In most cases you would use this functionality via [ajv-cli](https://github.com/jessedc/ajv-cli) (>= 4.0.0) to generate module that exports validation function.

```sh
npm install -g ajv-cli
ajv compile -s schema.json -o validate_schema.js
```

`validate_schema.js` will contain the module exporting validation function that can be bundled into your application.

See [ajv-cli](https://github.com/jessedc/ajv-cli) docs for additional information.

## Usage from code

```sh
npm install ajv
```

```javascript
const Ajv = require("ajv") // version >= v7.0.0
const ajv = new Ajv({code: {source: true}}) // this option is required to generate standalone code
const standaloneCode = require("ajv/dist/standalone")

const schema = {
$id: "https://example.com/object.json",
type: "object",
properties: {
foo: {
type: "string",
pattern: "^[a-z]+$",
},
},
}

// 1. generate module with a single default export (CommonJS and ESM compatible):
const validate = ajv.compile(schema)
let moduleCode = standaloneCode(ajv, validate)

// 2. pass map of schema IDs to generate multiple exports,
// it avoids code duplication if schemas are mutually recursive or have some share elements:
let moduleCode = standaloneCode(ajv, {
validateObject: "https://example.com/object.json",
})

// 3. or generate module with all schemas added to the instance (excluding meta-schemas),
// export names would use schema IDs (or keys passed to addSchema method):
let moduleCode = standaloneCode(ajv)

// now you can
// write module code to file
const fs = require("fs")
const path = require("path")
fs.writeFileSync(path.join(__dirname, "/validate.js"), moduleCode)

// ... or require module from string
const requireFromString = require("require-from-string")
const standaloneValidate = requireFromString(moduleCode) // for a single default export
```

Ajv package should still be a run-time dependency for most schemas, but generated modules can only depend on small parts of it, so the whole Ajv will not be included in the bundle (or executed) if you require the modules with standalone validation code from your application code.

## Configuration and limitations

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).
- 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
import myFormats from "./my-formats"
import Ajv, {_} from "ajv"
const ajv = new Ajv({
formats: myFormats,
code: {
source: true,
formats: _`require("./my-formats")`,
},
})
```

If you only use formats from [ajv-formats](https://github.com/ajv-validator/ajv-formats) this option will be set by this package automatically.
293 changes: 293 additions & 0 deletions docs/strict-mode.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,293 @@
## Strict mode

Strict mode intends to prevent any unexpected behaviours or silently ignored mistakes in user schemas. It does not change any validation results compared with JSON Schema specification, but it makes some schemas invalid and throws exception or logs warning (with `strict: "log"` option) in case any restriction is violated.

To disable all strict mode restrictions use option `strict: false`. Some of the restrictions can be changed with their own options

- [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)
- 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)

### Prohibit ignored keywords

#### Prohibit 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.

The problems with this approach are:

- Different validation results with the same schema and data, leading to bugs and inconsistent behaviours.
- Typos in keywords resulting in keywords being quietly ignored, requiring extensive test coverage of schemas to avoid these mistakes.

By default Ajv fails schema compilation when unknown keywords are used. Users can explicitly define the keywords that should be allowed and ignored:

```javascript
ajv.addKeyword("allowedKeyword")
```

or

```javascript
ajv.addVocabulary(["allowed1", "allowed2"])
```

#### Prohibit 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

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

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.

It is also implied that when "minContains" is 0 and "maxContains" is absent, "contains" keyword is always valid.

By default Ajv fails schema compilation in these cases.

#### Prohibit 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:

```javascript
const ajv = new Ajv({formats: {
reserved: true
})
```
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
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
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.
By default Ajv fails schema compilation if a pattern in "patternProperties" matches a property in "properties" in the same schema.
In addition to allowing such patterns by using option `strict: false`, there is an option `allowMatchingProperties: true` to only allow this case without disabling other strict mode restrictions - there are some rare cases when this is necessary.
To reiterate, neither this nor other strict mode restrictions change the validation results - they only restrict which schemas are valid.
#### Prohibit 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):
```javascript
{
type: "array",
items: [{type: "number"}, {type: "boolean"}]
}
```
The above schema may have a mistake, as tuples usually are expected to have a fixed size. To "fix" it:
```javascript
{
type: "array",
items: [{type: "number"}, {type: "boolean"}],
minItems: 2,
additionalItems: false
// or
// maxItems: 2
}
```
Sometimes users accidentally create schema for unit (a tuple with one item) that only validates the first item, this restriction prevents this mistake as well.
Use `strictTuples` option to suppress this warning (`false`) or turn it into exception (`true`).
If you use `JSONSchemaType<T>` this mistake will also be prevented on a type level.
### Strict types
An additional option `strictTypes` ("log" by default) imposes additional restrictions on how type keyword is used:
#### Prohibit union types
With `strictTypes` option "type" keywords with multiple types (other than with "null") are prohibited.
Invalid:
```javascript
{
type: ["string", "number"]
}
```
Valid:
```javascript
{
type: ["object", "null"]
}
```
and
```javascript
{
type: "object",
nullable: true
}
```
Unions can still be defined with `anyOf` keyword.
The motivation for this restriction is that "type" is usually not the only keyword in the schema, and mixing other keywords that apply to different types is confusing. It is also consistent with wider range of versions of OpenAPI specification and has better tooling support. E.g., this example violating `strictTypes`:
```javascript
{
type: ["number", "array"],
minimum: 0,
items: {
type: "number",
minimum: 0
}
}
```
is equivalent to this complying example, that is more verbose but also easier to maintain:
```javascript
{
anyOf: [
{
type: "number",
minimum: 0,
},
{
type: "array",
items: {
type: "number",
minimum: 0,
},
},
]
}
```
It also can be refactored:
```javascript
{
$defs: {
item: {
type: "number",
minimum: 0
}
},
anyOf: [
{$ref: "#/$defs/item"},
{
type: "array",
items: {$ref: "#/$defs/item"}
},
]
}
```
This restriction can be lifted separately from other `strictTypes` restrictions with `allowUnionTypes: true` option.
#### Prohibit 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:
```javascript
{
type: "object",
anyOf: [
{type: "array"},
{type: "object"}
]
}
```
The schema above violates `strictTypes` as "array" type is not compatible with object. If you used `allowUnionTypes: true` option, the above schema can be fixed in this way:
```javascript
{
type: ["array", "object"],
anyOf: [
{type: "array"},
{type: "object"}
]
}
```
**Please note**: type "number" can be narrowed to "integer", the opposite would violate `strictTypes`.
#### Require applicable types
This simple JSON Schema is valid, but it violates `strictTypes`:
```javascript
{
properties: {
foo: {type: "number"},
bar: {type: "string"}
}
required: ["foo", "bar"]
}
```
This is a very common mistake that even people experienced with JSON Schema often make - the problem here is that any value that is not an object would be valid against this schema - this is rarely intentional.
To fix it, "type" keyword has to be added:
```javascript
{
type: "object",
properties: {
foo: {type: "number"},
bar: {type: "string"}
},
required: ["foo", "bar"]
}
```
You do not necessarily have to have "type" keyword in the same schema object; as long as there is "type" keyword applying to the same part of data instance in the same schema document, not via "\$ref", it will be ok:
```javascript
{
type: "object",
anyOf: [
{
properties: {foo: {type: "number"}}
required: ["foo"]
},
{
properties: {bar: {type: "string"}}
required: ["bar"]
}
]
}
```
Both "properties" and "required" need `type: "object"` to satisfy `strictTypes` - it is sufficient to have it once in the parent schema, without repeating it in each schema.
### Strict number validation
Strict mode also affects number validation. By default Ajv fails `{"type": "number"}` (or `"integer"`) validation for `Infinity` and `NaN`.
729 changes: 729 additions & 0 deletions docs/validation.md

Large diffs are not rendered by default.

41 changes: 16 additions & 25 deletions karma.conf.js
Original file line number Diff line number Diff line change
@@ -1,50 +1,41 @@
// Karma configuration
// Generated on Thu Mar 13 2014 14:12:04 GMT-0700 (PDT)

module.exports = function(config) {
module.exports = function (config) {
config.set({

// base path that will be used to resolve all patterns (eg. files, exclude)
basePath: '',

basePath: "",

// frameworks to use
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
frameworks: ['mocha'],

frameworks: ["mocha"],

// list of files / patterns to load in the browser
files: [
'dist/ajv.min.js',
'node_modules/chai/chai.js',
'node_modules/ajv-async/dist/ajv-async.min.js',
'node_modules/bluebird/js/browser/bluebird.core.min.js',
'.browser/*.spec.js'
"bundle/ajv7.min.js",
"bundle/ajv2019.min.js",
"node_modules/chai/chai.js",
".browser/*.spec.js",
],

// test results reporter to use
// possible values: 'dots', 'progress'
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
reporters: ['dots'],

reporters: ["dots"],

// web server port
port: 9876,


// enable / disable colors in the output (reporters and logs)
colors: true,


// level of logging
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
logLevel: config.LOG_INFO,


// enable / disable watching file and executing tests whenever any file changes
autoWatch: false,


// Start these browsers, currently available:
// - Chrome
// - ChromeCanary
@@ -53,18 +44,18 @@ module.exports = function(config) {
// - Safari (only Mac)
// - PhantomJS
// - IE (only Windows)
browsers: ['HeadlessChrome'],
browsers: ["HeadlessChrome"],
customLaunchers: {
HeadlessChrome:{
base: 'ChromeHeadless',
flags: ['--no-sandbox']
},
HeadlessChrome: {
base: "ChromeHeadless",
flags: ["--no-sandbox"],
},
},

// Continuous Integration mode
// if true, Karma captures browsers, runs the tests and exits
singleRun: true,

browserNoActivityTimeout: 90000
});
};
browserNoActivityTimeout: 90000,
})
}
127 changes: 0 additions & 127 deletions karma.sauce.js

This file was deleted.

72 changes: 72 additions & 0 deletions lib/2019.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
export {
Format,
FormatDefinition,
AsyncFormatDefinition,
KeywordDefinition,
KeywordErrorDefinition,
CodeKeywordDefinition,
MacroKeywordDefinition,
FuncKeywordDefinition,
Vocabulary,
Schema,
SchemaObject,
AnySchemaObject,
AsyncSchema,
AnySchema,
ValidateFunction,
AsyncValidateFunction,
ErrorObject,
ErrorNoParams,
} from "./types"

export {Plugin, Options, CodeOptions, InstanceOptions, Logger, ErrorsTextOptions} from "./core"
export {SchemaCxt, SchemaObjCxt} from "./compile"
import KeywordCxt from "./compile/context"
export {KeywordCxt}
export {DefinedError} from "./vocabularies/errors"
export {JSONType} from "./compile/rules"
export {JSONSchemaType} from "./types/json-schema"
export {_, str, stringify, nil, Name, Code, CodeGen, CodeGenOptions} from "./compile/codegen"

import type {AnySchemaObject} from "./types"
import AjvCore, {Options} from "./core"

import draft7Vocabularies from "./vocabularies/draft7"
import dynamicVocabulary from "./vocabularies/dynamic"
import nextVocabulary from "./vocabularies/next"
import unevaluatedVocabulary from "./vocabularies/unevaluated"
import addMetaSchema2019 from "./refs/json-schema-2019-09"

const META_SCHEMA_ID = "https://json-schema.org/draft/2019-09/schema"

export default class Ajv2019 extends AjvCore {
constructor(opts: Options = {}) {
super({
...opts,
dynamicRef: true,
next: true,
unevaluated: true,
})
}

_addVocabularies(): void {
super._addVocabularies()
this.addVocabulary(dynamicVocabulary)
draft7Vocabularies.forEach((v) => this.addVocabulary(v))
this.addVocabulary(nextVocabulary)
this.addVocabulary(unevaluatedVocabulary)
}

_addDefaultMetaSchema(): void {
super._addDefaultMetaSchema()
const {$data, meta} = this.opts
if (!meta) return
addMetaSchema2019.call(this, $data)
this.refs["http://json-schema.org/schema"] = META_SCHEMA_ID
}

defaultMeta(): string | AnySchemaObject | undefined {
return (this.opts.defaultMeta =
super.defaultMeta() || (this.getSchema(META_SCHEMA_ID) ? META_SCHEMA_ID : undefined))
}
}
397 changes: 0 additions & 397 deletions lib/ajv.d.ts

This file was deleted.

Loading