feat: strictKeywords option to report unknown keywords, closes #781
parent
9a28689340
commit
e993bd6b4e
12
README.md
12
README.md
|
@ -1072,7 +1072,9 @@ Defaults:
|
|||
removeAdditional: false,
|
||||
useDefaults: false,
|
||||
coerceTypes: false,
|
||||
// strict mode options
|
||||
strictDefaults: false,
|
||||
strictKeywords: false,
|
||||
// asynchronous validation options:
|
||||
transpile: undefined, // requires ajv-async package
|
||||
// advanced options:
|
||||
|
@ -1154,10 +1156,18 @@ Defaults:
|
|||
- `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).
|
||||
- _strictDefaults_: specify behavior for ignored `default` keywords in schemas. Option values:
|
||||
|
||||
|
||||
##### Strict mode options
|
||||
|
||||
- _strictDefaults_: report ignored `default` keywords in schemas. Option values:
|
||||
- `false` (default) - ignored defaults are not reported
|
||||
- `true` - if an ignored default is present, throw an error
|
||||
- `"log"` - if an ignored default is present, log warning
|
||||
- _strictKeywords_: report unknown keywords in schemas. Option values:
|
||||
- `false` (default) - unknown keywords are not reported
|
||||
- `true` - if an unknown keyword is present, throw an error
|
||||
- `"log"` - if an unknown keyword is present, log warning
|
||||
|
||||
|
||||
##### Asynchronous validation options
|
||||
|
|
|
@ -20,7 +20,7 @@ module.exports = function rules() {
|
|||
|
||||
var ALL = [ 'type', '$comment' ];
|
||||
var KEYWORDS = [
|
||||
'$schema', '$id', 'id', '$data', 'title',
|
||||
'$schema', '$id', 'id', '$data', '$async', 'title',
|
||||
'description', 'default', 'definitions',
|
||||
'examples', 'readOnly', 'writeOnly',
|
||||
'contentMediaType', 'contentEncoding',
|
||||
|
|
|
@ -17,6 +17,7 @@ module.exports = {
|
|||
finalCleanUpCode: finalCleanUpCode,
|
||||
schemaHasRules: schemaHasRules,
|
||||
schemaHasRulesExcept: schemaHasRulesExcept,
|
||||
schemaUnknownRules: schemaUnknownRules,
|
||||
toQuotedString: toQuotedString,
|
||||
getPathExpr: getPathExpr,
|
||||
getPath: getPath,
|
||||
|
@ -183,6 +184,12 @@ function schemaHasRulesExcept(schema, rules, exceptKeyword) {
|
|||
}
|
||||
|
||||
|
||||
function schemaUnknownRules(schema, rules) {
|
||||
if (typeof schema == 'boolean') return;
|
||||
for (var key in schema) if (!rules[key]) return key;
|
||||
}
|
||||
|
||||
|
||||
function toQuotedString(str) {
|
||||
return '\'' + escapeQuotes(str) + '\'';
|
||||
}
|
||||
|
|
|
@ -20,6 +20,17 @@
|
|||
, $id = it.self._getId(it.schema);
|
||||
}}
|
||||
|
||||
{{
|
||||
if (it.opts.strictKeywords) {
|
||||
var $unknownKwd = it.util.schemaUnknownRules(it.schema, it.RULES.keywords);
|
||||
if ($unknownKwd) {
|
||||
var $keywordsMsg = 'unknown keyword: ' + $unknownKwd;
|
||||
if (it.opts.strictKeywords === 'log') it.logger.warn($keywordsMsg);
|
||||
else throw new Error($keywordsMsg);
|
||||
}
|
||||
}
|
||||
}}
|
||||
|
||||
{{? it.isTop }}
|
||||
var validate = {{?$async}}{{it.async = true;}}async {{?}}function(data, dataPath, parentData, parentDataProperty, rootData) {
|
||||
'use strict';
|
||||
|
|
|
@ -415,6 +415,7 @@ describe('Custom keywords', function () {
|
|||
it('should correctly expand macros in macro expansions', function() {
|
||||
instances.forEach(function (_ajv) {
|
||||
_ajv.addKeyword('range', { type: 'number', macro: macroRange });
|
||||
_ajv.addKeyword('exclusiveRange', { metaSchema: {type: 'boolean'} });
|
||||
_ajv.addKeyword('myContains', { type: 'array', macro: macroContains });
|
||||
|
||||
var schema = {
|
||||
|
@ -811,6 +812,7 @@ describe('Custom keywords', function () {
|
|||
function testRangeKeyword(definition, customErrors, numErrors) {
|
||||
instances.forEach(function (_ajv) {
|
||||
_ajv.addKeyword('x-range', definition);
|
||||
_ajv.addKeyword('exclusiveRange', {metaSchema: {type: 'boolean'}});
|
||||
|
||||
var schema = { "x-range": [2, 4] };
|
||||
var validate = _ajv.compile(schema);
|
||||
|
@ -849,6 +851,7 @@ describe('Custom keywords', function () {
|
|||
function testMultipleRangeKeyword(definition, numErrors) {
|
||||
instances.forEach(function (_ajv) {
|
||||
_ajv.addKeyword('x-range', definition);
|
||||
_ajv.addKeyword('exclusiveRange', {metaSchema: {type: 'boolean'}});
|
||||
|
||||
var schema = {
|
||||
"properties": {
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
'use strict';
|
||||
|
||||
var Ajv = require('../ajv');
|
||||
var should = require('../chai').should();
|
||||
|
||||
|
||||
describe('strictKeywords option', function() {
|
||||
describe('strictKeywords = false', function() {
|
||||
it('should NOT throw an error or log a warning given an unknown keyword', function() {
|
||||
var output = {};
|
||||
var ajv = new Ajv({
|
||||
strictKeywords: false,
|
||||
logger: getLogger(output)
|
||||
});
|
||||
var schema = {
|
||||
properties: {},
|
||||
unknownKeyword: 1
|
||||
};
|
||||
|
||||
ajv.compile(schema);
|
||||
should.not.exist(output.warning);
|
||||
});
|
||||
});
|
||||
|
||||
describe('strictKeywords = true', function() {
|
||||
it('should throw an error given an unknown keyword in the schema root when strictKeywords is true', function() {
|
||||
var ajv = new Ajv({strictKeywords: true});
|
||||
var schema = {
|
||||
properties: {},
|
||||
unknownKeyword: 1
|
||||
};
|
||||
should.throw(function() { ajv.compile(schema); });
|
||||
});
|
||||
});
|
||||
|
||||
describe('strictKeywords = "log"', function() {
|
||||
it('should log a warning given an unknown keyword in the schema root when strictKeywords is "log"', function() {
|
||||
var output = {};
|
||||
var ajv = new Ajv({
|
||||
strictKeywords: 'log',
|
||||
logger: getLogger(output)
|
||||
});
|
||||
var schema = {
|
||||
properties: {},
|
||||
unknownKeyword: 1
|
||||
};
|
||||
ajv.compile(schema);
|
||||
should.equal(output.warning, 'unknown keyword: unknownKeyword');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
function getLogger(output) {
|
||||
return {
|
||||
log: function() {
|
||||
throw new Error('log should not be called');
|
||||
},
|
||||
warn: function(warning) {
|
||||
output.warning = warning;
|
||||
},
|
||||
error: function() {
|
||||
throw new Error('error should not be called');
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
Loading…
Reference in New Issue