Skip to content
This repository was archived by the owner on Nov 2, 2023. It is now read-only.

Commit 996d7fb

Browse files
committed
Merge remote-tracking branch 'nickl/master'
Shortlog as follows: Camilo Aguilar (1): Fixes error message Dave Longley (6): Add support for uniqueItems. Fix inverted comparison. Add missing schema and value to type error. Add support for uniqueItems. Fix inverted comparison. Add missing schema and value to type error. David I. Lehn (6): Fix property path handling. Add value and schema to errors. Add more verbose handling. Fix property path handling. Add value and schema to errors. Add more verbose handling. Enrico Marino (1): Replaced "maxDecimal" attribute with "divisibleBy" attribute Francis Galiegue (5): draft-04/schema: modify the "type" property definition draft-04/schema: cosmetic: fix whitespaces draft-04/schema: catch up with "divisibleBy" rename Re-introduce "format" keyword, with some differences Separate core schema keywords into different sections Gary Court (1): * Restored "integer" type. * Renamed "divisibleBy" to "mod". Kris Zyp (2): Better wording of items and their array indices bump version Stacia Hartleben (1): Replaced obsolete optional with required fixed package.json nickl- (5): Merge branch 'master' of https://github.com/digitalbazaar/json-schema Merge branch 'master' of https://github.com/fge/json-schema Merge branch 'master' of https://github.com/c4milo/json-schema Merge branch 'master' of https://github.com/onirame/json-schema Merge branch 'master' of https://github.com/stacia/json-schema
2 parents 0077b4d + d38eb08 commit 996d7fb

File tree

1 file changed

+86
-24
lines changed

1 file changed

+86
-24
lines changed

lib/validate.js

Lines changed: 86 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -62,18 +62,29 @@ var validate = exports._validate = function(/*Any*/instance,/*Object*/schema,/*O
6262
}
6363
var errors = [];
6464
// validate a value against a property definition
65-
function checkProp(value, schema, path,i){
65+
function checkProp(value, schema, path, i){
6666

6767
var l;
68-
path += path ? typeof i == 'number' ? '[' + i + ']' : typeof i == 'undefined' ? '' : '.' + i : i;
69-
function addError(message){
70-
errors.push({property:path,message:message});
68+
if(typeof i !== 'undefined') {
69+
if(typeof i === 'number') {
70+
path += '[' + i + ']';
71+
} else {
72+
var escaped = i.replace(/\./g, '\\.');
73+
path += path ? ('.' + escaped) : escaped;
74+
}
75+
}
76+
function addError(message, value){
77+
var error = {property:path,message:message,schema:schema};
78+
if(typeof value !== 'undefined') {
79+
error.value = value;
80+
}
81+
errors.push(error);
7182
}
7283

7384
if((typeof schema != 'object' || schema instanceof Array) && (path || typeof schema != 'function') && !(schema && getType(schema))){
7485
if(typeof schema == 'function'){
7586
if(!(value instanceof schema)){
76-
addError("is not an instance of the class/constructor " + schema.name);
87+
addError("is not an instance of the class/constructor " + schema.name, value);
7788
}
7889
}else if(schema){
7990
addError("Invalid schema/property definition " + schema);
@@ -94,7 +105,7 @@ var validate = exports._validate = function(/*Any*/instance,/*Object*/schema,/*O
94105
!(value instanceof Array && type == 'array') &&
95106
!(value instanceof Date && type == 'date') &&
96107
!(type == 'integer' && value%1===0)){
97-
return [{property:path,message:(typeof value) + " value found, but a " + type + " is required"}];
108+
return [{property:path,message:(typeof value) + " value found, but a " + type + " is required",schema:schema,value:value}];
98109
}
99110
if(type instanceof Array){
100111
var unionErrors=[];
@@ -124,14 +135,14 @@ var validate = exports._validate = function(/*Any*/instance,/*Object*/schema,/*O
124135
}else{
125136
errors = errors.concat(checkType(getType(schema),value));
126137
if(schema.disallow && !checkType(schema.disallow,value).length){
127-
addError(" disallowed value was matched");
138+
addError(" disallowed value was matched", value);
128139
}
129140
if(value !== null){
130141
if(value instanceof Array){
131142
if(schema.items){
132143
var itemsIsArray = schema.items instanceof Array;
133144
var propDef = schema.items;
134-
for (i = 0, l = value.length; i < l; i += 1) {
145+
for (var i = 0, l = value.length; i < l; i += 1) {
135146
if (itemsIsArray)
136147
propDef = schema.items[i];
137148
if (options.coerce)
@@ -140,30 +151,40 @@ var validate = exports._validate = function(/*Any*/instance,/*Object*/schema,/*O
140151
}
141152
}
142153
if(schema.minItems && value.length < schema.minItems){
143-
addError("There must be a minimum of " + schema.minItems + " in the array");
154+
addError("There must be a minimum of " + schema.minItems + " in the array", value);
144155
}
145156
if(schema.maxItems && value.length > schema.maxItems){
146-
addError("There must be a maximum of " + schema.maxItems + " in the array");
157+
addError("There must be a maximum of " + schema.maxItems + " in the array", value);
158+
}
159+
if(schema.uniqueItems) {
160+
for(var i = 0, l = value.length; i < l; i += 1) {
161+
for(var j = i + 1; j < l; j += 1) {
162+
if(compareItems(value[i], value[j])) {
163+
addError("The items in the array must be unique.", value);
164+
break;
165+
}
166+
}
167+
}
147168
}
148169
}else if(schema.properties || schema.additionalProperties){
149170
errors.concat(checkObj(value, schema.properties, path, schema.additionalProperties));
150171
}
151172
if(schema.pattern && typeof value == 'string' && !value.match(schema.pattern)){
152-
addError("does not match the regex pattern " + schema.pattern);
173+
addError("does not match the regex pattern " + schema.pattern, value);
153174
}
154175
if(schema.maxLength && typeof value == 'string' && value.length > schema.maxLength){
155-
addError("may only be " + schema.maxLength + " characters long");
176+
addError("may only be " + schema.maxLength + " characters long", value);
156177
}
157178
if(schema.minLength && typeof value == 'string' && value.length < schema.minLength){
158-
addError("must be at least " + schema.minLength + " characters long");
179+
addError("must be at least " + schema.minLength + " characters long", value);
159180
}
160181
if(typeof schema.minimum !== undefined && typeof value == typeof schema.minimum &&
161182
schema.minimum > value){
162-
addError("must have a minimum value of " + schema.minimum);
183+
addError("must have a minimum value of " + schema.minimum, value);
163184
}
164185
if(typeof schema.maximum !== undefined && typeof value == typeof schema.maximum &&
165186
schema.maximum < value){
166-
addError("must have a maximum value of " + schema.maximum);
187+
addError("must have a maximum value of " + schema.maximum, value);
167188
}
168189
if(schema['enum']){
169190
var enumer = schema['enum'];
@@ -176,12 +197,12 @@ var validate = exports._validate = function(/*Any*/instance,/*Object*/schema,/*O
176197
}
177198
}
178199
if(!found){
179-
addError("does not have a value in the enumeration " + enumer.join(", "));
200+
addError("does not have a value in the enumeration " + enumer.join(", "), value);
180201
}
181202
}
182203
if(typeof schema.maxDecimal == 'number' &&
183204
(value.toString().match(new RegExp("\\.[0-9]{" + (schema.maxDecimal + 1) + ",}")))){
184-
addError("may only have " + schema.maxDecimal + " digits of decimal places");
205+
addError("may only have " + schema.maxDecimal + " digits of decimal places", value);
185206
}
186207
}
187208
}
@@ -190,12 +211,20 @@ var validate = exports._validate = function(/*Any*/instance,/*Object*/schema,/*O
190211
// validate an object against a schema
191212
function checkObj(instance,objTypeDef,path,additionalProp){
192213

214+
function addError(message, value){
215+
var error = {property:path,message:message,schema:objTypeDef};
216+
if(typeof value !== 'undefined') {
217+
error.value = value;
218+
}
219+
errors.push(error);
220+
}
221+
193222
if(typeof objTypeDef =='object'){
194223
if(typeof instance != 'object' || instance instanceof Array){
195-
errors.push({property:path,message:"an object is required"});
224+
addError("an object is required", instance);
196225
}
197-
198-
for(var i in objTypeDef){
226+
227+
for(var i in objTypeDef){
199228
if(objTypeDef.hasOwnProperty(i)){
200229
var value = instance[i];
201230
// skip _not_ specified properties
@@ -212,19 +241,19 @@ var validate = exports._validate = function(/*Any*/instance,/*Object*/schema,/*O
212241
}
213242
}
214243
}
215-
for(i in instance){
244+
for(var i in instance){
216245
if(instance.hasOwnProperty(i) && !(i.charAt(0) == '_' && i.charAt(1) == '_') && objTypeDef && !objTypeDef[i] && additionalProp===false){
217246
if (options.filter) {
218247
delete instance[i];
219248
continue;
220249
} else {
221-
errors.push({property:path,message:(typeof value) + "The property " + i +
222-
" is not defined in the schema and the schema does not allow additional properties"});
250+
addError("The property '" + i +
251+
"' is not defined in the schema and the schema does not allow additional properties", instance);
223252
}
224253
}
225254
var requires = objTypeDef && objTypeDef[i] && objTypeDef[i].requires;
226255
if(requires && !(requires in instance)){
227-
errors.push({property:path,message:"the presence of the property " + i + " requires that " + requires + " also be present"});
256+
addError("the presence of the property " + i + " requires that " + requires + " also be present", instance);
228257
}
229258
value = instance[i];
230259
if(additionalProp && (!(objTypeDef && typeof objTypeDef == 'object') || !(i in objTypeDef))){
@@ -239,6 +268,39 @@ var validate = exports._validate = function(/*Any*/instance,/*Object*/schema,/*O
239268
}
240269
return errors;
241270
}
271+
// compare a value against another for equality (for uniqueItems)
272+
function compareItems(item1, item2) {
273+
if(typeof item1 !== typeof item2) {
274+
return false;
275+
}
276+
if(Array.isArray(item1)) {
277+
if(item1.length !== item2.length) {
278+
return false;
279+
}
280+
for(var i = 0, l = item1.length; i < l; i += 1) {
281+
if(!compareItems(item1[i], item2[i])) {
282+
return false;
283+
}
284+
}
285+
return true;
286+
}
287+
if(item1 instanceof Object) {
288+
var item1Keys = Object.keys(item1);
289+
var item2Keys = Object.keys(item2);
290+
if(item1Keys.length !== item2Keys.length) {
291+
return false;
292+
}
293+
for(var i = 0, l = item1Keys.length; i < l; i += 1) {
294+
var key = item1Keys[i];
295+
if(!item2.hasOwnProperty(key) ||
296+
!compareItems(item1[key], item2[key])) {
297+
return false;
298+
}
299+
}
300+
return true;
301+
}
302+
return item1 === item2;
303+
}
242304
if(schema){
243305
checkProp(instance,schema,'',_changing || '');
244306
}

0 commit comments

Comments
 (0)