feat: option $comment, closes #609

master
Evgeny Poberezkin 2017-11-10 21:41:27 +00:00
parent d97543f327
commit dd884fe93d
8 changed files with 157 additions and 3 deletions

View File

@ -991,6 +991,7 @@ Defaults:
$data: false,
allErrors: false,
verbose: false,
$comment: false, // NEW in Ajv version 6.0
jsonPointers: false,
uniqueItems: true,
unicode: true,
@ -1032,6 +1033,10 @@ Defaults:
- _$data_: support [$data references](#data-reference). Draft 6 meta-schema that is added by default will be extended to allow them. If you want to use another meta-schema you need to use $dataMetaSchema method to add support for $data reference. See [API](#api).
- _allErrors_: check all rules collecting all errors. Default is to return after the first error.
- _verbose_: include the reference to the part of the schema (`schema` and `parentSchema`) and validated data in errors (false by default).
- _$comment_ (NEW in Ajv version 6.0): log or pass the value of `$comment` keyword to a function. Option values:
- `false` (default): ignore $comment keyword.
- `true`: log the keyword value to console.
- function: pass the keyword value, its schema path and root schema to the specified function
- _jsonPointers_: set `dataPath` property of errors using [JSON Pointers](https://tools.ietf.org/html/rfc6901) instead of JavaScript property access notation.
- _uniqueItems_: validate `uniqueItems` keyword (true by default).
- _unicode_: calculate correct length of strings with unicode pairs (true by default). Pass `false` to use `.length` of strings that is faster, but gives "incorrect" lengths of strings with unicode pairs - each unicode pair is counted as two characters.

View File

@ -18,10 +18,11 @@ module.exports = function rules() {
{ rules: [ '$ref', 'const', 'enum', 'not', 'anyOf', 'oneOf', 'allOf', 'if' ] }
];
var ALL = [ 'type' ];
var ALL = [ 'type', '$comment' ];
var KEYWORDS = [
'$schema', '$id', 'id', '$comment',
'title', 'description', 'default', 'definitions',
'$schema', '$id', 'id',
'title', 'description',
'default', 'definitions',
'additionalItems', 'then', 'else'
];
var TYPES = [ 'number', 'integer', 'string', 'array', 'object', 'boolean', 'null' ];
@ -49,6 +50,11 @@ module.exports = function rules() {
return rule;
});
RULES.all.$comment = {
keyword: '$comment',
code: ruleModules.$comment
};
if (group.type) RULES.types[group.type] = group;
});

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

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

View File

@ -127,6 +127,10 @@
{{?}}
{{?}}
{{? it.schema.$comment && it.opts.$comment }}
{{= it.RULES.all.$comment.code(it, '$comment') }}
{{?}}
{{? $typeSchema }}
{{? it.opts.coerceTypes }}
{{ var $coerceToTypes = it.util.coerceToTypes(it.opts.coerceTypes, $typeSchema); }}

View File

@ -5,6 +5,7 @@ module.exports = {
'$ref': require('./ref'),
allOf: require('./allOf'),
anyOf: require('./anyOf'),
'$comment': require('./comment'),
const: require('./const'),
contains: require('./contains'),
dependencies: require('./dependencies'),

View File

@ -8,3 +8,4 @@ globals:
it: false
before: false
beforeEach: false
afterEach: false

View File

@ -1219,4 +1219,92 @@ describe('Ajv Options', function () {
});
});
});
describe('$comment', function() {
describe('= true', function() {
var logCalls, consoleLog;
beforeEach(function () {
consoleLog = console.log;
console.log = log;
});
afterEach(function () {
console.log = consoleLog;
});
function log() {
logCalls.push(Array.prototype.slice.call(arguments));
}
it('should log the text from $comment keyword', function() {
var schema = {
properties: {
foo: {$comment: 'property foo'},
bar: {$comment: 'property bar', type: 'integer'}
}
};
var ajv = new Ajv({$comment: true});
var fullAjv = new Ajv({allErrors: true, $comment: true});
[ajv, fullAjv].forEach(function (_ajv) {
var validate = _ajv.compile(schema);
test({}, true, []);
test({foo: 1}, true, [['property foo']]);
test({foo: 1, bar: 2}, true, [['property foo'], ['property bar']]);
test({foo: 1, bar: 'baz'}, false, [['property foo'], ['property bar']]);
function test(data, valid, expectedLogCalls) {
logCalls = [];
validate(data) .should.equal(valid);
logCalls .should.eql(expectedLogCalls);
}
});
console.log = consoleLog;
});
});
describe('function hook', function() {
var hookCalls;
function hook() {
hookCalls.push(Array.prototype.slice.call(arguments));
}
it('should pass the text from $comment keyword to the hook', function() {
var schema = {
properties: {
foo: {$comment: 'property foo'},
bar: {$comment: 'property bar', type: 'integer'}
}
};
var ajv = new Ajv({$comment: hook});
var fullAjv = new Ajv({allErrors: true, $comment: hook});
[ajv, fullAjv].forEach(function (_ajv) {
var validate = _ajv.compile(schema);
test({}, true, []);
test({foo: 1}, true, [['property foo', '#/properties/foo/$comment', schema]]);
test({foo: 1, bar: 2}, true,
[['property foo', '#/properties/foo/$comment', schema],
['property bar', '#/properties/bar/$comment', schema]]);
test({foo: 1, bar: 'baz'}, false,
[['property foo', '#/properties/foo/$comment', schema],
['property bar', '#/properties/bar/$comment', schema]]);
function test(data, valid, expectedHookCalls) {
hookCalls = [];
validate(data) .should.equal(valid);
hookCalls .should.eql(expectedHookCalls);
}
});
});
});
});
});

View File

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