refactor: remove patternGroups keyword, #614

master
Evgeny Poberezkin 2017-11-26 10:11:55 +00:00
parent 18b4c3f3a4
commit e15f543dbd
10 changed files with 2 additions and 513 deletions

View File

@ -31,7 +31,6 @@ The keywords and their values define what rules the data should satisfy to be va
- [additionalProperties](#additionalproperties)
- [dependencies](#dependencies)
- [propertyNames](#propertynames) (added in draft-06)
- [patternGroups](#patterngroups-deprecated) (deprecated)
- [patternRequired](#patternrequired-proposed) (proposed)
- [Keywords for all types](#keywords-for-all-types)
- [enum](#enum)
@ -617,41 +616,6 @@ _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.

10
lib/ajv.d.ts vendored
View File

@ -225,8 +225,8 @@ declare namespace ajv {
DependenciesParams | FormatParams | ComparisonParams |
MultipleOfParams | PatternParams | RequiredParams |
TypeParams | UniqueItemsParams | CustomParams |
PatternGroupsParams | PatternRequiredParams |
PropertyNamesParams | SwitchParams | NoParams | EnumParams;
PatternRequiredParams | PropertyNamesParams |
SwitchParams | NoParams | EnumParams;
interface RefParams {
ref: string;
@ -282,12 +282,6 @@ declare namespace ajv {
keyword: string;
}
interface PatternGroupsParams {
reason: string;
limit: number;
pattern: string;
}
interface PatternRequiredParams {
missingPattern: string;
}

View File

@ -8,7 +8,6 @@ var compileSchema = require('./compile')
, formats = require('./compile/formats')
, rules = require('./compile/rules')
, $dataMetaSchema = require('./data')
, patternGroups = require('./patternGroups')
, util = require('./compile/util');
module.exports = Ajv;
@ -74,7 +73,6 @@ function Ajv(opts) {
addDraft6MetaSchema(this);
if (typeof opts.meta == 'object') this.addMetaSchema(opts.meta);
addInitialSchemas(this);
if (opts.patternGroups) patternGroups(this);
}

View File

@ -111,7 +111,6 @@
not: "'should NOT be valid'",
oneOf: "'should match exactly one schema in oneOf'",
pattern: "'should match pattern \"{{#def.concatSchemaEQ}}\"'",
patternGroups: "'should NOT have {{=$moreOrLess}} than {{=$limit}} properties matching pattern \"{{=it.util.escapeQuotes($pgProperty)}}\"'",
propertyNames: "'property name \\'{{=$invalidName}}\\' is invalid'",
required: "'{{? it.opts._errorDataPathProperty }}is a required property{{??}}should have required property \\'{{=$missingProperty}}\\'{{?}}'",
type: "'should be {{? $typeIsArray }}{{= $typeSchema.join(\",\") }}{{??}}{{=$typeSchema}}{{?}}'",
@ -148,7 +147,6 @@
not: "validate.schema{{=$schemaPath}}",
oneOf: "validate.schema{{=$schemaPath}}",
pattern: "{{#def.schemaRefOrQS}}",
patternGroups: "validate.schema{{=$schemaPath}}",
propertyNames: "validate.schema{{=$schemaPath}}",
required: "validate.schema{{=$schemaPath}}",
type: "validate.schema{{=$schemaPath}}",
@ -184,7 +182,6 @@
not: "{}",
oneOf: "{ passingSchemas: {{=$passingSchemas}} }",
pattern: "{ pattern: {{#def.schemaValueQS}} }",
patternGroups: "{ reason: '{{=$reason}}', limit: {{=$limit}}, pattern: '{{=it.util.escapeQuotes($pgProperty)}}' }",
propertyNames: "{ propertyName: '{{=$invalidName}}' }",
required: "{ missingProperty: '{{=$missingProperty}}' }",
type: "{ type: '{{? $typeIsArray }}{{= $typeSchema.join(\",\") }}{{??}}{{=$typeSchema}}{{?}}' }",

View File

@ -44,11 +44,6 @@
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);
}
}}
@ -76,11 +71,6 @@ var {{=$nextValid}} = true;
|| {{= it.usePattern($pProperty) }}.test({{=$key}})
{{~}}
{{?}}
{{? it.opts.patternGroups && $pgPropertyKeys.length }}
{{~ $pgPropertyKeys:$pgProperty:$i }}
|| {{= it.usePattern($pgProperty) }}.test({{=$key}})
{{~}}
{{?}}
);
if (isAdditional{{=$lvl}}) {
@ -246,79 +236,6 @@ var {{=$nextValid}} = true;
{{?}}
{{? 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) {

View File

@ -162,9 +162,6 @@
{{ $closingBraces2 += '}'; }}
{{?}}
{{??}}
{{? it.opts.v5 && it.schema.patternGroups }}
{{ it.logger.warn('keyword "patternGroups" is deprecated and disabled. Use option patternGroups: true to enable.'); }}
{{?}}
{{~ it.RULES:$rulesGroup }}
{{? $shouldUseGroup($rulesGroup) }}
{{? $rulesGroup.type }}

View File

@ -1,36 +0,0 @@
'use strict';
var META_SCHEMA_ID = 'http://json-schema.org/draft-07/schema';
module.exports = function (ajv) {
var defaultMeta = ajv._opts.defaultMeta;
var metaSchemaRef = typeof defaultMeta == 'string'
? { $ref: defaultMeta }
: ajv.getSchema(META_SCHEMA_ID)
? { $ref: META_SCHEMA_ID }
: {};
ajv.addKeyword('patternGroups', {
// implemented in properties.jst
metaSchema: {
type: 'object',
additionalProperties: {
type: 'object',
required: [ 'schema' ],
properties: {
maximum: {
type: 'integer',
minimum: 0
},
minimum: {
type: 'integer',
minimum: 0
},
schema: metaSchemaRef
},
additionalProperties: false
}
}
});
ajv.RULES.all.properties.implements.push('patternGroups');
};

View File

@ -8,7 +8,6 @@ var jsonSchemaTest = require('json-schema-test')
var instances = getAjvInstances(options, {
$data: true,
patternGroups: true,
unknownFormats: ['allowedUnknown']
});

View File

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

View File

@ -222,21 +222,6 @@ describe('Ajv Options', function () {
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: {
@ -1148,61 +1133,6 @@ describe('Ajv Options', function () {
});
describe('patternGroups without draft-07 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() {