From 34993de951c7b00b05f1a27a6e37e1ccd9a46ef9 Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin Date: Sun, 13 Sep 2015 00:50:56 +0100 Subject: [PATCH] i18n support for ajv-i18n package --- README.md | 30 +++++++++++++++++++++++++++++- karma.conf.js | 4 +++- lib/dot/definitions.def | 37 ++++++++++++++++++++++++++++++------- package.json | 2 +- spec/errors.spec.js | 28 ++++++++++++++-------------- spec/json-schema.spec.js | 7 ++++--- 6 files changed, 81 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index 3b6a228b5..0517a049b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # ajv - Another JSON Schema Validator -One of the fastest JSON Schema validators for node.js and browser. +Currently the fastest JSON Schema validator for node.js and browser. It uses precompiled [doT templates](https://github.com/olado/doT) to generate super-fast validating functions. @@ -255,6 +255,31 @@ Options can have properties `separator` (string used to separate errors, ", " by ## Options +Defaults: + +``` +{ + allErrors: false, + removeAdditional: false, + verbose: false, + format: 'fast', + formats: {}, + schemas: {}, + meta: true, + validateSchema: true, + inlineRefs: true, + missingRefs: true, + loadSchema: function(uri, cb) { /* ... */ cb(err, schema); }, + uniqueItems: true, + unicode: true, + beautify: false, + cache: new Cache, + jsonPointers: false, + i18n: false, + messages: true +} +``` + - _allErrors_: check all rules collecting all errors. Default is to return after the first error. - _removeAdditional_: remove additional properties. Default is not to remove. If the option is 'all', then all additional properties are removed, regardless of `additionalProperties` keyword in schema (and no validation is made for them). If the option is `true` (or truthy), only additional properties with `additionalProperties` keyword equal to `false` are removed. If the option is 'failing', then additional properties that fail schema validation will be removed too (where `additionalProperties` keyword is schema). - _verbose_: include the reference to the part of the schema and validated data in errors (false by default). @@ -271,6 +296,9 @@ Options can have properties `separator` (string used to separate errors, ", " by - _beautify_: format the generated function with [js-beautify](https://github.com/beautify-web/js-beautify) (the validating function is generated without line-breaks). `npm install js-beautify` to use this option. `true` or js-beautify options can be passed. - _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)` and `del(key)`. - _jsonPointers_: Output `dataPath` using JSON Pointers instead of JS path notation. +- _i18n_: Support internationalization of error messages using [ajv-i18n](https://github.com/epoberezkin/ajv-i18n). See its repo for details. +- _messages_: Include human-readable messages in errors. `true` by default. `messages: false` can be added when internationalization (options `i18n`) is used. + ## Tests diff --git a/karma.conf.js b/karma.conf.js index 5f7b030bb..bf5bb61c7 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -55,6 +55,8 @@ module.exports = function(config) { // Continuous Integration mode // if true, Karma captures browsers, runs the tests and exits - singleRun: true + singleRun: true, + + browserNoActivityTimeout: 30000 }); }; diff --git a/lib/dot/definitions.def b/lib/dot/definitions.def index e1e5d02cc..20278bdfa 100644 --- a/lib/dot/definitions.def +++ b/lib/dot/definitions.def @@ -90,9 +90,17 @@ {{## def._error:_rule: { keyword: '{{=_rule}}', - dataPath: (dataPath || '') + {{= it.errorPath }}, - message: {{# def._errorMessages[_rule] }} - {{? it.opts.verbose }}, schema: {{# def._errorSchemas[_rule] }}, data: {{=$data}}{{?}} + dataPath: (dataPath || '') + {{= it.errorPath }} + {{? it.opts.messages !== false }} + , message: {{# def._errorMessages[_rule] }} + {{?}} + {{? it.opts.verbose || it.opts.i18n }} + , schema: {{# def._errorSchemas[_rule] }} + {{?}} + {{? it.opts.verbose }} + , data: {{=$data}} + {{?}} + {{# def._errorParams[_rule] || '' }} } #}} @@ -125,9 +133,9 @@ {{## def._errorMessages = { $ref: "'can\\\'t resolve reference {{=it.util.escapeQuotes($schema)}}'", additionalItems: "'should NOT have more than {{=$schema.length}} items'", - additionalProperties: "'additional properties NOT allowed'", + additionalProperties: "'should NOT have additional properties'", anyOf: "'should match some schema in anyOf'", - dependencies: "'{{? $deps.length == 1 }}property {{= it.util.escapeQuotes($deps[0]) }} is{{??}}properties {{= it.util.escapeQuotes($deps.join(\", \")) }} are{{?}} required when property {{= it.util.escapeQuotes($property) }} is present'", + dependencies: "'should have {{? $deps.length == 1 }}property {{= it.util.escapeQuotes($deps[0]) }}{{??}}properties {{= it.util.escapeQuotes($deps.join(\", \")) }}{{?}} when property {{= it.util.escapeQuotes($property) }} is present'", enum: "'should be equal to one of values'", format: "'should match format {{=it.util.escapeQuotes($schema)}}'", maximum: "'should be {{=$op}} {{=$schema}}'", @@ -142,9 +150,9 @@ not: "'should NOT be valid'", oneOf: "'should match exactly one schema in oneOf'", pattern: "'should match pattern \"{{=it.util.escapeQuotes($schema)}}\"'", - required: "'property {{=$missingProperty}} is required'", + required: "'should have required property {{=$missingProperty}}'", type: "'should be {{? $isArray }}{{= $typeSchema.join(\",\") }}{{??}}{{=$typeSchema}}{{?}}'", - uniqueItems: "'items ## ' + j + ' and ' + i + ' are duplicate'" + uniqueItems: "'should NOT have duplicate items (items ## ' + j + ' and ' + i + ' are identical)'" } #}} @@ -172,3 +180,18 @@ type: "{{? $isArray }}['{{= $typeSchema.join(\"','\") }}']{{??}}'{{=$typeSchema}}'{{?}}", uniqueItems: "{{=$schema}}" } #}} + + +{{## def._params = "{{? it.opts.i18n }}, params: " #}} + +{{## def._errorParams = { + $ref: "{{# def._params }}{ escaped: '{{=it.util.escapeQuotes($schema)}}' }{{?}}", + dependencies: "{{# def._params }}{ n: {{=$deps.length}}, deps: '{{? $deps.length==1 }}{{= it.util.escapeQuotes($deps[0]) }}{{??}}{{= it.util.escapeQuotes($deps.join(\", \")) }}{{?}}', property: '{{= it.util.escapeQuotes($property) }}' }{{?}}", + format: "{{# def._params }}{ escaped: '{{=it.util.escapeQuotes($schema)}}' }{{?}}", + maximum: "{{# def._params }}{ condition: '{{=$op}} {{=$schema}}' }{{?}}", + minimum: "{{# def._params }}{ condition: '{{=$op}} {{=$schema}}' }{{?}}", + pattern: "{{# def._params }}{ escaped: '{{=it.util.escapeQuotes($schema)}}' }{{?}}", + required: "{{# def._params }}{ missingProperty: '{{=$missingProperty}}' }{{?}}", + type: "{{# def._params }}{ type: '{{? $isArray }}{{= $typeSchema.join(\",\") }}{{??}}{{=$typeSchema}}{{?}}' }{{?}}", + uniqueItems: "{{# def._params }}{ i: i, j: j }{{?}}" +} #}} diff --git a/package.json b/package.json index fbb658fb7..4d718b09f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ajv", - "version": "1.3.2", + "version": "1.4.0", "description": "Another JSON Schema Validator", "main": "lib/ajv.js", "files": [ diff --git a/spec/errors.spec.js b/spec/errors.spec.js index 1d0990209..e3e0fe75f 100644 --- a/spec/errors.spec.js +++ b/spec/errors.spec.js @@ -83,24 +83,24 @@ describe('Validation errors', function () { var validate = ajv.compile(schema); shouldBeValid(validate, data); shouldBeInvalid(validate, invalidData1); - shouldBeError(validate.errors[0], 'required', '.bar', 'property .bar is required'); + shouldBeError(validate.errors[0], 'required', '.bar', 'should have required property .bar'); shouldBeInvalid(validate, invalidData2); - shouldBeError(validate.errors[0], 'required', '.foo', 'property .foo is required'); + shouldBeError(validate.errors[0], 'required', '.foo', 'should have required property .foo'); var validateJP = ajvJP.compile(schema); shouldBeValid(validateJP, data); shouldBeInvalid(validateJP, invalidData1); - shouldBeError(validateJP.errors[0], 'required', '/bar', 'property bar is required'); + shouldBeError(validateJP.errors[0], 'required', '/bar', 'should have required property bar'); shouldBeInvalid(validateJP, invalidData2); - shouldBeError(validateJP.errors[0], 'required', '/foo', 'property foo is required'); + shouldBeError(validateJP.errors[0], 'required', '/foo', 'should have required property foo'); var fullValidate = fullAjv.compile(schema); shouldBeValid(fullValidate, data); shouldBeInvalid(fullValidate, invalidData1); - shouldBeError(fullValidate.errors[0], 'required', '/bar', 'property .bar is required'); + shouldBeError(fullValidate.errors[0], 'required', '/bar', 'should have required property .bar'); shouldBeInvalid(fullValidate, invalidData2, 2); - shouldBeError(fullValidate.errors[0], 'required', '/foo', 'property .foo is required'); - shouldBeError(fullValidate.errors[1], 'required', '/baz', 'property .baz is required'); + shouldBeError(fullValidate.errors[0], 'required', '/foo', 'should have required property .foo'); + shouldBeError(fullValidate.errors[1], 'required', '/baz', 'should have required property .baz'); }); @@ -121,24 +121,24 @@ describe('Validation errors', function () { var validate = ajv.compile(schema); shouldBeValid(validate, data); shouldBeInvalid(validate, invalidData1); - shouldBeError(validate.errors[0], 'required', "['1']", "property '1' is required"); + shouldBeError(validate.errors[0], 'required', "['1']", "should have required property '1'"); shouldBeInvalid(validate, invalidData2); - shouldBeError(validate.errors[0], 'required', "['2']", "property '2' is required"); + shouldBeError(validate.errors[0], 'required', "['2']", "should have required property '2'"); var validateJP = ajvJP.compile(schema); shouldBeValid(validateJP, data); shouldBeInvalid(validateJP, invalidData1); - shouldBeError(validateJP.errors[0], 'required', "/1", "property '1' is required"); + shouldBeError(validateJP.errors[0], 'required', "/1", "should have required property '1'"); shouldBeInvalid(validateJP, invalidData2); - shouldBeError(validateJP.errors[0], 'required', "/2", "property '2' is required"); + shouldBeError(validateJP.errors[0], 'required', "/2", "should have required property '2'"); var fullValidate = fullAjv.compile(schema); shouldBeValid(fullValidate, data); shouldBeInvalid(fullValidate, invalidData1); - shouldBeError(fullValidate.errors[0], 'required', '/1', "property '1' is required"); + shouldBeError(fullValidate.errors[0], 'required', '/1', "should have required property '1'"); shouldBeInvalid(fullValidate, invalidData2, 2); - shouldBeError(fullValidate.errors[0], 'required', '/2', "property '2' is required"); - shouldBeError(fullValidate.errors[1], 'required', '/98', "property '98' is required"); + shouldBeError(fullValidate.errors[0], 'required', '/2', "should have required property '2'"); + shouldBeError(fullValidate.errors[1], 'required', '/98', "should have required property '98'"); }); diff --git a/spec/json-schema.spec.js b/spec/json-schema.spec.js index ae0537fbd..b8376c2ef 100644 --- a/spec/json-schema.spec.js +++ b/spec/json-schema.spec.js @@ -13,7 +13,8 @@ var instances = getAjvInstances({ verbose: true, format: 'full', inlineRefs: false, - jsonPointers: true + jsonPointers: true, + i18n: true }); var remoteRefs = { @@ -25,7 +26,7 @@ var remoteRefs = { 'http://localhost:1234/name.json': require('./remotes/name.json') }; -var remoteRefsWithIds = [ // order is important +var remoteRefsWithIds = [ require('./remotes/bar.json'), require('./remotes/foo.json'), require('./remotes/buu.json'), @@ -57,7 +58,7 @@ jsonSchemaTest(instances, { ], cwd: __dirname, hideFolder: 'draft4/', - timeout: 60000 + timeout: 90000 });