OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // ----------------------------------------------------------------------------- | 5 // ----------------------------------------------------------------------------- |
6 // NOTE: If you change this file you need to touch renderer_resources.grd to | 6 // NOTE: If you change this file you need to touch renderer_resources.grd to |
7 // have your change take effect. | 7 // have your change take effect. |
8 // ----------------------------------------------------------------------------- | 8 // ----------------------------------------------------------------------------- |
9 | 9 |
10 //============================================================================== | 10 //============================================================================== |
(...skipping 18 matching lines...) Expand all Loading... |
29 // - hidden | 29 // - hidden |
30 // | 30 // |
31 // There are also these departures from the JSON Schema proposal: | 31 // There are also these departures from the JSON Schema proposal: |
32 // - function and undefined types are supported | 32 // - function and undefined types are supported |
33 // - null counts as 'unspecified' for optional values | 33 // - null counts as 'unspecified' for optional values |
34 // - added the 'choices' property, to allow specifying a list of possible types | 34 // - added the 'choices' property, to allow specifying a list of possible types |
35 // for a value | 35 // for a value |
36 // - made additionalProperties default to false | 36 // - made additionalProperties default to false |
37 //============================================================================== | 37 //============================================================================== |
38 | 38 |
39 var chrome = chrome || {}; | 39 (function() { |
| 40 native function GetChromeHidden(); |
| 41 var chromeHidden = GetChromeHidden(); |
40 | 42 |
41 /** | 43 /** |
42 * Validates an instance against a schema and accumulates errors. Usage: | 44 * Validates an instance against a schema and accumulates errors. Usage: |
43 * | 45 * |
44 * var validator = new chrome.JSONSchemaValidator(); | 46 * var validator = new chromeHidden.JSONSchemaValidator(); |
45 * validator.validate(inst, schema); | 47 * validator.validate(inst, schema); |
46 * if (validator.errors.length == 0) | 48 * if (validator.errors.length == 0) |
47 * console.log("Valid!"); | 49 * console.log("Valid!"); |
48 * else | 50 * else |
49 * console.log(validator.errors); | 51 * console.log(validator.errors); |
50 * | 52 * |
51 * The errors property contains a list of objects. Each object has two | 53 * The errors property contains a list of objects. Each object has two |
52 * properties: "path" and "message". The "path" property contains the path to | 54 * properties: "path" and "message". The "path" property contains the path to |
53 * the key that had the problem, and the "message" property contains a sentence | 55 * the key that had the problem, and the "message" property contains a sentence |
54 * describing the error. | 56 * describing the error. |
55 */ | 57 */ |
56 chrome.JSONSchemaValidator = function() { | 58 chromeHidden.JSONSchemaValidator = function() { |
57 this.errors = []; | 59 this.errors = []; |
58 this.types = []; | 60 this.types = []; |
59 }; | 61 }; |
60 | 62 |
61 chrome.JSONSchemaValidator.messages = { | 63 chromeHidden.JSONSchemaValidator.messages = { |
62 invalidEnum: "Value must be one of: [*].", | 64 invalidEnum: "Value must be one of: [*].", |
63 propertyRequired: "Property is required.", | 65 propertyRequired: "Property is required.", |
64 unexpectedProperty: "Unexpected property.", | 66 unexpectedProperty: "Unexpected property.", |
65 arrayMinItems: "Array must have at least * items.", | 67 arrayMinItems: "Array must have at least * items.", |
66 arrayMaxItems: "Array must not have more than * items.", | 68 arrayMaxItems: "Array must not have more than * items.", |
67 itemRequired: "Item is required.", | 69 itemRequired: "Item is required.", |
68 stringMinLength: "String must be at least * characters long.", | 70 stringMinLength: "String must be at least * characters long.", |
69 stringMaxLength: "String must not be more than * characters long.", | 71 stringMaxLength: "String must not be more than * characters long.", |
70 stringPattern: "String must match the pattern: *.", | 72 stringPattern: "String must match the pattern: *.", |
71 numberMinValue: "Value must not be less than *.", | 73 numberMinValue: "Value must not be less than *.", |
72 numberMaxValue: "Value must not be greater than *.", | 74 numberMaxValue: "Value must not be greater than *.", |
73 numberMaxDecimal: "Value must not have more than * decimal places.", | 75 numberMaxDecimal: "Value must not have more than * decimal places.", |
74 invalidType: "Expected '*' but got '*'.", | 76 invalidType: "Expected '*' but got '*'.", |
75 invalidChoice: "Value does not match any valid type choices.", | 77 invalidChoice: "Value does not match any valid type choices.", |
76 invalidPropertyType: "Missing property type.", | 78 invalidPropertyType: "Missing property type.", |
77 schemaRequired: "Schema value required.", | 79 schemaRequired: "Schema value required.", |
78 unknownSchemaReference: "Unknown schema reference: *." | 80 unknownSchemaReference: "Unknown schema reference: *." |
79 }; | 81 }; |
80 | 82 |
81 /** | 83 /** |
82 * Builds an error message. Key is the property in the |errors| object, and | 84 * Builds an error message. Key is the property in the |errors| object, and |
83 * |opt_replacements| is an array of values to replace "*" characters with. | 85 * |opt_replacements| is an array of values to replace "*" characters with. |
84 */ | 86 */ |
85 chrome.JSONSchemaValidator.formatError = function(key, opt_replacements) { | 87 chromeHidden.JSONSchemaValidator.formatError = function(key, opt_replacements) { |
86 var message = this.messages[key]; | 88 var message = this.messages[key]; |
87 if (opt_replacements) { | 89 if (opt_replacements) { |
88 for (var i = 0; i < opt_replacements.length; i++) { | 90 for (var i = 0; i < opt_replacements.length; i++) { |
89 message = message.replace("*", opt_replacements[i]); | 91 message = message.replace("*", opt_replacements[i]); |
90 } | 92 } |
91 } | 93 } |
92 return message; | 94 return message; |
93 }; | 95 }; |
94 | 96 |
95 /** | 97 /** |
96 * Classifies a value as one of the JSON schema primitive types. Note that we | 98 * Classifies a value as one of the JSON schema primitive types. Note that we |
97 * don't explicitly disallow 'function', because we want to allow functions in | 99 * don't explicitly disallow 'function', because we want to allow functions in |
98 * the input values. | 100 * the input values. |
99 */ | 101 */ |
100 chrome.JSONSchemaValidator.getType = function(value) { | 102 chromeHidden.JSONSchemaValidator.getType = function(value) { |
101 var s = typeof value; | 103 var s = typeof value; |
102 | 104 |
103 if (s == "object") { | 105 if (s == "object") { |
104 if (value === null) { | 106 if (value === null) { |
105 return "null"; | 107 return "null"; |
106 } else if (value instanceof Array || | 108 } else if (value instanceof Array || |
107 Object.prototype.toString.call(value) == "[Object Array]") { | 109 Object.prototype.toString.call(value) == "[Object Array]") { |
108 return "array"; | 110 return "array"; |
109 } | 111 } |
110 } else if (s == "number") { | 112 } else if (s == "number") { |
111 if (value % 1 == 0) { | 113 if (value % 1 == 0) { |
112 return "integer"; | 114 return "integer"; |
113 } | 115 } |
114 } | 116 } |
115 | 117 |
116 return s; | 118 return s; |
117 }; | 119 }; |
118 | 120 |
119 /** | 121 /** |
120 * Add types that may be referenced by validated schemas that reference them | 122 * Add types that may be referenced by validated schemas that reference them |
121 * with "$ref": <typeId>. Each type must be a valid schema and define an | 123 * with "$ref": <typeId>. Each type must be a valid schema and define an |
122 * "id" property. | 124 * "id" property. |
123 */ | 125 */ |
124 chrome.JSONSchemaValidator.prototype.addTypes = function(typeOrTypeList) { | 126 chromeHidden.JSONSchemaValidator.prototype.addTypes = function(typeOrTypeList) { |
125 function addType(validator, type) { | 127 function addType(validator, type) { |
126 if(!type.id) | 128 if(!type.id) |
127 throw "Attempt to addType with missing 'id' property"; | 129 throw "Attempt to addType with missing 'id' property"; |
128 validator.types[type.id] = type; | 130 validator.types[type.id] = type; |
129 } | 131 } |
130 | 132 |
131 if (typeOrTypeList instanceof Array) { | 133 if (typeOrTypeList instanceof Array) { |
132 for (var i = 0; i < typeOrTypeList.length; i++) { | 134 for (var i = 0; i < typeOrTypeList.length; i++) { |
133 addType(this, typeOrTypeList[i]); | 135 addType(this, typeOrTypeList[i]); |
134 } | 136 } |
135 } else { | 137 } else { |
136 addType(this, typeOrTypeList); | 138 addType(this, typeOrTypeList); |
137 } | 139 } |
138 } | 140 } |
139 | 141 |
140 /** | 142 /** |
141 * Validates an instance against a schema. The instance can be any JavaScript | 143 * Validates an instance against a schema. The instance can be any JavaScript |
142 * value and will be validated recursively. When this method returns, the | 144 * value and will be validated recursively. When this method returns, the |
143 * |errors| property will contain a list of errors, if any. | 145 * |errors| property will contain a list of errors, if any. |
144 */ | 146 */ |
145 chrome.JSONSchemaValidator.prototype.validate = function(instance, schema, | 147 chromeHidden.JSONSchemaValidator.prototype.validate = function( |
146 opt_path) { | 148 instance, schema, opt_path) { |
147 var path = opt_path || ""; | 149 var path = opt_path || ""; |
148 | 150 |
149 if (!schema) { | 151 if (!schema) { |
150 this.addError(path, "schemaRequired"); | 152 this.addError(path, "schemaRequired"); |
151 return; | 153 return; |
152 } | 154 } |
153 | 155 |
154 // If this schema defines itself as reference type, save it in this.types. | 156 // If this schema defines itself as reference type, save it in this.types. |
155 if (schema.id) | 157 if (schema.id) |
156 this.types[schema.id] = schema; | 158 this.types[schema.id] = schema; |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
203 this.validateNumber(instance, schema, path); | 205 this.validateNumber(instance, schema, path); |
204 break; | 206 break; |
205 } | 207 } |
206 } | 208 } |
207 }; | 209 }; |
208 | 210 |
209 /** | 211 /** |
210 * Validates an instance against a choices schema. The instance must match at | 212 * Validates an instance against a choices schema. The instance must match at |
211 * least one of the provided choices. | 213 * least one of the provided choices. |
212 */ | 214 */ |
213 chrome.JSONSchemaValidator.prototype.validateChoices = function(instance, | 215 chromeHidden.JSONSchemaValidator.prototype.validateChoices = function( |
214 schema, | 216 instance, schema, path) { |
215 path) { | |
216 var originalErrors = this.errors; | 217 var originalErrors = this.errors; |
217 | 218 |
218 for (var i = 0; i < schema.choices.length; i++) { | 219 for (var i = 0; i < schema.choices.length; i++) { |
219 this.errors = []; | 220 this.errors = []; |
220 this.validate(instance, schema.choices[i], path); | 221 this.validate(instance, schema.choices[i], path); |
221 if (this.errors.length == 0) { | 222 if (this.errors.length == 0) { |
222 this.errors = originalErrors; | 223 this.errors = originalErrors; |
223 return; | 224 return; |
224 } | 225 } |
225 } | 226 } |
226 | 227 |
227 this.errors = originalErrors; | 228 this.errors = originalErrors; |
228 this.addError(path, "invalidChoice"); | 229 this.addError(path, "invalidChoice"); |
229 }; | 230 }; |
230 | 231 |
231 /** | 232 /** |
232 * Validates an instance against a schema with an enum type. Populates the | 233 * Validates an instance against a schema with an enum type. Populates the |
233 * |errors| property, and returns a boolean indicating whether the instance | 234 * |errors| property, and returns a boolean indicating whether the instance |
234 * validates. | 235 * validates. |
235 */ | 236 */ |
236 chrome.JSONSchemaValidator.prototype.validateEnum = function(instance, schema, | 237 chromeHidden.JSONSchemaValidator.prototype.validateEnum = function( |
237 path) { | 238 instance, schema, path) { |
238 for (var i = 0; i < schema.enum.length; i++) { | 239 for (var i = 0; i < schema.enum.length; i++) { |
239 if (instance === schema.enum[i]) | 240 if (instance === schema.enum[i]) |
240 return true; | 241 return true; |
241 } | 242 } |
242 | 243 |
243 this.addError(path, "invalidEnum", [schema.enum.join(", ")]); | 244 this.addError(path, "invalidEnum", [schema.enum.join(", ")]); |
244 return false; | 245 return false; |
245 }; | 246 }; |
246 | 247 |
247 /** | 248 /** |
248 * Validates an instance against an object schema and populates the errors | 249 * Validates an instance against an object schema and populates the errors |
249 * property. | 250 * property. |
250 */ | 251 */ |
251 chrome.JSONSchemaValidator.prototype.validateObject = function(instance, | 252 chromeHidden.JSONSchemaValidator.prototype.validateObject = function( |
252 schema, path) { | 253 instance, schema, path) { |
253 for (var prop in schema.properties) { | 254 for (var prop in schema.properties) { |
254 var propPath = path ? path + "." + prop : prop; | 255 var propPath = path ? path + "." + prop : prop; |
255 if (schema.properties[prop] == undefined) { | 256 if (schema.properties[prop] == undefined) { |
256 this.addError(propPath, "invalidPropertyType"); | 257 this.addError(propPath, "invalidPropertyType"); |
257 } else if (prop in instance && instance[prop] !== null && | 258 } else if (prop in instance && instance[prop] !== null && |
258 instance[prop] !== undefined) { | 259 instance[prop] !== undefined) { |
259 this.validate(instance[prop], schema.properties[prop], propPath); | 260 this.validate(instance[prop], schema.properties[prop], propPath); |
260 } else if (!schema.properties[prop].optional) { | 261 } else if (!schema.properties[prop].optional) { |
261 this.addError(propPath, "propertyRequired"); | 262 this.addError(propPath, "propertyRequired"); |
262 } | 263 } |
(...skipping 11 matching lines...) Expand all Loading... |
274 this.validate(instance[prop], schema.additionalProperties, propPath); | 275 this.validate(instance[prop], schema.additionalProperties, propPath); |
275 else | 276 else |
276 this.addError(propPath, "unexpectedProperty"); | 277 this.addError(propPath, "unexpectedProperty"); |
277 } | 278 } |
278 }; | 279 }; |
279 | 280 |
280 /** | 281 /** |
281 * Validates an instance against an array schema and populates the errors | 282 * Validates an instance against an array schema and populates the errors |
282 * property. | 283 * property. |
283 */ | 284 */ |
284 chrome.JSONSchemaValidator.prototype.validateArray = function(instance, | 285 chromeHidden.JSONSchemaValidator.prototype.validateArray = function( |
285 schema, path) { | 286 instance, schema, path) { |
286 var typeOfItems = chrome.JSONSchemaValidator.getType(schema.items); | 287 var typeOfItems = chromeHidden.JSONSchemaValidator.getType(schema.items); |
287 | 288 |
288 if (typeOfItems == 'object') { | 289 if (typeOfItems == 'object') { |
289 if (schema.minItems && instance.length < schema.minItems) { | 290 if (schema.minItems && instance.length < schema.minItems) { |
290 this.addError(path, "arrayMinItems", [schema.minItems]); | 291 this.addError(path, "arrayMinItems", [schema.minItems]); |
291 } | 292 } |
292 | 293 |
293 if (typeof schema.maxItems != "undefined" && | 294 if (typeof schema.maxItems != "undefined" && |
294 instance.length > schema.maxItems) { | 295 instance.length > schema.maxItems) { |
295 this.addError(path, "arrayMaxItems", [schema.maxItems]); | 296 this.addError(path, "arrayMaxItems", [schema.maxItems]); |
296 } | 297 } |
(...skipping 24 matching lines...) Expand all Loading... |
321 if (instance.length > schema.items.length) { | 322 if (instance.length > schema.items.length) { |
322 this.addError(path, "arrayMaxItems", [schema.items.length]); | 323 this.addError(path, "arrayMaxItems", [schema.items.length]); |
323 } | 324 } |
324 } | 325 } |
325 } | 326 } |
326 }; | 327 }; |
327 | 328 |
328 /** | 329 /** |
329 * Validates a string and populates the errors property. | 330 * Validates a string and populates the errors property. |
330 */ | 331 */ |
331 chrome.JSONSchemaValidator.prototype.validateString = function(instance, | 332 chromeHidden.JSONSchemaValidator.prototype.validateString = function( |
332 schema, path) { | 333 instance, schema, path) { |
333 if (schema.minLength && instance.length < schema.minLength) | 334 if (schema.minLength && instance.length < schema.minLength) |
334 this.addError(path, "stringMinLength", [schema.minLength]); | 335 this.addError(path, "stringMinLength", [schema.minLength]); |
335 | 336 |
336 if (schema.maxLength && instance.length > schema.maxLength) | 337 if (schema.maxLength && instance.length > schema.maxLength) |
337 this.addError(path, "stringMaxLength", [schema.maxLength]); | 338 this.addError(path, "stringMaxLength", [schema.maxLength]); |
338 | 339 |
339 if (schema.pattern && !schema.pattern.test(instance)) | 340 if (schema.pattern && !schema.pattern.test(instance)) |
340 this.addError(path, "stringPattern", [schema.pattern]); | 341 this.addError(path, "stringPattern", [schema.pattern]); |
341 }; | 342 }; |
342 | 343 |
343 /** | 344 /** |
344 * Validates a number and populates the errors property. The instance is | 345 * Validates a number and populates the errors property. The instance is |
345 * assumed to be a number. | 346 * assumed to be a number. |
346 */ | 347 */ |
347 chrome.JSONSchemaValidator.prototype.validateNumber = function(instance, | 348 chromeHidden.JSONSchemaValidator.prototype.validateNumber = function( |
348 schema, path) { | 349 instance, schema, path) { |
349 if (schema.minimum && instance < schema.minimum) | 350 if (schema.minimum && instance < schema.minimum) |
350 this.addError(path, "numberMinValue", [schema.minimum]); | 351 this.addError(path, "numberMinValue", [schema.minimum]); |
351 | 352 |
352 if (schema.maximum && instance > schema.maximum) | 353 if (schema.maximum && instance > schema.maximum) |
353 this.addError(path, "numberMaxValue", [schema.maximum]); | 354 this.addError(path, "numberMaxValue", [schema.maximum]); |
354 | 355 |
355 if (schema.maxDecimal && instance * Math.pow(10, schema.maxDecimal) % 1) | 356 if (schema.maxDecimal && instance * Math.pow(10, schema.maxDecimal) % 1) |
356 this.addError(path, "numberMaxDecimal", [schema.maxDecimal]); | 357 this.addError(path, "numberMaxDecimal", [schema.maxDecimal]); |
357 }; | 358 }; |
358 | 359 |
359 /** | 360 /** |
360 * Validates the primitive type of an instance and populates the errors | 361 * Validates the primitive type of an instance and populates the errors |
361 * property. Returns true if the instance validates, false otherwise. | 362 * property. Returns true if the instance validates, false otherwise. |
362 */ | 363 */ |
363 chrome.JSONSchemaValidator.prototype.validateType = function(instance, schema, | 364 chromeHidden.JSONSchemaValidator.prototype.validateType = function( |
364 path) { | 365 instance, schema, path) { |
365 var actualType = chrome.JSONSchemaValidator.getType(instance); | 366 var actualType = chromeHidden.JSONSchemaValidator.getType(instance); |
366 if (schema.type != actualType && !(schema.type == "number" && | 367 if (schema.type != actualType && !(schema.type == "number" && |
367 actualType == "integer")) { | 368 actualType == "integer")) { |
368 this.addError(path, "invalidType", [schema.type, actualType]); | 369 this.addError(path, "invalidType", [schema.type, actualType]); |
369 return false; | 370 return false; |
370 } | 371 } |
371 | 372 |
372 return true; | 373 return true; |
373 }; | 374 }; |
374 | 375 |
375 /** | 376 /** |
376 * Adds an error message. |key| is an index into the |messages| object. | 377 * Adds an error message. |key| is an index into the |messages| object. |
377 * |replacements| is an array of values to replace '*' characters in the | 378 * |replacements| is an array of values to replace '*' characters in the |
378 * message. | 379 * message. |
379 */ | 380 */ |
380 chrome.JSONSchemaValidator.prototype.addError = function(path, key, | 381 chromeHidden.JSONSchemaValidator.prototype.addError = function( |
381 replacements) { | 382 path, key, replacements) { |
382 this.errors.push({ | 383 this.errors.push({ |
383 path: path, | 384 path: path, |
384 message: chrome.JSONSchemaValidator.formatError(key, replacements) | 385 message: chromeHidden.JSONSchemaValidator.formatError(key, replacements) |
385 }); | 386 }); |
386 }; | 387 }; |
| 388 |
| 389 })(); |
OLD | NEW |