diff --git a/lib/revalidator.js b/lib/revalidator.js index 58476b0..d3eed5f 100644 --- a/lib/revalidator.js +++ b/lib/revalidator.js @@ -249,7 +249,12 @@ } if (value === undefined) { - if (schema.required && schema.type !== 'any') { + var isRequired = schema.required; + if (typeof isRequired === 'function') { + isRequired = isRequired.bind(object)(); + } + + if (isRequired && schema.type !== 'any') { return error('required', property, undefined, schema, errors); } else { return; @@ -275,27 +280,6 @@ } } - if (schema.format && options.validateFormats) { - format = schema.format; - - if (options.validateFormatExtensions) { spec = validate.formatExtensions[format] } - if (!spec) { spec = validate.formats[format] } - if (!spec) { - if (options.validateFormatsStrict) { - return error('format', property, value, schema, errors); - } - } - else { - if (!spec.test(value)) { - return error('format', property, value, schema, errors); - } - } - } - - if (schema['enum'] && schema['enum'].indexOf(value) === -1) { - error('enum', property, value, schema, errors); - } - // Dependencies (see 5.8) if (typeof schema.dependencies === 'string' && object[schema.dependencies] === undefined) { @@ -317,8 +301,6 @@ checkType(value, schema.type, function(err, type) { if (err) return error('type', property, typeof value, schema, errors); - constrain('conform', value, function (a, e) { return e(a, object) }); - switch (type || (isArray(value) ? 'array' : typeof value)) { case 'string': constrain('allowEmpty', value, function (a, e) { return e ? e : a !== '' }); @@ -348,7 +330,12 @@ var nestedErrors; for (var i = 0, l = a.length; i < l; i++) { nestedErrors = []; - validateProperty(object, a[i], property, e, options, nestedErrors); + var newE = e; + if (typeof e === 'function') { + newE = e(a[i]); + } + + validateProperty(object, a[i], property, newE, options, nestedErrors); nestedErrors.forEach(function (err) { err.property = (property ? property + '.' : '') + @@ -386,10 +373,36 @@ }); nestedErrors.unshift(0, 0); Array.prototype.splice.apply(errors, nestedErrors); + + constrain('minItems', value, function (a, e) { return Object.keys(a).length >= e }); + constrain('maxItems', value, function (a, e) { return Object.keys(a).length <= e }); } break; } + + constrain('conform', value, function (a, e) { return e(a, object) }); }); + + if (schema.format && options.validateFormats) { + format = schema.format; + + if (options.validateFormatExtensions) { spec = validate.formatExtensions[format] } + if (!spec) { spec = validate.formats[format] } + if (!spec) { + if (options.validateFormatsStrict) { + return error('format', property, value, schema, errors); + } + } + else { + if (!spec.test(value)) { + return error('format', property, value, schema, errors); + } + } + } + + if (schema['enum'] && schema['enum'].indexOf(value) === -1) { + error('enum', property, value, schema, errors); + } } function checkType(val, type, callback) { diff --git a/test/validator-test.js b/test/validator-test.js index 195b690..bd1ca3a 100644 --- a/test/validator-test.js +++ b/test/validator-test.js @@ -530,6 +530,7 @@ vows.describe('revalidator', { }, publisher: { type: 'object', + minItems: 2, properties: { name: { type: 'string' }, agents: { @@ -633,6 +634,14 @@ vows.describe('revalidator', { }, "return an object with `valid` set to false": assertInvalid }, + "and if it has a incorrect property (< minItems)": { + topic: function (object, schema) { + object = clone(object); + delete object.publisher.name; + return revalidator.validate(object, schema); + }, + "return an object with `valid` set to false": assertInvalid + }, "and if it has a incorrect unique array property": { topic: function (object, schema) { object = clone(object);