1
- /**
2
- * JSONSchema Validator - Validates JavaScript objects using JSON Schemas
1
+ /**
2
+ * JSONSchema Validator - Validates JavaScript objects using JSON Schemas
3
3
* (http://www.json.com/json-schema-proposal/)
4
4
*
5
5
* Copyright (c) 2007 Kris Zyp SitePen (www.sitepen.com)
6
6
* Licensed under the MIT (MIT-LICENSE.txt) license.
7
7
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:
13
13
"property" which indicates which property had the error
14
14
"message" which indicates what the error was
15
15
*/
@@ -24,43 +24,47 @@ exports.Integer = {type:"integer"};
24
24
Object . type = "object" ;
25
25
Array . type = "array" ;
26
26
Date . type = "date" ;
27
- exports . validate = validate ;
27
+ exports . validate = validate ;
28
28
function validate ( /*Any*/ instance , /*Object*/ schema ) {
29
29
// Summary:
30
30
// 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).
34
34
// The validate method will return an object with two properties:
35
35
// 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:
38
38
// property: which indicates which property had the error
39
39
// message: which indicates what the error was
40
40
//
41
- return validate ( instance , schema , false ) ;
41
+ return validate ( instance , schema , { changing : false } ) ; //, coerce: false, existingOnly: false} );
42
42
} ;
43
- exports . checkPropertyChange = function ( /*Any*/ value , /*Object*/ schema , /*String*/ property ) {
43
+ exports . checkPropertyChange = function ( /*Any*/ value , /*Object*/ schema , /*String*/ property ) {
44
44
// Summary:
45
45
// The checkPropertyChange method will check to see if an value can legally be in property with the given schema
46
46
// 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
49
49
// information.
50
50
//
51
- return validate ( value , schema , property || "property" ) ;
51
+ return validate ( value , schema , { changing : property || "property" } ) ;
52
52
} ;
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
+
55
58
var errors = [ ] ;
56
- // validate a value against a property definition
59
+ // validate a value against a property definition
57
60
function checkProp ( value , schema , path , i ) {
61
+
58
62
var l ;
59
63
path += path ? typeof i == 'number' ? '[' + i + ']' : typeof i == 'undefined' ? '' : '.' + i : i ;
60
64
function addError ( message ) {
61
65
errors . push ( { property :path , message :message } ) ;
62
66
}
63
-
67
+
64
68
if ( ( typeof schema != 'object' || schema instanceof Array ) && ( path || typeof schema != 'function' ) && ! ( schema && schema . type ) ) {
65
69
if ( typeof schema == 'function' ) {
66
70
if ( ! ( value instanceof schema ) ) {
@@ -80,16 +84,16 @@ var validate = exports._validate = function(/*Any*/instance,/*Object*/schema,/*B
80
84
// validate a value against a type definition
81
85
function checkType ( type , value ) {
82
86
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 ) &&
85
89
! ( value instanceof Array && type == 'array' ) &&
86
90
! ( value instanceof Date && type == 'date' ) &&
87
91
! ( type == 'integer' && value % 1 === 0 ) ) {
88
92
return [ { property :path , message :( typeof value ) + " value found, but a " + type + " is required" } ] ;
89
93
}
90
94
if ( type instanceof Array ) {
91
95
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
93
97
if ( ! ( unionErrors = checkType ( type [ j ] , value ) ) . length ) {
94
98
break ;
95
99
}
@@ -99,17 +103,17 @@ var validate = exports._validate = function(/*Any*/instance,/*Object*/schema,/*B
99
103
}
100
104
} else if ( typeof type == 'object' ) {
101
105
var priorErrors = errors ;
102
- errors = [ ] ;
106
+ errors = [ ] ;
103
107
checkProp ( value , type , path ) ;
104
108
var theseErrors = errors ;
105
109
errors = priorErrors ;
106
- return theseErrors ;
107
- }
110
+ return theseErrors ;
111
+ }
108
112
}
109
113
return [ ] ;
110
114
}
111
115
if ( value === undefined ) {
112
- if ( ! schema . optional && ! schema . get ) {
116
+ if ( ! schema . optional && ! schema . get ) {
113
117
addError ( "is missing and it is not optional" ) ;
114
118
}
115
119
} else {
@@ -120,15 +124,15 @@ var validate = exports._validate = function(/*Any*/instance,/*Object*/schema,/*B
120
124
if ( value !== null ) {
121
125
if ( value instanceof Array ) {
122
126
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
+ }
132
136
}
133
137
if ( schema . minItems && value . length < schema . minItems ) {
134
138
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
148
152
if ( schema . minLength && typeof value == 'string' && value . length < schema . minLength ) {
149
153
addError ( "must be at least " + schema . minLength + " characters long" ) ;
150
154
}
151
- if ( typeof schema . minimum !== undefined && typeof value == typeof schema . minimum &&
155
+ if ( typeof schema . minimum !== undefined && typeof value == typeof schema . minimum &&
152
156
schema . minimum > value ) {
153
157
addError ( "must have a minimum value of " + schema . minimum ) ;
154
158
}
155
- if ( typeof schema . maximum !== undefined && typeof value == typeof schema . maximum &&
159
+ if ( typeof schema . maximum !== undefined && typeof value == typeof schema . maximum &&
156
160
schema . maximum < value ) {
157
161
addError ( "must have a maximum value of " + schema . maximum ) ;
158
162
}
@@ -170,7 +174,7 @@ var validate = exports._validate = function(/*Any*/instance,/*Object*/schema,/*B
170
174
addError ( "does not have a value in the enumeration " + enumer . join ( ", " ) ) ;
171
175
}
172
176
}
173
- if ( typeof schema . maxDecimal == 'number' &&
177
+ if ( typeof schema . maxDecimal == 'number' &&
174
178
( value . toString ( ) . match ( new RegExp ( "\\.[0-9]{" + ( schema . maxDecimal + 1 ) + ",}" ) ) ) ) {
175
179
addError ( "may only have " + schema . maxDecimal + " digits of decimal places" ) ;
176
180
}
@@ -180,7 +184,7 @@ var validate = exports._validate = function(/*Any*/instance,/*Object*/schema,/*B
180
184
}
181
185
// validate an object against a schema
182
186
function checkObj ( instance , objTypeDef , path , additionalProp ) {
183
-
187
+
184
188
if ( typeof objTypeDef == 'object' ) {
185
189
if ( typeof instance != 'object' || instance instanceof Array ) {
186
190
errors . push ( { property :path , message :"an object is required" } ) ;
@@ -189,33 +193,40 @@ var validate = exports._validate = function(/*Any*/instance,/*Object*/schema,/*B
189
193
for ( var i in objTypeDef ) {
190
194
if ( objTypeDef . hasOwnProperty ( i ) ) {
191
195
var value = instance [ i ] ;
196
+ // skip _not_ specified properties
197
+ if ( value === undefined && options . existingOnly ) continue ;
192
198
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
+ }
200
206
checkProp ( value , propDef , path , i ) ;
201
207
}
202
208
}
203
209
}
204
210
for ( i in instance ) {
205
211
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 +
207
217
" is not defined in the schema and the schema does not allow additional properties" } ) ;
218
+ }
208
219
}
209
220
var requires = objTypeDef && objTypeDef [ i ] && objTypeDef [ i ] . requires ;
210
221
if ( requires && ! ( requires in instance ) ) {
211
222
errors . push ( { property :path , message :"the presence of the property " + i + " requires that " + requires + " also be present" } ) ;
212
223
}
213
224
value = instance [ i ] ;
214
225
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 ) ;
219
230
}
220
231
if ( ! _changing && value && value . $schema ) {
221
232
errors = errors . concat ( checkProp ( value , value . $schema , path , i ) ) ;
@@ -237,8 +248,8 @@ exports.mustBeValid = function(result){
237
248
// result: the result returned from checkPropertyChange or validate
238
249
if ( ! result . valid ) {
239
250
throw new TypeError ( result . errors . map ( function ( error ) { return "for property " + error . property + ': ' + error . message ; } ) . join ( ", \n" ) ) ;
240
- }
251
+ }
241
252
}
242
253
243
254
return exports ;
244
- } ) ;
255
+ } ) ;
0 commit comments