source: Dev/trunk/src/client/dojox/json/schema.js @ 532

Last change on this file since 532 was 483, checked in by hendrikvanantwerpen, 11 years ago

Added Dojo 1.9.3 release.

File size: 8.3 KB
Line 
1define(["dojo/_base/kernel", "dojox", "dojo/_base/array"], function(dojo, dojox){
2
3dojo.getObject("json.schema", true, dojox);
4
5
6dojox.json.schema.validate = function(/*Any*/instance,/*Object*/schema){
7        // summary:
8        //              To use the validator call this with an instance object and an optional schema object.
9        //              If a schema is provided, it will be used to validate. If the instance object refers to a schema (self-validating),
10        //              that schema will be used to validate and the schema parameter is not necessary (if both exist,
11        //              both validations will occur).
12        // instance:
13        //              The instance value/object to validate
14        // schema:
15        //              The schema to use to validate
16        // description:
17        //              The validate method will return an object with two properties:
18        //
19        //              - valid: A boolean indicating if the instance is valid by the schema
20        //              - errors: An array of validation errors. If there are no errors, then an
21        //                empty list will be returned. A validation error will have two properties:
22        //              - property: which indicates which property had the error
23        //              - message: which indicates what the error was
24
25        return this._validate(instance,schema,false);
26};
27dojox.json.schema.checkPropertyChange = function(/*Any*/value,/*Object*/schema, /*String*/ property){
28        // summary:
29        //              The checkPropertyChange method will check to see if an value can legally be in property with the given schema
30        //              This is slightly different than the validate method in that it will fail if the schema is readonly and it will
31        //              not check for self-validation, it is assumed that the passed in value is already internally valid.
32        //              The checkPropertyChange method will return the same object type as validate, see JSONSchema.validate for
33        //              information.
34        // value:
35        //              The new instance value/object to check
36        // schema:
37        //              The schema to use to validate
38        // returns:
39        //              see dojox.validate.jsonSchema.validate
40
41        return this._validate(value,schema, property || "property");
42};
43dojox.json.schema.mustBeValid = function(result){
44        // summary:
45        //              This checks to ensure that the result is valid and will throw an appropriate error message if it is not
46        // result: the result returned from checkPropertyChange or validate
47        if(!result.valid){
48                throw new TypeError(dojo.map(result.errors,function(error){return "for property " + error.property + ': ' + error.message;}).join(", "));
49        }
50};
51dojox.json.schema._validate = function(/*Any*/instance,/*Object*/schema,/*Boolean*/ _changing){
52       
53        var errors = [];
54                // validate a value against a property definition
55        function checkProp(value, schema, path,i){
56                var l;
57                path += path ? typeof i == 'number' ? '[' + i + ']' : typeof i == 'undefined' ? '' : '.' + i : i;
58                function addError(message){
59                        errors.push({property:path,message:message});
60                }
61               
62                if((typeof schema != 'object' || schema instanceof Array) && (path || typeof schema != 'function')){
63                        if(typeof schema == 'function'){
64                                if(!(Object(value) instanceof schema)){
65                                        addError("is not an instance of the class/constructor " + schema.name);
66                                }
67                        }else if(schema){
68                                addError("Invalid schema/property definition " + schema);
69                        }
70                        return null;
71                }
72                if(_changing && schema.readonly){
73                        addError("is a readonly field, it can not be changed");
74                }
75                if(schema['extends']){ // if it extends another schema, it must pass that schema as well
76                        checkProp(value,schema['extends'],path,i);
77                }
78                // validate a value against a type definition
79                function checkType(type,value){
80                        if(type){
81                                if(typeof type == 'string' && type != 'any' &&
82                                                (type == 'null' ? value !== null : typeof value != type) &&
83                                                !(value instanceof Array && type == 'array') &&
84                                                !(type == 'integer' && value%1===0)){
85                                        return [{property:path,message:(typeof value) + " value found, but a " + type + " is required"}];
86                                }
87                                if(type instanceof Array){
88                                        var unionErrors=[];
89                                        for(var j = 0; j < type.length; j++){ // a union type
90                                                if(!(unionErrors=checkType(type[j],value)).length){
91                                                        break;
92                                                }
93                                        }
94                                        if(unionErrors.length){
95                                                return unionErrors;
96                                        }
97                                }else if(typeof type == 'object'){
98                                        var priorErrors = errors;
99                                        errors = [];
100                                        checkProp(value,type,path);
101                                        var theseErrors = errors;
102                                        errors = priorErrors;
103                                        return theseErrors;
104                                }
105                        }
106                        return [];
107                }
108                if(value === undefined){
109                        if(!schema.optional){
110                                addError("is missing and it is not optional");
111                        }
112                }else{
113                        errors = errors.concat(checkType(schema.type,value));
114                        if(schema.disallow && !checkType(schema.disallow,value).length){
115                                addError(" disallowed value was matched");
116                        }
117                        if(value !== null){
118                                if(value instanceof Array){
119                                        if(schema.items){
120                                                if(schema.items instanceof Array){
121                                                        for(i=0,l=value.length; i<l; i++){
122                                                                errors.concat(checkProp(value[i],schema.items[i],path,i));
123                                                        }
124                                                }else{
125                                                        for(i=0,l=value.length; i<l; i++){
126                                                                errors.concat(checkProp(value[i],schema.items,path,i));
127                                                        }
128                                                }
129                                        }
130                                        if(schema.minItems && value.length < schema.minItems){
131                                                addError("There must be a minimum of " + schema.minItems + " in the array");
132                                        }
133                                        if(schema.maxItems && value.length > schema.maxItems){
134                                                addError("There must be a maximum of " + schema.maxItems + " in the array");
135                                        }
136                                }else if(schema.properties){
137                                        errors.concat(checkObj(value,schema.properties,path,schema.additionalProperties));
138                                }
139                                if(schema.pattern && typeof value == 'string' && !value.match(schema.pattern)){
140                                        addError("does not match the regex pattern " + schema.pattern);
141                                }
142                                if(schema.maxLength && typeof value == 'string' && value.length > schema.maxLength){
143                                        addError("may only be " + schema.maxLength + " characters long");
144                                }
145                                if(schema.minLength && typeof value == 'string' && value.length < schema.minLength){
146                                        addError("must be at least " + schema.minLength + " characters long");
147                                }
148                                if(typeof schema.minimum !== undefined && typeof value == typeof schema.minimum &&
149                                                schema.minimum > value){
150                                        addError("must have a minimum value of " + schema.minimum);
151                                }
152                                if(typeof schema.maximum !== undefined && typeof value == typeof schema.maximum &&
153                                                schema.maximum < value){
154                                        addError("must have a maximum value of " + schema.maximum);
155                                }
156                                if(schema['enum']){
157                                        var enumer = schema['enum'];
158                                        l = enumer.length;
159                                        var found;
160                                        for(var j = 0; j < l; j++){
161                                                if(enumer[j]===value){
162                                                        found=1;
163                                                        break;
164                                                }
165                                        }
166                                        if(!found){
167                                                addError("does not have a value in the enumeration " + enumer.join(", "));
168                                        }
169                                }
170                                if(typeof schema.maxDecimal == 'number' &&
171                                        (value.toString().match(new RegExp("\\.[0-9]{" + (schema.maxDecimal + 1) + ",}")))){
172                                        addError("may only have " + schema.maxDecimal + " digits of decimal places");
173                                }
174                        }
175                }
176                return null;
177        }
178        // validate an object against a schema
179        function checkObj(instance,objTypeDef,path,additionalProp){
180       
181                if(typeof objTypeDef =='object'){
182                        if(typeof instance != 'object' || instance instanceof Array){
183                                errors.push({property:path,message:"an object is required"});
184                        }
185                       
186                        for(var i in objTypeDef){
187                                if(objTypeDef.hasOwnProperty(i) && !(i.charAt(0) == '_' && i.charAt(1) == '_')){
188                                        var value = instance[i];
189                                        var propDef = objTypeDef[i];
190                                        checkProp(value,propDef,path,i);
191                                }
192                        }
193                }
194                for(i in instance){
195                        if(instance.hasOwnProperty(i) && !(i.charAt(0) == '_' && i.charAt(1) == '_') && objTypeDef && !objTypeDef[i] && additionalProp===false){
196                                errors.push({property:path,message:(typeof value) + "The property " + i +
197                                                " is not defined in the schema and the schema does not allow additional properties"});
198                        }
199                        var requires = objTypeDef && objTypeDef[i] && objTypeDef[i].requires;
200                        if(requires && !(requires in instance)){
201                                errors.push({property:path,message:"the presence of the property " + i + " requires that " + requires + " also be present"});
202                        }
203                        value = instance[i];
204                        if(objTypeDef && typeof objTypeDef == 'object' && !(i in objTypeDef)){
205                                checkProp(value,additionalProp,path,i);
206                        }
207                        if(!_changing && value && value.$schema){
208                                errors = errors.concat(checkProp(value,value.$schema,path,i));
209                        }
210                }
211                return errors;
212        }
213        if(schema){
214                checkProp(instance,schema,'',_changing || '');
215        }
216        if(!_changing && instance && instance.$schema){
217                checkProp(instance,instance.$schema,'','');
218        }
219        return {valid:!errors.length,errors:errors};
220};
221
222return dojox.json.schema;
223});
Note: See TracBrowser for help on using the repository browser.