pax_global_header00006660000000000000000000000064130751466370014526gustar00rootroot0000000000000052 comment=8641c6b23a04aae7f73ddece698fa598266dc5ae ajv-5.0.0/000077500000000000000000000000001307514663700123105ustar00rootroot00000000000000ajv-5.0.0/.codeclimate.yml000066400000000000000000000000361307514663700153610ustar00rootroot00000000000000exclude_paths: - lib/dotjs/** ajv-5.0.0/.eslintrc.yml000066400000000000000000000012131307514663700147310ustar00rootroot00000000000000extends: eslint:recommended env: node: true browser: true rules: block-scoped-var: 2 callback-return: 2 complexity: [2, 13] curly: [2, multi-or-nest, consistent] dot-location: [2, property] dot-notation: 2 indent: [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-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] strict: [2, global] valid-jsdoc: [2, requireReturn: false] no-control-regex: 0 ajv-5.0.0/.github/000077500000000000000000000000001307514663700136505ustar00rootroot00000000000000ajv-5.0.0/.github/ISSUE_TEMPLATE.md000066400000000000000000000025131307514663700163560ustar00rootroot00000000000000 **What version of Ajv are you using? Does the issue happen if you use the latest version?** **Ajv options object (see https://github.com/epoberezkin/ajv#options):** ```javascript ``` **JSON Schema (please make it as small as possible to reproduce the issue):** ```json ``` **Data (please make it as small as posssible to reproduce the issue):** ```json ``` **Your code (please use `options`, `schema` and `data` as variables):** ```javascript ``` **Validation result, data AFTER validation, error messages:** ``` ``` **What results did you expect?** **Are you going to resolve the issue?** ajv-5.0.0/.github/PULL_REQUEST_TEMPLATE.md000066400000000000000000000010271307514663700174510ustar00rootroot00000000000000 **What issue does this pull request resolve?** **What changes did you make?** **Is there anything that requires more attention while reviewing?** ajv-5.0.0/.gitignore000066400000000000000000000011721307514663700143010ustar00rootroot00000000000000# Logs logs *.log # Runtime data pids *.pid *.seed # Directory for instrumented libs generated by jscoverage/JSCover lib-cov # Coverage directory used by tools like istanbul coverage .nyc_output # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) .grunt # node-waf configuration .lock-wscript # Compiled binary addons (http://nodejs.org/api/addons.html) build/Release # Dependency directory # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git node_modules .DS_Store # Compiled templates lib/dotjs/*.js # Browserified tests .browser # bundles dist/ ajv-5.0.0/.gitmodules000066400000000000000000000002171307514663700144650ustar00rootroot00000000000000[submodule "spec/JSON-Schema-Test-Suite"] path = spec/JSON-Schema-Test-Suite url = https://github.com/json-schema/JSON-Schema-Test-Suite.git ajv-5.0.0/.tonic_example.js000066400000000000000000000006631307514663700155600ustar00rootroot00000000000000var Ajv = require('ajv'); var ajv = Ajv({allErrors: true}); var schema = { "properties": { "foo": { "type": "string" }, "bar": { "type": "number", "maximum": 3 } } }; var validate = ajv.compile(schema); 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)); }ajv-5.0.0/.travis.yml000066400000000000000000000007031307514663700144210ustar00rootroot00000000000000language: node_js before_script: - git submodule update --init - npm install -g codeclimate-test-reporter node_js: - "0.12" - "4" - "5" - "6" - "7" after_script: - codeclimate-test-reporter < coverage/lcov.info - coveralls < coverage/lcov.info - scripts/travis-gh-pages notifications: webhooks: urls: - https://webhooks.gitter.im/e/9cab5fe0c9595511cd81 on_success: change on_failure: always on_start: never ajv-5.0.0/COERCION.md000066400000000000000000000101621307514663700140330ustar00rootroot00000000000000# Ajv type coercion rules To enable type coercion pass option `coerceTypes` to Ajv with `true` or `array` (it is `false` by default). See [example](https://github.com/epoberezkin/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`). Type coercion only happens if there is `type` keyword and if without coercion the validation would have failed. If coercion to the required type succeeds then the validation continues to other keywords, otherwise the validation fails. 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. 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]`|-| \* Requires option `{coerceTypes: 'array'}` ## Coercion from string values #### To number type Coercion to `number` is possible if the string is a valid number, `+data` is used. #### To integer type Coercion to `integer` is possible if the string is a valid number without fractional part (`data % 1 === 0`). #### To boolean type Unlike JavaScript, only these strings can be coerced to `boolean`: - `"true"` -> `true` - `"false"` -> `false` #### To null type Empty string is coerced to `null`, other strings can't be coerced. ## Coercion from number values #### To string type Always possible, `'' + data` is used #### To boolean type Unlike JavaScript, only these numbers can be coerced to `boolean`: - `1` -> `true` - `0` -> `false` #### To null type `0` coerces to `null`, other numbers can't be coerced. ## Coercion from boolean values #### To string type - `true` -> `"true"` - `false` -> `"false"` #### To number/integer types - `true` -> `1` - `false` -> `0` #### To null type `false` coerces to `null`, `true` can't be coerced. ## Coercion from null #### To string type `null` coerses to the empty string. #### 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"`. If a scalar data is present and array is required, Ajv wraps scalar data in an array. If an array with one item is present and a scalar is required, Ajv coerces array into its item. - `"foo"` -> `[ "foo" ]` - `[ "foo" ]` -> `"foo"` ajv-5.0.0/CONTRIBUTING.md000066400000000000000000000167421307514663700145530ustar00rootroot00000000000000# Contributing Thank you for your help making Ajv better! Every contribution is appreciated. If you plan to implement a new feature or some other change please create an issue first, to make sure that your work is not lost. - [Documentation](#documentation) - [Issues](#issues) - [Bug reports](#bug-reports) - [Change proposals](#changes) - [Browser and compatibility issues](#compatibility) - [JSON schema standard](#json-schema) - [Ajv usage questions](#usage) - [Code](#code) - [Development](#development) - [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/epoberezkin/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: 1. What version of Ajv are you using? Does the issue happen if you use the latest version? 2. Ajv options object (see https://github.com/epoberezkin/ajv#options). 3. JSON schema and the data you are validating (please make it as small as possible to reproduce the issue). 4. Your code (please use `options`, `schema` and `data` as variables). 5. Validation result, data AFTER validation, error messages. 6. What results did you expect? [Create bug report](https://github.com/epoberezkin/ajv/issues/new). #### Change proposals [Create a proposal](https://github.com/epoberezkin/ajv/issues/new?labels=suggestion&body=**What%20version%20of%20Ajv%20you%20are%20you%20using%3F**%0A%0A**What%20problem%20do%20you%20want%20to%20solve%3F**%0A%0A**What%20do%20you%20think%20is%20the%20correct%20solution%20to%20problem?**%0A%0A**Will%20you%20be%20able%20to%20implement%20it%3F**%0A%0A) for a new feature, option or some other improvement. Please include this information: 1. The version of Ajv you are using. 2. The problem you want to solve. 3. What do you think is the correct solution to problem? 4. Will you be able to implement it? If you’re requesting a change, it would be helpful to include this as well: 1. What you did. 2. What you would like to happen. 3. What actually happened. Please include as much details as possible. #### Browser and compatibility issues [Create an issue](https://github.com/epoberezkin/ajv/issues/new?labels=compatibility&body=**The%20version%20of%20Ajv%20you%20are%20using**%0A%0A**The%20environment%20you%20have%20the%20problem%20with.**%0A%0A**Your%20code%20(please%20make%20it%20as%20small%20as%20possible%20to%20reproduce%20the%20issue).**%0A%0A**If%20your%20issue%20is%20in%20the%20browser,%20please%20list%20the%20other%20packages%20loaded%20in%20the%20page%20in%20the%20order%20they%20are%20loaded.%20Please%20check%20if%20the%20issue%20gets%20resolved%20(or%20results%20change)%20if%20you%20move%20Ajv%20bundle%20closer%20to%20the%20top.**%0A%0A**Results%20in%20node.js%20v4.**%0A%0A**Results%20and%20error%20messages%20in%20your%20platform.**%0A%0A) to report a compatibility problem that only happens in a particular environemnt (when your code works correctly in node.js v4 in linux systems but fails in some other environment). Please include this information: 1. The version of Ajv you are using. 2. The environment you have the problem with. 3. Your code (please make it as small as possible to reproduce the issue). 4. If your issue is in the browser, please list the other packages loaded in the page in the order they are loaded. Please check if the issue gets resolved (or results change) if you move Ajv bundle closer to the top. 5. Results in node.js v4. 6. Results and error messages in your platform. #### Using JSON schema standard Ajv implements JSON schema standard draft 4 and the proposed extensions for the next version of the standard (available when you use the option `v5: true`). If the issue is related to using v5 extensions please submit it as a [bug report](https://github.com/epoberezkin/ajv/issues/new). If it is a general issue related to using the standard keywords included in JSON Schema or implementing some advanced validation logic please ask the question on [Stack Overflow](http://stackoverflow.com/questions/ask?tags=jsonschema,ajv) (my account is [esp](http://stackoverflow.com/users/1816503/esp)) or submitting the question to [JSON-Schema.org](https://github.com/json-schema-org/json-schema-spec/issues/new). Please mention @epoberezkin. #### 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: ```bash npm install git submodule update --init npm test ``` The full test suite runs for 3 minutes. If your change is trivial you can run quick test before committing (10 sec) and then disable pre-commit hook: ```bash npm run test-fast git commit -nm 'type: message' ``` All validation functions are generated using doT templates in [dot](https://github.com/epoberezkin/ajv/tree/master/lib/dot) folder. Templates are precompiled so doT is not a run-time dependency. `npm run build` - compiles templates to [dotjs](https://github.com/epoberezkin/ajv/tree/master/lib/dotjs) folder. `npm run watch` - automatically compiles templates when files in dot folder change #### Pull requests To make accepting your changes faster please follow these steps: 1. Submit an [issue with the bug](https://github.com/epoberezkin/ajv/issues/new) or with the proposed change (unless the contribution is to fix the documentation typos and mistakes). 2. Please describe the proposed api and implementation plan (unless the issue is a relatively simple bug and fixing it doesn't change any api). 3. Once agreed, please write as little code as possible to achieve the desired result. 4. Please avoid unnecessary changes, refactoring or changing coding styles as part of your change (unless the change was proposed as refactoring). 5. Please follow the coding conventions even if they are not validated (and/or you use different conventions in your code). 6. Please run the tests before committing your code. 7. If tests fail in Travis after you make a PR please investigate and fix the issue. #### Contributions license When contributing the code you confirm that: 1. Your contribution is created by you. 2. You have the right to submit it under the MIT license. 3. You understand and agree that your contribution is public, will be stored indefinitely, can be redistributed as the part of Ajv or another related package under MIT license, modified or completely removed from Ajv. 4. You grant irrevocable MIT license to use your contribution as part of Ajv or another related package. 5. You waive all rights to your contribution. 6. Unless you request otherwise, you can be mentioned as the author of the contribution in the Ajv documentation and change log. ajv-5.0.0/CUSTOM.md000066400000000000000000000513161307514663700136520ustar00rootroot00000000000000# Defining custom keywords ## Contents - Define keyword with: - [validation function](#define-keyword-with-validation-function) - [compilation function](#define-keyword-with-compilation-function) - [macro function](#define-keyword-with-macro-function) - [inline compilation function](#define-keyword-with-inline-compilation-function) - [Schema compilation context](#schema-compilation-context) - [Validation time variables](#validation-time-variables) - [Ajv utilities](#ajv-utilities) - [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 - current data path - parent data object - the property name in the parent data object - the root data The access to the parent data object and the current property name allow to create keywords that modify the validated data (`modifying` option MUST be used in keyword definition in this case). The function should return validation result as boolean. It can return an array of validation errors via `.errors` property of itself (otherwise a standard error will be used). 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/epoberezkin/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 draft6 keyword `const`, it is equivalent to `enum` keyword with one item): ```javascript ajv.addKeyword('constant', { validate: function (schema, data) { return typeof schema == 'object' && schema !== null ? deepEqual(schema, data) : schema === data; }, errors: false }); var schema = { "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 ``` `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. 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 - the property name in the parent data object - the root data The access to the parent data object and the current property name allow to create keywords that modify the validated data (`modifying` option MUST be used). The function should return validation result as boolean. It can return an array of validation errors via `.errors` property of itself (otherwise a standard error will be used). In some cases it is the best approach to define keywords, but it has the performance cost of an extra function call during validation. If keyword logic can be expressed via some other JSON-schema then `macro` keyword definition is more efficient (see below). All custom keywords types can have an optional `metaSchema` property in their definitions. It is a schema against which the value of keyword will be validated during schema compilation. Example. `range` and `exclusiveRange` keywords using compiled schema: ```javascript ajv.addKeyword('range', { type: 'number', compile: function (sch, parentSchema) { 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; } }, errors: false, metaSchema: { 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 ``` 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. It is the most efficient approach (in cases when the keyword logic can be expressed with another JSON-schema) because it is usually easy to implement and there is no extra function call during validation. In addition to the errors from the expanded schema macro keyword will add its own error in case validation fails. Example. `range` and `exclusiveRange` keywords from the previous example defined with macro: ```javascript ajv.addKeyword('range', { type: 'number', macro: function (schema, parentSchema) { return { minimum: schema[0], maximum: schema[1], exclusiveMinimum: !!parentSchema.exclusiveRange, exclusiveMaximum: !!parentSchema.exclusiveRange }; }, metaSchema: { 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 ajv.addKeyword('contains', { type: 'array', macro: function (schema) { return { "not": { "items": { "not": schema } } }; } }); var schema = { "contains": { "type": "number", "minimum": 4, "exclusiveMinimum": true } }; var validate = ajv.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" ``` `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/epoberezkin/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. While it can be more challenging to define keywords with "inline" functions, it has several advantages: - the best performance - the precise control over validation process - access to the parent data and the path to the currently validated data - access to Ajv utilities via `it.util` Example `even` keyword: ```javascript ajv.addKeyword('even', { type: 'number', inline: function (it, keyword, schema) { var op = schema ? '===' : '!=='; return 'data' + (it.dataLevel || '') + ' % 2 ' + op + ' 0'; }, metaSchema: { type: 'boolean' } }); var schema = { "even": true }; var validate = ajv.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 $data = 'data' + (it.dataLevel || '') \ , $min = it.schema.range[0] \ , $max = it.schema.range[1] \ , $gt = it.schema.exclusiveRange ? '>' : '>=' \ , $lt = it.schema.exclusiveRange ? '<' : '<='; \ }} \ var valid{{=it.level}} = {{=$data}} {{=$gt}} {{=$min}} && {{=$data}} {{=$lt}} {{=$max}}; \ "); ajv.addKeyword('range', { type: 'number', inline: inlineRangeTemplate, statements: true, metaSchema: { type: 'array', items: [ { type: 'number' }, { type: 'number' } ], additionalItems: false } }); // {% endraw %} ``` `'valid' + it.level` in the example above is the expected name of the variable that should be set to the validation result. Property `statements` in the keyword definition should be set to `true` if the validation code sets the variable instead of evaluating to the validation result. 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. 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. `it` object has the following properties: - _level_ - the level of the current schema, `0` on the top level, `1` in subschemas (e.g. schemas in `properties` or `anyOf` keyword). The value of this property should be appended to the validation-time variables you use in the generated code. - _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). - _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. - _compositeRule_ - boolean indicating that the current schema is inside the compound keyword where failing some rule doesn't mean validation failure (`anyOf`, `oneOf`, `not`, `if` in `switch`). This flag is used to determine whether you can return validation result immediately after any error in case the option `allErrors` is not `true. You only need to do it if you have many steps in your keywords and potentially can define multiple errors. - _validate_ - the function you need to use to compile subschemas in your keywords (see the [implementation](https://github.com/epoberezkin/ajv/blob/master/lib/dot/v5/switch.jst) of `switch` keyword for example). - _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. - `'data' + (it.dataLevel || '')` - the variable name for the data at the current level. - `'data' + ((it.dataLevel-1)||'')` - parent data if `it.dataLevel > 0`. - `'rootData'` - the root data. - `it.dataPathArr[it.dataLevel]` - the name of the property in the parent object that points to the current data if `it.dataLevel > 0`. - `'validate.schema'` - top level schema of the current validation function at validation-time. - `'validate.schema' + it.schemaPath` - current level schema available at validation time (the same schema at compile time is `it.schema`). - `'validate.schema' + it.schemaPath + '.' + keyword` - the value of your custom keyword at validation-time. Keyword is passed as the second parameter to the inline compilation function to allow using the same function to compile multiple keywords. - `'valid' + it.level` - the variable that you have to declare and to assign the validation result to if your keyword returns statements rather than expression (`statements: true`). - `'errors'` - the number of encountered errors. See [Reporting errors in custom keywords](https://github.com/epoberezkin/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/epoberezkin/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: ##### .copy(Object obj[, Object target]) -> Object 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 } ``` ##### .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'b") // "['a\\'b']" 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. ```javascript 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). ```javascript 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) // 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. Synchronous validating and compiled keywords should define errors by assigning them to `.errors` property of the validation function. Asynchronous keywords can return promise that rejects with `new Ajv.ValidationError(errors)`, where `errors` is an array of custom validation errors (if you don't want to define custom errors in asynchronous keyword, its validation function can return the promise that resolves with `false`). Inline custom keyword should increase error counter `errors` and add error to `vErrors` array (it can be null). This can be done for both synchronous and asynchronous keywords. See [example range keyword](https://github.com/epoberezkin/ajv/blob/master/spec/custom_rules/range_with_errors.jst). 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', inline: inlineRangeTemplate, statements: true, 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. Inlined keywords can optionally define `dataPath` and `schemaPath` properties in error objects, that will be assigned by Ajv unless `errors` option of the keyword is `"full"`. 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/epoberezkin/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). Two conditions should be checked before keyword can return the result: - option `allErrors` should not be used (`!it.opts.allErrors` should be true). - the current schema should not be inside composite rule (e.g. `not` or `anyOf`), when failing some keyword does not mean failing the validation (`!it.compositeRule` should be true). 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; ``` 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 ``` In case `allErrors` option is used the keyword should continue validation after it encounters an error trying to find as many errors as possible. If `allErrors` option is not used but `it.compositeRule` is truthy the keyword may short-circuit its own validation but it should not return the final validation result. ajv-5.0.0/FAQ.md000066400000000000000000000152721307514663700132500ustar00rootroot00000000000000# Frequently Asked Questions 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. ## Ajv API for returning validation errors See [#65](https://github.com/epoberezkin/ajv/issues/65), [#212](https://github.com/epoberezkin/ajv/issues/212), [#236](https://github.com/epoberezkin/ajv/issues/236), [#242](https://github.com/epoberezkin/ajv/issues/242), [#256](https://github.com/epoberezkin/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). ## Additional properties inside compound keywords anyOf, oneOf, etc. See [#127](https://github.com/epoberezkin/ajv/issues/127), [#129](https://github.com/epoberezkin/ajv/issues/129), [#134](https://github.com/epoberezkin/ajv/issues/134), [#140](https://github.com/epoberezkin/ajv/issues/140), [#193](https://github.com/epoberezkin/ajv/issues/193), [#205](https://github.com/epoberezkin/ajv/issues/205), [#238](https://github.com/epoberezkin/ajv/issues/238), [#264](https://github.com/epoberezkin/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. While you can expect that the schema below would allow the objects either with properties `foo` and `bar` or with properties `foo` and `baz` and all other properties will be prohibited, this schema will only allow objects with one property `foo` (an empty object and any non-objects will also be valid): ```json { "properties": { "foo": { "type": "number" } }, "additionalProperties": false, "oneOf": [ { "properties": { "bar": { "type": "number" } } }, { "properties": { "baz": { "type": "number" } } } ] } ``` The reason for that is that `additionalProperties` keyword ignores properties inside `oneOf` keyword subschemas. That's not the limitation of Ajv or any other validator, that's how it must work according to the standard (and if you consider all the problems with the alternatives it is the only sensible way to define this keyword). 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 sence of `additionalProperties` keyword, based on `properties`/`patternProperties` keyword in the same schema object. See the exemple in [Filtering Data](https://github.com/epoberezkin/ajv#filtering-data) section of readme. ## Generating schemas with resolved references ($ref) See [#22](https://github.com/epoberezkin/ajv/issues/22), [#125](https://github.com/epoberezkin/ajv/issues/125), [#146](https://github.com/epoberezkin/ajv/issues/146), [#228](https://github.com/epoberezkin/ajv/issues/228), [#336](https://github.com/epoberezkin/ajv/issues/336), [#454](https://github.com/epoberezkin/ajv/issues/454). ##### Why Ajv does not replace references ($ref) with the actual referenced schemas as some validators do? 1. The scope of Ajv is validating data against JSON-Schemas; inlining referenced schemas is not necessary for validation. When Ajv generates code for validation it either inlines the code of referenced schema or uses function calls. Doing schema manipulation is more complex and out of scope. 2. When schemas are recursive (or mutually recursive) resolving references would result in self-referencing recursive data-structures that can be difficult to process. 3. There are cases when such inlining would also require adding (or modyfing) `id` attribute in the inlined schema fragment to make the resulting schema equivalent. There were many conversations about the meaning of `$ref` in [JSON-Schema GitHub organisation](https://github.com/json-schema-org). The consesus 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: 1. Write code to traverse schema and replace every `$ref` with the referenced schema. An additional limitation is that `"$ref"` inside keywords "properties", "patternProperties" and "dependencies" means property name (or pattern) rather than the reference to another schema. 2. Use a specially constructed JSON Schema with a [custom keyword](https://github.com/epoberezkin/ajv/blob/master/CUSTOM.md) to traverse and modify your schema. ajv-5.0.0/KEYWORDS.md000066400000000000000000000600701307514663700141040ustar00rootroot00000000000000# 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 6) - [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) - [Keywords for arrays](#keywords-for-arrays) - [maxItems/minItems](#maxitems--minitems) - [uniqueItems](#uniqueitems) - [items](#items) - [additionalItems](#additionalitems) - [contains](#contains) (NEW in draft 6) - [Keywords for objects](#keywords-for-objects) - [maxProperties/minProperties](#maxproperties--minproperties) - [required](#required) - [properties](#properties) - [patternProperties](#patternproperties) - [additionalProperties](#additionalproperties) - [dependencies](#dependencies) - [propertyNames](#propertynames) (NEW in draft 6) - [patternGroups](#patterngroups-deprecated) (deprecated) - [patternRequired](#patternrequired-proposed) (proposed) - [Keywords for all types](#keywords-for-all-types) - [enum](#enum) - [const](#const) (NEW in draft 6) - [Compound keywords](#compound-keywords) - [not](#not) - [oneOf](#oneof) - [anyOf](#anyof) - [allOf](#allof) - [switch](#switch-proposed) (proposed) ## `type` `type` keyword requires that the data is of certain type (or some of types). Its value can be a string (the allowed type) or an array of strings (multiple allowed types). Type can be: number, integer, string, boolean, array, object or null. __Examples__ 1. _schema_: `{ "type": "number" }` _valid_: `1`, `1.5` _invalid_: `"abc"`, `"1"`, `[]`, `{}`, `null`, `true` 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. Draft 4: The value of keyword `exclusiveMaximum` (`exclusiveMinimum`) should be a boolean value. These keyword cannot be used without `maximum` (`minimum`). If this keyword value is equal to `true`, the data should not be equal to the value in `maximum` (`minimum`) keyword to be valid. Draft 6: The value of keyword `exclusiveMaximum` (`exclusiveMinimum`) should be a number. This value is the exclusive maximum (minimum) allowed value for the data to be valid (the data equal to this keyword value is invalid). Ajv supports both draft 4 and draft 6 syntaxes. __Examples__ 1. _schema_: `{ "maximum": 5 }` _valid_: `4`, `5`, any non-number (`"abc"`, `[]`, `{}`, `null`, `true`) _invalid_: `6`, `7` 2. _schema_: `{ "minimum": 5 }` _valid_: `5`, `6`, any non-number (`"abc"`, `[]`, `{}`, `null`, `true`) _invalid_: `4`, `4.5` 3. _schema_: draft 4: `{ "minimum": 5, "exclusiveMinimum": true }` draft 6: `{ "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__ 1. _schema_: `{ "multipleOf": 5 }` _valid_: `5`, `10`, any non-number (`"abc"`, `[]`, `{}`, `null`, `true`) _invalid_: `1`, `4` 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__ 1. _schema_: `{ "maxLength": 5 }` _valid_: `"abc"`, `"abcde"`, any non-string (`1`, `[]`, `{}`, `null`, `true`) _invalid_: `"abcdef"` 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__ _schema_: `{ "pattern": "[abc]+" }` _valid_: `"a"`, `"abcd"`, `"cde"`, any non-string (`1`, `[]`, `{}`, `null`, `true`) _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. __Example__ _schema_: `{ "format": "ipv4" }` _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/epoberezkin/ajv-keywords) package. The value of keyword `formatMaximum` (`formatMinimum`) should be a string. This value is the maximum (minimum) allowed value for the data to be valid as determined by `format` keyword. 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__ _schema_: ```json { "format": "date", "formatMaximum": "2016-02-06", "formatExclusiveMaximum": true } ``` _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__ _schema_: `{ "maxItems": 3 }` _valid_: `[]`, `[1]`, `["1", 2, "3"]`, any non-array (`"abc"`, `1`, `{}`, `null`, `true`) _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__ _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 }]` ### `items` The value of the keyword should be an object or an array of objects. If the keyword value is an object, then for the data array to be valid each item of the array should be valid according to the schema in this value. In this case the "additionalItems" keyword is ignored. If the keyword value is an array, then items with indeces less than the number of items in the keyword should be valid according to the schemas with the same indeces. Whether additional items are valid will depend on "additionalItems" keyword. __Examples__ 1. _schema_: `{ "items": { "type": "integer" } }` _valid_: `[1,2,3]`, `[]`, any non-array (`1`, `"abc"`, `{}`, `null`, `true`) _invalid_: `[1,"abc"]` 2. _schema_: ```json { "items": [ { "type": "integer" }, { "type": "string" } ] } ``` _valid_: `[1]`, `[1, "abc"]`, `[1, "abc", 2]`, `[]`, any non-array (`1`, `"abc"`, `{}`, `null`, `true`) _invalid_: `["abc", 1]`, `["abc"]` ### `additionalItems` The value of the keyword should be a boolean or an object. If "items" keyword is not present or it is an object, "additionalItems" keyword is ignored regardless of its value. If "items" keyword is an array and data array has not more items than the length of "items" keyword value, "additionalItems" keyword is also ignored. If the length of data array is bigger than the length of "items" keyword value than the result of the validation depends on the value of "additionalItems" keyword: - `false`: data is invalid - `true`: data is valid - an object: data is valid if all additional items (i.e. items with indeces greater or equal than "items" keyword value length) are valid according to the schema in "assitionalItems" keyword. __Examples__ 1. _schema_: `{ "additionalItems": { "type": "integer" } }` any data is valid against such schema - "additionalItems" is ignored. 2. _schema_: ```json { "items": { "type": "integer" }, "additionalItems": { "type": "string" } } ``` _valid_: `[]`, `[1, 2]`, any non-array ("additionalItems" is ignored) _invalid_: `[1, "abc"]`, (any array with some items other than integers) 3. _schema_: ```json { "items": [ { "type": "integer" }, { "type": "integer" } ], "additionalItems": true } ``` _valid_: `[]`, `[1, 2]`, `[1, 2, 3]`, `[1, 2, "abc"]`, any non-array _invalid_: `["abc"]`, `[1, "abc", 3]` 4. _schema_: ```json { "items": [ { "type": "integer" }, { "type": "integer" } ], "additionalItems": { "type": "string" } } ``` _valid_: `[]`, `[1, 2]`, `[1, 2, "abc"]`, any non-array _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__ _schema_: `{ "contains": { "type": "integer" } }` _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" } } } } ``` ## 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__ _schema_: `{ "maxProperties": 2 }` _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__ _schema_: `{ "required": ["a", "b"] }` _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). __Example__ _schema_: ```json { "properties": { "foo": { "type": "string" }, "bar": { "type": "number", "minimum": 2 } } } ``` _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). __Example__ _schema_: ```json { "patternProperties": { "^fo.*$": { "type": "string" }, "^ba.*$": { "type": "number" } } } ``` _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. If the value is `true` the keyword is ignored. If the value is `false` the data object to be valid should not have "additional properties" (i.e. properties other than those used in "properties" keyword and those that match patterns in "patternProperties" keyword). 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__ 1. _schema_: ```json { "properties": { "foo": { "type": "number" } }, "patternProperties": { "^.*r$": { "type": "number" } }, "additionalProperties": false } ``` _valid_: `{}`, `{"foo": 1}`, `{"foo": 1, "bar": 2}`, any non-object _invalid_: `{"a": 3}`, `{"foo": 1, "baz": 3}` 2. _schema_: ```json { "properties": { "foo": { "type": "number" } }, "patternProperties": { "^.*r$": { "type": "number" } }, "additionalProperties": { "type": "string" } } ``` _valid_: `{}`, `{"a": "b"}`, `{"foo": 1}`, `{"foo": 1, "bar": 2}`, `{"foo": 1, "bar": 2, "a": "b"}`, any non-object _invalid_: `{"a": 3}`, `{"foo": 1, "baz": 3}` 3. _schema_: ```json { "properties": { "foo": { "type": "number" } }, "additionalProperties": false, "anyOf": [ "properties": { "bar": { "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"). For property dependency, if the data object contains a property that is a key in the keyword value, then to be valid the data object should also contain all properties from the array of properties. 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__ 1. _schema (property dependency)_: ```json { "dependencies": { "foo": ["bar", "baz"] } } ``` _valid_: `{"foo": 1, "bar": 2, "baz": 3}`, `{}`, `{"a": 1}`, any non-object _invalid_: `{"foo": 1}`, `{"foo": 1, "bar": 2}`, `{"foo": 1, "baz": 3}` 2. _schema (schema dependency)_: ```json { "dependencies": { "foo": { "properties": { "bar": { "type": "number" } } } } } ``` _valid_: `{}`, `{"foo": 1}`, `{"foo": 1, "bar": 2}`, `{"a": 1}`, any non-object _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__ _schema_: ```json { "propertyNames": { "format": "email" } } ``` _valid_: `{"foo@bar.com": "any", "bar@bar.com": "any"}`, any non-object _invalid_: `{"foo": "any value"}` ### `patternGroups` (deprecated) This keyword is only provided for backward compatibility, it will be removed in the next major version. To use it, pass option `patternGroups: true`. The value of this keyword should be a map where keys should be regular expressions and the values should be objects with the following properties: - `schema` (required) - should be a JSON schema. For data object to be valid the values in data object properties that match regular expression(s) should be valid according to the corresponding `schema`(s). - `maximum` / `minimum` (optional) - should be integers. For data object to be valid the number of properties that match regular expression(s) should be within limits set by `minimum`(s) and `maximum`(s). __Example__ _schema_: ```json { "patternGroups": { "^[a-z]+$": { "minimum": 1, "schema": { "type": "string" } }, "^[0-9]+$": { "minimum": 1, "schema": { "type": "integer" } } } } ``` _valid_: `{ "foo": "bar", "1": "2" }`, any non-object _invalid_: `{}`, `{ "foo": "bar" }`, `{ "1": "2" }` ### `patternRequired` (proposed) Defined in [ajv-keywords](https://github.com/epoberezkin/ajv-keywords) package. The value of this keyword should be an array of strings, each string being a regular expression. For data object to be valid each regular expression in this array should match at least one property name in the data object. If the array contains multiple regular expressions, more than one expression can match the same property name. __Examples__ 1. _schema_: `{ "patternRequired": [ "f.*o" ] }` _valid_: `{ "foo": 1 }`, `{ "-fo-": 1 }`, `{ "foo": 1, "bar": 2 }`, any non-object _invalid_: `{}`, `{ "bar": 2 }`, `{ "Foo": 1 }`, 2. _schema_: `{ "patternRequired": [ "f.*o", "b.*r" ] }` _valid_: `{ "foo": 1, "bar": 2 }`, `{ "foobar": 3 }`, any non-object _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__ _schema_: `{ "enum": [ 2, "foo", {"foo": "bar" }, [1, 2, 3] ] }` _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__ _schema_: `{ "const": "foo" }` _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/epoberezkin/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__ _schema_: ```json { "properties": { "foo": { "type": "number" }, "bar": { "const": { "$data": "1/foo" } } } } ``` _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__ 1. _schema_: `{ "not": { "minimum": 3 } }` _valid_: `1`, `2` _invalid_: `3`, `4`, any non-number 2. _schema_: ```json { "not": { "items": { "not": { "type": "string" } } } } ``` _valid_: `["a"]`, `[1, "a"]`, any array containing at least one string _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__ _schema_: ```json { "oneOf": [ { "maximum": 3 }, { "type": "integer" } ] } ``` _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__ _schema_: ```json { "anyOf": [ { "maximum": 3 }, { "type": "integer" } ] } ``` _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__ _schema_: ```json { "allOf": [ { "maximum": 3 }, { "type": "integer" } ] } ``` _valid_: `2`, `3` _invalid_: `1.5`, `2.5`, `4`, `4.5`, `5`, `5.5`, any non-number ### `switch` (proposed) Defined in [ajv-keywords](https://github.com/epoberezkin/ajv-keywords) package. The value of the keyword is the array of if/then clauses. Each clause is the object with the following properties: - `if` (optional) - the value is JSON-schema - `then` (required) - the value is JSON-schema or boolean - `continue` (optional) - the value is boolean The validation process is dynamic; all clauses are executed sequentially in the following way: 1. `if`: 1. `if` property is JSON-schema according to which the data is: 1. valid => go to step 2. 2. invalid => go to the NEXT clause, if this was the last clause the validation of `switch` SUCCEEDS. 2. `if` property is absent => go to step 2. 2. `then`: 1. `then` property is `true` or it is JSON-schema according to which the data is valid => go to step 3. 2. `then` property is `false` or it is JSON-schema according to which the data is invalid => the validation of `switch` FAILS. 3. `continue`: 1. `continue` property is `true` => go to the NEXT clause, if this was the last clause the validation of `switch` SUCCEEDS. 2. `continue` property is `false` or absent => validation of `switch` SUCCEEDS. __Examples__ 1. _schema_: ```json { "switch": [ { "if": { "properties": { "power": { "minimum": 9000 } } }, "then": { "required": [ "disbelief" ] }, "continue": true }, { "then": { "required": [ "confidence" ] } } ] } ``` _valid_: - `{ "power": 9000, "disbelief": true, "confidence": true }` - `{ "confidence": true }` - `{ "power": 1000, "confidence": true }` _invalid_: - `{ "power": 9000 }` (`disbelief` & `confidence` are required) - `{ "power": 9000, "disbelief": true }` (`confidence` is always required) - `{ "power": 1000 }` - `{}` 2. _schema_: ```json { "type": "integer", "switch": [ { "if": { "not": { "minimum": 1 } }, "then": false }, { "if": { "maximum": 10 }, "then": true }, { "if": { "maximum": 100 }, "then": { "multipleOf": 10 } }, { "if": { "maximum": 1000 }, "then": { "multipleOf": 100 } }, { "then": false } ] } ``` _valid_: `1`, `5`, `10`, `20`, `50`, `100`, `200`, `500`, `1000` _invalid_: - `-1`, `0` (<1) - `2000` (>1000) - `11`, `57`, `123` (any number with more than one non-zero digit) - non-integers ajv-5.0.0/LICENSE000066400000000000000000000020751307514663700133210ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2015 Evgeny Poberezkin Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ajv-5.0.0/README.md000066400000000000000000002062251307514663700135760ustar00rootroot00000000000000Ajv logo # Ajv: Another JSON Schema Validator The fastest JSON Schema validator for node.js and browser with draft 6 support. [![Build Status](https://travis-ci.org/epoberezkin/ajv.svg?branch=master)](https://travis-ci.org/epoberezkin/ajv) [![npm version](https://badge.fury.io/js/ajv.svg)](https://www.npmjs.com/package/ajv) [![npm downloads](https://img.shields.io/npm/dm/ajv.svg)](https://www.npmjs.com/package/ajv) [![Code Climate](https://codeclimate.com/github/epoberezkin/ajv/badges/gpa.svg)](https://codeclimate.com/github/epoberezkin/ajv) [![Coverage Status](https://coveralls.io/repos/epoberezkin/ajv/badge.svg?branch=master&service=github)](https://coveralls.io/github/epoberezkin/ajv?branch=master) [![Gitter](https://img.shields.io/gitter/room/ajv-validator/ajv.svg)](https://gitter.im/ajv-validator/ajv) __Please note__: [JSON-Schema draft-06](https://trac.tools.ietf.org/html/draft-wright-json-schema-validation-01) is published. [Ajv version 5.0.0](https://github.com/epoberezkin/ajv/releases/tag/5.0.0) is released. You can still use [Ajv version 4](https://github.com/epoberezkin/ajv/tree/v4): `npm install ajv@^4`. ## Contents - [Performance](#performance) - [Features](#features) - [Getting started](#getting-started) - [Frequently Asked Questions](https://github.com/epoberezkin/ajv/blob/master/FAQ.md) - [Using in browser](#using-in-browser) - [Command line interface](#command-line-interface) - Validation - [Keywords](#validation-keywords) - [Formats](#formats) - [$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) - [Asynchronous validation](#asynchronous-validation) - Modifying data during validation - [Filtering data](#filtering-data) - [Assigning defaults](#assigning-defaults) - [Coercing data types](#coercing-data-types) - API - [Methods](#api) - [Options](#options) - [Validation errors](#validation-errors) - [Related packages](#related-packages) - [Packages using Ajv](#some-packages-using-ajv) - [Tests, Contributing, History, License](#tests) ## 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. Currently Ajv is the fastest and the most standard compliant validator according to these benchmarks: - [json-schema-benchmark](https://github.com/ebdrup/json-schema-benchmark) - 50% faster than the second place - [jsck benchmark](https://github.com/pandastrike/jsck#benchmarks) - 20-190% faster - [z-schema benchmark](https://rawgit.com/zaggino/z-schema/master/benchmark/results.html) - [themis benchmark](https://cdn.rawgit.com/playlyfe/themis/master/benchmark/results.html) Performace 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:%7Cajv%7Cis-my-json-valid%7Cjsen%7Cschemasaurus%7Cthemis%7Cz-schema%7Cjsck%7Cjsonschema%7Cskeemas%7Ctv4%7Cjayschema&chd=t:100,68,61,22.8,17.6,6.6,2.7,0.9,0.7,0.4,0.1)](https://github.com/ebdrup/json-schema-benchmark/blob/master/README.md#performance) ## Features - Ajv implements full JSON Schema [draft 6](http://json-schema.org/) and draft 4 standards: - all validation keywords (see [JSON-Schema validation keywords](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md)) - full support of remote refs (remote schemas have to be added with `addSchema` or compiled to be available) - support of circular references between schemas - correct string lengths for strings with unicode pairs (can be turned off) - [formats](#formats) defined by JSON Schema draft 4 standard and custom formats (can be turned off) - [validates schemas against meta-schema](#api-validateschema) - supports [browsers](#using-in-browser) and nodejs 0.10-6.x - [asynchronous loading](#asynchronous-schema-compilation) of referenced schemas during compilation - "All errors" validation mode with [option allErrors](#options) - [error messages with parameters](#validation-errors) describing error reasons to allow creating custom error messages - i18n error messages support with [ajv-i18n](https://github.com/epoberezkin/ajv-i18n) package - [filtering data](#filtering-data) from additional properties - [assigning defaults](#assigning-defaults) to missing properties and items - [coercing data](#coercing-data-types) to the types specified in `type` keywords - [custom keywords](#defining-custom-keywords) - draft-6 keywords `const`, `contains` and `propertyNames` - draft-6 boolean schemas (`true`/`false` as a schema to always pass/fail). - keywords `switch`, `patternRequired`, `formatMaximum` / `formatMinimum` and `formatExclusiveMaximum` / `formatExclusiveMinimum` from [JSON-schema extension proposals](https://github.com/json-schema/json-schema/wiki/v5-Proposals) with [ajv-keywords](https://github.com/epoberezkin/ajv-keywords) package - [$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 ``` To install a stable beta version [5.0.4](https://github.com/epoberezkin/ajv/releases/tag/5.0.4-beta.3) (see [migration guide from 4.x.x](https://github.com/epoberezkin/ajv/releases/tag/5.0.1-beta.0)): ``` npm install ajv@^5.0.4-beta ``` ## Getting started Try it in the node REPL: https://tonicdev.com/npm/ajv The fastest validation call: ```javascript var Ajv = require('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); ``` or with less code ```javascript // ... var valid = ajv.validate(schema, data); if (!valid) console.log(ajv.errors); // ... ``` or ```javascript // ... ajv.addSchema(schema, 'mySchema'); var valid = ajv.validate('mySchema', data); if (!valid) console.log(ajv.errorsText()); // ... ``` See [API](#api) and [Options](#options) for more details. Ajv compiles schemas to functions and caches them in all cases (using schema serialized with [json-stable-stringify](https://github.com/substack/json-stable-stringify) or a custom function as a key), so that the next time the same schema is used (not necessarily the same object instance) it won't be compiled again. The best performance is achieved when using compiled functions returned by `compile` or `getSchema` methods (there is no additional function call). __Please note__: every time 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) ## Using in browser You can require Ajv directly from the code you browserify - in this case Ajv will be a part of your bundle. 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 ``` This bundle can be used with different module systems or creates global `Ajv` if no module system is found. The browser bundle is available on [cdnjs](https://cdnjs.com/libraries/ajv). 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/epoberezkin/ajv/issues/234)). ## Command line interface CLI is available as a separate npm package [ajv-cli](https://github.com/jessedc/ajv-cli). It supports: - compiling JSON-schemas to test their validity - BETA: generating standalone module exporting a validation function to be used without Ajv (using [ajv-pack](https://github.com/epoberezkin/ajv-pack)) - migrate schemas to draft-06 (using [json-schema-migrate](https://github.com/epoberezkin/json-schema-migrate)) - validating data file(s) against JSON-schema - testing expected validity of data against JSON-schema - referenced schemas - custom meta-schemas - files in JSON and JavaScript format - 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 4 of JSON-schema standard: - [type](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md#type) - [for numbers](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md#keywords-for-numbers) - maximum, minimum, exclusiveMaximum, exclusiveMinimum, multipleOf - [for strings](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md#keywords-for-strings) - maxLength, minLength, pattern, format - [for arrays](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md#keywords-for-arrays) - maxItems, minItems, uniqueItems, items, additionalItems, [contains](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md#contains) - [for objects](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md#keywords-for-objects) - maxProperties, minproperties, required, properties, patternProperties, additionalProperties, dependencies, [propertyNames](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md#propertynames) - [for all types](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md#keywords-for-all-types) - enum, [const](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md#const) - [compound keywords](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md#compound-keywords) - not, oneOf, anyOf, allOf With [ajv-keywords](https://github.com/epoberezkin/ajv-keywords) package Ajv also supports validation keywords from [JSON-Schema extension proposals](https://github.com/json-schema/json-schema/wiki/v5-Proposals) for JSON-schema standard: - [switch](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md#switch-proposed) - conditional validation with a sequence of if/then clauses - [patternRequired](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md#patternrequired-proposed) - like `required` but with patterns that some property should match. - [formatMaximum, formatMinimum, formatExclusiveMaximum, formatExclusiveMinimum](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md#formatmaximum--formatminimum-and-exclusiveformatmaximum--exclusiveformatminimum-proposed) - setting limits for date, time, etc. See [JSON-Schema validation keywords](https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md) for more details. ## Formats The following formats are supported for string validation with "format" keyword: - _date_: full-date according to [RFC3339](http://tools.ietf.org/html/rfc3339#section-5.6). - _time_: time with optional time-zone. - _date-time_: date-time from the same source (time-zone is mandatory). `date`, `time` and `date-time` validate ranges in `full` mode and only regexp in `fast` mode (see [options](#options)). - _uri_: full uri with optional protocol. - _url_: [URL record](https://url.spec.whatwg.org/#concept-url). - _email_: email address. - _hostname_: host name acording to [RFC1034](http://tools.ietf.org/html/rfc1034#section-3.5). - _ipv4_: IP address v4. - _ipv6_: IP address v6. - _regex_: tests whether a string is a valid regular expression by passing it to RegExp constructor. - _uuid_: Universally Unique IDentifier according to [RFC4122](http://tools.ietf.org/html/rfc4122). - _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). There are two modes of format validation: `fast` and `full`. This mode affects formats `date`, `time`, `date-time`, `uri`, `email`, and `hostname`. See [Options](#options) for details. You can add additional formats and replace any of the formats above using [addFormat](#api-addformat) method. The option `unknownFormats` allows to change the behaviour in case an unknown format is encountered - Ajv can either fail schema compilation (default) or ignore it (default in versions before 5.0.0). You also can whitelist specific format(s) to be ignored. See [Options](#options) for details. You can find patterns used for format validation and the sources that were used in [formats.js](https://github.com/epoberezkin/ajv/blob/master/lib/compile/formats.js). ## $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/json-schema/wiki/$data-(v5-proposal)) 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). Examples. This schema requires that the value in property `smaller` is less or equal than the value in the property larger: ```javascript var schema = { "properties": { "smaller": { "type": "number", "maximum": { "$data": "1/larger" } }, "larger": { "type": "number" } } }; var validData = { smaller: 5, larger: 7 }; ``` This schema requires that the properties have the same format as their field names: ```javascript var schema = { "additionalProperties": { "type": "string", "format": { "$data": "0#" } } }; var validData = { 'date-time': '1963-06-19T08:30:06.283185Z', email: 'joe.bloggs@example.com' } ``` `$data` reference is resolved safely - it won't throw even if some property is undefined. If `$data` resolves to `undefined` the validation succeeds (with the exclusion of `const` keyword). If `$data` resolves to incorrect type (e.g. not "number" for maximum keyword) the validation fails. ## $merge and $patch keywords With the package [ajv-merge-patch](https://github.com/epoberezkin/ajv-merge-patch) you can use the keywords `$merge` and `$patch` that allow extending JSON-schemas with patches using formats [JSON Merge Patch (RFC 7396)](https://tools.ietf.org/html/rfc7396) and [JSON Patch (RFC 6902)](https://tools.ietf.org/html/rfc6902). To add keywords `$merge` and `$patch` to Ajv instance use this code: ```javascript require('ajv-merge-patch')(ajv); ``` Examples. Using `$merge`: ```json { "$merge": { "source": { "type": "object", "properties": { "p": { "type": "string" } }, "additionalProperties": false }, "with": { "properties": { "q": { "type": "number" } } } } } ``` Using `$patch`: ```json { "$patch": { "source": { "type": "object", "properties": { "p": { "type": "string" } }, "additionalProperties": false }, "with": [ { "op": "add", "path": "/properties/q", "value": { "type": "number" } } ] } } ``` The schemas above are equivalent to this schema: ```json { "type": "object", "properties": { "p": { "type": "string" }, "q": { "type": "number" } }, "additionalProperties": false } ``` The properties `source` and `with` in the keywords `$merge` and `$patch` can use absolute or relative `$ref` to point to other schemas previously added to the Ajv instance or to the fragments of the current schema. See the package [ajv-merge-patch](https://github.com/epoberezkin/ajv-merge-patch) for more information. ## Defining custom keywords The advantages of using custom keywords are: - allow creating validation scenarios that cannot be expressed using JSON-Schema - simplify your schemas - help bringing a bigger part of the validation logic to your schemas - make your schemas more expressive, less verbose and closer to your application domain - implement custom data processors that modify your data (`modifying` option MUST be used in keyword definition) and/or create side effects while the data is being validated If a keyword is used only for side-effects and its validation result is pre-defined, use option `valid: true/false` in keyword definition to simplify both generated code (no error handling in case of `valid: true`) and your keyword functions (no need to return any validation result). The concerns you have to be aware of when extending JSON-schema standard with custom keywords are the portability and understanding of your schemas. You will have to support these custom keywords on other platforms and to properly document these keywords so that everybody can understand them in your schemas. You can define custom keywords with [addKeyword](#api-addkeyword) method. Keywords are defined on the `ajv` instance level - new instances will not have previously defined keywords. Ajv allows defining keywords with: - validation function - compilation function - macro function - inline compilation function that should return code (as string) that will be inlined in the currently compiled schema. Example. `range` and `exclusiveRange` keywords using compiled schema: ```javascript ajv.addKeyword('range', { type: 'number', compile: function (sch, parentSchema) { 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 ``` Several custom keywords (typeof, instanceof, range and propertyNames) are defined in [ajv-keywords](https://github.com/epoberezkin/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/epoberezkin/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). Example: ```javascript var ajv = new Ajv({ loadSchema: loadSchema }); ajv.compileAsync(schema).then(function (validate) { 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; }); } ``` __Please note__: [Option](#options) `missingRefs` should NOT be set to `"ignore"` or `"fail"` for asynchronous compilation to work. ## Asynchronous validation Example in node REPL: https://tonicdev.com/esp/ajv-asynchronous-validation You can define custom formats and keywords that perform validation asyncronously by accessing database or some service. You should add `async: true` in the keyword or format defnition (see [addFormat](#api-addformat), [addKeyword](#api-addkeyword) and [Defining custom keywords](#defining-custom-keywords)). 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. Validation function for an asynchronous custom format/keyword should return a promise that resolves with `true` or `false` (or rejects with `new Ajv.ValidationError(errors)` if you want to return custom errors from the keyword function). Ajv compiles asynchronous schemas to either [es7 async functions](http://tc39.github.io/ecmascript-asyncawait/) that can optionally be transpiled with [nodent](https://github.com/MatAtBread/nodent) or with [regenerator](https://github.com/facebook/regenerator) or to [generator functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*) that can be optionally transpiled with regenerator as well. You can also supply any other transpiler as a function. See [Options](#options). The compiled validation function has `$async: true` property (if the schema is asynchronous), so you can differentiate these functions if you are using both syncronous and asynchronous schemas. If you are using generators, the compiled validation function can be either wrapped with [co](https://github.com/tj/co) (default) or returned as generator function, that can be used directly, e.g. in [koa](http://koajs.com/) 1.0. `co` is a small library, it is included in Ajv (both as npm dependency and in the browser bundle). Async functions are currently supported in Chrome 55, Firefox 52, Node 7 (with --harmony-async-await) and MS Edge 13 (with flag). Generator functions are currently supported in Chrome, Firefox and node.js. If you are using Ajv in other browsers or in older versions of node.js you should use one of available transpiling options. All provided async modes use global Promise class. If your platform does not have Promise you should use a polyfill that defines it. Validation result will be a promise that resolves with validated data or rejects with an exception `Ajv.ValidationError` that has the array of validation errors in `errors` property. Example: ```javascript /** * Default mode is non-transpiled generator function wrapped with `co`. * Using package ajv-async (https://github.com/epoberezkin/ajv-async) * you can auto-detect the best async mode. * In this case, without "async" and "transpile" options * (or with option {async: true}) * Ajv will choose the first supported/installed option in this order: * 1. native async function * 2. native generator function wrapped with co * 3. es7 async functions transpiled with nodent * 4. es7 async functions transpiled with regenerator */ var setupAsync = require('ajv-async'); var ajv = setupAsync(new Ajv); ajv.addKeyword('idExists', { async: true, type: 'number', validate: checkIdExists }); function checkIdExists(schema, data) { return knex(schema.table) .select('id') .where('id', data) .then(function (rows) { return !!rows.length; // true if record is found }); } var schema = { "$async": true, "properties": { "userId": { "type": "integer", "idExists": { "table": "users" } }, "postId": { "type": "integer", "idExists": { "table": "posts" } } } }; 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 asyncronous validation functions. To use a transpiler you should separately install it (or load its bundle in the browser). Ajv npm package includes minified browser bundles of regenerator and nodent in dist folder. #### Using nodent ```javascript var setupAsync = require('ajv-async'); var ajv = new Ajv({ /* async: 'es7', */ transpile: 'nodent' }); setupAsync(ajv); var validate = ajv.compile(schema); // transpiled es7 async function validate(data).then(successFunc).catch(errorFunc); ``` `npm install nodent` or use `nodent.min.js` from dist folder of npm package. #### Using regenerator ```javascript var setupAsync = require('ajv-async'); var ajv = new Ajv({ /* async: 'es7', */ transpile: 'regenerator' }); setupAsync(ajv); var validate = ajv.compile(schema); // transpiled es7 async function validate(data).then(successFunc).catch(errorFunc); ``` `npm install regenerator` or use `regenerator.min.js` from dist folder of npm package. #### Using other transpilers ```javascript var ajv = new Ajv({ async: 'es7', processCode: transpileFunc }); var validate = ajv.compile(schema); // transpiled es7 async function validate(data).then(successFunc).catch(errorFunc); ``` See [Options](#options). #### Comparison of async modes |mode|transpile
speed*|run-time
speed*|bundle
size| |---|:-:|:-:|:-:| |es7 async
(native)|-|0.75|-| |generators
(native)|-|1.0|-| |es7.nodent|1.35|1.1|215Kb| |es7.regenerator|1.0|2.7|1109Kb| |regenerator|1.0|3.2|1109Kb| \* Relative performance in node v.7, smaller is better. [nodent](https://github.com/MatAtBread/nodent) has several advantages: - much smaller browser bundle than regenerator - almost the same performance of generated code as native generators in nodejs and the latest Chrome - much better performace than native generators in other browsers - works in IE 9 (regenerator does not) ## Filtering data With [option `removeAdditional`](#options) (added by [andyscott](https://github.com/andyscott)) you can filter data during the validation. This option modifies original data. Example: ```javascript var ajv = new Ajv({ removeAdditional: true }); var schema = { "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 }, } var validate = ajv.compile(schema); console.log(validate(data)); // true console.log(data); // { "foo": 0, "bar": { "baz": "abc", "additional2": 2 } ``` If `removeAdditional` option in the example above were `"all"` then both `additional1` and `additional2` properties would have been removed. If the option were `"failing"` then property `additional1` would have been removed regardless of its value and property `additional2` would have been removed only if its value were failing the schema in the inner `additionalProperties` (so in the example above it would have stayed because it passes the schema, but any non-number would have been removed). __Please note__: If you use `removeAdditional` option with `additionalProperties` keyword inside `anyOf`/`oneOf` keywords your validation can fail with this schema, for example: ```json { "type": "object", "oneOf": [ { "properties": { "foo": { "type": "string" } }, "required": [ "foo" ], "additionalProperties": false }, { "properties": { "bar": { "type": "integer" } }, "required": [ "bar" ], "additionalProperties": false } ] } ``` The intention of the schema above is to allow objects with either the string property "foo" or the integer property "bar", but not with both and not with any other properties. With the option `removeAdditional: true` the validation will pass for the object `{ "foo": "abc"}` but will fail for the object `{"bar": 1}`. It happens because while the first subschema in `oneOf` is validated, the property `bar` is removed because it is an additional property according to the standard (because it is not included in `properties` keyword in the same schema). While this behaviour is unexpected (issues [#129](https://github.com/epoberezkin/ajv/issues/129), [#134](https://github.com/epoberezkin/ajv/issues/134)), it is correct. To have the expected behaviour (both objects are allowed and additional properties are removed) the schema has to be refactored in this way: ```json { "type": "object", "properties": { "foo": { "type": "string" }, "bar": { "type": "integer" } }, "additionalProperties": false, "oneOf": [ { "required": [ "foo" ] }, { "required": [ "bar" ] } ] } ``` The schema above is also more efficient - it will compile into a faster function. ## Assigning defaults With [option `useDefaults`](#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. This option modifies original data. __Please note__: by default the default value is inserted in the generated validation code as a literal (starting from v4.0), so the value inserted in the data will be the deep clone of the default in the schema. If you need to insert the default value in the data by reference pass the option `useDefaults: "shared"`. Inserting defaults by reference can be faster (in case you have an object in `default`) and it allows to have dynamic values in defaults, e.g. timestamp, without recompiling the schema. The side effect is that modifying the default value in any validated data instance will change the default in the schema and in other validated data instances. See example 3 below. Example 1 (`default` in `properties`): ```javascript var ajv = new Ajv({ useDefaults: true }); var schema = { "type": "object", "properties": { "foo": { "type": "number" }, "bar": { "type": "string", "default": "baz" } }, "required": [ "foo", "bar" ] }; var data = { "foo": 1 }; var validate = ajv.compile(schema); 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" } ] } var data = [ 1 ]; var validate = ajv.compile(schema); console.log(validate(data)); // true console.log(data); // [ 1, "foo" ] ``` Example 3 (inserting "defaults" by reference): ```javascript var ajv = new Ajv({ useDefaults: 'shared' }); var schema = { properties: { foo: { default: { bar: 1 } } } } var validate = ajv.compile(schema); var data = {}; console.log(validate(data)); // true console.log(data); // { foo: { bar: 1 } } data.foo.bar = 2; var data2 = {}; console.log(validate(data2)); // true console.log(data2); // { foo: { bar: 2 } } ``` `default` keywords in other cases are ignored: - not in `properties` or `items` subschemas - in schemas inside `anyOf`, `oneOf` and `not` (see [#42](https://github.com/epoberezkin/ajv/issues/42)) - in `if` subschema of `switch` keyword - in schemas generated by custom macro keywords ## 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. Example 1: ```javascript var ajv = new Ajv({ coerceTypes: true }); var schema = { "type": "object", "properties": { "foo": { "type": "number" }, "bar": { "type": "boolean" } }, "required": [ "foo", "bar" ] }; var data = { "foo": "1", "bar": "false" }; var validate = ajv.compile(schema); console.log(validate(data)); // true console.log(data); // { "foo": 1, "bar": false } ``` Example 2 (array coercions): ```javascript var ajv = new Ajv({ coerceTypes: 'array' }); var schema = { "properties": { "foo": { "type": "array", "items": { "type": "number" } }, "bar": { "type": "boolean" } } }; var data = { "foo": "1", "bar": ["false"] }; var validate = ajv.compile(schema); console.log(validate(data)); // true console.log(data); // { "foo": [1], "bar": false } ``` The coercion rules, as you can see from the example, are different from JavaScript both to validate user input as expected and to have the coercion reversible (to correctly validate cases where different types are defined in subschemas of "anyOf" and other compound keywords). See [Coercion rules](https://github.com/epoberezkin/ajv/blob/master/COERCION.md) for details. ## API ##### new Ajv(Object options) -> Object Create Ajv instance. All the instance methods below are bound to the instance, so they can be used without the instance. ##### .compile(Object schema) -> Function<Object data> Generate validating function and cache the compiled schema for future use. Validating function returns boolean and has properties `errors` with the errors from the last validation (`null` if there were no errors) and `schema` with the reference to the original schema. Unless the option `validateSchema` is false, the schema will be validated against meta-schema and if schema is invalid the error will be thrown. See [options](#options). ##### .compileAsync(Object schema [, Boolean meta] [, Function callback]) -> Promise Asyncronous 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 callback if passed will be called with an error) when: - missing schema can't be loaded (`loadSchema` returns the Promise that rejects). - the schema containing missing reference is loaded, but the reference cannot be resolved. - schema (or some referenced schema) is invalid. The function compiles schema and loads the first missing schema (or meta-schema), until all missing schemas are loaded. You can asynchronously compile meta-schema by passing `true` as the second parameter. 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). Instead of the schema you can use the key that was previously passed to `addSchema`, the schema id if it was present in the schema or any previously resolved reference. 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. 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]) 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. Array of schemas can be passed (schemas should have ids), the second parameter will be ignored. 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. ##### .addMetaSchema(Array<Object>|Object schema [, String key]) Adds meta schema(s) that can be used to validate other schemas. That function should be used instead of `addSchema` because there may be instance options that would compile a meta schema incorrectly (at the moment it is `removeAdditional` option). There is no need to explicitly add draft 6 meta schema (http://json-schema.org/draft-06/schema and http://json-schema.org/schema) - it is added by default, unless option `meta` is set to `false`. You only need to use it if you have a changed meta-schema that you want to use to validate your schemas. See `validateSchema`. ##### .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. By default this method is called automatically when the schema is added, so you rarely need to use it directly. If schema doesn't have `$schema` property it is validated against draft 6 meta-schema (option `meta` should not be false). If schema has `$schema` property then the schema with this id (that should be previously added) is used to validate passed schema. 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). Returned validating function has `schema` property with the reference to the original schema. ##### .removeSchema([Object schema|String key|String ref|RegExp pattern]) 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) - actual schema object that will be stable-stringified to remove schema from cache 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) Add custom format to validate strings or numbers. It can also be used to replace pre-defined formats for Ajv instance. Strings are converted to RegExp. Function should return validation result as `true` or `false`. If object is passed it should have properties `validate`, `compare` and `async`: - _validate_: a string, RegExp or a function as described above. - _compare_: an optional comparison function that accepts two strings and compares them according to the format meaning. This function is used with keywords `formatMaximum`/`formatMinimum` (defined in [ajv-keywords](https://github.com/epoberezkin/ajv-keywords) package). It should return `1` if the first value is bigger than the second value, `-1` if it is smaller and `0` if it is equal. - _async_: an optional `true` value if `validate` is an asynchronous function; in this case it should return a promise that resolves with a value `true` or `false`. - _type_: an optional type of data that the format applies to. It can be `"string"` (default) or `"number"` (see https://github.com/epoberezkin/ajv/issues/291#issuecomment-259923858). If the type of data is different, the validation will pass. Custom formats can be also added via `formats` option. ##### .addKeyword(String keyword, Object definition) Add custom validation keyword to Ajv instance. Keyword should be different from all standard JSON schema keywords and different from previously defined keywords. There is no way to redefine keywords or to remove keyword definition from the instance. Keyword must start with a letter, `_` or `$`, and may continue with letters, numbers, `_`, `$`, or `-`. It is recommended to use an application-specific prefix for keywords to avoid current and future name collisions. Example Keywords: - `"xyz-example"`: valid, and uses prefix for the xyz project to avoid name collisions. - `"example"`: valid, but not recommended as it could collide with future versions of JSON schema etc. - `"3-example"`: invalid as numbers are not allowed to be the first character in a keyword Keyword definition is an object with the following properties: - _type_: optional string or array of strings with data type(s) that the keyword applies to. If not present, the keyword will apply to all types. - _validate_: validating function - _compile_: compiling function - _macro_: macro function - _inline_: compiling function that returns code (as string) - _schema_: an optional `false` value used with "validate" keyword to not pass schema - _metaSchema_: an optional meta-schema for keyword schema - _modifying_: `true` MUST be passed if keyword modifies data - _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). - _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 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. __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) 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. ##### .errorsText([Array<Object> errors [, Object options]]) -> String Returns the text with all errors in a String. Options can have properties `separator` (string used to separate errors, ", " by default) and `dataVar` (the variable name that dataPaths are prefixed with, "data" by default). ## Options Defaults: ```javascript { // validation and reporting options: $data: false, allErrors: false, verbose: false, jsonPointers: false, uniqueItems: true, unicode: true, format: 'fast', formats: {}, unknownFormats: true, schemas: {}, // referenced schema options: schemaId: undefined // recommended '$id' missingRefs: true, extendRefs: 'ignore', // recommended 'fail' loadSchema: undefined, // function(uri: string): Promise {} // options to modify validated data: removeAdditional: false, useDefaults: false, coerceTypes: false, // asynchronous validation options: async: 'co*', transpile: undefined, // requires ajv-async package // advanced options: meta: true, validateSchema: true, addUsedSchema: true, inlineRefs: true, passContext: false, loopRequired: Infinity, ownProperties: false, multipleOfPrecision: false, errorDataPath: 'object', messages: true, sourceCode: false, processCode: undefined, // function (str: string): string {} cache: new Cache, serialize: undefined } ``` ##### Validation and reporting options - _$data_: support [$data references]([$data reference](#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). - _jsonPointers_: set `dataPath` propery of errors using [JSON Pointers](https://tools.ietf.org/html/rfc6901) instead of JavaScript property access notation. - _uniqueItems_: validate `uniqueItems` keyword (true by default). - _unicode_: calculate correct length of strings with unicode pairs (true by default). Pass `false` to use `.length` of strings that is faster, but gives "incorrect" lengths of strings with unicode pairs - each unicode pair is counted as two characters. - _format_: formats validation mode ('fast' by default). Pass 'full' for more correct and slow validation or `false` not to validate formats at all. 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. - _formats_: an object with custom formats. Keys and values will be passed to `addFormat` 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. - `"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. If the order is important, pass array. In this case schemas must have IDs in them. Otherwise the object can be passed - `addSchema(value, key)` will be called for each schema in this object. ##### Referenced schema options - _schemaId_: this option defines which keywords are used as schema URI. Option value: - `"$id"` (recommended) - only use `$id` keyword as schema URI (as specified in JSON-Schema draft-06), ignore `id` keyword (if it is present a warning will be logged). - `"id"` - only use `id` keyword as schema URI (as specified in JSON-Schema draft-04), ignore `$id` keyword (if it is present a warning will be logged). - `undefined` (default) - use both `$id` and `id` keywords as schema URI. If both are present (in the same schema object) and different the exception will be thrown during schema compilation. - _missingRefs_: handling of missing referenced schemas. Option values: - `true` (default) - if the reference cannot be resolved during compilation the exception is thrown. The thrown error has properties `missingRef` (with hash fragment) and `missingSchema` (without it). Both properties are resolved relative to the current base id (usually schema id, unless it was substituted). - `"ignore"` - to log error during compilation and always pass validation. - `"fail"` - to log error and successfully compile schema but fail validation if this rule is checked. - _extendRefs_: validation of other keywords when `$ref` is present in the schema. Option values: - `"ignore"` (default) - when `$ref` is used other keywords are ignored (as per [JSON Reference](https://tools.ietf.org/html/draft-pbryan-zyp-json-ref-03#section-3) standard). A warning will be logged during the schema compilation. - `"fail"` (recommended) - if other validation keywords are used together with `$ref` the exception will be thrown when the schema is compiled. This option is recomended to make sure schema has no keywords that are ignored, which can be confusing. - `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: - `false` (default) - not to remove additional properties - `"all"` - all additional properties are removed, regardless of `additionalProperties` keyword in schema (and no validation is made for them). - `true` - only additional properties with `additionalProperties` keyword equal to `false` are removed. - `"failing"` - additional properties that fail schema validation will be removed (where `additionalProperties` keyword is `false` or schema). - _useDefaults_: replace missing properties and items with the values from corresponding `default` keywords. Default behaviour is to ignore `default` keywords. This option is not used if schema is added with `addMetaSchema` method. See examples in [Assigning defaults](#assigning-defaults). Option values: - `false` (default) - do not use defaults - `true` - insert defaults by value (safer and slower, object literal is used). - `"shared"` - insert defaults by reference (faster). If the default is an object, it will be shared by all instances of validated data. If you modify the inserted default in the validated data, it will be modified in the schema as well. - _coerceTypes_: change data type of data to match `type` keyword. See the example in [Coercing data types](#coercing-data-types) and [coercion rules](https://github.com/epoberezkin/ajv/blob/master/COERCION.md). Option values: - `false` (default) - no type coercion. - `true` - coerce scalar data types. - `"array"` - in addition to coercions between scalar types, coerce scalar data to an array with one element and vice versa (as required by the schema). ##### Asynchronous validation options - _async_: determines how Ajv compiles asynchronous schemas (see [Asynchronous validation](#asynchronous-validation)) to functions. Option values: - `"*"` / `"co*"` (default) - compile to generator function ("co*" - wrapped with `co.wrap`). If generators are not supported and you don't provide `processCode` option (or `transpile` option if you use [ajv-async](https://github.com/epoberezkin/ajv-async) package), the exception will be thrown when async schema is compiled. - `"es7"` - compile to es7 async function. Unless your platform supports them you need to provide `processCode`/`transpile` option. According to [compatibility table](http://kangax.github.io/compat-table/es7/)) async functions are supported by: - Firefox 52, - Chrome 55, - Node.js 7 (with `--harmony-async-await`), - MS Edge 13 (with flag). - `undefined`/`true` - auto-detect async mode. It requires [ajv-async](https://github.com/epoberezkin/ajv-async) package. If transpile option is not passed ajv-async will choose the first of supported/installed async/transpile modes in this order: - "es7" (native async functions), - "co*" (native generators with co.wrap), - "es7"/"nodent", - "co*"/"regenerator" during the creation of the Ajv instance. If none of the options is available the exception will be thrown. - _transpile_: Requires [ajv-async](https://github.com/epoberezkin/ajv-async) package. It determines whether Ajv transpiles compiled asynchronous validation function. Option values: - `"nodent"` - transpile with [nodent](https://github.com/MatAtBread/nodent). If nodent is not installed, the exception will be thrown. nodent can only transpile es7 async functions; it will enforce this mode. - `"regenerator"` - transpile with [regenerator](https://github.com/facebook/regenerator). If regenerator is not installed, the exception will be thrown. - a function - this function should accept the code of validation function as a string and return transpiled code. This option allows you to use any other transpiler you prefer. If you are passing a function, you can simply pass it to `processCode` option without using ajv-async. ##### Advanced options - _meta_: add [meta-schema](http://json-schema.org/documentation.html) so it can be used by other schemas (true by default). If an object is passed, it will be used as the default meta-schema for schemas that have no `$schema` keyword. This default meta-schema MUST have `$schema` keyword. - _validateSchema_: validate added/compiled schemas against meta-schema (true by default). `$schema` property in the schema can either be http://json-schema.org/schema or http://json-schema.org/draft-04/schema or absent (draft-4 meta-schema will be used) or can be a reference to the schema previously added with `addMetaSchema` method. Option values: - `true` (default) - if the validation fails, throw the exception. - `"log"` - if the validation fails, log error. - `false` - skip schema validation. - _addUsedSchema_: by default methods `compile` and `validate` add schemas to the instance if they have `$id` (or `id`) property that doesn't start with "#". If `$id` is present and it is not unique the exception will be thrown. Set this option to `false` to skip adding schemas to the instance and the `$id` uniqueness check when these methods are used. This option does not affect `addSchema` method. - _inlineRefs_: Affects compilation of referenced schemas. Option values: - `true` (default) - the referenced schemas that don't have refs in them are inlined, regardless of their size - that substantially improves performance at the cost of the bigger size of compiled schema functions. - `false` - to not inline referenced schemas (they will be compiled as separate functions). - integer number - to limit the maximum number of keywords of the schema that will be inlined. - _passContext_: pass validation context to custom keyword functions. If this option is `true` and you pass some context to the compiled validation function with `validate.call(context, data)`, the `context` will be available as `this` in your custom keywords. By default `this` is Ajv instance. - _loopRequired_: by default `required` keyword is compiled into a single expression (or a sequence of statements in `allErrors` mode). In case of a very large number of properties in this keyword it may result in a very big validation function. Pass integer to set the number of properties above which `required` keyword will be validated in a loop - smaller validation function size but also worse performance. - _ownProperties_: by default Ajv iterates over all enumerable object properties; when this option is `true` only own enumerable object properties (i.e. found directly on the object rather than on its prototype) are iterated. Contributed by @mbroadst. - _multipleOfPrecision_: by default `multipleOf` keyword is validated by comparing the result of division with parseInt() of that result. It works for dividers that are bigger than 1. For small dividers such as 0.01 the result of the division is usually not integer (even when it should be integer, see issue [#84](https://github.com/epoberezkin/ajv/issues/84)). If you need to use fractional dividers set this option to some positive integer N to have `multipleOf` validated using this formula: `Math.abs(Math.round(division) - division) < 1e-N` (it is slower but allows for float arithmetics deviations). - _errorDataPath_: set `dataPath` to point to 'object' (default) or to 'property' when validating keywords `required`, `additionalProperties` and `dependencies`. - _messages_: Include human-readable messages in errors. `true` by default. `false` can be passed when custom messages are used (e.g. with [ajv-i18n](https://github.com/epoberezkin/ajv-i18n)). - _sourceCode_: add `sourceCode` property to validating function (for debugging; this code can be different from the result of toString call). - _processCode_: an optional function to process generated code before it is passed to Function constructor. It can be used to either beautify (the validating function is generated without line-breaks) or to transpile code. Starting from version 5.0.0 this option replaced options: - `beautify` that formatted the generated function using [js-beautify](https://github.com/beautify-web/js-beautify). If you want to beautify the generated code pass `require('js-beautify').js_beautify`. - `transpile` that transpiled asynchronous validation function. You can still use `transpile` option with [ajv-async](https://github.com/epoberezkin/ajv-async) package. See [Asynchronous validation](#asynchronous-validation) for more information. - _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 [json-stable-stringify](https://github.com/substack/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 in case `validate` or `validateSchema` methods were called). In case of [asynchronous validation](#asynchronous-validation) the returned promise is rejected with the exception of the class `Ajv.ValidationError` that has `.errors` poperty. ### Error objects Each error is an object with the following properties: - _keyword_: validation keyword. - _dataPath_: the path to the part of the data that was validated. By default `dataPath` uses JavaScript property access notation (e.g., `".prop[1].subProp"`). When the option `jsonPointers` is true (see [Options](#options)) `dataPath` will be set using JSON pointer standard (e.g., `"/prop/1/subProp"`). - _schemaPath_: the path (JSON-pointer as a URI fragment) to the schema of the keyword that failed validation. - _params_: the object with the additional information about error that can be used to create custom error messages (e.g., using [ajv-i18n](https://github.com/epoberezkin/ajv-i18n) package). See below for parameters set by all keywords. - _message_: the standard error message (can be excluded with option `messages` set to false). - _schema_: the schema of the keyword (added with `verbose` option). - _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"`. ### Error parameters Properties of `params` object in errors depend on the keyword that failed validation. - `maxItems`, `minItems`, `maxLength`, `minLength`, `maxProperties`, `minProperties` - property `limit` (number, the schema of the keyword). - `additionalItems` - property `limit` (the maximum number of allowed items in case when `items` keyword is an array of schemas and `additionalItems` is false). - `additionalProperties` - property `additionalProperty` (the property not used in `properties` and `patternProperties` keywords). - `dependencies` - properties: - `property` (dependent property), - `missingProperty` (required missing dependency - only the first one is reported currently) - `deps` (required dependencies, comma separated list as a string), - `depsCount` (the number of required dependedncies). - `format` - property `format` (the schema of the keyword). - `maximum`, `minimum` - properties: - `limit` (number, the schema of the keyword), - `exclusive` (boolean, the schema of `exclusiveMaximum` or `exclusiveMinimum`), - `comparison` (string, comparison operation to compare the data to the limit, with the data on the left and the limit on the right; can be "<", "<=", ">", ">=") - `multipleOf` - property `multipleOf` (the schema of the keyword) - `pattern` - property `pattern` (the schema of the keyword) - `required` - property `missingProperty` (required property that is missing). - `propertyNames` - property `propertyName` (an invalid property name). - `patternRequired` (in ajv-keywords) - property `missingPattern` (required pattern that did not match any property). - `type` - property `type` (required type(s), a string, can be a comma-separated list) - `uniqueItems` - properties `i` and `j` (indices of duplicate items). - `enum` - property `allowedValues` pointing to the array of values (the schema of the keyword). - `$ref` - property `ref` with the referenced schema URI. - custom keywords (in case keyword definition doesn't create errors) - property `keyword` (the keyword name). ## Related packages - [ajv-cli](https://github.com/epoberezkin/ajv-cli) - command line interface for Ajv - [ajv-i18n](https://github.com/epoberezkin/ajv-i18n) - internationalised error messages - [ajv-merge-patch](https://github.com/epoberezkin/ajv-merge-patch) - keywords $merge and $patch. - [ajv-keywords](https://github.com/epoberezkin/ajv-keywords) - several custom keywords that can be used with Ajv (typeof, instanceof, range, propertyNames) ## Some packages using Ajv - [webpack](https://github.com/webpack/webpack) - a module bundler. Its main purpose is to bundle JavaScript files for usage in a browser - [jsonscript-js](https://github.com/JSONScript/jsonscript-js) - the interpreter for [JSONScript](http://www.jsonscript.org) - scripted processing of existing endpoints and services - [osprey-method-handler](https://github.com/mulesoft-labs/osprey-method-handler) - Express middleware for validating requests and responses based on a RAML method object, used in [osprey](https://github.com/mulesoft/osprey) - validating API proxy generated from a RAML definition - [har-validator](https://github.com/ahmadnassri/har-validator) - HTTP Archive (HAR) validator - [jsoneditor](https://github.com/josdejong/jsoneditor) - a web-based tool to view, edit, format, and validate JSON http://jsoneditoronline.org - [JSON Schema Lint](https://github.com/nickcmaynard/jsonschemalint) - a web tool to validate JSON/YAML document against a single JSON-schema http://jsonschemalint.com - [objection](https://github.com/vincit/objection.js) - SQL-friendly ORM for node.js - [table](https://github.com/gajus/table) - formats data into a string table - [ripple-lib](https://github.com/ripple/ripple-lib) - a JavaScript API for interacting with [Ripple](https://ripple.com) in Node.js and the browser - [restbase](https://github.com/wikimedia/restbase) - distributed storage with REST API & dispatcher for backend services built to provide a low-latency & high-throughput API for Wikipedia / Wikimedia content - [hippie-swagger](https://github.com/CacheControl/hippie-swagger) - [Hippie](https://github.com/vesln/hippie) wrapper that provides end to end API testing with swagger validation - [react-form-controlled](https://github.com/seeden/react-form-controlled) - React controlled form components with validation - [rabbitmq-schema](https://github.com/tjmehta/rabbitmq-schema) - a schema definition module for RabbitMQ graphs and messages - [@query/schema](https://www.npmjs.com/package/@query/schema) - stream filtering with a URI-safe query syntax parsing to JSON Schema - [chai-ajv-json-schema](https://github.com/peon374/chai-ajv-json-schema) - chai plugin to us JSON-schema with expect in mocha tests - [grunt-jsonschema-ajv](https://github.com/SignpostMarv/grunt-jsonschema-ajv) - Grunt plugin for validating files against JSON-Schema - [extract-text-webpack-plugin](https://github.com/webpack-contrib/extract-text-webpack-plugin) - extract text from bundle into a file - [electron-builder](https://github.com/electron-userland/electron-builder) - a solution to package and build a ready for distribution Electron app - [addons-linter](https://github.com/mozilla/addons-linter) - Mozilla Add-ons Linter - [gh-pages-generator](https://github.com/epoberezkin/gh-pages-generator) - multi-page site generator converting markdown files to GitHub pages ## Tests ``` npm install git submodule update --init npm test ``` ## Contributing All validation functions are generated using doT templates in [dot](https://github.com/epoberezkin/ajv/tree/master/lib/dot) folder. Templates are precompiled so doT is not a run-time dependency. `npm run build` - compiles templates to [dotjs](https://github.com/epoberezkin/ajv/tree/master/lib/dotjs) folder. `npm run watch` - automatically compiles templates when files in dot folder change Please see [Contributing guidelines](https://github.com/epoberezkin/ajv/blob/master/CONTRIBUTING.md) ## Changes history See https://github.com/epoberezkin/ajv/releases __Please note__: [Changes in version 5.0.0](https://github.com/epoberezkin/ajv/releases/tag/5.0.0). [Changes in version 4.6.0](https://github.com/epoberezkin/ajv/releases/tag/4.6.0). [Changes in version 4.0.0](https://github.com/epoberezkin/ajv/releases/tag/4.0.0). [Changes in version 3.0.0](https://github.com/epoberezkin/ajv/releases/tag/3.0.0). [Changes in version 2.0.0](https://github.com/epoberezkin/ajv/releases/tag/2.0.0). ## License [MIT](https://github.com/epoberezkin/ajv/blob/master/LICENSE) ajv-5.0.0/bower.json000066400000000000000000000006341307514663700143240ustar00rootroot00000000000000{ "name": "ajv", "description": "Another JSON Schema Validator", "main": "dist/ajv.min.js", "authors": [ "Evgeny Poberezkin" ], "license": "MIT", "keywords": [ "JSON", "schema", "validator" ], "homepage": "https://github.com/epoberezkin/ajv", "moduleType": [ "amd", "globals", "node" ], "ignore": [ "node_modules", "bower_components", "spec" ] } ajv-5.0.0/circle.yml000066400000000000000000000012031307514663700142700ustar00rootroot00000000000000machine: node: version: 4 general: branches: ignore: - gh-pages checkout: post: - git submodule sync - git submodule update --init dependencies: post: - wget https://saucelabs.com/downloads/sc-latest-linux.tar.gz - tar -xzf sc-latest-linux.tar.gz test: override: - cd sc-*-linux && ./bin/sc --user $SAUCE_USERNAME --api-key $SAUCE_ACCESS_KEY --readyfile ~/sauce_is_ready: background: true - while [ ! -e ~/sauce_is_ready ]; do sleep 1; done - scripts/prepare-tests - karma start karma.sauce.js post: - killall --wait sc # wait for Sauce Connect to close the tunnel ajv-5.0.0/karma.conf.js000066400000000000000000000031411307514663700146640ustar00rootroot00000000000000// Karma configuration // Generated on Thu Mar 13 2014 14:12:04 GMT-0700 (PDT) module.exports = function(config) { config.set({ // base path that will be used to resolve all patterns (eg. files, exclude) basePath: '', // frameworks to use // available frameworks: https://npmjs.org/browse/keyword/karma-adapter frameworks: ['mocha'], // list of files / patterns to load in the browser files: [ 'dist/ajv.min.js', 'node_modules/chai/chai.js', 'dist/regenerator.min.js', 'dist/nodent.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'], // 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 // - Firefox // - Opera // - Safari (only Mac) // - PhantomJS // - IE (only Windows) browsers: ['Chrome'], // Continuous Integration mode // if true, Karma captures browsers, runs the tests and exits singleRun: true, browserNoActivityTimeout: 90000 }); }; ajv-5.0.0/karma.sauce.js000066400000000000000000000070631307514663700150460ustar00rootroot00000000000000'use strict'; 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); } else { 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_37': { // base: 'SauceLabs', // browserName: 'chrome', // version: '37' // }, 'SL_Chrome': { base: 'SauceLabs', browserName: 'chrome' }, 'SL_InternetExplorer_9': { base: 'SauceLabs', browserName: 'internet explorer', version: '9' }, 'SL_InternetExplorer_10': { base: 'SauceLabs', browserName: 'internet explorer', version: '10' }, 'SL_InternetExplorer_11': { base: 'SauceLabs', browserName: 'internet explorer', version: '11' // default }, 'SL_MicrosoftEdge': { base: 'SauceLabs', browserName: 'MicrosoftEdge' }, 'SL_FireFox_17': { base: 'SauceLabs', browserName: 'firefox', version: '17' }, // 'SL_FireFox_24': { // base: 'SauceLabs', // browserName: 'firefox', // version: '24' // }, 'SL_FireFox': { base: 'SauceLabs', browserName: 'firefox' }, 'SL_Safari_5': { base: 'SauceLabs', browserName: 'safari', version: '5' // default }, // 'SL_Safari_7': { // base: 'SauceLabs', // browserName: 'safari', // version: '7' // }, 'SL_Safari_9': { base: 'SauceLabs', browserName: 'safari', version: '9' }, 'SL_iPhone_8': { base: 'SauceLabs', browserName: 'iphone', version: '8.4' }, 'SL_iPhone_9': { base: 'SauceLabs', browserName: 'iphone', version: '9.2' } // 'SL_Android_4': { // base: 'SauceLabs', // browserName: 'android', // version: '4' // } }; config.set({ // base path that will be used to resolve all patterns (eg. files, exclude) basePath: '', // frameworks to use // available frameworks: https://npmjs.org/browse/keyword/karma-adapter frameworks: ['mocha'], // list of files / patterns to load in the browser files: [ 'dist/ajv.min.js', 'node_modules/chai/chai.js', 'dist/nodent.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'], // web server port port: 9876, 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, sauceLabs: { testName: 'Ajv', 'idleTimeout': 900 }, captureTimeout: 1200000, browserNoActivityTimeout: 600000, browserDisconnectTimeout: 60000, customLaunchers: customLaunchers, // start these browsers // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher browsers: Object.keys(customLaunchers), singleRun: true }); }; ajv-5.0.0/lib/000077500000000000000000000000001307514663700130565ustar00rootroot00000000000000ajv-5.0.0/lib/$data.js000066400000000000000000000020271307514663700143720ustar00rootroot00000000000000'use strict'; var KEYWORDS = [ 'multipleOf', 'maximum', 'exclusiveMaximum', 'minimum', 'exclusiveMinimum', 'maxLength', 'minLength', 'pattern', 'additionalItems', 'maxItems', 'minItems', 'uniqueItems', 'maxProperties', 'minProperties', 'required', 'additionalProperties', 'enum', 'format', 'const' ]; module.exports = function (metaSchema, keywordsJsonPointers) { for (var i=0; i; /** * 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 {Thenable} validating function */ compileAsync(schema: Object | boolean, meta?: Boolean, callback?: (err: Error, validate: ValidateFunction) => any): Thenable; /** * 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`. */ addSchema(schema: Array | Object, key?: string): void; /** * 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 */ addMetaSchema(schema: Object, key?: string): void; /** * 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`). */ getSchema(keyRef: string): ValidateFunction; /** * 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 */ removeSchema(schemaKeyRef?: Object | string | RegExp | boolean): void; /** * 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) */ addFormat(name: string, format: FormatValidator | FormatDefinition): void; /** * 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`. */ addKeyword(keyword: string, definition: KeywordDefinition): void; /** * 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. */ removeKeyword(keyword: string): void; /** * 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, options?: ErrorsTextOptions): string; errors?: Array; } interface Thenable { then (onFulfilled?: (value: R) => U | Thenable, onRejected?: (error: any) => U | Thenable): Thenable; } interface ValidateFunction { ( data: any, dataPath?: string, parentData?: Object | Array, parentDataProperty?: string | number, rootData?: Object | Array ): boolean | Thenable; errors?: Array; schema?: Object | boolean; } interface Options { $data?: boolean; allErrors?: boolean; verbose?: boolean; jsonPointers?: boolean; uniqueItems?: boolean; unicode?: boolean; format?: string; formats?: Object; unknownFormats?: true | string[] | 'ignore'; schemas?: Array | Object; schemaId?: '$id' | 'id'; missingRefs?: true | 'ignore' | 'fail'; extendRefs?: true | 'ignore' | 'fail'; loadSchema?: (uri: string, cb?: (err: Error, schema: Object) => void) => Thenable; removeAdditional?: boolean | 'all' | 'failing'; useDefaults?: boolean | 'shared'; coerceTypes?: boolean | 'array'; 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) => string; cache?: Object; } type FormatValidator = string | RegExp | ((data: string) => boolean); interface FormatDefinition { validate: FormatValidator; compare: (data1: string, data2: string) => number; async?: boolean; } interface KeywordDefinition { type?: string | Array; async?: boolean; $data?: boolean; errors?: boolean | string; metaSchema?: Object; // schema: false makes validate not to expect schema (ValidateFunction) schema?: boolean; modifying?: boolean; valid?: boolean; // one and only one of the following properties should be present validate?: SchemaValidateFunction | ValidateFunction; compile?: (schema: any, parentSchema: Object) => ValidateFunction; macro?: (schema: any, parentSchema: Object) => Object | boolean; inline?: (it: Object, keyword: string, schema: any, parentSchema: Object) => string; } interface SchemaValidateFunction { ( schema: any, data: any, parentSchema?: Object, dataPath?: string, parentData?: Object | Array, parentDataProperty?: string | number, rootData?: Object | Array ): boolean | Thenable; errors?: Array; } interface ErrorsTextOptions { separator?: string; dataVar?: string; } interface ErrorObject { keyword: string; dataPath: string; schemaPath: string; params: ErrorParameters; // Added to validation errors of propertyNames keyword schema propertyName?: string; // Excluded if messages set to false. message?: string; // These are added with the `verbose` option. schema?: any; parentSchema?: Object; data?: any; } type ErrorParameters = RefParams | LimitParams | AdditionalPropertiesParams | DependenciesParams | FormatParams | ComparisonParams | MultipleOfParams | PatternParams | RequiredParams | TypeParams | UniqueItemsParams | CustomParams | PatternGroupsParams | PatternRequiredParams | PropertyNamesParams | SwitchParams | NoParams | EnumParams; interface RefParams { ref: string; } interface LimitParams { limit: number; } interface AdditionalPropertiesParams { additionalProperty: string; } interface DependenciesParams { property: string; missingProperty: string; depsCount: number; deps: string; } interface FormatParams { format: string } interface ComparisonParams { comparison: string; limit: number | string; exclusive: boolean; } interface MultipleOfParams { multipleOf: number; } interface PatternParams { pattern: string; } interface RequiredParams { missingProperty: string; } interface TypeParams { type: string; } interface UniqueItemsParams { i: number; j: number; } interface CustomParams { keyword: string; } interface PatternGroupsParams { reason: string; limit: number; pattern: string; } interface PatternRequiredParams { missingPattern: string; } interface PropertyNamesParams { propertyName: string; } interface SwitchParams { caseIndex: number; } interface NoParams {} interface EnumParams { allowedValues: Array; } } export = ajv; ajv-5.0.0/lib/ajv.js000066400000000000000000000355001307514663700141770ustar00rootroot00000000000000'use strict'; var compileSchema = require('./compile') , resolve = require('./compile/resolve') , Cache = require('./cache') , SchemaObject = require('./compile/schema_obj') , stableStringify = require('json-stable-stringify') , formats = require('./compile/formats') , rules = require('./compile/rules') , $dataMetaSchema = require('./$data') , patternGroups = require('./patternGroups') , util = require('./compile/util') , co = require('co'); 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; 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-06/schema'; var META_IGNORE_OPTIONS = [ 'removeAdditional', 'useDefaults', 'coerceTypes' ]; var META_SUPPORT_DATA = ['/properties']; /** * Creates validator instance. * Usage: `Ajv(opts)` * @param {Object} opts optional options * @return {Object} ajv instance */ function Ajv(opts) { if (!(this instanceof Ajv)) return new Ajv(opts); opts = this._opts = util.copy(opts) || {}; this._schemas = {}; this._refs = {}; this._fragments = {}; this._formats = formats(opts.format); var schemaUriFormat = this._schemaUriFormat = this._formats['uri-reference']; this._schemaUriFormatFunc = function (str) { return schemaUriFormat.test(str); }; 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); addDraft6MetaSchema(this); if (typeof opts.meta == 'object') this.addMetaSchema(opts.meta); addInitialSchemas(this); if (opts.patternGroups) patternGroups(this); } /** * Validate data using schema * Schema will be compiled and cached (using serialized JSON as key. [json-stable-stringify](https://github.com/substack/json-stable-stringify) is used to serialize. * @this Ajv * @param {String|Object} 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`). */ 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 + '"'); } else { var schemaObj = this._addSchema(schemaKeyRef); v = schemaObj.validate || this._compile(schemaObj); } var valid = v(data); if (v.$async === true) return this._opts.async == '*' ? co(valid) : valid; this.errors = v.errors; return valid; } /** * Create validating function for passed schema. * @this Ajv * @param {Object} schema schema object * @param {Boolean} _meta true if schema is a meta-schema. Used internally to compile meta schemas of custom keywords. * @return {Function} validating function */ function compile(schema, _meta) { var schemaObj = this._addSchema(schema, undefined, _meta); return schemaObj.validate || this._compile(schemaObj); } /** * Adds schema to the instance. * @this Ajv * @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`. * @param {Boolean} _skipValidation true to skip schema validation. Used internally, option validateSchema should be used instead. * @param {Boolean} _meta true if schema is a meta-schema. Used internally, addMetaSchema should be used instead. */ function addSchema(schema, key, _skipValidation, _meta) { if (Array.isArray(schema)){ for (var i=0; i} 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 */ function errorsText(errors, options) { errors = errors || this.errors; if (!errors) return 'No errors'; options = options || {}; var separator = options.separator === undefined ? ', ' : options.separator; var dataVar = options.dataVar === undefined ? 'data' : options.dataVar; var text = ''; 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)*)*$|^\#(?:\/(?:[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(?:\.\d+)?(?:z|[+-]\d\d:\d\d)?$/i, 'date-time': /^\d\d\d\d-[0-1]\d-[0-3]\d[t\s][0-2]\d:[0-5]\d:[0-5]\d(?:\.\d+)?(?:z|[+-]\d\d:\d\d)$/i, // uri: https://github.com/mafintosh/is-my-json-valid/blob/master/formats.js uri: /^(?:[a-z][a-z0-9+-.]*)(?:\:|\/)\/?[^\s]*$/i, 'uri-reference': /^(?:(?:[a-z][a-z0-9+-.]*:)?\/\/)?[^\s]*$/i, 'uri-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, // 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, 'relative-json-pointer': RELATIVE_JSON_POINTER }; function date(str) { // full-date from http://tools.ietf.org/html/rfc3339#section-5.6 var matches = str.match(DATE); if (!matches) return false; var month = +matches[1]; var day = +matches[2]; return month >= 1 && month <= 12 && day >= 1 && day <= DAYS[month]; } 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 && (!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); } function hostname(str) { // https://tools.ietf.org/html/rfc1034#section-3.5 // https://tools.ietf.org/html/rfc1123#section-2 return str.length <= 255 && HOSTNAME.test(str); } 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; } } ajv-5.0.0/lib/compile/index.js000066400000000000000000000237071307514663700161640ustar00rootroot00000000000000'use strict'; var resolve = require('./resolve') , util = require('./util') , errorClasses = require('./error_classes') , stableStringify = require('json-stable-stringify'); var validateGenerator = require('../dotjs/validate'); /** * Functions below are used inside compiled validations function */ var co = require('co'); var ucs2length = util.ucs2length; var equal = require('./equal'); // this error is thrown by async schemas to return validation errors via exception var ValidationError = errorClasses.Validation; module.exports = compile; /** * Compiles schema to validation function * @this Ajv * @param {Object} schema schema object * @param {Object} root object with information about the root schema for this schema * @param {Object} localRefs the hash of local references inside the schema (created by resolve.id), used for inline resolution * @param {String} baseId base ID for IDs in the schema * @return {Function} validation function */ 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 = []; 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 formats = this._formats; var RULES = this.RULES; try { 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; } return v; } finally { endCompiling.call(this, schema, root, baseId); } function callValidate() { var validate = compilation.validate; var result = validate.apply(null, arguments); callValidate.errors = validate.errors; return result; } function localCompile(_schema, _root, localRefs, baseId) { var isRoot = !_root || (_root && _root.schema == _schema); if (_root.schema != root.schema) return compile.call(self, _schema, _root, localRefs, baseId); var $async = _schema.$async === true; var sourceCode = validateGenerator({ isTop: true, schema: _schema, isRoot: isRoot, baseId: baseId, root: _root, schemaPath: '', errSchemaPath: '#', errorPath: '""', MissingRefError: errorClasses.MissingRef, RULES: RULES, validate: validateGenerator, util: util, resolve: resolve, resolveRef: resolveRef, usePattern: usePattern, useDefault: useDefault, useCustomRule: useCustomRule, opts: opts, formats: formats, self: self }); sourceCode = vars(refVal, refValCode) + vars(patterns, patternCode) + vars(defaults, defaultCode) + vars(customRules, customRuleCode) + sourceCode; if (opts.processCode) sourceCode = opts.processCode(sourceCode); // console.log('\n\n\n *** \n', JSON.stringify(sourceCode)); var validate; try { var makeValidate = new Function( 'self', 'RULES', 'formats', 'root', 'refVal', 'defaults', 'customRules', 'co', 'equal', 'ucs2length', 'ValidationError', sourceCode ); validate = makeValidate( self, RULES, formats, root, refVal, defaults, customRules, co, equal, ucs2length, ValidationError ); refVal[0] = validate; } catch(e) { console.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; if (opts.sourceCode === true) { validate.source = { code: sourceCode, patterns: patterns, defaults: defaults }; } return validate; } function resolveRef(baseId, ref, isRoot) { 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); } if (!isRoot && root.refs) { var rootRefId = root.refs[ref]; if (rootRefId !== undefined) { _refVal = root.refVal[rootRefId]; refCode = addLocalRef(ref, _refVal); return resolvedRef(_refVal, refCode); } } refCode = addLocalRef(ref); var v = resolve.call(self, localCompile, root, ref); if (v === undefined) { var localSchema = localRefs && localRefs[ref]; if (localSchema) { v = resolve.inlineRef(localSchema, opts.inlineRefs) ? localSchema : compile.call(self, localSchema, root, localRefs, baseId); } } if (v !== undefined) { replaceLocalRef(ref, v); return resolvedRef(v, refCode); } } function addLocalRef(ref, v) { var refId = refVal.length; refVal[refId] = v; refs[ref] = refId; return 'refVal' + refId; } function replaceLocalRef(ref, 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 }; } function usePattern(regexStr) { var index = patternsHash[regexStr]; if (index === undefined) { index = patternsHash[regexStr] = patterns.length; patterns[index] = regexStr; } 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]; if (index === undefined) { index = defaultsHash[valueStr] = defaults.length; defaults[index] = value; } return 'default' + index; } } function useCustomRule(rule, schema, parentSchema, it) { var validateSchema = rule.definition.validateSchema; if (validateSchema && self._opts.validateSchema !== false) { var valid = validateSchema(schema); if (!valid) { var message = 'keyword schema is invalid: ' + self.errorsText(validateSchema.errors); if (self._opts.validateSchema == 'log') console.error(message); else throw new Error(message); } } var compile = rule.definition.compile , inline = rule.definition.inline , macro = rule.definition.macro; var validate; if (compile) { 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); } else if (inline) { validate = inline.call(self, it, rule.keyword, schema, parentSchema); } else { validate = rule.definition.validate; if (!validate) return; } if (validate === undefined) throw new Error('custom keyword "' + rule.keyword + '"failed to compile'); var index = customRules.length; customRules[index] = validate; return { code: 'customRule' + index, validate: validate }; } } /** * Checks if the schema is currently compiled * @this Ajv * @param {Object} schema schema to compile * @param {Object} root root object * @param {String} baseId base schema ID * @return {Object} object with properties "index" (compilation index) and "compiling" (boolean) */ 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; this._compilations[index] = { schema: schema, root: root, baseId: baseId }; return { index: index, compiling: false }; } /** * Removes the schema from the currently compiled list * @this Ajv * @param {Object} schema schema to compile * @param {Object} root root object * @param {String} baseId base schema ID */ function endCompiling(schema, root, baseId) { /* jshint validthis: true */ 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 * @param {Object} schema schema to compile * @param {Object} root root object * @param {String} baseId base schema ID * @return {Integer} compilation index */ function compIndex(schema, root, baseId) { /* jshint validthis: true */ for (var i=0; i= 0xD800 && value <= 0xDBFF && pos < len) { // high surrogate, and there is a next character value = str.charCodeAt(pos); if ((value & 0xFC00) == 0xDC00) pos++; // low surrogate } } return length; }; ajv-5.0.0/lib/compile/util.js000066400000000000000000000172071307514663700160300ustar00rootroot00000000000000'use strict'; module.exports = { copy: copy, checkDataType: checkDataType, checkDataTypes: checkDataTypes, coerceToTypes: coerceToTypes, toHash: toHash, getProperty: getProperty, escapeQuotes: escapeQuotes, ucs2length: require('./ucs2length'), varOccurences: varOccurences, varReplace: varReplace, cleanUpCode: cleanUpCode, finalCleanUpCode: finalCleanUpCode, schemaHasRules: schemaHasRules, schemaHasRulesExcept: schemaHasRulesExcept, toQuotedString: toQuotedString, getPathExpr: getPathExpr, getPath: getPath, getData: getData, unescapeFragment: unescapeFragment, escapeFragment: escapeFragment, escapeJsonPointer: escapeJsonPointer }; function copy(o, to) { to = to || {}; for (var key in o) to[key] = o[key]; return to; } function checkDataType(dataType, data, 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 + ')'; default: return 'typeof ' + data + EQUAL + '"' + dataType + '"'; } } function checkDataTypes(dataTypes, data) { switch (dataTypes.length) { case 1: return checkDataType(dataTypes[0], data, true); default: 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; } if (types.number) delete types.integer; for (var t in types) code += (code ? ' && ' : '' ) + checkDataType(t, data, true); return code; } } 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]; } 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' , $notOp = $isMax ? '>' : '<'; }} {{? $isDataExcl }} {{ var $schemaValueExcl = it.util.getData($schemaExcl.$data, $dataLvl, it.dataPathArr) , $exclusive = 'exclusive' + $lvl , $exclType = 'exclType' + $lvl , $exclIsNumber = 'exclIsNumber' + $lvl , $opExpr = 'op' + $lvl , $opStr = '\' + ' + $opExpr + ' + \''; }} var schemaExcl{{=$lvl}} = {{=$schemaValueExcl}}; {{ $schemaValueExcl = 'schemaExcl' + $lvl; }} var {{=$exclusive}}; var {{=$exclType}} = typeof {{=$schemaValueExcl}}; if ({{=$exclType}} != 'boolean' && {{=$exclType}} != 'undefined' && {{=$exclType}} != 'number') { {{ var $errorKeyword = $exclusiveKeyword; }} {{# def.error:'_exclusiveLimit' }} } else if ({{# def.$dataNotType:'number' }} {{=$exclType}} == 'number' ? ( ({{=$exclusive}} = {{=$schemaValue}} === undefined || {{=$schemaValueExcl}} {{=$op}}= {{=$schemaValue}}) ? {{=$data}} {{=$notOp}}= {{=$schemaValueExcl}} : {{=$data}} {{=$notOp}} {{=$schemaValue}} ) : ( ({{=$exclusive}} = {{=$schemaValueExcl}} === true) ? {{=$data}} {{=$notOp}}= {{=$schemaValue}} : {{=$data}} {{=$notOp}} {{=$schemaValue}} ) || {{=$data}} !== {{=$data}}) { var op{{=$lvl}} = {{=$exclusive}} ? '{{=$op}}' : '{{=$op}}='; {{??}} {{ var $exclIsNumber = typeof $schemaExcl == 'number' , $opStr = $op; /*used in error*/ }} {{? $exclIsNumber && $isData }} {{ var $opExpr = '\'' + $opStr + '\''; /*used in error*/ }} if ({{# def.$dataNotType:'number' }} ( {{=$schemaValue}} === undefined || {{=$schemaExcl}} {{=$op}}= {{=$schemaValue}} ? {{=$data}} {{=$notOp}}= {{=$schemaExcl}} : {{=$data}} {{=$notOp}} {{=$schemaValue}} ) || {{=$data}} !== {{=$data}}) { {{??}} {{ if ($exclIsNumber && $schema === undefined) { $schemaValue = $schemaExcl; $notOp += '='; } else { if ($exclIsNumber) $schemaValue = Math[$isMax ? 'min' : 'max']($schemaExcl, $schema); if ($schemaExcl === ($exclIsNumber ? $schemaValue : true)) $notOp += '='; else $opStr += '='; } var $opExpr = '\'' + $opStr + '\''; /*used in error*/ }} if ({{# def.$dataNotType:'number' }} {{=$data}} {{=$notOp}} {{=$schemaValue}} || {{=$data}} !== {{=$data}}) { {{?}} {{?}} {{ var $errorKeyword = $keyword; }} {{# def.error:'_limit' }} } {{? $breakOnError }} else { {{?}} ajv-5.0.0/lib/dot/_limitItems.jst000066400000000000000000000005071307514663700166470ustar00rootroot00000000000000{{# def.definitions }} {{# def.errors }} {{# def.setupKeyword }} {{# def.$data }} {{ var $op = $keyword == 'maxItems' ? '>' : '<'; }} if ({{# def.$dataNotType:'number' }} {{=$data}}.length {{=$op}} {{=$schemaValue}}) { {{ var $errorKeyword = $keyword; }} {{# def.error:'_limitItems' }} } {{? $breakOnError }} else { {{?}} ajv-5.0.0/lib/dot/_limitLength.jst000066400000000000000000000005141307514663700170050ustar00rootroot00000000000000{{# def.definitions }} {{# def.errors }} {{# def.setupKeyword }} {{# def.$data }} {{ var $op = $keyword == 'maxLength' ? '>' : '<'; }} if ({{# def.$dataNotType:'number' }} {{# def.strLength }} {{=$op}} {{=$schemaValue}}) { {{ var $errorKeyword = $keyword; }} {{# def.error:'_limitLength' }} } {{? $breakOnError }} else { {{?}} ajv-5.0.0/lib/dot/_limitProperties.jst000066400000000000000000000005361307514663700177240ustar00rootroot00000000000000{{# def.definitions }} {{# def.errors }} {{# def.setupKeyword }} {{# def.$data }} {{ var $op = $keyword == 'maxProperties' ? '>' : '<'; }} if ({{# def.$dataNotType:'number' }} Object.keys({{=$data}}).length {{=$op}} {{=$schemaValue}}) { {{ var $errorKeyword = $keyword; }} {{# def.error:'_limitProperties' }} } {{? $breakOnError }} else { {{?}} ajv-5.0.0/lib/dot/allOf.jst000066400000000000000000000011651307514663700154260ustar00rootroot00000000000000{{# def.definitions }} {{# def.errors }} {{# def.setupKeyword }} {{# def.setupNextLevel }} {{ var $currentBaseId = $it.baseId , $allSchemasEmpty = true; }} {{~ $schema:$sch:$i }} {{? {{# def.nonEmptySchema:$sch }} }} {{ $allSchemasEmpty = false; $it.schema = $sch; $it.schemaPath = $schemaPath + '[' + $i + ']'; $it.errSchemaPath = $errSchemaPath + '/' + $i; }} {{# def.insertSubschemaCode }} {{# def.ifResultValid }} {{?}} {{~}} {{? $breakOnError }} {{? $allSchemasEmpty }} if (true) { {{??}} {{= $closingBraces.slice(0,-1) }} {{?}} {{?}} {{# def.cleanUp }} ajv-5.0.0/lib/dot/anyOf.jst000066400000000000000000000016571307514663700154530ustar00rootroot00000000000000{{# def.definitions }} {{# def.errors }} {{# def.setupKeyword }} {{# def.setupNextLevel }} {{ var $noEmptySchema = $schema.every(function($sch) { return {{# def.nonEmptySchema:$sch }}; }); }} {{? $noEmptySchema }} {{ var $currentBaseId = $it.baseId; }} var {{=$errs}} = errors; var {{=$valid}} = false; {{# def.setCompositeRule }} {{~ $schema:$sch:$i }} {{ $it.schema = $sch; $it.schemaPath = $schemaPath + '[' + $i + ']'; $it.errSchemaPath = $errSchemaPath + '/' + $i; }} {{# def.insertSubschemaCode }} {{=$valid}} = {{=$valid}} || {{=$nextValid}}; if (!{{=$valid}}) { {{ $closingBraces += '}'; }} {{~}} {{# def.resetCompositeRule }} {{= $closingBraces }} if (!{{=$valid}}) { {{# def.extraError:'anyOf' }} } else { {{# def.resetErrors }} {{? it.opts.allErrors }} } {{?}} {{# def.cleanUp }} {{??}} {{? $breakOnError }} if (true) { {{?}} {{?}} ajv-5.0.0/lib/dot/coerce.def000066400000000000000000000042551307514663700155720ustar00rootroot00000000000000{{## def.coerceType: {{ var $dataType = 'dataType' + $lvl , $coerced = 'coerced' + $lvl; }} var {{=$dataType}} = typeof {{=$data}}; {{? it.opts.coerceTypes == 'array'}} if ({{=$dataType}} == 'object' && Array.isArray({{=$data}})) {{=$dataType}} = 'array'; {{?}} var {{=$coerced}} = undefined; {{ var $bracesCoercion = ''; }} {{~ $coerceToTypes:$type:$i }} {{? $i }} if ({{=$coerced}} === undefined) { {{ $bracesCoercion += '}'; }} {{?}} {{? it.opts.coerceTypes == 'array' && $type != 'array' }} if ({{=$dataType}} == 'array' && {{=$data}}.length == 1) { {{=$coerced}} = {{=$data}} = {{=$data}}[0]; {{=$dataType}} = typeof {{=$data}}; /*if ({{=$dataType}} == 'object' && Array.isArray({{=$data}})) {{=$dataType}} = 'array';*/ } {{?}} {{? $type == 'string' }} if ({{=$dataType}} == 'number' || {{=$dataType}} == 'boolean') {{=$coerced}} = '' + {{=$data}}; else if ({{=$data}} === null) {{=$coerced}} = ''; {{?? $type == 'number' || $type == 'integer' }} if ({{=$dataType}} == 'boolean' || {{=$data}} === null || ({{=$dataType}} == 'string' && {{=$data}} && {{=$data}} == +{{=$data}} {{? $type == 'integer' }} && !({{=$data}} % 1){{?}})) {{=$coerced}} = +{{=$data}}; {{?? $type == 'boolean' }} if ({{=$data}} === 'false' || {{=$data}} === 0 || {{=$data}} === null) {{=$coerced}} = false; else if ({{=$data}} === 'true' || {{=$data}} === 1) {{=$coerced}} = true; {{?? $type == 'null' }} if ({{=$data}} === '' || {{=$data}} === 0 || {{=$data}} === false) {{=$coerced}} = null; {{?? it.opts.coerceTypes == 'array' && $type == 'array' }} if ({{=$dataType}} == 'string' || {{=$dataType}} == 'number' || {{=$dataType}} == 'boolean' || {{=$data}} == null) {{=$coerced}} = [{{=$data}}]; {{?}} {{~}} {{= $bracesCoercion }} if ({{=$coerced}} === undefined) { {{# def.error:'type' }} } else { {{# def.setParentData }} {{=$data}} = {{=$coerced}}; {{? !$dataLvl }}if ({{=$parentData}} !== undefined){{?}} {{=$parentData}}[{{=$parentDataProperty}}] = {{=$coerced}}; } #}} ajv-5.0.0/lib/dot/const.jst000066400000000000000000000004301307514663700155110ustar00rootroot00000000000000{{# def.definitions }} {{# def.errors }} {{# def.setupKeyword }} {{# def.$data }} {{? !$isData }} var schema{{=$lvl}} = validate.schema{{=$schemaPath}}; {{?}} var {{=$valid}} = equal({{=$data}}, schema{{=$lvl}}); {{# def.checkError:'const' }} {{? $breakOnError }} else { {{?}} ajv-5.0.0/lib/dot/contains.jst000066400000000000000000000022301307514663700162010ustar00rootroot00000000000000{{# def.definitions }} {{# def.errors }} {{# def.setupKeyword }} {{# def.setupNextLevel }} {{ var $idx = 'i' + $lvl , $dataNxt = $it.dataLevel = it.dataLevel + 1 , $nextData = 'data' + $dataNxt , $currentBaseId = it.baseId , $nonEmptySchema = {{# def.nonEmptySchema:$schema }}; }} var {{=$errs}} = errors; var {{=$valid}}; {{? $nonEmptySchema }} {{# def.setCompositeRule }} {{ $it.schema = $schema; $it.schemaPath = $schemaPath; $it.errSchemaPath = $errSchemaPath; }} for (var {{=$idx}} = 0; {{=$idx}} < {{=$data}}.length; {{=$idx}}++) { {{ $it.errorPath = it.util.getPathExpr(it.errorPath, $idx, it.opts.jsonPointers, true); var $passData = $data + '[' + $idx + ']'; $it.dataPathArr[$dataNxt] = $idx; }} {{# def.generateSubschemaCode }} {{# def.optimizeValidate }} if ({{=$nextValid}}) break; } {{# def.resetCompositeRule }} {{= $closingBraces }} if (!{{=$nextValid}}) { {{??}} if ({{=$data}}.length == 0) { {{?}} {{# def.error:'contains' }} } else { {{? $nonEmptySchema }} {{# def.resetErrors }} {{?}} {{? it.opts.allErrors }} } {{?}} {{# def.cleanUp }} ajv-5.0.0/lib/dot/custom.jst000066400000000000000000000115511307514663700157030ustar00rootroot00000000000000{{# def.definitions }} {{# def.errors }} {{# def.setupKeyword }} {{# def.$data }} {{ var $rule = this , $definition = 'definition' + $lvl , $rDef = $rule.definition , $closingBraces = ''; var $validate = $rDef.validate; var $compile, $inline, $macro, $ruleValidate, $validateCode; }} {{? $isData && $rDef.$data }} {{ $validateCode = 'keywordValidate' + $lvl; var $validateSchema = $rDef.validateSchema; }} var {{=$definition}} = RULES.custom['{{=$keyword}}'].definition; var {{=$validateCode}} = {{=$definition}}.validate; {{??}} {{ $ruleValidate = it.useCustomRule($rule, $schema, it.schema, it); if (!$ruleValidate) return; $schemaValue = 'validate.schema' + $schemaPath; $validateCode = $ruleValidate.code; $compile = $rDef.compile; $inline = $rDef.inline; $macro = $rDef.macro; }} {{?}} {{ var $ruleErrs = $validateCode + '.errors' , $i = 'i' + $lvl , $ruleErr = 'ruleErr' + $lvl , $asyncKeyword = $rDef.async; if ($asyncKeyword && !it.async) throw new Error('async keyword in sync schema'); }} {{? !($inline || $macro) }}{{=$ruleErrs}} = null;{{?}} var {{=$errs}} = errors; var {{=$valid}}; {{## def.callRuleValidate: {{=$validateCode}}.call( {{? it.opts.passContext }}this{{??}}self{{?}} {{? $compile || $rDef.schema === false }} , {{=$data}} {{??}} , {{=$schemaValue}} , {{=$data}} , validate.schema{{=it.schemaPath}} {{?}} , {{# def.dataPath }} {{# def.passParentData }} , rootData ) #}} {{## def.extendErrors:_inline: for (var {{=$i}}={{=$errs}}; {{=$i}}= 0 }} {{# def.skipFormat }} {{??}} {{ throw new Error('unknown format "' + $schema + '" is used in schema at path "' + it.errSchemaPath + '"'); }} {{?}} {{?}} {{ var $isObject = typeof $format == 'object' && !($format instanceof RegExp) && $format.validate; var $formatType = $isObject && $format.type || 'string'; if ($isObject) { var $async = $format.async === true; $format = $format.validate; } }} {{? $formatType != $ruleType }} {{# def.skipFormat }} {{?}} {{? $async }} {{ if (!it.async) throw new Error('async format in sync schema'); var $formatRef = 'formats' + it.util.getProperty($schema) + '.validate'; }} if (!({{=it.yieldAwait}} {{=$formatRef}}({{=$data}}))) { {{??}} if (!{{# def.checkFormat }}) { {{?}} {{?}} {{# def.error:'format' }} } {{? $breakOnError }} else { {{?}} ajv-5.0.0/lib/dot/items.jst000066400000000000000000000051061307514663700155110ustar00rootroot00000000000000{{# def.definitions }} {{# def.errors }} {{# def.setupKeyword }} {{# def.setupNextLevel }} {{## def.validateItems:startFrom: for (var {{=$idx}} = {{=startFrom}}; {{=$idx}} < {{=$data}}.length; {{=$idx}}++) { {{ $it.errorPath = it.util.getPathExpr(it.errorPath, $idx, it.opts.jsonPointers, true); var $passData = $data + '[' + $idx + ']'; $it.dataPathArr[$dataNxt] = $idx; }} {{# def.generateSubschemaCode }} {{# def.optimizeValidate }} {{? $breakOnError }} if (!{{=$nextValid}}) break; {{?}} } #}} {{ var $idx = 'i' + $lvl , $dataNxt = $it.dataLevel = it.dataLevel + 1 , $nextData = 'data' + $dataNxt , $currentBaseId = it.baseId; }} var {{=$errs}} = errors; var {{=$valid}}; {{? Array.isArray($schema) }} {{ /* 'items' is an array of schemas */}} {{ var $additionalItems = it.schema.additionalItems; }} {{? $additionalItems === false }} {{=$valid}} = {{=$data}}.length <= {{= $schema.length }}; {{ var $currErrSchemaPath = $errSchemaPath; $errSchemaPath = it.errSchemaPath + '/additionalItems'; }} {{# def.checkError:'additionalItems' }} {{ $errSchemaPath = $currErrSchemaPath; }} {{# def.elseIfValid}} {{?}} {{~ $schema:$sch:$i }} {{? {{# def.nonEmptySchema:$sch }} }} {{=$nextValid}} = true; if ({{=$data}}.length > {{=$i}}) { {{ var $passData = $data + '[' + $i + ']'; $it.schema = $sch; $it.schemaPath = $schemaPath + '[' + $i + ']'; $it.errSchemaPath = $errSchemaPath + '/' + $i; $it.errorPath = it.util.getPathExpr(it.errorPath, $i, it.opts.jsonPointers, true); $it.dataPathArr[$dataNxt] = $i; }} {{# def.generateSubschemaCode }} {{# def.optimizeValidate }} } {{# def.ifResultValid }} {{?}} {{~}} {{? typeof $additionalItems == 'object' && {{# def.nonEmptySchema:$additionalItems }} }} {{ $it.schema = $additionalItems; $it.schemaPath = it.schemaPath + '.additionalItems'; $it.errSchemaPath = it.errSchemaPath + '/additionalItems'; }} {{=$nextValid}} = true; if ({{=$data}}.length > {{= $schema.length }}) { {{# def.validateItems: $schema.length }} } {{# def.ifResultValid }} {{?}} {{?? {{# def.nonEmptySchema:$schema }} }} {{ /* 'items' is a single schema */}} {{ $it.schema = $schema; $it.schemaPath = $schemaPath; $it.errSchemaPath = $errSchemaPath; }} {{# def.validateItems: 0 }} {{?}} {{? $breakOnError }} {{= $closingBraces }} if ({{=$errs}} == errors) { {{?}} {{# def.cleanUp }} ajv-5.0.0/lib/dot/missing.def000066400000000000000000000022521307514663700157760ustar00rootroot00000000000000{{## def.checkMissingProperty:_properties: {{~ _properties:$propertyKey:$i }} {{?$i}} || {{?}} {{ var $prop = it.util.getProperty($propertyKey) , $useData = $data + $prop; }} ( ({{# def.noPropertyInData }}) && (missing{{=$lvl}} = {{= it.util.toQuotedString(it.opts.jsonPointers ? $propertyKey : $prop) }}) ) {{~}} #}} {{## def.errorMissingProperty:_error: {{ var $propertyPath = 'missing' + $lvl , $missingProperty = '\' + ' + $propertyPath + ' + \''; if (it.opts._errorDataPathProperty) { it.errorPath = it.opts.jsonPointers ? it.util.getPathExpr($currentErrorPath, $propertyPath, true) : $currentErrorPath + ' + ' + $propertyPath; } }} {{# def.error:_error }} #}} {{## def.allErrorsMissingProperty:_error: {{ var $prop = it.util.getProperty($propertyKey) , $missingProperty = it.util.escapeQuotes($propertyKey) , $useData = $data + $prop; if (it.opts._errorDataPathProperty) { it.errorPath = it.util.getPath($currentErrorPath, $propertyKey, it.opts.jsonPointers); } }} if ({{# def.noPropertyInData }}) { {{# def.addError:_error }} } #}} ajv-5.0.0/lib/dot/multipleOf.jst000066400000000000000000000011521307514663700165050ustar00rootroot00000000000000{{# def.definitions }} {{# def.errors }} {{# def.setupKeyword }} {{# def.$data }} var division{{=$lvl}}; if ({{?$isData}} {{=$schemaValue}} !== undefined && ( typeof {{=$schemaValue}} != 'number' || {{?}} (division{{=$lvl}} = {{=$data}} / {{=$schemaValue}}, {{? it.opts.multipleOfPrecision }} Math.abs(Math.round(division{{=$lvl}}) - division{{=$lvl}}) > 1e-{{=it.opts.multipleOfPrecision}} {{??}} division{{=$lvl}} !== parseInt(division{{=$lvl}}) {{?}} ) {{?$isData}} ) {{?}} ) { {{# def.error:'multipleOf' }} } {{? $breakOnError }} else { {{?}} ajv-5.0.0/lib/dot/not.jst000066400000000000000000000015351307514663700151720ustar00rootroot00000000000000{{# def.definitions }} {{# def.errors }} {{# def.setupKeyword }} {{# def.setupNextLevel }} {{? {{# def.nonEmptySchema:$schema }} }} {{ $it.schema = $schema; $it.schemaPath = $schemaPath; $it.errSchemaPath = $errSchemaPath; }} var {{=$errs}} = errors; {{# def.setCompositeRule }} {{ $it.createErrors = false; var $allErrorsOption; if ($it.opts.allErrors) { $allErrorsOption = $it.opts.allErrors; $it.opts.allErrors = false; } }} {{= it.validate($it) }} {{ $it.createErrors = true; if ($allErrorsOption) $it.opts.allErrors = $allErrorsOption; }} {{# def.resetCompositeRule }} if ({{=$nextValid}}) { {{# def.error:'not' }} } else { {{# def.resetErrors }} {{? it.opts.allErrors }} } {{?}} {{??}} {{# def.addError:'not' }} {{? $breakOnError}} if (false) { {{?}} {{?}} ajv-5.0.0/lib/dot/oneOf.jst000066400000000000000000000016321307514663700154360ustar00rootroot00000000000000{{# def.definitions }} {{# def.errors }} {{# def.setupKeyword }} {{# def.setupNextLevel }} var {{=$errs}} = errors; var prevValid{{=$lvl}} = false; var {{=$valid}} = false; {{ var $currentBaseId = $it.baseId; }} {{# def.setCompositeRule }} {{~ $schema:$sch:$i }} {{? {{# def.nonEmptySchema:$sch }} }} {{ $it.schema = $sch; $it.schemaPath = $schemaPath + '[' + $i + ']'; $it.errSchemaPath = $errSchemaPath + '/' + $i; }} {{# def.insertSubschemaCode }} {{??}} var {{=$nextValid}} = true; {{?}} {{? $i }} if ({{=$nextValid}} && prevValid{{=$lvl}}) {{=$valid}} = false; else { {{ $closingBraces += '}'; }} {{?}} if ({{=$nextValid}}) {{=$valid}} = prevValid{{=$lvl}} = true; {{~}} {{# def.resetCompositeRule }} {{= $closingBraces }} if (!{{=$valid}}) { {{# def.extraError:'oneOf' }} } else { {{# def.resetErrors }} {{? it.opts.allErrors }} } {{?}} ajv-5.0.0/lib/dot/pattern.jst000066400000000000000000000005341307514663700160450ustar00rootroot00000000000000{{# def.definitions }} {{# def.errors }} {{# def.setupKeyword }} {{# def.$data }} {{ var $regexp = $isData ? '(new RegExp(' + $schemaValue + '))' : it.usePattern($schema); }} if ({{# def.$dataNotType:'string' }} !{{=$regexp}}.test({{=$data}}) ) { {{# def.error:'pattern' }} } {{? $breakOnError }} else { {{?}} ajv-5.0.0/lib/dot/properties.jst000066400000000000000000000241251307514663700165660ustar00rootroot00000000000000{{# def.definitions }} {{# def.errors }} {{# def.setupKeyword }} {{# def.setupNextLevel }} {{## def.validateAdditional: {{ /* additionalProperties is schema */ $it.schema = $aProperties; $it.schemaPath = it.schemaPath + '.additionalProperties'; $it.errSchemaPath = it.errSchemaPath + '/additionalProperties'; $it.errorPath = it.opts._errorDataPathProperty ? it.errorPath : it.util.getPathExpr(it.errorPath, $key, it.opts.jsonPointers); var $passData = $data + '[' + $key + ']'; $it.dataPathArr[$dataNxt] = $key; }} {{# def.generateSubschemaCode }} {{# def.optimizeValidate }} #}} {{ var $key = 'key' + $lvl , $idx = 'idx' + $lvl , $dataNxt = $it.dataLevel = it.dataLevel + 1 , $nextData = 'data' + $dataNxt , $dataProperties = 'dataProperties' + $lvl; var $schemaKeys = Object.keys($schema || {}) , $pProperties = it.schema.patternProperties || {} , $pPropertyKeys = Object.keys($pProperties) , $aProperties = it.schema.additionalProperties , $someProperties = $schemaKeys.length || $pPropertyKeys.length , $noAdditional = $aProperties === false , $additionalIsSchema = typeof $aProperties == 'object' && Object.keys($aProperties).length , $removeAdditional = it.opts.removeAdditional , $checkAdditional = $noAdditional || $additionalIsSchema || $removeAdditional , $ownProperties = it.opts.ownProperties , $currentBaseId = it.baseId; var $required = it.schema.required; if ($required && !(it.opts.v5 && $required.$data) && $required.length < it.opts.loopRequired) var $requiredHash = it.util.toHash($required); if (it.opts.patternGroups) { var $pgProperties = it.schema.patternGroups || {} , $pgPropertyKeys = Object.keys($pgProperties); } }} var {{=$errs}} = errors; var {{=$nextValid}} = true; {{? $ownProperties }} var {{=$dataProperties}} = undefined; {{?}} {{? $checkAdditional }} {{# def.iterateProperties }} {{? $someProperties }} var isAdditional{{=$lvl}} = !(false {{? $schemaKeys.length }} {{? $schemaKeys.length > 5 }} || validate.schema{{=$schemaPath}}[{{=$key}}] {{??}} {{~ $schemaKeys:$propertyKey }} || {{=$key}} == {{= it.util.toQuotedString($propertyKey) }} {{~}} {{?}} {{?}} {{? $pPropertyKeys.length }} {{~ $pPropertyKeys:$pProperty:$i }} || {{= it.usePattern($pProperty) }}.test({{=$key}}) {{~}} {{?}} {{? it.opts.patternGroups && $pgPropertyKeys.length }} {{~ $pgPropertyKeys:$pgProperty:$i }} || {{= it.usePattern($pgProperty) }}.test({{=$key}}) {{~}} {{?}} ); if (isAdditional{{=$lvl}}) { {{?}} {{? $removeAdditional == 'all' }} delete {{=$data}}[{{=$key}}]; {{??}} {{ var $currentErrorPath = it.errorPath; var $additionalProperty = '\' + ' + $key + ' + \''; if (it.opts._errorDataPathProperty) { it.errorPath = it.util.getPathExpr(it.errorPath, $key, it.opts.jsonPointers); } }} {{? $noAdditional }} {{? $removeAdditional }} delete {{=$data}}[{{=$key}}]; {{??}} {{=$nextValid}} = false; {{ var $currErrSchemaPath = $errSchemaPath; $errSchemaPath = it.errSchemaPath + '/additionalProperties'; }} {{# def.error:'additionalProperties' }} {{ $errSchemaPath = $currErrSchemaPath; }} {{? $breakOnError }} break; {{?}} {{?}} {{?? $additionalIsSchema }} {{? $removeAdditional == 'failing' }} var {{=$errs}} = errors; {{# def.setCompositeRule }} {{# def.validateAdditional }} if (!{{=$nextValid}}) { errors = {{=$errs}}; if (validate.errors !== null) { if (errors) validate.errors.length = errors; else validate.errors = null; } delete {{=$data}}[{{=$key}}]; } {{# def.resetCompositeRule }} {{??}} {{# def.validateAdditional }} {{? $breakOnError }} if (!{{=$nextValid}}) break; {{?}} {{?}} {{?}} {{ it.errorPath = $currentErrorPath; }} {{?}} {{? $someProperties }} } {{?}} } {{# def.ifResultValid }} {{?}} {{ var $useDefaults = it.opts.useDefaults && !it.compositeRule; }} {{? $schemaKeys.length }} {{~ $schemaKeys:$propertyKey }} {{ var $sch = $schema[$propertyKey]; }} {{? {{# def.nonEmptySchema:$sch}} }} {{ var $prop = it.util.getProperty($propertyKey) , $passData = $data + $prop , $hasDefault = $useDefaults && $sch.default !== undefined; $it.schema = $sch; $it.schemaPath = $schemaPath + $prop; $it.errSchemaPath = $errSchemaPath + '/' + it.util.escapeFragment($propertyKey); $it.errorPath = it.util.getPath(it.errorPath, $propertyKey, it.opts.jsonPointers); $it.dataPathArr[$dataNxt] = it.util.toQuotedString($propertyKey); }} {{# def.generateSubschemaCode }} {{? {{# def.willOptimize }} }} {{ $code = {{# def._optimizeValidate }}; var $useData = $passData; }} {{??}} {{ var $useData = $nextData; }} var {{=$nextData}} = {{=$passData}}; {{?}} {{? $hasDefault }} {{= $code }} {{??}} {{? $requiredHash && $requiredHash[$propertyKey] }} if ({{# def.noPropertyInData }}) { {{=$nextValid}} = false; {{ var $currentErrorPath = it.errorPath , $currErrSchemaPath = $errSchemaPath , $missingProperty = it.util.escapeQuotes($propertyKey); if (it.opts._errorDataPathProperty) { it.errorPath = it.util.getPath($currentErrorPath, $propertyKey, it.opts.jsonPointers); } $errSchemaPath = it.errSchemaPath + '/required'; }} {{# def.error:'required' }} {{ $errSchemaPath = $currErrSchemaPath; }} {{ it.errorPath = $currentErrorPath; }} } else { {{??}} {{? $breakOnError }} if ({{# def.noPropertyInData }}) { {{=$nextValid}} = true; } else { {{??}} if ({{=$useData}} !== undefined {{? $ownProperties }} && {{# def.isOwnProperty }} {{?}} ) { {{?}} {{?}} {{= $code }} } {{?}} {{ /* $hasDefault */ }} {{?}} {{ /* def.nonEmptySchema */ }} {{# def.ifResultValid }} {{~}} {{?}} {{? $pPropertyKeys.length }} {{~ $pPropertyKeys:$pProperty }} {{ var $sch = $pProperties[$pProperty]; }} {{? {{# def.nonEmptySchema:$sch}} }} {{ $it.schema = $sch; $it.schemaPath = it.schemaPath + '.patternProperties' + it.util.getProperty($pProperty); $it.errSchemaPath = it.errSchemaPath + '/patternProperties/' + it.util.escapeFragment($pProperty); }} {{# def.iterateProperties }} if ({{= it.usePattern($pProperty) }}.test({{=$key}})) { {{ $it.errorPath = it.util.getPathExpr(it.errorPath, $key, it.opts.jsonPointers); var $passData = $data + '[' + $key + ']'; $it.dataPathArr[$dataNxt] = $key; }} {{# def.generateSubschemaCode }} {{# def.optimizeValidate }} {{? $breakOnError }} if (!{{=$nextValid}}) break; {{?}} } {{? $breakOnError }} else {{=$nextValid}} = true; {{?}} } {{# def.ifResultValid }} {{?}} {{ /* def.nonEmptySchema */ }} {{~}} {{?}} {{? it.opts.patternGroups && $pgPropertyKeys.length }} {{~ $pgPropertyKeys:$pgProperty }} {{ var $pgSchema = $pgProperties[$pgProperty] , $sch = $pgSchema.schema; }} {{? {{# def.nonEmptySchema:$sch}} }} {{ $it.schema = $sch; $it.schemaPath = it.schemaPath + '.patternGroups' + it.util.getProperty($pgProperty) + '.schema'; $it.errSchemaPath = it.errSchemaPath + '/patternGroups/' + it.util.escapeFragment($pgProperty) + '/schema'; }} var pgPropCount{{=$lvl}} = 0; {{# def.iterateProperties }} if ({{= it.usePattern($pgProperty) }}.test({{=$key}})) { pgPropCount{{=$lvl}}++; {{ $it.errorPath = it.util.getPathExpr(it.errorPath, $key, it.opts.jsonPointers); var $passData = $data + '[' + $key + ']'; $it.dataPathArr[$dataNxt] = $key; }} {{# def.generateSubschemaCode }} {{# def.optimizeValidate }} {{? $breakOnError }} if (!{{=$nextValid}}) break; {{?}} } {{? $breakOnError }} else {{=$nextValid}} = true; {{?}} } {{# def.ifResultValid }} {{ var $pgMin = $pgSchema.minimum , $pgMax = $pgSchema.maximum; }} {{? $pgMin !== undefined || $pgMax !== undefined }} var {{=$valid}} = true; {{ var $currErrSchemaPath = $errSchemaPath; }} {{? $pgMin !== undefined }} {{ var $limit = $pgMin, $reason = 'minimum', $moreOrLess = 'less'; }} {{=$valid}} = pgPropCount{{=$lvl}} >= {{=$pgMin}}; {{ $errSchemaPath = it.errSchemaPath + '/patternGroups/minimum'; }} {{# def.checkError:'patternGroups' }} {{? $pgMax !== undefined }} else {{?}} {{?}} {{? $pgMax !== undefined }} {{ var $limit = $pgMax, $reason = 'maximum', $moreOrLess = 'more'; }} {{=$valid}} = pgPropCount{{=$lvl}} <= {{=$pgMax}}; {{ $errSchemaPath = it.errSchemaPath + '/patternGroups/maximum'; }} {{# def.checkError:'patternGroups' }} {{?}} {{ $errSchemaPath = $currErrSchemaPath; }} {{# def.ifValid }} {{?}} {{?}} {{ /* def.nonEmptySchema */ }} {{~}} {{?}} {{? $breakOnError }} {{= $closingBraces }} if ({{=$errs}} == errors) { {{?}} {{# def.cleanUp }} ajv-5.0.0/lib/dot/propertyNames.jst000066400000000000000000000024321307514663700172370ustar00rootroot00000000000000{{# def.definitions }} {{# def.errors }} {{# def.setupKeyword }} {{# def.setupNextLevel }} {{? {{# def.nonEmptySchema:$schema }} }} {{ $it.schema = $schema; $it.schemaPath = $schemaPath; $it.errSchemaPath = $errSchemaPath; }} {{ var $key = 'key' + $lvl , $idx = 'idx' + $lvl , $i = 'i' + $lvl , $invalidName = '\' + ' + $key + ' + \'' , $dataNxt = $it.dataLevel = it.dataLevel + 1 , $nextData = 'data' + $dataNxt , $dataProperties = 'dataProperties' + $lvl , $ownProperties = it.opts.ownProperties , $currentBaseId = it.baseId; }} var {{=$errs}} = errors; {{? $ownProperties }} var {{=$dataProperties}} = undefined; {{?}} {{# def.iterateProperties }} var startErrs{{=$lvl}} = errors; {{ var $passData = $key; }} {{# def.setCompositeRule }} {{# def.generateSubschemaCode }} {{# def.optimizeValidate }} {{# def.resetCompositeRule }} if (!{{=$nextValid}}) { for (var {{=$i}}=startErrs{{=$lvl}}; {{=$i}}= it.opts.loopRequired , $ownProperties = it.opts.ownProperties; }} {{? $breakOnError }} var missing{{=$lvl}}; {{? $loopRequired }} {{# def.setupLoop }} var {{=$valid}} = true; {{?$isData}}{{# def.check$dataIsArray }}{{?}} for (var {{=$i}} = 0; {{=$i}} < {{=$vSchema}}.length; {{=$i}}++) { {{=$valid}} = {{=$data}}[{{=$vSchema}}[{{=$i}}]] !== undefined {{? $ownProperties }} && {{# def.isRequiredOwnProperty }} {{?}}; if (!{{=$valid}}) break; } {{? $isData }} } {{?}} {{# def.checkError:'required' }} else { {{??}} if ({{# def.checkMissingProperty:$required }}) { {{# def.errorMissingProperty:'required' }} } else { {{?}} {{??}} {{? $loopRequired }} {{# def.setupLoop }} {{? $isData }} if ({{=$vSchema}} && !Array.isArray({{=$vSchema}})) { {{# def.addError:'required' }} } else if ({{=$vSchema}} !== undefined) { {{?}} for (var {{=$i}} = 0; {{=$i}} < {{=$vSchema}}.length; {{=$i}}++) { if ({{=$data}}[{{=$vSchema}}[{{=$i}}]] === undefined {{? $ownProperties }} || !{{# def.isRequiredOwnProperty }} {{?}}) { {{# def.addError:'required' }} } } {{? $isData }} } {{?}} {{??}} {{~ $required:$propertyKey }} {{# def.allErrorsMissingProperty:'required' }} {{~}} {{?}} {{?}} {{ it.errorPath = $currentErrorPath; }} {{?? $breakOnError }} if (true) { {{?}} ajv-5.0.0/lib/dot/uniqueItems.jst000066400000000000000000000015051307514663700166770ustar00rootroot00000000000000{{# def.definitions }} {{# def.errors }} {{# def.setupKeyword }} {{# def.$data }} {{? ($schema || $isData) && it.opts.uniqueItems !== false }} {{? $isData }} var {{=$valid}}; if ({{=$schemaValue}} === false || {{=$schemaValue}} === undefined) {{=$valid}} = true; else if (typeof {{=$schemaValue}} != 'boolean') {{=$valid}} = false; else { {{?}} var {{=$valid}} = true; if ({{=$data}}.length > 1) { var i = {{=$data}}.length, j; outer: for (;i--;) { for (j = i; j--;) { if (equal({{=$data}}[i], {{=$data}}[j])) { {{=$valid}} = false; break outer; } } } } {{? $isData }} } {{?}} if (!{{=$valid}}) { {{# def.error:'uniqueItems' }} } {{? $breakOnError }} else { {{?}} {{??}} {{? $breakOnError }} if (true) { {{?}} {{?}} ajv-5.0.0/lib/dot/validate.jst000066400000000000000000000153721307514663700161670ustar00rootroot00000000000000{{# def.definitions }} {{# def.errors }} {{# def.defaults }} {{# def.coerce }} {{ /** * schema compilation (render) time: * it = { schema, RULES, _validate, opts } * it.validate - this template function, * it is used recursively to generate code for subschemas * * runtime: * "validate" is a variable name to which this function will be assigned * validateRef etc. are defined in the parent scope in index.js */ }} {{ var $async = it.schema.$async === true , $refKeywords = it.util.schemaHasRulesExcept(it.schema, it.RULES.all, '$ref') , $id = it.self._getId(it.schema); }} {{? it.isTop }} {{? $async }} {{ it.async = true; var $es7 = it.opts.async == 'es7'; it.yieldAwait = $es7 ? 'await' : 'yield'; }} {{?}} var validate = {{? $async }} {{? $es7 }} (async function {{??}} {{? it.opts.async != '*'}}co.wrap{{?}}(function* {{?}} {{??}} (function {{?}} (data, dataPath, parentData, parentDataProperty, rootData) { 'use strict'; {{? $id && (it.opts.sourceCode || it.opts.processCode) }} {{= '/\*# sourceURL=' + $id + ' */' }} {{?}} {{?}} {{? typeof it.schema == 'boolean' || !($refKeywords || it.schema.$ref) }} {{ var $keyword = 'false schema'; }} {{# def.setupKeyword }} {{? it.schema === false}} {{? it.isTop}} {{ $breakOnError = true; }} {{??}} var {{=$valid}} = false; {{?}} {{# def.error:'false schema' }} {{??}} {{? it.isTop}} {{? $async }} return data; {{??}} validate.errors = null; return true; {{?}} {{??}} var {{=$valid}} = true; {{?}} {{?}} {{? it.isTop}} }); return validate; {{?}} {{ return out; }} {{?}} {{? it.isTop }} {{ var $top = it.isTop , $lvl = it.level = 0 , $dataLvl = it.dataLevel = 0 , $data = 'data'; it.rootId = it.resolve.fullPath(it.self._getId(it.root.schema)); it.baseId = it.baseId || it.rootId; delete it.isTop; it.dataPathArr = [undefined]; }} var vErrors = null; {{ /* don't edit, used in replace */ }} var errors = 0; {{ /* don't edit, used in replace */ }} if (rootData === undefined) rootData = data; {{ /* don't edit, used in replace */ }} {{??}} {{ var $lvl = it.level , $dataLvl = it.dataLevel , $data = 'data' + ($dataLvl || ''); if ($id) it.baseId = it.resolve.url(it.baseId, $id); if ($async && !it.async) throw new Error('async schema in sync schema'); }} var errs_{{=$lvl}} = errors; {{?}} {{ var $valid = 'valid' + $lvl , $breakOnError = !it.opts.allErrors , $closingBraces1 = '' , $closingBraces2 = ''; var $errorKeyword; var $typeSchema = it.schema.type , $typeIsArray = Array.isArray($typeSchema); }} {{## def.checkType: {{ var $schemaPath = it.schemaPath + '.type' , $errSchemaPath = it.errSchemaPath + '/type' , $method = $typeIsArray ? 'checkDataTypes' : 'checkDataType'; }} if ({{= it.util[$method]($typeSchema, $data, true) }}) { #}} {{? $typeSchema && it.opts.coerceTypes }} {{ var $coerceToTypes = it.util.coerceToTypes(it.opts.coerceTypes, $typeSchema); }} {{? $coerceToTypes }} {{# def.checkType }} {{# def.coerceType }} } {{?}} {{?}} {{? it.schema.$ref && $refKeywords }} {{? it.opts.extendRefs == 'fail' }} {{ throw new Error('$ref: validation keywords used in schema at path "' + it.errSchemaPath + '" (see option extendRefs)'); }} {{?? it.opts.extendRefs !== true }} {{ $refKeywords = false; console.warn('$ref: keywords ignored in schema at path "' + it.errSchemaPath + '"'); }} {{?}} {{?}} {{? it.schema.$ref && !$refKeywords }} {{= it.RULES.all.$ref.code(it, '$ref') }} {{? $breakOnError }} } if (errors === {{?$top}}0{{??}}errs_{{=$lvl}}{{?}}) { {{ $closingBraces2 += '}'; }} {{?}} {{??}} {{? it.opts.v5 && it.schema.patternGroups }} {{ console.warn('keyword "patternGroups" is deprecated and disabled. Use option patternGroups: true to enable.'); }} {{?}} {{~ it.RULES:$rulesGroup }} {{? $shouldUseGroup($rulesGroup) }} {{? $rulesGroup.type }} if ({{= it.util.checkDataType($rulesGroup.type, $data) }}) { {{?}} {{? it.opts.useDefaults && !it.compositeRule }} {{? $rulesGroup.type == 'object' && it.schema.properties }} {{# def.defaultProperties }} {{?? $rulesGroup.type == 'array' && Array.isArray(it.schema.items) }} {{# def.defaultItems }} {{?}} {{?}} {{~ $rulesGroup.rules:$rule }} {{? $shouldUseRule($rule) }} {{ var $code = $rule.code(it, $rule.keyword, $rulesGroup.type); }} {{? $code }} {{= $code }} {{? $breakOnError }} {{ $closingBraces1 += '}'; }} {{?}} {{?}} {{?}} {{~}} {{? $breakOnError }} {{= $closingBraces1 }} {{ $closingBraces1 = ''; }} {{?}} {{? $rulesGroup.type }} } {{? $typeSchema && $typeSchema === $rulesGroup.type }} {{ var $typeChecked = true; }} else { {{ var $schemaPath = it.schemaPath + '.type' , $errSchemaPath = it.errSchemaPath + '/type'; }} {{# def.error:'type' }} } {{?}} {{?}} {{? $breakOnError }} if (errors === {{?$top}}0{{??}}errs_{{=$lvl}}{{?}}) { {{ $closingBraces2 += '}'; }} {{?}} {{?}} {{~}} {{?}} {{? $typeSchema && !$typeChecked && !(it.opts.coerceTypes && $coerceToTypes) }} {{# def.checkType }} {{# def.error:'type' }} } {{?}} {{? $breakOnError }} {{= $closingBraces2 }} {{?}} {{? $top }} {{? $async }} if (errors === 0) return data; {{ /* don't edit, used in replace */ }} else throw new ValidationError(vErrors); {{ /* don't edit, used in replace */ }} {{??}} validate.errors = vErrors; {{ /* don't edit, used in replace */ }} return errors === 0; {{ /* don't edit, used in replace */ }} {{?}} }); return validate; {{??}} var {{=$valid}} = errors === errs_{{=$lvl}}; {{?}} {{# def.cleanUp }} {{? $top }} {{# def.finalCleanUp }} {{?}} {{ function $shouldUseGroup($rulesGroup) { var rules = $rulesGroup.rules; for (var i=0; i < rules.length; i++) if ($shouldUseRule(rules[i])) return true; } function $shouldUseRule($rule) { return it.schema[$rule.keyword] !== undefined || ($rule.implements && $ruleImlementsSomeKeyword($rule)); } function $ruleImlementsSomeKeyword($rule) { var impl = $rule.implements; for (var i=0; i < impl.length; i++) if (it.schema[impl[i]] !== undefined) return true; } }} ajv-5.0.0/lib/dotjs/000077500000000000000000000000001307514663700142015ustar00rootroot00000000000000ajv-5.0.0/lib/dotjs/README.md000066400000000000000000000002251307514663700154570ustar00rootroot00000000000000These files are compiled dot templates from dot folder. Do NOT edit them directly, edit the templates and run `npm run build` from main ajv folder. ajv-5.0.0/lib/keyword.js000066400000000000000000000067121307514663700151060ustar00rootroot00000000000000'use strict'; var IDENTIFIER = /^[a-z_$][a-z0-9_$\-]*$/i; var customRuleCode = require('./dotjs/custom'); module.exports = { add: addKeyword, get: getKeyword, remove: removeKeyword }; /** * Define custom keyword * @this Ajv * @param {String} keyword custom keyword, should be unique (including 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`. */ function addKeyword(keyword, definition) { /* jshint validthis: true */ /* eslint no-shadow: 0 */ var RULES = this.RULES; if (RULES.keywords[keyword]) throw new Error('Keyword ' + keyword + ' is already defined'); if (!IDENTIFIER.test(keyword)) throw new Error('Keyword ' + keyword + ' is not a valid identifier'); if (definition) { if (definition.macro && definition.valid !== undefined) throw new Error('"valid" option cannot be used with macro keywords'); var dataType = definition.type; if (Array.isArray(dataType)) { var i, len = dataType.length; for (i=0; i=4\" eslint lib/*.js lib/compile/*.js spec scripts", "test-spec": "mocha spec/*.spec.js -R spec $(if-node-version 7 echo --harmony-async-await)", "test-fast": "AJV_FAST_TEST=true npm run test-spec", "test-debug": "mocha spec/*.spec.js --debug-brk -R spec", "test-cov": "nyc npm run test-spec", "test-ts": "tsc --target ES5 --noImplicitAny lib/ajv.d.ts", "bundle": "node ./scripts/bundle.js . Ajv pure_getters", "bundle-regenerator": "node ./scripts/bundle.js regenerator", "bundle-nodent": "node ./scripts/bundle.js nodent", "bundle-all": "del-cli dist && npm run bundle && npm run bundle-regenerator && npm run bundle-nodent", "bundle-beautify": "node ./scripts/bundle.js js-beautify", "build": "del-cli lib/dotjs/*.js && node scripts/compile-dots.js", "test-karma": "karma start --single-run --browsers PhantomJS", "test-browser": "del-cli .browser && npm run bundle-all && scripts/prepare-tests && npm run test-karma", "test": "npm run eslint && npm run test-ts && npm run build && npm run test-cov && if-node-version 4 npm run test-browser", "prepublish": "npm run build && npm run bundle-all", "watch": "watch 'npm run build' ./lib/dot" }, "nyc": { "exclude": [ "**/spec/**", "node_modules" ], "reporter": [ "lcov", "text-summary" ] }, "repository": { "type": "git", "url": "https://github.com/epoberezkin/ajv.git" }, "keywords": [ "JSON", "schema", "validator", "validation", "jsonschema", "json-schema", "json-schema-validator", "json-schema-validation" ], "author": "Evgeny Poberezkin", "license": "MIT", "bugs": { "url": "https://github.com/epoberezkin/ajv/issues" }, "homepage": "https://github.com/epoberezkin/ajv", "tonicExampleFilename": ".tonic_example.js", "dependencies": { "co": "^4.6.0", "json-stable-stringify": "^1.0.1" }, "devDependencies": { "ajv-async": "^0.1.0", "bluebird": "^3.1.5", "brfs": "^1.4.3", "browserify": "^14.1.0", "chai": "^3.5.0", "coveralls": "^2.11.4", "del-cli": "^0.2.1", "dot": "^1.0.3", "eslint": "^3.2.2", "gh-pages-generator": "^0.2.0", "glob": "^7.0.0", "if-node-version": "^1.0.0", "js-beautify": "^1.5.6", "json-schema-test": "^1.3.0", "karma": "^1.0.0", "karma-chrome-launcher": "^2.0.0", "karma-mocha": "^1.1.1", "karma-phantomjs-launcher": "^1.0.0", "karma-sauce-launcher": "^1.1.0", "mocha": "^3.0.0", "nodent": "^3.0.17", "nyc": "^10.0.0", "phantomjs-prebuilt": "^2.1.4", "pre-commit": "^1.1.1", "regenerator": "0.9.7", "require-globify": "^1.3.0", "typescript": "^2.0.3", "uglify-js": "2.6.1", "watch": "^1.0.0" } } ajv-5.0.0/scripts/000077500000000000000000000000001307514663700137775ustar00rootroot00000000000000ajv-5.0.0/scripts/.eslintrc.yml000066400000000000000000000000761307514663700164260ustar00rootroot00000000000000rules: no-console: 0 no-empty: [2, allowEmptyCatch: true] ajv-5.0.0/scripts/bundle.js000066400000000000000000000031461307514663700156120ustar00rootroot00000000000000'use strict'; var fs = require('fs') , path = require('path') , browserify = require('browserify') , uglify = require('uglify-js'); var pkg = process.argv[2] , standalone = process.argv[3] , compress = process.argv[4]; var packageDir = path.join(__dirname, '..'); if (pkg != '.') packageDir = path.join(packageDir, 'node_modules', pkg); var json = require(path.join(packageDir, 'package.json')); var distDir = path.join(__dirname, '..', 'dist'); if (!fs.existsSync(distDir)) fs.mkdirSync(distDir); var bOpts = {}; if (standalone) bOpts.standalone = standalone; browserify(bOpts) .require(path.join(packageDir, json.main), {expose: json.name}) .bundle(function (err, buf) { if (err) { console.error('browserify error:', err); process.exit(1); } var outputFile = path.join(distDir, json.name); var outputBundle = outputFile + '.bundle.js'; fs.writeFileSync(outputBundle, buf); var uglifyOpts = { warnings: true, compress: {}, output: { preamble: '/* ' + json.name + ' ' + json.version + ': ' + json.description + ' */' } }; if (compress) { var compressOpts = compress.split(','); for (var i=0; i]+ajv_logo[^>]+>//" index.md git config user.email "$GIT_USER_EMAIL" git config user.name "$GIT_USER_NAME" git add . git commit -am "updated by travis build #$TRAVIS_BUILD_NUMBER" git push --quiet origin gh-pages > /dev/null 2>&1 } fi ajv-5.0.0/spec/000077500000000000000000000000001307514663700132425ustar00rootroot00000000000000ajv-5.0.0/spec/.eslintrc.yml000066400000000000000000000002521307514663700156650ustar00rootroot00000000000000rules: no-console: 0 no-empty: [2, allowEmptyCatch: true] quotes: 0 no-invalid-this: 0 globals: describe: false it: false before: false beforeEach: false ajv-5.0.0/spec/JSON-Schema-Test-Suite/000077500000000000000000000000001307514663700172155ustar00rootroot00000000000000ajv-5.0.0/spec/after_test.js000066400000000000000000000007101307514663700157360ustar00rootroot00000000000000'use strict'; var should = require('./chai').should(); exports.error = function (res) { console.log('ajv options:', res.validator._opts); }; exports.each = function (res) { // console.log(res.errors); res.valid .should.be.a('boolean'); if (res.valid === true ) { should.equal(res.errors, null); } else { res.errors .should.be.an('array'); for (var i=0; i 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; } }); 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() { var valid = ajv.validateSchema({ $schema: 'http://json-schema.org/draft-06/schema#', type: 'number' }); valid .should.equal(true); should.equal(ajv.errors, null); valid = ajv.validateSchema({ $schema: 'http://json-schema.org/draft-06/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() { ajv.validateSchema({ $schema: {}, type: 'number' }); }); }); }); }); ajv-5.0.0/spec/ajv_async_instances.js000066400000000000000000000056061307514663700176330ustar00rootroot00000000000000'use strict'; var Ajv = require('./ajv') , util = require('../lib/compile/util') , setupAsync = require('ajv-async'); module.exports = getAjvInstances; var firstTime = true; var isBrowser = typeof window == 'object'; var fullTest = isBrowser || !process.env.AJV_FAST_TEST; function getAjvInstances(opts) { opts = opts || {}; var instances = []; var options = [ {}, { async: true }, { async: 'co*' }, { async: 'es7' }, { async: 'es7', transpile: 'nodent' }, { async: 'co*', allErrors: true }, { async: 'es7', allErrors: true }, { async: 'es7', transpile: 'nodent', allErrors: true } ]; var ua; try { ua = window.navigator.userAgent.toLowerCase(); } catch(e) {} // regenerator does not work in IE9 if (!(ua && /msie\s9/.test(ua))) { options = options.concat([ { async: '*', transpile: 'regenerator' }, { async: '*', transpile: 'regenerator', allErrors: true } ]); } if (fullTest) { options = options.concat([ { async: '*' }, { allErrors: true }, { async: true, allErrors: true }, { async: '*', allErrors: true } ]); if (!(ua && /msie\s9/.test(ua))) { options = options.concat([ { async: 'co*', transpile: 'regenerator' }, { async: 'co*', transpile: 'regenerator', allErrors: true } ]); } // es7 functions transpiled with regenerator are excluded from test in Safari/Firefox/Edge/IE9. // They fail in IE9 and emit multiple 'uncaught exception' warnings in Safari/Firefox/Edge anc cause remote tests to disconnect. if (!(ua && ((/safari/.test(ua) && !/chrome|phantomjs/.test(ua)) || /firefox|edge|msie\s9/.test(ua)))) { options = options.concat([ { transpile: 'regenerator' }, { async: true, transpile: 'regenerator' }, { async: 'es7', transpile: 'regenerator' }, { transpile: 'regenerator', allErrors: true }, { async: true, transpile: 'regenerator', allErrors: true }, { async: 'es7', transpile: 'regenerator', allErrors: true } ]); } } // options = options.filter(function (_opts) { // return _opts.transpile == 'nodent'; // }); // var i = 10, repeatOptions = []; // while (i--) repeatOptions = repeatOptions.concat(options); // options = repeatOptions; options.forEach(function (_opts) { util.copy(opts, _opts); var ajv = getAjv(_opts); if (ajv) instances.push(ajv); }); if (firstTime) { var asyncModes = []; instances.forEach(function (ajv) { if (!ajv._opts.async) return; var t = ajv._opts.transpile; var mode = ajv._opts.async + (t === true ? '' : '.' + t); if (asyncModes.indexOf(mode) == -1) asyncModes.push(mode); }); console.log('Testing', instances.length, 'ajv instances:', asyncModes.join(',')); firstTime = false; } return instances; } function getAjv(opts){ try { return setupAsync(new Ajv(opts)); } catch(e) {} } ajv-5.0.0/spec/ajv_instances.js000066400000000000000000000013201307514663700164230ustar00rootroot00000000000000'use strict'; var Ajv = require('./ajv'); module.exports = getAjvInstances; function getAjvInstances(options, extraOpts) { return _getAjvInstances(options, extraOpts || {}); } function _getAjvInstances(opts, useOpts) { 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); } return [ new Ajv(useOpts) ]; } function copy(o, to) { to = to || {}; for (var key in o) to[key] = o[key]; return to; } ajv-5.0.0/spec/ajv_options.js000066400000000000000000000010431307514663700161310ustar00rootroot00000000000000'use strict'; 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 }; if (fullTest && !isBrowser) options.processCode = require('js-beautify').js_beautify; module.exports = options; ajv-5.0.0/spec/async.spec.js000066400000000000000000000274631307514663700156620ustar00rootroot00000000000000'use strict'; /* global Promise */ var Ajv = require('./ajv') , should = require('./chai').should(); 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" } } }, "http://example.com/int2plus.json": { "id": "http://example.com/int2plus.json", "type": "integer", "minimum": 2 }, "http://example.com/tree.json": { "id": "http://example.com/tree.json", "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" } } }, "http://example.com/recursive.json": { "id": "http://example.com/recursive.json", "properties": { "b": { "$ref": "parent.json" } }, "required": ["b"] }, "http://example.com/invalid.json": { "id": "http://example.com/recursive.json", "properties": { "invalid": { "type": "number" } }, "required": "invalid" }, "http://example.com/foobar.json": { "id": "http://example.com/foobar.json", "$schema": "http://example.com/foobar_meta.json", "myFooBar": "foo" }, "http://example.com/foobar_meta.json": { "id": "http://example.com/foobar_meta.json", "type": "object", "properties": { "myFooBar": { "enum": ["foo", "bar"] } } } }; beforeEach(function() { loadCallCount = 0; ajv = new Ajv({ loadSchema: loadSchema }); }); 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" } } }; 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) { var schema = { "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() { var schema = { "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() { var schema = { "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" } } }; 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); }); }); 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', validate: function (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); }); } }); 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; var p1 = ajv.compileAsync(schema).then(function (validate) { 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; 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); } }); 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" } } }; return Promise.all([ 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); } }); 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() { // function is needed for the test to pass in Firefox 4 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) { var schema = { "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) { var schema = { "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) { var schema = { "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')); } }); 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'); } }); function shouldFail(done) { return function (err, validate) { should.exist(err); should.not.exist(validate); done(); }; } }); 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() { var 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() { var 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() { var 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')); } }); 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'); } }); function shouldReject(p) { return p.then( function(validate) { should.not.exist(validate); throw new Error('Promise has resolved; it should have rejected'); }, function(err) { should.exist(err); } ); } }); function loadSchema(uri) { loadCallCount++; return new Promise(function (resolve, reject) { setTimeout(function() { if (SCHEMAS[uri]) resolve(SCHEMAS[uri]); else reject(new Error('404')); }, 10); }); } }); ajv-5.0.0/spec/async/000077500000000000000000000000001307514663700143575ustar00rootroot00000000000000ajv-5.0.0/spec/async/boolean.json000066400000000000000000000046521307514663700167000ustar00rootroot00000000000000[ { "description": "boolean schema = true in properties", "schema": { "$async": true, "properties": { "foo": true } }, "tests": [ { "description": "any data is valid", "data": { "foo": 1 }, "valid": true } ] }, { "description": "boolean schema = false in properties", "schema": { "$async": true, "properties": { "foo": false } }, "tests": [ { "description": "any property is invalid", "data": { "foo": 1 }, "valid": false }, { "description": "without property is valid", "data": { "bar": 1 }, "valid": true }, { "description": "empty object is valid", "data": {}, "valid": true } ] }, { "description": "boolean schema = true in $ref", "schema": { "$async": true, "$ref": "#/definitions/true", "definitions": { "true": true } }, "tests": [ { "description": "any data is valid", "data": 1, "valid": true } ] }, { "description": "boolean schema = false in $ref", "schema": { "$async": true, "$ref": "#/definitions/false", "definitions": { "false": false } }, "tests": [ { "description": "any data is invalid", "data": 1, "valid": false } ] }, { "description": "boolean schema = true in properties with $ref", "schema": { "$async": true, "properties": { "foo": { "$ref": "#/definitions/foo" } }, "definitions": { "foo": true } }, "tests": [ { "description": "any data is valid", "data": { "foo": 1 }, "valid": true } ] }, { "description": "boolean schema = false in properties with $ref", "schema": { "$async": true, "properties": { "foo": { "$ref": "#/definitions/foo" } }, "definitions": { "foo": false } }, "tests": [ { "description": "any property is invalid", "data": { "foo": 1 }, "valid": false }, { "description": "without property is valid", "data": { "bar": 1 }, "valid": true }, { "description": "empty object is valid", "data": {}, "valid": true } ] } ] ajv-5.0.0/spec/async/compound.json000066400000000000000000000046771307514663700171140ustar00rootroot00000000000000[ { "description": "allOf: async + sync", "schema": { "$async": true, "allOf": [ { "idExists": { "table": "users" } }, { "type": "integer", "minimum": 3 } ] }, "tests": [ { "description": "valid id", "data": 5, "valid": true }, { "description": "another valid id", "data": 8, "valid": true }, { "description": "invalid async - not user id", "data": 9, "valid": false }, { "description": "invalid sync - valid id but too small", "data": 1, "valid": false } ] }, { "description": "anyOf: async + sync", "schema": { "$async": true, "anyOf": [ { "idExists": { "table": "users" } }, { "type": "integer", "minimum": 3 } ] }, "tests": [ { "description": "valid id", "data": 1, "valid": true }, { "description": "valid - not id but big enough", "data": 4, "valid": true }, { "description": "valid - id and big enough", "data": 5, "valid": true }, { "description": "invalid both", "data": 2, "valid": false } ] }, { "description": "oneOf: async + sync", "schema": { "$async": true, "oneOf": [ { "idExists": { "table": "users" } }, { "type": "integer", "minimum": 3 } ] }, "tests": [ { "description": "valid id", "data": 1, "valid": true }, { "description": "valid - not id but big enough", "data": 4, "valid": true }, { "description": "invalid - id and big enough", "data": 5, "valid": false }, { "description": "invalid both", "data": 2, "valid": false } ] }, { "description": "not with async", "schema": { "$async": true, "not": { "idExists": { "table": "users" } } }, "tests": [ { "description": "invalid because valid id", "data": 1, "valid": false }, { "description": "valid because not a valid id", "data": 4, "valid": true } ] } ] ajv-5.0.0/spec/async/format.json000066400000000000000000000035361307514663700165510ustar00rootroot00000000000000[ { "description": "async custom formats", "schema": { "$async": true, "type": "string", "format": "english_word" }, "tests": [ { "description": "'tomorrow' is a valid english word", "data": "tomorrow", "valid": true }, { "description": "'manana' is an invalid english word", "data": "manana", "valid": false }, { "description": "number is invalid", "data": 1, "valid": false }, { "description": "'today' throws an exception, not in the dictionary", "data": "today", "error": "unknown word" } ] }, { "description": "async formats when $data ref resolves to async format name", "schema": { "$async": true, "additionalProperties": { "type": "string", "format": { "$data": "0#" } } }, "tests": [ { "description": "'tomorrow' is a valid english word", "data": { "english_word": "tomorrow" }, "valid": true }, { "description": "'manana' is an invalid english word", "data": { "english_word": "manana" }, "valid": false }, { "description": "number is invalid", "data": { "english_word": 1 }, "valid": false }, { "description": "'today' throws an exception, not in the dictionary", "data": { "english_word": "today" }, "error": "unknown word" }, { "description": "valid date", "data": { "date": "2016-01-25" }, "valid": true }, { "description": "invalid date", "data": { "date": "01/25/2016" }, "valid": false }, { "description": "number is invalid", "data": { "date": 1 }, "valid": false } ] } ] ajv-5.0.0/spec/async/items.json000066400000000000000000000016671307514663700164050ustar00rootroot00000000000000[ { "description": "items: async + sync", "schema": { "$async": true, "items": [ { "type": "integer", "idExists": { "table": "users" } }, { "type": "integer" }, { "type": "integer", "idExists": { "table": "users" } } ] }, "tests": [ { "description": "valid array", "data": [ 1, 2, 5 ], "valid": true }, { "description": "another valid array", "data": [ 5, 2, 8 ], "valid": true }, { "description": "invalid 1st async item", "data": [ 9, 2, 8 ], "valid": false }, { "description": "invalid 2nd async item", "data": [ 1, 2, 9 ], "valid": false }, { "description": "invalid sync item", "data": [ 1, "abc", 5 ], "valid": false } ] } ] ajv-5.0.0/spec/async/keyword.json000066400000000000000000000073151307514663700167440ustar00rootroot00000000000000[ { "description": "async custom keywords (validated)", "schema": { "$async": true, "properties": { "userId": { "type": "integer", "idExists": { "table": "users" } }, "postId": { "type": "integer", "idExists": { "table": "posts" } }, "categoryId": { "description": "will throw if present, no such table", "type": "integer", "idExists": { "table": "categories" } } } }, "tests": [ { "description": "valid object", "data": { "userId": 1, "postId": 21 }, "valid": true }, { "description": "another valid object", "data": { "userId": 5, "postId": 25 }, "valid": true }, { "description": "invalid - no such post", "data": { "userId": 5, "postId": 10 }, "valid": false }, { "description": "invalid - no such user", "data": { "userId": 9, "postId": 25 }, "valid": false }, { "description": "should throw exception during validation - no such table", "data": { "postId": 25, "categoryId": 1 }, "error": "no such table" } ] }, { "description": "async custom keywords (validated with errors)", "schema": { "$async": true, "properties": { "userId": { "type": "integer", "idExistsWithError": { "table": "users" } }, "postId": { "type": "integer", "idExistsWithError": { "table": "posts" } }, "categoryId": { "description": "will throw if present, no such table", "type": "integer", "idExistsWithError": { "table": "categories" } } } }, "tests": [ { "description": "valid object", "data": { "userId": 1, "postId": 21 }, "valid": true }, { "description": "another valid object", "data": { "userId": 5, "postId": 25 }, "valid": true }, { "description": "invalid - no such post", "data": { "userId": 5, "postId": 10 }, "valid": false }, { "description": "invalid - no such user", "data": { "userId": 9, "postId": 25 }, "valid": false }, { "description": "should throw exception during validation - no such table", "data": { "postId": 25, "categoryId": 1 }, "error": "no such table" } ] }, { "description": "async custom keywords (compiled)", "schema": { "$async": true, "properties": { "userId": { "type": "integer", "idExistsCompiled": { "table": "users" } }, "postId": { "type": "integer", "idExistsCompiled": { "table": "posts" } } } }, "tests": [ { "description": "valid object", "data": { "userId": 1, "postId": 21 }, "valid": true }, { "description": "another valid object", "data": { "userId": 5, "postId": 25 }, "valid": true }, { "description": "invalid - no such post", "data": { "userId": 5, "postId": 10 }, "valid": false }, { "description": "invalid - no such user", "data": { "userId": 9, "postId": 25 }, "valid": false } ] }, { "description": "custom keyword in async schema", "schema": { "$async": true, "const": 5 }, "tests": [ { "description": "valid", "data": 5, "valid": true }, { "description": "valid", "data": 1, "valid": false } ] } ] ajv-5.0.0/spec/async/no_async.json000066400000000000000000000010041307514663700170560ustar00rootroot00000000000000[ { "description": "async schema without async elements", "schema": { "$async": true, "type": "string", "maxLength": 3 }, "tests": [ { "description": "string <= 3 chars is valid", "data": "abc", "valid": true }, { "description": "string > 3 chars is invalid", "data": "abcd", "valid": false }, { "description": "number is invalid", "data": 1, "valid": false } ] } ] ajv-5.0.0/spec/async/properties.json000066400000000000000000000014561307514663700174540ustar00rootroot00000000000000[ { "description": "properties: async + sync", "schema": { "$async": true, "properties": { "foo": { "type": "integer", "idExists": { "table": "users" } }, "bar": { "type": "integer" } } }, "tests": [ { "description": "valid object", "data": { "foo": 1, "bar": 2 }, "valid": true }, { "description": "another valid object", "data": { "foo": 5, "bar": 2 }, "valid": true }, { "description": "invalid sync property", "data": { "foo": 1, "bar": "abc" }, "valid": false }, { "description": "invalid async property", "data": { "foo": 9, "bar": 2 }, "valid": false } ] } ] ajv-5.0.0/spec/async_schemas.spec.js000066400000000000000000000053101307514663700173500ustar00rootroot00000000000000'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 instances = getAjvInstances({ $data: true }); instances.forEach(addAsyncFormatsAndKeywords); jsonSchemaTest(instances, { 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: true, asyncValid: 'data', assert: require('./chai').assert, Promise: Promise, afterError: after.error, // afterEach: after.each, cwd: __dirname, hideFolder: 'async/', timeout: 90000 }); function addAsyncFormatsAndKeywords (ajv) { ajv.addFormat('english_word', { async: true, validate: checkWordOnServer }); ajv.addKeyword('idExists', { async: true, type: 'number', validate: checkIdExists, errors: false }); ajv.addKeyword('idExistsWithError', { async: true, type: 'number', validate: checkIdExistsWithError, errors: true }); ajv.addKeyword('idExistsCompiled', { async: true, type: 'number', compile: compileCheckIdExists }); } function checkWordOnServer(str) { 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'); } function check(IDs) { return Promise.resolve(IDs.indexOf(data) >= 0); } } function checkIdExistsWithError(schema, data) { 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'); } function check(_table, IDs) { 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])); } } 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'); } function compileCheck(IDs) { return function (data) { return Promise.resolve(IDs.indexOf(data) >= 0); }; } } ajv-5.0.0/spec/async_validate.spec.js000066400000000000000000000301401307514663700175150ustar00rootroot00000000000000'use strict'; var Ajv = require('./ajv') , Promise = require('./promise') , getAjvInstances = require('./ajv_async_instances') , should = require('./chai').should() , co = require('co') , setupAsync = require('ajv-async'); describe('async schemas, formats and keywords', function() { this.timeout(30000); var ajv, instances; beforeEach(function () { instances = getAjvInstances(); ajv = instances[0]; }); function useCo(_ajv) { var async = _ajv._opts.async; return async == 'es7' || async == 'co*' ? identity : co; } function identity(x) { return x; } describe('async schemas without async elements', function() { it('should return result as promise', function() { var schema = { $async: true, type: 'string', maxLength: 3 }; return repeat(function() { return Promise.all(instances.map(test)); }); function test(_ajv) { var validate = _ajv.compile(schema); var _co = useCo(_ajv); return Promise.all([ shouldBeValid( _co(validate('abc')), 'abc' ), shouldBeInvalid( _co(validate('abcd')) ), shouldBeInvalid( _co(validate(1)) ), ]); } }); 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; ajv.compile(schema); }); }); describe('async formats', function() { beforeEach(addFormatEnglishWord); 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() { instances.forEach(function (_ajv) { _ajv.addKeyword('idExists', { async: true, type: 'number', validate: checkIdExists, errors: false }); _ajv.addKeyword('idExistsWithError', { async: true, type: 'number', validate: checkIdExistsWithError, errors: true }); }); }); it('should fail compilation if async keyword is inside sync schema', function() { instances.forEach(function (_ajv) { var schema = { type: 'object', properties: { userId: { type: 'integer', idExists: { table: 'users' } } } }; 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' } }, postId: { type: 'integer', idExistsWithError: { table: 'posts' } } } }; var validate = _ajv.compile(schema); var _co = useCo(_ajv); return Promise.all([ shouldBeInvalid(_co(validate({ userId: 5, postId: 10 })), [ 'id not found in table posts' ]), shouldBeInvalid(_co(validate({ userId: 9, postId: 25 })), [ 'id not found in table users' ]) ]); })); }); 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'); } function check(IDs) { return Promise.resolve(IDs.indexOf(data) >= 0); } } function checkIdExistsWithError(schema, data) { 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'); } function check(_table, IDs) { 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])); } } }); describe('async referenced schemas', function() { beforeEach(function() { instances = getAjvInstances({ inlineRefs: false, extendRefs: 'ignore' }); addFormatEnglishWord(); }); it('should validate referenced async schema', function() { var schema = { $async: true, definitions: { english_word: { $async: true, 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 _co = useCo(_ajv); var validData = { word: 'tomorrow' }; return Promise.all([ shouldBeValid( _co(validate(validData)), validData ), shouldBeInvalid( _co(validate({ word: 'manana' })) ), shouldBeInvalid( _co(validate({ word: 1 })) ), shouldThrow( _co(validate({ word: 'today' })), 'unknown word' ) ]); })); }); }); it('should validate recursive async schema', function() { var schema = { $async: true, definitions: { english_word: { $async: true, type: 'string', format: 'english_word' } }, type: 'object', properties: { foo: { anyOf: [ { $ref: '#/definitions/english_word' }, { $ref: '#' } ] } } }; return recursiveTest(schema); }); it('should validate ref from referenced async schema to root schema', function() { var schema = { $async: true, definitions: { wordOrRoot: { $async: true, anyOf: [ { type: 'string', format: 'english_word' }, { $ref: '#' } ] } }, type: 'object', properties: { foo: { $ref: '#/definitions/wordOrRoot' } } }; return recursiveTest(schema); }); it('should validate refs between two async schemas', function() { var schemaObj = { id: 'http://e.com/obj.json#', $async: true, type: 'object', properties: { foo: { $ref: 'http://e.com/word.json#' } } }; var schemaWord = { id: 'http://e.com/word.json#', $async: true, anyOf: [ { type: 'string', format: 'english_word' }, { $ref: 'http://e.com/obj.json#' } ] }; return recursiveTest(schemaObj, schemaWord); }); it('should fail compilation if sync schema references async schema', function() { var schema = { id: 'http://e.com/obj.json#', type: 'object', properties: { foo: { $ref: 'http://e.com/word.json#' } } }; var schemaWord = { id: 'http://e.com/word.json#', $async: true, anyOf: [ { type: 'string', format: 'english_word' }, { $ref: 'http://e.com/obj.json#' } ] }; ajv.addSchema(schemaWord); ajv.addFormat('english_word', { async: true, validate: checkWordOnServer }); shouldThrowFunc('async schema referenced by sync schema', function() { ajv.compile(schema); }); schema.id = 'http://e.com/obj2.json#'; schema.$async = true; 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 _co = useCo(_ajv); var data; return Promise.all([ shouldBeValid( _co(validate(data = { foo: 'tomorrow' })), data ), shouldBeInvalid( _co(validate({ foo: 'manana' })) ), shouldBeInvalid( _co(validate({ foo: 1 })) ), shouldThrow( _co(validate({ foo: 'today' })), 'unknown word' ), shouldBeValid( _co(validate(data = { foo: { foo: 'tomorrow' }})), data ), shouldBeInvalid( _co(validate({ foo: { foo: 'manana' }})) ), shouldBeInvalid( _co(validate({ foo: { foo: 1 }})) ), shouldThrow( _co(validate({ foo: { foo: 'today' }})), 'unknown word' ), shouldBeValid( _co(validate(data = { foo: { foo: { foo: 'tomorrow' }}})), data ), shouldBeInvalid( _co(validate({ foo: { foo: { foo: 'manana' }}})) ), shouldBeInvalid( _co(validate({ foo: { foo: { foo: 1 }}})) ), shouldThrow( _co(validate({ foo: { foo: { foo: 'today' }}})), 'unknown word' ) ]); })); }); } }); function addFormatEnglishWord() { instances.forEach(function (_ajv) { _ajv.addFormat('english_word', { async: true, validate: checkWordOnServer }); }); } }); describe('async/transpile option', function() { it('should throw error with unknown async option', function() { shouldThrowFunc('bad async mode: es8', function() { setupAsync(new Ajv({ async: 'es8' })); }); }); it('should throw error with unknown transpile option', function() { shouldThrowFunc('bad transpiler: babel', function() { setupAsync(new Ajv({ transpile: 'babel' })); }); shouldThrowFunc('bad transpiler: [object Object]', function() { setupAsync(new Ajv({ transpile: {} })); }); }); it('should set async option to es7 if tranpiler is nodent', function() { var ajv1 = setupAsync(new Ajv({ transpile: 'nodent' })); ajv1._opts.async .should.equal('es7'); var ajv2 = setupAsync(new Ajv({ async: '*', transpile: 'nodent' })); ajv2._opts.async .should.equal('es7'); }); }); function checkWordOnServer(str) { return str == 'tomorrow' ? Promise.resolve(true) : str == 'manana' ? Promise.resolve(false) : Promise.reject(new Error('unknown word')); } function shouldThrowFunc(message, func) { var err; should.throw(function() { try { func(); } catch(e) { err = e; throw e; } }); err.message .should.equal(message); } function shouldBeValid(p, data) { return p.then(function (valid) { valid .should.equal(data); }); } 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); if (expectedMessages) { var messages = err.errors.map(function (e) { return e.message; }); messages .should.eql(expectedMessages); } }); } function shouldThrow(p, 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; }); } function repeat(func) { return func(); // var promises = []; // for (var i=0; i<1000; i++) promises.push(func()); // return Promise.all(promises); } ajv-5.0.0/spec/boolean.spec.js000066400000000000000000000304671307514663700161620ustar00rootroot00000000000000'use strict'; var Ajv = require('./ajv'); require('./chai').should(); describe('boolean schemas', function() { var ajvs; 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('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); }; } }); 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)); }); }); function test(boolSchema, valid) { return function (ajv) { var schema = { type: 'object', properties: { foo: boolSchema, bar: { 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); }; } }); 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)); }); }); function test(boolSchema, valid) { return function (ajv) { var schema = { 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); validate([]) .should.equal(true); schema = { type: 'array', items: [ true, { 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); }; } }); 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)); }); }); function test(boolSchema, valid) { return function (ajv) { var schema = { type: 'object', dependencies: { foo: boolSchema, bar: { 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); }; } }); 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)); }); }); function test(boolSchema, valid) { return function (ajv) { var schema = { type: 'object', patternProperties: { '^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); }; } }); 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)); }); }); function test(boolSchema, valid) { return function (ajv) { var schema = { type: 'object', propertyNames: boolSchema }; var validate = ajv.compile(schema); validate({ foo: 1 }) .should.equal(valid); validate({ bar: 1 }) .should.equal(valid); 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('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); }; } }); 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)); }); }); function test(boolSchema, valid) { return function (ajv) { var schema = { not: boolSchema }; 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('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 ] }; var validate = ajv.compile(schema); testSchema(validate, false); schema = { allOf: [ true, boolSchema ] }; 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('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 ] }; var validate = ajv.compile(schema); testSchema(validate, valid); schema = { anyOf: [ true, boolSchema ] }; 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('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 ] }; var validate = ajv.compile(schema); testSchema(validate, valid); schema = { oneOf: [ true, boolSchema ] }; 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('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', definitions: { bool: boolSchema } }; 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); } }); ajv-5.0.0/spec/browser_test_suite.js000066400000000000000000000002131307514663700175270ustar00rootroot00000000000000'use strict'; module.exports = function (suite) { suite.forEach(function (file) { file.test = file.module; }); return suite; }; ajv-5.0.0/spec/chai.js000066400000000000000000000001401307514663700144770ustar00rootroot00000000000000'use strict'; module.exports = typeof window == 'object' ? window.chai : require('' + 'chai'); ajv-5.0.0/spec/coercion.spec.js000066400000000000000000000257141307514663700163430ustar00rootroot00000000000000'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' } ], 'null': [ { from: null, to: '' } ], 'object': [ { from: {}, 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 } ], 'boolean': [ { from: false, to: 0 }, { from: true, to: 1 } ], 'null': [ { from: null, to: 0 } ], '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 } ], 'null': [ { from: null, to: 0 } ], 'object': [ { from: {}, 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 } ], 'number': [ { from: 0, to: false }, { from: 1, to: true }, { from: 2, to: undefined }, { from: 2.5, to: undefined } ], 'null': [ { from: null, to: false } ], '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 } ], 'number': [ { from: 0, to: null }, { from: 1, to: undefined } ], 'boolean': [ { from: false, to: null }, { from: true, to: undefined } ], 'object': [ { from: {}, 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 } ] }, '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)); coercionArrayRules.string.array = [ { 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 } ]; 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*/) { instances.forEach(function (_ajv) { 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) { 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 schemaObject = { type: 'object', properties: { foo: schema } }; var schemaArray = { type: 'array', items: schema }; var schemaArrObj = { 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 } ]); }); function testCoercion(_ajv, _schema, fromData, toData) { var valid = _ajv.validate(_schema, fromData); //if (valid !== canCoerce) console.log(schema, fromData, toData); valid. should.equal(canCoerce); if (valid) fromData.should.eql(toData); } }); }); it('should coerce to multiple types in order', function() { var schema = { type: 'object', properties: { foo: { type: [ 'number', 'boolean', 'null' ] } } }; instances.forEach(function (_ajv) { var data; _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: '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: 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: '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 }); }); it('should fail to coerce non-number if multiple properties/items are coerced (issue #152)', function() { var schema = { type: 'object', properties: { 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' }); 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 })); var schema = { type: 'object', definitions: { foo: { type: 'number' } }, properties: { foo: { $ref: '#/definitions/foo' } } }; var schema2 = { 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' }] }, bar: { type: 'number' } }, properties: { foo: { $ref: '#/definitions/foo' } } }; var schemaRecursive = { type: [ 'object', 'number' ], properties: { foo: { $ref: '#' } } }; var schemaRecursive2 = { id: 'http://e.com/schema.json#', definitions: { foo: { id: 'http://e.com/foo.json#', type: [ 'object', 'number' ], properties: { foo: { $ref: '#' } } } }, properties: { 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 } } }); function testCoercion(_schema, fromData, toData) { var valid = _ajv.validate(_schema, fromData); // if (!valid) console.log(schema, fromData, toData); valid. should.equal(true); fromData .should.eql(toData); } }); }); function testRules(rules, cb) { for (var toType in rules) { for (var fromType in rules[toType]) { var tests = rules[toType][fromType]; tests.forEach(function (test) { 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); }); } } } }); ajv-5.0.0/spec/custom.spec.js000066400000000000000000001032201307514663700160410ustar00rootroot00000000000000'use strict'; 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; 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 }); function validateEven(schema, data) { 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() { testEvenKeyword({ type: 'number', validate: validateEven, metaSchema: { "type": "boolean" } }); shouldBeInvalidSchema({ "x-even": "not_boolean" }); function validateEven(schema, data) { return data % 2 ? !schema : schema; } }); it('should pass parent schema to "interpreted" keyword validation', function() { testRangeKeyword({ type: 'number', validate: validateRange }); function validateRange(schema, data, parentSchema) { validateRangeSchema(schema, parentSchema); return parentSchema.exclusiveRange === true ? 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() { testRangeKeyword({ 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 ] }); function validateRange(schema, data, parentSchema) { return parentSchema.exclusiveRange === true ? 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); function validateRange(schema, data, parentSchema) { 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; if (!valid) { var err = { keyword: 'x-range' }; validateRange.errors = [err]; var comparison, limit; if (minOk) { comparison = exclusive ? '<' : '<='; limit = max; } else { comparison = exclusive ? '>' : '>='; limit = min; } err.message = 'should be ' + comparison + ' ' + limit; err.params = { comparison: comparison, limit: limit, exclusive: exclusive }; } 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" }); function compileEven(schema) { 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; } }); it('should add, validate keyword schema and validate rule', function() { testEvenKeyword({ type: 'number', compile: compileEven, metaSchema: { "type": "boolean" } }); shouldBeInvalidSchema({ "x-even": "not_boolean" }); function compileEven(schema) { 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 }); }); it('should allow multiple schemas for the same keyword', function () { testMultipleConstantKeyword({ compile: compileConstant }); }); 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; function isDeepEqual(data) { return equal(data, schema); } function isStrictEqual(data) { return data === schema; } } function compileRange(schema, parentSchema) { validateRangeSchema(schema, parentSchema); 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; }; } }); 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 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 allow multiple parent schemas for the same macro keyword', function () { testMultipleRangeKeyword({ type: 'number', macro: macroRange }, 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 }); var schema = { "deepProperties": { "a.b.c": { "type": "number", "range": [2,4] }, "d.e.f.g": { "type": "string" } } }; /* This schema recursively expands to: { "allOf": [ { "properties": { "a": { "properties": { "b": { "properties": { "c": { "type": "number", "minimum": 2, "exclusiveMinimum": false, "maximum": 4, "exclusiveMaximum": false } } } } } } }, { "properties": { "d": { "properties": { "e": { "properties": { "f": { "properties": { "g": { "type": "string" } } } } } } } } } ] } */ 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); 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'); var expanded = []; for (var prop in _schema) { var path = prop.split('.'); var properties = {}; if (path.length == 1) { properties[prop] = _schema[prop]; } else { var deepProperties = {}; deepProperties[path.slice(1).join('.')] = _schema[prop]; properties[path[0]] = { "deepProperties": deepProperties }; } expanded.push({ "properties": properties }); } return expanded.length == 1 ? expanded[0] : { "allOf": expanded }; } }); }); 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 }); 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() { instances.forEach(function (_ajv) { _ajv.addKeyword('range', { type: 'number', macro: macroRange }); var schema = { "range": [1,4], "minimum": 2.5 }; var validate = _ajv.compile(schema); shouldBeValid(validate, 3); shouldBeInvalid(validate, 2); }); }); it('should correctly expand macros in subschemas', function() { instances.forEach(function (_ajv) { _ajv.addKeyword('range', { type: 'number', macro: macroRange }); var schema = { "allOf": [ { "range": [4,8] }, { "range": [2,6] } ] }; 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); }); }); it('should correctly expand macros in macro expansions', function() { instances.forEach(function (_ajv) { _ajv.addKeyword('range', { type: 'number', macro: macroRange }); _ajv.addKeyword('myContains', { type: 'array', macro: macroContains }); var schema = { "myContains": { "type": "number", "range": [4,7], "exclusiveRange": true } }; 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); function macroContains(_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 }; should.throw(function() { ajv.compile(schema); }); function macroInvalid(/* schema */) { 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'); } function macroConstant(schema/*, parentSchema */) { return { "enum": [schema] }; } function macroRange(schema, parentSchema) { validateRangeSchema(schema, parentSchema); var exclusive = !!parentSchema.exclusiveRange; return exclusive ? { 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 }); }); 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; testRangeKeyword({ type: 'number', inline: inlineRangeTemplate, statements: true }); }); it('should define "inline" keyword without errors', function() { var inlineRangeTemplate = customRules.range; testRangeKeyword({ type: 'number', inline: inlineRangeTemplate, statements: true, errors: false }); }); 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, errors: true }, true); }); function inlineEven(it, keyword, schema) { 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 + ';'; } }); 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() { testEvenKeyword$data({ type: 'number', $data: true, validate: validateEven }); function validateEven(schema, data) { if (typeof schema != 'boolean') return false; return data % 2 ? !schema : schema; } }); it('should validate rule with "compile" and "validate" funcs', function() { var compileCalled; testEvenKeyword$data({ type: 'number', $data: true, compile: compileEven, validate: validateEven }); compileCalled .should.equal(true); function validateEven(schema, data) { 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; } 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; testEvenKeyword$data({ type: 'number', $data: true, compile: compileEven, validate: validateEven, metaSchema: { "type": "boolean" } }); compileCalled .should.equal(true); shouldBeInvalidSchema({ "x-even-$data": "false" }); function validateEven(schema, data) { return data % 2 ? !schema : schema; } function compileEven(schema) { compileCalled = true; return schema ? isEven : isOdd; } 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); function validateEven(schema, data) { 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'); } }); 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; } function macroEven(schema) { 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; testEvenKeyword$data({ type: 'number', $data: true, inline: inlineEven, validate: validateEven }); inlineCalled .should.equal(true); function validateEven(schema, data) { 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'; } }); it('should validate with "inline" and "validate" funcs with meta-schema', function() { var inlineCalled; testEvenKeyword$data({ type: 'number', $data: true, inline: inlineEven, validate: validateEven, metaSchema: { "type": "boolean" } }); inlineCalled .should.equal(true); shouldBeInvalidSchema({ "x-even-$data": "false" }); function validateEven(schema, data) { return data % 2 ? !schema : schema; } function inlineEven(it, keyword, schema) { 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', $data: true, 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); }); } function testEvenKeyword$data(definition, numErrors) { instances.forEach(function (_ajv) { _ajv.addKeyword('x-even-$data', definition); 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); 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 }); 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 }); }); } function testConstantKeyword(definition, numErrors) { instances.forEach(function (_ajv) { _ajv.addKeyword('myConstant', definition); var schema = { "myConstant": "abc" }; var validate = _ajv.compile(schema); shouldBeValid(validate, 'abc'); shouldBeInvalid(validate, 2, numErrors); shouldBeInvalid(validate, {}, numErrors); }); } function testMultipleConstantKeyword(definition, numErrors) { instances.forEach(function (_ajv) { _ajv.addKeyword('x-constant', definition); var schema = { "properties": { "a": { "x-constant": 1 }, "b": { "x-constant": 1 } }, "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, c: {foo: 'bar'}}); shouldBeInvalid(validate, {a:1, c: {foo: 'baz'}}, numErrors); shouldBeValid(validate, [{foo: 'bar'}]); shouldBeValid(validate, [{foo: 'bar'}, {foo: 'bar'}]); shouldBeInvalid(validate, [1], numErrors); }); } function testRangeKeyword(definition, customErrors, numErrors) { instances.forEach(function (_ajv) { _ajv.addKeyword('x-range', definition); var schema = { "x-range": [2, 4] }; var validate = _ajv.compile(schema); 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); schema = { "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); }); } function testMultipleRangeKeyword(definition, numErrors) { instances.forEach(function (_ajv) { _ajv.addKeyword('x-range', definition); var schema = { "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); 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, [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', dataPath: dataPath, schemaPath: schemaPath, message: 'should be ' + comparison + ' ' + limit, params: { comparison: comparison, limit: limit, 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'); } function shouldBeValid(validate, data) { 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); } function shouldBeInvalidSchema(schema) { instances.forEach(function (_ajv) { should.throw(function() { _ajv.compile(schema); }); }); } 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'); function testThrow(keywords) { TEST_TYPES.forEach(function (dataType, index) { should.throw(function(){ addKeyword(keywords[index], dataType); }); }); } function testThrowDuplicate(keywordPrefix) { 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); }); }); }); } }); 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 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() {} }); } }); 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() { 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', // make minimum exclusive 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); }); }); 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); }); function testModifying(withOption) { var collectionFormat = { csv: function (data, dataPath, parentData, parentDataProperty) { parentData[parentDataProperty] = data.split(','); return true; } }; ajv.addKeyword('collectionFormat', { type: 'string', modifying: withOption, compile: function(schema) { return collectionFormat[schema]; }, metaSchema: { enum: ['csv'] } }); var validate = ajv.compile({ type: 'object', properties: { foo: { allOf: [ { collectionFormat: 'csv' }, { type: 'array', items: { type: 'string' }, } ] } }, additionalProperties: false }); var obj = { 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 }); }); }); }); }); ajv-5.0.0/spec/custom_rules/000077500000000000000000000000001307514663700157665ustar00rootroot00000000000000ajv-5.0.0/spec/custom_rules/index.js000066400000000000000000000004101307514663700174260ustar00rootroot00000000000000'use strict'; 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')) }; ajv-5.0.0/spec/custom_rules/range.jst000066400000000000000000000004721307514663700176070ustar00rootroot00000000000000{{ var $data = 'data' + (it.dataLevel || '') , $min = it.schema['x-range'][0] , $max = it.schema['x-range'][1] , $gt = it.schema.exclusiveRange ? '>' : '>=' , $lt = it.schema.exclusiveRange ? '<' : '<='; }} var valid{{=it.level}} = {{=$data}} {{=$gt}} {{=$min}} && {{=$data}} {{=$lt}} {{=$max}}; ajv-5.0.0/spec/custom_rules/range_with_errors.jst000066400000000000000000000017751307514663700222450ustar00rootroot00000000000000{{ var $data = 'data' + (it.dataLevel || '') , $min = it.schema['x-range'][0] , $max = it.schema['x-range'][1] , $exclusive = !!it.schema.exclusiveRange , $gt = $exclusive ? '>' : '>=' , $lt = $exclusive ? '<' : '<=' , $lvl = it.level , $err = 'err' + $lvl; }} var minOk{{=$lvl}} = {{=$data}} {{=$gt}} {{=$min}}; var valid{{=$lvl}} = minOk{{=$lvl}} && {{=$data}} {{=$lt}} {{=$max}}; if (!valid{{=$lvl}}) { var {{=$err}}; if (minOk{{=$lvl}}) { {{=$err}} = { keyword: 'x-range', message: 'should be {{=$lt}} {{=$max}}', params: { comparison: '{{=$lt}}', limit: {{=$max}}, exclusive: {{=$exclusive}} } }; } else { {{=$err}} = { keyword: 'x-range', message: 'should be {{=$gt}} {{=$min}}', params: { comparison: '{{=$gt}}', limit: {{=$min}}, exclusive: {{=$exclusive}} } }; } errors++; if (vErrors) vErrors[vErrors.length] = {{=$err}}; else vErrors = [{{=$err}}]; } ajv-5.0.0/spec/equal.spec.js000066400000000000000000000034241307514663700156430ustar00rootroot00000000000000'use strict'; var equal = require('../lib/compile/equal'); require('./chai').should(); describe('equal', function() { it('should compare scalars', function() { equal(1, 1) .should.equal(true); equal(1, 2) .should.equal(false); equal(1, []) .should.equal(false); equal(0, null) .should.equal(false); equal('a', 'a') .should.equal(true); equal('a', 'b') .should.equal(false); equal('', null) .should.equal(false); equal(null, null) .should.equal(true); equal(true, true) .should.equal(true); equal(true, false) .should.equal(false); equal(true, 1) .should.equal(false); equal(false, 0) .should.equal(false); }); it('should compare objects', function() { equal({a: 1, b: '2'}, {b: '2', a: 1}) .should.equal(true); equal({a: 1, b: '2'}, {b: '2', a: 1, c: []}) .should.equal(false); equal({a: 1, b: '2', c: 3}, {b: '2', a: 1, d: 3}) .should.equal(false); equal({b: '2', a: 1, d: 3}, {a: 1, b: '2', c: 3}) .should.equal(false); equal({a: 1, b: '2'}, {a: 1, b: '2'}) .should.equal(true); equal({ a: [ { b: 'c' } ] }, { a: [ { b: 'c' } ] }) .should.equal(true); equal({ a: [ { b: 'c' } ] }, { a: [ { b: 'd' } ] }) .should.equal(false); equal({ a: [ { b: 'c' } ] }, { a: [ { c: 'c' } ] }) .should.equal(false); equal({}, []) .should.equal(false); equal({}, {}) .should.equal(true); }); it('should compare arrays', function() { equal([1, 2, 3], [1, 2, 3]) .should.equal(true); equal([1, 2, 3], [1, 2, 4]) .should.equal(false); equal([1, 2, 3], [1, 2]) .should.equal(false); equal([{a: 'a'}, {b: 'b'}], [{a: 'a'}, {b: 'b'}]) .should.equal(true); equal([{a: 'a'}, {b: 'b'}], [{a: 'a'}, {b: 'c'}]) .should.equal(false); equal({'0': 0, '1': 1, length: 2}, [0, 1]) .should.equal(false); }); }); ajv-5.0.0/spec/errors.spec.js000066400000000000000000000507141307514663700160540ustar00rootroot00000000000000'use strict'; var Ajv = require('./ajv') , should = require('./chai').should(); describe('Validation errors', function () { var ajv, ajvJP, fullAjv; 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 }); } it('error should include dataPath', function() { var schema = { properties: { foo: { type: 'number' } } }; testSchema1(schema); }); it('"refs" error should include dataPath', function() { var schema = { definitions: { num: { type: 'number' } }, properties: { 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'); }); it('should NOT include property in dataPath WITHOUT option errorDataPath', function() { testAdditional(); }); function testAdditional(errorDataPath) { var schema = { properties: { foo: {}, bar: {} }, additionalProperties: false }; var data = { foo: 1, bar: 2 } , invalidData = { foo: 1, bar: 2, baz: 3, quux: 4 }; var path = pathFunc(errorDataPath); var validate = ajv.compile(schema); shouldBeValid(validate, data); shouldBeInvalid(validate, invalidData); shouldBeError(validate.errors[0], 'additionalProperties', '#/additionalProperties', path("['baz']"), undefined, { additionalProperty: 'baz' }); var validateJP = ajvJP.compile(schema); shouldBeValid(validateJP, data); shouldBeInvalid(validateJP, invalidData); shouldBeError(validateJP.errors[0], 'additionalProperties', '#/additionalProperties', path("/baz"), undefined, { additionalProperty: 'baz' }); var fullValidate = fullAjv.compile(schema); shouldBeValid(fullValidate, data); shouldBeInvalid(fullValidate, invalidData, 2); shouldBeError(fullValidate.errors[0], 'additionalProperties', '#/additionalProperties', path('/baz'), undefined, { additionalProperty: 'baz' }); shouldBeError(fullValidate.errors[1], 'additionalProperties', '#/additionalProperties', path('/quux'), undefined, { 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 }); } } }); 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(); }); function testAdditionalIsSchema() { var schema = { properties: { foo: { type: 'integer' }, bar: { type: 'integer' } }, additionalProperties: { 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' }); 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'); }); it('should NOT include missing property in dataPath WITHOUT option errorDataPath', function() { testRequired(); }); function testRequired(errorDataPath) { var schema = { required: ['foo', 'bar', 'baz'] }; _testRequired(errorDataPath, schema, '#', '.'); } it('large data/schemas with option errorDataPath="property"', function() { createInstances('property'); testRequiredLargeSchema('property'); }); 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; } 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 = msgFunc(errorDataPath); test(); 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' }); } } it('with "properties" with option errorDataPath="property"', function() { createInstances('property'); testRequiredAndProperties('property'); }); it('with "properties" WITHOUT option errorDataPath', function() { testRequiredAndProperties(); }); function testRequiredAndProperties(errorDataPath) { var schema = { properties: { 'foo': { type: 'number' }, 'bar': { type: 'number' }, 'baz': { type: 'number' }, }, required: ['foo', 'bar', 'baz'] }; _testRequired(errorDataPath, schema); } it('in "anyOf" with option errorDataPath="property"', function() { createInstances('property'); testRequiredInAnyOf('property'); }); it('in "anyOf" WITHOUT option errorDataPath', function() { testRequiredInAnyOf(); }); function testRequiredInAnyOf(errorDataPath) { var schema = { anyOf: [ { required: ['foo', 'bar', 'baz'] } ] }; _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 }); var schema = { properties: { foo: { type: 'integer' }, bar: { type: 'integer' } }, required: ['foo', 'bar'] }; 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 }); var schema = { properties: { foo: { type: 'integer' }, bar: { type: 'integer' } }, required: { $data: '0/requiredProperties' } }; 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'); }); 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')); function params(missing) { var 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 = msgFunc(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 : ''; }; } function msgFunc(errorDataPath) { return function (prop) { return errorDataPath == 'property' ? 'is a required property' : 'should have required property \'' + prop + '\''; }; } it('"items" errors should include item index without quotes in dataPath (#48)', function() { var schema1 = { 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 }] }; 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 }; var data = [ 1, 2 ] , invalidData = [ 1, 2, 3 ]; 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'); } }); describe('"propertyNames" errors', function() { it('should add propertyName to errors', function() { var schema = { type: 'object', propertyNames: { format: 'email' } }; var data = { 'bar.baz@email.example.com': {} }; var invalidData = { 'foo': {}, 'bar': {}, 'bar.baz@email.example.com': {} }; 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'); 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'); } } }); }); describe('oneOf errors', function() { it('should have errors from inner schemas', function() { var schema = { oneOf: [ { type: 'number' }, { type: 'integer' } ] }; 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); } }); }); describe('anyOf errors', function() { it('should have errors from inner schemas', function() { var schema = { anyOf: [ { type: 'number' }, { type: 'integer' } ] }; 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); } }); }); function testSchema1(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'); } function shouldBeValid(validate, data) { 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); } 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); } }); ajv-5.0.0/spec/extras.spec.js000066400000000000000000000014631307514663700160430ustar00rootroot00000000000000'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 instances = getAjvInstances(options, { $data: true, patternGroups: true, unknownFormats: ['allowedUnknown'] }); jsonSchemaTest(instances, { 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' }, assert: require('./chai').assert, afterError: after.error, afterEach: after.each, cwd: __dirname, hideFolder: 'extras/', timeout: 90000 }); ajv-5.0.0/spec/extras/000077500000000000000000000000001307514663700145505ustar00rootroot00000000000000ajv-5.0.0/spec/extras/$data/000077500000000000000000000000001307514663700155255ustar00rootroot00000000000000ajv-5.0.0/spec/extras/$data/absolute_ref.json000066400000000000000000000211021307514663700210660ustar00rootroot00000000000000[ { "description": "property is equal to another property [absolute JSON pointer]", "schema": { "properties": { "sameAs": { "const": { "$data": "/thisOne" } }, "thisOne": {} } }, "tests": [ { "description": "same value is valid", "data": { "sameAs": 5, "thisOne": 5 }, "valid": true }, { "description": "same object is valid", "data": { "sameAs": { "foo": 1, "bar": 2 }, "thisOne": { "bar": 2, "foo": 1 } }, "valid": true }, { "description": "another value is invalid", "data": { "sameAs": { "foo": 1 }, "thisOne": { "foo": 2 } }, "valid": false }, { "description": "another type is invalid", "data": { "sameAs": 5, "thisOne": "5" }, "valid": false } ] }, { "description": "items in one array are equal to items in another (limited length) [absolute JSON pointer]", "schema": { "properties": { "arr": { "items": [ {}, {}, {} ], "additionalItems": false }, "sameArr": { "items": [ { "const": { "$data": "/arr/0" } }, { "const": { "$data": "/arr/1" } }, { "const": { "$data": "/arr/2" } } ], "additionalItems": false } } }, "tests": [ { "description": "equal arrays are valid", "data": { "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" } ] }, "valid": false } ] }, { "description": "property value is contained in array [absolute JSON pointer]", "schema": { "properties": { "name": { "type": "string" }, "list": { "type": "array", "contains": { "const": { "$data": "/name" } } } } }, "tests": [ { "description": "1 item array containing property is valid", "data": { "name": "foo", "list": [ "foo" ] }, "valid": true }, { "description": "2 item array containing property is valid", "data": { "name": "foo", "list": [ "foo", "bar" ] }, "valid": true }, { "description": "array not containing property is invalid", "data": { "name": "foo", "list": [ "bar" ] }, "valid": false }, { "description": "empty array is invalid", "data": { "name": "foo", "list": [] }, "valid": false } ] }, { "description": "property is one of values in another property [absolute JSON pointer]", "schema": { "properties": { "allowedValues": {}, "value": { "enum": { "$data": "/allowedValues" } } } }, "tests": [ { "description": "one of the enum is valid", "data": { "allowedValues": [ 1, 2, 3 ], "value": 1 }, "valid": true }, { "description": "something else is invalid", "data": { "allowedValues": [ 1, 2, 3 ], "value": 4 }, "valid": false }, { "description": "heterogeneous enum validation", "data": { "allowedValues": [ 6, "foo", [], true, { "foo": 12 } ], "value": { "foo": 12 } }, "valid": true }, { "description": "fail if value of enum is not an array", "data": { "allowedValues": "[1, 2, 3]", "value": 1 }, "valid": false }, { "description": "valid if value of enum is undefined", "data": { "value": 1 }, "valid": true } ] }, { "description": "enum in properties [absolute JSON pointer]", "schema": { "properties": { "allowedValues": {} }, "additionalProperties": { "enum": { "$data": "/allowedValues" } } }, "tests": [ { "description": "properties are valid", "data": { "allowedValues": [ "foo", "bar" ], "a": "foo", "b": "bar" }, "valid": true }, { "description": "properties are invalid", "data": { "allowedValues": [ "foo", "bar" ], "a": "foo", "b": "baz" }, "valid": false } ] }, { "description": "required schema in data property [absolute JSON pointer]", "schema": { "properties": { "foo": {}, "bar": {}, "requiredProperties": {} }, "required": { "$data": "/requiredProperties" } }, "tests": [ { "description": "present required property is valid", "data": { "foo": 1, "requiredProperties": [ "foo" ] }, "valid": true }, { "description": "non-present required property is invalid", "data": { "bar": 2, "requiredProperties": [ "foo" ] }, "valid": false }, { "description": "non-present second required property is invalid", "data": { "foo": 1, "requiredProperties": [ "foo", "bar" ] }, "valid": false }, { "description": "two present required properties is valid", "data": { "foo": 1, "bar": 2, "requiredProperties": [ "foo", "bar" ] }, "valid": true }, { "description": "fails if value of required is not an array", "data": { "foo": 1, "bar": 2, "requiredProperties": true }, "valid": false }, { "description": "valid if value of required is undefined", "data": { "foo": 1, "bar": 2 }, "valid": true } ] }, { "description": "absolute JSON pointer can access data outside of a $ref", "schema": { "definitions": { "baz": { "type": "object", "properties": { "foo": { "const": { "$data": "/bar" } }, "bar": {} } } }, "properties": { "foo": { "const": { "$data": "/bar" } }, "bar": {}, "baz": { "$ref": "#/definitions/baz" } } }, "tests": [ { "description": "$data reference with absolute JSON pointer resolves from root of data", "data": { "foo": 1, "bar": 1, "baz": { "foo": 1, "bar": 2 } }, "valid": true }, { "description": "$data reference with absolute JSON pointer should NOT resolve to root of $ref", "data": { "foo": 2, "bar": 2, "baz": { "foo": 1, "bar": 1 } }, "valid": false } ] } ]ajv-5.0.0/spec/extras/$data/const.json000066400000000000000000000103741307514663700175530ustar00rootroot00000000000000[ { "description": "property is equal to another property", "schema": { "properties": { "sameAs": { "const": { "$data": "1/thisOne" } }, "thisOne": {} } }, "tests": [ { "description": "same value is valid", "data": { "sameAs": 5, "thisOne": 5 }, "valid": true }, { "description": "same object is valid", "data": { "sameAs": { "foo": 1, "bar": 2 }, "thisOne": { "bar": 2, "foo": 1 } }, "valid": true }, { "description": "another value is invalid", "data": { "sameAs": { "foo": 1 }, "thisOne": { "foo": 2 } }, "valid": false }, { "description": "another type is invalid", "data": { "sameAs": 5, "thisOne": "5" }, "valid": false } ] }, { "description": "property values are equal to property names", "schema": { "additionalProperties": { "const": { "$data": "0#" } } }, "tests": [ { "description": "valid object", "data": { "foo": "foo", "bar": "bar", "baz": "baz" }, "valid": true }, { "description": "invalid object", "data": { "foo": "bar" }, "valid": false } ] }, { "description": "items are equal to their indeces", "schema": { "items": { "const": { "$data": "0#" } } }, "tests": [ { "description": "valid array", "data": [ 0, 1, 2, 3 ], "valid": true }, { "description": "invalid array", "data": [ 0, 2 ], "valid": false } ] }, { "description": "items in one array are equal to items in another (limited length)", "schema": { "properties": { "arr": { "items": [{},{},{}], "additionalItems": false }, "sameArr": { "items": [ { "const": { "$data": "2/arr/0" } }, { "const": { "$data": "2/arr/1" } }, { "const": { "$data": "2/arr/2" } } ], "additionalItems": false } } }, "tests": [ { "description": "equal arrays are valid", "data": { "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"} ] }, "valid": false } ] }, { "description": "any data is equal to itself", "schema": { "const": { "$data": "0" } }, "tests": [ { "description": "number is equal to itself", "data": 1, "valid": true }, { "description": "string is equal to itself", "data": "foo", "valid": true }, { "description": "object is equal to itself", "data": { "foo": "bar" }, "valid": true }, { "description": "array is equal to itself", "data": [ 1, 2, 3 ], "valid": true } ] }, { "description": "property value is contained in array", "schema": { "properties": { "name": { "type": "string" }, "list": { "type": "array", "contains": { "const": { "$data": "2/name" } } } } }, "tests": [ { "description": "1 item array containing property is valid", "data": { "name": "foo", "list": [ "foo" ] }, "valid": true }, { "description": "2 item array containing property is valid", "data": { "name": "foo", "list": [ "foo", "bar" ] }, "valid": true }, { "description": "array not containing property is invalid", "data": { "name": "foo", "list": [ "bar" ] }, "valid": false }, { "description": "empty array is invalid", "data": { "name": "foo", "list": [] }, "valid": false } ] } ] ajv-5.0.0/spec/extras/$data/enum.json000066400000000000000000000034161307514663700173700ustar00rootroot00000000000000[ { "description": "property is one of values in another property", "schema": { "properties": { "allowedValues": {}, "value": { "enum": { "$data": "1/allowedValues" } } } }, "tests": [ { "description": "one of the enum is valid", "data": { "allowedValues": [1, 2, 3], "value": 1 }, "valid": true }, { "description": "something else is invalid", "data": { "allowedValues": [1, 2, 3], "value": 4 }, "valid": false }, { "description": "heterogeneous enum validation", "data": { "allowedValues": [6, "foo", [], true, {"foo": 12}], "value": {"foo": 12} }, "valid": true }, { "description": "fail if value of enum is not an array", "data": { "allowedValues": "[1, 2, 3]", "value": 1 }, "valid": false }, { "description": "valid if value of enum is undefined", "data": { "value": 1 }, "valid": true } ] }, { "description": "enum in properties", "schema": { "properties": { "allowedValues": {} }, "additionalProperties": { "enum": { "$data": "1/allowedValues" } } }, "tests": [ { "description": "properties are valid", "data": { "allowedValues": ["foo", "bar"], "a": "foo", "b": "bar" }, "valid": true }, { "description": "properties are invalid", "data": { "allowedValues": ["foo", "bar"], "a": "foo", "b": "baz" }, "valid": false } ] } ] ajv-5.0.0/spec/extras/$data/exclusiveMaximum.json000066400000000000000000000157621307514663700220000ustar00rootroot00000000000000[ { "description": "one property is exclusiveMaximum for another", "schema": { "properties": { "larger": {}, "smaller": { "exclusiveMaximum": { "$data": "1/larger" } } } }, "tests": [ { "description": "below the exclusiveMaximum is valid", "data": { "larger": 3, "smaller": 2 }, "valid": true }, { "description": "equal to the exclusiveMaximum is invalid", "data": { "larger": 3, "smaller": 3 }, "valid": false }, { "description": "above the exclusiveMaximum is invalid", "data": { "larger": 3, "smaller": 4 }, "valid": false }, { "description": "ignores non-numbers", "data": { "larger": 3, "smaller": "4" }, "valid": true }, { "description": "fails if value of exclusiveMaximum is not number", "data": { "larger": "3", "smaller": 2 }, "valid": false }, { "description": "valid if value of exclusiveMaximum is undefined", "data": { "smaller": 2 }, "valid": true } ] }, { "description": "exclusiveMaximum as number and maximum as $data, exclusiveMaximum > maximum", "schema": { "properties": { "larger": {}, "smaller": { "exclusiveMaximum": 3.5, "maximum": { "$data": "1/larger" } } } }, "tests": [ { "description": "below the maximum is valid", "data": { "larger": 3, "smaller": 2 }, "valid": true }, { "description": "equal to the maximum is valid", "data": { "larger": 3, "smaller": 3 }, "valid": true }, { "description": "above the maximum is invalid", "data": { "larger": 3, "smaller": 3.2 }, "valid": false } ] }, { "description": "exclusiveMaximum as number and maximum as $data, exclusiveMaximum = maximum", "schema": { "properties": { "larger": {}, "smaller": { "exclusiveMaximum": 3, "maximum": { "$data": "1/larger" } } } }, "tests": [ { "description": "below the maximum is valid", "data": { "larger": 3, "smaller": 2 }, "valid": true }, { "description": "boundary point is invalid", "data": { "larger": 3, "smaller": 3 }, "valid": false }, { "description": "above the maximum is invalid", "data": { "larger": 3, "smaller": 4 }, "valid": false } ] }, { "description": "exclusiveMaximum as number and maximum as $data, exclusiveMaximum < maximum", "schema": { "properties": { "larger": {}, "smaller": { "exclusiveMaximum": 2.5, "maximum": { "$data": "1/larger" } } } }, "tests": [ { "description": "below the exclusiveMaximum is valid", "data": { "larger": 3, "smaller": 2 }, "valid": true }, { "description": "boundary point is invalid", "data": { "larger": 3, "smaller": 2.5 }, "valid": false }, { "description": "above the exclusiveMaximum is invalid", "data": { "larger": 3, "smaller": 2.8 }, "valid": false } ] }, { "description": "exclusiveMaximum and maximum as $data, exclusiveMaximum > maximum", "schema": { "properties": { "larger": {}, "largerExclusive": {}, "smaller": { "exclusiveMaximum": { "$data": "1/largerExclusive" }, "maximum": { "$data": "1/larger" } } } }, "tests": [ { "description": "below the maximum is valid", "data": { "larger": 3, "largerExclusive": 3.5, "smaller": 2 }, "valid": true }, { "description": "equal to the maximum is valid", "data": { "larger": 3, "largerExclusive": 3.5, "smaller": 3 }, "valid": true }, { "description": "above the maximum is invalid", "data": { "larger": 3, "largerExclusive": 3.5, "smaller": 3.2 }, "valid": false } ] }, { "description": "exclusiveMaximum as number and maximum as $data, exclusiveMaximum = maximum", "schema": { "properties": { "larger": {}, "largerExclusive": {}, "smaller": { "exclusiveMaximum": { "$data": "1/largerExclusive" }, "maximum": { "$data": "1/larger" } } } }, "tests": [ { "description": "below the maximum is valid", "data": { "larger": 3, "largerExclusive": 3, "smaller": 2 }, "valid": true }, { "description": "boundary point is invalid", "data": { "larger": 3, "largerExclusive": 3, "smaller": 3 }, "valid": false }, { "description": "above the maximum is invalid", "data": { "larger": 3, "largerExclusive": 3, "smaller": 4 }, "valid": false } ] }, { "description": "exclusiveMaximum as number and maximum as $data, exclusiveMaximum < maximum", "schema": { "properties": { "larger": {}, "largerExclusive": {}, "smaller": { "exclusiveMaximum": { "$data": "1/largerExclusive" }, "maximum": { "$data": "1/larger" } } } }, "tests": [ { "description": "below the exclusiveMaximum is valid", "data": { "larger": 3, "largerExclusive": 2.5, "smaller": 2 }, "valid": true }, { "description": "boundary point is invalid", "data": { "larger": 3, "largerExclusive": 2.5, "smaller": 2.5 }, "valid": false }, { "description": "above the exclusiveMaximum is invalid", "data": { "larger": 3, "largerExclusive": 2.5, "smaller": 2.8 }, "valid": false } ] }, { "description": "items in array are < than their indeces", "schema": { "items": { "exclusiveMaximum": { "$data": "0#" } } }, "tests": [ { "description": "valid array", "data": ["", 0, 1, 2, 3, 4], "valid": true }, { "description": "invalid array (1=1)", "data": ["", 1], "valid": false } ] } ] ajv-5.0.0/spec/extras/$data/exclusiveMinimum.json000066400000000000000000000155371307514663700217760ustar00rootroot00000000000000[ { "description": "one property is exclusiveMinimum for another", "schema": { "properties": { "smaller": {}, "larger": { "exclusiveMinimum": { "$data": "1/smaller" } } } }, "tests": [ { "description": "above the exclusiveMinimum is valid", "data": { "smaller": 3, "larger": 4 }, "valid": true }, { "description": "equal to the exclusiveMinimum is invalid", "data": { "smaller": 3, "larger": 3 }, "valid": false }, { "description": "below the exclusiveMinimum is invalid", "data": { "smaller": 3, "larger": 2 }, "valid": false }, { "description": "ignores non-numbers", "data": { "smaller": 3, "larger": "2" }, "valid": true }, { "description": "fails if value of exclusiveMinimum is not number", "data": { "smaller": "3", "larger": 4 }, "valid": false } ] }, { "description": "exclusiveMinimum as number and minimum as $data, exclusiveMinimum < minimum", "schema": { "properties": { "smaller": {}, "larger": { "exclusiveMinimum": 2.5, "minimum": { "$data": "1/smaller" } } } }, "tests": [ { "description": "above the minimum is valid", "data": { "smaller": 3, "larger": 4 }, "valid": true }, { "description": "equal to the minimum is valid", "data": { "smaller": 3, "larger": 3 }, "valid": true }, { "description": "below the minimum is invalid", "data": { "smaller": 3, "larger": 2.8 }, "valid": false } ] }, { "description": "exclusiveMinimum as number and minimum as $data, exclusiveMinimum = minimum", "schema": { "properties": { "smaller": {}, "larger": { "exclusiveMinimum": 3, "minimum": { "$data": "1/smaller" } } } }, "tests": [ { "description": "above the minimum is valid", "data": { "smaller": 3, "larger": 4 }, "valid": true }, { "description": "boundary point is invalid", "data": { "smaller": 3, "larger": 3 }, "valid": false }, { "description": "below the minimum is invalid", "data": { "smaller": 3, "larger": 2 }, "valid": false } ] }, { "description": "exclusiveMinimum as number and minimum as $data, exclusiveMinimum > minimum", "schema": { "properties": { "smaller": {}, "larger": { "exclusiveMinimum": 3.5, "minimum": { "$data": "1/smaller" } } } }, "tests": [ { "description": "above the exclusiveMinimum is valid", "data": { "smaller": 3, "larger": 4 }, "valid": true }, { "description": "boundary point is invalid", "data": { "smaller": 3, "larger": 3.5 }, "valid": false }, { "description": "below the exclusiveMinimum is invalid", "data": { "smaller": 3, "larger": 3.3 }, "valid": false } ] }, { "description": "exclusiveMinimum and minimum as $data, exclusiveMinimum < minimum", "schema": { "properties": { "smaller": {}, "smallerExclusive": {}, "larger": { "exclusiveMinimum": { "$data": "1/smallerExclusive" }, "minimum": { "$data": "1/smaller" } } } }, "tests": [ { "description": "above the minimum is valid", "data": { "smaller": 3, "smallerExclusive": 2.5, "larger": 4 }, "valid": true }, { "description": "equal to the minimum is valid", "data": { "smaller": 3, "smallerExclusive": 2.5, "larger": 3 }, "valid": true }, { "description": "below the minimum is invalid", "data": { "smaller": 3, "smallerExclusive": 2.5, "larger": 2.8 }, "valid": false } ] }, { "description": "exclusiveMinimum as number and minimum as $data, exclusiveMinimum = minimum", "schema": { "properties": { "smaller": {}, "smallerExclusive": {}, "larger": { "exclusiveMinimum": { "$data": "1/smallerExclusive" }, "minimum": { "$data": "1/smaller" } } } }, "tests": [ { "description": "above the minimum is valid", "data": { "smaller": 3, "smallerExclusive": 3, "larger": 4 }, "valid": true }, { "description": "boundary point is invalid", "data": { "smaller": 3, "smallerExclusive": 3, "larger": 3 }, "valid": false }, { "description": "below the minimum is invalid", "data": { "smaller": 3, "smallerExclusive": 3, "larger": 2 }, "valid": false } ] }, { "description": "exclusiveMinimum as number and minimum as $data, exclusiveMinimum > minimum", "schema": { "properties": { "smaller": {}, "smallerExclusive": {}, "larger": { "exclusiveMinimum": { "$data": "1/smallerExclusive" }, "minimum": { "$data": "1/smaller" } } } }, "tests": [ { "description": "above the exclusiveMinimum is valid", "data": { "smaller": 3, "smallerExclusive": 3.5, "larger": 4 }, "valid": true }, { "description": "boundary point is invalid", "data": { "smaller": 3, "smallerExclusive": 3.5, "larger": 3.5 }, "valid": false }, { "description": "below the exclusiveMinimum is invalid", "data": { "smaller": 3, "smallerExclusive": 3.5, "larger": 3.3 }, "valid": false } ] }, { "description": "items in array are > than their indeces", "schema": { "items": { "exclusiveMinimum": { "$data": "0#" } } }, "tests": [ { "description": "valid array", "data": [1, 2, 3, 4, 5, 6], "valid": true }, { "description": "invalid array (1=1)", "data": [2, 1], "valid": false } ] } ] ajv-5.0.0/spec/extras/$data/format.json000066400000000000000000000053611307514663700177150ustar00rootroot00000000000000[ { "description": "one property has format set in another property", "schema": { "properties": { "str": { "format": { "$data": "1/strFormat" } }, "strFormat": {} } }, "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": "whitelisted unknown format is valid", "data": { "str": "any value", "strFormat": "allowedUnknown" }, "valid": true }, { "description": "not whitelisted unknown format is invalid", "data": { "str": "any value", "strFormat": "completelyUnknown" }, "valid": false }, { "description": "valid if the format is undefined", "data": { "str": "any value" }, "valid": true }, { "description": "fails if value of format is not a string", "data": { "str": "1963-06-19T08:30:06.283185Z", "strFormat": 1963 }, "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 } ] } ] ajv-5.0.0/spec/extras/$data/maxItems.json000066400000000000000000000024051307514663700202100ustar00rootroot00000000000000[ { "description": "array length is <= than another property", "schema": { "properties": { "maxArrayLength": {}, "array": { "maxItems": { "$data": "1/maxArrayLength" } } } }, "tests": [ { "description": "shorter is valid", "data": { "maxArrayLength": 2, "array": [1] }, "valid": true }, { "description": "exact length is valid", "data": { "maxArrayLength": 2, "array": [1, 2] }, "valid": true }, { "description": "too long is invalid", "data": { "maxArrayLength": 2, "array": [1, 2, 3] }, "valid": false }, { "description": "ignores non-arrays", "data": { "maxArrayLength": 2, "array": "foobar" }, "valid": true }, { "description": "fails if value of maxItems is not a number", "data": { "maxArrayLength": "2", "array": [1, 2] }, "valid": false }, { "description": "valid if value of maxItems is undefined", "data": { "array": [1, 2] }, "valid": true } ] } ] ajv-5.0.0/spec/extras/$data/maxLength.json000066400000000000000000000023711307514663700203520ustar00rootroot00000000000000[ { "description": "string length is <= than another property", "schema": { "properties": { "maximumLength": {}, "string": { "maxLength": { "$data": "1/maximumLength" } } } }, "tests": [ { "description": "shorter is valid", "data": { "maximumLength": 2, "string": "f" }, "valid": true }, { "description": "exact length is valid", "data": { "maximumLength": 2, "string": "fo" }, "valid": true }, { "description": "too long is invalid", "data": { "maximumLength": 2, "string": "foo" }, "valid": false }, { "description": "ignores non-strings", "data": { "maximumLength": 2, "string": 100 }, "valid": true }, { "description": "fails if value of maxLength is not a number", "data": { "maximumLength": "2", "string": "f" }, "valid": false }, { "description": "valid if value of maxLength is undefined", "data": { "string": "f" }, "valid": true } ] } ] ajv-5.0.0/spec/extras/$data/maxProperties.json000066400000000000000000000025001307514663700212570ustar00rootroot00000000000000[ { "description": "number of object properties is <= than another property", "schema": { "properties": { "maxKeys": {}, "object": { "maxProperties": { "$data": "1/maxKeys" } } } }, "tests": [ { "description": "shorter is valid", "data": { "maxKeys": 2, "object": {"foo": 1} }, "valid": true }, { "description": "exact length is valid", "data": { "maxKeys": 2, "object": {"foo": 1, "bar": 2} }, "valid": true }, { "description": "too long is invalid", "data": { "maxKeys": 2, "object": {"foo": 1, "bar": 2, "baz": 3} }, "valid": false }, { "description": "ignores non-objects", "data": { "maxKeys": 2, "object": "foobar" }, "valid": true }, { "description": "fails if value of maxProperties is not a number", "data": { "maxKeys": "2", "object": {"foo": 1, "bar": 2} }, "valid": false }, { "description": "valid if value of maxProperties is undefined", "data": { "object": {"foo": 1, "bar": 2} }, "valid": true } ] } ] ajv-5.0.0/spec/extras/$data/maximum.json000066400000000000000000000147461307514663700201110ustar00rootroot00000000000000[ { "description": "one property is maximum for another", "schema": { "properties": { "larger": {}, "smallerOrEqual": { "maximum": { "$data": "1/larger" } } } }, "tests": [ { "description": "below the maximum is valid", "data": { "larger": 3, "smallerOrEqual": 2 }, "valid": true }, { "description": "equal to the maximum is valid", "data": { "larger": 3, "smallerOrEqual": 3 }, "valid": true }, { "description": "above the maximum is invalid", "data": { "larger": 3, "smallerOrEqual": 4 }, "valid": false }, { "description": "ignores non-numbers", "data": { "larger": 3, "smallerOrEqual": "4" }, "valid": true }, { "description": "fails if value of maximum is not number", "data": { "larger": "3", "smallerOrEqual": 2 }, "valid": false }, { "description": "valid if value of maximum is undefined", "data": { "smallerOrEqual": 2 }, "valid": true } ] }, { "description": "exclusiveMaximum is $data", "schema": { "properties": { "number": { "maximum": 3, "exclusiveMaximum": { "$data": "1/maxIsExclusive" } }, "maxIsExclusive": {} } }, "tests": [ { "description": "below the maximum is valid when exclusiveMaximum is true", "data": { "number": 2, "maxIsExclusive": true }, "valid": true }, { "description": "below the maximum is valid when exclusiveMaximum is false", "data": { "number": 2, "maxIsExclusive": false }, "valid": true }, { "description": "below the maximum is valid when exclusiveMaximum is undefined", "data": { "number": 2 }, "valid": true }, { "description": "boundary point is invalid when exclusiveMaximum is true", "data": { "number": 3, "maxIsExclusive": true }, "valid": false }, { "description": "boundary point is valid when exclusiveMaximum is false", "data": { "number": 3, "maxIsExclusive": false }, "valid": true }, { "description": "boundary point is valid when exclusiveMaximum is undefined", "data": { "number": 3 }, "valid": true }, { "description": "above the maximum is invalid when exclusiveMaximum is true", "data": { "number": 4, "maxIsExclusive": true }, "valid": false }, { "description": "above the maximum is invalid when exclusiveMaximum is false", "data": { "number": 4, "maxIsExclusive": false }, "valid": false }, { "description": "above the maximum is invalid when exclusiveMaximum is undefined", "data": { "number": 4 }, "valid": false }, { "description": "fails if value of exclusiveMaximum is not boolean", "data": { "number": 2, "maxIsExclusive": "false" }, "valid": false } ] }, { "description": "one property is maximum for another and exclusiveMaximum is $data", "schema": { "properties": { "larger": {}, "smallerOrEqual": { "maximum": { "$data": "1/larger" }, "exclusiveMaximum": { "$data": "1/maxIsExclusive" } }, "maxIsExclusive": {} } }, "tests": [ { "description": "below the maximum is valid when exclusiveMaximum is true", "data": { "larger": 3, "smallerOrEqual": 2, "maxIsExclusive": true }, "valid": true }, { "description": "below the maximum is valid when exclusiveMaximum is false", "data": { "larger": 3, "smallerOrEqual": 2, "maxIsExclusive": false }, "valid": true }, { "description": "below the maximum is valid when exclusiveMaximum is undefined", "data": { "larger": 3, "smallerOrEqual": 2 }, "valid": true }, { "description": "boundary point is invalid when exclusiveMaximum is true", "data": { "larger": 3, "smallerOrEqual": 3, "maxIsExclusive": true }, "valid": false }, { "description": "boundary point is valid when exclusiveMaximum is false", "data": { "larger": 3, "smallerOrEqual": 3, "maxIsExclusive": false }, "valid": true }, { "description": "boundary point is valid when exclusiveMaximum is undefined", "data": { "larger": 3, "smallerOrEqual": 3 }, "valid": true }, { "description": "above the maximum is invalid when exclusiveMaximum is true", "data": { "larger": 3, "smallerOrEqual": 4, "maxIsExclusive": true }, "valid": false }, { "description": "above the maximum is invalid when exclusiveMaximum is false", "data": { "larger": 3, "smallerOrEqual": 4, "maxIsExclusive": false }, "valid": false }, { "description": "above the maximum is invalid when exclusiveMaximum is undefined", "data": { "larger": 3, "smallerOrEqual": 4 }, "valid": false }, { "description": "fails if value of exclusiveMaximum is not boolean", "data": { "larger": 3, "smallerOrEqual": 2, "maxIsExclusive": "false" }, "valid": false } ] }, { "description": "items in array are <= than their indeces", "schema": { "items": { "maximum": { "$data": "0#" } } }, "tests": [ { "description": "valid array", "data": [0, 1, 1, 2, 2, 4], "valid": true }, { "description": "invalid array (2>1)", "data": [0, 2], "valid": false } ] } ] ajv-5.0.0/spec/extras/$data/minItems.json000066400000000000000000000021451307514663700202070ustar00rootroot00000000000000[ { "description": "array length is >= than another property", "schema": { "properties": { "minArrayLength": {}, "array": { "minItems": { "$data": "1/minArrayLength" } } } }, "tests": [ { "description": "longer is valid", "data": { "minArrayLength": 2, "array": [1, 2, 3] }, "valid": true }, { "description": "exact length is valid", "data": { "minArrayLength": 2, "array": [1, 2] }, "valid": true }, { "description": "too short is invalid", "data": { "minArrayLength": 2, "array": [1] }, "valid": false }, { "description": "ignores non-arrays", "data": { "minArrayLength": 2, "array": "foobar" }, "valid": true }, { "description": "fails if value of minItems is not a number", "data": { "minArrayLength": "2", "array": [1, 2] }, "valid": false } ] } ] ajv-5.0.0/spec/extras/$data/minLength.json000066400000000000000000000021341307514663700203450ustar00rootroot00000000000000[ { "description": "string length is >= than another property", "schema": { "properties": { "minimumLength": {}, "string": { "minLength": { "$data": "1/minimumLength" } } } }, "tests": [ { "description": "longer is valid", "data": { "minimumLength": 2, "string": "foo" }, "valid": true }, { "description": "exact length is valid", "data": { "minimumLength": 2, "string": "fo" }, "valid": true }, { "description": "too short is invalid", "data": { "minimumLength": 2, "string": "f" }, "valid": false }, { "description": "ignores non-strings", "data": { "minimumLength": 2, "string": 100 }, "valid": true }, { "description": "fails if value of minLength is not a number", "data": { "minimumLength": "2", "string": "foo" }, "valid": false } ] } ] ajv-5.0.0/spec/extras/$data/minProperties.json000066400000000000000000000022141307514663700212570ustar00rootroot00000000000000[ { "description": "number of object properties is >= than another property", "schema": { "properties": { "minKeys": {}, "object": { "minProperties": { "$data": "1/minKeys" } } } }, "tests": [ { "description": "longer is valid", "data": { "minKeys": 2, "object": {"foo": 1, "bar": 2, "baz": 3} }, "valid": true }, { "description": "exact length is valid", "data": { "minKeys": 2, "object": {"foo": 1, "bar": 2} }, "valid": true }, { "description": "too short is invalid", "data": { "minKeys": 2, "object": {"foo": 1} }, "valid": false }, { "description": "ignores non-objects", "data": { "minKeys": 2, "object": "foobar" }, "valid": true }, { "description": "fails if value of minProperties is not a number", "data": { "minKeys": "2", "object": {"foo": 1, "bar": 2} }, "valid": false } ] } ] ajv-5.0.0/spec/extras/$data/minimum.json000066400000000000000000000145111307514663700200750ustar00rootroot00000000000000[ { "description": "one property is minimum for another", "schema": { "properties": { "smaller": {}, "largerOrEqual": { "minimum": { "$data": "1/smaller" } } } }, "tests": [ { "description": "above the minimum is valid", "data": { "smaller": 3, "largerOrEqual": 4 }, "valid": true }, { "description": "equal to the minimum is valid", "data": { "smaller": 3, "largerOrEqual": 3 }, "valid": true }, { "description": "below the minimum is invalid", "data": { "smaller": 3, "largerOrEqual": 2 }, "valid": false }, { "description": "ignores non-numbers", "data": { "smaller": 3, "largerOrEqual": "2" }, "valid": true }, { "description": "fails if value of minimum is not number", "data": { "smaller": "3", "largerOrEqual": 4 }, "valid": false } ] }, { "description": "exclusiveMinimum is $data", "schema": { "properties": { "number": { "minimum": 3, "exclusiveMinimum": { "$data": "1/minIsExclusive" } }, "minIsExclusive": {} } }, "tests": [ { "description": "above the minimum is valid when exclusiveMinimum is true", "data": { "number": 4, "minIsExclusive": true }, "valid": true }, { "description": "above the minimum is valid when exclusiveMinimum is false", "data": { "number": 4, "minIsExclusive": false }, "valid": true }, { "description": "above the minimum is valid when exclusiveMinimum is undefined", "data": { "number": 4 }, "valid": true }, { "description": "boundary point is invalid when exclusiveMinimum is true", "data": { "number": 3, "minIsExclusive": true }, "valid": false }, { "description": "boundary point is valid when exclusiveMinimum is false", "data": { "number": 3, "minIsExclusive": false }, "valid": true }, { "description": "boundary point is valid when exclusiveMinimum is undefined", "data": { "number": 3 }, "valid": true }, { "description": "below the minimum is invalid when exclusiveMinimum is true", "data": { "number": 2, "minIsExclusive": true }, "valid": false }, { "description": "below the minimum is invalid when exclusiveMinimum is false", "data": { "number": 2, "minIsExclusive": false }, "valid": false }, { "description": "below the minimum is invalid when exclusiveMinimum is undefined", "data": { "number": 2 }, "valid": false }, { "description": "fails if value of exclusiveMinimum is not boolean", "data": { "number": 4, "minIsExclusive": "false" }, "valid": false } ] }, { "description": "one property is minimum for another and exclusiveMinimum is $data", "schema": { "properties": { "smaller": {}, "largerOrEqual": { "minimum": { "$data": "1/smaller" }, "exclusiveMinimum": { "$data": "1/minIsExclusive" } }, "minIsExclusive": {} } }, "tests": [ { "description": "above the minimum is valid when exclusiveMinimum is true", "data": { "smaller": 3, "largerOrEqual": 4, "minIsExclusive": true }, "valid": true }, { "description": "above the minimum is valid when exclusiveMinimum is false", "data": { "smaller": 3, "largerOrEqual": 4, "minIsExclusive": false }, "valid": true }, { "description": "above the minimum is valid when exclusiveMinimum is undefined", "data": { "smaller": 3, "largerOrEqual": 4 }, "valid": true }, { "description": "boundary point is invalid when exclusiveMinimum is true", "data": { "smaller": 3, "largerOrEqual": 3, "minIsExclusive": true }, "valid": false }, { "description": "boundary point is valid when exclusiveMinimum is false", "data": { "smaller": 3, "largerOrEqual": 3, "minIsExclusive": false }, "valid": true }, { "description": "boundary point is valid when exclusiveMinimum is undefined", "data": { "smaller": 3, "largerOrEqual": 3 }, "valid": true }, { "description": "below the minimum is invalid when exclusiveMinimum is true", "data": { "smaller": 3, "largerOrEqual": 2, "minIsExclusive": true }, "valid": false }, { "description": "below the minimum is invalid when exclusiveMinimum is false", "data": { "smaller": 3, "largerOrEqual": 2, "minIsExclusive": false }, "valid": false }, { "description": "below the minimum is invalid when exclusiveMinimum is undefined", "data": { "smaller": 3, "largerOrEqual": 2 }, "valid": false }, { "description": "fails if value of exclusiveMinimum is not boolean", "data": { "smaller": 3, "largerOrEqual": 4, "minIsExclusive": "false" }, "valid": false } ] }, { "description": "items in array are >= than their indeces", "schema": { "items": { "minimum": { "$data": "0#" } } }, "tests": [ { "description": "valid array", "data": [1, 2, 2, 4, 5, 5], "valid": true }, { "description": "invalid array (0.5<1)", "data": [0, 0.5], "valid": false } ] } ] ajv-5.0.0/spec/extras/$data/multipleOf.json000066400000000000000000000074431307514663700205500ustar00rootroot00000000000000[ { "description": "one property is multiple of another", "schema": { "properties": { "divider": {}, "multiple": { "multipleOf": { "$data": "1/divider" } } } }, "tests": [ { "description": "int by int valid", "data": { "divider": 3, "multiple": 12 }, "valid": true }, { "description": "float by float valid", "data": { "divider": 2.5, "multiple": 7.5 }, "valid": true }, { "description": "int by int invalid", "data": { "divider": 3, "multiple": 10 }, "valid": false }, { "description": "float by float invalid", "data": { "divider": 2.5, "multiple": 8 }, "valid": false }, { "description": "ignores non-numbers", "data": { "divider": 2.5, "multiple": "not a number" }, "valid": true }, { "description": "fails if value of multipleOf is not a number", "data": { "divider": "2.5", "multiple": 10 }, "valid": false }, { "description": "valid if value of multipleOf is undefined", "data": { "multiple": 10 }, "valid": true } ] }, { "description": "one property is multiple of another property with escaped characters", "schema": { "properties": { "/divider~": { "type": "number" }, "/multiple~": { "multipleOf": { "$data": "1/~1divider~0" } } } }, "tests": [ { "description": "int by int valid", "data": { "/divider~": 3, "/multiple~": 12 }, "valid": true }, { "description": "int by int invalid", "data": { "/divider~": 3, "/multiple~": 10 }, "valid": false } ] }, { "description": "one subproperty is multiple of another", "schema": { "properties": { "divider": { "properties": { "value": { "type": "number" } } }, "multiple": { "properties": { "value": { "multipleOf": { "$data": "2/divider/value" } } } } } }, "tests": [ { "description": "int by int valid", "data": { "divider": { "value": 3 }, "multiple": { "value": 12 } }, "valid": true }, { "description": "int by int invalid", "data": { "divider": { "value": 3 }, "multiple": { "value": 10 } }, "valid": false } ] }, { "description": "item is a multiple of its index", "schema": { "items": [ {} ], "additionalItems": { "multipleOf": { "$data": "0#" } } }, "tests": [ { "description": "valid array", "data": ["anything", 1, 4, 12, 8, 10], "valid": true }, { "description": "invalid array (3 is not a multiple of 2)", "data": ["anything", 1, 3], "valid": false } ] }, { "description": "item property is a multiple of item index", "schema": { "items": [ {} ], "additionalItems": { "properties": { "value": { "multipleOf": { "$data": "1#" } } } } }, "tests": [ { "description": "valid array", "data": ["anything", {"value": 1}, {"value": 4}, {"value": 12}], "valid": true }, { "description": "invalid array (3 is not a multiple of 2)", "data": ["anything", {"value": 1}, {"value": 3}], "valid": false } ] } ] ajv-5.0.0/spec/extras/$data/pattern.json000066400000000000000000000030721307514663700200770ustar00rootroot00000000000000[ { "description": "one property is pattern for another", "schema": { "properties": { "shouldMatch": {}, "string": { "pattern": { "$data": "1/shouldMatch" } } } }, "tests": [ { "description": "a matching pattern is valid", "data": { "shouldMatch": "^a*$", "string": "aaa" }, "valid": true }, { "description": "a non-matching pattern is invalid", "data": { "shouldMatch": "^a*$", "string": "abc" }, "valid": false }, { "description": "ignores non-strings", "data": { "shouldMatch": "^a*$", "string": 123 }, "valid": true }, { "description": "fails if value of pattern is not a string", "data": { "shouldMatch": 123, "string": "123" }, "valid": false }, { "description": "valid if value of pattern is undefined", "data": { "string": "123" }, "valid": true } ] }, { "description": "property values should contain their names", "schema": { "additionalProperties": { "pattern": { "$data": "0#" } } }, "tests": [ { "description": "valid property values", "data": { "foo": "1foo", "bar": "bar2", "baz": "3baz4" }, "valid": true }, { "description": "invalid property values", "data": { "foo": "fo" }, "valid": false } ] } ] ajv-5.0.0/spec/extras/$data/required.json000066400000000000000000000026771307514663700202540ustar00rootroot00000000000000[ { "description": "required schema in data property", "schema": { "properties": { "foo": {}, "bar": {}, "requiredProperties": {} }, "required": { "$data": "0/requiredProperties" } }, "tests": [ { "description": "present required property is valid", "data": { "foo": 1, "requiredProperties": ["foo"] }, "valid": true }, { "description": "non-present required property is invalid", "data": { "bar": 2, "requiredProperties": ["foo"] }, "valid": false }, { "description": "non-present second required property is invalid", "data": { "foo": 1, "requiredProperties": ["foo", "bar"] }, "valid": false }, { "description": "two present required properties is valid", "data": { "foo": 1, "bar": 2, "requiredProperties": ["foo", "bar"] }, "valid": true }, { "description": "fails if value of required is not an array", "data": { "foo": 1, "bar": 2, "requiredProperties": true }, "valid": false }, { "description": "valid if value of required is undefined", "data": { "foo": 1, "bar": 2 }, "valid": true } ] } ] ajv-5.0.0/spec/extras/$data/uniqueItems.json000066400000000000000000000021471307514663700207340ustar00rootroot00000000000000[ { "description": "uniqueItems in property", "schema": { "properties": { "list": { "uniqueItems": { "$data": "1/unique" } }, "unique": {} } }, "tests": [ { "description": "unique array is valid", "data": { "list": [1, 2], "unique": true }, "valid": true }, { "description": "non-unique array of is invalid", "data": { "list": [1, 1], "unique": true }, "valid": false }, { "description": "non-unique array is valid if uniqueItems is false", "data": { "list": [1, 1], "unique": false }, "valid": true }, { "description": "non-unique array is valid if uniqueItems is undefined", "data": { "list": [1, 1] }, "valid": true }, { "description": "fails if uniqueItems is not boolean", "data": { "list": [1, 2], "unique": "true" }, "valid": false } ] } ] ajv-5.0.0/spec/extras/const.json000066400000000000000000000027271307514663700166010ustar00rootroot00000000000000[ { "description": "const keyword requires the value to be equal to some constant", "schema": { "const": 2 }, "tests": [ { "description": "same value is valid", "data": 2, "valid": true }, { "description": "another value is invalid", "data": 5, "valid": false }, { "description": "another type is invalid", "data": "a", "valid": false } ] }, { "description": "const keyword requires the value to be equal to some object", "schema": { "const": { "foo": "bar", "baz": "bax" } }, "tests": [ { "description": "same object is valid", "data": { "foo": "bar", "baz": "bax" }, "valid": true }, { "description": "same object with different property order is valid", "data": { "baz": "bax", "foo": "bar" }, "valid": true }, { "description": "another object is invalid", "data": { "foo": "bar" }, "valid": false }, { "description": "another type is invalid", "data": [ 1, 2 ], "valid": false } ] }, { "description": "const keyword with null", "schema": { "const": null }, "tests": [ { "description": "null is valid", "data": null, "valid": true }, { "description": "not null is invalid", "data": 0, "valid": false } ] } ] ajv-5.0.0/spec/extras/contains.json000066400000000000000000000023271307514663700172650ustar00rootroot00000000000000[ { "description": "contains keyword requires the item matching schema to be present", "schema": { "contains": { "minimum": 5 } }, "tests": [ { "description": "array with item matching schema (5) is valid", "data": [3, 4, 5], "valid": true }, { "description": "array with item matching schema (6) is valid", "data": [3, 4, 6], "valid": true }, { "description": "array without item matching schema is invalid", "data": [1, 2, 3, 4], "valid": false }, { "description": "empty array is invalid", "data": [], "valid": false }, { "description": "not array is valid", "data": {}, "valid": true } ] }, { "description": "contains keyword with const keyword requires a specific item to be present", "schema": { "contains": { "const": 5 } }, "tests": [ { "description": "array with item 5 is valid", "data": [3, 4, 5], "valid": true }, { "description": "array without item 5 is invalid", "data": [1, 2, 3, 4], "valid": false } ] } ] ajv-5.0.0/spec/extras/exclusiveMaximum.json000066400000000000000000000041131307514663700210070ustar00rootroot00000000000000[ { "description": "exclusiveMaximum as number", "schema": { "exclusiveMaximum": 3.0 }, "tests": [ { "description": "below the exclusiveMaximum is valid", "data": 2.2, "valid": true }, { "description": "boundary point is invalid", "data": 3.0, "valid": false }, { "description": "above the exclusiveMaximum is invalid", "data": 3.2, "valid": false } ] }, { "description": "both exclusiveMaximum and maximum are numbers, exclusiveMaximum > maximum", "schema": { "exclusiveMaximum": 3.0, "maximum": 2.0 }, "tests": [ { "description": "below the maximum is valid", "data": 1.2, "valid": true }, { "description": "boundary point is valid", "data": 2.0, "valid": true }, { "description": "above maximum is invalid", "data": 2.2, "valid": false } ] }, { "description": "both exclusiveMaximum and maximum are numbers, exclusiveMaximum = maximum", "schema": { "exclusiveMaximum": 3.0, "maximum": 3.0 }, "tests": [ { "description": "below the maximum is valid", "data": 2.2, "valid": true }, { "description": "boundary point is invalid", "data": 3.0, "valid": false }, { "description": "above maximum is invalid", "data": 3.2, "valid": false } ] }, { "description": "both exclusiveMaximum and maximum are numbers, exclusiveMaximum < maximum", "schema": { "exclusiveMaximum": 2.0, "maximum": 3.0 }, "tests": [ { "description": "below the exclusiveMaximum is valid", "data": 1.2, "valid": true }, { "description": "boundary point is invalid", "data": 2.0, "valid": false }, { "description": "above exclusiveMaximum is invalid", "data": 2.2, "valid": false } ] } ] ajv-5.0.0/spec/extras/exclusiveMinimum.json000066400000000000000000000041151307514663700210070ustar00rootroot00000000000000[ { "description": "exclusiveMinimum as number", "schema": { "exclusiveMinimum": 1.1 }, "tests": [ { "description": "above the exclusiveMinimum is still valid", "data": 1.2, "valid": true }, { "description": "boundary point is invalid", "data": 1.1, "valid": false }, { "description": "below exclusiveMinimum is invalid", "data": 1.0, "valid": false } ] }, { "description": "both exclusiveMinimum and minimum are numbers, exclusiveMinimum < minimum", "schema": { "exclusiveMinimum": 2.0, "minimum": 3.0 }, "tests": [ { "description": "above the minimum is valid", "data": 3.2, "valid": true }, { "description": "boundary point is valid", "data": 3.0, "valid": true }, { "description": "below minimum is invalid", "data": 2.2, "valid": false } ] }, { "description": "both exclusiveMinimum and minimum are numbers, exclusiveMinimum = minimum", "schema": { "exclusiveMinimum": 3.0, "minimum": 3.0 }, "tests": [ { "description": "above the minimum is valid", "data": 3.2, "valid": true }, { "description": "boundary point is invalid", "data": 3.0, "valid": false }, { "description": "below minimum is invalid", "data": 2.2, "valid": false } ] }, { "description": "both exclusiveMinimum and minimum are numbers, exclusiveMinimum > minimum", "schema": { "exclusiveMinimum": 3.0, "minimum": 2.0 }, "tests": [ { "description": "above the exclusiveMinimum is valid", "data": 3.2, "valid": true }, { "description": "boundary point is invalid", "data": 3.0, "valid": false }, { "description": "below exclusiveMinimum is invalid", "data": 2.2, "valid": false } ] } ] ajv-5.0.0/spec/extras/patternGroups.json000066400000000000000000000152241307514663700203240ustar00rootroot00000000000000[ { "description": "patternGroups validates properties matching a regex (equivalent to the test from draft 4)", "schema": { "patternGroups": { "f.*o": { "schema": {"type": "integer"} } } }, "tests": [ { "description": "a single valid match is valid", "data": {"foo": 1}, "valid": true }, { "description": "multiple valid matches is valid", "data": {"foo": 1, "foooooo" : 2}, "valid": true }, { "description": "a single invalid match is invalid", "data": {"foo": "bar", "fooooo": 2}, "valid": false }, { "description": "multiple invalid matches is invalid", "data": {"foo": "bar", "foooooo" : "baz"}, "valid": false }, { "description": "ignores non-objects", "data": 12, "valid": true } ] }, { "description": "multiple simultaneous patternGroups are validated (equivalent to the test from draft 4)", "schema": { "patternGroups": { "a*": { "schema": {"type": "integer"} }, "aaa*": { "schema": {"maximum": 20} } } }, "tests": [ { "description": "a single valid match is valid", "data": {"a": 21}, "valid": true }, { "description": "a simultaneous match is valid", "data": {"aaaa": 18}, "valid": true }, { "description": "multiple matches is valid", "data": {"a": 21, "aaaa": 18}, "valid": true }, { "description": "an invalid due to one is invalid", "data": {"a": "bar"}, "valid": false }, { "description": "an invalid due to the other is invalid", "data": {"aaaa": 31}, "valid": false }, { "description": "an invalid due to both is invalid", "data": {"aaa": "foo", "aaaa": 31}, "valid": false } ] }, { "description": "regexes in patternGroups are not anchored by default and are case sensitive (equivalent to the test from draft 4)", "schema": { "patternGroups": { "[0-9]{2,}": { "schema": { "type": "boolean" } }, "X_": { "schema": { "type": "string" } } } }, "tests": [ { "description": "non recognized members are ignored", "data": { "answer 1": "42" }, "valid": true }, { "description": "recognized members are accounted for", "data": { "a31b": null }, "valid": false }, { "description": "regexes are case sensitive", "data": { "a_x_3": 3 }, "valid": true }, { "description": "regexes are case sensitive, 2", "data": { "a_X_3": 3 }, "valid": false } ] }, { "description": "patternGroups validates that the number of properties matching a regex is within limit", "schema": { "patternGroups": { "f.*o": { "schema": {"type": "integer"}, "minimum": 1, "maximum": 2 } } }, "tests": [ { "description": "a single valid match is valid", "data": {"foo": 1}, "valid": true }, { "description": "2 valid matches are valid", "data": {"foo": 1, "foooo" : 2}, "valid": true }, { "description": "no valid matches are invalid", "data": {}, "valid": false }, { "description": "more than 2 valid matches are invalid", "data": {"foo": 1, "foooo" : 2, "foooooo" : 3}, "valid": false }, { "description": "sinlge invalid match is invalid", "data": {"foo": 1, "foooooo" : "baz"}, "valid": false } ] }, { "description": "multiple simultaneous patternGroups are validated for number of matching properties", "schema": { "patternGroups": { "a*": { "schema": {"type": "integer"}, "minimum": 1 }, "aaa*": { "schema": {"maximum": 20}, "maximum": 1 } } }, "tests": [ { "description": "a single first match is valid", "data": {"a": 21}, "valid": true }, { "description": "no first match is invalid", "data": {}, "valid": false }, { "description": "simultaneous match is valid", "data": {"aaaa": 18}, "valid": true }, { "description": "multiple matches is valid", "data": {"a": 21, "aaaa": 18}, "valid": true }, { "description": "two second matches are invalid", "data": {"aaa": 17, "aaaa": 18}, "valid": false }, { "description": "invalid due to the first is invalid", "data": {"a": "bar"}, "valid": false }, { "description": "invalid due to the second is invalid", "data": {"a": 21, "aaaa": 31}, "valid": false }, { "description": "invalid due to both is invalid", "data": {"a": "foo", "aaaa": 31}, "valid": false } ] }, { "description": "properties, patternGroups, additionalProperties interaction (equivalent to the test from draft 4)", "schema": { "properties": { "foo": {"type": "array", "maxItems": 3}, "bar": {"type": "array"} }, "patternGroups": { "f.o": { "schema": {"minItems": 2} } }, "additionalProperties": {"type": "integer"} }, "tests": [ { "description": "property validates property", "data": {"foo": [1, 2]}, "valid": true }, { "description": "property invalidates property", "data": {"foo": [1, 2, 3, 4]}, "valid": false }, { "description": "patternGroups invalidates property", "data": {"foo": []}, "valid": false }, { "description": "patternGroups validates nonproperty", "data": {"fxo": [1, 2]}, "valid": true }, { "description": "patternGroups invalidates nonproperty", "data": {"fxo": []}, "valid": false }, { "description": "additionalProperty ignores property", "data": {"bar": []}, "valid": true }, { "description": "additionalProperty validates others", "data": {"quux": 3}, "valid": true }, { "description": "additionalProperty invalidates others", "data": {"quux": "foo"}, "valid": false } ] } ] ajv-5.0.0/spec/extras/propertyNames.json000066400000000000000000000012371307514663700203160ustar00rootroot00000000000000[ { "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 } ] } ] ajv-5.0.0/spec/issues.spec.js000066400000000000000000000336521307514663700160550ustar00rootroot00000000000000'use strict'; var Ajv = require('./ajv') , should = require('./chai').should(); describe('issue #8: schema with shared references', function() { it('should be supported by addSchema', spec('addSchema')); it('should be supported by compile', spec('compile')); function spec(method) { return function() { var ajv = new Ajv; var propertySchema = { type: 'string', maxLength: 4 }; var schema = { id: 'obj.json#', type: 'object', properties: { foo: propertySchema, bar: propertySchema } }; ajv[method](schema); 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); }; } }); describe('issue #50: references with "definitions"', function () { it('should be supported by addSchema', spec('addSchema')); it('should be supported by compile', spec('addSchema')); function spec(method) { return function() { var result; var ajv = new Ajv; ajv[method]({ id: 'http://example.com/test/person.json#', definitions: { name: { type: 'string' } }, type: 'object', properties: { name: { $ref: '#/definitions/name'} } }); ajv[method]({ id: 'http://example.com/test/employee.json#', type: 'object', properties: { person: { $ref: '/test/person.json#' }, role: { type: 'string' } } }); result = ajv.validate('http://example.com/test/employee.json#', { person: { name: 'Alice' }, role: 'Programmer' }); result. should.equal(true); should.equal(ajv.errors, null); }; } }); 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 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); } }); 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 }); var schema = { const: 42 }; var validate = ajv.compile(schema); validate(42) .should.equal(true); validate(43) .should.equal(false); ajv.validate('str', 'foo') .should.equal(true); ajv.validate('str', 42) .should.equal(false); }); }); 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', errors: true, validate: function v(/* value */) { return false; } }); }); it('should validate custom keyword that creates errors', function() { testCustomKeywordErrors({ type:'object', errors: true, validate: function v(/* value */) { v.errors = v.errors || []; v.errors.push({ keyword: 'alwaysFails', message: 'alwaysFails error', params: { keyword: 'alwaysFails' } }); return false; } }); }); function testCustomKeywordErrors(def) { var ajv = new Ajv({ allErrors: true }); ajv.addKeyword('alwaysFails', def); var schema = { required: ['foo'], alwaysFails: true }; 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({}) .should.equal(false); validate.errors .should.have.length(2); validate.errors[0].keyword .should.equal('required'); validate.errors[1].keyword .should.equal('alwaysFails'); } }); 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" } ] } } } } }); ajv.addSchema({ "id" : "boo", "type": "object", "required": ["quux"], "properties": { "quux": { "$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); }); 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" } ] } } } } }); ajv.addSchema({ "id" : "boo", "definitions": { "buu": { "type": "object", "required": ["quux"], "properties": { "quux": { "$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); }); }); describe('issue #240, mutually recursive fragment refs reference a common schema', function() { var apiSchema = { $schema: 'http://json-schema.org/draft-06/schema#', id: 'schema://api.schema#', resource: { id: '#resource', properties: { id: { type: 'string' } } }, resourceIdentifier: { id: '#resource_identifier', properties: { id: { type: 'string' }, type: { type: 'string' } } } }; var domainSchema = { $schema: 'http://json-schema.org/draft-06/schema#', id: 'schema://domain.schema#', properties: { data: { oneOf: [ { $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; var librarySchema = { $schema: 'http://json-schema.org/draft-06/schema#', id: 'schema://library.schema#', properties: { name: { type: 'string' }, links: { properties: { catalogItems: { type: 'array', items: { $ref: 'schema://catalog_item_resource_identifier.schema#' } } } } }, definitions: { resource_identifier: { id: '#resource_identifier', allOf: [ { properties: { type: { type: 'string', 'enum': ['Library'] } } }, { $ref: 'schema://api.schema#resource_identifier' } ] } } }; var catalogItemSchema = { $schema: 'http://json-schema.org/draft-06/schema#', id: 'schema://catalog_item.schema#', properties: { name: { type: 'string' }, links: { properties: { library: { $ref: 'schema://library.schema#resource_identifier' } } } }, definitions: { resource_identifier: { id: '#resource_identifier', allOf: [ { properties: { type: { type: 'string', 'enum': ['CatalogItem'] } } }, { $ref: 'schema://api.schema#resource_identifier' } ] } } }; var catalogItemResourceIdentifierSchema = { $schema: 'http://json-schema.org/draft-06/schema#', id: 'schema://catalog_item_resource_identifier.schema#', allOf: [ { properties: { type: { type: 'string', enum: ['CatalogItem'] } } }, { $ref: 'schema://api.schema#resource_identifier' } ] }; ajv.addSchema(librarySchema); ajv.addSchema(catalogItemSchema); ajv.addSchema(catalogItemResourceIdentifierSchema); ajv.addSchema(apiSchema); var validate = ajv.compile(domainSchema); testSchema(validate); }); it('should compile and validate schema when both refs are fragments', function() { var ajv = new Ajv; var librarySchema = { $schema: 'http://json-schema.org/draft-06/schema#', id: 'schema://library.schema#', properties: { name: { type: 'string' }, links: { properties: { catalogItems: { type: 'array', items: { $ref: 'schema://catalog_item.schema#resource_identifier' } } } } }, definitions: { resource_identifier: { id: '#resource_identifier', allOf: [ { properties: { type: { type: 'string', 'enum': ['Library'] } } }, { $ref: 'schema://api.schema#resource_identifier' } ] } } }; var catalogItemSchema = { $schema: 'http://json-schema.org/draft-06/schema#', id: 'schema://catalog_item.schema#', properties: { name: { type: 'string' }, links: { properties: { library: { $ref: 'schema://library.schema#resource_identifier' } } } }, definitions: { resource_identifier: { id: '#resource_identifier', allOf: [ { properties: { type: { type: 'string', 'enum': ['CatalogItem'] } } }, { $ref: 'schema://api.schema#resource_identifier' } ] } } }; 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); } }); describe('issue #259, support validating [meta-]schemas against themselves', function() { it('should add schema before validation if "id" is the same as "$schema"', function() { var ajv = new Ajv; ajv.addMetaSchema(require('../lib/refs/json-schema-draft-04.json')); var hyperSchema = require('./remotes/hyper-schema.json'); ajv.addMetaSchema(hyperSchema); }); }); 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" } } }; var referencedSchema = { "id": "int", "type": "integer" }; ajv.addSchema(referencedSchema); var validate = ajv.compile(schema); validate({ "a": "foo" }) .should.equal(false); validate.errors[0].schemaPath .should.equal('int#/type'); } }); }); describe('issue #342, support uniqueItems with some non-JSON objects', function() { var validate; 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/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 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); }); }); describe('issue #388, code clean-up not working', function() { it('should remove assignement to rootData if it is not used', function() { var ajv = new Ajv; var validate = ajv.compile({ type: 'object', properties: { foo: { type: 'string' } } }); var code = validate.toString(); code.match(/rootData/g).length .should.equal(1); }); it('should remove assignement to errors if they are not used', function() { var ajv = new Ajv; var validate = ajv.compile({ type: 'object' }); var code = validate.toString(); should.equal(code.match(/[^\.]errors|vErrors/g), null); }); }); ajv-5.0.0/spec/json-schema.spec.js000066400000000000000000000042571307514663700167500ustar00rootroot00000000000000'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 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'), }; runTest(getAjvInstances(options, {meta: false}), 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), 6, typeof window == 'object' ? suite(require('./JSON-Schema-Test-Suite/tests/draft6/{**/,}*.json', {mode: 'list'})) : './JSON-Schema-Test-Suite/tests/draft6/{**/,}*.json'); function runTest(instances, draft, tests) { instances.forEach(function (ajv) { ajv.addMetaSchema(require('../lib/refs/json-schema-draft-04.json')); if (draft == 4) ajv._opts.defaultMeta = 'http://json-schema.org/draft-04/schema#'; for (var id in remoteRefs) ajv.addSchema(remoteRefs[id], id); }); jsonSchemaTest(instances, { description: 'JSON-Schema Test Suite draft-0' + draft + ': ' + instances.length + ' ajv instances with different options', suites: {tests: tests}, only: [ // 'type', 'not', 'allOf', 'anyOf', 'oneOf', 'enum', // 'maximum', 'minimum', 'multipleOf', 'maxLength', 'minLength', 'pattern', // 'properties', 'patternProperties', 'additionalProperties', // 'dependencies', 'required', // 'maxProperties', 'minProperties', 'maxItems', 'minItems', // 'items', 'additionalItems', 'uniqueItems', // 'optional/format', 'optional/bignum', // 'ref', 'refRemote', 'definitions', ], skip: ['optional/zeroTerminatedFloats'], assert: require('./chai').assert, afterError: after.error, afterEach: after.each, cwd: __dirname, hideFolder: 'draft' + draft + '/', timeout: 120000 }); } ajv-5.0.0/spec/options.spec.js000066400000000000000000001106201307514663700162240ustar00rootroot00000000000000'use strict'; var Ajv = require('./ajv') , getAjvInstances = require('./ajv_instances') , should = require('./chai').should(); describe('Ajv Options', function () { describe('removeAdditional', 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' } } }); 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'); }); 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 }); 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'); }); 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' } }); 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'); ajv.addSchema({ 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'); }); }); describe('ownProperties', function() { var ajv, ajvOP, ajvOP1; 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() { var schema = { properties: { a: { type: 'number' } }, additionalProperties: false }; var obj = { a: 1 }; var proto = { b: 2 }; test(schema, obj, proto); }); it('should only validate own properties with properties keyword', function() { var schema = { properties: { a: { type: 'number' }, b: { type: 'number' } } }; var obj = { a: 1 }; var proto = { b: 'not a number' }; test(schema, obj, proto); }); it('should only validate own properties with required keyword', function() { var schema = { required: ['a', 'b'] }; 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 }); var schema = { required: ['a', 'b', 'c', 'd'] }; 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 }); var schema = { required: { $data: '0/req' }, properties: { req: { 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() { var schema = { properties: { a: { type: 'number' }, b: { type: 'number' } }, required: ['a', 'b'] }; var obj = { a: 1 }; var proto = { b: 2 }; test(schema, obj, proto, 1, true); }); it('should only validate own properties with dependencies keyword', function() { var schema = { dependencies: { a: ['c'], b: ['d'] } }; 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); }); it('should only validate own properties with schema dependencies', function() { var schema = { dependencies: { a: { not: { required: ['c'] } }, b: { not: { required: ['d'] } } } }; 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); }); it('should only validate own properties with patternProperties', function() { var schema = { patternProperties: { 'f.*o': { type: 'integer' } }, }; var obj = { fooo: 1 }; var proto = { foo: 'not a number' }; test(schema, obj, proto); }); it('should only validate own properties with patternGroups', function() { ajv = new Ajv({ allErrors: true, patternGroups: true }); ajvOP = new Ajv({ ownProperties: true, allErrors: true, patternGroups: true }); var schema = { patternGroups: { 'f.*o': { schema: { type: 'integer' } } } }; var obj = { fooo: 1 }; var proto = { foo: 'not a number' }; test(schema, obj, proto); }); it('should only validate own properties with propertyNames', function() { var schema = { propertyNames: { format: 'email' } }; var obj = { 'e@example.com': 2 }; var proto = { 'not email': 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]; 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); } else { validate(data) .should.equal(false); validate.errors .should.have.length(errors); validateOP(data) .should.equal(true); validateOP1(data) .should.equal(true); } } }); describe('meta and validateSchema', function() { it('should add draft-6 meta schema by default', function() { testOptionMeta(new Ajv); testOptionMeta(new Ajv({ meta: true })); function testOptionMeta(ajv) { ajv.getSchema('http://json-schema.org/draft-06/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-06/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'); }); 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'); }); }); 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); 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 use option meta as default meta schema', function() { var meta = { $schema: 'http://json-schema.org/draft-06/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-06/schema', myKeyword: 2 }) .should.equal(true); ajv = new Ajv; ajv.validateSchema({ myKeyword: true }) .should.equal(true); ajv.validateSchema({ myKeyword: 2 }) .should.equal(true); }); }); 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('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('123') .should.equal(false); validate(123) .should.equal(true); }); }); 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 })); function testMissingRefsIgnore(ajv) { 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 })); 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); } }); }); 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); } }); }); 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 }); validateWithUnicode('😀') .should.equal(false); validate('😀') .should.equal(true); validateWithUnicode = ajvUnicode.compile({ maxLength: 1 }); validate = ajv.compile({ maxLength: 1 }); validateWithUnicode('😀') .should.equal(true); validate('😀') .should.equal(false); } }); }); 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); } }); }); 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); validate(4.18) .should.equal(true); validate(4.181) .should.equal(false); 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); } }); }); describe('useDefaults', function() { it('should replace undefined property with default value', function() { var instances = getAjvInstances({ allErrors: true, loopRequired: 3 }, { useDefaults: true }); 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: [] } }, 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:[] }); 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 })); function test(ajv) { var schema = { items: [ { type: 'string', default: 'abc' }, { type: 'number', default: 1 }, { type: 'boolean', default: false } ], minItems: 3 }; var validate = ajv.compile(schema); 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', 2,'false']; validate(data) .should.equal(false); validate.errors .should.have.length(1); data .should.eql([ 'foo', 2, 'false' ]); } }); 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'); } }); }); 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('passContext', 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 }); var schema = { definitions: { test1: { testValidate: true, testCompile: true, }, test2: { allOf: [ { $ref: '#/definitions/test1' } ] } }, allOf: [ { $ref: '#/definitions/test1' }, { $ref: '#/definitions/test2' } ] }; return ajv.compile(schema); } function storeContext() { contexts.push(this); return true; } function compileTestValidate() { return storeContext; } }); 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; ajv.addFormat('format1', function() { format1called = true; return false; }); ajv.addFormat('format2', function() { format2called = true; return false; }); var schema1 = { 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); 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); } }); }); 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() { var schema = { "definitions": { "int": { "type": "integer" } }, "$ref": "#/definitions/int", "minimum": 10 }; ajv.compile(schema); }); should.not.throw(function() { var schema = { "definitions": { "int": { "type": "integer" } }, "allOf": [ { "$ref": "#/definitions/int" }, { "minimum": 10 } ] }; ajv.compile(schema); }); } }); }); function test(ajv, shouldExtendRef) { var schema = { "definitions": { "int": { "type": "integer" } }, "$ref": "#/definitions/int", "minimum": 10 }; var validate = ajv.compile(schema); validate(10) .should.equal(true); validate(1) .should.equal(!shouldExtendRef); schema = { "definitions": { "int": { "type": "integer" } }, "type": "object", "properties": { "foo": { "$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); } function testWarning(ajv, msgPattern) { var oldConsole; try { oldConsole = console.warn; var consoleMsg; console.warn = function() { consoleMsg = Array.prototype.join.call(arguments, ' '); }; var schema = { "definitions": { "int": { "type": "integer" } }, "$ref": "#/definitions/int", "minimum": 10 }; ajv.compile(schema); if (msgPattern) consoleMsg .should.match(msgPattern); else should.not.exist(consoleMsg); } finally { console.warn = oldConsole; } } }); 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'); } }); }); 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); } }); }); }); describe('unknownFormats', 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' }); }); } }); 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) { var validate = ajv.compile({ properties: { 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: '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'})); function test(ajv) { 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'})); function test(ajv) { 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); } }); }); describe('= [String]', function() { it('should pass schema compilation and be valid if whitelisted unknown format is used', function() { test(new Ajv({unknownFormats: ['allowed']})); function test(ajv) { var validate = ajv.compile({ format: 'allowed' }); validate('anything') .should.equal(true); should.throw(function() { ajv.compile({ format: 'unknown' }); }); } }); it('should be valid if whitelisted unknown format is used via $data', function() { test(new Ajv({$data: true, unknownFormats: ['allowed']})); function test(ajv) { 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); } }); }); }); 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('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); } }); describe('patternGroups without draft-06 meta-schema', function() { it('should use default meta-schema', function() { var ajv = new Ajv({ patternGroups: true, meta: require('../lib/refs/json-schema-draft-04.json') }); ajv.compile({ patternGroups: { '^foo': { schema: { type: 'number' }, minimum: 1 } } }); should.throw(function() { ajv.compile({ patternGroups: { '^foo': { schema: { type: 'wrong_type' }, minimum: 1 } } }); }); }); it('should not use meta-schema if not available', function() { var ajv = new Ajv({ patternGroups: true, meta: false }); ajv.compile({ patternGroups: { '^foo': { schema: { type: 'number' }, minimum: 1 } } }); ajv.compile({ patternGroups: { '^foo': { schema: { type: 'wrong_type' }, minimum: 1 } } }); }); }); describe('schemaId', function() { describe('= undefined (default)', function() { it('should throw if both id and $id are available and different', function() { var ajv = new Ajv; ajv.compile({ id: 'mySchema', $id: 'mySchema' }); should.throw(function() { ajv.compile({ id: 'mySchema1', $id: 'mySchema2' }); }); }); }); describe('= "id"', function() { it('should use id and ignore $id', function() { var ajv = new Ajv({schemaId: 'id'}); ajv.addSchema({ id: 'mySchema1', type: 'string' }); var validate = ajv.getSchema('mySchema1'); validate('foo') .should.equal(true); validate(1) .should.equal(false); 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'}); 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')); }); }); }); }); ajv-5.0.0/spec/promise.js000066400000000000000000000003621307514663700152570ustar00rootroot00000000000000'use strict'; var g = typeof global == 'object' ? global : typeof window == 'object' ? window : this; if (!g.Promise) { g.Promise = require('' + 'bluebird'); g.Promise.config({ warnings: false }); } module.exports = g.Promise; ajv-5.0.0/spec/remotes/000077500000000000000000000000001307514663700147205ustar00rootroot00000000000000ajv-5.0.0/spec/remotes/bar.json000066400000000000000000000001011307514663700163470ustar00rootroot00000000000000{ "id": "http://localhost:1234/bar.json", "type": "string" } ajv-5.0.0/spec/remotes/buu.json000066400000000000000000000002641307514663700164100ustar00rootroot00000000000000{ "id": "http://localhost:1234/buu.json", "definitions": { "buu": { "type": "object", "properties": { "bar": { "$ref": "bar.json" } } } } } ajv-5.0.0/spec/remotes/first.json000066400000000000000000000001071307514663700167400ustar00rootroot00000000000000{ "id": "http://localhost:1234/first.json", "type": "string" } ajv-5.0.0/spec/remotes/foo.json000066400000000000000000000001721307514663700163760ustar00rootroot00000000000000{ "id": "http://localhost:1234/foo.json", "type": "object", "properties": { "bar": { "$ref": "bar.json" } } } ajv-5.0.0/spec/remotes/hyper-schema.json000066400000000000000000000113171307514663700202030ustar00rootroot00000000000000{ "$schema": "http://json-schema.org/draft-04/hyper-schema#", "id": "http://json-schema.org/draft-04/hyper-schema#", "title": "JSON Hyper-Schema", "allOf": [ { "$ref": "http://json-schema.org/draft-04/schema#" } ], "properties": { "additionalItems": { "anyOf": [ { "type": "boolean" }, { "$ref": "#" } ] }, "additionalProperties": { "anyOf": [ { "type": "boolean" }, { "$ref": "#" } ] }, "dependencies": { "additionalProperties": { "anyOf": [ { "$ref": "#" }, { "type": "array" } ] } }, "items": { "anyOf": [ { "$ref": "#" }, { "$ref": "#/definitions/schemaArray" } ] }, "definitions": { "additionalProperties": { "$ref": "#" } }, "patternProperties": { "additionalProperties": { "$ref": "#" } }, "properties": { "additionalProperties": { "$ref": "#" } }, "allOf": { "$ref": "#/definitions/schemaArray" }, "anyOf": { "$ref": "#/definitions/schemaArray" }, "oneOf": { "$ref": "#/definitions/schemaArray" }, "not": { "$ref": "#" }, "links": { "type": "array", "items": { "$ref": "#/definitions/linkDescription" } }, "fragmentResolution": { "type": "string" }, "media": { "type": "object", "properties": { "type": { "description": "A media type, as described in RFC 2046", "type": "string" }, "binaryEncoding": { "description": "A content encoding scheme, as described in RFC 2045", "type": "string" } } }, "pathStart": { "description": "Instances' URIs must start with this value for this schema to apply to them", "type": "string", "format": "uri" } }, "definitions": { "schemaArray": { "type": "array", "items": { "$ref": "#" } }, "linkDescription": { "title": "Link Description Object", "type": "object", "required": [ "href", "rel" ], "properties": { "href": { "description": "a URI template, as defined by RFC 6570, with the addition of the $, ( and ) characters for pre-processing", "type": "string" }, "rel": { "description": "relation to the target resource of the link", "type": "string" }, "title": { "description": "a title for the link", "type": "string" }, "targetSchema": { "description": "JSON Schema describing the link target", "$ref": "#" }, "mediaType": { "description": "media type (as defined by RFC 2046) describing the link target", "type": "string" }, "method": { "description": "method for requesting the target of the link (e.g. for HTTP this might be \"GET\" or \"DELETE\")", "type": "string" }, "encType": { "description": "The media type in which to submit data along with the request", "type": "string", "default": "application/json" }, "schema": { "description": "Schema describing the data to submit along with the request", "$ref": "#" } } } }, "links": [ { "rel": "self", "href": "{+id}" }, { "rel": "full", "href": "{+($ref)}" } ] } ajv-5.0.0/spec/remotes/name.json000066400000000000000000000002221307514663700165270ustar00rootroot00000000000000{ "definitions": { "orNull": { "anyOf": [ { "type": "null" }, { "$ref": "#" } ] } }, "type": "string" } ajv-5.0.0/spec/remotes/node.json000066400000000000000000000003251307514663700165400ustar00rootroot00000000000000{ "id": "http://localhost:1234/node.json", "description": "node", "type": "object", "properties": { "value": { "type": "number" }, "subtree": { "$ref": "tree.json" } }, "required": ["value"] } ajv-5.0.0/spec/remotes/scope_change.json000066400000000000000000000006461307514663700202370ustar00rootroot00000000000000{ "id": "http://localhost:1234/scope_change.json", "definitions": { "foo": { "id": "http://localhost:1234/scope_foo.json", "definitions": { "bar": { "type": "string" } } }, "baz": { "id": "folder/", "type": "array", "items": { "$ref": "folderInteger.json" }, "bar": { "items": { "$ref": "folderInteger.json" } } } } } ajv-5.0.0/spec/remotes/second.json000066400000000000000000000002151307514663700170640ustar00rootroot00000000000000{ "id": "http://localhost:1234/second.json", "type": "object", "properties": { "first": { "$ref": "first.json" } } } ajv-5.0.0/spec/remotes/tree.json000066400000000000000000000004201307514663700165460ustar00rootroot00000000000000{ "id": "http://localhost:1234/tree.json", "description": "tree of nodes", "type": "object", "properties": { "meta": { "type": "string" }, "nodes": { "type": "array", "items": { "$ref": "node.json"} } }, "required": ["meta", "nodes"] } ajv-5.0.0/spec/resolve.spec.js000066400000000000000000000221411307514663700162100ustar00rootroot00000000000000'use strict'; var Ajv = require('./ajv') , should = require('./chai').should() , getAjvInstances = require('./ajv_instances'); describe('resolve', function () { var instances; beforeEach(function() { instances = getAjvInstances({ 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" }, "schema2": { "id": "otherschema.json", "description": "schema2", "nested": { "id": "#bar", "description": "nested", "type": "string" }, "alsonested": { "id": "t/inner.json#a", "description": "alsonested", "type": "boolean" } }, "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#" } }, "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); }); }); 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() { ajv.compile({ "additionalProperties": { "id": "http://example.com/1.json", "type": "string" } }); }); should.throw(function() { ajv.compile({ "items": { "id": "#int", "type": "integer" }, "additionalProperties": { "id": "#int", "type": "string" } }); }); }); }); }); 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); }); }); }); describe('missing schema error', function() { this.timeout(4000); 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() { 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() { 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() { 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() { 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' }); }); 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); } }); } }); 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 }); var schemaMessage = { $schema: "http://json-schema.org/draft-06/schema#", id: "http://e.com/message.json#", type: "object", required: ["header"], properties: { header: { allOf: [ { $ref: "header.json" }, { properties: { msgType: { "enum": [0] } } } ] } } }; // header schema var schemaHeader = { $schema: "http://json-schema.org/draft-06/schema#", id: "http://e.com/header.json#", type: "object", properties: { version: { type: "integer", maximum: 5 }, msgType: { type: "integer" } }, required: ["version", "msgType"] }; // a good message var validMessage = { header: { version: 4, msgType: 0 } }; // a bad message var invalidMessage = { header: { version: 6, 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#'); 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); } function testObjSchema(validate) { 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); } function testInlined(validate, expectedInlined) { var inlined = !(/refVal/.test(validate.toString())); inlined .should.equal(expectedInlined); } }); }); ajv-5.0.0/spec/schema-tests.spec.js000066400000000000000000000032211307514663700171270ustar00rootroot00000000000000'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 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') }; 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); jsonSchemaTest(instances, { 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' }, only: [ // 'schemas/complex', 'schemas/basic', 'schemas/advanced', ], assert: require('./chai').assert, afterError: after.error, afterEach: after.each, cwd: __dirname, timeout: 120000 }); function addRemoteRefs(ajv) { ajv.addMetaSchema(require('../lib/refs/json-schema-draft-04.json')); for (var id in remoteRefs) ajv.addSchema(remoteRefs[id], id); ajv.addSchema(remoteRefsWithIds); } ajv-5.0.0/spec/tests/000077500000000000000000000000001307514663700144045ustar00rootroot00000000000000ajv-5.0.0/spec/tests/issues/000077500000000000000000000000001307514663700157175ustar00rootroot00000000000000ajv-5.0.0/spec/tests/issues/12_restoring_root_after_resolve.json000066400000000000000000000023711307514663700251160ustar00rootroot00000000000000[ { "description": "restoring root after ref resolution (#12)", "schema": { "definitions": { "int": { "$ref": "http://localhost:1234/integer.json" }, "str": { "type": "string" } }, "anyOf": [ { "$ref": "#/definitions/int" }, { "$ref": "#/definitions/str" } ] }, "tests": [ { "description": "valid string", "data": "foo", "valid": true }, { "description": "valid number", "data": 1, "valid": true }, { "description": "invalid object", "data": {}, "valid": false } ] }, { "description": "all refs are in the same place", "schema": { "definitions": { "int": { "type": "integer" }, "str": { "type": "string" } }, "anyOf": [ { "$ref": "#/definitions/int" }, { "$ref": "#/definitions/str" } ] }, "tests": [ { "description": "valid string", "data": "foo", "valid": true }, { "description": "valid number", "data": 1, "valid": true }, { "description": "invalid object", "data": {}, "valid": false } ] } ] ajv-5.0.0/spec/tests/issues/13_root_ref_in_ref_in_remote_ref.json000066400000000000000000000016261307514663700251600ustar00rootroot00000000000000[ { "description": "root ref in remote ref (#13)", "schemas": [ { "id": "http://localhost:1234/issue13_1", "type": "object", "properties": { "name": { "$ref": "name.json#/definitions/orNull" } } }, { "$id": "http://localhost:1234/issue13_2", "type": "object", "properties": { "name": { "$ref": "name.json#/definitions/orNull" } } } ], "tests": [ { "description": "string is valid", "data": { "name": "foo" }, "valid": true }, { "description": "null is valid", "data": { "name": null }, "valid": true }, { "description": "object is invalid", "data": { "name": { "name": null } }, "valid": false } ] } ] ajv-5.0.0/spec/tests/issues/14_ref_in_remote_ref_with_id.json000066400000000000000000000027011307514663700242760ustar00rootroot00000000000000[ { "description": "ref in remote ref with ids", "schemas": [ { "id": "http://localhost:1234/issue14a_1.json", "type": "array", "items": { "$ref": "foo.json" } }, { "$id": "http://localhost:1234/issue14a_2.json", "type": "array", "items": { "$ref": "foo.json" } } ], "tests": [ { "description": "string is valid", "data": [ { "bar": "any string" } ], "valid": true }, { "description": "not string is invalid", "data": [ { "bar": 1 } ], "valid": false } ] }, { "description": "remote ref in definitions in remote ref with ids (#14)", "schemas": [ { "id": "http://localhost:1234/issue14b_1.json", "type": "array", "items": { "$ref": "buu.json#/definitions/buu" } }, { "$id": "http://localhost:1234/issue14b_2.json", "type": "array", "items": { "$ref": "buu.json#/definitions/buu" } } ], "tests": [ { "description": "string is valid", "data": [ { "bar": "any string" } ], "valid": true }, { "description": "not string is invalid", "data": [ { "bar": 1 } ], "valid": false } ] } ] ajv-5.0.0/spec/tests/issues/170_ref_and_id_in_sibling.json000066400000000000000000000160031307514663700234500ustar00rootroot00000000000000[ { "description": "sibling property has id (#170)", "schemas": [ { "$schema": "http://json-schema.org/draft-04/schema#", "id": "http://example.com/base_object_1", "type": "object", "properties": { "title": { "id": "http://example.com/title", "type": "string" }, "file": { "$ref": "#/definitions/file-entry" } }, "definitions": { "file-entry": { "type": "string" } } }, { "$schema": "http://json-schema.org/draft-06/schema#", "$id": "http://example.com/base_object_2", "type": "object", "properties": { "title": { "$id": "http://example.com/title", "type": "string" }, "file": { "$ref": "#/definitions/file-entry" } }, "definitions": { "file-entry": { "type": "string" } } } ], "tests": [ { "description": "valid object", "data": { "title": "foo", "file": "bar" }, "valid": true }, { "description": "invalid object", "data": { "title": "foo", "file": 2 }, "valid": false } ] }, { "description": "sibling item has id", "schemas": [ { "$schema": "http://json-schema.org/draft-04/schema#", "id": "http://example.com/base_array_1", "type": "array", "items": [ { "id": "http://example.com/0", "type": "string" }, { "$ref": "#/definitions/file-entry" } ], "definitions": { "file-entry": { "type": "string" } } }, { "$schema": "http://json-schema.org/draft-06/schema#", "$id": "http://example.com/base_array_2", "type": "array", "items": [ { "$id": "http://example.com/0", "type": "string" }, { "$ref": "#/definitions/file-entry" } ], "definitions": { "file-entry": { "type": "string" } } } ], "tests": [ { "description": "valid array", "data": [ "foo", "bar" ], "valid": true }, { "description": "invalid array", "data": [ "foo", 2 ], "valid": false } ] }, { "description": "sibling schema in anyOf has id", "schemas": [ { "$schema": "http://json-schema.org/draft-04/schema#", "id": "http://example.com/base_anyof_1", "anyOf": [ { "id": "http://example.com/0", "type": "number" }, { "$ref": "#/definitions/def" } ], "definitions": { "def": { "type": "string" } } }, { "$schema": "http://json-schema.org/draft-06/schema#", "$id": "http://example.com/base_anyof_2", "anyOf": [ { "$id": "http://example.com/0", "type": "number" }, { "$ref": "#/definitions/def" } ], "definitions": { "def": { "type": "string" } } } ], "tests": [ { "description": "valid string", "data": "foo", "valid": true }, { "description": "valid number", "data": 1, "valid": true }, { "description": "invalid object", "data": {}, "valid": false } ] }, { "description": "sibling schema in oneOf has id", "schemas": [ { "$schema": "http://json-schema.org/draft-04/schema#", "id": "http://example.com/base_oneof_1", "oneOf": [ { "id": "http://example.com/0", "type": "number" }, { "$ref": "#/definitions/def" } ], "definitions": { "def": { "type": "string" } } }, { "$schema": "http://json-schema.org/draft-06/schema#", "$id": "http://example.com/base_oneof_2", "oneOf": [ { "$id": "http://example.com/0", "type": "number" }, { "$ref": "#/definitions/def" } ], "definitions": { "def": { "type": "string" } } } ], "tests": [ { "description": "valid string", "data": "foo", "valid": true }, { "description": "valid number", "data": 1, "valid": true }, { "description": "invalid object", "data": {}, "valid": false } ] }, { "description": "sibling schema in allOf has id", "schemas": [ { "$schema": "http://json-schema.org/draft-04/schema#", "id": "http://example.com/base_allof_1", "allOf": [ { "id": "http://example.com/0", "type": "string", "maxLength": 3 }, { "$ref": "#/definitions/def" } ], "definitions": { "def": { "type": "string" } } }, { "$schema": "http://json-schema.org/draft-06/schema#", "$id": "http://example.com/base_allof_2", "allOf": [ { "$id": "http://example.com/0", "type": "string", "maxLength": 3 }, { "$ref": "#/definitions/def" } ], "definitions": { "def": { "type": "string" } } } ], "tests": [ { "description": "valid string", "data": "foo", "valid": true }, { "description": "invalid string", "data": "quux", "valid": false } ] }, { "description": "sibling schema in dependencies has id", "schemas": [ { "$schema": "http://json-schema.org/draft-04/schema#", "id": "http://example.com/base_dependencies_1", "type": "object", "dependencies": { "foo": { "id": "http://example.com/foo", "required": [ "bar" ] }, "bar": { "$ref": "#/definitions/def" } }, "definitions": { "def": { "required": [ "baz" ] } } }, { "$schema": "http://json-schema.org/draft-06/schema#", "$id": "http://example.com/base_dependencies_2", "type": "object", "dependencies": { "foo": { "$id": "http://example.com/foo", "required": [ "bar" ] }, "bar": { "$ref": "#/definitions/def" } }, "definitions": { "def": { "required": [ "baz" ] } } } ], "tests": [ { "description": "valid object", "data": { "foo": 1, "bar": 2, "baz": 3 }, "valid": true }, { "description": "invalid object 2", "data": { "foo": 1 }, "valid": false }, { "description": "invalid object 2", "data": { "foo": 1, "bar": 2 }, "valid": false } ] } ] ajv-5.0.0/spec/tests/issues/17_escaping_pattern_property.json000066400000000000000000000006151307514663700244150ustar00rootroot00000000000000[ { "description": "escaping pattern property (#17)", "schema": { "type" : "object", "patternProperties": { "^.+$" : { "type" : "object", "required" : ["unit"] } }, "additionalProperties" : false }, "tests": [ { "description": "empty object", "data": {}, "valid": true } ] } ] ajv-5.0.0/spec/tests/issues/19_required_many_properties.json000066400000000000000000000037061307514663700242510ustar00rootroot00000000000000[ { "description": "Required for many properties in inner level (#19)", "schema": { "type": "array", "items": { "type": "object", "required": [ "p1", "p2", "p3", "p4", "p5", "p6", "p7", "p8", "p9", "p10", "p11", "p12", "p13", "p14", "p15", "p16", "p17", "p18", "p19", "p20", "p21", "p22" ] } }, "tests": [ { "description": "valid", "data": [ { "p1": "test", "p2": "test", "p3": "test", "p4": "test", "p5": "test", "p6": "test", "p7": "test", "p8": "test", "p9": "test", "p10": "test", "p11": "test", "p12": "test", "p13": "test", "p14": "test", "p15": "test", "p16": "test", "p17": "test", "p18": "test", "p19": "test", "p20": "test", "p21": "test", "p22": "test" } ], "valid": true }, { "description": "invalid", "data": [ { "p2": "test", "p3": "test", "p4": "test", "p5": "test", "p6": "test", "p7": "test", "p8": "test", "p9": "test", "p10": "test", "p11": "test", "p12": "test", "p13": "test", "p14": "test", "p15": "test", "p16": "test", "p17": "test", "p18": "test", "p19": "test", "p20": "test", "p21": "test", "p22": "test" } ], "valid": false } ] } ] ajv-5.0.0/spec/tests/issues/1_ids_in_refs.json000066400000000000000000000030311307514663700213130ustar00rootroot00000000000000[ { "description": "IDs in refs without root id (#1)", "schemas": [ { "definitions": { "int": { "id": "#int", "type": "integer" } }, "$ref": "#int" }, { "definitions": { "int": { "$id": "#int", "type": "integer" } }, "$ref": "#int" } ], "tests": [ { "description": "valid", "data": 1, "valid": true }, { "description": "invalid", "data": "foo", "valid": false } ] }, { "description": "IDs in refs with root id", "schemas": [ { "id": "http://example.com/int_1.json", "definitions": { "int": { "id": "#int", "type": "integer" } }, "$ref": "#int" }, { "$id": "http://example.com/int_2.json", "definitions": { "int": { "$id": "#int", "type": "integer" } }, "$ref": "#int" } ], "tests": [ { "description": "valid", "data": 1, "valid": true }, { "description": "invalid", "data": "foo", "valid": false } ] }, { "description": "Definitions instead of IDs", "schema": { "definitions": { "int": { "type": "integer" } }, "$ref": "#/definitions/int" }, "tests": [ { "description": "valid", "data": 1, "valid": true }, { "description": "invalid", "data": "foo", "valid": false } ] } ] ajv-5.0.0/spec/tests/issues/20_failing_to_parse_schema.json000066400000000000000000000036271307514663700237500ustar00rootroot00000000000000[ { "description": "Failing to parse schema with required property that is not an identifier (#20)", "schema": { "type": "object", "required": [ "a-b", "a'", "a\"" ] }, "tests": [ { "description": "valid", "data": { "a-b": "test", "a'": "test", "a\"": "test" }, "valid": true }, { "description": "invalid", "data": {}, "valid": false } ] }, { "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", "'", "\"" ] }, "tests": [ { "description": "valid", "data": { "a-1": "test", "a-2": "test", "a-3": "test", "a-4": "test", "a-5": "test", "a-6": "test", "a-7": "test", "a-8": "test", "a-9": "test", "a-10": "test", "a-11": "test", "a-12": "test", "a-13": "test", "a-14": "test", "a-15": "test", "a-16": "test", "a-17": "test", "a-18": "test", "a-19": "test", "a-20": "test", "a-21": "test", "a-22": "test", "'": "test", "\"": "test" }, "valid": true }, { "description": "invalid", "data": {}, "valid": false } ] } ] ajv-5.0.0/spec/tests/issues/226_json_with_control_chars.json000066400000000000000000000060561307514663700241360ustar00rootroot00000000000000[ { "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" } } }, "tests": [ { "description": "object with all numbers is valid", "data": { "foo\nbar": 1, "foo\"bar": 1, "foo\\bar": 1, "foo\rbar": 1, "foo\tbar": 1, "foo\fbar": 1 }, "valid": true }, { "description": "object with strings is invalid", "data": { "foo\nbar": "1", "foo\"bar": "1", "foo\\bar": "1", "foo\rbar": "1", "foo\tbar": "1", "foo\fbar": "1" }, "valid": false } ] }, { "description": "JSON with control characters - 'required' (#226)", "schema": { "required": [ "foo\nbar", "foo\"bar", "foo\\bar", "foo\rbar", "foo\tbar", "foo\fbar" ] }, "tests": [ { "description": "object with all properties present is valid", "data": { "foo\nbar": 1, "foo\"bar": 1, "foo\\bar": 1, "foo\rbar": 1, "foo\tbar": 1, "foo\fbar": 1 }, "valid": true }, { "description": "object with some properties missing is invalid", "data": { "foo\nbar": "1", "foo\"bar": "1" }, "valid": false } ] }, { "description": "JSON with control characters - 'enum'", "schema": { "enum": [ "foo\nbar", "foo\rbar" ] }, "tests": [ { "description": "member 1 is valid", "data": "foo\nbar", "valid": true }, { "description": "member 2 is valid", "data": "foo\rbar", "valid": true }, { "description": "another string is invalid", "data": "abc", "valid": false } ] }, { "description": "JSON with control characters - 'dependencies'", "schema": { "dependencies": { "foo\nbar": [ "foo\rbar" ], "foo\tbar": { "minProperties": 4 } } }, "tests": [ { "description": "valid object 1", "data": { "foo\nbar": 1, "foo\rbar": 2 }, "valid": true }, { "description": "valid object 2", "data": { "foo\tbar": 1, "a": 2, "b": 3, "c": 4 }, "valid": true }, { "description": "invalid object 1", "data": { "foo\nbar": 1, "foo": 2 }, "valid": false }, { "description": "invalid object 2", "data": { "foo\tbar": 1, "a": 2 }, "valid": false } ] } ] ajv-5.0.0/spec/tests/issues/27_1_recursive_raml_schema.json000066400000000000000000000577611307514663700237240ustar00rootroot00000000000000[ { "description": "JSON schema for a standard RAML object (#27)", "schema": { "title": "A JSON schema for a standard RAML object", "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "required": [ "title" ], "properties": { "title": { "type": "string", "description": "The title property is a short plain text description of the RESTful API. The title property's value SHOULD be suitable for use as a title for the contained user documentation." }, "version": { "type": "string", "description": "If the RAML API definition is targeted to a specific API version, the API definition MUST contain a version property." }, "baseUri": { "type": "string", "format": "uri", "description": "A RESTful API's resources are defined relative to the API's base URI. The use of the baseUri field is OPTIONAL to allow describing APIs that have not yet been implemented." }, "baseUriParameters": { "$ref": "#/definitions/namedParameters" }, "mediaType": { "$ref": "#/definitions/mediaType" }, "protocols": { "$ref": "#/definitions/protocols" }, "securitySchemes": { "$ref": "#/definitions/securitySchemes" }, "securedBy": { "$ref": "#/definitions/securedBy" }, "documentation": { "$ref": "#/definitions/documentation" }, "resources": { "$ref": "#/definitions/rootResource" }, "traits": { "$ref": "#/definitions/traits" }, "resourceTypes": { "$ref": "#/definitions/resourceTypes" } }, "definitions": { "namedParameters": { "patternProperties": { "^[\\w-]+$": { "oneOf": [ { "$ref": "#/definitions/namedParameter" }, { "type": "array", "items": { "$ref": "#/definitions/namedParameter" } } ] } }, "description": "This RAML Specification describes collections of named parameters for the following properties: URI parameters, query string parameters, form parameters, request bodies (depending on the media type), and request and response headers. Read more: https://github.com/raml-org/raml-spec/blob/master/raml-0.8.md#named-parameters" }, "namedParameter": { "type": "object", "properties": { "displayName": { "type": "string", "description": "The displayName attribute specifies the parameter's display name. It is a friendly name used only for display or documentation purposes. If displayName is not specified, it defaults to the property's key (the name of the property itself)." }, "description": { "type": "string", "description": "The description attribute describes the intended use or meaning of the parameter. This value MAY be formatted using Markdown." }, "type": { "type": "string", "enum": [ "string", "number", "integer", "date", "boolean", "file" ], "default": "string", "description": "The type attribute specifies the primitive type of the parameter's resolved value. If the type is not specified, it defaults to string. API clients MUST return/throw an error if the parameter's resolved value does not match the specified type." }, "enum": { "$ref": "#/definitions/enum", "description": "The enum attribute provides an enumeration of the parameter's valid values. This MUST be an array. If the enum attribute is defined, API clients and servers MUST verify that a parameter's value matches a value in the enum array. If there is no matching value, the clients and servers MUST treat this as an error." }, "pattern": { "type": "string", "format": "regex", "description": "The pattern attribute is a regular expression that a parameter of type string MUST match. Regular expressions MUST follow the regular expression specification from ECMA 262/Perl 5." }, "minLength": { "$ref": "#/definitions/minIntegerDefault0", "description": "The minLength attribute specifies the parameter value's minimum number of characters." }, "maxLength": { "$ref": "#/definitions/minInteger", "description": "The maxLength attribute specifies the parameter value's maximum number of characters." }, "minimum": { "type": "number", "description": "The minimum attribute specifies the parameter's minimum value." }, "maximum": { "type": "number", "description": "The maximum attribute specifies the parameter's maximum value." }, "example": { "$ref": "#/definitions/primitiveType", "description": "The example attribute shows an example value for the property. This can be used, e.g., by documentation generators to generate sample values for the property." }, "repeat": { "$ref": "#/definitions/booleanDefaultFalse", "description": "The repeat attribute specifies that the parameter can be repeated. If the parameter can be used multiple times, the repeat parameter value MUST be set to true. Otherwise, the default value is false and the parameter may not be repeated." }, "required": { "$ref": "#/definitions/booleanDefaultFalse", "description": "The required attribute specifies whether the parameter and its value MUST be present in the API definition. It must be either 'true' if the value MUST be present or false otherwise. arameters are optional unless the required attribute is included and its value set to true. For a URI parameter, the required attribute MAY be omitted, but its default value is true." }, "default": { "$ref": "#/definitions/primitiveType", "default": "The default attribute specifies the default value to use for the property if the property is omitted or its value is not specified. This SHOULD NOT be interpreted as a requirement for the client to send the default attribute's value if there is no other value to send. Instead, the default attribute's value is the value the server uses if the client does not send a value." } }, "additionalProperties": false }, "mediaType": { "type": "string", "pattern": "^[a-zA-Z0-9!#$%^&*_\\-+{}|'.`~]+/[a-zA-Z0-9!#$%^&*_\\-+{}|'.`~]+$", "description": "The media types returned by API responses, and expected from API requests that accept a body, MAY be defaulted by specifying the mediaType property." }, "protocols": { "type": "array", "minItems": 1, "items": { "type": "string", "enum": ["HTTP", "HTTPS"] }, "uniqueItems": true, "description": "A RESTful API can be reached via HTTP, HTTPS, or both. The protocols property MAY be used to specify the protocols that an API supports. If the protocols property is not specified, the protocol specified at the baseUri property is used." }, "securitySchemes": { "type": "object", "patternProperties": { "^[\\w-]+$": { "$ref": "#/definitions/securityScheme" } }, "additionalProperties": false, "description": "The securitySchemes property MUST be used to specify an API's security mechanisms, including the required settings and the authentication methods that the API supports. one authentication method is allowed if the API supports them." }, "securityScheme": { "type": "object", "properties": { "type": { "type": "string", "description": "The type attribute MAY be used to convey information about authentication flows and mechanisms to processing applications such as Documentation Generators and Client generators." }, "description": { "type": "string", "description": "The description attribute MAY be used to describe a securitySchemes property." }, "describedBy": { "$ref": "#/definitions/describedBy" }, "settings": { "type": "object", "description": "The settings attribute MAY be used to provide security schema-specific information. Depending on the value of the type parameter, its attributes can vary." } }, "oneOf": [ { "type": "object", "required": [ "type" ], "properties": { "type": { "enum": ["OAuth 1.0"] }, "settings": { "type": "object", "required": [ "requestTokenUri", "authorizationUri", "tokenCredentialsUri" ], "properties": { "requestTokenUri": { "type": "string", "format": "uri" }, "authorizationUri": { "type": "string", "format": "uri" }, "tokenCredentialsUri": { "type": "string", "format": "uri" } } } } }, { "type": "object", "required": [ "type" ], "properties": { "type": { "enum": ["OAuth 2.0"] }, "settings": { "type": "object", "required": [ "authorizationUri", "accessTokenUri", "authorizationGrants" ], "properties": { "authorizationUri": { "type": "string", "format": "uri" }, "accessTokenUri": { "type": "string", "format": "uri" }, "authorizationGrants": { "type": "array", "items": { "enum": ["code", "token", "owner", "credentials"] } }, "scopes": { "type": "array", "items": { "type": "string" } } } } } }, { "type": "object", "required": [ "type" ], "properties": { "type": { "oneOf": [ { "enum": [ "Basic Authentication", "Digest Authentication" ] }, { "type": "string", "pattern": "^x-" } ] } } } ], "additionalProperties": false }, "traits": { "type": "object", "patternProperties": { "^[\\w-]+$": { "$ref": "#/definitions/trait" } }, "additionalProperties": false }, "describedBy": { "type": "object", "properties": { "description": { "type": "string" }, "queryParameters": { "$ref": "#/definitions/namedParameters" }, "headers": { "$ref": "#/definitions/namedParameters" }, "responses": { "$ref": "#/definitions/responses" }, "body": { "$ref": "#/definitions/body" } }, "additionalProperties": false, "description": "The describedBy attribute MAY be used to apply a trait-like structure to a security scheme mechanism so as to extend the mechanism, such as specifying response codes, HTTP headers or custom documentation." }, "trait": { "type": "object", "properties": { "description": { "type": "string" }, "queryParameters": { "$ref": "#/definitions/namedParameters" }, "headers": { "$ref": "#/definitions/namedParameters" }, "responses": { "$ref": "#/definitions/responses" }, "body": { "$ref": "#/definitions/body" }, "securedBy": { "$ref": "#/definitions/securedBy" } }, "additionalProperties": false, "description": "A trait is a partial method definition that, like a method, can provide method-level properties such as description, headers, query string parameters, and responses. Methods that use one or more traits inherit those traits' properties." }, "resourceTypes": { "type": "object", "patternProperties": { "^[\\w-]+$": { "$ref": "#/definitions/resourceType" } } }, "resourceType": { "type": "object", "properties": { "is": { "$ref": "#/definitions/is" }, "type": { "$ref": "#/definitions/reference" } }, "patternProperties": { "^(?:head|get|post|put|patch|delete|options|trace|connect)\\??$": { "$ref": "#/definitions/method" } }, "additionalProperties": false, "description": "A resource type is a partial resource definition that, like a resource, can specify a description and methods and their properties. Resources that use a resource type inherit its properties, such as its methods." }, "body": { "type": "object", "properties": { "schema": { "type": "string" }, "formParameters": { "$ref": "#/definitions/namedParameters" }, "application/x-www-form-urlencoded": { "$ref": "#/definitions/formBody" }, "multipart/form-data": { "$ref": "#/definitions/formBody" }, "application/json": { "$ref": "#/definitions/schemaBody" }, "text/xml": { "$ref": "#/definitions/schemaBody" } }, "patternProperties": { "^[a-zA-Z0-9!#$%^&*_\\-+{}|'.`~]+/[a-zA-Z0-9!#$%^&*_\\-+{}|'.`~]+$": { "$ref": "#/definitions/standardResponseBody" } }, "additionalProperties": false }, "formBody": { "$ref": "#/definitions/responseBody", "properties": { "formParameters": { "$ref": "#/definitions/namedParameters" } }, "additionalProperties": false, "description": "Web forms REQUIRE special encoding and custom declaration." }, "schemaBody": { "$ref": "#/definitions/responseBody", "properties": { "schema": { "type": "string" } }, "additionalProperties": false, "description": "The structure of a request or response body MAY be further specified by the schema property under the appropriate media type." }, "standardResponseBody": { "$ref": "#/definitions/responseBody", "additionalProperties": false }, "responseBody": { "type": ["null", "object"], "properties": { "example": { "type": "string" } } }, "responses": { "type": "object", "patternProperties": { "^\\d{3}$": { "$ref": "#/definitions/response" } }, "additionalProperties": false }, "response": { "type": "object", "properties": { "description": { "type": "string" }, "headers": { "$ref": "#/definitions/namedParameters", "description": "An API's methods may support custom header values in responses. The custom, non-standard HTTP headers MUST be specified by the headers property." }, "body": { "$ref": "#/definitions/body" } }, "additionalProperties": false }, "securedBy": { "$ref": "#/definitions/enum", "items": { "oneOf": [ { "type": "null" }, { "$ref": "#/definitions/reference" } ] }, "description": "A securityScheme may also be applied to a resource by using the securedBy key, which is equivalent to applying the securityScheme to all methods that may be declared, explicitly or implicitly, by defining the resourceTypes or traits property for that resource." }, "reference": { "oneOf": [ { "type": "string", "pattern": "^[\\w-]+$" }, { "type": "object", "minProperties": 1, "maxProperties": 1, "patternProperties": { "^[\\w-]+$": { "type": "object" } } } ] }, "documentation": { "type": "array", "items": { "type": "object", "properties": { "title": { "type": "string" }, "content": { "type": "string" } }, "additionalProperties": false }, "description": "The API definition can include a variety of documents that serve as a user guides and reference documentation for the API. Such documents can clarify how the API works or provide business context." }, "rootResource": { "type": "object", "patternProperties": { "^/": { "$ref": "#/definitions/resource" } }, "additionalProperties": false }, "resource": { "type": "object", "properties": { "displayName": { "type": "string", "description": "The displayName attribute provides a friendly name to the resource and can be used by documentation generation tools. The displayName key is OPTIONAL. If the displayName attribute is not defined for a resource, documentation tools SHOULD refer to the resource by its property key (i.e. its relative URI, e.g., \"/jobs\"), which acts as the resource's name." }, "description": { "type": "string", "description": "Each resource, whether top-level or nested, MAY contain a description property that briefly describes the resource. It is RECOMMENDED that all the API definition's resources includes the description property." }, "uriParameters": { "$ref": "#/definitions/namedParameters" }, "is": { "$ref": "#/definitions/is" }, "type": { "$ref": "#/definitions/reference" } }, "patternProperties": { "^(?:head|get|post|put|patch|delete|options|trace|connect)$": { "$ref": "#/definitions/method" }, "^/": { "$ref": "#/definitions/resource" } }, "additionalProperties": false }, "method": { "type": "object", "properties": { "description": { "type": "string", "description": "Each declared method MAY contain a description attribute that briefly describes what the method does to the resource. It is RECOMMENDED that all API definition methods include the description property." }, "queryParameters": { "$ref": "#/definitions/namedParameters", "description": "An API's resources MAY be filtered (to return a subset of results) or altered (such as transforming a response body from JSON to XML format) by the use of query strings. If the resource or its method supports a query string, the query string MUST be defined by the queryParameters property." }, "headers": { "$ref": "#/definitions/namedParameters", "description": "An API's methods MAY support or require non-standard HTTP headers. In the API definition, specify the non-standard HTTP headers by using the headers property." }, "protocols": { "$ref": "#/definitions/protocols", "description": "A method can override an API's protocols value for that single method by setting a different value for the fields." }, "responses": { "$ref": "#/definitions/responses", "description": "Resource methods MAY have one or more responses. Responses MAY be described using the description property, and MAY include example attributes or schema properties." }, "body": { "$ref": "#/definitions/body", "description": "Some method verbs expect the resource to be sent as a request body. For example, to create a resource, the request must include the details of the resource to create. Resources CAN have alternate representations. For example, an API might support both JSON and XML representations." }, "securedBy": { "$ref": "#/definitions/securedBy" }, "is": { "$ref": "#/definitions/is" } }, "additionalProperties": false }, "is": { "$ref": "#/definitions/enum", "items": { "$ref": "#/definitions/reference" } }, "enum": { "type": "array", "minItems": 1, "uniqueItems": true }, "minInteger": { "type": "integer", "minimum": 0 }, "minIntegerDefault0": { "allOf": [ { "$ref": "#/definitions/minInteger" }, { "default": 0 } ] }, "booleanDefaultFalse": { "type": "boolean", "default": false }, "date": { "type": "string", "pattern": "^(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat), \\d{2} (?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) \\d{4} \\d{2}:\\d{2}:\\d{2} GMT$" }, "primitiveType": { "type": ["boolean", "integer", "number", "string"] } }, "additionalProperties": false }, "tests": [ { "description": "empty object is invalid", "data": {}, "valid": false } ] } ] ajv-5.0.0/spec/tests/issues/27_recursive_reference.json000066400000000000000000000051421307514663700231510ustar00rootroot00000000000000[ { "description": "Recursive reference (#27)", "schemas": [ { "$schema": "http://json-schema.org/draft-04/schema#", "id": "testrec_1", "type": "object", "properties": { "layout": { "id": "layout", "type": "object", "properties": { "layout": { "type": "string" }, "panels": { "type": "array", "items": { "anyOf": [ { "type": "string" }, { "$ref": "layout" } ] } } }, "required": [ "layout", "panels" ] } } }, { "$schema": "http://json-schema.org/draft-06/schema#", "$id": "testrec_2", "type": "object", "properties": { "layout": { "$id": "layout", "type": "object", "properties": { "layout": { "type": "string" }, "panels": { "type": "array", "items": { "anyOf": [ { "type": "string" }, { "$ref": "layout" } ] } } }, "required": [ "layout", "panels" ] } } } ], "tests": [ { "description": "empty object is valid", "data": {}, "valid": true }, { "description": "valid object", "data": { "layout": { "layout": "test1", "panels": [ "panel1", { "layout": "test2", "panels": [ "panel2", { "layout": "test3", "panels": [ "panel3" ] } ] } ] } }, "valid": true }, { "description": "invalid object", "data": { "layout": { "layout": "test1", "panels": [ "panel1", { "layout": "test2", "panels": [ "panel2", { "layout": "test3", "panels": [ 3 ] } ] } ] } }, "valid": false } ] } ] ajv-5.0.0/spec/tests/issues/28_escaping_pattern_error.json000066400000000000000000000006311307514663700236620ustar00rootroot00000000000000[ { "description": "escaping pattern error (#28)", "schema": { "type" : "object", "properties": { "mediaType": { "type": "string", "pattern": "^[a-zA-Z0-9!#$%^&*_\\-+{}|'.`~]+/[a-zA-Z0-9!#$%^&*_\\-+{}|'.`~]+$" } } }, "tests": [ { "description": "empty object", "data": {}, "valid": true } ] } ] ajv-5.0.0/spec/tests/issues/2_root_ref_in_ref.json000066400000000000000000000054761307514663700222100ustar00rootroot00000000000000[ { "description": "root ref in ref (#2)", "schema": { "definitions": { "arr": { "type": "array", "items": { "$ref": "#" } } }, "type": "object", "properties": { "name": { "type": "string" }, "children": { "$ref": "#/definitions/arr" } } }, "tests": [ { "description": "valid", "data": { "name": "foo", "children": [ { "name": "bar" }, { "name": "baz" } ] }, "valid": true }, { "description": "child numbers are invalid", "data": { "name": "foo", "children": [ { "name": 1 }, { "name": 2 } ] }, "valid": false }, { "description": "child arrays are invalid", "data": { "name": "foo", "children": [ [ ], [ ] ] }, "valid": false } ] }, { "description": "root ref in ref with anyOf (#2)", "schema": { "definitions": { "orNull": { "anyOf": [ { "type": "null" }, { "$ref": "#" } ] } }, "type": "object", "properties": { "name": { "type": "string" }, "parent": { "$ref": "#/definitions/orNull" } } }, "tests": [ { "description": "null parent is valid", "data": { "name": "foo", "parent": null }, "valid": true }, { "skip": false, "description": "object parent is valid", "data": { "name": "foo", "parent": { "name": "bar", "parent": null } }, "valid": true }, { "description": "object parent is valid", "data": { "name": "foo", "parent": { "name": "bar", "parent": { "name": "baz", "parent": null } } }, "valid": true }, { "description": "string parent is invalid", "data": { "name": "foo", "parent": "buu" }, "valid": false }, { "description": "string subparent is invalid", "data": { "name": "foo", "parent": { "name": "bar", "parent": "baz" } }, "valid": false }, { "description": "string sub-subparent is invalid", "data": { "name": "foo", "parent": { "name": "bar", "parent": { "name": "baz", "parent": "quux" } } }, "valid": false } ] } ] ajv-5.0.0/spec/tests/issues/311_quotes_in_refs.json000066400000000000000000000014661307514663700222320ustar00rootroot00000000000000[ { "description": "quotes in refs (#311)", "schema": { "properties": { "foo\"bar": { "$ref": "#/definitions/foo\"bar" } }, "definitions": { "foo\"bar": { "type": "number" } } }, "tests": [ { "description": "object with all numbers is valid", "data": { "foo\"bar": 1, "foo\\bar": 1, "foo\nbar": 1, "foo\rbar": 1, "foo\tbar": 1, "foo\fbar": 1 }, "valid": true }, { "description": "object with strings is invalid", "data": { "foo\"bar": "1", "foo\\bar": "1", "foo\nbar": "1", "foo\rbar": "1", "foo\tbar": "1", "foo\fbar": "1" }, "valid": false } ] } ] ajv-5.0.0/spec/tests/issues/33_json_schema_latest.json000066400000000000000000000005651307514663700227720ustar00rootroot00000000000000[ { "description": "use latest json schema as v4 (#33)", "schema": { "$schema": "http://json-schema.org/schema", "type": "object", "properties": { "username": { "type": "string" } } }, "tests": [ { "description": "empty object", "data": {}, "valid": true } ] } ] ajv-5.0.0/spec/tests/issues/413_dependencies_with_quote.json000066400000000000000000000007761307514663700241110ustar00rootroot00000000000000[ { "description": "JSON with control characters - 'dependencies'", "schema": { "dependencies": { "foo'bar": { "not": { "required": ["bar"] } } } }, "tests": [ { "description": "valid object", "data": { "foo'bar": 1 }, "valid": true }, { "description": "invalid object", "data": { "foo'bar": 1, "bar": 2 }, "valid": false } ] } ] ajv-5.0.0/spec/tests/issues/5_adding_dependency_after.json000066400000000000000000000005701307514663700236450ustar00rootroot00000000000000[ { "description": "Adding dependency after dependent schema (#5)", "schema": "http://localhost:1234/second.json", "tests": [ { "description": "valid object", "data": { "first": "foo" }, "valid": true }, { "description": "valid object", "data": { "first": 1 }, "valid": false } ] } ] ajv-5.0.0/spec/tests/issues/5_recursive_references.json000066400000000000000000000027101307514663700232460ustar00rootroot00000000000000[ { "description": "Recursive references between schemas (#5)", "schema": "http://localhost:1234/tree.json", "tests": [ { "description": "valid tree", "data": { "meta": "root", "nodes": [ { "value": 1, "subtree": { "meta": "child", "nodes": [ { "value": 1.1 }, { "value": 1.2 } ] } }, { "value": 2, "subtree": { "meta": "child", "nodes": [ { "value": 2.1 }, { "value": 2.2 } ] } } ] }, "valid": true }, { "description": "invalid tree", "data": { "meta": "root", "nodes": [ { "value": 1, "subtree": { "meta": "child", "nodes": [ { "value": "string is invalid" }, { "value": 1.2 } ] } }, { "value": 2, "subtree": { "meta": "child", "nodes": [ { "value": 2.1 }, { "value": 2.2 } ] } } ] }, "valid": false } ] } ] ajv-5.0.0/spec/tests/issues/62_resolution_scope_change.json000066400000000000000000000027411307514663700240260ustar00rootroot00000000000000[ { "description": "change resolution scope - change filename (#62)", "schema": { "type" : "object", "properties": { "title": { "$ref": "http://localhost:1234/scope_foo.json#/definitions/bar" } } }, "tests": [ { "description": "string is valid", "data": { "title": "baz" }, "valid": true }, { "description": "number is invalid", "data": { "title": 1 }, "valid": false } ] }, { "description": "resolution scope change - change folder (#62)", "schema": { "type" : "object", "properties": { "list": { "$ref": "http://localhost:1234/scope_change.json#/definitions/baz" } } }, "tests": [ { "description": "number is valid", "data": { "list": [1] }, "valid": true }, { "description": "string is invalid", "data": { "list": ["a"] }, "valid": false } ] }, { "description": "resolution scope change - change folder in subschema (#62)", "schema": { "type" : "object", "properties": { "list": { "$ref": "http://localhost:1234/scope_change.json#/definitions/baz/bar" } } }, "tests": [ { "description": "number is valid", "data": { "list": [1] }, "valid": true }, { "description": "string is invalid", "data": { "list": ["a"] }, "valid": false } ] } ] ajv-5.0.0/spec/tests/issues/63_id_property_not_in_schema.json000066400000000000000000000014671307514663700243600ustar00rootroot00000000000000[ { "description": "id property in referenced schema in object that is not a schema (#63)", "schemas": [ { "type" : "object", "properties": { "title": { "$ref": "http://json-schema.org/draft-04/schema#/properties/title" } } }, { "type" : "object", "properties": { "title": { "$ref": "http://json-schema.org/draft-06/schema#/properties/title" } } } ], "tests": [ { "description": "empty object is valid", "data": {}, "valid": true }, { "description": "string is valid", "data": { "title": "foo" }, "valid": true }, { "description": "number is invalid", "data": { "title": 1 }, "valid": false } ] } ] ajv-5.0.0/spec/tests/issues/70_1_recursive_hash_ref_in_remote_ref.json000066400000000000000000000045151307514663700261100ustar00rootroot00000000000000[ { "description": "hash ref inside hash ref in remote ref (#70, was passing)", "schema": { "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" }, "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" } ] }, { "description": "hash ref inside hash ref in remote ref with id (#70, was passing)", "schemas": [ { "id": "http://example.com/my_schema_1.json", "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" }, { "$id": "http://example.com/my_schema_2.json", "$ref": "http://json-schema.org/draft-06/schema#/definitions/nonNegativeIntegerDefault0" } ], "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" } ] }, { "description": "local hash ref with remote hash ref without inner hash ref (#70, was passing)", "schema": { "definitions": { "a": { "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" } }, "properties": { "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" } ] }, { "description": "local hash ref with remote hash ref that has inner hash ref (#70)", "schema": { "definitions": { "a": { "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" } }, "properties": { "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" } ] } ] ajv-5.0.0/spec/tests/issues/70_swagger_schema.json000066400000000000000000001334331307514663700221060ustar00rootroot00000000000000[ { "description": "Swagger api schema does not compile (#70)", "schema": { "title": "A JSON Schema for Swagger 2.0 API.", "id": "http://swagger.io/v2/schema.json#", "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "required": [ "swagger", "info", "paths" ], "additionalProperties": false, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } }, "properties": { "swagger": { "type": "string", "enum": [ "2.0" ], "description": "The Swagger version of this document." }, "info": { "$ref": "#/definitions/info" }, "host": { "type": "string", "pattern": "^[^{}/ :\\\\]+(?::\\d+)?$", "description": "The host (name or ip) of the API. Example: 'swagger.io'" }, "basePath": { "type": "string", "pattern": "^/", "description": "The base path to the API. Example: '/api'." }, "schemes": { "$ref": "#/definitions/schemesList" }, "consumes": { "description": "A list of MIME types accepted by the API.", "$ref": "#/definitions/mediaTypeList" }, "produces": { "description": "A list of MIME types the API can produce.", "$ref": "#/definitions/mediaTypeList" }, "paths": { "$ref": "#/definitions/paths" }, "definitions": { "$ref": "#/definitions/definitions" }, "parameters": { "$ref": "#/definitions/parameterDefinitions" }, "responses": { "$ref": "#/definitions/responseDefinitions" }, "security": { "$ref": "#/definitions/security" }, "securityDefinitions": { "$ref": "#/definitions/securityDefinitions" }, "tags": { "type": "array", "items": { "$ref": "#/definitions/tag" }, "uniqueItems": true }, "externalDocs": { "$ref": "#/definitions/externalDocs" } }, "definitions": { "info": { "type": "object", "description": "General information about the API.", "required": [ "version", "title" ], "additionalProperties": false, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } }, "properties": { "title": { "type": "string", "description": "A unique and precise title of the API." }, "version": { "type": "string", "description": "A semantic version number of the API." }, "description": { "type": "string", "description": "A longer description of the API. Should be different from the title. GitHub Flavored Markdown is allowed." }, "termsOfService": { "type": "string", "description": "The terms of service for the API." }, "contact": { "$ref": "#/definitions/contact" }, "license": { "$ref": "#/definitions/license" } } }, "contact": { "type": "object", "description": "Contact information for the owners of the API.", "additionalProperties": false, "properties": { "name": { "type": "string", "description": "The identifying name of the contact person/organization." }, "url": { "type": "string", "description": "The URL pointing to the contact information.", "format": "uri" }, "email": { "type": "string", "description": "The email address of the contact person/organization.", "format": "email" } }, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } } }, "license": { "type": "object", "required": [ "name" ], "additionalProperties": false, "properties": { "name": { "type": "string", "description": "The name of the license type. It's encouraged to use an OSI compatible license." }, "url": { "type": "string", "description": "The URL pointing to the license.", "format": "uri" } }, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } } }, "paths": { "type": "object", "description": "Relative paths to the individual endpoints. They must be relative to the 'basePath'.", "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" }, "^/": { "$ref": "#/definitions/pathItem" } }, "additionalProperties": false }, "definitions": { "type": "object", "additionalProperties": { "$ref": "#/definitions/schema" }, "description": "One or more JSON objects describing the schemas being consumed and produced by the API." }, "parameterDefinitions": { "type": "object", "additionalProperties": { "$ref": "#/definitions/parameter" }, "description": "One or more JSON representations for parameters" }, "responseDefinitions": { "type": "object", "additionalProperties": { "$ref": "#/definitions/response" }, "description": "One or more JSON representations for parameters" }, "externalDocs": { "type": "object", "additionalProperties": false, "description": "information about external documentation", "required": [ "url" ], "properties": { "description": { "type": "string" }, "url": { "type": "string", "format": "uri" } }, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } } }, "examples": { "type": "object", "additionalProperties": true }, "mimeType": { "type": "string", "description": "The MIME type of the HTTP message." }, "operation": { "type": "object", "required": [ "responses" ], "additionalProperties": false, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } }, "properties": { "tags": { "type": "array", "items": { "type": "string" }, "uniqueItems": true }, "summary": { "type": "string", "description": "A brief summary of the operation." }, "description": { "type": "string", "description": "A longer description of the operation, GitHub Flavored Markdown is allowed." }, "externalDocs": { "$ref": "#/definitions/externalDocs" }, "operationId": { "type": "string", "description": "A unique identifier of the operation." }, "produces": { "description": "A list of MIME types the API can produce.", "$ref": "#/definitions/mediaTypeList" }, "consumes": { "description": "A list of MIME types the API can consume.", "$ref": "#/definitions/mediaTypeList" }, "parameters": { "$ref": "#/definitions/parametersList" }, "responses": { "$ref": "#/definitions/responses" }, "schemes": { "$ref": "#/definitions/schemesList" }, "deprecated": { "type": "boolean", "default": false }, "security": { "$ref": "#/definitions/security" } } }, "pathItem": { "type": "object", "additionalProperties": false, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } }, "properties": { "$ref": { "type": "string" }, "get": { "$ref": "#/definitions/operation" }, "put": { "$ref": "#/definitions/operation" }, "post": { "$ref": "#/definitions/operation" }, "delete": { "$ref": "#/definitions/operation" }, "options": { "$ref": "#/definitions/operation" }, "head": { "$ref": "#/definitions/operation" }, "patch": { "$ref": "#/definitions/operation" }, "parameters": { "$ref": "#/definitions/parametersList" } } }, "responses": { "type": "object", "description": "Response objects names can either be any valid HTTP status code or 'default'.", "minProperties": 1, "additionalProperties": false, "patternProperties": { "^([0-9]{3})$|^(default)$": { "$ref": "#/definitions/responseValue" }, "^x-": { "$ref": "#/definitions/vendorExtension" } }, "not": { "type": "object", "additionalProperties": false, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } } } }, "responseValue": { "oneOf": [ { "$ref": "#/definitions/response" }, { "$ref": "#/definitions/jsonReference" } ] }, "response": { "type": "object", "required": [ "description" ], "properties": { "description": { "type": "string" }, "schema": { "oneOf": [ { "$ref": "#/definitions/schema" }, { "$ref": "#/definitions/fileSchema" } ] }, "headers": { "$ref": "#/definitions/headers" }, "examples": { "$ref": "#/definitions/examples" } }, "additionalProperties": false, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } } }, "headers": { "type": "object", "additionalProperties": { "$ref": "#/definitions/header" } }, "header": { "type": "object", "additionalProperties": false, "required": [ "type" ], "properties": { "type": { "type": "string", "enum": [ "string", "number", "integer", "boolean", "array" ] }, "format": { "type": "string" }, "items": { "$ref": "#/definitions/primitivesItems" }, "collectionFormat": { "$ref": "#/definitions/collectionFormat" }, "default": { "$ref": "#/definitions/default" }, "maximum": { "$ref": "#/definitions/maximum" }, "exclusiveMaximum": { "$ref": "#/definitions/exclusiveMaximum" }, "minimum": { "$ref": "#/definitions/minimum" }, "exclusiveMinimum": { "$ref": "#/definitions/exclusiveMinimum" }, "maxLength": { "$ref": "#/definitions/maxLength" }, "minLength": { "$ref": "#/definitions/minLength" }, "pattern": { "$ref": "#/definitions/pattern" }, "maxItems": { "$ref": "#/definitions/maxItems" }, "minItems": { "$ref": "#/definitions/minItems" }, "uniqueItems": { "$ref": "#/definitions/uniqueItems" }, "enum": { "$ref": "#/definitions/enum" }, "multipleOf": { "$ref": "#/definitions/multipleOf" }, "description": { "type": "string" } }, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } } }, "vendorExtension": { "description": "Any property starting with x- is valid.", "additionalProperties": true, "additionalItems": true }, "bodyParameter": { "type": "object", "required": [ "name", "in", "schema" ], "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } }, "properties": { "description": { "type": "string", "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed." }, "name": { "type": "string", "description": "The name of the parameter." }, "in": { "type": "string", "description": "Determines the location of the parameter.", "enum": [ "body" ] }, "required": { "type": "boolean", "description": "Determines whether or not this parameter is required or optional.", "default": false }, "schema": { "$ref": "#/definitions/schema" } }, "additionalProperties": false }, "headerParameterSubSchema": { "additionalProperties": false, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } }, "properties": { "required": { "type": "boolean", "description": "Determines whether or not this parameter is required or optional.", "default": false }, "in": { "type": "string", "description": "Determines the location of the parameter.", "enum": [ "header" ] }, "description": { "type": "string", "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed." }, "name": { "type": "string", "description": "The name of the parameter." }, "type": { "type": "string", "enum": [ "string", "number", "boolean", "integer", "array" ] }, "format": { "type": "string" }, "items": { "$ref": "#/definitions/primitivesItems" }, "collectionFormat": { "$ref": "#/definitions/collectionFormat" }, "default": { "$ref": "#/definitions/default" }, "maximum": { "$ref": "#/definitions/maximum" }, "exclusiveMaximum": { "$ref": "#/definitions/exclusiveMaximum" }, "minimum": { "$ref": "#/definitions/minimum" }, "exclusiveMinimum": { "$ref": "#/definitions/exclusiveMinimum" }, "maxLength": { "$ref": "#/definitions/maxLength" }, "minLength": { "$ref": "#/definitions/minLength" }, "pattern": { "$ref": "#/definitions/pattern" }, "maxItems": { "$ref": "#/definitions/maxItems" }, "minItems": { "$ref": "#/definitions/minItems" }, "uniqueItems": { "$ref": "#/definitions/uniqueItems" }, "enum": { "$ref": "#/definitions/enum" }, "multipleOf": { "$ref": "#/definitions/multipleOf" } } }, "queryParameterSubSchema": { "additionalProperties": false, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } }, "properties": { "required": { "type": "boolean", "description": "Determines whether or not this parameter is required or optional.", "default": false }, "in": { "type": "string", "description": "Determines the location of the parameter.", "enum": [ "query" ] }, "description": { "type": "string", "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed." }, "name": { "type": "string", "description": "The name of the parameter." }, "allowEmptyValue": { "type": "boolean", "default": false, "description": "allows sending a parameter by name only or with an empty value." }, "type": { "type": "string", "enum": [ "string", "number", "boolean", "integer", "array" ] }, "format": { "type": "string" }, "items": { "$ref": "#/definitions/primitivesItems" }, "collectionFormat": { "$ref": "#/definitions/collectionFormatWithMulti" }, "default": { "$ref": "#/definitions/default" }, "maximum": { "$ref": "#/definitions/maximum" }, "exclusiveMaximum": { "$ref": "#/definitions/exclusiveMaximum" }, "minimum": { "$ref": "#/definitions/minimum" }, "exclusiveMinimum": { "$ref": "#/definitions/exclusiveMinimum" }, "maxLength": { "$ref": "#/definitions/maxLength" }, "minLength": { "$ref": "#/definitions/minLength" }, "pattern": { "$ref": "#/definitions/pattern" }, "maxItems": { "$ref": "#/definitions/maxItems" }, "minItems": { "$ref": "#/definitions/minItems" }, "uniqueItems": { "$ref": "#/definitions/uniqueItems" }, "enum": { "$ref": "#/definitions/enum" }, "multipleOf": { "$ref": "#/definitions/multipleOf" } } }, "formDataParameterSubSchema": { "additionalProperties": false, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } }, "properties": { "required": { "type": "boolean", "description": "Determines whether or not this parameter is required or optional.", "default": false }, "in": { "type": "string", "description": "Determines the location of the parameter.", "enum": [ "formData" ] }, "description": { "type": "string", "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed." }, "name": { "type": "string", "description": "The name of the parameter." }, "allowEmptyValue": { "type": "boolean", "default": false, "description": "allows sending a parameter by name only or with an empty value." }, "type": { "type": "string", "enum": [ "string", "number", "boolean", "integer", "array", "file" ] }, "format": { "type": "string" }, "items": { "$ref": "#/definitions/primitivesItems" }, "collectionFormat": { "$ref": "#/definitions/collectionFormatWithMulti" }, "default": { "$ref": "#/definitions/default" }, "maximum": { "$ref": "#/definitions/maximum" }, "exclusiveMaximum": { "$ref": "#/definitions/exclusiveMaximum" }, "minimum": { "$ref": "#/definitions/minimum" }, "exclusiveMinimum": { "$ref": "#/definitions/exclusiveMinimum" }, "maxLength": { "$ref": "#/definitions/maxLength" }, "minLength": { "$ref": "#/definitions/minLength" }, "pattern": { "$ref": "#/definitions/pattern" }, "maxItems": { "$ref": "#/definitions/maxItems" }, "minItems": { "$ref": "#/definitions/minItems" }, "uniqueItems": { "$ref": "#/definitions/uniqueItems" }, "enum": { "$ref": "#/definitions/enum" }, "multipleOf": { "$ref": "#/definitions/multipleOf" } } }, "pathParameterSubSchema": { "additionalProperties": false, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } }, "required": [ "required" ], "properties": { "required": { "type": "boolean", "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" ] }, "description": { "type": "string", "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed." }, "name": { "type": "string", "description": "The name of the parameter." }, "type": { "type": "string", "enum": [ "string", "number", "boolean", "integer", "array" ] }, "format": { "type": "string" }, "items": { "$ref": "#/definitions/primitivesItems" }, "collectionFormat": { "$ref": "#/definitions/collectionFormat" }, "default": { "$ref": "#/definitions/default" }, "maximum": { "$ref": "#/definitions/maximum" }, "exclusiveMaximum": { "$ref": "#/definitions/exclusiveMaximum" }, "minimum": { "$ref": "#/definitions/minimum" }, "exclusiveMinimum": { "$ref": "#/definitions/exclusiveMinimum" }, "maxLength": { "$ref": "#/definitions/maxLength" }, "minLength": { "$ref": "#/definitions/minLength" }, "pattern": { "$ref": "#/definitions/pattern" }, "maxItems": { "$ref": "#/definitions/maxItems" }, "minItems": { "$ref": "#/definitions/minItems" }, "uniqueItems": { "$ref": "#/definitions/uniqueItems" }, "enum": { "$ref": "#/definitions/enum" }, "multipleOf": { "$ref": "#/definitions/multipleOf" } } }, "nonBodyParameter": { "type": "object", "required": [ "name", "in", "type" ], "oneOf": [ { "$ref": "#/definitions/headerParameterSubSchema" }, { "$ref": "#/definitions/formDataParameterSubSchema" }, { "$ref": "#/definitions/queryParameterSubSchema" }, { "$ref": "#/definitions/pathParameterSubSchema" } ] }, "parameter": { "oneOf": [ { "$ref": "#/definitions/bodyParameter" }, { "$ref": "#/definitions/nonBodyParameter" } ] }, "schema": { "type": "object", "description": "A deterministic version of a JSON Schema object.", "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } }, "properties": { "$ref": { "type": "string" }, "format": { "type": "string" }, "title": { "$ref": "http://json-schema.org/draft-04/schema#/properties/title" }, "description": { "$ref": "http://json-schema.org/draft-04/schema#/properties/description" }, "default": { "$ref": "http://json-schema.org/draft-04/schema#/properties/default" }, "multipleOf": { "$ref": "http://json-schema.org/draft-04/schema#/properties/multipleOf" }, "maximum": { "$ref": "http://json-schema.org/draft-04/schema#/properties/maximum" }, "exclusiveMaximum": { "$ref": "http://json-schema.org/draft-04/schema#/properties/exclusiveMaximum" }, "minimum": { "$ref": "http://json-schema.org/draft-04/schema#/properties/minimum" }, "exclusiveMinimum": { "$ref": "http://json-schema.org/draft-04/schema#/properties/exclusiveMinimum" }, "maxLength": { "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" }, "minLength": { "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" }, "pattern": { "$ref": "http://json-schema.org/draft-04/schema#/properties/pattern" }, "maxItems": { "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" }, "minItems": { "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" }, "uniqueItems": { "$ref": "http://json-schema.org/draft-04/schema#/properties/uniqueItems" }, "maxProperties": { "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" }, "minProperties": { "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" }, "required": { "$ref": "http://json-schema.org/draft-04/schema#/definitions/stringArray" }, "enum": { "$ref": "http://json-schema.org/draft-04/schema#/properties/enum" }, "additionalProperties": { "anyOf": [ { "$ref": "#/definitions/schema" }, { "type": "boolean" } ], "default": {} }, "type": { "$ref": "http://json-schema.org/draft-04/schema#/properties/type" }, "items": { "anyOf": [ { "$ref": "#/definitions/schema" }, { "type": "array", "minItems": 1, "items": { "$ref": "#/definitions/schema" } } ], "default": {} }, "allOf": { "type": "array", "minItems": 1, "items": { "$ref": "#/definitions/schema" } }, "properties": { "type": "object", "additionalProperties": { "$ref": "#/definitions/schema" }, "default": {} }, "discriminator": { "type": "string" }, "readOnly": { "type": "boolean", "default": false }, "xml": { "$ref": "#/definitions/xml" }, "externalDocs": { "$ref": "#/definitions/externalDocs" }, "example": {} }, "additionalProperties": false }, "fileSchema": { "type": "object", "description": "A deterministic version of a JSON Schema object.", "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } }, "required": [ "type" ], "properties": { "format": { "type": "string" }, "title": { "$ref": "http://json-schema.org/draft-04/schema#/properties/title" }, "description": { "$ref": "http://json-schema.org/draft-04/schema#/properties/description" }, "default": { "$ref": "http://json-schema.org/draft-04/schema#/properties/default" }, "required": { "$ref": "http://json-schema.org/draft-04/schema#/definitions/stringArray" }, "type": { "type": "string", "enum": [ "file" ] }, "readOnly": { "type": "boolean", "default": false }, "externalDocs": { "$ref": "#/definitions/externalDocs" }, "example": {} }, "additionalProperties": false }, "primitivesItems": { "type": "object", "additionalProperties": false, "properties": { "type": { "type": "string", "enum": [ "string", "number", "integer", "boolean", "array" ] }, "format": { "type": "string" }, "items": { "$ref": "#/definitions/primitivesItems" }, "collectionFormat": { "$ref": "#/definitions/collectionFormat" }, "default": { "$ref": "#/definitions/default" }, "maximum": { "$ref": "#/definitions/maximum" }, "exclusiveMaximum": { "$ref": "#/definitions/exclusiveMaximum" }, "minimum": { "$ref": "#/definitions/minimum" }, "exclusiveMinimum": { "$ref": "#/definitions/exclusiveMinimum" }, "maxLength": { "$ref": "#/definitions/maxLength" }, "minLength": { "$ref": "#/definitions/minLength" }, "pattern": { "$ref": "#/definitions/pattern" }, "maxItems": { "$ref": "#/definitions/maxItems" }, "minItems": { "$ref": "#/definitions/minItems" }, "uniqueItems": { "$ref": "#/definitions/uniqueItems" }, "enum": { "$ref": "#/definitions/enum" }, "multipleOf": { "$ref": "#/definitions/multipleOf" } }, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } } }, "security": { "type": "array", "items": { "$ref": "#/definitions/securityRequirement" }, "uniqueItems": true }, "securityRequirement": { "type": "object", "additionalProperties": { "type": "array", "items": { "type": "string" }, "uniqueItems": true } }, "xml": { "type": "object", "additionalProperties": false, "properties": { "name": { "type": "string" }, "namespace": { "type": "string" }, "prefix": { "type": "string" }, "attribute": { "type": "boolean", "default": false }, "wrapped": { "type": "boolean", "default": false } }, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } } }, "tag": { "type": "object", "additionalProperties": false, "required": [ "name" ], "properties": { "name": { "type": "string" }, "description": { "type": "string" }, "externalDocs": { "$ref": "#/definitions/externalDocs" } }, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } } }, "securityDefinitions": { "type": "object", "additionalProperties": { "oneOf": [ { "$ref": "#/definitions/basicAuthenticationSecurity" }, { "$ref": "#/definitions/apiKeySecurity" }, { "$ref": "#/definitions/oauth2ImplicitSecurity" }, { "$ref": "#/definitions/oauth2PasswordSecurity" }, { "$ref": "#/definitions/oauth2ApplicationSecurity" }, { "$ref": "#/definitions/oauth2AccessCodeSecurity" } ] } }, "basicAuthenticationSecurity": { "type": "object", "additionalProperties": false, "required": [ "type" ], "properties": { "type": { "type": "string", "enum": [ "basic" ] }, "description": { "type": "string" } }, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } } }, "apiKeySecurity": { "type": "object", "additionalProperties": false, "required": [ "type", "name", "in" ], "properties": { "type": { "type": "string", "enum": [ "apiKey" ] }, "name": { "type": "string" }, "in": { "type": "string", "enum": [ "header", "query" ] }, "description": { "type": "string" } }, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } } }, "oauth2ImplicitSecurity": { "type": "object", "additionalProperties": false, "required": [ "type", "flow", "authorizationUrl" ], "properties": { "type": { "type": "string", "enum": [ "oauth2" ] }, "flow": { "type": "string", "enum": [ "implicit" ] }, "scopes": { "$ref": "#/definitions/oauth2Scopes" }, "authorizationUrl": { "type": "string", "format": "uri" }, "description": { "type": "string" } }, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } } }, "oauth2PasswordSecurity": { "type": "object", "additionalProperties": false, "required": [ "type", "flow", "tokenUrl" ], "properties": { "type": { "type": "string", "enum": [ "oauth2" ] }, "flow": { "type": "string", "enum": [ "password" ] }, "scopes": { "$ref": "#/definitions/oauth2Scopes" }, "tokenUrl": { "type": "string", "format": "uri" }, "description": { "type": "string" } }, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } } }, "oauth2ApplicationSecurity": { "type": "object", "additionalProperties": false, "required": [ "type", "flow", "tokenUrl" ], "properties": { "type": { "type": "string", "enum": [ "oauth2" ] }, "flow": { "type": "string", "enum": [ "application" ] }, "scopes": { "$ref": "#/definitions/oauth2Scopes" }, "tokenUrl": { "type": "string", "format": "uri" }, "description": { "type": "string" } }, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } } }, "oauth2AccessCodeSecurity": { "type": "object", "additionalProperties": false, "required": [ "type", "flow", "authorizationUrl", "tokenUrl" ], "properties": { "type": { "type": "string", "enum": [ "oauth2" ] }, "flow": { "type": "string", "enum": [ "accessCode" ] }, "scopes": { "$ref": "#/definitions/oauth2Scopes" }, "authorizationUrl": { "type": "string", "format": "uri" }, "tokenUrl": { "type": "string", "format": "uri" }, "description": { "type": "string" } }, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } } }, "oauth2Scopes": { "type": "object", "additionalProperties": { "type": "string" } }, "mediaTypeList": { "type": "array", "items": { "$ref": "#/definitions/mimeType" }, "uniqueItems": true }, "parametersList": { "type": "array", "description": "The parameters needed to send a valid API call.", "additionalItems": false, "items": { "oneOf": [ { "$ref": "#/definitions/parameter" }, { "$ref": "#/definitions/jsonReference" } ] }, "uniqueItems": true }, "schemesList": { "type": "array", "description": "The transfer protocol of the API.", "items": { "type": "string", "enum": [ "http", "https", "ws", "wss" ] }, "uniqueItems": true }, "collectionFormat": { "type": "string", "enum": [ "csv", "ssv", "tsv", "pipes" ], "default": "csv" }, "collectionFormatWithMulti": { "type": "string", "enum": [ "csv", "ssv", "tsv", "pipes", "multi" ], "default": "csv" }, "title": { "$ref": "http://json-schema.org/draft-04/schema#/properties/title" }, "description": { "$ref": "http://json-schema.org/draft-04/schema#/properties/description" }, "default": { "$ref": "http://json-schema.org/draft-04/schema#/properties/default" }, "multipleOf": { "$ref": "http://json-schema.org/draft-04/schema#/properties/multipleOf" }, "maximum": { "$ref": "http://json-schema.org/draft-04/schema#/properties/maximum" }, "exclusiveMaximum": { "$ref": "http://json-schema.org/draft-04/schema#/properties/exclusiveMaximum" }, "minimum": { "$ref": "http://json-schema.org/draft-04/schema#/properties/minimum" }, "exclusiveMinimum": { "$ref": "http://json-schema.org/draft-04/schema#/properties/exclusiveMinimum" }, "maxLength": { "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" }, "minLength": { "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" }, "pattern": { "$ref": "http://json-schema.org/draft-04/schema#/properties/pattern" }, "maxItems": { "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" }, "minItems": { "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" }, "uniqueItems": { "$ref": "http://json-schema.org/draft-04/schema#/properties/uniqueItems" }, "enum": { "$ref": "http://json-schema.org/draft-04/schema#/properties/enum" }, "jsonReference": { "type": "object", "required": [ "$ref" ], "additionalProperties": false, "properties": { "$ref": { "type": "string" } } } } }, "tests": [ { "description": "empty object is invalid", "data": {}, "valid": false }, { "description": "minimal valid object", "data": { "swagger": "2.0", "info": { "title": "sample api definition", "version": "0.1" }, "paths": {} }, "valid": true } ] } ] ajv-5.0.0/spec/tests/issues/87_$_property.json000066400000000000000000000004121307514663700212140ustar00rootroot00000000000000[ { "description": "$ in properties (#87)", "schema": { "properties": { "$": { "type": "string" } } }, "tests": [ { "description": "valid", "data": { "$": "foo" }, "valid": true } ] } ] ajv-5.0.0/spec/tests/issues/94_dependencies_fail.json000066400000000000000000000024431307514663700225520ustar00rootroot00000000000000[ { "description": "second dependency is not checked (#94)", "schema": { "dependencies": { "bar" : ["baz"], "foo" : ["bar"] } }, "tests": [ { "description": "object with only foo is invalid (bar is missing)", "data": { "foo": 1 }, "valid": false }, { "description": "object with foo and bar is invalid (baz is missing)", "data": { "foo": 1, "bar": 2 }, "valid": false }, { "description": "object with foo, bar and baz is valid", "data": { "foo": 1, "bar": 2, "baz": 3 }, "valid": true } ] }, { "description": "second dependency is checked when order is changed", "schema": { "dependencies": { "foo" : ["bar"], "bar" : ["baz"] } }, "tests": [ { "description": "object with only foo is invalid (bar is missing)", "data": { "foo": 1 }, "valid": false }, { "description": "object with foo and bar is invalid (baz is missing)", "data": { "foo": 1, "bar": 2 }, "valid": false }, { "description": "object with foo, bar and baz is valid", "data": { "foo": 1, "bar": 2, "baz": 3 }, "valid": true } ] } ] ajv-5.0.0/spec/tests/rules/000077500000000000000000000000001307514663700155365ustar00rootroot00000000000000ajv-5.0.0/spec/tests/rules/allOf.json000066400000000000000000000023751307514663700174750ustar00rootroot00000000000000[ { "description": "allOf with one empty schema", "schema": { "allOf": [ {} ] }, "tests": [ { "description": "any data is valid", "data": 1, "valid": true } ] }, { "description": "allOf with two empty schemas", "schema": { "allOf": [ {}, {} ] }, "tests": [ { "description": "any data is valid", "data": 1, "valid": true } ] }, { "description": "allOf with two schemas, the first is empty", "schema": { "allOf": [ {}, { "type": "number" } ] }, "tests": [ { "description": "number is valid", "data": 1, "valid": true }, { "description": "string is invalid", "data": "foo", "valid": false } ] }, { "description": "allOf with two schemas, the second is empty", "schema": { "allOf": [ { "type": "number" }, {} ] }, "tests": [ { "description": "number is valid", "data": 1, "valid": true }, { "description": "string is invalid", "data": "foo", "valid": false } ] } ] ajv-5.0.0/spec/tests/rules/anyOf.json000066400000000000000000000005751307514663700175140ustar00rootroot00000000000000[ { "description": "anyOf with one of schemas empty", "schema": { "anyOf": [ { "type": "number" }, {} ] }, "tests": [ { "description": "string is valid", "data": "foo", "valid": true }, { "description": "number is valid", "data": 123, "valid": true } ] } ] ajv-5.0.0/spec/tests/rules/dependencies.json000066400000000000000000000007651307514663700210670ustar00rootroot00000000000000[ { "description": "dependencies keyword with empty array", "schema": { "dependencies": { "foo": [] } }, "tests": [ { "description": "object with property is valid", "data": { "foo": 1 }, "valid": true }, { "description": "empty object is valid", "data": {}, "valid": true }, { "description": "non-object is valid", "data": 1, "valid": true } ] } ] ajv-5.0.0/spec/tests/rules/format.json000066400000000000000000000401411307514663700177210ustar00rootroot00000000000000[ { "description": "whitelisted unknown format is valid", "schema": { "format": "allowedUnknown" }, "tests": [ { "description": "any string is valid", "data": "any value", "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 #312", "data": "lead-routing-qa.lvuucj.0001.use1.cache.amazonaws.com", "valid": true } ] }, { "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": "not valid time", "data": "12.34.56", "valid": false } ] }, { "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": "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": "a valid JSON-pointer as uri fragment", "data": "#/foo/%25a", "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": "not a valid JSON-pointer as uri fragment (% not URL-encoded)", "data": "#/foo/%a", "valid": false }, { "description": "valid JSON-pointer with empty segment", "data": "/foo//bar", "valid": true }, { "description": "valid JSON-pointer with the last empty segment", "data": "/foo/bar/", "valid": true }, { "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 } ] } ] ajv-5.0.0/spec/tests/rules/items.json000066400000000000000000000064361307514663700175630ustar00rootroot00000000000000[ { "description": "items with empty schema", "schema": { "items": [{}], "additionalItems": { "type": "string" } }, "tests": [ { "description": "array with second string is valid", "data": [1, "a"], "valid": true }, { "description": "array with second number is invalid", "data": [1, 2], "valid": false } ] }, { "description": "items with subitems", "schema": { "definitions": { "child": { "type": "array", "additionalItems": false, "items": [ { "$ref": "#/definitions/sub-child" }, { "$ref": "#/definitions/sub-child" } ] }, "sub-child": { "type": "object", "properties": { "foo": {} }, "required": ["foo"], "additionalProperties": false } }, "type": "array", "additionalItems": false, "items": [ { "$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} ] ], "valid": true }, { "description": "too many children", "data": [ [ {"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} ] ], "valid": false }, { "description": "wrong child", "data": [ {"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} ] ], "valid": false }, { "description": "fewer children is valid", "data": [ [ {"foo": null} ], [ {"foo": null} ] ], "valid": true } ] }, { "description": "deeply nested items", "schema": { "type": "array", "items": { "type": "array", "items": { "type": "array", "items": { "type": "array", "items": { "type": "number" } } } } }, "tests": [ { "description": "valid nested array", "data": [[[[1]], [[2],[3]]], [[[4], [5], [6]]]], "valid": true }, { "description": "nested array with invalid type", "data": [[[["1"]], [[2],[3]]], [[[4], [5], [6]]]], "valid": false }, { "description": "not deep enough", "data": [[[1], [2],[3]], [[4], [5], [6]]], "valid": false } ] } ] ajv-5.0.0/spec/tests/rules/oneOf.json000066400000000000000000000045131307514663700175020ustar00rootroot00000000000000[ { "description": "oneOf with one of schemas empty", "schema": { "oneOf": [ { "type": "number" }, {} ] }, "tests": [ { "description": "string is valid", "data": "foo", "valid": true }, { "description": "number is invalid", "data": 123, "valid": false } ] }, { "description": "oneOf with required", "schema": { "type": "object", "oneOf": [ { "required": ["foo", "bar"] }, { "required": ["foo", "baz"] } ] }, "tests": [ { "description": "object with foo and bar is valid", "data": {"foo": 1, "bar": 2}, "valid": true }, { "description": "object with foo and baz is valid", "data": {"foo": 1, "baz": 3}, "valid": true }, { "description": "object with foo, bar and baz is invalid", "data": {"foo": 1, "bar": 2, "baz" : 3}, "valid": false } ] }, { "description": "oneOf with required with 20+ properties", "schema": { "type": "object", "oneOf": [ { "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" ] } ] }, "tests": [ { "description": "object with foo and bar is valid", "data": {"foo": 1, "bar": 2}, "valid": true }, { "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 }, "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 }, "valid": false } ] } ] ajv-5.0.0/spec/tests/rules/required.json000066400000000000000000000007241307514663700202540ustar00rootroot00000000000000[ { "description": "required keyword with empty array", "schema": { "required": [] }, "tests": [ { "description": "object with property is valid", "data": { "foo": 1 }, "valid": true }, { "description": "empty object is valid", "data": {}, "valid": true }, { "description": "non-object is valid", "data": 1, "valid": true } ] } ] ajv-5.0.0/spec/tests/rules/type.json000066400000000000000000000032101307514663700174060ustar00rootroot00000000000000[ { "description": "type as array with one item", "schema": { "type": ["string"] }, "tests": [ { "description": "string is valid", "data": "foo", "valid": true }, { "description": "number is invalid", "data": 123, "valid": false } ] }, { "description": "type: array or object", "schema": { "type": ["array", "object"] }, "tests": [ { "description": "array is valid", "data": [1,2,3], "valid": true }, { "description": "object is valid", "data": {"foo":123}, "valid": true }, { "description": "number is invalid", "data": 123, "valid": false }, { "description": "string is invalid", "data": "foo", "valid": false }, { "description": "null is invalid", "data": null, "valid": false } ] }, { "description": "type: array, object or null", "schema": { "type": ["array", "object", "null"] }, "tests": [ { "description": "array is valid", "data": [1,2,3], "valid": true }, { "description": "object is valid", "data": {"foo":123}, "valid": true }, { "description": "null is valid", "data": null, "valid": true }, { "description": "number is invalid", "data": 123, "valid": false }, { "description": "string is invalid", "data": "foo", "valid": false } ] } ] ajv-5.0.0/spec/tests/schemas/000077500000000000000000000000001307514663700160275ustar00rootroot00000000000000ajv-5.0.0/spec/tests/schemas/advanced.json000066400000000000000000000221171307514663700204720ustar00rootroot00000000000000[ { "description": "advanced schema from z-schema benchmark (https://github.com/zaggino/z-schema)", "schema": { "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "/": { "$ref": "#/definitions/entry" } }, "patternProperties": { "^(/[^/]+)+$": { "$ref": "#/definitions/entry" } }, "additionalProperties": false, "required": [ "/" ], "definitions": { "entry": { "$schema": "http://json-schema.org/draft-04/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 } } } } }, "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 }, { "description": "not object", "data": 1, "valid": false }, { "description": "root only is valid", "data": { "/": { "storage": { "type": "disk", "device": "/dev/sda1" }, "fstype": "btrfs", "readonly": true } }, "valid": true }, { "description": "missing root entry", "data": { "no root/": { "storage": { "type": "disk", "device": "/dev/sda1" }, "fstype": "btrfs", "readonly": true } }, "valid": false }, { "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 }, { "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 } ] } ] ajv-5.0.0/spec/tests/schemas/basic.json000066400000000000000000000116461307514663700200130ustar00rootroot00000000000000[ { "description": "basic schema from z-schema benchmark (https://github.com/zaggino/z-schema)", "schema": { "$schema": "http://json-schema.org/draft-04/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", "minimum": 0, "exclusiveMinimum": true }, "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 }, { "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 } ] } ] ajv-5.0.0/spec/tests/schemas/complex.json000066400000000000000000000304421307514663700203740ustar00rootroot00000000000000[ { "description": "complex schema from jsck benchmark (https://github.com/pandastrike/jsck)", "schema": { "type": "array", "items": { "$ref": "#transaction" }, "minItems": 1, "definitions": { "base58": { "id": "#base58", "type": "string", "pattern": "^[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+$" }, "hex": { "id": "#hex", "type": "string", "pattern": "^[0123456789A-Fa-f]+$" }, "tx_id": { "id": "#tx_id", "allOf": [ { "$ref": "#hex" }, { "minLength": 64, "maxLength": 64 } ] }, "address": { "id": "#address", "allOf": [ { "$ref": "#base58" }, { "minLength": 34, "maxLength": 34 } ] }, "signature": { "id": "#signature", "allOf": [ { "$ref": "#hex" }, { "minLength": 128, "maxLength": 128 } ] }, "transaction": { "id": "#transaction", "additionalProperties": false, "required": [ "metadata", "hash", "inputs", "outputs" ], "properties": { "metadata": { "type": "object", "required": [ "amount", "fee" ], "properties": { "amount": { "type": "integer" }, "fee": { "type": "integer", "multipleOf": 10000 }, "status": { "type": "string", "enum": [ "unsigned", "unconfirmed", "confirmed", "invalid" ] }, "confirmations": { "type": "integer", "minimum": 0 }, "block_time": { "type": "integer" } } }, "version": { "type": "integer" }, "lock_time": { "type": "integer" }, "hash": { "$ref": "#tx_id" }, "inputs": { "type": "array", "items": { "$ref": "#input" }, "minItems": 1 }, "outputs": { "type": "array", "items": { "$ref": "#output" }, "minItems": 1 } } }, "input": { "id": "#input", "type": "object", "additionalProperties": false, "required": [ "index", "output", "script_sig" ], "properties": { "index": { "type": "integer", "minimum": 0 }, "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" } } } }, "output": { "id": "#output", "type": "object", "additionalProperties": false, "required": [ "hash", "index", "value", "script" ], "properties": { "hash": { "$ref": "#tx_id" }, "index": { "type": "integer", "minimum": 0 }, "value": { "type": "integer" }, "script": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "standard", "p2sh" ] }, "asm": { "type": "string" } } }, "address": { "$ref": "#address" }, "metadata": { "type": "object", "dependencies": { "wallet_path": [ "public_seeds" ] }, "properties": { "wallet_path": { "type": "string" }, "public_seeds": { "type": "object", "minProperties": 1, "maxProperties": 3, "additionalProperties": { "anyOf": [ { "$ref": "#base58" }, { "$ref": "#hex" } ] } } } } } } } }, "tests": [ { "description": "valid array from jsck benchmark", "data": [ { "metadata": { "amount": 38043749285, "fee": 20000, "status": "confirmed", "confirmations": 73, "block_time": 1415993584376 }, "version": 1, "lock_time": 0, "hash": "60c1f1a3160042152114e2bba45600a5045711c3a8a458016248acec59653471", "inputs": [ { "index": 0, "script_sig": "3046022100be69797cf5d784412b1258256eb657c191a04893479dfa2ae5c7f2088c7adbe0022100e6b000bd633b286ed1b9bc7682fe753d9fdad61fbe5da2a6e9444198e33a670f01", "signatures": { "primary": "3046022100be69797cf5d784412b1258256eb657c191a04893479dfa2ae5c7f2088c7adbe0022100e6b000bd633b286ed1b9bc7682fe753d9fdad61fbe5da2a7", "cosigner": "a2ad5ebf16dadf9d357ef2867cb9b1de682b336db000b6e0012200ebda7c8802f7c5ea2afd97439840a191c756be6528521b214487d5fc79796eb00122064037" }, "output": { "hash": "6b040cd7a4676b5c7b11f144e73c1958c177fcd79e934f6be8ce02c8cd12546d", "index": 1, "value": 38043749285, "script": { "type": "standard", "asm": "OP_DUP OP_HASH160 7d4e6d55e1dffb0df85f509343451d170d147551 OP_EQUALVERIFY OP_CHECKSIG" } } } ], "outputs": [ { "hash": "60c1f1a3160042152114e2bba45600a5045711c3a8a458016248acec59653471", "index": 0, "value": 38042249285, "script": { "type": "standard", "asm": "OP_DUP OP_HASH160 7d4e6d55e1dffb0df85f509343451d170d147551 OP_EQUALVERIFY OP_CHECKSIG" }, "address": "1CRZRBwfuwUaVSPJtd6DBuezbm7XPBHLa1", "metadata": { "type": "change", "wallet_path": "m/44/0/1/356", "public_seeds": { "primary": "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8", "cosigner": "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8" } } }, { "hash": "60c1f1a3160042152114e2bba45600a5045711c3a8a458016248acec59653471", "index": 1, "value": 1500000, "script": { "type": "standard", "asm": "OP_DUP OP_HASH160 3bc576e6960a9d45201ba5087e39224d0a05a079 OP_EQUALVERIFY OP_CHECKSIG" }, "address": "16T3RPZLmxtXQCgWi1S8kef5Ca6jqXhoeT" } ] }, { "metadata": { "amount": 38043749285, "fee": 20000, "status": "unconfirmed", "confirmations": 73, "block_time": 1415993584376 }, "version": 1, "lock_time": 0, "hash": "60c1f1a3160042152114e2bba45600a5045711c3a8a458016248acec59653471", "inputs": [ { "index": 0, "script_sig": "3046022100be69797cf5d784412b1258256eb657c191a04893479dfa2ae5c7f2088c7adbe0022100e6b000bd633b286ed1b9bc7682fe753d9fdad61fbe5da2a6e9444198e33a670f01", "output": { "hash": "6b040cd7a4676b5c7b11f144e73c1958c177fcd79e934f6be8ce02c8cd12546d", "index": 1, "value": 38043749285, "script": { "type": "standard", "asm": "OP_DUP OP_HASH160 7d4e6d55e1dffb0df85f509343451d170d147551 OP_EQUALVERIFY OP_CHECKSIG" } } } ], "outputs": [ { "hash": "60c1f1a3160042152114e2bba45600a5045711c3a8a458016248acec59653471", "index": 0, "value": 38042249285, "script": { "type": "standard", "asm": "OP_DUP OP_HASH160 7d4e6d55e1dffb0df85f509343451d170d147551 OP_EQUALVERIFY OP_CHECKSIG" }, "address": "1CRZRBwfuwUaVSPJtd6DBuezbm7XPBHLa1", "metadata": { "type": "change" } }, { "hash": "60c1f1a3160042152114e2bba45600a5045711c3a8a458016248acec59653471", "index": 1, "value": 1500000, "script": { "type": "standard", "asm": "OP_DUP OP_HASH160 3bc576e6960a9d45201ba5087e39224d0a05a079 OP_EQUALVERIFY OP_CHECKSIG" }, "address": "16T3RPZLmxtXQCgWi1S8kef5Ca6jqXhoeT" } ] }, { "metadata": { "amount": 38043749285, "fee": 20000, "status": "unconfirmed", "confirmations": 73, "block_time": 1415993584376 }, "version": 1, "lock_time": 0, "hash": "60c1f1a3160042152114e2bba45600a5045711c3a8a458016248acec59653471", "inputs": [ { "index": 0, "script_sig": "3046022100be69797cf5d784412b1258256eb657c191a04893479dfa2ae5c7f2088c7adbe0022100e6b000bd633b286ed1b9bc7682fe753d9fdad61fbe5da2a6e9444198e33a670f01", "output": { "hash": "6b040cd7a4676b5c7b11f144e73c1958c177fcd79e934f6be8ce02c8cd12546d", "index": 1, "value": 38043749285, "script": { "type": "standard", "asm": "OP_DUP OP_HASH160 7d4e6d55e1dffb0df85f509343451d170d147551 OP_EQUALVERIFY OP_CHECKSIG" } } } ], "outputs": [ { "hash": "60c1f1a3160042152114e2bba45600a5045711c3a8a458016248acec59653471", "index": 0, "value": 38042249285, "script": { "type": "standard", "asm": "OP_DUP OP_HASH160 7d4e6d55e1dffb0df85f509343451d170d147551 OP_EQUALVERIFY OP_CHECKSIG" }, "address": "1CRZRBwfuwUaVSPJtd6DBuezbm7XPBHLa1", "metadata": { "type": "change" } }, { "hash": "60c1f1a3160042152114e2bba45600a5045711c3a8a458016248acec59653471", "index": 1, "value": 1500000, "script": { "type": "standard", "asm": "OP_DUP OP_HASH160 3bc576e6960a9d45201ba5087e39224d0a05a079 OP_EQUALVERIFY OP_CHECKSIG" }, "address": "16T3RPZLmxtXQCgWi1S8kef5Ca6jqXhoeT" } ] } ], "valid": true }, { "description": "not array", "data": 1, "valid": false } ] } ] ajv-5.0.0/spec/tests/schemas/complex2.json000066400000000000000000000410331307514663700204540ustar00rootroot00000000000000[ { "description": "complex schema from jsck benchmark without IDs in definitions", "schema": { "type": "array", "items": { "$ref": "#/definitions/transaction" }, "minItems": 1, "definitions": { "base58": { "type": "string", "pattern": "^[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+$" }, "hex": { "type": "string", "pattern": "^[0123456789A-Fa-f]+$" }, "tx_id": { "allOf": [ { "$ref": "#/definitions/hex" }, { "minLength": 64, "maxLength": 64 } ] }, "address": { "allOf": [ { "$ref": "#/definitions/base58" }, { "minLength": 34, "maxLength": 34 } ] }, "signature": { "allOf": [ { "$ref": "#/definitions/hex" }, { "minLength": 128, "maxLength": 128 } ] }, "transaction": { "additionalProperties": false, "required": [ "metadata", "hash", "inputs", "outputs" ], "properties": { "metadata": { "type": "object", "required": [ "amount", "fee" ], "properties": { "amount": { "type": "integer" }, "fee": { "type": "integer", "multipleOf": 10000 }, "status": { "type": "string", "enum": [ "unsigned", "unconfirmed", "confirmed", "invalid" ] }, "confirmations": { "type": "integer", "minimum": 0 }, "block_time": { "type": "integer" } } }, "version": { "type": "integer" }, "lock_time": { "type": "integer" }, "hash": { "$ref": "#/definitions/tx_id" }, "inputs": { "type": "array", "items": { "$ref": "#/definitions/input" }, "minItems": 1 }, "outputs": { "type": "array", "items": { "$ref": "#/definitions/output" }, "minItems": 1 } } }, "input": { "type": "object", "additionalProperties": false, "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" }, "signatures": { "type": "object", "description": "A dictionary of signatures. Keys represent keypair names", "minProperties": 1, "maxProperties": 3, "additionalProperties": { "$ref": "#/definitions/signature" } } } }, "output": { "type": "object", "additionalProperties": false, "required": [ "hash", "index", "value", "script" ], "properties": { "hash": { "$ref": "#/definitions/tx_id" }, "index": { "type": "integer", "minimum": 0 }, "value": { "type": "integer" }, "script": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "standard", "p2sh" ] }, "asm": { "type": "string" } } }, "address": { "$ref": "#/definitions/address" }, "metadata": { "type": "object", "dependencies": { "wallet_path": [ "public_seeds" ] }, "properties": { "wallet_path": { "type": "string" }, "public_seeds": { "type": "object", "minProperties": 1, "maxProperties": 3, "additionalProperties": { "anyOf": [ { "$ref": "#/definitions/base58" }, { "$ref": "#/definitions/hex" } ] } } } } } } } }, "tests": [ { "description": "valid array from jsck benchmark", "data": [ { "metadata": { "amount": 38043749285, "fee": 20000, "status": "confirmed", "confirmations": 73, "block_time": 1415993584376 }, "version": 1, "lock_time": 0, "hash": "60c1f1a3160042152114e2bba45600a5045711c3a8a458016248acec59653471", "inputs": [ { "index": 0, "script_sig": "3046022100be69797cf5d784412b1258256eb657c191a04893479dfa2ae5c7f2088c7adbe0022100e6b000bd633b286ed1b9bc7682fe753d9fdad61fbe5da2a6e9444198e33a670f01", "signatures": { "primary": "3046022100be69797cf5d784412b1258256eb657c191a04893479dfa2ae5c7f2088c7adbe0022100e6b000bd633b286ed1b9bc7682fe753d9fdad61fbe5da2a7", "cosigner": "a2ad5ebf16dadf9d357ef2867cb9b1de682b336db000b6e0012200ebda7c8802f7c5ea2afd97439840a191c756be6528521b214487d5fc79796eb00122064037" }, "output": { "hash": "6b040cd7a4676b5c7b11f144e73c1958c177fcd79e934f6be8ce02c8cd12546d", "index": 1, "value": 38043749285, "script": { "type": "standard", "asm": "OP_DUP OP_HASH160 7d4e6d55e1dffb0df85f509343451d170d147551 OP_EQUALVERIFY OP_CHECKSIG" } } } ], "outputs": [ { "hash": "60c1f1a3160042152114e2bba45600a5045711c3a8a458016248acec59653471", "index": 0, "value": 38042249285, "script": { "type": "standard", "asm": "OP_DUP OP_HASH160 7d4e6d55e1dffb0df85f509343451d170d147551 OP_EQUALVERIFY OP_CHECKSIG" }, "address": "1CRZRBwfuwUaVSPJtd6DBuezbm7XPBHLa1", "metadata": { "type": "change", "wallet_path": "m/44/0/1/356", "public_seeds": { "primary": "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8", "cosigner": "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8" } } }, { "hash": "60c1f1a3160042152114e2bba45600a5045711c3a8a458016248acec59653471", "index": 1, "value": 1500000, "script": { "type": "standard", "asm": "OP_DUP OP_HASH160 3bc576e6960a9d45201ba5087e39224d0a05a079 OP_EQUALVERIFY OP_CHECKSIG" }, "address": "16T3RPZLmxtXQCgWi1S8kef5Ca6jqXhoeT" } ] }, { "metadata": { "amount": 38043749285, "fee": 20000, "status": "unconfirmed", "confirmations": 73, "block_time": 1415993584376 }, "version": 1, "lock_time": 0, "hash": "60c1f1a3160042152114e2bba45600a5045711c3a8a458016248acec59653471", "inputs": [ { "index": 0, "script_sig": "3046022100be69797cf5d784412b1258256eb657c191a04893479dfa2ae5c7f2088c7adbe0022100e6b000bd633b286ed1b9bc7682fe753d9fdad61fbe5da2a6e9444198e33a670f01", "output": { "hash": "6b040cd7a4676b5c7b11f144e73c1958c177fcd79e934f6be8ce02c8cd12546d", "index": 1, "value": 38043749285, "script": { "type": "standard", "asm": "OP_DUP OP_HASH160 7d4e6d55e1dffb0df85f509343451d170d147551 OP_EQUALVERIFY OP_CHECKSIG" } } } ], "outputs": [ { "hash": "60c1f1a3160042152114e2bba45600a5045711c3a8a458016248acec59653471", "index": 0, "value": 38042249285, "script": { "type": "standard", "asm": "OP_DUP OP_HASH160 7d4e6d55e1dffb0df85f509343451d170d147551 OP_EQUALVERIFY OP_CHECKSIG" }, "address": "1CRZRBwfuwUaVSPJtd6DBuezbm7XPBHLa1", "metadata": { "type": "change" } }, { "hash": "60c1f1a3160042152114e2bba45600a5045711c3a8a458016248acec59653471", "index": 1, "value": 1500000, "script": { "type": "standard", "asm": "OP_DUP OP_HASH160 3bc576e6960a9d45201ba5087e39224d0a05a079 OP_EQUALVERIFY OP_CHECKSIG" }, "address": "16T3RPZLmxtXQCgWi1S8kef5Ca6jqXhoeT" } ] }, { "metadata": { "amount": 38043749285, "fee": 20000, "status": "unconfirmed", "confirmations": 73, "block_time": 1415993584376 }, "version": 1, "lock_time": 0, "hash": "60c1f1a3160042152114e2bba45600a5045711c3a8a458016248acec59653471", "inputs": [ { "index": 0, "script_sig": "3046022100be69797cf5d784412b1258256eb657c191a04893479dfa2ae5c7f2088c7adbe0022100e6b000bd633b286ed1b9bc7682fe753d9fdad61fbe5da2a6e9444198e33a670f01", "output": { "hash": "6b040cd7a4676b5c7b11f144e73c1958c177fcd79e934f6be8ce02c8cd12546d", "index": 1, "value": 38043749285, "script": { "type": "standard", "asm": "OP_DUP OP_HASH160 7d4e6d55e1dffb0df85f509343451d170d147551 OP_EQUALVERIFY OP_CHECKSIG" } } } ], "outputs": [ { "hash": "60c1f1a3160042152114e2bba45600a5045711c3a8a458016248acec59653471", "index": 0, "value": 38042249285, "script": { "type": "standard", "asm": "OP_DUP OP_HASH160 7d4e6d55e1dffb0df85f509343451d170d147551 OP_EQUALVERIFY OP_CHECKSIG" }, "address": "1CRZRBwfuwUaVSPJtd6DBuezbm7XPBHLa1", "metadata": { "type": "change" } }, { "hash": "60c1f1a3160042152114e2bba45600a5045711c3a8a458016248acec59653471", "index": 1, "value": 1500000, "script": { "type": "standard", "asm": "OP_DUP OP_HASH160 3bc576e6960a9d45201ba5087e39224d0a05a079 OP_EQUALVERIFY OP_CHECKSIG" }, "address": "16T3RPZLmxtXQCgWi1S8kef5Ca6jqXhoeT" } ] } ], "valid": true }, { "description": "not array", "data": 1, "valid": false }, { "description": "one valid item", "data": [ { "metadata": { "amount": 38043749285, "fee": 20000, "status": "unconfirmed", "confirmations": 73, "block_time": 1415993584376 }, "version": 1, "lock_time": 0, "hash": "60c1f1a3160042152114e2bba45600a5045711c3a8a458016248acec59653471", "inputs": [ { "index": 0, "script_sig": "3046022100be69797cf5d784412b1258256eb657c191a04893479dfa2ae5c7f2088c7adbe0022100e6b000bd633b286ed1b9bc7682fe753d9fdad61fbe5da2a6e9444198e33a670f01", "output": { "hash": "6b040cd7a4676b5c7b11f144e73c1958c177fcd79e934f6be8ce02c8cd12546d", "index": 1, "value": 38043749285, "script": { "type": "standard", "asm": "OP_DUP OP_HASH160 7d4e6d55e1dffb0df85f509343451d170d147551 OP_EQUALVERIFY OP_CHECKSIG" } } } ], "outputs": [ { "hash": "60c1f1a3160042152114e2bba45600a5045711c3a8a458016248acec59653471", "index": 0, "value": 38042249285, "script": { "type": "standard", "asm": "OP_DUP OP_HASH160 7d4e6d55e1dffb0df85f509343451d170d147551 OP_EQUALVERIFY OP_CHECKSIG" }, "address": "1CRZRBwfuwUaVSPJtd6DBuezbm7XPBHLa1", "metadata": { "type": "change" } }, { "hash": "60c1f1a3160042152114e2bba45600a5045711c3a8a458016248acec59653471", "index": 1, "value": 1500000, "script": { "type": "standard", "asm": "OP_DUP OP_HASH160 3bc576e6960a9d45201ba5087e39224d0a05a079 OP_EQUALVERIFY OP_CHECKSIG" }, "address": "16T3RPZLmxtXQCgWi1S8kef5Ca6jqXhoeT" } ] } ], "valid": true }, { "description": "one invalid item", "data": [ { "metadata": { "amount": 38043749285, "fee": 20000, "status": "unconfirmed", "confirmations": 73, "block_time": 1415993584376 }, "version": 1, "lock_time": 0, "hash": "$_is_invalid", "inputs": [ { "index": 0, "script_sig": "3046022100be69797cf5d784412b1258256eb657c191a04893479dfa2ae5c7f2088c7adbe0022100e6b000bd633b286ed1b9bc7682fe753d9fdad61fbe5da2a6e9444198e33a670f01", "output": { "hash": "6b040cd7a4676b5c7b11f144e73c1958c177fcd79e934f6be8ce02c8cd12546d", "index": 1, "value": 38043749285, "script": { "type": "standard", "asm": "OP_DUP OP_HASH160 7d4e6d55e1dffb0df85f509343451d170d147551 OP_EQUALVERIFY OP_CHECKSIG" } } } ], "outputs": [ { "hash": "60c1f1a3160042152114e2bba45600a5045711c3a8a458016248acec59653471", "index": 0, "value": 38042249285, "script": { "type": "standard", "asm": "OP_DUP OP_HASH160 7d4e6d55e1dffb0df85f509343451d170d147551 OP_EQUALVERIFY OP_CHECKSIG" }, "address": "1CRZRBwfuwUaVSPJtd6DBuezbm7XPBHLa1", "metadata": { "type": "change" } }, { "hash": "60c1f1a3160042152114e2bba45600a5045711c3a8a458016248acec59653471", "index": 1, "value": 1500000, "script": { "type": "standard", "asm": "OP_DUP OP_HASH160 3bc576e6960a9d45201ba5087e39224d0a05a079 OP_EQUALVERIFY OP_CHECKSIG" }, "address": "16T3RPZLmxtXQCgWi1S8kef5Ca6jqXhoeT" } ] } ], "valid": false } ] } ] ajv-5.0.0/spec/tests/schemas/complex3.json000066400000000000000000000305221307514663700204560ustar00rootroot00000000000000[ { "description": "complex schema from jsck benchmark (https://github.com/pandastrike/jsck)", "schema": { "id": "http://example.com/complex3.json", "type": "array", "items": { "$ref": "#transaction" }, "minItems": 1, "definitions": { "base58": { "id": "#base58", "type": "string", "pattern": "^[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+$" }, "hex": { "id": "#hex", "type": "string", "pattern": "^[0123456789A-Fa-f]+$" }, "tx_id": { "id": "#tx_id", "allOf": [ { "$ref": "#hex" }, { "minLength": 64, "maxLength": 64 } ] }, "address": { "id": "#address", "allOf": [ { "$ref": "#base58" }, { "minLength": 34, "maxLength": 34 } ] }, "signature": { "id": "#signature", "allOf": [ { "$ref": "#hex" }, { "minLength": 128, "maxLength": 128 } ] }, "transaction": { "id": "#transaction", "additionalProperties": false, "required": [ "metadata", "hash", "inputs", "outputs" ], "properties": { "metadata": { "type": "object", "required": [ "amount", "fee" ], "properties": { "amount": { "type": "integer" }, "fee": { "type": "integer", "multipleOf": 10000 }, "status": { "type": "string", "enum": [ "unsigned", "unconfirmed", "confirmed", "invalid" ] }, "confirmations": { "type": "integer", "minimum": 0 }, "block_time": { "type": "integer" } } }, "version": { "type": "integer" }, "lock_time": { "type": "integer" }, "hash": { "$ref": "#tx_id" }, "inputs": { "type": "array", "items": { "$ref": "#input" }, "minItems": 1 }, "outputs": { "type": "array", "items": { "$ref": "#output" }, "minItems": 1 } } }, "input": { "id": "#input", "type": "object", "additionalProperties": false, "required": [ "index", "output", "script_sig" ], "properties": { "index": { "type": "integer", "minimum": 0 }, "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" } } } }, "output": { "id": "#output", "type": "object", "additionalProperties": false, "required": [ "hash", "index", "value", "script" ], "properties": { "hash": { "$ref": "#tx_id" }, "index": { "type": "integer", "minimum": 0 }, "value": { "type": "integer" }, "script": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "standard", "p2sh" ] }, "asm": { "type": "string" } } }, "address": { "$ref": "#address" }, "metadata": { "type": "object", "dependencies": { "wallet_path": [ "public_seeds" ] }, "properties": { "wallet_path": { "type": "string" }, "public_seeds": { "type": "object", "minProperties": 1, "maxProperties": 3, "additionalProperties": { "anyOf": [ { "$ref": "#base58" }, { "$ref": "#hex" } ] } } } } } } } }, "tests": [ { "description": "valid array from jsck benchmark", "data": [ { "metadata": { "amount": 38043749285, "fee": 20000, "status": "confirmed", "confirmations": 73, "block_time": 1415993584376 }, "version": 1, "lock_time": 0, "hash": "60c1f1a3160042152114e2bba45600a5045711c3a8a458016248acec59653471", "inputs": [ { "index": 0, "script_sig": "3046022100be69797cf5d784412b1258256eb657c191a04893479dfa2ae5c7f2088c7adbe0022100e6b000bd633b286ed1b9bc7682fe753d9fdad61fbe5da2a6e9444198e33a670f01", "signatures": { "primary": "3046022100be69797cf5d784412b1258256eb657c191a04893479dfa2ae5c7f2088c7adbe0022100e6b000bd633b286ed1b9bc7682fe753d9fdad61fbe5da2a7", "cosigner": "a2ad5ebf16dadf9d357ef2867cb9b1de682b336db000b6e0012200ebda7c8802f7c5ea2afd97439840a191c756be6528521b214487d5fc79796eb00122064037" }, "output": { "hash": "6b040cd7a4676b5c7b11f144e73c1958c177fcd79e934f6be8ce02c8cd12546d", "index": 1, "value": 38043749285, "script": { "type": "standard", "asm": "OP_DUP OP_HASH160 7d4e6d55e1dffb0df85f509343451d170d147551 OP_EQUALVERIFY OP_CHECKSIG" } } } ], "outputs": [ { "hash": "60c1f1a3160042152114e2bba45600a5045711c3a8a458016248acec59653471", "index": 0, "value": 38042249285, "script": { "type": "standard", "asm": "OP_DUP OP_HASH160 7d4e6d55e1dffb0df85f509343451d170d147551 OP_EQUALVERIFY OP_CHECKSIG" }, "address": "1CRZRBwfuwUaVSPJtd6DBuezbm7XPBHLa1", "metadata": { "type": "change", "wallet_path": "m/44/0/1/356", "public_seeds": { "primary": "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8", "cosigner": "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8" } } }, { "hash": "60c1f1a3160042152114e2bba45600a5045711c3a8a458016248acec59653471", "index": 1, "value": 1500000, "script": { "type": "standard", "asm": "OP_DUP OP_HASH160 3bc576e6960a9d45201ba5087e39224d0a05a079 OP_EQUALVERIFY OP_CHECKSIG" }, "address": "16T3RPZLmxtXQCgWi1S8kef5Ca6jqXhoeT" } ] }, { "metadata": { "amount": 38043749285, "fee": 20000, "status": "unconfirmed", "confirmations": 73, "block_time": 1415993584376 }, "version": 1, "lock_time": 0, "hash": "60c1f1a3160042152114e2bba45600a5045711c3a8a458016248acec59653471", "inputs": [ { "index": 0, "script_sig": "3046022100be69797cf5d784412b1258256eb657c191a04893479dfa2ae5c7f2088c7adbe0022100e6b000bd633b286ed1b9bc7682fe753d9fdad61fbe5da2a6e9444198e33a670f01", "output": { "hash": "6b040cd7a4676b5c7b11f144e73c1958c177fcd79e934f6be8ce02c8cd12546d", "index": 1, "value": 38043749285, "script": { "type": "standard", "asm": "OP_DUP OP_HASH160 7d4e6d55e1dffb0df85f509343451d170d147551 OP_EQUALVERIFY OP_CHECKSIG" } } } ], "outputs": [ { "hash": "60c1f1a3160042152114e2bba45600a5045711c3a8a458016248acec59653471", "index": 0, "value": 38042249285, "script": { "type": "standard", "asm": "OP_DUP OP_HASH160 7d4e6d55e1dffb0df85f509343451d170d147551 OP_EQUALVERIFY OP_CHECKSIG" }, "address": "1CRZRBwfuwUaVSPJtd6DBuezbm7XPBHLa1", "metadata": { "type": "change" } }, { "hash": "60c1f1a3160042152114e2bba45600a5045711c3a8a458016248acec59653471", "index": 1, "value": 1500000, "script": { "type": "standard", "asm": "OP_DUP OP_HASH160 3bc576e6960a9d45201ba5087e39224d0a05a079 OP_EQUALVERIFY OP_CHECKSIG" }, "address": "16T3RPZLmxtXQCgWi1S8kef5Ca6jqXhoeT" } ] }, { "metadata": { "amount": 38043749285, "fee": 20000, "status": "unconfirmed", "confirmations": 73, "block_time": 1415993584376 }, "version": 1, "lock_time": 0, "hash": "60c1f1a3160042152114e2bba45600a5045711c3a8a458016248acec59653471", "inputs": [ { "index": 0, "script_sig": "3046022100be69797cf5d784412b1258256eb657c191a04893479dfa2ae5c7f2088c7adbe0022100e6b000bd633b286ed1b9bc7682fe753d9fdad61fbe5da2a6e9444198e33a670f01", "output": { "hash": "6b040cd7a4676b5c7b11f144e73c1958c177fcd79e934f6be8ce02c8cd12546d", "index": 1, "value": 38043749285, "script": { "type": "standard", "asm": "OP_DUP OP_HASH160 7d4e6d55e1dffb0df85f509343451d170d147551 OP_EQUALVERIFY OP_CHECKSIG" } } } ], "outputs": [ { "hash": "60c1f1a3160042152114e2bba45600a5045711c3a8a458016248acec59653471", "index": 0, "value": 38042249285, "script": { "type": "standard", "asm": "OP_DUP OP_HASH160 7d4e6d55e1dffb0df85f509343451d170d147551 OP_EQUALVERIFY OP_CHECKSIG" }, "address": "1CRZRBwfuwUaVSPJtd6DBuezbm7XPBHLa1", "metadata": { "type": "change" } }, { "hash": "60c1f1a3160042152114e2bba45600a5045711c3a8a458016248acec59653471", "index": 1, "value": 1500000, "script": { "type": "standard", "asm": "OP_DUP OP_HASH160 3bc576e6960a9d45201ba5087e39224d0a05a079 OP_EQUALVERIFY OP_CHECKSIG" }, "address": "16T3RPZLmxtXQCgWi1S8kef5Ca6jqXhoeT" } ] } ], "valid": true }, { "description": "not array", "data": 1, "valid": false } ] } ] ajv-5.0.0/spec/tests/schemas/cosmicrealms.json000066400000000000000000000073341307514663700214120ustar00rootroot00000000000000[ { "description": "schema from cosmicrealms benchmark", "schema": { "name": "test", "type": "object", "additionalProperties": false, "required": [ "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 }, "topThreeFavoriteColors": { "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 } }, "favoriteFiveLetterWord": { "type": "string", "minLength": 5, "maxLength": 5 }, "emailAddresses": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "type": "string", "format": "email" } }, "ipAddresses": { "type": "array", "uniqueItems": true, "items": { "type": "string", "format": "ipv4" } } } }, "tests": [ { "description": "valid data from cosmicrealms benchmark", "data": { "fullName": "John Smith", "state": "CA", "city": "Los Angeles", "favoriteFiveLetterWord": "hello", "emailAddresses": [ "NRorsfCYtvB5bKAf1jZMu1GAJzAhhg5lEvh@inTqnn.net", "6tjWtYxjaan2Ivm5QZVhKxImKawRCA6gcqtMEwV1@bB01pCtIBY0F.org", "j68UnHfrHiKwpAm8iYokoMuRTpWUj8bfxspusNFK@COoWeMZL.edu", "qlnrIsYSWCGUQW6f8HL@UBOqUYQQzugVL.uk" ], "dozen": 12, "dozenOrBakersDozen": 13, "favoriteEvenNumber": 24, "married": true, "age": 17, "zip": 65794, "topThreeFavoriteColors": [ "blue", "black", "yellow" ], "favoriteSingleDigitWholeNumbers": [ 2, 1, 3, 9 ], "ipAddresses": [ "225.234.40.3", "96.216.243.54", "18.126.145.83", "196.17.191.239" ] }, "valid": true }, { "description": "invalid data", "data": { "state": null, "city": 90912, "zip": [ null ], "married": "married", "dozen": 90912, "dozenOrBakersDozen": null, "favoriteEvenNumber": -1294145, "emailAddresses": [], "topThreeFavoriteColors": [ null, null, 0.7925170068027211, 1.2478632478632479, 1.173913043478261, 0.4472049689440994 ], "favoriteSingleDigitWholeNumbers": [], "favoriteFiveLetterWord": "more than five letters", "ipAddresses": [ "55.335.74.758", "191.266.92.805", "193.388.390.250", "269.375.318.49", "120.268.59.140" ] }, "valid": false } ] } ] ajv-5.0.0/spec/tests/schemas/medium.json000066400000000000000000000063271307514663700202120ustar00rootroot00000000000000[ { "description": "medium schema from jsck benchmark (https://github.com/pandastrike/jsck)", "schema": { "description": "A moderately complex schema with some nesting and value constraints", "type": "object", "additionalProperties": false, "required": [ "api_server", "transport", "storage", "chain" ], "properties": { "api_server": { "description": "Settings for the HTTP API server", "type": "object", "additionalProperties": false, "required": [ "url", "host", "port" ], "properties": { "url": { "type": "string", "format": "uri" }, "host": { "type": "string" }, "port": { "type": "integer", "minimum": 1000 } } }, "transport": { "description": "Settings for the Redis tranport", "additionalProperties": false, "required": [ "server" ], "properties": { "server": { "type": "string" }, "options": { "type": "object" }, "queues": { "properties": { "blocking_timeout": { "type": "integer", "minimum": 0 } } } } }, "storage": { "description": "Settings for the PostgreSQL storage", "required": [ "server", "database", "user" ], "properties": { "server": { "type": "string" }, "database": { "type": "string" }, "user": { "type": "string" }, "options": { "type": "object" } } }, "chain": { "description": "Settings for the Chain.com client", "required": [ "api_key_id", "api_key_secret" ], "properties": { "api_key_id": { "type": "string" }, "api_key_secret": { "type": "string" } } } } }, "tests": [ { "description": "valid object from jsck benchmark", "data": { "api_server": { "url": "http://example.com:8998", "host": "example.com", "port": 8998 }, "transport": { "server": "127.0.0.1:6381", "queues": { "blocking_timeout": 0 } }, "storage": { "server": "127.0.0.1:5432", "database": "thingy-test", "user": "thingy-test", "password": "password" }, "chain": { "api_key_id": "cafebabe", "api_key_secret": "babecafe" } }, "valid": true }, { "description": "not object", "data": 1, "valid": false } ] } ]