diff --git a/.eslintrc.yml b/.eslintrc.yml index 9fe920d6ab..f8ed3b2c38 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -1,4 +1,6 @@ extends: eslint:recommended +parserOptions: + ecmaVersion: 6 env: node: true browser: true @@ -9,20 +11,19 @@ rules: curly: [2, multi-or-nest, consistent] dot-location: [2, property] dot-notation: 2 - indent-legacy: [2, 2, SwitchCase: 1] linebreak-style: [2, unix] new-cap: 2 no-console: [2, allow: [warn, error]] no-else-return: 2 no-eq-null: 2 + no-extra-semi: 0 no-fallthrough: 2 no-invalid-this: 2 no-return-assign: 2 no-shadow: 1 no-trailing-spaces: 2 no-use-before-define: [2, nofunc] - quotes: [2, single, avoid-escape] - semi: [2, always] + semi: 0 strict: [2, global] valid-jsdoc: [2, requireReturn: false] no-control-regex: 0 diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 5585010365..46d6f970fe 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -12,18 +12,13 @@ This template is for bug or error reports. For other issues please use: **What version of Ajv are you using? Does the issue happen if you use the latest version?** - - **Ajv options object** ```javascript - - ``` - **JSON Schema** @@ -33,7 +28,6 @@ This template is for bug or error reports. For other issues please use: ``` - **Sample data** @@ -43,7 +37,6 @@ This template is for bug or error reports. For other issues please use: ``` - **Your code** ```javascript - - ``` - **Validation result, data AFTER validation, error messages** ``` @@ -72,5 +62,4 @@ Thank you! **What results did you expect?** - **Are you going to resolve the issue?** diff --git a/.github/ISSUE_TEMPLATE/bug-or-error-report.md b/.github/ISSUE_TEMPLATE/bug-or-error-report.md index c590321ca9..9f4aeed90d 100644 --- a/.github/ISSUE_TEMPLATE/bug-or-error-report.md +++ b/.github/ISSUE_TEMPLATE/bug-or-error-report.md @@ -1,10 +1,9 @@ --- name: Bug or error report about: Please use for issues related to incorrect validation behaviour -title: '' -labels: 'bug report' -assignees: '' - +title: "" +labels: "bug report" +assignees: "" --- ```javascript - - ``` - **JSON Schema** @@ -38,7 +32,6 @@ For other issues please see https://github.com/ajv-validator/ajv/blob/master/CON ``` - **Sample data** @@ -48,7 +41,6 @@ For other issues please see https://github.com/ajv-validator/ajv/blob/master/CON ``` - **Your code** ```javascript - - ``` - **Validation result, data AFTER validation, error messages** ``` @@ -77,5 +66,4 @@ Thank you! **What results did you expect?** - **Are you going to resolve the issue?** diff --git a/.github/ISSUE_TEMPLATE/change.md b/.github/ISSUE_TEMPLATE/change.md index 0c8035d1a6..13eb1ed0fd 100644 --- a/.github/ISSUE_TEMPLATE/change.md +++ b/.github/ISSUE_TEMPLATE/change.md @@ -1,10 +1,9 @@ --- name: Feature or change proposal about: For proposals of new features, options or some other improvements -title: '' -labels: 'enhancement' -assignees: '' - +title: "" +labels: "enhancement" +assignees: "" --- ```typescript - - ``` - **Typescript compiler error messages** ``` @@ -38,5 +33,4 @@ Please make it as small as posssible to reproduce the issue **Describe the change that should be made to address the issue?** - **Are you going to resolve the issue?** diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 7abf655f1f..3595869ae2 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -11,8 +11,6 @@ Please answer the questions below. **What issue does this pull request resolve?** - **What changes did you make?** - **Is there anything that requires more attention while reviewing?** diff --git a/.jshintrc b/.jshintrc deleted file mode 100644 index fffe0aac2b..0000000000 --- a/.jshintrc +++ /dev/null @@ -1,9 +0,0 @@ -{ - "laxcomma": true, - "laxbreak": true, - "curly": false, - "-W058": true, - "eqeqeq": false, - "node": true, - "validthis": true -} diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000000..e2fcb36476 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,6 @@ +spec/JSON-Schema-Test-Suite +.browser +coverage +dist +.nyc_output +lib/dotjs diff --git a/.tonic_example.js b/.tonic_example.js index aa11812d87..2b0d6683ee 100644 --- a/.tonic_example.js +++ b/.tonic_example.js @@ -1,20 +1,20 @@ -var Ajv = require('ajv'); -var ajv = new Ajv({allErrors: true}); +var Ajv = require("ajv") +var ajv = new Ajv({allErrors: true}) var schema = { - "properties": { - "foo": { "type": "string" }, - "bar": { "type": "number", "maximum": 3 } - } -}; + properties: { + foo: {type: "string"}, + bar: {type: "number", maximum: 3}, + }, +} -var validate = ajv.compile(schema); +var validate = ajv.compile(schema) -test({"foo": "abc", "bar": 2}); -test({"foo": 2, "bar": 4}); +test({foo: "abc", bar: 2}) +test({foo: 2, bar: 4}) function test(data) { - var valid = validate(data); - if (valid) console.log('Valid!'); - else console.log('Invalid: ' + ajv.errorsText(validate.errors)); -} \ No newline at end of file + var valid = validate(data) + if (valid) console.log("Valid!") + else console.log("Invalid: " + ajv.errorsText(validate.errors)) +} diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 410cda6416..b8026a2cf8 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -14,22 +14,22 @@ appearance, race, religion, or sexual identity and orientation. Examples of behavior that contributes to creating a positive environment include: -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members +- Using welcoming and inclusive language +- Being respectful of differing viewpoints and experiences +- Gracefully accepting constructive criticism +- Focusing on what is best for the community +- Showing empathy towards other community members Examples of unacceptable behavior by participants include: -* The use of sexualized language or imagery and unwelcome sexual attention or - advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic - address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting +- The use of sexualized language or imagery and unwelcome sexual attention or + advances +- Trolling, insulting/derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or electronic + address, without explicit permission +- Other conduct which could reasonably be considered inappropriate in a + professional setting ## Our Responsibilities diff --git a/COERCION.md b/COERCION.md index 6a0a41a68c..c2b159f391 100644 --- a/COERCION.md +++ b/COERCION.md @@ -3,6 +3,7 @@ To enable type coercion pass option `coerceTypes` to Ajv with `true` or `array` (it is `false` by default). See [example](https://github.com/ajv-validator/ajv#coercing-data-types). The coercion rules are different from JavaScript: + - to validate user input as expected - to have the coercion reversible - to correctly validate cases where different types are required in subschemas (e.g., in `anyOf`). @@ -11,64 +12,58 @@ Type coercion only happens if there is `type` keyword and if without coercion th If there are multiple types allowed in `type` keyword the coercion will only happen if none of the types match the data and some of the scalar types are present (coercion to/from `object`/`array` is not possible). In this case the validating function will try coercing the data to each type in order until some of them succeeds. -Application of these rules can have some unexpected consequences. Ajv may coerce the same value multiple times (this is why coercion reversibility is required) as needed at different points in the schema. This is particularly evident when using `oneOf`, which must test all of the subschemas. Ajv will coerce the type for each subschema, possibly resulting in unexpected failure if it can coerce to match more than one of the subschemas. Even if it succeeds, Ajv will not backtrack, so you'll get the type of the final coercion even if that's not the one that allowed the data to pass validation. If possible, structure your schema with `anyOf`, which won't validate subsequent subschemas as soon as it encounters one subschema that matches. +Application of these rules can have some unexpected consequences. Ajv may coerce the same value multiple times (this is why coercion reversibility is required) as needed at different points in the schema. This is particularly evident when using `oneOf`, which must test all of the subschemas. Ajv will coerce the type for each subschema, possibly resulting in unexpected failure if it can coerce to match more than one of the subschemas. Even if it succeeds, Ajv will not backtrack, so you'll get the type of the final coercion even if that's not the one that allowed the data to pass validation. If possible, structure your schema with `anyOf`, which won't validate subsequent subschemas as soon as it encounters one subschema that matches. Possible type coercions: -|from type →
to type ↓|string|number|boolean|null|array*| -|---|:-:|:-:|:-:|:-:|:-:| -|string |-|`x`→`""+x`|`false`→`"false"`
`true`→`"true"`|`null`→`""`|`[x]`→`x`| -|number /
integer|Valid number /
integer: `x`→`+x`
|-|`false`→`0`
`true`→`1`|`null`→`0`|`[x]`→`x`| -|boolean |`"false"`→`false`
`"true"`→`true`
`"abc"`⇸
`""`⇸|`0`→`false`
`1`→`true`
`x`⇸|-|`null`→`false`|`[false]`→`false`
`[true]`→`true`| -|null |`""`→`null`
`"null"`⇸
`"abc"`⇸|`0`→`null`
`x`⇸|`false`→`null`
`true`⇸|-|`[null]`→`null`| -|array* |`x`→`[x]`|`x`→`[x]`|`false`→`[false]`
`true`→`[true]`|`null`→`[null]`|-| +| from type →
to type ↓ | string | number | boolean | null | array\* | +| ------------------------------------------------------ | :-----------------------------------------------------------------------------: | :-----------------------------------------------: | :--------------------------------------------: | :------------------: | :--------------------------------------------: | +| string | - | `x`→`""+x` | `false`→`"false"`
`true`→`"true"` | `null`→`""` | `[x]`→`x` | +| number /
integer | Valid number /
integer: `x`→`+x`
| - | `false`→`0`
`true`→`1` | `null`→`0` | `[x]`→`x` | +| boolean | `"false"`→`false`
`"true"`→`true`
`"abc"`⇸
`""`⇸ | `0`→`false`
`1`→`true`
`x`⇸ | - | `null`→`false` | `[false]`→`false`
`[true]`→`true` | +| null | `""`→`null`
`"null"`⇸
`"abc"`⇸ | `0`→`null`
`x`⇸ | `false`→`null`
`true`⇸ | - | `[null]`→`null` | +| array\* | `x`→`[x]` | `x`→`[x]` | `false`→`[false]`
`true`→`[true]` | `null`→`[null]` | - | \* Requires option `{coerceTypes: 'array'}` - ## Coercion from string values #### To number type Coercion to `number` is possible if the string is a valid number, `+data` is used. - #### To integer type Coercion to `integer` is possible if the string is a valid number without fractional part (`data % 1 === 0`). - #### To boolean type Unlike JavaScript, only these strings can be coerced to `boolean`: + - `"true"` -> `true` - `"false"` -> `false` - #### To null type Empty string is coerced to `null`, other strings can't be coerced. - ## Coercion from number values #### To string type Always possible, `'' + data` is used - #### To boolean type Unlike JavaScript, only these numbers can be coerced to `boolean`: + - `1` -> `true` - `0` -> `false` - #### To null type `0` coerces to `null`, other numbers can't be coerced. - ## Coercion from boolean values #### To string type @@ -76,35 +71,29 @@ Unlike JavaScript, only these numbers can be coerced to `boolean`: - `true` -> `"true"` - `false` -> `"false"` - #### To number/integer types - `true` -> `1` - `false` -> `0` - #### To null type `false` coerces to `null`, `true` can't be coerced. - ## Coercion from null #### To string type `null` coerses to the empty string. - #### To number/integer types `null` coerces to `0` - #### To boolean type `null` coerces to `false` - ## Coercion to and from array These coercions require that the option `coerceTypes` is `"array"`. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4f2f8aaede..00a6afcd1d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,19 +16,16 @@ Thank you for your help making Ajv better! Every contribution is appreciated. If - [Pull requests](#pull-requests) - [Contributions license](#contributions-license) - ## Documentation Ajv has a lot of features and maintaining documentation takes time. I appreciate the time you spend correcting or clarifying the documentation. - ## Issues Before submitting the issue please search the existing issues and also review [Frequently Asked Questions](https://github.com/ajv-validator/ajv/blob/master/FAQ.md). I would really appreciate the time you spend providing all the information and reducing both your schema and data to the smallest possible size when they still have the issue. Simplifying the issue also makes it more valuable for other users (in cases it turns out to be an incorrect usage rather than a bug). - #### Bug reports Please make sure to include the following information in the issue: @@ -44,7 +41,6 @@ Please include the link to the working code sample at Runkit.com (please clone h [Create bug report](https://github.com/ajv-validator/ajv/issues/new?template=bug-or-error-report.md). - #### Security vulnerabilities To report a security vulnerability, please use the @@ -53,7 +49,6 @@ Tidelift will coordinate the fix and disclosure. Please do NOT report security vulnerabilities via GitHub issues. - #### Change proposals [Create a proposal](https://github.com/ajv-validator/ajv/issues/new?template=change.md) for a new feature, option or some other improvement. @@ -73,7 +68,6 @@ If you’re requesting a change, it would be helpful to include this as well: Please include as much details as possible. - #### Browser and compatibility issues [Create an issue](https://github.com/ajv-validator/ajv/issues/new?template=compatibility.md) to report a compatibility problem that only happens in a particular environment (when your code works correctly in node.js v8+ in linux systems but fails in some other environment). @@ -87,12 +81,12 @@ Please include this information: 5. Results in node.js v8+. 6. Results and error messages in your platform. - #### Installation and dependency issues [Create an issue](https://github.com/ajv-validator/ajv/issues/new?template=installation.md) to report problems that happen during Ajv installation or when Ajv is missing some dependency. Before submitting the issue, please try the following: + - use the latest stable Node.js and `npm` - use `yarn` instead of `npm` - the issue can be related to https://github.com/npm/npm/issues/19877 - remove `node_modules` and `package-lock.json` and run install again @@ -106,26 +100,22 @@ If nothing helps, please submit: 5. Error messages 6. The output of `npm ls` - #### Using JSON Schema standard Ajv implements JSON Schema standard draft-04 and draft-06/07. If it is a general issue related to using the standard keywords included in JSON Schema or implementing some advanced validation logic please ask the question on [Stack Overflow](https://stackoverflow.com/questions/ask?tags=jsonschema,ajv) (my account is [esp](https://stackoverflow.com/users/1816503/esp)) or submitting the question to [JSON-Schema.org](https://github.com/json-schema-org/json-schema-spec/issues/new). Please mention @epoberezkin. - #### Ajv usage questions The best place to ask a question about using Ajv is [Gitter chat](https://gitter.im/ajv-validator/ajv). If the question is advanced, it can be submitted to [Stack Overflow](http://stackoverflow.com/questions/ask?tags=jsonschema,ajv). - ## Code Thanks a lot for considering contributing to Ajv. Many very useful features were created by its users. - #### Development Running tests: @@ -149,7 +139,6 @@ All validation functions are generated using doT templates in [dot](https://gith `npm run watch` - automatically compiles templates when files in dot folder change - #### Pull requests To make accepting your changes faster please follow these steps: @@ -162,7 +151,6 @@ To make accepting your changes faster please follow these steps: 6. Please run the tests before committing your code. 7. If tests fail in Travis after you make a PR please investigate and fix the issue. - #### Contributions license When contributing the code you confirm that: diff --git a/CUSTOM.md b/CUSTOM.md index 68cac5ab34..49d5b7a907 100644 --- a/CUSTOM.md +++ b/CUSTOM.md @@ -13,10 +13,10 @@ - [Reporting errors in custom keywords](#reporting-errors-in-custom-keywords) - [Short-circuit validation](#short-circuit-validation) - ### Define keyword with validation function Validation function will be called during data validation and it will be passed: + - schema - data - parent schema @@ -34,50 +34,49 @@ This way to define keywords is useful for: - testing your keywords before converting them to compiled/inlined keywords - defining keywords that do not depend on the schema value (e.g., when the value is always `true`). In this case you can add option `schema: false` to the keyword definition and the schemas won't be passed to the validation function, it will only receive the same 4 parameters as compiled validation function (see the next section). - defining keywords where the schema is a value used in some expression. -- defining keywords that support [$data reference](https://github.com/ajv-validator/ajv#data-reference) - in this case validation function is required, either as the only option or in addition to compile, macro or inline function (see below). - -__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. +- defining keywords that support [\$data reference](https://github.com/ajv-validator/ajv#data-reference) - in this case validation function is required, either as the only option or in addition to compile, macro or inline function (see below). +**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 draft-06 keyword `const`, it is equivalent to `enum` keyword with one item): ```javascript -ajv.addKeyword('constant', { +ajv.addKeyword("constant", { validate: function (schema, data) { - return typeof schema == 'object' && schema !== null - ? deepEqual(schema, data) - : schema === data; + return typeof schema == "object" && schema !== null + ? deepEqual(schema, data) + : schema === data }, - errors: false -}); + errors: false, +}) var schema = { - "constant": 2 -}; -var validate = ajv.compile(schema); -console.log(validate(2)); // true -console.log(validate(3)); // false + constant: 2, +} +var validate = ajv.compile(schema) +console.log(validate(2)) // true +console.log(validate(3)) // false var schema = { - "constant": { - "foo": "bar" - } -}; -var validate = ajv.compile(schema); -console.log(validate({foo: 'bar'})); // true -console.log(validate({foo: 'baz'})); // false + constant: { + foo: "bar", + }, +} +var validate = ajv.compile(schema) +console.log(validate({foo: "bar"})) // true +console.log(validate({foo: "baz"})) // false ``` `const` keyword is already available in Ajv. -__Please note:__ If the keyword does not define custom errors (see [Reporting errors in custom keywords](#reporting-errors-in-custom-keywords)) pass `errors: false` in its definition; it will make generated code more efficient. +**Please note:** If the keyword does not define custom errors (see [Reporting errors in custom keywords](#reporting-errors-in-custom-keywords)) pass `errors: false` in its definition; it will make generated code more efficient. To add asynchronous keyword pass `async: true` in its definition. - ### Define keyword with "compilation" function Compilation function will be called during schema compilation. It will be passed schema, parent schema and [schema compilation context](#schema-compilation-context) and it should return a validation function. This validation function will be passed during validation: + - data - current data path - parent data object @@ -97,41 +96,41 @@ Custom keyword can also have an optional `dependencies` property in their defini Example. `range` and `exclusiveRange` keywords using compiled schema: ```javascript -ajv.addKeyword('range', { - type: 'number', +ajv.addKeyword("range", { + type: "number", compile: function (sch, parentSchema) { - var min = sch[0]; - var max = sch[1]; + var min = sch[0] + var max = sch[1] return parentSchema.exclusiveRange === true - ? function (data) { return data > min && data < max; } - : function (data) { return data >= min && data <= max; } + ? function (data) { + return data > min && data < max + } + : function (data) { + return data >= min && data <= max + } }, errors: false, metaSchema: { - type: 'array', - items: [ - { type: 'number' }, - { type: 'number' } - ], - additionalItems: false - } -}); + type: "array", + items: [{type: "number"}, {type: "number"}], + additionalItems: false, + }, +}) var schema = { - "range": [2, 4], - "exclusiveRange": true -}; -var validate = ajv.compile(schema); -console.log(validate(2.01)); // true -console.log(validate(3.99)); // true -console.log(validate(2)); // false -console.log(validate(4)); // false + range: [2, 4], + exclusiveRange: true, +} +var validate = ajv.compile(schema) +console.log(validate(2.01)) // true +console.log(validate(3.99)) // true +console.log(validate(2)) // false +console.log(validate(4)) // false ``` See note on custom errors and asynchronous keywords in the previous section. - ### Define keyword with "macro" function "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. @@ -140,66 +139,62 @@ It is the most efficient approach (in cases when the keyword logic can be expres In addition to the errors from the expanded schema macro keyword will add its own error in case validation fails. - Example. `range` and `exclusiveRange` keywords from the previous example defined with macro: ```javascript -ajv.addKeyword('range', { - type: 'number', +ajv.addKeyword("range", { + type: "number", macro: function (schema, parentSchema) { return { minimum: schema[0], maximum: schema[1], exclusiveMinimum: !!parentSchema.exclusiveRange, - exclusiveMaximum: !!parentSchema.exclusiveRange - }; + exclusiveMaximum: !!parentSchema.exclusiveRange, + } }, metaSchema: { - type: 'array', - items: [ - { type: 'number' }, - { type: 'number' } - ], - additionalItems: false - } -}); + type: "array", + items: [{type: "number"}, {type: "number"}], + additionalItems: false, + }, +}) ``` Example. `contains` keyword from version 5 proposals that requires that the array has at least one item matching schema (see https://github.com/json-schema/json-schema/wiki/contains-(v5-proposal)): ```javascript var schema = { - "contains": { - "type": "number", - "minimum": 4, - "exclusiveMinimum": true - } -}; - -var validate = ajv.addKeyword('contains', { - type: 'array', - macro: function (schema) { - return { - "not": { - "items": { - "not": schema - } + contains: { + type: "number", + minimum: 4, + exclusiveMinimum: true, + }, +} + +var validate = ajv + .addKeyword("contains", { + type: "array", + macro: function (schema) { + return { + not: { + items: { + not: schema, + }, + }, } - }; - } -}) -.compile(schema); + }, + }) + .compile(schema) -console.log(validate([1,2,3])); // false -console.log(validate([2,3,4])); // false -console.log(validate([3,4,5])); // true, number 5 matches schema inside "contains" +console.log(validate([1, 2, 3])) // false +console.log(validate([2, 3, 4])) // false +console.log(validate([3, 4, 5])) // true, number 5 matches schema inside "contains" ``` `contains` keyword is already available in Ajv with option `v5: true`. See the example of defining recursive macro keyword `deepProperties` in the [test](https://github.com/ajv-validator/ajv/blob/master/spec/custom.spec.js#L151). - ### Define keyword with "inline" compilation function Inline compilation function is called during schema compilation. It is passed four parameters: `it` (the current schema compilation context), `keyword` (added in v3.0 to allow defining multiple keywords with a single function), `schema` and `parentSchema` and it should return the code (as a string) that will be inlined in the code of compiled schema. This code can be either an expression that evaluates to the validation result (boolean) or a set of statements that assigns the validation result to a variable. @@ -211,35 +206,35 @@ While it can be more challenging to define keywords with "inline" functions, it - access to the parent data and the path to the currently validated data - access to Ajv utilities via `it.util` - Example `even` keyword: ```javascript -var schema = { "even": true }; - -var validate = ajv.addKeyword('even', { - type: 'number', - inline: function (it, keyword, schema) { - var op = schema ? '===' : '!=='; - return 'data' + (it.dataLevel || '') + ' % 2 ' + op + ' 0'; - }, - metaSchema: { type: 'boolean' } -}) -.compile(schema); - -console.log(validate(2)); // true -console.log(validate(3)); // false +var schema = {even: true} + +var validate = ajv + .addKeyword("even", { + type: "number", + inline: function (it, keyword, schema) { + var op = schema ? "===" : "!==" + return "data" + (it.dataLevel || "") + " % 2 " + op + " 0" + }, + metaSchema: {type: "boolean"}, + }) + .compile(schema) + +console.log(validate(2)) // true +console.log(validate(3)) // false ``` `'data' + (it.dataLevel || '')` in the example above is the reference to the currently validated data. Also note that `schema` (keyword schema) is the same as `it.schema.even`, so schema is not strictly necessary here - it is passed for convenience. - Example `range` keyword defined using [doT template](https://github.com/olado/doT): ```javascript // {% raw %} -var doT = require('dot'); -var inlineRangeTemplate = doT.compile("\ +var doT = require("dot") +var inlineRangeTemplate = doT.compile( + "\ {{ \ var $data = 'data' + (it.dataLevel || '') \ , $min = it.schema.range[0] \ @@ -248,21 +243,19 @@ var inlineRangeTemplate = doT.compile("\ , $lt = it.schema.exclusiveRange ? '<' : '<='; \ }} \ var valid{{=it.level}} = {{=$data}} {{=$gt}} {{=$min}} && {{=$data}} {{=$lt}} {{=$max}}; \ -"); +" +) -ajv.addKeyword('range', { - type: 'number', +ajv.addKeyword("range", { + type: "number", inline: inlineRangeTemplate, statements: true, metaSchema: { - type: 'array', - items: [ - { type: 'number' }, - { type: 'number' } - ], - additionalItems: false - } -}); + type: "array", + items: [{type: "number"}, {type: "number"}], + additionalItems: false, + }, +}) // {% endraw %} ``` @@ -272,13 +265,12 @@ Property `statements` in the keyword definition should be set to `true` if the v The main challenge of defining inline keywords is that you have to write both the code that will execute during schema compilation (compile-time) and the code that will execute during data validation (validation-time - this code can be generated either using strings concatenation or using templates, see the examples below). -Ajv uses [doT templates](https://github.com/olado/doT) to generate the code of validation functions that makes it easier to separate compile-time and validation-time code because of the different syntax used in templates and in the code. Ajv also uses different variable names for compile-time and validation-time variables to make it easier to differentiate - compile-time variable names start with $ character. +Ajv uses [doT templates](https://github.com/olado/doT) to generate the code of validation functions that makes it easier to separate compile-time and validation-time code because of the different syntax used in templates and in the code. Ajv also uses different variable names for compile-time and validation-time variables to make it easier to differentiate - compile-time variable names start with \$ character. Also you have to bear in mind that while compile-time variables exist in the scope of the function you wrote to compile the keyword, so they are isolated, validation-time variables share the scope with all the variables in the scope of a single validation function. So if your keyword has subschemas you have to append the schema level (`it.level`) to the variable names. See [schema compilation context](#schema-compilation-context) for more information on which properties and utilities from the schema compilation context you can use. - ## Schema compilation context The first parameter passed to inline keyword compilation function (and the 3rd parameter passed to compile and macro keyword functions) is `it`, the schema compilation context. All the properties and functions documented here are safe to use in your keywords, they won't be renamed or change their meaning without major version change. @@ -289,7 +281,7 @@ The first parameter passed to inline keyword compilation function (and the 3rd p - _dataLevel_ - the level of the currently validated data. It can be used to access both the property names and the data on all levels from the top. See [Validation time variables](#validation-time-variables). - _schema_ - current level schema. The value of your keyword is `it.schema[keyword]`. This value is also passed as the 3rd parameter to the inline compilation function and the current level schema as the 4th parameter. - _schemaPath_ - the validation time expression that evaluates to the property name of the current schema. -- _baseId_ - the current schema base URI that should be used as the base for resolving URIs in references ($ref). +- _baseId_ - the current schema base URI that should be used as the base for resolving URIs in references (\$ref). - _async_ - truthy if the current schema is asynchronous. - _opts_ - Ajv instance option. You should not be changing them. - _formats_ - all formats available in Ajv instance, including the custom ones. @@ -298,7 +290,6 @@ The first parameter passed to inline keyword compilation function (and the 3rd p - _util_ - [Ajv utilities](#ajv-utilities) you can use in your inline compilation functions. - _self_ - Ajv instance. - ## Validation time variables There is a number of variables and expressions you can use in the generated (validation-time) code of your keywords. @@ -314,7 +305,6 @@ There is a number of variables and expressions you can use in the generated (val - `'errors'` - the number of encountered errors. See [Reporting errors in custom keywords](https://github.com/ajv-validator/ajv/blob/master/CUSTOM.md#reporting-errors-in-custom-keywords). - `'vErrors'` - the array with errors collected so far. See [Reporting errors in custom keywords](https://github.com/ajv-validator/ajv/blob/master/CUSTOM.md#reporting-errors-in-custom-keywords). - ## Ajv utilities There are sevral useful functions you can use in your inline keywords. These functions are available as properties of `it.util` object: @@ -323,33 +313,29 @@ There are sevral useful functions you can use in your inline keywords. These fun Clone or extend the object. If one object is passed, it is cloned. If two objects are passed, the second object is extended with the properties of the first. - ##### .toHash(Array arr) -> Object Converts the array of strings to the object where each string becomes the key with the value of `true`. ```javascript -it.util.toHash(['a', 'b', 'c']) // { a: true, b: true, c: true } +it.util.toHash(["a", "b", "c"]) // { a: true, b: true, c: true } ``` - ##### .equal(value1, value2) -> Boolean Performs deep equality comparison. This function is used in keywords `enum`, `constant`, `uniqueItems` and can be used in custom keywords. - ##### .getProperty(String key) -> String Converts the string that is the key/index to access the property/item to the JavaScript syntax to access the property (either "." notation or "[...]" notation). ```javascript -it.util.getProperty('a') // ".a" -it.util.getProperty('1') // "['1']" +it.util.getProperty("a") // ".a" +it.util.getProperty("1") // "['1']" it.util.getProperty("a'b") // "['a\\'b']" -it.util.getProperty(1) // "[1]" +it.util.getProperty(1) // "[1]" ``` - ##### .schemaHasRules(Object schema, Object rules) -> String Determines whether the passed schema has rules that should be validated. This function should be used before calling `it.validate` to compile subschemas. @@ -358,12 +344,10 @@ Determines whether the passed schema has rules that should be validated. This fu it.util.schemaHasRules(schema, it.RULES.all) // true or false ``` - ##### .escapeQuotes(String str) -> String Escapes single quotes in the string, so it can be inserted in the generated code inside the string constant with the single quotes. - ##### .toQuotedString(String str) -> String Converts the string to the JavaScript string constant in single quotes (using the escaped string). @@ -372,38 +356,32 @@ Converts the string to the JavaScript string constant in single quotes (using th it.util.toQuotedString("a'b") // "'a\\'b'" ``` - ##### .getData(String jsonPointer, Number dataLevel, Array paths) -> String Returns the validation-time expression to safely access data based on the passed [relative json pointer](https://tools.ietf.org/html/draft-luff-relative-json-pointer-00) (See [examples](https://gist.github.com/geraintluff/5911303)). ```javascript -it.util.getData('2/test/1', it.dataLevel, it.dataPathArr) +it.util.getData("2/test/1", it.dataLevel, it.dataPathArr) // The result depends on the current level // if it.dataLevel is 3 the result is "data1 && data1.test && data1.test[1]" ``` - ##### .escapeJsonPointer(String str) -> String Converts the property name to the JSON-Pointer fragment. - ##### .unescapeJsonPointer (String str) -> String Converts JSON-Pointer fragment to the property name. - ##### .unescapeFragment(String str) -> String Converts the property name to the JSON-Pointer fragment that can be used in URI. - ##### .escapeFragment(String str) -> String Converts the JSON-Pointer fragment from URI to the property name. - ## Reporting errors in custom keywords All custom keywords but macro keywords can optionally create custom error messages. @@ -415,14 +393,14 @@ Inline custom keyword should increase error counter `errors` and add error to `v When inline keyword performs validation Ajv checks whether it created errors by comparing errors count before and after validation. To skip this check add option `errors` (can be `"full"`, `true` or `false`) to keyword definition: ```javascript -ajv.addKeyword('range', { - type: 'number', +ajv.addKeyword("range", { + type: "number", inline: inlineRangeTemplate, statements: true, - errors: true // keyword should create custom errors when validation fails + errors: true, // keyword should create custom errors when validation fails // errors: 'full' // created errors should have dataPath already set // errors: false // keyword never creates errors, Ajv will add a default error -}); +}) ``` Each error object should at least have properties `keyword`, `message` and `params`, other properties will be added. @@ -431,7 +409,6 @@ Inlined keywords can optionally define `dataPath` and `schemaPath` properties in If custom keyword doesn't create errors, the default error will be created in case the keyword fails validation (see [Validation errors](https://github.com/ajv-validator/ajv#validation-errors)). - ## Short-circuit validation In some cases inline keyword can terminate validation and return the result as soon as it encounters the error. It is only practical if the keyword you define has many criteria to validate and you want it to be able to fail fast. You only need to do it if your keyword defines errors itself, otherwise Ajv will return when it creates the default error (if the conditions below are met). @@ -444,18 +421,18 @@ Two conditions should be checked before keyword can return the result: If these conditions are met your keyword can immediately return result. In case the current schema is synchronous (`it.async` is not `true`) you can add this to keyword's generated code when it encounters error `err`: ```javascript -if (vErrors === null) vErrors = [err]; -else vErrors.push(err); -validate.errors = vErrors; -return false; +if (vErrors === null) vErrors = [err] +else vErrors.push(err) +validate.errors = vErrors +return false ``` In case the current schema is asynchronous (it.async is truthy) to return result you need: ```javascript -if (vErrors === null) vErrors = [err]; -else vErrors.push(err); -throw new ValidationError(vErrors); // ValidationError is in the scope +if (vErrors === null) vErrors = [err] +else vErrors.push(err) +throw new ValidationError(vErrors) // ValidationError is in the scope ``` In case `allErrors` option is used the keyword should continue validation after it encounters an error trying to find as many errors as possible. diff --git a/FAQ.md b/FAQ.md index f010a51c8a..902a94f7ac 100644 --- a/FAQ.md +++ b/FAQ.md @@ -2,8 +2,6 @@ The purpose of this document is to help find answers quicker. I am happy to continue the discussion about these issues, so please comment on some of the issues mentioned below or create a new issue if it seems more appropriate. - - ## Using JSON schema Ajv implements JSON schema specification. Before submitting the issue about the behaviour of any validation keywords please review them in: @@ -12,53 +10,42 @@ Ajv implements JSON schema specification. Before submitting the issue about the - [Validation keywords](https://github.com/ajv-validator/ajv/blob/master/KEYWORDS.md) in Ajv documentation - [JSON Schema tutorial](https://spacetelescope.github.io/understanding-json-schema/) (for draft-04) - ##### Why Ajv validates empty object as valid? "properties" keyword does not require the presence of any properties, you need to use "required" keyword. It also doesn't require that the data is an object, so any other type of data will also be valid. To require a specific type use "type" keyword. - ##### Why Ajv validates only the first item of the array? "items" keyword support [two syntaxes](https://github.com/ajv-validator/ajv/blob/master/KEYWORDS.md#items) - 1) when the schema applies to all items; 2) when there is a different schema for each item in the beginning of the array. This problem means you are using the second syntax. - - ## Ajv API for returning validation errors See [#65](https://github.com/ajv-validator/ajv/issues/65), [#212](https://github.com/ajv-validator/ajv/issues/212), [#236](https://github.com/ajv-validator/ajv/issues/236), [#242](https://github.com/ajv-validator/ajv/issues/242), [#256](https://github.com/ajv-validator/ajv/issues/256). - ##### Why Ajv assigns errors as a property of validation function (or instance) instead of returning an object with validation results and errors? The reasons are history (other fast validators with the same api) and performance (returning boolean is faster). Although more code is written to process errors than to handle successful results, almost all server-side validations pass. The existing API is more efficient from the performance point of view. Ajv also supports asynchronous validation (with custom asynchronous formats and keywords) that returns a promise that either resolves to `true` or rejects with an error. - ##### Would errors get overwritten in case of "concurrent" validations? No. There is no concurrency in JavaScript - it is single-threaded. While a validation is run no other JavaScript code (that can access the same memory) can be executed. As long as the errors are used in the same execution block, the errors will not be overwritten. - ##### Can we change / extend API to add a method that would return errors (rather than assign them to `errors` property)? No. In many cases there is a module responsible for the validation in the application, usually to load schemas and to process errors. This module is the right place to introduce any custom API. Convenience is a subjective thing, changing or extending API purely because of convenience would either break backward compatibility (even if it's done in a new major version it still complicates migration) or bloat API (making it more difficult to maintain). - ##### Why don't `"additionalProperties": false` errors display the property name? Doing this would create a precedent where validated data is used in error messages, creating a vulnerability (e.g., when ajv is used to validate API data/parameters and error messages are logged). Since the property name is already in the params object, in an application you can modify messages in any way you need. ajv-errors package allows modifying messages as well. - - ## Additional properties inside compound keywords anyOf, oneOf, etc. See [#127](https://github.com/ajv-validator/ajv/issues/127), [#129](https://github.com/ajv-validator/ajv/issues/129), [#134](https://github.com/ajv-validator/ajv/issues/134), [#140](https://github.com/ajv-validator/ajv/issues/140), [#193](https://github.com/ajv-validator/ajv/issues/193), [#205](https://github.com/ajv-validator/ajv/issues/205), [#238](https://github.com/ajv-validator/ajv/issues/238), [#264](https://github.com/ajv-validator/ajv/issues/264). - ##### Why the keyword `additionalProperties: false` fails validation when some properties are "declared" inside a subschema in `anyOf`/etc.? 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. @@ -67,11 +54,11 @@ While you can expect that the schema below would allow the objects either with p ```json { - "properties": { "foo": { "type": "number" } }, + "properties": {"foo": {"type": "number"}}, "additionalProperties": false, "oneOf": [ - { "properties": { "bar": { "type": "number" } } }, - { "properties": { "baz": { "type": "number" } } } + {"properties": {"bar": {"type": "number"}}}, + {"properties": {"baz": {"type": "number"}}} ] } ``` @@ -80,21 +67,17 @@ The reason for that is that `additionalProperties` keyword ignores properties in There are several ways to implement the described logic that would allow two properties, please see the suggestions in the issues mentioned above. - ##### Why the validation fails when I use option `removeAdditional` with the keyword `anyOf`/etc.? This problem is related to the problem explained above - properties treated as additional in the sense of `additionalProperties` keyword, based on `properties`/`patternProperties` keyword in the same schema object. See the exemple in [Filtering Data](https://github.com/ajv-validator/ajv#filtering-data) section of readme. - - -## Generating schemas with resolved references ($ref) +## Generating schemas with resolved references (\$ref) See [#22](https://github.com/ajv-validator/ajv/issues/22), [#125](https://github.com/ajv-validator/ajv/issues/125), [#146](https://github.com/ajv-validator/ajv/issues/146), [#228](https://github.com/ajv-validator/ajv/issues/228), [#336](https://github.com/ajv-validator/ajv/issues/336), [#454](https://github.com/ajv-validator/ajv/issues/454). - -##### Why Ajv does not replace references ($ref) with the actual referenced schemas as some validators do? +##### Why Ajv does not replace references (\$ref) with the actual referenced schemas as some validators do? 1. The scope of Ajv is validating data against JSON Schemas; inlining referenced schemas is not necessary for validation. When Ajv generates code for validation it either inlines the code of referenced schema or uses function calls. Doing schema manipulation is more complex and out of scope. 2. When schemas are recursive (or mutually recursive) resolving references would result in self-referencing recursive data-structures that can be difficult to process. @@ -102,7 +85,6 @@ See [#22](https://github.com/ajv-validator/ajv/issues/22), [#125](https://github There were many conversations about the meaning of `$ref` in [JSON Schema GitHub organisation](https://github.com/json-schema-org). The consensus is that while it is possible to treat `$ref` as schema inclusion with two caveats (above), this interpretation is unnecessary complex. A more efficient approach is to treat `$ref` as a delegation, i.e. a special keyword that validates the current data instance against the referenced schema. The analogy with programming languages is that `$ref` is a function call rather than a macro. See [here](https://github.com/json-schema-org/json-schema-spec/issues/279), for example. - ##### How can I generate a schema where `$ref` keywords are replaced with referenced schemas? There are two possible approaches: diff --git a/KEYWORDS.md b/KEYWORDS.md index 6601a9a1b3..56175a1baa 100644 --- a/KEYWORDS.md +++ b/KEYWORDS.md @@ -1,48 +1,44 @@ # JSON Schema 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. - ## Keywords - [type](#type) - [Keywords for numbers](#keywords-for-numbers) - - [maximum / minimum and exclusiveMaximum / exclusiveMinimum](#maximum--minimum-and-exclusivemaximum--exclusiveminimum) (changed in draft-06) - - [multipleOf](#multipleof) + - [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) - - [pattern](#pattern) - - [format](#format) - - [formatMaximum / formatMinimum and formatExclusiveMaximum / formatExclusiveMinimum](#formatmaximum--formatminimum-and-formatexclusivemaximum--formatexclusiveminimum-proposed) (proposed) + - [maxLength/minLength](#maxlength--minlength) + - [pattern](#pattern) + - [format](#format) + - [formatMaximum / formatMinimum and formatExclusiveMaximum / formatExclusiveMinimum](#formatmaximum--formatminimum-and-formatexclusivemaximum--formatexclusiveminimum-proposed) (proposed) - [Keywords for arrays](#keywords-for-arrays) - - [maxItems/minItems](#maxitems--minitems) - - [uniqueItems](#uniqueitems) - - [items](#items) - - [additionalItems](#additionalitems) - - [contains](#contains) (added in draft-06) + - [maxItems/minItems](#maxitems--minitems) + - [uniqueItems](#uniqueitems) + - [items](#items) + - [additionalItems](#additionalitems) + - [contains](#contains) (added in draft-06) - [Keywords for objects](#keywords-for-objects) - - [maxProperties/minProperties](#maxproperties--minproperties) - - [required](#required) - - [properties](#properties) - - [patternProperties](#patternproperties) - - [additionalProperties](#additionalproperties) - - [dependencies](#dependencies) - - [propertyNames](#propertynames) (added in draft-06) - - [patternRequired](#patternrequired-proposed) (proposed) + - [maxProperties/minProperties](#maxproperties--minproperties) + - [required](#required) + - [properties](#properties) + - [patternProperties](#patternproperties) + - [additionalProperties](#additionalproperties) + - [dependencies](#dependencies) + - [propertyNames](#propertynames) (added in draft-06) + - [patternRequired](#patternrequired-proposed) (proposed) - [Keywords for all types](#keywords-for-all-types) - - [enum](#enum) - - [const](#const) (added in draft-06) + - [enum](#enum) + - [const](#const) (added in draft-06) - [Compound keywords](#compound-keywords) - - [not](#not) - - [oneOf](#oneof) - - [anyOf](#anyof) - - [allOf](#allof) - - [if/then/else](#ifthenelse) (NEW in draft-07) - - + - [not](#not) + - [oneOf](#oneof) + - [anyOf](#anyof) + - [allOf](#allof) + - [if/then/else](#ifthenelse) (NEW in draft-07) ## `type` @@ -50,8 +46,7 @@ The keywords and their values define what rules the data should satisfy to be va Type can be: `number`, `integer`, `string`, `boolean`, `array`, `object` or `null`. - -__Examples__ +**Examples** 1. _schema_: `{ "type": "number" }` @@ -59,30 +54,24 @@ __Examples__ _invalid_: `"abc"`, `"1"`, `[]`, `{}`, `null`, `true` - -2. _schema_: `{ "type": "integer" }` +2) _schema_: `{ "type": "integer" }` _valid_: `1`, `2` _invalid_: `"abc"`, `"1"`, `1.5`, `[]`, `{}`, `null`, `true` - 3. _schema_: `{ "type": ["number", "string"] }` _valid_: `1`, `1.5`, `"abc"`, `"1"` _invalid_: `[]`, `{}`, `null`, `true` - 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. - - ## Keywords for numbers - ### `maximum` / `minimum` and `exclusiveMaximum` / `exclusiveMinimum` The value of keyword `maximum` (`minimum`) should be a number. This value is the maximum (minimum) allowed value for the data to be valid. @@ -93,8 +82,7 @@ Draft-06/07: The value of keyword `exclusiveMaximum` (`exclusiveMinimum`) should Ajv supports both draft-04 and draft-06/07 syntaxes. - -__Examples__ +**Examples** 1. _schema_: `{ "maximum": 5 }` @@ -102,30 +90,25 @@ __Examples__ _invalid_: `6`, `7` - -2. _schema_: `{ "minimum": 5 }` +2) _schema_: `{ "minimum": 5 }` _valid_: `5`, `6`, any non-number (`"abc"`, `[]`, `{}`, `null`, `true`) _invalid_: `4`, `4.5` - 3. _schema_: - draft-04: `{ "minimum": 5, "exclusiveMinimum": true }` - draft-06/07: `{ "exclusiveMinimum": 5 }` + draft-04: `{ "minimum": 5, "exclusiveMinimum": true }` + draft-06/07: `{ "exclusiveMinimum": 5 }` _valid_: `6`, `7`, any non-number (`"abc"`, `[]`, `{}`, `null`, `true`) _invalid_: `4.5`, `5` - - ### `multipleOf` The value of the keyword should be a number. The data to be valid should be a multiple of the keyword value (i.e. the result of division of the data on the value should be integer). - -__Examples__ +**Examples** 1. _schema_: `{ "multipleOf": 5 }` @@ -133,23 +116,19 @@ __Examples__ _invalid_: `1`, `4` - -2. _schema_: `{ "multipleOf": 2.5 }` +2) _schema_: `{ "multipleOf": 2.5 }` _valid_: `2.5`, `5`, `7.5`, any non-number (`"abc"`, `[]`, `{}`, `null`, `true`) _invalid_: `1`, `4` - - ## Keywords for strings ### `maxLength` / `minLength` The value of the keywords should be a number. The data to be valid should have length satisfying this rule. Unicode pairs are counted as a single character. - -__Examples__ +**Examples** 1. _schema_: `{ "maxLength": 5 }` @@ -157,23 +136,19 @@ __Examples__ _invalid_: `"abcdef"` - -2. _schema_: `{ "minLength": 2 }` +2) _schema_: `{ "minLength": 2 }` _valid_: `"ab"`, `"😀😀"`, any non-string (`1`, `[]`, `{}`, `null`, `true`) _invalid_: `"a"`, `"😀"` - - ### `pattern` The value of the keyword should be a string. The data to be valid should match the regular expression defined by the keyword value. Ajv uses `new RegExp(value)` to create the regular expression that will be used to test data. - -__Example__ +**Example** _schema_: `{ "pattern": "[abc]+" }` @@ -181,16 +156,13 @@ _valid_: `"a"`, `"abcd"`, `"cde"`, any non-string (`1`, `[]`, `{}`, `null`, `tru _invalid_: `"def"`, `""` - - ### `format` The value of the keyword should be a string. The data to be valid should match the format with this name. -Ajv defines these formats: date, date-time, uri, email, hostname, ipv4, ipv6, regex. +Ajv does not include any formats, they can be added with [ajv-formats](https://github.com/ajv-validator/ajv-formats) plugin. - -__Example__ +**Example** _schema_: `{ "format": "ipv4" }` @@ -198,8 +170,6 @@ _valid_: `"192.168.0.1"`, any non-string (`1`, `[]`, `{}`, `null`, `true`) _invalid_: `"abc"` - - ### `formatMaximum` / `formatMinimum` and `formatExclusiveMaximum` / `formatExclusiveMinimum` (proposed) Defined in [ajv-keywords](https://github.com/ajv-validator/ajv-keywords) package. @@ -210,16 +180,15 @@ Ajv defines comparison rules for formats `"date"`, `"time"` and `"date-time"`. The value of keyword `formatExclusiveMaximum` (`formatExclusiveMinimum`) should be a boolean value. These keyword cannot be used without `formatMaximum` (`formatMinimum`). If this keyword value is equal to `true`, the data to be valid should not be equal to the value in `formatMaximum` (`formatMinimum`) keyword. - -__Example__ +**Example** _schema_: ```json { - "format": "date", - "formatMaximum": "2016-02-06", - "formatExclusiveMaximum": true + "format": "date", + "formatMaximum": "2016-02-06", + "formatExclusiveMaximum": true } ``` @@ -227,16 +196,13 @@ _valid_: `"2015-12-31"`, `"2016-02-05"`, any non-string _invalid_: `"2016-02-06"`, `"2016-02-07"`, `"abc"` - - ## Keywords for arrays ### `maxItems` / `minItems` The value of the keywords should be a number. The data array to be valid should not have more (less) items than the keyword value. - -__Example__ +**Example** _schema_: `{ "maxItems": 3 }` @@ -244,22 +210,17 @@ _valid_: `[]`, `[1]`, `["1", 2, "3"]`, any non-array (`"abc"`, `1`, `{}`, `null` _invalid_: `[1, 2, 3, 4]` - - ### `uniqueItems` The value of the keyword should be a boolean. If the keyword value is `true`, the data array to be valid should have unique items. - -__Example__ +**Example** _schema_: `{ "uniqueItems": true }` _valid_: `[]`, `[1]`, `["1", 2, "3"]`, any non-array (`"abc"`, `1`, `{}`, `null`, `true`) -_invalid_: `[1, 2, 1]`, `[{ "a": 1, "b": 2 }, { "b": 2, "a": 1 }]` - - +_invalid_: `[1, 2, 1]`, `[{ "a": 1, "b": 2 }, { "b": 2, "a": 1 }]` ### `items` @@ -269,8 +230,7 @@ If the keyword value is an object, then for the data array to be valid each item If the keyword value is an array, then items with indices less than the number of items in the keyword should be valid according to the schemas with the same indices. Whether additional items are valid will depend on "additionalItems" keyword. - -__Examples__ +**Examples** 1. _schema_: `{ "items": { "type": "integer" } }` @@ -278,14 +238,11 @@ __Examples__ _invalid_: `[1,"abc"]` +2) _schema_: -2. _schema_: ```json { - "items": [ - { "type": "integer" }, - { "type": "string" } - ] + "items": [{"type": "integer"}, {"type": "string"}] } ``` @@ -293,8 +250,6 @@ __Examples__ _invalid_: `["abc", 1]`, `["abc"]` - - ### `additionalItems` The value of the keyword should be a boolean or an object. @@ -309,19 +264,18 @@ If the length of data array is bigger than the length of "items" keyword value t - `true`: data is valid - an object: data is valid if all additional items (i.e. items with indices greater or equal than "items" keyword value length) are valid according to the schema in "additionalItems" keyword. - -__Examples__ +**Examples** 1. _schema_: `{ "additionalItems": { "type": "integer" } }` any data is valid against such schema - "additionalItems" is ignored. +2) _schema_: -2. _schema_: ```json { - "items": { "type": "integer" }, - "additionalItems": { "type": "string" } + "items": {"type": "integer"}, + "additionalItems": {"type": "string"} } ``` @@ -329,15 +283,12 @@ __Examples__ _invalid_: `[1, "abc"]`, (any array with some items other than integers) - 3. _schema_: + ```json { - "items": [ - { "type": "integer" }, - { "type": "integer" } - ], - "additionalItems": true + "items": [{"type": "integer"}, {"type": "integer"}], + "additionalItems": true } ``` @@ -345,15 +296,12 @@ __Examples__ _invalid_: `["abc"]`, `[1, "abc", 3]` +4) _schema_: -4. _schema_: ```json { - "items": [ - { "type": "integer" }, - { "type": "integer" } - ], - "additionalItems": { "type": "string" } + "items": [{"type": "integer"}, {"type": "integer"}], + "additionalItems": {"type": "string"} } ``` @@ -361,12 +309,11 @@ __Examples__ _invalid_: `["abc"]`, `[1, 2, 3]` - ### `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. -__Example__ +**Example** _schema_: `{ "contains": { "type": "integer" } }` @@ -374,29 +321,26 @@ _valid_: `[1]`, `[1, "foo"]`, any array with at least one integer, any non-array _invalid_: `[]`, `["foo", "bar"]`, any array without integers - The schema from the example above is equivalent to: ```json { - "not": { - "type": "array", - "items": { - "not": { "type": "integer" } - } + "not": { + "type": "array", + "items": { + "not": {"type": "integer"} } + } } ``` - ## Keywords for objects ### `maxProperties` / `minProperties` The value of the keywords should be a number. The data object to be valid should have not more (less) properties than the keyword value. - -__Example__ +**Example** _schema_: `{ "maxProperties": 2 }` @@ -404,14 +348,11 @@ _valid_: `{}`, `{"a": 1}`, `{"a": "1", "b": 2}`, any non-object _invalid_: `{"a": 1, "b": 2, "c": 3}` - - ### `required` The value of the keyword should be an array of unique strings. The data object to be valid should contain all properties with names equal to the elements in the keyword value. - -__Example__ +**Example** _schema_: `{ "required": ["a", "b"] }` @@ -419,26 +360,25 @@ _valid_: `{"a": 1, "b": 2}`, `{"a": 1, "b": 2, "c": 3}`, any non-object _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. -__Please note__: `properties` keyword does not require that the properties mentioned in it are present in the object (see examples). +**Please note**: `properties` keyword does not require that the properties mentioned in it are present in the object (see examples). -__Example__ +**Example** _schema_: + ```json { - "properties": { - "foo": { "type": "string" }, - "bar": { - "type": "number", - "minimum": 2 - } + "properties": { + "foo": {"type": "string"}, + "bar": { + "type": "number", + "minimum": 2 } + } } ``` @@ -446,26 +386,24 @@ _valid_: `{}`, `{"foo": "a"}`, `{"foo": "a", "bar": 2}`, any non-object _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). When the value in data object property matches multiple regular expressions it should be valid according to all the schemas for all matched regular expressions. -__Please note__: `patternProperties` keyword does not require that properties matching patterns are present in the object (see examples). +**Please note**: `patternProperties` keyword does not require that properties matching patterns are present in the object (see examples). - -__Example__ +**Example** _schema_: + ```json { - "patternProperties": { - "^fo.*$": { "type": "string" }, - "^ba.*$": { "type": "number" } - } + "patternProperties": { + "^fo.*$": {"type": "string"}, + "^ba.*$": {"type": "number"} + } } ``` @@ -473,8 +411,6 @@ _valid_: `{}`, `{"foo": "a"}`, `{"foo": "a", "bar": 1}`, any non-object _invalid_: `{"foo": 1}`, `{"foo": "a", "bar": "b"}` - - ### `additionalProperties` The value of the keyword should be either a boolean or a JSON Schema. @@ -485,19 +421,19 @@ If the value is `false` the data object to be valid should not have "additional If the value is a schema for the data object to be valid the values in all "additional properties" should be valid according to this schema. - -__Examples__ +**Examples** 1. _schema_: + ```json { - "properties": { - "foo": { "type": "number" } - }, - "patternProperties": { - "^.*r$": { "type": "number" } - }, - "additionalProperties": false + "properties": { + "foo": {"type": "number"} + }, + "patternProperties": { + "^.*r$": {"type": "number"} + }, + "additionalProperties": false } ``` @@ -505,16 +441,17 @@ __Examples__ _invalid_: `{"a": 3}`, `{"foo": 1, "baz": 3}` -2. _schema_: +2. _schema_: + ```json { - "properties": { - "foo": { "type": "number" } - }, - "patternProperties": { - "^.*r$": { "type": "number" } - }, - "additionalProperties": { "type": "string" } + "properties": { + "foo": {"type": "number"} + }, + "patternProperties": { + "^.*r$": {"type": "number"} + }, + "additionalProperties": {"type": "string"} } ``` @@ -522,33 +459,33 @@ __Examples__ _invalid_: `{"a": 3}`, `{"foo": 1, "baz": 3}` -3. _schema_: +3. _schema_: + ```json { - "properties": { - "foo": { "type": "number" } + "properties": { + "foo": {"type": "number"} + }, + "additionalProperties": false, + "anyOf": [ + { + "properties": { + "bar": {"type": "number"} + } }, - "additionalProperties": false, - "anyOf": [ - { - "properties": { - "bar": { "type": "number" } - } - }, - { - "properties": { - "baz": { "type": "number" } - } - } - ] + { + "properties": { + "baz": {"type": "number"} + } + } + ] } ``` + _valid_: `{}`, `{"foo": 1}`, any non-object _invalid_: `{"bar": 2}`, `{"baz": 3}`, `{"foo": 1, "bar": 2}`, etc. - - ### `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"). @@ -557,15 +494,15 @@ For property dependency, if the data object contains a property that is a key in For schema dependency, if the data object contains a property that is a key in the keyword value, then to be valid the data object itself (NOT the property value) should be valid according to the schema. - -__Examples__ +**Examples** 1. _schema (property dependency)_: + ```json { - "dependencies": { - "foo": ["bar", "baz"] - } + "dependencies": { + "foo": ["bar", "baz"] + } } ``` @@ -573,17 +510,17 @@ __Examples__ _invalid_: `{"foo": 1}`, `{"foo": 1, "bar": 2}`, `{"foo": 1, "baz": 3}` +2) _schema (schema dependency)_: -2. _schema (schema dependency)_: ```json { - "dependencies": { - "foo": { - "properties": { - "bar": { "type": "number" } - } - } + "dependencies": { + "foo": { + "properties": { + "bar": {"type": "number"} + } } + } } ``` @@ -591,22 +528,19 @@ __Examples__ _invalid_: `{"foo": 1, "bar": "a"}` - - ### `propertyNames` 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. +**Example** -__Example__ - -_schema_: +_schema_ (requires `email` format from [ajv-formats](https://github.com/ajv-validator/ajv-formats)): ```json { - "propertyNames": { "format": "email" } + "propertyNames": {"format": "email"} } ``` @@ -614,8 +548,6 @@ _valid_: `{"foo@bar.com": "any", "bar@bar.com": "any"}`, any non-object _invalid_: `{"foo": "any value"}` - - ### `patternRequired` (proposed) Defined in [ajv-keywords](https://github.com/ajv-validator/ajv-keywords) package. @@ -624,7 +556,7 @@ The value of this keyword should be an array of strings, each string being a reg If the array contains multiple regular expressions, more than one expression can match the same property name. -__Examples__ +**Examples** 1. _schema_: `{ "patternRequired": [ "f.*o" ] }` @@ -638,16 +570,13 @@ __Examples__ _invalid_: `{}`, `{ "foo": 1 }`, `{ "bar": 2 }` - - ## Keywords for all types ### `enum` The value of the keyword should be an array of unique items of any types. The data is valid if it is deeply equal to one of items in the array. - -__Example__ +**Example** _schema_: `{ "enum": [ 2, "foo", {"foo": "bar" }, [1, 2, 3] ] }` @@ -655,13 +584,11 @@ _valid_: `2`, `"foo"`, `{"foo": "bar"}`, `[1, 2, 3]` _invalid_: `1`, `"bar"`, `{"foo": "baz"}`, `[1, 2, 3, 4]`, any value not in the array - - ### `const` The value of this keyword can be anything. The data is valid if it is deeply equal to the value of the keyword. -__Example__ +**Example** _schema_: `{ "const": "foo" }` @@ -669,20 +596,18 @@ _valid_: `"foo"` _invalid_: any other value +The same can be achieved with `enum` keyword using the array with one item. But `const` keyword is more than just a syntax sugar for `enum`. In combination with the [\$data reference](https://github.com/ajv-validator/ajv#data-reference) it allows to define equality relations between different parts of the data. This cannot be achieved with `enum` keyword even with `$data` reference because `$data` cannot be used in place of one item - it can only be used in place of the whole array in `enum` keyword. -The same can be achieved with `enum` keyword using the array with one item. But `const` keyword is more than just a syntax sugar for `enum`. In combination with the [$data reference](https://github.com/ajv-validator/ajv#data-reference) it allows to define equality relations between different parts of the data. This cannot be achieved with `enum` keyword even with `$data` reference because `$data` cannot be used in place of one item - it can only be used in place of the whole array in `enum` keyword. - - -__Example__ +**Example** _schema_: ```json { - "properties": { - "foo": { "type": "number" }, - "bar": { "const": { "$data": "1/foo" } } - } + "properties": { + "foo": {"type": "number"}, + "bar": {"const": {"$data": "1/foo"}} + } } ``` @@ -690,16 +615,13 @@ _valid_: `{ "foo": 1, "bar": 1 }`, `{}` _invalid_: `{ "foo": 1 }`, `{ "bar": 1 }`, `{ "foo": 1, "bar": 2 }` - - ## Compound keywords ### `not` The value of the keyword should be a JSON Schema. The data is valid if it is invalid according to this schema. - -__Examples__ +**Examples** 1. _schema_: `{ "not": { "minimum": 3 } }` @@ -711,11 +633,11 @@ __Examples__ ```json { - "not": { - "items": { - "not": { "type": "string" } - } + "not": { + "items": { + "not": {"type": "string"} } + } } ``` @@ -723,22 +645,17 @@ __Examples__ _invalid_: `[]`, `[1]`, any non-array, any array not containing strings - - ### `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. - -__Example__ +**Example** _schema_: + ```json { - "oneOf": [ - { "maximum": 3 }, - { "type": "integer" } - ] + "oneOf": [{"maximum": 3}, {"type": "integer"}] } ``` @@ -746,22 +663,17 @@ _valid_: `1.5`, `2.5`, `4`, `5`, any non-number _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. - -__Example__ +**Example** _schema_: + ```json { - "anyOf": [ - { "maximum": 3 }, - { "type": "integer" } - ] + "anyOf": [{"maximum": 3}, {"type": "integer"}] } ``` @@ -769,22 +681,17 @@ _valid_: `1.5`, `2`, `2.5`, `3`, `4`, `5`, any non-number _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. - -__Example__ +**Example** _schema_: + ```json { - "allOf": [ - { "maximum": 3 }, - { "type": "integer" } - ] + "allOf": [{"maximum": 3}, {"type": "integer"}] } ``` @@ -792,8 +699,6 @@ _valid_: `2`, `3` _invalid_: `1.5`, `2.5`, `4`, `4.5`, `5`, `5.5`, any non-number - - ### `if`/`then`/`else` These keywords allow to implement conditional validation. Their values should be valid JSON Schemas (object or boolean). @@ -804,16 +709,15 @@ If the data is valid against the sub-schema in `if` keyword, then the validation 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__ +**Examples** 1. _schema_: ```json { - "if": { "properties": { "power": { "minimum": 9000 } } }, - "then": { "required": [ "disbelief" ] }, - "else": { "required": [ "confidence" ] } + "if": {"properties": {"power": {"minimum": 9000}}}, + "then": {"required": ["disbelief"]}, + "else": {"required": ["confidence"]} } ``` @@ -830,20 +734,19 @@ __Examples__ - `{ "power": 10000, "confidence": true }` (`disbelief` is required) - `{ "power": 1000 }` (`confidence` is required) - -2. _schema_: +2) _schema_: ```json { - "type": "integer", - "minimum": 1, - "maximum": 1000, - "if": { "minimum": 100 }, - "then": { "multipleOf": 100 }, - "else": { - "if": { "minimum": 10 }, - "then": { "multipleOf": 10 } - } + "type": "integer", + "minimum": 1, + "maximum": 1000, + "if": {"minimum": 100}, + "then": {"multipleOf": 100}, + "else": { + "if": {"minimum": 10}, + "then": {"multipleOf": 10} + } } ``` diff --git a/README.md b/README.md index ce4507fdbb..4c266ba595 100644 --- a/README.md +++ b/README.md @@ -11,12 +11,12 @@ The fastest JSON Schema validator for Node.js and browser. Supports draft-04/06/ [![Gitter](https://img.shields.io/gitter/room/ajv-validator/ajv.svg)](https://gitter.im/ajv-validator/ajv) [![GitHub Sponsors](https://img.shields.io/badge/$-sponsors-brightgreen)](https://github.com/sponsors/epoberezkin) - ## Please [sponsor Ajv development](https://github.com/sponsors/epoberezkin) I will get straight to the point - I need your support to ensure that the development of Ajv continues. -I have developed Ajv for 5 years in my free time, but it is not sustainable. I'd appreciate if you consider supporting its further development with donations: +I have developed Ajv for 5 years in my free time, but it is not sustainable. I'd appreciate if you consider supporting its further development with donations: + - [GitHub sponsors page](https://github.com/sponsors/epoberezkin) (GitHub will match it) - [Ajv Open Collective️](https://opencollective.com/ajv) @@ -36,7 +36,6 @@ I believe it would benefit all Ajv users to help put together the fund that will Thank you - #### Open Collective sponsors @@ -52,29 +51,27 @@ Thank you - ## Using version 6 [JSON Schema draft-07](http://json-schema.org/latest/json-schema-validation.html) is published. [Ajv version 6.0.0](https://github.com/ajv-validator/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). -__Please note__: To use Ajv with draft-06 schemas you need to explicitly add the 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')); +ajv.addMetaSchema(require("ajv/lib/refs/json-schema-draft-06.json")) ``` To use Ajv with draft-04 schemas in addition to explicitly adding meta-schema you also need to use option schemaId: ```javascript -var ajv = new Ajv({schemaId: 'id'}); +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')); +ajv.addMetaSchema(require("ajv/lib/refs/json-schema-draft-04.json")) ``` - ## Contents - [Performance](#performance) @@ -88,8 +85,8 @@ ajv.addMetaSchema(require('ajv/lib/refs/json-schema-draft-04.json')); - [Keywords](#validation-keywords) - [Annotation keywords](#annotation-keywords) - [Formats](#formats) - - [Combining schemas with $ref](#ref) - - [$data reference](#data-reference) + - [Combining schemas with \$ref](#ref) + - [\$data reference](#data-reference) - NEW: [$merge and $patch keywords](#merge-and-patch-keywords) - [Defining custom keywords](#defining-custom-keywords) - [Asynchronous schema compilation](#asynchronous-schema-compilation) @@ -114,7 +111,6 @@ ajv.addMetaSchema(require('ajv/lib/refs/json-schema-draft-04.json')); - [Tests, Contributing, Changes history](#tests) - [Support, Code of conduct, License](#open-source-software-support) - ## 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. @@ -126,12 +122,10 @@ Currently Ajv is the fastest and the most standard compliant validator according - [z-schema benchmark](https://rawgit.com/zaggino/z-schema/master/benchmark/results.html) - [themis benchmark](https://cdn.rawgit.com/playlyfe/themis/master/benchmark/results.html) - Performance of different validators by [json-schema-benchmark](https://github.com/ebdrup/json-schema-benchmark): [![performance](https://chart.googleapis.com/chart?chxt=x,y&cht=bhs&chco=76A4FB&chls=2.0&chbh=32,4,1&chs=600x416&chxl=-1:|djv|ajv|json-schema-validator-generator|jsen|is-my-json-valid|themis|z-schema|jsck|skeemas|json-schema-library|tv4&chd=t:100,98,72.1,66.8,50.1,15.1,6.1,3.8,1.2,0.7,0.2)](https://github.com/ebdrup/json-schema-benchmark/blob/master/README.md#performance) - ## Features - Ajv implements full JSON Schema [draft-06/07](http://json-schema.org/) and draft-04 standards: @@ -139,7 +133,7 @@ Performance of different validators by [json-schema-benchmark](https://github.co - 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-07 standard and custom formats (can be turned off) + - [formats](#formats) defined by JSON Schema draft-07 standard (with [ajv-formats](https://github.com/ajv-validator/ajv-formats) plugin) and custom formats (can be turned off) - [validates schemas against meta-schema](#api-validateschema) - supports [browsers](#using-in-browser) and Node.js 0.10-14.x - [asynchronous loading](#asynchronous-schema-compilation) of referenced schemas during compilation @@ -153,44 +147,41 @@ Performance of different validators by [json-schema-benchmark](https://github.co - draft-06/07 keywords `const`, `contains`, `propertyNames` and `if/then/else` - draft-06 boolean schemas (`true`/`false` as a schema to always pass/fail). - 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/ajv-validator/ajv-keywords) package -- [$data reference](#data-reference) to use values from the validated data as values for the schema keywords +- [\$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 Currently Ajv is the only validator that passes all the tests from [JSON Schema Test Suite](https://github.com/json-schema/JSON-Schema-Test-Suite) (according to [json-schema-benchmark](https://github.com/ebdrup/json-schema-benchmark), apart from the test that requires that `1.0` is not an integer that is impossible to satisfy in JavaScript). - ## Install ``` npm install ajv ``` - ## Getting started Try it in the Node.js REPL: https://tonicdev.com/npm/ajv - The fastest validation call: ```javascript // Node.js require: -var Ajv = require('ajv'); +var Ajv = require("ajv") // or ESM/TypeScript import -import Ajv from 'ajv'; +import Ajv from "ajv" -var ajv = new Ajv(); // options can be passed, e.g. {allErrors: true} -var validate = ajv.compile(schema); -var valid = validate(data); -if (!valid) console.log(validate.errors); +var ajv = new Ajv() // options can be passed, e.g. {allErrors: true} +var validate = ajv.compile(schema) +var valid = validate(data) +if (!valid) console.log(validate.errors) ``` or with less code ```javascript // ... -var valid = ajv.validate(schema, data); -if (!valid) console.log(ajv.errors); +var valid = ajv.validate(schema, data) +if (!valid) console.log(ajv.errors) // ... ``` @@ -198,9 +189,8 @@ or ```javascript // ... -var valid = ajv.addSchema(schema, 'mySchema') - .validate('mySchema', data); -if (!valid) console.log(ajv.errorsText()); +var valid = ajv.addSchema(schema, "mySchema").validate("mySchema", data) +if (!valid) console.log(ajv.errorsText()) // ... ``` @@ -210,13 +200,12 @@ Ajv compiles schemas to functions and caches them in all cases (using schema ser The best performance is achieved when using compiled functions returned by `compile` or `getSchema` methods (there is no additional function call). -__Please note__: every time a validation function or `ajv.validate` are called `errors` property is overwritten. You need to copy `errors` array reference to another variable if you want to use it later (e.g., in the callback). See [Validation errors](#validation-errors) +**Please note**: every time a validation function or `ajv.validate` are called `errors` property is overwritten. You need to copy `errors` array reference to another variable if you want to use it later (e.g., in the callback). See [Validation errors](#validation-errors) -__Note for TypeScript users__: `ajv` provides its own TypeScript declarations +**Note for TypeScript users**: `ajv` provides its own TypeScript declarations out of the box, so you don't need to install the deprecated `@types/ajv` module. - ## Using in browser You can require Ajv directly from the code you browserify - in this case Ajv will be a part of your bundle. @@ -224,6 +213,7 @@ You can require Ajv directly from the code you browserify - in this case Ajv wil If you need to use Ajv in several bundles you can create a separate UMD bundle using `npm run bundle` script (thanks to [siddo420](https://github.com/siddo420)). Then you need to load Ajv in the browser: + ```html ``` @@ -236,8 +226,7 @@ Ajv is tested with these browsers: [![Sauce Test Status](https://saucelabs.com/browser-matrix/epoberezkin.svg)](https://saucelabs.com/u/epoberezkin) -__Please note__: some frameworks, e.g. Dojo, may redefine global require in such way that is not compatible with CommonJS module format. In such case Ajv bundle has to be loaded before the framework and then you can use global Ajv (see issue [#234](https://github.com/ajv-validator/ajv/issues/234)). - +**Please note**: some frameworks, e.g. Dojo, may redefine global require in such way that is not compatible with CommonJS module format. In such case Ajv bundle has to be loaded before the framework and then you can use global Ajv (see issue [#234](https://github.com/ajv-validator/ajv/issues/234)). ### Ajv and Content Security Policies (CSP) @@ -248,7 +237,6 @@ In order to make use of Ajv without easing your CSP, you can [pre-compile a sche Note that pre-compilation of schemas is performed using [ajv-pack](https://github.com/ajv-validator/ajv-pack) and there are [some limitations to the schema features it can compile](https://github.com/ajv-validator/ajv-pack#limitations). A successfully pre-compiled schema is equivalent to the same schema compiled at runtime. - ## Command line interface CLI is available as a separate npm package [ajv-cli](https://github.com/ajv-validator/ajv-cli). It supports: @@ -264,7 +252,6 @@ CLI is available as a separate npm package [ajv-cli](https://github.com/ajv-vali - all Ajv options - reporting changes in data after validation in [JSON-patch](https://tools.ietf.org/html/rfc6902) format - ## Validation keywords Ajv supports all validation keywords from draft-07 of JSON Schema standard: @@ -284,7 +271,6 @@ With [ajv-keywords](https://github.com/ajv-validator/ajv-keywords) package Ajv a See [JSON Schema validation keywords](https://github.com/ajv-validator/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. @@ -294,19 +280,29 @@ JSON Schema specification defines several annotation keywords that describe sche - `default`: a default value of the data instance, see [Assigning defaults](#assigning-defaults). - `examples` (NEW in draft-06): an array of data instances. Ajv does not check the validity of these instances against the schema. - `readOnly` and `writeOnly` (NEW in draft-07): marks data-instance as read-only or write-only in relation to the source of the data (database, api, etc.). -- `contentEncoding`: [RFC 2045](https://tools.ietf.org/html/rfc2045#section-6.1 ), e.g., "base64". +- `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 keywords from the instance. - +**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 keywords from the instance. ## Formats -Ajv implements formats defined by JSON Schema specification and several other formats. It is recommended NOT to use "format" keyword implementations with untrusted data, as they use potentially unsafe regular expressions - see [ReDoS attack](#redos-attack). +From version 7 Ajv does not include formats defined by JSON Schema specification - these and several others formats are provided by [ajv-formats](https://github.com/ajv-validator/ajv-formats) plugin. -__Please note__: if you need to use "format" keyword to validate untrusted data, you MUST assess their suitability and safety for your validation scenarios. +To add all formats from this plugin: -The following formats are implemented for string validation with "format" keyword: +```javascript +const ajv = new Ajv() +require("ajv-formats")(ajv) +``` + +See ajv-formats documentation for further details. + +It is recommended NOT to use "format" keyword implementations with untrusted data, as they use potentially unsafe regular expressions - see [ReDoS attack](#redos-attack). + +**Please note**: if you need to use "format" keyword to validate untrusted data, you MUST assess their suitability and safety for your validation scenarios. + +The following formats are defined in [ajv-formats](https://github.com/ajv-validator/ajv-formats) for string validation with "format" keyword: - _date_: full-date according to [RFC3339](http://tools.ietf.org/html/rfc3339#section-5.6). - _time_: time with optional time-zone. @@ -324,18 +320,15 @@ The following formats are implemented for string validation with "format" keywor - _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 to mention this plugin here. - -There are two modes of format validation: `fast` and `full`. This mode affects formats `date`, `time`, `date-time`, `uri`, `uri-reference`, and `email`. See [Options](#options) for details. +**Please note**: JSON Schema draft-07 also defines formats `iri`, `iri-reference`, `idn-hostname` and `idn-email` for URLs, hostnames and emails with international characters. These formats are available in [ajv-formats-draft2019](https://github.com/luzlab/ajv-formats-draft2019) plugin. -You can add additional formats and replace any of the formats above using [addFormat](#api-addformat) method. +You can add (and replace) any formats using [addFormat](#api-addformat) method. The option `unknownFormats` allows changing the default behaviour when an unknown format is encountered. In this case Ajv can either fail schema compilation (default) or ignore it (default in versions before 5.0.0). You also can allow specific format(s) that will be ignored. See [Options](#options) for details. You can find regular expressions used for format validation and the sources that were used in [formats.js](https://github.com/ajv-validator/ajv/blob/master/lib/compile/formats.js). - -## Combining schemas with $ref +## Combining schemas with \$ref You can structure your validation logic across multiple schema files and have schemas reference each other using `$ref` keyword. @@ -343,102 +336,100 @@ Example: ```javascript var schema = { - "$id": "http://example.com/schemas/schema.json", - "type": "object", - "properties": { - "foo": { "$ref": "defs.json#/definitions/int" }, - "bar": { "$ref": "defs.json#/definitions/str" } - } -}; + $id: "http://example.com/schemas/schema.json", + type: "object", + properties: { + foo: {$ref: "defs.json#/definitions/int"}, + bar: {$ref: "defs.json#/definitions/str"}, + }, +} var defsSchema = { - "$id": "http://example.com/schemas/defs.json", - "definitions": { - "int": { "type": "integer" }, - "str": { "type": "string" } - } -}; + $id: "http://example.com/schemas/defs.json", + definitions: { + int: {type: "integer"}, + str: {type: "string"}, + }, +} ``` Now to compile your schema you can either pass all schemas to Ajv instance: ```javascript -var ajv = new Ajv({schemas: [schema, defsSchema]}); -var validate = ajv.getSchema('http://example.com/schemas/schema.json'); +var ajv = new Ajv({schemas: [schema, defsSchema]}) +var validate = ajv.getSchema("http://example.com/schemas/schema.json") ``` or use `addSchema` method: ```javascript -var ajv = new Ajv; -var validate = ajv.addSchema(defsSchema) - .compile(schema); +var ajv = new Ajv() +var validate = ajv.addSchema(defsSchema).compile(schema) ``` See [Options](#options) and [addSchema](#api) method. -__Please note__: -- `$ref` is resolved as the uri-reference using schema $id as the base URI (see the example). +**Please note**: + +- `$ref` is resolved as the uri-reference using schema \$id as the base URI (see the example). - References can be recursive (and mutually recursive) to implement the schemas for different data structures (such as linked lists, trees, graphs, etc.). -- You don't have to host your schema files at the URIs that you use as schema $id. These URIs are only used to identify the schemas, and according to JSON Schema specification validators should not expect to be able to download the schemas from these URIs. +- You don't have to host your schema files at the URIs that you use as schema \$id. These URIs are only used to identify the schemas, and according to JSON Schema specification validators should not expect to be able to download the schemas from these URIs. - The actual location of the schema file in the file system is not used. -- You can pass the identifier of the schema as the second parameter of `addSchema` method or as a property name in `schemas` option. This identifier can be used instead of (or in addition to) schema $id. -- You cannot have the same $id (or the schema identifier) used for more than one schema - the exception will be thrown. +- You can pass the identifier of the schema as the second parameter of `addSchema` method or as a property name in `schemas` option. This identifier can be used instead of (or in addition to) schema \$id. +- You cannot have the same \$id (or the schema identifier) used for more than one schema - the exception will be thrown. - You can implement dynamic resolution of the referenced schemas using `compileAsync` method. In this way you can store schemas in any system (files, web, database, etc.) and reference them without explicitly adding to Ajv instance. See [Asynchronous schema compilation](#asynchronous-schema-compilation). - -## $data reference +## \$data reference With `$data` option you can use values from the validated data as the values for the schema keywords. See [proposal](https://github.com/json-schema-org/json-schema-spec/issues/51) for more information about how it works. `$data` reference is supported in the keywords: const, enum, format, maximum/minimum, exclusiveMaximum / exclusiveMinimum, maxLength / minLength, maxItems / minItems, maxProperties / minProperties, formatMaximum / formatMinimum, formatExclusiveMaximum / formatExclusiveMinimum, multipleOf, pattern, required, uniqueItems. -The value of "$data" should be a [JSON-pointer](https://tools.ietf.org/html/rfc6901) to the data (the root is always the top level data object, even if the $data reference is inside a referenced subschema) or a [relative JSON-pointer](http://tools.ietf.org/html/draft-luff-relative-json-pointer-00) (it is relative to the current point in data; if the $data reference is inside a referenced subschema it cannot point to the data outside of the root level for this subschema). +The value of "$data" should be a [JSON-pointer](https://tools.ietf.org/html/rfc6901) to the data (the root is always the top level data object, even if the $data reference is inside a referenced subschema) or a [relative JSON-pointer](http://tools.ietf.org/html/draft-luff-relative-json-pointer-00) (it is relative to the current point in data; if the \$data reference is inside a referenced subschema it cannot point to the data outside of the root level for this subschema). Examples. This schema requires that the value in property `smaller` is less or equal than the value in the property larger: ```javascript -var ajv = new Ajv({$data: true}); +var ajv = new Ajv({$data: true}) var schema = { - "properties": { - "smaller": { - "type": "number", - "maximum": { "$data": "1/larger" } + properties: { + smaller: { + type: "number", + maximum: {$data: "1/larger"}, }, - "larger": { "type": "number" } - } -}; + larger: {type: "number"}, + }, +} var validData = { smaller: 5, - larger: 7 -}; + larger: 7, +} -ajv.validate(schema, validData); // true +ajv.validate(schema, validData) // true ``` This schema requires that the properties have the same format as their field names: ```javascript var schema = { - "additionalProperties": { - "type": "string", - "format": { "$data": "0#" } - } -}; + additionalProperties: { + type: "string", + format: {$data: "0#"}, + }, +} var validData = { - 'date-time': '1963-06-19T08:30:06.283185Z', - email: 'joe.bloggs@example.com' + "date-time": "1963-06-19T08:30:06.283185Z", + email: "joe.bloggs@example.com", } ``` `$data` reference is resolved safely - it won't throw even if some property is undefined. If `$data` resolves to `undefined` the validation succeeds (with the exclusion of `const` keyword). If `$data` resolves to incorrect type (e.g. not "number" for maximum keyword) the validation fails. - ## $merge and $patch keywords With the package [ajv-merge-patch](https://github.com/ajv-validator/ajv-merge-patch) you can use the keywords `$merge` and `$patch` that allow extending JSON Schemas with patches using formats [JSON Merge Patch (RFC 7396)](https://tools.ietf.org/html/rfc7396) and [JSON Patch (RFC 6902)](https://tools.ietf.org/html/rfc6902). @@ -446,7 +437,7 @@ With the package [ajv-merge-patch](https://github.com/ajv-validator/ajv-merge-pa To add keywords `$merge` and `$patch` to Ajv instance use this code: ```javascript -require('ajv-merge-patch')(ajv); +require("ajv-merge-patch")(ajv) ``` Examples. @@ -458,11 +449,11 @@ Using `$merge`: "$merge": { "source": { "type": "object", - "properties": { "p": { "type": "string" } }, + "properties": {"p": {"type": "string"}}, "additionalProperties": false }, "with": { - "properties": { "q": { "type": "number" } } + "properties": {"q": {"type": "number"}} } } } @@ -475,11 +466,11 @@ Using `$patch`: "$patch": { "source": { "type": "object", - "properties": { "p": { "type": "string" } }, + "properties": {"p": {"type": "string"}}, "additionalProperties": false }, "with": [ - { "op": "add", "path": "/properties/q", "value": { "type": "number" } } + {"op": "add", "path": "/properties/q", "value": {"type": "number"}} ] } } @@ -491,8 +482,8 @@ The schemas above are equivalent to this schema: { "type": "object", "properties": { - "p": { "type": "string" }, - "q": { "type": "number" } + "p": {"type": "string"}, + "q": {"type": "number"} }, "additionalProperties": false } @@ -502,7 +493,6 @@ The properties `source` and `with` in the keywords `$merge` and `$patch` can use See the package [ajv-merge-patch](https://github.com/ajv-validator/ajv-merge-patch) for more information. - ## Defining custom keywords The advantages of using custom keywords are: @@ -520,6 +510,7 @@ The concerns you have to be aware of when extending JSON Schema standard with cu 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. Ajv allows defining keywords with: + - validation function - compilation function - macro function @@ -528,31 +519,34 @@ Ajv allows defining keywords with: Example. `range` and `exclusiveRange` keywords using compiled schema: ```javascript -ajv.addKeyword('range', { - type: 'number', +ajv.addKeyword("range", { + type: "number", compile: function (sch, parentSchema) { - var min = sch[0]; - var max = sch[1]; + var min = sch[0] + var max = sch[1] return parentSchema.exclusiveRange === true - ? function (data) { return data > min && data < max; } - : function (data) { return data >= min && data <= max; } - } -}); - -var schema = { "range": [2, 4], "exclusiveRange": true }; -var validate = ajv.compile(schema); -console.log(validate(2.01)); // true -console.log(validate(3.99)); // true -console.log(validate(2)); // false -console.log(validate(4)); // false + ? function (data) { + return data > min && data < max + } + : function (data) { + return data >= min && data <= max + } + }, +}) + +var schema = {range: [2, 4], exclusiveRange: true} +var validate = ajv.compile(schema) +console.log(validate(2.01)) // true +console.log(validate(3.99)) // true +console.log(validate(2)) // false +console.log(validate(4)) // false ``` Several custom keywords (typeof, instanceof, range and propertyNames) are defined in [ajv-keywords](https://github.com/ajv-validator/ajv-keywords) package - they can be used for your schemas and as a starting point for your own custom keywords. See [Defining custom keywords](https://github.com/ajv-validator/ajv/blob/master/CUSTOM.md) for more details. - ## Asynchronous schema compilation During asynchronous compilation remote references are loaded using supplied function. See `compileAsync` [method](#api-compileAsync) and `loadSchema` [option](#options). @@ -560,24 +554,23 @@ During asynchronous compilation remote references are loaded using supplied func Example: ```javascript -var ajv = new Ajv({ loadSchema: loadSchema }); +var ajv = new Ajv({loadSchema: loadSchema}) ajv.compileAsync(schema).then(function (validate) { - var valid = validate(data); + var valid = validate(data) // ... -}); +}) function loadSchema(uri) { return request.json(uri).then(function (res) { if (res.statusCode >= 400) - throw new Error('Loading error: ' + res.statusCode); - return res.body; - }); + throw new Error("Loading error: " + res.statusCode) + return res.body + }) } ``` -__Please note__: [Option](#options) `missingRefs` should NOT be set to `"ignore"` or `"fail"` for asynchronous compilation to work. - +**Please note**: [Option](#options) `missingRefs` should NOT be set to `"ignore"` or `"fail"` for asynchronous compilation to work. ## Asynchronous validation @@ -587,7 +580,7 @@ You can define custom formats and keywords that perform validation asynchronousl If your schema uses asynchronous formats/keywords or refers to some schema that contains them it should have `"$async": true` keyword so that Ajv can compile it correctly. If asynchronous format/keyword or reference to asynchronous schema is used in the schema without `$async` keyword Ajv will throw an exception during schema compilation. -__Please note__: all asynchronous subschemas that are referenced from the current or other schemas should have `"$async": true` keyword as well, otherwise the schema compilation will fail. +**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). @@ -597,101 +590,95 @@ The compiled validation function has `$async: true` property (if the schema is a 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 -var ajv = new Ajv; +var ajv = new Ajv() // require('ajv-async')(ajv); -ajv.addKeyword('idExists', { +ajv.addKeyword("idExists", { async: true, - type: 'number', - validate: checkIdExists -}); - + type: "number", + validate: checkIdExists, +}) function checkIdExists(schema, data) { return knex(schema.table) - .select('id') - .where('id', data) - .then(function (rows) { - return !!rows.length; // true if record is found - }); + .select("id") + .where("id", data) + .then(function (rows) { + return !!rows.length // true if record is found + }) } var schema = { - "$async": true, - "properties": { - "userId": { - "type": "integer", - "idExists": { "table": "users" } + $async: true, + properties: { + userId: { + type: "integer", + idExists: {table: "users"}, }, - "postId": { - "type": "integer", - "idExists": { "table": "posts" } - } - } -}; - -var validate = ajv.compile(schema); + postId: { + type: "integer", + idExists: {table: "posts"}, + }, + }, +} -validate({ userId: 1, postId: 19 }) -.then(function (data) { - console.log('Data is valid', data); // { userId: 1, postId: 19 } -}) -.catch(function (err) { - if (!(err instanceof Ajv.ValidationError)) throw err; - // data is invalid - console.log('Validation errors:', err.errors); -}); +var validate = ajv.compile(schema) + +validate({userId: 1, postId: 19}) + .then(function (data) { + console.log("Data is valid", data) // { userId: 1, postId: 19 } + }) + .catch(function (err) { + if (!(err instanceof Ajv.ValidationError)) throw err + // data is invalid + console.log("Validation errors:", err.errors) + }) ``` ### Using transpilers with asynchronous validation functions. [ajv-async](https://github.com/ajv-validator/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 ajv = new Ajv; -require('ajv-async')(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); +var validate = ajv.compile(schema) // transpiled es7 async function +validate(data).then(successFunc).catch(errorFunc) ``` - #### Using other transpilers ```javascript -var ajv = new Ajv({ processCode: transpileFunc }); -var validate = ajv.compile(schema); // transpiled es7 async function -validate(data).then(successFunc).catch(errorFunc); +var ajv = new Ajv({processCode: transpileFunc}) +var validate = ajv.compile(schema) // transpiled es7 async function +validate(data).then(successFunc).catch(errorFunc) ``` See [Options](#options). - ## Security considerations JSON Schema, if properly used, can replace data sanitisation. It doesn't replace other API security considerations. It also introduces additional security aspects to consider. - ##### Security contact To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security). Tidelift will coordinate the fix and disclosure. Please do NOT report security vulnerabilities via GitHub issues. - ##### Untrusted schemas Ajv treats JSON schemas as trusted as your application code. This security model is based on the most common use case, when the schemas are static and bundled together with the application. If your schemas are received from untrusted sources (or generated from untrusted data) there are several scenarios you need to prevent: + - compiling schemas can cause stack overflow (if they are too deep) - compiling schemas can be slow (e.g. [#557](https://github.com/ajv-validator/ajv/issues/557)) - validating certain data can be slow @@ -700,14 +687,12 @@ It is difficult to predict all the scenarios, but at the very least it may help Regardless the measures you take, using untrusted schemas increases security risks. - ##### Circular references in JavaScript objects Ajv does not support schemas and validated data that have circular references in objects. See [issue #802](https://github.com/ajv-validator/ajv/issues/802). An attempt to compile such schemas or validate such data would cause stack overflow (or will not complete in case of asynchronous validation). Depending on the parser you use, untrusted data can lead to circular references. - ##### Security risks of trusted schemas Some keywords in JSON Schemas can lead to very slow validation for certain data. These keywords include (but may be not limited to): @@ -716,26 +701,27 @@ Some keywords in JSON Schemas can lead to very slow validation for certain data. - `patternProperties` for large property names - use `propertyNames` to mitigate, but some regular expressions can have exponential evaluation time as well. - `uniqueItems` for large non-scalar arrays - use `maxItems` to mitigate -__Please note__: The suggestions above to prevent slow validation would only work if you do NOT use `allErrors: true` in production code (using it would continue validation after validation errors). +**Please note**: The suggestions above to prevent slow validation would only work if you do NOT use `allErrors: true` in production code (using it would continue validation after validation errors). You can validate your JSON schemas against [this meta-schema](https://github.com/ajv-validator/ajv/blob/master/lib/refs/json-schema-secure.json) to check that these recommendations are followed: ```javascript -const isSchemaSecure = ajv.compile(require('ajv/lib/refs/json-schema-secure.json')); +const isSchemaSecure = ajv.compile( + require("ajv/lib/refs/json-schema-secure.json") +) -const schema1 = {format: 'email'}; -isSchemaSecure(schema1); // false +const schema1 = {format: "email"} +isSchemaSecure(schema1) // false -const schema2 = {format: 'email', maxLength: MAX_LENGTH}; -isSchemaSecure(schema2); // true +const schema2 = {format: "email", maxLength: MAX_LENGTH} +isSchemaSecure(schema2) // true ``` -__Please note__: following all these recommendation is not a guarantee that validation of untrusted data is safe - it can still lead to some undesirable results. - +**Please note**: following all these recommendation is not a guarantee that validation of untrusted data is safe - it can still lead to some undesirable results. ##### Content Security Policies (CSP) -See [Ajv and Content Security Policies (CSP)](#ajv-and-content-security-policies-csp) +See [Ajv and Content Security Policies (CSP)](#ajv-and-content-security-policies-csp) ## ReDoS attack @@ -743,7 +729,7 @@ Certain regular expressions can lead to the exponential evaluation time even wit Please assess the regular expressions you use in the schemas on their vulnerability to this attack - see [safe-regex](https://github.com/substack/safe-regex), for example. -__Please note__: some formats that Ajv implements use [regular expressions](https://github.com/ajv-validator/ajv/blob/master/lib/compile/formats.js) that can be vulnerable to ReDoS attack, so if you use Ajv to validate data from untrusted sources __it is strongly recommended__ to consider the following: +**Please note**: some formats that Ajv implements use [regular expressions](https://github.com/ajv-validator/ajv/blob/master/lib/compile/formats.js) that can be vulnerable to ReDoS attack, so if you use Ajv to validate data from untrusted sources **it is strongly recommended** to consider the following: - making assessment of "format" implementations in Ajv. - using `format: 'fast'` option that simplifies some of the regular expressions (although it does not guarantee that they are safe). @@ -752,7 +738,6 @@ __Please note__: some formats that Ajv implements use [regular expressions](http Whatever mitigation you choose, please assume all formats provided by Ajv as potentially unsafe and make your own assessment of their suitability for your validation scenarios. - ## Filtering data With [option `removeAdditional`](#options) (added by [andyscott](https://github.com/andyscott)) you can filter data during the validation. @@ -762,40 +747,40 @@ This option modifies original data. Example: ```javascript -var ajv = new Ajv({ removeAdditional: true }); +var ajv = new Ajv({removeAdditional: true}) var schema = { - "additionalProperties": false, - "properties": { - "foo": { "type": "number" }, - "bar": { - "additionalProperties": { "type": "number" }, - "properties": { - "baz": { "type": "string" } - } - } - } + additionalProperties: false, + properties: { + foo: {type: "number"}, + bar: { + additionalProperties: {type: "number"}, + properties: { + baz: {type: "string"}, + }, + }, + }, } var data = { - "foo": 0, - "additional1": 1, // will be removed; `additionalProperties` == false - "bar": { - "baz": "abc", - "additional2": 2 // will NOT be removed; `additionalProperties` != false + foo: 0, + additional1: 1, // will be removed; `additionalProperties` == false + bar: { + baz: "abc", + additional2: 2, // will NOT be removed; `additionalProperties` != false }, } -var validate = ajv.compile(schema); +var validate = ajv.compile(schema) -console.log(validate(data)); // true -console.log(data); // { "foo": 0, "bar": { "baz": "abc", "additional2": 2 } +console.log(validate(data)) // true +console.log(data) // { "foo": 0, "bar": { "baz": "abc", "additional2": 2 } ``` If `removeAdditional` option in the example above were `"all"` then both `additional1` and `additional2` properties would have been removed. If the option were `"failing"` then property `additional1` would have been removed regardless of its value and property `additional2` would have been removed only if its value were failing the schema in the inner `additionalProperties` (so in the example above it would have stayed because it passes the schema, but any non-number would have been removed). -__Please note__: If you use `removeAdditional` option with `additionalProperties` keyword inside `anyOf`/`oneOf` keywords your validation can fail with this schema, for example: +**Please note**: If you use `removeAdditional` option with `additionalProperties` keyword inside `anyOf`/`oneOf` keywords your validation can fail with this schema, for example: ```json { @@ -803,16 +788,16 @@ __Please note__: If you use `removeAdditional` option with `additionalProperties "oneOf": [ { "properties": { - "foo": { "type": "string" } + "foo": {"type": "string"} }, - "required": [ "foo" ], + "required": ["foo"], "additionalProperties": false }, { "properties": { - "bar": { "type": "integer" } + "bar": {"type": "integer"} }, - "required": [ "bar" ], + "required": ["bar"], "additionalProperties": false } ] @@ -829,20 +814,16 @@ While this behaviour is unexpected (issues [#129](https://github.com/ajv-validat { "type": "object", "properties": { - "foo": { "type": "string" }, - "bar": { "type": "integer" } + "foo": {"type": "string"}, + "bar": {"type": "integer"} }, "additionalProperties": false, - "oneOf": [ - { "required": [ "foo" ] }, - { "required": [ "bar" ] } - ] + "oneOf": [{"required": ["foo"]}, {"required": ["bar"]}] } ``` The schema above is also more efficient - it will compile into a faster function. - ## Assigning defaults With [option `useDefaults`](#options) Ajv will assign values from `default` keyword in the schemas of `properties` and `items` (when it is the array of schemas) to the missing properties and items. @@ -851,47 +832,43 @@ With the option value `"empty"` properties and items equal to `null` or `""` (em This option modifies original data. -__Please note__: the default value is inserted in the generated validation code as a literal, so the value inserted in the data will be the deep clone of the default in the schema. - +**Please note**: the default value is inserted in the generated validation code as a literal, so the value inserted in the data will be the deep clone of the default in the schema. Example 1 (`default` in `properties`): ```javascript -var ajv = new Ajv({ useDefaults: true }); +var ajv = new Ajv({useDefaults: true}) var schema = { - "type": "object", - "properties": { - "foo": { "type": "number" }, - "bar": { "type": "string", "default": "baz" } + type: "object", + properties: { + foo: {type: "number"}, + bar: {type: "string", default: "baz"}, }, - "required": [ "foo", "bar" ] -}; + required: ["foo", "bar"], +} -var data = { "foo": 1 }; +var data = {foo: 1} -var validate = ajv.compile(schema); +var validate = ajv.compile(schema) -console.log(validate(data)); // true -console.log(data); // { "foo": 1, "bar": "baz" } +console.log(validate(data)) // true +console.log(data) // { "foo": 1, "bar": "baz" } ``` Example 2 (`default` in `items`): ```javascript var schema = { - "type": "array", - "items": [ - { "type": "number" }, - { "type": "string", "default": "foo" } - ] + type: "array", + items: [{type: "number"}, {type: "string", default: "foo"}], } -var data = [ 1 ]; +var data = [1] -var validate = ajv.compile(schema); +var validate = ajv.compile(schema) -console.log(validate(data)); // true -console.log(data); // [ 1, "foo" ] +console.log(validate(data)) // true +console.log(data) // [ 1, "foo" ] ``` `default` keywords in other cases are ignored: @@ -903,68 +880,64 @@ console.log(data); // [ 1, "foo" ] The [`strictDefaults` option](#options) customizes Ajv's behavior for the defaults that Ajv ignores (`true` raises an error, and `"log"` outputs a warning). - ## Coercing data types When you are validating user inputs all your data properties are usually strings. The option `coerceTypes` allows you to have your data types coerced to the types specified in your schema `type` keywords, both to pass the validation and to use the correctly typed data afterwards. This option modifies original data. -__Please note__: if you pass a scalar value to the validating function its type will be coerced and it will pass the validation, but the value of the variable you pass won't be updated because scalars are passed by value. - +**Please note**: if you pass a scalar value to the validating function its type will be coerced and it will pass the validation, but the value of the variable you pass won't be updated because scalars are passed by value. Example 1: ```javascript -var ajv = new Ajv({ coerceTypes: true }); +var ajv = new Ajv({coerceTypes: true}) var schema = { - "type": "object", - "properties": { - "foo": { "type": "number" }, - "bar": { "type": "boolean" } + type: "object", + properties: { + foo: {type: "number"}, + bar: {type: "boolean"}, }, - "required": [ "foo", "bar" ] -}; + required: ["foo", "bar"], +} -var data = { "foo": "1", "bar": "false" }; +var data = {foo: "1", bar: "false"} -var validate = ajv.compile(schema); +var validate = ajv.compile(schema) -console.log(validate(data)); // true -console.log(data); // { "foo": 1, "bar": false } +console.log(validate(data)) // true +console.log(data) // { "foo": 1, "bar": false } ``` Example 2 (array coercions): ```javascript -var ajv = new Ajv({ coerceTypes: 'array' }); +var ajv = new Ajv({coerceTypes: "array"}) var schema = { - "properties": { - "foo": { "type": "array", "items": { "type": "number" } }, - "bar": { "type": "boolean" } - } -}; + properties: { + foo: {type: "array", items: {type: "number"}}, + bar: {type: "boolean"}, + }, +} -var data = { "foo": "1", "bar": ["false"] }; +var data = {foo: "1", bar: ["false"]} -var validate = ajv.compile(schema); +var validate = ajv.compile(schema) -console.log(validate(data)); // true -console.log(data); // { "foo": [1], "bar": false } +console.log(validate(data)) // true +console.log(data) // { "foo": [1], "bar": false } ``` The coercion rules, as you can see from the example, are different from JavaScript both to validate user input as expected and to have the coercion reversible (to correctly validate cases where different types are defined in subschemas of "anyOf" and other compound keywords). See [Coercion rules](https://github.com/ajv-validator/ajv/blob/master/COERCION.md) for details. - ## API ##### new Ajv(Object options) -> Object Create Ajv instance. - ##### .compile(Object schema) -> Function<Object data> Generate validating function and cache the compiled schema for future use. @@ -973,8 +946,7 @@ Validating function returns a boolean value. This function has properties `error The schema passed to this method will be validated against meta-schema unless `validateSchema` option is false. If schema is invalid, an error will be thrown. See [options](#options). - -##### .compileAsync(Object schema [, Boolean meta] [, Function callback]) -> Promise +##### .compileAsync(Object schema [, Boolean meta][, function callback]) -> Promise Asynchronous version of `compile` method that loads missing remote schemas using asynchronous function in `options.loadSchema`. This function returns a Promise that resolves to a validation function. An optional callback passed to `compileAsync` will be called with 2 parameters: error (or null) and validating function. The returned promise will reject (and the callback will be called with an error) when: @@ -988,7 +960,6 @@ You can asynchronously compile meta-schema by passing `true` as the second param See example in [Asynchronous compilation](#asynchronous-schema-compilation). - ##### .validate(Object schema|String key|String ref, data) -> Boolean Validate data using passed schema (it will be compiled and cached). @@ -997,11 +968,10 @@ Instead of the schema you can use the key that was previously passed to `addSche Validation errors will be available in the `errors` property of Ajv instance (`null` if there were no errors). -__Please note__: every time this method is called the errors are overwritten so you need to copy them to another variable if you want to use them later. +**Please note**: every time this method is called the errors are overwritten so you need to copy them to another variable if you want to use them later. If the schema is asynchronous (has `$async` keyword on the top level) this method returns a Promise. See [Asynchronous validation](#asynchronous-validation). - ##### .addSchema(Array<Object>|Object schema [, String key]) -> Ajv Add schema(s) to validator instance. This method does not compile schemas (but it still validates them). Because of that dependencies can be added in any order and circular dependencies are supported. It also prevents unnecessary compilation of schemas that are containers for other schemas but not used as a whole. @@ -1010,18 +980,17 @@ Array of schemas can be passed (schemas should have ids), the second parameter w Key can be passed that can be used to reference the schema and will be used as the schema id if there is no id inside the schema. If the key is not passed, the schema id will be used as the key. - Once the schema is added, it (and all the references inside it) can be referenced in other schemas and used to validate data. Although `addSchema` does not compile schemas, explicit compilation is not required - the schema will be compiled when it is used first time. By default the schema is validated against meta-schema before it is added, and if the schema does not pass validation the exception is thrown. This behaviour is controlled by `validateSchema` option. -__Please note__: Ajv uses the [method chaining syntax](https://en.wikipedia.org/wiki/Method_chaining) for all methods with the prefix `add*` and `remove*`. +**Please note**: Ajv uses the [method chaining syntax](https://en.wikipedia.org/wiki/Method_chaining) for all methods with the prefix `add*` and `remove*`. This allows you to do nice things like the following. ```javascript -var validate = new Ajv().addSchema(schema).addFormat(name, regex).getSchema(uri); +var validate = new Ajv().addSchema(schema).addFormat(name, regex).getSchema(uri) ``` ##### .addMetaSchema(Array<Object>|Object schema [, String key]) -> Ajv @@ -1030,7 +999,6 @@ Adds meta schema(s) that can be used to validate other schemas. That function sh 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`. - ##### .validateSchema(Object schema) -> Boolean Validates schema. This method should be used to validate schemas rather than `validate` due to the inconsistency of `uri` format in JSON Schema standard. @@ -1043,17 +1011,16 @@ If schema has `$schema` property, then the schema with this id (that should be p Errors will be available at `ajv.errors`. - ##### .getSchema(String key) -> Function<Object data> Retrieve compiled schema previously added with `addSchema` by the key passed to `addSchema` or by its full reference (id). The returned validating function has `schema` property with the reference to the original schema. - ##### .removeSchema([Object schema|String key|String ref|RegExp pattern]) -> Ajv Remove added/cached schema. Even if schema is referenced by other schemas it can be safely removed as dependent schemas have local references. Schema can be removed using: + - key passed to `addSchema` - it's full reference (id) - RegExp that should match schema id or key (meta-schemas won't be removed) @@ -1061,7 +1028,6 @@ Schema can be removed using: If no parameter is passed all schemas but meta-schemas will be removed and the cache will be cleared. - ##### .addFormat(String name, String|RegExp|Function|Object format) -> Ajv Add custom format to validate strings or numbers. It can also be used to replace pre-defined formats for Ajv instance. @@ -1079,7 +1045,6 @@ If object is passed it should have properties `validate`, `compare` and `async`: Custom formats can be also added via `formats` option. - ##### .addKeyword(String keyword, Object definition) -> Ajv Add custom validation keyword to Ajv instance. @@ -1090,6 +1055,7 @@ Keyword must start with a letter, `_` or `$`, and may continue with letters, num 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. - `"3-example"`: invalid as numbers are not allowed to be the first character in a keyword @@ -1107,30 +1073,27 @@ Keyword definition is an object with the following properties: - _modifying_: `true` MUST be passed if keyword modifies data - _statements_: `true` can be passed in case inline keyword generates statements (as opposed to expression) - _valid_: pass `true`/`false` to pre-define validation result, the result returned from validation function will be ignored. This option cannot be used with macro keywords. -- _$data_: an optional `true` value to support [$data reference](#data-reference) as the value of custom keyword. The reference will be resolved at validation time. If the keyword has meta-schema it would be extended to allow $data and it will be used to validate the resolved value. Supporting $data reference requires that keyword has validating function (as the only option or in addition to compile, macro or inline function). +- _\$data_: an optional `true` value to support [\$data reference](#data-reference) as the value of custom keyword. The reference will be resolved at validation time. If the keyword has meta-schema it would be extended to allow $data and it will be used to validate the resolved value. Supporting $data reference requires that keyword has validating function (as the only option or in addition to compile, macro or inline function). - _async_: an optional `true` value if the validation function is asynchronous (whether it is compiled or passed in _validate_ property); in this case it should return a promise that resolves with a value `true` or `false`. This option is ignored in case of "macro" and "inline" keywords. - _errors_: an optional boolean or string `"full"` indicating whether keyword returns errors. If this property is not set Ajv will determine if the errors were set in case of failed validation. -_compile_, _macro_ and _inline_ are mutually exclusive, only one should be used at a time. _validate_ can be used separately or in addition to them to support $data reference. +_compile_, _macro_ and _inline_ are mutually exclusive, only one should be used at a time. _validate_ can be used separately or in addition to them to support \$data reference. -__Please note__: If the keyword is validating data type that is different from the type(s) in its definition, the validation function will not be called (and expanded macro will not be used), so there is no need to check for data type inside validation function or inside schema returned by macro function (unless you want to enforce a specific type and for some reason do not want to use a separate `type` keyword for that). In the same way as standard keywords work, if the keyword does not apply to the data type being validated, the validation of this keyword will succeed. +**Please note**: If the keyword is validating data type that is different from the type(s) in its definition, the validation function will not be called (and expanded macro will not be used), so there is no need to check for data type inside validation function or inside schema returned by macro function (unless you want to enforce a specific type and for some reason do not want to use a separate `type` keyword for that). In the same way as standard keywords work, if the keyword does not apply to the data type being validated, the validation of this keyword will succeed. See [Defining custom keywords](#defining-custom-keywords) for more details. - ##### .getKeyword(String keyword) -> Object|Boolean Returns custom keyword definition, `true` for pre-defined keywords and `false` if the keyword is unknown. - ##### .removeKeyword(String keyword) -> Ajv Removes custom or pre-defined keyword so you can redefine them. While this method can be used to extend pre-defined keywords, it can also be used to completely change their meaning - it may lead to unexpected results. -__Please note__: schemas compiled before the keyword is removed will continue to work without changes. To recompile schemas use `removeSchema` method and compile them again. - +**Please note**: schemas compiled before the keyword is removed will continue to work without changes. To recompile schemas use `removeSchema` method and compile them again. ##### .errorsText([Array<Object> errors [, Object options]]) -> String @@ -1138,7 +1101,6 @@ Returns the text with all errors in a String. Options can have properties `separator` (string used to separate errors, ", " by default) and `dataVar` (the variable name that dataPaths are prefixed with, "data" by default). - ## Options Defaults: @@ -1154,7 +1116,7 @@ Defaults: uniqueItems: true, unicode: true, nullable: false, - format: 'fast', + format: true, formats: {}, unknownFormats: true, schemas: {}, @@ -1194,11 +1156,11 @@ Defaults: ##### Validation and reporting options -- _$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). +- _\$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. +- _\$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. @@ -1206,21 +1168,19 @@ Defaults: - _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. - _nullable_: support keyword "nullable" from [Open API 3 specification](https://swagger.io/docs/specification/data-models/data-types/). - _format_: formats validation mode. Option values: - - `"fast"` (default) - simplified and fast validation (see [Formats](#formats) for details of which formats are available and affected by this option). - - `"full"` - more restrictive and slow validation. E.g., 25:00:00 and 2015/14/33 will be invalid time and date in 'full' mode but it will be valid in 'fast' mode. + - `true` (default) - validate added formats (see [Formats](#formats)). - `false` - ignore all format keywords. - _formats_: an object with custom formats. Keys and values will be passed to `addFormat` method. - _keywords_: an object with custom keywords. Keys and values will be passed to `addKeyword` method. - _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. + - `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. - _schemas_: an array or object of schemas that will be added to the instance. In case you pass the array the schemas must have IDs in them. When the object is passed the method `addSchema(value, key)` will be called for each schema in this object. - _logger_: sets the logging method. Default is the global `console` object that should have methods `log`, `warn` and `error`. See [Error logging](#error-logging). Option values: - custom logger - it should have methods `log`, `warn` and `error`. If any of these methods is missing an exception will be thrown. - `false` - logging is disabled. - ##### Referenced schema options - _schemaId_: this option defines which keywords are used as schema URI. Option value: @@ -1237,7 +1197,6 @@ Defaults: - `true` - validate all keywords in the schemas with `$ref` (the default behaviour in versions before 5.0.0). - _loadSchema_: asynchronous function that will be used to load remote schemas when `compileAsync` [method](#api-compileAsync) is used and some reference is missing (option `missingRefs` should NOT be 'fail' or 'ignore'). This function should accept remote schema uri as a parameter and return a Promise that resolves to a schema. See example in [Asynchronous compilation](#asynchronous-schema-compilation). - ##### Options to modify validated data - _removeAdditional_: remove additional properties - see example in [Filtering data](#filtering-data). This option is not used if schema is added with `addMetaSchema` method. Option values: @@ -1255,7 +1214,6 @@ Defaults: - `true` - coerce scalar data types. - `"array"` - in addition to coercions between scalar types, coerce scalar data to an array with one element and vice versa (as required by the schema). - ##### Strict mode options - _strictDefaults_: report ignored `default` keywords in schemas. Option values: @@ -1277,12 +1235,11 @@ Defaults: - `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 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. + - `true` (default) - if the validation fails, throw the exception. - `"log"` - if the validation fails, log error. - `false` - skip schema validation. - _addUsedSchema_: by default methods `compile` and `validate` add schemas to the instance if they have `$id` (or `id`) property that doesn't start with "#". If `$id` is present and it is not unique the exception will be thrown. Set this option to `false` to skip adding schemas to the instance and the `$id` uniqueness check when these methods are used. This option does not affect `addSchema` method. @@ -1303,12 +1260,10 @@ Defaults: - _cache_: an optional instance of cache to store compiled schemas using stable-stringified schema as a key. For example, set-associative cache [sacjs](https://github.com/epoberezkin/sacjs) can be used. If not passed then a simple hash is used which is good enough for the common use case (a limited number of statically defined schemas). Cache should have methods `put(key, value)`, `get(key)`, `del(key)` and `clear()`. - _serialize_: an optional function to serialize schema to cache key. Pass `false` to use schema itself as a key (e.g., if WeakMap used as a cache). By default [fast-json-stable-stringify](https://github.com/epoberezkin/fast-json-stable-stringify) is used. - ## Validation errors In case of validation failure, Ajv assigns the array of errors to `errors` property of validation function (or to `errors` property of Ajv instance when `validate` or `validateSchema` methods were called). In case of [asynchronous validation](#asynchronous-validation), the returned promise is rejected with exception `Ajv.ValidationError` that has `errors` property. - ### Error objects Each error is an object with the following properties: @@ -1322,8 +1277,7 @@ Each error is an object with the following properties: - _parentSchema_: the schema containing the keyword (added with `verbose` option) - _data_: the data validated by the keyword (added with `verbose` option). -__Please note__: `propertyNames` keyword schema validation errors have an additional property `propertyName`, `dataPath` points to the object. After schema validation for each property name, if it is invalid an additional error is added with the property `keyword` equal to `"propertyNames"`. - +**Please note**: `propertyNames` keyword schema validation errors have an additional property `propertyName`, `dataPath` points to the object. After schema validation for each property name, if it is invalid an additional error is added with the property `keyword` equal to `"propertyNames"`. ### Error parameters @@ -1355,29 +1309,28 @@ Properties of `params` object in errors depend on the keyword that failed valida - `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). - ### Error logging Using the `logger` option when initiallizing Ajv will allow you to define custom logging. Here you can build upon the exisiting logging. The use of other logging packages is supported as long as the package or its associated wrapper exposes the required methods. If any of the required methods are missing an exception will be thrown. + - **Required Methods**: `log`, `warn`, `error` ```javascript -var otherLogger = new OtherLogger(); +var otherLogger = new OtherLogger() var ajv = new Ajv({ logger: { log: console.log.bind(console), warn: function warn() { - otherLogger.logWarn.apply(otherLogger, arguments); + otherLogger.logWarn.apply(otherLogger, arguments) }, error: function error() { - otherLogger.logError.apply(otherLogger, arguments); - console.error.apply(console, arguments); - } - } -}); + otherLogger.logError.apply(otherLogger, arguments) + console.error.apply(console, arguments) + }, + }, +}) ``` - ## 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: @@ -1388,19 +1341,19 @@ Ajv can be extended with plugins that add custom keywords, formats or functions 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/ajv-validator/ajv-async) - plugin to configure async validation mode +- [ajv-async](https://github.com/ajv-validator/ajv-async) - plugin to configure async validation mode (DEPRECATED) - [ajv-bsontype](https://github.com/BoLaMN/ajv-bsontype) - plugin to validate mongodb's bsonType formats - [ajv-cli](https://github.com/jessedc/ajv-cli) - command line interface +- [ajv-formats](https://github.com/ajv-validator/ajv-formats) - formats defined in JSON Schema specification. - [ajv-errors](https://github.com/ajv-validator/ajv-errors) - plugin for custom error messages - [ajv-i18n](https://github.com/ajv-validator/ajv-i18n) - internationalised error messages - [ajv-istanbul](https://github.com/ajv-validator/ajv-istanbul) - plugin to instrument generated validation code to measure test coverage of your schemas - [ajv-keywords](https://github.com/ajv-validator/ajv-keywords) - plugin with custom validation keywords (select, typeof, etc.) - [ajv-merge-patch](https://github.com/ajv-validator/ajv-merge-patch) - plugin with keywords $merge and $patch - [ajv-pack](https://github.com/ajv-validator/ajv-pack) - produces a compact module exporting validation functions -- [ajv-formats-draft2019](https://github.com/luzlab/ajv-formats-draft2019) - format validators for draft2019 that aren't already included in ajv (ie. `idn-hostname`, `idn-email`, `iri`, `iri-reference` and `duration`). +- [ajv-formats-draft2019](https://github.com/luzlab/ajv-formats-draft2019) - format validators for draft2019 that aren't included in [ajv-formats](https://github.com/ajv-validator/ajv-formats) (ie. `idn-hostname`, `idn-email`, `iri`, `iri-reference` and `duration`). ## Some packages using Ajv @@ -1426,7 +1379,6 @@ If you have published a useful plugin please submit a PR to add it to the next s - [gh-pages-generator](https://github.com/epoberezkin/gh-pages-generator) - multi-page site generator converting markdown files to GitHub pages - [ESLint](https://github.com/eslint/eslint) - the pluggable linting utility for JavaScript and JSX - ## Tests ``` @@ -1445,12 +1397,11 @@ All validation functions are generated using doT templates in [dot](https://gith Please see [Contributing guidelines](https://github.com/ajv-validator/ajv/blob/master/CONTRIBUTING.md) - ## Changes history See https://github.com/ajv-validator/ajv/releases -__Please note__: [Changes in version 6.0.0](https://github.com/ajv-validator/ajv/releases/tag/v6.0.0). +**Please note**: [Changes in version 6.0.0](https://github.com/ajv-validator/ajv/releases/tag/v6.0.0). [Version 5.0.0](https://github.com/ajv-validator/ajv/releases/tag/5.0.0). @@ -1460,19 +1411,16 @@ __Please note__: [Changes in version 6.0.0](https://github.com/ajv-validator/ajv [Version 2.0.0](https://github.com/ajv-validator/ajv/releases/tag/2.0.0). - ## Code of conduct Please review and follow the [Code of conduct](https://github.com/ajv-validator/ajv/blob/master/CODE_OF_CONDUCT.md). Please report any unacceptable behaviour to ajv.validator@gmail.com - it will be reviewed by the project team. - ## Open-source software support Ajv is a part of [Tidelift subscription](https://tidelift.com/subscription/pkg/npm-ajv?utm_source=npm-ajv&utm_medium=referral&utm_campaign=readme) - it provides a centralised support to open-source software users, in addition to the support provided by software maintainers. - ## License [MIT](https://github.com/ajv-validator/ajv/blob/master/LICENSE) diff --git a/bower.json b/bower.json index 507989c626..6e8d8a893a 100644 --- a/bower.json +++ b/bower.json @@ -2,24 +2,10 @@ "name": "ajv", "description": "Another JSON Schema Validator", "main": "dist/ajv.min.js", - "authors": [ - "Evgeny Poberezkin" - ], + "authors": ["Evgeny Poberezkin"], "license": "MIT", - "keywords": [ - "JSON", - "schema", - "validator" - ], + "keywords": ["JSON", "schema", "validator"], "homepage": "https://github.com/ajv-validator/ajv", - "moduleType": [ - "amd", - "globals", - "node" - ], - "ignore": [ - "node_modules", - "bower_components", - "spec" - ] + "moduleType": ["amd", "globals", "node"], + "ignore": ["node_modules", "bower_components", "spec"] } diff --git a/karma.conf.js b/karma.conf.js index 155d0874ee..5c2a3eb1c5 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -1,50 +1,42 @@ // Karma configuration // Generated on Thu Mar 13 2014 14:12:04 GMT-0700 (PDT) -module.exports = function(config) { +module.exports = function (config) { config.set({ - // base path that will be used to resolve all patterns (eg. files, exclude) - basePath: '', - + basePath: "", // frameworks to use // available frameworks: https://npmjs.org/browse/keyword/karma-adapter - frameworks: ['mocha'], - + frameworks: ["mocha"], // list of files / patterns to load in the browser files: [ - 'dist/ajv.min.js', - 'node_modules/chai/chai.js', - 'node_modules/ajv-async/dist/ajv-async.min.js', - 'node_modules/bluebird/js/browser/bluebird.core.min.js', - '.browser/*.spec.js' + "dist/ajv.min.js", + "node_modules/chai/chai.js", + "node_modules/ajv-async/dist/ajv-async.min.js", + "node_modules/bluebird/js/browser/bluebird.core.min.js", + ".browser/*.spec.js", ], // test results reporter to use // possible values: 'dots', 'progress' // available reporters: https://npmjs.org/browse/keyword/karma-reporter - reporters: ['dots'], - + reporters: ["dots"], // web server port port: 9876, - // enable / disable colors in the output (reporters and logs) colors: true, - // level of logging // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG logLevel: config.LOG_INFO, - // enable / disable watching file and executing tests whenever any file changes autoWatch: false, - // Start these browsers, currently available: // - Chrome // - ChromeCanary @@ -53,18 +45,18 @@ module.exports = function(config) { // - Safari (only Mac) // - PhantomJS // - IE (only Windows) - browsers: ['HeadlessChrome'], + browsers: ["HeadlessChrome"], customLaunchers: { - HeadlessChrome:{ - base: 'ChromeHeadless', - flags: ['--no-sandbox'] - }, + HeadlessChrome: { + base: "ChromeHeadless", + flags: ["--no-sandbox"], + }, }, // Continuous Integration mode // if true, Karma captures browsers, runs the tests and exits singleRun: true, - browserNoActivityTimeout: 90000 - }); -}; + browserNoActivityTimeout: 90000, + }) +} diff --git a/karma.sauce.js b/karma.sauce.js index fac172e36f..dc54aa486d 100644 --- a/karma.sauce.js +++ b/karma.sauce.js @@ -1,104 +1,99 @@ -'use strict'; +"use strict" -var fs = require('fs'); - -module.exports = function(config) { +var fs = require("fs") +module.exports = function (config) { // Use ENV vars on Travis and sauce.json locally to get credentials if (!process.env.SAUCE_USERNAME) { - if (!fs.existsSync('sauce.json')) { - console.log('Create a sauce.json with your credentials based on the sauce-sample.json file.'); - process.exit(1); + if (!fs.existsSync("sauce.json")) { + console.log( + "Create a sauce.json with your credentials based on the sauce-sample.json file." + ) + process.exit(1) } else { - process.env.SAUCE_USERNAME = require('./sauce').username; - process.env.SAUCE_ACCESS_KEY = require('./sauce').accessKey; + process.env.SAUCE_USERNAME = require("./sauce").username + process.env.SAUCE_ACCESS_KEY = require("./sauce").accessKey } } // Browsers to run on Sauce Labs var customLaunchers = { - 'SL_Chrome_27': { - base: 'SauceLabs', - browserName: 'chrome', - version: '27' + SL_Chrome_27: { + base: "SauceLabs", + browserName: "chrome", + version: "27", }, - 'SL_Chrome': { - base: 'SauceLabs', - browserName: 'chrome' + SL_Chrome: { + base: "SauceLabs", + browserName: "chrome", }, - 'SL_InternetExplorer_10': { - base: 'SauceLabs', - browserName: 'internet explorer', - version: '10' + SL_InternetExplorer_10: { + base: "SauceLabs", + browserName: "internet explorer", + version: "10", }, - 'SL_InternetExplorer': { - base: 'SauceLabs', - browserName: 'internet explorer' + SL_InternetExplorer: { + base: "SauceLabs", + browserName: "internet explorer", }, - 'SL_MicrosoftEdge': { - base: 'SauceLabs', - browserName: 'MicrosoftEdge' + SL_MicrosoftEdge: { + base: "SauceLabs", + browserName: "MicrosoftEdge", }, - 'SL_FireFox_17': { - base: 'SauceLabs', - browserName: 'firefox', - version: '17' + SL_FireFox_17: { + base: "SauceLabs", + browserName: "firefox", + version: "17", }, - 'SL_FireFox': { - base: 'SauceLabs', - browserName: 'firefox' + SL_FireFox: { + base: "SauceLabs", + browserName: "firefox", }, - 'SL_Safari_7': { - base: 'SauceLabs', - browserName: 'safari', - version: '7' + SL_Safari_7: { + base: "SauceLabs", + browserName: "safari", + version: "7", }, - 'SL_Safari': { - base: 'SauceLabs', - browserName: 'safari' + SL_Safari: { + base: "SauceLabs", + browserName: "safari", }, - 'SL_iPhone_8': { - base: 'SauceLabs', - browserName: 'iphone', - version: '8.4' + SL_iPhone_8: { + base: "SauceLabs", + browserName: "iphone", + version: "8.4", }, - 'SL_iPhone': { - base: 'SauceLabs', - browserName: 'iphone' + SL_iPhone: { + base: "SauceLabs", + browserName: "iphone", }, - 'SL_Android': { - base: 'SauceLabs', - browserName: 'android' - } - }; - + SL_Android: { + base: "SauceLabs", + browserName: "android", + }, + } config.set({ - // base path that will be used to resolve all patterns (eg. files, exclude) - basePath: '', - + basePath: "", // frameworks to use // available frameworks: https://npmjs.org/browse/keyword/karma-adapter - frameworks: ['mocha'], - + frameworks: ["mocha"], // list of files / patterns to load in the browser files: [ - 'dist/ajv.min.js', - 'node_modules/chai/chai.js', - 'node_modules/ajv-async/dist/ajv-async.min.js', - 'node_modules/bluebird/js/browser/bluebird.core.min.js', - '.browser/*.spec.js' + "dist/ajv.min.js", + "node_modules/chai/chai.js", + "node_modules/ajv-async/dist/ajv-async.min.js", + "node_modules/bluebird/js/browser/bluebird.core.min.js", + ".browser/*.spec.js", ], - // test results reporter to use // possible values: 'dots', 'progress' // available reporters: https://npmjs.org/browse/keyword/karma-reporter - reporters: ['dots', 'saucelabs'], - + reporters: ["dots", "saucelabs"], // web server port port: 9876, @@ -110,8 +105,8 @@ module.exports = function(config) { logLevel: config.LOG_INFO, sauceLabs: { - testName: 'Ajv', - 'idleTimeout': 900 + testName: "Ajv", + idleTimeout: 900, }, captureTimeout: 1200000, browserNoActivityTimeout: 600000, @@ -122,6 +117,6 @@ module.exports = function(config) { // start these browsers // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher browsers: Object.keys(customLaunchers), - singleRun: true - }); -}; + singleRun: true, + }) +} diff --git a/lib/ajv.d.ts b/lib/ajv.d.ts index cc2881b33b..57ac813893 100644 --- a/lib/ajv.d.ts +++ b/lib/ajv.d.ts @@ -1,148 +1,158 @@ declare var ajv: { - (options?: ajv.Options): ajv.Ajv; - new(options?: ajv.Options): ajv.Ajv; - ValidationError: typeof AjvErrors.ValidationError; - MissingRefError: typeof AjvErrors.MissingRefError; - $dataMetaSchema: object; + (options?: ajv.Options): ajv.Ajv + new (options?: ajv.Options): ajv.Ajv + ValidationError: typeof AjvErrors.ValidationError + MissingRefError: typeof AjvErrors.MissingRefError + $dataMetaSchema: object } declare namespace AjvErrors { class ValidationError extends Error { - constructor(errors: Array); + constructor(errors: Array) - message: string; - errors: Array; - ajv: true; - validation: true; + message: string + errors: Array + ajv: true + validation: true } class MissingRefError extends Error { - constructor(baseId: string, ref: string, message?: string); - static message: (baseId: string, ref: string) => string; + constructor(baseId: string, ref: string, message?: string) + static message: (baseId: string, ref: string) => string - message: string; - missingRef: string; - missingSchema: string; + message: string + missingRef: string + missingSchema: string } } declare namespace ajv { - type ValidationError = AjvErrors.ValidationError; + type ValidationError = AjvErrors.ValidationError - type MissingRefError = AjvErrors.MissingRefError; + type MissingRefError = AjvErrors.MissingRefError interface Ajv { /** - * Validate data using schema - * Schema will be compiled and cached (using serialized JSON as key, [fast-json-stable-stringify](https://github.com/epoberezkin/fast-json-stable-stringify) is used to serialize by default). - * @param {string|object|Boolean} schemaKeyRef key, ref or schema object - * @param {Any} data to be validated - * @return {Boolean} validation result. Errors from the last validation will be available in `ajv.errors` (and also in compiled schema: `schema.errors`). - */ - validate(schemaKeyRef: object | string | boolean, data: any): boolean | PromiseLike; + * Validate data using schema + * Schema will be compiled and cached (using serialized JSON as key, [fast-json-stable-stringify](https://github.com/epoberezkin/fast-json-stable-stringify) is used to serialize by default). + * @param {string|object|Boolean} schemaKeyRef key, ref or schema object + * @param {Any} data to be validated + * @return {Boolean} validation result. Errors from the last validation will be available in `ajv.errors` (and also in compiled schema: `schema.errors`). + */ + validate( + schemaKeyRef: object | string | boolean, + data: any + ): boolean | PromiseLike /** - * Create validating function for passed schema. - * @param {object|Boolean} schema schema object - * @return {Function} validating function - */ - compile(schema: object | boolean): ValidateFunction; + * Create validating function for passed schema. + * @param {object|Boolean} schema schema object + * @return {Function} validating function + */ + compile(schema: object | boolean): ValidateFunction /** - * Creates validating function for passed schema with asynchronous loading of missing schemas. - * `loadSchema` option should be a function that accepts schema uri and node-style callback. - * @this Ajv - * @param {object|Boolean} schema schema object - * @param {Boolean} meta optional true to compile meta-schema; this parameter can be skipped - * @param {Function} callback optional node-style callback, it is always called with 2 parameters: error (or null) and validating function. - * @return {PromiseLike} validating function - */ - compileAsync(schema: object | boolean, meta?: Boolean, callback?: (err: Error, validate: ValidateFunction) => any): PromiseLike; + * Creates validating function for passed schema with asynchronous loading of missing schemas. + * `loadSchema` option should be a function that accepts schema uri and node-style callback. + * @this Ajv + * @param {object|Boolean} schema schema object + * @param {Boolean} meta optional true to compile meta-schema; this parameter can be skipped + * @param {Function} callback optional node-style callback, it is always called with 2 parameters: error (or null) and validating function. + * @return {PromiseLike} validating function + */ + compileAsync( + schema: object | boolean, + meta?: Boolean, + callback?: (err: Error, validate: ValidateFunction) => any + ): PromiseLike /** - * Adds schema to the instance. - * @param {object|Array} schema schema or array of schemas. If array is passed, `key` and other parameters will be ignored. - * @param {string} key Optional schema key. Can be passed to `validate` method instead of schema object or id/ref. One schema per instance can have empty `id` and `key`. - * @return {Ajv} this for method chaining - */ - addSchema(schema: Array | object, key?: string): Ajv; + * Adds schema to the instance. + * @param {object|Array} schema schema or array of schemas. If array is passed, `key` and other parameters will be ignored. + * @param {string} key Optional schema key. Can be passed to `validate` method instead of schema object or id/ref. One schema per instance can have empty `id` and `key`. + * @return {Ajv} this for method chaining + */ + addSchema(schema: Array | object, key?: string): Ajv /** - * Add schema that will be used to validate other schemas - * options in META_IGNORE_OPTIONS are alway set to false - * @param {object} schema schema object - * @param {string} key optional schema key - * @return {Ajv} this for method chaining - */ - addMetaSchema(schema: object, key?: string): Ajv; + * Add schema that will be used to validate other schemas + * options in META_IGNORE_OPTIONS are alway set to false + * @param {object} schema schema object + * @param {string} key optional schema key + * @return {Ajv} this for method chaining + */ + addMetaSchema(schema: object, key?: string): Ajv /** - * Validate schema - * @param {object|Boolean} schema schema to validate - * @return {Boolean} true if schema is valid - */ - validateSchema(schema: object | boolean): boolean; + * Validate schema + * @param {object|Boolean} schema schema to validate + * @return {Boolean} true if schema is valid + */ + validateSchema(schema: object | boolean): boolean /** - * Get compiled schema from the instance by `key` or `ref`. - * @param {string} keyRef `key` that was passed to `addSchema` or full schema reference (`schema.id` or resolved id). - * @return {Function} schema validating function (with property `schema`). Returns undefined if keyRef can't be resolved to an existing schema. - */ - getSchema(keyRef: string): ValidateFunction | undefined; + * Get compiled schema from the instance by `key` or `ref`. + * @param {string} keyRef `key` that was passed to `addSchema` or full schema reference (`schema.id` or resolved id). + * @return {Function} schema validating function (with property `schema`). Returns undefined if keyRef can't be resolved to an existing schema. + */ + getSchema(keyRef: string): ValidateFunction | undefined /** - * Remove cached schema(s). - * If no parameter is passed all schemas but meta-schemas are removed. - * If RegExp is passed all schemas with key/id matching pattern but meta-schemas are removed. - * Even if schema is referenced by other schemas it still can be removed as other schemas have local references. - * @param {string|object|RegExp|Boolean} schemaKeyRef key, ref, pattern to match key/ref or schema object - * @return {Ajv} this for method chaining - */ - removeSchema(schemaKeyRef?: object | string | RegExp | boolean): Ajv; + * Remove cached schema(s). + * If no parameter is passed all schemas but meta-schemas are removed. + * If RegExp is passed all schemas with key/id matching pattern but meta-schemas are removed. + * Even if schema is referenced by other schemas it still can be removed as other schemas have local references. + * @param {string|object|RegExp|Boolean} schemaKeyRef key, ref, pattern to match key/ref or schema object + * @return {Ajv} this for method chaining + */ + removeSchema(schemaKeyRef?: object | string | RegExp | boolean): Ajv /** - * Add custom format - * @param {string} name format name - * @param {string|RegExp|Function} format string is converted to RegExp; function should return boolean (true when valid) - * @return {Ajv} this for method chaining - */ - addFormat(name: string, format: FormatValidator | FormatDefinition): Ajv; + * Add custom format + * @param {string} name format name + * @param {string|RegExp|Function} format string is converted to RegExp; function should return boolean (true when valid) + * @return {Ajv} this for method chaining + */ + addFormat(name: string, format: FormatValidator | FormatDefinition): Ajv /** - * Define custom keyword - * @this Ajv - * @param {string} keyword custom keyword, should be a valid identifier, should be different from all standard, custom and macro keywords. - * @param {object} definition keyword definition object with properties `type` (type(s) which the keyword applies to), `validate` or `compile`. - * @return {Ajv} this for method chaining - */ - addKeyword(keyword: string, definition: KeywordDefinition): Ajv; + * Define custom keyword + * @this Ajv + * @param {string} keyword custom keyword, should be a valid identifier, should be different from all standard, custom and macro keywords. + * @param {object} definition keyword definition object with properties `type` (type(s) which the keyword applies to), `validate` or `compile`. + * @return {Ajv} this for method chaining + */ + addKeyword(keyword: string, definition: KeywordDefinition): Ajv /** - * Get keyword definition - * @this Ajv - * @param {string} keyword pre-defined or custom keyword. - * @return {object|Boolean} custom keyword definition, `true` if it is a predefined keyword, `false` otherwise. - */ - getKeyword(keyword: string): object | boolean; + * Get keyword definition + * @this Ajv + * @param {string} keyword pre-defined or custom keyword. + * @return {object|Boolean} custom keyword definition, `true` if it is a predefined keyword, `false` otherwise. + */ + getKeyword(keyword: string): object | boolean /** - * Remove keyword - * @this Ajv - * @param {string} keyword pre-defined or custom keyword. - * @return {Ajv} this for method chaining - */ - removeKeyword(keyword: string): Ajv; + * Remove keyword + * @this Ajv + * @param {string} keyword pre-defined or custom keyword. + * @return {Ajv} this for method chaining + */ + removeKeyword(keyword: string): Ajv /** - * Validate keyword - * @this Ajv - * @param {object} definition keyword definition object - * @param {boolean} throwError true to throw exception if definition is invalid - * @return {boolean} validation result - */ - validateKeyword(definition: KeywordDefinition, throwError: boolean): boolean; + * Validate keyword + * @this Ajv + * @param {object} definition keyword definition object + * @param {boolean} throwError true to throw exception if definition is invalid + * @return {boolean} validation result + */ + validateKeyword(definition: KeywordDefinition, throwError: boolean): boolean /** - * Convert array of error message objects to string - * @param {Array} errors optional array of validation errors, if not passed errors from the instance are used. - * @param {object} options optional options with properties `separator` and `dataVar`. - * @return {string} human readable string with all errors descriptions - */ - errorsText(errors?: Array | null, options?: ErrorsTextOptions): string; - errors?: Array | null; + * Convert array of error message objects to string + * @param {Array} errors optional array of validation errors, if not passed errors from the instance are used. + * @param {object} options optional options with properties `separator` and `dataVar`. + * @return {string} human readable string with all errors descriptions + */ + errorsText( + errors?: Array | null, + options?: ErrorsTextOptions + ): string + errors?: Array | null } interface CustomLogger { - log(...args: any[]): any; - warn(...args: any[]): any; - error(...args: any[]): any; + log(...args: any[]): any + warn(...args: any[]): any + error(...args: any[]): any } interface ValidateFunction { @@ -152,128 +162,147 @@ declare namespace ajv { parentData?: object | Array, parentDataProperty?: string | number, rootData?: object | Array - ): boolean | PromiseLike; - schema?: object | boolean; - errors?: null | Array; - refs?: object; - refVal?: Array; - root?: ValidateFunction | object; - $async?: true; - source?: object; + ): boolean | PromiseLike + schema?: object | boolean + errors?: null | Array + refs?: object + refVal?: Array + root?: ValidateFunction | object + $async?: true + source?: object } interface Options { - $data?: boolean; - allErrors?: boolean; - verbose?: boolean; - jsonPointers?: boolean; - uniqueItems?: boolean; - unicode?: boolean; - format?: false | string; - formats?: object; - keywords?: object; - unknownFormats?: true | string[] | 'ignore'; - schemas?: Array | object; - schemaId?: '$id' | 'id' | 'auto'; - missingRefs?: true | 'ignore' | 'fail'; - extendRefs?: true | 'ignore' | 'fail'; - loadSchema?: (uri: string, cb?: (err: Error, schema: object) => void) => PromiseLike; - removeAdditional?: boolean | 'all' | 'failing'; - useDefaults?: boolean | 'empty' | 'shared'; - coerceTypes?: boolean | 'array'; - strictDefaults?: boolean | 'log'; - strictKeywords?: boolean | 'log'; - strictNumbers?: boolean; - async?: boolean | string; - transpile?: string | ((code: string) => string); - meta?: boolean | object; - validateSchema?: boolean | 'log'; - addUsedSchema?: boolean; - inlineRefs?: boolean | number; - passContext?: boolean; - loopRequired?: number; - ownProperties?: boolean; - multipleOfPrecision?: boolean | number; - errorDataPath?: string, - messages?: boolean; - sourceCode?: boolean; - processCode?: (code: string, schema: object) => string; - cache?: object; - logger?: CustomLogger | false; - nullable?: boolean; - serialize?: ((schema: object | boolean) => any) | false; + $data?: boolean + allErrors?: boolean + verbose?: boolean + jsonPointers?: boolean + uniqueItems?: boolean + unicode?: boolean + format?: false | string + formats?: object + keywords?: object + unknownFormats?: true | string[] | "ignore" + schemas?: Array | object + schemaId?: "$id" | "id" | "auto" + missingRefs?: true | "ignore" | "fail" + extendRefs?: true | "ignore" | "fail" + loadSchema?: ( + uri: string, + cb?: (err: Error, schema: object) => void + ) => PromiseLike + removeAdditional?: boolean | "all" | "failing" + useDefaults?: boolean | "empty" | "shared" + coerceTypes?: boolean | "array" + strictDefaults?: boolean | "log" + strictKeywords?: boolean | "log" + strictNumbers?: boolean + async?: boolean | string + transpile?: string | ((code: string) => string) + meta?: boolean | object + validateSchema?: boolean | "log" + addUsedSchema?: boolean + inlineRefs?: boolean | number + passContext?: boolean + loopRequired?: number + ownProperties?: boolean + multipleOfPrecision?: boolean | number + errorDataPath?: string + messages?: boolean + sourceCode?: boolean + processCode?: (code: string, schema: object) => string + cache?: object + logger?: CustomLogger | false + nullable?: boolean + serialize?: ((schema: object | boolean) => any) | false } - type FormatValidator = string | RegExp | ((data: string) => boolean | PromiseLike); - type NumberFormatValidator = ((data: number) => boolean | PromiseLike); + type FormatValidator = + | string + | RegExp + | ((data: string) => boolean | PromiseLike) + type NumberFormatValidator = (data: number) => boolean | PromiseLike interface NumberFormatDefinition { - type: "number", - validate: NumberFormatValidator; - compare?: (data1: number, data2: number) => number; - async?: boolean; + type: "number" + validate: NumberFormatValidator + compare?: (data1: number, data2: number) => number + async?: boolean } interface StringFormatDefinition { - type?: "string", - validate: FormatValidator; - compare?: (data1: string, data2: string) => number; - async?: boolean; + type?: "string" + validate: FormatValidator + compare?: (data1: string, data2: string) => number + async?: boolean } - type FormatDefinition = NumberFormatDefinition | StringFormatDefinition; + type FormatDefinition = NumberFormatDefinition | StringFormatDefinition interface KeywordDefinition { - type?: string | Array; - async?: boolean; - $data?: boolean; - errors?: boolean | string; - metaSchema?: object; + type?: string | Array + async?: boolean + $data?: boolean + errors?: boolean | string + metaSchema?: object // schema: false makes validate not to expect schema (ValidateFunction) - schema?: boolean; - statements?: boolean; - dependencies?: Array; - modifying?: boolean; - valid?: boolean; + schema?: boolean + statements?: boolean + dependencies?: Array + modifying?: boolean + valid?: boolean // one and only one of the following properties should be present - validate?: SchemaValidateFunction | ValidateFunction; - compile?: (schema: any, parentSchema: object, it: CompilationContext) => ValidateFunction; - macro?: (schema: any, parentSchema: object, it: CompilationContext) => object | boolean; - inline?: (it: CompilationContext, keyword: string, schema: any, parentSchema: object) => string; + validate?: SchemaValidateFunction | ValidateFunction + compile?: ( + schema: any, + parentSchema: object, + it: CompilationContext + ) => ValidateFunction + macro?: ( + schema: any, + parentSchema: object, + it: CompilationContext + ) => object | boolean + inline?: ( + it: CompilationContext, + keyword: string, + schema: any, + parentSchema: object + ) => string } interface CompilationContext { - level: number; - dataLevel: number; - dataPathArr: string[]; - schema: any; - schemaPath: string; - baseId: string; - async: boolean; - opts: Options; + level: number + dataLevel: number + dataPathArr: string[] + schema: any + schemaPath: string + baseId: string + async: boolean + opts: Options formats: { - [index: string]: FormatDefinition | undefined; - }; + [index: string]: FormatDefinition | undefined + } keywords: { - [index: string]: KeywordDefinition | undefined; - }; - compositeRule: boolean; - validate: (schema: object) => boolean; + [index: string]: KeywordDefinition | undefined + } + compositeRule: boolean + validate: (schema: object) => boolean util: { - copy(obj: any, target?: any): any; - toHash(source: string[]): { [index: string]: true | undefined }; - equal(obj: any, target: any): boolean; - getProperty(str: string): string; - schemaHasRules(schema: object, rules: any): string; - escapeQuotes(str: string): string; - toQuotedString(str: string): string; - getData(jsonPointer: string, dataLevel: number, paths: string[]): string; - escapeJsonPointer(str: string): string; - unescapeJsonPointer(str: string): string; - escapeFragment(str: string): string; - unescapeFragment(str: string): string; - }; - self: Ajv; + copy(obj: any, target?: any): any + toHash(source: string[]): {[index: string]: true | undefined} + equal(obj: any, target: any): boolean + getProperty(str: string): string + schemaHasRules(schema: object, rules: any): string + escapeQuotes(str: string): string + toQuotedString(str: string): string + getData(jsonPointer: string, dataLevel: number, paths: string[]): string + escapeJsonPointer(str: string): string + unescapeJsonPointer(str: string): string + escapeFragment(str: string): string + unescapeFragment(str: string): string + } + self: Ajv } interface SchemaValidateFunction { @@ -285,54 +314,67 @@ declare namespace ajv { parentData?: object | Array, parentDataProperty?: string | number, rootData?: object | Array - ): boolean | PromiseLike; - errors?: Array; + ): boolean | PromiseLike + errors?: Array } interface ErrorsTextOptions { - separator?: string; - dataVar?: string; + separator?: string + dataVar?: string } interface ErrorObject { - keyword: string; - dataPath: string; - schemaPath: string; - params: ErrorParameters; + keyword: string + dataPath: string + schemaPath: string + params: ErrorParameters // Added to validation errors of propertyNames keyword schema - propertyName?: string; + propertyName?: string // Excluded if messages set to false. - message?: string; + message?: string // These are added with the `verbose` option. - schema?: any; - parentSchema?: object; - data?: any; + schema?: any + parentSchema?: object + data?: any } - type ErrorParameters = RefParams | LimitParams | AdditionalPropertiesParams | - DependenciesParams | FormatParams | ComparisonParams | - MultipleOfParams | PatternParams | RequiredParams | - TypeParams | UniqueItemsParams | CustomParams | - PatternRequiredParams | PropertyNamesParams | - IfParams | SwitchParams | NoParams | EnumParams; + type ErrorParameters = + | RefParams + | LimitParams + | AdditionalPropertiesParams + | DependenciesParams + | FormatParams + | ComparisonParams + | MultipleOfParams + | PatternParams + | RequiredParams + | TypeParams + | UniqueItemsParams + | CustomParams + | PatternRequiredParams + | PropertyNamesParams + | IfParams + | SwitchParams + | NoParams + | EnumParams interface RefParams { - ref: string; + ref: string } interface LimitParams { - limit: number; + limit: number } interface AdditionalPropertiesParams { - additionalProperty: string; + additionalProperty: string } interface DependenciesParams { - property: string; - missingProperty: string; - depsCount: number; - deps: string; + property: string + missingProperty: string + depsCount: number + deps: string } interface FormatParams { @@ -340,57 +382,57 @@ declare namespace ajv { } interface ComparisonParams { - comparison: string; - limit: number | string; - exclusive: boolean; + comparison: string + limit: number | string + exclusive: boolean } interface MultipleOfParams { - multipleOf: number; + multipleOf: number } interface PatternParams { - pattern: string; + pattern: string } interface RequiredParams { - missingProperty: string; + missingProperty: string } interface TypeParams { - type: string; + type: string } interface UniqueItemsParams { - i: number; - j: number; + i: number + j: number } interface CustomParams { - keyword: string; + keyword: string } interface PatternRequiredParams { - missingPattern: string; + missingPattern: string } interface PropertyNamesParams { - propertyName: string; + propertyName: string } interface IfParams { - failingKeyword: string; + failingKeyword: string } interface SwitchParams { - caseIndex: number; + caseIndex: number } - interface NoParams { } + interface NoParams {} interface EnumParams { - allowedValues: Array; + allowedValues: Array } } -export = ajv; +export = ajv diff --git a/lib/ajv.js b/lib/ajv.js index 06a45b650b..228d83ba87 100644 --- a/lib/ajv.js +++ b/lib/ajv.js @@ -1,46 +1,50 @@ -'use strict'; - -var compileSchema = require('./compile') - , resolve = require('./compile/resolve') - , Cache = require('./cache') - , SchemaObject = require('./compile/schema_obj') - , stableStringify = require('fast-json-stable-stringify') - , formats = require('./compile/formats') - , rules = require('./compile/rules') - , $dataMetaSchema = require('./data') - , util = require('./compile/util'); - -module.exports = Ajv; - -Ajv.prototype.validate = validate; -Ajv.prototype.compile = compile; -Ajv.prototype.addSchema = addSchema; -Ajv.prototype.addMetaSchema = addMetaSchema; -Ajv.prototype.validateSchema = validateSchema; -Ajv.prototype.getSchema = getSchema; -Ajv.prototype.removeSchema = removeSchema; -Ajv.prototype.addFormat = addFormat; -Ajv.prototype.errorsText = errorsText; - -Ajv.prototype._addSchema = _addSchema; -Ajv.prototype._compile = _compile; - -Ajv.prototype.compileAsync = require('./compile/async'); -var customKeyword = require('./keyword'); -Ajv.prototype.addKeyword = customKeyword.add; -Ajv.prototype.getKeyword = customKeyword.get; -Ajv.prototype.removeKeyword = customKeyword.remove; -Ajv.prototype.validateKeyword = customKeyword.validate; - -var errorClasses = require('./compile/error_classes'); -Ajv.ValidationError = errorClasses.Validation; -Ajv.MissingRefError = errorClasses.MissingRef; -Ajv.$dataMetaSchema = $dataMetaSchema; - -var META_SCHEMA_ID = 'http://json-schema.org/draft-07/schema'; - -var META_IGNORE_OPTIONS = [ 'removeAdditional', 'useDefaults', 'coerceTypes', 'strictDefaults' ]; -var META_SUPPORT_DATA = ['/properties']; +"use strict" + +var compileSchema = require("./compile"), + resolve = require("./compile/resolve"), + Cache = require("./cache"), + SchemaObject = require("./compile/schema_obj"), + stableStringify = require("fast-json-stable-stringify"), + rules = require("./compile/rules"), + $dataMetaSchema = require("./data"), + util = require("./compile/util") + +module.exports = Ajv + +Ajv.prototype.validate = validate +Ajv.prototype.compile = compile +Ajv.prototype.addSchema = addSchema +Ajv.prototype.addMetaSchema = addMetaSchema +Ajv.prototype.validateSchema = validateSchema +Ajv.prototype.getSchema = getSchema +Ajv.prototype.removeSchema = removeSchema +Ajv.prototype.addFormat = addFormat +Ajv.prototype.errorsText = errorsText + +Ajv.prototype._addSchema = _addSchema +Ajv.prototype._compile = _compile + +Ajv.prototype.compileAsync = require("./compile/async") +var customKeyword = require("./keyword") +Ajv.prototype.addKeyword = customKeyword.add +Ajv.prototype.getKeyword = customKeyword.get +Ajv.prototype.removeKeyword = customKeyword.remove +Ajv.prototype.validateKeyword = customKeyword.validate + +var errorClasses = require("./compile/error_classes") +Ajv.ValidationError = errorClasses.Validation +Ajv.MissingRefError = errorClasses.MissingRef +Ajv.$dataMetaSchema = $dataMetaSchema + +var META_SCHEMA_ID = "http://json-schema.org/draft-07/schema" + +var META_IGNORE_OPTIONS = [ + "removeAdditional", + "useDefaults", + "coerceTypes", + "strictDefaults", +] +var META_SUPPORT_DATA = ["/properties"] /** * Creates validator instance. @@ -49,35 +53,37 @@ var META_SUPPORT_DATA = ['/properties']; * @return {Object} ajv instance */ function Ajv(opts) { - if (!(this instanceof Ajv)) return new Ajv(opts); - opts = this._opts = util.copy(opts) || {}; - setLogger(this); - this._schemas = {}; - this._refs = {}; - this._fragments = {}; - this._formats = formats(opts.format); - - this._cache = opts.cache || new Cache; - this._loadingSchemas = {}; - this._compilations = []; - this.RULES = rules(); - this._getId = chooseGetId(opts); - - opts.loopRequired = opts.loopRequired || Infinity; - if (opts.errorDataPath == 'property') opts._errorDataPathProperty = true; - if (opts.serialize === undefined) opts.serialize = stableStringify; - this._metaOpts = getMetaSchemaOptions(this); - - if (opts.formats) addInitialFormats(this); - if (opts.keywords) addInitialKeywords(this); - addDefaultMetaSchema(this); - if (typeof opts.meta == 'object') this.addMetaSchema(opts.meta); - if (opts.nullable) this.addKeyword('nullable', {metaSchema: {type: 'boolean'}}); - addInitialSchemas(this); + if (!(this instanceof Ajv)) return new Ajv(opts) + opts = this._opts = util.copy(opts) || {} + setLogger(this) + this._schemas = {} + this._refs = {} + this._fragments = {} + this._formats = {} + const formatOpt = opts.format + opts.format = false + + this._cache = opts.cache || new Cache() + this._loadingSchemas = {} + this._compilations = [] + this.RULES = rules() + this._getId = chooseGetId(opts) + + opts.loopRequired = opts.loopRequired || Infinity + if (opts.errorDataPath == "property") opts._errorDataPathProperty = true + if (opts.serialize === undefined) opts.serialize = stableStringify + this._metaOpts = getMetaSchemaOptions(this) + + if (opts.formats) addInitialFormats(this) + if (opts.keywords) addInitialKeywords(this) + addDefaultMetaSchema(this) + if (typeof opts.meta == "object") this.addMetaSchema(opts.meta) + if (opts.nullable) + this.addKeyword("nullable", {metaSchema: {type: "boolean"}}) + addInitialSchemas(this) + opts.format = formatOpt } - - /** * Validate data using schema * Schema will be compiled and cached (using serialized JSON as key. [fast-json-stable-stringify](https://github.com/epoberezkin/fast-json-stable-stringify) is used to serialize. @@ -87,21 +93,20 @@ function Ajv(opts) { * @return {Boolean} validation result. Errors from the last validation will be available in `ajv.errors` (and also in compiled schema: `schema.errors`). */ function validate(schemaKeyRef, data) { - var v; - if (typeof schemaKeyRef == 'string') { - v = this.getSchema(schemaKeyRef); - if (!v) throw new Error('no schema with key or ref "' + schemaKeyRef + '"'); + var v + if (typeof schemaKeyRef == "string") { + v = this.getSchema(schemaKeyRef) + if (!v) throw new Error('no schema with key or ref "' + schemaKeyRef + '"') } else { - var schemaObj = this._addSchema(schemaKeyRef); - v = schemaObj.validate || this._compile(schemaObj); + var schemaObj = this._addSchema(schemaKeyRef) + v = schemaObj.validate || this._compile(schemaObj) } - var valid = v(data); - if (v.$async !== true) this.errors = v.errors; - return valid; + var valid = v(data) + if (v.$async !== true) this.errors = v.errors + return valid } - /** * Create validating function for passed schema. * @this Ajv @@ -110,11 +115,10 @@ function validate(schemaKeyRef, data) { * @return {Function} validating function */ function compile(schema, _meta) { - var schemaObj = this._addSchema(schema, undefined, _meta); - return schemaObj.validate || this._compile(schemaObj); + var schemaObj = this._addSchema(schema, undefined, _meta) + return schemaObj.validate || this._compile(schemaObj) } - /** * Adds schema to the instance. * @this Ajv @@ -125,20 +129,20 @@ function compile(schema, _meta) { * @return {Ajv} this for method chaining */ function addSchema(schema, key, _skipValidation, _meta) { - if (Array.isArray(schema)){ - for (var i=0; i%\\^`{|}]|%[0-9a-f]{2})|\{[+#./;?&=,!@|]?(?:[a-z0-9_]|%[0-9a-f]{2})+(?::[1-9][0-9]{0,3}|\*)?(?:,(?:[a-z0-9_]|%[0-9a-f]{2})+(?::[1-9][0-9]{0,3}|\*)?)*\})*$/i; -// For the source: https://gist.github.com/dperini/729294 -// For test cases: https://mathiasbynens.be/demo/url-regex -// @todo Delete current URL in favour of the commented out URL rule when this issue is fixed https://github.com/eslint/eslint/issues/7983. -// 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)*)*$/; -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)*)*)$/; - - -module.exports = formats; - -function formats(mode) { - mode = mode == 'full' ? 'full' : 'fast'; - return util.copy(formats[mode]); -} - - -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|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#][^\s#]*)?(?:#[^\\\s]*)?$/i, - 'uri-template': URITEMPLATE, - url: URL, - // email (sources from jsen validator): - // http://stackoverflow.com/questions/201323/using-a-regular-expression-to-validate-an-email-address#answer-8829363 - // http://www.w3.org/TR/html5/forms.html#valid-e-mail-address (search for 'willful violation') - email: /^[a-z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*$/i, - hostname: HOSTNAME, - // optimized https://www.safaribooksonline.com/library/view/regular-expressions-cookbook/9780596802837/ch07s16.html - ipv4: /^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$/, - // optimized http://stackoverflow.com/questions/53497/regular-expression-that-matches-valid-ipv6-addresses - ipv6: /^\s*(?:(?:(?:[0-9a-f]{1,4}:){7}(?:[0-9a-f]{1,4}|:))|(?:(?:[0-9a-f]{1,4}:){6}(?::[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){5}(?:(?:(?::[0-9a-f]{1,4}){1,2})|:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){4}(?:(?:(?::[0-9a-f]{1,4}){1,3})|(?:(?::[0-9a-f]{1,4})?:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){3}(?:(?:(?::[0-9a-f]{1,4}){1,4})|(?:(?::[0-9a-f]{1,4}){0,2}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){2}(?:(?:(?::[0-9a-f]{1,4}){1,5})|(?:(?::[0-9a-f]{1,4}){0,3}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){1}(?:(?:(?::[0-9a-f]{1,4}){1,6})|(?:(?::[0-9a-f]{1,4}){0,4}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?::(?:(?:(?::[0-9a-f]{1,4}){1,7})|(?:(?::[0-9a-f]{1,4}){0,5}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(?:%.+)?\s*$/i, - regex: regex, - // uuid: http://tools.ietf.org/html/rfc4122 - uuid: UUID, - // 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 -}; - - -formats.full = { - date: date, - time: time, - 'date-time': date_time, - uri: uri, - 'uri-reference': URIREF, - 'uri-template': URITEMPLATE, - url: URL, - email: /^[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i, - hostname: HOSTNAME, - ipv4: /^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$/, - ipv6: /^\s*(?:(?:(?:[0-9a-f]{1,4}:){7}(?:[0-9a-f]{1,4}|:))|(?:(?:[0-9a-f]{1,4}:){6}(?::[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){5}(?:(?:(?::[0-9a-f]{1,4}){1,2})|:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){4}(?:(?:(?::[0-9a-f]{1,4}){1,3})|(?:(?::[0-9a-f]{1,4})?:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){3}(?:(?:(?::[0-9a-f]{1,4}){1,4})|(?:(?::[0-9a-f]{1,4}){0,2}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){2}(?:(?:(?::[0-9a-f]{1,4}){1,5})|(?:(?::[0-9a-f]{1,4}){0,3}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){1}(?:(?:(?::[0-9a-f]{1,4}){1,6})|(?:(?::[0-9a-f]{1,4}){0,4}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?::(?:(?:(?::[0-9a-f]{1,4}){1,7})|(?:(?::[0-9a-f]{1,4}){0,5}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(?:%.+)?\s*$/i, - 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 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]); -} - - -function time(str, full) { - var matches = str.match(TIME); - if (!matches) return false; - - var hour = matches[1]; - var minute = matches[2]; - var second = matches[3]; - var timeZone = matches[5]; - return ((hour <= 23 && minute <= 59 && second <= 59) || - (hour == 23 && minute == 59 && second == 60)) && - (!full || timeZone); -} - - -var DATE_TIME_SEPARATOR = /t|\s/i; -function date_time(str) { - // http://tools.ietf.org/html/rfc3339#section-5.6 - var dateTime = str.split(DATE_TIME_SEPARATOR); - return dateTime.length == 2 && date(dateTime[0]) && time(dateTime[1], true); -} - - -var NOT_URI_FRAGMENT = /\/|:/; -function uri(str) { - // http://jmrware.com/articles/2009/uri_regexp/URI_regex.html + optional protocol + required "." - return NOT_URI_FRAGMENT.test(str) && URI.test(str); -} - - -var Z_ANCHOR = /[^\\]\\Z/; -function regex(str) { - if (Z_ANCHOR.test(str)) return false; - try { - new RegExp(str); - return true; - } catch(e) { - return false; - } -} diff --git a/lib/compile/index.js b/lib/compile/index.js index 97518c4247..2eb4750d2a 100644 --- a/lib/compile/index.js +++ b/lib/compile/index.js @@ -1,24 +1,23 @@ -'use strict'; +"use strict" -var resolve = require('./resolve') - , util = require('./util') - , errorClasses = require('./error_classes') - , stableStringify = require('fast-json-stable-stringify'); +var resolve = require("./resolve"), + util = require("./util"), + errorClasses = require("./error_classes"), + stableStringify = require("fast-json-stable-stringify") -var validateGenerator = require('../dotjs/validate'); +var validateGenerator = require("../dotjs/validate") /** * Functions below are used inside compiled validations function */ -var ucs2length = util.ucs2length; -var equal = require('fast-deep-equal'); +var ucs2length = util.ucs2length +var equal = require("fast-deep-equal") // this error is thrown by async schemas to return validation errors via exception -var ValidationError = errorClasses.Validation; - -module.exports = compile; +var ValidationError = errorClasses.Validation +module.exports = compile /** * Compiles schema to validation function @@ -32,58 +31,58 @@ module.exports = compile; function compile(schema, root, localRefs, baseId) { /* jshint validthis: true, evil: true */ /* eslint no-shadow: 0 */ - var self = this - , opts = this._opts - , refVal = [ undefined ] - , refs = {} - , patterns = [] - , patternsHash = {} - , defaults = [] - , defaultsHash = {} - , customRules = []; + var self = this, + opts = this._opts, + refVal = [undefined], + refs = {}, + patterns = [], + patternsHash = {}, + defaults = [], + defaultsHash = {}, + customRules = [] - root = root || { schema: schema, refVal: refVal, refs: refs }; + root = root || {schema: schema, refVal: refVal, refs: refs} - var c = checkCompiling.call(this, schema, root, baseId); - var compilation = this._compilations[c.index]; - if (c.compiling) return (compilation.callValidate = callValidate); + var c = checkCompiling.call(this, schema, root, baseId) + var compilation = this._compilations[c.index] + if (c.compiling) return (compilation.callValidate = callValidate) - var formats = this._formats; - var RULES = this.RULES; + var formats = this._formats + var RULES = this.RULES try { - var v = localCompile(schema, root, localRefs, baseId); - compilation.validate = v; - var cv = compilation.callValidate; + var v = localCompile(schema, root, localRefs, baseId) + compilation.validate = v + var cv = compilation.callValidate if (cv) { - cv.schema = v.schema; - cv.errors = null; - cv.refs = v.refs; - cv.refVal = v.refVal; - cv.root = v.root; - cv.$async = v.$async; - if (opts.sourceCode) cv.source = v.source; + cv.schema = v.schema + cv.errors = null + cv.refs = v.refs + cv.refVal = v.refVal + cv.root = v.root + cv.$async = v.$async + if (opts.sourceCode) cv.source = v.source } - return v; + return v } finally { - endCompiling.call(this, schema, root, baseId); + endCompiling.call(this, schema, root, baseId) } /* @this {*} - custom context, see passContext option */ function callValidate() { /* jshint validthis: true */ - var validate = compilation.validate; - var result = validate.apply(this, arguments); - callValidate.errors = validate.errors; - return result; + var validate = compilation.validate + var result = validate.apply(this, arguments) + callValidate.errors = validate.errors + return result } function localCompile(_schema, _root, localRefs, baseId) { - var isRoot = !_root || (_root && _root.schema == _schema); + var isRoot = !_root || (_root && _root.schema == _schema) if (_root.schema != root.schema) - return compile.call(self, _schema, _root, localRefs, baseId); + return compile.call(self, _schema, _root, localRefs, baseId) - var $async = _schema.$async === true; + var $async = _schema.$async === true var sourceCode = validateGenerator({ isTop: true, @@ -91,8 +90,8 @@ function compile(schema, root, localRefs, baseId) { isRoot: isRoot, baseId: baseId, root: _root, - schemaPath: '', - errSchemaPath: '#', + schemaPath: "", + errSchemaPath: "#", errorPath: '""', MissingRefError: errorClasses.MissingRef, RULES: RULES, @@ -106,30 +105,33 @@ function compile(schema, root, localRefs, baseId) { opts: opts, formats: formats, logger: self.logger, - self: self - }); + self: self, + }) - sourceCode = vars(refVal, refValCode) + vars(patterns, patternCode) - + vars(defaults, defaultCode) + vars(customRules, customRuleCode) - + sourceCode; + sourceCode = + vars(refVal, refValCode) + + vars(patterns, patternCode) + + vars(defaults, defaultCode) + + vars(customRules, customRuleCode) + + sourceCode - if (opts.processCode) sourceCode = opts.processCode(sourceCode, _schema); + if (opts.processCode) sourceCode = opts.processCode(sourceCode, _schema) // console.log('\n\n\n *** \n', JSON.stringify(sourceCode)); - var validate; + var validate try { var makeValidate = new Function( - 'self', - 'RULES', - 'formats', - 'root', - 'refVal', - 'defaults', - 'customRules', - 'equal', - 'ucs2length', - 'ValidationError', + "self", + "RULES", + "formats", + "root", + "refVal", + "defaults", + "customRules", + "equal", + "ucs2length", + "ValidationError", sourceCode - ); + ) validate = makeValidate( self, @@ -142,168 +144,175 @@ function compile(schema, root, localRefs, baseId) { equal, ucs2length, ValidationError - ); + ) - refVal[0] = validate; - } catch(e) { - self.logger.error('Error compiling schema, function code:', sourceCode); - throw e; + refVal[0] = validate + } catch (e) { + self.logger.error("Error compiling schema, function code:", sourceCode) + throw e } - validate.schema = _schema; - validate.errors = null; - validate.refs = refs; - validate.refVal = refVal; - validate.root = isRoot ? validate : _root; - if ($async) validate.$async = true; + validate.schema = _schema + validate.errors = null + validate.refs = refs + validate.refVal = refVal + validate.root = isRoot ? validate : _root + if ($async) validate.$async = true if (opts.sourceCode === true) { validate.source = { code: sourceCode, patterns: patterns, - defaults: defaults - }; + defaults: defaults, + } } - return validate; + return validate } function resolveRef(baseId, ref, isRoot) { - ref = resolve.url(baseId, ref); - var refIndex = refs[ref]; - var _refVal, refCode; + ref = resolve.url(baseId, ref) + var refIndex = refs[ref] + var _refVal, refCode if (refIndex !== undefined) { - _refVal = refVal[refIndex]; - refCode = 'refVal[' + refIndex + ']'; - return resolvedRef(_refVal, refCode); + _refVal = refVal[refIndex] + refCode = "refVal[" + refIndex + "]" + return resolvedRef(_refVal, refCode) } if (!isRoot && root.refs) { - var rootRefId = root.refs[ref]; + var rootRefId = root.refs[ref] if (rootRefId !== undefined) { - _refVal = root.refVal[rootRefId]; - refCode = addLocalRef(ref, _refVal); - return resolvedRef(_refVal, refCode); + _refVal = root.refVal[rootRefId] + refCode = addLocalRef(ref, _refVal) + return resolvedRef(_refVal, refCode) } } - refCode = addLocalRef(ref); - var v = resolve.call(self, localCompile, root, ref); + refCode = addLocalRef(ref) + var v = resolve.call(self, localCompile, root, ref) if (v === undefined) { - var localSchema = localRefs && localRefs[ref]; + var localSchema = localRefs && localRefs[ref] if (localSchema) { v = resolve.inlineRef(localSchema, opts.inlineRefs) - ? localSchema - : compile.call(self, localSchema, root, localRefs, baseId); + ? localSchema + : compile.call(self, localSchema, root, localRefs, baseId) } } if (v === undefined) { - removeLocalRef(ref); + removeLocalRef(ref) } else { - replaceLocalRef(ref, v); - return resolvedRef(v, refCode); + replaceLocalRef(ref, v) + return resolvedRef(v, refCode) } } function addLocalRef(ref, v) { - var refId = refVal.length; - refVal[refId] = v; - refs[ref] = refId; - return 'refVal' + refId; + var refId = refVal.length + refVal[refId] = v + refs[ref] = refId + return "refVal" + refId } function removeLocalRef(ref) { - delete refs[ref]; + delete refs[ref] } function replaceLocalRef(ref, v) { - var refId = refs[ref]; - refVal[refId] = v; + var refId = refs[ref] + refVal[refId] = v } function resolvedRef(refVal, code) { - return typeof refVal == 'object' || typeof refVal == 'boolean' - ? { code: code, schema: refVal, inline: true } - : { code: code, $async: refVal && !!refVal.$async }; + return typeof refVal == "object" || typeof refVal == "boolean" + ? {code: code, schema: refVal, inline: true} + : {code: code, $async: refVal && !!refVal.$async} } function usePattern(regexStr) { - var index = patternsHash[regexStr]; + var index = patternsHash[regexStr] if (index === undefined) { - index = patternsHash[regexStr] = patterns.length; - patterns[index] = regexStr; + index = patternsHash[regexStr] = patterns.length + patterns[index] = regexStr } - return 'pattern' + index; + return "pattern" + index } function useDefault(value) { switch (typeof value) { - case 'boolean': - case 'number': - return '' + value; - case 'string': - return util.toQuotedString(value); - case 'object': - if (value === null) return 'null'; - var valueStr = stableStringify(value); - var index = defaultsHash[valueStr]; + case "boolean": + case "number": + return "" + value + case "string": + return util.toQuotedString(value) + case "object": + if (value === null) return "null" + var valueStr = stableStringify(value) + var index = defaultsHash[valueStr] if (index === undefined) { - index = defaultsHash[valueStr] = defaults.length; - defaults[index] = value; + index = defaultsHash[valueStr] = defaults.length + defaults[index] = value } - return 'default' + index; + return "default" + index } } function useCustomRule(rule, schema, parentSchema, it) { if (self._opts.validateSchema !== false) { - var deps = rule.definition.dependencies; - if (deps && !deps.every(function(keyword) { - return Object.prototype.hasOwnProperty.call(parentSchema, keyword); - })) - throw new Error('parent schema must have all required keywords: ' + deps.join(',')); + var deps = rule.definition.dependencies + if ( + deps && + !deps.every(function (keyword) { + return Object.prototype.hasOwnProperty.call(parentSchema, keyword) + }) + ) { + throw new Error( + "parent schema must have all required keywords: " + deps.join(",") + ) + } - var validateSchema = rule.definition.validateSchema; + var validateSchema = rule.definition.validateSchema if (validateSchema) { - var valid = validateSchema(schema); + var valid = validateSchema(schema) if (!valid) { - var message = 'keyword schema is invalid: ' + self.errorsText(validateSchema.errors); - if (self._opts.validateSchema == 'log') self.logger.error(message); - else throw new Error(message); + var message = + "keyword schema is invalid: " + + self.errorsText(validateSchema.errors) + if (self._opts.validateSchema == "log") self.logger.error(message) + else throw new Error(message) } } } - var compile = rule.definition.compile - , inline = rule.definition.inline - , macro = rule.definition.macro; + var compile = rule.definition.compile, + inline = rule.definition.inline, + macro = rule.definition.macro - var validate; + var validate if (compile) { - validate = compile.call(self, schema, parentSchema, it); + validate = compile.call(self, schema, parentSchema, it) } else if (macro) { - validate = macro.call(self, schema, parentSchema, it); - if (opts.validateSchema !== false) self.validateSchema(validate, true); + validate = macro.call(self, schema, parentSchema, it) + if (opts.validateSchema !== false) self.validateSchema(validate, true) } else if (inline) { - validate = inline.call(self, it, rule.keyword, schema, parentSchema); + validate = inline.call(self, it, rule.keyword, schema, parentSchema) } else { - validate = rule.definition.validate; - if (!validate) return; + validate = rule.definition.validate + if (!validate) return } if (validate === undefined) - throw new Error('custom keyword "' + rule.keyword + '"failed to compile'); + throw new Error('custom keyword "' + rule.keyword + '"failed to compile') - var index = customRules.length; - customRules[index] = validate; + var index = customRules.length + customRules[index] = validate return { - code: 'customRule' + index, - validate: validate - }; + code: "customRule" + index, + validate: validate, + } } } - /** * Checks if the schema is currently compiled * @this Ajv @@ -314,18 +323,17 @@ function compile(schema, root, localRefs, baseId) { */ function checkCompiling(schema, root, baseId) { /* jshint validthis: true */ - var index = compIndex.call(this, schema, root, baseId); - if (index >= 0) return { index: index, compiling: true }; - index = this._compilations.length; + var index = compIndex.call(this, schema, root, baseId) + if (index >= 0) return {index: index, compiling: true} + index = this._compilations.length this._compilations[index] = { schema: schema, root: root, - baseId: baseId - }; - return { index: index, compiling: false }; + baseId: baseId, + } + return {index: index, compiling: false} } - /** * Removes the schema from the currently compiled list * @this Ajv @@ -335,11 +343,10 @@ function checkCompiling(schema, root, baseId) { */ function endCompiling(schema, root, baseId) { /* jshint validthis: true */ - var i = compIndex.call(this, schema, root, baseId); - if (i >= 0) this._compilations.splice(i, 1); + var i = compIndex.call(this, schema, root, baseId) + if (i >= 0) this._compilations.splice(i, 1) } - /** * Index of schema compilation in the currently compiled list * @this Ajv @@ -350,38 +357,40 @@ function endCompiling(schema, root, baseId) { */ function compIndex(schema, root, baseId) { /* jshint validthis: true */ - for (var i=0; i= 0xD800 && value <= 0xDBFF && pos < len) { + length++ + value = str.charCodeAt(pos++) + if (value >= 0xd800 && value <= 0xdbff && pos < len) { // high surrogate, and there is a next character - value = str.charCodeAt(pos); - if ((value & 0xFC00) == 0xDC00) pos++; // low surrogate + value = str.charCodeAt(pos) + if ((value & 0xfc00) == 0xdc00) pos++ // low surrogate } } - return length; -}; + return length +} diff --git a/lib/compile/util.js b/lib/compile/util.js index ef07b8c757..e944274187 100644 --- a/lib/compile/util.js +++ b/lib/compile/util.js @@ -1,5 +1,4 @@ -'use strict'; - +"use strict" module.exports = { copy: copy, @@ -9,8 +8,8 @@ module.exports = { toHash: toHash, getProperty: getProperty, escapeQuotes: escapeQuotes, - equal: require('fast-deep-equal'), - ucs2length: require('./ucs2length'), + equal: require("fast-deep-equal"), + ucs2length: require("./ucs2length"), varOccurences: varOccurences, varReplace: varReplace, schemaHasRules: schemaHasRules, @@ -23,217 +22,256 @@ module.exports = { unescapeFragment: unescapeFragment, unescapeJsonPointer: unescapeJsonPointer, escapeFragment: escapeFragment, - escapeJsonPointer: escapeJsonPointer -}; - + escapeJsonPointer: escapeJsonPointer, +} function copy(o, to) { - to = to || {}; - for (var key in o) to[key] = o[key]; - return to; + to = to || {} + for (var key in o) to[key] = o[key] + return to } - function checkDataType(dataType, data, strictNumbers, negate) { - var EQUAL = negate ? ' !== ' : ' === ' - , AND = negate ? ' || ' : ' && ' - , OK = negate ? '!' : '' - , NOT = negate ? '' : '!'; + var EQUAL = negate ? " !== " : " === ", + AND = negate ? " || " : " && ", + OK = negate ? "!" : "", + NOT = negate ? "" : "!" switch (dataType) { - case 'null': return data + EQUAL + 'null'; - case 'array': return OK + 'Array.isArray(' + data + ')'; - case 'object': return '(' + OK + data + AND + - 'typeof ' + data + EQUAL + '"object"' + AND + - NOT + 'Array.isArray(' + data + '))'; - case 'integer': return '(typeof ' + data + EQUAL + '"number"' + AND + - NOT + '(' + data + ' % 1)' + - AND + data + EQUAL + data + - (strictNumbers ? (AND + OK + 'isFinite(' + data + ')') : '') + ')'; - case 'number': return '(typeof ' + data + EQUAL + '"' + dataType + '"' + - (strictNumbers ? (AND + OK + 'isFinite(' + data + ')') : '') + ')'; - default: return 'typeof ' + data + EQUAL + '"' + dataType + '"'; + case "null": + return data + EQUAL + "null" + case "array": + return OK + "Array.isArray(" + data + ")" + case "object": + return ( + "(" + + OK + + data + + AND + + "typeof " + + data + + EQUAL + + '"object"' + + AND + + NOT + + "Array.isArray(" + + data + + "))" + ) + case "integer": + return ( + "(typeof " + + data + + EQUAL + + '"number"' + + AND + + NOT + + "(" + + data + + " % 1)" + + AND + + data + + EQUAL + + data + + (strictNumbers ? AND + OK + "isFinite(" + data + ")" : "") + + ")" + ) + case "number": + return ( + "(typeof " + + data + + EQUAL + + '"' + + dataType + + '"' + + (strictNumbers ? AND + OK + "isFinite(" + data + ")" : "") + + ")" + ) + default: + return "typeof " + data + EQUAL + '"' + dataType + '"' } } - function checkDataTypes(dataTypes, data, strictNumbers) { switch (dataTypes.length) { - case 1: return checkDataType(dataTypes[0], data, strictNumbers, true); + case 1: + return checkDataType(dataTypes[0], data, strictNumbers, true) default: - var code = ''; - var types = toHash(dataTypes); + var code = "" + var types = toHash(dataTypes) if (types.array && types.object) { - code = types.null ? '(': '(!' + data + ' || '; - code += 'typeof ' + data + ' !== "object")'; - delete types.null; - delete types.array; - delete types.object; + code = types.null ? "(" : "(!" + data + " || " + code += "typeof " + data + ' !== "object")' + delete types.null + delete types.array + delete types.object + } + if (types.number) delete types.integer + for (var t in types) { + code += + (code ? " && " : "") + checkDataType(t, data, strictNumbers, true) } - if (types.number) delete types.integer; - for (var t in types) - code += (code ? ' && ' : '' ) + checkDataType(t, data, strictNumbers, true); - return code; + return code } } - -var COERCE_TO_TYPES = toHash([ 'string', 'number', 'integer', 'boolean', 'null' ]); +var COERCE_TO_TYPES = toHash(["string", "number", "integer", "boolean", "null"]) function coerceToTypes(optionCoerceTypes, dataTypes) { if (Array.isArray(dataTypes)) { - var types = []; - for (var i=0; i= lvl) throw new Error('Cannot access property/index ' + up + ' levels up, current level is ' + lvl); - return paths[lvl - up]; + matches = $data.match(RELATIVE_JSON_POINTER) + if (!matches) throw new Error("Invalid JSON-pointer: " + $data) + up = +matches[1] + jsonPointer = matches[2] + if (jsonPointer == "#") { + if (up >= lvl) { + throw new Error( + "Cannot access property/index " + + up + + " levels up, current level is " + + lvl + ) + } + return paths[lvl - up] } - if (up > lvl) throw new Error('Cannot access data ' + up + ' levels up, current level is ' + lvl); - data = 'data' + ((lvl - up) || ''); - if (!jsonPointer) return data; + if (up > lvl) { + throw new Error( + "Cannot access data " + up + " levels up, current level is " + lvl + ) + } + data = "data" + (lvl - up || "") + if (!jsonPointer) return data } - var expr = data; - var segments = jsonPointer.split('/'); - for (var i=0; i 0; - } - }); + describe("formats for number", function () { + it("should validate only numbers", function () { + ajv.addFormat("positive", { + type: "number", + validate: function (x) { + return x > 0 + }, + }) var validate = ajv.compile({ - format: 'positive' - }); - validate(-2) .should.equal(false); - validate(0) .should.equal(false); - validate(2) .should.equal(true); - validate('abc') .should.equal(true); - }); - - it('should validate numbers with format via $data', function() { - ajv = new Ajv({$data: true}); - ajv.addFormat('positive', { - type: 'number', - validate: function(x) { - return x > 0; - } - }); + format: "positive", + }) + validate(-2).should.equal(false) + validate(0).should.equal(false) + validate(2).should.equal(true) + validate("abc").should.equal(true) + }) + + it("should validate numbers with format via $data", function () { + ajv = new Ajv({$data: true}) + ajv.addFormat("positive", { + type: "number", + validate: function (x) { + return x > 0 + }, + }) var validate = ajv.compile({ properties: { - data: { format: { $data: '1/frmt' } }, - frmt: { type: 'string' } - } - }); - validate({data: -2, frmt: 'positive'}) .should.equal(false); - validate({data: 0, frmt: 'positive'}) .should.equal(false); - validate({data: 2, frmt: 'positive'}) .should.equal(true); - validate({data: 'abc', frmt: 'positive'}) .should.equal(true); - }); - }); - }); - - - describe('validateSchema method', function() { - it('should validate schema against meta-schema', function() { + data: {format: {$data: "1/frmt"}}, + frmt: {type: "string"}, + }, + }) + validate({data: -2, frmt: "positive"}).should.equal(false) + validate({data: 0, frmt: "positive"}).should.equal(false) + validate({data: 2, frmt: "positive"}).should.equal(true) + validate({data: "abc", frmt: "positive"}).should.equal(true) + }) + }) + }) + + describe("validateSchema method", function () { + it("should validate schema against meta-schema", function () { var valid = ajv.validateSchema({ - $schema: 'http://json-schema.org/draft-07/schema#', - type: 'number' - }); + $schema: "http://json-schema.org/draft-07/schema#", + type: "number", + }) - valid .should.equal(true); - should.equal(ajv.errors, null); + valid.should.equal(true) + should.equal(ajv.errors, null) valid = ajv.validateSchema({ - $schema: 'http://json-schema.org/draft-07/schema#', - type: 'wrong_type' - }); - - valid .should.equal(false); - ajv.errors.length .should.equal(3); - ajv.errors[0].keyword .should.equal('enum'); - ajv.errors[1].keyword .should.equal('type'); - ajv.errors[2].keyword .should.equal('anyOf'); - }); - - it('should throw exception if meta-schema is unknown', function() { - should.throw(function() { + $schema: "http://json-schema.org/draft-07/schema#", + type: "wrong_type", + }) + + valid.should.equal(false) + ajv.errors.length.should.equal(3) + ajv.errors[0].keyword.should.equal("enum") + ajv.errors[1].keyword.should.equal("type") + ajv.errors[2].keyword.should.equal("anyOf") + }) + + it("should throw exception if meta-schema is unknown", function () { + should.throw(function () { ajv.validateSchema({ - $schema: 'http://example.com/unknown/schema#', - type: 'number' - }); - }); - }); - - it('should throw exception if $schema is not a string', function() { - should.throw(function() { + $schema: "http://example.com/unknown/schema#", + type: "number", + }) + }) + }) + + it("should throw exception if $schema is not a string", function () { + should.throw(function () { ajv.validateSchema({ $schema: {}, - type: 'number' - }); - }); - }); + type: "number", + }) + }) + }) - describe('sub-schema validation outside of definitions during compilation', function() { - it('maximum', function() { + describe("sub-schema validation outside of definitions during compilation", function () { + it("maximum", function () { passValidationThrowCompile({ - $ref: '#/foo', - foo: {maximum: 'bar'} - }); - }); + $ref: "#/foo", + foo: {maximum: "bar"}, + }) + }) - it('exclusiveMaximum', function() { + it("exclusiveMaximum", function () { passValidationThrowCompile({ - $ref: '#/foo', - foo: {exclusiveMaximum: 'bar'} - }); - }); + $ref: "#/foo", + foo: {exclusiveMaximum: "bar"}, + }) + }) - it('maxItems', function() { + it("maxItems", function () { passValidationThrowCompile({ - $ref: '#/foo', - foo: {maxItems: 'bar'} - }); - }); + $ref: "#/foo", + foo: {maxItems: "bar"}, + }) + }) - it('maxLength', function() { + it("maxLength", function () { passValidationThrowCompile({ - $ref: '#/foo', - foo: {maxLength: 'bar'} - }); - }); + $ref: "#/foo", + foo: {maxLength: "bar"}, + }) + }) - it('maxProperties', function() { + it("maxProperties", function () { passValidationThrowCompile({ - $ref: '#/foo', - foo: {maxProperties: 'bar'} - }); - }); + $ref: "#/foo", + foo: {maxProperties: "bar"}, + }) + }) - it('multipleOf', function() { + it("multipleOf", function () { passValidationThrowCompile({ - $ref: '#/foo', - foo: {maxProperties: 'bar'} - }); - }); + $ref: "#/foo", + foo: {maxProperties: "bar"}, + }) + }) function passValidationThrowCompile(schema) { - ajv.validateSchema(schema) .should.equal(true); - should.throw(function() { - ajv.compile(schema); - }); + ajv.validateSchema(schema).should.equal(true) + should.throw(function () { + ajv.compile(schema) + }) } - }); - }); -}); + }) + }) +}) diff --git a/spec/ajv_async_instances.js b/spec/ajv_async_instances.js index 8facd36374..8a41945a45 100644 --- a/spec/ajv_async_instances.js +++ b/spec/ajv_async_instances.js @@ -1,39 +1,39 @@ -'use strict'; +"use strict" -var Ajv = require('./ajv') - , util = require('../lib/compile/util') - , setupAsync = require('./ajv-async'); +var Ajv = require("./ajv"), + util = require("../lib/compile/util"), + setupAsync = require("./ajv-async") -module.exports = getAjvInstances; - -var firstTime = true; +module.exports = getAjvInstances +var firstTime = true function getAjvInstances(opts) { - opts = opts || {}; - var instances = []; + opts = opts || {} + var instances = [] var options = [ {}, - { transpile: true }, - { allErrors: true }, - { transpile: true, allErrors: true } - ]; + {transpile: true}, + {allErrors: true}, + {transpile: true, allErrors: true}, + ] options.forEach(function (_opts) { - util.copy(opts, _opts); - var ajv = getAjv(_opts); - if (ajv) instances.push(ajv); - }); + util.copy(opts, _opts) + var ajv = getAjv(_opts) + if (ajv) instances.push(ajv) + }) if (firstTime) { - console.log('Testing', instances.length, 'ajv instances:'); - firstTime = false; + console.log("Testing", instances.length, "ajv instances:") + firstTime = false } - return instances; + return instances } - -function getAjv(opts){ - try { return setupAsync(new Ajv(opts)); } catch(e) {} +function getAjv(opts) { + try { + return setupAsync(new Ajv(opts)) + } catch (e) {} } diff --git a/spec/ajv_instances.js b/spec/ajv_instances.js index f056d5a01d..4ca9fa5385 100644 --- a/spec/ajv_instances.js +++ b/spec/ajv_instances.js @@ -1,32 +1,30 @@ -'use strict'; +"use strict" -var Ajv = require('./ajv'); - -module.exports = getAjvInstances; +var Ajv = require("./ajv") +module.exports = getAjvInstances function getAjvInstances(options, extraOpts) { - return _getAjvInstances(options, extraOpts || {}); + return _getAjvInstances(options, extraOpts || {}) } function _getAjvInstances(opts, useOpts) { - var optNames = Object.keys(opts); + var optNames = Object.keys(opts) if (optNames.length) { - opts = copy(opts); - var useOpts1 = copy(useOpts) - , optName = optNames[0]; - useOpts1[optName] = opts[optName]; - delete opts[optName]; - var instances = _getAjvInstances(opts, useOpts) - , instances1 = _getAjvInstances(opts, useOpts1); - return instances.concat(instances1); + opts = copy(opts) + var useOpts1 = copy(useOpts), + optName = optNames[0] + useOpts1[optName] = opts[optName] + delete opts[optName] + var instances = _getAjvInstances(opts, useOpts), + instances1 = _getAjvInstances(opts, useOpts1) + return instances.concat(instances1) } - return [ new Ajv(useOpts) ]; + return [new Ajv(useOpts)] } - function copy(o, to) { - to = to || {}; - for (var key in o) to[key] = o[key]; - return to; + to = to || {} + for (var key in o) to[key] = o[key] + return to } diff --git a/spec/ajv_options.js b/spec/ajv_options.js index e09e73b634..711fa9678d 100644 --- a/spec/ajv_options.js +++ b/spec/ajv_options.js @@ -1,20 +1,20 @@ -'use strict'; +"use strict" -var isBrowser = typeof window == 'object'; -var fullTest = isBrowser || !process.env.AJV_FAST_TEST; +var isBrowser = typeof window == "object" +var fullTest = isBrowser || !process.env.AJV_FAST_TEST var options = fullTest - ? { - allErrors: true, - verbose: true, - format: 'full', - extendRefs: 'ignore', - inlineRefs: false, - jsonPointers: true - } - : { allErrors: true }; + ? { + allErrors: true, + verbose: true, + format: "full", + extendRefs: "ignore", + inlineRefs: false, + jsonPointers: true, + } + : {allErrors: true} if (fullTest && !isBrowser) - options.processCode = require('js-beautify').js_beautify; + options.processCode = require("js-beautify").js_beautify -module.exports = options; +module.exports = options diff --git a/spec/async.spec.js b/spec/async.spec.js index 5b4c5ff6e5..691de0b202 100644 --- a/spec/async.spec.js +++ b/spec/async.spec.js @@ -1,459 +1,441 @@ -'use strict'; +"use strict" /* global Promise */ -var Ajv = require('./ajv') - , should = require('./chai').should(); +var Ajv = require("./ajv"), + should = require("./chai").should() - -describe('compileAsync method', function() { - var ajv, loadCallCount; +describe("compileAsync method", function () { + var ajv, loadCallCount var SCHEMAS = { "http://example.com/object.json": { - "$id": "http://example.com/object.json", - "properties": { - "a": { "type": "string" }, - "b": { "$ref": "int2plus.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", - "type": "integer", - "minimum": 2 + $id: "http://example.com/int2plus.json", + type: "integer", + minimum: 2, }, "http://example.com/tree.json": { - "$id": "http://example.com/tree.json", - "type": "array", - "items": { "$ref": "leaf.json" } + $id: "http://example.com/tree.json", + type: "array", + items: {$ref: "leaf.json"}, }, "http://example.com/leaf.json": { - "$id": "http://example.com/leaf.json", - "properties": { - "name": { "type": "string" }, - "subtree": { "$ref": "tree.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", - "properties": { - "b": { "$ref": "parent.json" } + $id: "http://example.com/recursive.json", + properties: { + b: {$ref: "parent.json"}, }, - "required": ["b"] + required: ["b"], }, "http://example.com/invalid.json": { - "$id": "http://example.com/recursive.json", - "properties": { - "invalid": { "type": "number" } + $id: "http://example.com/recursive.json", + properties: { + invalid: {type: "number"}, }, - "required": "invalid" + required: "invalid", }, "http://example.com/foobar.json": { - "$id": "http://example.com/foobar.json", - "$schema": "http://example.com/foobar_meta.json", - "myFooBar": "foo" + $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", - "type": "object", - "properties": { - "myFooBar": { - "enum": ["foo", "bar"] - } - } + $id: "http://example.com/foobar_meta.json", + type: "object", + properties: { + myFooBar: { + enum: ["foo", "bar"], + }, + }, }, "http://example.com/foo.json": { - "$id": "http://example.com/foo.json", - "type": "object", - "properties": { - "bar": {"$ref": "bar.json"}, - "other": {"$ref": "other.json"} - } + $id: "http://example.com/foo.json", + type: "object", + properties: { + bar: {$ref: "bar.json"}, + other: {$ref: "other.json"}, + }, }, "http://example.com/bar.json": { - "$id": "http://example.com/bar.json", - "type": "object", - "properties": { - "foo": {"$ref": "foo.json"} - } + $id: "http://example.com/bar.json", + type: "object", + properties: { + foo: {$ref: "foo.json"}, + }, }, "http://example.com/other.json": { - "$id": "http://example.com/other.json" - } - }; - - beforeEach(function() { - loadCallCount = 0; - ajv = new Ajv({ loadSchema: loadSchema }); - }); + $id: "http://example.com/other.json", + }, + } + beforeEach(function () { + loadCallCount = 0 + ajv = new Ajv({loadSchema: loadSchema}) + }) - it('should compile schemas loading missing schemas with options.loadSchema function', function() { + it("should compile schemas loading missing schemas with options.loadSchema function", function () { var schema = { - "$id": "http://example.com/parent.json", - "properties": { - "a": { "$ref": "object.json" } - } - }; + $id: "http://example.com/parent.json", + properties: { + a: {$ref: "object.json"}, + }, + } return ajv.compileAsync(schema).then(function (validate) { - should.equal(loadCallCount, 2); - validate .should.be.a('function'); - validate({ a: { b: 2 } }) .should.equal(true); - validate({ a: { b: 1 } }) .should.equal(false); - }); - }); - - - it('should compile schemas loading missing schemas and return function via callback', function (done) { + should.equal(loadCallCount, 2) + validate.should.be.a("function") + validate({a: {b: 2}}).should.equal(true) + validate({a: {b: 1}}).should.equal(false) + }) + }) + + it("should compile schemas loading missing schemas and return function via callback", function (done) { var schema = { - "$id": "http://example.com/parent.json", - "properties": { - "a": { "$ref": "object.json" } - } - }; + $id: "http://example.com/parent.json", + properties: { + a: {$ref: "object.json"}, + }, + } ajv.compileAsync(schema, function (err, validate) { - should.equal(loadCallCount, 2); - should.not.exist(err); - validate .should.be.a('function'); - validate({ a: { b: 2 } }) .should.equal(true); - validate({ a: { b: 1 } }) .should.equal(false); - done(); - }); - }); - - - it('should correctly load schemas when missing reference has JSON path', function() { + should.equal(loadCallCount, 2) + should.not.exist(err) + validate.should.be.a("function") + validate({a: {b: 2}}).should.equal(true) + validate({a: {b: 1}}).should.equal(false) + done() + }) + }) + + it("should correctly load schemas when missing reference has JSON path", function () { var schema = { - "$id": "http://example.com/parent.json", - "properties": { - "a": { "$ref": "object.json#/properties/b" } - } - }; + $id: "http://example.com/parent.json", + properties: { + a: {$ref: "object.json#/properties/b"}, + }, + } return ajv.compileAsync(schema).then(function (validate) { - should.equal(loadCallCount, 2); - validate .should.be.a('function'); - validate({ a: 2 }) .should.equal(true); - validate({ a: 1 }) .should.equal(false); - }); - }); - - - it('should correctly compile with remote schemas that have mutual references', function() { + should.equal(loadCallCount, 2) + validate.should.be.a("function") + validate({a: 2}).should.equal(true) + validate({a: 1}).should.equal(false) + }) + }) + + it("should correctly compile with remote schemas that have mutual references", function () { var schema = { - "$id": "http://example.com/root.json", - "properties": { - "tree": { "$ref": "tree.json" } - } - }; + $id: "http://example.com/root.json", + properties: { + tree: {$ref: "tree.json"}, + }, + } return ajv.compileAsync(schema).then(function (validate) { - validate .should.be.a('function'); - var validData = { tree: [ - { name: 'a', subtree: [ { name: 'a.a' } ] }, - { name: 'b' } - ] }; - var invalidData = { tree: [ - { name: 'a', subtree: [ { name: 1 } ] } - ] }; - validate(validData) .should.equal(true); - validate(invalidData) .should.equal(false); - }); - }); - - - it('should correctly compile with remote schemas that reference the compiled schema', function() { - var schema = { - "$id": "http://example.com/parent.json", - "properties": { - "a": { "$ref": "recursive.json" } + validate.should.be.a("function") + var validData = { + tree: [{name: "a", subtree: [{name: "a.a"}]}, {name: "b"}], } - }; - return ajv.compileAsync(schema).then(function (validate) { - should.equal(loadCallCount, 1); - validate .should.be.a('function'); - var validData = { a: { b: { a: { b: {} } } } }; - var invalidData = { a: { b: { a: {} } } }; - validate(validData) .should.equal(true); - validate(invalidData) .should.equal(false); - }); - }); - + var invalidData = {tree: [{name: "a", subtree: [{name: 1}]}]} + validate(validData).should.equal(true) + validate(invalidData).should.equal(false) + }) + }) - it('should resolve reference containing "properties" segment with the same property (issue #220)', function() { + it("should correctly compile with remote schemas that reference the compiled schema", function () { var schema = { - "$id": "http://example.com/parent.json", - "properties": { - "a": { - "$ref": "object.json#/properties/a" - } - } - }; + $id: "http://example.com/parent.json", + properties: { + a: {$ref: "recursive.json"}, + }, + } return ajv.compileAsync(schema).then(function (validate) { - should.equal(loadCallCount, 2); - validate .should.be.a('function'); - validate({ a: 'foo' }) .should.equal(true); - validate({ a: 42 }) .should.equal(false); - }); - }); - - - describe('loading metaschemas (#334)', function() { - it('should load metaschema if not available', function() { - return test(SCHEMAS['http://example.com/foobar.json'], 1); - }); - - it('should load metaschema of referenced schema if not available', function() { - return test({ "$ref": "http://example.com/foobar.json" }, 2); - }); + should.equal(loadCallCount, 1) + validate.should.be.a("function") + var validData = {a: {b: {a: {b: {}}}}} + var invalidData = {a: {b: {a: {}}}} + validate(validData).should.equal(true) + validate(invalidData).should.equal(false) + }) + }) + + it('should resolve reference containing "properties" segment with the same property (issue #220)', function () { + var schema = { + $id: "http://example.com/parent.json", + properties: { + a: { + $ref: "object.json#/properties/a", + }, + }, + } + return ajv.compileAsync(schema).then(function (validate) { + should.equal(loadCallCount, 2) + validate.should.be.a("function") + validate({a: "foo"}).should.equal(true) + validate({a: 42}).should.equal(false) + }) + }) + + describe("loading metaschemas (#334)", function () { + it("should load metaschema if not available", function () { + return test(SCHEMAS["http://example.com/foobar.json"], 1) + }) + + it("should load metaschema of referenced schema if not available", function () { + return test({$ref: "http://example.com/foobar.json"}, 2) + }) function test(schema, expectedLoadCallCount) { - ajv.addKeyword('myFooBar', { - type: 'string', + ajv.addKeyword("myFooBar", { + type: "string", validate: function (sch, data) { - return sch == data; - } - }); + return sch == data + }, + }) return ajv.compileAsync(schema).then(function (validate) { - should.equal(loadCallCount, expectedLoadCallCount); - validate .should.be.a('function'); - validate('foo') .should.equal(true); - validate('bar') .should.equal(false); - }); + should.equal(loadCallCount, expectedLoadCallCount) + validate.should.be.a("function") + validate("foo").should.equal(true) + validate("bar").should.equal(false) + }) } - }); + }) - - it('should return compiled schema on the next tick if there are no references (#51)', 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", - "type": "integer", - "minimum": 2 - }; - var beforeCallback1; + $id: "http://example.com/int2plus.json", + type: "integer", + minimum: 2, + } + var beforeCallback1 var p1 = ajv.compileAsync(schema).then(function (validate) { - beforeCallback1 .should.equal(true); - spec(validate); - var beforeCallback2; + beforeCallback1.should.equal(true) + spec(validate) + var beforeCallback2 var p2 = ajv.compileAsync(schema).then(function (_validate) { - beforeCallback2 .should.equal(true); - spec(_validate); - }); - beforeCallback2 = true; - return p2; - }); - beforeCallback1 = true; - return p1; + beforeCallback2.should.equal(true) + spec(_validate) + }) + beforeCallback2 = true + return p2 + }) + beforeCallback1 = true + return p1 function spec(validate) { - should.equal(loadCallCount, 0); - validate .should.be.a('function'); - var validData = 2; - var invalidData = 1; - validate(validData) .should.equal(true); - validate(invalidData) .should.equal(false); + should.equal(loadCallCount, 0) + validate.should.be.a("function") + var validData = 2 + var invalidData = 1 + validate(validData).should.equal(true) + validate(invalidData).should.equal(false) } - }); - + }) - it('should queue calls so only one compileAsync executes at a time (#52)', function() { + it("should queue calls so only one compileAsync executes at a time (#52)", function () { var schema = { - "$id": "http://example.com/parent.json", - "properties": { - "a": { "$ref": "object.json" } - } - }; + $id: "http://example.com/parent.json", + properties: { + a: {$ref: "object.json"}, + }, + } return Promise.all([ ajv.compileAsync(schema).then(spec), ajv.compileAsync(schema).then(spec), - ajv.compileAsync(schema).then(spec) - ]); + ajv.compileAsync(schema).then(spec), + ]) function spec(validate) { - should.equal(loadCallCount, 2); - validate .should.be.a('function'); - validate({ a: { b: 2 } }) .should.equal(true); - validate({ a: { b: 1 } }) .should.equal(false); + should.equal(loadCallCount, 2) + validate.should.be.a("function") + validate({a: {b: 2}}).should.equal(true) + validate({a: {b: 1}}).should.equal(false) } - }); - + }) - it('should throw exception if loadSchema is not passed', function (done) { + it("should throw exception if loadSchema is not passed", function (done) { var schema = { - "$id": "http://example.com/int2plus.json", - "type": "integer", - "minimum": 2 - }; - ajv = new Ajv; - should.throw(function() { - ajv.compileAsync(schema, function() { - done(new Error('it should have thrown exception')); - }); - }); - setTimeout(function() { + $id: "http://example.com/int2plus.json", + type: "integer", + minimum: 2, + } + ajv = new Ajv() + should.throw(function () { + ajv.compileAsync(schema, function () { + done(new Error("it should have thrown exception")) + }) + }) + setTimeout(function () { // function is needed for the test to pass in Firefox 4 - done(); - }); - }); + done() + }) + }) - - describe('should return error via callback', function() { - it('if passed schema is invalid', function (done) { + describe("should return error via callback", function () { + it("if passed schema is invalid", function (done) { var invalidSchema = { - "$id": "http://example.com/int2plus.json", - "type": "integer", - "minimum": "invalid" - }; - ajv.compileAsync(invalidSchema, shouldFail(done)); - }); - - it('if loaded schema is invalid', function (done) { + $id: "http://example.com/int2plus.json", + type: "integer", + minimum: "invalid", + } + ajv.compileAsync(invalidSchema, shouldFail(done)) + }) + + it("if loaded schema is invalid", function (done) { var schema = { - "$id": "http://example.com/parent.json", - "properties": { - "a": { "$ref": "invalid.json" } - } - }; - ajv.compileAsync(schema, shouldFail(done)); - }); + $id: "http://example.com/parent.json", + properties: { + a: {$ref: "invalid.json"}, + }, + } + ajv.compileAsync(schema, shouldFail(done)) + }) - it('if required schema is loaded but the reference cannot be resolved', function (done) { + it("if required schema is loaded but the reference cannot be resolved", function (done) { var schema = { - "$id": "http://example.com/parent.json", - "properties": { - "a": { "$ref": "object.json#/definitions/not_found" } - } - }; - ajv.compileAsync(schema, shouldFail(done)); - }); + $id: "http://example.com/parent.json", + properties: { + a: {$ref: "object.json#/definitions/not_found"}, + }, + } + ajv.compileAsync(schema, shouldFail(done)) + }) - it('if loadSchema returned error', function (done) { + it("if loadSchema returned error", function (done) { var schema = { - "$id": "http://example.com/parent.json", - "properties": { - "a": { "$ref": "object.json" } - } - }; - ajv = new Ajv({ loadSchema: badLoadSchema }); - ajv.compileAsync(schema, shouldFail(done)); + $id: "http://example.com/parent.json", + properties: { + a: {$ref: "object.json"}, + }, + } + ajv = new Ajv({loadSchema: badLoadSchema}) + ajv.compileAsync(schema, shouldFail(done)) function badLoadSchema() { - return Promise.reject(new Error('cant load')); + return Promise.reject(new Error("cant load")) } - }); + }) - it('if schema compilation throws some other exception', function (done) { - ajv.addKeyword('badkeyword', { compile: badCompile }); - var schema = { badkeyword: true }; - ajv.compileAsync(schema, shouldFail(done)); + it("if schema compilation throws some other exception", function (done) { + ajv.addKeyword("badkeyword", {compile: badCompile}) + var schema = {badkeyword: true} + ajv.compileAsync(schema, shouldFail(done)) function badCompile(/* schema */) { - throw new Error('cant compile keyword schema'); + throw new Error("cant compile keyword schema") } - }); + }) function shouldFail(done) { return function (err, validate) { - should.exist(err); - should.not.exist(validate); - done(); - }; + should.exist(err) + should.not.exist(validate) + done() + } } - }); - + }) - describe('should return error via promise', function() { - it('if passed schema is invalid', function() { + describe("should return error via promise", function () { + it("if passed schema is invalid", function () { var invalidSchema = { - "$id": "http://example.com/int2plus.json", - "type": "integer", - "minimum": "invalid" - }; - return shouldReject(ajv.compileAsync(invalidSchema)); - }); - - it('if loaded schema is invalid', function() { + $id: "http://example.com/int2plus.json", + type: "integer", + minimum: "invalid", + } + return shouldReject(ajv.compileAsync(invalidSchema)) + }) + + it("if loaded schema is invalid", function () { var schema = { - "$id": "http://example.com/parent.json", - "properties": { - "a": { "$ref": "invalid.json" } - } - }; - return shouldReject(ajv.compileAsync(schema)); - }); + $id: "http://example.com/parent.json", + properties: { + a: {$ref: "invalid.json"}, + }, + } + return shouldReject(ajv.compileAsync(schema)) + }) - it('if required schema is loaded but the reference cannot be resolved', function() { + it("if required schema is loaded but the reference cannot be resolved", function () { var schema = { - "$id": "http://example.com/parent.json", - "properties": { - "a": { "$ref": "object.json#/definitions/not_found" } - } - }; - return shouldReject(ajv.compileAsync(schema)); - }); + $id: "http://example.com/parent.json", + properties: { + a: {$ref: "object.json#/definitions/not_found"}, + }, + } + return shouldReject(ajv.compileAsync(schema)) + }) - it('if loadSchema returned error', function() { + it("if loadSchema returned error", function () { var schema = { - "$id": "http://example.com/parent.json", - "properties": { - "a": { "$ref": "object.json" } - } - }; - ajv = new Ajv({ loadSchema: badLoadSchema }); - return shouldReject(ajv.compileAsync(schema)); + $id: "http://example.com/parent.json", + properties: { + a: {$ref: "object.json"}, + }, + } + ajv = new Ajv({loadSchema: badLoadSchema}) + return shouldReject(ajv.compileAsync(schema)) function badLoadSchema() { - return Promise.reject(new Error('cant load')); + return Promise.reject(new Error("cant load")) } - }); + }) - it('if schema compilation throws some other exception', function() { - ajv.addKeyword('badkeyword', { compile: badCompile }); - var schema = { badkeyword: true }; - return shouldReject(ajv.compileAsync(schema)); + it("if schema compilation throws some other exception", function () { + ajv.addKeyword("badkeyword", {compile: badCompile}) + var schema = {badkeyword: true} + return shouldReject(ajv.compileAsync(schema)) function badCompile(/* schema */) { - throw new Error('cant compile keyword schema'); + throw new Error("cant compile keyword schema") } - }); + }) function shouldReject(p) { return p.then( - function(validate) { - should.not.exist(validate); - throw new Error('Promise has resolved; it should have rejected'); + function (validate) { + should.not.exist(validate) + throw new Error("Promise has resolved; it should have rejected") }, - function(err) { - should.exist(err); + function (err) { + should.exist(err) } - ); + ) } - }); + }) - - describe('schema with multiple remote properties, the first is recursive schema (#801)', function() { - it('should validate data', function() { + describe("schema with multiple remote properties, the first is recursive schema (#801)", function () { + it("should validate data", function () { var schema = { - "$id": "http://example.com/list.json", - "type": "object", - "properties": { - "foo": {"$ref": "foo.json"} - } - }; + $id: "http://example.com/list.json", + type: "object", + properties: { + foo: {$ref: "foo.json"}, + }, + } return ajv.compileAsync(schema).then(function (validate) { - validate({foo: {}}) .should.equal(true); - }); - }); - }); - + validate({foo: {}}).should.equal(true) + }) + }) + }) function loadSchema(uri) { - loadCallCount++; + loadCallCount++ return new Promise(function (resolve, reject) { - setTimeout(function() { - if (SCHEMAS[uri]) resolve(SCHEMAS[uri]); - else reject(new Error('404')); - }, 10); - }); + setTimeout(function () { + if (SCHEMAS[uri]) resolve(SCHEMAS[uri]) + else reject(new Error("404")) + }, 10) + }) } -}); +}) diff --git a/spec/async/boolean.json b/spec/async/boolean.json index 59284c556f..db2226fb6c 100644 --- a/spec/async/boolean.json +++ b/spec/async/boolean.json @@ -10,7 +10,7 @@ "tests": [ { "description": "any data is valid", - "data": { "foo": 1 }, + "data": {"foo": 1}, "valid": true } ] @@ -26,12 +26,12 @@ "tests": [ { "description": "any property is invalid", - "data": { "foo": 1 }, + "data": {"foo": 1}, "valid": false }, { "description": "without property is valid", - "data": { "bar": 1 }, + "data": {"bar": 1}, "valid": true }, { @@ -80,7 +80,7 @@ "schema": { "$async": true, "properties": { - "foo": { "$ref": "#/definitions/foo" } + "foo": {"$ref": "#/definitions/foo"} }, "definitions": { "foo": true @@ -89,7 +89,7 @@ "tests": [ { "description": "any data is valid", - "data": { "foo": 1 }, + "data": {"foo": 1}, "valid": true } ] @@ -99,7 +99,7 @@ "schema": { "$async": true, "properties": { - "foo": { "$ref": "#/definitions/foo" } + "foo": {"$ref": "#/definitions/foo"} }, "definitions": { "foo": false @@ -108,12 +108,12 @@ "tests": [ { "description": "any property is invalid", - "data": { "foo": 1 }, + "data": {"foo": 1}, "valid": false }, { "description": "without property is valid", - "data": { "bar": 1 }, + "data": {"bar": 1}, "valid": true }, { diff --git a/spec/async/compound.json b/spec/async/compound.json index 9b9ed40bfd..23c78aee10 100644 --- a/spec/async/compound.json +++ b/spec/async/compound.json @@ -5,7 +5,7 @@ "$async": true, "allOf": [ { - "idExists": { "table": "users" } + "idExists": {"table": "users"} }, { "type": "integer", @@ -42,7 +42,7 @@ "$async": true, "anyOf": [ { - "idExists": { "table": "users" } + "idExists": {"table": "users"} }, { "type": "integer", @@ -79,7 +79,7 @@ "$async": true, "oneOf": [ { - "idExists": { "table": "users" } + "idExists": {"table": "users"} }, { "type": "integer", @@ -115,7 +115,7 @@ "schema": { "$async": true, "not": { - "idExists": { "table": "users" } + "idExists": {"table": "users"} } }, "tests": [ diff --git a/spec/async/format.json b/spec/async/format.json index d8a0cbb467..438bd05994 100644 --- a/spec/async/format.json +++ b/spec/async/format.json @@ -35,43 +35,43 @@ "$async": true, "additionalProperties": { "type": "string", - "format": { "$data": "0#" } + "format": {"$data": "0#"} } }, "tests": [ { "description": "'tomorrow' is a valid english word", - "data": { "english_word": "tomorrow" }, + "data": {"english_word": "tomorrow"}, "valid": true }, { "description": "'manana' is an invalid english word", - "data": { "english_word": "manana" }, + "data": {"english_word": "manana"}, "valid": false }, { "description": "number is invalid", - "data": { "english_word": 1 }, + "data": {"english_word": 1}, "valid": false }, { "description": "'today' throws an exception, not in the dictionary", - "data": { "english_word": "today" }, + "data": {"english_word": "today"}, "error": "unknown word" }, { "description": "valid date", - "data": { "date": "2016-01-25" }, + "data": {"date": "2016-01-25"}, "valid": true }, { "description": "invalid date", - "data": { "date": "01/25/2016" }, + "data": {"date": "01/25/2016"}, "valid": false }, { "description": "number is invalid", - "data": { "date": 1 }, + "data": {"date": 1}, "valid": false } ] diff --git a/spec/async/items.json b/spec/async/items.json index 067c7094f6..9885610237 100644 --- a/spec/async/items.json +++ b/spec/async/items.json @@ -6,41 +6,41 @@ "items": [ { "type": "integer", - "idExists": { "table": "users" } + "idExists": {"table": "users"} }, { "type": "integer" }, { "type": "integer", - "idExists": { "table": "users" } + "idExists": {"table": "users"} } ] }, "tests": [ { "description": "valid array", - "data": [ 1, 2, 5 ], + "data": [1, 2, 5], "valid": true }, { "description": "another valid array", - "data": [ 5, 2, 8 ], + "data": [5, 2, 8], "valid": true }, { "description": "invalid 1st async item", - "data": [ 9, 2, 8 ], + "data": [9, 2, 8], "valid": false }, { "description": "invalid 2nd async item", - "data": [ 1, 2, 9 ], + "data": [1, 2, 9], "valid": false }, { "description": "invalid sync item", - "data": [ 1, "abc", 5 ], + "data": [1, "abc", 5], "valid": false } ] diff --git a/spec/async/keyword.json b/spec/async/keyword.json index 34e10f3c0c..1b34fa00b7 100644 --- a/spec/async/keyword.json +++ b/spec/async/keyword.json @@ -6,43 +6,43 @@ "properties": { "userId": { "type": "integer", - "idExists": { "table": "users" } + "idExists": {"table": "users"} }, "postId": { "type": "integer", - "idExists": { "table": "posts" } + "idExists": {"table": "posts"} }, "categoryId": { "description": "will throw if present, no such table", "type": "integer", - "idExists": { "table": "categories" } + "idExists": {"table": "categories"} } } }, "tests": [ { "description": "valid object", - "data": { "userId": 1, "postId": 21 }, + "data": {"userId": 1, "postId": 21}, "valid": true }, { "description": "another valid object", - "data": { "userId": 5, "postId": 25 }, + "data": {"userId": 5, "postId": 25}, "valid": true }, { "description": "invalid - no such post", - "data": { "userId": 5, "postId": 10 }, + "data": {"userId": 5, "postId": 10}, "valid": false }, { "description": "invalid - no such user", - "data": { "userId": 9, "postId": 25 }, + "data": {"userId": 9, "postId": 25}, "valid": false }, { "description": "should throw exception during validation - no such table", - "data": { "postId": 25, "categoryId": 1 }, + "data": {"postId": 25, "categoryId": 1}, "error": "no such table" } ] @@ -54,43 +54,43 @@ "properties": { "userId": { "type": "integer", - "idExistsWithError": { "table": "users" } + "idExistsWithError": {"table": "users"} }, "postId": { "type": "integer", - "idExistsWithError": { "table": "posts" } + "idExistsWithError": {"table": "posts"} }, "categoryId": { "description": "will throw if present, no such table", "type": "integer", - "idExistsWithError": { "table": "categories" } + "idExistsWithError": {"table": "categories"} } } }, "tests": [ { "description": "valid object", - "data": { "userId": 1, "postId": 21 }, + "data": {"userId": 1, "postId": 21}, "valid": true }, { "description": "another valid object", - "data": { "userId": 5, "postId": 25 }, + "data": {"userId": 5, "postId": 25}, "valid": true }, { "description": "invalid - no such post", - "data": { "userId": 5, "postId": 10 }, + "data": {"userId": 5, "postId": 10}, "valid": false }, { "description": "invalid - no such user", - "data": { "userId": 9, "postId": 25 }, + "data": {"userId": 9, "postId": 25}, "valid": false }, { "description": "should throw exception during validation - no such table", - "data": { "postId": 25, "categoryId": 1 }, + "data": {"postId": 25, "categoryId": 1}, "error": "no such table" } ] @@ -102,33 +102,33 @@ "properties": { "userId": { "type": "integer", - "idExistsCompiled": { "table": "users" } + "idExistsCompiled": {"table": "users"} }, "postId": { "type": "integer", - "idExistsCompiled": { "table": "posts" } + "idExistsCompiled": {"table": "posts"} } } }, "tests": [ { "description": "valid object", - "data": { "userId": 1, "postId": 21 }, + "data": {"userId": 1, "postId": 21}, "valid": true }, { "description": "another valid object", - "data": { "userId": 5, "postId": 25 }, + "data": {"userId": 5, "postId": 25}, "valid": true }, { "description": "invalid - no such post", - "data": { "userId": 5, "postId": 10 }, + "data": {"userId": 5, "postId": 10}, "valid": false }, { "description": "invalid - no such user", - "data": { "userId": 9, "postId": 25 }, + "data": {"userId": 9, "postId": 25}, "valid": false } ] diff --git a/spec/async/properties.json b/spec/async/properties.json index a695062753..e905228f32 100644 --- a/spec/async/properties.json +++ b/spec/async/properties.json @@ -6,7 +6,7 @@ "properties": { "foo": { "type": "integer", - "idExists": { "table": "users" } + "idExists": {"table": "users"} }, "bar": { "type": "integer" @@ -16,22 +16,22 @@ "tests": [ { "description": "valid object", - "data": { "foo": 1, "bar": 2 }, + "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "another valid object", - "data": { "foo": 5, "bar": 2 }, + "data": {"foo": 5, "bar": 2}, "valid": true }, { "description": "invalid sync property", - "data": { "foo": 1, "bar": "abc" }, + "data": {"foo": 1, "bar": "abc"}, "valid": false }, { "description": "invalid async property", - "data": { "foo": 9, "bar": 2 }, + "data": {"foo": 9, "bar": 2}, "valid": false } ] diff --git a/spec/async_schemas.spec.js b/spec/async_schemas.spec.js index cca8202ac5..aab643bb63 100644 --- a/spec/async_schemas.spec.js +++ b/spec/async_schemas.spec.js @@ -1,118 +1,125 @@ -'use strict'; +"use strict" -var jsonSchemaTest = require('json-schema-test') - , Promise = require('./promise') - , getAjvInstances = require('./ajv_async_instances') - , Ajv = require('./ajv') - , suite = require('./browser_test_suite') - , after = require('./after_test'); +var jsonSchemaTest = require("json-schema-test"), + Promise = require("./promise"), + getAjvInstances = require("./ajv_async_instances"), + Ajv = require("./ajv"), + suite = require("./browser_test_suite"), + after = require("./after_test") +var instances = getAjvInstances({$data: true}) -var instances = getAjvInstances({ $data: true }); - - -instances.forEach(addAsyncFormatsAndKeywords); - +instances.forEach(addAsyncFormatsAndKeywords) jsonSchemaTest(instances, { - description: 'asynchronous schemas tests of ' + instances.length + ' ajv instances with different options', + description: + "asynchronous schemas tests of " + + instances.length + + " ajv instances with different options", suites: { - 'async schemas': - typeof window == 'object' - ? suite(require('./async/{**/,}*.json', {mode: 'list'})) - : './async/{**/,}*.json' + "async schemas": + typeof window == "object" + ? suite(require("./async/{**/,}*.json", {mode: "list"})) + : "./async/{**/,}*.json", }, async: true, - asyncValid: 'data', - assert: require('./chai').assert, + asyncValid: "data", + assert: require("./chai").assert, Promise: Promise, afterError: after.error, // afterEach: after.each, cwd: __dirname, - hideFolder: 'async/', - timeout: 90000 -}); + hideFolder: "async/", + timeout: 90000, +}) +function addAsyncFormatsAndKeywords(ajv) { + ajv.addFormat("date", /^\d\d\d\d-[0-1]\d-[0-3]\d$/) -function addAsyncFormatsAndKeywords (ajv) { - ajv.addFormat('english_word', { + ajv.addFormat("english_word", { async: true, - validate: checkWordOnServer - }); + validate: checkWordOnServer, + }) - ajv.addKeyword('idExists', { + ajv.addKeyword("idExists", { async: true, - type: 'number', + type: "number", validate: checkIdExists, - errors: false - }); + errors: false, + }) - ajv.addKeyword('idExistsWithError', { + ajv.addKeyword("idExistsWithError", { async: true, - type: 'number', + type: "number", validate: checkIdExistsWithError, - errors: true - }); + errors: true, + }) - ajv.addKeyword('idExistsCompiled', { + ajv.addKeyword("idExistsCompiled", { async: true, - type: 'number', - compile: compileCheckIdExists - }); + type: "number", + compile: compileCheckIdExists, + }) } - function checkWordOnServer(str) { - return str == 'tomorrow' ? Promise.resolve(true) - : str == 'manana' ? Promise.resolve(false) - : Promise.reject(new Error('unknown word')); + return str == "tomorrow" + ? Promise.resolve(true) + : str == "manana" + ? Promise.resolve(false) + : Promise.reject(new Error("unknown word")) } - function checkIdExists(schema, data) { switch (schema.table) { - case 'users': return check([1, 5, 8]); - case 'posts': return check([21, 25, 28]); - default: throw new Error('no such table'); + case "users": + return check([1, 5, 8]) + case "posts": + return check([21, 25, 28]) + default: + throw new Error("no such table") } function check(IDs) { - return Promise.resolve(IDs.indexOf(data) >= 0); + return Promise.resolve(IDs.indexOf(data) >= 0) } } - function checkIdExistsWithError(schema, data) { - var table = schema.table; + var table = schema.table switch (table) { - case 'users': return check(table, [1, 5, 8]); - case 'posts': return check(table, [21, 25, 28]); - default: throw new Error('no such table'); + case "users": + return check(table, [1, 5, 8]) + case "posts": + return check(table, [21, 25, 28]) + default: + throw new Error("no such table") } function check(_table, IDs) { - if (IDs.indexOf(data) >= 0) - return Promise.resolve(true); + if (IDs.indexOf(data) >= 0) return Promise.resolve(true) var error = { - keyword: 'idExistsWithError', - message: 'id not found in table ' + _table - }; - return Promise.reject(new Ajv.ValidationError([error])); + keyword: "idExistsWithError", + message: "id not found in table " + _table, + } + return Promise.reject(new Ajv.ValidationError([error])) } } - function compileCheckIdExists(schema) { switch (schema.table) { - case 'users': return compileCheck([1, 5, 8]); - case 'posts': return compileCheck([21, 25, 28]); - default: throw new Error('no such table'); + case "users": + return compileCheck([1, 5, 8]) + case "posts": + return compileCheck([21, 25, 28]) + default: + throw new Error("no such table") } function compileCheck(IDs) { return function (data) { - return Promise.resolve(IDs.indexOf(data) >= 0); - }; + return Promise.resolve(IDs.indexOf(data) >= 0) + } } } diff --git a/spec/async_validate.spec.js b/spec/async_validate.spec.js index 04d47cecef..0e9724a49b 100644 --- a/spec/async_validate.spec.js +++ b/spec/async_validate.spec.js @@ -1,271 +1,277 @@ -'use strict'; +"use strict" -var Ajv = require('./ajv') - , Promise = require('./promise') - , getAjvInstances = require('./ajv_async_instances') - , should = require('./chai').should(); +var Ajv = require("./ajv"), + Promise = require("./promise"), + getAjvInstances = require("./ajv_async_instances"), + should = require("./chai").should() - -describe('async schemas, formats and keywords', function() { - this.timeout(30000); - var ajv, instances; +describe("async schemas, formats and keywords", function () { + this.timeout(30000) + var ajv, instances beforeEach(function () { - instances = getAjvInstances(); - ajv = instances[0]; - }); - + instances = getAjvInstances() + ajv = instances[0] + }) - describe('async schemas without async elements', function() { - it('should return result as promise', function() { + describe("async schemas without async elements", function () { + it("should return result as promise", function () { var schema = { $async: true, - type: 'string', - maxLength: 3 - }; + type: "string", + maxLength: 3, + } - return repeat(function() { return Promise.all(instances.map(test)); }); + return repeat(function () { + return Promise.all(instances.map(test)) + }) function test(_ajv) { - var validate = _ajv.compile(schema); + var validate = _ajv.compile(schema) return Promise.all([ - shouldBeValid( validate('abc'), 'abc' ), - shouldBeInvalid( validate('abcd') ), - shouldBeInvalid( validate(1) ), - ]); + shouldBeValid(validate("abc"), "abc"), + shouldBeInvalid(validate("abcd")), + shouldBeInvalid(validate(1)), + ]) } - }); + }) - it('should fail compilation if async schema is inside sync schema', function() { + it("should fail compilation if async schema is inside sync schema", function () { var schema = { properties: { foo: { $async: true, - type: 'string', - maxLength: 3 - } - } - }; - - shouldThrowFunc('async schema in sync schema', function() { - ajv.compile(schema); - }); - - schema.$async = true; + type: "string", + maxLength: 3, + }, + }, + } - ajv.compile(schema); - }); - }); + shouldThrowFunc("async schema in sync schema", function () { + ajv.compile(schema) + }) + schema.$async = true - describe('async formats', function() { - beforeEach(addFormatEnglishWord); + ajv.compile(schema) + }) + }) + describe("async formats", function () { + beforeEach(addFormatEnglishWord) - it('should fail compilation if async format is inside sync schema', function() { + it("should fail compilation if async format is inside sync schema", function () { instances.forEach(function (_ajv) { var schema = { - type: 'string', - format: 'english_word' - }; - - shouldThrowFunc('async format in sync schema', function() { - _ajv.compile(schema); - }); - schema.$async = true; - _ajv.compile(schema); - }); - }); - }); - - - describe('async custom keywords', function() { - beforeEach(function() { + type: "string", + format: "english_word", + } + + shouldThrowFunc("async format in sync schema", function () { + _ajv.compile(schema) + }) + schema.$async = true + _ajv.compile(schema) + }) + }) + }) + + describe("async custom keywords", function () { + beforeEach(function () { instances.forEach(function (_ajv) { - _ajv.addKeyword('idExists', { + _ajv.addKeyword("idExists", { async: true, - type: 'number', + type: "number", validate: checkIdExists, - errors: false - }); + errors: false, + }) - _ajv.addKeyword('idExistsWithError', { + _ajv.addKeyword("idExistsWithError", { async: true, - type: 'number', + type: "number", validate: checkIdExistsWithError, - errors: true - }); - }); - }); - + errors: true, + }) + }) + }) - it('should fail compilation if async keyword is inside sync schema', function() { + it("should fail compilation if async keyword is inside sync schema", function () { instances.forEach(function (_ajv) { var schema = { - type: 'object', + type: "object", properties: { userId: { - type: 'integer', - idExists: { table: 'users' } - } - } - }; - - shouldThrowFunc('async keyword in sync schema', function() { - _ajv.compile(schema); - }); + type: "integer", + idExists: {table: "users"}, + }, + }, + } - schema.$async = true; - _ajv.compile(schema); - }); - }); + shouldThrowFunc("async keyword in sync schema", function () { + _ajv.compile(schema) + }) + schema.$async = true + _ajv.compile(schema) + }) + }) - it('should return custom error', function() { - return Promise.all(instances.map(function (_ajv) { - var schema = { - $async: true, - type: 'object', - properties: { - userId: { - type: 'integer', - idExistsWithError: { table: 'users' } + it("should return custom error", function () { + return Promise.all( + instances.map(function (_ajv) { + var schema = { + $async: true, + type: "object", + properties: { + userId: { + type: "integer", + idExistsWithError: {table: "users"}, + }, + postId: { + type: "integer", + idExistsWithError: {table: "posts"}, + }, }, - postId: { - type: 'integer', - idExistsWithError: { table: 'posts' } - } } - }; - var validate = _ajv.compile(schema); - - return Promise.all([ - shouldBeInvalid( validate({ userId: 5, postId: 10 }), [ 'id not found in table posts' ] ), - shouldBeInvalid( validate({ userId: 9, postId: 25 }), [ 'id not found in table users' ] ) - ]); - })); - }); + var validate = _ajv.compile(schema) + return Promise.all([ + shouldBeInvalid(validate({userId: 5, postId: 10}), [ + "id not found in table posts", + ]), + shouldBeInvalid(validate({userId: 9, postId: 25}), [ + "id not found in table users", + ]), + ]) + }) + ) + }) function checkIdExists(schema, data) { switch (schema.table) { - case 'users': return check([1, 5, 8]); - case 'posts': return check([21, 25, 28]); - default: throw new Error('no such table'); + case "users": + return check([1, 5, 8]) + case "posts": + return check([21, 25, 28]) + default: + throw new Error("no such table") } function check(IDs) { - return Promise.resolve(IDs.indexOf(data) >= 0); + return Promise.resolve(IDs.indexOf(data) >= 0) } } function checkIdExistsWithError(schema, data) { - var table = schema.table; + var table = schema.table switch (table) { - case 'users': return check(table, [1, 5, 8]); - case 'posts': return check(table, [21, 25, 28]); - default: throw new Error('no such table'); + case "users": + return check(table, [1, 5, 8]) + case "posts": + return check(table, [21, 25, 28]) + default: + throw new Error("no such table") } function check(_table, IDs) { - if (IDs.indexOf(data) >= 0) return Promise.resolve(true); + if (IDs.indexOf(data) >= 0) return Promise.resolve(true) var error = { - keyword: 'idExistsWithError', - message: 'id not found in table ' + _table - }; - return Promise.reject(new Ajv.ValidationError([error])); + keyword: "idExistsWithError", + message: "id not found in table " + _table, + } + return Promise.reject(new Ajv.ValidationError([error])) } } - }); - + }) - describe('async referenced schemas', function() { - beforeEach(function() { - instances = getAjvInstances({ inlineRefs: false, extendRefs: 'ignore' }); - addFormatEnglishWord(); - }); + describe("async referenced schemas", function () { + beforeEach(function () { + instances = getAjvInstances({inlineRefs: false, extendRefs: "ignore"}) + addFormatEnglishWord() + }) - it('should validate referenced async schema', function() { + it("should validate referenced async schema", function () { var schema = { $async: true, definitions: { english_word: { $async: true, - type: 'string', - format: 'english_word' - } + type: "string", + format: "english_word", + }, }, properties: { - word: { $ref: '#/definitions/english_word' } - } - }; - - return repeat(function() { return Promise.all(instances.map(function (_ajv) { - var validate = _ajv.compile(schema); - var validData = { word: 'tomorrow' }; + word: {$ref: "#/definitions/english_word"}, + }, + } - return Promise.all([ - shouldBeValid( validate(validData), validData ), - shouldBeInvalid( validate({ word: 'manana' }) ), - shouldBeInvalid( validate({ word: 1 }) ), - shouldThrow( validate({ word: 'today' }), 'unknown word' ) - ]); - })); }); - }); - - it('should validate recursive async schema', function() { + return repeat(function () { + return Promise.all( + instances.map(function (_ajv) { + var validate = _ajv.compile(schema) + var validData = {word: "tomorrow"} + + return Promise.all([ + shouldBeValid(validate(validData), validData), + shouldBeInvalid(validate({word: "manana"})), + shouldBeInvalid(validate({word: 1})), + shouldThrow(validate({word: "today"}), "unknown word"), + ]) + }) + ) + }) + }) + + it("should validate recursive async schema", function () { var schema = { $async: true, definitions: { english_word: { $async: true, - type: 'string', - format: 'english_word' - } + type: "string", + format: "english_word", + }, }, - type: 'object', + type: "object", properties: { foo: { - anyOf: [ - { $ref: '#/definitions/english_word' }, - { $ref: '#' } - ] - } - } - }; + anyOf: [{$ref: "#/definitions/english_word"}, {$ref: "#"}], + }, + }, + } - return recursiveTest(schema); - }); + return recursiveTest(schema) + }) - it('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', + type: "object", properties: { foo: { $async: true, anyOf: [ { - type: 'string', - format: 'english_word' + type: "string", + format: "english_word", }, { - type: 'object', + type: "object", properties: { - foo: { $ref: '#/properties/foo' } - } - } - ] - } - } - }; + foo: {$ref: "#/properties/foo"}, + }, + }, + ], + }, + }, + } - return recursiveTest(schema); - }); + return recursiveTest(schema) + }) - it('should validate ref from referenced async schema to root schema', function() { + it("should validate ref from referenced async schema to root schema", function () { var schema = { $async: true, definitions: { @@ -273,184 +279,195 @@ describe('async schemas, formats and keywords', function() { $async: true, anyOf: [ { - type: 'string', - format: 'english_word' + type: "string", + format: "english_word", }, - { $ref: '#' } - ] - } + {$ref: "#"}, + ], + }, }, - type: 'object', + type: "object", properties: { - foo: { $ref: '#/definitions/wordOrRoot' } - } - }; + foo: {$ref: "#/definitions/wordOrRoot"}, + }, + } - return recursiveTest(schema); - }); + return recursiveTest(schema) + }) - it('should validate refs between two async schemas', 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', + type: "object", properties: { - foo: { $ref: 'http://e.com/word.json#' } - } - }; + foo: {$ref: "http://e.com/word.json#"}, + }, + } var schemaWord = { - $id: 'http://e.com/word.json#', + $id: "http://e.com/word.json#", $async: true, anyOf: [ { - type: 'string', - format: 'english_word' + type: "string", + format: "english_word", }, - { $ref: 'http://e.com/obj.json#' } - ] - }; + {$ref: "http://e.com/obj.json#"}, + ], + } - return recursiveTest(schemaObj, schemaWord); - }); + return recursiveTest(schemaObj, schemaWord) + }) - it('should fail compilation if sync schema references async schema', function() { + it("should fail compilation if sync schema references async schema", function () { var schema = { - $id: 'http://e.com/obj.json#', - type: 'object', + $id: "http://e.com/obj.json#", + type: "object", properties: { - foo: { $ref: 'http://e.com/word.json#' } - } - }; + foo: {$ref: "http://e.com/word.json#"}, + }, + } var schemaWord = { - $id: 'http://e.com/word.json#', + $id: "http://e.com/word.json#", $async: true, anyOf: [ { - type: 'string', - format: 'english_word' + type: "string", + format: "english_word", }, - { $ref: 'http://e.com/obj.json#' } - ] - }; + {$ref: "http://e.com/obj.json#"}, + ], + } - ajv.addSchema(schemaWord); - ajv.addFormat('english_word', { + ajv.addSchema(schemaWord) + ajv.addFormat("english_word", { async: true, - validate: checkWordOnServer - }); + validate: checkWordOnServer, + }) - shouldThrowFunc('async schema referenced by sync schema', function() { - ajv.compile(schema); - }); + shouldThrowFunc("async schema referenced by sync schema", function () { + ajv.compile(schema) + }) - schema.$id = 'http://e.com/obj2.json#'; - schema.$async = true; + schema.$id = "http://e.com/obj2.json#" + schema.$async = true - ajv.compile(schema); - }); + ajv.compile(schema) + }) function recursiveTest(schema, refSchema) { - return repeat(function() { return Promise.all(instances.map(function (_ajv) { - if (refSchema) try { _ajv.addSchema(refSchema); } catch(e) {} - var validate = _ajv.compile(schema); - var data; - - return Promise.all([ - 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' ) - ]); - })); }); + return repeat(function () { + return Promise.all( + instances.map(function (_ajv) { + if (refSchema) { + try { + _ajv.addSchema(refSchema) + } catch (e) {} + } + var validate = _ajv.compile(schema) + var data + + return Promise.all([ + 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" + ), + ]) + }) + ) + }) } - }); - + }) function addFormatEnglishWord() { instances.forEach(function (_ajv) { - _ajv.addFormat('english_word', { + _ajv.addFormat("english_word", { async: true, - validate: checkWordOnServer - }); - }); + validate: checkWordOnServer, + }) + }) } -}); - +}) function checkWordOnServer(str) { - return str == 'tomorrow' ? Promise.resolve(true) - : str == 'manana' ? Promise.resolve(false) - : Promise.reject(new Error('unknown word')); + return str == "tomorrow" + ? Promise.resolve(true) + : str == "manana" + ? Promise.resolve(false) + : Promise.reject(new Error("unknown word")) } - function shouldThrowFunc(message, func) { - var err; - should.throw(function() { - try { func(); } - catch(e) { err = e; throw e; } - }); + var err + should.throw(function () { + try { + func() + } catch (e) { + err = e + throw e + } + }) - err.message .should.equal(message); + err.message.should.equal(message) } - function shouldBeValid(p, data) { return p.then(function (valid) { - valid .should.equal(data); - }); + valid.should.equal(data) + }) } - -var SHOULD_BE_INVALID = 'test: should be invalid'; +var SHOULD_BE_INVALID = "test: should be invalid" function shouldBeInvalid(p, expectedMessages) { - return checkNotValid(p) - .then(function (err) { - err .should.be.instanceof(Ajv.ValidationError); - err.errors .should.be.an('array'); - err.validation .should.equal(true); + return checkNotValid(p).then(function (err) { + err.should.be.instanceof(Ajv.ValidationError) + err.errors.should.be.an("array") + err.validation.should.equal(true) if (expectedMessages) { var messages = err.errors.map(function (e) { - return e.message; - }); - messages .should.eql(expectedMessages); + return e.message + }) + messages.should.eql(expectedMessages) } - }); + }) } - function shouldThrow(p, exception) { - return checkNotValid(p) - .then(function (err) { - err.message .should.equal(exception); - }); + return checkNotValid(p).then(function (err) { + err.message.should.equal(exception) + }) } - function checkNotValid(p) { - return p.then(function (/* valid */) { - throw new Error(SHOULD_BE_INVALID); - }) - .catch(function (err) { - err. should.be.instanceof(Error); - if (err.message == SHOULD_BE_INVALID) throw err; - return err; - }); + return p + .then(function (/* valid */) { + throw new Error(SHOULD_BE_INVALID) + }) + .catch(function (err) { + err.should.be.instanceof(Error) + if (err.message == SHOULD_BE_INVALID) throw err + return err + }) } - function repeat(func) { - return func(); + return func() // var promises = []; // for (var i=0; i<1000; i++) promises.push(func()); // return Promise.all(promises); diff --git a/spec/boolean.spec.js b/spec/boolean.spec.js index c4c3b3eb19..5da22820f4 100644 --- a/spec/boolean.spec.js +++ b/spec/boolean.spec.js @@ -1,476 +1,438 @@ -'use strict'; +"use strict" -var Ajv = require('./ajv'); -require('./chai').should(); +var Ajv = require("./ajv") +require("./chai").should() +describe("boolean schemas", function () { + var ajvs -describe('boolean schemas', function() { - var ajvs; + before(function () { + ajvs = [new Ajv(), new Ajv({allErrors: true}), new Ajv({inlineRefs: false})] + }) - before(function() { - ajvs = [ - new Ajv, - new Ajv({allErrors: true}), - new Ajv({inlineRefs: false}) - ]; - }); + describe("top level schema", function () { + describe("schema = true", function () { + it("should validate any data as valid", function () { + ajvs.forEach(test(true, true)) + }) + }) - describe('top level schema', function() { - describe('schema = true', function() { - it('should validate any data as valid', function() { - ajvs.forEach(test(true, true)); - }); - }); - - describe('schema = false', function() { - it('should validate any data as invalid', function() { - ajvs.forEach(test(false, false)); - }); - }); + describe("schema = false", function () { + it("should validate any data as invalid", function () { + ajvs.forEach(test(false, false)) + }) + }) function test(boolSchema, valid) { return function (ajv) { - var validate = ajv.compile(boolSchema); - testSchema(validate, valid); - }; + var validate = ajv.compile(boolSchema) + testSchema(validate, valid) + } } - }); - + }) - describe('in properties / sub-properties', function() { - describe('schema = true', function() { - it('should be valid with any property value', function() { - ajvs.forEach(test(true, true)); - }); - }); + describe("in properties / sub-properties", function () { + describe("schema = true", function () { + it("should be valid with any property value", function () { + ajvs.forEach(test(true, true)) + }) + }) - describe('schema = false', function() { - it('should be invalid with any property value', function() { - ajvs.forEach(test(false, false)); - }); - }); + describe("schema = false", function () { + it("should be invalid with any property value", function () { + ajvs.forEach(test(false, false)) + }) + }) function test(boolSchema, valid) { return function (ajv) { var schema = { - type: 'object', + type: "object", properties: { foo: boolSchema, bar: { - type: 'object', + type: "object", properties: { - baz: boolSchema - } - } - } - }; - - var validate = ajv.compile(schema); - validate({ foo: 1, bar: { baz: 1 }}) .should.equal(valid); - validate({ foo: '1', bar: { baz: '1' }}) .should.equal(valid); - validate({ foo: {}, bar: { baz: {} }}) .should.equal(valid); - validate({ foo: [], bar: { baz: [] }}) .should.equal(valid); - validate({ foo: true, bar: { baz: true }}) .should.equal(valid); - validate({ foo: false, bar: { baz: false }}) .should.equal(valid); - validate({ foo: null, bar: { baz: null }}) .should.equal(valid); - - validate({ bar: { quux: 1 } }) .should.equal(true); - }; + baz: boolSchema, + }, + }, + }, + } + + var validate = ajv.compile(schema) + validate({foo: 1, bar: {baz: 1}}).should.equal(valid) + validate({foo: "1", bar: {baz: "1"}}).should.equal(valid) + validate({foo: {}, bar: {baz: {}}}).should.equal(valid) + validate({foo: [], bar: {baz: []}}).should.equal(valid) + validate({foo: true, bar: {baz: true}}).should.equal(valid) + validate({foo: false, bar: {baz: false}}).should.equal(valid) + validate({foo: null, bar: {baz: null}}).should.equal(valid) + + validate({bar: {quux: 1}}).should.equal(true) + } } - }); + }) + describe("in items / sub-items", function () { + describe("schema = true", function () { + it("should be valid with any item value", function () { + ajvs.forEach(test(true, true)) + }) + }) - describe('in items / sub-items', function() { - describe('schema = true', function() { - it('should be valid with any item value', function() { - ajvs.forEach(test(true, true)); - }); - }); - - describe('schema = false', function() { - it('should be invalid with any item value', function() { - ajvs.forEach(test(false, false)); - }); - }); + describe("schema = false", function () { + it("should be invalid with any item value", function () { + ajvs.forEach(test(false, false)) + }) + }) function test(boolSchema, valid) { return function (ajv) { var schema = { - type: 'array', - items: boolSchema - }; + type: "array", + items: boolSchema, + } - var validate = ajv.compile(schema); - validate([ 1 ]) .should.equal(valid); - validate([ '1' ]) .should.equal(valid); - validate([ {} ]) .should.equal(valid); - validate([ [] ]) .should.equal(valid); - validate([ true ]) .should.equal(valid); - validate([ false ]) .should.equal(valid); - validate([ null ]) .should.equal(valid); + var validate = ajv.compile(schema) + validate([1]).should.equal(valid) + validate(["1"]).should.equal(valid) + validate([{}]).should.equal(valid) + validate([[]]).should.equal(valid) + validate([true]).should.equal(valid) + validate([false]).should.equal(valid) + validate([null]).should.equal(valid) - validate([]) .should.equal(true); + validate([]).should.equal(true) schema = { - type: 'array', + type: "array", items: [ true, { - type: 'array', - items: [ - true, - boolSchema - ] + type: "array", + items: [true, boolSchema], }, - boolSchema - ] - }; - - validate = ajv.compile(schema); - validate([ 1, [ 1, 1 ], 1 ]) .should.equal(valid); - validate([ '1', [ '1', '1' ], '1' ]) .should.equal(valid); - validate([ {}, [ {}, {} ], {} ]) .should.equal(valid); - validate([ [], [ [], [] ], [] ]) .should.equal(valid); - validate([ true, [ true, true ], true ]) .should.equal(valid); - validate([ false, [ false, false ], false ]) .should.equal(valid); - validate([ null, [ null, null ], null ]) .should.equal(valid); - - validate([ 1, [ 1 ] ]) .should.equal(true); - }; + boolSchema, + ], + } + + validate = ajv.compile(schema) + validate([1, [1, 1], 1]).should.equal(valid) + validate(["1", ["1", "1"], "1"]).should.equal(valid) + validate([{}, [{}, {}], {}]).should.equal(valid) + validate([[], [[], []], []]).should.equal(valid) + validate([true, [true, true], true]).should.equal(valid) + validate([false, [false, false], false]).should.equal(valid) + validate([null, [null, null], null]).should.equal(valid) + + validate([1, [1]]).should.equal(true) + } } - }); - + }) - describe('in dependencies and sub-dependencies', function() { - describe('schema = true', function() { - it('should be valid with any property value', function() { - ajvs.forEach(test(true, true)); - }); - }); + describe("in dependencies and sub-dependencies", function () { + describe("schema = true", function () { + it("should be valid with any property value", function () { + ajvs.forEach(test(true, true)) + }) + }) - describe('schema = false', function() { - it('should be invalid with any property value', function() { - ajvs.forEach(test(false, false)); - }); - }); + describe("schema = false", function () { + it("should be invalid with any property value", function () { + ajvs.forEach(test(false, false)) + }) + }) function test(boolSchema, valid) { return function (ajv) { var schema = { - type: 'object', + type: "object", dependencies: { foo: boolSchema, bar: { - type: 'object', + type: "object", dependencies: { - baz: boolSchema - } - } - } - }; - - var validate = ajv.compile(schema); - validate({ foo: 1, bar: 1, baz: 1 }) .should.equal(valid); - validate({ foo: '1', bar: '1', baz: '1' }) .should.equal(valid); - validate({ foo: {}, bar: {}, baz: {} }) .should.equal(valid); - validate({ foo: [], bar: [], baz: [] }) .should.equal(valid); - validate({ foo: true, bar: true, baz: true }) .should.equal(valid); - validate({ foo: false, bar: false, baz: false }) .should.equal(valid); - validate({ foo: null, bar: null, baz: null }) .should.equal(valid); - - validate({ bar: 1, quux: 1 }) .should.equal(true); - }; + baz: boolSchema, + }, + }, + }, + } + + var validate = ajv.compile(schema) + validate({foo: 1, bar: 1, baz: 1}).should.equal(valid) + validate({foo: "1", bar: "1", baz: "1"}).should.equal(valid) + validate({foo: {}, bar: {}, baz: {}}).should.equal(valid) + validate({foo: [], bar: [], baz: []}).should.equal(valid) + validate({foo: true, bar: true, baz: true}).should.equal(valid) + validate({foo: false, bar: false, baz: false}).should.equal(valid) + validate({foo: null, bar: null, baz: null}).should.equal(valid) + + validate({bar: 1, quux: 1}).should.equal(true) + } } - }); - + }) - describe('in patternProperties', function () { - describe('schema = true', function() { - it('should be valid with any property matching pattern', function() { - ajvs.forEach(test(true, true)); - }); - }); + describe("in patternProperties", function () { + describe("schema = true", function () { + it("should be valid with any property matching pattern", function () { + ajvs.forEach(test(true, true)) + }) + }) - describe('schema = false', function() { - it('should be invalid with any property matching pattern', function() { - ajvs.forEach(test(false, false)); - }); - }); + describe("schema = false", function () { + it("should be invalid with any property matching pattern", function () { + ajvs.forEach(test(false, false)) + }) + }) function test(boolSchema, valid) { return function (ajv) { var schema = { - type: 'object', + type: "object", patternProperties: { - '^f': boolSchema, - 'r$': { - type: 'object', + "^f": boolSchema, + r$: { + type: "object", patternProperties: { - 'z$': boolSchema - } - } - } - }; - - var validate = ajv.compile(schema); - validate({ foo: 1, bar: { baz: 1 }}) .should.equal(valid); - validate({ foo: '1', bar: { baz: '1' }}) .should.equal(valid); - validate({ foo: {}, bar: { baz: {} }}) .should.equal(valid); - validate({ foo: [], bar: { baz: [] }}) .should.equal(valid); - validate({ foo: true, bar: { baz: true }}) .should.equal(valid); - validate({ foo: false, bar: { baz: false }}) .should.equal(valid); - validate({ foo: null, bar: { baz: null }}) .should.equal(valid); - - validate({ bar: { quux: 1 } }) .should.equal(true); - }; + z$: boolSchema, + }, + }, + }, + } + + var validate = ajv.compile(schema) + validate({foo: 1, bar: {baz: 1}}).should.equal(valid) + validate({foo: "1", bar: {baz: "1"}}).should.equal(valid) + validate({foo: {}, bar: {baz: {}}}).should.equal(valid) + validate({foo: [], bar: {baz: []}}).should.equal(valid) + validate({foo: true, bar: {baz: true}}).should.equal(valid) + validate({foo: false, bar: {baz: false}}).should.equal(valid) + validate({foo: null, bar: {baz: null}}).should.equal(valid) + + validate({bar: {quux: 1}}).should.equal(true) + } } - }); + }) + describe("in propertyNames", function () { + describe("schema = true", function () { + it("should be valid with any property", function () { + ajvs.forEach(test(true, true)) + }) + }) - describe('in propertyNames', function() { - describe('schema = true', function() { - it('should be valid with any property', function() { - ajvs.forEach(test(true, true)); - }); - }); - - describe('schema = false', function() { - it('should be invalid with any property', function() { - ajvs.forEach(test(false, false)); - }); - }); + describe("schema = false", function () { + it("should be invalid with any property", function () { + ajvs.forEach(test(false, false)) + }) + }) function test(boolSchema, valid) { return function (ajv) { var schema = { - type: 'object', - propertyNames: boolSchema - }; + type: "object", + propertyNames: boolSchema, + } - var validate = ajv.compile(schema); - validate({ foo: 1 }) .should.equal(valid); - validate({ bar: 1 }) .should.equal(valid); + var validate = ajv.compile(schema) + validate({foo: 1}).should.equal(valid) + validate({bar: 1}).should.equal(valid) - validate({}) .should.equal(true); - }; + validate({}).should.equal(true) + } } - }); - + }) - describe('in contains', function() { - describe('schema = true', function() { - it('should be valid with any items', function() { - ajvs.forEach(test(true, true)); - }); - }); + describe("in contains", function () { + describe("schema = true", function () { + it("should be valid with any items", function () { + ajvs.forEach(test(true, true)) + }) + }) - describe('schema = false', function() { - it('should be invalid with any items', function() { - ajvs.forEach(test(false, false)); - }); - }); + describe("schema = false", function () { + it("should be invalid with any items", function () { + ajvs.forEach(test(false, false)) + }) + }) function test(boolSchema, valid) { return function (ajv) { var schema = { - type: 'array', - contains: boolSchema - }; - - var validate = ajv.compile(schema); - validate([ 1 ]) .should.equal(valid); - validate([ 'foo' ]) .should.equal(valid); - validate([ {} ]) .should.equal(valid); - validate([ [] ]) .should.equal(valid); - validate([ true ]) .should.equal(valid); - validate([ false ]) .should.equal(valid); - validate([ null ]) .should.equal(valid); - - validate([]) .should.equal(false); - }; + type: "array", + contains: boolSchema, + } + + var validate = ajv.compile(schema) + validate([1]).should.equal(valid) + validate(["foo"]).should.equal(valid) + validate([{}]).should.equal(valid) + validate([[]]).should.equal(valid) + validate([true]).should.equal(valid) + validate([false]).should.equal(valid) + validate([null]).should.equal(valid) + + validate([]).should.equal(false) + } } - }); + }) + describe("in not", function () { + describe("schema = true", function () { + it("should be invalid with any data", function () { + ajvs.forEach(test(true, false)) + }) + }) - describe('in not', function() { - describe('schema = true', function() { - it('should be invalid with any data', function() { - ajvs.forEach(test(true, false)); - }); - }); - - describe('schema = false', function() { - it('should be valid with any data', function() { - ajvs.forEach(test(false, true)); - }); - }); + describe("schema = false", function () { + it("should be valid with any data", function () { + ajvs.forEach(test(false, true)) + }) + }) function test(boolSchema, valid) { return function (ajv) { var schema = { - not: boolSchema - }; + not: boolSchema, + } - var validate = ajv.compile(schema); - testSchema(validate, valid); - }; + var validate = ajv.compile(schema) + testSchema(validate, valid) + } } - }); - + }) - describe('in allOf', function() { - describe('schema = true', function() { - it('should be valid with any data', function() { - ajvs.forEach(test(true, true)); - }); - }); + describe("in allOf", function () { + describe("schema = true", function () { + it("should be valid with any data", function () { + ajvs.forEach(test(true, true)) + }) + }) - describe('schema = false', function() { - it('should be invalid with any data', function() { - ajvs.forEach(test(false, false)); - }); - }); + describe("schema = false", function () { + it("should be invalid with any data", function () { + ajvs.forEach(test(false, false)) + }) + }) function test(boolSchema, valid) { return function (ajv) { var schema = { - allOf: [ - false, - boolSchema - ] - }; + allOf: [false, boolSchema], + } - var validate = ajv.compile(schema); - testSchema(validate, false); + var validate = ajv.compile(schema) + testSchema(validate, false) schema = { - allOf: [ - true, - boolSchema - ] - }; + allOf: [true, boolSchema], + } - validate = ajv.compile(schema); - testSchema(validate, valid); - }; + validate = ajv.compile(schema) + testSchema(validate, valid) + } } - }); + }) + describe("in anyOf", function () { + describe("schema = true", function () { + it("should be valid with any data", function () { + ajvs.forEach(test(true, true)) + }) + }) - describe('in anyOf', function() { - describe('schema = true', function() { - it('should be valid with any data', function() { - ajvs.forEach(test(true, true)); - }); - }); - - describe('schema = false', function() { - it('should be invalid with any data', function() { - ajvs.forEach(test(false, false)); - }); - }); + describe("schema = false", function () { + it("should be invalid with any data", function () { + ajvs.forEach(test(false, false)) + }) + }) function test(boolSchema, valid) { return function (ajv) { var schema = { - anyOf: [ - false, - boolSchema - ] - }; + anyOf: [false, boolSchema], + } - var validate = ajv.compile(schema); - testSchema(validate, valid); + var validate = ajv.compile(schema) + testSchema(validate, valid) schema = { - anyOf: [ - true, - boolSchema - ] - }; + anyOf: [true, boolSchema], + } - validate = ajv.compile(schema); - testSchema(validate, true); - }; + validate = ajv.compile(schema) + testSchema(validate, true) + } } - }); + }) + describe("in oneOf", function () { + describe("schema = true", function () { + it("should be valid with any data", function () { + ajvs.forEach(test(true, true)) + }) + }) - describe('in oneOf', function() { - describe('schema = true', function() { - it('should be valid with any data', function() { - ajvs.forEach(test(true, true)); - }); - }); - - describe('schema = false', function() { - it('should be invalid with any data', function() { - ajvs.forEach(test(false, false)); - }); - }); + describe("schema = false", function () { + it("should be invalid with any data", function () { + ajvs.forEach(test(false, false)) + }) + }) function test(boolSchema, valid) { return function (ajv) { var schema = { - oneOf: [ - false, - boolSchema - ] - }; + oneOf: [false, boolSchema], + } - var validate = ajv.compile(schema); - testSchema(validate, valid); + var validate = ajv.compile(schema) + testSchema(validate, valid) schema = { - oneOf: [ - true, - boolSchema - ] - }; + oneOf: [true, boolSchema], + } - validate = ajv.compile(schema); - testSchema(validate, !valid); - }; + validate = ajv.compile(schema) + testSchema(validate, !valid) + } } - }); + }) + describe("in $ref", function () { + describe("schema = true", function () { + it("should be valid with any data", function () { + ajvs.forEach(test(true, true)) + }) + }) - describe('in $ref', function() { - describe('schema = true', function() { - it('should be valid with any data', function() { - ajvs.forEach(test(true, true)); - }); - }); - - describe('schema = false', function() { - it('should be invalid with any data', function() { - ajvs.forEach(test(false, false)); - }); - }); + describe("schema = false", function () { + it("should be invalid with any data", function () { + ajvs.forEach(test(false, false)) + }) + }) function test(boolSchema, valid) { return function (ajv) { var schema = { - $ref: '#/definitions/bool', + $ref: "#/definitions/bool", definitions: { - bool: boolSchema - } - }; + bool: boolSchema, + }, + } - var validate = ajv.compile(schema); - testSchema(validate, valid); - }; + var validate = ajv.compile(schema) + testSchema(validate, valid) + } } - }); - + }) function testSchema(validate, valid) { - validate(1) .should.equal(valid); - validate('foo') .should.equal(valid); - validate({}) .should.equal(valid); - validate([]) .should.equal(valid); - validate(true) .should.equal(valid); - validate(false) .should.equal(valid); - validate(null) .should.equal(valid); + validate(1).should.equal(valid) + validate("foo").should.equal(valid) + validate({}).should.equal(valid) + validate([]).should.equal(valid) + validate(true).should.equal(valid) + validate(false).should.equal(valid) + validate(null).should.equal(valid) } -}); +}) diff --git a/spec/browser_test_suite.js b/spec/browser_test_suite.js index 40e138c7c6..f7016eb0e2 100644 --- a/spec/browser_test_suite.js +++ b/spec/browser_test_suite.js @@ -1,10 +1,10 @@ -'use strict'; +"use strict" 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; -}; + if (file.name.indexOf("optional/format") == 0) + file.name = file.name.replace("optional/", "") + file.test = file.module + }) + return suite +} diff --git a/spec/chai.js b/spec/chai.js index b3cd0ed78f..2bb98a87e9 100644 --- a/spec/chai.js +++ b/spec/chai.js @@ -1,3 +1,3 @@ -'use strict'; +"use strict" -module.exports = typeof window == 'object' ? window.chai : require('' + 'chai'); +module.exports = typeof window == "object" ? window.chai : require("" + "chai") diff --git a/spec/coercion.spec.js b/spec/coercion.spec.js index a9f13de5c4..64406f7ee4 100644 --- a/spec/coercion.spec.js +++ b/spec/coercion.spec.js @@ -1,507 +1,485 @@ -'use strict'; - -var Ajv = require('./ajv'); -require('./chai').should(); +"use strict" +var Ajv = require("./ajv") +require("./chai").should() var coercionRules = { - 'string': { - 'number': [ - { from: 1, to: '1' }, - { from: 1.5, to: '1.5' }, - { from: 2e100, to: '2e+100' } - ], - 'boolean': [ - { from: false, to: 'false' }, - { from: true, to: 'true' } + string: { + number: [ + {from: 1, to: "1"}, + {from: 1.5, to: "1.5"}, + {from: 2e100, to: "2e+100"}, ], - 'null': [ - { from: null, to: '' } + boolean: [ + {from: false, to: "false"}, + {from: true, to: "true"}, ], - 'object': [ - { from: {}, to: undefined } + null: [{from: null, to: ""}], + object: [{from: {}, to: undefined}], + array: [ + {from: [], to: undefined}, + {from: [1], to: undefined}, ], - 'array': [ - { from: [], to: undefined }, - { from: [1], to: undefined } - ] }, - 'number': { - 'string': [ - { from: '1', to: 1 }, - { from: '1.5', to: 1.5 }, - { from: '2e10', to: 2e10 }, - { from: '1a', to: undefined }, - { from: 'abc', to: undefined }, - { from: '', to: undefined } + number: { + string: [ + {from: "1", to: 1}, + {from: "1.5", to: 1.5}, + {from: "2e10", to: 2e10}, + {from: "1a", to: undefined}, + {from: "abc", to: undefined}, + {from: "", to: undefined}, ], - 'boolean': [ - { from: false, to: 0 }, - { from: true, to: 1 } + boolean: [ + {from: false, to: 0}, + {from: true, to: 1}, ], - 'null': [ - { from: null, to: 0 } + null: [{from: null, to: 0}], + object: [{from: {}, to: undefined}], + array: [ + {from: [], to: undefined}, + {from: [true], to: undefined}, ], - 'object': [ - { from: {}, to: undefined } - ], - 'array': [ - { from: [], to: undefined }, - { from: [true], to: undefined } - ] }, - 'integer': { - 'string': [ - { from: '1', to: 1 }, - { from: '1.5', to: undefined }, - { from: '2e10', to: 2e10 }, - { from: '1a', to: undefined }, - { from: 'abc', to: undefined }, - { from: '', to: undefined } - ], - 'boolean': [ - { from: false, to: 0 }, - { from: true, to: 1 } + integer: { + string: [ + {from: "1", to: 1}, + {from: "1.5", to: undefined}, + {from: "2e10", to: 2e10}, + {from: "1a", to: undefined}, + {from: "abc", to: undefined}, + {from: "", to: undefined}, ], - 'null': [ - { from: null, to: 0 } + boolean: [ + {from: false, to: 0}, + {from: true, to: 1}, ], - 'object': [ - { from: {}, to: undefined } + null: [{from: null, to: 0}], + object: [{from: {}, to: undefined}], + array: [ + {from: [], to: undefined}, + {from: ["1"], to: undefined}, ], - 'array': [ - { from: [], to: undefined }, - { from: ['1'], to: undefined } - ] }, - 'boolean': { - 'string': [ - { from: 'false', to: false }, - { from: 'true', to: true }, - { from: '', to: undefined }, - { from: 'abc', to: undefined } + boolean: { + string: [ + {from: "false", to: false}, + {from: "true", to: true}, + {from: "", to: undefined}, + {from: "abc", to: undefined}, ], - 'number': [ - { from: 0, to: false }, - { from: 1, to: true }, - { from: 2, to: undefined }, - { from: 2.5, to: undefined } + number: [ + {from: 0, to: false}, + {from: 1, to: true}, + {from: 2, to: undefined}, + {from: 2.5, to: undefined}, ], - 'null': [ - { from: null, to: false } + null: [{from: null, to: false}], + object: [{from: {}, to: undefined}], + array: [ + {from: [], to: undefined}, + {from: [0], to: undefined}, ], - 'object': [ - { from: {}, to: undefined } - ], - 'array': [ - { from: [], to: undefined }, - { from: [0], to: undefined } - ] }, - 'null': { - 'string': [ - { from: '', to: null }, - { from: 'abc', to: undefined }, - { from: 'null', to: undefined } + null: { + string: [ + {from: "", to: null}, + {from: "abc", to: undefined}, + {from: "null", to: undefined}, ], - 'number': [ - { from: 0, to: null }, - { from: 1, to: undefined } + number: [ + {from: 0, to: null}, + {from: 1, to: undefined}, ], - 'boolean': [ - { from: false, to: null }, - { from: true, to: undefined } + boolean: [ + {from: false, to: null}, + {from: true, to: undefined}, ], - 'object': [ - { from: {}, to: undefined } + object: [{from: {}, to: undefined}], + array: [ + {from: [], to: undefined}, + {from: [null], to: undefined}, ], - 'array': [ - { from: [], to: undefined }, - { from: [null], to: undefined } - ] }, - 'array': { - 'all': [ - { type: 'string', from: 'abc', to: undefined }, - { type: 'number', from: 1, to: undefined }, - { type: 'boolean', from: true, to: undefined }, - { type: 'null', from: null, to: undefined }, - { type: 'object', from: {}, to: undefined } - ] + array: { + all: [ + {type: "string", from: "abc", to: undefined}, + {type: "number", from: 1, to: undefined}, + {type: "boolean", from: true, to: undefined}, + {type: "null", from: null, to: undefined}, + {type: "object", from: {}, to: undefined}, + ], }, - 'object': { - 'all': [ - { type: 'string', from: 'abc', to: undefined }, - { type: 'number', from: 1, to: undefined }, - { type: 'boolean', from: true, to: undefined }, - { type: 'null', from: null, to: undefined }, - { type: 'array', from: [], to: undefined } - ] - } -}; + object: { + all: [ + {type: "string", from: "abc", to: undefined}, + {type: "number", from: 1, to: undefined}, + {type: "boolean", from: true, to: undefined}, + {type: "null", from: null, to: undefined}, + {type: "array", from: [], to: undefined}, + ], + }, +} -var coercionArrayRules = JSON.parse(JSON.stringify(coercionRules)); +var coercionArrayRules = JSON.parse(JSON.stringify(coercionRules)) coercionArrayRules.string.array = [ - { from: ['abc'], to: 'abc' }, - { from: [123], to: '123' }, - { from: ['abc', 'def'], to: undefined }, - { from: [], to: undefined } -]; + {from: ["abc"], to: "abc"}, + {from: [123], to: "123"}, + {from: ["abc", "def"], to: undefined}, + {from: [], to: undefined}, +] coercionArrayRules.number.array = [ - { from: [1.5], to: 1.5 }, - { from: ['1.5'], to: 1.5 } -]; -coercionArrayRules.integer.array = [ - { from: [1], to: 1 }, - { from: ['1'], to: 1 }, - { from: [true], to: 1 }, - { from: [null], to: 0 } -]; -coercionArrayRules.boolean.array = [ - { from: [true], to: true }, - { from: ['true'], to: true }, - { from: [1], to: true } -]; -coercionArrayRules.null.array = [ - { from: [null], to: null }, - { from: [''], to: null }, - { from: [0], to: null }, - { from: [false], to: null } -]; -coercionArrayRules.object.array = [ - { from: [{}], to: undefined } -]; + {from: [1.5], to: 1.5}, + {from: ["1.5"], to: 1.5}, +] +coercionArrayRules.integer.array = [ + {from: [1], to: 1}, + {from: ["1"], to: 1}, + {from: [true], to: 1}, + {from: [null], to: 0}, +] +coercionArrayRules.boolean.array = [ + {from: [true], to: true}, + {from: ["true"], to: true}, + {from: [1], to: true}, +] +coercionArrayRules.null.array = [ + {from: [null], to: null}, + {from: [""], to: null}, + {from: [0], to: null}, + {from: [false], to: null}, +] +coercionArrayRules.object.array = [{from: [{}], to: undefined}] coercionArrayRules.array = { - 'string': [ - {from: 'abc', to: ['abc']} - ], - 'number': [ - {from: 1, to: [1]} - ], - 'boolean': [ - {from: true, to: [true]} - ], - 'null': [ - {from: null, to: [null]} - ], - 'object': [ - {from: {}, to: undefined} - ] -}; - -describe('Type coercion', function () { - var ajv, fullAjv, instances; - - beforeEach(function() { - ajv = new Ajv({ coerceTypes: true, verbose: true }); - fullAjv = new Ajv({ coerceTypes: true, verbose: true, allErrors: true }); - instances = [ ajv, fullAjv ]; - }); - - - it('should coerce scalar values', function() { - testRules(coercionRules, function (test, schema, canCoerce/*, toType, fromType*/) { + string: [{from: "abc", to: ["abc"]}], + number: [{from: 1, to: [1]}], + boolean: [{from: true, to: [true]}], + null: [{from: null, to: [null]}], + object: [{from: {}, to: undefined}], +} + +describe("Type coercion", function () { + var ajv, fullAjv, instances + + beforeEach(function () { + ajv = new Ajv({coerceTypes: true, verbose: true}) + fullAjv = new Ajv({coerceTypes: true, verbose: true, allErrors: true}) + instances = [ajv, fullAjv] + }) + + it("should coerce scalar values", function () { + testRules(coercionRules, function ( + test, + schema, + canCoerce /*, toType, fromType*/ + ) { instances.forEach(function (_ajv) { - var valid = _ajv.validate(schema, test.from); + var valid = _ajv.validate(schema, test.from) //if (valid !== canCoerce) console.log('true', toType, fromType, test, ajv.errors); - valid. should.equal(canCoerce); - }); - }); - }); - - it('should coerce scalar values (coerceTypes = array)', function() { - ajv = new Ajv({ coerceTypes: 'array', verbose: true }); - fullAjv = new Ajv({ coerceTypes: 'array', verbose: true, allErrors: true }); - instances = [ ajv, fullAjv ]; - - testRules(coercionArrayRules, function (test, schema, canCoerce, toType, fromType) { + valid.should.equal(canCoerce) + }) + }) + }) + + it("should coerce scalar values (coerceTypes = array)", function () { + ajv = new Ajv({coerceTypes: "array", verbose: true}) + fullAjv = new Ajv({coerceTypes: "array", verbose: true, allErrors: true}) + instances = [ajv, fullAjv] + + testRules(coercionArrayRules, function ( + test, + schema, + canCoerce, + toType, + fromType + ) { instances.forEach(function (_ajv) { - var valid = _ajv.validate(schema, test.from); - if (valid !== canCoerce) console.log(toType, '.', fromType, test, schema, ajv.errors); - valid. should.equal(canCoerce); - }); - }); - }); - - it('should coerce values in objects/arrays and update properties/items', function() { - testRules(coercionRules, function (test, schema, canCoerce/*, toType, fromType*/) { + var valid = _ajv.validate(schema, test.from) + if (valid !== canCoerce) + console.log(toType, ".", fromType, test, schema, ajv.errors) + valid.should.equal(canCoerce) + }) + }) + }) + + it("should coerce values in objects/arrays and update properties/items", function () { + testRules(coercionRules, function ( + test, + schema, + canCoerce /*, toType, fromType*/ + ) { var schemaObject = { - type: 'object', + type: "object", properties: { - foo: schema - } - }; + foo: schema, + }, + } var schemaArray = { - type: 'array', - items: schema - }; + type: "array", + items: schema, + } var schemaArrObj = { - type: 'array', - items: schemaObject - }; - + type: "array", + items: schemaObject, + } instances.forEach(function (_ajv) { - testCoercion(_ajv, schemaArray, [ test.from ], [ test.to ]); - testCoercion(_ajv, schemaObject, { foo: test.from }, { foo: test.to }); - testCoercion(_ajv, schemaArrObj, [ { foo: test.from } ], [ { foo: test.to } ]); - }); + testCoercion(_ajv, schemaArray, [test.from], [test.to]) + testCoercion(_ajv, schemaObject, {foo: test.from}, {foo: test.to}) + testCoercion(_ajv, schemaArrObj, [{foo: test.from}], [{foo: test.to}]) + }) function testCoercion(_ajv, _schema, fromData, toData) { - var valid = _ajv.validate(_schema, fromData); + var valid = _ajv.validate(_schema, fromData) //if (valid !== canCoerce) console.log(schema, fromData, toData); - valid. should.equal(canCoerce); - if (valid) fromData.should.eql(toData); + valid.should.equal(canCoerce) + if (valid) fromData.should.eql(toData) } - }); - }); - + }) + }) - it('should coerce to multiple types in order with number type', function() { + it("should coerce to multiple types in order with number type", function () { var schema = { - type: 'object', + type: "object", properties: { foo: { - type: [ 'number', 'boolean', 'null' ] - } - } - }; + type: ["number", "boolean", "null"], + }, + }, + } instances.forEach(function (_ajv) { - var data; + var data - _ajv.validate(schema, data = { foo: '1' }) .should.equal(true); - data .should.eql({ foo: 1 }); + _ajv.validate(schema, (data = {foo: "1"})).should.equal(true) + data.should.eql({foo: 1}) - _ajv.validate(schema, data = { foo: '1.5' }) .should.equal(true); - data .should.eql({ foo: 1.5 }); + _ajv.validate(schema, (data = {foo: "1.5"})).should.equal(true) + data.should.eql({foo: 1.5}) - _ajv.validate(schema, data = { foo: 'false' }) .should.equal(true); - data .should.eql({ foo: false }); + _ajv.validate(schema, (data = {foo: "false"})).should.equal(true) + data.should.eql({foo: false}) - _ajv.validate(schema, data = { foo: 1 }) .should.equal(true); - data .should.eql({ foo: 1 }); // no coercion + _ajv.validate(schema, (data = {foo: 1})).should.equal(true) + data.should.eql({foo: 1}) // no coercion - _ajv.validate(schema, data = { foo: true }) .should.equal(true); - data .should.eql({ foo: true }); // no coercion + _ajv.validate(schema, (data = {foo: true})).should.equal(true) + data.should.eql({foo: true}) // no coercion - _ajv.validate(schema, data = { foo: null }) .should.equal(true); - data .should.eql({ foo: null }); // no coercion + _ajv.validate(schema, (data = {foo: null})).should.equal(true) + data.should.eql({foo: null}) // no coercion - _ajv.validate(schema, data = { foo: 'abc' }) .should.equal(false); - data .should.eql({ foo: 'abc' }); // can't coerce + _ajv.validate(schema, (data = {foo: "abc"})).should.equal(false) + data.should.eql({foo: "abc"}) // can't coerce - _ajv.validate(schema, data = { foo: {} }) .should.equal(false); - data .should.eql({ foo: {} }); // can't coerce + _ajv.validate(schema, (data = {foo: {}})).should.equal(false) + data.should.eql({foo: {}}) // can't coerce - _ajv.validate(schema, data = { foo: [] }) .should.equal(false); - data .should.eql({ foo: [] }); // can't coerce - }); - }); + _ajv.validate(schema, (data = {foo: []})).should.equal(false) + data.should.eql({foo: []}) // can't coerce + }) + }) - it('should coerce to multiple types in order with integer type', function() { + it("should coerce to multiple types in order with integer type", function () { var schema = { - type: 'object', + type: "object", properties: { foo: { - type: [ 'integer', 'boolean', 'null' ] - } - } - }; + type: ["integer", "boolean", "null"], + }, + }, + } instances.forEach(function (_ajv) { - var data; - - _ajv.validate(schema, data = { foo: '1' }) .should.equal(true); - data .should.eql({ foo: 1 }); + var data - _ajv.validate(schema, data = { foo: 'false' }) .should.equal(true); - data .should.eql({ foo: false }); + _ajv.validate(schema, (data = {foo: "1"})).should.equal(true) + data.should.eql({foo: 1}) - _ajv.validate(schema, data = { foo: 1 }) .should.equal(true); - data .should.eql({ foo: 1 }); // no coercion + _ajv.validate(schema, (data = {foo: "false"})).should.equal(true) + data.should.eql({foo: false}) - _ajv.validate(schema, data = { foo: true }) .should.equal(true); - data .should.eql({ foo: true }); // no coercion + _ajv.validate(schema, (data = {foo: 1})).should.equal(true) + data.should.eql({foo: 1}) // no coercion - _ajv.validate(schema, data = { foo: null }) .should.equal(true); - data .should.eql({ foo: null }); // no coercion + _ajv.validate(schema, (data = {foo: true})).should.equal(true) + data.should.eql({foo: true}) // no coercion - _ajv.validate(schema, data = { foo: 'abc' }) .should.equal(false); - data .should.eql({ foo: 'abc' }); // can't coerce + _ajv.validate(schema, (data = {foo: null})).should.equal(true) + data.should.eql({foo: null}) // no coercion - _ajv.validate(schema, data = { foo: {} }) .should.equal(false); - data .should.eql({ foo: {} }); // can't coerce + _ajv.validate(schema, (data = {foo: "abc"})).should.equal(false) + data.should.eql({foo: "abc"}) // can't coerce - _ajv.validate(schema, data = { foo: [] }) .should.equal(false); - data .should.eql({ foo: [] }); // can't coerce - }); - }); + _ajv.validate(schema, (data = {foo: {}})).should.equal(false) + data.should.eql({foo: {}}) // can't coerce + _ajv.validate(schema, (data = {foo: []})).should.equal(false) + data.should.eql({foo: []}) // can't coerce + }) + }) - it('should fail to coerce non-number if multiple properties/items are coerced (issue #152)', function() { + it("should fail to coerce non-number if multiple properties/items are coerced (issue #152)", function () { var schema = { - type: 'object', + type: "object", properties: { - foo: { type: 'number' }, - bar: { type: 'number' } - } - }; + foo: {type: "number"}, + bar: {type: "number"}, + }, + } var schema2 = { - type: 'array', - items: { type: 'number' } - }; - - instances.forEach(function (_ajv) { - var data = { foo: '123', bar: 'bar' }; - _ajv.validate(schema, data) .should.equal(false); - data .should.eql({ foo: 123, bar: 'bar' }); + type: "array", + items: {type: "number"}, + } - var data2 = [ '123', 'bar' ]; - _ajv.validate(schema2, data2) .should.equal(false); - data2 .should.eql([ 123, 'bar' ]); - }); - }); + instances.forEach(function (_ajv) { + var data = {foo: "123", bar: "bar"} + _ajv.validate(schema, data).should.equal(false) + data.should.eql({foo: 123, bar: "bar"}) + var data2 = ["123", "bar"] + _ajv.validate(schema2, data2).should.equal(false) + data2.should.eql([123, "bar"]) + }) + }) - it('should update data if the schema is in ref that is not inlined', function () { - instances.push(new Ajv({ coerceTypes: true, inlineRefs: false })); + it("should update data if the schema is in ref that is not inlined", function () { + instances.push(new Ajv({coerceTypes: true, inlineRefs: false})) var schema = { - type: 'object', + type: "object", definitions: { - foo: { type: 'number' } + foo: {type: "number"}, }, properties: { - foo: { $ref: '#/definitions/foo' } - } - }; + foo: {$ref: "#/definitions/foo"}, + }, + } var schema2 = { - type: 'object', + type: "object", definitions: { foo: { // allOf is needed to make sure that "foo" is compiled to a separate function // and not simply passed through (as it would be if it were only $ref) - allOf: [{ $ref: '#/definitions/bar' }] + allOf: [{$ref: "#/definitions/bar"}], }, - bar: { type: 'number' } + bar: {type: "number"}, }, properties: { - foo: { $ref: '#/definitions/foo' } - } - }; + foo: {$ref: "#/definitions/foo"}, + }, + } var schemaRecursive = { - type: [ 'object', 'number' ], + type: ["object", "number"], properties: { - foo: { $ref: '#' } - } - }; + foo: {$ref: "#"}, + }, + } var schemaRecursive2 = { - $id: 'http://e.com/schema.json#', + $id: "http://e.com/schema.json#", definitions: { foo: { - $id: 'http://e.com/foo.json#', - type: [ 'object', 'number' ], + $id: "http://e.com/foo.json#", + type: ["object", "number"], properties: { - foo: { $ref: '#' } - } - } + foo: {$ref: "#"}, + }, + }, }, properties: { - foo: { $ref: 'http://e.com/foo.json#' } - } - }; + foo: {$ref: "http://e.com/foo.json#"}, + }, + } instances.forEach(function (_ajv) { - testCoercion(schema, { foo: '1' }, { foo: 1 }); - testCoercion(schema2, { foo: '1' }, { foo: 1 }); - testCoercion(schemaRecursive, { foo: { foo: '1' } }, { foo: { foo: 1 } }); - testCoercion(schemaRecursive2, { foo: { foo: { foo: '1' } } }, - { foo: { foo: { foo: 1 } } }); + testCoercion(schema, {foo: "1"}, {foo: 1}) + testCoercion(schema2, {foo: "1"}, {foo: 1}) + testCoercion(schemaRecursive, {foo: {foo: "1"}}, {foo: {foo: 1}}) + testCoercion( + schemaRecursive2, + {foo: {foo: {foo: "1"}}}, + {foo: {foo: {foo: 1}}} + ) function testCoercion(_schema, fromData, toData) { - var valid = _ajv.validate(_schema, fromData); + var valid = _ajv.validate(_schema, fromData) // if (!valid) console.log(schema, fromData, toData); - valid. should.equal(true); - fromData .should.eql(toData); + valid.should.equal(true) + fromData.should.eql(toData) } - }); - }); - + }) + }) - it('should generate one error for type with coerceTypes option (issue #469)', function() { + it("should generate one error for type with coerceTypes option (issue #469)", function () { var schema = { - "type": "number", - "minimum": 10 - }; + type: "number", + minimum: 10, + } instances.forEach(function (_ajv) { - var validate = _ajv.compile(schema); - validate(9). should.equal(false); - validate.errors.length .should.equal(1); - - validate(11). should.equal(true); + var validate = _ajv.compile(schema) + validate(9).should.equal(false) + validate.errors.length.should.equal(1) - validate('foo'). should.equal(false); - validate.errors.length .should.equal(1); - }); - }); + validate(11).should.equal(true) + validate("foo").should.equal(false) + validate.errors.length.should.equal(1) + }) + }) - it('should check "uniqueItems" after coercion', function() { + it('should check "uniqueItems" after coercion', function () { var schema = { - items: {type: 'number'}, - uniqueItems: true - }; + items: {type: "number"}, + uniqueItems: true, + } instances.forEach(function (_ajv) { - var validate = _ajv.compile(schema); - validate([1, '2', 3]). should.equal(true); + 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'); - }); - }); + 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() { + it('should check "contains" after coercion', function () { var schema = { - items: {type: 'number'}, - contains: {const: 2} - }; + 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'); - }); - }); + 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]) { - var tests = rules[toType][fromType]; + var tests = rules[toType][fromType] tests.forEach(function (test) { - var canCoerce = test.to !== undefined; + var canCoerce = test.to !== undefined var schema = canCoerce - ? (Array.isArray(test.to) - ? { "type": toType, "items": { "type": fromType, "enum": [ test.to[0] ] } } - : { "type": toType, "enum": [ test.to ] }) - : { type: toType }; - cb(test, schema, canCoerce, toType, fromType); - }); + ? Array.isArray(test.to) + ? {type: toType, items: {type: fromType, enum: [test.to[0]]}} + : {type: toType, enum: [test.to]} + : {type: toType} + cb(test, schema, canCoerce, toType, fromType) + }) } } } -}); +}) diff --git a/spec/custom.spec.js b/spec/custom.spec.js index 2924fceea9..e36b29a64f 100644 --- a/spec/custom.spec.js +++ b/spec/custom.spec.js @@ -1,263 +1,281 @@ -'use strict'; +"use strict" -var getAjvInstances = require('./ajv_instances') - , should = require('./chai').should() - , equal = require('../lib/compile/equal') - , customRules = require('./custom_rules'); +var getAjvInstances = require("./ajv_instances"), + should = require("./chai").should(), + equal = require("../lib/compile/equal"), + customRules = require("./custom_rules") +describe("Custom keywords", function () { + var ajv, instances -describe('Custom keywords', function () { - var ajv, instances; - - beforeEach(function() { + beforeEach(function () { instances = getAjvInstances({ - allErrors: true, - verbose: true, - inlineRefs: false - }); - ajv = instances[0]; - }); - - - describe('custom rules', function() { - describe('rule with "interpreted" keyword validation', function() { - it('should add and validate rule', function() { - testEvenKeyword({ type: 'number', validate: validateEven }); + allErrors: true, + verbose: true, + inlineRefs: false, + }) + ajv = instances[0] + }) + + describe("custom rules", function () { + describe('rule with "interpreted" keyword validation', function () { + it("should add and validate rule", function () { + testEvenKeyword({type: "number", validate: validateEven}) function validateEven(schema, data) { - if (typeof schema != 'boolean') throw new Error('The value of "even" keyword must be boolean'); - return data % 2 ? !schema : schema; + if (typeof schema != "boolean") + throw new Error('The value of "even" keyword must be boolean') + return data % 2 ? !schema : schema } - }); + }) - it('should add, validate keyword schema and validate rule', function() { + it("should add, validate keyword schema and validate rule", function () { testEvenKeyword({ - type: 'number', + type: "number", validate: validateEven, - metaSchema: { "type": "boolean" } - }); + metaSchema: {type: "boolean"}, + }) - shouldBeInvalidSchema({ "x-even": "not_boolean" }); + shouldBeInvalidSchema({"x-even": "not_boolean"}) function validateEven(schema, data) { - return data % 2 ? !schema : schema; + return data % 2 ? !schema : schema } - }); + }) - it('should pass parent schema to "interpreted" keyword validation', function() { + it('should pass parent schema to "interpreted" keyword validation', function () { testRangeKeyword({ - type: 'number', - validate: validateRange - }); + type: "number", + validate: validateRange, + }) function validateRange(schema, data, parentSchema) { - validateRangeSchema(schema, parentSchema); + validateRangeSchema(schema, parentSchema) return parentSchema.exclusiveRange === true - ? data > schema[0] && data < schema[1] - : data >= schema[0] && data <= schema[1]; + ? data > schema[0] && data < schema[1] + : data >= schema[0] && data <= schema[1] } - }); + }) - it('should validate meta schema and pass parent schema to "interpreted" keyword validation', function() { + it('should validate meta schema and pass parent schema to "interpreted" keyword validation', function () { testRangeKeyword({ - type: 'number', + type: "number", validate: validateRange, metaSchema: { - "type": "array", - "items": [ { "type": "number" }, { "type": "number" } ], - "additionalItems": false - } - }); - shouldBeInvalidSchema({ 'x-range': [ "1", 2 ] }); - shouldBeInvalidSchema({ 'x-range': {} }); - shouldBeInvalidSchema({ 'x-range': [ 1, 2, 3 ] }); + type: "array", + items: [{type: "number"}, {type: "number"}], + additionalItems: false, + }, + }) + shouldBeInvalidSchema({"x-range": ["1", 2]}) + shouldBeInvalidSchema({"x-range": {}}) + shouldBeInvalidSchema({"x-range": [1, 2, 3]}) function validateRange(schema, data, parentSchema) { return parentSchema.exclusiveRange === true - ? data > schema[0] && data < schema[1] - : data >= schema[0] && data <= schema[1]; + ? data > schema[0] && data < schema[1] + : data >= schema[0] && data <= schema[1] } - }); + }) - it('should allow defining custom errors for "interpreted" keyword', function() { - testRangeKeyword({ type: 'number', validate: validateRange }, true); + it('should allow defining custom errors for "interpreted" keyword', function () { + testRangeKeyword({type: "number", validate: validateRange}, true) function validateRange(schema, data, parentSchema) { - validateRangeSchema(schema, parentSchema); - var min = schema[0] - , max = schema[1] - , exclusive = parentSchema.exclusiveRange === true; + validateRangeSchema(schema, parentSchema) + var min = schema[0], + max = schema[1], + exclusive = parentSchema.exclusiveRange === true - var minOk = exclusive ? data > min : data >= min; - var maxOk = exclusive ? data < max : data <= max; - var valid = minOk && maxOk; + var minOk = exclusive ? data > min : data >= min + var maxOk = exclusive ? data < max : data <= max + var valid = minOk && maxOk if (!valid) { - var err = { keyword: 'x-range' }; - validateRange.errors = [err]; - var comparison, limit; + var err = {keyword: "x-range"} + validateRange.errors = [err] + var comparison, limit if (minOk) { - comparison = exclusive ? '<' : '<='; - limit = max; + comparison = exclusive ? "<" : "<=" + limit = max } else { - comparison = exclusive ? '>' : '>='; - limit = min; + comparison = exclusive ? ">" : ">=" + limit = min } - err.message = 'should be ' + comparison + ' ' + limit; + err.message = "should be " + comparison + " " + limit err.params = { comparison: comparison, limit: limit, - exclusive: exclusive - }; + exclusive: exclusive, + } } - return valid; + return valid } - }); - }); - + }) + }) - describe('rule with "compiled" keyword validation', function() { - it('should add and validate rule', function() { - testEvenKeyword({ type: 'number', compile: compileEven }); - shouldBeInvalidSchema({ "x-even": "not_boolean" }); + describe('rule with "compiled" keyword validation', function () { + it("should add and validate rule", function () { + testEvenKeyword({type: "number", compile: compileEven}) + shouldBeInvalidSchema({"x-even": "not_boolean"}) function compileEven(schema) { - if (typeof schema != 'boolean') throw new Error('The value of "even" keyword must be boolean'); - return schema ? isEven : isOdd; + if (typeof schema != "boolean") + throw new Error('The value of "even" keyword must be boolean') + return schema ? isEven : isOdd } - function isEven(data) { return data % 2 === 0; } - function isOdd(data) { return data % 2 !== 0; } - }); + function isEven(data) { + return data % 2 === 0 + } + function isOdd(data) { + return data % 2 !== 0 + } + }) - it('should add, validate keyword schema and validate rule', function() { + it("should add, validate keyword schema and validate rule", function () { testEvenKeyword({ - type: 'number', + type: "number", compile: compileEven, - metaSchema: { "type": "boolean" } - }); - shouldBeInvalidSchema({ "x-even": "not_boolean" }); + metaSchema: {type: "boolean"}, + }) + shouldBeInvalidSchema({"x-even": "not_boolean"}) function compileEven(schema) { - return schema ? isEven : isOdd; + return schema ? isEven : isOdd } - function isEven(data) { return data % 2 === 0; } - function isOdd(data) { return data % 2 !== 0; } - }); - - it('should compile keyword validating function only once per schema', function () { - testConstantKeyword({ compile: compileConstant }); - }); + function isEven(data) { + return data % 2 === 0 + } + function isOdd(data) { + return data % 2 !== 0 + } + }) - it('should allow multiple schemas for the same keyword', function () { - testMultipleConstantKeyword({ compile: compileConstant }); - }); + it("should compile keyword validating function only once per schema", function () { + testConstantKeyword({compile: compileConstant}) + }) - it('should pass parent schema to "compiled" keyword validation', function() { - testRangeKeyword({ type: 'number', compile: compileRange }); - }); + it("should allow multiple schemas for the same keyword", function () { + testMultipleConstantKeyword({compile: compileConstant}) + }) - it('should allow multiple parent schemas for the same keyword', function () { - testMultipleRangeKeyword({ type: 'number', compile: compileRange }); - }); - }); + it('should pass parent schema to "compiled" keyword validation', function () { + testRangeKeyword({type: "number", compile: compileRange}) + }) + it("should allow multiple parent schemas for the same keyword", function () { + testMultipleRangeKeyword({type: "number", compile: compileRange}) + }) + }) function compileConstant(schema) { - return typeof schema == 'object' && schema !== null - ? isDeepEqual - : isStrictEqual; + return typeof schema == "object" && schema !== null + ? isDeepEqual + : isStrictEqual - function isDeepEqual(data) { return equal(data, schema); } - function isStrictEqual(data) { return data === schema; } + function isDeepEqual(data) { + return equal(data, schema) + } + function isStrictEqual(data) { + return data === schema + } } function compileRange(schema, parentSchema) { - validateRangeSchema(schema, parentSchema); + validateRangeSchema(schema, parentSchema) - var min = schema[0]; - var max = schema[1]; + var min = schema[0] + var max = schema[1] return parentSchema.exclusiveRange === true - ? function (data) { return data > min && data < max; } - : function (data) { return data >= min && data <= max; }; + ? function (data) { + return data > min && data < max + } + : function (data) { + return data >= min && data <= max + } } - }); - + }) - describe('macro rules', function() { - it('should add and validate rule with "macro" keyword', function() { - testEvenKeyword({ type: 'number', macro: macroEven }, 2); - }); + describe("macro rules", function () { + it('should add and validate rule with "macro" keyword', function () { + testEvenKeyword({type: "number", macro: macroEven}, 2) + }) - it('should add and expand macro rule', function() { - testConstantKeyword({ macro: macroConstant }, 2); - }); + it("should add and expand macro rule", function () { + testConstantKeyword({macro: macroConstant}, 2) + }) - it('should allow multiple schemas for the same macro keyword', function () { - testMultipleConstantKeyword({ macro: macroConstant }, 2); - }); + it("should allow multiple schemas for the same macro keyword", function () { + testMultipleConstantKeyword({macro: macroConstant}, 2) + }) - it('should pass parent schema to "macro" keyword', function() { - testRangeKeyword({ type: 'number', macro: macroRange }, undefined, 2); - }); + it('should pass parent schema to "macro" keyword', function () { + testRangeKeyword({type: "number", macro: macroRange}, undefined, 2) + }) - it('should allow multiple parent schemas for the same macro keyword', function () { - testMultipleRangeKeyword({ type: 'number', macro: macroRange }, 2); - }); + it("should allow multiple parent schemas for the same macro keyword", function () { + testMultipleRangeKeyword({type: "number", macro: macroRange}, 2) + }) - it('should support resolving $ref without id or $id', function () { + it("should support resolving $ref without id or $id", function () { instances.forEach(function (_ajv) { - _ajv.addKeyword('macroRef', { + _ajv.addKeyword("macroRef", { macro: function (schema, parentSchema, it) { - it.baseId .should.equal('#'); - var ref = schema.$ref; - var validate = _ajv.getSchema(ref); - if (validate) return validate.schema; - throw new ajv.constructor.MissingRefError(it.baseId, ref); + it.baseId.should.equal("#") + var ref = schema.$ref + var validate = _ajv.getSchema(ref) + if (validate) return validate.schema + throw new ajv.constructor.MissingRefError(it.baseId, ref) }, metaSchema: { - "type": "object", - "required": [ "$ref" ], - "additionalProperties": false, - "properties": { - "$ref": { - "type": "string" - } - } - } - }); + type: "object", + required: ["$ref"], + additionalProperties: false, + properties: { + $ref: { + type: "string", + }, + }, + }, + }) var schema = { - "macroRef": { - "$ref": "#/definitions/schema" + macroRef: { + $ref: "#/definitions/schema", }, - "definitions": { - "schema": { - "type": "string" - } - } - }; - var validate; - (function compileMacroRef () { validate = _ajv.compile(schema); }).should.not.throw(); - shouldBeValid(validate, 'foo'); - shouldBeInvalid(validate, 1, 2); - }); - }); - - it('should recursively expand macro keywords', function() { + definitions: { + schema: { + type: "string", + }, + }, + } + var validate + ;(function compileMacroRef() { + validate = _ajv.compile(schema) + }.should.not.throw()) + shouldBeValid(validate, "foo") + shouldBeInvalid(validate, 1, 2) + }) + }) + + it("should recursively expand macro keywords", function () { instances.forEach(function (_ajv) { - _ajv.addKeyword('deepProperties', { type: 'object', macro: macroDeepProperties }); - _ajv.addKeyword('range', { type: 'number', macro: macroRange }); + _ajv.addKeyword("deepProperties", { + type: "object", + macro: macroDeepProperties, + }) + _ajv.addKeyword("range", {type: "number", macro: macroRange}) var schema = { - "deepProperties": { - "a.b.c": { "type": "number", "range": [2,4] }, - "d.e.f.g": { "type": "string" } - } - }; + deepProperties: { + "a.b.c": {type: "number", range: [2, 4]}, + "d.e.f.g": {type: "string"}, + }, + } /* This schema recursively expands to: { @@ -304,931 +322,1049 @@ describe('Custom keywords', function () { } */ - var validate = _ajv.compile(schema); + var validate = _ajv.compile(schema) shouldBeValid(validate, { a: {b: {c: 3}}, - d: {e: {f: {g: 'foo'}}} - }); - - shouldBeInvalid(validate, { - a: {b: {c: 5}}, // out of range - d: {e: {f: {g: 'foo'}}} - }, 5); - - shouldBeInvalid(validate, { - a: {b: {c: 'bar'}}, // not number - d: {e: {f: {g: 'foo'}}} - }, 4); + d: {e: {f: {g: "foo"}}}, + }) - shouldBeInvalid(validate, { - a: {b: {c: 3}}, - d: {e: {f: {g: 2}}} // not string - }, 5); + shouldBeInvalid( + validate, + { + a: {b: {c: 5}}, // out of range + d: {e: {f: {g: "foo"}}}, + }, + 5 + ) + + shouldBeInvalid( + validate, + { + a: {b: {c: "bar"}}, // not number + d: {e: {f: {g: "foo"}}}, + }, + 4 + ) + + shouldBeInvalid( + validate, + { + a: {b: {c: 3}}, + d: {e: {f: {g: 2}}}, // not string + }, + 5 + ) function macroDeepProperties(_schema) { - if (typeof _schema != 'object') - throw new Error('schema of deepProperty should be an object'); + if (typeof _schema != "object") + throw new Error("schema of deepProperty should be an object") - var expanded = []; + var expanded = [] for (var prop in _schema) { - var path = prop.split('.'); - var properties = {}; + var path = prop.split(".") + var properties = {} if (path.length == 1) { - properties[prop] = _schema[prop]; + properties[prop] = _schema[prop] } else { - var deepProperties = {}; - deepProperties[path.slice(1).join('.')] = _schema[prop]; - properties[path[0]] = { "deepProperties": deepProperties }; + var deepProperties = {} + deepProperties[path.slice(1).join(".")] = _schema[prop] + properties[path[0]] = {deepProperties: deepProperties} } - expanded.push({ "properties": properties }); + expanded.push({properties: properties}) } - return expanded.length == 1 ? expanded[0] : { "allOf": expanded }; + return expanded.length == 1 ? expanded[0] : {allOf: expanded} } - }); - }); + }) + }) - it('should correctly expand multiple macros on the same level', function() { + it("should correctly expand multiple macros on the same level", function () { instances.forEach(function (_ajv) { - _ajv.addKeyword('range', { type: 'number', macro: macroRange }); - _ajv.addKeyword('even', { type: 'number', macro: macroEven }); + _ajv.addKeyword("range", {type: "number", macro: macroRange}) + _ajv.addKeyword("even", {type: "number", macro: macroEven}) var schema = { - "range": [4,6], - "even": true - }; - - var validate = _ajv.compile(schema); - var numErrors = _ajv._opts.allErrors ? 4 : 2; - - shouldBeInvalid(validate, 2, 2); - shouldBeInvalid(validate, 3, numErrors); - shouldBeValid(validate, 4); - shouldBeInvalid(validate, 5, 2); - shouldBeValid(validate, 6); - shouldBeInvalid(validate, 7, numErrors); - shouldBeInvalid(validate, 8, 2); - }); - }); - - it('should validate macro keyword when it resolves to the same keyword as exists', function() { + range: [4, 6], + even: true, + } + + var validate = _ajv.compile(schema) + var numErrors = _ajv._opts.allErrors ? 4 : 2 + + shouldBeInvalid(validate, 2, 2) + shouldBeInvalid(validate, 3, numErrors) + shouldBeValid(validate, 4) + shouldBeInvalid(validate, 5, 2) + shouldBeValid(validate, 6) + shouldBeInvalid(validate, 7, numErrors) + shouldBeInvalid(validate, 8, 2) + }) + }) + + it("should validate macro keyword when it resolves to the same keyword as exists", function () { instances.forEach(function (_ajv) { - _ajv.addKeyword('range', { type: 'number', macro: macroRange }); + _ajv.addKeyword("range", {type: "number", macro: macroRange}) var schema = { - "range": [1,4], - "minimum": 2.5 - }; + range: [1, 4], + minimum: 2.5, + } - var validate = _ajv.compile(schema); + var validate = _ajv.compile(schema) - shouldBeValid(validate, 3); - shouldBeInvalid(validate, 2); - }); - }); + shouldBeValid(validate, 3) + shouldBeInvalid(validate, 2) + }) + }) - it('should correctly expand macros in subschemas', function() { + it("should correctly expand macros in subschemas", function () { instances.forEach(function (_ajv) { - _ajv.addKeyword('range', { type: 'number', macro: macroRange }); + _ajv.addKeyword("range", {type: "number", macro: macroRange}) var schema = { - "allOf": [ - { "range": [4,8] }, - { "range": [2,6] } - ] - }; + allOf: [{range: [4, 8]}, {range: [2, 6]}], + } - var validate = _ajv.compile(schema); + var validate = _ajv.compile(schema) - shouldBeInvalid(validate, 2, 2); - shouldBeInvalid(validate, 3, 2); - shouldBeValid(validate, 4); - shouldBeValid(validate, 5); - shouldBeValid(validate, 6); - shouldBeInvalid(validate, 7, 2); - shouldBeInvalid(validate, 8, 2); - }); - }); + shouldBeInvalid(validate, 2, 2) + shouldBeInvalid(validate, 3, 2) + shouldBeValid(validate, 4) + shouldBeValid(validate, 5) + shouldBeValid(validate, 6) + shouldBeInvalid(validate, 7, 2) + shouldBeInvalid(validate, 8, 2) + }) + }) - it('should correctly expand macros in macro expansions', function() { + it("should correctly expand macros in macro expansions", function () { instances.forEach(function (_ajv) { - _ajv.addKeyword('range', { type: 'number', macro: macroRange }); - _ajv.addKeyword('exclusiveRange', { metaSchema: {type: 'boolean'} }); - _ajv.addKeyword('myContains', { type: 'array', macro: macroContains }); + _ajv.addKeyword("range", {type: "number", macro: macroRange}) + _ajv.addKeyword("exclusiveRange", {metaSchema: {type: "boolean"}}) + _ajv.addKeyword("myContains", {type: "array", macro: macroContains}) var schema = { - "myContains": { - "type": "number", - "range": [4,7], - "exclusiveRange": true - } - }; + myContains: { + type: "number", + range: [4, 7], + exclusiveRange: true, + }, + } - var validate = _ajv.compile(schema); + var validate = _ajv.compile(schema) - shouldBeInvalid(validate, [1,2,3], 2); - shouldBeInvalid(validate, [2,3,4], 2); - shouldBeValid(validate, [3,4,5]); // only 5 is in range - shouldBeValid(validate, [6,7,8]); // only 6 is in range - shouldBeInvalid(validate, [7,8,9], 2); - shouldBeInvalid(validate, [8,9,10], 2); + shouldBeInvalid(validate, [1, 2, 3], 2) + shouldBeInvalid(validate, [2, 3, 4], 2) + shouldBeValid(validate, [3, 4, 5]) // only 5 is in range + shouldBeValid(validate, [6, 7, 8]) // only 6 is in range + shouldBeInvalid(validate, [7, 8, 9], 2) + shouldBeInvalid(validate, [8, 9, 10], 2) function macroContains(_schema) { - return { "not": { "items": { "not": _schema } } }; + return {not: {items: {not: _schema}}} } - }); - }); + }) + }) - it('should throw exception if macro expansion is an invalid schema', function() { - ajv.addKeyword('invalid', { macro: macroInvalid }); - var schema = { "invalid": true }; + it("should throw exception if macro expansion is an invalid schema", function () { + ajv.addKeyword("invalid", {macro: macroInvalid}) + var schema = {invalid: true} - should.throw(function() { - ajv.compile(schema); - }); + should.throw(function () { + ajv.compile(schema) + }) function macroInvalid(/* schema */) { - return { "type": "invalid" }; + return {type: "invalid"} } - }); + }) function macroEven(schema) { - if (schema === true) return { "multipleOf": 2 }; - if (schema === false) return { "not": { "multipleOf": 2 } }; - throw new Error('Schema for "even" keyword should be boolean'); + if (schema === true) return {multipleOf: 2} + if (schema === false) return {not: {multipleOf: 2}} + throw new Error('Schema for "even" keyword should be boolean') } - function macroConstant(schema/*, parentSchema */) { - return { "enum": [schema] }; + function macroConstant(schema /*, parentSchema */) { + return {enum: [schema]} } function macroRange(schema, parentSchema) { - validateRangeSchema(schema, parentSchema); - var exclusive = !!parentSchema.exclusiveRange; + validateRangeSchema(schema, parentSchema) + var exclusive = !!parentSchema.exclusiveRange return exclusive - ? { exclusiveMinimum: schema[0], exclusiveMaximum: schema[1] } - : { minimum: schema[0], maximum: schema[1] }; + ? {exclusiveMinimum: schema[0], exclusiveMaximum: schema[1]} + : {minimum: schema[0], maximum: schema[1]} } - }); - + }) - describe('inline rules', function() { - it('should add and validate rule with "inline" code keyword', function() { - testEvenKeyword({ type: 'number', inline: inlineEven }); - }); + describe("inline rules", function () { + it('should add and validate rule with "inline" code keyword', function () { + testEvenKeyword({type: "number", inline: inlineEven}) + }) - it('should pass parent schema to "inline" keyword', function() { - testRangeKeyword({ type: 'number', inline: inlineRange, statements: true }); - }); + it('should pass parent schema to "inline" keyword', function () { + testRangeKeyword({type: "number", inline: inlineRange, statements: true}) + }) - it('should define "inline" keyword as template', function() { - var inlineRangeTemplate = customRules.range; + it('should define "inline" keyword as template', function () { + var inlineRangeTemplate = customRules.range testRangeKeyword({ - type: 'number', + type: "number", inline: inlineRangeTemplate, - statements: true - }); - }); + statements: true, + }) + }) - it('should define "inline" keyword without errors', function() { - var inlineRangeTemplate = customRules.range; + it('should define "inline" keyword without errors', function () { + var inlineRangeTemplate = customRules.range testRangeKeyword({ - type: 'number', + type: "number", inline: inlineRangeTemplate, statements: true, - errors: false - }); - }); + errors: false, + }) + }) - it('should allow defining optional errors', function() { - var inlineRangeTemplate = customRules.rangeWithErrors; + it("should allow defining optional errors", function () { + var inlineRangeTemplate = customRules.rangeWithErrors - testRangeKeyword({ - type: 'number', - inline: inlineRangeTemplate, - statements: true - }, true); - }); - - it('should allow defining required errors', function() { - var inlineRangeTemplate = customRules.rangeWithErrors; + testRangeKeyword( + { + type: "number", + inline: inlineRangeTemplate, + statements: true, + }, + true + ) + }) - testRangeKeyword({ - type: 'number', - inline: inlineRangeTemplate, - statements: true, - errors: true - }, true); - }); + it("should allow defining required errors", function () { + var inlineRangeTemplate = customRules.rangeWithErrors + testRangeKeyword( + { + type: "number", + inline: inlineRangeTemplate, + statements: true, + errors: true, + }, + true + ) + }) function inlineEven(it, keyword, schema) { - var op = schema ? '===' : '!=='; - return 'data' + (it.dataLevel || '') + ' % 2 ' + op + ' 0'; + var op = schema ? "===" : "!==" + return "data" + (it.dataLevel || "") + " % 2 " + op + " 0" } function inlineRange(it, keyword, schema, parentSchema) { - var min = schema[0] - , max = schema[1] - , data = 'data' + (it.dataLevel || '') - , gt = parentSchema.exclusiveRange ? ' > ' : ' >= ' - , lt = parentSchema.exclusiveRange ? ' < ' : ' <= '; - return 'var valid' + it.level + ' = ' + data + gt + min + ' && ' + data + lt + max + ';'; + var min = schema[0], + max = schema[1], + data = "data" + (it.dataLevel || ""), + gt = parentSchema.exclusiveRange ? " > " : " >= ", + lt = parentSchema.exclusiveRange ? " < " : " <= " + return ( + "var valid" + + it.level + + " = " + + data + + gt + + min + + " && " + + data + + lt + + max + + ";" + ) } - }); - + }) - describe('$data reference support with custom keywords (with $data option)', function() { - beforeEach(function() { - instances = getAjvInstances({ - allErrors: true, - verbose: true, - inlineRefs: false - }, { $data: true }); - ajv = instances[0]; - }); + describe("$data reference support with custom keywords (with $data option)", function () { + beforeEach(function () { + instances = getAjvInstances( + { + allErrors: true, + verbose: true, + inlineRefs: false, + }, + {$data: true} + ) + ajv = instances[0] + }) - it('should validate "interpreted" rule', function() { + it('should validate "interpreted" rule', function () { testEvenKeyword$data({ - type: 'number', + type: "number", $data: true, - validate: validateEven - }); + validate: validateEven, + }) function validateEven(schema, data) { - if (typeof schema != 'boolean') return false; - return data % 2 ? !schema : schema; + if (typeof schema != "boolean") return false + return data % 2 ? !schema : schema } - }); + }) - it('should validate rule with "compile" and "validate" funcs', function() { - var compileCalled; + it('should validate rule with "compile" and "validate" funcs', function () { + var compileCalled testEvenKeyword$data({ - type: 'number', + type: "number", $data: true, compile: compileEven, - validate: validateEven - }); - compileCalled .should.equal(true); + validate: validateEven, + }) + compileCalled.should.equal(true) function validateEven(schema, data) { - if (typeof schema != 'boolean') return false; - return data % 2 ? !schema : schema; + if (typeof schema != "boolean") return false + return data % 2 ? !schema : schema } function compileEven(schema) { - compileCalled = true; - if (typeof schema != 'boolean') throw new Error('The value of "even" keyword must be boolean'); - return schema ? isEven : isOdd; + compileCalled = true + if (typeof schema != "boolean") + throw new Error('The value of "even" keyword must be boolean') + return schema ? isEven : isOdd } - function isEven(data) { return data % 2 === 0; } - function isOdd(data) { return data % 2 !== 0; } - }); + function isEven(data) { + return data % 2 === 0 + } + function isOdd(data) { + return data % 2 !== 0 + } + }) - it('should validate with "compile" and "validate" funcs with meta-schema', function() { - var compileCalled; + it('should validate with "compile" and "validate" funcs with meta-schema', function () { + var compileCalled testEvenKeyword$data({ - type: 'number', + type: "number", $data: true, compile: compileEven, validate: validateEven, - metaSchema: { "type": "boolean" } - }); - compileCalled .should.equal(true); - shouldBeInvalidSchema({ "x-even-$data": "false" }); + metaSchema: {type: "boolean"}, + }) + compileCalled.should.equal(true) + shouldBeInvalidSchema({"x-even-$data": "false"}) function validateEven(schema, data) { - return data % 2 ? !schema : schema; + return data % 2 ? !schema : schema } function compileEven(schema) { - compileCalled = true; - return schema ? isEven : isOdd; + compileCalled = true + return schema ? isEven : isOdd } - function isEven(data) { return data % 2 === 0; } - function isOdd(data) { return data % 2 !== 0; } - }); + function isEven(data) { + return data % 2 === 0 + } + function isOdd(data) { + return data % 2 !== 0 + } + }) - it('should validate rule with "macro" and "validate" funcs', function() { - var macroCalled; - testEvenKeyword$data({ - type: 'number', - $data: true, - macro: macroEven, - validate: validateEven - }, 2); - macroCalled .should.equal(true); + it('should validate rule with "macro" and "validate" funcs', function () { + var macroCalled + testEvenKeyword$data( + { + type: "number", + $data: true, + macro: macroEven, + validate: validateEven, + }, + 2 + ) + macroCalled.should.equal(true) function validateEven(schema, data) { - if (typeof schema != 'boolean') return false; - return data % 2 ? !schema : schema; + if (typeof schema != "boolean") return false + return data % 2 ? !schema : schema } function macroEven(schema) { - macroCalled = true; - if (schema === true) return { "multipleOf": 2 }; - if (schema === false) return { "not": { "multipleOf": 2 } }; - throw new Error('Schema for "even" keyword should be boolean'); + macroCalled = true + if (schema === true) return {multipleOf: 2} + if (schema === false) return {not: {multipleOf: 2}} + throw new Error('Schema for "even" keyword should be boolean') } - }); + }) - it('should validate with "macro" and "validate" funcs with meta-schema', function() { - var macroCalled; - testEvenKeyword$data({ - type: 'number', - $data: true, - macro: macroEven, - validate: validateEven, - metaSchema: { "type": "boolean" } - }, 2); - macroCalled .should.equal(true); - shouldBeInvalidSchema({ "x-even-$data": "false" }); + it('should validate with "macro" and "validate" funcs with meta-schema', function () { + var macroCalled + testEvenKeyword$data( + { + type: "number", + $data: true, + macro: macroEven, + validate: validateEven, + metaSchema: {type: "boolean"}, + }, + 2 + ) + macroCalled.should.equal(true) + shouldBeInvalidSchema({"x-even-$data": "false"}) function validateEven(schema, data) { - return data % 2 ? !schema : schema; + return data % 2 ? !schema : schema } function macroEven(schema) { - macroCalled = true; - if (schema === true) return { "multipleOf": 2 }; - if (schema === false) return { "not": { "multipleOf": 2 } }; + macroCalled = true + if (schema === true) return {multipleOf: 2} + if (schema === false) return {not: {multipleOf: 2}} } - }); + }) - it('should validate rule with "inline" and "validate" funcs', function() { - var inlineCalled; + it('should validate rule with "inline" and "validate" funcs', function () { + var inlineCalled testEvenKeyword$data({ - type: 'number', + type: "number", $data: true, inline: inlineEven, - validate: validateEven - }); - inlineCalled .should.equal(true); + validate: validateEven, + }) + inlineCalled.should.equal(true) function validateEven(schema, data) { - if (typeof schema != 'boolean') return false; - return data % 2 ? !schema : schema; + if (typeof schema != "boolean") return false + return data % 2 ? !schema : schema } function inlineEven(it, keyword, schema) { - inlineCalled = true; - var op = schema ? '===' : '!=='; - return 'data' + (it.dataLevel || '') + ' % 2 ' + op + ' 0'; + inlineCalled = true + var op = schema ? "===" : "!==" + return "data" + (it.dataLevel || "") + " % 2 " + op + " 0" } - }); + }) - it('should validate with "inline" and "validate" funcs with meta-schema', function() { - var inlineCalled; + it('should validate with "inline" and "validate" funcs with meta-schema', function () { + var inlineCalled testEvenKeyword$data({ - type: 'number', + type: "number", $data: true, inline: inlineEven, validate: validateEven, - metaSchema: { "type": "boolean" } - }); - inlineCalled .should.equal(true); - shouldBeInvalidSchema({ "x-even-$data": "false" }); + metaSchema: {type: "boolean"}, + }) + inlineCalled.should.equal(true) + shouldBeInvalidSchema({"x-even-$data": "false"}) function validateEven(schema, data) { - return data % 2 ? !schema : schema; + return data % 2 ? !schema : schema } function inlineEven(it, keyword, schema) { - inlineCalled = true; - var op = schema ? '===' : '!=='; - return 'data' + (it.dataLevel || '') + ' % 2 ' + op + ' 0'; + inlineCalled = true + var op = schema ? "===" : "!==" + return "data" + (it.dataLevel || "") + " % 2 " + op + " 0" } - }); + }) - it('should fail if keyword definition has "$data" but no "validate"', function() { - should.throw(function() { - ajv.addKeyword('even', { - type: 'number', + it('should fail if keyword definition has "$data" but no "validate"', function () { + should.throw(function () { + ajv.addKeyword("even", { + type: "number", $data: true, - macro: function() { return {}; } - }); - }); - }); - }); - + macro: function () { + return {} + }, + }) + }) + }) + }) function testEvenKeyword(definition, numErrors) { instances.forEach(function (_ajv) { - _ajv.addKeyword('x-even', definition); - var schema = { "x-even": true }; - var validate = _ajv.compile(schema); - - shouldBeValid(validate, 2); - shouldBeValid(validate, 'abc'); - shouldBeInvalid(validate, 2.5, numErrors); - shouldBeInvalid(validate, 3, numErrors); - }); + _ajv.addKeyword("x-even", definition) + var schema = {"x-even": true} + var validate = _ajv.compile(schema) + + shouldBeValid(validate, 2) + shouldBeValid(validate, "abc") + shouldBeInvalid(validate, 2.5, numErrors) + shouldBeInvalid(validate, 3, numErrors) + }) } function testEvenKeyword$data(definition, numErrors) { instances.forEach(function (_ajv) { - _ajv.addKeyword('x-even-$data', definition); + _ajv.addKeyword("x-even-$data", definition) - var schema = { "x-even-$data": true }; - var validate = _ajv.compile(schema); + var schema = {"x-even-$data": true} + var validate = _ajv.compile(schema) - shouldBeValid(validate, 2); - shouldBeValid(validate, 'abc'); - shouldBeInvalid(validate, 2.5, numErrors); - shouldBeInvalid(validate, 3, numErrors); + shouldBeValid(validate, 2) + shouldBeValid(validate, "abc") + shouldBeInvalid(validate, 2.5, numErrors) + shouldBeInvalid(validate, 3, numErrors) schema = { - "properties": { - "data": { "x-even-$data": { "$data": "1/evenValue" } }, - "evenValue": {} - } - }; - validate = _ajv.compile(schema); + properties: { + data: {"x-even-$data": {$data: "1/evenValue"}}, + evenValue: {}, + }, + } + validate = _ajv.compile(schema) - shouldBeValid(validate, { data: 2, evenValue: true }); - shouldBeInvalid(validate, { data: 2, evenValue: false }); - shouldBeValid(validate, { data: 'abc', evenValue: true }); - shouldBeValid(validate, { data: 'abc', evenValue: false }); - shouldBeInvalid(validate, { data: 2.5, evenValue: true }); - shouldBeValid(validate, { data: 2.5, evenValue: false }); - shouldBeInvalid(validate, { data: 3, evenValue: true }); - shouldBeValid(validate, { data: 3, evenValue: false }); + shouldBeValid(validate, {data: 2, evenValue: true}) + shouldBeInvalid(validate, {data: 2, evenValue: false}) + shouldBeValid(validate, {data: "abc", evenValue: true}) + shouldBeValid(validate, {data: "abc", evenValue: false}) + shouldBeInvalid(validate, {data: 2.5, evenValue: true}) + shouldBeValid(validate, {data: 2.5, evenValue: false}) + shouldBeInvalid(validate, {data: 3, evenValue: true}) + shouldBeValid(validate, {data: 3, evenValue: false}) - shouldBeInvalid(validate, { data: 2, evenValue: "true" }); + shouldBeInvalid(validate, {data: 2, evenValue: "true"}) // valid if the value of x-even-$data keyword is undefined - shouldBeValid(validate, { data: 2 }); - shouldBeValid(validate, { data: 3 }); - }); + shouldBeValid(validate, {data: 2}) + shouldBeValid(validate, {data: 3}) + }) } function testConstantKeyword(definition, numErrors) { instances.forEach(function (_ajv) { - _ajv.addKeyword('myConstant', definition); + _ajv.addKeyword("myConstant", definition) - var schema = { "myConstant": "abc" }; - var validate = _ajv.compile(schema); + var schema = {myConstant: "abc"} + var validate = _ajv.compile(schema) - shouldBeValid(validate, 'abc'); - shouldBeInvalid(validate, 2, numErrors); - shouldBeInvalid(validate, {}, numErrors); - }); + shouldBeValid(validate, "abc") + shouldBeInvalid(validate, 2, numErrors) + shouldBeInvalid(validate, {}, numErrors) + }) } function testMultipleConstantKeyword(definition, numErrors) { instances.forEach(function (_ajv) { - _ajv.addKeyword('x-constant', definition); + _ajv.addKeyword("x-constant", definition) var schema = { - "properties": { - "a": { "x-constant": 1 }, - "b": { "x-constant": 1 } + properties: { + a: {"x-constant": 1}, + b: {"x-constant": 1}, }, - "additionalProperties": { "x-constant": { "foo": "bar" } }, - "items": { "x-constant": { "foo": "bar" } } - }; - var validate = _ajv.compile(schema); + additionalProperties: {"x-constant": {foo: "bar"}}, + items: {"x-constant": {foo: "bar"}}, + } + var validate = _ajv.compile(schema) - shouldBeValid(validate, {a:1, b:1}); - shouldBeInvalid(validate, {a:2, b:1}, numErrors); + shouldBeValid(validate, {a: 1, b: 1}) + shouldBeInvalid(validate, {a: 2, b: 1}, numErrors) - shouldBeValid(validate, {a:1, c: {foo: 'bar'}}); - shouldBeInvalid(validate, {a:1, c: {foo: 'baz'}}, numErrors); + shouldBeValid(validate, {a: 1, c: {foo: "bar"}}) + shouldBeInvalid(validate, {a: 1, c: {foo: "baz"}}, numErrors) - shouldBeValid(validate, [{foo: 'bar'}]); - shouldBeValid(validate, [{foo: 'bar'}, {foo: 'bar'}]); + shouldBeValid(validate, [{foo: "bar"}]) + shouldBeValid(validate, [{foo: "bar"}, {foo: "bar"}]) - shouldBeInvalid(validate, [1], numErrors); - }); + shouldBeInvalid(validate, [1], numErrors) + }) } function testRangeKeyword(definition, customErrors, numErrors) { instances.forEach(function (_ajv) { - _ajv.addKeyword('x-range', definition); - _ajv.addKeyword('exclusiveRange', {metaSchema: {type: 'boolean'}}); + _ajv.addKeyword("x-range", definition) + _ajv.addKeyword("exclusiveRange", {metaSchema: {type: "boolean"}}) - var schema = { "x-range": [2, 4] }; - var validate = _ajv.compile(schema); + var schema = {"x-range": [2, 4]} + var validate = _ajv.compile(schema) - shouldBeValid(validate, 2); - shouldBeValid(validate, 3); - shouldBeValid(validate, 4); - shouldBeValid(validate, 'abc'); + shouldBeValid(validate, 2) + shouldBeValid(validate, 3) + shouldBeValid(validate, 4) + shouldBeValid(validate, "abc") - shouldBeInvalid(validate, 1.99, numErrors); - if (customErrors) shouldBeRangeError(validate.errors[0], '', '#/x-range', '>=', 2); - shouldBeInvalid(validate, 4.01, numErrors); - if (customErrors) shouldBeRangeError(validate.errors[0], '', '#/x-range','<=', 4); + shouldBeInvalid(validate, 1.99, numErrors) + if (customErrors) + shouldBeRangeError(validate.errors[0], "", "#/x-range", ">=", 2) + shouldBeInvalid(validate, 4.01, numErrors) + if (customErrors) + shouldBeRangeError(validate.errors[0], "", "#/x-range", "<=", 4) schema = { - "properties": { - "foo": { + properties: { + foo: { "x-range": [2, 4], - "exclusiveRange": true - } - } - }; - validate = _ajv.compile(schema); - - shouldBeValid(validate, { foo: 2.01 }); - shouldBeValid(validate, { foo: 3 }); - shouldBeValid(validate, { foo: 3.99 }); - - shouldBeInvalid(validate, { foo: 2 }, numErrors); - if (customErrors) shouldBeRangeError(validate.errors[0], '.foo', '#/properties/foo/x-range', '>', 2, true); - shouldBeInvalid(validate, { foo: 4 }, numErrors); - if (customErrors) shouldBeRangeError(validate.errors[0], '.foo', '#/properties/foo/x-range', '<', 4, true); - }); + exclusiveRange: true, + }, + }, + } + validate = _ajv.compile(schema) + + shouldBeValid(validate, {foo: 2.01}) + shouldBeValid(validate, {foo: 3}) + shouldBeValid(validate, {foo: 3.99}) + + shouldBeInvalid(validate, {foo: 2}, numErrors) + if (customErrors) { + shouldBeRangeError( + validate.errors[0], + ".foo", + "#/properties/foo/x-range", + ">", + 2, + true + ) + } + shouldBeInvalid(validate, {foo: 4}, numErrors) + if (customErrors) { + shouldBeRangeError( + validate.errors[0], + ".foo", + "#/properties/foo/x-range", + "<", + 4, + true + ) + } + }) } function testMultipleRangeKeyword(definition, numErrors) { instances.forEach(function (_ajv) { - _ajv.addKeyword('x-range', definition); - _ajv.addKeyword('exclusiveRange', {metaSchema: {type: 'boolean'}}); + _ajv.addKeyword("x-range", definition) + _ajv.addKeyword("exclusiveRange", {metaSchema: {type: "boolean"}}) var schema = { - "properties": { - "a": { "x-range": [2, 4], "exclusiveRange": true }, - "b": { "x-range": [2, 4], "exclusiveRange": false } + properties: { + a: {"x-range": [2, 4], exclusiveRange: true}, + b: {"x-range": [2, 4], exclusiveRange: false}, }, - "additionalProperties": { "x-range": [5, 7] }, - "items": { "x-range": [5, 7] } - }; - var validate = _ajv.compile(schema); + additionalProperties: {"x-range": [5, 7]}, + items: {"x-range": [5, 7]}, + } + var validate = _ajv.compile(schema) - shouldBeValid(validate, {a:3.99, b:4}); - shouldBeInvalid(validate, {a:4, b:4}, numErrors); + shouldBeValid(validate, {a: 3.99, b: 4}) + shouldBeInvalid(validate, {a: 4, b: 4}, numErrors) - shouldBeValid(validate, {a:2.01, c: 7}); - shouldBeInvalid(validate, {a:2.01, c: 7.01}, numErrors); + shouldBeValid(validate, {a: 2.01, c: 7}) + shouldBeInvalid(validate, {a: 2.01, c: 7.01}, numErrors) - shouldBeValid(validate, [5, 6, 7]); - shouldBeInvalid(validate, [7.01], numErrors); - }); + shouldBeValid(validate, [5, 6, 7]) + shouldBeInvalid(validate, [7.01], numErrors) + }) } - function shouldBeRangeError(error, dataPath, schemaPath, comparison, limit, exclusive) { - delete error.schema; - delete error.data; - error .should.eql({ - keyword: 'x-range', + function shouldBeRangeError( + error, + dataPath, + schemaPath, + comparison, + limit, + exclusive + ) { + delete error.schema + delete error.data + error.should.eql({ + keyword: "x-range", dataPath: dataPath, schemaPath: schemaPath, - message: 'should be ' + comparison + ' ' + limit, + message: "should be " + comparison + " " + limit, params: { comparison: comparison, limit: limit, - exclusive: !!exclusive - } - }); + exclusive: !!exclusive, + }, + }) } function validateRangeSchema(schema, parentSchema) { - var schemaValid = Array.isArray(schema) && schema.length == 2 - && typeof schema[0] == 'number' - && typeof schema[1] == 'number'; - if (!schemaValid) throw new Error('Invalid schema for range keyword, should be array of 2 numbers'); - - var exclusiveRangeSchemaValid = parentSchema.exclusiveRange === undefined - || typeof parentSchema.exclusiveRange == 'boolean'; - if (!exclusiveRangeSchemaValid) throw new Error('Invalid schema for exclusiveRange keyword, should be bolean'); + var schemaValid = + Array.isArray(schema) && + schema.length == 2 && + typeof schema[0] == "number" && + typeof schema[1] == "number" + if (!schemaValid) { + throw new Error( + "Invalid schema for range keyword, should be array of 2 numbers" + ) + } + + var exclusiveRangeSchemaValid = + parentSchema.exclusiveRange === undefined || + typeof parentSchema.exclusiveRange == "boolean" + if (!exclusiveRangeSchemaValid) { + throw new Error( + "Invalid schema for exclusiveRange keyword, should be boolean" + ) + } } function shouldBeValid(validate, data) { - validate(data) .should.equal(true); - should.not.exist(validate.errors); + validate(data).should.equal(true) + should.not.exist(validate.errors) } function shouldBeInvalid(validate, data, numErrors) { - validate(data) .should.equal(false); - validate.errors .should.have.length(numErrors || 1); + validate(data).should.equal(false) + validate.errors.should.have.length(numErrors || 1) } function shouldBeInvalidSchema(schema) { instances.forEach(function (_ajv) { - should.throw(function() { - _ajv.compile(schema); - }); - }); + should.throw(function () { + _ajv.compile(schema) + }) + }) } - describe('addKeyword method', function() { - var TEST_TYPES = [ undefined, 'number', 'string', 'boolean', ['number', 'string']]; + describe("addKeyword method", function () { + var TEST_TYPES = [ + undefined, + "number", + "string", + "boolean", + ["number", "string"], + ] - it('should throw if defined keyword is passed', function() { - testThrow(['minimum', 'maximum', 'multipleOf', 'minLength', 'maxLength']); - testThrowDuplicate('custom'); + it("should throw if defined keyword is passed", function () { + testThrow(["minimum", "maximum", "multipleOf", "minLength", "maxLength"]) + testThrowDuplicate("custom") function testThrow(keywords) { TEST_TYPES.forEach(function (dataType, index) { - should.throw(function(){ - addKeyword(keywords[index], dataType); - }); - }); + should.throw(function () { + addKeyword(keywords[index], dataType) + }) + }) } function testThrowDuplicate(keywordPrefix) { - var index = 0; + var index = 0 TEST_TYPES.forEach(function (dataType1) { TEST_TYPES.forEach(function (dataType2) { - var keyword = keywordPrefix + (index++); - addKeyword(keyword, dataType1); - should.throw(function() { - addKeyword(keyword, dataType2); - }); - }); - }); + var keyword = keywordPrefix + index++ + addKeyword(keyword, dataType1) + should.throw(function () { + addKeyword(keyword, dataType2) + }) + }) + }) } - }); - - it('should throw if keyword is not a valid name', function() { - should.not.throw(function() { - ajv.addKeyword('mykeyword', { - validate: function() { return true; } - }); - }); - - should.not.throw(function() { - ajv.addKeyword('hyphens-are-valid', { - validate: function() { return true; } - }); - }); - - should.throw(function() { - ajv.addKeyword('3-start-with-number-not-valid`', { - validate: function() { return true; } - }); - }); - - should.throw(function() { - ajv.addKeyword('-start-with-hyphen-not-valid`', { - validate: function() { return true; } - }); - }); - - should.throw(function() { - ajv.addKeyword('spaces not valid`', { - validate: function() { return true; } - }); - }); - }); - - it('should return instance of itself', function() { - var res = ajv.addKeyword('any', { - validate: function() { return true; } - }); - res.should.equal(ajv); - }); - - it('should throw if unknown type is passed', function() { - should.throw(function() { - addKeyword('custom1', 'wrongtype'); - }); - - should.throw(function() { - addKeyword('custom2', ['number', 'wrongtype']); - }); - - should.throw(function() { - addKeyword('custom3', ['number', undefined]); - }); - }); + }) + + it("should throw if keyword is not a valid name", function () { + should.not.throw(function () { + ajv.addKeyword("mykeyword", { + validate: function () { + return true + }, + }) + }) + + should.not.throw(function () { + ajv.addKeyword("hyphens-are-valid", { + validate: function () { + return true + }, + }) + }) + + should.throw(function () { + ajv.addKeyword("3-start-with-number-not-valid`", { + validate: function () { + return true + }, + }) + }) + + should.throw(function () { + ajv.addKeyword("-start-with-hyphen-not-valid`", { + validate: function () { + return true + }, + }) + }) + + should.throw(function () { + ajv.addKeyword("spaces not valid`", { + validate: function () { + return true + }, + }) + }) + }) + + it("should return instance of itself", function () { + var res = ajv.addKeyword("any", { + validate: function () { + return true + }, + }) + res.should.equal(ajv) + }) + + it("should throw if unknown type is passed", function () { + should.throw(function () { + addKeyword("custom1", "wrongtype") + }) + + should.throw(function () { + addKeyword("custom2", ["number", "wrongtype"]) + }) + + should.throw(function () { + addKeyword("custom3", ["number", undefined]) + }) + }) function addKeyword(keyword, dataType) { ajv.addKeyword(keyword, { type: dataType, - validate: function() {} - }); + validate: function () {}, + }) } - }); + }) + describe("getKeyword", function () { + it("should return boolean for pre-defined and unknown keywords", function () { + ajv.getKeyword("type").should.equal(true) + ajv.getKeyword("properties").should.equal(true) + ajv.getKeyword("additionalProperties").should.equal(true) + ajv.getKeyword("unknown").should.equal(false) + }) - describe('getKeyword', function() { - it('should return boolean for pre-defined and unknown keywords', function() { - ajv.getKeyword('type') .should.equal(true); - ajv.getKeyword('properties') .should.equal(true); - ajv.getKeyword('additionalProperties') .should.equal(true); - ajv.getKeyword('unknown') .should.equal(false); - }); - - it('should return keyword definition for custom keywords', function() { + it("should return keyword definition for custom keywords", function () { var definition = { - validate: function() { return true; } - }; - - ajv.addKeyword('mykeyword', definition); - ajv.getKeyword('mykeyword') .should.equal(definition); - }); - }); - - - describe('removeKeyword', function() { - it('should remove and allow redefining custom keyword', function() { - ajv.addKeyword('positive', { - type: 'number', - validate: function (schema, data) { return data > 0; } - }); - - var schema = { positive: true }; - - var validate = ajv.compile(schema); - validate(0) .should.equal(false); - validate(1) .should.equal(true); - - should.throw(function() { - ajv.addKeyword('positive', { - type: 'number', - validate: function(sch, data) { return data >= 0; } - }); - }); - - ajv.removeKeyword('positive'); - ajv.removeSchema(schema); - ajv.addKeyword('positive', { - type: 'number', - validate: function (sch, data) { return data >= 0; } - }); - - validate = ajv.compile(schema); - validate(-1) .should.equal(false); - validate(0) .should.equal(true); - validate(1) .should.equal(true); - }); - - it('should remove and allow redefining standard keyword', function() { - var schema = { minimum: 1 }; - var validate = ajv.compile(schema); - validate(0) .should.equal(false); - validate(1) .should.equal(true); - validate(2) .should.equal(true); - - ajv.removeKeyword('minimum'); - ajv.removeSchema(schema); - - validate = ajv.compile(schema); - validate(0) .should.equal(true); - validate(1) .should.equal(true); - validate(2) .should.equal(true); - - ajv.addKeyword('minimum', { - type: 'number', + validate: function () { + return true + }, + } + + ajv.addKeyword("mykeyword", definition) + ajv.getKeyword("mykeyword").should.equal(definition) + }) + }) + + describe("removeKeyword", function () { + it("should remove and allow redefining custom keyword", function () { + ajv.addKeyword("positive", { + type: "number", + validate: function (schema, data) { + return data > 0 + }, + }) + + var schema = {positive: true} + + var validate = ajv.compile(schema) + validate(0).should.equal(false) + validate(1).should.equal(true) + + should.throw(function () { + ajv.addKeyword("positive", { + type: "number", + validate: function (sch, data) { + return data >= 0 + }, + }) + }) + + ajv.removeKeyword("positive") + ajv.removeSchema(schema) + ajv.addKeyword("positive", { + type: "number", + validate: function (sch, data) { + return data >= 0 + }, + }) + + validate = ajv.compile(schema) + validate(-1).should.equal(false) + validate(0).should.equal(true) + validate(1).should.equal(true) + }) + + it("should remove and allow redefining standard keyword", function () { + var schema = {minimum: 1} + var validate = ajv.compile(schema) + validate(0).should.equal(false) + validate(1).should.equal(true) + validate(2).should.equal(true) + + ajv.removeKeyword("minimum") + ajv.removeSchema(schema) + + validate = ajv.compile(schema) + validate(0).should.equal(true) + validate(1).should.equal(true) + validate(2).should.equal(true) + + ajv.addKeyword("minimum", { + type: "number", // make minimum exclusive - validate: function (sch, data) { return data > sch; } - }); - ajv.removeSchema(schema); + validate: function (sch, data) { + return data > sch + }, + }) + ajv.removeSchema(schema) - validate = ajv.compile(schema); - validate(0) .should.equal(false); - validate(1) .should.equal(false); - validate(2) .should.equal(true); - }); + validate = ajv.compile(schema) + validate(0).should.equal(false) + validate(1).should.equal(false) + validate(2).should.equal(true) + }) - it('should return instance of itself', function() { + it("should return instance of itself", function () { var res = ajv - .addKeyword('any', { - validate: function() { return true; } + .addKeyword("any", { + validate: function () { + return true + }, }) - .removeKeyword('any'); - res.should.equal(ajv); - }); - }); - + .removeKeyword("any") + res.should.equal(ajv) + }) + }) - describe('custom keywords mutating data', function() { - it('should NOT update data without option modifying', function() { - should.throw(function() { - testModifying(false); - }); - }); + describe("custom keywords mutating data", function () { + it("should NOT update data without option modifying", function () { + should.throw(function () { + testModifying(false) + }) + }) - it('should update data with option modifying', function() { - testModifying(true); - }); + it("should update data with option modifying", function () { + testModifying(true) + }) function testModifying(withOption) { var collectionFormat = { csv: function (data, dataPath, parentData, parentDataProperty) { - parentData[parentDataProperty] = data.split(','); - return true; - } - }; + parentData[parentDataProperty] = data.split(",") + return true + }, + } - ajv.addKeyword('collectionFormat', { - type: 'string', + ajv.addKeyword("collectionFormat", { + type: "string", modifying: withOption, - compile: function(schema) { return collectionFormat[schema]; }, + compile: function (schema) { + return collectionFormat[schema] + }, metaSchema: { - enum: ['csv'] - } - }); + enum: ["csv"], + }, + }) var validate = ajv.compile({ - type: 'object', + type: "object", properties: { foo: { allOf: [ - { collectionFormat: 'csv' }, + {collectionFormat: "csv"}, { - type: 'array', - items: { type: 'string' }, - } - ] - } + type: "array", + items: {type: "string"}, + }, + ], + }, }, - additionalProperties: false - }); + additionalProperties: false, + }) - var obj = { foo: 'bar,baz,quux' }; + var obj = {foo: "bar,baz,quux"} - validate(obj) .should.equal(true); - obj .should.eql({ foo: ['bar', 'baz', 'quux'] }); + validate(obj).should.equal(true) + obj.should.eql({foo: ["bar", "baz", "quux"]}) } - }); - - - describe('custom keywords with predefined validation result', function() { - it('should ignore result from validation function', function() { - ajv.addKeyword('pass', { - validate: function() { return false; }, - valid: true - }); - - ajv.addKeyword('fail', { - validate: function() { return true; }, - valid: false - }); - - ajv.validate({ pass: '' }, 1) .should.equal(true); - ajv.validate({ fail: '' }, 1) .should.equal(false); - }); - - it('should throw exception if used with macro keyword', function() { - should.throw(function() { - ajv.addKeyword('pass', { - macro: function() { return {}; }, - valid: true - }); - }); - - should.throw(function() { - ajv.addKeyword('fail', { - macro: function() { return {not:{}}; }, - valid: false - }); - }); - }); - }); - - - describe('"dependencies" in keyword definition', function() { - it("should require properties in the parent schema", function() { - ajv.addKeyword('allRequired', { - macro: function(schema, parentSchema) { - return schema ? {required: Object.keys(parentSchema.properties)} : true; + }) + + describe("custom keywords with predefined validation result", function () { + it("should ignore result from validation function", function () { + ajv.addKeyword("pass", { + validate: function () { + return false + }, + valid: true, + }) + + ajv.addKeyword("fail", { + validate: function () { + return true }, - metaSchema: {type: 'boolean'}, - dependencies: ['properties'] - }); + valid: false, + }) + + ajv.validate({pass: ""}, 1).should.equal(true) + ajv.validate({fail: ""}, 1).should.equal(false) + }) + + it("should throw exception if used with macro keyword", function () { + should.throw(function () { + ajv.addKeyword("pass", { + macro: function () { + return {} + }, + valid: true, + }) + }) + + should.throw(function () { + ajv.addKeyword("fail", { + macro: function () { + return {not: {}} + }, + valid: false, + }) + }) + }) + }) + + describe('"dependencies" in keyword definition', function () { + it("should require properties in the parent schema", function () { + ajv.addKeyword("allRequired", { + macro: function (schema, parentSchema) { + return schema + ? {required: Object.keys(parentSchema.properties)} + : true + }, + metaSchema: {type: "boolean"}, + dependencies: ["properties"], + }) var invalidSchema = { - allRequired: true - }; + allRequired: true, + } should.throw(function () { - ajv.compile(invalidSchema); - }); + ajv.compile(invalidSchema) + }) var schema = { properties: { - foo: true + foo: true, }, - allRequired: true - }; + allRequired: true, + } - var v = ajv.compile(schema); - v({foo: 1}) .should.equal(true); - v({}) .should.equal(false); - }); + var v = ajv.compile(schema) + v({foo: 1}).should.equal(true) + v({}).should.equal(false) + }) - it("'dependencies'should be array of valid strings", function() { - ajv.addKeyword('newKeyword1', { - metaSchema: {type: 'boolean'}, - dependencies: ['dep1'] - }); + it("'dependencies'should be array of valid strings", function () { + ajv.addKeyword("newKeyword1", { + metaSchema: {type: "boolean"}, + dependencies: ["dep1"], + }) should.throw(function () { - ajv.addKeyword('newKeyword2', { - metaSchema: {type: 'boolean'}, - dependencies: [1] - }); - }); - }); - }); -}); + ajv.addKeyword("newKeyword2", { + metaSchema: {type: "boolean"}, + dependencies: [1], + }) + }) + }) + }) +}) diff --git a/spec/custom_rules/index.js b/spec/custom_rules/index.js index afc02fb4b1..534fc1495f 100644 --- a/spec/custom_rules/index.js +++ b/spec/custom_rules/index.js @@ -1,9 +1,11 @@ -'use strict'; +"use strict" -var fs = require('fs') - , doT = require('dot'); +var fs = require("fs"), + doT = require("dot") module.exports = { - range: doT.compile(fs.readFileSync(__dirname + '/range.jst', 'utf8')), - rangeWithErrors: doT.compile(fs.readFileSync(__dirname + '/range_with_errors.jst', 'utf8')) -}; + range: doT.compile(fs.readFileSync(__dirname + "/range.jst", "utf8")), + rangeWithErrors: doT.compile( + fs.readFileSync(__dirname + "/range_with_errors.jst", "utf8") + ), +} diff --git a/spec/errors.spec.js b/spec/errors.spec.js index 6291b15ae1..b318dbe32c 100644 --- a/spec/errors.spec.js +++ b/spec/errors.spec.js @@ -1,899 +1,1223 @@ -'use strict'; +"use strict" -var Ajv = require('./ajv') - , should = require('./chai').should(); +var Ajv = require("./ajv"), + should = require("./chai").should() +describe("Validation errors", function () { + var ajv, ajvJP, fullAjv -describe('Validation errors', function () { - var ajv, ajvJP, fullAjv; - - beforeEach(function() { - createInstances(); - }); + beforeEach(function () { + createInstances() + }) function createInstances(errorDataPath) { - ajv = new Ajv({ errorDataPath: errorDataPath, loopRequired: 21 }); - ajvJP = new Ajv({ errorDataPath: errorDataPath, jsonPointers: true, loopRequired: 21 }); - fullAjv = new Ajv({ errorDataPath: errorDataPath, allErrors: true, verbose: true, jsonPointers: true, loopRequired: 21 }); + ajv = new Ajv({errorDataPath: errorDataPath, loopRequired: 21}) + ajvJP = new Ajv({ + errorDataPath: errorDataPath, + jsonPointers: true, + loopRequired: 21, + }) + fullAjv = new Ajv({ + errorDataPath: errorDataPath, + allErrors: true, + verbose: true, + jsonPointers: true, + loopRequired: 21, + }) } - it('error should include dataPath', function() { + it("error should include dataPath", function () { var schema = { properties: { - foo: { type: 'number' } - } - }; + foo: {type: "number"}, + }, + } - testSchema1(schema); - }); + testSchema1(schema) + }) - it('"refs" error should include dataPath', function() { + it('"refs" error should include dataPath', function () { var schema = { definitions: { - num: { type: 'number' } + num: {type: "number"}, }, properties: { - foo: { $ref: '#/definitions/num' } - } - }; - - testSchema1(schema, '#/definitions/num'); - }); + foo: {$ref: "#/definitions/num"}, + }, + } + testSchema1(schema, "#/definitions/num") + }) - describe('"additionalProperties" errors', function() { - it('should include property in dataPath with option errorDataPath="property"', function() { - createInstances('property'); - testAdditional('property'); - }); + describe('"additionalProperties" errors', function () { + it('should include property in dataPath with option errorDataPath="property"', function () { + createInstances("property") + testAdditional("property") + }) - it('should NOT include property in dataPath WITHOUT option errorDataPath', function() { - testAdditional(); - }); + it("should NOT include property in dataPath WITHOUT option errorDataPath", function () { + testAdditional() + }) function testAdditional(errorDataPath) { var schema = { properties: { foo: {}, - bar: {} + bar: {}, }, - additionalProperties: false - }; - - var data = { foo: 1, bar: 2 } - , invalidData = { foo: 1, bar: 2, baz: 3, quux: 4 }; - - var path = pathFunc(errorDataPath); - var msg = additionalFunc(errorDataPath); - - var validate = ajv.compile(schema); - shouldBeValid(validate, data); - shouldBeInvalid(validate, invalidData); - shouldBeError(validate.errors[0], 'additionalProperties', '#/additionalProperties', path("['baz']"), msg, { additionalProperty: 'baz' }); - - var validateJP = ajvJP.compile(schema); - shouldBeValid(validateJP, data); - shouldBeInvalid(validateJP, invalidData); - shouldBeError(validateJP.errors[0], 'additionalProperties', '#/additionalProperties', path("/baz"), msg, { additionalProperty: 'baz' }); - - var fullValidate = fullAjv.compile(schema); - shouldBeValid(fullValidate, data); - shouldBeInvalid(fullValidate, invalidData, 2); - shouldBeError(fullValidate.errors[0], 'additionalProperties', '#/additionalProperties', path('/baz'), msg, { additionalProperty: 'baz' }); - shouldBeError(fullValidate.errors[1], 'additionalProperties', '#/additionalProperties', path('/quux'), msg, { additionalProperty: 'quux' }); + additionalProperties: false, + } - if (errorDataPath == 'property') { + var data = {foo: 1, bar: 2}, + invalidData = {foo: 1, bar: 2, baz: 3, quux: 4} + + var path = pathFunc(errorDataPath) + var msg = additionalFunc(errorDataPath) + + var validate = ajv.compile(schema) + shouldBeValid(validate, data) + shouldBeInvalid(validate, invalidData) + shouldBeError( + validate.errors[0], + "additionalProperties", + "#/additionalProperties", + path("['baz']"), + msg, + {additionalProperty: "baz"} + ) + + var validateJP = ajvJP.compile(schema) + shouldBeValid(validateJP, data) + shouldBeInvalid(validateJP, invalidData) + shouldBeError( + validateJP.errors[0], + "additionalProperties", + "#/additionalProperties", + path("/baz"), + msg, + {additionalProperty: "baz"} + ) + + var fullValidate = fullAjv.compile(schema) + shouldBeValid(fullValidate, data) + shouldBeInvalid(fullValidate, invalidData, 2) + shouldBeError( + fullValidate.errors[0], + "additionalProperties", + "#/additionalProperties", + path("/baz"), + msg, + {additionalProperty: "baz"} + ) + shouldBeError( + fullValidate.errors[1], + "additionalProperties", + "#/additionalProperties", + path("/quux"), + msg, + {additionalProperty: "quux"} + ) + + if (errorDataPath == "property") { fullValidate.errors - .filter(function(err) { return err.keyword == 'additionalProperties'; }) - .map(function(err) { return fullAjv._opts.jsonPointers ? err.dataPath.substr(1) : err.dataPath.slice(2,-2); }) - .forEach(function(p) { delete invalidData[p]; }); - - invalidData .should.eql({ foo: 1, bar: 2 }); + .filter(function (err) { + return err.keyword == "additionalProperties" + }) + .map(function (err) { + return fullAjv._opts.jsonPointers + ? err.dataPath.substr(1) + : err.dataPath.slice(2, -2) + }) + .forEach(function (p) { + delete invalidData[p] + }) + + invalidData.should.eql({foo: 1, bar: 2}) } } - }); - + }) - describe('errors when "additionalProperties" is schema', function() { - it('should include property in dataPath with option errorDataPath="property"', function() { - createInstances('property'); - testAdditionalIsSchema('property'); - }); + describe('errors when "additionalProperties" is schema', function () { + it('should include property in dataPath with option errorDataPath="property"', function () { + createInstances("property") + testAdditionalIsSchema("property") + }) - it('should NOT include property in dataPath WITHOUT option errorDataPath', function() { - testAdditionalIsSchema(); - }); + it("should NOT include property in dataPath WITHOUT option errorDataPath", function () { + testAdditionalIsSchema() + }) function testAdditionalIsSchema() { var schema = { properties: { - foo: { type: 'integer' }, - bar: { type: 'integer' } + foo: {type: "integer"}, + bar: {type: "integer"}, }, additionalProperties: { - type: 'object', + type: "object", properties: { - quux: { type: 'string' } - } - } - }; - - var data = { foo: 1, bar: 2, baz: { quux: 'abc' } } - , invalidData = { foo: 1, bar: 2, baz: { quux: 3 }, boo: { quux: 4 } }; - - var schPath = '#/additionalProperties/properties/quux/type'; - - var validate = ajv.compile(schema); - shouldBeValid(validate, data); - shouldBeInvalid(validate, invalidData); - shouldBeError(validate.errors[0], 'type', schPath, "['baz'].quux", 'should be string', { type: 'string' }); - - var validateJP = ajvJP.compile(schema); - shouldBeValid(validateJP, data); - shouldBeInvalid(validateJP, invalidData); - shouldBeError(validateJP.errors[0], 'type', schPath, "/baz/quux", 'should be string', { type: 'string' }); + quux: {type: "string"}, + }, + }, + } - var fullValidate = fullAjv.compile(schema); - shouldBeValid(fullValidate, data); - shouldBeInvalid(fullValidate, invalidData, 2); - shouldBeError(fullValidate.errors[0], 'type', schPath, '/baz/quux', 'should be string', { type: 'string' }); - shouldBeError(fullValidate.errors[1], 'type', schPath, '/boo/quux', 'should be string', { type: 'string' }); + var data = {foo: 1, bar: 2, baz: {quux: "abc"}}, + invalidData = {foo: 1, bar: 2, baz: {quux: 3}, boo: {quux: 4}} + + var schPath = "#/additionalProperties/properties/quux/type" + + var validate = ajv.compile(schema) + shouldBeValid(validate, data) + shouldBeInvalid(validate, invalidData) + shouldBeError( + validate.errors[0], + "type", + schPath, + "['baz'].quux", + "should be string", + {type: "string"} + ) + + var validateJP = ajvJP.compile(schema) + shouldBeValid(validateJP, data) + shouldBeInvalid(validateJP, invalidData) + shouldBeError( + validateJP.errors[0], + "type", + schPath, + "/baz/quux", + "should be string", + {type: "string"} + ) + + var fullValidate = fullAjv.compile(schema) + shouldBeValid(fullValidate, data) + shouldBeInvalid(fullValidate, invalidData, 2) + shouldBeError( + fullValidate.errors[0], + "type", + schPath, + "/baz/quux", + "should be string", + {type: "string"} + ) + shouldBeError( + fullValidate.errors[1], + "type", + schPath, + "/boo/quux", + "should be string", + {type: "string"} + ) } - }); - + }) - describe('"required" errors', function() { - it('should include missing property in dataPath with option errorDataPath="property"', function() { - createInstances('property'); - testRequired('property'); - }); + describe('"required" errors', function () { + it('should include missing property in dataPath with option errorDataPath="property"', function () { + createInstances("property") + testRequired("property") + }) - it('should NOT include missing property in dataPath WITHOUT option errorDataPath', function() { - testRequired(); - }); + it("should NOT include missing property in dataPath WITHOUT option errorDataPath", function () { + testRequired() + }) function testRequired(errorDataPath) { var schema = { - required: ['foo', 'bar', 'baz'] - }; + required: ["foo", "bar", "baz"], + } - _testRequired(errorDataPath, schema, '#', '.'); + _testRequired(errorDataPath, schema, "#", ".") } + it('large data/schemas with option errorDataPath="property"', function () { + createInstances("property") + testRequiredLargeSchema("property") + }) - it('large data/schemas with option errorDataPath="property"', function() { - createInstances('property'); - testRequiredLargeSchema('property'); - }); - - it('large data/schemas WITHOUT option errorDataPath', function() { - testRequiredLargeSchema(); - }); + it("large data/schemas WITHOUT option errorDataPath", function () { + testRequiredLargeSchema() + }) function testRequiredLargeSchema(errorDataPath) { - var schema = { required: [] } - , data = {} - , invalidData1 = {} - , invalidData2 = {}; - for (var i=0; i<100; i++) { - schema.required.push(''+i); // properties from '0' to '99' are required - data[i] = invalidData1[i] = invalidData2[i] = i; + var schema = {required: []}, + data = {}, + invalidData1 = {}, + invalidData2 = {} + for (var i = 0; i < 100; i++) { + schema.required.push("" + i) // properties from '0' to '99' are required + data[i] = invalidData1[i] = invalidData2[i] = i } - delete invalidData1[1]; // property '1' will be missing - delete invalidData2[2]; // properties '2' and '198' will be missing - delete invalidData2[98]; + delete invalidData1[1] // property '1' will be missing + delete invalidData2[2] // properties '2' and '198' will be missing + delete invalidData2[98] - var path = pathFunc(errorDataPath); - var msg = requiredFunc(errorDataPath); + var path = pathFunc(errorDataPath) + var msg = requiredFunc(errorDataPath) - test(); + test() - schema = { anyOf: [ schema ] }; - test(1, '#/anyOf/0'); + schema = {anyOf: [schema]} + test(1, "#/anyOf/0") function test(extraErrors, schemaPathPrefix) { - extraErrors = extraErrors || 0; - var schPath = (schemaPathPrefix || '#') + '/required'; - var validate = ajv.compile(schema); - shouldBeValid(validate, data); - shouldBeInvalid(validate, invalidData1, 1 + extraErrors); - shouldBeError(validate.errors[0], 'required', schPath, path("['1']"), msg('1'), { missingProperty: '1' }); - shouldBeInvalid(validate, invalidData2, 1 + extraErrors); - shouldBeError(validate.errors[0], 'required', schPath, path("['2']"), msg('2'), { missingProperty: '2' }); - - var validateJP = ajvJP.compile(schema); - shouldBeValid(validateJP, data); - shouldBeInvalid(validateJP, invalidData1, 1 + extraErrors); - shouldBeError(validateJP.errors[0], 'required', schPath, path("/1"), msg('1'), { missingProperty: '1' }); - shouldBeInvalid(validateJP, invalidData2, 1 + extraErrors); - shouldBeError(validateJP.errors[0], 'required', schPath, path("/2"), msg('2'), { missingProperty: '2' }); - - var fullValidate = fullAjv.compile(schema); - shouldBeValid(fullValidate, data); - shouldBeInvalid(fullValidate, invalidData1, 1 + extraErrors); - shouldBeError(fullValidate.errors[0], 'required', schPath, path('/1'), msg('1'), { missingProperty: '1' }); - shouldBeInvalid(fullValidate, invalidData2, 2 + extraErrors); - shouldBeError(fullValidate.errors[0], 'required', schPath, path('/2'), msg('2'), { missingProperty: '2' }); - shouldBeError(fullValidate.errors[1], 'required', schPath, path('/98'), msg('98'), { missingProperty: '98' }); + extraErrors = extraErrors || 0 + var schPath = (schemaPathPrefix || "#") + "/required" + var validate = ajv.compile(schema) + shouldBeValid(validate, data) + shouldBeInvalid(validate, invalidData1, 1 + extraErrors) + shouldBeError( + validate.errors[0], + "required", + schPath, + path("['1']"), + msg("1"), + {missingProperty: "1"} + ) + shouldBeInvalid(validate, invalidData2, 1 + extraErrors) + shouldBeError( + validate.errors[0], + "required", + schPath, + path("['2']"), + msg("2"), + {missingProperty: "2"} + ) + + var validateJP = ajvJP.compile(schema) + shouldBeValid(validateJP, data) + shouldBeInvalid(validateJP, invalidData1, 1 + extraErrors) + shouldBeError( + validateJP.errors[0], + "required", + schPath, + path("/1"), + msg("1"), + {missingProperty: "1"} + ) + shouldBeInvalid(validateJP, invalidData2, 1 + extraErrors) + shouldBeError( + validateJP.errors[0], + "required", + schPath, + path("/2"), + msg("2"), + {missingProperty: "2"} + ) + + var fullValidate = fullAjv.compile(schema) + shouldBeValid(fullValidate, data) + shouldBeInvalid(fullValidate, invalidData1, 1 + extraErrors) + shouldBeError( + fullValidate.errors[0], + "required", + schPath, + path("/1"), + msg("1"), + {missingProperty: "1"} + ) + shouldBeInvalid(fullValidate, invalidData2, 2 + extraErrors) + shouldBeError( + fullValidate.errors[0], + "required", + schPath, + path("/2"), + msg("2"), + {missingProperty: "2"} + ) + shouldBeError( + fullValidate.errors[1], + "required", + schPath, + path("/98"), + msg("98"), + {missingProperty: "98"} + ) } } + it('with "properties" with option errorDataPath="property"', function () { + createInstances("property") + testRequiredAndProperties("property") + }) - it('with "properties" with option errorDataPath="property"', function() { - createInstances('property'); - testRequiredAndProperties('property'); - }); - - it('with "properties" WITHOUT option errorDataPath', function() { - testRequiredAndProperties(); - }); + it('with "properties" WITHOUT option errorDataPath', function () { + testRequiredAndProperties() + }) function testRequiredAndProperties(errorDataPath) { var schema = { properties: { - 'foo': { type: 'number' }, - 'bar': { type: 'number' }, - 'baz': { type: 'number' }, + foo: {type: "number"}, + bar: {type: "number"}, + baz: {type: "number"}, }, - required: ['foo', 'bar', 'baz'] - }; + required: ["foo", "bar", "baz"], + } - _testRequired(errorDataPath, schema); + _testRequired(errorDataPath, schema) } + it('in "anyOf" with option errorDataPath="property"', function () { + createInstances("property") + testRequiredInAnyOf("property") + }) - it('in "anyOf" with option errorDataPath="property"', function() { - createInstances('property'); - testRequiredInAnyOf('property'); - }); - - it('in "anyOf" WITHOUT option errorDataPath', function() { - testRequiredInAnyOf(); - }); + it('in "anyOf" WITHOUT option errorDataPath', function () { + testRequiredInAnyOf() + }) function testRequiredInAnyOf(errorDataPath) { var schema = { - anyOf: [ - { required: ['foo', 'bar', 'baz'] } - ] - }; + anyOf: [{required: ["foo", "bar", "baz"]}], + } - _testRequired(errorDataPath, schema, '#/anyOf/0', '.', 1); + _testRequired(errorDataPath, schema, "#/anyOf/0", ".", 1) } - - it('should not validate required twice in large schemas with loopRequired option', function() { - ajv = new Ajv({ loopRequired: 1, allErrors: true }); + it("should not validate required twice in large schemas with loopRequired option", function () { + ajv = new Ajv({loopRequired: 1, allErrors: true}) var schema = { properties: { - foo: { type: 'integer' }, - bar: { type: 'integer' } + foo: {type: "integer"}, + bar: {type: "integer"}, }, - required: ['foo', 'bar'] - }; - - var validate = ajv.compile(schema); + required: ["foo", "bar"], + } - validate({}) .should.equal(false); - validate.errors .should.have.length(2); - }); + var validate = ajv.compile(schema) + validate({}).should.equal(false) + validate.errors.should.have.length(2) + }) - it('should not validate required twice with $data ref', function() { - ajv = new Ajv({ $data: true, allErrors: true }); + it("should not validate required twice with $data ref", function () { + ajv = new Ajv({$data: true, allErrors: true}) var schema = { properties: { - foo: { type: 'integer' }, - bar: { type: 'integer' } + foo: {type: "integer"}, + bar: {type: "integer"}, }, - required: { $data: '0/requiredProperties' } - }; - - var validate = ajv.compile(schema); + required: {$data: "0/requiredProperties"}, + } - validate({ requiredProperties: ['foo', 'bar'] }) .should.equal(false); - validate.errors .should.have.length(2); - }); - }); + var validate = ajv.compile(schema) + validate({requiredProperties: ["foo", "bar"]}).should.equal(false) + validate.errors.should.have.length(2) + }) + }) - describe('"dependencies" errors', function() { - it('should include missing property in dataPath with option errorDataPath="property"', function() { - createInstances('property'); - testDependencies('property'); - }); + describe('"dependencies" errors', function () { + it('should include missing property in dataPath with option errorDataPath="property"', function () { + createInstances("property") + testDependencies("property") + }) - it('should NOT include missing property in dataPath WITHOUT option errorDataPath', function() { - testDependencies(); - }); + it("should NOT include missing property in dataPath WITHOUT option errorDataPath", function () { + testDependencies() + }) function testDependencies(errorDataPath) { var schema = { dependencies: { - a: ['foo', 'bar', 'baz'] - } - }; - - var data = { a: 0, foo: 1, bar: 2, baz: 3 } - , invalidData1 = { a: 0, foo: 1, baz: 3 } - , invalidData2 = { a: 0, bar: 2 }; - - var path = pathFunc(errorDataPath); - var msg = 'should have properties foo, bar, baz when property a is present'; - - var validate = ajv.compile(schema); - shouldBeValid(validate, data); - shouldBeInvalid(validate, invalidData1); - shouldBeError(validate.errors[0], 'dependencies', '#/dependencies', path('.bar'), msg, params('.bar')); - shouldBeInvalid(validate, invalidData2); - shouldBeError(validate.errors[0], 'dependencies', '#/dependencies', path('.foo'), msg, params('.foo')); - - var validateJP = ajvJP.compile(schema); - shouldBeValid(validateJP, data); - shouldBeInvalid(validateJP, invalidData1); - shouldBeError(validateJP.errors[0], 'dependencies', '#/dependencies', path('/bar'), msg, params('bar')); - shouldBeInvalid(validateJP, invalidData2); - shouldBeError(validateJP.errors[0], 'dependencies', '#/dependencies', path('/foo'), msg, params('foo')); - - var fullValidate = fullAjv.compile(schema); - shouldBeValid(fullValidate, data); - shouldBeInvalid(fullValidate, invalidData1); - shouldBeError(fullValidate.errors[0], 'dependencies', '#/dependencies', path('/bar'), msg, params('bar')); - shouldBeInvalid(fullValidate, invalidData2, 2); - shouldBeError(fullValidate.errors[0], 'dependencies', '#/dependencies', path('/foo'), msg, params('foo')); - shouldBeError(fullValidate.errors[1], 'dependencies', '#/dependencies', path('/baz'), msg, params('baz')); + a: ["foo", "bar", "baz"], + }, + } + + var data = {a: 0, foo: 1, bar: 2, baz: 3}, + invalidData1 = {a: 0, foo: 1, baz: 3}, + invalidData2 = {a: 0, bar: 2} + + var path = pathFunc(errorDataPath) + var msg = + "should have properties foo, bar, baz when property a is present" + + var validate = ajv.compile(schema) + shouldBeValid(validate, data) + shouldBeInvalid(validate, invalidData1) + shouldBeError( + validate.errors[0], + "dependencies", + "#/dependencies", + path(".bar"), + msg, + params(".bar") + ) + shouldBeInvalid(validate, invalidData2) + shouldBeError( + validate.errors[0], + "dependencies", + "#/dependencies", + path(".foo"), + msg, + params(".foo") + ) + + var validateJP = ajvJP.compile(schema) + shouldBeValid(validateJP, data) + shouldBeInvalid(validateJP, invalidData1) + shouldBeError( + validateJP.errors[0], + "dependencies", + "#/dependencies", + path("/bar"), + msg, + params("bar") + ) + shouldBeInvalid(validateJP, invalidData2) + shouldBeError( + validateJP.errors[0], + "dependencies", + "#/dependencies", + path("/foo"), + msg, + params("foo") + ) + + var fullValidate = fullAjv.compile(schema) + shouldBeValid(fullValidate, data) + shouldBeInvalid(fullValidate, invalidData1) + shouldBeError( + fullValidate.errors[0], + "dependencies", + "#/dependencies", + path("/bar"), + msg, + params("bar") + ) + shouldBeInvalid(fullValidate, invalidData2, 2) + shouldBeError( + fullValidate.errors[0], + "dependencies", + "#/dependencies", + path("/foo"), + msg, + params("foo") + ) + shouldBeError( + fullValidate.errors[1], + "dependencies", + "#/dependencies", + path("/baz"), + msg, + params("baz") + ) function params(missing) { var p = { - property: 'a', - deps: 'foo, bar, baz', - depsCount: 3 - }; - p.missingProperty = missing; - return p; + property: "a", + deps: "foo, bar, baz", + depsCount: 3, + } + p.missingProperty = missing + return p } } - }); - - - function _testRequired(errorDataPath, schema, schemaPathPrefix, prefix, extraErrors) { - var schPath = (schemaPathPrefix || '#') + '/required'; - prefix = prefix || ''; - extraErrors = extraErrors || 0; - - var data = { foo: 1, bar: 2, baz: 3 } - , invalidData1 = { foo: 1, baz: 3 } - , invalidData2 = { bar: 2 }; - - var path = pathFunc(errorDataPath); - var msg = requiredFunc(errorDataPath); - - var validate = ajv.compile(schema); - shouldBeValid(validate, data); - shouldBeInvalid(validate, invalidData1, 1 + extraErrors); - shouldBeError(validate.errors[0], 'required', schPath, path('.bar'), msg(prefix + 'bar'), { missingProperty: prefix + 'bar' }); - shouldBeInvalid(validate, invalidData2, 1 + extraErrors); - shouldBeError(validate.errors[0], 'required', schPath, path('.foo'), msg(prefix + 'foo'), { missingProperty: prefix + 'foo' }); - - var validateJP = ajvJP.compile(schema); - shouldBeValid(validateJP, data); - shouldBeInvalid(validateJP, invalidData1, 1 + extraErrors); - shouldBeError(validateJP.errors[0], 'required', schPath, path('/bar'), msg('bar'), { missingProperty: 'bar' }); - shouldBeInvalid(validateJP, invalidData2, 1 + extraErrors); - shouldBeError(validateJP.errors[0], 'required', schPath, path('/foo'), msg('foo'), { missingProperty: 'foo' }); - - var fullValidate = fullAjv.compile(schema); - shouldBeValid(fullValidate, data); - shouldBeInvalid(fullValidate, invalidData1, 1 + extraErrors); - shouldBeError(fullValidate.errors[0], 'required', schPath, path('/bar'), msg('bar'), { missingProperty: 'bar' }); - shouldBeInvalid(fullValidate, invalidData2, 2 + extraErrors); - shouldBeError(fullValidate.errors[0], 'required', schPath, path('/foo'), msg('foo'), { missingProperty: 'foo' }); - shouldBeError(fullValidate.errors[1], 'required', schPath, path('/baz'), msg('baz'), { missingProperty: 'baz' }); + }) + + function _testRequired( + errorDataPath, + schema, + schemaPathPrefix, + prefix, + extraErrors + ) { + var schPath = (schemaPathPrefix || "#") + "/required" + prefix = prefix || "" + extraErrors = extraErrors || 0 + + var data = {foo: 1, bar: 2, baz: 3}, + invalidData1 = {foo: 1, baz: 3}, + invalidData2 = {bar: 2} + + var path = pathFunc(errorDataPath) + var msg = requiredFunc(errorDataPath) + + var validate = ajv.compile(schema) + shouldBeValid(validate, data) + shouldBeInvalid(validate, invalidData1, 1 + extraErrors) + shouldBeError( + validate.errors[0], + "required", + schPath, + path(".bar"), + msg(prefix + "bar"), + {missingProperty: prefix + "bar"} + ) + shouldBeInvalid(validate, invalidData2, 1 + extraErrors) + shouldBeError( + validate.errors[0], + "required", + schPath, + path(".foo"), + msg(prefix + "foo"), + {missingProperty: prefix + "foo"} + ) + + var validateJP = ajvJP.compile(schema) + shouldBeValid(validateJP, data) + shouldBeInvalid(validateJP, invalidData1, 1 + extraErrors) + shouldBeError( + validateJP.errors[0], + "required", + schPath, + path("/bar"), + msg("bar"), + {missingProperty: "bar"} + ) + shouldBeInvalid(validateJP, invalidData2, 1 + extraErrors) + shouldBeError( + validateJP.errors[0], + "required", + schPath, + path("/foo"), + msg("foo"), + {missingProperty: "foo"} + ) + + var fullValidate = fullAjv.compile(schema) + shouldBeValid(fullValidate, data) + shouldBeInvalid(fullValidate, invalidData1, 1 + extraErrors) + shouldBeError( + fullValidate.errors[0], + "required", + schPath, + path("/bar"), + msg("bar"), + {missingProperty: "bar"} + ) + shouldBeInvalid(fullValidate, invalidData2, 2 + extraErrors) + shouldBeError( + fullValidate.errors[0], + "required", + schPath, + path("/foo"), + msg("foo"), + {missingProperty: "foo"} + ) + shouldBeError( + fullValidate.errors[1], + "required", + schPath, + path("/baz"), + msg("baz"), + {missingProperty: "baz"} + ) } function pathFunc(errorDataPath) { return function (dataPath) { - return errorDataPath == 'property' ? dataPath : ''; - }; + return errorDataPath == "property" ? dataPath : "" + } } function requiredFunc(errorDataPath) { return function (prop) { - return errorDataPath == 'property' - ? 'is a required property' - : 'should have required property \'' + prop + '\''; - }; + return errorDataPath == "property" + ? "is a required property" + : "should have required property '" + prop + "'" + } } function additionalFunc(errorDataPath) { - return errorDataPath == 'property' - ? 'is an invalid additional property' - : 'should NOT have additional properties'; + return errorDataPath == "property" + ? "is an invalid additional property" + : "should NOT have additional properties" } - - it('"items" errors should include item index without quotes in dataPath (#48)', function() { + it('"items" errors should include item index without quotes in dataPath (#48)', function () { var schema1 = { - $id: 'schema1', - type: 'array', + $id: "schema1", + type: "array", items: { - type: 'integer', - minimum: 10 - } - }; - - var data = [ 10, 11, 12] - , invalidData1 = [ 1, 10 ] - , invalidData2 = [ 10, 9, 11, 8, 12]; - - var validate = ajv.compile(schema1); - shouldBeValid(validate, data); - shouldBeInvalid(validate, invalidData1); - shouldBeError(validate.errors[0], 'minimum', '#/items/minimum', '[0]', 'should be >= 10'); - shouldBeInvalid(validate, invalidData2); - shouldBeError(validate.errors[0], 'minimum', '#/items/minimum', '[1]', 'should be >= 10'); - - var validateJP = ajvJP.compile(schema1); - shouldBeValid(validateJP, data); - shouldBeInvalid(validateJP, invalidData1); - shouldBeError(validateJP.errors[0], 'minimum', '#/items/minimum', '/0', 'should be >= 10'); - shouldBeInvalid(validateJP, invalidData2); - shouldBeError(validateJP.errors[0], 'minimum', '#/items/minimum', '/1', 'should be >= 10'); - - var fullValidate = fullAjv.compile(schema1); - shouldBeValid(fullValidate, data); - shouldBeInvalid(fullValidate, invalidData1); - shouldBeError(fullValidate.errors[0], 'minimum', '#/items/minimum', '/0', 'should be >= 10'); - shouldBeInvalid(fullValidate, invalidData2, 2); - shouldBeError(fullValidate.errors[0], 'minimum', '#/items/minimum', '/1', 'should be >= 10'); - shouldBeError(fullValidate.errors[1], 'minimum', '#/items/minimum', '/3', 'should be >= 10'); - - var schema2 = { - $id: 'schema2', - type: 'array', - items: [{ minimum: 10 }, { minimum: 9 }, { minimum: 12 }] - }; + type: "integer", + minimum: 10, + }, + } - validate = ajv.compile(schema2); - shouldBeValid(validate, data); - shouldBeInvalid(validate, invalidData1); - shouldBeError(validate.errors[0], 'minimum', '#/items/0/minimum', '[0]', 'should be >= 10'); - shouldBeInvalid(validate, invalidData2); - shouldBeError(validate.errors[0], 'minimum', '#/items/2/minimum', '[2]', 'should be >= 12'); - }); + var data = [10, 11, 12], + invalidData1 = [1, 10], + invalidData2 = [10, 9, 11, 8, 12] + + var validate = ajv.compile(schema1) + shouldBeValid(validate, data) + shouldBeInvalid(validate, invalidData1) + shouldBeError( + validate.errors[0], + "minimum", + "#/items/minimum", + "[0]", + "should be >= 10" + ) + shouldBeInvalid(validate, invalidData2) + shouldBeError( + validate.errors[0], + "minimum", + "#/items/minimum", + "[1]", + "should be >= 10" + ) + + var validateJP = ajvJP.compile(schema1) + shouldBeValid(validateJP, data) + shouldBeInvalid(validateJP, invalidData1) + shouldBeError( + validateJP.errors[0], + "minimum", + "#/items/minimum", + "/0", + "should be >= 10" + ) + shouldBeInvalid(validateJP, invalidData2) + shouldBeError( + validateJP.errors[0], + "minimum", + "#/items/minimum", + "/1", + "should be >= 10" + ) + + var fullValidate = fullAjv.compile(schema1) + shouldBeValid(fullValidate, data) + shouldBeInvalid(fullValidate, invalidData1) + shouldBeError( + fullValidate.errors[0], + "minimum", + "#/items/minimum", + "/0", + "should be >= 10" + ) + shouldBeInvalid(fullValidate, invalidData2, 2) + shouldBeError( + fullValidate.errors[0], + "minimum", + "#/items/minimum", + "/1", + "should be >= 10" + ) + shouldBeError( + fullValidate.errors[1], + "minimum", + "#/items/minimum", + "/3", + "should be >= 10" + ) + var schema2 = { + $id: "schema2", + type: "array", + items: [{minimum: 10}, {minimum: 9}, {minimum: 12}], + } - it('should have correct schema path for additionalItems', function() { + validate = ajv.compile(schema2) + shouldBeValid(validate, data) + shouldBeInvalid(validate, invalidData1) + shouldBeError( + validate.errors[0], + "minimum", + "#/items/0/minimum", + "[0]", + "should be >= 10" + ) + shouldBeInvalid(validate, invalidData2) + shouldBeError( + validate.errors[0], + "minimum", + "#/items/2/minimum", + "[2]", + "should be >= 12" + ) + }) + + it("should have correct schema path for additionalItems", function () { var schema = { - type: 'array', - items: [ { type: 'integer' }, { type: 'integer' } ], - additionalItems: false - }; + type: "array", + items: [{type: "integer"}, {type: "integer"}], + additionalItems: false, + } - var data = [ 1, 2 ] - , invalidData = [ 1, 2, 3 ]; + var data = [1, 2], + invalidData = [1, 2, 3] - test(ajv); - test(ajvJP); - test(fullAjv); + test(ajv) + test(ajvJP) + test(fullAjv) function test(_ajv) { - var validate = _ajv.compile(schema); - shouldBeValid(validate, data); - shouldBeInvalid(validate, invalidData); - shouldBeError(validate.errors[0], 'additionalItems', '#/additionalItems', '', 'should NOT have more than 2 items'); + var validate = _ajv.compile(schema) + shouldBeValid(validate, data) + shouldBeInvalid(validate, invalidData) + shouldBeError( + validate.errors[0], + "additionalItems", + "#/additionalItems", + "", + "should NOT have more than 2 items" + ) } - }); - + }) - describe('"propertyNames" errors', function() { - it('should add propertyName to errors', function() { + describe('"propertyNames" errors', function () { + it("should add propertyName to errors", function () { var schema = { - type: 'object', - propertyNames: { format: 'email' } - }; + type: "object", + propertyNames: {pattern: "bar"}, + } var data = { - 'bar.baz@email.example.com': {} - }; + bar: {}, + "bar.baz@email.example.com": {}, + } var invalidData = { - 'foo': {}, - 'bar': {}, - 'bar.baz@email.example.com': {} - }; + bar: {}, + "bar.baz@email.example.com": {}, + foo: {}, + quux: {}, + } - test(ajv, 2); - test(ajvJP, 2); - test(fullAjv, 4); + test(ajv, 2) + test(ajvJP, 2) + test(fullAjv, 4) function test(_ajv, numErrors) { - var validate = _ajv.compile(schema); - shouldBeValid(validate, data); - shouldBeInvalid(validate, invalidData, numErrors); - shouldBeError(validate.errors[0], 'format', '#/propertyNames/format', '', 'should match format "email"'); - shouldBeError(validate.errors[1], 'propertyNames', '#/propertyNames', '', 'property name \'foo\' is invalid'); + var validate = _ajv.compile(schema) + shouldBeValid(validate, data) + shouldBeInvalid(validate, invalidData, numErrors) + shouldBeError( + validate.errors[0], + "pattern", + "#/propertyNames/pattern", + "", + 'should match pattern "bar"' + ) + shouldBeError( + validate.errors[1], + "propertyNames", + "#/propertyNames", + "", + "property name 'foo' is invalid" + ) if (numErrors == 4) { - shouldBeError(validate.errors[2], 'format', '#/propertyNames/format', '', 'should match format "email"'); - shouldBeError(validate.errors[3], 'propertyNames', '#/propertyNames', '', 'property name \'bar\' is invalid'); + shouldBeError( + validate.errors[2], + "pattern", + "#/propertyNames/pattern", + "", + 'should match pattern "bar"' + ) + shouldBeError( + validate.errors[3], + "propertyNames", + "#/propertyNames", + "", + "property name 'quux' is invalid" + ) } } - }); - }); + }) + }) - - describe('oneOf errors', function() { - it('should have errors from inner schemas', function() { + describe("oneOf errors", function () { + it("should have errors from inner schemas", function () { var schema = { - oneOf: [ - { type: 'number' }, - { type: 'integer' } - ] - }; + oneOf: [{type: "number"}, {type: "integer"}], + } - test(ajv); - test(fullAjv); + test(ajv) + test(fullAjv) function test(_ajv) { - var validate = _ajv.compile(schema); - validate('foo') .should.equal(false); - validate.errors.length .should.equal(3); - validate(1) .should.equal(false); - validate.errors.length .should.equal(1); - validate(1.5) .should.equal(true); + var validate = _ajv.compile(schema) + validate("foo").should.equal(false) + validate.errors.length.should.equal(3) + validate(1).should.equal(false) + validate.errors.length.should.equal(1) + validate(1.5).should.equal(true) } - }); + }) - it('should return passing schemas in error params', function() { + it("should return passing schemas in error params", function () { var schema = { - oneOf: [ - { type: 'number' }, - { type: 'integer' }, - { const: 1.5 } - ] - }; + oneOf: [{type: "number"}, {type: "integer"}, {const: 1.5}], + } - test(ajv); - test(fullAjv); + 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}); + 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}) } - }); - }); + }) + }) - - describe('anyOf errors', function() { - it('should have errors from inner schemas', function() { + describe("anyOf errors", function () { + it("should have errors from inner schemas", function () { var schema = { - anyOf: [ - { type: 'number' }, - { type: 'integer' } - ] - }; + anyOf: [{type: "number"}, {type: "integer"}], + } - test(ajv); - test(fullAjv); + test(ajv) + test(fullAjv) function test(_ajv) { - var validate = _ajv.compile(schema); - validate('foo') .should.equal(false); - validate.errors.length .should.equal(3); - validate(1) .should.equal(true); - validate(1.5) .should.equal(true); + var validate = _ajv.compile(schema) + validate("foo").should.equal(false) + validate.errors.length.should.equal(3) + validate(1).should.equal(true) + validate(1.5).should.equal(true) } - }); - }); - + }) + }) - describe('type errors', function() { - describe('integer', function() { - it('should have only one error in {allErrors: false} mode', function() { - test(ajv); - }); + describe("type errors", function () { + describe("integer", function () { + it("should have only one error in {allErrors: false} mode", function () { + test(ajv) + }) - it('should return all errors in {allErrors: true} mode', function() { - test(fullAjv, 2); - }); + it("should return all errors in {allErrors: true} mode", function () { + test(fullAjv, 2) + }) function test(_ajv, numErrors) { var schema = { - type: 'integer', - minimum: 5 - }; - + type: "integer", + minimum: 5, + } - var validate = _ajv.compile(schema); - shouldBeValid(validate, 5); - shouldBeInvalid(validate, 5.5); - shouldBeInvalid(validate, 4); - shouldBeInvalid(validate, '4'); - shouldBeInvalid(validate, 4.5, numErrors); + var validate = _ajv.compile(schema) + shouldBeValid(validate, 5) + shouldBeInvalid(validate, 5.5) + shouldBeInvalid(validate, 4) + shouldBeInvalid(validate, "4") + shouldBeInvalid(validate, 4.5, numErrors) } - }); + }) - describe('keyword for another type', function() { - it('should have only one error in {allErrors: false} mode', function() { - test(ajv); - }); + describe("keyword for another type", function () { + it("should have only one error in {allErrors: false} mode", function () { + test(ajv) + }) - it('should return all errors in {allErrors: true} mode', function() { - test(fullAjv, 2); - }); + it("should return all errors in {allErrors: true} mode", function () { + test(fullAjv, 2) + }) function test(_ajv, numErrors) { var schema = { - type: 'array', + type: "array", minItems: 2, - minimum: 5 - }; - + minimum: 5, + } - var validate = _ajv.compile(schema); - shouldBeValid(validate, [1, 2]); - shouldBeInvalid(validate, [1]); - shouldBeInvalid(validate, 5); - shouldBeInvalid(validate, 4, numErrors); + var validate = _ajv.compile(schema) + shouldBeValid(validate, [1, 2]) + shouldBeInvalid(validate, [1]) + shouldBeInvalid(validate, 5) + shouldBeInvalid(validate, 4, numErrors) } - }); + }) - describe('array of types', function() { - it('should have only one error in {allErrors: false} mode', function() { - test(ajv); - }); + describe("array of types", function () { + it("should have only one error in {allErrors: false} mode", function () { + test(ajv) + }) - it('should return all errors in {allErrors: true} mode', function() { - test(fullAjv, 2); - }); + it("should return all errors in {allErrors: true} mode", function () { + test(fullAjv, 2) + }) function test(_ajv, numErrors) { var schema = { - type: ['array', 'object'], + type: ["array", "object"], minItems: 2, minProperties: 2, - minimum: 5 - }; - + minimum: 5, + } - var validate = _ajv.compile(schema); - shouldBeValid(validate, [1, 2]); - shouldBeValid(validate, {foo: 1, bar: 2}); - shouldBeInvalid(validate, [1]); - shouldBeInvalid(validate, {foo: 1}); - shouldBeInvalid(validate, 5); - shouldBeInvalid(validate, 4, numErrors); + var validate = _ajv.compile(schema) + shouldBeValid(validate, [1, 2]) + shouldBeValid(validate, {foo: 1, bar: 2}) + shouldBeInvalid(validate, [1]) + shouldBeInvalid(validate, {foo: 1}) + shouldBeInvalid(validate, 5) + shouldBeInvalid(validate, 4, numErrors) } - }); - }); + }) + }) - - describe('exclusiveMaximum/Minimum errors', function() { - it('should include limits in error message', function() { + describe("exclusiveMaximum/Minimum errors", function () { + it("should include limits in error message", function () { var schema = { - type: 'integer', + type: "integer", exclusiveMinimum: 2, - exclusiveMaximum: 5 - }; - - [ajv, fullAjv].forEach(function (_ajv) { - var validate = _ajv.compile(schema); - shouldBeValid(validate, 3); - shouldBeValid(validate, 4); - - shouldBeInvalid(validate, 2); - testError('exclusiveMinimum', 'should be > 2', {comparison: '>', limit: 2, exclusive: true}); + exclusiveMaximum: 5, + } - shouldBeInvalid(validate, 5); - testError('exclusiveMaximum', 'should be < 5', {comparison: '<', limit: 5, exclusive: true}); + ;[ajv, fullAjv].forEach(function (_ajv) { + var validate = _ajv.compile(schema) + shouldBeValid(validate, 3) + shouldBeValid(validate, 4) + + shouldBeInvalid(validate, 2) + testError("exclusiveMinimum", "should be > 2", { + comparison: ">", + limit: 2, + exclusive: true, + }) + + shouldBeInvalid(validate, 5) + testError("exclusiveMaximum", "should be < 5", { + comparison: "<", + limit: 5, + exclusive: true, + }) function testError(keyword, message, params) { - var err = validate.errors[0]; - shouldBeError(err, keyword, '#/' + keyword, '', message, params); + var err = validate.errors[0] + shouldBeError(err, keyword, "#/" + keyword, "", message, params) } - }); - }); + }) + }) - it('should include limits in error message with $data', function() { + it("should include limits in error message with $data", function () { var schema = { - "properties": { - "smaller": { - "type": "number", - "exclusiveMaximum": { "$data": "1/larger" } + properties: { + smaller: { + type: "number", + exclusiveMaximum: {$data: "1/larger"}, }, - "larger": { "type": "number" } - } - }; - - ajv = new Ajv({$data: true}); - fullAjv = new Ajv({$data: true, allErrors: true, verbose: true, jsonPointers: true}); + larger: {type: "number"}, + }, + } - [ajv, fullAjv].forEach(function (_ajv) { - var validate = _ajv.compile(schema); - shouldBeValid(validate, {smaller: 2, larger: 4}); - shouldBeValid(validate, {smaller: 3, larger: 4}); + ajv = new Ajv({$data: true}) + fullAjv = new Ajv({ + $data: true, + allErrors: true, + verbose: true, + jsonPointers: true, + }) + ;[ajv, fullAjv].forEach(function (_ajv) { + var validate = _ajv.compile(schema) + shouldBeValid(validate, {smaller: 2, larger: 4}) + shouldBeValid(validate, {smaller: 3, larger: 4}) - shouldBeInvalid(validate, {smaller: 4, larger: 4}); - testError(); + shouldBeInvalid(validate, {smaller: 4, larger: 4}) + testError() - shouldBeInvalid(validate, {smaller: 5, larger: 4}); - testError(); + shouldBeInvalid(validate, {smaller: 5, larger: 4}) + testError() function testError() { - var err = validate.errors[0]; - shouldBeError(err, 'exclusiveMaximum', - '#/properties/smaller/exclusiveMaximum', - _ajv._opts.jsonPointers ? '/smaller' : '.smaller', - 'should be < 4', - {comparison: '<', limit: 4, exclusive: true}); + var err = validate.errors[0] + shouldBeError( + err, + "exclusiveMaximum", + "#/properties/smaller/exclusiveMaximum", + _ajv._opts.jsonPointers ? "/smaller" : ".smaller", + "should be < 4", + {comparison: "<", limit: 4, exclusive: true} + ) } - }); - }); - }); + }) + }) + }) + describe("if/then/else errors", function () { + var validate, numErrors - describe('if/then/else errors', function() { - var validate, numErrors; - - it('if/then/else should include failing keyword in message and params', function() { + it("if/then/else should include failing keyword in message and params", function () { var schema = { - 'if': { maximum: 10 }, - 'then': { multipleOf: 2 }, - 'else': { multipleOf: 5 } - }; + if: {maximum: 10}, + then: {multipleOf: 2}, + else: {multipleOf: 5}, + } - [ajv, fullAjv].forEach(function (_ajv) { - prepareTest(_ajv, schema); - shouldBeValid(validate, 8); - shouldBeValid(validate, 15); + ;[ajv, fullAjv].forEach(function (_ajv) { + prepareTest(_ajv, schema) + shouldBeValid(validate, 8) + shouldBeValid(validate, 15) - shouldBeInvalid(validate, 7, numErrors); - testIfError('then', 2); + shouldBeInvalid(validate, 7, numErrors) + testIfError("then", 2) - shouldBeInvalid(validate, 17, numErrors); - testIfError('else', 5); - }); - }); + shouldBeInvalid(validate, 17, numErrors) + testIfError("else", 5) + }) + }) - it('if/then should include failing keyword in message and params', function() { + 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() { + 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 } - }; + if: {maximum: 10}, + else: {multipleOf: 5}, + } - [ajv, fullAjv].forEach(function (_ajv) { - prepareTest(_ajv, schema); - shouldBeValid(validate, 7); - shouldBeValid(validate, 8); - shouldBeValid(validate, 15); + ;[ajv, fullAjv].forEach(function (_ajv) { + prepareTest(_ajv, schema) + shouldBeValid(validate, 7) + shouldBeValid(validate, 8) + shouldBeValid(validate, 15) - shouldBeInvalid(validate, 17, numErrors); - testIfError('else', 5); - }); - }); + shouldBeInvalid(validate, 17, numErrors) + testIfError("else", 5) + }) + }) function prepareTest(_ajv, schema) { - validate = _ajv.compile(schema); - numErrors = _ajv._opts.allErrors ? 2 : 1; + 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}); + 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}); + 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() { + 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}); + items: {type: "number"}, + uniqueItems: true, + } - var expectedErrors = _ajv._opts.allErrors ? 2 : 1; - shouldBeInvalid(validate, [1, "2", "2", 2], expectedErrors); - testTypeError(0, '/1'); - if (expectedErrors == 2) testTypeError(1, '/2'); + ;[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'); + 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); - _testSchema1(fullAjv, schema, schemaPathPrefix); + _testSchema1(ajv, schema, schemaPathPrefix) + _testSchema1(ajvJP, schema, schemaPathPrefix) + _testSchema1(fullAjv, schema, schemaPathPrefix) } - function _testSchema1(_ajv, schema, schemaPathPrefix) { - var schPath = (schemaPathPrefix || '#/properties/foo') + '/type'; - - var data = { foo: 1 } - , invalidData = { foo: 'bar' }; - - var validate = _ajv.compile(schema); - shouldBeValid(validate, data); - shouldBeInvalid(validate, invalidData); - shouldBeError(validate.errors[0], 'type', schPath, _ajv._opts.jsonPointers ? '/foo' : '.foo'); + var schPath = (schemaPathPrefix || "#/properties/foo") + "/type" + + var data = {foo: 1}, + invalidData = {foo: "bar"} + + var validate = _ajv.compile(schema) + shouldBeValid(validate, data) + shouldBeInvalid(validate, invalidData) + shouldBeError( + validate.errors[0], + "type", + schPath, + _ajv._opts.jsonPointers ? "/foo" : ".foo" + ) } - function shouldBeValid(validate, data) { - validate(data) .should.equal(true); - should.equal(validate.errors, null); + validate(data).should.equal(true) + should.equal(validate.errors, null) } - function shouldBeInvalid(validate, data, numErrors) { - validate(data) .should.equal(false); - should.equal(validate.errors.length, numErrors || 1); + validate(data).should.equal(false) + should.equal(validate.errors.length, numErrors || 1) } - - function shouldBeError(error, keyword, schemaPath, dataPath, message, params) { - error.keyword .should.equal(keyword); - error.schemaPath .should.equal(schemaPath); - error.dataPath .should.equal(dataPath); - error.message .should.be.a('string'); - if (message !== undefined) error.message .should.equal(message); - if (params !== undefined) error.params .should.eql(params); + function shouldBeError( + error, + keyword, + schemaPath, + dataPath, + message, + params + ) { + error.keyword.should.equal(keyword) + error.schemaPath.should.equal(schemaPath) + error.dataPath.should.equal(dataPath) + error.message.should.be.a("string") + if (message !== undefined) error.message.should.equal(message) + if (params !== undefined) error.params.should.eql(params) } -}); +}) diff --git a/spec/extras.spec.js b/spec/extras.spec.js index 15c51a6bcf..1b5c338d52 100644 --- a/spec/extras.spec.js +++ b/spec/extras.spec.js @@ -1,28 +1,31 @@ -'use strict'; +"use strict" -var jsonSchemaTest = require('json-schema-test') - , getAjvInstances = require('./ajv_instances') - , options = require('./ajv_options') - , suite = require('./browser_test_suite') - , after = require('./after_test'); +var jsonSchemaTest = require("json-schema-test"), + getAjvInstances = require("./ajv_instances"), + options = require("./ajv_options"), + suite = require("./browser_test_suite"), + after = require("./after_test") var instances = getAjvInstances(options, { $data: true, - unknownFormats: ['allowedUnknown'] -}); - + unknownFormats: ["allowedUnknown"], +}) jsonSchemaTest(instances, { - description: 'Extra keywords schemas tests of ' + instances.length + ' ajv instances with different options', + description: + "Extra keywords schemas tests of " + + instances.length + + " ajv instances with different options", suites: { - 'extras': typeof window == 'object' - ? suite(require('./extras/{**/,}*.json', {mode: 'list'})) - : './extras/{**/,}*.json' + extras: + typeof window == "object" + ? suite(require("./extras/{**/,}*.json", {mode: "list"})) + : "./extras/{**/,}*.json", }, - assert: require('./chai').assert, + assert: require("./chai").assert, afterError: after.error, afterEach: after.each, cwd: __dirname, - hideFolder: 'extras/', - timeout: 90000 -}); + hideFolder: "extras/", + timeout: 90000, +}) diff --git a/spec/extras/$data/absolute_ref.json b/spec/extras/$data/absolute_ref.json index 38b3fe5d50..74968ae6d6 100644 --- a/spec/extras/$data/absolute_ref.json +++ b/spec/extras/$data/absolute_ref.json @@ -61,11 +61,7 @@ "schema": { "properties": { "arr": { - "items": [ - {}, - {}, - {} - ], + "items": [{}, {}, {}], "additionalItems": false }, "sameArr": { @@ -155,9 +151,7 @@ "description": "1 item array containing property is valid", "data": { "name": "foo", - "list": [ - "foo" - ] + "list": ["foo"] }, "valid": true }, @@ -165,10 +159,7 @@ "description": "2 item array containing property is valid", "data": { "name": "foo", - "list": [ - "foo", - "bar" - ] + "list": ["foo", "bar"] }, "valid": true }, @@ -176,9 +167,7 @@ "description": "array not containing property is invalid", "data": { "name": "foo", - "list": [ - "bar" - ] + "list": ["bar"] }, "valid": false }, @@ -208,11 +197,7 @@ { "description": "one of the enum is valid", "data": { - "allowedValues": [ - 1, - 2, - 3 - ], + "allowedValues": [1, 2, 3], "value": 1 }, "valid": true @@ -220,11 +205,7 @@ { "description": "something else is invalid", "data": { - "allowedValues": [ - 1, - 2, - 3 - ], + "allowedValues": [1, 2, 3], "value": 4 }, "valid": false @@ -280,10 +261,7 @@ { "description": "properties are valid", "data": { - "allowedValues": [ - "foo", - "bar" - ], + "allowedValues": ["foo", "bar"], "a": "foo", "b": "bar" }, @@ -292,10 +270,7 @@ { "description": "properties are invalid", "data": { - "allowedValues": [ - "foo", - "bar" - ], + "allowedValues": ["foo", "bar"], "a": "foo", "b": "baz" }, @@ -320,9 +295,7 @@ "description": "present required property is valid", "data": { "foo": 1, - "requiredProperties": [ - "foo" - ] + "requiredProperties": ["foo"] }, "valid": true }, @@ -330,9 +303,7 @@ "description": "non-present required property is invalid", "data": { "bar": 2, - "requiredProperties": [ - "foo" - ] + "requiredProperties": ["foo"] }, "valid": false }, @@ -340,10 +311,7 @@ "description": "non-present second required property is invalid", "data": { "foo": 1, - "requiredProperties": [ - "foo", - "bar" - ] + "requiredProperties": ["foo", "bar"] }, "valid": false }, @@ -352,10 +320,7 @@ "data": { "foo": 1, "bar": 2, - "requiredProperties": [ - "foo", - "bar" - ] + "requiredProperties": ["foo", "bar"] }, "valid": true }, @@ -433,4 +398,4 @@ } ] } -] \ No newline at end of file +] diff --git a/spec/extras/$data/const.json b/spec/extras/$data/const.json index b6143c4482..44c917dd88 100644 --- a/spec/extras/$data/const.json +++ b/spec/extras/$data/const.json @@ -3,7 +3,7 @@ "description": "property is equal to another property", "schema": { "properties": { - "sameAs": { "const": { "$data": "1/thisOne" } }, + "sameAs": {"const": {"$data": "1/thisOne"}}, "thisOne": {} } }, @@ -19,16 +19,16 @@ { "description": "same object is valid", "data": { - "sameAs": { "foo": 1, "bar": 2 }, - "thisOne": { "bar": 2, "foo": 1 } + "sameAs": {"foo": 1, "bar": 2}, + "thisOne": {"bar": 2, "foo": 1} }, "valid": true }, { "description": "another value is invalid", "data": { - "sameAs": { "foo": 1 }, - "thisOne": { "foo": 2 } + "sameAs": {"foo": 1}, + "thisOne": {"foo": 2} }, "valid": false }, @@ -46,18 +46,18 @@ "description": "property values are equal to property names", "schema": { "additionalProperties": { - "const": { "$data": "0#" } + "const": {"$data": "0#"} } }, "tests": [ { "description": "valid object", - "data": { "foo": "foo", "bar": "bar", "baz": "baz" }, + "data": {"foo": "foo", "bar": "bar", "baz": "baz"}, "valid": true }, { "description": "invalid object", - "data": { "foo": "bar" }, + "data": {"foo": "bar"}, "valid": false } ] @@ -66,18 +66,18 @@ "description": "items are equal to their indeces", "schema": { "items": { - "const": { "$data": "0#" } + "const": {"$data": "0#"} } }, "tests": [ { "description": "valid array", - "data": [ 0, 1, 2, 3 ], + "data": [0, 1, 2, 3], "valid": true }, { "description": "invalid array", - "data": [ 0, 2 ], + "data": [0, 2], "valid": false } ] @@ -87,14 +87,14 @@ "schema": { "properties": { "arr": { - "items": [{},{},{}], + "items": [{}, {}, {}], "additionalItems": false }, "sameArr": { "items": [ - { "const": { "$data": "2/arr/0" } }, - { "const": { "$data": "2/arr/1" } }, - { "const": { "$data": "2/arr/2" } } + {"const": {"$data": "2/arr/0"}}, + {"const": {"$data": "2/arr/1"}}, + {"const": {"$data": "2/arr/2"}} ], "additionalItems": false } @@ -104,16 +104,16 @@ { "description": "equal arrays are valid", "data": { - "arr": [ 1, "abc", {"foo": "bar"} ], - "sameArr": [ 1, "abc", {"foo": "bar"} ] + "arr": [1, "abc", {"foo": "bar"}], + "sameArr": [1, "abc", {"foo": "bar"}] }, "valid": true }, { "description": "different arrays are invalid", "data": { - "arr": [ 1, "abc", {"foo": "bar"} ], - "sameArr": [ 1, "abc", {"foo": "foo"} ] + "arr": [1, "abc", {"foo": "bar"}], + "sameArr": [1, "abc", {"foo": "foo"}] }, "valid": false } @@ -122,7 +122,7 @@ { "description": "any data is equal to itself", "schema": { - "const": { "$data": "0" } + "const": {"$data": "0"} }, "tests": [ { @@ -137,12 +137,12 @@ }, { "description": "object is equal to itself", - "data": { "foo": "bar" }, + "data": {"foo": "bar"}, "valid": true }, { "description": "array is equal to itself", - "data": [ 1, 2, 3 ], + "data": [1, 2, 3], "valid": true } ] @@ -151,10 +151,10 @@ "description": "property value is contained in array", "schema": { "properties": { - "name": { "type": "string" }, + "name": {"type": "string"}, "list": { "type": "array", - "contains": { "const": { "$data": "2/name" } } + "contains": {"const": {"$data": "2/name"}} } } }, @@ -163,7 +163,7 @@ "description": "1 item array containing property is valid", "data": { "name": "foo", - "list": [ "foo" ] + "list": ["foo"] }, "valid": true }, @@ -171,7 +171,7 @@ "description": "2 item array containing property is valid", "data": { "name": "foo", - "list": [ "foo", "bar" ] + "list": ["foo", "bar"] }, "valid": true }, @@ -179,7 +179,7 @@ "description": "array not containing property is invalid", "data": { "name": "foo", - "list": [ "bar" ] + "list": ["bar"] }, "valid": false }, diff --git a/spec/extras/$data/enum.json b/spec/extras/$data/enum.json index 1aab4bd210..b2f895af93 100644 --- a/spec/extras/$data/enum.json +++ b/spec/extras/$data/enum.json @@ -4,7 +4,7 @@ "schema": { "properties": { "allowedValues": {}, - "value": { "enum": { "$data": "1/allowedValues" } } + "value": {"enum": {"$data": "1/allowedValues"}} } }, "tests": [ @@ -56,7 +56,7 @@ "allowedValues": {} }, "additionalProperties": { - "enum": { "$data": "1/allowedValues" } + "enum": {"$data": "1/allowedValues"} } }, "tests": [ diff --git a/spec/extras/$data/exclusiveMaximum.json b/spec/extras/$data/exclusiveMaximum.json index a33e1918c6..a1010571c9 100644 --- a/spec/extras/$data/exclusiveMaximum.json +++ b/spec/extras/$data/exclusiveMaximum.json @@ -5,7 +5,7 @@ "properties": { "larger": {}, "smaller": { - "exclusiveMaximum": { "$data": "1/larger" } + "exclusiveMaximum": {"$data": "1/larger"} } } }, @@ -59,7 +59,7 @@ } ] }, - + { "description": "exclusiveMaximum as number and maximum as $data, exclusiveMaximum > maximum", "schema": { @@ -67,7 +67,7 @@ "larger": {}, "smaller": { "exclusiveMaximum": 3.5, - "maximum": { "$data": "1/larger" } + "maximum": {"$data": "1/larger"} } } }, @@ -105,7 +105,7 @@ "larger": {}, "smaller": { "exclusiveMaximum": 3, - "maximum": { "$data": "1/larger" } + "maximum": {"$data": "1/larger"} } } }, @@ -143,7 +143,7 @@ "larger": {}, "smaller": { "exclusiveMaximum": 2.5, - "maximum": { "$data": "1/larger" } + "maximum": {"$data": "1/larger"} } } }, @@ -182,8 +182,8 @@ "larger": {}, "largerExclusive": {}, "smaller": { - "exclusiveMaximum": { "$data": "1/largerExclusive" }, - "maximum": { "$data": "1/larger" } + "exclusiveMaximum": {"$data": "1/largerExclusive"}, + "maximum": {"$data": "1/larger"} } } }, @@ -224,8 +224,8 @@ "larger": {}, "largerExclusive": {}, "smaller": { - "exclusiveMaximum": { "$data": "1/largerExclusive" }, - "maximum": { "$data": "1/larger" } + "exclusiveMaximum": {"$data": "1/largerExclusive"}, + "maximum": {"$data": "1/larger"} } } }, @@ -266,8 +266,8 @@ "larger": {}, "largerExclusive": {}, "smaller": { - "exclusiveMaximum": { "$data": "1/largerExclusive" }, - "maximum": { "$data": "1/larger" } + "exclusiveMaximum": {"$data": "1/largerExclusive"}, + "maximum": {"$data": "1/larger"} } } }, @@ -306,7 +306,7 @@ "description": "items in array are < than their indeces", "schema": { "items": { - "exclusiveMaximum": { "$data": "0#" } + "exclusiveMaximum": {"$data": "0#"} } }, "tests": [ diff --git a/spec/extras/$data/exclusiveMinimum.json b/spec/extras/$data/exclusiveMinimum.json index abb5ade814..6700c06901 100644 --- a/spec/extras/$data/exclusiveMinimum.json +++ b/spec/extras/$data/exclusiveMinimum.json @@ -5,7 +5,7 @@ "properties": { "smaller": {}, "larger": { - "exclusiveMinimum": { "$data": "1/smaller" } + "exclusiveMinimum": {"$data": "1/smaller"} } } }, @@ -60,7 +60,7 @@ "smaller": {}, "larger": { "exclusiveMinimum": 2.5, - "minimum": { "$data": "1/smaller" } + "minimum": {"$data": "1/smaller"} } } }, @@ -98,7 +98,7 @@ "smaller": {}, "larger": { "exclusiveMinimum": 3, - "minimum": { "$data": "1/smaller" } + "minimum": {"$data": "1/smaller"} } } }, @@ -136,7 +136,7 @@ "smaller": {}, "larger": { "exclusiveMinimum": 3.5, - "minimum": { "$data": "1/smaller" } + "minimum": {"$data": "1/smaller"} } } }, @@ -175,8 +175,8 @@ "smaller": {}, "smallerExclusive": {}, "larger": { - "exclusiveMinimum": { "$data": "1/smallerExclusive" }, - "minimum": { "$data": "1/smaller" } + "exclusiveMinimum": {"$data": "1/smallerExclusive"}, + "minimum": {"$data": "1/smaller"} } } }, @@ -217,8 +217,8 @@ "smaller": {}, "smallerExclusive": {}, "larger": { - "exclusiveMinimum": { "$data": "1/smallerExclusive" }, - "minimum": { "$data": "1/smaller" } + "exclusiveMinimum": {"$data": "1/smallerExclusive"}, + "minimum": {"$data": "1/smaller"} } } }, @@ -259,8 +259,8 @@ "smaller": {}, "smallerExclusive": {}, "larger": { - "exclusiveMinimum": { "$data": "1/smallerExclusive" }, - "minimum": { "$data": "1/smaller" } + "exclusiveMinimum": {"$data": "1/smallerExclusive"}, + "minimum": {"$data": "1/smaller"} } } }, @@ -299,7 +299,7 @@ "description": "items in array are > than their indeces", "schema": { "items": { - "exclusiveMinimum": { "$data": "0#" } + "exclusiveMinimum": {"$data": "0#"} } }, "tests": [ diff --git a/spec/extras/$data/format.json b/spec/extras/$data/format.json index 97c7fa7977..48fb5f1009 100644 --- a/spec/extras/$data/format.json +++ b/spec/extras/$data/format.json @@ -12,46 +12,6 @@ } }, "tests": [ - { - "description": "a valid date-time string", - "data": { - "str": "1963-06-19T08:30:06.283185Z", - "strFormat": "date-time" - }, - "valid": true - }, - { - "description": "an invalid date-time string", - "data": { - "str": "06/19/1963 08:30:06 PST", - "strFormat": "date-time" - }, - "valid": false - }, - { - "description": "only RFC3339 not all of ISO 8601 are valid", - "data": { - "str": "2013-350T01:01:01", - "strFormat": "date-time" - }, - "valid": false - }, - { - "description": "a valid e-mail address", - "data": { - "str": "joe.bloggs@example.com", - "strFormat": "email" - }, - "valid": true - }, - { - "description": "an invalid e-mail address", - "data": { - "str": "2962", - "strFormat": "email" - }, - "valid": false - }, { "description": "allowed unknown format is valid", "data": { @@ -84,41 +44,5 @@ "valid": false } ] - }, - { - "description": "property name is the format for the property value", - "schema": { - "additionalProperties": { - "format": { - "$data": "0#" - } - } - }, - "tests": [ - { - "description": "valid formats", - "data": { - "date-time": "1963-06-19T08:30:06.283185Z", - "email": "joe.bloggs@example.com" - }, - "valid": true - }, - { - "description": "invalid date-time", - "data": { - "date-time": "06/19/1963 08:30:06 PST", - "email": "joe.bloggs@example.com" - }, - "valid": false - }, - { - "description": "invalid e-mail", - "data": { - "date-time": "1963-06-19T08:30:06.283185Z", - "email": "2962" - }, - "valid": false - } - ] } -] \ No newline at end of file +] diff --git a/spec/extras/$data/maxItems.json b/spec/extras/$data/maxItems.json index 03d599264c..377ca2b315 100644 --- a/spec/extras/$data/maxItems.json +++ b/spec/extras/$data/maxItems.json @@ -4,7 +4,7 @@ "schema": { "properties": { "maxArrayLength": {}, - "array": { "maxItems": { "$data": "1/maxArrayLength" } } + "array": {"maxItems": {"$data": "1/maxArrayLength"}} } }, "tests": [ diff --git a/spec/extras/$data/maxLength.json b/spec/extras/$data/maxLength.json index 9edd20fa1f..3b6a4a613a 100644 --- a/spec/extras/$data/maxLength.json +++ b/spec/extras/$data/maxLength.json @@ -4,7 +4,7 @@ "schema": { "properties": { "maximumLength": {}, - "string": { "maxLength": { "$data": "1/maximumLength" } } + "string": {"maxLength": {"$data": "1/maximumLength"}} } }, "tests": [ diff --git a/spec/extras/$data/maxProperties.json b/spec/extras/$data/maxProperties.json index 44469e038b..1b653aa26e 100644 --- a/spec/extras/$data/maxProperties.json +++ b/spec/extras/$data/maxProperties.json @@ -4,7 +4,7 @@ "schema": { "properties": { "maxKeys": {}, - "object": { "maxProperties": { "$data": "1/maxKeys" } } + "object": {"maxProperties": {"$data": "1/maxKeys"}} } }, "tests": [ diff --git a/spec/extras/$data/maximum.json b/spec/extras/$data/maximum.json index 9d99ead7e1..e9f9807c55 100644 --- a/spec/extras/$data/maximum.json +++ b/spec/extras/$data/maximum.json @@ -5,7 +5,7 @@ "properties": { "larger": {}, "smallerOrEqual": { - "maximum": { "$data": "1/larger" } + "maximum": {"$data": "1/larger"} } } }, @@ -65,7 +65,7 @@ "properties": { "number": { "maximum": 3, - "exclusiveMaximum": { "$data": "1/maxIsExclusive" } + "exclusiveMaximum": {"$data": "1/maxIsExclusive"} }, "maxIsExclusive": {} } @@ -156,8 +156,8 @@ "properties": { "larger": {}, "smallerOrEqual": { - "maximum": { "$data": "1/larger" }, - "exclusiveMaximum": { "$data": "1/maxIsExclusive" } + "maximum": {"$data": "1/larger"}, + "exclusiveMaximum": {"$data": "1/maxIsExclusive"} }, "maxIsExclusive": {} } @@ -256,7 +256,7 @@ "description": "items in array are <= than their indeces", "schema": { "items": { - "maximum": { "$data": "0#" } + "maximum": {"$data": "0#"} } }, "tests": [ diff --git a/spec/extras/$data/minItems.json b/spec/extras/$data/minItems.json index bae4d0dac3..fec3a7d593 100644 --- a/spec/extras/$data/minItems.json +++ b/spec/extras/$data/minItems.json @@ -4,7 +4,7 @@ "schema": { "properties": { "minArrayLength": {}, - "array": { "minItems": { "$data": "1/minArrayLength" } } + "array": {"minItems": {"$data": "1/minArrayLength"}} } }, "tests": [ diff --git a/spec/extras/$data/minLength.json b/spec/extras/$data/minLength.json index 71e36624f6..d4b338215d 100644 --- a/spec/extras/$data/minLength.json +++ b/spec/extras/$data/minLength.json @@ -4,7 +4,7 @@ "schema": { "properties": { "minimumLength": {}, - "string": { "minLength": { "$data": "1/minimumLength" } } + "string": {"minLength": {"$data": "1/minimumLength"}} } }, "tests": [ diff --git a/spec/extras/$data/minProperties.json b/spec/extras/$data/minProperties.json index d1393b6e4f..f8e990c6b2 100644 --- a/spec/extras/$data/minProperties.json +++ b/spec/extras/$data/minProperties.json @@ -4,7 +4,7 @@ "schema": { "properties": { "minKeys": {}, - "object": { "minProperties": { "$data": "1/minKeys" } } + "object": {"minProperties": {"$data": "1/minKeys"}} } }, "tests": [ diff --git a/spec/extras/$data/minimum.json b/spec/extras/$data/minimum.json index dc96f3a08c..00ddc30a7c 100644 --- a/spec/extras/$data/minimum.json +++ b/spec/extras/$data/minimum.json @@ -5,7 +5,7 @@ "properties": { "smaller": {}, "largerOrEqual": { - "minimum": { "$data": "1/smaller" } + "minimum": {"$data": "1/smaller"} } } }, @@ -58,7 +58,7 @@ "properties": { "number": { "minimum": 3, - "exclusiveMinimum": { "$data": "1/minIsExclusive" } + "exclusiveMinimum": {"$data": "1/minIsExclusive"} }, "minIsExclusive": {} } @@ -149,8 +149,8 @@ "properties": { "smaller": {}, "largerOrEqual": { - "minimum": { "$data": "1/smaller" }, - "exclusiveMinimum": { "$data": "1/minIsExclusive" } + "minimum": {"$data": "1/smaller"}, + "exclusiveMinimum": {"$data": "1/minIsExclusive"} }, "minIsExclusive": {} } @@ -249,7 +249,7 @@ "description": "items in array are >= than their indeces", "schema": { "items": { - "minimum": { "$data": "0#" } + "minimum": {"$data": "0#"} } }, "tests": [ diff --git a/spec/extras/$data/multipleOf.json b/spec/extras/$data/multipleOf.json index e463911d10..525e331c20 100644 --- a/spec/extras/$data/multipleOf.json +++ b/spec/extras/$data/multipleOf.json @@ -4,7 +4,7 @@ "schema": { "properties": { "divider": {}, - "multiple": { "multipleOf": { "$data": "1/divider" } } + "multiple": {"multipleOf": {"$data": "1/divider"}} } }, "tests": [ @@ -69,8 +69,8 @@ "description": "one property is multiple of another property with escaped characters", "schema": { "properties": { - "/divider~": { "type": "number" }, - "/multiple~": { "multipleOf": { "$data": "1/~1divider~0" } } + "/divider~": {"type": "number"}, + "/multiple~": {"multipleOf": {"$data": "1/~1divider~0"}} } }, "tests": [ @@ -98,12 +98,12 @@ "properties": { "divider": { "properties": { - "value": { "type": "number" } + "value": {"type": "number"} } }, "multiple": { "properties": { - "value": { "multipleOf": { "$data": "2/divider/value" } } + "value": {"multipleOf": {"$data": "2/divider/value"}} } } } @@ -112,16 +112,16 @@ { "description": "int by int valid", "data": { - "divider": { "value": 3 }, - "multiple": { "value": 12 } + "divider": {"value": 3}, + "multiple": {"value": 12} }, "valid": true }, { "description": "int by int invalid", "data": { - "divider": { "value": 3 }, - "multiple": { "value": 10 } + "divider": {"value": 3}, + "multiple": {"value": 10} }, "valid": false } @@ -130,9 +130,9 @@ { "description": "item is a multiple of its index", "schema": { - "items": [ {} ], + "items": [{}], "additionalItems": { - "multipleOf": { "$data": "0#" } + "multipleOf": {"$data": "0#"} } }, "tests": [ @@ -151,11 +151,11 @@ { "description": "item property is a multiple of item index", "schema": { - "items": [ {} ], + "items": [{}], "additionalItems": { "properties": { "value": { - "multipleOf": { "$data": "1#" } + "multipleOf": {"$data": "1#"} } } } diff --git a/spec/extras/$data/pattern.json b/spec/extras/$data/pattern.json index 76912485be..4b93aac7ab 100644 --- a/spec/extras/$data/pattern.json +++ b/spec/extras/$data/pattern.json @@ -4,7 +4,7 @@ "schema": { "properties": { "shouldMatch": {}, - "string": { "pattern": { "$data": "1/shouldMatch" } } + "string": {"pattern": {"$data": "1/shouldMatch"}} } }, "tests": [ @@ -53,18 +53,18 @@ "description": "property values should contain their names", "schema": { "additionalProperties": { - "pattern": { "$data": "0#" } + "pattern": {"$data": "0#"} } }, "tests": [ { "description": "valid property values", - "data": { "foo": "1foo", "bar": "bar2", "baz": "3baz4" }, + "data": {"foo": "1foo", "bar": "bar2", "baz": "3baz4"}, "valid": true }, { "description": "invalid property values", - "data": { "foo": "fo" }, + "data": {"foo": "fo"}, "valid": false } ] diff --git a/spec/extras/$data/required.json b/spec/extras/$data/required.json index f6c6200b28..0c29b1259d 100644 --- a/spec/extras/$data/required.json +++ b/spec/extras/$data/required.json @@ -7,7 +7,7 @@ "bar": {}, "requiredProperties": {} }, - "required": { "$data": "0/requiredProperties" } + "required": {"$data": "0/requiredProperties"} }, "tests": [ { diff --git a/spec/extras/$data/uniqueItems.json b/spec/extras/$data/uniqueItems.json index ab9486b3ae..ac97f8b768 100644 --- a/spec/extras/$data/uniqueItems.json +++ b/spec/extras/$data/uniqueItems.json @@ -4,7 +4,7 @@ "schema": { "properties": { "list": { - "uniqueItems": { "$data": "1/unique" } + "uniqueItems": {"$data": "1/unique"} }, "unique": {} } diff --git a/spec/extras/const.json b/spec/extras/const.json index a58429fcf2..c8ed9c629d 100644 --- a/spec/extras/const.json +++ b/spec/extras/const.json @@ -1,7 +1,7 @@ [ { "description": "const keyword requires the value to be equal to some constant", - "schema": { "const": 2 }, + "schema": {"const": 2}, "tests": [ { "description": "same value is valid", @@ -22,33 +22,33 @@ }, { "description": "const keyword requires the value to be equal to some object", - "schema": { "const": { "foo": "bar", "baz": "bax" } }, + "schema": {"const": {"foo": "bar", "baz": "bax"}}, "tests": [ { "description": "same object is valid", - "data": { "foo": "bar", "baz": "bax" }, + "data": {"foo": "bar", "baz": "bax"}, "valid": true }, { "description": "same object with different property order is valid", - "data": { "baz": "bax", "foo": "bar" }, + "data": {"baz": "bax", "foo": "bar"}, "valid": true }, { "description": "another object is invalid", - "data": { "foo": "bar" }, + "data": {"foo": "bar"}, "valid": false }, { "description": "another type is invalid", - "data": [ 1, 2 ], + "data": [1, 2], "valid": false } ] }, { "description": "const keyword with null", - "schema": { "const": null }, + "schema": {"const": null}, "tests": [ { "description": "null is valid", diff --git a/spec/extras/contains.json b/spec/extras/contains.json index 369c10aa83..cbcd1d323f 100644 --- a/spec/extras/contains.json +++ b/spec/extras/contains.json @@ -2,7 +2,7 @@ { "description": "contains keyword requires the item matching schema to be present", "schema": { - "contains": { "minimum": 5 } + "contains": {"minimum": 5} }, "tests": [ { @@ -35,7 +35,7 @@ { "description": "contains keyword with const keyword requires a specific item to be present", "schema": { - "contains": { "const": 5 } + "contains": {"const": 5} }, "tests": [ { diff --git a/spec/extras/propertyNames.json b/spec/extras/propertyNames.json deleted file mode 100644 index 745530f8e6..0000000000 --- a/spec/extras/propertyNames.json +++ /dev/null @@ -1,32 +0,0 @@ -[ - { - "description": "propertyNames validation", - "schema": { - "type": "object", - "propertyNames": { "format": "email" } - }, - "tests": [ - { - "description": "all property names valid", - "data": { - "foo@example.com": {}, - "bar.baz@email.example.com": {} - }, - "valid": true - }, - { - "description": "some property names invalid", - "data": { - "foo": {}, - "bar.baz@email.example.com": {} - }, - "valid": false - }, - { - "description": "object without properties is valid", - "data": {}, - "valid": true - } - ] - } -] diff --git a/spec/issues/1001_addKeyword_and_schema_without_id.spec.js b/spec/issues/1001_addKeyword_and_schema_without_id.spec.js index bc3d0d7d0c..3c00e17f04 100644 --- a/spec/issues/1001_addKeyword_and_schema_without_id.spec.js +++ b/spec/issues/1001_addKeyword_and_schema_without_id.spec.js @@ -1,20 +1,19 @@ -'use strict'; +"use strict" -var Ajv = require('../ajv'); -require('../chai').should(); +var Ajv = require("../ajv") +require("../chai").should() - -describe('issue #1001: addKeyword breaks schema without ID', function() { - it('should allow using schemas without ID with addKeyword', function() { +describe("issue #1001: addKeyword breaks schema without ID", function () { + it("should allow using schemas without ID with addKeyword", function () { var schema = { definitions: { - foo: {} - } - }; + foo: {}, + }, + } - var ajv = new Ajv(); - ajv.addSchema(schema); - ajv.addKeyword('myKeyword', {}); - ajv.getSchema('#/definitions/foo') .should.be.a('function'); - }); -}); + var ajv = new Ajv() + ajv.addSchema(schema) + ajv.addKeyword("myKeyword", {}) + ajv.getSchema("#/definitions/foo").should.be.a("function") + }) +}) diff --git a/spec/issues/181_allErrors_custom_keyword_skipped.spec.js b/spec/issues/181_allErrors_custom_keyword_skipped.spec.js index aa734aa153..e79fa641b0 100644 --- a/spec/issues/181_allErrors_custom_keyword_skipped.spec.js +++ b/spec/issues/181_allErrors_custom_keyword_skipped.spec.js @@ -1,58 +1,57 @@ -'use strict'; +"use strict" -var Ajv = require('../ajv'); -require('../chai').should(); +var Ajv = require("../ajv") +require("../chai").should() - -describe('issue #181, custom keyword is not validated in allErrors mode if there were previous error', function() { - it('should validate custom keyword that doesn\'t create errors', function() { +describe("issue #181, custom keyword is not validated in allErrors mode if there were previous error", function () { + it("should validate custom keyword that doesn't create errors", function () { testCustomKeywordErrors({ - type:'object', + type: "object", errors: true, validate: function v(/* value */) { - return false; - } - }); - }); + return false + }, + }) + }) - it('should validate custom keyword that creates errors', function() { + it("should validate custom keyword that creates errors", function () { testCustomKeywordErrors({ - type:'object', + type: "object", errors: true, validate: function v(/* value */) { - v.errors = v.errors || []; + v.errors = v.errors || [] v.errors.push({ - keyword: 'alwaysFails', - message: 'alwaysFails error', + keyword: "alwaysFails", + message: "alwaysFails error", params: { - keyword: 'alwaysFails' - } - }); + keyword: "alwaysFails", + }, + }) - return false; - } - }); - }); + return false + }, + }) + }) function testCustomKeywordErrors(def) { - var ajv = new Ajv({ allErrors: true }); + var ajv = new Ajv({allErrors: true}) - ajv.addKeyword('alwaysFails', def); + ajv.addKeyword("alwaysFails", def) var schema = { - required: ['foo'], - alwaysFails: true - }; + required: ["foo"], + alwaysFails: true, + } - var validate = ajv.compile(schema); + var validate = ajv.compile(schema) - validate({ foo: 1 }) .should.equal(false); - validate.errors .should.have.length(1); - validate.errors[0].keyword .should.equal('alwaysFails'); + validate({foo: 1}).should.equal(false) + validate.errors.should.have.length(1) + validate.errors[0].keyword.should.equal("alwaysFails") - validate({}) .should.equal(false); - validate.errors .should.have.length(2); - validate.errors[0].keyword .should.equal('required'); - validate.errors[1].keyword .should.equal('alwaysFails'); + validate({}).should.equal(false) + validate.errors.should.have.length(2) + validate.errors[0].keyword.should.equal("required") + validate.errors[1].keyword.should.equal("alwaysFails") } -}); +}) diff --git a/spec/issues/182_nan_validation.spec.js b/spec/issues/182_nan_validation.spec.js index 4d341a3c95..cdb756265f 100644 --- a/spec/issues/182_nan_validation.spec.js +++ b/spec/issues/182_nan_validation.spec.js @@ -1,26 +1,25 @@ -'use strict'; +"use strict" -var Ajv = require('../ajv'); -require('../chai').should(); +var Ajv = require("../ajv") +require("../chai").should() +describe("issue #182, NaN validation", function () { + it("should not pass minimum/maximum validation", function () { + testNaN({minimum: 1}, false) + testNaN({maximum: 1}, false) + }) -describe('issue #182, NaN validation', function() { - it('should not pass minimum/maximum validation', function() { - testNaN({ minimum: 1 }, false); - testNaN({ maximum: 1 }, false); - }); + it("should pass type: number validation", function () { + testNaN({type: "number"}, true) + }) - it('should pass type: number validation', function() { - testNaN({ type: 'number' }, true); - }); - - it('should not pass type: integer validation', function() { - testNaN({ type: 'integer' }, false); - }); + it("should not pass type: integer validation", function () { + testNaN({type: "integer"}, false) + }) function testNaN(schema, NaNisValid) { - var ajv = new Ajv; - var validate = ajv.compile(schema); - validate(NaN) .should.equal(NaNisValid); + var ajv = new Ajv() + var validate = ajv.compile(schema) + validate(NaN).should.equal(NaNisValid) } -}); +}) diff --git a/spec/issues/204_options_schemas_data_together.spec.js b/spec/issues/204_options_schemas_data_together.spec.js index 73746c17eb..1863993343 100644 --- a/spec/issues/204_options_schemas_data_together.spec.js +++ b/spec/issues/204_options_schemas_data_together.spec.js @@ -1,23 +1,22 @@ -'use strict'; +"use strict" -var Ajv = require('../ajv'); -require('../chai').should(); +var Ajv = require("../ajv") +require("../chai").should() - -describe('issue #204, options schemas and $data used together', function() { - it('should use v5 metaschemas by default', 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'}], - $data: true - }); + schemas: [{$id: "str", type: "string"}], + $data: true, + }) - var schema = { const: 42 }; - var validate = ajv.compile(schema); + var schema = {const: 42} + var validate = ajv.compile(schema) - validate(42) .should.equal(true); - validate(43) .should.equal(false); + validate(42).should.equal(true) + validate(43).should.equal(false) - ajv.validate('str', 'foo') .should.equal(true); - ajv.validate('str', 42) .should.equal(false); - }); -}); + ajv.validate("str", "foo").should.equal(true) + ajv.validate("str", 42).should.equal(false) + }) +}) diff --git a/spec/issues/210_mutual_recur_frags.spec.js b/spec/issues/210_mutual_recur_frags.spec.js index 58847f017a..4da6c4cfe7 100644 --- a/spec/issues/210_mutual_recur_frags.spec.js +++ b/spec/issues/210_mutual_recur_frags.spec.js @@ -1,79 +1,72 @@ -'use strict'; +"use strict" -var Ajv = require('../ajv'); -require('../chai').should(); +var Ajv = require("../ajv") +require("../chai").should() - -describe('issue #210, mutual recursive $refs that are schema fragments', function() { - it('should compile and validate schema when one ref is fragment', function() { - var ajv = new Ajv; +describe("issue #210, mutual recursive $refs that are schema fragments", function () { + it("should compile and validate schema when one ref is fragment", function () { + var ajv = new Ajv() ajv.addSchema({ - "$id" : "foo", - "definitions": { - "bar": { - "properties": { - "baz": { - "anyOf": [ - { "enum": [42] }, - { "$ref": "boo" } - ] - } - } - } - } - }); + $id: "foo", + definitions: { + bar: { + properties: { + baz: { + anyOf: [{enum: [42]}, {$ref: "boo"}], + }, + }, + }, + }, + }) ajv.addSchema({ - "$id" : "boo", - "type": "object", - "required": ["quux"], - "properties": { - "quux": { "$ref": "foo#/definitions/bar" } - } - }); + $id: "boo", + type: "object", + required: ["quux"], + properties: { + quux: {$ref: "foo#/definitions/bar"}, + }, + }) - var validate = ajv.compile({ "$ref": "foo#/definitions/bar" }); + var validate = ajv.compile({$ref: "foo#/definitions/bar"}) - validate({ baz: { quux: { baz: 42 } } }) .should.equal(true); - validate({ baz: { quux: { baz: "foo" } } }) .should.equal(false); - }); + validate({baz: {quux: {baz: 42}}}).should.equal(true) + validate({baz: {quux: {baz: "foo"}}}).should.equal(false) + }) - it('should compile and validate schema when both refs are fragments', function() { - var ajv = new Ajv; + it("should compile and validate schema when both refs are fragments", function () { + var ajv = new Ajv() ajv.addSchema({ - "$id" : "foo", - "definitions": { - "bar": { - "properties": { - "baz": { - "anyOf": [ - { "enum": [42] }, - { "$ref": "boo#/definitions/buu" } - ] - } - } - } - } - }); + $id: "foo", + definitions: { + bar: { + properties: { + baz: { + anyOf: [{enum: [42]}, {$ref: "boo#/definitions/buu"}], + }, + }, + }, + }, + }) ajv.addSchema({ - "$id" : "boo", - "definitions": { - "buu": { - "type": "object", - "required": ["quux"], - "properties": { - "quux": { "$ref": "foo#/definitions/bar" } - } - } - } - }); + $id: "boo", + definitions: { + buu: { + type: "object", + required: ["quux"], + properties: { + quux: {$ref: "foo#/definitions/bar"}, + }, + }, + }, + }) - var validate = ajv.compile({ "$ref": "foo#/definitions/bar" }); + var validate = ajv.compile({$ref: "foo#/definitions/bar"}) - validate({ baz: { quux: { baz: 42 } } }) .should.equal(true); - validate({ baz: { quux: { baz: "foo" } } }) .should.equal(false); - }); -}); + validate({baz: {quux: {baz: 42}}}).should.equal(true) + validate({baz: {quux: {baz: "foo"}}}).should.equal(false) + }) +}) diff --git a/spec/issues/240_mutual_recur_frags_common_ref.spec.js b/spec/issues/240_mutual_recur_frags_common_ref.spec.js index d9e40241dd..9bcbc076d4 100644 --- a/spec/issues/240_mutual_recur_frags_common_ref.spec.js +++ b/spec/issues/240_mutual_recur_frags_common_ref.spec.js @@ -1,210 +1,210 @@ -'use strict'; +"use strict" -var Ajv = require('../ajv'); -require('../chai').should(); +var Ajv = require("../ajv") +require("../chai").should() - -describe('issue #240, mutually recursive fragment refs reference a common schema', function() { +describe("issue #240, mutually recursive fragment refs reference a common schema", function () { var apiSchema = { - $schema: 'http://json-schema.org/draft-07/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' } - } + id: {type: "string"}, + }, }, resourceIdentifier: { - $id: '#resource_identifier', + $id: "#resource_identifier", properties: { - id: { type: 'string' }, - type: { type: 'string' } - } - } - }; + id: {type: "string"}, + type: {type: "string"}, + }, + }, + } var domainSchema = { - $schema: 'http://json-schema.org/draft-07/schema#', - $id: 'schema://domain.schema#', + $schema: "http://json-schema.org/draft-07/schema#", + $id: "schema://domain.schema#", properties: { data: { oneOf: [ - { $ref: 'schema://library.schema#resource_identifier' }, - { $ref: 'schema://catalog_item.schema#resource_identifier' }, - ] - } - } - }; + {$ref: "schema://library.schema#resource_identifier"}, + {$ref: "schema://catalog_item.schema#resource_identifier"}, + ], + }, + }, + } - it('should compile and validate schema when one ref is fragment', function() { - var ajv = new Ajv; + it("should compile and validate schema when one ref is fragment", function () { + var ajv = new Ajv() var librarySchema = { - $schema: 'http://json-schema.org/draft-07/schema#', - $id: 'schema://library.schema#', + $schema: "http://json-schema.org/draft-07/schema#", + $id: "schema://library.schema#", properties: { - name: { type: 'string' }, + name: {type: "string"}, links: { properties: { catalogItems: { - type: 'array', - items: { $ref: 'schema://catalog_item_resource_identifier.schema#' } - } - } - } + type: "array", + items: { + $ref: "schema://catalog_item_resource_identifier.schema#", + }, + }, + }, + }, }, definitions: { resource_identifier: { - $id: '#resource_identifier', + $id: "#resource_identifier", allOf: [ { properties: { type: { - type: 'string', - 'enum': ['Library'] - } - } + type: "string", + enum: ["Library"], + }, + }, }, - { $ref: 'schema://api.schema#resource_identifier' } - ] - } - } - }; + {$ref: "schema://api.schema#resource_identifier"}, + ], + }, + }, + } var catalogItemSchema = { - $schema: 'http://json-schema.org/draft-07/schema#', - $id: 'schema://catalog_item.schema#', + $schema: "http://json-schema.org/draft-07/schema#", + $id: "schema://catalog_item.schema#", properties: { - name: { type: 'string' }, + name: {type: "string"}, links: { properties: { - library: { $ref: 'schema://library.schema#resource_identifier' } - } - } + library: {$ref: "schema://library.schema#resource_identifier"}, + }, + }, }, definitions: { resource_identifier: { - $id: '#resource_identifier', + $id: "#resource_identifier", allOf: [ { properties: { type: { - type: 'string', - 'enum': ['CatalogItem'] - } - } + type: "string", + enum: ["CatalogItem"], + }, + }, }, - { $ref: 'schema://api.schema#resource_identifier' } - ] - } - } - }; + {$ref: "schema://api.schema#resource_identifier"}, + ], + }, + }, + } var catalogItemResourceIdentifierSchema = { - $schema: 'http://json-schema.org/draft-07/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: { type: { - type: 'string', - enum: ['CatalogItem'] - } - } + type: "string", + enum: ["CatalogItem"], + }, + }, }, { - $ref: 'schema://api.schema#resource_identifier' - } - ] - }; + $ref: "schema://api.schema#resource_identifier", + }, + ], + } - ajv.addSchema(librarySchema); - ajv.addSchema(catalogItemSchema); - ajv.addSchema(catalogItemResourceIdentifierSchema); - ajv.addSchema(apiSchema); + ajv.addSchema(librarySchema) + ajv.addSchema(catalogItemSchema) + ajv.addSchema(catalogItemResourceIdentifierSchema) + ajv.addSchema(apiSchema) - var validate = ajv.compile(domainSchema); - testSchema(validate); - }); + var validate = ajv.compile(domainSchema) + testSchema(validate) + }) - it('should compile and validate schema when both refs are fragments', function() { - var ajv = new Ajv; + it("should compile and validate schema when both refs are fragments", function () { + var ajv = new Ajv() var librarySchema = { - $schema: 'http://json-schema.org/draft-07/schema#', - $id: 'schema://library.schema#', + $schema: "http://json-schema.org/draft-07/schema#", + $id: "schema://library.schema#", properties: { - name: { type: 'string' }, + name: {type: "string"}, links: { properties: { catalogItems: { - type: 'array', - items: { $ref: 'schema://catalog_item.schema#resource_identifier' } - } - } - } + type: "array", + items: {$ref: "schema://catalog_item.schema#resource_identifier"}, + }, + }, + }, }, definitions: { resource_identifier: { - $id: '#resource_identifier', + $id: "#resource_identifier", allOf: [ { properties: { type: { - type: 'string', - 'enum': ['Library'] - } - } + type: "string", + enum: ["Library"], + }, + }, }, - { $ref: 'schema://api.schema#resource_identifier' } - ] - } - } - }; + {$ref: "schema://api.schema#resource_identifier"}, + ], + }, + }, + } var catalogItemSchema = { - $schema: 'http://json-schema.org/draft-07/schema#', - $id: 'schema://catalog_item.schema#', + $schema: "http://json-schema.org/draft-07/schema#", + $id: "schema://catalog_item.schema#", properties: { - name: { type: 'string' }, + name: {type: "string"}, links: { properties: { - library: { $ref: 'schema://library.schema#resource_identifier' } - } - } + library: {$ref: "schema://library.schema#resource_identifier"}, + }, + }, }, definitions: { resource_identifier: { - $id: '#resource_identifier', + $id: "#resource_identifier", allOf: [ { properties: { type: { - type: 'string', - 'enum': ['CatalogItem'] - } - } + type: "string", + enum: ["CatalogItem"], + }, + }, }, - { $ref: 'schema://api.schema#resource_identifier' } - ] - } - } - }; - - ajv.addSchema(librarySchema); - ajv.addSchema(catalogItemSchema); - ajv.addSchema(apiSchema); + {$ref: "schema://api.schema#resource_identifier"}, + ], + }, + }, + } - var validate = ajv.compile(domainSchema); - testSchema(validate); - }); + ajv.addSchema(librarySchema) + ajv.addSchema(catalogItemSchema) + ajv.addSchema(apiSchema) + var validate = ajv.compile(domainSchema) + testSchema(validate) + }) function testSchema(validate) { - validate({ data: { type: 'Library', id: '123' } }) .should.equal(true); - validate({ data: { type: 'Library', id: 123 } }) .should.equal(false); - validate({ data: { type: 'CatalogItem', id: '123' } }) .should.equal(true); - validate({ data: { type: 'CatalogItem', id: 123 } }) .should.equal(false); - validate({ data: { type: 'Foo', id: '123' } }) .should.equal(false); + validate({data: {type: "Library", id: "123"}}).should.equal(true) + validate({data: {type: "Library", id: 123}}).should.equal(false) + validate({data: {type: "CatalogItem", id: "123"}}).should.equal(true) + validate({data: {type: "CatalogItem", id: 123}}).should.equal(false) + validate({data: {type: "Foo", id: "123"}}).should.equal(false) } -}); +}) diff --git a/spec/issues/259_validate_meta_against_itself.spec.js b/spec/issues/259_validate_meta_against_itself.spec.js index d99fc21efd..ff9cffd6a6 100644 --- a/spec/issues/259_validate_meta_against_itself.spec.js +++ b/spec/issues/259_validate_meta_against_itself.spec.js @@ -1,13 +1,12 @@ -'use strict'; +"use strict" -var Ajv = require('../ajv'); -require('../chai').should(); +var Ajv = require("../ajv") +require("../chai").should() - -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; - var hyperSchema = require('../remotes/hyper-schema.json'); - ajv.addMetaSchema(hyperSchema); - }); -}); +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() + var hyperSchema = require("../remotes/hyper-schema.json") + ajv.addMetaSchema(hyperSchema) + }) +}) diff --git a/spec/issues/273_error_schemaPath_refd_schema.spec.js b/spec/issues/273_error_schemaPath_refd_schema.spec.js index 9271640872..f8242643c2 100644 --- a/spec/issues/273_error_schemaPath_refd_schema.spec.js +++ b/spec/issues/273_error_schemaPath_refd_schema.spec.js @@ -1,31 +1,30 @@ -'use strict'; +"use strict" -var Ajv = require('../ajv'); -require('../chai').should(); +var Ajv = require("../ajv") +require("../chai").should() - -describe.skip('issue #273, schemaPath in error in referenced schema', function() { - it('should have canonic reference with hash after file name', function() { - test(new Ajv); - test(new Ajv({inlineRefs: false})); +describe.skip("issue #273, schemaPath in error in referenced schema", function () { + it("should have canonic reference with hash after file name", function () { + test(new Ajv()) + test(new Ajv({inlineRefs: false})) function test(ajv) { var schema = { - "properties": { - "a": { "$ref": "int" } - } - }; + properties: { + a: {$ref: "int"}, + }, + } var referencedSchema = { - "id": "int", - "type": "integer" - }; + id: "int", + type: "integer", + } - ajv.addSchema(referencedSchema); - var validate = ajv.compile(schema); + ajv.addSchema(referencedSchema) + var validate = ajv.compile(schema) - validate({ "a": "foo" }) .should.equal(false); - validate.errors[0].schemaPath .should.equal('int#/type'); + validate({a: "foo"}).should.equal(false) + validate.errors[0].schemaPath.should.equal("int#/type") } - }); -}); + }) +}) diff --git a/spec/issues/342_uniqueItems_non-json_objects.spec.js b/spec/issues/342_uniqueItems_non-json_objects.spec.js index ae7eee0cf1..81ca66bad5 100644 --- a/spec/issues/342_uniqueItems_non-json_objects.spec.js +++ b/spec/issues/342_uniqueItems_non-json_objects.spec.js @@ -1,33 +1,36 @@ -'use strict'; +"use strict" -var Ajv = require('../ajv'); -require('../chai').should(); +var Ajv = require("../ajv") +require("../chai").should() +describe("issue #342, support uniqueItems with some non-JSON objects", function () { + var validate -describe('issue #342, support uniqueItems with some non-JSON objects', function() { - var validate; + before(function () { + var ajv = new Ajv() + validate = ajv.compile({uniqueItems: true}) + }) - before(function() { - var ajv = new Ajv; - validate = ajv.compile({ uniqueItems: true }); - }); + it("should allow different RegExps", function () { + validate([/foo/, /bar/]).should.equal(true) + validate([/foo/gi, /foo/gi]).should.equal(false) + validate([/foo/, {}]).should.equal(true) + }) - it('should allow different RegExps', function() { - validate([/foo/, /bar/]) .should.equal(true); - validate([/foo/ig, /foo/gi]) .should.equal(false); - validate([/foo/, {}]) .should.equal(true); - }); + it("should allow different Dates", function () { + validate([new Date("2016-11-11"), new Date("2016-11-12")]).should.equal( + true + ) + validate([new Date("2016-11-11"), new Date("2016-11-11")]).should.equal( + false + ) + validate([new Date("2016-11-11"), {}]).should.equal(true) + }) - it('should allow different Dates', function() { - validate([new Date('2016-11-11'), new Date('2016-11-12')]) .should.equal(true); - validate([new Date('2016-11-11'), new Date('2016-11-11')]) .should.equal(false); - validate([new Date('2016-11-11'), {}]) .should.equal(true); - }); - - it('should allow undefined properties', function() { - validate([{}, {foo: undefined}]) .should.equal(true); - validate([{foo: undefined}, {}]) .should.equal(true); - validate([{foo: undefined}, {bar: undefined}]) .should.equal(true); - validate([{foo: undefined}, {foo: undefined}]) .should.equal(false); - }); -}); + it("should allow undefined properties", function () { + validate([{}, {foo: undefined}]).should.equal(true) + validate([{foo: undefined}, {}]).should.equal(true) + validate([{foo: undefined}, {bar: undefined}]).should.equal(true) + validate([{foo: undefined}, {foo: undefined}]).should.equal(false) + }) +}) diff --git a/spec/issues/485_type_validation_priority.spec.js b/spec/issues/485_type_validation_priority.spec.js index eb2b1e9df3..a05b28c151 100644 --- a/spec/issues/485_type_validation_priority.spec.js +++ b/spec/issues/485_type_validation_priority.spec.js @@ -1,32 +1,31 @@ -'use strict'; +"use strict" -var Ajv = require('../ajv'); -require('../chai').should(); +var Ajv = require("../ajv") +require("../chai").should() - -describe('issue #485, order of type validation', function() { - it('should validate types before keywords', function() { - var ajv = new Ajv({allErrors: true}); +describe("issue #485, order of type validation", function () { + it("should validate types before keywords", function () { + var ajv = new Ajv({allErrors: true}) var validate = ajv.compile({ - type: ['integer', 'string'], - required: ['foo'], - minimum: 2 - }); + type: ["integer", "string"], + required: ["foo"], + minimum: 2, + }) - validate(2) .should.equal(true); - validate('foo') .should.equal(true); + validate(2).should.equal(true) + validate("foo").should.equal(true) - validate(1.5) .should.equal(false); - checkErrors(['type', 'minimum']); + validate(1.5).should.equal(false) + checkErrors(["type", "minimum"]) - validate({}) .should.equal(false); - checkErrors(['type', 'required']); + validate({}).should.equal(false) + checkErrors(["type", "required"]) function checkErrors(expectedErrs) { - validate.errors .should.have.length(expectedErrs.length); + validate.errors.should.have.length(expectedErrs.length) expectedErrs.forEach(function (keyword, i) { - validate.errors[i].keyword .should.equal(keyword); - }); + validate.errors[i].keyword.should.equal(keyword) + }) } - }); -}); + }) +}) diff --git a/spec/issues/50_refs_with_definitions.spec.js b/spec/issues/50_refs_with_definitions.spec.js index 26b84a8cc2..4750d9101b 100644 --- a/spec/issues/50_refs_with_definitions.spec.js +++ b/spec/issues/50_refs_with_definitions.spec.js @@ -1,49 +1,48 @@ -'use strict'; - -var Ajv = require('../ajv'); -var should = require('../chai').should(); +"use strict" +var Ajv = require("../ajv") +var should = require("../chai").should() describe('issue #50: references with "definitions"', function () { - it('should be supported by addSchema', spec('addSchema')); + it("should be supported by addSchema", spec("addSchema")) - it('should be supported by compile', spec('addSchema')); + it("should be supported by compile", spec("addSchema")) function spec(method) { - return function() { - var result; + return function () { + var result - var ajv = new Ajv; + var ajv = new Ajv() ajv[method]({ - $id: 'http://example.com/test/person.json#', + $id: "http://example.com/test/person.json#", definitions: { - name: { type: 'string' } + name: {type: "string"}, }, - type: 'object', + type: "object", properties: { - name: { $ref: '#/definitions/name'} - } - }); + name: {$ref: "#/definitions/name"}, + }, + }) ajv[method]({ - $id: 'http://example.com/test/employee.json#', - type: 'object', + $id: "http://example.com/test/employee.json#", + type: "object", properties: { - person: { $ref: '/test/person.json#' }, - role: { type: 'string' } - } - }); + person: {$ref: "/test/person.json#"}, + role: {type: "string"}, + }, + }) - result = ajv.validate('http://example.com/test/employee.json#', { + result = ajv.validate("http://example.com/test/employee.json#", { person: { - name: 'Alice' + name: "Alice", }, - role: 'Programmer' - }); + role: "Programmer", + }) - result. should.equal(true); - should.equal(ajv.errors, null); - }; + result.should.equal(true) + should.equal(ajv.errors, null) + } } -}); +}) diff --git a/spec/issues/521_wrong_warning_id_property.spec.js b/spec/issues/521_wrong_warning_id_property.spec.js index 79fbbce7ed..308ebe662b 100644 --- a/spec/issues/521_wrong_warning_id_property.spec.js +++ b/spec/issues/521_wrong_warning_id_property.spec.js @@ -1,28 +1,27 @@ -'use strict'; +"use strict" -var Ajv = require('../ajv'); -require('../chai').should(); +var Ajv = require("../ajv") +require("../chai").should() - -describe('issue #521, incorrect warning with "id" property', function() { - it('should not log warning', function() { - var ajv = new Ajv({schemaId: '$id'}); - var consoleWarn = console.warn; - console.warn = function() { - throw new Error('should not log warning'); - }; +describe('issue #521, incorrect warning with "id" property', function () { + it("should not log warning", function () { + var ajv = new Ajv({schemaId: "$id"}) + var consoleWarn = console.warn + console.warn = function () { + throw new Error("should not log warning") + } try { ajv.compile({ - "$id": "http://example.com/schema.json", - "type": "object", - "properties": { - "id": {"type": "string"}, + $id: "http://example.com/schema.json", + type: "object", + properties: { + id: {type: "string"}, }, - "required": [ "id"] - }); + required: ["id"], + }) } finally { - console.warn = consoleWarn; + console.warn = consoleWarn } - }); -}); + }) +}) diff --git a/spec/issues/533_missing_ref_error_when_ignore.spec.js b/spec/issues/533_missing_ref_error_when_ignore.spec.js index 4e77d5fc65..933544f574 100644 --- a/spec/issues/533_missing_ref_error_when_ignore.spec.js +++ b/spec/issues/533_missing_ref_error_when_ignore.spec.js @@ -1,29 +1,28 @@ -'use strict'; +"use strict" -var Ajv = require('../ajv'); -var should = require('../chai').should(); +var Ajv = require("../ajv") +var should = require("../chai").should() - -describe('issue #533, throwing missing ref exception with option missingRefs: "ignore"', function() { +describe('issue #533, throwing missing ref exception with option missingRefs: "ignore"', function () { var schema = { - "type": "object", - "properties": { - "foo": {"$ref": "#/definitions/missing"}, - "bar": {"$ref": "#/definitions/missing"} - } - }; + type: "object", + properties: { + foo: {$ref: "#/definitions/missing"}, + bar: {$ref: "#/definitions/missing"}, + }, + } - it('should pass validation without throwing exception', function() { - var ajv = new Ajv({missingRefs: 'ignore'}); - var validate = ajv.compile(schema); - validate({foo: 'anything'}) .should.equal(true); - validate({foo: 'anything', bar: 'whatever'}) .should.equal(true); - }); + it("should pass validation without throwing exception", function () { + var ajv = new Ajv({missingRefs: "ignore"}) + var validate = ajv.compile(schema) + validate({foo: "anything"}).should.equal(true) + validate({foo: "anything", bar: "whatever"}).should.equal(true) + }) - it('should throw exception during schema compilation with option missingRefs: true', function() { - var ajv = new Ajv; - should.throw(function() { - ajv.compile(schema); - }); - }); -}); + it("should throw exception during schema compilation with option missingRefs: true", function () { + var ajv = new Ajv() + should.throw(function () { + ajv.compile(schema) + }) + }) +}) diff --git a/spec/issues/617_full_format_leap_year.spec.js b/spec/issues/617_full_format_leap_year.spec.js deleted file mode 100644 index 995c4ba13c..0000000000 --- a/spec/issues/617_full_format_leap_year.spec.js +++ /dev/null @@ -1,47 +0,0 @@ -'use strict'; - -var Ajv = require('../ajv'); -require('../chai').should(); - - -describe('PR #617, 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); - }); -}); diff --git a/spec/issues/743_removeAdditional_to_remove_proto.spec.js b/spec/issues/743_removeAdditional_to_remove_proto.spec.js index f5a01926de..6f8b5c0385 100644 --- a/spec/issues/743_removeAdditional_to_remove_proto.spec.js +++ b/spec/issues/743_removeAdditional_to_remove_proto.spec.js @@ -1,41 +1,40 @@ -'use strict'; +"use strict" -var Ajv = require('../ajv'); -require('../chai').should(); +var Ajv = require("../ajv") +require("../chai").should() - -describe('issue #743, property __proto__ should be removed with removeAdditional option', function() { - it('should remove additional properties', function() { - var ajv = new Ajv({removeAdditional: true}); +describe("issue #743, property __proto__ should be removed with removeAdditional option", function () { + it("should remove additional properties", function () { + var ajv = new Ajv({removeAdditional: true}) var schema = { properties: { obj: { additionalProperties: false, properties: { - a: { type: 'string' }, - b: { type: 'string' }, - c: { type: 'string' }, - d: { type: 'string' }, - e: { type: 'string' }, - f: { type: 'string' }, - g: { type: 'string' }, - h: { type: 'string' }, - i: { type: 'string' } - } - } - } - }; + a: {type: "string"}, + b: {type: "string"}, + c: {type: "string"}, + d: {type: "string"}, + e: {type: "string"}, + f: {type: "string"}, + g: {type: "string"}, + h: {type: "string"}, + i: {type: "string"}, + }, + }, + }, + } - var obj= Object.create(null); - obj.__proto__ = null; // should be removed - obj.additional = 'will be removed'; - obj.a = 'valid'; - obj.b = 'valid'; + var obj = Object.create(null) + obj.__proto__ = null // should be removed + obj.additional = "will be removed" + obj.a = "valid" + obj.b = "valid" - var data = {obj: obj}; + var data = {obj: obj} - ajv.validate(schema, data) .should.equal(true); - Object.keys(data.obj) .should.eql(['a', 'b']); - }); -}); + ajv.validate(schema, data).should.equal(true) + Object.keys(data.obj).should.eql(["a", "b"]) + }) +}) diff --git a/spec/issues/768_passContext_recursive_ref.spec.js b/spec/issues/768_passContext_recursive_ref.spec.js index 3410f74626..c820f34581 100644 --- a/spec/issues/768_passContext_recursive_ref.spec.js +++ b/spec/issues/768_passContext_recursive_ref.spec.js @@ -1,114 +1,112 @@ -'use strict'; - -var Ajv = require('../ajv'); -require('../chai').should(); - - -describe('issue #768, fix passContext in recursive $ref', function() { - var ajv, contexts; - - beforeEach(function() { - contexts = []; - }); - - describe('passContext = true', function() { - it('should pass this value as context to custom keyword validation function', function() { - var validate = getValidate(true); - var self = {}; - validate.call(self, { bar: 'a', baz: { bar: 'b' } }); - contexts .should.have.length(2); - contexts.forEach(function(ctx) { - ctx .should.equal(self); - }); - }); - }); - - describe('passContext = false', function() { - it('should pass ajv instance as context to custom keyword validation function', function() { - var validate = getValidate(false); - validate({ bar: 'a', baz: { bar: 'b' } }); - contexts .should.have.length(2); - contexts.forEach(function(ctx) { - ctx .should.equal(ajv); - }); - }); - }); - - describe('ref is fragment and passContext = true', function() { - it('should pass this value as context to custom keyword validation function', function() { - var validate = getValidateFragments(true); - var self = {}; - validate.call(self, { baz: { corge: 'a', quux: { baz: { corge: 'b' } } } }); - contexts .should.have.length(2); - contexts.forEach(function(ctx) { - ctx .should.equal(self); - }); - }); - }); - - describe('ref is fragment and passContext = false', function() { - it('should pass ajv instance as context to custom keyword validation function', function() { - var validate = getValidateFragments(false); - validate({ baz: { corge: 'a', quux: { baz: { corge: 'b' } } } }); - contexts .should.have.length(2); - contexts.forEach(function(ctx) { - ctx .should.equal(ajv); - }); - }); - }); +"use strict" + +var Ajv = require("../ajv") +require("../chai").should() + +describe("issue #768, fix passContext in recursive $ref", function () { + var ajv, contexts + + beforeEach(function () { + contexts = [] + }) + + describe("passContext = true", function () { + it("should pass this value as context to custom keyword validation function", function () { + var validate = getValidate(true) + var self = {} + validate.call(self, {bar: "a", baz: {bar: "b"}}) + contexts.should.have.length(2) + contexts.forEach(function (ctx) { + ctx.should.equal(self) + }) + }) + }) + + describe("passContext = false", function () { + it("should pass ajv instance as context to custom keyword validation function", function () { + var validate = getValidate(false) + validate({bar: "a", baz: {bar: "b"}}) + contexts.should.have.length(2) + contexts.forEach(function (ctx) { + ctx.should.equal(ajv) + }) + }) + }) + + describe("ref is fragment and passContext = true", function () { + it("should pass this value as context to custom keyword validation function", function () { + var validate = getValidateFragments(true) + var self = {} + validate.call(self, {baz: {corge: "a", quux: {baz: {corge: "b"}}}}) + contexts.should.have.length(2) + contexts.forEach(function (ctx) { + ctx.should.equal(self) + }) + }) + }) + + describe("ref is fragment and passContext = false", function () { + it("should pass ajv instance as context to custom keyword validation function", function () { + var validate = getValidateFragments(false) + validate({baz: {corge: "a", quux: {baz: {corge: "b"}}}}) + contexts.should.have.length(2) + contexts.forEach(function (ctx) { + ctx.should.equal(ajv) + }) + }) + }) function getValidate(passContext) { - ajv = new Ajv({ passContext: passContext }); - ajv.addKeyword('testValidate', { validate: storeContext }); + ajv = new Ajv({passContext: passContext}) + ajv.addKeyword("testValidate", {validate: storeContext}) var schema = { - "$id" : "foo", - "type": "object", - "required": ["bar"], - "properties": { - "bar": { "testValidate": true }, - "baz": { - "$ref": "foo" - } - } - }; - - return ajv.compile(schema); + $id: "foo", + type: "object", + required: ["bar"], + properties: { + bar: {testValidate: true}, + baz: { + $ref: "foo", + }, + }, + } + + return ajv.compile(schema) } - function getValidateFragments(passContext) { - ajv = new Ajv({ passContext: passContext }); - ajv.addKeyword('testValidate', { validate: storeContext }); + ajv = new Ajv({passContext: passContext}) + ajv.addKeyword("testValidate", {validate: storeContext}) ajv.addSchema({ - "$id" : "foo", - "definitions": { - "bar": { - "properties": { - "baz": { - "$ref": "boo" - } - } - } - } - }); + $id: "foo", + definitions: { + bar: { + properties: { + baz: { + $ref: "boo", + }, + }, + }, + }, + }) ajv.addSchema({ - "$id" : "boo", - "type": "object", - "required": ["corge"], - "properties": { - "quux": { "$ref": "foo#/definitions/bar" }, - "corge": { "testValidate": true } - } - }); - - return ajv.compile({ "$ref": "foo#/definitions/bar" }); + $id: "boo", + type: "object", + required: ["corge"], + properties: { + quux: {$ref: "foo#/definitions/bar"}, + corge: {testValidate: true}, + }, + }) + + return ajv.compile({$ref: "foo#/definitions/bar"}) } function storeContext() { - contexts.push(this); - return true; + contexts.push(this) + return true } -}); +}) diff --git a/spec/issues/8_shared_refs.spec.js b/spec/issues/8_shared_refs.spec.js index 2208f452e6..9b13c31057 100644 --- a/spec/issues/8_shared_refs.spec.js +++ b/spec/issues/8_shared_refs.spec.js @@ -1,40 +1,39 @@ -'use strict'; +"use strict" -var Ajv = require('../ajv'); -require('../chai').should(); +var Ajv = require("../ajv") +require("../chai").should() +describe("issue #8: schema with shared references", function () { + it("should be supported by addSchema", spec("addSchema")) -describe('issue #8: schema with shared references', function() { - it('should be supported by addSchema', spec('addSchema')); - - it('should be supported by compile', spec('compile')); + it("should be supported by compile", spec("compile")) function spec(method) { - return function() { - var ajv = new Ajv; + return function () { + var ajv = new Ajv() var propertySchema = { - type: 'string', - maxLength: 4 - }; + type: "string", + maxLength: 4, + } var schema = { - $id: 'obj.json#', - type: 'object', + $id: "obj.json#", + type: "object", properties: { foo: propertySchema, - bar: propertySchema - } - }; + bar: propertySchema, + }, + } - ajv[method](schema); + ajv[method](schema) - var result = ajv.validate('obj.json#', { foo: 'abc', bar: 'def' }); - result .should.equal(true); + var result = ajv.validate("obj.json#", {foo: "abc", bar: "def"}) + result.should.equal(true) - result = ajv.validate('obj.json#', { foo: 'abcde', bar: 'fghg' }); - result .should.equal(false); - ajv.errors .should.have.length(1); - }; + result = ajv.validate("obj.json#", {foo: "abcde", bar: "fghg"}) + result.should.equal(false) + ajv.errors.should.have.length(1) + } } -}); +}) diff --git a/spec/issues/955_removeAdditional_custom_keywords.spec.js b/spec/issues/955_removeAdditional_custom_keywords.spec.js index 4ef949d608..7735a590f7 100644 --- a/spec/issues/955_removeAdditional_custom_keywords.spec.js +++ b/spec/issues/955_removeAdditional_custom_keywords.spec.js @@ -1,48 +1,47 @@ -'use strict'; +"use strict" -var Ajv = require('../ajv'); -require('../chai').should(); +var Ajv = require("../ajv") +require("../chai").should() +describe("issue #955: option removeAdditional breaks custom keywords", function () { + it("should support custom keywords with option removeAdditional", function () { + var ajv = new Ajv({removeAdditional: "all"}) -describe('issue #955: option removeAdditional breaks custom keywords', function() { - it('should support custom keywords with option removeAdditional', function() { - var ajv = new Ajv({removeAdditional: 'all'}); - - ajv.addKeyword('minTrimmedLength', { - type: 'string', - compile: function(schema) { - return function(str) { - return str.trim().length >= schema; - }; + ajv.addKeyword("minTrimmedLength", { + type: "string", + compile: function (schema) { + return function (str) { + return str.trim().length >= schema + } }, - metaSchema: {type: 'integer'} - }); + metaSchema: {type: "integer"}, + }) var schema = { - type: 'object', + type: "object", properties: { foo: { - type: 'string', - minTrimmedLength: 3 - } + type: "string", + minTrimmedLength: 3, + }, }, - required: ['foo'] - }; + required: ["foo"], + } - var validate = ajv.compile(schema); + var validate = ajv.compile(schema) var data = { - foo: ' bar ', - baz: '' - }; - validate(data) .should.equal(true); - data .should.not.have.property('baz'); + foo: " bar ", + baz: "", + } + validate(data).should.equal(true) + data.should.not.have.property("baz") data = { - foo: ' ba ', - baz: '' - }; - validate(data) .should.equal(false); - data .should.not.have.property('baz'); - }); -}); + foo: " ba ", + baz: "", + } + validate(data).should.equal(false) + data.should.not.have.property("baz") + }) +}) diff --git a/spec/json-schema.spec.js b/spec/json-schema.spec.js index 48bce96188..3505763ab4 100644 --- a/spec/json-schema.spec.js +++ b/spec/json-schema.spec.js @@ -1,68 +1,117 @@ -'use strict'; +"use strict" -var jsonSchemaTest = require('json-schema-test') - , getAjvInstances = require('./ajv_instances') - , options = require('./ajv_options') - , suite = require('./browser_test_suite') - , after = require('./after_test'); +var jsonSchemaTest = require("json-schema-test"), + getAjvInstances = require("./ajv_instances"), + options = require("./ajv_options"), + suite = require("./browser_test_suite"), + after = require("./after_test") var remoteRefs = { - 'http://localhost:1234/integer.json': require('./JSON-Schema-Test-Suite/remotes/integer.json'), - 'http://localhost:1234/subSchemas.json': require('./JSON-Schema-Test-Suite/remotes/subSchemas.json'), - 'http://localhost:1234/folder/folderInteger.json': require('./JSON-Schema-Test-Suite/remotes/folder/folderInteger.json'), - 'http://localhost:1234/name.json': require('./JSON-Schema-Test-Suite/remotes/name.json') -}; + "http://localhost:1234/integer.json": require("./JSON-Schema-Test-Suite/remotes/integer.json"), + "http://localhost:1234/subSchemas.json": require("./JSON-Schema-Test-Suite/remotes/subSchemas.json"), + "http://localhost:1234/folder/folderInteger.json": require("./JSON-Schema-Test-Suite/remotes/folder/folderInteger.json"), + "http://localhost:1234/name.json": require("./JSON-Schema-Test-Suite/remotes/name.json"), +} var SKIP = { - 4: ['optional/zeroTerminatedFloats'], + 4: [ + "optional/zeroTerminatedFloats", + "optional/ecmascript-regex", // TODO only format needs to be skipped, too much is skipped here + "optional/format", + ], + 6: [ + "optional/ecmascript-regex", // TODO only format needs to be skipped, too much is skipped here + "optional/format", + ], 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'); + "optional/ecmascript-regex", // TODO only format needs to be skipped, too much is skipped here + "optional/content", + "format/date", + "format/date-time", + "format/email", + "format/hostname", + "format/idn-email", + "format/idn-hostname", + "format/ipv4", + "format/ipv6", + "format/iri", + "format/iri-reference", + "format/json-pointer", + "format/regex", + "format/relative-json-pointer", + "format/time", + "format/uri", + "format/uri-reference", + "format/uri-template", + ], +} -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, {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), 7, typeof window == 'object' - ? suite(require('./JSON-Schema-Test-Suite/tests/draft7/{**/,}*.json', {mode: 'list'})) - : './JSON-Schema-Test-Suite/tests/draft7/{**/,}*.json'); +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) { 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; + 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; + 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); - }); + 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', + description: + "JSON-Schema Test Suite draft-0" + + draft + + ": " + + instances.length + + " ajv instances with different options", suites: {tests: tests}, only: [], skip: SKIP[draft], - assert: require('./chai').assert, + assert: require("./chai").assert, afterError: after.error, afterEach: after.each, cwd: __dirname, - hideFolder: 'draft' + draft + '/', - timeout: 120000 - }); + hideFolder: "draft" + draft + "/", + timeout: 120000, + }) } diff --git a/spec/options/comment.spec.js b/spec/options/comment.spec.js index efdc98b5ef..154626c64e 100644 --- a/spec/options/comment.spec.js +++ b/spec/options/comment.spec.js @@ -1,92 +1,95 @@ -'use strict'; +"use strict" -var Ajv = require('../ajv'); -require('../chai').should(); +var Ajv = require("../ajv") +require("../chai").should() - -describe('$comment option', function() { - describe('= true', function() { - var logCalls, consoleLog; +describe("$comment option", function () { + describe("= true", function () { + var logCalls, consoleLog beforeEach(function () { - consoleLog = console.log; - console.log = log; - }); + consoleLog = console.log + console.log = log + }) afterEach(function () { - console.log = consoleLog; - }); + console.log = consoleLog + }) function log() { - logCalls.push(Array.prototype.slice.call(arguments)); + logCalls.push(Array.prototype.slice.call(arguments)) } - it('should log the text from $comment keyword', function() { + it("should log the text from $comment keyword", function () { var schema = { properties: { - foo: {$comment: 'property foo'}, - bar: {$comment: 'property bar', type: 'integer'} - } - }; + foo: {$comment: "property foo"}, + bar: {$comment: "property bar", type: "integer"}, + }, + } - var ajv = new Ajv({$comment: true}); - var fullAjv = new Ajv({allErrors: true, $comment: true}); + var ajv = new Ajv({$comment: true}) + var fullAjv = new Ajv({allErrors: true, $comment: true}) - [ajv, fullAjv].forEach(function (_ajv) { - var validate = _ajv.compile(schema); + ;[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']]); + 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); + logCalls = [] + validate(data).should.equal(valid) + logCalls.should.eql(expectedLogCalls) } - }); + }) - console.log = consoleLog; - }); - }); + console.log = consoleLog + }) + }) - describe('function hook', function() { - var hookCalls; + describe("function hook", function () { + var hookCalls function hook() { - hookCalls.push(Array.prototype.slice.call(arguments)); + hookCalls.push(Array.prototype.slice.call(arguments)) } - it('should pass the text from $comment keyword to the hook', function() { + 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]]); + 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); + hookCalls = [] + validate(data).should.equal(valid) + hookCalls.should.eql(expectedHookCalls) } - }); - }); - }); -}); + }) + }) + }) +}) diff --git a/spec/options/meta_validateSchema.spec.js b/spec/options/meta_validateSchema.spec.js index 2e287da75f..8229c67288 100644 --- a/spec/options/meta_validateSchema.spec.js +++ b/spec/options/meta_validateSchema.spec.js @@ -1,79 +1,101 @@ -'use strict'; +"use strict" -var Ajv = require('../ajv'); -var should = require('../chai').should(); +var Ajv = require("../ajv") +var should = require("../chai").should() - -describe('meta and validateSchema options', function() { - it('should add draft-7 meta schema by default', function() { - testOptionMeta(new Ajv); - testOptionMeta(new Ajv({ meta: true })); +describe("meta and validateSchema options", function () { + it("should add draft-7 meta schema by default", function () { + testOptionMeta(new Ajv()) + testOptionMeta(new Ajv({meta: true})) function testOptionMeta(ajv) { - 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' }); }); - should.throw(function() { ajv.addSchema({ type: 123 }); }); + 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"}) + }) + should.throw(function () { + ajv.addSchema({type: 123}) + }) } - }); + }) - 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-07/schema')); - should.not.throw(function() { ajv.addSchema({ type: 'wrong_type' }, 'integer'); }); - }); + 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-07/schema")) + should.not.throw(function () { + ajv.addSchema({type: "wrong_type"}, "integer") + }) + }) - it('should skip schema validation with validateSchema: false', function() { - var ajv = new Ajv; - should.throw(function() { ajv.addSchema({ type: 123 }, 'integer'); }); + it("should skip schema validation with validateSchema: false", function () { + var ajv = new Ajv() + should.throw(function () { + ajv.addSchema({type: 123}, "integer") + }) - ajv = new Ajv({ validateSchema: false }); - should.not.throw(function() { ajv.addSchema({ type: 123 }, 'integer'); }); + ajv = new Ajv({validateSchema: false}) + should.not.throw(function () { + ajv.addSchema({type: 123}, "integer") + }) - ajv = new Ajv({ validateSchema: false, meta: false }); - should.not.throw(function() { ajv.addSchema({ type: 123 }, 'integer'); }); - }); + ajv = new Ajv({validateSchema: false, meta: false}) + should.not.throw(function () { + ajv.addSchema({type: 123}, "integer") + }) + }) - it('should not throw on invalid schema with validateSchema: "log"', function() { - var logError = console.error; - var loggedError = false; - console.error = function() { loggedError = true; logError.apply(console, arguments); }; + it('should not throw on invalid schema with validateSchema: "log"', function () { + var logError = console.error + var loggedError = false + console.error = function () { + loggedError = true + logError.apply(console, arguments) + } - var ajv = new Ajv({ validateSchema: 'log' }); - should.not.throw(function() { ajv.addSchema({ type: 123 }, 'integer'); }); - loggedError .should.equal(true); + var ajv = new Ajv({validateSchema: "log"}) + should.not.throw(function () { + ajv.addSchema({type: 123}, "integer") + }) + loggedError.should.equal(true) - loggedError = false; - ajv = new Ajv({ validateSchema: 'log', meta: false }); - should.not.throw(function() { ajv.addSchema({ type: 123 }, 'integer'); }); - loggedError .should.equal(false); - console.error = logError; - }); + loggedError = false + ajv = new Ajv({validateSchema: "log", meta: false}) + should.not.throw(function () { + ajv.addSchema({type: 123}, "integer") + }) + loggedError.should.equal(false) + console.error = logError + }) - it('should validate v6 schema', function() { - var ajv = new Ajv; - ajv.validateSchema({ contains: { minimum: 2 } }) .should.equal(true); - ajv.validateSchema({ contains: 2 }). should.equal(false); - }); + it("should validate v6 schema", function () { + var ajv = new Ajv() + ajv.validateSchema({contains: {minimum: 2}}).should.equal(true) + ajv.validateSchema({contains: 2}).should.equal(false) + }) - it('should use option meta as default meta schema', function() { + it("should use option meta as default meta schema", function () { var meta = { - $schema: 'http://json-schema.org/draft-07/schema', + $schema: "http://json-schema.org/draft-07/schema", properties: { - myKeyword: { type: 'boolean' } - } - }; - var ajv = new Ajv({ meta: meta }); - ajv.validateSchema({ myKeyword: true }) .should.equal(true); - ajv.validateSchema({ myKeyword: 2 }) .should.equal(false); - ajv.validateSchema({ - $schema: 'http://json-schema.org/draft-07/schema', - myKeyword: 2 - }) .should.equal(true); + myKeyword: {type: "boolean"}, + }, + } + var ajv = new Ajv({meta: meta}) + ajv.validateSchema({myKeyword: true}).should.equal(true) + ajv.validateSchema({myKeyword: 2}).should.equal(false) + ajv + .validateSchema({ + $schema: "http://json-schema.org/draft-07/schema", + myKeyword: 2, + }) + .should.equal(true) - ajv = new Ajv; - ajv.validateSchema({ myKeyword: true }) .should.equal(true); - ajv.validateSchema({ myKeyword: 2 }) .should.equal(true); - }); -}); + ajv = new Ajv() + ajv.validateSchema({myKeyword: true}).should.equal(true) + ajv.validateSchema({myKeyword: 2}).should.equal(true) + }) +}) diff --git a/spec/options/nullable.spec.js b/spec/options/nullable.spec.js index df1bda5e44..9fb3013b8a 100644 --- a/spec/options/nullable.spec.js +++ b/spec/options/nullable.spec.js @@ -1,97 +1,96 @@ -'use strict'; +"use strict" -var Ajv = require('../ajv'); -var should = require('../chai').should(); +var Ajv = require("../ajv") +var should = require("../chai").should() +describe("nullable option", function () { + var ajv -describe('nullable option', function() { - var ajv; - - describe('= true', function() { + describe("= true", function () { beforeEach(function () { ajv = new Ajv({ - nullable: true - }); - }); + nullable: true, + }) + }) - it('should add keyword "nullable"', function() { + it('should add keyword "nullable"', function () { testNullable({ - type: 'number', - nullable: true - }); + type: "number", + nullable: true, + }) testNullable({ - type: ['number'], - nullable: true - }); + type: ["number"], + nullable: true, + }) testNullable({ - type: ['number', 'null'] - }); + type: ["number", "null"], + }) testNullable({ - type: ['number', 'null'], - nullable: true - }); + type: ["number", "null"], + nullable: true, + }) - testNotNullable({type: 'number'}); + testNotNullable({type: "number"}) - testNotNullable({type: ['number']}); - }); + testNotNullable({type: ["number"]}) + }) - it('should respect "nullable" == false with opts.nullable == true', function() { + it('should respect "nullable" == false with opts.nullable == true', function () { testNotNullable({ - type: 'number', - nullable: false - }); + type: "number", + nullable: false, + }) testNotNullable({ - type: ['number'], - nullable: false - }); - }); - }); + type: ["number"], + nullable: false, + }) + }) + }) - describe('without option "nullable"', function() { - it('should ignore keyword nullable', function() { - ajv = new Ajv; + describe('without option "nullable"', function () { + it("should ignore keyword nullable", function () { + ajv = new Ajv() testNotNullable({ - type: 'number', - nullable: true - }); + type: "number", + nullable: true, + }) testNotNullable({ - type: ['number'], - nullable: true - }); + type: ["number"], + nullable: true, + }) testNullable({ - type: ['number', 'null'], - }); + type: ["number", "null"], + }) testNullable({ - type: ['number', 'null'], - nullable: true - }); + type: ["number", "null"], + nullable: true, + }) should.not.throw(function () { - ajv.compile({nullable: false}); - }); - }); - }); + ajv.compile({nullable: false}) + }) + }) + }) function testNullable(schema) { - var validate = ajv.compile(schema); - validate(1) .should.equal(true); - validate(null) .should.equal(true); - validate('1') .should.equal(false); + var validate = ajv.compile(schema) + validate(1).should.equal(true) + validate(null).should.equal(true) + validate("1").should.equal(false) } function testNotNullable(schema) { - var validate = ajv.compile(schema); - validate(1) .should.equal(true); - validate(null) .should.equal(false); - validate('1') .should.equal(false); + var validate = ajv.compile(schema) + validate(1).should.equal(true) + validate(null).should.equal(false) + validate("1").should.equal(false) } -}); +}) diff --git a/spec/options/options_add_schemas.spec.js b/spec/options/options_add_schemas.spec.js index e1a59f2365..1574839a80 100644 --- a/spec/options/options_add_schemas.spec.js +++ b/spec/options/options_add_schemas.spec.js @@ -1,130 +1,130 @@ -'use strict'; - -var Ajv = require('../ajv'); -var should = require('../chai').should(); - - -describe('options to add schemas', function() { - describe('schemas', function() { - it('should add schemas from object', function() { - var ajv = new Ajv({ schemas: { - int: { type: 'integer' }, - str: { type: 'string' } - }}); - - ajv.validate('int', 123) .should.equal(true); - ajv.validate('int', 'foo') .should.equal(false); - ajv.validate('str', 'foo') .should.equal(true); - ajv.validate('str', 123) .should.equal(false); - }); - - 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' } } } - ]}); - - ajv.validate('obj', { int: 123, str: 'foo' }) .should.equal(true); - ajv.validate('obj', { int: 'foo', str: 'bar' }) .should.equal(false); - ajv.validate('obj', { int: 123, str: 456 }) .should.equal(false); - }); - }); - - - describe('addUsedSchema', function() { - [true, undefined].forEach(function (optionValue) { - describe('= ' + optionValue, function() { - var ajv; - - beforeEach(function() { - ajv = new Ajv({ addUsedSchema: optionValue }); - }); - - describe('compile and validate', function() { - it('should add schema', function() { - 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' }; - 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' }); - should.throw(function() { - ajv.compile({ $id: 'str', minLength: 2 }); - }); - - 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); - }); - }); - }); - }); - }); - - describe('= false', function() { - var ajv; - - beforeEach(function() { - ajv = new Ajv({ addUsedSchema: false }); - }); - - - describe('compile and validate', function() { - it('should NOT add schema', function() { - 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' }; - 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' }); - should.not.throw(function() { - ajv.compile({ $id: 'str', minLength: 2 }); - }); - - 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); - }); - }); - }); - }); - }); - - - describe('serialize', function() { - var serializeCalled; - - it('should use custom function to serialize schema to string', function() { - serializeCalled = undefined; - var ajv = new Ajv({ serialize: serialize }); - ajv.addSchema({ type: 'string' }); - should.equal(serializeCalled, true); - }); +"use strict" + +var Ajv = require("../ajv") +var should = require("../chai").should() + +describe("options to add schemas", function () { + describe("schemas", function () { + it("should add schemas from object", function () { + var ajv = new Ajv({ + schemas: { + int: {type: "integer"}, + str: {type: "string"}, + }, + }) + + ajv.validate("int", 123).should.equal(true) + ajv.validate("int", "foo").should.equal(false) + ajv.validate("str", "foo").should.equal(true) + ajv.validate("str", 123).should.equal(false) + }) + + 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"}}}, + ], + }) + + ajv.validate("obj", {int: 123, str: "foo"}).should.equal(true) + ajv.validate("obj", {int: "foo", str: "bar"}).should.equal(false) + ajv.validate("obj", {int: 123, str: 456}).should.equal(false) + }) + }) + + describe("addUsedSchema", function () { + ;[true, undefined].forEach(function (optionValue) { + describe("= " + optionValue, function () { + var ajv + + beforeEach(function () { + ajv = new Ajv({addUsedSchema: optionValue}) + }) + + describe("compile and validate", function () { + it("should add schema", function () { + 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"} + 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"}) + should.throw(function () { + ajv.compile({$id: "str", minLength: 2}) + }) + + 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) + }) + }) + }) + }) + }) + + describe("= false", function () { + var ajv + + beforeEach(function () { + ajv = new Ajv({addUsedSchema: false}) + }) + + describe("compile and validate", function () { + it("should NOT add schema", function () { + 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"} + 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"}) + should.not.throw(function () { + ajv.compile({$id: "str", minLength: 2}) + }) + + 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) + }) + }) + }) + }) + }) + + describe("serialize", function () { + var serializeCalled + + it("should use custom function to serialize schema to string", function () { + serializeCalled = undefined + var ajv = new Ajv({serialize: serialize}) + ajv.addSchema({type: "string"}) + should.equal(serializeCalled, true) + }) function serialize(schema) { - serializeCalled = true; - return JSON.stringify(schema); + serializeCalled = true + return JSON.stringify(schema) } - }); -}); + }) +}) diff --git a/spec/options/options_code.spec.js b/spec/options/options_code.spec.js index 8884c8c4c0..742b0d1b2b 100644 --- a/spec/options/options_code.spec.js +++ b/spec/options/options_code.spec.js @@ -1,88 +1,85 @@ -'use strict'; +"use strict" -var Ajv = require('../ajv'); -var should = require('../chai').should(); +var Ajv = require("../ajv") +var should = require("../chai").should() - -describe('code generation options', function () { - describe('sourceCode', function() { - describe('= true', function() { - it('should add source.code property', function() { - test(new Ajv({sourceCode: true})); +describe("code generation options", function () { + describe("sourceCode", function () { + describe("= true", function () { + it("should add source.code property", function () { + test(new Ajv({sourceCode: true})) function test(ajv) { - var validate = ajv.compile({ "type": "number" }); - validate.source.code .should.be.a('string'); + var validate = ajv.compile({type: "number"}) + validate.source.code.should.be.a("string") } - }); - }); + }) + }) - describe('= false and default', function() { - it('should not add source and sourceCode properties', function() { - test(new Ajv); - test(new Ajv({sourceCode: false})); + describe("= false and default", function () { + it("should not add source and sourceCode properties", function () { + test(new Ajv()) + test(new Ajv({sourceCode: false})) function test(ajv) { - var validate = ajv.compile({ "type": "number" }); - should.not.exist(validate.source); - should.not.exist(validate.sourceCode); + var validate = ajv.compile({type: "number"}) + should.not.exist(validate.source) + should.not.exist(validate.sourceCode) } - }); - }); - }); - - - describe('processCode', function() { - it('should process generated code', function() { - var ajv = new Ajv; - var validate = ajv.compile({type: 'string'}); - validate.toString().split('\n').length .should.equal(1); - - var beautify = require('js-beautify').js_beautify; - var ajvPC = new Ajv({processCode: beautify}); - validate = ajvPC.compile({type: 'string'}); - validate.toString().split('\n').length .should.be.above(1); - validate('foo') .should.equal(true); - validate(1) .should.equal(false); - }); - }); - - - describe('passContext option', function() { - var ajv, contexts; - - beforeEach(function() { - contexts = []; - }); - - describe('= true', function() { - it('should pass this value as context to custom keyword validation function', function() { - var validate = getValidate(true); - var self = {}; - validate.call(self, {}); - contexts .should.have.length(4); - contexts.forEach(function(ctx) { - ctx .should.equal(self); - }); - }); - }); - - describe('= false', function() { - it('should pass ajv instance as context to custom keyword validation function', function() { - var validate = getValidate(false); - var self = {}; - validate.call(self, {}); - contexts .should.have.length(4); - contexts.forEach(function(ctx) { - ctx .should.equal(ajv); - }); - }); - }); + }) + }) + }) + + describe("processCode", function () { + it("should process generated code", function () { + var ajv = new Ajv() + var validate = ajv.compile({type: "string"}) + validate.toString().split("\n").length.should.equal(1) + + var beautify = require("js-beautify").js_beautify + var ajvPC = new Ajv({processCode: beautify}) + validate = ajvPC.compile({type: "string"}) + validate.toString().split("\n").length.should.be.above(1) + validate("foo").should.equal(true) + validate(1).should.equal(false) + }) + }) + + describe("passContext option", function () { + var ajv, contexts + + beforeEach(function () { + contexts = [] + }) + + describe("= true", function () { + it("should pass this value as context to custom keyword validation function", function () { + var validate = getValidate(true) + var self = {} + validate.call(self, {}) + contexts.should.have.length(4) + contexts.forEach(function (ctx) { + ctx.should.equal(self) + }) + }) + }) + + describe("= false", function () { + it("should pass ajv instance as context to custom keyword validation function", function () { + var validate = getValidate(false) + var self = {} + validate.call(self, {}) + contexts.should.have.length(4) + contexts.forEach(function (ctx) { + ctx.should.equal(ajv) + }) + }) + }) function getValidate(passContext) { - ajv = new Ajv({ passContext: passContext, inlineRefs: false }); - ajv.addKeyword('testValidate', { validate: storeContext }); - ajv.addKeyword('testCompile', { compile: compileTestValidate }); + ajv = new Ajv({passContext: passContext, inlineRefs: false}) + ajv.addKeyword("testValidate", {validate: storeContext}) + ajv.addKeyword("testCompile", {compile: compileTestValidate}) var schema = { definitions: { @@ -91,25 +88,22 @@ describe('code generation options', function () { testCompile: true, }, test2: { - allOf: [ { $ref: '#/definitions/test1' } ] - } + allOf: [{$ref: "#/definitions/test1"}], + }, }, - allOf: [ - { $ref: '#/definitions/test1' }, - { $ref: '#/definitions/test2' } - ] - }; + allOf: [{$ref: "#/definitions/test1"}, {$ref: "#/definitions/test2"}], + } - return ajv.compile(schema); + return ajv.compile(schema) } function storeContext() { - contexts.push(this); - return true; + contexts.push(this) + return true } function compileTestValidate() { - return storeContext; + return storeContext } - }); -}); + }) +}) diff --git a/spec/options/options_refs.spec.js b/spec/options/options_refs.spec.js index 1f1d20a757..a5a68f8427 100644 --- a/spec/options/options_refs.spec.js +++ b/spec/options/options_refs.spec.js @@ -1,167 +1,158 @@ -'use strict'; - -var Ajv = require('../ajv'); -var should = require('../chai').should(); - - -describe('referenced schema options', function() { - describe('extendRefs', function() { - describe('= true', function() { - it('should allow extending $ref with other keywords', function() { - test(new Ajv({ extendRefs: true }), true); - }); - - it('should NOT log warning if extendRefs is true', function() { - testWarning(new Ajv({ extendRefs: true })); - }); - }); - - describe('= "ignore" and default', function() { - it('should ignore other keywords when $ref is used', function() { - test(new Ajv); - test(new Ajv({ extendRefs: 'ignore' }), false); - }); - - it('should log warning when other keywords are used with $ref', function() { - testWarning(new Ajv, /keywords\signored/); - testWarning(new Ajv({ extendRefs: 'ignore' }), /keywords\signored/); - }); - }); - - describe('= "fail"', function() { - it('should fail schema compilation if other keywords are used with $ref', function() { - testFail(new Ajv({ extendRefs: 'fail' })); +"use strict" + +var Ajv = require("../ajv") +var should = require("../chai").should() + +describe("referenced schema options", function () { + describe("extendRefs", function () { + describe("= true", function () { + it("should allow extending $ref with other keywords", function () { + test(new Ajv({extendRefs: true}), true) + }) + + it("should NOT log warning if extendRefs is true", function () { + testWarning(new Ajv({extendRefs: true})) + }) + }) + + describe('= "ignore" and default', function () { + it("should ignore other keywords when $ref is used", function () { + test(new Ajv()) + test(new Ajv({extendRefs: "ignore"}), false) + }) + + it("should log warning when other keywords are used with $ref", function () { + testWarning(new Ajv(), /keywords\signored/) + testWarning(new Ajv({extendRefs: "ignore"}), /keywords\signored/) + }) + }) + + describe('= "fail"', function () { + it("should fail schema compilation if other keywords are used with $ref", function () { + testFail(new Ajv({extendRefs: "fail"})) function testFail(ajv) { - should.throw(function() { + should.throw(function () { var schema = { - "definitions": { - "int": { "type": "integer" } + definitions: { + int: {type: "integer"}, }, - "$ref": "#/definitions/int", - "minimum": 10 - }; - ajv.compile(schema); - }); + $ref: "#/definitions/int", + minimum: 10, + } + ajv.compile(schema) + }) - should.not.throw(function() { + should.not.throw(function () { var schema = { - "definitions": { - "int": { "type": "integer" } + definitions: { + int: {type: "integer"}, }, - "allOf": [ - { "$ref": "#/definitions/int" }, - { "minimum": 10 } - ] - }; - ajv.compile(schema); - }); + allOf: [{$ref: "#/definitions/int"}, {minimum: 10}], + } + ajv.compile(schema) + }) } - }); - }); + }) + }) function test(ajv, shouldExtendRef) { var schema = { - "definitions": { - "int": { "type": "integer" } + definitions: { + int: {type: "integer"}, }, - "$ref": "#/definitions/int", - "minimum": 10 - }; + $ref: "#/definitions/int", + minimum: 10, + } - var validate = ajv.compile(schema); - validate(10) .should.equal(true); - validate(1) .should.equal(!shouldExtendRef); + var validate = ajv.compile(schema) + validate(10).should.equal(true) + validate(1).should.equal(!shouldExtendRef) schema = { - "definitions": { - "int": { "type": "integer" } + definitions: { + int: {type: "integer"}, }, - "type": "object", - "properties": { - "foo": { - "$ref": "#/definitions/int", - "minimum": 10 + type: "object", + properties: { + foo: { + $ref: "#/definitions/int", + minimum: 10, }, - "bar": { - "allOf": [ - { "$ref": "#/definitions/int" }, - { "minimum": 10 } - ] - } - } - }; + bar: { + allOf: [{$ref: "#/definitions/int"}, {minimum: 10}], + }, + }, + } - validate = ajv.compile(schema); - validate({ foo: 10, bar: 10 }) .should.equal(true); - validate({ foo: 1, bar: 10 }) .should.equal(!shouldExtendRef); - validate({ foo: 10, bar: 1 }) .should.equal(false); + validate = ajv.compile(schema) + validate({foo: 10, bar: 10}).should.equal(true) + validate({foo: 1, bar: 10}).should.equal(!shouldExtendRef) + validate({foo: 10, bar: 1}).should.equal(false) } function testWarning(ajv, msgPattern) { - var oldConsole; + var oldConsole try { - oldConsole = console.warn; - var consoleMsg; - console.warn = function() { - consoleMsg = Array.prototype.join.call(arguments, ' '); - }; + oldConsole = console.warn + var consoleMsg + console.warn = function () { + consoleMsg = Array.prototype.join.call(arguments, " ") + } var schema = { - "definitions": { - "int": { "type": "integer" } + definitions: { + int: {type: "integer"}, }, - "$ref": "#/definitions/int", - "minimum": 10 - }; + $ref: "#/definitions/int", + minimum: 10, + } - ajv.compile(schema); - if (msgPattern) consoleMsg .should.match(msgPattern); - else should.not.exist(consoleMsg); + ajv.compile(schema) + if (msgPattern) consoleMsg.should.match(msgPattern) + else should.not.exist(consoleMsg) } finally { - console.warn = oldConsole; + console.warn = oldConsole } } - }); + }) + describe("missingRefs", function () { + it("should throw if ref is missing without this option", function () { + var ajv = new Ajv() + should.throw(function () { + ajv.compile({$ref: "missing_reference"}) + }) + }) - describe('missingRefs', function() { - it('should throw if ref is missing without this option', function() { - var ajv = new Ajv; - should.throw(function() { - ajv.compile({ $ref: 'missing_reference' }); - }); - }); - - it('should not throw and pass validation with missingRef == "ignore"', function() { - testMissingRefsIgnore(new Ajv({ missingRefs: 'ignore' })); - testMissingRefsIgnore(new Ajv({ missingRefs: 'ignore', allErrors: true })); + it('should not throw and pass validation with missingRef == "ignore"', function () { + testMissingRefsIgnore(new Ajv({missingRefs: "ignore"})) + testMissingRefsIgnore(new Ajv({missingRefs: "ignore", allErrors: true})) function testMissingRefsIgnore(ajv) { - var validate = ajv.compile({ $ref: 'missing_reference' }); - validate({}) .should.equal(true); + var validate = ajv.compile({$ref: "missing_reference"}) + validate({}).should.equal(true) } - }); + }) - it('should not throw and fail validation with missingRef == "fail" if the ref is used', function() { - testMissingRefsFail(new Ajv({ missingRefs: 'fail' })); - testMissingRefsFail(new Ajv({ missingRefs: 'fail', verbose: true })); - testMissingRefsFail(new Ajv({ missingRefs: 'fail', allErrors: true })); - testMissingRefsFail(new Ajv({ missingRefs: 'fail', allErrors: true, verbose: true })); + it('should not throw and fail validation with missingRef == "fail" if the ref is used', function () { + testMissingRefsFail(new Ajv({missingRefs: "fail"})) + testMissingRefsFail(new Ajv({missingRefs: "fail", verbose: true})) + testMissingRefsFail(new Ajv({missingRefs: "fail", allErrors: true})) + testMissingRefsFail( + new Ajv({missingRefs: "fail", allErrors: true, verbose: true}) + ) function testMissingRefsFail(ajv) { var validate = ajv.compile({ - anyOf: [ - { type: 'number' }, - { $ref: 'missing_reference' } - ] - }); - validate(123) .should.equal(true); - validate('foo') .should.equal(false); - - validate = ajv.compile({ $ref: 'missing_reference' }); - validate({}) .should.equal(false); + anyOf: [{type: "number"}, {$ref: "missing_reference"}], + }) + validate(123).should.equal(true) + validate("foo").should.equal(false) + + validate = ajv.compile({$ref: "missing_reference"}) + validate({}).should.equal(false) } - }); - }); -}); + }) + }) +}) diff --git a/spec/options/options_reporting.spec.js b/spec/options/options_reporting.spec.js index 578611e807..fcae23338c 100644 --- a/spec/options/options_reporting.spec.js +++ b/spec/options/options_reporting.spec.js @@ -1,158 +1,155 @@ -'use strict'; +"use strict" -var Ajv = require('../ajv'); -var should = require('../chai').should(); +var Ajv = require("../ajv") +var should = require("../chai").should() - -describe('reporting options', function () { - describe('verbose', function() { - it('should add schema, parentSchema and data to errors with verbose option == true', function() { - testVerbose(new Ajv({ verbose: true })); - testVerbose(new Ajv({ verbose: true, allErrors: true })); +describe("reporting options", function () { + describe("verbose", function () { + it("should add schema, parentSchema and data to errors with verbose option == true", function () { + testVerbose(new Ajv({verbose: true})) + testVerbose(new Ajv({verbose: true, allErrors: true})) function testVerbose(ajv) { - var schema = { properties: { foo: { minimum: 5 } } }; - var validate = ajv.compile(schema); - - var data = { foo: 3 }; - validate(data) .should.equal(false); - validate.errors .should.have.length(1); - var err = validate.errors[0]; - - should.equal(err.schema, 5); - err.parentSchema .should.eql({ minimum: 5 }); - err.parentSchema .should.equal(schema.properties.foo); // by reference - should.equal(err.data, 3); + var schema = {properties: {foo: {minimum: 5}}} + var validate = ajv.compile(schema) + + var data = {foo: 3} + validate(data).should.equal(false) + validate.errors.should.have.length(1) + var err = validate.errors[0] + + should.equal(err.schema, 5) + err.parentSchema.should.eql({minimum: 5}) + err.parentSchema.should.equal(schema.properties.foo) // by reference + should.equal(err.data, 3) } - }); - }); - + }) + }) - describe('allErrors', function() { - it('should be disabled inside "not" keyword', function() { - test(new Ajv, false); - test(new Ajv({ allErrors: true }), true); + describe("allErrors", function () { + it('should be disabled inside "not" keyword', function () { + test(new Ajv(), false) + test(new Ajv({allErrors: true}), true) function test(ajv, allErrors) { - var format1called = false - , format2called = false; + var format1called = false, + format2called = false - ajv.addFormat('format1', function() { - format1called = true; - return false; - }); + ajv.addFormat("format1", function () { + format1called = true + return false + }) - ajv.addFormat('format2', function() { - format2called = true; - return false; - }); + ajv.addFormat("format2", function () { + format2called = true + return false + }) var schema1 = { - allOf: [ - { format: 'format1' }, - { format: 'format2' } - ] - }; + allOf: [{format: "format1"}, {format: "format2"}], + } - ajv.validate(schema1, 'abc') .should.equal(false); - ajv.errors .should.have.length(allErrors ? 2 : 1); - format1called .should.equal(true); - format2called .should.equal(allErrors); + ajv.validate(schema1, "abc").should.equal(false) + ajv.errors.should.have.length(allErrors ? 2 : 1) + format1called.should.equal(true) + format2called.should.equal(allErrors) var schema2 = { - not: schema1 - }; - - format1called = format2called = false; - ajv.validate(schema2, 'abc') .should.equal(true); - should.equal(ajv.errors, null); - format1called .should.equal(true); - format2called .should.equal(false); + not: schema1, + } + + format1called = format2called = false + ajv.validate(schema2, "abc").should.equal(true) + should.equal(ajv.errors, null) + format1called.should.equal(true) + format2called.should.equal(false) } - }); - }); - + }) + }) - describe('logger', function() { + describe("logger", function () { /** * The logger option tests are based on the meta scenario which writes into the logger.warn */ - var origConsoleWarn = console.warn; - var consoleCalled; + var origConsoleWarn = console.warn + var consoleCalled - beforeEach(function() { - consoleCalled = false; - console.warn = function() { - consoleCalled = true; - }; - }); + beforeEach(function () { + consoleCalled = false + console.warn = function () { + consoleCalled = true + } + }) - afterEach(function() { - console.warn = origConsoleWarn; - }); + afterEach(function () { + console.warn = origConsoleWarn + }) - it('no custom logger is given - global console should be used', function() { + it("no custom logger is given - global console should be used", function () { var ajv = new Ajv({ - meta: false - }); + meta: false, + }) ajv.compile({ - type: 'number', - minimum: 1 - }); + type: "number", + minimum: 1, + }) - should.equal(consoleCalled, true); - }); + should.equal(consoleCalled, true) + }) - it('custom logger is an object - logs should only report to it', function() { - var loggerCalled = false; + it("custom logger is an object - logs should only report to it", function () { + var loggerCalled = false var logger = { warn: log, log: log, - error: log - }; + error: log, + } var ajv = new Ajv({ meta: false, - logger: logger - }); + logger: logger, + }) ajv.compile({ - type: 'number', - minimum: 1 - }); + type: "number", + minimum: 1, + }) - should.equal(loggerCalled, true); - should.equal(consoleCalled, false); + should.equal(loggerCalled, true) + should.equal(consoleCalled, false) function log() { - loggerCalled = true; + loggerCalled = true } - }); + }) - it('logger option is false - no logs should be reported', function() { + it("logger option is false - no logs should be reported", function () { var ajv = new Ajv({ meta: false, - logger: false - }); + logger: false, + }) ajv.compile({ - type: 'number', - minimum: 1 - }); + type: "number", + minimum: 1, + }) - should.equal(consoleCalled, false); - }); + should.equal(consoleCalled, false) + }) - it('logger option is an object without required methods - an error should be thrown', function() { - (function(){ + it("logger option is an object without required methods - an error should be thrown", function () { + ;(function () { new Ajv({ meta: false, - logger: {} - }); - }).should.throw(Error, /logger must implement log, warn and error methods/); - }); - }); -}); + logger: {}, + }) + }.should.throw( + Error, + /logger must implement log, warn and error methods/ + )) + }) + }) +}) diff --git a/spec/options/options_validation.spec.js b/spec/options/options_validation.spec.js index 950a0c2894..5ee2ff2df5 100644 --- a/spec/options/options_validation.spec.js +++ b/spec/options/options_validation.spec.js @@ -1,116 +1,116 @@ -'use strict'; - -var Ajv = require('../ajv'); -require('../chai').should(); - - -describe('validation options', function() { - describe('format', function() { - it('should not validate formats if option format == false', function() { - var ajv = new Ajv - , ajvFF = new Ajv({ format: false }); - - var schema = { format: 'date-time' }; - var invalideDateTime = '06/19/1963 08:30:06 PST'; - - ajv.validate(schema, invalideDateTime) .should.equal(false); - ajvFF.validate(schema, invalideDateTime) .should.equal(true); - }); - }); - - - describe('formats', function() { - it('should add formats from options', function() { - var ajv = new Ajv({ formats: { - identifier: /^[a-z_$][a-z0-9_$]*$/i - }}); - - var validate = ajv.compile({ format: 'identifier' }); - - validate('Abc1') .should.equal(true); - validate('foo bar') .should.equal(false); - validate('123') .should.equal(false); - validate(123) .should.equal(true); - }); - }); - - describe('keywords', function() { - it('should add keywords from options', function() { - var ajv = new Ajv({ keywords: { - identifier: { - type: 'string', - validate: function (schema, data ) { - return /^[a-z_$][a-z0-9_$]*$/i.test(data); - } - } - }}); - - var validate = ajv.compile({ identifier: true }); - - validate('Abc1') .should.equal(true); - validate('foo bar') .should.equal(false); - validate('123') .should.equal(false); - validate(123) .should.equal(true); - }); - }); - - - describe('uniqueItems', function() { - it('should not validate uniqueItems with uniqueItems option == false', function() { - testUniqueItems(new Ajv({ uniqueItems: false })); - testUniqueItems(new Ajv({ uniqueItems: false, allErrors: true })); +"use strict" + +const Ajv = require("../ajv") +require("../chai").should() +const DATE_FORMAT = /^\d\d\d\d-[0-1]\d-[0-3]\d$/ + +describe("validation options", function () { + describe("format", function () { + it("should not validate formats if option format == false", function () { + var ajv = new Ajv({formats: {date: DATE_FORMAT}}), + ajvFF = new Ajv({formats: {date: DATE_FORMAT}, format: false}) + + var schema = {format: "date"} + var invalideDateTime = "06/19/1963" // expects hyphens + + ajv.validate(schema, invalideDateTime).should.equal(false) + ajvFF.validate(schema, invalideDateTime).should.equal(true) + }) + }) + + describe("formats", function () { + it("should add formats from options", function () { + var ajv = new Ajv({ + formats: { + identifier: /^[a-z_$][a-z0-9_$]*$/i, + }, + }) + + var validate = ajv.compile({format: "identifier"}) + + validate("Abc1").should.equal(true) + validate("foo bar").should.equal(false) + validate("123").should.equal(false) + validate(123).should.equal(true) + }) + }) + + describe("keywords", function () { + it("should add keywords from options", function () { + var ajv = new Ajv({ + keywords: { + identifier: { + type: "string", + validate: function (schema, data) { + return /^[a-z_$][a-z0-9_$]*$/i.test(data) + }, + }, + }, + }) + + var validate = ajv.compile({identifier: true}) + + validate("Abc1").should.equal(true) + validate("foo bar").should.equal(false) + validate("123").should.equal(false) + validate(123).should.equal(true) + }) + }) + + describe("uniqueItems", function () { + it("should not validate uniqueItems with uniqueItems option == false", function () { + testUniqueItems(new Ajv({uniqueItems: false})) + testUniqueItems(new Ajv({uniqueItems: false, allErrors: true})) function testUniqueItems(ajv) { - var validate = ajv.compile({ uniqueItems: true }); - validate([1,2,3]) .should.equal(true); - validate([1,1,1]) .should.equal(true); + var validate = ajv.compile({uniqueItems: true}) + validate([1, 2, 3]).should.equal(true) + validate([1, 1, 1]).should.equal(true) } - }); - }); + }) + }) - - describe('unicode', function() { - it('should use String.prototype.length with unicode option == false', function() { - var ajvUnicode = new Ajv; - testUnicode(new Ajv({ unicode: false })); - testUnicode(new Ajv({ unicode: false, allErrors: true })); + describe("unicode", function () { + it("should use String.prototype.length with unicode option == false", function () { + var ajvUnicode = new Ajv() + testUnicode(new Ajv({unicode: false})) + testUnicode(new Ajv({unicode: false, allErrors: true})) function testUnicode(ajv) { - var validateWithUnicode = ajvUnicode.compile({ minLength: 2 }); - var validate = ajv.compile({ minLength: 2 }); + var validateWithUnicode = ajvUnicode.compile({minLength: 2}) + var validate = ajv.compile({minLength: 2}) - validateWithUnicode('😀') .should.equal(false); - validate('😀') .should.equal(true); + validateWithUnicode("😀").should.equal(false) + validate("😀").should.equal(true) - validateWithUnicode = ajvUnicode.compile({ maxLength: 1 }); - validate = ajv.compile({ maxLength: 1 }); + validateWithUnicode = ajvUnicode.compile({maxLength: 1}) + validate = ajv.compile({maxLength: 1}) - validateWithUnicode('😀') .should.equal(true); - validate('😀') .should.equal(false); + validateWithUnicode("😀").should.equal(true) + validate("😀").should.equal(false) } - }); - }); - + }) + }) - describe('multipleOfPrecision', function() { - it('should allow for some deviation from 0 when validating multipleOf with value < 1', function() { - test(new Ajv({ multipleOfPrecision: 7 })); - test(new Ajv({ multipleOfPrecision: 7, allErrors: true })); + describe("multipleOfPrecision", function () { + it("should allow for some deviation from 0 when validating multipleOf with value < 1", function () { + test(new Ajv({multipleOfPrecision: 7})) + test(new Ajv({multipleOfPrecision: 7, allErrors: true})) function test(ajv) { - var schema = { multipleOf: 0.01 }; - var validate = ajv.compile(schema); + var schema = {multipleOf: 0.01} + var validate = ajv.compile(schema) - validate(4.18) .should.equal(true); - validate(4.181) .should.equal(false); + validate(4.18).should.equal(true) + validate(4.181).should.equal(false) - schema = { multipleOf: 0.0000001 }; - validate = ajv.compile(schema); + schema = {multipleOf: 0.0000001} + validate = ajv.compile(schema) - validate(53.198098) .should.equal(true); - validate(53.1980981) .should.equal(true); - validate(53.19809811) .should.equal(false); + validate(53.198098).should.equal(true) + validate(53.1980981).should.equal(true) + validate(53.19809811).should.equal(false) } - }); - }); -}); + }) + }) +}) diff --git a/spec/options/ownProperties.spec.js b/spec/options/ownProperties.spec.js index 312579f96e..d72cf863cb 100644 --- a/spec/options/ownProperties.spec.js +++ b/spec/options/ownProperties.spec.js @@ -1,178 +1,177 @@ -'use strict'; +"use strict" -var Ajv = require('../ajv'); -require('../chai').should(); +var Ajv = require("../ajv") +require("../chai").should() +describe("ownProperties option", function () { + var ajv, ajvOP, ajvOP1 -describe('ownProperties option', function() { - var ajv, ajvOP, ajvOP1; + beforeEach(function () { + ajv = new Ajv({allErrors: true}) + ajvOP = new Ajv({ownProperties: true, allErrors: true}) + ajvOP1 = new Ajv({ownProperties: true}) + }) - beforeEach(function() { - ajv = new Ajv({ allErrors: true }); - ajvOP = new Ajv({ ownProperties: true, allErrors: true }); - ajvOP1 = new Ajv({ ownProperties: true }); - }); - - it('should only validate own properties with additionalProperties', function() { + it("should only validate own properties with additionalProperties", function () { var schema = { - properties: { a: { type: 'number' } }, - additionalProperties: false - }; + properties: {a: {type: "number"}}, + additionalProperties: false, + } - var obj = { a: 1 }; - var proto = { b: 2 }; - test(schema, obj, proto); - }); + var obj = {a: 1} + var proto = {b: 2} + test(schema, obj, proto) + }) - it('should only validate own properties with properties keyword', function() { + it("should only validate own properties with properties keyword", function () { var schema = { properties: { - a: { type: 'number' }, - b: { type: 'number' } - } - }; + a: {type: "number"}, + b: {type: "number"}, + }, + } - var obj = { a: 1 }; - var proto = { b: 'not a number' }; - test(schema, obj, proto); - }); + var obj = {a: 1} + var proto = {b: "not a number"} + test(schema, obj, proto) + }) - it('should only validate own properties with required keyword', function() { + it("should only validate own properties with required keyword", function () { var schema = { - required: ['a', 'b'] - }; + required: ["a", "b"], + } - var obj = { a: 1 }; - var proto = { b: 2 }; - test(schema, obj, proto, 1, true); - }); + var obj = {a: 1} + var proto = {b: 2} + test(schema, obj, proto, 1, true) + }) - it('should only validate own properties with required keyword - many properties', function() { - ajv = new Ajv({ allErrors: true, loopRequired: 1 }); - ajvOP = new Ajv({ ownProperties: true, allErrors: true, loopRequired: 1 }); - ajvOP1 = new Ajv({ ownProperties: true, loopRequired: 1 }); + it("should only validate own properties with required keyword - many properties", function () { + ajv = new Ajv({allErrors: true, loopRequired: 1}) + ajvOP = new Ajv({ownProperties: true, allErrors: true, loopRequired: 1}) + ajvOP1 = new Ajv({ownProperties: true, loopRequired: 1}) var schema = { - required: ['a', 'b', 'c', 'd'] - }; + required: ["a", "b", "c", "d"], + } - var obj = { a: 1, b: 2 }; - var proto = { c: 3, d: 4 }; - test(schema, obj, proto, 2, true); - }); + var obj = {a: 1, b: 2} + var proto = {c: 3, d: 4} + test(schema, obj, proto, 2, true) + }) - it('should only validate own properties with required keyword as $data', function() { - ajv = new Ajv({ allErrors: true, $data: true }); - ajvOP = new Ajv({ ownProperties: true, allErrors: true, $data: true }); - ajvOP1 = new Ajv({ ownProperties: true, $data: true }); + it("should only validate own properties with required keyword as $data", function () { + ajv = new Ajv({allErrors: true, $data: true}) + ajvOP = new Ajv({ownProperties: true, allErrors: true, $data: true}) + ajvOP1 = new Ajv({ownProperties: true, $data: true}) var schema = { - required: { $data: '0/req' }, + required: {$data: "0/req"}, properties: { req: { - type: 'array', - items: { type: 'string' } - } - } - }; + type: "array", + items: {type: "string"}, + }, + }, + } var obj = { - req: ['a', 'b'], - a: 1 - }; - var proto = { b: 2 }; - test(schema, obj, proto, 1, true); - }); - - it('should only validate own properties with properties and required keyword', function() { + req: ["a", "b"], + a: 1, + } + var proto = {b: 2} + test(schema, obj, proto, 1, true) + }) + + it("should only validate own properties with properties and required keyword", function () { var schema = { properties: { - a: { type: 'number' }, - b: { type: 'number' } + a: {type: "number"}, + b: {type: "number"}, }, - required: ['a', 'b'] - }; + required: ["a", "b"], + } - var obj = { a: 1 }; - var proto = { b: 2 }; - test(schema, obj, proto, 1, true); - }); + var obj = {a: 1} + var proto = {b: 2} + test(schema, obj, proto, 1, true) + }) - it('should only validate own properties with dependencies keyword', function() { + it("should only validate own properties with dependencies keyword", function () { var schema = { dependencies: { - a: ['c'], - b: ['d'] - } - }; + a: ["c"], + b: ["d"], + }, + } - var obj = { a: 1, c: 3 }; - var proto = { b: 2 }; - test(schema, obj, proto); + var obj = {a: 1, c: 3} + var proto = {b: 2} + test(schema, obj, proto) - obj = { a: 1, b: 2, c: 3 }; - proto = { d: 4 }; - test(schema, obj, proto, 1, true); - }); + obj = {a: 1, b: 2, c: 3} + proto = {d: 4} + test(schema, obj, proto, 1, true) + }) - it('should only validate own properties with schema dependencies', function() { + it("should only validate own properties with schema dependencies", function () { var schema = { dependencies: { - a: { not: { required: ['c'] } }, - b: { not: { required: ['d'] } } - } - }; + a: {not: {required: ["c"]}}, + b: {not: {required: ["d"]}}, + }, + } - var obj = { a: 1, d: 3 }; - var proto = { b: 2 }; - test(schema, obj, proto); + var obj = {a: 1, d: 3} + var proto = {b: 2} + test(schema, obj, proto) - obj = { a: 1, b: 2 }; - proto = { d: 4 }; - test(schema, obj, proto); - }); + obj = {a: 1, b: 2} + proto = {d: 4} + test(schema, obj, proto) + }) - it('should only validate own properties with patternProperties', function() { + it("should only validate own properties with patternProperties", function () { var schema = { - patternProperties: { 'f.*o': { type: 'integer' } }, - }; + patternProperties: {"f.*o": {type: "integer"}}, + } - var obj = { fooo: 1 }; - var proto = { foo: 'not a number' }; - test(schema, obj, proto); - }); + var obj = {fooo: 1} + var proto = {foo: "not a number"} + test(schema, obj, proto) + }) - it('should only validate own properties with propertyNames', function() { + it("should only validate own properties with propertyNames", function () { var schema = { propertyNames: { - format: 'email' - } - }; + pattern: "foo", + }, + } - var obj = { 'e@example.com': 2 }; - var proto = { 'not email': 1 }; - test(schema, obj, proto, 2); - }); + var obj = {foo: 2} + var proto = {bar: 1} + test(schema, obj, proto, 2) + }) function test(schema, obj, proto, errors, reverse) { - errors = errors || 1; - var validate = ajv.compile(schema); - var validateOP = ajvOP.compile(schema); - var validateOP1 = ajvOP1.compile(schema); - var data = Object.create(proto); - for (var key in obj) data[key] = obj[key]; + errors = errors || 1 + var validate = ajv.compile(schema) + var validateOP = ajvOP.compile(schema) + var validateOP1 = ajvOP1.compile(schema) + var data = Object.create(proto) + for (var key in obj) data[key] = obj[key] if (reverse) { - validate(data) .should.equal(true); - validateOP(data) .should.equal(false); - validateOP.errors .should.have.length(errors); - validateOP1(data) .should.equal(false); - validateOP1.errors .should.have.length(1); + validate(data).should.equal(true) + validateOP(data).should.equal(false) + validateOP.errors.should.have.length(errors) + validateOP1(data).should.equal(false) + validateOP1.errors.should.have.length(1) } else { - validate(data) .should.equal(false); - validate.errors .should.have.length(errors); - validateOP(data) .should.equal(true); - validateOP1(data) .should.equal(true); + validate(data).should.equal(false) + validate.errors.should.have.length(errors) + validateOP(data).should.equal(true) + validateOP1(data).should.equal(true) } } -}); +}) diff --git a/spec/options/removeAdditional.spec.js b/spec/options/removeAdditional.spec.js index 1eef0b7959..017f9b908b 100644 --- a/spec/options/removeAdditional.spec.js +++ b/spec/options/removeAdditional.spec.js @@ -1,122 +1,129 @@ -'use strict'; +"use strict" -var Ajv = require('../ajv'); -require('../chai').should(); +var Ajv = require("../ajv") +require("../chai").should() - -describe('removeAdditional option', function() { - it('should remove all additional properties', function() { - var ajv = new Ajv({ removeAdditional: 'all' }); +describe("removeAdditional option", function () { + it("should remove all additional properties", function () { + var ajv = new Ajv({removeAdditional: "all"}) ajv.addSchema({ - $id: '//test/fooBar', - properties: { foo: { type: 'string' }, bar: { type: 'string' } } - }); + $id: "//test/fooBar", + properties: {foo: {type: "string"}, bar: {type: "string"}}, + }) var object = { - foo: 'foo', bar: 'bar', baz: 'baz-to-be-removed' - }; - - ajv.validate('//test/fooBar', object).should.equal(true); - object.should.have.property('foo'); - object.should.have.property('bar'); - object.should.not.have.property('baz'); - }); + foo: "foo", + bar: "bar", + baz: "baz-to-be-removed", + } + ajv.validate("//test/fooBar", object).should.equal(true) + object.should.have.property("foo") + object.should.have.property("bar") + object.should.not.have.property("baz") + }) - it('should remove properties that would error when `additionalProperties = false`', function() { - var ajv = new Ajv({ removeAdditional: true }); + it("should remove properties that would error when `additionalProperties = false`", function () { + var ajv = new Ajv({removeAdditional: true}) ajv.addSchema({ - $id: '//test/fooBar', - properties: { foo: { type: 'string' }, bar: { type: 'string' } }, - additionalProperties: false - }); + $id: "//test/fooBar", + properties: {foo: {type: "string"}, bar: {type: "string"}}, + additionalProperties: false, + }) var object = { - foo: 'foo', bar: 'bar', baz: 'baz-to-be-removed' - }; - - ajv.validate('//test/fooBar', object).should.equal(true); - object.should.have.property('foo'); - object.should.have.property('bar'); - object.should.not.have.property('baz'); - }); + foo: "foo", + bar: "bar", + baz: "baz-to-be-removed", + } + ajv.validate("//test/fooBar", object).should.equal(true) + object.should.have.property("foo") + object.should.have.property("bar") + object.should.not.have.property("baz") + }) - it('should remove properties that would error when `additionalProperties = false` (many properties, boolean schema)', function() { - var ajv = new Ajv({removeAdditional: true}); + it("should remove properties that would error when `additionalProperties = false` (many properties, boolean schema)", function () { + var ajv = new Ajv({removeAdditional: true}) var schema = { properties: { obj: { additionalProperties: false, properties: { - a: { type: 'string' }, + a: {type: "string"}, b: false, - c: { type: 'string' }, - d: { type: 'string' }, - e: { type: 'string' }, - f: { type: 'string' }, - g: { type: 'string' }, - h: { type: 'string' }, - i: { type: 'string' } - } - } - } - }; + c: {type: "string"}, + d: {type: "string"}, + e: {type: "string"}, + f: {type: "string"}, + g: {type: "string"}, + h: {type: "string"}, + i: {type: "string"}, + }, + }, + }, + } var data = { obj: { - a: 'valid', - b: 'should not be removed', - additional: 'will be removed' - } - }; - - ajv.validate(schema, data) .should.equal(false); - data .should.eql({ + a: "valid", + b: "should not be removed", + additional: "will be removed", + }, + } + + ajv.validate(schema, data).should.equal(false) + data.should.eql({ obj: { - a: 'valid', - b: 'should not be removed' - } - }); - }); + a: "valid", + b: "should not be removed", + }, + }) + }) - - it('should remove properties that would error when `additionalProperties` is a schema', function() { - var ajv = new Ajv({ removeAdditional: 'failing' }); + it("should remove properties that would error when `additionalProperties` is a schema", function () { + var ajv = new Ajv({removeAdditional: "failing"}) ajv.addSchema({ - $id: '//test/fooBar', - properties: { foo: { type: 'string' }, bar: { type: 'string' } }, - additionalProperties: { type: 'string' } - }); + $id: "//test/fooBar", + properties: {foo: {type: "string"}, bar: {type: "string"}}, + additionalProperties: {type: "string"}, + }) var object = { - foo: 'foo', bar: 'bar', baz: 'baz-to-be-kept', fizz: 1000 - }; - - ajv.validate('//test/fooBar', object).should.equal(true); - object.should.have.property('foo'); - object.should.have.property('bar'); - object.should.have.property('baz'); - object.should.not.have.property('fizz'); + foo: "foo", + bar: "bar", + baz: "baz-to-be-kept", + fizz: 1000, + } + + ajv.validate("//test/fooBar", object).should.equal(true) + object.should.have.property("foo") + object.should.have.property("bar") + object.should.have.property("baz") + object.should.not.have.property("fizz") ajv.addSchema({ - $id: '//test/fooBar2', - properties: { foo: { type: 'string' }, bar: { type: 'string' } }, - additionalProperties: { type: 'string', pattern: '^to-be-', maxLength: 10 } - }); + $id: "//test/fooBar2", + properties: {foo: {type: "string"}, bar: {type: "string"}}, + additionalProperties: {type: "string", pattern: "^to-be-", maxLength: 10}, + }) object = { - foo: 'foo', bar: 'bar', baz: 'to-be-kept', quux: 'to-be-removed', fizz: 1000 - }; - - ajv.validate('//test/fooBar2', object).should.equal(true); - object.should.have.property('foo'); - object.should.have.property('bar'); - object.should.have.property('baz'); - object.should.not.have.property('fizz'); - }); -}); + foo: "foo", + bar: "bar", + baz: "to-be-kept", + quux: "to-be-removed", + fizz: 1000, + } + + ajv.validate("//test/fooBar2", object).should.equal(true) + object.should.have.property("foo") + object.should.have.property("bar") + object.should.have.property("baz") + object.should.not.have.property("fizz") + }) +}) diff --git a/spec/options/schemaId.spec.js b/spec/options/schemaId.spec.js index f8871034f2..7600f24fcd 100644 --- a/spec/options/schemaId.spec.js +++ b/spec/options/schemaId.spec.js @@ -1,72 +1,71 @@ -'use strict'; +"use strict" -var Ajv = require('../ajv'); -var should = require('../chai').should(); +var Ajv = require("../ajv") +var should = require("../chai").should() - -describe('schemaId option', function() { - describe('= "$id" (default)', function() { - it('should use $id and ignore id', function() { - test(new Ajv); - test(new Ajv({schemaId: '$id'})); +describe("schemaId option", 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); + 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')); + 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('../../lib/refs/json-schema-draft-04.json')); - ajv._opts.defaultMeta = 'http://json-schema.org/draft-04/schema#'; + describe('= "id"', function () { + it("should use id and ignore $id", function () { + var ajv = new Ajv({schemaId: "id", meta: false}) + ajv.addMetaSchema(require("../../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); + 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')); - }); - }); + 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'}); + 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: "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); - }); + 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({schemaId: 'auto'}); + it("should throw if both id and $id are available and different", function () { + var ajv = new Ajv({schemaId: "auto"}) ajv.compile({ - id: 'mySchema', - $id: 'mySchema' - }); + id: "mySchema", + $id: "mySchema", + }) - should.throw(function() { + should.throw(function () { ajv.compile({ - id: 'mySchema1', - $id: 'mySchema2' - }); - }); - }); - }); -}); + id: "mySchema1", + $id: "mySchema2", + }) + }) + }) + }) +}) diff --git a/spec/options/strictDefaults.spec.js b/spec/options/strictDefaults.spec.js index 1f1093a69d..7fc6f633d5 100644 --- a/spec/options/strictDefaults.spec.js +++ b/spec/options/strictDefaults.spec.js @@ -1,165 +1,170 @@ -'use strict'; +"use strict" -var Ajv = require('../ajv'); -var should = require('../chai').should(); +var Ajv = require("../ajv") +var should = require("../chai").should() - -describe('strictDefaults option', function() { - describe('useDefaults = true', function() { - describe('strictDefaults = false', function() { - it('should NOT throw an error or log a warning given an ignored default', function() { - var output = {}; +describe("strictDefaults option", function () { + describe("useDefaults = true", function () { + describe("strictDefaults = false", function () { + it("should NOT throw an error or log a warning given an ignored default", function () { + var output = {} var ajv = new Ajv({ useDefaults: true, strictDefaults: false, - logger: getLogger(output) - }); + logger: getLogger(output), + }) var schema = { default: 5, - properties: {} - }; + properties: {}, + } - ajv.compile(schema); - should.not.exist(output.warning); - }); + ajv.compile(schema) + should.not.exist(output.warning) + }) - it('should NOT throw an error or log a warning given an ignored default', function() { - var output = {}; + it("should NOT throw an error or log a warning given an ignored default", function () { + var output = {} var ajv = new Ajv({ useDefaults: true, strictDefaults: false, - logger: getLogger(output) - }); + logger: getLogger(output), + }) var schema = { oneOf: [ - { enum: ['foo', 'bar'] }, + {enum: ["foo", "bar"]}, { properties: { foo: { - default: true - } - } - } - ] - }; + default: true, + }, + }, + }, + ], + } - ajv.compile(schema); - should.not.exist(output.warning); - }); - }); + ajv.compile(schema) + should.not.exist(output.warning) + }) + }) - describe('strictDefaults = true', function() { - it('should throw an error given an ignored default in the schema root when strictDefaults is true', function() { - var ajv = new Ajv({useDefaults: true, strictDefaults: true}); + describe("strictDefaults = true", function () { + it("should throw an error given an ignored default in the schema root when strictDefaults is true", function () { + var ajv = new Ajv({useDefaults: true, strictDefaults: true}) var schema = { default: 5, - properties: {} - }; - should.throw(function() { ajv.compile(schema); }); - }); + properties: {}, + } + should.throw(function () { + ajv.compile(schema) + }) + }) - it('should throw an error given an ignored default in oneOf when strictDefaults is true', function() { - var ajv = new Ajv({useDefaults: true, strictDefaults: true}); + it("should throw an error given an ignored default in oneOf when strictDefaults is true", function () { + var ajv = new Ajv({useDefaults: true, strictDefaults: true}) var schema = { oneOf: [ - { enum: ['foo', 'bar'] }, + {enum: ["foo", "bar"]}, { properties: { foo: { - default: true - } - } - } - ] - }; - should.throw(function() { ajv.compile(schema); }); - }); - }); + default: true, + }, + }, + }, + ], + } + should.throw(function () { + ajv.compile(schema) + }) + }) + }) - describe('strictDefaults = "log"', function() { - it('should log a warning given an ignored default in the schema root when strictDefaults is "log"', function() { - var output = {}; + describe('strictDefaults = "log"', function () { + it('should log a warning given an ignored default in the schema root when strictDefaults is "log"', function () { + var output = {} var ajv = new Ajv({ useDefaults: true, - strictDefaults: 'log', - logger: getLogger(output) - }); + strictDefaults: "log", + logger: getLogger(output), + }) var schema = { default: 5, - properties: {} - }; - ajv.compile(schema); - should.equal(output.warning, 'default is ignored in the schema root'); - }); + properties: {}, + } + ajv.compile(schema) + should.equal(output.warning, "default is ignored in the schema root") + }) - it('should log a warning given an ignored default in oneOf when strictDefaults is "log"', function() { - var output = {}; + it('should log a warning given an ignored default in oneOf when strictDefaults is "log"', function () { + var output = {} var ajv = new Ajv({ useDefaults: true, - strictDefaults: 'log', - logger: getLogger(output) - }); + strictDefaults: "log", + logger: getLogger(output), + }) var schema = { oneOf: [ - { enum: ['foo', 'bar'] }, + {enum: ["foo", "bar"]}, { properties: { foo: { - default: true - } - } - } - ] - }; - ajv.compile(schema); - should.equal(output.warning, 'default is ignored for: data.foo'); - }); - }); - }); - + default: true, + }, + }, + }, + ], + } + ajv.compile(schema) + should.equal(output.warning, "default is ignored for: data.foo") + }) + }) + }) - describe('useDefaults = false', function() { - describe('strictDefaults = true', function() { - it('should NOT throw an error given an ignored default in the schema root when useDefaults is false', function() { - var ajv = new Ajv({useDefaults: false, strictDefaults: true}); + describe("useDefaults = false", function () { + describe("strictDefaults = true", function () { + it("should NOT throw an error given an ignored default in the schema root when useDefaults is false", function () { + var ajv = new Ajv({useDefaults: false, strictDefaults: true}) var schema = { default: 5, - properties: {} - }; - should.not.throw(function() { ajv.compile(schema); }); - }); + properties: {}, + } + should.not.throw(function () { + ajv.compile(schema) + }) + }) - it('should NOT throw an error given an ignored default in oneOf when useDefaults is false', function() { - var ajv = new Ajv({useDefaults: false, strictDefaults: true}); + it("should NOT throw an error given an ignored default in oneOf when useDefaults is false", function () { + var ajv = new Ajv({useDefaults: false, strictDefaults: true}) var schema = { oneOf: [ - { enum: ['foo', 'bar'] }, + {enum: ["foo", "bar"]}, { properties: { foo: { - default: true - } - } - } - ] - }; - should.not.throw(function() { ajv.compile(schema); }); - }); - }); - }); - + default: true, + }, + }, + }, + ], + } + should.not.throw(function () { + ajv.compile(schema) + }) + }) + }) + }) function getLogger(output) { return { - log: function() { - throw new Error('log should not be called'); + log: function () { + throw new Error("log should not be called") + }, + warn: function (warning) { + output.warning = warning }, - warn: function(warning) { - output.warning = warning; + error: function () { + throw new Error("error should not be called") }, - error: function() { - throw new Error('error should not be called'); - } - }; + } } -}); +}) diff --git a/spec/options/strictKeywords.spec.js b/spec/options/strictKeywords.spec.js index 4895b78e46..9143d74e6f 100644 --- a/spec/options/strictKeywords.spec.js +++ b/spec/options/strictKeywords.spec.js @@ -1,79 +1,82 @@ -'use strict'; +"use strict" -var Ajv = require('../ajv'); -var should = require('../chai').should(); +var Ajv = require("../ajv") +var should = require("../chai").should() - -describe('strictKeywords option', function() { - describe('strictKeywords = false', function() { - it('should NOT throw an error or log a warning given an unknown keyword', function() { - var output = {}; +describe("strictKeywords option", function () { + describe("strictKeywords = false", function () { + it("should NOT throw an error or log a warning given an unknown keyword", function () { + var output = {} var ajv = new Ajv({ strictKeywords: false, - logger: getLogger(output) - }); + logger: getLogger(output), + }) var schema = { properties: {}, - unknownKeyword: 1 - }; + unknownKeyword: 1, + } - ajv.compile(schema); - should.not.exist(output.warning); - }); - }); + ajv.compile(schema) + should.not.exist(output.warning) + }) + }) - describe('strictKeywords = true', function() { - it('should throw an error given an unknown keyword in the schema root when strictKeywords is true', function() { - var ajv = new Ajv({strictKeywords: true}); + describe("strictKeywords = true", function () { + it("should throw an error given an unknown keyword in the schema root when strictKeywords is true", function () { + var ajv = new Ajv({strictKeywords: true}) var schema = { properties: {}, - unknownKeyword: 1 - }; - should.throw(function() { ajv.compile(schema); }); - }); - }); + unknownKeyword: 1, + } + should.throw(function () { + ajv.compile(schema) + }) + }) + }) - describe('strictKeywords = "log"', function() { - it('should log a warning given an unknown keyword in the schema root when strictKeywords is "log"', function() { - var output = {}; + describe('strictKeywords = "log"', function () { + it('should log a warning given an unknown keyword in the schema root when strictKeywords is "log"', function () { + var output = {} var ajv = new Ajv({ - strictKeywords: 'log', - logger: getLogger(output) - }); + strictKeywords: "log", + logger: getLogger(output), + }) var schema = { properties: {}, - unknownKeyword: 1 - }; - ajv.compile(schema); - should.equal(output.warning, 'unknown keyword: unknownKeyword'); - }); - }); + unknownKeyword: 1, + } + ajv.compile(schema) + should.equal(output.warning, "unknown keyword: unknownKeyword") + }) + }) - describe('unknown keyword inside schema that has no known keyword in compound keyword', function() { - it('should throw an error given an unknown keyword when strictKeywords is true', function() { - var ajv = new Ajv({strictKeywords: true}); + describe("unknown keyword inside schema that has no known keyword in compound keyword", function () { + it("should throw an error given an unknown keyword when strictKeywords is true", function () { + var ajv = new Ajv({strictKeywords: true}) var schema = { anyOf: [ { - unknownKeyword: 1 - } - ] - }; - should.throw(function() { ajv.compile(schema); }); - }); - }); + unknownKeyword: 1, + }, + ], + } + should.throw(function () { + ajv.compile(schema) + }) + }) + }) function getLogger(output) { return { - log: function() { - throw new Error('log should not be called'); + log: function () { + throw new Error("log should not be called") }, - warn: function(warning) { - output.warning = warning; + warn: function (warning) { + output.warning = warning }, - error: function() { - throw new Error('error should not be called'); - } - }; + error: function () { + throw new Error("error should not be called") + }, + } } -}); +}) diff --git a/spec/options/strictNumbers.spec.js b/spec/options/strictNumbers.spec.js index adf63b026d..9f939b2138 100644 --- a/spec/options/strictNumbers.spec.js +++ b/spec/options/strictNumbers.spec.js @@ -1,55 +1,57 @@ -'use strict'; +"use strict" -var Ajv = require('../ajv'); +var Ajv = require("../ajv") -describe('structNumbers option', function() { - var ajv; - describe('strictNumbers default', testWithoutStrictNumbers(new Ajv())); - describe('strictNumbers = false', testWithoutStrictNumbers(new Ajv({strictNumbers: false}))); - describe('strictNumbers = true', function() { +describe("structNumbers option", function () { + var ajv + describe("strictNumbers default", testWithoutStrictNumbers(new Ajv())) + describe( + "strictNumbers = false", + testWithoutStrictNumbers(new Ajv({strictNumbers: false})) + ) + describe("strictNumbers = true", function () { beforeEach(function () { - ajv = new Ajv({strictNumbers: true}); - }); + ajv = new Ajv({strictNumbers: true}) + }) - it('should fail validation for NaN/Infinity as type number', function() { - var validate = ajv.compile({type: 'number'}); - validate("1.1").should.equal(false); - validate(1.1).should.equal(true); - validate(1).should.equal(true); - validate(NaN).should.equal(false); - validate(Infinity).should.equal(false); - }); - - it('should fail validation for NaN as type integer', function() { - var validate = ajv.compile({type: 'integer'}); - validate("1.1").should.equal(false); - validate(1.1).should.equal(false); - validate(1).should.equal(true); - validate(NaN).should.equal(false); - validate(Infinity).should.equal(false); - }); - }); -}); + it("should fail validation for NaN/Infinity as type number", function () { + var validate = ajv.compile({type: "number"}) + validate("1.1").should.equal(false) + validate(1.1).should.equal(true) + validate(1).should.equal(true) + validate(NaN).should.equal(false) + validate(Infinity).should.equal(false) + }) + it("should fail validation for NaN as type integer", function () { + var validate = ajv.compile({type: "integer"}) + validate("1.1").should.equal(false) + validate(1.1).should.equal(false) + validate(1).should.equal(true) + validate(NaN).should.equal(false) + validate(Infinity).should.equal(false) + }) + }) +}) function testWithoutStrictNumbers(_ajv) { return function () { - it('should NOT fail validation for NaN/Infinity as type number', function() { - var validate = _ajv.compile({type: 'number'}); - validate("1.1").should.equal(false); - validate(1.1).should.equal(true); - validate(1).should.equal(true); - validate(NaN).should.equal(true); - validate(Infinity).should.equal(true); - }); + it("should NOT fail validation for NaN/Infinity as type number", function () { + var validate = _ajv.compile({type: "number"}) + validate("1.1").should.equal(false) + validate(1.1).should.equal(true) + validate(1).should.equal(true) + validate(NaN).should.equal(true) + validate(Infinity).should.equal(true) + }) - it('should NOT fail validation for NaN/Infinity as type integer', function() { - var validate = _ajv.compile({type: 'integer'}); - validate("1.1").should.equal(false); - validate(1.1).should.equal(false); - validate(1).should.equal(true); - validate(NaN).should.equal(false); - validate(Infinity).should.equal(true); - }); - }; + it("should NOT fail validation for NaN/Infinity as type integer", function () { + var validate = _ajv.compile({type: "integer"}) + validate("1.1").should.equal(false) + validate(1.1).should.equal(false) + validate(1).should.equal(true) + validate(NaN).should.equal(false) + validate(Infinity).should.equal(true) + }) + } } diff --git a/spec/options/unknownFormats.spec.js b/spec/options/unknownFormats.spec.js index 6e6dfde3d8..302e892c50 100644 --- a/spec/options/unknownFormats.spec.js +++ b/spec/options/unknownFormats.spec.js @@ -1,108 +1,111 @@ -'use strict'; +"use strict" -var Ajv = require('../ajv'); -var should = require('../chai').should(); +var Ajv = require("../ajv") +var should = require("../chai").should() +const DATE_FORMAT = /^\d\d\d\d-[0-1]\d-[0-3]\d$/ - -describe('unknownFormats option', function() { - describe('= true (default)', function() { - it('should fail schema compilation if unknown format is used', function() { - test(new Ajv); - test(new Ajv({unknownFormats: true})); +describe("unknownFormats option", function () { + describe("= true (default)", function () { + it("should fail schema compilation if unknown format is used", function () { + test(new Ajv()) + test(new Ajv({unknownFormats: true})) function test(ajv) { - should.throw(function() { - ajv.compile({ format: 'unknown' }); - }); + should.throw(function () { + ajv.compile({format: "unknown"}) + }) } - }); + }) - it('should fail validation if unknown format is used via $data', function() { - test(new Ajv({$data: true})); - test(new Ajv({$data: true, unknownFormats: true})); + it("should fail validation if unknown format is used via $data", function () { + test(new Ajv({$data: true})) + test(new Ajv({$data: true, unknownFormats: true})) function test(ajv) { + ajv.addFormat("date", DATE_FORMAT) var validate = ajv.compile({ properties: { - foo: { format: { $data: '1/bar' } }, - bar: { type: 'string' } - } - }); + foo: {format: {$data: "1/bar"}}, + bar: {type: "string"}, + }, + }) - validate({foo: 1, bar: 'unknown'}) .should.equal(false); - validate({foo: '2016-10-16', bar: 'date'}) .should.equal(true); - validate({foo: '20161016', bar: 'date'}) .should.equal(false); - validate({foo: '20161016'}) .should.equal(true); + validate({foo: 1, bar: "unknown"}).should.equal(false) + validate({foo: "2016-10-16", bar: "date"}).should.equal(true) + validate({foo: "20161016", bar: "date"}).should.equal(false) + validate({foo: "20161016"}).should.equal(true) - validate({foo: '2016-10-16', bar: 'unknown'}) .should.equal(false); + validate({foo: "2016-10-16", bar: "unknown"}).should.equal(false) } - }); - }); + }) + }) - describe('= "ignore (default before 5.0.0)"', function() { - it('should pass schema compilation and be valid if unknown format is used', function() { - test(new Ajv({unknownFormats: 'ignore'})); + describe('= "ignore (default before 5.0.0)"', function () { + it("should pass schema compilation and be valid if unknown format is used", function () { + test(new Ajv({unknownFormats: "ignore"})) function test(ajv) { - var validate = ajv.compile({ format: 'unknown' }); - validate('anything') .should.equal(true); + var validate = ajv.compile({format: "unknown"}) + validate("anything").should.equal(true) } - }); + }) - it('should be valid if unknown format is used via $data', function() { - test(new Ajv({$data: true, unknownFormats: 'ignore'})); + it("should be valid if unknown format is used via $data", function () { + test(new Ajv({$data: true, unknownFormats: "ignore"})) function test(ajv) { + ajv.addFormat("date", DATE_FORMAT) var validate = ajv.compile({ properties: { - foo: { format: { $data: '1/bar' } }, - bar: { type: 'string' } - } - }); - - validate({foo: 1, bar: 'unknown'}) .should.equal(true); - validate({foo: '2016-10-16', bar: 'date'}) .should.equal(true); - validate({foo: '20161016', bar: 'date'}) .should.equal(false); - validate({foo: '20161016'}) .should.equal(true); - validate({foo: '2016-10-16', bar: 'unknown'}) .should.equal(true); + foo: {format: {$data: "1/bar"}}, + bar: {type: "string"}, + }, + }) + + validate({foo: 1, bar: "unknown"}).should.equal(true) + validate({foo: "2016-10-16", bar: "date"}).should.equal(true) + validate({foo: "20161016", bar: "date"}).should.equal(false) + validate({foo: "20161016"}).should.equal(true) + validate({foo: "2016-10-16", bar: "unknown"}).should.equal(true) } - }); - }); + }) + }) - describe('= [String]', function() { - it('should pass schema compilation and be valid if allowed unknown format is used', function() { - test(new Ajv({unknownFormats: ['allowed']})); + describe("= [String]", function () { + it("should pass schema compilation and be valid if allowed unknown format is used", function () { + test(new Ajv({unknownFormats: ["allowed"]})) function test(ajv) { - var validate = ajv.compile({ format: 'allowed' }); - validate('anything') .should.equal(true); + var validate = ajv.compile({format: "allowed"}) + validate("anything").should.equal(true) - should.throw(function() { - ajv.compile({ format: 'unknown' }); - }); + should.throw(function () { + ajv.compile({format: "unknown"}) + }) } - }); + }) - it('should be valid if allowed unknown format is used via $data', function() { - test(new Ajv({$data: true, unknownFormats: ['allowed']})); + it("should be valid if allowed unknown format is used via $data", function () { + test(new Ajv({$data: true, unknownFormats: ["allowed"]})) function test(ajv) { + ajv.addFormat("date", DATE_FORMAT) var validate = ajv.compile({ properties: { - foo: { format: { $data: '1/bar' } }, - bar: { type: 'string' } - } - }); - - validate({foo: 1, bar: 'allowed'}) .should.equal(true); - validate({foo: 1, bar: 'unknown'}) .should.equal(false); - validate({foo: '2016-10-16', bar: 'date'}) .should.equal(true); - validate({foo: '20161016', bar: 'date'}) .should.equal(false); - validate({foo: '20161016'}) .should.equal(true); - - validate({foo: '2016-10-16', bar: 'allowed'}) .should.equal(true); - validate({foo: '2016-10-16', bar: 'unknown'}) .should.equal(false); + foo: {format: {$data: "1/bar"}}, + bar: {type: "string"}, + }, + }) + + validate({foo: 1, bar: "allowed"}).should.equal(true) + validate({foo: 1, bar: "unknown"}).should.equal(false) + validate({foo: "2016-10-16", bar: "date"}).should.equal(true) + validate({foo: "20161016", bar: "date"}).should.equal(false) + validate({foo: "20161016"}).should.equal(true) + + validate({foo: "2016-10-16", bar: "allowed"}).should.equal(true) + validate({foo: "2016-10-16", bar: "unknown"}).should.equal(false) } - }); - }); -}); + }) + }) +}) diff --git a/spec/options/useDefaults.spec.js b/spec/options/useDefaults.spec.js index 7a12e8423b..b660a0c5ba 100644 --- a/spec/options/useDefaults.spec.js +++ b/spec/options/useDefaults.spec.js @@ -1,223 +1,229 @@ -'use strict'; +"use strict" -var Ajv = require('../ajv'); -var getAjvInstances = require('../ajv_instances'); -require('../chai').should(); +var Ajv = require("../ajv") +var getAjvInstances = require("../ajv_instances") +require("../chai").should() +describe("useDefaults options", function () { + it("should replace undefined property with default value", function () { + var instances = getAjvInstances( + { + allErrors: true, + loopRequired: 3, + }, + {useDefaults: true} + ) -describe('useDefaults options', function() { - it('should replace undefined property with default value', function() { - var instances = getAjvInstances({ - allErrors: true, - loopRequired: 3 - }, { useDefaults: true }); - - instances.forEach(test); - + instances.forEach(test) function test(ajv) { var schema = { properties: { - foo: { type: 'string', default: 'abc' }, - bar: { type: 'number', default: 1 }, - baz: { type: 'boolean', default: false }, - nil: { type: 'null', default: null }, - obj: { type: 'object', default: {} }, - arr: { type: 'array', default: [] } + foo: {type: "string", default: "abc"}, + bar: {type: "number", default: 1}, + baz: {type: "boolean", default: false}, + nil: {type: "null", default: null}, + obj: {type: "object", default: {}}, + arr: {type: "array", default: []}, }, - required: ['foo', 'bar', 'baz', 'nil', 'obj', 'arr'], - minProperties: 6 - }; - - var validate = ajv.compile(schema); - - var data = {}; - validate(data) .should.equal(true); - data .should.eql({ foo: 'abc', bar: 1, baz: false, nil: null, obj: {}, arr:[] }); + required: ["foo", "bar", "baz", "nil", "obj", "arr"], + minProperties: 6, + } - data = { foo: 'foo', bar: 2, obj: { test: true } }; - validate(data) .should.equal(true); - data .should.eql({ foo: 'foo', bar: 2, baz: false, nil: null, obj: { test: true }, arr:[] }); + var validate = ajv.compile(schema) + + var data = {} + validate(data).should.equal(true) + data.should.eql({ + foo: "abc", + bar: 1, + baz: false, + nil: null, + obj: {}, + arr: [], + }) + + data = {foo: "foo", bar: 2, obj: {test: true}} + validate(data).should.equal(true) + data.should.eql({ + foo: "foo", + bar: 2, + baz: false, + nil: null, + obj: {test: true}, + arr: [], + }) } - }); + }) - it('should replace undefined item with default value', function() { - test(new Ajv({ useDefaults: true })); - test(new Ajv({ useDefaults: true, allErrors: true })); + it("should replace undefined item with default value", function () { + test(new Ajv({useDefaults: true})) + test(new Ajv({useDefaults: true, allErrors: true})) function test(ajv) { var schema = { items: [ - { type: 'string', default: 'abc' }, - { type: 'number', default: 1 }, - { type: 'boolean', default: false } + {type: "string", default: "abc"}, + {type: "number", default: 1}, + {type: "boolean", default: false}, ], - minItems: 3 - }; + minItems: 3, + } - var validate = ajv.compile(schema); + var validate = ajv.compile(schema) - var data = []; - validate(data) .should.equal(true); - data .should.eql([ 'abc', 1, false ]); + var data = [] + validate(data).should.equal(true) + data.should.eql(["abc", 1, false]) - data = [ 'foo' ]; - validate(data) .should.equal(true); - data .should.eql([ 'foo', 1, false ]); + data = ["foo"] + validate(data).should.equal(true) + data.should.eql(["foo", 1, false]) - data = ['foo', 2,'false']; - validate(data) .should.equal(false); - validate.errors .should.have.length(1); - data .should.eql([ 'foo', 2, 'false' ]); + data = ["foo", 2, "false"] + validate(data).should.equal(false) + validate.errors.should.have.length(1) + data.should.eql(["foo", 2, "false"]) } - }); + }) - it('should apply default in "then" subschema (issue #635)', function() { - test(new Ajv({ useDefaults: true })); - test(new Ajv({ useDefaults: true, allErrors: true })); + 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'] }, + if: {required: ["foo"]}, then: { properties: { - bar: { default: 2 } - } + bar: {default: 2}, + }, }, else: { properties: { - foo: { default: 1 } - } - } - }; + foo: {default: 1}, + }, + }, + } - var validate = ajv.compile(schema); + var validate = ajv.compile(schema) - var data = {}; - validate(data) .should.equal(true); - data .should.eql({foo: 1}); + 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}); + 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() { - it('should NOT modify underlying defaults when modifying validated data', function() { - test('value', new Ajv({ useDefaults: true })); - test('value', new Ajv({ useDefaults: true, allErrors: true })); - }); - }); - - describe('using by reference', function() { - it('should modify underlying defaults when modifying validated data', function() { - test('reference', new Ajv({ useDefaults: 'shared' })); - test('reference', new Ajv({ useDefaults: 'shared', allErrors: true })); - }); - }); + }) + + describe("useDefaults: by value / by reference", function () { + describe("using by value", function () { + it("should NOT modify underlying defaults when modifying validated data", function () { + test("value", new Ajv({useDefaults: true})) + test("value", new Ajv({useDefaults: true, allErrors: true})) + }) + }) + + describe("using by reference", function () { + it("should modify underlying defaults when modifying validated data", function () { + test("reference", new Ajv({useDefaults: "shared"})) + test("reference", new Ajv({useDefaults: "shared", allErrors: true})) + }) + }) function test(useDefaultsMode, ajv) { var schema = { properties: { items: { - type: 'array', - default: ['a-default'] - } - } - }; - - var validate = ajv.compile(schema); - - var data = {}; - validate(data) .should.equal(true); - data.items .should.eql([ 'a-default' ]); - - data.items.push('another-value'); - data.items .should.eql([ 'a-default', 'another-value' ]); - - var data2 = {}; - validate(data2) .should.equal(true); - - if (useDefaultsMode == 'reference') - data2.items .should.eql([ 'a-default', 'another-value' ]); - else if (useDefaultsMode == 'value') - data2.items .should.eql([ 'a-default' ]); - else - throw new Error('unknown useDefaults mode'); - } - }); + type: "array", + default: ["a-default"], + }, + }, + } + var validate = ajv.compile(schema) - describe('defaults with "empty" values', function() { - var schema, data; + var data = {} + validate(data).should.equal(true) + data.items.should.eql(["a-default"]) - beforeEach(function() { + data.items.push("another-value") + data.items.should.eql(["a-default", "another-value"]) + + var data2 = {} + validate(data2).should.equal(true) + + if (useDefaultsMode == "reference") + data2.items.should.eql(["a-default", "another-value"]) + else if (useDefaultsMode == "value") data2.items.should.eql(["a-default"]) + else throw new Error("unknown useDefaults mode") + } + }) + + describe('defaults with "empty" values', function () { + var schema, data + + beforeEach(function () { schema = { properties: { obj: { properties: { - str: {default: 'foo'}, + str: {default: "foo"}, n1: {default: 1}, n2: {default: 2}, - n3: {default: 3} - } + n3: {default: 3}, + }, }, arr: { - items: [ - {default: 'foo'}, - {default: 1}, - {default: 2}, - {default: 3} - ] - } - } - }; + items: [{default: "foo"}, {default: 1}, {default: 2}, {default: 3}], + }, + }, + } data = { obj: { - str: '', + str: "", n1: null, - n2: undefined + n2: undefined, }, - arr: ['', null, undefined] - }; - }); + arr: ["", null, undefined], + } + }) - it('should NOT assign defaults when useDefaults is true/"shared"', function() { - test(new Ajv({useDefaults: true})); - test(new Ajv({useDefaults: 'shared'})); + it('should NOT assign defaults when useDefaults is true/"shared"', function () { + test(new Ajv({useDefaults: true})) + test(new Ajv({useDefaults: "shared"})) function test(ajv) { - var validate = ajv.compile(schema); - validate(data) .should.equal(true); - data .should.eql({ + var validate = ajv.compile(schema) + validate(data).should.equal(true) + data.should.eql({ obj: { - str: '', + str: "", n1: null, n2: 2, - n3: 3 + n3: 3, }, - arr: ['', null, 2, 3] - }); + arr: ["", null, 2, 3], + }) } - }); + }) - it('should assign defaults when useDefaults = "empty"', function() { - var ajv = new Ajv({useDefaults: 'empty'}); - var validate = ajv.compile(schema); - validate(data) .should.equal(true); - data .should.eql({ + it('should assign defaults when useDefaults = "empty"', function () { + var ajv = new Ajv({useDefaults: "empty"}) + var validate = ajv.compile(schema) + validate(data).should.equal(true) + data.should.eql({ obj: { - str: 'foo', + str: "foo", n1: 1, n2: 2, - n3: 3 + n3: 3, }, - arr: ['foo', 1, 2, 3] - }); - }); - }); -}); + arr: ["foo", 1, 2, 3], + }) + }) + }) +}) diff --git a/spec/promise.js b/spec/promise.js index 8c55c8750d..98caf040ee 100644 --- a/spec/promise.js +++ b/spec/promise.js @@ -1,11 +1,11 @@ -'use strict'; +"use strict" -var g = typeof global == 'object' ? global : - typeof window == 'object' ? window : this; +var g = + typeof global == "object" ? global : typeof window == "object" ? window : this if (!g.Promise) { - g.Promise = require('' + 'bluebird'); - g.Promise.config({ warnings: false }); + g.Promise = require("" + "bluebird") + g.Promise.config({warnings: false}) } -module.exports = g.Promise; +module.exports = g.Promise diff --git a/spec/remotes/buu.json b/spec/remotes/buu.json index f3d905c4a1..df6af16b09 100644 --- a/spec/remotes/buu.json +++ b/spec/remotes/buu.json @@ -4,7 +4,7 @@ "buu": { "type": "object", "properties": { - "bar": { "$ref": "bar.json" } + "bar": {"$ref": "bar.json"} } } } diff --git a/spec/remotes/first.json b/spec/remotes/first.json index 9fdb8d486f..0ddfe2a3fe 100644 --- a/spec/remotes/first.json +++ b/spec/remotes/first.json @@ -1,4 +1,4 @@ { - "$id": "http://localhost:1234/first.json", - "type": "string" + "$id": "http://localhost:1234/first.json", + "type": "string" } diff --git a/spec/remotes/foo.json b/spec/remotes/foo.json index 9e565666f1..2ea24f33b4 100644 --- a/spec/remotes/foo.json +++ b/spec/remotes/foo.json @@ -2,6 +2,6 @@ "$id": "http://localhost:1234/foo.json", "type": "object", "properties": { - "bar": { "$ref": "bar.json" } + "bar": {"$ref": "bar.json"} } } diff --git a/spec/remotes/hyper-schema.json b/spec/remotes/hyper-schema.json index 349ee2de95..59787c54df 100644 --- a/spec/remotes/hyper-schema.json +++ b/spec/remotes/hyper-schema.json @@ -1,69 +1,65 @@ { - "$schema": "http://json-schema.org/draft-07/hyper-schema#", - "$id": "http://json-schema.org/draft-07/hyper-schema#", - "title": "JSON Hyper-Schema", - "definitions": { - "schemaArray": { - "allOf": [ - { "$ref": "http://json-schema.org/draft-07/schema#/definitions/schemaArray" }, - { - "items": { "$ref": "#" } - } - ] + "$schema": "http://json-schema.org/draft-07/hyper-schema#", + "$id": "http://json-schema.org/draft-07/hyper-schema#", + "title": "JSON Hyper-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": {"$ref": "#"}, + "additionalProperties": {"$ref": "#"}, + "dependencies": { + "additionalProperties": { + "anyOf": [{"$ref": "#"}, {"type": "array"}] + } + }, + "items": { + "anyOf": [{"$ref": "#"}, {"$ref": "#/definitions/schemaArray"}] + }, + "definitions": { + "additionalProperties": {"$ref": "#"} + }, + "patternProperties": { + "additionalProperties": {"$ref": "#"} }, - "allOf": [ { "$ref": "http://json-schema.org/draft-07/schema#" } ], "properties": { - "additionalItems": { "$ref": "#" }, - "additionalProperties": { "$ref": "#"}, - "dependencies": { - "additionalProperties": { - "anyOf": [ - { "$ref": "#" }, - { "type": "array" } - ] - } - }, - "items": { - "anyOf": [ - { "$ref": "#" }, - { "$ref": "#/definitions/schemaArray" } - ] - }, - "definitions": { - "additionalProperties": { "$ref": "#" } - }, - "patternProperties": { - "additionalProperties": { "$ref": "#" } - }, - "properties": { - "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": "#" }, + "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": "http://json-schema.org/draft-07/hyper-schema#/links" - } - } + "base": { + "type": "string", + "format": "uri-template" }, - "links": [ - { - "rel": "self", - "href": "{+%24id}" - } - ] + "links": { + "type": "array", + "items": { + "$ref": "http://json-schema.org/draft-07/hyper-schema#/links" + } + } + }, + "links": [ + { + "rel": "self", + "href": "{+%24id}" + } + ] } diff --git a/spec/remotes/name.json b/spec/remotes/name.json index 3fa219a6eb..96ad9227a8 100644 --- a/spec/remotes/name.json +++ b/spec/remotes/name.json @@ -1,10 +1,7 @@ { "definitions": { "orNull": { - "anyOf": [ - { "type": "null" }, - { "$ref": "#" } - ] + "anyOf": [{"type": "null"}, {"$ref": "#"}] } }, "type": "string" diff --git a/spec/remotes/node.json b/spec/remotes/node.json index 41120c1efe..b2a09868e7 100644 --- a/spec/remotes/node.json +++ b/spec/remotes/node.json @@ -3,8 +3,8 @@ "description": "node", "type": "object", "properties": { - "value": { "type": "number" }, - "subtree": { "$ref": "tree.json" } + "value": {"type": "number"}, + "subtree": {"$ref": "tree.json"} }, "required": ["value"] } diff --git a/spec/remotes/scope_change.json b/spec/remotes/scope_change.json index 67991f9716..612b54725a 100644 --- a/spec/remotes/scope_change.json +++ b/spec/remotes/scope_change.json @@ -12,9 +12,9 @@ "baz": { "$id": "folder/", "type": "array", - "items": { "$ref": "folderInteger.json" }, + "items": {"$ref": "folderInteger.json"}, "bar": { - "items": { "$ref": "folderInteger.json" } + "items": {"$ref": "folderInteger.json"} } } } diff --git a/spec/remotes/second.json b/spec/remotes/second.json index 56e32ebfd2..2bce3a6e1e 100644 --- a/spec/remotes/second.json +++ b/spec/remotes/second.json @@ -1,7 +1,7 @@ { - "$id": "http://localhost:1234/second.json", - "type": "object", - "properties": { - "first": { "$ref": "first.json" } - } + "$id": "http://localhost:1234/second.json", + "type": "object", + "properties": { + "first": {"$ref": "first.json"} + } } diff --git a/spec/remotes/tree.json b/spec/remotes/tree.json index 39df56141c..daf3657b72 100644 --- a/spec/remotes/tree.json +++ b/spec/remotes/tree.json @@ -3,10 +3,10 @@ "description": "tree of nodes", "type": "object", "properties": { - "meta": { "type": "string" }, + "meta": {"type": "string"}, "nodes": { "type": "array", - "items": { "$ref": "node.json"} + "items": {"$ref": "node.json"} } }, "required": ["meta", "nodes"] diff --git a/spec/resolve.spec.js b/spec/resolve.spec.js index f04eabe96f..a4f03247b9 100644 --- a/spec/resolve.spec.js +++ b/spec/resolve.spec.js @@ -1,251 +1,237 @@ -'use strict'; +"use strict" -var Ajv = require('./ajv') - , should = require('./chai').should() - , getAjvInstances = require('./ajv_instances'); +var Ajv = require("./ajv"), + should = require("./chai").should(), + getAjvInstances = require("./ajv_instances") +describe("resolve", function () { + var instances -describe('resolve', function () { - var instances; - - beforeEach(function() { + beforeEach(function () { instances = getAjvInstances({ - allErrors: true, - verbose: true, - inlineRefs: false - }); - }); - - describe('resolve.ids method', function() { - it('should resolve ids in schema', function() { + allErrors: true, + verbose: true, + inlineRefs: false, + }) + }) + + describe("resolve.ids method", 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#", - "schema1": { - "$id": "#foo", - "description": "schema1", - "type": "integer" + $id: "http://x.y.z/rootschema.json#", + schema1: { + $id: "#foo", + description: "schema1", + type: "integer", }, - "schema2": { - "$id": "otherschema.json", - "description": "schema2", - "nested": { - "$id": "#bar", - "description": "nested", - "type": "string" + schema2: { + $id: "otherschema.json", + description: "schema2", + nested: { + $id: "#bar", + description: "nested", + type: "string", + }, + alsonested: { + $id: "t/inner.json#a", + description: "alsonested", + type: "boolean", }, - "alsonested": { - "$id": "t/inner.json#a", - "description": "alsonested", - "type": "boolean" - } }, - "schema3": { - "$id": "some://where.else/completely#", - "description": "schema3", - "type": "null" + schema3: { + $id: "some://where.else/completely#", + description: "schema3", + type: "null", }, - "properties": { - "foo": { "$ref": "#foo" }, - "bar": { "$ref": "otherschema.json#bar" }, - "baz": { "$ref": "t/inner.json#a" }, - "bax": { "$ref": "some://where.else/completely#" } + properties: { + foo: {$ref: "#foo"}, + bar: {$ref: "otherschema.json#bar"}, + baz: {$ref: "t/inner.json#a"}, + bax: {$ref: "some://where.else/completely#"}, }, - "required": [ "foo", "bar", "baz", "bax" ] - }; + required: ["foo", "bar", "baz", "bax"], + } instances.forEach(function (ajv) { - var validate = ajv.compile(schema); - var data = { foo: 1, bar: 'abc', baz: true, bax: null }; - validate(data) .should.equal(true); - }); - }); + var validate = ajv.compile(schema) + var data = {foo: 1, bar: "abc", baz: true, bax: null} + validate(data).should.equal(true) + }) + }) - - it('should throw if the same id resolves to two different schemas', 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", - "type": "integer" - }); - should.throw(function() { + $id: "http://example.com/1.json", + type: "integer", + }) + should.throw(function () { ajv.compile({ - "additionalProperties": { - "$id": "http://example.com/1.json", - "type": "string" - } - }); - }); - - should.throw(function() { + additionalProperties: { + $id: "http://example.com/1.json", + type: "string", + }, + }) + }) + + should.throw(function () { ajv.compile({ - "items": { - "$id": "#int", - "type": "integer" + items: { + $id: "#int", + type: "integer", + }, + additionalProperties: { + $id: "#int", + type: "string", }, - "additionalProperties": { - "$id": "#int", - "type": "string" - } - }); - }); - }); - }); - - it('should resolve ids defined as urn\'s (issue #423)', function() { + }) + }) + }) + }) + + it("should resolve ids defined as urn's (issue #423)", function () { var schema = { - "type": "object", - "properties": { - "ip1": { - "$id": "urn:some:ip:prop", - "type": "string", - "format": "ipv4" + type: "object", + properties: { + ip1: { + $id: "urn:some:ip:prop", + type: "string", + pattern: "^(\\d+\\.){3}\\d+$", + }, + ip2: { + $ref: "urn:some:ip:prop", }, - "ip2": { - "$ref": "urn:some:ip:prop" - } }, - "required": [ - "ip1", - "ip2" - ] - }; + required: ["ip1", "ip2"], + } var data = { - "ip1": "0.0.0.0", - "ip2": "0.0.0.0" - }; + ip1: "0.0.0.0", + ip2: "0.0.0.0", + } + instances.forEach(function (ajv) { + var validate = ajv.compile(schema) + validate(data).should.equal(true) + }) + }) + }) + + describe("protocol-relative URIs", function () { + it("should resolve fragment", function () { instances.forEach(function (ajv) { - var validate = ajv.compile(schema); - validate(data) .should.equal(true); - }); - }); - }); - - - describe('protocol-relative URIs', function() { - it('should resolve fragment', function() { - instances.forEach(function(ajv) { var schema = { - "$id": "//e.com/types", - "definitions": { - "int": { "type": "integer" } - } - }; - - ajv.addSchema(schema); - var validate = ajv.compile({ $ref: '//e.com/types#/definitions/int' }); - validate(1) .should.equal(true); - validate('foo') .should.equal(false); - }); - }); - }); + $id: "//e.com/types", + definitions: { + int: {type: "integer"}, + }, + } + ajv.addSchema(schema) + var validate = ajv.compile({$ref: "//e.com/types#/definitions/int"}) + validate(1).should.equal(true) + validate("foo").should.equal(false) + }) + }) + }) - describe('missing schema error', function() { - this.timeout(4000); + describe("missing schema error", function () { + this.timeout(4000) - it('should contain missingRef and missingSchema', function() { + it("should contain missingRef and missingSchema", function () { testMissingSchemaError({ - baseId: 'http://example.com/1.json', - ref: 'http://another.com/int.json', - expectedMissingRef: 'http://another.com/int.json', - expectedMissingSchema: 'http://another.com/int.json' - }); - }); - - it('should resolve missingRef and missingSchema relative to base id', function() { + baseId: "http://example.com/1.json", + ref: "http://another.com/int.json", + expectedMissingRef: "http://another.com/int.json", + expectedMissingSchema: "http://another.com/int.json", + }) + }) + + it("should resolve missingRef and missingSchema relative to base id", function () { testMissingSchemaError({ - baseId: 'http://example.com/folder/1.json', - ref: 'int.json', - expectedMissingRef: 'http://example.com/folder/int.json', - expectedMissingSchema: 'http://example.com/folder/int.json' - }); - }); - - it('should resolve missingRef and missingSchema relative to base id from root', function() { + baseId: "http://example.com/folder/1.json", + ref: "int.json", + expectedMissingRef: "http://example.com/folder/int.json", + expectedMissingSchema: "http://example.com/folder/int.json", + }) + }) + + it("should resolve missingRef and missingSchema relative to base id from root", function () { testMissingSchemaError({ - baseId: 'http://example.com/folder/1.json', - ref: '/int.json', - expectedMissingRef: 'http://example.com/int.json', - expectedMissingSchema: 'http://example.com/int.json' - }); - }); - - it('missingRef should and missingSchema should NOT include JSON path (hash fragment)', function() { + baseId: "http://example.com/folder/1.json", + ref: "/int.json", + expectedMissingRef: "http://example.com/int.json", + expectedMissingSchema: "http://example.com/int.json", + }) + }) + + it("missingRef should and missingSchema should NOT include JSON path (hash fragment)", function () { testMissingSchemaError({ - baseId: 'http://example.com/1.json', - ref: 'int.json#/definitions/positive', - expectedMissingRef: 'http://example.com/int.json#/definitions/positive', - expectedMissingSchema: 'http://example.com/int.json' - }); - }); - - it('should throw missing schema error if same path exist in the current schema but id is different (issue #220)', function() { + baseId: "http://example.com/1.json", + ref: "int.json#/definitions/positive", + expectedMissingRef: "http://example.com/int.json#/definitions/positive", + expectedMissingSchema: "http://example.com/int.json", + }) + }) + + it("should throw missing schema error if same path exist in the current schema but id is different (issue #220)", function () { testMissingSchemaError({ - baseId: 'http://example.com/parent.json', - ref: 'object.json#/properties/a', - expectedMissingRef: 'http://example.com/object.json#/properties/a', - expectedMissingSchema: 'http://example.com/object.json' - }); - }); - + baseId: "http://example.com/parent.json", + ref: "object.json#/properties/a", + expectedMissingRef: "http://example.com/object.json#/properties/a", + expectedMissingSchema: "http://example.com/object.json", + }) + }) function testMissingSchemaError(opts) { instances.forEach(function (ajv) { try { ajv.compile({ - "$id": opts.baseId, - "properties": { "a": { "$ref": opts.ref } } - }); - } catch(e) { - e.missingRef .should.equal(opts.expectedMissingRef); - e.missingSchema .should.equal(opts.expectedMissingSchema); + $id: opts.baseId, + properties: {a: {$ref: opts.ref}}, + }) + } catch (e) { + e.missingRef.should.equal(opts.expectedMissingRef) + e.missingSchema.should.equal(opts.expectedMissingSchema) } - }); + }) } - }); + }) - - describe('inline referenced schemas without refs in them', function() { + describe("inline referenced schemas without refs in them", function () { var schemas = [ - { $id: 'http://e.com/obj.json#', - properties: { a: { $ref: 'int.json#' } } }, - { $id: 'http://e.com/int.json#', - type: 'integer', minimum: 2, maximum: 4 }, - { $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#', - items: { $ref: 'obj.json#' } } - ]; - - it('by default should inline schema if it doesn\'t contain refs', function() { - var ajv = new Ajv({ schemas: schemas }); - testSchemas(ajv, true); - }); - - - it('should NOT inline schema if option inlineRefs == false', function() { - var ajv = new Ajv({ schemas: schemas, inlineRefs: false }); - testSchemas(ajv, false); - }); - - - it('should inline schema if option inlineRefs is bigger than number of keys in referenced schema', function() { - var ajv = new Ajv({ schemas: schemas, inlineRefs: 3 }); - testSchemas(ajv, true); - }); - - - it('should NOT inline schema if option inlineRefs is less than number of keys in referenced schema', function() { - var ajv = new Ajv({ schemas: schemas, inlineRefs: 2 }); - testSchemas(ajv, false); - }); - - - it('should avoid schema substitution when refs are inlined (issue #77)', function() { - var ajv = new Ajv({ verbose: true }); + {$id: "http://e.com/obj.json#", properties: {a: {$ref: "int.json#"}}}, + {$id: "http://e.com/int.json#", type: "integer", minimum: 2, maximum: 4}, + { + $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#", items: {$ref: "obj.json#"}}, + ] + + it("by default should inline schema if it doesn't contain refs", function () { + var ajv = new Ajv({schemas: schemas}) + testSchemas(ajv, true) + }) + + it("should NOT inline schema if option inlineRefs == false", function () { + var ajv = new Ajv({schemas: schemas, inlineRefs: false}) + testSchemas(ajv, false) + }) + + it("should inline schema if option inlineRefs is bigger than number of keys in referenced schema", function () { + var ajv = new Ajv({schemas: schemas, inlineRefs: 3}) + testSchemas(ajv, true) + }) + + it("should NOT inline schema if option inlineRefs is less than number of keys in referenced schema", function () { + var ajv = new Ajv({schemas: schemas, inlineRefs: 2}) + testSchemas(ajv, false) + }) + + it("should avoid schema substitution when refs are inlined (issue #77)", function () { + var ajv = new Ajv({verbose: true}) var schemaMessage = { $schema: "http://json-schema.org/draft-07/schema#", @@ -255,12 +241,12 @@ describe('resolve', function () { properties: { header: { allOf: [ - { $ref: "header.json" }, - { properties: { msgType: { "enum": [0] } } } - ] - } - } - }; + {$ref: "header.json"}, + {properties: {msgType: {enum: [0]}}}, + ], + }, + }, + } // header schema var schemaHeader = { @@ -270,73 +256,72 @@ describe('resolve', function () { properties: { version: { type: "integer", - maximum: 5 + maximum: 5, }, - msgType: { type: "integer" } + msgType: {type: "integer"}, }, - required: ["version", "msgType"] - }; + required: ["version", "msgType"], + } // a good message var validMessage = { header: { version: 4, - msgType: 0 - } - }; + msgType: 0, + }, + } // a bad message var invalidMessage = { header: { version: 6, - msgType: 0 - } - }; + msgType: 0, + }, + } // add schemas and get validator function - ajv.addSchema(schemaHeader); - ajv.addSchema(schemaMessage); - var v = ajv.getSchema('http://e.com/message.json#'); - - v(validMessage) .should.equal(true); - v.schema.$id .should.equal('http://e.com/message.json#'); + ajv.addSchema(schemaHeader) + ajv.addSchema(schemaMessage) + var v = ajv.getSchema("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(validMessage).should.equal(true) + 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(invalidMessage).should.equal(false) + v.errors.should.have.length(1) + 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#") + }) function testSchemas(ajv, expectedInlined) { - var v1 = ajv.getSchema('http://e.com/obj.json') - , v2 = ajv.getSchema('http://e.com/obj1.json') - , vl = ajv.getSchema('http://e.com/list.json'); - testObjSchema(v1); - testObjSchema(v2); - testListSchema(vl); - testInlined(v1, expectedInlined); - testInlined(v2, expectedInlined); - testInlined(vl, false); + var v1 = ajv.getSchema("http://e.com/obj.json"), + v2 = ajv.getSchema("http://e.com/obj1.json"), + vl = ajv.getSchema("http://e.com/list.json") + testObjSchema(v1) + testObjSchema(v2) + testListSchema(vl) + testInlined(v1, expectedInlined) + testInlined(v2, expectedInlined) + testInlined(vl, false) } function testObjSchema(validate) { - validate({a:3}) .should.equal(true); - validate({a:1}) .should.equal(false); - validate({a:5}) .should.equal(false); + validate({a: 3}).should.equal(true) + validate({a: 1}).should.equal(false) + validate({a: 5}).should.equal(false) } function testListSchema(validate) { - validate([{a:3}]) .should.equal(true); - validate([{a:1}]) .should.equal(false); - validate([{a:5}]) .should.equal(false); + validate([{a: 3}]).should.equal(true) + validate([{a: 1}]).should.equal(false) + validate([{a: 5}]).should.equal(false) } function testInlined(validate, expectedInlined) { - var inlined = !(/refVal/.test(validate.toString())); - inlined .should.equal(expectedInlined); + var inlined = !/refVal/.test(validate.toString()) + inlined.should.equal(expectedInlined) } - }); -}); + }) +}) diff --git a/spec/schema-tests.spec.js b/spec/schema-tests.spec.js index a076057106..3eabd831ca 100644 --- a/spec/schema-tests.spec.js +++ b/spec/schema-tests.spec.js @@ -1,51 +1,54 @@ -'use strict'; +"use strict" -var jsonSchemaTest = require('json-schema-test') - , getAjvInstances = require('./ajv_instances') - , options = require('./ajv_options') - , suite = require('./browser_test_suite') - , after = require('./after_test'); +var jsonSchemaTest = require("json-schema-test"), + addFormats = require("ajv-formats"), + getAjvInstances = require("./ajv_instances"), + options = require("./ajv_options"), + suite = require("./browser_test_suite"), + after = require("./after_test") -var instances = getAjvInstances(options, {unknownFormats: ['allowedUnknown']}); +var instances = getAjvInstances(options, {unknownFormats: ["allowedUnknown"]}) var remoteRefs = { - 'http://localhost:1234/integer.json': require('./JSON-Schema-Test-Suite/remotes/integer.json'), - 'http://localhost:1234/folder/folderInteger.json': require('./JSON-Schema-Test-Suite/remotes/folder/folderInteger.json'), - 'http://localhost:1234/name.json': require('./remotes/name.json') -}; + "http://localhost:1234/integer.json": require("./JSON-Schema-Test-Suite/remotes/integer.json"), + "http://localhost:1234/folder/folderInteger.json": require("./JSON-Schema-Test-Suite/remotes/folder/folderInteger.json"), + "http://localhost:1234/name.json": require("./remotes/name.json"), +} var remoteRefsWithIds = [ - require('./remotes/bar.json'), - require('./remotes/foo.json'), - require('./remotes/buu.json'), - require('./remotes/tree.json'), - require('./remotes/node.json'), - require('./remotes/second.json'), - require('./remotes/first.json'), - require('./remotes/scope_change.json'), -]; - -instances.forEach(addRemoteRefs); - + require("./remotes/bar.json"), + require("./remotes/foo.json"), + require("./remotes/buu.json"), + require("./remotes/tree.json"), + require("./remotes/node.json"), + require("./remotes/second.json"), + require("./remotes/first.json"), + require("./remotes/scope_change.json"), +] + +instances.forEach(addRemoteRefsAndFormats) jsonSchemaTest(instances, { - description: 'Schema tests of ' + instances.length + ' ajv instances with different options', + description: + "Schema tests of " + + instances.length + + " ajv instances with different options", suites: { - 'Advanced schema tests': - typeof window == 'object' - ? suite(require('./tests/{**/,}*.json', {mode: 'list'})) - : './tests/{**/,}*.json' + "Advanced schema tests": + typeof window == "object" + ? suite(require("./tests/{**/,}*.json", {mode: "list"})) + : "./tests/{**/,}*.json", }, only: [], - assert: require('./chai').assert, + assert: require("./chai").assert, afterError: after.error, afterEach: after.each, cwd: __dirname, - timeout: 120000 -}); - + timeout: 120000, +}) -function addRemoteRefs(ajv) { - for (var id in remoteRefs) ajv.addSchema(remoteRefs[id], id); - ajv.addSchema(remoteRefsWithIds); +function addRemoteRefsAndFormats(ajv) { + for (var id in remoteRefs) ajv.addSchema(remoteRefs[id], id) + ajv.addSchema(remoteRefsWithIds) + addFormats(ajv) } diff --git a/spec/security.spec.js b/spec/security.spec.js index 182e8b89f1..0b3436073e 100644 --- a/spec/security.spec.js +++ b/spec/security.spec.js @@ -1,27 +1,30 @@ -'use strict'; +"use strict" -var jsonSchemaTest = require('json-schema-test') - , getAjvInstances = require('./ajv_instances') - , options = require('./ajv_options') - , suite = require('./browser_test_suite') - , after = require('./after_test'); +var jsonSchemaTest = require("json-schema-test"), + getAjvInstances = require("./ajv_instances"), + options = require("./ajv_options"), + suite = require("./browser_test_suite"), + after = require("./after_test") var instances = getAjvInstances(options, { - schemas: [require('../lib/refs/json-schema-secure.json')] -}); - + schemas: [require("../lib/refs/json-schema-secure.json")], +}) jsonSchemaTest(instances, { - description: 'Secure schemas tests of ' + instances.length + ' ajv instances with different options', + description: + "Secure schemas tests of " + + instances.length + + " ajv instances with different options", suites: { - 'security': typeof window == 'object' - ? suite(require('./security/{**/,}*.json', {mode: 'list'})) - : './security/{**/,}*.json' + security: + typeof window == "object" + ? suite(require("./security/{**/,}*.json", {mode: "list"})) + : "./security/{**/,}*.json", }, - assert: require('./chai').assert, + assert: require("./chai").assert, afterError: after.error, afterEach: after.each, cwd: __dirname, - hideFolder: 'security/', - timeout: 90000 -}); + hideFolder: "security/", + timeout: 90000, +}) diff --git a/spec/security/array.json b/spec/security/array.json index 25b655f955..449cf89ee4 100644 --- a/spec/security/array.json +++ b/spec/security/array.json @@ -1,7 +1,9 @@ [ { "description": "uniqueItems without type keyword should be used together with maxItems", - "schema": {"$ref": "https://raw.githubusercontent.com/ajv-validator/ajv/master/lib/refs/json-schema-secure.json#"}, + "schema": { + "$ref": "https://raw.githubusercontent.com/ajv-validator/ajv/master/lib/refs/json-schema-secure.json#" + }, "tests": [ { "description": "uniqueItems keyword used without maxItems is unsafe", @@ -29,7 +31,9 @@ }, { "description": "uniqueItems with scalar type(s) is safe to use without maxItems", - "schema": {"$ref": "https://raw.githubusercontent.com/ajv-validator/ajv/master/lib/refs/json-schema-secure.json#"}, + "schema": { + "$ref": "https://raw.githubusercontent.com/ajv-validator/ajv/master/lib/refs/json-schema-secure.json#" + }, "tests": [ { "description": "uniqueItems keyword with a single scalar type is safe", @@ -55,7 +59,9 @@ }, { "description": "uniqueItems with compound type(s) should be used together with maxItems", - "schema": {"$ref": "https://raw.githubusercontent.com/ajv-validator/ajv/master/lib/refs/json-schema-secure.json#"}, + "schema": { + "$ref": "https://raw.githubusercontent.com/ajv-validator/ajv/master/lib/refs/json-schema-secure.json#" + }, "tests": [ { "description": "uniqueItems keyword with a single compound type and without maxItems is unsafe", @@ -83,7 +89,7 @@ "data": { "uniqueItems": true, "items": { - "type": ["array","number"] + "type": ["array", "number"] } }, "valid": false @@ -94,7 +100,7 @@ "uniqueItems": true, "maxItems": "10", "items": { - "type": ["array","number"] + "type": ["array", "number"] } }, "valid": true diff --git a/spec/security/object.json b/spec/security/object.json index 9de069b8a3..d23561a41d 100644 --- a/spec/security/object.json +++ b/spec/security/object.json @@ -1,7 +1,9 @@ [ { "description": "patternProperties keyword should be used together with propertyNames", - "schema": { "$ref": "https://raw.githubusercontent.com/ajv-validator/ajv/master/lib/refs/json-schema-secure.json#" }, + "schema": { + "$ref": "https://raw.githubusercontent.com/ajv-validator/ajv/master/lib/refs/json-schema-secure.json#" + }, "tests": [ { "description": "patternProperties keyword used without propertyNames is unsafe", diff --git a/spec/security/string.json b/spec/security/string.json index c6fb55292b..5890aa288d 100644 --- a/spec/security/string.json +++ b/spec/security/string.json @@ -1,7 +1,9 @@ [ { "description": "pattern keyword should be used together with maxLength", - "schema": { "$ref": "https://raw.githubusercontent.com/ajv-validator/ajv/master/lib/refs/json-schema-secure.json#" }, + "schema": { + "$ref": "https://raw.githubusercontent.com/ajv-validator/ajv/master/lib/refs/json-schema-secure.json#" + }, "tests": [ { "description": "pattern keyword used without maxLength is unsafe", @@ -22,7 +24,9 @@ }, { "description": "format keyword should be used together with maxLength", - "schema": { "$ref": "https://raw.githubusercontent.com/ajv-validator/ajv/master/lib/refs/json-schema-secure.json#" }, + "schema": { + "$ref": "https://raw.githubusercontent.com/ajv-validator/ajv/master/lib/refs/json-schema-secure.json#" + }, "tests": [ { "description": "format keyword used without maxLength is unsafe", diff --git a/spec/tests/issues/1061_alternative_time_offsets.json b/spec/tests/issues/1061_alternative_time_offsets.json deleted file mode 100644 index bf80f9581c..0000000000 --- a/spec/tests/issues/1061_alternative_time_offsets.json +++ /dev/null @@ -1,74 +0,0 @@ -[ - { - "description": "Support for alternative ISO-8601 timezone offset formats (#1061)", - "schema": {"format": "date-time"}, - "tests": [ - { - "description": "valid positiive two digit", - "data": "2016-01-31T02:31:17+01", - "valid": true - }, - { - "description": "valid negative two digit", - "data": "2016-01-31T02:31:17-01", - "valid": true - }, - { - "description": "valid positiive four digit no colon", - "data": "2016-01-31T02:31:17+0130", - "valid": true - }, - { - "description": "valid negative four digit no colon", - "data": "2016-01-31T02:31:17-0130", - "valid": true - }, - { - "description": "invalid positiive three digit no colon", - "data": "2016-01-31T02:31:17+013", - "valid": false - }, - { - "description": "invalid negative three digit no colon", - "data": "2016-01-31T02:31:17-013", - "valid": false - } - ] - }, - { - "description": "Support for alternative ISO-8601 timezone offset formats (#1061)", - "schema": {"format": "time"}, - "tests": [ - { - "description": "valid positiive two digit", - "data": "02:31:17+01", - "valid": true - }, - { - "description": "valid negative two digit", - "data": "02:31:17-01", - "valid": true - }, - { - "description": "valid positiive four digit no colon", - "data": "02:31:17+0130", - "valid": true - }, - { - "description": "valid negative four digit no colon", - "data": "02:31:17-0130", - "valid": true - }, - { - "description": "invalid positiive three digit no colon", - "data": "02:31:17+013", - "valid": false - }, - { - "description": "invalid negative three digit no colon", - "data": "02:31:17-013", - "valid": false - } - ] - } -] diff --git a/spec/tests/issues/12_restoring_root_after_resolve.json b/spec/tests/issues/12_restoring_root_after_resolve.json index cc1d615595..57375ee80e 100644 --- a/spec/tests/issues/12_restoring_root_after_resolve.json +++ b/spec/tests/issues/12_restoring_root_after_resolve.json @@ -3,13 +3,10 @@ "description": "restoring root after ref resolution (#12)", "schema": { "definitions": { - "int": { "$ref": "http://localhost:1234/integer.json" }, - "str": { "type": "string" } + "int": {"$ref": "http://localhost:1234/integer.json"}, + "str": {"type": "string"} }, - "anyOf": [ - { "$ref": "#/definitions/int" }, - { "$ref": "#/definitions/str" } - ] + "anyOf": [{"$ref": "#/definitions/int"}, {"$ref": "#/definitions/str"}] }, "tests": [ { @@ -33,13 +30,10 @@ "description": "all refs are in the same place", "schema": { "definitions": { - "int": { "type": "integer" }, - "str": { "type": "string" } + "int": {"type": "integer"}, + "str": {"type": "string"} }, - "anyOf": [ - { "$ref": "#/definitions/int" }, - { "$ref": "#/definitions/str" } - ] + "anyOf": [{"$ref": "#/definitions/int"}, {"$ref": "#/definitions/str"}] }, "tests": [ { diff --git a/spec/tests/issues/13_root_ref_in_ref_in_remote_ref.json b/spec/tests/issues/13_root_ref_in_ref_in_remote_ref.json index a55625abb0..fc77ffed70 100644 --- a/spec/tests/issues/13_root_ref_in_ref_in_remote_ref.json +++ b/spec/tests/issues/13_root_ref_in_ref_in_remote_ref.json @@ -5,7 +5,7 @@ "$id": "http://localhost:1234/issue13", "type": "object", "properties": { - "name": { "$ref": "name.json#/definitions/orNull" } + "name": {"$ref": "name.json#/definitions/orNull"} } }, "tests": [ diff --git a/spec/tests/issues/14_ref_in_remote_ref_with_id.json b/spec/tests/issues/14_ref_in_remote_ref_with_id.json index 57b474a4b4..ae4cbeac18 100644 --- a/spec/tests/issues/14_ref_in_remote_ref_with_id.json +++ b/spec/tests/issues/14_ref_in_remote_ref_with_id.json @@ -4,7 +4,7 @@ "schema": { "$id": "http://localhost:1234/issue14a.json", "type": "array", - "items": { "$ref": "foo.json" } + "items": {"$ref": "foo.json"} }, "tests": [ { @@ -32,7 +32,7 @@ "schema": { "$id": "http://localhost:1234/issue14b.json", "type": "array", - "items": { "$ref": "buu.json#/definitions/buu" } + "items": {"$ref": "buu.json#/definitions/buu"} }, "tests": [ { diff --git a/spec/tests/issues/170_ref_and_id_in_sibling.json b/spec/tests/issues/170_ref_and_id_in_sibling.json index bb08d82944..afdabbebe9 100644 --- a/spec/tests/issues/170_ref_and_id_in_sibling.json +++ b/spec/tests/issues/170_ref_and_id_in_sibling.json @@ -11,10 +11,10 @@ "$id": "http://example.com/title", "type": "string" }, - "file": { "$ref": "#/definitions/file-entry" } + "file": {"$ref": "#/definitions/file-entry"} }, "definitions": { - "file-entry": { "type": "string" } + "file-entry": {"type": "string"} } }, { @@ -26,10 +26,10 @@ "$id": "http://example.com/title", "type": "string" }, - "file": { "$ref": "#/definitions/file-entry" } + "file": {"$ref": "#/definitions/file-entry"} }, "definitions": { - "file-entry": { "type": "string" } + "file-entry": {"type": "string"} } } ], @@ -64,10 +64,10 @@ "$id": "http://example.com/0", "type": "string" }, - { "$ref": "#/definitions/file-entry" } + {"$ref": "#/definitions/file-entry"} ], "definitions": { - "file-entry": { "type": "string" } + "file-entry": {"type": "string"} } }, { @@ -79,22 +79,22 @@ "$id": "http://example.com/0", "type": "string" }, - { "$ref": "#/definitions/file-entry" } + {"$ref": "#/definitions/file-entry"} ], "definitions": { - "file-entry": { "type": "string" } + "file-entry": {"type": "string"} } } ], "tests": [ { "description": "valid array", - "data": [ "foo", "bar" ], + "data": ["foo", "bar"], "valid": true }, { "description": "invalid array", - "data": [ "foo", 2 ], + "data": ["foo", 2], "valid": false } ] @@ -110,10 +110,10 @@ "$id": "http://example.com/0", "type": "number" }, - { "$ref": "#/definitions/def" } + {"$ref": "#/definitions/def"} ], "definitions": { - "def": { "type": "string" } + "def": {"type": "string"} } }, { @@ -124,10 +124,10 @@ "$id": "http://example.com/0", "type": "number" }, - { "$ref": "#/definitions/def" } + {"$ref": "#/definitions/def"} ], "definitions": { - "def": { "type": "string" } + "def": {"type": "string"} } } ], @@ -160,10 +160,10 @@ "$id": "http://example.com/0", "type": "number" }, - { "$ref": "#/definitions/def" } + {"$ref": "#/definitions/def"} ], "definitions": { - "def": { "type": "string" } + "def": {"type": "string"} } }, { @@ -174,10 +174,10 @@ "$id": "http://example.com/0", "type": "number" }, - { "$ref": "#/definitions/def" } + {"$ref": "#/definitions/def"} ], "definitions": { - "def": { "type": "string" } + "def": {"type": "string"} } } ], @@ -211,10 +211,10 @@ "type": "string", "maxLength": 3 }, - { "$ref": "#/definitions/def" } + {"$ref": "#/definitions/def"} ], "definitions": { - "def": { "type": "string" } + "def": {"type": "string"} } }, { @@ -226,10 +226,10 @@ "type": "string", "maxLength": 3 }, - { "$ref": "#/definitions/def" } + {"$ref": "#/definitions/def"} ], "definitions": { - "def": { "type": "string" } + "def": {"type": "string"} } } ], @@ -256,12 +256,12 @@ "dependencies": { "foo": { "$id": "http://example.com/foo", - "required": [ "bar" ] + "required": ["bar"] }, - "bar": { "$ref": "#/definitions/def" } + "bar": {"$ref": "#/definitions/def"} }, "definitions": { - "def": { "required": [ "baz" ] } + "def": {"required": ["baz"]} } }, { @@ -271,29 +271,29 @@ "dependencies": { "foo": { "$id": "http://example.com/foo", - "required": [ "bar" ] + "required": ["bar"] }, - "bar": { "$ref": "#/definitions/def" } + "bar": {"$ref": "#/definitions/def"} }, "definitions": { - "def": { "required": [ "baz" ] } + "def": {"required": ["baz"]} } } ], "tests": [ { "description": "valid object", - "data": { "foo": 1, "bar": 2, "baz": 3 }, + "data": {"foo": 1, "bar": 2, "baz": 3}, "valid": true }, { "description": "invalid object 2", - "data": { "foo": 1 }, + "data": {"foo": 1}, "valid": false }, { "description": "invalid object 2", - "data": { "foo": 1, "bar": 2 }, + "data": {"foo": 1, "bar": 2}, "valid": false } ] diff --git a/spec/tests/issues/17_escaping_pattern_property.json b/spec/tests/issues/17_escaping_pattern_property.json index edc70f5e49..b632c08995 100644 --- a/spec/tests/issues/17_escaping_pattern_property.json +++ b/spec/tests/issues/17_escaping_pattern_property.json @@ -2,14 +2,14 @@ { "description": "escaping pattern property (#17)", "schema": { - "type" : "object", + "type": "object", "patternProperties": { - "^.+$" : { - "type" : "object", - "required" : ["unit"] + "^.+$": { + "type": "object", + "required": ["unit"] } }, - "additionalProperties" : false + "additionalProperties": false }, "tests": [ { diff --git a/spec/tests/issues/1_ids_in_refs.json b/spec/tests/issues/1_ids_in_refs.json index 579e7d072a..2db0cac81f 100644 --- a/spec/tests/issues/1_ids_in_refs.json +++ b/spec/tests/issues/1_ids_in_refs.json @@ -22,8 +22,8 @@ } ], "tests": [ - { "description": "valid", "data": 1, "valid": true }, - { "description": "invalid", "data": "foo", "valid": false } + {"description": "valid", "data": 1, "valid": true}, + {"description": "invalid", "data": "foo", "valid": false} ] }, { @@ -51,8 +51,8 @@ } ], "tests": [ - { "description": "valid", "data": 1, "valid": true }, - { "description": "invalid", "data": "foo", "valid": false } + {"description": "valid", "data": 1, "valid": true}, + {"description": "invalid", "data": "foo", "valid": false} ] }, { @@ -66,8 +66,8 @@ "$ref": "#/definitions/int" }, "tests": [ - { "description": "valid", "data": 1, "valid": true }, - { "description": "invalid", "data": "foo", "valid": false } + {"description": "valid", "data": 1, "valid": true}, + {"description": "invalid", "data": "foo", "valid": false} ] } ] diff --git a/spec/tests/issues/20_failing_to_parse_schema.json b/spec/tests/issues/20_failing_to_parse_schema.json index b86a3a904e..259936da75 100644 --- a/spec/tests/issues/20_failing_to_parse_schema.json +++ b/spec/tests/issues/20_failing_to_parse_schema.json @@ -2,8 +2,8 @@ { "description": "Failing to parse schema with required property that is not an identifier (#20)", "schema": { - "type": "object", - "required": [ "a-b", "a'", "a\"" ] + "type": "object", + "required": ["a-b", "a'", "a\""] }, "tests": [ { @@ -25,33 +25,33 @@ { "description": "Failing to parse schema with required property that is not an identifier for many properties (#20)", "schema": { - "type": "object", - "required": [ - "a-1", - "a-2", - "a-3", - "a-4", - "a-5", - "a-6", - "a-7", - "a-8", - "a-9", - "a-10", - "a-11", - "a-12", - "a-13", - "a-14", - "a-15", - "a-16", - "a-17", - "a-18", - "a-19", - "a-20", - "a-21", - "a-22", - "'", - "\"" - ] + "type": "object", + "required": [ + "a-1", + "a-2", + "a-3", + "a-4", + "a-5", + "a-6", + "a-7", + "a-8", + "a-9", + "a-10", + "a-11", + "a-12", + "a-13", + "a-14", + "a-15", + "a-16", + "a-17", + "a-18", + "a-19", + "a-20", + "a-21", + "a-22", + "'", + "\"" + ] }, "tests": [ { diff --git a/spec/tests/issues/226_json_with_control_chars.json b/spec/tests/issues/226_json_with_control_chars.json index 5006d2293e..3e56dd8b2b 100644 --- a/spec/tests/issues/226_json_with_control_chars.json +++ b/spec/tests/issues/226_json_with_control_chars.json @@ -3,12 +3,12 @@ "description": "JSON with control characters - 'properties' (#226)", "schema": { "properties": { - "foo\nbar": { "type": "number" }, - "foo\"bar": { "type": "number" }, - "foo\\bar": { "type": "number" }, - "foo\rbar": { "type": "number" }, - "foo\tbar": { "type": "number" }, - "foo\fbar": { "type": "number" } + "foo\nbar": {"type": "number"}, + "foo\"bar": {"type": "number"}, + "foo\\bar": {"type": "number"}, + "foo\rbar": {"type": "number"}, + "foo\tbar": {"type": "number"}, + "foo\fbar": {"type": "number"} } }, "tests": [ @@ -76,7 +76,7 @@ { "description": "JSON with control characters - 'enum'", "schema": { - "enum": [ "foo\nbar", "foo\rbar" ] + "enum": ["foo\nbar", "foo\rbar"] }, "tests": [ { @@ -100,7 +100,7 @@ "description": "JSON with control characters - 'dependencies'", "schema": { "dependencies": { - "foo\nbar": [ "foo\rbar" ], + "foo\nbar": ["foo\rbar"], "foo\tbar": { "minProperties": 4 } diff --git a/spec/tests/issues/27_1_recursive_raml_schema.json b/spec/tests/issues/27_1_recursive_raml_schema.json index e2146b2d95..3869ddfdb0 100644 --- a/spec/tests/issues/27_1_recursive_raml_schema.json +++ b/spec/tests/issues/27_1_recursive_raml_schema.json @@ -5,9 +5,7 @@ "title": "A JSON Schema for a standard RAML object", "$schema": "http://json-schema.org/draft-07/schema#", "type": "object", - "required": [ - "title" - ], + "required": ["title"], "properties": { "title": { "type": "string", @@ -184,9 +182,7 @@ "oneOf": [ { "type": "object", - "required": [ - "type" - ], + "required": ["type"], "properties": { "type": { "enum": ["OAuth 1.0"] @@ -217,9 +213,7 @@ }, { "type": "object", - "required": [ - "type" - ], + "required": ["type"], "properties": { "type": { "enum": ["OAuth 2.0"] @@ -258,17 +252,12 @@ }, { "type": "object", - "required": [ - "type" - ], + "required": ["type"], "properties": { "type": { "oneOf": [ { - "enum": [ - "Basic Authentication", - "Digest Authentication" - ] + "enum": ["Basic Authentication", "Digest Authentication"] }, { "type": "string", diff --git a/spec/tests/issues/27_recursive_reference.json b/spec/tests/issues/27_recursive_reference.json index 6da686979c..77d2ac788f 100644 --- a/spec/tests/issues/27_recursive_reference.json +++ b/spec/tests/issues/27_recursive_reference.json @@ -11,21 +11,15 @@ "$id": "layout", "type": "object", "properties": { - "layout": { "type": "string" }, + "layout": {"type": "string"}, "panels": { "type": "array", "items": { - "anyOf": [ - { "type": "string" }, - { "$ref": "layout" } - ] + "anyOf": [{"type": "string"}, {"$ref": "layout"}] } } }, - "required": [ - "layout", - "panels" - ] + "required": ["layout", "panels"] } } }, @@ -38,21 +32,15 @@ "$id": "layout", "type": "object", "properties": { - "layout": { "type": "string" }, + "layout": {"type": "string"}, "panels": { "type": "array", "items": { - "anyOf": [ - { "type": "string" }, - { "$ref": "layout" } - ] + "anyOf": [{"type": "string"}, {"$ref": "layout"}] } } }, - "required": [ - "layout", - "panels" - ] + "required": ["layout", "panels"] } } } @@ -76,9 +64,7 @@ "panel2", { "layout": "test3", - "panels": [ - "panel3" - ] + "panels": ["panel3"] } ] } @@ -100,9 +86,7 @@ "panel2", { "layout": "test3", - "panels": [ - 3 - ] + "panels": [3] } ] } diff --git a/spec/tests/issues/28_escaping_pattern_error.json b/spec/tests/issues/28_escaping_pattern_error.json index 2f8a8fa718..d07dd1bbbd 100644 --- a/spec/tests/issues/28_escaping_pattern_error.json +++ b/spec/tests/issues/28_escaping_pattern_error.json @@ -2,7 +2,7 @@ { "description": "escaping pattern error (#28)", "schema": { - "type" : "object", + "type": "object", "properties": { "mediaType": { "type": "string", diff --git a/spec/tests/issues/2_root_ref_in_ref.json b/spec/tests/issues/2_root_ref_in_ref.json index 341cce07ab..cc50ffe4f8 100644 --- a/spec/tests/issues/2_root_ref_in_ref.json +++ b/spec/tests/issues/2_root_ref_in_ref.json @@ -4,14 +4,14 @@ "schema": { "definitions": { "arr": { - "type": "array", - "items": { "$ref": "#" } + "type": "array", + "items": {"$ref": "#"} } }, "type": "object", "properties": { - "name": { "type": "string" }, - "children": { "$ref": "#/definitions/arr" } + "name": {"type": "string"}, + "children": {"$ref": "#/definitions/arr"} } }, "tests": [ @@ -19,10 +19,7 @@ "description": "valid", "data": { "name": "foo", - "children": [ - { "name": "bar" }, - { "name": "baz" } - ] + "children": [{"name": "bar"}, {"name": "baz"}] }, "valid": true }, @@ -30,10 +27,7 @@ "description": "child numbers are invalid", "data": { "name": "foo", - "children": [ - { "name": 1 }, - { "name": 2 } - ] + "children": [{"name": 1}, {"name": 2}] }, "valid": false }, @@ -41,10 +35,7 @@ "description": "child arrays are invalid", "data": { "name": "foo", - "children": [ - [ ], - [ ] - ] + "children": [[], []] }, "valid": false } @@ -55,16 +46,13 @@ "schema": { "definitions": { "orNull": { - "anyOf": [ - { "type": "null" }, - { "$ref": "#" } - ] + "anyOf": [{"type": "null"}, {"$ref": "#"}] } }, "type": "object", "properties": { - "name": { "type": "string" }, - "parent": { "$ref": "#/definitions/orNull" } + "name": {"type": "string"}, + "parent": {"$ref": "#/definitions/orNull"} } }, "tests": [ diff --git a/spec/tests/issues/311_quotes_in_refs.json b/spec/tests/issues/311_quotes_in_refs.json index 04de75d339..d534524750 100644 --- a/spec/tests/issues/311_quotes_in_refs.json +++ b/spec/tests/issues/311_quotes_in_refs.json @@ -3,10 +3,10 @@ "description": "quotes in refs (#311)", "schema": { "properties": { - "foo\"bar": { "$ref": "#/definitions/foo\"bar" } + "foo\"bar": {"$ref": "#/definitions/foo\"bar"} }, "definitions": { - "foo\"bar": { "type": "number" } + "foo\"bar": {"type": "number"} } }, "tests": [ diff --git a/spec/tests/issues/413_dependencies_with_quote.json b/spec/tests/issues/413_dependencies_with_quote.json index 1b1cee3395..bf724cb96b 100644 --- a/spec/tests/issues/413_dependencies_with_quote.json +++ b/spec/tests/issues/413_dependencies_with_quote.json @@ -4,7 +4,7 @@ "schema": { "dependencies": { "foo'bar": { - "not": { "required": ["bar"] } + "not": {"required": ["bar"]} } } }, diff --git a/spec/tests/issues/502_contains_empty_array_with_ref_in_another_property.json b/spec/tests/issues/502_contains_empty_array_with_ref_in_another_property.json index 1c931a2414..6068c71027 100644 --- a/spec/tests/issues/502_contains_empty_array_with_ref_in_another_property.json +++ b/spec/tests/issues/502_contains_empty_array_with_ref_in_another_property.json @@ -4,14 +4,14 @@ "schema": { "type": "object", "properties": { - "str": { "$ref": "#/definitions/str" }, + "str": {"$ref": "#/definitions/str"}, "arr": { "type": "array", - "contains": { "type": "number" } + "contains": {"type": "number"} } }, "definitions": { - "str": { "type": "string" } + "str": {"type": "string"} } }, "tests": [ diff --git a/spec/tests/issues/5_adding_dependency_after.json b/spec/tests/issues/5_adding_dependency_after.json index 4c59b491c9..9be83495ed 100644 --- a/spec/tests/issues/5_adding_dependency_after.json +++ b/spec/tests/issues/5_adding_dependency_after.json @@ -5,12 +5,12 @@ "tests": [ { "description": "valid object", - "data": { "first": "foo" }, + "data": {"first": "foo"}, "valid": true }, { "description": "valid object", - "data": { "first": 1 }, + "data": {"first": 1}, "valid": false } ] diff --git a/spec/tests/issues/5_recursive_references.json b/spec/tests/issues/5_recursive_references.json index df39ba9245..c9832fe979 100644 --- a/spec/tests/issues/5_recursive_references.json +++ b/spec/tests/issues/5_recursive_references.json @@ -5,27 +5,21 @@ "tests": [ { "description": "valid tree", - "data": { + "data": { "meta": "root", "nodes": [ { "value": 1, "subtree": { "meta": "child", - "nodes": [ - { "value": 1.1 }, - { "value": 1.2 } - ] + "nodes": [{"value": 1.1}, {"value": 1.2}] } }, { "value": 2, "subtree": { "meta": "child", - "nodes": [ - { "value": 2.1 }, - { "value": 2.2 } - ] + "nodes": [{"value": 2.1}, {"value": 2.2}] } } ] @@ -34,27 +28,21 @@ }, { "description": "invalid tree", - "data": { + "data": { "meta": "root", "nodes": [ { "value": 1, "subtree": { "meta": "child", - "nodes": [ - { "value": "string is invalid" }, - { "value": 1.2 } - ] + "nodes": [{"value": "string is invalid"}, {"value": 1.2}] } }, { "value": 2, "subtree": { "meta": "child", - "nodes": [ - { "value": 2.1 }, - { "value": 2.2 } - ] + "nodes": [{"value": 2.1}, {"value": 2.2}] } } ] diff --git a/spec/tests/issues/62_resolution_scope_change.json b/spec/tests/issues/62_resolution_scope_change.json index 0db6ec69c5..efe6a11118 100644 --- a/spec/tests/issues/62_resolution_scope_change.json +++ b/spec/tests/issues/62_resolution_scope_change.json @@ -2,20 +2,22 @@ { "description": "change resolution scope - change filename (#62)", "schema": { - "type" : "object", + "type": "object", "properties": { - "title": { "$ref": "http://localhost:1234/scope_foo.json#/definitions/bar" } + "title": { + "$ref": "http://localhost:1234/scope_foo.json#/definitions/bar" + } } }, "tests": [ { "description": "string is valid", - "data": { "title": "baz" }, + "data": {"title": "baz"}, "valid": true }, { "description": "number is invalid", - "data": { "title": 1 }, + "data": {"title": 1}, "valid": false } ] @@ -23,20 +25,22 @@ { "description": "resolution scope change - change folder (#62)", "schema": { - "type" : "object", + "type": "object", "properties": { - "list": { "$ref": "http://localhost:1234/scope_change.json#/definitions/baz" } + "list": { + "$ref": "http://localhost:1234/scope_change.json#/definitions/baz" + } } }, "tests": [ { "description": "number is valid", - "data": { "list": [1] }, + "data": {"list": [1]}, "valid": true }, { "description": "string is invalid", - "data": { "list": ["a"] }, + "data": {"list": ["a"]}, "valid": false } ] @@ -44,20 +48,22 @@ { "description": "resolution scope change - change folder in subschema (#62)", "schema": { - "type" : "object", + "type": "object", "properties": { - "list": { "$ref": "http://localhost:1234/scope_change.json#/definitions/baz/bar" } + "list": { + "$ref": "http://localhost:1234/scope_change.json#/definitions/baz/bar" + } } }, "tests": [ { "description": "number is valid", - "data": { "list": [1] }, + "data": {"list": [1]}, "valid": true }, { "description": "string is invalid", - "data": { "list": ["a"] }, + "data": {"list": ["a"]}, "valid": false } ] diff --git a/spec/tests/issues/63_id_property_not_in_schema.json b/spec/tests/issues/63_id_property_not_in_schema.json index ce425cc3fe..daf5c930b4 100644 --- a/spec/tests/issues/63_id_property_not_in_schema.json +++ b/spec/tests/issues/63_id_property_not_in_schema.json @@ -2,9 +2,11 @@ { "description": "id property in referenced schema in object that is not a schema (#63)", "schema": { - "type" : "object", + "type": "object", "properties": { - "title": { "$ref": "http://json-schema.org/draft-07/schema#/properties/title" } + "title": { + "$ref": "http://json-schema.org/draft-07/schema#/properties/title" + } } }, "tests": [ @@ -15,12 +17,12 @@ }, { "description": "string is valid", - "data": { "title": "foo" }, + "data": {"title": "foo"}, "valid": true }, { "description": "number is invalid", - "data": { "title": 1 }, + "data": {"title": 1}, "valid": false } ] diff --git a/spec/tests/issues/70_1_recursive_hash_ref_in_remote_ref.json b/spec/tests/issues/70_1_recursive_hash_ref_in_remote_ref.json index 651e3d019e..8e14e762c5 100644 --- a/spec/tests/issues/70_1_recursive_hash_ref_in_remote_ref.json +++ b/spec/tests/issues/70_1_recursive_hash_ref_in_remote_ref.json @@ -5,9 +5,9 @@ "$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" }, - { "data": -1, "valid": false, "description": "negative integer is invalid" } + {"data": 1, "valid": true, "description": "positive integer is valid"}, + {"data": 0, "valid": true, "description": "zero is valid"}, + {"data": -1, "valid": false, "description": "negative integer is invalid"} ] }, { @@ -17,41 +17,61 @@ "$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" }, - { "data": -1, "valid": false, "description": "negative integer is invalid" } + {"data": 1, "valid": true, "description": "positive integer is valid"}, + {"data": 0, "valid": true, "description": "zero is valid"}, + {"data": -1, "valid": false, "description": "negative integer is invalid"} ] }, { "description": "local hash ref with remote hash ref without inner hash ref (#70, was passing)", "schema": { "definitions": { - "a": { "$ref": "http://json-schema.org/draft-07/schema#/definitions/nonNegativeIntegerDefault0" } + "a": { + "$ref": "http://json-schema.org/draft-07/schema#/definitions/nonNegativeIntegerDefault0" + } }, "properties": { - "b": { "$ref": "#/definitions/a" } + "b": {"$ref": "#/definitions/a"} } }, "tests": [ - { "data": { "b": 1 }, "valid": true, "description": "positive integer is valid" }, - { "data": { "b": 0 }, "valid": true, "description": "zero is valid" }, - { "data": { "b": -1 }, "valid": false, "description": "negative integer is invalid" } + { + "data": {"b": 1}, + "valid": true, + "description": "positive integer is valid" + }, + {"data": {"b": 0}, "valid": true, "description": "zero is valid"}, + { + "data": {"b": -1}, + "valid": false, + "description": "negative integer is invalid" + } ] }, { "description": "local hash ref with remote hash ref that has inner hash ref (#70)", "schema": { "definitions": { - "a": { "$ref": "http://json-schema.org/draft-07/schema#/definitions/nonNegativeIntegerDefault0" } + "a": { + "$ref": "http://json-schema.org/draft-07/schema#/definitions/nonNegativeIntegerDefault0" + } }, "properties": { - "b": { "$ref": "#/definitions/a" } + "b": {"$ref": "#/definitions/a"} } }, "tests": [ - { "data": { "b": 1 }, "valid": true, "description": "positive integer is valid" }, - { "data": { "b": 0 }, "valid": true, "description": "zero is valid" }, - { "data": { "b": -1 }, "valid": false, "description": "negative integer is invalid" } + { + "data": {"b": 1}, + "valid": true, + "description": "positive integer is valid" + }, + {"data": {"b": 0}, "valid": true, "description": "zero is valid"}, + { + "data": {"b": -1}, + "valid": false, + "description": "negative integer is invalid" + } ] } ] diff --git a/spec/tests/issues/70_swagger_schema.json b/spec/tests/issues/70_swagger_schema.json index 3c9a2c80da..0b3da339a0 100644 --- a/spec/tests/issues/70_swagger_schema.json +++ b/spec/tests/issues/70_swagger_schema.json @@ -6,11 +6,7 @@ "$id": "http://swagger.io/v2/schema.json#", "$schema": "http://json-schema.org/draft-07/schema#", "type": "object", - "required": [ - "swagger", - "info", - "paths" - ], + "required": ["swagger", "info", "paths"], "additionalProperties": false, "patternProperties": { "^x-": { @@ -20,9 +16,7 @@ "properties": { "swagger": { "type": "string", - "enum": [ - "2.0" - ], + "enum": ["2.0"], "description": "The Swagger version of this document." }, "info": { @@ -82,10 +76,7 @@ "info": { "type": "object", "description": "General information about the API.", - "required": [ - "version", - "title" - ], + "required": ["version", "title"], "additionalProperties": false, "patternProperties": { "^x-": { @@ -145,9 +136,7 @@ }, "license": { "type": "object", - "required": [ - "name" - ], + "required": ["name"], "additionalProperties": false, "properties": { "name": { @@ -204,9 +193,7 @@ "type": "object", "additionalProperties": false, "description": "information about external documentation", - "required": [ - "url" - ], + "required": ["url"], "properties": { "description": { "type": "string" @@ -232,9 +219,7 @@ }, "operation": { "type": "object", - "required": [ - "responses" - ], + "required": ["responses"], "additionalProperties": false, "patternProperties": { "^x-": { @@ -363,9 +348,7 @@ }, "response": { "type": "object", - "required": [ - "description" - ], + "required": ["description"], "properties": { "description": { "type": "string" @@ -403,19 +386,11 @@ "header": { "type": "object", "additionalProperties": false, - "required": [ - "type" - ], + "required": ["type"], "properties": { "type": { "type": "string", - "enum": [ - "string", - "number", - "integer", - "boolean", - "array" - ] + "enum": ["string", "number", "integer", "boolean", "array"] }, "format": { "type": "string" @@ -482,11 +457,7 @@ }, "bodyParameter": { "type": "object", - "required": [ - "name", - "in", - "schema" - ], + "required": ["name", "in", "schema"], "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" @@ -504,9 +475,7 @@ "in": { "type": "string", "description": "Determines the location of the parameter.", - "enum": [ - "body" - ] + "enum": ["body"] }, "required": { "type": "boolean", @@ -535,9 +504,7 @@ "in": { "type": "string", "description": "Determines the location of the parameter.", - "enum": [ - "header" - ] + "enum": ["header"] }, "description": { "type": "string", @@ -549,13 +516,7 @@ }, "type": { "type": "string", - "enum": [ - "string", - "number", - "boolean", - "integer", - "array" - ] + "enum": ["string", "number", "boolean", "integer", "array"] }, "format": { "type": "string" @@ -623,9 +584,7 @@ "in": { "type": "string", "description": "Determines the location of the parameter.", - "enum": [ - "query" - ] + "enum": ["query"] }, "description": { "type": "string", @@ -642,13 +601,7 @@ }, "type": { "type": "string", - "enum": [ - "string", - "number", - "boolean", - "integer", - "array" - ] + "enum": ["string", "number", "boolean", "integer", "array"] }, "format": { "type": "string" @@ -716,9 +669,7 @@ "in": { "type": "string", "description": "Determines the location of the parameter.", - "enum": [ - "formData" - ] + "enum": ["formData"] }, "description": { "type": "string", @@ -801,23 +752,17 @@ "$ref": "#/definitions/vendorExtension" } }, - "required": [ - "required" - ], + "required": ["required"], "properties": { "required": { "type": "boolean", - "enum": [ - true - ], + "enum": [true], "description": "Determines whether or not this parameter is required or optional." }, "in": { "type": "string", "description": "Determines the location of the parameter.", - "enum": [ - "path" - ] + "enum": ["path"] }, "description": { "type": "string", @@ -829,13 +774,7 @@ }, "type": { "type": "string", - "enum": [ - "string", - "number", - "boolean", - "integer", - "array" - ] + "enum": ["string", "number", "boolean", "integer", "array"] }, "format": { "type": "string" @@ -889,11 +828,7 @@ }, "nonBodyParameter": { "type": "object", - "required": [ - "name", - "in", - "type" - ], + "required": ["name", "in", "type"], "oneOf": [ { "$ref": "#/definitions/headerParameterSubSchema" @@ -1056,9 +991,7 @@ "$ref": "#/definitions/vendorExtension" } }, - "required": [ - "type" - ], + "required": ["type"], "properties": { "format": { "type": "string" @@ -1077,9 +1010,7 @@ }, "type": { "type": "string", - "enum": [ - "file" - ] + "enum": ["file"] }, "readOnly": { "type": "boolean", @@ -1098,13 +1029,7 @@ "properties": { "type": { "type": "string", - "enum": [ - "string", - "number", - "integer", - "boolean", - "array" - ] + "enum": ["string", "number", "integer", "boolean", "array"] }, "format": { "type": "string" @@ -1209,9 +1134,7 @@ "tag": { "type": "object", "additionalProperties": false, - "required": [ - "name" - ], + "required": ["name"], "properties": { "name": { "type": "string" @@ -1257,15 +1180,11 @@ "basicAuthenticationSecurity": { "type": "object", "additionalProperties": false, - "required": [ - "type" - ], + "required": ["type"], "properties": { "type": { "type": "string", - "enum": [ - "basic" - ] + "enum": ["basic"] }, "description": { "type": "string" @@ -1280,27 +1199,18 @@ "apiKeySecurity": { "type": "object", "additionalProperties": false, - "required": [ - "type", - "name", - "in" - ], + "required": ["type", "name", "in"], "properties": { "type": { "type": "string", - "enum": [ - "apiKey" - ] + "enum": ["apiKey"] }, "name": { "type": "string" }, "in": { "type": "string", - "enum": [ - "header", - "query" - ] + "enum": ["header", "query"] }, "description": { "type": "string" @@ -1315,23 +1225,15 @@ "oauth2ImplicitSecurity": { "type": "object", "additionalProperties": false, - "required": [ - "type", - "flow", - "authorizationUrl" - ], + "required": ["type", "flow", "authorizationUrl"], "properties": { "type": { "type": "string", - "enum": [ - "oauth2" - ] + "enum": ["oauth2"] }, "flow": { "type": "string", - "enum": [ - "implicit" - ] + "enum": ["implicit"] }, "scopes": { "$ref": "#/definitions/oauth2Scopes" @@ -1353,23 +1255,15 @@ "oauth2PasswordSecurity": { "type": "object", "additionalProperties": false, - "required": [ - "type", - "flow", - "tokenUrl" - ], + "required": ["type", "flow", "tokenUrl"], "properties": { "type": { "type": "string", - "enum": [ - "oauth2" - ] + "enum": ["oauth2"] }, "flow": { "type": "string", - "enum": [ - "password" - ] + "enum": ["password"] }, "scopes": { "$ref": "#/definitions/oauth2Scopes" @@ -1391,23 +1285,15 @@ "oauth2ApplicationSecurity": { "type": "object", "additionalProperties": false, - "required": [ - "type", - "flow", - "tokenUrl" - ], + "required": ["type", "flow", "tokenUrl"], "properties": { "type": { "type": "string", - "enum": [ - "oauth2" - ] + "enum": ["oauth2"] }, "flow": { "type": "string", - "enum": [ - "application" - ] + "enum": ["application"] }, "scopes": { "$ref": "#/definitions/oauth2Scopes" @@ -1429,24 +1315,15 @@ "oauth2AccessCodeSecurity": { "type": "object", "additionalProperties": false, - "required": [ - "type", - "flow", - "authorizationUrl", - "tokenUrl" - ], + "required": ["type", "flow", "authorizationUrl", "tokenUrl"], "properties": { "type": { "type": "string", - "enum": [ - "oauth2" - ] + "enum": ["oauth2"] }, "flow": { "type": "string", - "enum": [ - "accessCode" - ] + "enum": ["accessCode"] }, "scopes": { "$ref": "#/definitions/oauth2Scopes" @@ -1503,34 +1380,18 @@ "description": "The transfer protocol of the API.", "items": { "type": "string", - "enum": [ - "http", - "https", - "ws", - "wss" - ] + "enum": ["http", "https", "ws", "wss"] }, "uniqueItems": true }, "collectionFormat": { "type": "string", - "enum": [ - "csv", - "ssv", - "tsv", - "pipes" - ], + "enum": ["csv", "ssv", "tsv", "pipes"], "default": "csv" }, "collectionFormatWithMulti": { "type": "string", - "enum": [ - "csv", - "ssv", - "tsv", - "pipes", - "multi" - ], + "enum": ["csv", "ssv", "tsv", "pipes", "multi"], "default": "csv" }, "title": { @@ -1580,9 +1441,7 @@ }, "jsonReference": { "type": "object", - "required": [ - "$ref" - ], + "required": ["$ref"], "additionalProperties": false, "properties": { "$ref": { diff --git a/spec/tests/issues/87_$_property.json b/spec/tests/issues/87_$_property.json index 378f92ed89..fb48531aad 100644 --- a/spec/tests/issues/87_$_property.json +++ b/spec/tests/issues/87_$_property.json @@ -3,13 +3,13 @@ "description": "$ in properties (#87)", "schema": { "properties": { - "$": { "type": "string" } + "$": {"type": "string"} } }, "tests": [ { "description": "valid", - "data": { "$": "foo" }, + "data": {"$": "foo"}, "valid": true } ] diff --git a/spec/tests/issues/94_dependencies_fail.json b/spec/tests/issues/94_dependencies_fail.json index 65ce4234fb..5aff18df29 100644 --- a/spec/tests/issues/94_dependencies_fail.json +++ b/spec/tests/issues/94_dependencies_fail.json @@ -3,24 +3,24 @@ "description": "second dependency is not checked (#94)", "schema": { "dependencies": { - "bar" : ["baz"], - "foo" : ["bar"] + "bar": ["baz"], + "foo": ["bar"] } }, "tests": [ { "description": "object with only foo is invalid (bar is missing)", - "data": { "foo": 1 }, + "data": {"foo": 1}, "valid": false }, { "description": "object with foo and bar is invalid (baz is missing)", - "data": { "foo": 1, "bar": 2 }, + "data": {"foo": 1, "bar": 2}, "valid": false }, { "description": "object with foo, bar and baz is valid", - "data": { "foo": 1, "bar": 2, "baz": 3 }, + "data": {"foo": 1, "bar": 2, "baz": 3}, "valid": true } ] @@ -29,24 +29,24 @@ "description": "second dependency is checked when order is changed", "schema": { "dependencies": { - "foo" : ["bar"], - "bar" : ["baz"] + "foo": ["bar"], + "bar": ["baz"] } }, "tests": [ { "description": "object with only foo is invalid (bar is missing)", - "data": { "foo": 1 }, + "data": {"foo": 1}, "valid": false }, { "description": "object with foo and bar is invalid (baz is missing)", - "data": { "foo": 1, "bar": 2 }, + "data": {"foo": 1, "bar": 2}, "valid": false }, { "description": "object with foo, bar and baz is valid", - "data": { "foo": 1, "bar": 2, "baz": 3 }, + "data": {"foo": 1, "bar": 2, "baz": 3}, "valid": true } ] diff --git a/spec/tests/rules/allOf.json b/spec/tests/rules/allOf.json index ca6c7a9b04..c2a49e74d4 100644 --- a/spec/tests/rules/allOf.json +++ b/spec/tests/rules/allOf.json @@ -2,9 +2,7 @@ { "description": "allOf with one empty schema", "schema": { - "allOf": [ - {} - ] + "allOf": [{}] }, "tests": [ { @@ -17,10 +15,7 @@ { "description": "allOf with two empty schemas", "schema": { - "allOf": [ - {}, - {} - ] + "allOf": [{}, {}] }, "tests": [ { @@ -33,10 +28,7 @@ { "description": "allOf with two schemas, the first is empty", "schema": { - "allOf": [ - {}, - { "type": "number" } - ] + "allOf": [{}, {"type": "number"}] }, "tests": [ { @@ -54,10 +46,7 @@ { "description": "allOf with two schemas, the second is empty", "schema": { - "allOf": [ - { "type": "number" }, - {} - ] + "allOf": [{"type": "number"}, {}] }, "tests": [ { diff --git a/spec/tests/rules/anyOf.json b/spec/tests/rules/anyOf.json index c5e3fa03c9..8c085edb34 100644 --- a/spec/tests/rules/anyOf.json +++ b/spec/tests/rules/anyOf.json @@ -2,10 +2,7 @@ { "description": "anyOf with one of schemas empty", "schema": { - "anyOf": [ - { "type": "number" }, - {} - ] + "anyOf": [{"type": "number"}, {}] }, "tests": [ { diff --git a/spec/tests/rules/dependencies.json b/spec/tests/rules/dependencies.json index 9a3f6166ee..7b24c53ddf 100644 --- a/spec/tests/rules/dependencies.json +++ b/spec/tests/rules/dependencies.json @@ -9,7 +9,7 @@ "tests": [ { "description": "object with property is valid", - "data": { "foo": 1 }, + "data": {"foo": 1}, "valid": true }, { diff --git a/spec/tests/rules/format.json b/spec/tests/rules/format.json index 433a0aaf8f..d52f4e5db0 100644 --- a/spec/tests/rules/format.json +++ b/spec/tests/rules/format.json @@ -11,735 +11,5 @@ "valid": true } ] - }, - { - "description": "format: regex", - "schema": { - "format": "regex" - }, - "tests": [ - { - "description": "valid regex", - "data": "[0-9]", - "valid": true - }, - { - "description": "invalid regex", - "data": "[9-0]", - "valid": false - }, - { - "description": "not string is valid", - "data": 123, - "valid": true - } - ] - }, - { - "description": "format: uri", - "schema": { - "format": "uri" - }, - "tests": [ - { - "description": "valid uri", - "data": "urn:isbn:978-3-531-18621-4", - "valid": true - }, - { - "description": "invalid relative uri-reference", - "data": "/abc", - "valid": false - } - ] - }, - { - "description": "format: uri-template", - "schema": { - "format": "uri-template" - }, - "tests": [ - { - "description": "valid uri-template", - "data": "http://example.com/dictionary/{term:1}/{term}", - "valid": true - }, - { - "description": "invalid uri-template", - "data": "http://example.com/dictionary/{term:1}/{term", - "valid": false - } - ] - }, - { - "description": "format: hostname", - "schema": { - "format": "hostname" - }, - "tests": [ - { - "description": "valid hostname", - "data": "123.example.com", - "valid": true - }, - { - "description": "valid hostname - trailing dot", - "data": "123.example.com.", - "valid": true - }, - { - "description": "valid hostname - single label", - "data": "localhost", - "valid": true - }, - { - "description": "valid hostname - single label with trailing dot", - "data": "localhost.", - "valid": true - }, - { - "description": "valid hostname #312", - "data": "lead-routing-qa.lvuucj.0001.use1.cache.amazonaws.com", - "valid": true - }, - { - "description": "valid hostname - maximum length label (63 chars)", - "data": "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.example.com", - "valid": true - }, - { - "description": "invalid hostname - label too long (64 chars)", - "data": "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkl.example.com", - "valid": false - }, - { - "description": "valid hostname - maximum length hostname (255 octets)", - "data": "abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxy.example.com", - "valid": true - }, - { - "description": "valid hostname - maximum length hostname (255 octets) with trailing dot", - "data": "abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxy.example.com.", - "valid": true - }, - { - "description": "invalid hostname - hostname too long (256 octets)", - "data": "abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz.example.com", - "valid": false - }, - { - "description": "invalid hostname - hostname too long (256 octets) with trailing dot", - "data": "abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz.example.com.", - "valid": false - } - ] - }, - { - "description": "validation of URL strings", - "schema": {"format": "url"}, - "tests": [ - { - "data": "http://foo.com/blah_blah", - "description": "a valid URL string", - "valid": true - }, - { - "data": "http://foo.com/blah_blah/", - "description": "a valid URL string", - "valid": true - }, - { - "data": "http://foo.com/blah_blah_(wikipedia)", - "description": "a valid URL string", - "valid": true - }, - { - "data": "http://foo.com/blah_blah_(wikipedia)_(again)", - "description": "a valid URL string", - "valid": true - }, - { - "data": "http://www.example.com/wpstyle/?p=364", - "description": "a valid URL string", - "valid": true - }, - { - "data": "https://www.example.com/foo/?bar=baz&inga=42&quux", - "description": "a valid URL string", - "valid": true - }, - { - "data": "http://✪df.ws/123", - "description": "a valid URL string", - "valid": true - }, - { - "data": "http://userid:password@example.com:8080", - "description": "a valid URL string", - "valid": true - }, - { - "data": "http://userid:password@example.com:8080/", - "description": "a valid URL string", - "valid": true - }, - { - "data": "http://userid@example.com", - "description": "a valid URL string", - "valid": true - }, - { - "data": "http://userid@example.com/", - "description": "a valid URL string", - "valid": true - }, - { - "data": "http://userid@example.com:8080", - "description": "a valid URL string", - "valid": true - }, - { - "data": "http://userid@example.com:8080/", - "description": "a valid URL string", - "valid": true - }, - { - "data": "http://userid:password@example.com", - "description": "a valid URL string", - "valid": true - }, - { - "data": "http://userid:password@example.com/", - "description": "a valid URL string", - "valid": true - }, - { - "data": "http://142.42.1.1/", - "description": "a valid URL string", - "valid": true - }, - { - "data": "http://142.42.1.1:8080/", - "description": "a valid URL string", - "valid": true - }, - { - "data": "http://➡.ws/䨹", - "description": "a valid URL string", - "valid": true - }, - { - "data": "http://⌘.ws", - "description": "a valid URL string", - "valid": true - }, - { - "data": "http://⌘.ws/", - "description": "a valid URL string", - "valid": true - }, - { - "data": "http://foo.com/blah_(wikipedia)#cite-1", - "description": "a valid URL string", - "valid": true - }, - { - "data": "http://foo.com/blah_(wikipedia)_blah#cite-1", - "description": "a valid URL string", - "valid": true - }, - { - "data": "http://foo.com/unicode_(✪)_in_parens", - "description": "a valid URL string", - "valid": true - }, - { - "data": "http://foo.com/(something)?after=parens", - "description": "a valid URL string", - "valid": true - }, - { - "data": "http://☺.damowmow.com/", - "description": "a valid URL string", - "valid": true - }, - { - "data": "http://code.google.com/events/#&product=browser", - "description": "a valid URL string", - "valid": true - }, - { - "data": "http://j.mp", - "description": "a valid URL string", - "valid": true - }, - { - "data": "ftp://foo.bar/baz", - "description": "a valid URL string", - "valid": true - }, - { - "data": "http://foo.bar/?q=Test%20URL-encoded%20stuff", - "description": "a valid URL string", - "valid": true - }, - { - "data": "http://مثال.إختبار", - "description": "a valid URL string", - "valid": true - }, - { - "data": "http://例子.测试", - "description": "a valid URL string", - "valid": true - }, - { - "data": "http://उदाहरण.परीक्षा", - "description": "a valid URL string", - "valid": true - }, - { - "data": "http://-.~_!$&'()*+,;=:%40:80%2f::::::@example.com", - "description": "a valid URL string", - "valid": true - }, - { - "data": "http://1337.net", - "description": "a valid URL string", - "valid": true - }, - { - "data": "http://a.b-c.de", - "description": "a valid URL string", - "valid": true - }, - { - "data": "http://223.255.255.254", - "description": "a valid URL string", - "valid": true - }, - { - "data": "http://", - "description": "an invalid URL string", - "valid": false - }, - { - "data": "http://.", - "description": "an invalid URL string", - "valid": false - }, - { - "data": "http://..", - "description": "an invalid URL string", - "valid": false - }, - { - "data": "http://../", - "description": "an invalid URL string", - "valid": false - }, - { - "data": "http://?", - "description": "an invalid URL string", - "valid": false - }, - { - "data": "http://??", - "description": "an invalid URL string", - "valid": false - }, - { - "data": "http://??/", - "description": "an invalid URL string", - "valid": false - }, - { - "data": "http://#", - "description": "an invalid URL string", - "valid": false - }, - { - "data": "http://##", - "description": "an invalid URL string", - "valid": false - }, - { - "data": "http://##/", - "description": "an invalid URL string", - "valid": false - }, - { - "data": "http://foo.bar?q=Spaces should be encoded", - "description": "an invalid URL string", - "valid": false - }, - { - "data": "//", - "description": "an invalid URL string", - "valid": false - }, - { - "data": "//a", - "description": "an invalid URL string", - "valid": false - }, - { - "data": "///a", - "description": "an invalid URL string", - "valid": false - }, - { - "data": "///", - "description": "an invalid URL string", - "valid": false - }, - { - "data": "http:///a", - "description": "an invalid URL string", - "valid": false - }, - { - "data": "foo.com", - "description": "an invalid URL string", - "valid": false - }, - { - "data": "rdar://1234", - "description": "an invalid URL string", - "valid": false - }, - { - "data": "h://test", - "description": "an invalid URL string", - "valid": false - }, - { - "data": "http:// shouldfail.com", - "description": "an invalid URL string", - "valid": false - }, - { - "data": ":// should fail", - "description": "an invalid URL string", - "valid": false - }, - { - "data": "http://foo.bar/foo(bar)baz quux", - "description": "an invalid URL string", - "valid": false - }, - { - "data": "ftps://foo.bar/", - "description": "an invalid URL string", - "valid": false - }, - { - "data": "http://-error-.invalid/", - "description": "an invalid URL string", - "valid": false - }, - { - "data": "http://a.b--c.de/", - "description": "an invalid URL string", - "valid": false - }, - { - "data": "http://-a.b.co", - "description": "an invalid URL string", - "valid": false - }, - { - "data": "http://a.b-.co", - "description": "an invalid URL string", - "valid": false - }, - { - "data": "http://0.0.0.0", - "description": "an invalid URL string", - "valid": false - }, - { - "data": "http://10.1.1.0", - "description": "an invalid URL string", - "valid": false - }, - { - "data": "http://10.1.1.255", - "description": "an invalid URL string", - "valid": false - }, - { - "data": "http://224.1.1.1", - "description": "an invalid URL string", - "valid": false - }, - { - "data": "http://1.1.1.1.1", - "description": "an invalid URL string", - "valid": false - }, - { - "data": "http://123.123.123", - "description": "an invalid URL string", - "valid": false - }, - { - "data": "http://3628126748", - "description": "an invalid URL string", - "valid": false - }, - { - "data": "http://.www.foo.bar/", - "description": "an invalid URL string", - "valid": false - }, - { - "data": "http://www.foo.bar./", - "description": "an invalid URL string", - "valid": false - }, - { - "data": "http://.www.foo.bar./", - "description": "an invalid URL string", - "valid": false - }, - { - "data": "http://10.1.1.1", - "description": "an invalid URL string", - "valid": false - }, - { - "data": "http://10.1.1.254", - "description": "an invalid URL string", - "valid": false - } - ] - }, - { - "description": "validation of date strings", - "schema": {"format": "date"}, - "tests": [ - { - "description": "a valid date string", - "data": "1963-06-19", - "valid": true - }, - { - "description": "an invalid date string", - "data": "06/19/1963", - "valid": false - }, - { - "description": "only RFC3339 not all of ISO 8601 are valid", - "data": "2013-350", - "valid": false - } - ] - }, - { - "description": "validation of time strings", - "schema": {"format": "time"}, - "tests": [ - { - "description": "a valid time", - "data": "12:34:56", - "valid": true - }, - { - "description": "a valid time with milliseconds", - "data": "12:34:56.789", - "valid": true - }, - { - "description": "a valid time with timezone", - "data": "12:34:56+01:00", - "valid": true - }, - { - "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 - } - ] - }, - { - "description": "validation of date-time strings", - "schema": {"format": "date-time"}, - "tests": [ - { - "description": "a valid date-time string", - "data": "1963-06-19T12:13:14Z", - "valid": true - }, - { - "description": "an invalid date-time string (no time)", - "data": "1963-06-19", - "valid": false - }, - { - "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 - } - ] - }, - { - "description": "validation of uuid strings", - "schema": {"format": "uuid"}, - "tests": [ - { - "description": "a valid uuid", - "data": "f81d4fae-7dec-11d0-a765-00a0c91e6bf6", - "valid": true - }, - { - "description": "a valid uuid with uri prefix", - "data": "urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6", - "valid": true - }, - { - "description": "not valid uuid", - "data": "f81d4fae7dec11d0a76500a0c91e6bf6", - "valid": false - } - ] - }, - { - "description": "validation of JSON-pointer strings", - "schema": {"format": "json-pointer"}, - "tests": [ - { - "description": "a valid JSON-pointer", - "data": "/foo/bar~0/baz~1/%a", - "valid": true - }, - { - "description": "empty string is valid", - "data": "", - "valid": true - }, - { - "description": "/ is valid", - "data": "/", - "valid": true - }, - { - "description": "not a valid JSON-pointer (~ not escaped)", - "data": "/foo/bar~", - "valid": false - }, - { - "description": "valid JSON-pointer with empty segment", - "data": "/foo//bar", - "valid": true - }, - { - "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", - "data": "#/foo//bar", - "valid": true - }, - { - "description": "valid JSON-pointer with the last empty segment as uri fragment", - "data": "#/foo/bar/", - "valid": true - } - ] - }, - { - "description": "validation of relative JSON-pointer strings", - "schema": {"format": "relative-json-pointer"}, - "tests": [ - { - "description": "a valid relative JSON-pointer", - "data": "1/foo/bar~0/baz~1/%a", - "valid": true - }, - { - "description": "a valid relative JSON-pointer with #", - "data": "2#", - "valid": true - }, - { - "description": "parent reference is valid", - "data": "1", - "valid": true - }, - { - "description": "empty string is invalid", - "data": "", - "valid": false - }, - { - "description": "not a valid relative JSON-pointer (~ not escaped)", - "data": "1/foo/bar~", - "valid": false - }, - { - "description": "not a valid relative JSON-pointer (leading 0)", - "data": "01/foo", - "valid": false - }, - { - "description": "not a valid relative JSON-pointer with # (leading 0)", - "data": "02#", - "valid": false - }, - { - "description": "valid relative JSON-pointer with empty segment", - "data": "1/foo//bar", - "valid": true - }, - { - "description": "valid relative JSON-pointer with the last empty segment", - "data": "1/foo/bar/", - "valid": true - } - ] } ] diff --git a/spec/tests/rules/if.json b/spec/tests/rules/if.json index 87e9e7bc21..82f9998ab7 100644 --- a/spec/tests/rules/if.json +++ b/spec/tests/rules/if.json @@ -2,8 +2,8 @@ { "description": "if/then keyword validation", "schema": { - "if": { "minimum": 10 }, - "then": { "multipleOf": 2 } + "if": {"minimum": 10}, + "then": {"multipleOf": 2} }, "tests": [ { @@ -26,9 +26,9 @@ { "description": "if/then/else keyword validation", "schema": { - "if": { "maximum": 10 }, - "then": { "multipleOf": 2 }, - "else": { "multipleOf": 5 } + "if": {"maximum": 10}, + "then": {"multipleOf": 2}, + "else": {"multipleOf": 5} }, "tests": [ { @@ -61,9 +61,9 @@ "$id": "http://example.com/if", "minimum": 10 }, - "then": { "$ref": "#/definitions/def" }, + "then": {"$ref": "#/definitions/def"}, "definitions": { - "def": { "multipleOf": 2 } + "def": {"multipleOf": 2} } }, "tests": [ @@ -87,8 +87,8 @@ { "description": "then/else without if should be ignored", "schema": { - "then": { "multipleOf": 2 }, - "else": { "multipleOf": 5 } + "then": {"multipleOf": 2}, + "else": {"multipleOf": 5} }, "tests": [ { @@ -116,7 +116,7 @@ { "description": "if without then/else should be ignored", "schema": { - "if": { "maximum": 10 } + "if": {"maximum": 10} }, "tests": [ { diff --git a/spec/tests/rules/items.json b/spec/tests/rules/items.json index cb80cc09ad..b1726fa6f5 100644 --- a/spec/tests/rules/items.json +++ b/spec/tests/rules/items.json @@ -3,7 +3,7 @@ "description": "items with empty schema", "schema": { "items": [{}], - "additionalItems": { "type": "string" } + "additionalItems": {"type": "string"} }, "tests": [ { @@ -26,13 +26,13 @@ "type": "array", "additionalItems": false, "items": [ - { "$ref": "#/definitions/sub-child" }, - { "$ref": "#/definitions/sub-child" } + {"$ref": "#/definitions/sub-child"}, + {"$ref": "#/definitions/sub-child"} ] }, "sub-child": { "type": "object", - "properties": { "foo": {} }, + "properties": {"foo": {}}, "required": ["foo"], "additionalProperties": false } @@ -40,37 +40,37 @@ "type": "array", "additionalItems": false, "items": [ - { "$ref": "#/definitions/child" }, - { "$ref": "#/definitions/child" }, - { "$ref": "#/definitions/child" } + {"$ref": "#/definitions/child"}, + {"$ref": "#/definitions/child"}, + {"$ref": "#/definitions/child"} ] }, "tests": [ { "description": "valid items", "data": [ - [ {"foo": null}, {"foo": null} ], - [ {"foo": null}, {"foo": null} ], - [ {"foo": null}, {"foo": null} ] + [{"foo": null}, {"foo": null}], + [{"foo": null}, {"foo": null}], + [{"foo": null}, {"foo": null}] ], "valid": true }, { "description": "too many children", "data": [ - [ {"foo": null}, {"foo": null} ], - [ {"foo": null}, {"foo": null} ], - [ {"foo": null}, {"foo": null} ], - [ {"foo": null}, {"foo": null} ] + [{"foo": null}, {"foo": null}], + [{"foo": null}, {"foo": null}], + [{"foo": null}, {"foo": null}], + [{"foo": null}, {"foo": null}] ], "valid": false }, { "description": "too many sub-children", "data": [ - [ {"foo": null}, {"foo": null}, {"foo": null} ], - [ {"foo": null}, {"foo": null} ], - [ {"foo": null}, {"foo": null} ] + [{"foo": null}, {"foo": null}, {"foo": null}], + [{"foo": null}, {"foo": null}], + [{"foo": null}, {"foo": null}] ], "valid": false }, @@ -78,26 +78,23 @@ "description": "wrong child", "data": [ {"foo": null}, - [ {"foo": null}, {"foo": null} ], - [ {"foo": null}, {"foo": null} ] + [{"foo": null}, {"foo": null}], + [{"foo": null}, {"foo": null}] ], "valid": false }, { "description": "wrong sub-child", "data": [ - [ {"bar": null}, {"foo": null} ], - [ {"foo": null}, {"foo": null} ], - [ {"foo": null}, {"foo": null} ] + [{"bar": null}, {"foo": null}], + [{"foo": null}, {"foo": null}], + [{"foo": null}, {"foo": null}] ], "valid": false }, { "description": "fewer children is valid", - "data": [ - [ {"foo": null} ], - [ {"foo": null} ] - ], + "data": [[{"foo": null}], [{"foo": null}]], "valid": true } ] @@ -122,17 +119,20 @@ "tests": [ { "description": "valid nested array", - "data": [[[[1]], [[2],[3]]], [[[4], [5], [6]]]], + "data": [[[[1]], [[2], [3]]], [[[4], [5], [6]]]], "valid": true }, { "description": "nested array with invalid type", - "data": [[[["1"]], [[2],[3]]], [[[4], [5], [6]]]], + "data": [[[["1"]], [[2], [3]]], [[[4], [5], [6]]]], "valid": false }, { "description": "not deep enough", - "data": [[[1], [2],[3]], [[4], [5], [6]]], + "data": [ + [[1], [2], [3]], + [[4], [5], [6]] + ], "valid": false } ] diff --git a/spec/tests/rules/oneOf.json b/spec/tests/rules/oneOf.json index f40fac8063..e6433ac638 100644 --- a/spec/tests/rules/oneOf.json +++ b/spec/tests/rules/oneOf.json @@ -2,10 +2,7 @@ { "description": "oneOf with one of schemas empty", "schema": { - "oneOf": [ - { "type": "number" }, - {} - ] + "oneOf": [{"type": "number"}, {}] }, "tests": [ { @@ -24,10 +21,7 @@ "description": "oneOf with required", "schema": { "type": "object", - "oneOf": [ - { "required": ["foo", "bar"] }, - { "required": ["foo", "baz"] } - ] + "oneOf": [{"required": ["foo", "bar"]}, {"required": ["foo", "baz"]}] }, "tests": [ { @@ -42,7 +36,7 @@ }, { "description": "object with foo, bar and baz is invalid", - "data": {"foo": 1, "bar": 2, "baz" : 3}, + "data": {"foo": 1, "bar": 2, "baz": 3}, "valid": false } ] @@ -52,12 +46,35 @@ "schema": { "type": "object", "oneOf": [ - { "required": ["foo", "bar"] }, + {"required": ["foo", "bar"]}, { "required": [ - "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", - "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", - "u", "v", "w", "x", "y", "z" + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z" ] } ] @@ -71,19 +88,66 @@ { "description": "object with a, b, c, ... properties is valid", "data": { - "a": 0, "b": 0, "c": 0, "d": 0, "e": 0, "f": 0, "g": 0, "h": 0, "i": 0, "j": 0, - "k": 0, "l": 0, "m": 0, "n": 0, "o": 0, "p": 0, "q": 0, "r": 0, "s": 0, "t": 0, - "u": 0, "v": 0, "w": 0, "x": 0, "y": 0, "z": 0 + "a": 0, + "b": 0, + "c": 0, + "d": 0, + "e": 0, + "f": 0, + "g": 0, + "h": 0, + "i": 0, + "j": 0, + "k": 0, + "l": 0, + "m": 0, + "n": 0, + "o": 0, + "p": 0, + "q": 0, + "r": 0, + "s": 0, + "t": 0, + "u": 0, + "v": 0, + "w": 0, + "x": 0, + "y": 0, + "z": 0 }, "valid": true }, { "description": "object with foo, bar and a, b, c ... is invalid", "data": { - "a": 0, "b": 0, "c": 0, "d": 0, "e": 0, "f": 0, "g": 0, "h": 0, "i": 0, "j": 0, - "k": 0, "l": 0, "m": 0, "n": 0, "o": 0, "p": 0, "q": 0, "r": 0, "s": 0, "t": 0, - "u": 0, "v": 0, "w": 0, "x": 0, "y": 0, "z": 0, - "foo": 1, "bar": 2 + "a": 0, + "b": 0, + "c": 0, + "d": 0, + "e": 0, + "f": 0, + "g": 0, + "h": 0, + "i": 0, + "j": 0, + "k": 0, + "l": 0, + "m": 0, + "n": 0, + "o": 0, + "p": 0, + "q": 0, + "r": 0, + "s": 0, + "t": 0, + "u": 0, + "v": 0, + "w": 0, + "x": 0, + "y": 0, + "z": 0, + "foo": 1, + "bar": 2 }, "valid": false } diff --git a/spec/tests/rules/required.json b/spec/tests/rules/required.json index c84f4fd8ae..dc4d5be8e0 100644 --- a/spec/tests/rules/required.json +++ b/spec/tests/rules/required.json @@ -7,7 +7,7 @@ "tests": [ { "description": "object with property is valid", - "data": { "foo": 1 }, + "data": {"foo": 1}, "valid": true }, { diff --git a/spec/tests/rules/type.json b/spec/tests/rules/type.json index b73270dce7..f0f6be9299 100644 --- a/spec/tests/rules/type.json +++ b/spec/tests/rules/type.json @@ -25,12 +25,12 @@ "tests": [ { "description": "array is valid", - "data": [1,2,3], + "data": [1, 2, 3], "valid": true }, { "description": "object is valid", - "data": {"foo":123}, + "data": {"foo": 123}, "valid": true }, { @@ -58,12 +58,12 @@ "tests": [ { "description": "array is valid", - "data": [1,2,3], + "data": [1, 2, 3], "valid": true }, { "description": "object is valid", - "data": {"foo":123}, + "data": {"foo": 123}, "valid": true }, { diff --git a/spec/tests/rules/uniqueItems.json b/spec/tests/rules/uniqueItems.json index d283d20451..17339d49a0 100644 --- a/spec/tests/rules/uniqueItems.json +++ b/spec/tests/rules/uniqueItems.json @@ -2,7 +2,7 @@ { "description": "uniqueItems with algorithm using hash", "schema": { - "items": { "type": "string" }, + "items": {"type": "string"}, "uniqueItems": true }, "tests": [ @@ -31,7 +31,7 @@ { "description": "uniqueItems with multiple types when the list of types includes array", "schema": { - "items": { "type": ["array", "string"] }, + "items": {"type": ["array", "string"]}, "uniqueItems": true }, "tests": [ @@ -55,7 +55,7 @@ { "description": "uniqueItems with multiple types when the list of types includes object", "schema": { - "items": { "type": ["object", "string"] }, + "items": {"type": ["object", "string"]}, "uniqueItems": true }, "tests": [ @@ -79,7 +79,7 @@ { "description": "uniqueItems with multiple types when all types are scalar", "schema": { - "items": { "type": ["number", "string", "boolean", "null"] }, + "items": {"type": ["number", "string", "boolean", "null"]}, "uniqueItems": true }, "tests": [ diff --git a/spec/tests/schemas/advanced.json b/spec/tests/schemas/advanced.json index 7c6cea9ad4..7a8b115366 100644 --- a/spec/tests/schemas/advanced.json +++ b/spec/tests/schemas/advanced.json @@ -1,244 +1,244 @@ [ - { - "description": "advanced schema from z-schema benchmark (https://github.com/zaggino/z-schema)", - "schema": { - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "properties": { - "/": { "$ref": "#/definitions/entry" } + { + "description": "advanced schema from z-schema benchmark (https://github.com/zaggino/z-schema)", + "schema": { + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "/": {"$ref": "#/definitions/entry"} + }, + "patternProperties": { + "^(/[^/]+)+$": {"$ref": "#/definitions/entry"} + }, + "additionalProperties": false, + "required": ["/"], + "definitions": { + "entry": { + "$schema": "http://json-schema.org/draft-07/schema#", + "description": "schema for an fstab entry", + "type": "object", + "required": ["storage"], + "properties": { + "storage": { + "type": "object", + "oneOf": [ + {"$ref": "#/definitions/entry/definitions/diskDevice"}, + {"$ref": "#/definitions/entry/definitions/diskUUID"}, + {"$ref": "#/definitions/entry/definitions/nfs"}, + {"$ref": "#/definitions/entry/definitions/tmpfs"} + ] }, - "patternProperties": { - "^(/[^/]+)+$": { "$ref": "#/definitions/entry" } + "fstype": { + "enum": ["ext3", "ext4", "btrfs"] }, - "additionalProperties": false, - "required": [ "/" ], - "definitions": { - "entry": { - "$schema": "http://json-schema.org/draft-07/schema#", - "description": "schema for an fstab entry", - "type": "object", - "required": [ "storage" ], - "properties": { - "storage": { - "type": "object", - "oneOf": [ - { "$ref": "#/definitions/entry/definitions/diskDevice" }, - { "$ref": "#/definitions/entry/definitions/diskUUID" }, - { "$ref": "#/definitions/entry/definitions/nfs" }, - { "$ref": "#/definitions/entry/definitions/tmpfs" } - ] - }, - "fstype": { - "enum": [ "ext3", "ext4", "btrfs" ] - }, - "options": { - "type": "array", - "minItems": 1, - "items": { "type": "string" }, - "uniqueItems": true - }, - "readonly": { "type": "boolean" } - }, - "definitions": { - "diskDevice": { - "properties": { - "type": { "enum": [ "disk" ] }, - "device": { - "type": "string", - "pattern": "^/dev/[^/]+(/[^/]+)*$" - } - }, - "required": [ "type", "device" ], - "additionalProperties": false - }, - "diskUUID": { - "properties": { - "type": { "enum": [ "disk" ] }, - "label": { - "type": "string", - "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$" - } - }, - "required": [ "type", "label" ], - "additionalProperties": false - }, - "nfs": { - "properties": { - "type": { "enum": [ "nfs" ] }, - "remotePath": { - "type": "string", - "pattern": "^(/[^/]+)+$" - }, - "server": { - "type": "string", - "anyOf": [ - { "format": "hostname" }, - { "format": "ipv4" }, - { "format": "ipv6" } - ] - } - }, - "required": [ "type", "server", "remotePath" ], - "additionalProperties": false - }, - "tmpfs": { - "properties": { - "type": { "enum": [ "tmpfs" ] }, - "sizeInMB": { - "type": "integer", - "minimum": 16, - "maximum": 512 - } - }, - "required": [ "type", "sizeInMB" ], - "additionalProperties": false - } - } + "options": { + "type": "array", + "minItems": 1, + "items": {"type": "string"}, + "uniqueItems": true + }, + "readonly": {"type": "boolean"} + }, + "definitions": { + "diskDevice": { + "properties": { + "type": {"enum": ["disk"]}, + "device": { + "type": "string", + "pattern": "^/dev/[^/]+(/[^/]+)*$" } - } - }, - "tests": [ - { - "description": "valid object from z-schema benchmark", - "data": { - "/": { - "storage": { - "type": "disk", - "device": "/dev/sda1" - }, - "fstype": "btrfs", - "readonly": true - }, - "/var": { - "storage": { - "type": "disk", - "label": "8f3ba6f4-5c70-46ec-83af-0d5434953e5f" - }, - "fstype": "ext4", - "options": [ "nosuid" ] - }, - "/tmp": { - "storage": { - "type": "tmpfs", - "sizeInMB": 64 - } - }, - "/var/www": { - "storage": { - "type": "nfs", - "server": "my.nfs.server", - "remotePath": "/exports/mypath" - } - } - }, - "valid": true + }, + "required": ["type", "device"], + "additionalProperties": false }, - { - "description": "not object", - "data": 1, - "valid": false + "diskUUID": { + "properties": { + "type": {"enum": ["disk"]}, + "label": { + "type": "string", + "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$" + } + }, + "required": ["type", "label"], + "additionalProperties": false }, - { - "description": "root only is valid", - "data": { - "/": { - "storage": { - "type": "disk", - "device": "/dev/sda1" - }, - "fstype": "btrfs", - "readonly": true - } + "nfs": { + "properties": { + "type": {"enum": ["nfs"]}, + "remotePath": { + "type": "string", + "pattern": "^(/[^/]+)+$" }, - "valid": true + "server": { + "type": "string", + "anyOf": [ + {"format": "hostname"}, + {"format": "ipv4"}, + {"format": "ipv6"} + ] + } + }, + "required": ["type", "server", "remotePath"], + "additionalProperties": false }, - { - "description": "missing root entry", - "data": { - "no root/": { - "storage": { - "type": "disk", - "device": "/dev/sda1" - }, - "fstype": "btrfs", - "readonly": true - } - }, - "valid": false + "tmpfs": { + "properties": { + "type": {"enum": ["tmpfs"]}, + "sizeInMB": { + "type": "integer", + "minimum": 16, + "maximum": 512 + } + }, + "required": ["type", "sizeInMB"], + "additionalProperties": false + } + } + } + } + }, + "tests": [ + { + "description": "valid object from z-schema benchmark", + "data": { + "/": { + "storage": { + "type": "disk", + "device": "/dev/sda1" }, - { - "description": "invalid entry key", - "data": { - "/": { - "storage": { - "type": "disk", - "device": "/dev/sda1" - }, - "fstype": "btrfs", - "readonly": true - }, - "invalid/var": { - "storage": { - "type": "disk", - "label": "8f3ba6f4-5c70-46ec-83af-0d5434953e5f" - }, - "fstype": "ext4", - "options": [ "nosuid" ] - } - }, - "valid": false + "fstype": "btrfs", + "readonly": true + }, + "/var": { + "storage": { + "type": "disk", + "label": "8f3ba6f4-5c70-46ec-83af-0d5434953e5f" }, - { - "description": "missing storage in entry", - "data": { - "/": { - "fstype": "btrfs", - "readonly": true - } - }, - "valid": false + "fstype": "ext4", + "options": ["nosuid"] + }, + "/tmp": { + "storage": { + "type": "tmpfs", + "sizeInMB": 64 + } + }, + "/var/www": { + "storage": { + "type": "nfs", + "server": "my.nfs.server", + "remotePath": "/exports/mypath" + } + } + }, + "valid": true + }, + { + "description": "not object", + "data": 1, + "valid": false + }, + { + "description": "root only is valid", + "data": { + "/": { + "storage": { + "type": "disk", + "device": "/dev/sda1" }, - { - "description": "missing storage type", - "data": { - "/": { - "storage": { - "device": "/dev/sda1" - }, - "fstype": "btrfs", - "readonly": true - } - }, - "valid": false + "fstype": "btrfs", + "readonly": true + } + }, + "valid": true + }, + { + "description": "missing root entry", + "data": { + "no root/": { + "storage": { + "type": "disk", + "device": "/dev/sda1" }, - { - "description": "storage type should be a string", - "data": { - "/": { - "storage": { - "type": null, - "device": "/dev/sda1" - }, - "fstype": "btrfs", - "readonly": true - } - }, - "valid": false + "fstype": "btrfs", + "readonly": true + } + }, + "valid": false + }, + { + "description": "invalid entry key", + "data": { + "/": { + "storage": { + "type": "disk", + "device": "/dev/sda1" }, - { - "description": "storage device should match pattern", - "data": { - "/": { - "storage": { - "type": null, - "device": "invalid/dev/sda1" - }, - "fstype": "btrfs", - "readonly": true - } - }, - "valid": false - } - ] - } + "fstype": "btrfs", + "readonly": true + }, + "invalid/var": { + "storage": { + "type": "disk", + "label": "8f3ba6f4-5c70-46ec-83af-0d5434953e5f" + }, + "fstype": "ext4", + "options": ["nosuid"] + } + }, + "valid": false + }, + { + "description": "missing storage in entry", + "data": { + "/": { + "fstype": "btrfs", + "readonly": true + } + }, + "valid": false + }, + { + "description": "missing storage type", + "data": { + "/": { + "storage": { + "device": "/dev/sda1" + }, + "fstype": "btrfs", + "readonly": true + } + }, + "valid": false + }, + { + "description": "storage type should be a string", + "data": { + "/": { + "storage": { + "type": null, + "device": "/dev/sda1" + }, + "fstype": "btrfs", + "readonly": true + } + }, + "valid": false + }, + { + "description": "storage device should match pattern", + "data": { + "/": { + "storage": { + "type": null, + "device": "invalid/dev/sda1" + }, + "fstype": "btrfs", + "readonly": true + } + }, + "valid": false + } + ] + } ] diff --git a/spec/tests/schemas/basic.json b/spec/tests/schemas/basic.json index a650069084..45800a228b 100644 --- a/spec/tests/schemas/basic.json +++ b/spec/tests/schemas/basic.json @@ -1,135 +1,153 @@ [ - { - "description": "basic schema from z-schema benchmark (https://github.com/zaggino/z-schema)", - "schema": { - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "Product set", + { + "description": "basic schema from z-schema benchmark (https://github.com/zaggino/z-schema)", + "schema": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Product set", + "type": "array", + "items": { + "title": "Product", + "type": "object", + "properties": { + "id": { + "description": "The unique identifier for a product", + "type": "number" + }, + "name": { + "type": "string" + }, + "price": { + "type": "number", + "exclusiveMinimum": 0 + }, + "tags": { "type": "array", "items": { - "title": "Product", - "type": "object", - "properties": { - "id": { - "description": "The unique identifier for a product", - "type": "number" - }, - "name": { - "type": "string" - }, - "price": { - "type": "number", - "exclusiveMinimum": 0 - }, - "tags": { - "type": "array", - "items": { - "type": "string" - }, - "minItems": 1, - "uniqueItems": true - }, - "dimensions": { - "type": "object", - "properties": { - "length": {"type": "number"}, - "width": {"type": "number"}, - "height": {"type": "number"} - }, - "required": ["length", "width", "height"] - }, - "warehouseLocation": { - "description": "Coordinates of the warehouse with the product" - } - }, - "required": ["id", "name", "price"] - } - }, - "tests": [ - { - "description": "valid array from z-schema benchmark", - "data": [ - { - "id": 2, - "name": "An ice sculpture", - "price": 12.50, - "tags": ["cold", "ice"], - "dimensions": { - "length": 7.0, - "width": 12.0, - "height": 9.5 - }, - "warehouseLocation": { - "latitude": -78.75, - "longitude": 20.4 - } - }, - { - "id": 3, - "name": "A blue mouse", - "price": 25.50, - "dimensions": { - "length": 3.1, - "width": 1.0, - "height": 1.0 - }, - "warehouseLocation": { - "latitude": 54.4, - "longitude": -32.7 - } - } - ], - "valid": true - }, - { - "description": "not array", - "data": 1, - "valid": false - }, - { - "description": "array of not onjects", - "data": [1,2,3], - "valid": false - }, - { - "description": "missing required properties", - "data": [{}], - "valid": false + "type": "string" }, - { - "description": "required property of wrong type", - "data": [{"id": 1, "name": "product", "price": "not valid"}], - "valid": false + "minItems": 1, + "uniqueItems": true + }, + "dimensions": { + "type": "object", + "properties": { + "length": {"type": "number"}, + "width": {"type": "number"}, + "height": {"type": "number"} }, - { - "description": "smallest valid product", - "data": [{"id": 1, "name": "product", "price": 100}], - "valid": true - }, - { - "description": "tags should be array", - "data": [{"tags":{}, "id": 1, "name": "product", "price": 100}], - "valid": false - }, - { - "description": "dimensions should be object", - "data": [{"dimensions":[], "id": 1, "name": "product", "price": 100}], - "valid": false - }, - { - "description": "valid product with tag", - "data": [{"tags":["product"], "id": 1, "name": "product", "price": 100}], - "valid": true + "required": ["length", "width", "height"] + }, + "warehouseLocation": { + "description": "Coordinates of the warehouse with the product" + } + }, + "required": ["id", "name", "price"] + } + }, + "tests": [ + { + "description": "valid array from z-schema benchmark", + "data": [ + { + "id": 2, + "name": "An ice sculpture", + "price": 12.5, + "tags": ["cold", "ice"], + "dimensions": { + "length": 7.0, + "width": 12.0, + "height": 9.5 }, - { - "description": "dimensions miss required properties", - "data": [{"dimensions":{}, "tags":["product"], "id": 1, "name": "product", "price": 100}], - "valid": false + "warehouseLocation": { + "latitude": -78.75, + "longitude": 20.4 + } + }, + { + "id": 3, + "name": "A blue mouse", + "price": 25.5, + "dimensions": { + "length": 3.1, + "width": 1.0, + "height": 1.0 }, - { - "description": "valid product with tag and dimensions", - "data": [{"dimensions":{"length": 7,"width": 12,"height": 9.5}, "tags":["product"], "id": 1, "name": "product", "price": 100}], - "valid": true + "warehouseLocation": { + "latitude": 54.4, + "longitude": -32.7 } - ] - } + } + ], + "valid": true + }, + { + "description": "not array", + "data": 1, + "valid": false + }, + { + "description": "array of not onjects", + "data": [1, 2, 3], + "valid": false + }, + { + "description": "missing required properties", + "data": [{}], + "valid": false + }, + { + "description": "required property of wrong type", + "data": [{"id": 1, "name": "product", "price": "not valid"}], + "valid": false + }, + { + "description": "smallest valid product", + "data": [{"id": 1, "name": "product", "price": 100}], + "valid": true + }, + { + "description": "tags should be array", + "data": [{"tags": {}, "id": 1, "name": "product", "price": 100}], + "valid": false + }, + { + "description": "dimensions should be object", + "data": [{"dimensions": [], "id": 1, "name": "product", "price": 100}], + "valid": false + }, + { + "description": "valid product with tag", + "data": [ + {"tags": ["product"], "id": 1, "name": "product", "price": 100} + ], + "valid": true + }, + { + "description": "dimensions miss required properties", + "data": [ + { + "dimensions": {}, + "tags": ["product"], + "id": 1, + "name": "product", + "price": 100 + } + ], + "valid": false + }, + { + "description": "valid product with tag and dimensions", + "data": [ + { + "dimensions": {"length": 7, "width": 12, "height": 9.5}, + "tags": ["product"], + "id": 1, + "name": "product", + "price": 100 + } + ], + "valid": true + } + ] + } ] diff --git a/spec/tests/schemas/complex.json b/spec/tests/schemas/complex.json index 46d15446b3..306d37fbc1 100644 --- a/spec/tests/schemas/complex.json +++ b/spec/tests/schemas/complex.json @@ -3,7 +3,7 @@ "description": "complex schema from jsck benchmark (https://github.com/pandastrike/jsck)", "schema": { "type": "array", - "items": { "$ref": "#transaction" }, + "items": {"$ref": "#transaction"}, "minItems": 1, "definitions": { "base58": { @@ -19,7 +19,7 @@ "tx_id": { "$id": "#tx_id", "allOf": [ - { "$ref": "#hex" }, + {"$ref": "#hex"}, { "minLength": 64, "maxLength": 64 @@ -29,7 +29,7 @@ "address": { "$id": "#address", "allOf": [ - { "$ref": "#base58" }, + {"$ref": "#base58"}, { "minLength": 34, "maxLength": 34 @@ -39,7 +39,7 @@ "signature": { "$id": "#signature", "allOf": [ - { "$ref": "#hex" }, + {"$ref": "#hex"}, { "minLength": 128, "maxLength": 128 @@ -49,19 +49,11 @@ "transaction": { "$id": "#transaction", "additionalProperties": false, - "required": [ - "metadata", - "hash", - "inputs", - "outputs" - ], + "required": ["metadata", "hash", "inputs", "outputs"], "properties": { "metadata": { "type": "object", - "required": [ - "amount", - "fee" - ], + "required": ["amount", "fee"], "properties": { "amount": { "type": "integer" @@ -72,12 +64,7 @@ }, "status": { "type": "string", - "enum": [ - "unsigned", - "unconfirmed", - "confirmed", - "invalid" - ] + "enum": ["unsigned", "unconfirmed", "confirmed", "invalid"] }, "confirmations": { "type": "integer", @@ -94,15 +81,15 @@ "lock_time": { "type": "integer" }, - "hash": { "$ref": "#tx_id" }, + "hash": {"$ref": "#tx_id"}, "inputs": { "type": "array", - "items": { "$ref": "#input" }, + "items": {"$ref": "#input"}, "minItems": 1 }, "outputs": { "type": "array", - "items": { "$ref": "#output" }, + "items": {"$ref": "#output"}, "minItems": 1 } } @@ -111,25 +98,21 @@ "$id": "#input", "type": "object", "additionalProperties": false, - "required": [ - "index", - "output", - "script_sig" - ], + "required": ["index", "output", "script_sig"], "properties": { "index": { "type": "integer", "minimum": 0 }, - "output": { "$ref": "#output" }, - "sig_hash": { "$ref": "#hex" }, - "script_sig": { "$ref": "#hex" }, + "output": {"$ref": "#output"}, + "sig_hash": {"$ref": "#hex"}, + "script_sig": {"$ref": "#hex"}, "signatures": { "type": "object", "description": "A dictionary of signatures. Keys represent keypair names", "minProperties": 1, "maxProperties": 3, - "additionalProperties": { "$ref": "#signature" } + "additionalProperties": {"$ref": "#signature"} } } }, @@ -137,14 +120,9 @@ "$id": "#output", "type": "object", "additionalProperties": false, - "required": [ - "hash", - "index", - "value", - "script" - ], + "required": ["hash", "index", "value", "script"], "properties": { - "hash": { "$ref": "#tx_id" }, + "hash": {"$ref": "#tx_id"}, "index": { "type": "integer", "minimum": 0 @@ -157,23 +135,18 @@ "properties": { "type": { "type": "string", - "enum": [ - "standard", - "p2sh" - ] + "enum": ["standard", "p2sh"] }, "asm": { "type": "string" } } }, - "address": { "$ref": "#address" }, + "address": {"$ref": "#address"}, "metadata": { "type": "object", "dependencies": { - "wallet_path": [ - "public_seeds" - ] + "wallet_path": ["public_seeds"] }, "properties": { "wallet_path": { @@ -184,10 +157,7 @@ "minProperties": 1, "maxProperties": 3, "additionalProperties": { - "anyOf": [ - { "$ref": "#base58" }, - { "$ref": "#hex" } - ] + "anyOf": [{"$ref": "#base58"}, {"$ref": "#hex"}] } } } diff --git a/spec/tests/schemas/complex2.json b/spec/tests/schemas/complex2.json index d38a96c7d2..0dcf32ff36 100644 --- a/spec/tests/schemas/complex2.json +++ b/spec/tests/schemas/complex2.json @@ -3,7 +3,7 @@ "description": "complex schema from jsck benchmark without IDs in definitions", "schema": { "type": "array", - "items": { "$ref": "#/definitions/transaction" }, + "items": {"$ref": "#/definitions/transaction"}, "minItems": 1, "definitions": { "base58": { @@ -16,7 +16,7 @@ }, "tx_id": { "allOf": [ - { "$ref": "#/definitions/hex" }, + {"$ref": "#/definitions/hex"}, { "minLength": 64, "maxLength": 64 @@ -25,7 +25,7 @@ }, "address": { "allOf": [ - { "$ref": "#/definitions/base58" }, + {"$ref": "#/definitions/base58"}, { "minLength": 34, "maxLength": 34 @@ -34,7 +34,7 @@ }, "signature": { "allOf": [ - { "$ref": "#/definitions/hex" }, + {"$ref": "#/definitions/hex"}, { "minLength": 128, "maxLength": 128 @@ -43,19 +43,11 @@ }, "transaction": { "additionalProperties": false, - "required": [ - "metadata", - "hash", - "inputs", - "outputs" - ], + "required": ["metadata", "hash", "inputs", "outputs"], "properties": { "metadata": { "type": "object", - "required": [ - "amount", - "fee" - ], + "required": ["amount", "fee"], "properties": { "amount": { "type": "integer" @@ -66,12 +58,7 @@ }, "status": { "type": "string", - "enum": [ - "unsigned", - "unconfirmed", - "confirmed", - "invalid" - ] + "enum": ["unsigned", "unconfirmed", "confirmed", "invalid"] }, "confirmations": { "type": "integer", @@ -88,15 +75,15 @@ "lock_time": { "type": "integer" }, - "hash": { "$ref": "#/definitions/tx_id" }, + "hash": {"$ref": "#/definitions/tx_id"}, "inputs": { "type": "array", - "items": { "$ref": "#/definitions/input" }, + "items": {"$ref": "#/definitions/input"}, "minItems": 1 }, "outputs": { "type": "array", - "items": { "$ref": "#/definitions/output" }, + "items": {"$ref": "#/definitions/output"}, "minItems": 1 } } @@ -104,39 +91,30 @@ "input": { "type": "object", "additionalProperties": false, - "required": [ - "index", - "output", - "script_sig" - ], + "required": ["index", "output", "script_sig"], "properties": { "index": { "type": "integer", "minimum": 0 }, - "output": { "$ref": "#/definitions/output" }, - "sig_hash": { "$ref": "#/definitions/hex" }, - "script_sig": { "$ref": "#/definitions/hex" }, + "output": {"$ref": "#/definitions/output"}, + "sig_hash": {"$ref": "#/definitions/hex"}, + "script_sig": {"$ref": "#/definitions/hex"}, "signatures": { "type": "object", "description": "A dictionary of signatures. Keys represent keypair names", "minProperties": 1, "maxProperties": 3, - "additionalProperties": { "$ref": "#/definitions/signature" } + "additionalProperties": {"$ref": "#/definitions/signature"} } } }, "output": { "type": "object", "additionalProperties": false, - "required": [ - "hash", - "index", - "value", - "script" - ], + "required": ["hash", "index", "value", "script"], "properties": { - "hash": { "$ref": "#/definitions/tx_id" }, + "hash": {"$ref": "#/definitions/tx_id"}, "index": { "type": "integer", "minimum": 0 @@ -149,23 +127,18 @@ "properties": { "type": { "type": "string", - "enum": [ - "standard", - "p2sh" - ] + "enum": ["standard", "p2sh"] }, "asm": { "type": "string" } } }, - "address": { "$ref": "#/definitions/address" }, + "address": {"$ref": "#/definitions/address"}, "metadata": { "type": "object", "dependencies": { - "wallet_path": [ - "public_seeds" - ] + "wallet_path": ["public_seeds"] }, "properties": { "wallet_path": { @@ -177,8 +150,8 @@ "maxProperties": 3, "additionalProperties": { "anyOf": [ - { "$ref": "#/definitions/base58" }, - { "$ref": "#/definitions/hex" } + {"$ref": "#/definitions/base58"}, + {"$ref": "#/definitions/hex"} ] } } diff --git a/spec/tests/schemas/complex3.json b/spec/tests/schemas/complex3.json index 1591d7814e..0fd8a976bb 100644 --- a/spec/tests/schemas/complex3.json +++ b/spec/tests/schemas/complex3.json @@ -4,7 +4,7 @@ "schema": { "$id": "http://example.com/complex3.json", "type": "array", - "items": { "$ref": "#transaction" }, + "items": {"$ref": "#transaction"}, "minItems": 1, "definitions": { "base58": { @@ -20,7 +20,7 @@ "tx_id": { "$id": "#tx_id", "allOf": [ - { "$ref": "#hex" }, + {"$ref": "#hex"}, { "minLength": 64, "maxLength": 64 @@ -30,7 +30,7 @@ "address": { "$id": "#address", "allOf": [ - { "$ref": "#base58" }, + {"$ref": "#base58"}, { "minLength": 34, "maxLength": 34 @@ -40,7 +40,7 @@ "signature": { "$id": "#signature", "allOf": [ - { "$ref": "#hex" }, + {"$ref": "#hex"}, { "minLength": 128, "maxLength": 128 @@ -50,19 +50,11 @@ "transaction": { "$id": "#transaction", "additionalProperties": false, - "required": [ - "metadata", - "hash", - "inputs", - "outputs" - ], + "required": ["metadata", "hash", "inputs", "outputs"], "properties": { "metadata": { "type": "object", - "required": [ - "amount", - "fee" - ], + "required": ["amount", "fee"], "properties": { "amount": { "type": "integer" @@ -73,12 +65,7 @@ }, "status": { "type": "string", - "enum": [ - "unsigned", - "unconfirmed", - "confirmed", - "invalid" - ] + "enum": ["unsigned", "unconfirmed", "confirmed", "invalid"] }, "confirmations": { "type": "integer", @@ -95,15 +82,15 @@ "lock_time": { "type": "integer" }, - "hash": { "$ref": "#tx_id" }, + "hash": {"$ref": "#tx_id"}, "inputs": { "type": "array", - "items": { "$ref": "#input" }, + "items": {"$ref": "#input"}, "minItems": 1 }, "outputs": { "type": "array", - "items": { "$ref": "#output" }, + "items": {"$ref": "#output"}, "minItems": 1 } } @@ -112,25 +99,21 @@ "$id": "#input", "type": "object", "additionalProperties": false, - "required": [ - "index", - "output", - "script_sig" - ], + "required": ["index", "output", "script_sig"], "properties": { "index": { "type": "integer", "minimum": 0 }, - "output": { "$ref": "#output" }, - "sig_hash": { "$ref": "#hex" }, - "script_sig": { "$ref": "#hex" }, + "output": {"$ref": "#output"}, + "sig_hash": {"$ref": "#hex"}, + "script_sig": {"$ref": "#hex"}, "signatures": { "type": "object", "description": "A dictionary of signatures. Keys represent keypair names", "minProperties": 1, "maxProperties": 3, - "additionalProperties": { "$ref": "#signature" } + "additionalProperties": {"$ref": "#signature"} } } }, @@ -138,14 +121,9 @@ "$id": "#output", "type": "object", "additionalProperties": false, - "required": [ - "hash", - "index", - "value", - "script" - ], + "required": ["hash", "index", "value", "script"], "properties": { - "hash": { "$ref": "#tx_id" }, + "hash": {"$ref": "#tx_id"}, "index": { "type": "integer", "minimum": 0 @@ -158,23 +136,18 @@ "properties": { "type": { "type": "string", - "enum": [ - "standard", - "p2sh" - ] + "enum": ["standard", "p2sh"] }, "asm": { "type": "string" } } }, - "address": { "$ref": "#address" }, + "address": {"$ref": "#address"}, "metadata": { "type": "object", "dependencies": { - "wallet_path": [ - "public_seeds" - ] + "wallet_path": ["public_seeds"] }, "properties": { "wallet_path": { @@ -185,10 +158,7 @@ "minProperties": 1, "maxProperties": 3, "additionalProperties": { - "anyOf": [ - { "$ref": "#base58" }, - { "$ref": "#hex" } - ] + "anyOf": [{"$ref": "#base58"}, {"$ref": "#hex"}] } } } diff --git a/spec/tests/schemas/cosmicrealms.json b/spec/tests/schemas/cosmicrealms.json index 7ff641dc21..1b506608c7 100644 --- a/spec/tests/schemas/cosmicrealms.json +++ b/spec/tests/schemas/cosmicrealms.json @@ -6,39 +6,59 @@ "type": "object", "additionalProperties": false, "required": [ - "fullName", "age", "zip", "married", - "dozen", "dozenOrBakersDozen", - "favoriteEvenNumber", "topThreeFavoriteColors", - "favoriteSingleDigitWholeNumbers", "favoriteFiveLetterWord", - "emailAddresses", "ipAddresses" + "fullName", + "age", + "zip", + "married", + "dozen", + "dozenOrBakersDozen", + "favoriteEvenNumber", + "topThreeFavoriteColors", + "favoriteSingleDigitWholeNumbers", + "favoriteFiveLetterWord", + "emailAddresses", + "ipAddresses" ], "properties": { - "fullName": { "type": "string" }, - "age": { "type": "integer", "minimum": 0 }, - "optionalItem": { "type": "string" }, - "state": { "type": "string" }, - "city": { "type": "string" }, - "zip": { "type": "integer", "minimum": 0, "maximum": 99999 }, - "married": { "type": "boolean" }, - "dozen": { "type": "integer", "minimum": 12, "maximum": 12 }, - "dozenOrBakersDozen": { "type": "integer", "minimum": 12, "maximum": 13 }, - "favoriteEvenNumber": { "type": "integer", "multipleOf": 2 }, + "fullName": {"type": "string"}, + "age": {"type": "integer", "minimum": 0}, + "optionalItem": {"type": "string"}, + "state": {"type": "string"}, + "city": {"type": "string"}, + "zip": {"type": "integer", "minimum": 0, "maximum": 99999}, + "married": {"type": "boolean"}, + "dozen": {"type": "integer", "minimum": 12, "maximum": 12}, + "dozenOrBakersDozen": {"type": "integer", "minimum": 12, "maximum": 13}, + "favoriteEvenNumber": {"type": "integer", "multipleOf": 2}, "topThreeFavoriteColors": { - "type": "array", "minItems": 3, "maxItems": 3, "uniqueItems": true, - "items": { "type": "string" } + "type": "array", + "minItems": 3, + "maxItems": 3, + "uniqueItems": true, + "items": {"type": "string"} }, "favoriteSingleDigitWholeNumbers": { - "type": "array", "minItems": 1, "maxItems": 10, "uniqueItems": true, - "items": { "type": "integer", "minimum": 0, "maximum": 9 } + "type": "array", + "minItems": 1, + "maxItems": 10, + "uniqueItems": true, + "items": {"type": "integer", "minimum": 0, "maximum": 9} + }, + "favoriteFiveLetterWord": { + "type": "string", + "minLength": 5, + "maxLength": 5 }, - "favoriteFiveLetterWord": { "type": "string", "minLength": 5, "maxLength": 5 }, "emailAddresses": { - "type": "array", "minItems": 1, "uniqueItems": true, - "items": { "type": "string", "format": "email" } + "type": "array", + "minItems": 1, + "uniqueItems": true, + "items": {"type": "string", "format": "email"} }, "ipAddresses": { - "type": "array", "uniqueItems": true, - "items": { "type": "string", "format": "ipv4" } + "type": "array", + "uniqueItems": true, + "items": {"type": "string", "format": "ipv4"} } } }, @@ -62,17 +82,8 @@ "married": true, "age": 17, "zip": 65794, - "topThreeFavoriteColors": [ - "blue", - "black", - "yellow" - ], - "favoriteSingleDigitWholeNumbers": [ - 2, - 1, - 3, - 9 - ], + "topThreeFavoriteColors": ["blue", "black", "yellow"], + "favoriteSingleDigitWholeNumbers": [2, 1, 3, 9], "ipAddresses": [ "225.234.40.3", "96.216.243.54", @@ -87,7 +98,7 @@ "data": { "state": null, "city": 90912, - "zip": [ null ], + "zip": [null], "married": "married", "dozen": 90912, "dozenOrBakersDozen": null, diff --git a/spec/tests/schemas/medium.json b/spec/tests/schemas/medium.json index 6d285b88c6..bd0f51e274 100644 --- a/spec/tests/schemas/medium.json +++ b/spec/tests/schemas/medium.json @@ -5,22 +5,13 @@ "description": "A moderately complex schema with some nesting and value constraints", "type": "object", "additionalProperties": false, - "required": [ - "api_server", - "transport", - "storage", - "chain" - ], + "required": ["api_server", "transport", "storage", "chain"], "properties": { "api_server": { "description": "Settings for the HTTP API server", "type": "object", "additionalProperties": false, - "required": [ - "url", - "host", - "port" - ], + "required": ["url", "host", "port"], "properties": { "url": { "type": "string", @@ -38,9 +29,7 @@ "transport": { "description": "Settings for the Redis tranport", "additionalProperties": false, - "required": [ - "server" - ], + "required": ["server"], "properties": { "server": { "type": "string" @@ -60,11 +49,7 @@ }, "storage": { "description": "Settings for the PostgreSQL storage", - "required": [ - "server", - "database", - "user" - ], + "required": ["server", "database", "user"], "properties": { "server": { "type": "string" @@ -82,10 +67,7 @@ }, "chain": { "description": "Settings for the Chain.com client", - "required": [ - "api_key_id", - "api_key_secret" - ], + "required": ["api_key_id", "api_key_secret"], "properties": { "api_key_id": { "type": "string" diff --git a/spec/typescript/index.ts b/spec/typescript/index.ts index 0858180e99..9fac0b1f49 100644 --- a/spec/typescript/index.ts +++ b/spec/typescript/index.ts @@ -1,60 +1,60 @@ -import ajv = require("../.."); +import ajv = require("../..") // #region new() const options: ajv.Options = { - verbose: true, -}; + verbose: true, +} -let instance: ajv.Ajv; +let instance: ajv.Ajv -instance = ajv(); -instance = ajv(options); +instance = ajv() +instance = ajv(options) -instance = new ajv(); -instance = new ajv(options); +instance = new ajv() +instance = new ajv(options) // #endregion new() // #region validate() let data = { - foo: 42, + foo: 42, } -let result = instance.validate("", data); +let result = instance.validate("", data) if (typeof result === "boolean") { - // sync - console.log(result); + // sync + console.log(result) } else { - // async - result.then(value => { - data = value; - }); + // async + result.then((value) => { + data = value + }) } // #endregion validate() // #region compile() -const validator = instance.compile({}); -result = validator(data); +const validator = instance.compile({}) +result = validator(data) if (typeof result === "boolean") { - // sync - console.log(result); + // sync + console.log(result) } else { - // async - result.then(value => { - data = value; - }); + // async + result.then((value) => { + data = value + }) } // #endregion compile() // #region errors -const validationError: ajv.ValidationError = new ajv.ValidationError([]); -validationError instanceof ajv.ValidationError; -validationError.ajv === true; -validationError.validation === true; - -ajv.MissingRefError.message("", ""); -const missingRefError: ajv.MissingRefError = new ajv.MissingRefError("", "", ""); -missingRefError instanceof ajv.MissingRefError; -missingRefError.missingRef; +const validationError: ajv.ValidationError = new ajv.ValidationError([]) +validationError instanceof ajv.ValidationError +validationError.ajv === true +validationError.validation === true + +ajv.MissingRefError.message("", "") +const missingRefError: ajv.MissingRefError = new ajv.MissingRefError("", "", "") +missingRefError instanceof ajv.MissingRefError +missingRefError.missingRef // #endregion