From 5e0fa811eba7a46cdac418adcffa19d6b5d7d82e Mon Sep 17 00:00:00 2001 From: Leonidaz Date: Tue, 16 Apr 2013 19:09:57 -0300 Subject: [PATCH 1/8] fix enum validation when type is array fix enum validation when attribute is of type 'array' before the fix indexOf was used to compare the whole value of the field but since the value is an array ['item1', 'item2'], it would end up looking for the whole piece ['item1', 'item2'] instead of examing each item in the value array. --- lib/revalidator.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/lib/revalidator.js b/lib/revalidator.js index 1faa25f..2278114 100644 --- a/lib/revalidator.js +++ b/lib/revalidator.js @@ -270,8 +270,18 @@ } } - if (schema['enum'] && schema['enum'].indexOf(value) === -1) { - error('enum', property, value, schema, errors); + if (schema['enum']){ + if(schema['type']=='array' && isArray(value)){ + for(var i=0; i Date: Tue, 16 Apr 2013 23:22:15 -0300 Subject: [PATCH 2/8] add path to error object for nested properties add path to error object for nested properties, so that the name of the property contains the parent name and its property name: parent{ properties{ verify: { properties:{ email: { description: 'Verify Email Address', 'type': 'string', format: 'email', required: true, maxLength: 200, }, file: { description: 'Upload Document', 'type': 'string', required: true, maxLength: 250 } } } } } with errors containing path for each nested property: { "valid": false, "errors": [ { "attribute": "format", "property": "email", "expected": "email", "actual": "dfdfd", "message": "is not a valid email", "path": "verify.email" }, { "attribute": "required", "property": "file", "expected": true, "message": "is required", "path": "verify.file" } ] } --- lib/revalidator.js | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/lib/revalidator.js b/lib/revalidator.js index 2278114..0f64dde 100644 --- a/lib/revalidator.js +++ b/lib/revalidator.js @@ -158,7 +158,7 @@ return obj; }; - function validateObject(object, schema, options, errors) { + function validateObject(object, schema, options, errors, path) { var props, allProps = Object.keys(object), visitedProps = []; @@ -168,7 +168,7 @@ for (var p in props) { if (props.hasOwnProperty(p)) { visitedProps.push(p); - validateProperty(object, object[p], p, props[p], options, errors); + validateProperty(object, object[p], p, props[p], options, errors, path); } } } @@ -185,7 +185,7 @@ if (object.hasOwnProperty(k)) { visitedProps.push(k); if (re.exec(k) !== null) { - validateProperty(object, object[k], p, props[p], options, errors); + validateProperty(object, object[k], p, props[p], options, errors, path); } } } @@ -204,20 +204,20 @@ // Prevent additional properties; each unvisited property is therefore an error if (schema.additionalProperties === false && unvisitedProps.length > 0) { for (i = 0, l = unvisitedProps.length; i < l; i++) { - error("additionalProperties", unvisitedProps[i], object[unvisitedProps[i]], false, errors); + error("additionalProperties", unvisitedProps[i], object[unvisitedProps[i]], false, errors, path); } } // additionalProperties is a schema and validate unvisited properties against that schema else if (typeof schema.additionalProperties == "object" && unvisitedProps.length > 0) { for (i = 0, l = unvisitedProps.length; i < l; i++) { - validateProperty(object, object[unvisitedProps[i]], unvisitedProps[i], schema.unvisitedProperties, options, errors); + validateProperty(object, object[unvisitedProps[i]], unvisitedProps[i], schema.unvisitedProperties, options, errors, path); } } } }; - function validateProperty(object, value, property, schema, options, errors) { + function validateProperty(object, value, property, schema, options, errors, path) { var format, valid, spec, @@ -225,13 +225,13 @@ function constrain(name, value, assert) { if (schema[name] !== undefined && !assert(value, schema[name])) { - error(name, property, value, schema, errors); + error(name, property, value, schema, errors, path); } } if (value === undefined) { if (schema.required && schema.type !== 'any') { - return error('required', property, undefined, schema, errors); + return error('required', property, undefined, schema, errors, path); } else { return; } @@ -260,12 +260,12 @@ if (!spec) { spec = validate.formats[format] } if (!spec) { if (options.validateFormatsStrict) { - return error('format', property, value, schema, errors); + return error('format', property, value, schema, errors, path); } } else { if (!spec.test(value)) { - return error('format', property, value, schema, errors); + return error('format', property, value, schema, errors, path); } } } @@ -274,26 +274,26 @@ if(schema['type']=='array' && isArray(value)){ for(var i=0; i Date: Thu, 18 Apr 2013 14:41:02 -0300 Subject: [PATCH 3/8] fix cast for the case when 'type' is an array fix cast for the case when 'type' is an array change string comparison to indexOf search that works both for strings and arrays --- lib/revalidator.js | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/lib/revalidator.js b/lib/revalidator.js index 0f64dde..f12d842 100644 --- a/lib/revalidator.js +++ b/lib/revalidator.js @@ -238,17 +238,19 @@ } if (options.cast) { - if (('integer' === schema.type || 'number' === schema.type) && value == +value) { - value = +value; - } - - if ('boolean' === schema.type) { - if ('true' === value || '1' === value || 1 === value) { - value = true; + if(schema.type !== undefined && schema.type !== null){ + if((schema.type.indexOf('integer') > -1 || schema.type.indexOf('number') > -1) && value == +value){ + value = +value; } - if ('false' === value || '0' === value || 0 === value) { - value = false; + if (schema.type.indexOf('boolean') > -1){ + if ('true' === value || '1' === value || 1 === value) { + value = true; + } + + if ('false' === value || '0' === value || 0 === value) { + value = false; + } } } } From 8217163b7546dda6d9ca623cd5c4d733fd395ab4 Mon Sep 17 00:00:00 2001 From: Leonidaz Date: Sat, 20 Apr 2013 23:13:24 -0300 Subject: [PATCH 4/8] add support for path in errors for arrays of objects --- lib/revalidator.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/revalidator.js b/lib/revalidator.js index f12d842..65ff589 100644 --- a/lib/revalidator.js +++ b/lib/revalidator.js @@ -335,7 +335,7 @@ case 'array': constrain('items', value, function (a, e) { for (var i = 0, l = a.length; i < l; i++) { - validateProperty(object, a[i], property, e, options, errors, path); + validateProperty(object, a[i], property, e, options, errors, (!path ? property : path) + "[" + i + "]"); } return true; }); @@ -356,7 +356,7 @@ case 'object': // Recursive validation if (schema.properties || schema.patternProperties || schema.additionalProperties) { - validateObject(value, schema, options, errors, property + "."); + validateObject(value, schema, options, errors, (!path ? property : path) + "."); } break; } From b15f05ca35760e8973cf8b162c07b36880677ec3 Mon Sep 17 00:00:00 2001 From: Leonidaz Date: Wed, 16 Oct 2013 22:12:58 -0400 Subject: [PATCH 5/8] added default error message for 'additionalProperties' --- lib/revalidator.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/revalidator.js b/lib/revalidator.js index 65ff589..e1f2da1 100644 --- a/lib/revalidator.js +++ b/lib/revalidator.js @@ -97,7 +97,8 @@ uniqueItems: "must hold a unique set of values", format: "is not a valid %{expected}", conform: "must conform to given constraint", - type: "must be of %{expected} type" + type: "must be of %{expected} type", + additionalProperties: "extra properties are not allowed" }; validate.messages['enum'] = "must be present in given enumerator"; From 6f9d69ee65f53385c4095c829a89901014e52e87 Mon Sep 17 00:00:00 2001 From: Leonidaz Date: Wed, 16 Oct 2013 23:15:51 -0400 Subject: [PATCH 6/8] add object (data to check) to conform --- lib/revalidator.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/revalidator.js b/lib/revalidator.js index e1f2da1..c082d51 100644 --- a/lib/revalidator.js +++ b/lib/revalidator.js @@ -308,7 +308,7 @@ checkType(value, schema.type, function(err, type) { if (err) return error('type', property, typeof value, schema, errors, path); - constrain('conform', value, function (a, e) { return e(a) }); + constrain('conform', value, function (a, e) { return e(a, object) }); switch (type || (isArray(value) ? 'array' : typeof value)) { case 'string': From 9c73e6d1e1df3ca8658c2f8eaa803a8cd3bd0e0e Mon Sep 17 00:00:00 2001 From: Leonidaz Date: Fri, 18 Oct 2013 18:49:22 -0400 Subject: [PATCH 7/8] add recursive check for children when parent property is missing of type 'object' and of type 'array' with 'items' if a property has children (child schemas) and this property is missing then the children would not get checked. If the children, for example, are required those errors would never show up. This makes sure that all errors on all child properties are returned. In most case the parent is just a holder for the child properties and if it's missing it's not that interesting to know that it's missing but if its children are missing, which may correspond for form fields, it would be very useful to know since the focus was initially on the child fields. --- lib/revalidator.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/revalidator.js b/lib/revalidator.js index c082d51..d2c6505 100644 --- a/lib/revalidator.js +++ b/lib/revalidator.js @@ -232,7 +232,15 @@ if (value === undefined) { if (schema.required && schema.type !== 'any') { - return error('required', property, undefined, schema, errors, path); + error('required', property, undefined, schema, errors, path); + + if (schema.properties || schema.patternProperties || schema.additionalProperties) { + validateObject({}, schema, options, errors, (!path ? property : path) + "."); + } + else if(schema.items && schema.items.properties){ + validateObject({}, schema.items, options, errors, (!path ? property : path) + "[0]."); + } + return; } else { return; } From 4207b6ab8a001316cf8be6bc72efc056c21e686d Mon Sep 17 00:00:00 2001 From: Leonidaz Date: Fri, 18 Oct 2013 18:56:34 -0400 Subject: [PATCH 8/8] minor adjustment to previous commit to make sure schema type == 'array' --- lib/revalidator.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/revalidator.js b/lib/revalidator.js index d2c6505..dd19999 100644 --- a/lib/revalidator.js +++ b/lib/revalidator.js @@ -238,7 +238,11 @@ validateObject({}, schema, options, errors, (!path ? property : path) + "."); } else if(schema.items && schema.items.properties){ - validateObject({}, schema.items, options, errors, (!path ? property : path) + "[0]."); + checkType([], schema.type, function(err, type){ + if(!err && type=='array'){ + validateObject({}, schema.items, options, errors, (!path ? property : path) + "[0]."); + } + }); } return; } else {