Merge branch 'master' into master

master
Danila Shutov 2018-01-09 12:25:03 +03:00 committed by GitHub
commit 2c830558df
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
75 changed files with 1571 additions and 1775 deletions

2
.gitignore vendored
View File

@ -37,3 +37,5 @@ lib/dotjs/*.js
# bundles
dist/
package-lock.json

View File

@ -5,8 +5,8 @@ before_script:
node_js:
- "4"
- "6"
- "7"
- "8"
- "9"
after_script:
- codeclimate-test-reporter < coverage/lcov.info
- coveralls < coverage/lcov.info

View File

@ -7,7 +7,7 @@ Thank you for your help making Ajv better! Every contribution is appreciated. If
- [Bug reports](#bug-reports)
- [Change proposals](#changes)
- [Browser and compatibility issues](#compatibility)
- [JSON schema standard](#json-schema)
- [JSON Schema standard](#json-schema)
- [Ajv usage questions](#usage)
- [Code](#code)
- [Development](#development)
@ -33,7 +33,7 @@ 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/epoberezkin/ajv#options).
3. JSON schema and the data you are validating (please make it as small as possible to reproduce the issue).
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).
5. Validation result, data AFTER validation, error messages.
6. What results did you expect?
@ -63,7 +63,7 @@ Please include as much details as possible.
#### <a name="compatibility"></a>Browser and compatibility issues
[Create an issue](https://github.com/epoberezkin/ajv/issues/new?labels=compatibility&body=**The%20version%20of%20Ajv%20you%20are%20using**%0A%0A**The%20environment%20you%20have%20the%20problem%20with.**%0A%0A**Your%20code%20(please%20make%20it%20as%20small%20as%20possible%20to%20reproduce%20the%20issue).**%0A%0A**If%20your%20issue%20is%20in%20the%20browser,%20please%20list%20the%20other%20packages%20loaded%20in%20the%20page%20in%20the%20order%20they%20are%20loaded.%20Please%20check%20if%20the%20issue%20gets%20resolved%20(or%20results%20change)%20if%20you%20move%20Ajv%20bundle%20closer%20to%20the%20top.**%0A%0A**Results%20in%20node.js%20v4.**%0A%0A**Results%20and%20error%20messages%20in%20your%20platform.**%0A%0A) to report a compatibility problem that only happens in a particular environemnt (when your code works correctly in node.js v4 in linux systems but fails in some other environment).
[Create an issue](https://github.com/epoberezkin/ajv/issues/new?labels=compatibility&body=**The%20version%20of%20Ajv%20you%20are%20using**%0A%0A**The%20environment%20you%20have%20the%20problem%20with.**%0A%0A**Your%20code%20(please%20make%20it%20as%20small%20as%20possible%20to%20reproduce%20the%20issue).**%0A%0A**If%20your%20issue%20is%20in%20the%20browser,%20please%20list%20the%20other%20packages%20loaded%20in%20the%20page%20in%20the%20order%20they%20are%20loaded.%20Please%20check%20if%20the%20issue%20gets%20resolved%20(or%20results%20change)%20if%20you%20move%20Ajv%20bundle%20closer%20to%20the%20top.**%0A%0A**Results%20in%20node.js%20v4.**%0A%0A**Results%20and%20error%20messages%20in%20your%20platform.**%0A%0A) to report a compatibility problem that only happens in a particular environment (when your code works correctly in node.js v4 in linux systems but fails in some other environment).
Please include this information:
@ -75,11 +75,9 @@ Please include this information:
6. Results and error messages in your platform.
#### <a name="json-schema"></a>Using JSON schema standard
#### <a name="json-schema"></a>Using JSON Schema standard
Ajv implements JSON schema standard draft 4 and the proposed extensions for the next version of the standard (available when you use the option `v5: true`).
If the issue is related to using v5 extensions please submit it as a [bug report](https://github.com/epoberezkin/ajv/issues/new).
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](http://stackoverflow.com/questions/ask?tags=jsonschema,ajv) (my account is [esp](http://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.

View File

@ -39,7 +39,7 @@ This way to define keywords is useful for:
__Please note__: In cases when validation flow is different depending on the schema and you have to use `if`s, this way to define keywords will have worse performance than compiled keyword returning different validation functions depending on the schema.
Example. `constant` keyword (a synonym for draft6 keyword `const`, it is equivalent to `enum` keyword with one item):
Example. `constant` keyword (a synonym for draft-06 keyword `const`, it is equivalent to `enum` keyword with one item):
```javascript
ajv.addKeyword('constant', {
@ -88,7 +88,7 @@ The access to the parent data object and the current property name allow to crea
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).
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).
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).
All custom keywords types can have an optional `metaSchema` property in their definitions. It is a schema against which the value of keyword will be validated during schema compilation.
@ -134,7 +134,7 @@ See note on custom errors and asynchronous keywords in the previous section.
"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 the most 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.
It is the most 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.

6
FAQ.md
View File

@ -29,7 +29,7 @@ No. In many cases there is a module responsible for the validation in the applic
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 will allow to modify messages as well - templating is [not there yet](https://github.com/epoberezkin/ajv-errors/issues/4), though.
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.
## Additional properties inside compound keywords anyOf, oneOf, etc.
@ -39,7 +39,7 @@ See [#127](https://github.com/epoberezkin/ajv/issues/127), [#129](https://github
##### 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.
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):
@ -84,5 +84,5 @@ There were many conversations about the meaning of `$ref` in [JSON Schema GitHub
There are two possible approaches:
1. Write code to traverse schema and replace every `$ref` with the referenced schema. An additional limitation is that `"$ref"` inside keywords "properties", "patternProperties" and "dependencies" means property name (or pattern) rather than the reference to another schema.
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/epoberezkin/ajv/blob/master/CUSTOM.md) to traverse and modify your schema.

View File

@ -1,7 +1,7 @@
# JSON Schema validation keywords
In a simple way, JSON schema is an object with validation keywords.
In a simple way, JSON Schema is an object with validation keywords.
The keywords and their values define what rules the data should satisfy to be valid.
@ -10,7 +10,7 @@ The keywords and their values define what rules the data should satisfy to be va
- [type](#type)
- [Keywords for numbers](#keywords-for-numbers)
- [maximum / minimum and exclusiveMaximum / exclusiveMinimum](#maximum--minimum-and-exclusivemaximum--exclusiveminimum) (CHANGED in draft 6)
- [maximum / minimum and exclusiveMaximum / exclusiveMinimum](#maximum--minimum-and-exclusivemaximum--exclusiveminimum) (changed in draft-06)
- [multipleOf](#multipleof)
- [Keywords for strings](#keywords-for-strings)
- [maxLength/minLength](#maxlength--minlength)
@ -22,7 +22,7 @@ The keywords and their values define what rules the data should satisfy to be va
- [uniqueItems](#uniqueitems)
- [items](#items)
- [additionalItems](#additionalitems)
- [contains](#contains) (NEW in draft 6)
- [contains](#contains) (added in draft-06)
- [Keywords for objects](#keywords-for-objects)
- [maxProperties/minProperties](#maxproperties--minproperties)
- [required](#required)
@ -30,18 +30,17 @@ The keywords and their values define what rules the data should satisfy to be va
- [patternProperties](#patternproperties)
- [additionalProperties](#additionalproperties)
- [dependencies](#dependencies)
- [propertyNames](#propertynames) (NEW in draft 6)
- [patternGroups](#patterngroups-deprecated) (deprecated)
- [propertyNames](#propertynames) (added in draft-06)
- [patternRequired](#patternrequired-proposed) (proposed)
- [Keywords for all types](#keywords-for-all-types)
- [enum](#enum)
- [const](#const) (NEW in draft 6)
- [const](#const) (added in draft-06)
- [Compound keywords](#compound-keywords)
- [not](#not)
- [oneOf](#oneof)
- [anyOf](#anyof)
- [allOf](#allof)
- [switch](#switch-proposed) (proposed)
- [if/then/else](#ifthenelse) (NEW in draft-07)
@ -75,7 +74,7 @@ __Examples__
_invalid_: `[]`, `{}`, `null`, `true`
All examples above are JSON schemas that only require data to be of certain type to be valid.
All examples above are JSON Schemas that only require data to be of certain type to be valid.
Most other keywords apply only to a particular type of data. If the data is of different type, the keyword will not apply and the data will be considered valid.
@ -88,11 +87,11 @@ Most other keywords apply only to a particular type of data. If the data is of d
The value of keyword `maximum` (`minimum`) should be a number. This value is the maximum (minimum) allowed value for the data to be valid.
Draft 4: The value of keyword `exclusiveMaximum` (`exclusiveMinimum`) should be a boolean value. These keyword cannot be used without `maximum` (`minimum`). If this keyword value is equal to `true`, the data should not be equal to the value in `maximum` (`minimum`) keyword to be valid.
Draft-04: The value of keyword `exclusiveMaximum` (`exclusiveMinimum`) should be a boolean value. These keyword cannot be used without `maximum` (`minimum`). If this keyword value is equal to `true`, the data should not be equal to the value in `maximum` (`minimum`) keyword to be valid.
Draft 6: 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).
Draft-06/07: 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).
Ajv supports both draft 4 and draft 6 syntaxes.
Ajv supports both draft-04 and draft-06/07 syntaxes.
__Examples__
@ -112,8 +111,8 @@ __Examples__
3. _schema_:
draft 4: `{ "minimum": 5, "exclusiveMinimum": true }`
draft 6: `{ "exclusiveMinimum": 5 }`
draft-04: `{ "minimum": 5, "exclusiveMinimum": true }`
draft-06/07: `{ "exclusiveMinimum": 5 }`
_valid_: `6`, `7`, any non-number (`"abc"`, `[]`, `{}`, `null`, `true`)
@ -365,7 +364,7 @@ __Examples__
### `contains`
The value of the keyword is a JSON-schema. The array is valid if it contains at least one item that is valid according to this schema.
The value of the keyword is a JSON Schema. The array is valid if it contains at least one item that is valid according to this schema.
__Example__
@ -424,7 +423,7 @@ _invalid_: `{}`, `{"a": 1}`, `{"c": 3, "d":4}`
### `properties`
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.
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).
@ -451,7 +450,7 @@ _invalid_: `{"foo": 1}`, `{"foo": "a", "bar": 1}`
### `patternProperties`
The value of this keyword should be a map where keys should be regular expressions and the values should be JSON schemas. For data object to be valid the values in data object properties that match regular expression(s) should be valid according to the corresponding schema(s).
The value of this keyword should be a map where keys should be regular expressions and the values should be JSON Schemas. For data object to be valid the values in data object properties that match regular expression(s) should be valid according to the corresponding schema(s).
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.
@ -478,7 +477,7 @@ _invalid_: `{"foo": 1}`, `{"foo": "a", "bar": "b"}`
### `additionalProperties`
The value of the keyword should be either a boolean or a JSON schema.
The value of the keyword should be either a boolean or a JSON Schema.
If the value is `true` the keyword is ignored.
@ -552,7 +551,7 @@ __Examples__
### `dependencies`
The value of the keyword is a map with keys equal to data object properties. Each value in the map should be either an array of unique property names ("property dependency") or a JSON schema ("schema dependency").
The value of the keyword is a map with keys equal to data object properties. Each value in the map should be either an array of unique property names ("property dependency") or a JSON Schema ("schema dependency").
For property dependency, if the data object contains a property that is a key in the keyword value, then to be valid the data object should also contain all properties from the array of properties.
@ -596,7 +595,7 @@ __Examples__
### `propertyNames`
The value of this keyword is a JSON schema.
The value of this keyword is a JSON Schema.
For data object to be valid each property name in this object should be valid according to this schema.
@ -617,41 +616,6 @@ _invalid_: `{"foo": "any value"}`
### `patternGroups` (deprecated)
This keyword is only provided for backward compatibility, it will be removed in the next major version. To use it, pass option `patternGroups: true`.
The value of this keyword should be a map where keys should be regular expressions and the values should be objects with the following properties:
- `schema` (required) - should be a JSON schema. For data object to be valid the values in data object properties that match regular expression(s) should be valid according to the corresponding `schema`(s).
- `maximum` / `minimum` (optional) - should be integers. For data object to be valid the number of properties that match regular expression(s) should be within limits set by `minimum`(s) and `maximum`(s).
__Example__
_schema_:
```json
{
"patternGroups": {
"^[a-z]+$": {
"minimum": 1,
"schema": { "type": "string" }
},
"^[0-9]+$": {
"minimum": 1,
"schema": { "type": "integer" }
}
}
}
```
_valid_: `{ "foo": "bar", "1": "2" }`, any non-object
_invalid_: `{}`, `{ "foo": "bar" }`, `{ "1": "2" }`
### `patternRequired` (proposed)
Defined in [ajv-keywords](https://github.com/epoberezkin/ajv-keywords) package.
@ -732,7 +696,7 @@ _invalid_: `{ "foo": 1 }`, `{ "bar": 1 }`, `{ "foo": 1, "bar": 2 }`
### `not`
The value of the keyword should be a JSON schema. The data is valid if it is invalid according to this schema.
The value of the keyword should be a JSON Schema. The data is valid if it is invalid according to this schema.
__Examples__
@ -763,7 +727,7 @@ __Examples__
### `oneOf`
The value of the keyword should be an array of JSON schemas. The data is valid if it matches exactly one JSON schema from this array. Validators have to validate data against all schemas to establish validity according to this keyword.
The value of the keyword should be an array of JSON Schemas. The data is valid if it matches exactly one JSON Schema from this array. Validators have to validate data against all schemas to establish validity according to this keyword.
__Example__
@ -786,7 +750,7 @@ _invalid_: `2`, `3`, `4.5`, `5.5`
### `anyOf`
The value of the keyword should be an array of JSON schemas. The data is valid if it is valid according to one or more JSON schemas in this array. Validators only need to validate data against schemas in order until the first schema matches (or until all schemas have been tried). For this reason validating against this keyword is faster than against "oneOf" keyword in most cases.
The value of the keyword should be an array of JSON Schemas. The data is valid if it is valid according to one or more JSON Schemas in this array. Validators only need to validate data against schemas in order until the first schema matches (or until all schemas have been tried). For this reason validating against this keyword is faster than against "oneOf" keyword in most cases.
__Example__
@ -809,7 +773,7 @@ _invalid_: `4.5`, `5.5`
### `allOf`
The value of the keyword should be an array of JSON schemas. The data is valid if it is valid according to all JSON schemas in this array.
The value of the keyword should be an array of JSON Schemas. The data is valid if it is valid according to all JSON Schemas in this array.
__Example__
@ -830,29 +794,15 @@ _invalid_: `1.5`, `2.5`, `4`, `4.5`, `5`, `5.5`, any non-number
### `switch` (proposed)
### `if`/`then`/`else`
Defined in [ajv-keywords](https://github.com/epoberezkin/ajv-keywords) package.
These keywords allow to implement conditional validation. Their values should be valid JSON Schemas (object or boolean).
The value of the keyword is the array of if/then clauses. Each clause is the object with the following properties:
If `if` keyword is absent, the validation succeds.
- `if` (optional) - the value is JSON-schema
- `then` (required) - the value is JSON-schema or boolean
- `continue` (optional) - the value is boolean
If the data is valid against the sub-schema in `if` keyword, then the validation result is equal to the result of data validation against the sub-schema in `then` keyword (if `then` is absent, the validation succeeds).
The validation process is dynamic; all clauses are executed sequentially in the following way:
1. `if`:
1. `if` property is JSON-schema according to which the data is:
1. valid => go to step 2.
2. invalid => go to the NEXT clause, if this was the last clause the validation of `switch` SUCCEEDS.
2. `if` property is absent => go to step 2.
2. `then`:
1. `then` property is `true` or it is JSON-schema according to which the data is valid => go to step 3.
2. `then` property is `false` or it is JSON-schema according to which the data is invalid => the validation of `switch` FAILS.
3. `continue`:
1. `continue` property is `true` => go to the NEXT clause, if this was the last clause the validation of `switch` SUCCEEDS.
2. `continue` property is `false` or absent => validation of `switch` SUCCEEDS.
If the data is invalid against the sub-schema in `if` keyword, then the validation result is equal to the result of data validation against the sub-schema in `else` keyword (if `else` is absent, the validation succeeds).
__Examples__
@ -861,29 +811,24 @@ __Examples__
```json
{
"switch": [
{
"if": { "properties": { "power": { "minimum": 9000 } } },
"then": { "required": [ "disbelief" ] },
"continue": true
},
{ "then": { "required": [ "confidence" ] } }
]
"if": { "properties": { "power": { "minimum": 9000 } } },
"then": { "required": [ "disbelief" ] },
"else": { "required": [ "confidence" ] }
}
```
_valid_:
- `{ "power": 9000, "disbelief": true, "confidence": true }`
- `{ "confidence": true }`
- `{ "power": 10000, "disbelief": true }`
- `{}`
- `{ "power": 1000, "confidence": true }`
- any non-object
_invalid_:
- `{ "power": 9000 }` (`disbelief` & `confidence` are required)
- `{ "power": 9000, "disbelief": true }` (`confidence` is always required)
- `{ "power": 1000 }`
- `{}`
- `{ "power": 10000 }` (`disbelief` is required)
- `{ "power": 10000, "confidence": true }` (`disbelief` is required)
- `{ "power": 1000 }` (`confidence` is required)
2. _schema_:
@ -891,13 +836,14 @@ __Examples__
```json
{
"type": "integer",
"switch": [
{ "if": { "not": { "minimum": 1 } }, "then": false },
{ "if": { "maximum": 10 }, "then": true },
{ "if": { "maximum": 100 }, "then": { "multipleOf": 10 } },
{ "if": { "maximum": 1000 }, "then": { "multipleOf": 100 } },
{ "then": false }
]
"minimum": 1,
"maximum": 1000,
"if": { "minimum": 100 },
"then": { "multipleOf": 100 },
"else": {
"if": { "minimum": 10 },
"then": { "multipleOf": 10 }
}
}
```

View File

@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2015 Evgeny Poberezkin
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

232
README.md
View File

@ -2,30 +2,35 @@
# Ajv: Another JSON Schema Validator
The fastest JSON Schema validator for Node.js and browser with draft 6 support.
The fastest JSON Schema validator for Node.js and browser. Supports draft-04/06/07.
[![Build Status](https://travis-ci.org/epoberezkin/ajv.svg?branch=master)](https://travis-ci.org/epoberezkin/ajv)
[![npm version](https://badge.fury.io/js/ajv.svg)](https://www.npmjs.com/package/ajv)
[![npm@beta](https://img.shields.io/npm/v/ajv/beta.svg)](https://github.com/epoberezkin/ajv/tree/beta)
[![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/epoberezkin/ajv/badge.svg?branch=master&service=github)](https://coveralls.io/github/epoberezkin/ajv?branch=master)
[![Greenkeeper badge](https://badges.greenkeeper.io/epoberezkin/ajv.svg)](https://greenkeeper.io/)
[![Gitter](https://img.shields.io/gitter/room/ajv-validator/ajv.svg)](https://gitter.im/ajv-validator/ajv)
__Please note__: Ajv [version 6](https://github.com/epoberezkin/ajv/tree/beta) with [JSON Schema draft-07](http://json-schema.org/work-in-progress) support is released. Use `npm install ajv@beta` to install.
## Using version 6
[JSON Schema draft-07](http://json-schema.org/latest/json-schema-validation.html) is published.
## Using version 5
[Ajv version 6.0.0](https://github.com/epoberezkin/ajv/releases/tag/v6.0.0) that supports draft-07 is released. It may require either migrating your schemas or updating your code (to continue using draft-04 and v5 schemas, draft-06 schemas will be supported without changes).
[JSON Schema draft-06](https://trac.tools.ietf.org/html/draft-wright-json-schema-validation-01) is published.
[Ajv version 5.0.0](https://github.com/epoberezkin/ajv/releases/tag/5.0.0) that supports draft-06 is released. It may require either migrating your schemas or updating your code (to continue using draft-04 and v5 schemas).
__Please note__: To use Ajv with draft-04 schemas you need to explicitly add meta-schema to the validator instance:
__Please note__: To use Ajv with draft-06 schemas you need to explicitly add the meta-schema to the validator instance:
```javascript
ajv.addMetaSchema(require('ajv/lib/refs/json-schema-draft-06.json'));
```
To use Ajv with draft-04 schemas in addition to explicitely adding meta-schema you also need to use option schemaId:
```javascript
var ajv = new Ajv({schemaId: 'id'});
// If you want to use both draft-04 and draft-06/07 schemas:
// var ajv = new Ajv({schemaId: 'auto'});
ajv.addMetaSchema(require('ajv/lib/refs/json-schema-draft-04.json'));
```
@ -40,6 +45,7 @@ ajv.addMetaSchema(require('ajv/lib/refs/json-schema-draft-04.json'));
- [Command line interface](#command-line-interface)
- Validation
- [Keywords](#validation-keywords)
- [Annotation keywords](#annotation-keywords)
- [Formats](#formats)
- [Combining schemas with $ref](#ref)
- [$data reference](#data-reference)
@ -55,6 +61,7 @@ ajv.addMetaSchema(require('ajv/lib/refs/json-schema-draft-04.json'));
- [Methods](#api)
- [Options](#options)
- [Validation errors](#validation-errors)
- [Plugins](#plugins)
- [Related packages](#related-packages)
- [Packages using Ajv](#some-packages-using-ajv)
- [Tests, Contributing, History, License](#tests)
@ -62,7 +69,7 @@ ajv.addMetaSchema(require('ajv/lib/refs/json-schema-draft-04.json'));
## Performance
Ajv generates code using [doT templates](https://github.com/olado/doT) to turn JSON schemas into super-fast validation functions that are efficient for v8 optimization.
Ajv generates code using [doT templates](https://github.com/olado/doT) 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:
@ -79,12 +86,12 @@ Performance of different validators by [json-schema-benchmark](https://github.co
## Features
- Ajv implements full JSON Schema [draft 6](http://json-schema.org/) and draft 4 standards:
- Ajv implements full JSON Schema [draft-06/07](http://json-schema.org/) and draft-04 standards:
- all validation keywords (see [JSON Schema validation keywords](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md))
- full support of remote refs (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 (can be turned off)
- [formats](#formats) defined by JSON Schema draft 4 standard and custom formats (can be turned off)
- [formats](#formats) defined by JSON Schema draft-07 standard and custom formats (can be turned off)
- [validates schemas against meta-schema](#api-validateschema)
- supports [browsers](#using-in-browser) and Node.js 0.10-8.x
- [asynchronous loading](#asynchronous-schema-compilation) of referenced schemas during compilation
@ -97,7 +104,7 @@ Performance of different validators by [json-schema-benchmark](https://github.co
- [custom keywords](#defining-custom-keywords)
- draft-6 keywords `const`, `contains` and `propertyNames`
- draft-6 boolean schemas (`true`/`false` as a schema to always pass/fail).
- keywords `switch`, `patternRequired`, `formatMaximum` / `formatMinimum` and `formatExclusiveMaximum` / `formatExclusiveMinimum` from [JSON-schema extension proposals](https://github.com/json-schema/json-schema/wiki/v5-Proposals) with [ajv-keywords](https://github.com/epoberezkin/ajv-keywords) package
- keywords `switch`, `patternRequired`, `formatMaximum` / `formatMinimum` and `formatExclusiveMaximum` / `formatExclusiveMinimum` from [JSON Schema extension proposals](https://github.com/json-schema/json-schema/wiki/v5-Proposals) with [ajv-keywords](https://github.com/epoberezkin/ajv-keywords) package
- [$data reference](#data-reference) to use values from the validated data as values for the schema keywords
- [asynchronous validation](#asynchronous-validation) of custom formats and keywords
@ -110,12 +117,6 @@ Currently Ajv is the only validator that passes all the tests from [JSON Schema
npm install ajv
```
or to install [version 6](https://github.com/epoberezkin/ajv/tree/beta):
```
npm install ajv@beta
```
## <a name="usage"></a>Getting started
@ -186,11 +187,11 @@ __Please note__: some frameworks, e.g. Dojo, may redefine global require in such
CLI is available as a separate npm package [ajv-cli](https://github.com/jessedc/ajv-cli). It supports:
- compiling JSON-schemas to test their validity
- compiling JSON Schemas to test their validity
- BETA: generating standalone module exporting a validation function to be used without Ajv (using [ajv-pack](https://github.com/epoberezkin/ajv-pack))
- migrate schemas to draft-06 (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
- migrate schemas to draft-07 (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
- custom meta-schemas
- files in JSON and JavaScript format
@ -200,7 +201,7 @@ CLI is available as a separate npm package [ajv-cli](https://github.com/jessedc/
## Validation keywords
Ajv supports all validation keywords from draft 4 of JSON-schema standard:
Ajv supports all validation keywords from draft-07 of JSON Schema standard:
- [type](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md#type)
- [for numbers](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md#keywords-for-numbers) - maximum, minimum, exclusiveMaximum, exclusiveMinimum, multipleOf
@ -208,17 +209,31 @@ Ajv supports all validation keywords from draft 4 of JSON-schema standard:
- [for arrays](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md#keywords-for-arrays) - maxItems, minItems, uniqueItems, items, additionalItems, [contains](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md#contains)
- [for objects](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md#keywords-for-objects) - maxProperties, minProperties, required, properties, patternProperties, additionalProperties, dependencies, [propertyNames](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md#propertynames)
- [for all types](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md#keywords-for-all-types) - enum, [const](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md#const)
- [compound keywords](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md#compound-keywords) - not, oneOf, anyOf, allOf
- [compound keywords](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md#compound-keywords) - not, oneOf, anyOf, allOf, [if/then/else](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md#ifthenelse)
With [ajv-keywords](https://github.com/epoberezkin/ajv-keywords) package Ajv also supports validation keywords from [JSON Schema extension proposals](https://github.com/json-schema/json-schema/wiki/v5-Proposals) for JSON-schema standard:
With [ajv-keywords](https://github.com/epoberezkin/ajv-keywords) package Ajv also supports validation keywords from [JSON Schema extension proposals](https://github.com/json-schema/json-schema/wiki/v5-Proposals) for JSON Schema standard:
- [switch](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md#switch-proposed) - conditional validation with a sequence of if/then clauses
- [patternRequired](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md#patternrequired-proposed) - like `required` but with patterns that some property should match.
- [formatMaximum, formatMinimum, formatExclusiveMaximum, formatExclusiveMinimum](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md#formatmaximum--formatminimum-and-exclusiveformatmaximum--exclusiveformatminimum-proposed) - setting limits for date, time, etc.
See [JSON Schema validation keywords](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md) for more details.
## Annotation keywords
JSON Schema specification defines several annotation keywords that describe 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](#options).
- `default`: a default value of the data instance, see [Assigning defaults](#assigning-defaults).
- `examples` (NEW in draft-07): 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://tools.ietf.org/html/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 some of them, it should remove these kewords from the instance.
## Formats
The following formats are supported for string validation with "format" keyword:
@ -238,6 +253,8 @@ The following formats are supported for string validation with "format" keyword:
- _json-pointer_: JSON-pointer according to [RFC6901](https://tools.ietf.org/html/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. Ajv does not implement these formats. If you create Ajv plugin that implements them please make a PR here to mention this plugin.
There are two modes of format validation: `fast` and `full`. This mode affects formats `date`, `time`, `date-time`, `uri`, `email`, and `hostname`. See [Options](#options) for details.
You can add additional formats and replace any of the formats above using [addFormat](#api-addformat) method.
@ -353,7 +370,7 @@ var validData = {
## $merge and $patch keywords
With the package [ajv-merge-patch](https://github.com/epoberezkin/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://tools.ietf.org/html/rfc7396) and [JSON Patch (RFC 6902)](https://tools.ietf.org/html/rfc6902).
With the package [ajv-merge-patch](https://github.com/epoberezkin/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://tools.ietf.org/html/rfc7396) and [JSON Patch (RFC 6902)](https://tools.ietf.org/html/rfc6902).
To add keywords `$merge` and `$patch` to Ajv instance use this code:
@ -427,7 +444,7 @@ The advantages of using custom keywords are:
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 custom keywords are the portability and understanding of your schemas. You will have to support these custom keywords on other platforms and to properly document these keywords so that everybody can understand them in your schemas.
The concerns you have to be aware of when extending JSON Schema standard with custom keywords are the portability and understanding of your schemas. You will have to support these custom keywords on other platforms and to properly document these keywords so that everybody can understand them in your schemas.
You can define custom keywords with [addKeyword](#api-addkeyword) method. Keywords are defined on the `ajv` instance level - new instances will not have previously defined keywords.
@ -501,39 +518,20 @@ If your schema uses asynchronous formats/keywords or refers to some schema that
__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 custom format/keyword should return a promise that resolves with `true` or `false` (or rejects with `new Ajv.ValidationError(errors)` if you want to return custom errors from the keyword function). Ajv compiles asynchronous schemas to either [es7 async functions](http://tc39.github.io/ecmascript-asyncawait/) that can optionally be transpiled with [nodent](https://github.com/MatAtBread/nodent) or with [regenerator](https://github.com/facebook/regenerator) or to [generator functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*) that can be optionally transpiled with regenerator as well. You can also supply any other transpiler as a function. See [Options](#options).
Validation function for an asynchronous custom format/keyword should return a promise that resolves with `true` or `false` (or rejects with `new Ajv.ValidationError(errors)` if you want to return custom errors from the keyword function).
Ajv compiles asynchronous schemas to [es7 async functions](http://tc39.github.io/ecmascript-asyncawait/) that can optionally be transpiled with [nodent](https://github.com/MatAtBread/nodent). Async functions are supported in Node.js 7+ and all modern browsers. You can also supply any other transpiler as a function via `processCode` option. See [Options](#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.
If you are using generators, the compiled validation function can be either wrapped with [co](https://github.com/tj/co) (default) or returned as generator function, that can be used directly, e.g. in [koa](http://koajs.com/) 1.0. `co` is a small library, it is included in Ajv (both as npm dependency and in the browser bundle).
Async functions are currently supported in Chrome 55, Firefox 52, Node.js 7 (with --harmony-async-await) and MS Edge 13 (with flag).
Generator functions are currently supported in Chrome, Firefox and Node.js.
If you are using Ajv in other browsers or in older versions of Node.js you should use one of available transpiling options. All provided async modes use global Promise class. If your platform does not have Promise you should use a polyfill that defines it.
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
/**
* Default mode is non-transpiled generator function wrapped with `co`.
* Using package ajv-async (https://github.com/epoberezkin/ajv-async)
* you can auto-detect the best async mode.
* In this case, without "async" and "transpile" options
* (or with option {async: true})
* Ajv will choose the first supported/installed option in this order:
* 1. native async function
* 2. native generator function wrapped with co
* 3. es7 async functions transpiled with nodent
* 4. es7 async functions transpiled with regenerator
*/
var setupAsync = require('ajv-async');
var ajv = setupAsync(new Ajv);
var ajv = new Ajv;
// require('ajv-async')(ajv);
ajv.addKeyword('idExists', {
async: true,
@ -580,41 +578,25 @@ validate({ userId: 1, postId: 19 })
### Using transpilers with asynchronous validation functions.
To use a transpiler you should separately install it (or load its bundle in the browser).
Ajv npm package includes minified browser bundles of regenerator and nodent in dist folder.
[ajv-async](https://github.com/epoberezkin/ajv-async) uses [nodent](https://github.com/MatAtBread/nodent) to transpile async functions. To use another transpiler you should separately install it (or load its bundle in the browser).
#### Using nodent
```javascript
var setupAsync = require('ajv-async');
var ajv = new Ajv({ /* async: 'es7', */ transpile: 'nodent' });
setupAsync(ajv);
var ajv = new Ajv;
require('ajv-async')(ajv);
// in the browser if you want to load ajv-async bundle separately you can:
// window.ajvAsync(ajv);
var validate = ajv.compile(schema); // transpiled es7 async function
validate(data).then(successFunc).catch(errorFunc);
```
`npm install nodent` or use `nodent.min.js` from dist folder of npm package.
#### Using regenerator
```javascript
var setupAsync = require('ajv-async');
var ajv = new Ajv({ /* async: 'es7', */ transpile: 'regenerator' });
setupAsync(ajv);
var validate = ajv.compile(schema); // transpiled es7 async function
validate(data).then(successFunc).catch(errorFunc);
```
`npm install regenerator` or use `regenerator.min.js` from dist folder of npm package.
#### Using other transpilers
```javascript
var ajv = new Ajv({ async: 'es7', processCode: transpileFunc });
var ajv = new Ajv({ processCode: transpileFunc });
var validate = ajv.compile(schema); // transpiled es7 async function
validate(data).then(successFunc).catch(errorFunc);
```
@ -622,26 +604,6 @@ validate(data).then(successFunc).catch(errorFunc);
See [Options](#options).
#### Comparison of async modes
|mode|transpile<br>speed*|run-time<br>speed*|bundle<br>size|
|---|:-:|:-:|:-:|
|es7 async<br>(native)|-|0.75|-|
|generators<br>(native)|-|1.0|-|
|es7.nodent|1.35|1.1|215Kb|
|es7.regenerator|1.0|2.7|1109Kb|
|regenerator|1.0|3.2|1109Kb|
\* Relative performance in Node.js 7.x — smaller is better.
[nodent](https://github.com/MatAtBread/nodent) has several advantages:
- much smaller browser bundle than regenerator
- almost the same performance of generated code as native generators in Node.js and the latest Chrome
- much better performance than native generators in other browsers
- works in IE 9 (regenerator does not)
## Filtering data
With [option `removeAdditional`](#options) (added by [andyscott](https://github.com/andyscott)) you can filter data during the validation.
@ -943,7 +905,7 @@ var validate = new Ajv().addSchema(schema).addFormat(name, regex).getSchema(uri)
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 6 meta schema (http://json-schema.org/draft-06/schema and http://json-schema.org/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`.
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`.
##### <a name="api-validateschema"></a>.validateSchema(Object schema) -&gt; Boolean
@ -999,14 +961,14 @@ Custom formats can be also added via `formats` option.
Add custom validation keyword to Ajv instance.
Keyword should be different from all standard JSON schema keywords and different from previously defined keywords. There is no way to redefine keywords or to remove keyword definition from the instance.
Keyword should be different from all standard JSON Schema keywords and different from previously defined keywords. There is no way to redefine keywords or to remove keyword definition from the instance.
Keyword must start with a letter, `_` or `$`, and may continue with letters, numbers, `_`, `$`, or `-`.
It is recommended to use an application-specific prefix for keywords to avoid current and future name collisions.
Example Keywords:
- `"xyz-example"`: valid, and uses prefix for the xyz project to avoid name collisions.
- `"example"`: valid, but not recommended as it could collide with future versions of JSON schema etc.
- `"example"`: valid, but not recommended as it could collide with future versions of JSON Schema etc.
- `"3-example"`: invalid as numbers are not allowed to be the first character in a keyword
Keyword definition is an object with the following properties:
@ -1062,6 +1024,7 @@ Defaults:
$data: false,
allErrors: false,
verbose: false,
$comment: false, // NEW in Ajv version 6.0
jsonPointers: false,
uniqueItems: true,
unicode: true,
@ -1071,7 +1034,7 @@ Defaults:
schemas: {},
logger: undefined,
// referenced schema options:
schemaId: undefined // recommended '$id'
schemaId: '$id',
missingRefs: true,
extendRefs: 'ignore', // recommended 'fail'
loadSchema: undefined, // function(uri: string): Promise {}
@ -1080,7 +1043,6 @@ Defaults:
useDefaults: false,
coerceTypes: false,
// asynchronous validation options:
async: 'co*',
transpile: undefined, // requires ajv-async package
// advanced options:
meta: true,
@ -1105,6 +1067,10 @@ Defaults:
- _$data_: support [$data references](#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](#api).
- _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_ (NEW in Ajv version 6.0): 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
- _jsonPointers_: set `dataPath` property of errors using [JSON Pointers](https://tools.ietf.org/html/rfc6901) instead of JavaScript property access notation.
- _uniqueItems_: validate `uniqueItems` keyword (true by default).
- _unicode_: calculate correct length of strings with unicode pairs (true by default). Pass `false` to use `.length` of strings that is faster, but gives "incorrect" lengths of strings with unicode pairs - each unicode pair is counted as two characters.
@ -1113,7 +1079,7 @@ Defaults:
- _unknownFormats_: handling of unknown formats. Option values:
- `true` (default) - if an unknown format is encountered the exception is thrown during schema compilation. If `format` keyword value is [$data reference](#data-reference) and it is unknown the validation will fail.
- `[String]` - an array of unknown format names that will be ignored. This option can be used to allow usage of third party schemas with format(s) for which you don't have definitions, but still fail if another unknown format is used. If `format` keyword value is [$data reference](#data-reference) and it is not in this array the validation will fail.
- `"ignore"` - to log warning during schema compilation and always pass validation (the default behaviour in versions before 5.0.0). This option is not recommended, as it allows to mistype format name and it won't be validated without any error message. This behaviour is required by JSON-schema specification.
- `"ignore"` - to log warning during schema compilation and always pass validation (the default behaviour in versions before 5.0.0). This option is not recommended, as it allows to mistype format name and it won't be validated without any error message. This behaviour is required by JSON Schema specification.
- _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`. Option values:
- custom logger - it should have methods `log`, `warn` and `error`. If any of these methods is missing an exception will be thrown.
@ -1123,9 +1089,9 @@ Defaults:
##### Referenced schema options
- _schemaId_: this option defines which keywords are used as schema URI. Option value:
- `"$id"` (recommended) - only use `$id` keyword as schema URI (as specified in JSON Schema draft-06), ignore `id` keyword (if it is present a warning will be logged).
- `"$id"` (default) - only use `$id` keyword as schema URI (as specified in JSON Schema draft-06/07), ignore `id` keyword (if it is present a warning will be logged).
- `"id"` - only use `id` keyword as schema URI (as specified in JSON Schema draft-04), ignore `$id` keyword (if it is present a warning will be logged).
- `undefined` (default) - use both `$id` and `id` keywords as schema URI. If both are present (in the same schema object) and different the exception will be thrown during schema compilation.
- `"auto"` - use both `$id` and `id` keywords as schema URI. If both are present (in the same schema object) and different the exception will be thrown during schema compilation.
- _missingRefs_: handling of missing referenced schemas. Option values:
- `true` (default) - if the reference cannot be resolved during compilation the exception is thrown. The thrown error has properties `missingRef` (with hash fragment) and `missingSchema` (without it). Both properties are resolved relative to the current base id (usually schema id, unless it was substituted).
- `"ignore"` - to log error during compilation and always pass validation.
@ -1156,30 +1122,16 @@ Defaults:
##### Asynchronous validation options
- _async_: determines how Ajv compiles asynchronous schemas (see [Asynchronous validation](#asynchronous-validation)) to functions. Option values:
- `"*"` / `"co*"` (default) - compile to generator function ("co*" - wrapped with `co.wrap`). If generators are not supported and you don't provide `processCode` option (or `transpile` option if you use [ajv-async](https://github.com/epoberezkin/ajv-async) package), the exception will be thrown when async schema is compiled.
- `"es7"` - compile to es7 async function. Unless your platform supports them you need to provide `processCode` or `transpile` option. According to [compatibility table](http://kangax.github.io/compat-table/es7/)) async functions are supported by:
- Firefox 52,
- Chrome 55,
- Node.js 7 (with `--harmony-async-await`),
- MS Edge 13 (with flag).
- `undefined`/`true` - auto-detect async mode. It requires [ajv-async](https://github.com/epoberezkin/ajv-async) package. If `transpile` option is not passed, ajv-async will choose the first of supported/installed async/transpile modes in this order:
- "es7" (native async functions),
- "co*" (native generators with co.wrap),
- "es7"/"nodent",
- "co*"/"regenerator" during the creation of the Ajv instance.
If none of the options is available the exception will be thrown.
- _transpile_: Requires [ajv-async](https://github.com/epoberezkin/ajv-async) package. It determines whether Ajv transpiles compiled asynchronous validation function. Option values:
- `"nodent"` - transpile with [nodent](https://github.com/MatAtBread/nodent). If nodent is not installed, the exception will be thrown. nodent can only transpile es7 async functions; it will enforce this mode.
- `"regenerator"` - transpile with [regenerator](https://github.com/facebook/regenerator). If regenerator is not installed, the exception will be thrown.
- a function - this function should accept the code of validation function as a string and return transpiled code. This option allows you to use any other transpiler you prefer. If you are passing a function, you can simply pass it to `processCode` option without using ajv-async.
- `undefined` (default) - transpile with [nodent](https://github.com/MatAtBread/nodent) if async functions are not supported.
- `true` - always transpile with nodent.
- `false` - do not transpile; if async functions are not supported an exception will be thrown.
##### 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 either be http://json-schema.org/schema or http://json-schema.org/draft-04/schema or absent (draft-4 meta-schema will be used) or can be a reference to the schema previously added with `addMetaSchema` method. Option values:
- _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.
@ -1249,18 +1201,30 @@ Properties of `params` object in errors depend on the keyword that failed valida
- `uniqueItems` - properties `i` and `j` (indices of duplicate items).
- `enum` - property `allowedValues` pointing to the array of values (the schema of the keyword).
- `$ref` - property `ref` with the referenced schema URI.
- `oneOf` - property `passingSchemas` (array of indices of passing schemas, null if no schema passes).
- custom keywords (in case keyword definition doesn't create errors) - property `keyword` (the keyword name).
## Plugins
Ajv can be extended with plugins that add custom 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
- this function accepts ajv instance as the first parameter and returns the same instance to allow chaining
- this function can accept an optional configuration as the second parameter
If you have published a useful plugin please submit a PR to add it to the next section.
## Related packages
- [ajv-async](https://github.com/epoberezkin/ajv-async) - configure async validation mode
- [ajv-async](https://github.com/epoberezkin/ajv-async) - plugin to configure async validation mode
- [ajv-cli](https://github.com/jessedc/ajv-cli) - command line interface
- [ajv-errors](https://github.com/epoberezkin/ajv-errors) - custom error messages
- [ajv-errors](https://github.com/epoberezkin/ajv-errors) - plugin for custom error messages
- [ajv-i18n](https://github.com/epoberezkin/ajv-i18n) - internationalised error messages
- [ajv-istanbul](https://github.com/epoberezkin/ajv-istanbul) - instrument generated validation code to measure test coverage of your schemas
- [ajv-keywords](https://github.com/epoberezkin/ajv-keywords) - custom validation keywords (if/then/else, select, typeof, etc.)
- [ajv-merge-patch](https://github.com/epoberezkin/ajv-merge-patch) - keywords $merge and $patch
- [ajv-istanbul](https://github.com/epoberezkin/ajv-istanbul) - plugin to instrument generated validation code to measure test coverage of your schemas
- [ajv-keywords](https://github.com/epoberezkin/ajv-keywords) - plugin with custom validation keywords (if/then/else, select, typeof, etc.)
- [ajv-merge-patch](https://github.com/epoberezkin/ajv-merge-patch) - plugin with keywords $merge and $patch
- [ajv-pack](https://github.com/epoberezkin/ajv-pack) - produces a compact module exporting validation functions
@ -1271,7 +1235,7 @@ Properties of `params` object in errors depend on the keyword that failed valida
- [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
- [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
@ -1280,7 +1244,7 @@ Properties of `params` object in errors depend on the keyword that failed valida
- [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
- [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
@ -1311,15 +1275,15 @@ Please see [Contributing guidelines](https://github.com/epoberezkin/ajv/blob/mas
See https://github.com/epoberezkin/ajv/releases
__Please note__: [Changes in version 5.0.0](https://github.com/epoberezkin/ajv/releases/tag/5.0.0).
__Please note__: [Changes in version 6.0.0](https://github.com/epoberezkin/ajv/releases/tag/v6.0.0).
[Changes in version 4.6.0](https://github.com/epoberezkin/ajv/releases/tag/4.6.0).
[Version 5.0.0](https://github.com/epoberezkin/ajv/releases/tag/5.0.0).
[Changes in version 4.0.0](https://github.com/epoberezkin/ajv/releases/tag/4.0.0).
[Version 4.0.0](https://github.com/epoberezkin/ajv/releases/tag/4.0.0).
[Changes in version 3.0.0](https://github.com/epoberezkin/ajv/releases/tag/3.0.0).
[Version 3.0.0](https://github.com/epoberezkin/ajv/releases/tag/3.0.0).
[Changes in version 2.0.0](https://github.com/epoberezkin/ajv/releases/tag/2.0.0).
[Version 2.0.0](https://github.com/epoberezkin/ajv/releases/tag/2.0.0).
## License

View File

@ -17,8 +17,7 @@ module.exports = function(config) {
files: [
'dist/ajv.min.js',
'node_modules/chai/chai.js',
'dist/regenerator.min.js',
'dist/nodent.min.js',
'node_modules/ajv-async/dist/ajv-async.min.js',
'node_modules/bluebird/js/browser/bluebird.core.min.js',
'.browser/*.spec.js'
],

View File

@ -22,29 +22,18 @@ module.exports = function(config) {
browserName: 'chrome',
version: '27'
},
// 'SL_Chrome_37': {
// base: 'SauceLabs',
// browserName: 'chrome',
// version: '37'
// },
'SL_Chrome': {
base: 'SauceLabs',
browserName: 'chrome'
},
'SL_InternetExplorer_9': {
base: 'SauceLabs',
browserName: 'internet explorer',
version: '9'
},
'SL_InternetExplorer_10': {
base: 'SauceLabs',
browserName: 'internet explorer',
version: '10'
},
'SL_InternetExplorer_11': {
'SL_InternetExplorer': {
base: 'SauceLabs',
browserName: 'internet explorer',
version: '11' // default
browserName: 'internet explorer'
},
'SL_MicrosoftEdge': {
base: 'SauceLabs',
@ -55,45 +44,32 @@ module.exports = function(config) {
browserName: 'firefox',
version: '17'
},
// 'SL_FireFox_24': {
// base: 'SauceLabs',
// browserName: 'firefox',
// version: '24'
// },
'SL_FireFox': {
base: 'SauceLabs',
browserName: 'firefox'
},
'SL_Safari_5': {
'SL_Safari_7': {
base: 'SauceLabs',
browserName: 'safari',
version: '5' // default
version: '7'
},
// 'SL_Safari_7': {
// base: 'SauceLabs',
// browserName: 'safari',
// version: '7'
// },
'SL_Safari_9': {
'SL_Safari': {
base: 'SauceLabs',
browserName: 'safari',
version: '9'
browserName: 'safari'
},
'SL_iPhone_8': {
base: 'SauceLabs',
browserName: 'iphone',
version: '8.4'
},
'SL_iPhone_9': {
'SL_iPhone': {
base: 'SauceLabs',
browserName: 'iphone',
version: '9.2'
browserName: 'iphone'
},
'SL_Android': {
base: 'SauceLabs',
browserName: 'android'
}
// 'SL_Android_4': {
// base: 'SauceLabs',
// browserName: 'android',
// version: '4'
// }
};
@ -112,7 +88,7 @@ module.exports = function(config) {
files: [
'dist/ajv.min.js',
'node_modules/chai/chai.js',
'dist/nodent.min.js',
'node_modules/ajv-async/dist/ajv-async.min.js',
'node_modules/bluebird/js/browser/bluebird.core.min.js',
'.browser/*.spec.js'
],

14
lib/ajv.d.ts vendored
View File

@ -255,8 +255,8 @@ declare namespace ajv {
DependenciesParams | FormatParams | ComparisonParams |
MultipleOfParams | PatternParams | RequiredParams |
TypeParams | UniqueItemsParams | CustomParams |
PatternGroupsParams | PatternRequiredParams |
PropertyNamesParams | SwitchParams | NoParams | EnumParams;
PatternRequiredParams | PropertyNamesParams |
IfParams | SwitchParams | NoParams | EnumParams;
interface RefParams {
ref: string;
@ -312,12 +312,6 @@ declare namespace ajv {
keyword: string;
}
interface PatternGroupsParams {
reason: string;
limit: number;
pattern: string;
}
interface PatternRequiredParams {
missingPattern: string;
}
@ -326,6 +320,10 @@ declare namespace ajv {
propertyName: string;
}
interface IfParams {
failingKeyword: string;
}
interface SwitchParams {
caseIndex: number;
}

View File

@ -7,10 +7,8 @@ var compileSchema = require('./compile')
, stableStringify = require('fast-json-stable-stringify')
, formats = require('./compile/formats')
, rules = require('./compile/rules')
, $dataMetaSchema = require('./$data')
, patternGroups = require('./patternGroups')
, util = require('./compile/util')
, co = require('co');
, $dataMetaSchema = require('./data')
, util = require('./compile/util');
module.exports = Ajv;
@ -38,7 +36,7 @@ Ajv.ValidationError = errorClasses.Validation;
Ajv.MissingRefError = errorClasses.MissingRef;
Ajv.$dataMetaSchema = $dataMetaSchema;
var META_SCHEMA_ID = 'http://json-schema.org/draft-06/schema';
var META_SCHEMA_ID = 'http://json-schema.org/draft-07/schema';
var META_IGNORE_OPTIONS = [ 'removeAdditional', 'useDefaults', 'coerceTypes' ];
var META_SUPPORT_DATA = ['/properties'];
@ -75,7 +73,6 @@ function Ajv(opts) {
addDraft6MetaSchema(this);
if (typeof opts.meta == 'object') this.addMetaSchema(opts.meta);
addInitialSchemas(this);
if (opts.patternGroups) patternGroups(this);
}
@ -99,9 +96,7 @@ function validate(schemaKeyRef, data) {
}
var valid = v(data);
if (v.$async === true)
return this._opts.async == '*' ? co(valid) : valid;
this.errors = v.errors;
if (v.$async !== true) this.errors = v.errors;
return valid;
}
@ -379,9 +374,9 @@ function _compile(schemaObj, root) {
function chooseGetId(opts) {
switch (opts.schemaId) {
case '$id': return _get$Id;
case 'auto': return _get$IdOrId;
case 'id': return _getId;
default: return _get$IdOrId;
default: return _get$Id;
}
}
@ -445,11 +440,11 @@ function addFormat(name, format) {
function addDraft6MetaSchema(self) {
var $dataSchema;
if (self._opts.$data) {
$dataSchema = require('./refs/$data.json');
$dataSchema = require('./refs/data.json');
self.addMetaSchema($dataSchema, $dataSchema.$id, true);
}
if (self._opts.meta === false) return;
var metaSchema = require('./refs/json-schema-draft-06.json');
var metaSchema = require('./refs/json-schema-draft-07.json');
if (self._opts.$data) metaSchema = $dataMetaSchema(metaSchema, META_SUPPORT_DATA);
self.addMetaSchema(metaSchema, META_SCHEMA_ID, true);
self._refs['http://json-schema.org/schema'] = META_SCHEMA_ID;

View File

@ -1,31 +0,0 @@
'use strict';
//all requires must be explicit because browserify won't work with dynamic requires
module.exports = {
'$ref': require('../dotjs/ref'),
allOf: require('../dotjs/allOf'),
anyOf: require('../dotjs/anyOf'),
const: require('../dotjs/const'),
contains: require('../dotjs/contains'),
dependencies: require('../dotjs/dependencies'),
'enum': require('../dotjs/enum'),
format: require('../dotjs/format'),
items: require('../dotjs/items'),
maximum: require('../dotjs/_limit'),
minimum: require('../dotjs/_limit'),
maxItems: require('../dotjs/_limitItems'),
minItems: require('../dotjs/_limitItems'),
maxLength: require('../dotjs/_limitLength'),
minLength: require('../dotjs/_limitLength'),
maxProperties: require('../dotjs/_limitProperties'),
minProperties: require('../dotjs/_limitProperties'),
multipleOf: require('../dotjs/multipleOf'),
not: require('../dotjs/not'),
oneOf: require('../dotjs/oneOf'),
pattern: require('../dotjs/pattern'),
properties: require('../dotjs/properties'),
propertyNames: require('../dotjs/propertyNames'),
required: require('../dotjs/required'),
uniqueItems: require('../dotjs/uniqueItems'),
validate: require('../dotjs/validate')
};

View File

@ -2,8 +2,8 @@
var util = require('./util');
var DATE = /^\d\d\d\d-(\d\d)-(\d\d)$/;
var DAYS = [0,31,29,31,30,31,30,31,31,30,31,30,31];
var DATE = /^(\d\d\d\d)-(\d\d)-(\d\d)$/;
var DAYS = [0,31,28,31,30,31,30,31,31,30,31,30,31];
var TIME = /^(\d\d):(\d\d):(\d\d)(\.\d+)?(z|[+-]\d\d:\d\d)?$/i;
var HOSTNAME = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[-0-9a-z]{0,61}[0-9a-z])?)*$/i;
var URI = /^(?:[a-z][a-z0-9+\-.]*:)(?:\/?\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|[Vv][0-9a-f]+\.[a-z0-9\-._~!$&'()*+,;=:]+)\]|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)|(?:[a-z0-9\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\d*)?(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?|(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)(?:\?(?:[a-z0-9\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$/i;
@ -16,7 +16,8 @@ var URITEMPLATE = /^(?:(?:[^\x00-\x20"'<>%\\^`{|}]|%[0-9a-f]{2})|\{[+#./;?&=,!@|
// var URL = /^(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?!10(?:\.\d{1,3}){3})(?!127(?:\.\d{1,3}){3})(?!169\.254(?:\.\d{1,3}){2})(?!192\.168(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u{00a1}-\u{ffff}0-9]+-?)*[a-z\u{00a1}-\u{ffff}0-9]+)(?:\.(?:[a-z\u{00a1}-\u{ffff}0-9]+-?)*[a-z\u{00a1}-\u{ffff}0-9]+)*(?:\.(?:[a-z\u{00a1}-\u{ffff}]{2,})))(?::\d{2,5})?(?:\/[^\s]*)?$/iu;
var URL = /^(?:(?:http[s\u017F]?|ftp):\/\/)(?:(?:[\0-\x08\x0E-\x1F!-\x9F\xA1-\u167F\u1681-\u1FFF\u200B-\u2027\u202A-\u202E\u2030-\u205E\u2060-\u2FFF\u3001-\uD7FF\uE000-\uFEFE\uFF00-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])+(?::(?:[\0-\x08\x0E-\x1F!-\x9F\xA1-\u167F\u1681-\u1FFF\u200B-\u2027\u202A-\u202E\u2030-\u205E\u2060-\u2FFF\u3001-\uD7FF\uE000-\uFEFE\uFF00-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])*)?@)?(?:(?!10(?:\.[0-9]{1,3}){3})(?!127(?:\.[0-9]{1,3}){3})(?!169\.254(?:\.[0-9]{1,3}){2})(?!192\.168(?:\.[0-9]{1,3}){2})(?!172\.(?:1[6-9]|2[0-9]|3[01])(?:\.[0-9]{1,3}){2})(?:[1-9][0-9]?|1[0-9][0-9]|2[01][0-9]|22[0-3])(?:\.(?:1?[0-9]{1,2}|2[0-4][0-9]|25[0-5])){2}(?:\.(?:[1-9][0-9]?|1[0-9][0-9]|2[0-4][0-9]|25[0-4]))|(?:(?:(?:[0-9KSa-z\xA1-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])+-?)*(?:[0-9KSa-z\xA1-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])+)(?:\.(?:(?:[0-9KSa-z\xA1-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])+-?)*(?:[0-9KSa-z\xA1-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])+)*(?:\.(?:(?:[KSa-z\xA1-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]){2,})))(?::[0-9]{2,5})?(?:\/(?:[\0-\x08\x0E-\x1F!-\x9F\xA1-\u167F\u1681-\u1FFF\u200B-\u2027\u202A-\u202E\u2030-\u205E\u2060-\u2FFF\u3001-\uD7FF\uE000-\uFEFE\uFF00-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])*)?$/i;
var UUID = /^(?:urn:uuid:)?[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}$/i;
var JSON_POINTER = /^(?:\/(?:[^~/]|~0|~1)*)*$|^#(?:\/(?:[a-z0-9_\-.!$&'()*+,;:=@]|%[0-9a-f]{2}|~0|~1)*)*$/i;
var JSON_POINTER = /^(?:\/(?:[^~/]|~0|~1)*)*$/;
var JSON_POINTER_URI_FRAGMENT = /^#(?:\/(?:[a-z0-9_\-.!$&'()*+,;:=@]|%[0-9a-f]{2}|~0|~1)*)*$/i;
var RELATIVE_JSON_POINTER = /^(?:0|[1-9][0-9]*)(?:#|(?:\/(?:[^~/]|~0|~1)*)*)$/;
@ -32,11 +33,11 @@ formats.fast = {
// date: http://tools.ietf.org/html/rfc3339#section-5.6
date: /^\d\d\d\d-[0-1]\d-[0-3]\d$/,
// date-time: http://tools.ietf.org/html/rfc3339#section-5.6
time: /^[0-2]\d:[0-5]\d:[0-5]\d(?:\.\d+)?(?:z|[+-]\d\d:\d\d)?$/i,
'date-time': /^\d\d\d\d-[0-1]\d-[0-3]\d[t\s][0-2]\d:[0-5]\d:[0-5]\d(?:\.\d+)?(?:z|[+-]\d\d:\d\d)$/i,
time: /^(?:[0-2]\d:[0-5]\d:[0-5]\d|23:59:60)(?:\.\d+)?(?:z|[+-]\d\d:\d\d)?$/i,
'date-time': /^\d\d\d\d-[0-1]\d-[0-3]\d[t\s](?:[0-2]\d:[0-5]\d:[0-5]\d|23:59:60)(?:\.\d+)?(?:z|[+-]\d\d:\d\d)$/i,
// uri: https://github.com/mafintosh/is-my-json-valid/blob/master/formats.js
uri: /^(?:[a-z][a-z0-9+-.]*)(?::|\/)\/?[^\s]*$/i,
'uri-reference': /^(?:(?:[a-z][a-z0-9+-.]*:)?\/\/)?[^\s]*$/i,
uri: /^(?:[a-z][a-z0-9+-.]*:)(?:\/?\/)?[^\s]*$/i,
'uri-reference': /^(?:(?:[a-z][a-z0-9+-.]*:)?\/?\/)?(?:[^\\\s#][^\s#]*)?(?:#[^\\\s]*)?$/i,
'uri-template': URITEMPLATE,
url: URL,
// email (sources from jsen validator):
@ -54,6 +55,7 @@ formats.fast = {
// JSON-pointer: https://tools.ietf.org/html/rfc6901
// uri fragment: https://tools.ietf.org/html/rfc3986#appendix-A
'json-pointer': JSON_POINTER,
'json-pointer-uri-fragment': JSON_POINTER_URI_FRAGMENT,
// relative JSON-pointer: http://tools.ietf.org/html/draft-luff-relative-json-pointer-00
'relative-json-pointer': RELATIVE_JSON_POINTER
};
@ -74,18 +76,28 @@ formats.full = {
regex: regex,
uuid: UUID,
'json-pointer': JSON_POINTER,
'json-pointer-uri-fragment': JSON_POINTER_URI_FRAGMENT,
'relative-json-pointer': RELATIVE_JSON_POINTER
};
function isLeapYear(year) {
// https://tools.ietf.org/html/rfc3339#appendix-C
return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
}
function date(str) {
// full-date from http://tools.ietf.org/html/rfc3339#section-5.6
var matches = str.match(DATE);
if (!matches) return false;
var month = +matches[1];
var day = +matches[2];
return month >= 1 && month <= 12 && day >= 1 && day <= DAYS[month];
var year = +matches[1];
var month = +matches[2];
var day = +matches[3];
return month >= 1 && month <= 12 && day >= 1 &&
day <= (month == 2 && isLeapYear(year) ? 29 : DAYS[month]);
}
@ -97,7 +109,9 @@ function time(str, full) {
var minute = matches[2];
var second = matches[3];
var timeZone = matches[5];
return hour <= 23 && minute <= 59 && second <= 59 && (!full || timeZone);
return ((hour <= 23 && minute <= 59 && second <= 59) ||
(hour == 23 && minute == 59 && second == 60)) &&
(!full || timeZone);
}

View File

@ -11,7 +11,6 @@ var validateGenerator = require('../dotjs/validate');
* Functions below are used inside compiled validations function
*/
var co = require('co');
var ucs2length = util.ucs2length;
var equal = require('fast-deep-equal');
@ -124,7 +123,6 @@ function compile(schema, root, localRefs, baseId) {
'refVal',
'defaults',
'customRules',
'co',
'equal',
'ucs2length',
'ValidationError',
@ -139,7 +137,6 @@ function compile(schema, root, localRefs, baseId) {
refVal,
defaults,
customRules,
co,
equal,
ucs2length,
ValidationError
@ -224,7 +221,7 @@ function compile(schema, root, localRefs, baseId) {
function resolvedRef(refVal, code) {
return typeof refVal == 'object' || typeof refVal == 'boolean'
? { code: code, schema: refVal, inline: true }
: { code: code, $async: refVal && refVal.$async };
: { code: code, $async: refVal && !!refVal.$async };
}
function usePattern(regexStr) {

View File

@ -1,6 +1,6 @@
'use strict';
var ruleModules = require('./_rules')
var ruleModules = require('../dotjs')
, toHash = require('./util').toHash;
module.exports = function rules() {
@ -11,17 +11,20 @@ module.exports = function rules() {
{ type: 'string',
rules: [ 'maxLength', 'minLength', 'pattern', 'format' ] },
{ type: 'array',
rules: [ 'maxItems', 'minItems', 'uniqueItems', 'contains', 'items' ] },
rules: [ 'maxItems', 'minItems', 'items', 'contains', 'uniqueItems' ] },
{ type: 'object',
rules: [ 'maxProperties', 'minProperties', 'required', 'dependencies', 'propertyNames',
{ 'properties': ['additionalProperties', 'patternProperties'] } ] },
{ rules: [ '$ref', 'const', 'enum', 'not', 'anyOf', 'oneOf', 'allOf' ] }
{ rules: [ '$ref', 'const', 'enum', 'not', 'anyOf', 'oneOf', 'allOf', 'if' ] }
];
var ALL = [ 'type' ];
var ALL = [ 'type', '$comment' ];
var KEYWORDS = [
'additionalItems', '$schema', '$id', 'id', 'title',
'description', 'default', 'definitions'
'$schema', '$id', 'id', '$data', 'title',
'description', 'default', 'definitions',
'examples', 'readOnly', 'writeOnly',
'contentMediaType', 'contentEncoding',
'additionalItems', 'then', 'else'
];
var TYPES = [ 'number', 'integer', 'string', 'array', 'object', 'boolean', 'null' ];
RULES.all = toHash(ALL);
@ -48,6 +51,11 @@ module.exports = function rules() {
return rule;
});
RULES.all.$comment = {
keyword: '$comment',
code: ruleModules.$comment
};
if (group.type) RULES.types[group.type] = group;
});

View File

@ -38,7 +38,7 @@ module.exports = function (metaSchema, keywordsJsonPointers) {
keywords[key] = {
anyOf: [
schema,
{ $ref: 'https://raw.githubusercontent.com/epoberezkin/ajv/master/lib/refs/$data.json#' }
{ $ref: 'https://raw.githubusercontent.com/epoberezkin/ajv/master/lib/refs/data.json#' }
]
};
}

9
lib/dot/comment.jst Normal file
View File

@ -0,0 +1,9 @@
{{# def.definitions }}
{{# def.setupKeyword }}
{{ var $comment = it.util.toQuotedString($schema); }}
{{? it.opts.$comment === true }}
console.log({{=$comment}});
{{?? typeof it.opts.$comment == 'function' }}
self._opts.$comment({{=$comment}}, {{=it.util.toQuotedString($errSchemaPath)}}, validate.root.schema);
{{?}}

View File

@ -112,13 +112,13 @@ var {{=$valid}};
{{# def.storeDefOut:def_callRuleValidate }}
{{? $rDef.errors === false }}
{{=$valid}} = {{? $asyncKeyword }}{{=it.yieldAwait}}{{?}}{{= def_callRuleValidate }};
{{=$valid}} = {{? $asyncKeyword }}await {{?}}{{= def_callRuleValidate }};
{{??}}
{{? $asyncKeyword }}
{{ $ruleErrs = 'customErrors' + $lvl; }}
var {{=$ruleErrs}} = null;
try {
{{=$valid}} = {{=it.yieldAwait}}{{= def_callRuleValidate }};
{{=$valid}} = await {{= def_callRuleValidate }};
} catch (e) {
{{=$valid}} = false;
if (e instanceof ValidationError) {{=$ruleErrs}} = e.errors;

View File

@ -101,6 +101,7 @@
dependencies: "'should have {{? $deps.length == 1 }}property {{= it.util.escapeQuotes($deps[0]) }}{{??}}properties {{= it.util.escapeQuotes($deps.join(\", \")) }}{{?}} when property {{= it.util.escapeQuotes($property) }} is present'",
'enum': "'should be equal to one of the allowed values'",
format: "'should match format \"{{#def.concatSchemaEQ}}\"'",
'if': "'should match \"' + {{=$ifClause}} + '\" schema'",
_limit: "'should be {{=$opStr}} {{#def.appendSchema}}",
_exclusiveLimit: "'{{=$exclusiveKeyword}} should be boolean'",
_limitItems: "'should NOT have {{?$keyword=='maxItems'}}more{{??}}less{{?}} than {{#def.concatSchema}} items'",
@ -110,7 +111,6 @@
not: "'should NOT be valid'",
oneOf: "'should match exactly one schema in oneOf'",
pattern: "'should match pattern \"{{#def.concatSchemaEQ}}\"'",
patternGroups: "'should NOT have {{=$moreOrLess}} than {{=$limit}} properties matching pattern \"{{=it.util.escapeQuotes($pgProperty)}}\"'",
propertyNames: "'property name \\'{{=$invalidName}}\\' is invalid'",
required: "'{{? it.opts._errorDataPathProperty }}is a required property{{??}}should have required property \\'{{=$missingProperty}}\\'{{?}}'",
type: "'should be {{? $typeIsArray }}{{= $typeSchema.join(\",\") }}{{??}}{{=$typeSchema}}{{?}}'",
@ -137,6 +137,7 @@
dependencies: "validate.schema{{=$schemaPath}}",
'enum': "validate.schema{{=$schemaPath}}",
format: "{{#def.schemaRefOrQS}}",
'if': "validate.schema{{=$schemaPath}}",
_limit: "{{#def.schemaRefOrVal}}",
_exclusiveLimit: "validate.schema{{=$schemaPath}}",
_limitItems: "{{#def.schemaRefOrVal}}",
@ -146,7 +147,6 @@
not: "validate.schema{{=$schemaPath}}",
oneOf: "validate.schema{{=$schemaPath}}",
pattern: "{{#def.schemaRefOrQS}}",
patternGroups: "validate.schema{{=$schemaPath}}",
propertyNames: "validate.schema{{=$schemaPath}}",
required: "validate.schema{{=$schemaPath}}",
type: "validate.schema{{=$schemaPath}}",
@ -172,6 +172,7 @@
dependencies: "{ property: '{{= it.util.escapeQuotes($property) }}', missingProperty: '{{=$missingProperty}}', depsCount: {{=$deps.length}}, deps: '{{= it.util.escapeQuotes($deps.length==1 ? $deps[0] : $deps.join(\", \")) }}' }",
'enum': "{ allowedValues: schema{{=$lvl}} }",
format: "{ format: {{#def.schemaValueQS}} }",
'if': "{ failingKeyword: {{=$ifClause}} }",
_limit: "{ comparison: {{=$opExpr}}, limit: {{=$schemaValue}}, exclusive: {{=$exclusive}} }",
_exclusiveLimit: "{}",
_limitItems: "{ limit: {{=$schemaValue}} }",
@ -179,9 +180,8 @@
_limitProperties:"{ limit: {{=$schemaValue}} }",
multipleOf: "{ multipleOf: {{=$schemaValue}} }",
not: "{}",
oneOf: "{}",
oneOf: "{ passingSchemas: {{=$passingSchemas}} }",
pattern: "{ pattern: {{#def.schemaValueQS}} }",
patternGroups: "{ reason: '{{=$reason}}', limit: {{=$limit}}, pattern: '{{=it.util.escapeQuotes($pgProperty)}}' }",
propertyNames: "{ propertyName: '{{=$invalidName}}' }",
required: "{ missingProperty: '{{=$missingProperty}}' }",
type: "{ type: '{{? $typeIsArray }}{{= $typeSchema.join(\",\") }}{{??}}{{=$typeSchema}}{{?}}' }",

View File

@ -24,7 +24,7 @@
({{=$format}} && {{=$formatType}} == '{{=$ruleType}}'
&& !(typeof {{=$format}} == 'function'
? {{? it.async}}
(async{{=$lvl}} ? {{=it.yieldAwait}} {{=$format}}({{=$data}}) : {{=$format}}({{=$data}}))
(async{{=$lvl}} ? await {{=$format}}({{=$data}}) : {{=$format}}({{=$data}}))
{{??}}
{{=$format}}({{=$data}})
{{?}}
@ -97,7 +97,7 @@
if (!it.async) throw new Error('async format in sync schema');
var $formatRef = 'formats' + it.util.getProperty($schema) + '.validate';
}}
if (!({{=it.yieldAwait}} {{=$formatRef}}({{=$data}}))) {
if (!(await {{=$formatRef}}({{=$data}}))) {
{{??}}
if (!{{# def.checkFormat }}) {
{{?}}

75
lib/dot/if.jst Normal file
View File

@ -0,0 +1,75 @@
{{# def.definitions }}
{{# def.errors }}
{{# def.setupKeyword }}
{{# def.setupNextLevel }}
{{## def.validateIfClause:_clause:
{{
$it.schema = it.schema['_clause'];
$it.schemaPath = it.schemaPath + '._clause';
$it.errSchemaPath = it.errSchemaPath + '/_clause';
}}
{{# def.insertSubschemaCode }}
{{=$valid}} = {{=$nextValid}};
{{? $thenPresent && $elsePresent }}
{{ $ifClause = 'ifClause' + $lvl; }}
var {{=$ifClause}} = '_clause';
{{??}}
{{ $ifClause = '\'_clause\''; }}
{{?}}
#}}
{{
var $thenSch = it.schema['then']
, $elseSch = it.schema['else']
, $thenPresent = $thenSch !== undefined && {{# def.nonEmptySchema:$thenSch }}
, $elsePresent = $elseSch !== undefined && {{# def.nonEmptySchema:$elseSch }}
, $currentBaseId = $it.baseId;
}}
{{? $thenPresent || $elsePresent }}
{{
var $ifClause;
$it.createErrors = false;
$it.schema = $schema;
$it.schemaPath = $schemaPath;
$it.errSchemaPath = $errSchemaPath;
}}
var {{=$errs}} = errors;
var {{=$valid}} = true;
{{# def.setCompositeRule }}
{{# def.insertSubschemaCode }}
{{ $it.createErrors = true; }}
{{# def.resetErrors }}
{{# def.resetCompositeRule }}
{{? $thenPresent }}
if ({{=$nextValid}}) {
{{# def.validateIfClause:then }}
}
{{? $elsePresent }}
else {
{{?}}
{{??}}
if (!{{=$nextValid}}) {
{{?}}
{{? $elsePresent }}
{{# def.validateIfClause:else }}
}
{{?}}
if (!{{=$valid}}) {
{{# def.extraError:'if' }}
}
{{? $breakOnError }} else { {{?}}
{{# def.cleanUp }}
{{??}}
{{? $breakOnError }}
if (true) {
{{?}}
{{?}}

View File

@ -3,11 +3,17 @@
{{# def.setupKeyword }}
{{# def.setupNextLevel }}
var {{=$errs}} = errors;
var prevValid{{=$lvl}} = false;
var {{=$valid}} = false;
{{
var $currentBaseId = $it.baseId
, $prevValid = 'prevValid' + $lvl
, $passingSchemas = 'passingSchemas' + $lvl;
}}
var {{=$errs}} = errors
, {{=$prevValid}} = false
, {{=$valid}} = false
, {{=$passingSchemas}} = null;
{{ var $currentBaseId = $it.baseId; }}
{{# def.setCompositeRule }}
{{~ $schema:$sch:$i }}
@ -24,13 +30,17 @@ var {{=$valid}} = false;
{{?}}
{{? $i }}
if ({{=$nextValid}} && prevValid{{=$lvl}})
if ({{=$nextValid}} && {{=$prevValid}}) {
{{=$valid}} = false;
else {
{{=$passingSchemas}} = [{{=$passingSchemas}}, {{=$i}}];
} else {
{{ $closingBraces += '}'; }}
{{?}}
if ({{=$nextValid}}) {{=$valid}} = prevValid{{=$lvl}} = true;
if ({{=$nextValid}}) {
{{=$valid}} = {{=$prevValid}} = true;
{{=$passingSchemas}} = {{=$i}};
}
{{~}}
{{# def.resetCompositeRule }}

View File

@ -44,11 +44,6 @@
var $required = it.schema.required;
if ($required && !(it.opts.v5 && $required.$data) && $required.length < it.opts.loopRequired)
var $requiredHash = it.util.toHash($required);
if (it.opts.patternGroups) {
var $pgProperties = it.schema.patternGroups || {}
, $pgPropertyKeys = Object.keys($pgProperties);
}
}}
@ -76,11 +71,6 @@ var {{=$nextValid}} = true;
|| {{= it.usePattern($pProperty) }}.test({{=$key}})
{{~}}
{{?}}
{{? it.opts.patternGroups && $pgPropertyKeys.length }}
{{~ $pgPropertyKeys:$pgProperty:$i }}
|| {{= it.usePattern($pgProperty) }}.test({{=$key}})
{{~}}
{{?}}
);
if (isAdditional{{=$lvl}}) {
@ -246,79 +236,6 @@ var {{=$nextValid}} = true;
{{?}}
{{? it.opts.patternGroups && $pgPropertyKeys.length }}
{{~ $pgPropertyKeys:$pgProperty }}
{{
var $pgSchema = $pgProperties[$pgProperty]
, $sch = $pgSchema.schema;
}}
{{? {{# def.nonEmptySchema:$sch}} }}
{{
$it.schema = $sch;
$it.schemaPath = it.schemaPath + '.patternGroups' + it.util.getProperty($pgProperty) + '.schema';
$it.errSchemaPath = it.errSchemaPath + '/patternGroups/'
+ it.util.escapeFragment($pgProperty)
+ '/schema';
}}
var pgPropCount{{=$lvl}} = 0;
{{# def.iterateProperties }}
if ({{= it.usePattern($pgProperty) }}.test({{=$key}})) {
pgPropCount{{=$lvl}}++;
{{
$it.errorPath = it.util.getPathExpr(it.errorPath, $key, it.opts.jsonPointers);
var $passData = $data + '[' + $key + ']';
$it.dataPathArr[$dataNxt] = $key;
}}
{{# def.generateSubschemaCode }}
{{# def.optimizeValidate }}
{{? $breakOnError }} if (!{{=$nextValid}}) break; {{?}}
}
{{? $breakOnError }} else {{=$nextValid}} = true; {{?}}
}
{{# def.ifResultValid }}
{{
var $pgMin = $pgSchema.minimum
, $pgMax = $pgSchema.maximum;
}}
{{? $pgMin !== undefined || $pgMax !== undefined }}
var {{=$valid}} = true;
{{ var $currErrSchemaPath = $errSchemaPath; }}
{{? $pgMin !== undefined }}
{{ var $limit = $pgMin, $reason = 'minimum', $moreOrLess = 'less'; }}
{{=$valid}} = pgPropCount{{=$lvl}} >= {{=$pgMin}};
{{ $errSchemaPath = it.errSchemaPath + '/patternGroups/minimum'; }}
{{# def.checkError:'patternGroups' }}
{{? $pgMax !== undefined }}
else
{{?}}
{{?}}
{{? $pgMax !== undefined }}
{{ var $limit = $pgMax, $reason = 'maximum', $moreOrLess = 'more'; }}
{{=$valid}} = pgPropCount{{=$lvl}} <= {{=$pgMax}};
{{ $errSchemaPath = it.errSchemaPath + '/patternGroups/maximum'; }}
{{# def.checkError:'patternGroups' }}
{{?}}
{{ $errSchemaPath = $currErrSchemaPath; }}
{{# def.ifValid }}
{{?}}
{{?}} {{ /* def.nonEmptySchema */ }}
{{~}}
{{?}}
{{? $breakOnError }}
{{= $closingBraces }}
if ({{=$errs}} == errors) {

View File

@ -50,7 +50,7 @@
{{?}}
{{??}}
{{
$async = $refVal.$async === true;
$async = $refVal.$async === true || (it.async && $refVal.$async !== false);
$refCode = $refVal.code;
}}
{{?}}
@ -65,7 +65,7 @@
{{ if (!it.async) throw new Error('async schema referenced by sync schema'); }}
{{? $breakOnError }} var {{=$valid}}; {{?}}
try {
{{=it.yieldAwait}} {{=__callValidate}};
await {{=__callValidate}};
{{? $breakOnError }} {{=$valid}} = true; {{?}}
} catch (e) {
if (!(e instanceof ValidationError)) throw e;

View File

@ -14,18 +14,34 @@
else {
{{?}}
var {{=$valid}} = true;
if ({{=$data}}.length > 1) {
var i = {{=$data}}.length, j;
outer:
for (;i--;) {
for (j = i; j--;) {
if (equal({{=$data}}[i], {{=$data}}[j])) {
{{=$valid}} = false;
break outer;
var i = {{=$data}}.length
, {{=$valid}} = true
, j;
if (i > 1) {
{{ var $itemType = it.schema.items && it.schema.items.type; }}
{{? !$itemType || $itemType == 'object' || $itemType == 'array' }}
outer:
for (;i--;) {
for (j = i; j--;) {
if (equal({{=$data}}[i], {{=$data}}[j])) {
{{=$valid}} = false;
break outer;
}
}
}
}
{{??}}
var itemIndices = {}, item;
for (;i--;) {
var item = {{=$data}}[i];
if (typeof item != '{{=$itemType}}') continue;
if (itemIndices[item] !== undefined) {
{{=$valid}} = false;
j = itemIndices[item];
break;
}
itemIndices[item] = i;
}
{{?}}
}
{{? $isData }} } {{?}}

View File

@ -21,29 +21,11 @@
}}
{{? it.isTop }}
{{? $async }}
{{
it.async = true;
var $es7 = it.opts.async == 'es7';
it.yieldAwait = $es7 ? 'await' : 'yield';
}}
{{?}}
var validate =
{{? $async }}
{{? $es7 }}
(async function
{{??}}
{{? it.opts.async != '*'}}co.wrap{{?}}(function*
{{?}}
{{??}}
(function
var validate = {{?$async}}{{it.async = true;}}async {{?}}function(data, dataPath, parentData, parentDataProperty, rootData) {
'use strict';
{{? $id && (it.opts.sourceCode || it.opts.processCode) }}
{{= '/\*# sourceURL=' + $id + ' */' }}
{{?}}
(data, dataPath, parentData, parentDataProperty, rootData) {
'use strict';
{{? $id && (it.opts.sourceCode || it.opts.processCode) }}
{{= '/\*# sourceURL=' + $id + ' */' }}
{{?}}
{{?}}
{{? typeof it.schema == 'boolean' || !($refKeywords || it.schema.$ref) }}
@ -70,7 +52,7 @@
{{?}}
{{? it.isTop}}
});
};
return validate;
{{?}}
@ -145,6 +127,10 @@
{{?}}
{{?}}
{{? it.schema.$comment && it.opts.$comment }}
{{= it.RULES.all.$comment.code(it, '$comment') }}
{{?}}
{{? $typeSchema }}
{{? it.opts.coerceTypes }}
{{ var $coerceToTypes = it.util.coerceToTypes(it.opts.coerceTypes, $typeSchema); }}
@ -176,9 +162,6 @@
{{ $closingBraces2 += '}'; }}
{{?}}
{{??}}
{{? it.opts.v5 && it.schema.patternGroups }}
{{ it.logger.warn('keyword "patternGroups" is deprecated and disabled. Use option patternGroups: true to enable.'); }}
{{?}}
{{~ it.RULES:$rulesGroup }}
{{? $shouldUseGroup($rulesGroup) }}
{{? $rulesGroup.type }}
@ -237,7 +220,7 @@
validate.errors = vErrors; {{ /* don't edit, used in replace */ }}
return errors === 0; {{ /* don't edit, used in replace */ }}
{{?}}
});
};
return validate;
{{??}}

33
lib/dotjs/index.js Normal file
View File

@ -0,0 +1,33 @@
'use strict';
//all requires must be explicit because browserify won't work with dynamic requires
module.exports = {
'$ref': require('./ref'),
allOf: require('./allOf'),
anyOf: require('./anyOf'),
'$comment': require('./comment'),
const: require('./const'),
contains: require('./contains'),
dependencies: require('./dependencies'),
'enum': require('./enum'),
format: require('./format'),
'if': require('./if'),
items: require('./items'),
maximum: require('./_limit'),
minimum: require('./_limit'),
maxItems: require('./_limitItems'),
minItems: require('./_limitItems'),
maxLength: require('./_limitLength'),
minLength: require('./_limitLength'),
maxProperties: require('./_limitProperties'),
minProperties: require('./_limitProperties'),
multipleOf: require('./multipleOf'),
not: require('./not'),
oneOf: require('./oneOf'),
pattern: require('./pattern'),
properties: require('./properties'),
propertyNames: require('./propertyNames'),
required: require('./required'),
uniqueItems: require('./uniqueItems'),
validate: require('./validate')
};

View File

@ -51,7 +51,7 @@ function addKeyword(keyword, definition) {
metaSchema = {
anyOf: [
metaSchema,
{ '$ref': 'https://raw.githubusercontent.com/epoberezkin/ajv/master/lib/refs/$data.json#' }
{ '$ref': 'https://raw.githubusercontent.com/epoberezkin/ajv/master/lib/refs/data.json#' }
]
};
}

View File

@ -1,36 +0,0 @@
'use strict';
var META_SCHEMA_ID = 'http://json-schema.org/draft-06/schema';
module.exports = function (ajv) {
var defaultMeta = ajv._opts.defaultMeta;
var metaSchemaRef = typeof defaultMeta == 'string'
? { $ref: defaultMeta }
: ajv.getSchema(META_SCHEMA_ID)
? { $ref: META_SCHEMA_ID }
: {};
ajv.addKeyword('patternGroups', {
// implemented in properties.jst
metaSchema: {
type: 'object',
additionalProperties: {
type: 'object',
required: [ 'schema' ],
properties: {
maximum: {
type: 'integer',
minimum: 0
},
minimum: {
type: 'integer',
minimum: 0
},
schema: metaSchemaRef
},
additionalProperties: false
}
}
});
ajv.RULES.all.properties.implements.push('patternGroups');
};

View File

@ -1,7 +1,7 @@
{
"$schema": "http://json-schema.org/draft-06/schema#",
"$id": "https://raw.githubusercontent.com/epoberezkin/ajv/master/lib/refs/$data.json#",
"description": "Meta-schema for $data reference (JSON-schema extension proposal)",
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://raw.githubusercontent.com/epoberezkin/ajv/master/lib/refs/data.json#",
"description": "Meta-schema for $data reference (JSON Schema extension proposal)",
"type": "object",
"required": [ "$data" ],
"properties": {

View File

@ -0,0 +1,167 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "http://json-schema.org/draft-07/schema#",
"title": "Core schema meta-schema",
"definitions": {
"schemaArray": {
"type": "array",
"minItems": 1,
"items": { "$ref": "#" }
},
"nonNegativeInteger": {
"type": "integer",
"minimum": 0
},
"nonNegativeIntegerDefault0": {
"allOf": [
{ "$ref": "#/definitions/nonNegativeInteger" },
{ "default": 0 }
]
},
"simpleTypes": {
"enum": [
"array",
"boolean",
"integer",
"null",
"number",
"object",
"string"
]
},
"stringArray": {
"type": "array",
"items": { "type": "string" },
"uniqueItems": true,
"default": []
}
},
"type": ["object", "boolean"],
"properties": {
"$id": {
"type": "string",
"format": "uri-reference"
},
"$schema": {
"type": "string",
"format": "uri"
},
"$ref": {
"type": "string",
"format": "uri-reference"
},
"$comment": {
"type": "string"
},
"title": {
"type": "string"
},
"description": {
"type": "string"
},
"default": {},
"readOnly": {
"type": "boolean",
"default": false
},
"examples": {
"type": "array",
"items": {}
},
"multipleOf": {
"type": "number",
"exclusiveMinimum": 0
},
"maximum": {
"type": "number"
},
"exclusiveMaximum": {
"type": "number"
},
"minimum": {
"type": "number"
},
"exclusiveMinimum": {
"type": "number"
},
"maxLength": { "$ref": "#/definitions/nonNegativeInteger" },
"minLength": { "$ref": "#/definitions/nonNegativeIntegerDefault0" },
"pattern": {
"type": "string",
"format": "regex"
},
"additionalItems": { "$ref": "#" },
"items": {
"anyOf": [
{ "$ref": "#" },
{ "$ref": "#/definitions/schemaArray" }
],
"default": {}
},
"maxItems": { "$ref": "#/definitions/nonNegativeInteger" },
"minItems": { "$ref": "#/definitions/nonNegativeIntegerDefault0" },
"uniqueItems": {
"type": "boolean",
"default": false
},
"contains": { "$ref": "#" },
"maxProperties": { "$ref": "#/definitions/nonNegativeInteger" },
"minProperties": { "$ref": "#/definitions/nonNegativeIntegerDefault0" },
"required": { "$ref": "#/definitions/stringArray" },
"additionalProperties": { "$ref": "#" },
"definitions": {
"type": "object",
"additionalProperties": { "$ref": "#" },
"default": {}
},
"properties": {
"type": "object",
"additionalProperties": { "$ref": "#" },
"default": {}
},
"patternProperties": {
"type": "object",
"additionalProperties": { "$ref": "#" },
"propertyNames": { "format": "regex" },
"default": {}
},
"dependencies": {
"type": "object",
"additionalProperties": {
"anyOf": [
{ "$ref": "#" },
{ "$ref": "#/definitions/stringArray" }
]
}
},
"propertyNames": { "$ref": "#" },
"const": {},
"enum": {
"type": "array",
"minItems": 1,
"uniqueItems": true
},
"type": {
"anyOf": [
{ "$ref": "#/definitions/simpleTypes" },
{
"type": "array",
"items": { "$ref": "#/definitions/simpleTypes" },
"minItems": 1,
"uniqueItems": true
}
]
},
"format": { "type": "string" },
"contentMediaType": { "type": "string" },
"contentEncoding": { "type": "string" },
"if": {"$ref": "#"},
"then": {"$ref": "#"},
"else": {"$ref": "#"},
"allOf": { "$ref": "#/definitions/schemaArray" },
"anyOf": { "$ref": "#/definitions/schemaArray" },
"oneOf": { "$ref": "#/definitions/schemaArray" },
"not": { "$ref": "#" }
},
"default": {}
}

View File

@ -1,250 +0,0 @@
{
"id": "https://raw.githubusercontent.com/epoberezkin/ajv/master/lib/refs/json-schema-v5.json#",
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Core schema meta-schema (v5 proposals - deprecated)",
"definitions": {
"schemaArray": {
"type": "array",
"minItems": 1,
"items": { "$ref": "#" }
},
"positiveInteger": {
"type": "integer",
"minimum": 0
},
"positiveIntegerDefault0": {
"allOf": [ { "$ref": "#/definitions/positiveInteger" }, { "default": 0 } ]
},
"simpleTypes": {
"enum": [ "array", "boolean", "integer", "null", "number", "object", "string" ]
},
"stringArray": {
"type": "array",
"items": { "type": "string" },
"minItems": 1,
"uniqueItems": true
},
"$data": {
"type": "object",
"required": [ "$data" ],
"properties": {
"$data": {
"type": "string",
"anyOf": [
{ "format": "relative-json-pointer" },
{ "format": "json-pointer" }
]
}
},
"additionalProperties": false
}
},
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uri"
},
"$schema": {
"type": "string",
"format": "uri"
},
"title": {
"type": "string"
},
"description": {
"type": "string"
},
"default": {},
"multipleOf": {
"anyOf": [
{
"type": "number",
"minimum": 0,
"exclusiveMinimum": true
},
{ "$ref": "#/definitions/$data" }
]
},
"maximum": {
"anyOf": [
{ "type": "number" },
{ "$ref": "#/definitions/$data" }
]
},
"exclusiveMaximum": {
"anyOf": [
{
"type": "boolean",
"default": false
},
{ "$ref": "#/definitions/$data" }
]
},
"minimum": {
"anyOf": [
{ "type": "number" },
{ "$ref": "#/definitions/$data" }
]
},
"exclusiveMinimum": {
"anyOf": [
{
"type": "boolean",
"default": false
},
{ "$ref": "#/definitions/$data" }
]
},
"maxLength": {
"anyOf": [
{ "$ref": "#/definitions/positiveInteger" },
{ "$ref": "#/definitions/$data" }
]
},
"minLength": {
"anyOf": [
{ "$ref": "#/definitions/positiveIntegerDefault0" },
{ "$ref": "#/definitions/$data" }
]
},
"pattern": {
"anyOf": [
{
"type": "string",
"format": "regex"
},
{ "$ref": "#/definitions/$data" }
]
},
"additionalItems": {
"anyOf": [
{ "type": "boolean" },
{ "$ref": "#" },
{ "$ref": "#/definitions/$data" }
],
"default": {}
},
"items": {
"anyOf": [
{ "$ref": "#" },
{ "$ref": "#/definitions/schemaArray" }
],
"default": {}
},
"maxItems": {
"anyOf": [
{ "$ref": "#/definitions/positiveInteger" },
{ "$ref": "#/definitions/$data" }
]
},
"minItems": {
"anyOf": [
{ "$ref": "#/definitions/positiveIntegerDefault0" },
{ "$ref": "#/definitions/$data" }
]
},
"uniqueItems": {
"anyOf": [
{
"type": "boolean",
"default": false
},
{ "$ref": "#/definitions/$data" }
]
},
"maxProperties": {
"anyOf": [
{ "$ref": "#/definitions/positiveInteger" },
{ "$ref": "#/definitions/$data" }
]
},
"minProperties": {
"anyOf": [
{ "$ref": "#/definitions/positiveIntegerDefault0" },
{ "$ref": "#/definitions/$data" }
]
},
"required": {
"anyOf": [
{ "$ref": "#/definitions/stringArray" },
{ "$ref": "#/definitions/$data" }
]
},
"additionalProperties": {
"anyOf": [
{ "type": "boolean" },
{ "$ref": "#" },
{ "$ref": "#/definitions/$data" }
],
"default": {}
},
"definitions": {
"type": "object",
"additionalProperties": { "$ref": "#" },
"default": {}
},
"properties": {
"type": "object",
"additionalProperties": { "$ref": "#" },
"default": {}
},
"patternProperties": {
"type": "object",
"additionalProperties": { "$ref": "#" },
"default": {}
},
"dependencies": {
"type": "object",
"additionalProperties": {
"anyOf": [
{ "$ref": "#" },
{ "$ref": "#/definitions/stringArray" }
]
}
},
"enum": {
"anyOf": [
{
"type": "array",
"minItems": 1,
"uniqueItems": true
},
{ "$ref": "#/definitions/$data" }
]
},
"type": {
"anyOf": [
{ "$ref": "#/definitions/simpleTypes" },
{
"type": "array",
"items": { "$ref": "#/definitions/simpleTypes" },
"minItems": 1,
"uniqueItems": true
}
]
},
"allOf": { "$ref": "#/definitions/schemaArray" },
"anyOf": { "$ref": "#/definitions/schemaArray" },
"oneOf": { "$ref": "#/definitions/schemaArray" },
"not": { "$ref": "#" },
"format": {
"anyOf": [
{ "type": "string" },
{ "$ref": "#/definitions/$data" }
]
},
"constant": {
"anyOf": [
{},
{ "$ref": "#/definitions/$data" }
]
},
"contains": { "$ref": "#" }
},
"dependencies": {
"exclusiveMaximum": [ "maximum" ],
"exclusiveMinimum": [ "minimum" ]
},
"default": {}
}

View File

@ -1,6 +1,6 @@
{
"name": "ajv",
"version": "5.5.2",
"version": "6.0.0",
"description": "Another JSON Schema Validator",
"main": "lib/ajv.js",
"typings": "lib/ajv.d.ts",
@ -19,16 +19,13 @@
"test-debug": "mocha spec/*.spec.js --debug-brk -R spec",
"test-cov": "nyc npm run test-spec",
"test-ts": "tsc --target ES5 --noImplicitAny lib/ajv.d.ts",
"bundle": "node ./scripts/bundle.js . Ajv pure_getters",
"bundle-regenerator": "node ./scripts/bundle.js regenerator",
"bundle-nodent": "node ./scripts/bundle.js nodent",
"bundle-all": "del-cli dist && npm run bundle && npm run bundle-regenerator && npm run bundle-nodent",
"bundle": "del-cli dist && node ./scripts/bundle.js . Ajv pure_getters",
"bundle-beautify": "node ./scripts/bundle.js js-beautify",
"build": "del-cli lib/dotjs/*.js && node scripts/compile-dots.js",
"build": "del-cli lib/dotjs/*.js '!lib/dotjs/index.js' && node scripts/compile-dots.js",
"test-karma": "karma start --single-run --browsers PhantomJS",
"test-browser": "del-cli .browser && npm run bundle-all && scripts/prepare-tests && npm run test-karma",
"test-browser": "del-cli .browser && npm run bundle && scripts/prepare-tests && npm run test-karma",
"test": "npm run jshint && npm run eslint && npm run test-ts && npm run build && npm run test-cov && if-node-version 4 npm run test-browser",
"prepublish": "npm run build && npm run bundle-all",
"prepublish": "npm run build && npm run bundle",
"watch": "watch 'npm run build' ./lib/dot"
},
"nyc": {
@ -63,16 +60,15 @@
"homepage": "https://github.com/epoberezkin/ajv",
"tonicExampleFilename": ".tonic_example.js",
"dependencies": {
"co": "^4.6.0",
"fast-deep-equal": "^1.0.0",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.3.0"
},
"devDependencies": {
"ajv-async": "^0.1.0",
"ajv-async": "^1.0.0",
"bluebird": "^3.1.5",
"brfs": "^1.4.3",
"browserify": "^14.1.0",
"browserify": "^15.0.0",
"chai": "^4.0.1",
"coveralls": "^3.0.0",
"del-cli": "^1.1.0",
@ -90,14 +86,12 @@
"karma-phantomjs-launcher": "^1.0.0",
"karma-sauce-launcher": "^1.1.0",
"mocha": "^4.0.0",
"nodent": "^3.0.17",
"nyc": "^11.0.2",
"phantomjs-prebuilt": "^2.1.4",
"pre-commit": "^1.1.1",
"regenerator": "^0.12.2",
"require-globify": "^1.3.0",
"typescript": "^2.6.2",
"uglify-js": "3.2.2",
"uglify-js": "^3.3.1",
"watch": "^1.0.0"
}
}

3
spec/ajv-async.js Normal file
View File

@ -0,0 +1,3 @@
'use strict';
module.exports = typeof window == 'object' ? window.ajvAsync : require('' + 'ajv-async');

View File

@ -27,15 +27,15 @@ describe('Ajv', function () {
});
it('should cache compiled functions for the same schema', function() {
var v1 = ajv.compile({ id: '//e.com/int.json', type: 'integer', minimum: 1 });
var v2 = ajv.compile({ id: '//e.com/int.json', minimum: 1, type: 'integer' });
var v1 = ajv.compile({ $id: '//e.com/int.json', type: 'integer', minimum: 1 });
var v2 = ajv.compile({ $id: '//e.com/int.json', minimum: 1, type: 'integer' });
v1 .should.equal(v2);
});
it('should throw if different schema has the same id', function() {
ajv.compile({ id: '//e.com/int.json', type: 'integer' });
ajv.compile({ $id: '//e.com/int.json', type: 'integer' });
should.throw(function() {
ajv.compile({ id: '//e.com/int.json', type: 'integer', minimum: 1 });
ajv.compile({ $id: '//e.com/int.json', type: 'integer', minimum: 1 });
});
});
@ -74,24 +74,24 @@ describe('Ajv', function () {
});
it('should validate against previously compiled schema by id (also see addSchema)', function() {
ajv.validate({ id: '//e.com/int.json', type: 'integer' }, 1) .should.equal(true);
ajv.validate({ $id: '//e.com/int.json', type: 'integer' }, 1) .should.equal(true);
ajv.validate('//e.com/int.json', 1) .should.equal(true);
ajv.validate('//e.com/int.json', '1') .should.equal(false);
ajv.compile({ id: '//e.com/str.json', type: 'string' }) .should.be.a('function');
ajv.compile({ $id: '//e.com/str.json', type: 'string' }) .should.be.a('function');
ajv.validate('//e.com/str.json', 'a') .should.equal(true);
ajv.validate('//e.com/str.json', 1) .should.equal(false);
});
it('should throw exception if no schema with ref', function() {
ajv.validate({ id: 'integer', type: 'integer' }, 1) .should.equal(true);
ajv.validate({ $id: 'integer', type: 'integer' }, 1) .should.equal(true);
ajv.validate('integer', 1) .should.equal(true);
should.throw(function() { ajv.validate('string', 'foo'); });
});
it('should validate schema fragment by ref', function() {
ajv.addSchema({
"id": "http://e.com/types.json",
"$id": "http://e.com/types.json",
"definitions": {
"int": { "type": "integer" },
"str": { "type": "string" }
@ -104,10 +104,10 @@ describe('Ajv', function () {
it('should return schema fragment by id', function() {
ajv.addSchema({
"id": "http://e.com/types.json",
"$id": "http://e.com/types.json",
"definitions": {
"int": { "id": "#int", "type": "integer" },
"str": { "id": "#str", "type": "string" }
"int": { "$id": "#int", "type": "integer" },
"str": { "$id": "#str", "type": "string" }
}
});
@ -137,13 +137,13 @@ describe('Ajv', function () {
});
it('should add and compile schema with id', function() {
ajv.addSchema({ id: '//e.com/int.json', type: 'integer' });
ajv.addSchema({ $id: '//e.com/int.json', type: 'integer' });
ajv.validate('//e.com/int.json', 1) .should.equal(true);
ajv.validate('//e.com/int.json', '1') .should.equal(false);
});
it('should normalize schema keys and ids', function() {
ajv.addSchema({ id: '//e.com/int.json#', type: 'integer' }, 'int#');
ajv.addSchema({ $id: '//e.com/int.json#', type: 'integer' }, 'int#');
ajv.validate('int', 1) .should.equal(true);
ajv.validate('int', '1') .should.equal(false);
ajv.validate('//e.com/int.json', 1) .should.equal(true);
@ -156,8 +156,8 @@ describe('Ajv', function () {
it('should add and compile array of schemas with ids', function() {
ajv.addSchema([
{ id: '//e.com/int.json', type: 'integer' },
{ id: '//e.com/str.json', type: 'string' }
{ $id: '//e.com/int.json', type: 'integer' },
{ $id: '//e.com/str.json', type: 'string' }
]);
var validate0 = ajv.getSchema('//e.com/int.json');
@ -210,7 +210,7 @@ describe('Ajv', function () {
it('should throw if schema id is not a string', function() {
try {
ajv.addSchema({ id: 1, type: 'integer' });
ajv.addSchema({ $id: 1, type: 'integer' });
throw new Error('should have throw exception');
} catch(e) {
e.message .should.equal('schema id must be string');
@ -233,7 +233,7 @@ describe('Ajv', function () {
});
it('should return compiled schema by id or ref', function() {
ajv.addSchema({ id: '//e.com/int.json', type: 'integer' });
ajv.addSchema({ $id: '//e.com/int.json', type: 'integer' });
var validate = ajv.getSchema('//e.com/int.json');
validate(1) .should.equal(true);
validate('1') .should.equal(false);
@ -252,7 +252,7 @@ describe('Ajv', function () {
it('should return schema fragment by ref', function() {
ajv.addSchema({
"id": "http://e.com/types.json",
"$id": "http://e.com/types.json",
"definitions": {
"int": { "type": "integer" },
"str": { "type": "string" }
@ -266,7 +266,7 @@ describe('Ajv', function () {
it('should return schema fragment by ref with protocol-relative URIs', function() {
ajv.addSchema({
"id": "//e.com/types.json",
"$id": "//e.com/types.json",
"definitions": {
"int": { "type": "integer" },
"str": { "type": "string" }
@ -280,10 +280,10 @@ describe('Ajv', function () {
it('should return schema fragment by id', function() {
ajv.addSchema({
"id": "http://e.com/types.json",
"$id": "http://e.com/types.json",
"definitions": {
"int": { "id": "#int", "type": "integer" },
"str": { "id": "#str", "type": "string" }
"int": { "$id": "#int", "type": "integer" },
"str": { "$id": "#str", "type": "string" }
}
});
@ -310,7 +310,7 @@ describe('Ajv', function () {
});
it('should remove schema by id', function() {
var schema = { id: '//e.com/int.json', type: 'integer' }
var schema = { $id: '//e.com/int.json', type: 'integer' }
, str = stableStringify(schema);
ajv.addSchema(schema);
@ -333,11 +333,11 @@ describe('Ajv', function () {
});
it('should remove schema with id by schema object', function() {
var schema = { id: '//e.com/int.json', type: 'integer' }
var schema = { $id: '//e.com/int.json', type: 'integer' }
, str = stableStringify(schema);
ajv.addSchema(schema);
ajv._cache.get(str) .should.be.an('object');
ajv.removeSchema({ id: '//e.com/int.json', type: 'integer' });
ajv.removeSchema({ $id: '//e.com/int.json', type: 'integer' });
// should.not.exist(ajv.getSchema('//e.com/int.json'));
should.not.exist(ajv._cache.get(str));
});
@ -350,7 +350,7 @@ describe('Ajv', function () {
});
it('should remove all schemas but meta-schemas if called without an arguments', function() {
var schema1 = { id: '//e.com/int.json', type: 'integer' }
var schema1 = { $id: '//e.com/int.json', type: 'integer' }
, str1 = stableStringify(schema1);
ajv.addSchema(schema1);
ajv._cache.get(str1) .should.be.an('object');
@ -366,12 +366,12 @@ describe('Ajv', function () {
});
it('should remove all schemas but meta-schemas with key/id matching pattern', function() {
var schema1 = { id: '//e.com/int.json', type: 'integer' }
var schema1 = { $id: '//e.com/int.json', type: 'integer' }
, str1 = stableStringify(schema1);
ajv.addSchema(schema1);
ajv._cache.get(str1) .should.be.an('object');
var schema2 = { id: 'str.json', type: 'string' }
var schema2 = { $id: 'str.json', type: 'string' }
, str2 = stableStringify(schema2);
ajv.addSchema(schema2, '//e.com/str.json');
ajv._cache.get(str2) .should.be.an('object');
@ -476,7 +476,7 @@ describe('Ajv', function () {
describe('validateSchema method', function() {
it('should validate schema against meta-schema', function() {
var valid = ajv.validateSchema({
$schema: 'http://json-schema.org/draft-06/schema#',
$schema: 'http://json-schema.org/draft-07/schema#',
type: 'number'
});
@ -484,7 +484,7 @@ describe('Ajv', function () {
should.equal(ajv.errors, null);
valid = ajv.validateSchema({
$schema: 'http://json-schema.org/draft-06/schema#',
$schema: 'http://json-schema.org/draft-07/schema#',
type: 'wrong_type'
});

View File

@ -2,95 +2,31 @@
var Ajv = require('./ajv')
, util = require('../lib/compile/util')
, setupAsync = require('ajv-async');
, setupAsync = require('./ajv-async');
module.exports = getAjvInstances;
var firstTime = true;
var isBrowser = typeof window == 'object';
var fullTest = isBrowser || !process.env.AJV_FAST_TEST;
function getAjvInstances(opts) {
opts = opts || {};
var instances = [];
var options = [
{},
{ async: true },
{ async: 'co*' },
{ async: 'es7' },
{ async: 'es7', transpile: 'nodent' },
{ async: 'co*', allErrors: true },
{ async: 'es7', allErrors: true },
{ async: 'es7', transpile: 'nodent', allErrors: true }
{ transpile: true },
{ allErrors: true },
{ transpile: true, allErrors: true }
];
var ua;
try { ua = window.navigator.userAgent.toLowerCase(); } catch(e) {}
// regenerator does not work in IE9
if (!(ua && /msie\s9/.test(ua))) {
options = options.concat([
{ async: '*', transpile: 'regenerator' },
{ async: '*', transpile: 'regenerator', allErrors: true }
]);
}
if (fullTest) {
options = options.concat([
{ async: '*' },
{ allErrors: true },
{ async: true, allErrors: true },
{ async: '*', allErrors: true }
]);
if (!(ua && /msie\s9/.test(ua))) {
options = options.concat([
{ async: 'co*', transpile: 'regenerator' },
{ async: 'co*', transpile: 'regenerator', allErrors: true }
]);
}
// es7 functions transpiled with regenerator are excluded from test in Safari/Firefox/Edge/IE9.
// They fail in IE9 and emit multiple 'uncaught exception' warnings in Safari/Firefox/Edge anc cause remote tests to disconnect.
if (!(ua && ((/safari/.test(ua) && !/chrome|phantomjs/.test(ua)) || /firefox|edge|msie\s9/.test(ua)))) {
options = options.concat([
{ transpile: 'regenerator' },
{ async: true, transpile: 'regenerator' },
{ async: 'es7', transpile: 'regenerator' },
{ transpile: 'regenerator', allErrors: true },
{ async: true, transpile: 'regenerator', allErrors: true },
{ async: 'es7', transpile: 'regenerator', allErrors: true }
]);
}
}
// options = options.filter(function (_opts) {
// return _opts.transpile == 'nodent';
// });
// var i = 10, repeatOptions = [];
// while (i--) repeatOptions = repeatOptions.concat(options);
// options = repeatOptions;
options.forEach(function (_opts) {
util.copy(opts, _opts);
var ajv = getAjv(_opts);
if (ajv) instances.push(ajv);
});
if (firstTime) {
var asyncModes = [];
instances.forEach(function (ajv) {
if (!ajv._opts.async) return;
var t = ajv._opts.transpile;
var mode = ajv._opts.async + (t === true ? '' : '.' + t);
if (asyncModes.indexOf(mode) == -1) asyncModes.push(mode);
});
console.log('Testing', instances.length, 'ajv instances:', asyncModes.join(','));
console.log('Testing', instances.length, 'ajv instances:');
firstTime = false;
}

View File

@ -10,50 +10,50 @@ describe('compileAsync method', function() {
var SCHEMAS = {
"http://example.com/object.json": {
"id": "http://example.com/object.json",
"$id": "http://example.com/object.json",
"properties": {
"a": { "type": "string" },
"b": { "$ref": "int2plus.json" }
}
},
"http://example.com/int2plus.json": {
"id": "http://example.com/int2plus.json",
"$id": "http://example.com/int2plus.json",
"type": "integer",
"minimum": 2
},
"http://example.com/tree.json": {
"id": "http://example.com/tree.json",
"$id": "http://example.com/tree.json",
"type": "array",
"items": { "$ref": "leaf.json" }
},
"http://example.com/leaf.json": {
"id": "http://example.com/leaf.json",
"$id": "http://example.com/leaf.json",
"properties": {
"name": { "type": "string" },
"subtree": { "$ref": "tree.json" }
}
},
"http://example.com/recursive.json": {
"id": "http://example.com/recursive.json",
"$id": "http://example.com/recursive.json",
"properties": {
"b": { "$ref": "parent.json" }
},
"required": ["b"]
},
"http://example.com/invalid.json": {
"id": "http://example.com/recursive.json",
"$id": "http://example.com/recursive.json",
"properties": {
"invalid": { "type": "number" }
},
"required": "invalid"
},
"http://example.com/foobar.json": {
"id": "http://example.com/foobar.json",
"$id": "http://example.com/foobar.json",
"$schema": "http://example.com/foobar_meta.json",
"myFooBar": "foo"
},
"http://example.com/foobar_meta.json": {
"id": "http://example.com/foobar_meta.json",
"$id": "http://example.com/foobar_meta.json",
"type": "object",
"properties": {
"myFooBar": {
@ -71,7 +71,7 @@ describe('compileAsync method', function() {
it('should compile schemas loading missing schemas with options.loadSchema function', function() {
var schema = {
"id": "http://example.com/parent.json",
"$id": "http://example.com/parent.json",
"properties": {
"a": { "$ref": "object.json" }
}
@ -87,7 +87,7 @@ describe('compileAsync method', function() {
it('should compile schemas loading missing schemas and return function via callback', function (done) {
var schema = {
"id": "http://example.com/parent.json",
"$id": "http://example.com/parent.json",
"properties": {
"a": { "$ref": "object.json" }
}
@ -105,7 +105,7 @@ describe('compileAsync method', function() {
it('should correctly load schemas when missing reference has JSON path', function() {
var schema = {
"id": "http://example.com/parent.json",
"$id": "http://example.com/parent.json",
"properties": {
"a": { "$ref": "object.json#/properties/b" }
}
@ -121,7 +121,7 @@ describe('compileAsync method', function() {
it('should correctly compile with remote schemas that have mutual references', function() {
var schema = {
"id": "http://example.com/root.json",
"$id": "http://example.com/root.json",
"properties": {
"tree": { "$ref": "tree.json" }
}
@ -143,7 +143,7 @@ describe('compileAsync method', function() {
it('should correctly compile with remote schemas that reference the compiled schema', function() {
var schema = {
"id": "http://example.com/parent.json",
"$id": "http://example.com/parent.json",
"properties": {
"a": { "$ref": "recursive.json" }
}
@ -161,7 +161,7 @@ describe('compileAsync method', function() {
it('should resolve reference containing "properties" segment with the same property (issue #220)', function() {
var schema = {
"id": "http://example.com/parent.json",
"$id": "http://example.com/parent.json",
"properties": {
"a": {
"$ref": "object.json#/properties/a"
@ -206,7 +206,7 @@ describe('compileAsync method', function() {
it('should return compiled schema on the next tick if there are no references (#51)', function() {
var schema = {
"id": "http://example.com/int2plus.json",
"$id": "http://example.com/int2plus.json",
"type": "integer",
"minimum": 2
};
@ -238,7 +238,7 @@ describe('compileAsync method', function() {
it('should queue calls so only one compileAsync executes at a time (#52)', function() {
var schema = {
"id": "http://example.com/parent.json",
"$id": "http://example.com/parent.json",
"properties": {
"a": { "$ref": "object.json" }
}
@ -261,7 +261,7 @@ describe('compileAsync method', function() {
it('should throw exception if loadSchema is not passed', function (done) {
var schema = {
"id": "http://example.com/int2plus.json",
"$id": "http://example.com/int2plus.json",
"type": "integer",
"minimum": 2
};
@ -281,7 +281,7 @@ describe('compileAsync method', function() {
describe('should return error via callback', function() {
it('if passed schema is invalid', function (done) {
var invalidSchema = {
"id": "http://example.com/int2plus.json",
"$id": "http://example.com/int2plus.json",
"type": "integer",
"minimum": "invalid"
};
@ -290,7 +290,7 @@ describe('compileAsync method', function() {
it('if loaded schema is invalid', function (done) {
var schema = {
"id": "http://example.com/parent.json",
"$id": "http://example.com/parent.json",
"properties": {
"a": { "$ref": "invalid.json" }
}
@ -300,7 +300,7 @@ describe('compileAsync method', function() {
it('if required schema is loaded but the reference cannot be resolved', function (done) {
var schema = {
"id": "http://example.com/parent.json",
"$id": "http://example.com/parent.json",
"properties": {
"a": { "$ref": "object.json#/definitions/not_found" }
}
@ -310,7 +310,7 @@ describe('compileAsync method', function() {
it('if loadSchema returned error', function (done) {
var schema = {
"id": "http://example.com/parent.json",
"$id": "http://example.com/parent.json",
"properties": {
"a": { "$ref": "object.json" }
}
@ -346,7 +346,7 @@ describe('compileAsync method', function() {
describe('should return error via promise', function() {
it('if passed schema is invalid', function() {
var invalidSchema = {
"id": "http://example.com/int2plus.json",
"$id": "http://example.com/int2plus.json",
"type": "integer",
"minimum": "invalid"
};
@ -355,7 +355,7 @@ describe('compileAsync method', function() {
it('if loaded schema is invalid', function() {
var schema = {
"id": "http://example.com/parent.json",
"$id": "http://example.com/parent.json",
"properties": {
"a": { "$ref": "invalid.json" }
}
@ -365,7 +365,7 @@ describe('compileAsync method', function() {
it('if required schema is loaded but the reference cannot be resolved', function() {
var schema = {
"id": "http://example.com/parent.json",
"$id": "http://example.com/parent.json",
"properties": {
"a": { "$ref": "object.json#/definitions/not_found" }
}
@ -375,7 +375,7 @@ describe('compileAsync method', function() {
it('if loadSchema returned error', function() {
var schema = {
"id": "http://example.com/parent.json",
"$id": "http://example.com/parent.json",
"properties": {
"a": { "$ref": "object.json" }
}

View File

@ -3,9 +3,7 @@
var Ajv = require('./ajv')
, Promise = require('./promise')
, getAjvInstances = require('./ajv_async_instances')
, should = require('./chai').should()
, co = require('co')
, setupAsync = require('ajv-async');
, should = require('./chai').should();
describe('async schemas, formats and keywords', function() {
@ -17,12 +15,6 @@ describe('async schemas, formats and keywords', function() {
ajv = instances[0];
});
function useCo(_ajv) {
var async = _ajv._opts.async;
return async == 'es7' || async == 'co*' ? identity : co;
}
function identity(x) { return x; }
describe('async schemas without async elements', function() {
it('should return result as promise', function() {
@ -36,12 +28,11 @@ describe('async schemas, formats and keywords', function() {
function test(_ajv) {
var validate = _ajv.compile(schema);
var _co = useCo(_ajv);
return Promise.all([
shouldBeValid( _co(validate('abc')), 'abc' ),
shouldBeInvalid( _co(validate('abcd')) ),
shouldBeInvalid( _co(validate(1)) ),
shouldBeValid( validate('abc'), 'abc' ),
shouldBeInvalid( validate('abcd') ),
shouldBeInvalid( validate(1) ),
]);
}
});
@ -149,11 +140,10 @@ describe('async schemas, formats and keywords', function() {
};
var validate = _ajv.compile(schema);
var _co = useCo(_ajv);
return Promise.all([
shouldBeInvalid(_co(validate({ userId: 5, postId: 10 })), [ 'id not found in table posts' ]),
shouldBeInvalid(_co(validate({ userId: 9, postId: 25 })), [ 'id not found in table users' ])
shouldBeInvalid( validate({ userId: 5, postId: 10 }), [ 'id not found in table posts' ] ),
shouldBeInvalid( validate({ userId: 9, postId: 25 }), [ 'id not found in table users' ] )
]);
}));
});
@ -214,14 +204,13 @@ describe('async schemas, formats and keywords', function() {
return repeat(function() { return Promise.all(instances.map(function (_ajv) {
var validate = _ajv.compile(schema);
var _co = useCo(_ajv);
var validData = { word: 'tomorrow' };
return Promise.all([
shouldBeValid( _co(validate(validData)), validData ),
shouldBeInvalid( _co(validate({ word: 'manana' })) ),
shouldBeInvalid( _co(validate({ word: 1 })) ),
shouldThrow( _co(validate({ word: 'today' })), 'unknown word' )
shouldBeValid( validate(validData), validData ),
shouldBeInvalid( validate({ word: 'manana' }) ),
shouldBeInvalid( validate({ word: 1 }) ),
shouldThrow( validate({ word: 'today' }), 'unknown word' )
]);
})); });
});
@ -250,7 +239,7 @@ describe('async schemas, formats and keywords', function() {
return recursiveTest(schema);
});
it.skip('should validate recursive ref to async sub-schema, issue #612', function() {
it('should validate recursive ref to async sub-schema, issue #612', function() {
var schema = {
$async: true,
type: 'object',
@ -302,7 +291,7 @@ describe('async schemas, formats and keywords', function() {
it('should validate refs between two async schemas', function() {
var schemaObj = {
id: 'http://e.com/obj.json#',
$id: 'http://e.com/obj.json#',
$async: true,
type: 'object',
properties: {
@ -311,7 +300,7 @@ describe('async schemas, formats and keywords', function() {
};
var schemaWord = {
id: 'http://e.com/word.json#',
$id: 'http://e.com/word.json#',
$async: true,
anyOf: [
{
@ -327,7 +316,7 @@ describe('async schemas, formats and keywords', function() {
it('should fail compilation if sync schema references async schema', function() {
var schema = {
id: 'http://e.com/obj.json#',
$id: 'http://e.com/obj.json#',
type: 'object',
properties: {
foo: { $ref: 'http://e.com/word.json#' }
@ -335,7 +324,7 @@ describe('async schemas, formats and keywords', function() {
};
var schemaWord = {
id: 'http://e.com/word.json#',
$id: 'http://e.com/word.json#',
$async: true,
anyOf: [
{
@ -356,7 +345,7 @@ describe('async schemas, formats and keywords', function() {
ajv.compile(schema);
});
schema.id = 'http://e.com/obj2.json#';
schema.$id = 'http://e.com/obj2.json#';
schema.$async = true;
ajv.compile(schema);
@ -366,22 +355,21 @@ describe('async schemas, formats and keywords', function() {
return repeat(function() { return Promise.all(instances.map(function (_ajv) {
if (refSchema) try { _ajv.addSchema(refSchema); } catch(e) {}
var validate = _ajv.compile(schema);
var _co = useCo(_ajv);
var data;
return Promise.all([
shouldBeValid( _co(validate(data = { foo: 'tomorrow' })), data ),
shouldBeInvalid( _co(validate({ foo: 'manana' })) ),
shouldBeInvalid( _co(validate({ foo: 1 })) ),
shouldThrow( _co(validate({ foo: 'today' })), 'unknown word' ),
shouldBeValid( _co(validate(data = { foo: { foo: 'tomorrow' }})), data ),
shouldBeInvalid( _co(validate({ foo: { foo: 'manana' }})) ),
shouldBeInvalid( _co(validate({ foo: { foo: 1 }})) ),
shouldThrow( _co(validate({ foo: { foo: 'today' }})), 'unknown word' ),
shouldBeValid( _co(validate(data = { foo: { foo: { foo: 'tomorrow' }}})), data ),
shouldBeInvalid( _co(validate({ foo: { foo: { foo: 'manana' }}})) ),
shouldBeInvalid( _co(validate({ foo: { foo: { foo: 1 }}})) ),
shouldThrow( _co(validate({ foo: { foo: { foo: 'today' }}})), 'unknown word' )
shouldBeValid( validate(data = { foo: 'tomorrow' }), data ),
shouldBeInvalid( validate({ foo: 'manana' }) ),
shouldBeInvalid( validate({ foo: 1 }) ),
shouldThrow( validate({ foo: 'today' }), 'unknown word' ),
shouldBeValid( validate(data = { foo: { foo: 'tomorrow' }}), data ),
shouldBeInvalid( validate({ foo: { foo: 'manana' }}) ),
shouldBeInvalid( validate({ foo: { foo: 1 }}) ),
shouldThrow( validate({ foo: { foo: 'today' }}), 'unknown word' ),
shouldBeValid( validate(data = { foo: { foo: { foo: 'tomorrow' }}}), data ),
shouldBeInvalid( validate({ foo: { foo: { foo: 'manana' }}}) ),
shouldBeInvalid( validate({ foo: { foo: { foo: 1 }}}) ),
shouldThrow( validate({ foo: { foo: { foo: 'today' }}}), 'unknown word' )
]);
})); });
}
@ -399,35 +387,6 @@ describe('async schemas, formats and keywords', function() {
});
describe('async/transpile option', function() {
it('should throw error with unknown async option', function() {
shouldThrowFunc('bad async mode: es8', function() {
setupAsync(new Ajv({ async: 'es8' }));
});
});
it('should throw error with unknown transpile option', function() {
shouldThrowFunc('bad transpiler: babel', function() {
setupAsync(new Ajv({ transpile: 'babel' }));
});
shouldThrowFunc('bad transpiler: [object Object]', function() {
setupAsync(new Ajv({ transpile: {} }));
});
});
it('should set async option to es7 if tranpiler is nodent', function() {
var ajv1 = setupAsync(new Ajv({ transpile: 'nodent' }));
ajv1._opts.async .should.equal('es7');
var ajv2 = setupAsync(new Ajv({ async: '*', transpile: 'nodent' }));
ajv2._opts.async .should.equal('es7');
});
});
function checkWordOnServer(str) {
return str == 'tomorrow' ? Promise.resolve(true)
: str == 'manana' ? Promise.resolve(false)

View File

@ -2,6 +2,8 @@
module.exports = function (suite) {
suite.forEach(function (file) {
if (file.name.indexOf('optional/format') == 0)
file.name = file.name.replace('optional/', '');
file.test = file.module;
});
return suite;

View File

@ -365,10 +365,10 @@ describe('Type coercion', function () {
};
var schemaRecursive2 = {
id: 'http://e.com/schema.json#',
$id: 'http://e.com/schema.json#',
definitions: {
foo: {
id: 'http://e.com/foo.json#',
$id: 'http://e.com/foo.json#',
type: [ 'object', 'number' ],
properties: {
foo: { $ref: '#' }
@ -416,6 +416,39 @@ describe('Type coercion', function () {
});
it('should check "uniqueItems" after coercion', function() {
var schema = {
items: {type: 'number'},
uniqueItems: true
};
instances.forEach(function (_ajv) {
var validate = _ajv.compile(schema);
validate([1, '2', 3]). should.equal(true);
validate([1, '2', 2]). should.equal(false);
validate.errors.length .should.equal(1);
validate.errors[0].keyword .should.equal('uniqueItems');
});
});
it('should check "contains" after coercion', function() {
var schema = {
items: {type: 'number'},
contains: {const: 2}
};
instances.forEach(function (_ajv) {
var validate = _ajv.compile(schema);
validate([1, '2', 3]). should.equal(true);
validate([1, '3', 4]). should.equal(false);
validate.errors.pop().keyword .should.equal('contains');
});
});
function testRules(rules, cb) {
for (var toType in rules) {
for (var fromType in rules[toType]) {

View File

@ -410,7 +410,7 @@ describe('Validation errors', function () {
it('"items" errors should include item index without quotes in dataPath (#48)', function() {
var schema1 = {
id: 'schema1',
$id: 'schema1',
type: 'array',
items: {
type: 'integer',
@ -445,7 +445,7 @@ describe('Validation errors', function () {
shouldBeError(fullValidate.errors[1], 'minimum', '#/items/minimum', '/3', 'should be >= 10');
var schema2 = {
id: 'schema2',
$id: 'schema2',
type: 'array',
items: [{ minimum: 10 }, { minimum: 9 }, { minimum: 12 }]
};
@ -539,6 +539,39 @@ describe('Validation errors', function () {
validate(1.5) .should.equal(true);
}
});
it('should return passing schemas in error params', function() {
var schema = {
oneOf: [
{ type: 'number' },
{ type: 'integer' },
{ const: 1.5 }
]
};
test(ajv);
test(fullAjv);
function test(_ajv) {
var validate = _ajv.compile(schema);
validate(1) .should.equal(false);
var err = validate.errors.pop();
err.keyword .should.equal('oneOf');
err.params .should.eql({passingSchemas: [0, 1]});
validate(1.5) .should.equal(false);
err = validate.errors.pop();
err.keyword .should.equal('oneOf');
err.params .should.eql({passingSchemas: [0, 2]});
validate(2.5) .should.equal(true);
validate('foo') .should.equal(false);
err = validate.errors.pop();
err.keyword .should.equal('oneOf');
err.params .should.eql({passingSchemas: null});
}
});
});
@ -674,6 +707,112 @@ describe('Validation errors', function () {
});
describe('if/then/else errors', function() {
var validate, numErrors;
it('if/then/else should include failing keyword in message and params', function() {
var schema = {
'if': { maximum: 10 },
'then': { multipleOf: 2 },
'else': { multipleOf: 5 }
};
[ajv, fullAjv].forEach(function (_ajv) {
prepareTest(_ajv, schema);
shouldBeValid(validate, 8);
shouldBeValid(validate, 15);
shouldBeInvalid(validate, 7, numErrors);
testIfError('then', 2);
shouldBeInvalid(validate, 17, numErrors);
testIfError('else', 5);
});
});
it('if/then should include failing keyword in message and params', function() {
var schema = {
'if': { maximum: 10 },
'then': { multipleOf: 2 }
};
[ajv, fullAjv].forEach(function (_ajv) {
prepareTest(_ajv, schema);
shouldBeValid(validate, 8);
shouldBeValid(validate, 11);
shouldBeValid(validate, 12);
shouldBeInvalid(validate, 7, numErrors);
testIfError('then', 2);
});
});
it('if/else should include failing keyword in message and params', function() {
var schema = {
'if': { maximum: 10 },
'else': { multipleOf: 5 }
};
[ajv, fullAjv].forEach(function (_ajv) {
prepareTest(_ajv, schema);
shouldBeValid(validate, 7);
shouldBeValid(validate, 8);
shouldBeValid(validate, 15);
shouldBeInvalid(validate, 17, numErrors);
testIfError('else', 5);
});
});
function prepareTest(_ajv, schema) {
validate = _ajv.compile(schema);
numErrors = _ajv._opts.allErrors ? 2 : 1;
}
function testIfError(ifClause, multipleOf) {
var err = validate.errors[0];
shouldBeError(err, 'multipleOf', '#/' + ifClause + '/multipleOf', '',
'should be multiple of ' + multipleOf, {multipleOf: multipleOf});
if (numErrors == 2) {
err = validate.errors[1];
shouldBeError(err, 'if', '#/if', '',
'should match "' + ifClause + '" schema', {failingKeyword: ifClause});
}
}
});
describe('uniqueItems errors', function() {
it('should not return uniqueItems error when non-unique items are of a different type than required', function() {
var schema = {
items: {type: 'number'},
uniqueItems: true
};
[ajvJP, fullAjv].forEach(function (_ajv) {
var validate = _ajv.compile(schema);
shouldBeValid(validate, [1, 2, 3]);
shouldBeInvalid(validate, [1, 2, 2]);
shouldBeError(validate.errors[0], 'uniqueItems', '#/uniqueItems', '',
'should NOT have duplicate items (items ## 2 and 1 are identical)',
{i: 1, j: 2});
var expectedErrors = _ajv._opts.allErrors ? 2 : 1;
shouldBeInvalid(validate, [1, "2", "2", 2], expectedErrors);
testTypeError(0, '/1');
if (expectedErrors == 2) testTypeError(1, '/2');
function testTypeError(i, dataPath) {
var err = validate.errors[i];
shouldBeError(err, 'type', '#/items/type', dataPath, 'should be number');
}
});
});
});
function testSchema1(schema, schemaPathPrefix) {
_testSchema1(ajv, schema, schemaPathPrefix);
_testSchema1(ajvJP, schema, schemaPathPrefix);

View File

@ -8,7 +8,6 @@ var jsonSchemaTest = require('json-schema-test')
var instances = getAjvInstances(options, {
$data: true,
patternGroups: true,
unknownFormats: ['allowedUnknown']
});

View File

@ -1,271 +0,0 @@
[
{
"description": "patternGroups validates properties matching a regex (equivalent to the test from draft 4)",
"schema": {
"patternGroups": {
"f.*o": {
"schema": {"type": "integer"}
}
}
},
"tests": [
{
"description": "a single valid match is valid",
"data": {"foo": 1},
"valid": true
},
{
"description": "multiple valid matches is valid",
"data": {"foo": 1, "foooooo" : 2},
"valid": true
},
{
"description": "a single invalid match is invalid",
"data": {"foo": "bar", "fooooo": 2},
"valid": false
},
{
"description": "multiple invalid matches is invalid",
"data": {"foo": "bar", "foooooo" : "baz"},
"valid": false
},
{
"description": "ignores non-objects",
"data": 12,
"valid": true
}
]
},
{
"description": "multiple simultaneous patternGroups are validated (equivalent to the test from draft 4)",
"schema": {
"patternGroups": {
"a*": {
"schema": {"type": "integer"}
},
"aaa*": {
"schema": {"maximum": 20}
}
}
},
"tests": [
{
"description": "a single valid match is valid",
"data": {"a": 21},
"valid": true
},
{
"description": "a simultaneous match is valid",
"data": {"aaaa": 18},
"valid": true
},
{
"description": "multiple matches is valid",
"data": {"a": 21, "aaaa": 18},
"valid": true
},
{
"description": "an invalid due to one is invalid",
"data": {"a": "bar"},
"valid": false
},
{
"description": "an invalid due to the other is invalid",
"data": {"aaaa": 31},
"valid": false
},
{
"description": "an invalid due to both is invalid",
"data": {"aaa": "foo", "aaaa": 31},
"valid": false
}
]
},
{
"description": "regexes in patternGroups are not anchored by default and are case sensitive (equivalent to the test from draft 4)",
"schema": {
"patternGroups": {
"[0-9]{2,}": {
"schema": { "type": "boolean" }
},
"X_": {
"schema": { "type": "string" }
}
}
},
"tests": [
{
"description": "non recognized members are ignored",
"data": { "answer 1": "42" },
"valid": true
},
{
"description": "recognized members are accounted for",
"data": { "a31b": null },
"valid": false
},
{
"description": "regexes are case sensitive",
"data": { "a_x_3": 3 },
"valid": true
},
{
"description": "regexes are case sensitive, 2",
"data": { "a_X_3": 3 },
"valid": false
}
]
},
{
"description":
"patternGroups validates that the number of properties matching a regex is within limit",
"schema": {
"patternGroups": {
"f.*o": {
"schema": {"type": "integer"},
"minimum": 1,
"maximum": 2
}
}
},
"tests": [
{
"description": "a single valid match is valid",
"data": {"foo": 1},
"valid": true
},
{
"description": "2 valid matches are valid",
"data": {"foo": 1, "foooo" : 2},
"valid": true
},
{
"description": "no valid matches are invalid",
"data": {},
"valid": false
},
{
"description": "more than 2 valid matches are invalid",
"data": {"foo": 1, "foooo" : 2, "foooooo" : 3},
"valid": false
},
{
"description": "sinlge invalid match is invalid",
"data": {"foo": 1, "foooooo" : "baz"},
"valid": false
}
]
},
{
"description": "multiple simultaneous patternGroups are validated for number of matching properties",
"schema": {
"patternGroups": {
"a*": {
"schema": {"type": "integer"},
"minimum": 1
},
"aaa*": {
"schema": {"maximum": 20},
"maximum": 1
}
}
},
"tests": [
{
"description": "a single first match is valid",
"data": {"a": 21},
"valid": true
},
{
"description": "no first match is invalid",
"data": {},
"valid": false
},
{
"description": "simultaneous match is valid",
"data": {"aaaa": 18},
"valid": true
},
{
"description": "multiple matches is valid",
"data": {"a": 21, "aaaa": 18},
"valid": true
},
{
"description": "two second matches are invalid",
"data": {"aaa": 17, "aaaa": 18},
"valid": false
},
{
"description": "invalid due to the first is invalid",
"data": {"a": "bar"},
"valid": false
},
{
"description": "invalid due to the second is invalid",
"data": {"a": 21, "aaaa": 31},
"valid": false
},
{
"description": "invalid due to both is invalid",
"data": {"a": "foo", "aaaa": 31},
"valid": false
}
]
},
{
"description": "properties, patternGroups, additionalProperties interaction (equivalent to the test from draft 4)",
"schema": {
"properties": {
"foo": {"type": "array", "maxItems": 3},
"bar": {"type": "array"}
},
"patternGroups": {
"f.o": { "schema": {"minItems": 2} }
},
"additionalProperties": {"type": "integer"}
},
"tests": [
{
"description": "property validates property",
"data": {"foo": [1, 2]},
"valid": true
},
{
"description": "property invalidates property",
"data": {"foo": [1, 2, 3, 4]},
"valid": false
},
{
"description": "patternGroups invalidates property",
"data": {"foo": []},
"valid": false
},
{
"description": "patternGroups validates nonproperty",
"data": {"fxo": [1, 2]},
"valid": true
},
{
"description": "patternGroups invalidates nonproperty",
"data": {"fxo": []},
"valid": false
},
{
"description": "additionalProperty ignores property",
"data": {"bar": []},
"valid": true
},
{
"description": "additionalProperty validates others",
"data": {"quux": 3},
"valid": true
},
{
"description": "additionalProperty invalidates others",
"data": {"quux": "foo"},
"valid": false
}
]
}
]

View File

@ -19,7 +19,7 @@ describe('issue #8: schema with shared references', function() {
};
var schema = {
id: 'obj.json#',
$id: 'obj.json#',
type: 'object',
properties: {
foo: propertySchema,
@ -51,7 +51,7 @@ describe('issue #50: references with "definitions"', function () {
var ajv = new Ajv;
ajv[method]({
id: 'http://example.com/test/person.json#',
$id: 'http://example.com/test/person.json#',
definitions: {
name: { type: 'string' }
},
@ -62,7 +62,7 @@ describe('issue #50: references with "definitions"', function () {
});
ajv[method]({
id: 'http://example.com/test/employee.json#',
$id: 'http://example.com/test/employee.json#',
type: 'object',
properties: {
person: { $ref: '/test/person.json#' },
@ -109,7 +109,7 @@ describe('issue #182, NaN validation', function() {
describe('issue #204, options schemas and $data used together', function() {
it('should use v5 metaschemas by default', function() {
var ajv = new Ajv({
schemas: [{id: 'str', type: 'string'}],
schemas: [{$id: 'str', type: 'string'}],
$data: true
});
@ -184,7 +184,7 @@ describe('issue #210, mutual recursive $refs that are schema fragments', functio
var ajv = new Ajv;
ajv.addSchema({
"id" : "foo",
"$id" : "foo",
"definitions": {
"bar": {
"properties": {
@ -200,7 +200,7 @@ describe('issue #210, mutual recursive $refs that are schema fragments', functio
});
ajv.addSchema({
"id" : "boo",
"$id" : "boo",
"type": "object",
"required": ["quux"],
"properties": {
@ -218,7 +218,7 @@ describe('issue #210, mutual recursive $refs that are schema fragments', functio
var ajv = new Ajv;
ajv.addSchema({
"id" : "foo",
"$id" : "foo",
"definitions": {
"bar": {
"properties": {
@ -234,7 +234,7 @@ describe('issue #210, mutual recursive $refs that are schema fragments', functio
});
ajv.addSchema({
"id" : "boo",
"$id" : "boo",
"definitions": {
"buu": {
"type": "object",
@ -256,16 +256,16 @@ describe('issue #210, mutual recursive $refs that are schema fragments', functio
describe('issue #240, mutually recursive fragment refs reference a common schema', function() {
var apiSchema = {
$schema: 'http://json-schema.org/draft-06/schema#',
id: 'schema://api.schema#',
$schema: 'http://json-schema.org/draft-07/schema#',
$id: 'schema://api.schema#',
resource: {
id: '#resource',
$id: '#resource',
properties: {
id: { type: 'string' }
}
},
resourceIdentifier: {
id: '#resource_identifier',
$id: '#resource_identifier',
properties: {
id: { type: 'string' },
type: { type: 'string' }
@ -274,8 +274,8 @@ describe('issue #240, mutually recursive fragment refs reference a common schema
};
var domainSchema = {
$schema: 'http://json-schema.org/draft-06/schema#',
id: 'schema://domain.schema#',
$schema: 'http://json-schema.org/draft-07/schema#',
$id: 'schema://domain.schema#',
properties: {
data: {
oneOf: [
@ -290,8 +290,8 @@ describe('issue #240, mutually recursive fragment refs reference a common schema
var ajv = new Ajv;
var librarySchema = {
$schema: 'http://json-schema.org/draft-06/schema#',
id: 'schema://library.schema#',
$schema: 'http://json-schema.org/draft-07/schema#',
$id: 'schema://library.schema#',
properties: {
name: { type: 'string' },
links: {
@ -305,7 +305,7 @@ describe('issue #240, mutually recursive fragment refs reference a common schema
},
definitions: {
resource_identifier: {
id: '#resource_identifier',
$id: '#resource_identifier',
allOf: [
{
properties: {
@ -322,8 +322,8 @@ describe('issue #240, mutually recursive fragment refs reference a common schema
};
var catalogItemSchema = {
$schema: 'http://json-schema.org/draft-06/schema#',
id: 'schema://catalog_item.schema#',
$schema: 'http://json-schema.org/draft-07/schema#',
$id: 'schema://catalog_item.schema#',
properties: {
name: { type: 'string' },
links: {
@ -334,7 +334,7 @@ describe('issue #240, mutually recursive fragment refs reference a common schema
},
definitions: {
resource_identifier: {
id: '#resource_identifier',
$id: '#resource_identifier',
allOf: [
{
properties: {
@ -351,8 +351,8 @@ describe('issue #240, mutually recursive fragment refs reference a common schema
};
var catalogItemResourceIdentifierSchema = {
$schema: 'http://json-schema.org/draft-06/schema#',
id: 'schema://catalog_item_resource_identifier.schema#',
$schema: 'http://json-schema.org/draft-07/schema#',
$id: 'schema://catalog_item_resource_identifier.schema#',
allOf: [
{
properties: {
@ -381,8 +381,8 @@ describe('issue #240, mutually recursive fragment refs reference a common schema
var ajv = new Ajv;
var librarySchema = {
$schema: 'http://json-schema.org/draft-06/schema#',
id: 'schema://library.schema#',
$schema: 'http://json-schema.org/draft-07/schema#',
$id: 'schema://library.schema#',
properties: {
name: { type: 'string' },
links: {
@ -396,7 +396,7 @@ describe('issue #240, mutually recursive fragment refs reference a common schema
},
definitions: {
resource_identifier: {
id: '#resource_identifier',
$id: '#resource_identifier',
allOf: [
{
properties: {
@ -413,8 +413,8 @@ describe('issue #240, mutually recursive fragment refs reference a common schema
};
var catalogItemSchema = {
$schema: 'http://json-schema.org/draft-06/schema#',
id: 'schema://catalog_item.schema#',
$schema: 'http://json-schema.org/draft-07/schema#',
$id: 'schema://catalog_item.schema#',
properties: {
name: { type: 'string' },
links: {
@ -425,7 +425,7 @@ describe('issue #240, mutually recursive fragment refs reference a common schema
},
definitions: {
resource_identifier: {
id: '#resource_identifier',
$id: '#resource_identifier',
allOf: [
{
properties: {
@ -463,7 +463,6 @@ describe('issue #240, mutually recursive fragment refs reference a common schema
describe('issue #259, support validating [meta-]schemas against themselves', function() {
it('should add schema before validation if "id" is the same as "$schema"', function() {
var ajv = new Ajv;
ajv.addMetaSchema(require('../lib/refs/json-schema-draft-04.json'));
var hyperSchema = require('./remotes/hyper-schema.json');
ajv.addMetaSchema(hyperSchema);
});
@ -625,3 +624,45 @@ describe('issue #533, throwing missing ref exception with option missingRefs: "i
});
});
});
describe('full date format validation should understand leap years', function () {
it('should handle non leap year affected dates with date-time', function() {
var ajv = new Ajv({ format: 'full' });
var schema = { format: 'date-time' };
var validDateTime = '2016-01-31T00:00:00Z';
ajv.validate(schema, validDateTime).should.equal(true);
});
it('should handle non leap year affected dates with date', function () {
var ajv = new Ajv({ format: 'full' });
var schema = { format: 'date' };
var validDate = '2016-11-30';
ajv.validate(schema, validDate).should.equal(true);
});
it('should handle year leaps as date-time', function() {
var ajv = new Ajv({ format: 'full' });
var schema = { format: 'date-time' };
var validDateTime = '2016-02-29T00:00:00Z';
var invalidDateTime = '2017-02-29T00:00:00Z';
ajv.validate(schema, validDateTime) .should.equal(true);
ajv.validate(schema, invalidDateTime) .should.equal(false);
});
it('should handle year leaps as date', function() {
var ajv = new Ajv({ format: 'full' });
var schema = { format: 'date' };
var validDate = '2016-02-29';
var invalidDate = '2017-02-29';
ajv.validate(schema, validDate) .should.equal(true);
ajv.validate(schema, invalidDate) .should.equal(false);
});
});

View File

@ -13,41 +13,51 @@ var remoteRefs = {
'http://localhost:1234/name.json': require('./JSON-Schema-Test-Suite/remotes/name.json')
};
runTest(getAjvInstances(options, {meta: false}), 4, typeof window == 'object'
var SKIP = {
4: ['optional/zeroTerminatedFloats'],
7: [
'optional/content',
'format/idn-email',
'format/idn-hostname',
'format/iri',
'format/iri-reference'
]
};
runTest(getAjvInstances(options, {meta: false, schemaId: 'id'}), 4, typeof window == 'object'
? suite(require('./JSON-Schema-Test-Suite/tests/draft4/{**/,}*.json', {mode: 'list'}))
: './JSON-Schema-Test-Suite/tests/draft4/{**/,}*.json');
runTest(getAjvInstances(options, {
format: 'full',
formats: {
'json-pointer': /^(?:\/(?:[^~/]|~0|~1)*)*$/
}
}), 6, typeof window == 'object'
runTest(getAjvInstances(options, {meta: false}), 6, typeof window == 'object'
? suite(require('./JSON-Schema-Test-Suite/tests/draft6/{**/,}*.json', {mode: 'list'}))
: './JSON-Schema-Test-Suite/tests/draft6/{**/,}*.json');
runTest(getAjvInstances(options), 7, typeof window == 'object'
? suite(require('./JSON-Schema-Test-Suite/tests/draft7/{**/,}*.json', {mode: 'list'}))
: './JSON-Schema-Test-Suite/tests/draft7/{**/,}*.json');
function runTest(instances, draft, tests) {
instances.forEach(function (ajv) {
ajv.addMetaSchema(require('../lib/refs/json-schema-draft-04.json'));
if (draft == 4) ajv._opts.defaultMeta = 'http://json-schema.org/draft-04/schema#';
switch (draft) {
case 4:
ajv.addMetaSchema(require('../lib/refs/json-schema-draft-04.json'));
ajv._opts.defaultMeta = 'http://json-schema.org/draft-04/schema#';
break;
case 6:
ajv.addMetaSchema(require('../lib/refs/json-schema-draft-06.json'));
ajv._opts.defaultMeta = 'http://json-schema.org/draft-06/schema#';
break;
}
for (var id in remoteRefs) ajv.addSchema(remoteRefs[id], id);
});
jsonSchemaTest(instances, {
description: 'JSON-Schema Test Suite draft-0' + draft + ': ' + instances.length + ' ajv instances with different options',
suites: {tests: tests},
only: [
// 'type', 'not', 'allOf', 'anyOf', 'oneOf', 'enum',
// 'maximum', 'minimum', 'multipleOf', 'maxLength', 'minLength', 'pattern',
// 'properties', 'patternProperties', 'additionalProperties',
// 'dependencies', 'required',
// 'maxProperties', 'minProperties', 'maxItems', 'minItems',
// 'items', 'additionalItems', 'uniqueItems',
// 'optional/format', 'optional/bignum',
// 'ref', 'refRemote', 'definitions',
],
skip: ['optional/zeroTerminatedFloats'],
only: [],
skip: SKIP[draft],
assert: require('./chai').assert,
afterError: after.error,
afterEach: after.each,

View File

@ -11,7 +11,7 @@ describe('Ajv Options', function () {
var ajv = new Ajv({ removeAdditional: 'all' });
ajv.addSchema({
id: '//test/fooBar',
$id: '//test/fooBar',
properties: { foo: { type: 'string' }, bar: { type: 'string' } }
});
@ -30,7 +30,7 @@ describe('Ajv Options', function () {
var ajv = new Ajv({ removeAdditional: true });
ajv.addSchema({
id: '//test/fooBar',
$id: '//test/fooBar',
properties: { foo: { type: 'string' }, bar: { type: 'string' } },
additionalProperties: false
});
@ -50,7 +50,7 @@ describe('Ajv Options', function () {
var ajv = new Ajv({ removeAdditional: 'failing' });
ajv.addSchema({
id: '//test/fooBar',
$id: '//test/fooBar',
properties: { foo: { type: 'string' }, bar: { type: 'string' } },
additionalProperties: { type: 'string' }
});
@ -66,7 +66,7 @@ describe('Ajv Options', function () {
object.should.not.have.property('fizz');
ajv.addSchema({
id: '//test/fooBar2',
$id: '//test/fooBar2',
properties: { foo: { type: 'string' }, bar: { type: 'string' } },
additionalProperties: { type: 'string', pattern: '^to-be-', maxLength: 10 }
});
@ -222,21 +222,6 @@ describe('Ajv Options', function () {
test(schema, obj, proto);
});
it('should only validate own properties with patternGroups', function() {
ajv = new Ajv({ allErrors: true, patternGroups: true });
ajvOP = new Ajv({ ownProperties: true, allErrors: true, patternGroups: true });
var schema = {
patternGroups: {
'f.*o': { schema: { type: 'integer' } }
}
};
var obj = { fooo: 1 };
var proto = { foo: 'not a number' };
test(schema, obj, proto);
});
it('should only validate own properties with propertyNames', function() {
var schema = {
propertyNames: {
@ -278,7 +263,7 @@ describe('Ajv Options', function () {
testOptionMeta(new Ajv({ meta: true }));
function testOptionMeta(ajv) {
ajv.getSchema('http://json-schema.org/draft-06/schema') .should.be.a('function');
ajv.getSchema('http://json-schema.org/draft-07/schema') .should.be.a('function');
ajv.validateSchema({ type: 'integer' }) .should.equal(true);
ajv.validateSchema({ type: 123 }) .should.equal(false);
should.not.throw(function() { ajv.addSchema({ type: 'integer' }); });
@ -288,7 +273,7 @@ describe('Ajv Options', function () {
it('should throw if meta: false and validateSchema: true', function() {
var ajv = new Ajv({ meta: false });
should.not.exist(ajv.getSchema('http://json-schema.org/draft-06/schema'));
should.not.exist(ajv.getSchema('http://json-schema.org/draft-07/schema'));
should.not.throw(function() { ajv.addSchema({ type: 'wrong_type' }, 'integer'); });
});
@ -327,7 +312,7 @@ describe('Ajv Options', function () {
it('should use option meta as default meta schema', function() {
var meta = {
$schema: 'http://json-schema.org/draft-06/schema',
$schema: 'http://json-schema.org/draft-07/schema',
properties: {
myKeyword: { type: 'boolean' }
}
@ -336,7 +321,7 @@ describe('Ajv Options', function () {
ajv.validateSchema({ myKeyword: true }) .should.equal(true);
ajv.validateSchema({ myKeyword: 2 }) .should.equal(false);
ajv.validateSchema({
$schema: 'http://json-schema.org/draft-06/schema',
$schema: 'http://json-schema.org/draft-07/schema',
myKeyword: 2
}) .should.equal(true);
@ -362,9 +347,9 @@ describe('Ajv Options', function () {
it('should add schemas from array', function() {
var ajv = new Ajv({ schemas: [
{ id: 'int', type: 'integer' },
{ id: 'str', type: 'string' },
{ id: 'obj', properties: { int: { $ref: 'int' }, str: { $ref: 'str' } } }
{ $id: 'int', type: 'integer' },
{ $id: 'str', type: 'string' },
{ $id: 'obj', properties: { int: { $ref: 'int' }, str: { $ref: 'str' } } }
]});
ajv.validate('obj', { int: 123, str: 'foo' }) .should.equal(true);
@ -593,6 +578,37 @@ describe('Ajv Options', function () {
}
});
it('should apply default in "then" subschema (issue #635)', function() {
test(new Ajv({ useDefaults: true }));
test(new Ajv({ useDefaults: true, allErrors: true }));
function test(ajv) {
var schema = {
if: { required: ['foo'] },
then: {
properties: {
bar: { default: 2 }
}
},
else: {
properties: {
foo: { default: 1 }
}
}
};
var validate = ajv.compile(schema);
var data = {};
validate(data) .should.equal(true);
data .should.eql({foo: 1});
data = {foo: 1};
validate(data) .should.equal(true);
data .should.eql({foo: 1, bar: 2});
}
});
describe('useDefaults: by value / by reference', function() {
describe('using by value', function() {
@ -653,26 +669,26 @@ describe('Ajv Options', function () {
describe('compile and validate', function() {
it('should add schema', function() {
var schema = { id: 'str', type: 'string' };
var schema = { $id: 'str', type: 'string' };
var validate = ajv.compile(schema);
validate('abc') .should.equal(true);
validate(1) .should.equal(false);
ajv.getSchema('str') .should.equal(validate);
schema = { id: 'int', type: 'integer' };
schema = { $id: 'int', type: 'integer' };
ajv.validate(schema, 1) .should.equal(true);
ajv.validate(schema, 'abc') .should.equal(false);
ajv.getSchema('int') .should.be.a('function');
});
it('should throw with duplicate ID', function() {
ajv.compile({ id: 'str', type: 'string' });
ajv.compile({ $id: 'str', type: 'string' });
should.throw(function() {
ajv.compile({ id: 'str', minLength: 2 });
ajv.compile({ $id: 'str', minLength: 2 });
});
var schema = { id: 'int', type: 'integer' };
var schema2 = { id: 'int', minimum: 0 };
var schema = { $id: 'int', type: 'integer' };
var schema2 = { $id: 'int', minimum: 0 };
ajv.validate(schema, 1) .should.equal(true);
should.throw(function() {
ajv.validate(schema2, 1);
@ -692,26 +708,26 @@ describe('Ajv Options', function () {
describe('compile and validate', function() {
it('should NOT add schema', function() {
var schema = { id: 'str', type: 'string' };
var schema = { $id: 'str', type: 'string' };
var validate = ajv.compile(schema);
validate('abc') .should.equal(true);
validate(1) .should.equal(false);
should.equal(ajv.getSchema('str'), undefined);
schema = { id: 'int', type: 'integer' };
schema = { $id: 'int', type: 'integer' };
ajv.validate(schema, 1) .should.equal(true);
ajv.validate(schema, 'abc') .should.equal(false);
should.equal(ajv.getSchema('int'), undefined);
});
it('should NOT throw with duplicate ID', function() {
ajv.compile({ id: 'str', type: 'string' });
ajv.compile({ $id: 'str', type: 'string' });
should.not.throw(function() {
ajv.compile({ id: 'str', minLength: 2 });
ajv.compile({ $id: 'str', minLength: 2 });
});
var schema = { id: 'int', type: 'integer' };
var schema2 = { id: 'int', minimum: 0 };
var schema = { $id: 'int', type: 'integer' };
var schema2 = { $id: 'int', minimum: 0 };
ajv.validate(schema, 1) .should.equal(true);
should.not.throw(function() {
ajv.validate(schema2, 1) .should.equal(true);
@ -1117,65 +1133,57 @@ describe('Ajv Options', function () {
});
describe('patternGroups without draft-06 meta-schema', function() {
it('should use default meta-schema', function() {
var ajv = new Ajv({
patternGroups: true,
meta: require('../lib/refs/json-schema-draft-04.json')
});
ajv.compile({
patternGroups: {
'^foo': {
schema: { type: 'number' },
minimum: 1
}
}
});
should.throw(function() {
ajv.compile({
patternGroups: {
'^foo': {
schema: { type: 'wrong_type' },
minimum: 1
}
}
});
});
});
it('should not use meta-schema if not available', function() {
var ajv = new Ajv({
patternGroups: true,
meta: false
});
ajv.compile({
patternGroups: {
'^foo': {
schema: { type: 'number' },
minimum: 1
}
}
});
ajv.compile({
patternGroups: {
'^foo': {
schema: { type: 'wrong_type' },
minimum: 1
}
}
});
});
});
describe('schemaId', function() {
describe('= undefined (default)', function() {
describe('= "$id" (default)', function() {
it('should use $id and ignore id', function() {
test(new Ajv);
test(new Ajv({schemaId: '$id'}));
function test(ajv) {
ajv.addSchema({ $id: 'mySchema1', type: 'string' });
var validate = ajv.getSchema('mySchema1');
validate('foo') .should.equal(true);
validate(1) .should.equal(false);
validate = ajv.compile({ id: 'mySchema2', type: 'string' });
should.not.exist(ajv.getSchema('mySchema2'));
}
});
});
describe('= "id"', function() {
it('should use id and ignore $id', function() {
var ajv = new Ajv({schemaId: 'id', meta: false});
ajv.addMetaSchema(require('ajv/lib/refs/json-schema-draft-04.json'));
ajv._opts.defaultMeta = 'http://json-schema.org/draft-04/schema#';
ajv.addSchema({ id: 'mySchema1', type: 'string' });
var validate = ajv.getSchema('mySchema1');
validate('foo') .should.equal(true);
validate(1) .should.equal(false);
validate = ajv.compile({ $id: 'mySchema2', type: 'string' });
should.not.exist(ajv.getSchema('mySchema2'));
});
});
describe('= "auto"', function() {
it('should use both id and $id', function() {
var ajv = new Ajv({schemaId: 'auto'});
ajv.addSchema({ $id: 'mySchema1', type: 'string' });
var validate = ajv.getSchema('mySchema1');
validate('foo') .should.equal(true);
validate(1) .should.equal(false);
ajv.addSchema({ id: 'mySchema2', type: 'string' });
validate = ajv.getSchema('mySchema2');
validate('foo') .should.equal(true);
validate(1) .should.equal(false);
});
it('should throw if both id and $id are available and different', function() {
var ajv = new Ajv;
var ajv = new Ajv({schemaId: 'auto'});
ajv.compile({
id: 'mySchema',
@ -1190,36 +1198,97 @@ describe('Ajv Options', function () {
});
});
});
});
describe('= "id"', function() {
it('should use id and ignore $id', function() {
var ajv = new Ajv({schemaId: 'id'});
ajv.addSchema({ id: 'mySchema1', type: 'string' });
var validate = ajv.getSchema('mySchema1');
validate('foo') .should.equal(true);
validate(1) .should.equal(false);
describe('$comment', function() {
describe('= true', function() {
var logCalls, consoleLog;
validate = ajv.compile({ $id: 'mySchema2', type: 'string' });
should.not.exist(ajv.getSchema('mySchema2'));
beforeEach(function () {
consoleLog = console.log;
console.log = log;
});
afterEach(function () {
console.log = consoleLog;
});
function log() {
logCalls.push(Array.prototype.slice.call(arguments));
}
it('should log the text from $comment keyword', function() {
var schema = {
properties: {
foo: {$comment: 'property foo'},
bar: {$comment: 'property bar', type: 'integer'}
}
};
var ajv = new Ajv({$comment: true});
var fullAjv = new Ajv({allErrors: true, $comment: true});
[ajv, fullAjv].forEach(function (_ajv) {
var validate = _ajv.compile(schema);
test({}, true, []);
test({foo: 1}, true, [['property foo']]);
test({foo: 1, bar: 2}, true, [['property foo'], ['property bar']]);
test({foo: 1, bar: 'baz'}, false, [['property foo'], ['property bar']]);
function test(data, valid, expectedLogCalls) {
logCalls = [];
validate(data) .should.equal(valid);
logCalls .should.eql(expectedLogCalls);
}
});
console.log = consoleLog;
});
});
describe('= "$id"', function() {
it('should use $id and ignore id', function() {
var ajv = new Ajv({schemaId: '$id'});
describe('function hook', function() {
var hookCalls;
ajv.addSchema({ $id: 'mySchema1', type: 'string' });
var validate = ajv.getSchema('mySchema1');
validate('foo') .should.equal(true);
validate(1) .should.equal(false);
function hook() {
hookCalls.push(Array.prototype.slice.call(arguments));
}
validate = ajv.compile({ id: 'mySchema2', type: 'string' });
should.not.exist(ajv.getSchema('mySchema2'));
it('should pass the text from $comment keyword to the hook', function() {
var schema = {
properties: {
foo: {$comment: 'property foo'},
bar: {$comment: 'property bar', type: 'integer'}
}
};
var ajv = new Ajv({$comment: hook});
var fullAjv = new Ajv({allErrors: true, $comment: hook});
[ajv, fullAjv].forEach(function (_ajv) {
var validate = _ajv.compile(schema);
test({}, true, []);
test({foo: 1}, true, [['property foo', '#/properties/foo/$comment', schema]]);
test({foo: 1, bar: 2}, true,
[['property foo', '#/properties/foo/$comment', schema],
['property bar', '#/properties/bar/$comment', schema]]);
test({foo: 1, bar: 'baz'}, false,
[['property foo', '#/properties/foo/$comment', schema],
['property bar', '#/properties/bar/$comment', schema]]);
function test(data, valid, expectedHookCalls) {
hookCalls = [];
validate(data) .should.equal(valid);
hookCalls .should.eql(expectedHookCalls);
}
});
});
});
});
describe('logger', function() {
/**

View File

@ -1,4 +1,4 @@
{
"id": "http://localhost:1234/bar.json",
"$id": "http://localhost:1234/bar.json",
"type": "string"
}

View File

@ -1,5 +1,5 @@
{
"id": "http://localhost:1234/buu.json",
"$id": "http://localhost:1234/buu.json",
"definitions": {
"buu": {
"type": "object",

View File

@ -1,4 +1,4 @@
{
"id": "http://localhost:1234/first.json",
"$id": "http://localhost:1234/first.json",
"type": "string"
}

View File

@ -1,5 +1,5 @@
{
"id": "http://localhost:1234/foo.json",
"$id": "http://localhost:1234/foo.json",
"type": "object",
"properties": {
"bar": { "$ref": "bar.json" }

View File

@ -1,167 +1,69 @@
{
"$schema": "http://json-schema.org/draft-04/hyper-schema#",
"id": "http://json-schema.org/draft-04/hyper-schema#",
"$schema": "http://json-schema.org/draft-07/hyper-schema#",
"$id": "http://json-schema.org/draft-07/hyper-schema#",
"title": "JSON Hyper-Schema",
"allOf": [
{
"$ref": "http://json-schema.org/draft-04/schema#"
"definitions": {
"schemaArray": {
"allOf": [
{ "$ref": "http://json-schema.org/draft-07/schema#/definitions/schemaArray" },
{
"items": { "$ref": "#" }
}
]
}
],
},
"allOf": [ { "$ref": "http://json-schema.org/draft-07/schema#" } ],
"properties": {
"additionalItems": {
"anyOf": [
{
"type": "boolean"
},
{
"$ref": "#"
}
]
},
"additionalProperties": {
"anyOf": [
{
"type": "boolean"
},
{
"$ref": "#"
}
]
},
"additionalItems": { "$ref": "#" },
"additionalProperties": { "$ref": "#"},
"dependencies": {
"additionalProperties": {
"anyOf": [
{
"$ref": "#"
},
{
"type": "array"
}
{ "$ref": "#" },
{ "type": "array" }
]
}
},
"items": {
"anyOf": [
{
"$ref": "#"
},
{
"$ref": "#/definitions/schemaArray"
}
{ "$ref": "#" },
{ "$ref": "#/definitions/schemaArray" }
]
},
"definitions": {
"additionalProperties": {
"$ref": "#"
}
"additionalProperties": { "$ref": "#" }
},
"patternProperties": {
"additionalProperties": {
"$ref": "#"
}
"additionalProperties": { "$ref": "#" }
},
"properties": {
"additionalProperties": {
"$ref": "#"
}
},
"allOf": {
"$ref": "#/definitions/schemaArray"
},
"anyOf": {
"$ref": "#/definitions/schemaArray"
},
"oneOf": {
"$ref": "#/definitions/schemaArray"
},
"not": {
"$ref": "#"
"additionalProperties": { "$ref": "#" }
},
"if": {"$ref": "#"},
"then": {"$ref": "#"},
"else": {"$ref": "#"},
"allOf": { "$ref": "#/definitions/schemaArray" },
"anyOf": { "$ref": "#/definitions/schemaArray" },
"oneOf": { "$ref": "#/definitions/schemaArray" },
"not": { "$ref": "#" },
"contains": { "$ref": "#" },
"propertyNames": { "$ref": "#" },
"base": {
"type": "string",
"format": "uri-template"
},
"links": {
"type": "array",
"items": {
"$ref": "#/definitions/linkDescription"
}
},
"fragmentResolution": {
"type": "string"
},
"media": {
"type": "object",
"properties": {
"type": {
"description": "A media type, as described in RFC 2046",
"type": "string"
},
"binaryEncoding": {
"description": "A content encoding scheme, as described in RFC 2045",
"type": "string"
}
}
},
"pathStart": {
"description": "Instances' URIs must start with this value for this schema to apply to them",
"type": "string",
"format": "uri"
}
},
"definitions": {
"schemaArray": {
"type": "array",
"items": {
"$ref": "#"
}
},
"linkDescription": {
"title": "Link Description Object",
"type": "object",
"required": [ "href", "rel" ],
"properties": {
"href": {
"description": "a URI template, as defined by RFC 6570, with the addition of the $, ( and ) characters for pre-processing",
"type": "string"
},
"rel": {
"description": "relation to the target resource of the link",
"type": "string"
},
"title": {
"description": "a title for the link",
"type": "string"
},
"targetSchema": {
"description": "JSON Schema describing the link target",
"$ref": "#"
},
"mediaType": {
"description": "media type (as defined by RFC 2046) describing the link target",
"type": "string"
},
"method": {
"description": "method for requesting the target of the link (e.g. for HTTP this might be \"GET\" or \"DELETE\")",
"type": "string"
},
"encType": {
"description": "The media type in which to submit data along with the request",
"type": "string",
"default": "application/json"
},
"schema": {
"description": "Schema describing the data to submit along with the request",
"$ref": "#"
}
"$ref": "http://json-schema.org/draft-07/hyper-schema#/links"
}
}
},
"links": [
{
"rel": "self",
"href": "{+id}"
},
{
"rel": "full",
"href": "{+($ref)}"
"href": "{+%24id}"
}
]
}

View File

@ -1,5 +1,5 @@
{
"id": "http://localhost:1234/node.json",
"$id": "http://localhost:1234/node.json",
"description": "node",
"type": "object",
"properties": {

View File

@ -1,8 +1,8 @@
{
"id": "http://localhost:1234/scope_change.json",
"$id": "http://localhost:1234/scope_change.json",
"definitions": {
"foo": {
"id": "http://localhost:1234/scope_foo.json",
"$id": "http://localhost:1234/scope_foo.json",
"definitions": {
"bar": {
"type": "string"
@ -10,7 +10,7 @@
}
},
"baz": {
"id": "folder/",
"$id": "folder/",
"type": "array",
"items": { "$ref": "folderInteger.json" },
"bar": {

View File

@ -1,5 +1,5 @@
{
"id": "http://localhost:1234/second.json",
"$id": "http://localhost:1234/second.json",
"type": "object",
"properties": {
"first": { "$ref": "first.json" }

View File

@ -1,5 +1,5 @@
{
"id": "http://localhost:1234/tree.json",
"$id": "http://localhost:1234/tree.json",
"description": "tree of nodes",
"type": "object",
"properties": {

View File

@ -20,28 +20,28 @@ describe('resolve', function () {
it('should resolve ids in schema', function() {
// Example from http://json-schema.org/latest/json-schema-core.html#anchor29
var schema = {
"id": "http://x.y.z/rootschema.json#",
"$id": "http://x.y.z/rootschema.json#",
"schema1": {
"id": "#foo",
"$id": "#foo",
"description": "schema1",
"type": "integer"
},
"schema2": {
"id": "otherschema.json",
"$id": "otherschema.json",
"description": "schema2",
"nested": {
"id": "#bar",
"$id": "#bar",
"description": "nested",
"type": "string"
},
"alsonested": {
"id": "t/inner.json#a",
"$id": "t/inner.json#a",
"description": "alsonested",
"type": "boolean"
}
},
"schema3": {
"id": "some://where.else/completely#",
"$id": "some://where.else/completely#",
"description": "schema3",
"type": "null"
},
@ -65,13 +65,13 @@ describe('resolve', function () {
it('should throw if the same id resolves to two different schemas', function() {
instances.forEach(function (ajv) {
ajv.compile({
"id": "http://example.com/1.json",
"$id": "http://example.com/1.json",
"type": "integer"
});
should.throw(function() {
ajv.compile({
"additionalProperties": {
"id": "http://example.com/1.json",
"$id": "http://example.com/1.json",
"type": "string"
}
});
@ -80,11 +80,11 @@ describe('resolve', function () {
should.throw(function() {
ajv.compile({
"items": {
"id": "#int",
"$id": "#int",
"type": "integer"
},
"additionalProperties": {
"id": "#int",
"$id": "#int",
"type": "string"
}
});
@ -98,7 +98,7 @@ describe('resolve', function () {
it('should resolve fragment', function() {
instances.forEach(function(ajv) {
var schema = {
"id": "//e.com/types",
"$id": "//e.com/types",
"definitions": {
"int": { "type": "integer" }
}
@ -166,7 +166,7 @@ describe('resolve', function () {
instances.forEach(function (ajv) {
try {
ajv.compile({
"id": opts.baseId,
"$id": opts.baseId,
"properties": { "a": { "$ref": opts.ref } }
});
} catch(e) {
@ -180,14 +180,14 @@ describe('resolve', function () {
describe('inline referenced schemas without refs in them', function() {
var schemas = [
{ id: 'http://e.com/obj.json#',
{ $id: 'http://e.com/obj.json#',
properties: { a: { $ref: 'int.json#' } } },
{ id: 'http://e.com/int.json#',
{ $id: 'http://e.com/int.json#',
type: 'integer', minimum: 2, maximum: 4 },
{ id: 'http://e.com/obj1.json#',
{ $id: 'http://e.com/obj1.json#',
definitions: { int: { type: 'integer', minimum: 2, maximum: 4 } },
properties: { a: { $ref: '#/definitions/int' } } },
{ id: 'http://e.com/list.json#',
{ $id: 'http://e.com/list.json#',
items: { $ref: 'obj.json#' } }
];
@ -219,8 +219,8 @@ describe('resolve', function () {
var ajv = new Ajv({ verbose: true });
var schemaMessage = {
$schema: "http://json-schema.org/draft-06/schema#",
id: "http://e.com/message.json#",
$schema: "http://json-schema.org/draft-07/schema#",
$id: "http://e.com/message.json#",
type: "object",
required: ["header"],
properties: {
@ -235,8 +235,8 @@ describe('resolve', function () {
// header schema
var schemaHeader = {
$schema: "http://json-schema.org/draft-06/schema#",
id: "http://e.com/header.json#",
$schema: "http://json-schema.org/draft-07/schema#",
$id: "http://e.com/header.json#",
type: "object",
properties: {
version: {
@ -270,14 +270,14 @@ describe('resolve', function () {
var v = ajv.getSchema('http://e.com/message.json#');
v(validMessage) .should.equal(true);
v.schema.id .should.equal('http://e.com/message.json#');
v.schema.$id .should.equal('http://e.com/message.json#');
v(invalidMessage) .should.equal(false);
v.errors .should.have.length(1);
v.schema.id .should.equal('http://e.com/message.json#');
v.schema.$id .should.equal('http://e.com/message.json#');
v(validMessage) .should.equal(true);
v.schema.id .should.equal('http://e.com/message.json#');
v.schema.$id .should.equal('http://e.com/message.json#');
});

View File

@ -36,9 +36,7 @@ jsonSchemaTest(instances, {
? suite(require('./tests/{**/,}*.json', {mode: 'list'}))
: './tests/{**/,}*.json'
},
only: [
// 'schemas/complex', 'schemas/basic', 'schemas/advanced',
],
only: [],
assert: require('./chai').assert,
afterError: after.error,
afterEach: after.each,
@ -48,7 +46,6 @@ jsonSchemaTest(instances, {
function addRemoteRefs(ajv) {
ajv.addMetaSchema(require('../lib/refs/json-schema-draft-04.json'));
for (var id in remoteRefs) ajv.addSchema(remoteRefs[id], id);
ajv.addSchema(remoteRefsWithIds);
}

View File

@ -1,22 +1,13 @@
[
{
"description": "root ref in remote ref (#13)",
"schemas": [
{
"id": "http://localhost:1234/issue13_1",
"type": "object",
"properties": {
"name": { "$ref": "name.json#/definitions/orNull" }
}
},
{
"$id": "http://localhost:1234/issue13_2",
"type": "object",
"properties": {
"name": { "$ref": "name.json#/definitions/orNull" }
}
"schema": {
"$id": "http://localhost:1234/issue13",
"type": "object",
"properties": {
"name": { "$ref": "name.json#/definitions/orNull" }
}
],
},
"tests": [
{
"description": "string is valid",

View File

@ -1,18 +1,11 @@
[
{
"description": "ref in remote ref with ids",
"schemas": [
{
"id": "http://localhost:1234/issue14a_1.json",
"type": "array",
"items": { "$ref": "foo.json" }
},
{
"$id": "http://localhost:1234/issue14a_2.json",
"type": "array",
"items": { "$ref": "foo.json" }
}
],
"schema": {
"$id": "http://localhost:1234/issue14a.json",
"type": "array",
"items": { "$ref": "foo.json" }
},
"tests": [
{
"description": "string is valid",
@ -36,18 +29,11 @@
},
{
"description": "remote ref in definitions in remote ref with ids (#14)",
"schemas": [
{
"id": "http://localhost:1234/issue14b_1.json",
"type": "array",
"items": { "$ref": "buu.json#/definitions/buu" }
},
{
"$id": "http://localhost:1234/issue14b_2.json",
"type": "array",
"items": { "$ref": "buu.json#/definitions/buu" }
}
],
"schema": {
"$id": "http://localhost:1234/issue14b.json",
"type": "array",
"items": { "$ref": "buu.json#/definitions/buu" }
},
"tests": [
{
"description": "string is valid",

View File

@ -3,12 +3,12 @@
"description": "sibling property has id (#170)",
"schemas": [
{
"$schema": "http://json-schema.org/draft-04/schema#",
"id": "http://example.com/base_object_1",
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "http://example.com/base_object_1",
"type": "object",
"properties": {
"title": {
"id": "http://example.com/title",
"$id": "http://example.com/title",
"type": "string"
},
"file": { "$ref": "#/definitions/file-entry" }
@ -18,7 +18,7 @@
}
},
{
"$schema": "http://json-schema.org/draft-06/schema#",
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "http://example.com/base_object_2",
"type": "object",
"properties": {
@ -56,12 +56,12 @@
"description": "sibling item has id",
"schemas": [
{
"$schema": "http://json-schema.org/draft-04/schema#",
"id": "http://example.com/base_array_1",
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "http://example.com/base_array_1",
"type": "array",
"items": [
{
"id": "http://example.com/0",
"$id": "http://example.com/0",
"type": "string"
},
{ "$ref": "#/definitions/file-entry" }
@ -71,7 +71,7 @@
}
},
{
"$schema": "http://json-schema.org/draft-06/schema#",
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "http://example.com/base_array_2",
"type": "array",
"items": [
@ -103,11 +103,11 @@
"description": "sibling schema in anyOf has id",
"schemas": [
{
"$schema": "http://json-schema.org/draft-04/schema#",
"id": "http://example.com/base_anyof_1",
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "http://example.com/base_anyof_1",
"anyOf": [
{
"id": "http://example.com/0",
"$id": "http://example.com/0",
"type": "number"
},
{ "$ref": "#/definitions/def" }
@ -117,7 +117,7 @@
}
},
{
"$schema": "http://json-schema.org/draft-06/schema#",
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "http://example.com/base_anyof_2",
"anyOf": [
{
@ -153,11 +153,11 @@
"description": "sibling schema in oneOf has id",
"schemas": [
{
"$schema": "http://json-schema.org/draft-04/schema#",
"id": "http://example.com/base_oneof_1",
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "http://example.com/base_oneof_1",
"oneOf": [
{
"id": "http://example.com/0",
"$id": "http://example.com/0",
"type": "number"
},
{ "$ref": "#/definitions/def" }
@ -167,7 +167,7 @@
}
},
{
"$schema": "http://json-schema.org/draft-06/schema#",
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "http://example.com/base_oneof_2",
"oneOf": [
{
@ -203,11 +203,11 @@
"description": "sibling schema in allOf has id",
"schemas": [
{
"$schema": "http://json-schema.org/draft-04/schema#",
"id": "http://example.com/base_allof_1",
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "http://example.com/base_allof_1",
"allOf": [
{
"id": "http://example.com/0",
"$id": "http://example.com/0",
"type": "string",
"maxLength": 3
},
@ -218,7 +218,7 @@
}
},
{
"$schema": "http://json-schema.org/draft-06/schema#",
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "http://example.com/base_allof_2",
"allOf": [
{
@ -250,12 +250,12 @@
"description": "sibling schema in dependencies has id",
"schemas": [
{
"$schema": "http://json-schema.org/draft-04/schema#",
"id": "http://example.com/base_dependencies_1",
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "http://example.com/base_dependencies_1",
"type": "object",
"dependencies": {
"foo": {
"id": "http://example.com/foo",
"$id": "http://example.com/foo",
"required": [ "bar" ]
},
"bar": { "$ref": "#/definitions/def" }
@ -265,7 +265,7 @@
}
},
{
"$schema": "http://json-schema.org/draft-06/schema#",
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "http://example.com/base_dependencies_2",
"type": "object",
"dependencies": {

View File

@ -5,7 +5,7 @@
{
"definitions": {
"int": {
"id": "#int",
"$id": "#int",
"type": "integer"
}
},
@ -30,10 +30,10 @@
"description": "IDs in refs with root id",
"schemas": [
{
"id": "http://example.com/int_1.json",
"$id": "http://example.com/int_1.json",
"definitions": {
"int": {
"id": "#int",
"$id": "#int",
"type": "integer"
}
},

View File

@ -1,9 +1,9 @@
[
{
"description": "JSON schema for a standard RAML object (#27)",
"description": "JSON Schema for a standard RAML object (#27)",
"schema": {
"title": "A JSON schema for a standard RAML object",
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "A JSON Schema for a standard RAML object",
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": [
"title"

View File

@ -3,12 +3,12 @@
"description": "Recursive reference (#27)",
"schemas": [
{
"$schema": "http://json-schema.org/draft-04/schema#",
"id": "testrec_1",
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "testrec_1",
"type": "object",
"properties": {
"layout": {
"id": "layout",
"$id": "layout",
"type": "object",
"properties": {
"layout": { "type": "string" },
@ -30,7 +30,7 @@
}
},
{
"$schema": "http://json-schema.org/draft-06/schema#",
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "testrec_2",
"type": "object",
"properties": {

View File

@ -1,20 +1,12 @@
[
{
"description": "id property in referenced schema in object that is not a schema (#63)",
"schemas": [
{
"type" : "object",
"properties": {
"title": { "$ref": "http://json-schema.org/draft-04/schema#/properties/title" }
}
},
{
"type" : "object",
"properties": {
"title": { "$ref": "http://json-schema.org/draft-06/schema#/properties/title" }
}
"schema": {
"type" : "object",
"properties": {
"title": { "$ref": "http://json-schema.org/draft-07/schema#/properties/title" }
}
],
},
"tests": [
{
"description": "empty object is valid",

View File

@ -2,7 +2,7 @@
{
"description": "hash ref inside hash ref in remote ref (#70, was passing)",
"schema": {
"$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0"
"$ref": "http://json-schema.org/draft-07/schema#/definitions/nonNegativeIntegerDefault0"
},
"tests": [
{ "data": 1, "valid": true, "description": "positive integer is valid" },
@ -12,16 +12,10 @@
},
{
"description": "hash ref inside hash ref in remote ref with id (#70, was passing)",
"schemas": [
{
"id": "http://example.com/my_schema_1.json",
"$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0"
},
{
"$id": "http://example.com/my_schema_2.json",
"$ref": "http://json-schema.org/draft-06/schema#/definitions/nonNegativeIntegerDefault0"
}
],
"schema": {
"$id": "http://example.com/my_schema_2.json",
"$ref": "http://json-schema.org/draft-07/schema#/definitions/nonNegativeIntegerDefault0"
},
"tests": [
{ "data": 1, "valid": true, "description": "positive integer is valid" },
{ "data": 0, "valid": true, "description": "zero is valid" },
@ -32,7 +26,7 @@
"description": "local hash ref with remote hash ref without inner hash ref (#70, was passing)",
"schema": {
"definitions": {
"a": { "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" }
"a": { "$ref": "http://json-schema.org/draft-07/schema#/definitions/nonNegativeIntegerDefault0" }
},
"properties": {
"b": { "$ref": "#/definitions/a" }
@ -48,7 +42,7 @@
"description": "local hash ref with remote hash ref that has inner hash ref (#70)",
"schema": {
"definitions": {
"a": { "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" }
"a": { "$ref": "http://json-schema.org/draft-07/schema#/definitions/nonNegativeIntegerDefault0" }
},
"properties": {
"b": { "$ref": "#/definitions/a" }

View File

@ -3,8 +3,8 @@
"description": "Swagger api schema does not compile (#70)",
"schema": {
"title": "A JSON Schema for Swagger 2.0 API.",
"id": "http://swagger.io/v2/schema.json#",
"$schema": "http://json-schema.org/draft-04/schema#",
"$id": "http://swagger.io/v2/schema.json#",
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": [
"swagger",
@ -935,58 +935,58 @@
"type": "string"
},
"title": {
"$ref": "http://json-schema.org/draft-04/schema#/properties/title"
"$ref": "http://json-schema.org/draft-07/schema#/properties/title"
},
"description": {
"$ref": "http://json-schema.org/draft-04/schema#/properties/description"
"$ref": "http://json-schema.org/draft-07/schema#/properties/description"
},
"default": {
"$ref": "http://json-schema.org/draft-04/schema#/properties/default"
"$ref": "http://json-schema.org/draft-07/schema#/properties/default"
},
"multipleOf": {
"$ref": "http://json-schema.org/draft-04/schema#/properties/multipleOf"
"$ref": "http://json-schema.org/draft-07/schema#/properties/multipleOf"
},
"maximum": {
"$ref": "http://json-schema.org/draft-04/schema#/properties/maximum"
"$ref": "http://json-schema.org/draft-07/schema#/properties/maximum"
},
"exclusiveMaximum": {
"$ref": "http://json-schema.org/draft-04/schema#/properties/exclusiveMaximum"
"$ref": "http://json-schema.org/draft-07/schema#/properties/exclusiveMaximum"
},
"minimum": {
"$ref": "http://json-schema.org/draft-04/schema#/properties/minimum"
"$ref": "http://json-schema.org/draft-07/schema#/properties/minimum"
},
"exclusiveMinimum": {
"$ref": "http://json-schema.org/draft-04/schema#/properties/exclusiveMinimum"
"$ref": "http://json-schema.org/draft-07/schema#/properties/exclusiveMinimum"
},
"maxLength": {
"$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger"
"$ref": "http://json-schema.org/draft-07/schema#/definitions/nonNegativeInteger"
},
"minLength": {
"$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0"
"$ref": "http://json-schema.org/draft-07/schema#/definitions/nonNegativeIntegerDefault0"
},
"pattern": {
"$ref": "http://json-schema.org/draft-04/schema#/properties/pattern"
"$ref": "http://json-schema.org/draft-07/schema#/properties/pattern"
},
"maxItems": {
"$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger"
"$ref": "http://json-schema.org/draft-07/schema#/definitions/nonNegativeInteger"
},
"minItems": {
"$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0"
"$ref": "http://json-schema.org/draft-07/schema#/definitions/nonNegativeIntegerDefault0"
},
"uniqueItems": {
"$ref": "http://json-schema.org/draft-04/schema#/properties/uniqueItems"
"$ref": "http://json-schema.org/draft-07/schema#/properties/uniqueItems"
},
"maxProperties": {
"$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger"
"$ref": "http://json-schema.org/draft-07/schema#/definitions/nonNegativeInteger"
},
"minProperties": {
"$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0"
"$ref": "http://json-schema.org/draft-07/schema#/definitions/nonNegativeIntegerDefault0"
},
"required": {
"$ref": "http://json-schema.org/draft-04/schema#/definitions/stringArray"
"$ref": "http://json-schema.org/draft-07/schema#/definitions/stringArray"
},
"enum": {
"$ref": "http://json-schema.org/draft-04/schema#/properties/enum"
"$ref": "http://json-schema.org/draft-07/schema#/properties/enum"
},
"additionalProperties": {
"anyOf": [
@ -1000,7 +1000,7 @@
"default": {}
},
"type": {
"$ref": "http://json-schema.org/draft-04/schema#/properties/type"
"$ref": "http://json-schema.org/draft-07/schema#/properties/type"
},
"items": {
"anyOf": [
@ -1064,16 +1064,16 @@
"type": "string"
},
"title": {
"$ref": "http://json-schema.org/draft-04/schema#/properties/title"
"$ref": "http://json-schema.org/draft-07/schema#/properties/title"
},
"description": {
"$ref": "http://json-schema.org/draft-04/schema#/properties/description"
"$ref": "http://json-schema.org/draft-07/schema#/properties/description"
},
"default": {
"$ref": "http://json-schema.org/draft-04/schema#/properties/default"
"$ref": "http://json-schema.org/draft-07/schema#/properties/default"
},
"required": {
"$ref": "http://json-schema.org/draft-04/schema#/definitions/stringArray"
"$ref": "http://json-schema.org/draft-07/schema#/definitions/stringArray"
},
"type": {
"type": "string",
@ -1534,49 +1534,49 @@
"default": "csv"
},
"title": {
"$ref": "http://json-schema.org/draft-04/schema#/properties/title"
"$ref": "http://json-schema.org/draft-07/schema#/properties/title"
},
"description": {
"$ref": "http://json-schema.org/draft-04/schema#/properties/description"
"$ref": "http://json-schema.org/draft-07/schema#/properties/description"
},
"default": {
"$ref": "http://json-schema.org/draft-04/schema#/properties/default"
"$ref": "http://json-schema.org/draft-07/schema#/properties/default"
},
"multipleOf": {
"$ref": "http://json-schema.org/draft-04/schema#/properties/multipleOf"
"$ref": "http://json-schema.org/draft-07/schema#/properties/multipleOf"
},
"maximum": {
"$ref": "http://json-schema.org/draft-04/schema#/properties/maximum"
"$ref": "http://json-schema.org/draft-07/schema#/properties/maximum"
},
"exclusiveMaximum": {
"$ref": "http://json-schema.org/draft-04/schema#/properties/exclusiveMaximum"
"$ref": "http://json-schema.org/draft-07/schema#/properties/exclusiveMaximum"
},
"minimum": {
"$ref": "http://json-schema.org/draft-04/schema#/properties/minimum"
"$ref": "http://json-schema.org/draft-07/schema#/properties/minimum"
},
"exclusiveMinimum": {
"$ref": "http://json-schema.org/draft-04/schema#/properties/exclusiveMinimum"
"$ref": "http://json-schema.org/draft-07/schema#/properties/exclusiveMinimum"
},
"maxLength": {
"$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger"
"$ref": "http://json-schema.org/draft-07/schema#/definitions/nonNegativeInteger"
},
"minLength": {
"$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0"
"$ref": "http://json-schema.org/draft-07/schema#/definitions/nonNegativeIntegerDefault0"
},
"pattern": {
"$ref": "http://json-schema.org/draft-04/schema#/properties/pattern"
"$ref": "http://json-schema.org/draft-07/schema#/properties/pattern"
},
"maxItems": {
"$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger"
"$ref": "http://json-schema.org/draft-07/schema#/definitions/nonNegativeInteger"
},
"minItems": {
"$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0"
"$ref": "http://json-schema.org/draft-07/schema#/definitions/nonNegativeIntegerDefault0"
},
"uniqueItems": {
"$ref": "http://json-schema.org/draft-04/schema#/properties/uniqueItems"
"$ref": "http://json-schema.org/draft-07/schema#/properties/uniqueItems"
},
"enum": {
"$ref": "http://json-schema.org/draft-04/schema#/properties/enum"
"$ref": "http://json-schema.org/draft-07/schema#/properties/enum"
},
"jsonReference": {
"type": "object",

View File

@ -0,0 +1,40 @@
[
{
"description": "$comment keyword",
"schema": {
"$comment": "test"
},
"tests": [
{
"description": "any value is valid",
"data": 1,
"valid": true
}
]
},
{
"description": "$comment keyword in subschemas",
"schema": {
"type": "object",
"properties": {
"foo": {
"$comment": "test"
}
}
},
"tests": [
{
"description": "empty object is valid",
"data": {},
"valid": true
},
{
"description": "any value of property foo is valid object is valid",
"data": {
"foo": 1
},
"valid": true
}
]
}
]

View File

@ -511,9 +511,19 @@
"valid": true
},
{
"description": "not valid time",
"description": "an invalid time format",
"data": "12.34.56",
"valid": false
},
{
"description": "an invalid time",
"data": "12:34:67",
"valid": false
},
{
"description": "a valid time (leap second)",
"data": "23:59:60",
"valid": true
}
]
},
@ -535,6 +545,21 @@
"description": "an invalid date-time string (additional part)",
"data": "1963-06-19T12:13:14ZTinvalid",
"valid": false
},
{
"description": "an invalid date-time string (invalid date)",
"data": "1963-20-19T12:13:14Z",
"valid": false
},
{
"description": "an invalid date-time string (invalid time)",
"data": "1963-06-19T12:13:67Z",
"valid": false
},
{
"description": "a valid date-time string (leap second)",
"data": "2016-12-31T23:59:60Z",
"valid": true
}
]
},
@ -568,11 +593,6 @@
"data": "/foo/bar~0/baz~1/%a",
"valid": true
},
{
"description": "a valid JSON-pointer as uri fragment",
"data": "#/foo/%25a",
"valid": true
},
{
"description": "empty string is valid",
"data": "",
@ -588,11 +608,6 @@
"data": "/foo/bar~",
"valid": false
},
{
"description": "not a valid JSON-pointer as uri fragment (% not URL-encoded)",
"data": "#/foo/%a",
"valid": false
},
{
"description": "valid JSON-pointer with empty segment",
"data": "/foo//bar",
@ -602,6 +617,22 @@
"description": "valid JSON-pointer with the last empty segment",
"data": "/foo/bar/",
"valid": true
}
]
},
{
"description": "validation of JSON-pointer URI fragment strings",
"schema": {"format": "json-pointer-uri-fragment"},
"tests": [
{
"description": "a valid JSON-pointer as uri fragment",
"data": "#/foo/%25a",
"valid": true
},
{
"description": "not a valid JSON-pointer as uri fragment (% not URL-encoded)",
"data": "#/foo/%a",
"valid": false
},
{
"description": "valid JSON-pointer with empty segment as uri fragment",

134
spec/tests/rules/if.json Normal file
View File

@ -0,0 +1,134 @@
[
{
"description": "if/then keyword validation",
"schema": {
"if": { "minimum": 10 },
"then": { "multipleOf": 2 }
},
"tests": [
{
"description": ">= 10 and even is valid",
"data": 12,
"valid": true
},
{
"description": ">= 10 and odd is invalid",
"data": 11,
"valid": false
},
{
"description": "< 10 is valid",
"data": 9,
"valid": true
}
]
},
{
"description": "if/then/else keyword validation",
"schema": {
"if": { "maximum": 10 },
"then": { "multipleOf": 2 },
"else": { "multipleOf": 5 }
},
"tests": [
{
"description": "<=10 and even is valid",
"data": 8,
"valid": true
},
{
"description": "<=10 and odd is invalid",
"data": 7,
"valid": false
},
{
"description": ">10 and mulitple of 5 is valid",
"data": 15,
"valid": true
},
{
"description": ">10 and not mulitple of 5 is invalid",
"data": 17,
"valid": false
}
]
},
{
"description": "if keyword with id in sibling subschema",
"schema": {
"$id": "http://example.com/base_if",
"if": {
"$id": "http://example.com/if",
"minimum": 10
},
"then": { "$ref": "#/definitions/def" },
"definitions": {
"def": { "multipleOf": 2 }
}
},
"tests": [
{
"description": ">= 10 and even is valid",
"data": 12,
"valid": true
},
{
"description": ">= 10 and odd is invalid",
"data": 11,
"valid": false
},
{
"description": "< 10 is valid",
"data": 9,
"valid": true
}
]
},
{
"description": "then/else without if should be ignored",
"schema": {
"then": { "multipleOf": 2 },
"else": { "multipleOf": 5 }
},
"tests": [
{
"description": "even is valid",
"data": 8,
"valid": true
},
{
"description": "odd is valid",
"data": 7,
"valid": true
},
{
"description": "mulitple of 5 is valid",
"data": 15,
"valid": true
},
{
"description": "not mulitple of 5 is valid",
"data": 17,
"valid": true
}
]
},
{
"description": "if without then/else should be ignored",
"schema": {
"if": { "maximum": 10 }
},
"tests": [
{
"description": "<=10 is valid",
"data": 8,
"valid": true
},
{
"description": ">10 is valid",
"data": 15,
"valid": true
}
]
}
]

View File

@ -0,0 +1,26 @@
[
{
"description": "uniqueItems with algorithm using hash",
"schema": {
"items": { "type": "string" },
"uniqueItems": true
},
"tests": [
{
"description": "array of unique strings are valid",
"data": ["foo", "bar", "baz"],
"valid": true
},
{
"description": "array of non-unique strings are invalid",
"data": ["foo", "bar", "bar"],
"valid": false
},
{
"description": "array with non-strings is invalid",
"data": ["1", 2],
"valid": false
}
]
}
]

View File

@ -2,7 +2,7 @@
{
"description": "advanced schema from z-schema benchmark (https://github.com/zaggino/z-schema)",
"schema": {
"$schema": "http://json-schema.org/draft-04/schema#",
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"/": { "$ref": "#/definitions/entry" }
@ -14,7 +14,7 @@
"required": [ "/" ],
"definitions": {
"entry": {
"$schema": "http://json-schema.org/draft-04/schema#",
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "schema for an fstab entry",
"type": "object",
"required": [ "storage" ],

View File

@ -2,7 +2,7 @@
{
"description": "basic schema from z-schema benchmark (https://github.com/zaggino/z-schema)",
"schema": {
"$schema": "http://json-schema.org/draft-04/schema#",
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Product set",
"type": "array",
"items": {
@ -18,8 +18,7 @@
},
"price": {
"type": "number",
"minimum": 0,
"exclusiveMinimum": true
"exclusiveMinimum": 0
},
"tags": {
"type": "array",

View File

@ -7,17 +7,17 @@
"minItems": 1,
"definitions": {
"base58": {
"id": "#base58",
"$id": "#base58",
"type": "string",
"pattern": "^[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+$"
},
"hex": {
"id": "#hex",
"$id": "#hex",
"type": "string",
"pattern": "^[0123456789A-Fa-f]+$"
},
"tx_id": {
"id": "#tx_id",
"$id": "#tx_id",
"allOf": [
{ "$ref": "#hex" },
{
@ -27,7 +27,7 @@
]
},
"address": {
"id": "#address",
"$id": "#address",
"allOf": [
{ "$ref": "#base58" },
{
@ -37,7 +37,7 @@
]
},
"signature": {
"id": "#signature",
"$id": "#signature",
"allOf": [
{ "$ref": "#hex" },
{
@ -47,7 +47,7 @@
]
},
"transaction": {
"id": "#transaction",
"$id": "#transaction",
"additionalProperties": false,
"required": [
"metadata",
@ -108,7 +108,7 @@
}
},
"input": {
"id": "#input",
"$id": "#input",
"type": "object",
"additionalProperties": false,
"required": [
@ -134,7 +134,7 @@
}
},
"output": {
"id": "#output",
"$id": "#output",
"type": "object",
"additionalProperties": false,
"required": [

View File

@ -2,23 +2,23 @@
{
"description": "complex schema from jsck benchmark (https://github.com/pandastrike/jsck)",
"schema": {
"id": "http://example.com/complex3.json",
"$id": "http://example.com/complex3.json",
"type": "array",
"items": { "$ref": "#transaction" },
"minItems": 1,
"definitions": {
"base58": {
"id": "#base58",
"$id": "#base58",
"type": "string",
"pattern": "^[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+$"
},
"hex": {
"id": "#hex",
"$id": "#hex",
"type": "string",
"pattern": "^[0123456789A-Fa-f]+$"
},
"tx_id": {
"id": "#tx_id",
"$id": "#tx_id",
"allOf": [
{ "$ref": "#hex" },
{
@ -28,7 +28,7 @@
]
},
"address": {
"id": "#address",
"$id": "#address",
"allOf": [
{ "$ref": "#base58" },
{
@ -38,7 +38,7 @@
]
},
"signature": {
"id": "#signature",
"$id": "#signature",
"allOf": [
{ "$ref": "#hex" },
{
@ -48,7 +48,7 @@
]
},
"transaction": {
"id": "#transaction",
"$id": "#transaction",
"additionalProperties": false,
"required": [
"metadata",
@ -109,7 +109,7 @@
}
},
"input": {
"id": "#input",
"$id": "#input",
"type": "object",
"additionalProperties": false,
"required": [
@ -135,7 +135,7 @@
}
},
"output": {
"id": "#output",
"$id": "#output",
"type": "object",
"additionalProperties": false,
"required": [