Merge pull request #198 from mbroadst/own-properties

feat(own-properties): support optionally checking own properties
master
Evgeny Poberezkin 2016-05-27 20:36:07 +01:00
commit a1b6ebc6eb
5 changed files with 88 additions and 4 deletions

View File

@ -842,6 +842,7 @@ Defaults:
format: 'fast',
formats: {},
schemas: {},
ownProperties: false,
// referenced schema options:
missingRefs: true,
loadSchema: undefined, // function(uri, cb) { /* ... */ cb(err, schema); },
@ -878,7 +879,7 @@ Defaults:
- _format_: formats validation mode ('fast' by default). Pass 'full' for more correct and slow validation or `false` not to validate formats at all. E.g., 25:00:00 and 2015/14/33 will be invalid time and date in 'full' mode but it will be valid in 'fast' mode.
- _formats_: an object with custom formats. Keys and values will be passed to `addFormat` method.
- _schemas_: an array or object of schemas that will be added to the instance. If the order is important, pass array. In this case schemas must have IDs in them. Otherwise the object can be passed - `addSchema(value, key)` will be called for each schema in this object.
- _ownProperties_: indicates that when iterating properties of data to be validated, only properties found directly upon the object are used (rather than all enumerable properties)
##### Referenced schema options

1
lib/ajv.d.ts vendored
View File

@ -104,6 +104,7 @@ declare namespace ajv {
format?: string;
formats?: Object;
schemas?: Array<Object> | Object;
ownProperties?: boolean;
missingRefs?: boolean | string;
loadSchema?: (uri: string, cb: (err: Error, schema: Object) => any) => any;
removeAdditional?: boolean | string;

View File

@ -34,6 +34,7 @@
&& Object.keys($aProperties).length
, $removeAdditional = it.opts.removeAdditional
, $checkAdditional = $noAdditional || $additionalIsSchema || $removeAdditional
, $ownProperties = it.opts.ownProperties
, $currentBaseId = it.baseId;
var $required = it.schema.required;
@ -52,6 +53,10 @@ var valid{{=$it.level}} = true;
{{? $checkAdditional }}
for (var key{{=$lvl}} in {{=$data}}) {
{{? $ownProperties }}
if (!{{=$data}}.hasOwnProperty(key{{=$lvl}})) continue;
{{?}}
{{? $someProperties }}
var isAdditional{{=$lvl}} = !(false
{{? $schemaKeys.length }}
@ -212,6 +217,10 @@ var valid{{=$it.level}} = true;
}}
for (var key{{=$lvl}} in {{=$data}}) {
{{? $ownProperties }}
if (!{{=$data}}.hasOwnProperty(key{{=$lvl}})) continue;
{{?}}
if ({{= it.usePattern($pProperty) }}.test(key{{=$lvl}})) {
{{
$it.errorPath = it.util.getPathExpr(it.errorPath, 'key' + $lvl, it.opts.jsonPointers);
@ -251,6 +260,10 @@ var valid{{=$it.level}} = true;
var pgPropCount{{=$lvl}} = 0;
for (var key{{=$lvl}} in {{=$data}}) {
{{? $ownProperties }}
if (!{{=$data}}.hasOwnProperty(key{{=$lvl}})) continue;
{{?}}
if ({{= it.usePattern($pgProperty) }}.test(key{{=$lvl}})) {
pgPropCount{{=$lvl}}++;

View File

@ -5,13 +5,17 @@
{{
var $key = 'key' + $lvl
, $matched = 'patternMatched' + $lvl
, $closingBraces = '';
, $closingBraces = ''
, $ownProperties = it.opts.ownProperties;
}}
var {{=$valid}} = true;
{{~ $schema:$pProperty }}
var {{=$matched}} = false;
for (var {{=$key}} in {{=$data}}) {
{{? $ownProperties }}
if (!{{=$data}}.hasOwnProperty({{=$key}})) continue;
{{?}}
{{=$matched}} = {{= it.usePattern($pProperty) }}.test({{=$key}});
if ({{=$matched}}) break;
}

View File

@ -85,6 +85,71 @@ describe('Ajv Options', function () {
});
describe('ownProperties', function() {
it('should only validate against own properties of data if specified', function() {
var ajv = Ajv({ ownProperties: true });
var validate = ajv.compile({
properties: { c: { type: 'number' } },
additionalProperties: false
});
var triangle = { a: 1, b: 2 };
function ColoredTriangle() { this.c = 3; }
ColoredTriangle.prototype = triangle;
var object = new ColoredTriangle();
validate(object).should.equal(true);
should.equal(validate.errors, null);
});
it('should only validate against own properties when using patternProperties', function() {
var ajv = Ajv({ allErrors: true, ownProperties: true });
var validate = ajv.compile({
patternProperties: { 'f.*o': { type: 'integer' } },
});
var baz = { foooo: false, fooooooo: 42.31 };
function FooThing() { this.foo = 'not a number'; }
FooThing.prototype = baz;
var object = new FooThing();
validate(object).should.equal(false);
validate.errors.should.have.length(1);
});
it('should only validate against own properties when using patternGroups', function() {
var ajv = Ajv({ v5: true, allErrors: true, ownProperties: true });
var validate = ajv.compile({
patternGroups: {
'f.*o': { schema: { type: 'integer' } }
}
});
var baz = { foooo: false, fooooooo: 42.31 };
function FooThing() { this.foo = 'not a number'; }
FooThing.prototype = baz;
var object = new FooThing();
validate(object).should.equal(false);
validate.errors.should.have.length(1);
});
it('should only validate against own properties when using patternRequired', function() {
var ajv = Ajv({ v5: true, allErrors: true, ownProperties: true });
var validate = ajv.compile({
patternRequired: [ 'f.*o' ]
});
var baz = { foooo: false, fooooooo: 42.31 };
function FooThing() { this.bar = 123; }
FooThing.prototype = baz;
var object = new FooThing();
validate(object).should.equal(false);
validate.errors.should.have.length(1);
});
});
describe('meta and validateSchema', function() {
it('should add draft-4 meta schema by default', function() {
testOptionMeta(Ajv());
@ -296,13 +361,13 @@ describe('Ajv Options', function () {
var validate = ajv.compile({ minLength: 2 });
validateWithUnicode('😀') .should.equal(false);
validate('😀') .should.equal(true);
validate('😀') .should.equal(true);
var validateWithUnicode = ajvUnicode.compile({ maxLength: 1 });
var validate = ajv.compile({ maxLength: 1 });
validateWithUnicode('😀') .should.equal(true);
validate('😀') .should.equal(false);
validate('😀') .should.equal(false);
}
});
});