source: Dev/branches/rest-dojo-ui/client/dojox/json/schema.js @ 256

Last change on this file since 256 was 256, checked in by hendrikvanantwerpen, 13 years ago

Reworked project structure based on REST interaction and Dojo library. As
soon as this is stable, the old jQueryUI branch can be removed (it's
kept for reference).

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