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

Commit 9f93ce2

Browse files
committed
Merge branch 'master' of git://github.com/dvv/json-schema
Conflicts: lib/validate.js
2 parents fdc23eb + 6acf3a9 commit 9f93ce2

File tree

1 file changed

+67
-56
lines changed

1 file changed

+67
-56
lines changed

lib/validate.js

Lines changed: 67 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1-
/**
2-
* JSONSchema Validator - Validates JavaScript objects using JSON Schemas
1+
/**
2+
* JSONSchema Validator - Validates JavaScript objects using JSON Schemas
33
* (http://www.json.com/json-schema-proposal/)
44
*
55
* Copyright (c) 2007 Kris Zyp SitePen (www.sitepen.com)
66
* Licensed under the MIT (MIT-LICENSE.txt) license.
77
To use the validator call the validate function with an instance object and an optional schema object.
8-
If a schema is provided, it will be used to validate. If the instance object refers to a schema (self-validating),
9-
that schema will be used to validate and the schema parameter is not necessary (if both exist,
10-
both validations will occur).
11-
The validate method will return an array of validation errors. If there are no errors, then an
12-
empty list will be returned. A validation error will have two properties:
8+
If a schema is provided, it will be used to validate. If the instance object refers to a schema (self-validating),
9+
that schema will be used to validate and the schema parameter is not necessary (if both exist,
10+
both validations will occur).
11+
The validate method will return an array of validation errors. If there are no errors, then an
12+
empty list will be returned. A validation error will have two properties:
1313
"property" which indicates which property had the error
1414
"message" which indicates what the error was
1515
*/
@@ -24,43 +24,47 @@ exports.Integer = {type:"integer"};
2424
Object.type = "object";
2525
Array.type = "array";
2626
Date.type = "date";
27-
exports.validate = validate;
27+
exports.validate = validate;
2828
function validate(/*Any*/instance,/*Object*/schema) {
2929
// Summary:
3030
// To use the validator call JSONSchema.validate with an instance object and an optional schema object.
31-
// If a schema is provided, it will be used to validate. If the instance object refers to a schema (self-validating),
32-
// that schema will be used to validate and the schema parameter is not necessary (if both exist,
33-
// both validations will occur).
31+
// If a schema is provided, it will be used to validate. If the instance object refers to a schema (self-validating),
32+
// that schema will be used to validate and the schema parameter is not necessary (if both exist,
33+
// both validations will occur).
3434
// The validate method will return an object with two properties:
3535
// valid: A boolean indicating if the instance is valid by the schema
36-
// errors: An array of validation errors. If there are no errors, then an
37-
// empty list will be returned. A validation error will have two properties:
36+
// errors: An array of validation errors. If there are no errors, then an
37+
// empty list will be returned. A validation error will have two properties:
3838
// property: which indicates which property had the error
3939
// message: which indicates what the error was
4040
//
41-
return validate(instance,schema,false);
41+
return validate(instance, schema, {changing: false});//, coerce: false, existingOnly: false});
4242
};
43-
exports.checkPropertyChange = function(/*Any*/value,/*Object*/schema, /*String*/ property) {
43+
exports.checkPropertyChange = function(/*Any*/value,/*Object*/schema, /*String*/property) {
4444
// Summary:
4545
// The checkPropertyChange method will check to see if an value can legally be in property with the given schema
4646
// This is slightly different than the validate method in that it will fail if the schema is readonly and it will
47-
// not check for self-validation, it is assumed that the passed in value is already internally valid.
48-
// The checkPropertyChange method will return the same object type as validate, see JSONSchema.validate for
47+
// not check for self-validation, it is assumed that the passed in value is already internally valid.
48+
// The checkPropertyChange method will return the same object type as validate, see JSONSchema.validate for
4949
// information.
5050
//
51-
return validate(value,schema, property || "property");
51+
return validate(value, schema, {changing: property || "property"});
5252
};
53-
var validate = exports._validate = function(/*Any*/instance,/*Object*/schema,/*Boolean*/ _changing) {
54-
53+
var validate = exports._validate = function(/*Any*/instance,/*Object*/schema,/*Object*/options) {
54+
55+
if (!options) options = {};
56+
var _changing = options.changing;
57+
5558
var errors = [];
56-
// validate a value against a property definition
59+
// validate a value against a property definition
5760
function checkProp(value, schema, path,i){
61+
5862
var l;
5963
path += path ? typeof i == 'number' ? '[' + i + ']' : typeof i == 'undefined' ? '' : '.' + i : i;
6064
function addError(message){
6165
errors.push({property:path,message:message});
6266
}
63-
67+
6468
if((typeof schema != 'object' || schema instanceof Array) && (path || typeof schema != 'function') && !(schema && schema.type)){
6569
if(typeof schema == 'function'){
6670
if(!(value instanceof schema)){
@@ -80,16 +84,16 @@ var validate = exports._validate = function(/*Any*/instance,/*Object*/schema,/*B
8084
// validate a value against a type definition
8185
function checkType(type,value){
8286
if(type){
83-
if(typeof type == 'string' && type != 'any' &&
84-
(type == 'null' ? value !== null : typeof value != type) &&
87+
if(typeof type == 'string' && type != 'any' &&
88+
(type == 'null' ? value !== null : typeof value != type) &&
8589
!(value instanceof Array && type == 'array') &&
8690
!(value instanceof Date && type == 'date') &&
8791
!(type == 'integer' && value%1===0)){
8892
return [{property:path,message:(typeof value) + " value found, but a " + type + " is required"}];
8993
}
9094
if(type instanceof Array){
9195
var unionErrors=[];
92-
for(var j = 0; j < type.length; j++){ // a union type
96+
for(var j = 0; j < type.length; j++){ // a union type
9397
if(!(unionErrors=checkType(type[j],value)).length){
9498
break;
9599
}
@@ -99,17 +103,17 @@ var validate = exports._validate = function(/*Any*/instance,/*Object*/schema,/*B
99103
}
100104
}else if(typeof type == 'object'){
101105
var priorErrors = errors;
102-
errors = [];
106+
errors = [];
103107
checkProp(value,type,path);
104108
var theseErrors = errors;
105109
errors = priorErrors;
106-
return theseErrors;
107-
}
110+
return theseErrors;
111+
}
108112
}
109113
return [];
110114
}
111115
if(value === undefined){
112-
if(!schema.optional && !schema.get){
116+
if(!schema.optional && !schema.get){
113117
addError("is missing and it is not optional");
114118
}
115119
}else{
@@ -120,15 +124,15 @@ var validate = exports._validate = function(/*Any*/instance,/*Object*/schema,/*B
120124
if(value !== null){
121125
if(value instanceof Array){
122126
if(schema.items){
123-
if(schema.items instanceof Array){
124-
for(i=0,l=value.length; i<l; i++){
125-
errors.concat(checkProp(value[i],schema.items[i],path,i));
126-
}
127-
}else{
128-
for(i=0,l=value.length; i<l; i++){
129-
errors.concat(checkProp(value[i],schema.items,path,i));
130-
}
131-
}
127+
var itemsIsArray = schema.items instanceof Array;
128+
var propDef = schema.items;
129+
for (i = 0, l = value.length; i < l; i += 1) {
130+
if (itemsIsArray)
131+
propDef = schema.items[i];
132+
if (options.coerce)
133+
value[i] = options.coerce(value[i], propDef);
134+
errors.concat(checkProp(value[i],propDef,path,i));
135+
}
132136
}
133137
if(schema.minItems && value.length < schema.minItems){
134138
addError("There must be a minimum of " + schema.minItems + " in the array");
@@ -148,11 +152,11 @@ var validate = exports._validate = function(/*Any*/instance,/*Object*/schema,/*B
148152
if(schema.minLength && typeof value == 'string' && value.length < schema.minLength){
149153
addError("must be at least " + schema.minLength + " characters long");
150154
}
151-
if(typeof schema.minimum !== undefined && typeof value == typeof schema.minimum &&
155+
if(typeof schema.minimum !== undefined && typeof value == typeof schema.minimum &&
152156
schema.minimum > value){
153157
addError("must have a minimum value of " + schema.minimum);
154158
}
155-
if(typeof schema.maximum !== undefined && typeof value == typeof schema.maximum &&
159+
if(typeof schema.maximum !== undefined && typeof value == typeof schema.maximum &&
156160
schema.maximum < value){
157161
addError("must have a maximum value of " + schema.maximum);
158162
}
@@ -170,7 +174,7 @@ var validate = exports._validate = function(/*Any*/instance,/*Object*/schema,/*B
170174
addError("does not have a value in the enumeration " + enumer.join(", "));
171175
}
172176
}
173-
if(typeof schema.maxDecimal == 'number' &&
177+
if(typeof schema.maxDecimal == 'number' &&
174178
(value.toString().match(new RegExp("\\.[0-9]{" + (schema.maxDecimal + 1) + ",}")))){
175179
addError("may only have " + schema.maxDecimal + " digits of decimal places");
176180
}
@@ -180,7 +184,7 @@ var validate = exports._validate = function(/*Any*/instance,/*Object*/schema,/*B
180184
}
181185
// validate an object against a schema
182186
function checkObj(instance,objTypeDef,path,additionalProp){
183-
187+
184188
if(typeof objTypeDef =='object'){
185189
if(typeof instance != 'object' || instance instanceof Array){
186190
errors.push({property:path,message:"an object is required"});
@@ -189,33 +193,40 @@ var validate = exports._validate = function(/*Any*/instance,/*Object*/schema,/*B
189193
for(var i in objTypeDef){
190194
if(objTypeDef.hasOwnProperty(i)){
191195
var value = instance[i];
196+
// skip _not_ specified properties
197+
if (value === undefined && options.existingOnly) continue;
192198
var propDef = objTypeDef[i];
193-
// set default
194-
if(value === undefined && propDef["default"]){
195-
value = instance[i] = propDef["default"];
196-
}
197-
if(propDef.coerce && exports.coerce && i in instance){
198-
value = instance[i] = exports.coerce(value, propDef);
199-
}
199+
// set default
200+
if(value === undefined && propDef["default"]){
201+
value = instance[i] = propDef["default"];
202+
}
203+
if(options.coerce && i in instance){
204+
value = instance[i] = options.coerce(value, propDef);
205+
}
200206
checkProp(value,propDef,path,i);
201207
}
202208
}
203209
}
204210
for(i in instance){
205211
if(instance.hasOwnProperty(i) && !(i.charAt(0) == '_' && i.charAt(1) == '_') && objTypeDef && !objTypeDef[i] && additionalProp===false){
206-
errors.push({property:path,message:(typeof value) + "The property " + i +
212+
if (options.filter) {
213+
delete instance[i];
214+
continue;
215+
} else {
216+
errors.push({property:path,message:(typeof value) + "The property " + i +
207217
" is not defined in the schema and the schema does not allow additional properties"});
218+
}
208219
}
209220
var requires = objTypeDef && objTypeDef[i] && objTypeDef[i].requires;
210221
if(requires && !(requires in instance)){
211222
errors.push({property:path,message:"the presence of the property " + i + " requires that " + requires + " also be present"});
212223
}
213224
value = instance[i];
214225
if(additionalProp && (!(objTypeDef && typeof objTypeDef == 'object') || !(i in objTypeDef))){
215-
if(additionalProp.coerce && exports.coerce){
216-
value = instance[i] = exports.coerce(value, additionalProp);
217-
}
218-
checkProp(value,additionalProp,path,i);
226+
if(options.coerce){
227+
value = instance[i] = options.coerce(value, additionalProp);
228+
}
229+
checkProp(value,additionalProp,path,i);
219230
}
220231
if(!_changing && value && value.$schema){
221232
errors = errors.concat(checkProp(value,value.$schema,path,i));
@@ -237,8 +248,8 @@ exports.mustBeValid = function(result){
237248
// result: the result returned from checkPropertyChange or validate
238249
if(!result.valid){
239250
throw new TypeError(result.errors.map(function(error){return "for property " + error.property + ': ' + error.message;}).join(", \n"));
240-
}
251+
}
241252
}
242253

243254
return exports;
244-
});
255+
});

0 commit comments

Comments
 (0)