feat: draft6 propertyName keyword (standard, inline)

master
Evgeny Poberezkin 2016-12-23 23:45:48 +00:00
parent d41d150ba3
commit 82775ee8de
6 changed files with 126 additions and 3 deletions

View File

@ -23,6 +23,7 @@ module.exports = {
pattern: require('../dotjs/pattern'),
properties: require('../dotjs/properties'),
required: require('../dotjs/required'),
propertyNames: require('../dotjs/propertyNames'),
uniqueItems: require('../dotjs/uniqueItems'),
validate: require('../dotjs/validate')
};

View File

@ -12,7 +12,7 @@ module.exports = function rules() {
{ type: 'array',
rules: [ 'maxItems', 'minItems', 'uniqueItems', 'items' ] },
{ type: 'object',
rules: [ 'maxProperties', 'minProperties', 'required', 'dependencies',
rules: [ 'maxProperties', 'minProperties', 'required', 'dependencies', 'propertyNames',
{ 'properties': ['additionalProperties', 'patternProperties'] } ] },
{ rules: [ '$ref', 'enum', 'not', 'anyOf', 'oneOf', 'allOf' ] }
];

View File

@ -64,7 +64,7 @@
throw new ValidationError(vErrors);
{{??}}
validate.errors = vErrors;
return false
return false;
{{?}}
{{?}}
#}}
@ -111,6 +111,7 @@
type: "'should be {{? $typeIsArray }}{{= $typeSchema.join(\",\") }}{{??}}{{=$typeSchema}}{{?}}'",
uniqueItems: "'should NOT have duplicate items (items ## ' + j + ' and ' + i + ' are identical)'",
custom: "'should pass \"{{=$rule.keyword}}\" keyword validation'",
propertyNames: "'property name \\'{{=$invalidName}}\\' is invalid'",
patternGroups: "'should NOT have {{=$moreOrLess}} than {{=$limit}} properties matching pattern \"{{=it.util.escapeQuotes($pgProperty)}}\"'",
patternRequired: "'should have property matching pattern \\'{{=$missingPattern}}\\''",
switch: "'should pass \"switch\" keyword validation'",
@ -144,6 +145,7 @@
type: "validate.schema{{=$schemaPath}}",
uniqueItems: "{{#def.schemaRefOrVal}}",
custom: "validate.schema{{=$schemaPath}}",
propertyNames: "validate.schema{{=$schemaPath}}",
patternGroups: "validate.schema{{=$schemaPath}}",
patternRequired: "validate.schema{{=$schemaPath}}",
switch: "validate.schema{{=$schemaPath}}",
@ -176,6 +178,7 @@
type: "{ type: '{{? $typeIsArray }}{{= $typeSchema.join(\",\") }}{{??}}{{=$typeSchema}}{{?}}' }",
uniqueItems: "{ i: i, j: j }",
custom: "{ keyword: '{{=$rule.keyword}}' }",
propertyNames: "{ propertyName: '{{=$invalidName}}' }",
patternGroups: "{ reason: '{{=$reason}}', limit: {{=$limit}}, pattern: '{{=it.util.escapeQuotes($pgProperty)}}' }",
patternRequired: "{ missingPattern: '{{=$missingPattern}}' }",
switch: "{ caseIndex: {{=$caseIndex}} }",

51
lib/dot/propertyNames.jst Normal file
View File

@ -0,0 +1,51 @@
{{# def.definitions }}
{{# def.errors }}
{{# def.setupKeyword }}
{{# def.setupNextLevel }}
{{? {{# def.nonEmptySchema:$schema }} }}
{{
$it.schema = $schema;
$it.schemaPath = $schemaPath;
$it.errSchemaPath = $errSchemaPath;
}}
{{
var $key = 'key' + $lvl
, $i = 'i' + $lvl
, $invalidName = '\' + ' + $key + ' + \''
, $dataNxt = $it.dataLevel = it.dataLevel + 1
, $nextData = 'data' + $dataNxt
, $ownProperties = it.opts.ownProperties
, $currentBaseId = it.baseId;
}}
var {{=$errs}} = errors;
for (var {{=$key}} in {{=$data}}) {
{{# def.checkOwnProperty }}
var startErrs{{=$lvl}} = errors;
{{ var $passData = $key; }}
{{# def.setCompositeRule }}
{{# def.generateSubschemaCode }}
{{# def.optimizeValidate }}
{{# def.resetCompositeRule }}
if (!{{=$nextValid}}) {
for (var {{=$i}}=startErrs{{=$lvl}}; {{=$i}}<errors; {{=$i}}++) {
vErrors[{{=$i}}].propertyName = {{=$key}};
}
{{# def.extraError:'propertyNames' }}
{{? $breakOnError }} break; {{?}}
}
}
{{?}}
{{? $breakOnError }}
{{= $closingBraces }}
if ({{=$errs}} == errors) {
{{?}}
{{# def.cleanUp }}

View File

@ -14,7 +14,7 @@ describe('Validation errors', function () {
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, jsonPointers: true, loopRequired: 21 });
fullAjv = new Ajv({ errorDataPath: errorDataPath, allErrors: true, verbose: true, jsonPointers: true, loopRequired: 21 });
}
it('error should include dataPath', function() {
@ -482,6 +482,42 @@ describe('Validation errors', function () {
});
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');
}
}
});
});
function testSchema1(schema, schemaPathPrefix) {
_testSchema1(ajv, schema, schemaPathPrefix);
_testSchema1(ajvJP, schema, schemaPathPrefix);

View File

@ -0,0 +1,32 @@
[
{
"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
}
]
}
]