Guest User

json-schema-draft-01 und 02

a guest
Oct 30th, 2020
33
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /**
  2.  * json-schema-draft-01 Environment
  3.  *
  4.  * @fileOverview Implementation of the first revision of the JSON Schema specification draft.
  5.  * @author <a href="mailto:gary.court@gmail.com">Gary Court</a>
  6.  * @version 1.7.1
  7.  * @see http://github.com/garycourt/JSV
  8.  */
  9.  
  10. /*
  11.  * Copyright 2010 Gary Court. All rights reserved.
  12.  *
  13.  * Redistribution and use in source and binary forms, with or without modification, are
  14.  * permitted provided that the following conditions are met:
  15.  *
  16.  *    1. Redistributions of source code must retain the above copyright notice, this list of
  17.  *       conditions and the following disclaimer.
  18.  *
  19.  *    2. Redistributions in binary form must reproduce the above copyright notice, this list
  20.  *       of conditions and the following disclaimer in the documentation and/or other materials
  21.  *       provided with the distribution.
  22.  *
  23.  * THIS SOFTWARE IS PROVIDED BY GARY COURT ``AS IS'' AND ANY EXPRESS OR IMPLIED
  24.  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  25.  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GARY COURT OR
  26.  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  27.  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  28.  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  29.  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  30.  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  31.  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  32.  *
  33.  * The views and conclusions contained in the software and documentation are those of the
  34.  * authors and should not be interpreted as representing official policies, either expressed
  35.  * or implied, of Gary Court or the JSON Schema specification.
  36.  */
  37.  
  38. /*jslint white: true, sub: true, onevar: true, undef: true, eqeqeq: true, newcap: true, immed: true, indent: 4 */
  39. /*global require */
  40.  
  41. (function () {
  42.     var O = {},
  43.         JSV = require('./jsv').JSV,
  44.         ENVIRONMENT,
  45.         TYPE_VALIDATORS,
  46.         SCHEMA,
  47.         HYPERSCHEMA,
  48.         LINKS;
  49.    
  50.     TYPE_VALIDATORS = {
  51.         "string" : function (instance, report) {
  52.             return instance.getType() === "string";
  53.         },
  54.        
  55.         "number" : function (instance, report) {
  56.             return instance.getType() === "number";
  57.         },
  58.        
  59.         "integer" : function (instance, report) {
  60.             return instance.getType() === "number" && instance.getValue() % 1 === 0;
  61.         },
  62.        
  63.         "boolean" : function (instance, report) {
  64.             return instance.getType() === "boolean";
  65.         },
  66.        
  67.         "object" : function (instance, report) {
  68.             return instance.getType() === "object";
  69.         },
  70.        
  71.         "array" : function (instance, report) {
  72.             return instance.getType() === "array";
  73.         },
  74.        
  75.         "null" : function (instance, report) {
  76.             return instance.getType() === "null";
  77.         },
  78.        
  79.         "any" : function (instance, report) {
  80.             return true;
  81.         }
  82.     };
  83.    
  84.     ENVIRONMENT = new JSV.Environment();
  85.     ENVIRONMENT.setOption("defaultFragmentDelimiter", ".");
  86.     ENVIRONMENT.setOption("defaultSchemaURI", "http://json-schema.org/schema#");  //updated later
  87.    
  88.     SCHEMA = ENVIRONMENT.createSchema({
  89.         "$schema" : "http://json-schema.org/hyper-schema#",
  90.         "id" : "http://json-schema.org/schema#",
  91.         "type" : "object",
  92.        
  93.         "properties" : {
  94.             "type" : {
  95.                 "type" : ["string", "array"],
  96.                 "items" : {
  97.                     "type" : ["string", {"$ref" : "#"}]
  98.                 },
  99.                 "optional" : true,
  100.                 "uniqueItems" : true,
  101.                 "default" : "any",
  102.                
  103.                 "parser" : function (instance, self) {
  104.                     var parser;
  105.                    
  106.                     if (instance.getType() === "string") {
  107.                         return instance.getValue();
  108.                     } else if (instance.getType() === "object") {
  109.                         return instance.getEnvironment().createSchema(
  110.                             instance,
  111.                             self.getEnvironment().findSchema(self.resolveURI("#"))
  112.                         );
  113.                     } else if (instance.getType() === "array") {
  114.                         parser = self.getValueOfProperty("parser");
  115.                         return JSV.mapArray(instance.getProperties(), function (prop) {
  116.                             return parser(prop, self);
  117.                         });
  118.                     }
  119.                     //else
  120.                     return "any";
  121.                 },
  122.            
  123.                 "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  124.                     var requiredTypes = JSV.toArray(schema.getAttribute("type")),
  125.                         x, xl, type, subreport, typeValidators;
  126.                    
  127.                     //for instances that are required to be a certain type
  128.                     if (instance.getType() !== "undefined" && requiredTypes && requiredTypes.length) {
  129.                         typeValidators = self.getValueOfProperty("typeValidators") || {};
  130.                        
  131.                         //ensure that type matches for at least one of the required types
  132.                         for (x = 0, xl = requiredTypes.length; x < xl; ++x) {
  133.                             type = requiredTypes[x];
  134.                             if (JSV.isJSONSchema(type)) {
  135.                                 subreport = JSV.createObject(report);
  136.                                 subreport.errors = [];
  137.                                 subreport.validated = JSV.clone(report.validated);
  138.                                 if (type.validate(instance, subreport, parent, parentSchema, name).errors.length === 0) {
  139.                                     return true;  //instance matches this schema
  140.                                 }
  141.                             } else {
  142.                                 if (typeValidators[type] !== O[type] && typeof typeValidators[type] === "function") {
  143.                                     if (typeValidators[type](instance, report)) {
  144.                                         return true;  //type is valid
  145.                                     }
  146.                                 } else {
  147.                                     return true;  //unknown types are assumed valid
  148.                                 }
  149.                             }
  150.                         }
  151.                        
  152.                         //if we get to this point, type is invalid
  153.                         report.addError(instance, schema, "type", "Instance is not a required type", requiredTypes);
  154.                         return false;
  155.                     }
  156.                     //else, anything is allowed if no type is specified
  157.                     return true;
  158.                 },
  159.                
  160.                 "typeValidators" : TYPE_VALIDATORS
  161.             },
  162.            
  163.             "properties" : {
  164.                 "type" : "object",
  165.                 "additionalProperties" : {"$ref" : "#"},
  166.                 "optional" : true,
  167.                 "default" : {},
  168.                
  169.                 "parser" : function (instance, self, arg) {
  170.                     var env = instance.getEnvironment(),
  171.                         selfEnv = self.getEnvironment();
  172.                     if (instance.getType() === "object") {
  173.                         if (arg) {
  174.                             return env.createSchema(instance.getProperty(arg), selfEnv.findSchema(self.resolveURI("#")));
  175.                         } else {
  176.                             return JSV.mapObject(instance.getProperties(), function (instance) {
  177.                                 return env.createSchema(instance, selfEnv.findSchema(self.resolveURI("#")));
  178.                             });
  179.                         }
  180.                     }
  181.                     //else
  182.                     return {};
  183.                 },
  184.                
  185.                 "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  186.                     var propertySchemas, key;
  187.                     //this attribute is for object type instances only
  188.                     if (instance.getType() === "object") {
  189.                         //for each property defined in the schema
  190.                         propertySchemas = schema.getAttribute("properties");
  191.                         for (key in propertySchemas) {
  192.                             if (propertySchemas[key] !== O[key] && propertySchemas[key]) {
  193.                                 //ensure that instance property is valid
  194.                                 propertySchemas[key].validate(instance.getProperty(key), report, instance, schema, key);
  195.                             }
  196.                         }
  197.                     }
  198.                 }
  199.             },
  200.            
  201.             "items" : {
  202.                 "type" : [{"$ref" : "#"}, "array"],
  203.                 "items" : {"$ref" : "#"},
  204.                 "optional" : true,
  205.                 "default" : {},
  206.                
  207.                 "parser" : function (instance, self) {
  208.                     if (instance.getType() === "object") {
  209.                         return instance.getEnvironment().createSchema(instance, self.getEnvironment().findSchema(self.resolveURI("#")));
  210.                     } else if (instance.getType() === "array") {
  211.                         return JSV.mapArray(instance.getProperties(), function (instance) {
  212.                             return instance.getEnvironment().createSchema(instance, self.getEnvironment().findSchema(self.resolveURI("#")));
  213.                         });
  214.                     }
  215.                     //else
  216.                     return instance.getEnvironment().createEmptySchema();
  217.                 },
  218.                
  219.                 "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  220.                     var properties, items, x, xl, itemSchema, additionalProperties;
  221.                    
  222.                     if (instance.getType() === "array") {
  223.                         properties = instance.getProperties();
  224.                         items = schema.getAttribute("items");
  225.                         additionalProperties = schema.getAttribute("additionalProperties");
  226.                        
  227.                         if (JSV.typeOf(items) === "array") {
  228.                             for (x = 0, xl = properties.length; x < xl; ++x) {
  229.                                 itemSchema = items[x] || additionalProperties;
  230.                                 if (itemSchema !== false) {
  231.                                     itemSchema.validate(properties[x], report, instance, schema, x);
  232.                                 } else {
  233.                                     report.addError(instance, schema, "additionalProperties", "Additional items are not allowed", itemSchema);
  234.                                 }
  235.                             }
  236.                         } else {
  237.                             itemSchema = items || additionalProperties;
  238.                             for (x = 0, xl = properties.length; x < xl; ++x) {
  239.                                 itemSchema.validate(properties[x], report, instance, schema, x);
  240.                             }
  241.                         }
  242.                     }
  243.                 }
  244.             },
  245.            
  246.             "optional" : {
  247.                 "type" : "boolean",
  248.                 "optional" : true,
  249.                 "default" : true,
  250.                
  251.                 "parser" : function (instance, self) {
  252.                     return !!instance.getValue();
  253.                 },
  254.                
  255.                 "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  256.                     if (instance.getType() === "undefined" && !schema.getAttribute("optional")) {
  257.                         report.addError(instance, schema, "optional", "Property is required", false);
  258.                     }
  259.                 },
  260.                
  261.                 "validationRequired" : true
  262.             },
  263.            
  264.             "additionalProperties" : {
  265.                 "type" : [{"$ref" : "#"}, "boolean"],
  266.                 "optional" : true,
  267.                 "default" : {},
  268.                
  269.                 "parser" : function (instance, self) {
  270.                     if (instance.getType() === "object") {
  271.                         return instance.getEnvironment().createSchema(instance, self.getEnvironment().findSchema(self.resolveURI("#")));
  272.                     } else if (instance.getType() === "boolean" && instance.getValue() === false) {
  273.                         return false;
  274.                     }
  275.                     //else
  276.                     return instance.getEnvironment().createEmptySchema();
  277.                 },
  278.                
  279.                 "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  280.                     var additionalProperties, propertySchemas, properties, key;
  281.                     //we only need to check against object types as arrays do their own checking on this property
  282.                     if (instance.getType() === "object") {
  283.                         additionalProperties = schema.getAttribute("additionalProperties");
  284.                         propertySchemas = schema.getAttribute("properties") || {};
  285.                         properties = instance.getProperties();
  286.                         for (key in properties) {
  287.                             if (properties[key] !== O[key] && properties[key] && !propertySchemas[key]) {
  288.                                 if (JSV.isJSONSchema(additionalProperties)) {
  289.                                     additionalProperties.validate(properties[key], report, instance, schema, key);
  290.                                 } else if (additionalProperties === false) {
  291.                                     report.addError(instance, schema, "additionalProperties", "Additional properties are not allowed", additionalProperties);
  292.                                 }
  293.                             }
  294.                         }
  295.                     }
  296.                 }
  297.             },
  298.            
  299.             "requires" : {
  300.                 "type" : ["string", {"$ref" : "#"}],
  301.                 "optional" : true,
  302.                
  303.                 "parser" : function (instance, self) {
  304.                     if (instance.getType() === "string") {
  305.                         return instance.getValue();
  306.                     } else if (instance.getType() === "object") {
  307.                         return instance.getEnvironment().createSchema(instance, self.getEnvironment().findSchema(self.resolveURI("#")));
  308.                     }
  309.                 },
  310.                
  311.                 "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  312.                     var requires;
  313.                     if (instance.getType() !== "undefined" && parent && parent.getType() !== "undefined") {
  314.                         requires = schema.getAttribute("requires");
  315.                         if (typeof requires === "string") {
  316.                             if (parent.getProperty(requires).getType() === "undefined") {
  317.                                 report.addError(instance, schema, "requires", 'Property requires sibling property "' + requires + '"', requires);
  318.                             }
  319.                         } else if (JSV.isJSONSchema(requires)) {
  320.                             requires.validate(parent, report);  //WATCH: A "requires" schema does not support the "requires" attribute
  321.                         }
  322.                     }
  323.                 }
  324.             },
  325.            
  326.             "minimum" : {
  327.                 "type" : "number",
  328.                 "optional" : true,
  329.                
  330.                 "parser" : function (instance, self) {
  331.                     if (instance.getType() === "number") {
  332.                         return instance.getValue();
  333.                     }
  334.                 },
  335.                
  336.                 "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  337.                     var minimum, minimumCanEqual;
  338.                     if (instance.getType() === "number") {
  339.                         minimum = schema.getAttribute("minimum");
  340.                         minimumCanEqual = schema.getAttribute("minimumCanEqual");
  341.                         if (typeof minimum === "number" && (instance.getValue() < minimum || (minimumCanEqual === false && instance.getValue() === minimum))) {
  342.                             report.addError(instance, schema, "minimum", "Number is less than the required minimum value", minimum);
  343.                         }
  344.                     }
  345.                 }
  346.             },
  347.            
  348.             "maximum" : {
  349.                 "type" : "number",
  350.                 "optional" : true,
  351.                
  352.                 "parser" : function (instance, self) {
  353.                     if (instance.getType() === "number") {
  354.                         return instance.getValue();
  355.                     }
  356.                 },
  357.                
  358.                 "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  359.                     var maximum, maximumCanEqual;
  360.                     if (instance.getType() === "number") {
  361.                         maximum = schema.getAttribute("maximum");
  362.                         maximumCanEqual = schema.getAttribute("maximumCanEqual");
  363.                         if (typeof maximum === "number" && (instance.getValue() > maximum || (maximumCanEqual === false && instance.getValue() === maximum))) {
  364.                             report.addError(instance, schema, "maximum", "Number is greater than the required maximum value", maximum);
  365.                         }
  366.                     }
  367.                 }
  368.             },
  369.            
  370.             "minimumCanEqual" : {
  371.                 "type" : "boolean",
  372.                 "optional" : true,
  373.                 "requires" : "minimum",
  374.                 "default" : true,
  375.                
  376.                 "parser" : function (instance, self) {
  377.                     if (instance.getType() === "boolean") {
  378.                         return instance.getValue();
  379.                     }
  380.                     //else
  381.                     return true;
  382.                 }
  383.             },
  384.            
  385.             "maximumCanEqual" : {
  386.                 "type" : "boolean",
  387.                 "optional" : true,
  388.                 "requires" : "maximum",
  389.                 "default" : true,
  390.                
  391.                 "parser" : function (instance, self) {
  392.                     if (instance.getType() === "boolean") {
  393.                         return instance.getValue();
  394.                     }
  395.                     //else
  396.                     return true;
  397.                 }
  398.             },
  399.            
  400.             "minItems" : {
  401.                 "type" : "integer",
  402.                 "optional" : true,
  403.                 "minimum" : 0,
  404.                 "default" : 0,
  405.                
  406.                 "parser" : function (instance, self) {
  407.                     if (instance.getType() === "number") {
  408.                         return instance.getValue();
  409.                     }
  410.                     //else
  411.                     return 0;
  412.                 },
  413.                
  414.                 "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  415.                     var minItems;
  416.                     if (instance.getType() === "array") {
  417.                         minItems = schema.getAttribute("minItems");
  418.                         if (typeof minItems === "number" && instance.getProperties().length < minItems) {
  419.                             report.addError(instance, schema, "minItems", "The number of items is less than the required minimum", minItems);
  420.                         }
  421.                     }
  422.                 }
  423.             },
  424.            
  425.             "maxItems" : {
  426.                 "type" : "integer",
  427.                 "optional" : true,
  428.                 "minimum" : 0,
  429.                
  430.                 "parser" : function (instance, self) {
  431.                     if (instance.getType() === "number") {
  432.                         return instance.getValue();
  433.                     }
  434.                 },
  435.                
  436.                 "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  437.                     var maxItems;
  438.                     if (instance.getType() === "array") {
  439.                         maxItems = schema.getAttribute("maxItems");
  440.                         if (typeof maxItems === "number" && instance.getProperties().length > maxItems) {
  441.                             report.addError(instance, schema, "maxItems", "The number of items is greater than the required maximum", maxItems);
  442.                         }
  443.                     }
  444.                 }
  445.             },
  446.            
  447.             "pattern" : {
  448.                 "type" : "string",
  449.                 "optional" : true,
  450.                 "format" : "regex",
  451.                
  452.                 "parser" : function (instance, self) {
  453.                     if (instance.getType() === "string") {
  454.                         return instance.getValue();
  455.                     }
  456.                 },
  457.                
  458.                 "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  459.                     var pattern;
  460.                     try {
  461.                         pattern = new RegExp(schema.getAttribute("pattern"));
  462.                         if (instance.getType() === "string" && pattern && !pattern.test(instance.getValue())) {
  463.                             report.addError(instance, schema, "pattern", "String does not match pattern", pattern.toString());
  464.                         }
  465.                     } catch (e) {
  466.                         report.addError(instance, schema, "pattern", "Invalid pattern", e);
  467.                     }
  468.                 }
  469.             },
  470.            
  471.             "minLength" : {
  472.                 "type" : "integer",
  473.                 "optional" : true,
  474.                 "minimum" : 0,
  475.                 "default" : 0,
  476.                
  477.                 "parser" : function (instance, self) {
  478.                     if (instance.getType() === "number") {
  479.                         return instance.getValue();
  480.                     }
  481.                     //else
  482.                     return 0;
  483.                 },
  484.                
  485.                 "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  486.                     var minLength;
  487.                     if (instance.getType() === "string") {
  488.                         minLength = schema.getAttribute("minLength");
  489.                         if (typeof minLength === "number" && instance.getValue().length < minLength) {
  490.                             report.addError(instance, schema, "minLength", "String is less than the required minimum length", minLength);
  491.                         }
  492.                     }
  493.                 }
  494.             },
  495.            
  496.             "maxLength" : {
  497.                 "type" : "integer",
  498.                 "optional" : true,
  499.                
  500.                 "parser" : function (instance, self) {
  501.                     if (instance.getType() === "number") {
  502.                         return instance.getValue();
  503.                     }
  504.                 },
  505.                
  506.                 "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  507.                     var maxLength;
  508.                     if (instance.getType() === "string") {
  509.                         maxLength = schema.getAttribute("maxLength");
  510.                         if (typeof maxLength === "number" && instance.getValue().length > maxLength) {
  511.                             report.addError(instance, schema, "maxLength", "String is greater than the required maximum length", maxLength);
  512.                         }
  513.                     }
  514.                 }
  515.             },
  516.            
  517.             "enum" : {
  518.                 "type" : "array",
  519.                 "optional" : true,
  520.                 "minItems" : 1,
  521.                 "uniqueItems" : true,
  522.                
  523.                 "parser" : function (instance, self) {
  524.                     if (instance.getType() === "array") {
  525.                         return instance.getValue();
  526.                     }
  527.                 },
  528.                
  529.                 "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  530.                     var enums, x, xl;
  531.                     if (instance.getType() !== "undefined") {
  532.                         enums = schema.getAttribute("enum");
  533.                         if (enums) {
  534.                             for (x = 0, xl = enums.length; x < xl; ++x) {
  535.                                 if (instance.equals(enums[x])) {
  536.                                     return true;
  537.                                 }
  538.                             }
  539.                             report.addError(instance, schema, "enum", "Instance is not one of the possible values", enums);
  540.                         }
  541.                     }
  542.                 }
  543.             },
  544.            
  545.             "title" : {
  546.                 "type" : "string",
  547.                 "optional" : true
  548.             },
  549.            
  550.             "description" : {
  551.                 "type" : "string",
  552.                 "optional" : true
  553.             },
  554.            
  555.             "format" : {
  556.                 "type" : "string",
  557.                 "optional" : true,
  558.                
  559.                 "parser" : function (instance, self) {
  560.                     if (instance.getType() === "string") {
  561.                         return instance.getValue();
  562.                     }
  563.                 },
  564.                
  565.                 "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  566.                     var format, formatValidators;
  567.                     if (instance.getType() === "string") {
  568.                         format = schema.getAttribute("format");
  569.                         formatValidators = self.getValueOfProperty("formatValidators");
  570.                         if (typeof format === "string" && formatValidators[format] !== O[format] && typeof formatValidators[format] === "function" && !formatValidators[format].call(this, instance, report)) {
  571.                             report.addError(instance, schema, "format", "String is not in the required format", format);
  572.                         }
  573.                     }
  574.                 },
  575.                
  576.                 "formatValidators" : {}
  577.             },
  578.            
  579.             "contentEncoding" : {
  580.                 "type" : "string",
  581.                 "optional" : true
  582.             },
  583.            
  584.             "default" : {
  585.                 "type" : "any",
  586.                 "optional" : true
  587.             },
  588.            
  589.             "maxDecimal" : {
  590.                 "type" : "integer",
  591.                 "optional" : true,
  592.                 "minimum" : 0,
  593.                                
  594.                 "parser" : function (instance, self) {
  595.                     if (instance.getType() === "number") {
  596.                         return instance.getValue();
  597.                     }
  598.                 },
  599.                
  600.                 "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  601.                     var maxDecimal, decimals;
  602.                     if (instance.getType() === "number") {
  603.                         maxDecimal = schema.getAttribute("maxDecimal");
  604.                         if (typeof maxDecimal === "number") {
  605.                             decimals = instance.getValue().toString(10).split('.')[1];
  606.                             if (decimals && decimals.length > maxDecimal) {
  607.                                 report.addError(instance, schema, "maxDecimal", "The number of decimal places is greater than the allowed maximum", maxDecimal);
  608.                             }
  609.                         }
  610.                     }
  611.                 }
  612.             },
  613.            
  614.             "disallow" : {
  615.                 "type" : ["string", "array"],
  616.                 "items" : {"type" : "string"},
  617.                 "optional" : true,
  618.                 "uniqueItems" : true,
  619.                
  620.                 "parser" : function (instance, self) {
  621.                     if (instance.getType() === "string" || instance.getType() === "array") {
  622.                         return instance.getValue();
  623.                     }
  624.                 },
  625.                
  626.                 "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  627.                     var disallowedTypes = JSV.toArray(schema.getAttribute("disallow")),
  628.                         x, xl, key, typeValidators;
  629.                    
  630.                     //for instances that are required to be a certain type
  631.                     if (instance.getType() !== "undefined" && disallowedTypes && disallowedTypes.length) {
  632.                         typeValidators = self.getValueOfProperty("typeValidators") || {};
  633.                        
  634.                         //ensure that type matches for at least one of the required types
  635.                         for (x = 0, xl = disallowedTypes.length; x < xl; ++x) {
  636.                             key = disallowedTypes[x];
  637.                             if (typeValidators[key] !== O[key] && typeof typeValidators[key] === "function") {
  638.                                 if (typeValidators[key](instance, report)) {
  639.                                     report.addError(instance, schema, "disallow", "Instance is a disallowed type", disallowedTypes);
  640.                                     return 8;
  641.                                 }
  642.                             }
  643.                             /*
  644.                             else {
  645.                                 report.addError(instance, schema, "disallow", "Instance may be a disallowed type", disallowedTypes);
  646.                                 return false;
  647.                             }
  648.                             */
  649.                         }
  650.                        
  651.                         //if we get to this point, type is valid
  652.                         return true;
  653.                     }
  654.                     //else, everything is allowed if no disallowed types are specified
  655.                     return true;
  656.                 },
  657.                
  658.                 "typeValidators" : TYPE_VALIDATORS
  659.             },
  660.        
  661.             "extends" : {
  662.                 "type" : [{"$ref" : "#"}, "array"],
  663.                 "items" : {"$ref" : "#"},
  664.                 "optional" : true,
  665.                 "default" : {},
  666.                
  667.                 "parser" : function (instance, self) {
  668.                     if (instance.getType() === "object") {
  669.                         return instance.getEnvironment().createSchema(instance, self.getEnvironment().findSchema(self.resolveURI("#")));
  670.                     } else if (instance.getType() === "array") {
  671.                         return JSV.mapArray(instance.getProperties(), function (instance) {
  672.                             return instance.getEnvironment().createSchema(instance, self.getEnvironment().findSchema(self.resolveURI("#")));
  673.                         });
  674.                     }
  675.                 },
  676.                
  677.                 "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  678.                     var extensions = schema.getAttribute("extends"), x, xl;
  679.                     if (extensions) {
  680.                         if (JSV.isJSONSchema(extensions)) {
  681.                             extensions.validate(instance, report, parent, parentSchema, name);
  682.                         } else if (JSV.typeOf(extensions) === "array") {
  683.                             for (x = 0, xl = extensions.length; x < xl; ++x) {
  684.                                 extensions[x].validate(instance, report, parent, parentSchema, name);
  685.                             }
  686.                         }
  687.                     }
  688.                 }
  689.             }
  690.         },
  691.        
  692.         "optional" : true,
  693.         "default" : {},
  694.         "fragmentResolution" : "dot-delimited",
  695.        
  696.         "parser" : function (instance, self) {
  697.             if (instance.getType() === "object") {
  698.                 return instance.getEnvironment().createSchema(instance, self);
  699.             }
  700.         },
  701.        
  702.         "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  703.             var propNames = schema.getPropertyNames(),
  704.                 x, xl,
  705.                 attributeSchemas = self.getAttribute("properties"),
  706.                 validator;
  707.            
  708.             for (x in attributeSchemas) {
  709.                 if (attributeSchemas[x] !== O[x] && attributeSchemas[x].getValueOfProperty("validationRequired")) {
  710.                     JSV.pushUnique(propNames, x);
  711.                 }
  712.             }
  713.            
  714.             for (x = 0, xl = propNames.length; x < xl; ++x) {
  715.                 if (attributeSchemas[propNames[x]] !== O[propNames[x]]) {
  716.                     validator = attributeSchemas[propNames[x]].getValueOfProperty("validator");
  717.                     if (typeof validator === "function") {
  718.                         validator(instance, schema, attributeSchemas[propNames[x]], report, parent, parentSchema, name);
  719.                     }
  720.                 }
  721.             }
  722.         },
  723.                
  724.         "initializer" : function (instance) {
  725.             var link, extension, extended;
  726.            
  727.             //if there is a link to a different schema, set reference
  728.             link = instance._schema.getLink("describedby", instance);
  729.             if (link && instance._schema._uri !== link) {
  730.                 instance.setReference("describedby", link);
  731.             }
  732.            
  733.             //if instance has a URI link to itself, update it's own URI
  734.             link = instance._schema.getLink("self", instance);
  735.             if (JSV.typeOf(link) === "string") {
  736.                 instance._uri = JSV.formatURI(link);
  737.             }
  738.            
  739.             //if there is a link to the full representation, set reference
  740.             link = instance._schema.getLink("full", instance);
  741.             if (link && instance._uri !== link) {
  742.                 instance.setReference("full", link);
  743.             }
  744.            
  745.             //extend schema
  746.             extension = instance.getAttribute("extends");
  747.             if (JSV.isJSONSchema(extension)) {
  748.                 extended = JSV.inherits(extension, instance, true);
  749.                 instance = instance._env.createSchema(extended, instance._schema, instance._uri);
  750.             }
  751.            
  752.             return instance;
  753.         }
  754.     }, true, "http://json-schema.org/schema#");
  755.    
  756.     HYPERSCHEMA = ENVIRONMENT.createSchema(JSV.inherits(SCHEMA, ENVIRONMENT.createSchema({
  757.         "$schema" : "http://json-schema.org/hyper-schema#",
  758.         "id" : "http://json-schema.org/hyper-schema#",
  759.    
  760.         "properties" : {
  761.             "links" : {
  762.                 "type" : "array",
  763.                 "items" : {"$ref" : "links#"},
  764.                 "optional" : true,
  765.                
  766.                 "parser" : function (instance, self, arg) {
  767.                     var links,
  768.                         linkSchemaURI = self.getValueOfProperty("items")["$ref"],
  769.                         linkSchema = self.getEnvironment().findSchema(linkSchemaURI),
  770.                         linkParser = linkSchema && linkSchema.getValueOfProperty("parser");
  771.                     arg = JSV.toArray(arg);
  772.                    
  773.                     if (typeof linkParser === "function") {
  774.                         links = JSV.mapArray(instance.getProperties(), function (link) {
  775.                             return linkParser(link, linkSchema);
  776.                         });
  777.                     } else {
  778.                         links = JSV.toArray(instance.getValue());
  779.                     }
  780.                    
  781.                     if (arg[0]) {
  782.                         links = JSV.filterArray(links, function (link) {
  783.                             return link["rel"] === arg[0];
  784.                         });
  785.                     }
  786.                    
  787.                     if (arg[1]) {
  788.                         links = JSV.mapArray(links, function (link) {
  789.                             var instance = arg[1],
  790.                                 href = link["href"];
  791.                             href = href.replace(/\{(.+)\}/g, function (str, p1, offset, s) {
  792.                                 var value;
  793.                                 if (p1 === "-this") {
  794.                                     value = instance.getValue();
  795.                                 } else {
  796.                                     value = instance.getValueOfProperty(p1);
  797.                                 }
  798.                                 return value !== undefined ? String(value) : "";
  799.                             });
  800.                             return href ? JSV.formatURI(instance.resolveURI(href)) : href;
  801.                         });
  802.                     }
  803.                    
  804.                     return links;
  805.                 }
  806.             },
  807.            
  808.             "fragmentResolution" : {
  809.                 "type" : "string",
  810.                 "optional" : true,
  811.                 "default" : "dot-delimited"
  812.             },
  813.            
  814.             "root" : {
  815.                 "type" : "boolean",
  816.                 "optional" : true,
  817.                 "default" : false
  818.             },
  819.            
  820.             "readonly" : {
  821.                 "type" : "boolean",
  822.                 "optional" : true,
  823.                 "default" : false
  824.             },
  825.            
  826.             "pathStart" : {
  827.                 "type" : "string",
  828.                 "optional" : true,
  829.                 "format" : "uri",
  830.                
  831.                 "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  832.                     var pathStart;
  833.                     if (instance.getType() !== "undefined") {
  834.                         pathStart = schema.getAttribute("pathStart");
  835.                         if (typeof pathStart === "string") {
  836.                             //TODO: Find out what pathStart is relative to
  837.                             if (instance.getURI().indexOf(pathStart) !== 0) {
  838.                                 report.addError(instance, schema, "pathStart", "Instance's URI does not start with " + pathStart, pathStart);
  839.                             }
  840.                         }
  841.                     }
  842.                 }
  843.             },
  844.            
  845.             "mediaType" : {
  846.                 "type" : "string",
  847.                 "optional" : true,
  848.                 "format" : "media-type"
  849.             },
  850.            
  851.             "alternate" : {
  852.                 "type" : "array",
  853.                 "items" : {"$ref" : "#"},
  854.                 "optional" : true
  855.             }
  856.         },
  857.        
  858.         "links" : [
  859.             {
  860.                 "href" : "{$ref}",
  861.                 "rel" : "full"
  862.             },
  863.            
  864.             {
  865.                 "href" : "{$schema}",
  866.                 "rel" : "describedby"
  867.             },
  868.            
  869.             {
  870.                 "href" : "{id}",
  871.                 "rel" : "self"
  872.             }
  873.         ]//,
  874.        
  875.         //not needed as JSV.inherits does the job for us
  876.         //"extends" : {"$ref" : "http://json-schema.org/schema#"}
  877.     }, SCHEMA), true), true, "http://json-schema.org/hyper-schema#");
  878.    
  879.     ENVIRONMENT.setOption("defaultSchemaURI", "http://json-schema.org/hyper-schema#");
  880.    
  881.     LINKS = ENVIRONMENT.createSchema({
  882.         "$schema" : "http://json-schema.org/hyper-schema#",
  883.         "id" : "http://json-schema.org/links#",
  884.         "type" : "object",
  885.        
  886.         "properties" : {
  887.             "href" : {
  888.                 "type" : "string"
  889.             },
  890.            
  891.             "rel" : {
  892.                 "type" : "string"
  893.             },
  894.            
  895.             "method" : {
  896.                 "type" : "string",
  897.                 "default" : "GET",
  898.                 "optional" : true
  899.             },
  900.            
  901.             "enctype" : {
  902.                 "type" : "string",
  903.                 "requires" : "method",
  904.                 "optional" : true
  905.             },
  906.            
  907.             "properties" : {
  908.                 "type" : "object",
  909.                 "additionalProperties" : {"$ref" : "hyper-schema#"},
  910.                 "optional" : true,
  911.                
  912.                 "parser" : function (instance, self, arg) {
  913.                     var env = instance.getEnvironment(),
  914.                         selfEnv = self.getEnvironment(),
  915.                         additionalPropertiesSchemaURI = self.getValueOfProperty("additionalProperties")["$ref"];
  916.                     if (instance.getType() === "object") {
  917.                         if (arg) {
  918.                             return env.createSchema(instance.getProperty(arg), selfEnv.findSchema(self.resolveURI(additionalPropertiesSchemaURI)));
  919.                         } else {
  920.                             return JSV.mapObject(instance.getProperties(), function (instance) {
  921.                                 return env.createSchema(instance, selfEnv.findSchema(self.resolveURI(additionalPropertiesSchemaURI)));
  922.                             });
  923.                         }
  924.                     }
  925.                 }
  926.             }
  927.         },
  928.        
  929.         "parser" : function (instance, self) {
  930.             var selfProperties = self.getProperty("properties");
  931.             if (instance.getType() === "object") {
  932.                 return JSV.mapObject(instance.getProperties(), function (property, key) {
  933.                     var propertySchema = selfProperties.getProperty(key),
  934.                         parser = propertySchema && propertySchema.getValueOfProperty("parser");
  935.                     if (typeof parser === "function") {
  936.                         return parser(property, propertySchema);
  937.                     }
  938.                     //else
  939.                     return property.getValue();
  940.                 });
  941.             }
  942.             return instance.getValue();
  943.         }
  944.     }, HYPERSCHEMA, "http://json-schema.org/links#");
  945.    
  946.     JSV.registerEnvironment("json-schema-draft-00", ENVIRONMENT);
  947.     JSV.registerEnvironment("json-schema-draft-01", JSV.createEnvironment("json-schema-draft-00"));
  948.    
  949.     if (!JSV.getDefaultEnvironmentID()) {
  950.         JSV.setDefaultEnvironmentID("json-schema-draft-01");
  951.     }
  952.    
  953. }());
  954.  
  955. /////////////////////////////////////////////////////////////////////////////////////////////////////////
  956.  
  957. /**
  958.  * json-schema-draft-02 Environment
  959.  *
  960.  * @fileOverview Implementation of the second revision of the JSON Schema specification draft.
  961.  * @author <a href="mailto:gary.court@gmail.com">Gary Court</a>
  962.  * @version 1.7.1
  963.  * @see http://github.com/garycourt/JSV
  964.  */
  965.  
  966. /*
  967.  * Copyright 2010 Gary Court. All rights reserved.
  968.  *
  969.  * Redistribution and use in source and binary forms, with or without modification, are
  970.  * permitted provided that the following conditions are met:
  971.  *
  972.  *    1. Redistributions of source code must retain the above copyright notice, this list of
  973.  *       conditions and the following disclaimer.
  974.  *
  975.  *    2. Redistributions in binary form must reproduce the above copyright notice, this list
  976.  *       of conditions and the following disclaimer in the documentation and/or other materials
  977.  *       provided with the distribution.
  978.  *
  979.  * THIS SOFTWARE IS PROVIDED BY GARY COURT ``AS IS'' AND ANY EXPRESS OR IMPLIED
  980.  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  981.  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GARY COURT OR
  982.  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  983.  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  984.  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  985.  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  986.  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  987.  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  988.  *
  989.  * The views and conclusions contained in the software and documentation are those of the
  990.  * authors and should not be interpreted as representing official policies, either expressed
  991.  * or implied, of Gary Court or the JSON Schema specification.
  992.  */
  993.  
  994. /*jslint white: true, sub: true, onevar: true, undef: true, eqeqeq: true, newcap: true, immed: true, indent: 4 */
  995. /*global require */
  996.  
  997. (function () {
  998.     var O = {},
  999.         JSV = require('./jsv').JSV,
  1000.         ENVIRONMENT,
  1001.         TYPE_VALIDATORS,
  1002.         SCHEMA,
  1003.         HYPERSCHEMA,
  1004.         LINKS;
  1005.    
  1006.     TYPE_VALIDATORS = {
  1007.         "string" : function (instance, report) {
  1008.             return instance.getType() === "string";
  1009.         },
  1010.        
  1011.         "number" : function (instance, report) {
  1012.             return instance.getType() === "number";
  1013.         },
  1014.        
  1015.         "integer" : function (instance, report) {
  1016.             return instance.getType() === "number" && instance.getValue() % 1 === 0;
  1017.         },
  1018.        
  1019.         "boolean" : function (instance, report) {
  1020.             return instance.getType() === "boolean";
  1021.         },
  1022.        
  1023.         "object" : function (instance, report) {
  1024.             return instance.getType() === "object";
  1025.         },
  1026.        
  1027.         "array" : function (instance, report) {
  1028.             return instance.getType() === "array";
  1029.         },
  1030.        
  1031.         "null" : function (instance, report) {
  1032.             return instance.getType() === "null";
  1033.         },
  1034.        
  1035.         "any" : function (instance, report) {
  1036.             return true;
  1037.         }
  1038.     };
  1039.    
  1040.     ENVIRONMENT = new JSV.Environment();
  1041.     ENVIRONMENT.setOption("defaultFragmentDelimiter", "/");
  1042.     ENVIRONMENT.setOption("defaultSchemaURI", "http://json-schema.org/schema#");  //updated later
  1043.    
  1044.     SCHEMA = ENVIRONMENT.createSchema({
  1045.         "$schema" : "http://json-schema.org/hyper-schema#",
  1046.         "id" : "http://json-schema.org/schema#",
  1047.         "type" : "object",
  1048.        
  1049.         "properties" : {
  1050.             "type" : {
  1051.                 "type" : ["string", "array"],
  1052.                 "items" : {
  1053.                     "type" : ["string", {"$ref" : "#"}]
  1054.                 },
  1055.                 "optional" : true,
  1056.                 "uniqueItems" : true,
  1057.                 "default" : "any",
  1058.                
  1059.                 "parser" : function (instance, self) {
  1060.                     var parser;
  1061.                    
  1062.                     if (instance.getType() === "string") {
  1063.                         return instance.getValue();
  1064.                     } else if (instance.getType() === "object") {
  1065.                         return instance.getEnvironment().createSchema(
  1066.                             instance,
  1067.                             self.getEnvironment().findSchema(self.resolveURI("#"))
  1068.                         );
  1069.                     } else if (instance.getType() === "array") {
  1070.                         parser = self.getValueOfProperty("parser");
  1071.                         return JSV.mapArray(instance.getProperties(), function (prop) {
  1072.                             return parser(prop, self);
  1073.                         });
  1074.                     }
  1075.                     //else
  1076.                     return "any";
  1077.                 },
  1078.            
  1079.                 "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  1080.                     var requiredTypes = JSV.toArray(schema.getAttribute("type")),
  1081.                         x, xl, type, subreport, typeValidators;
  1082.                    
  1083.                     //for instances that are required to be a certain type
  1084.                     if (instance.getType() !== "undefined" && requiredTypes && requiredTypes.length) {
  1085.                         typeValidators = self.getValueOfProperty("typeValidators") || {};
  1086.                        
  1087.                         //ensure that type matches for at least one of the required types
  1088.                         for (x = 0, xl = requiredTypes.length; x < xl; ++x) {
  1089.                             type = requiredTypes[x];
  1090.                             if (JSV.isJSONSchema(type)) {
  1091.                                 subreport = JSV.createObject(report);
  1092.                                 subreport.errors = [];
  1093.                                 subreport.validated = JSV.clone(report.validated);
  1094.                                 if (type.validate(instance, subreport, parent, parentSchema, name).errors.length === 0) {
  1095.                                     return true;  //instance matches this schema
  1096.                                 }
  1097.                             } else {
  1098.                                 if (typeValidators[type] !== O[type] && typeof typeValidators[type] === "function") {
  1099.                                     if (typeValidators[type](instance, report)) {
  1100.                                         return true;  //type is valid
  1101.                                     }
  1102.                                 } else {
  1103.                                     return true;  //unknown types are assumed valid
  1104.                                 }
  1105.                             }
  1106.                         }
  1107.                        
  1108.                         //if we get to this point, type is invalid
  1109.                         report.addError(instance, schema, "type", "Instance is not a required type", requiredTypes);
  1110.                         return false;
  1111.                     }
  1112.                     //else, anything is allowed if no type is specified
  1113.                     return true;
  1114.                 },
  1115.                
  1116.                 "typeValidators" : TYPE_VALIDATORS
  1117.             },
  1118.            
  1119.             "properties" : {
  1120.                 "type" : "object",
  1121.                 "additionalProperties" : {"$ref" : "#"},
  1122.                 "optional" : true,
  1123.                 "default" : {},
  1124.                
  1125.                 "parser" : function (instance, self, arg) {
  1126.                     var env = instance.getEnvironment(),
  1127.                         selfEnv = self.getEnvironment();
  1128.                     if (instance.getType() === "object") {
  1129.                         if (arg) {
  1130.                             return env.createSchema(instance.getProperty(arg), selfEnv.findSchema(self.resolveURI("#")));
  1131.                         } else {
  1132.                             return JSV.mapObject(instance.getProperties(), function (instance) {
  1133.                                 return env.createSchema(instance, selfEnv.findSchema(self.resolveURI("#")));
  1134.                             });
  1135.                         }
  1136.                     }
  1137.                     //else
  1138.                     return {};
  1139.                 },
  1140.                
  1141.                 "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  1142.                     var propertySchemas, key;
  1143.                     //this attribute is for object type instances only
  1144.                     if (instance.getType() === "object") {
  1145.                         //for each property defined in the schema
  1146.                         propertySchemas = schema.getAttribute("properties");
  1147.                         for (key in propertySchemas) {
  1148.                             if (propertySchemas[key] !== O[key] && propertySchemas[key]) {
  1149.                                 //ensure that instance property is valid
  1150.                                 propertySchemas[key].validate(instance.getProperty(key), report, instance, schema, key);
  1151.                             }
  1152.                         }
  1153.                     }
  1154.                 }
  1155.             },
  1156.            
  1157.             "items" : {
  1158.                 "type" : [{"$ref" : "#"}, "array"],
  1159.                 "items" : {"$ref" : "#"},
  1160.                 "optional" : true,
  1161.                 "default" : {},
  1162.                
  1163.                 "parser" : function (instance, self) {
  1164.                     if (instance.getType() === "object") {
  1165.                         return instance.getEnvironment().createSchema(instance, self.getEnvironment().findSchema(self.resolveURI("#")));
  1166.                     } else if (instance.getType() === "array") {
  1167.                         return JSV.mapArray(instance.getProperties(), function (instance) {
  1168.                             return instance.getEnvironment().createSchema(instance, self.getEnvironment().findSchema(self.resolveURI("#")));
  1169.                         });
  1170.                     }
  1171.                     //else
  1172.                     return instance.getEnvironment().createEmptySchema();
  1173.                 },
  1174.                
  1175.                 "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  1176.                     var properties, items, x, xl, itemSchema, additionalProperties;
  1177.                    
  1178.                     if (instance.getType() === "array") {
  1179.                         properties = instance.getProperties();
  1180.                         items = schema.getAttribute("items");
  1181.                         additionalProperties = schema.getAttribute("additionalProperties");
  1182.                        
  1183.                         if (JSV.typeOf(items) === "array") {
  1184.                             for (x = 0, xl = properties.length; x < xl; ++x) {
  1185.                                 itemSchema = items[x] || additionalProperties;
  1186.                                 if (itemSchema !== false) {
  1187.                                     itemSchema.validate(properties[x], report, instance, schema, x);
  1188.                                 } else {
  1189.                                     report.addError(instance, schema, "additionalProperties", "Additional items are not allowed", itemSchema);
  1190.                                 }
  1191.                             }
  1192.                         } else {
  1193.                             itemSchema = items || additionalProperties;
  1194.                             for (x = 0, xl = properties.length; x < xl; ++x) {
  1195.                                 itemSchema.validate(properties[x], report, instance, schema, x);
  1196.                             }
  1197.                         }
  1198.                     }
  1199.                 }
  1200.             },
  1201.            
  1202.             "optional" : {
  1203.                 "type" : "boolean",
  1204.                 "optional" : true,
  1205.                 "default" : false,
  1206.                
  1207.                 "parser" : function (instance, self) {
  1208.                     return !!instance.getValue();
  1209.                 },
  1210.                
  1211.                 "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  1212.                     if (instance.getType() === "undefined" && !schema.getAttribute("optional")) {
  1213.                         report.addError(instance, schema, "optional", "Property is required", false);
  1214.                     }
  1215.                 },
  1216.                
  1217.                 "validationRequired" : true
  1218.             },
  1219.            
  1220.             "additionalProperties" : {
  1221.                 "type" : [{"$ref" : "#"}, "boolean"],
  1222.                 "optional" : true,
  1223.                 "default" : {},
  1224.                
  1225.                 "parser" : function (instance, self) {
  1226.                     if (instance.getType() === "object") {
  1227.                         return instance.getEnvironment().createSchema(instance, self.getEnvironment().findSchema(self.resolveURI("#")));
  1228.                     } else if (instance.getType() === "boolean" && instance.getValue() === false) {
  1229.                         return false;
  1230.                     }
  1231.                     //else
  1232.                     return instance.getEnvironment().createEmptySchema();
  1233.                 },
  1234.                
  1235.                 "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  1236.                     var additionalProperties, propertySchemas, properties, key;
  1237.                     //we only need to check against object types as arrays do their own checking on this property
  1238.                     if (instance.getType() === "object") {
  1239.                         additionalProperties = schema.getAttribute("additionalProperties");
  1240.                         propertySchemas = schema.getAttribute("properties") || {};
  1241.                         properties = instance.getProperties();
  1242.                         for (key in properties) {
  1243.                             if (properties[key] !== O[key] && properties[key] && !propertySchemas[key]) {
  1244.                                 if (JSV.isJSONSchema(additionalProperties)) {
  1245.                                     additionalProperties.validate(properties[key], report, instance, schema, key);
  1246.                                 } else if (additionalProperties === false) {
  1247.                                     report.addError(instance, schema, "additionalProperties", "Additional properties are not allowed", additionalProperties);
  1248.                                 }
  1249.                             }
  1250.                         }
  1251.                     }
  1252.                 }
  1253.             },
  1254.            
  1255.             "requires" : {
  1256.                 "type" : ["string", {"$ref" : "#"}],
  1257.                 "optional" : true,
  1258.                
  1259.                 "parser" : function (instance, self) {
  1260.                     if (instance.getType() === "string") {
  1261.                         return instance.getValue();
  1262.                     } else if (instance.getType() === "object") {
  1263.                         return instance.getEnvironment().createSchema(instance, self.getEnvironment().findSchema(self.resolveURI("#")));
  1264.                     }
  1265.                 },
  1266.                
  1267.                 "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  1268.                     var requires;
  1269.                     if (instance.getType() !== "undefined" && parent && parent.getType() !== "undefined") {
  1270.                         requires = schema.getAttribute("requires");
  1271.                         if (typeof requires === "string") {
  1272.                             if (parent.getProperty(requires).getType() === "undefined") {
  1273.                                 report.addError(instance, schema, "requires", 'Property requires sibling property "' + requires + '"', requires);
  1274.                             }
  1275.                         } else if (JSV.isJSONSchema(requires)) {
  1276.                             requires.validate(parent, report);  //WATCH: A "requires" schema does not support the "requires" attribute
  1277.                         }
  1278.                     }
  1279.                 }
  1280.             },
  1281.            
  1282.             "minimum" : {
  1283.                 "type" : "number",
  1284.                 "optional" : true,
  1285.                
  1286.                 "parser" : function (instance, self) {
  1287.                     if (instance.getType() === "number") {
  1288.                         return instance.getValue();
  1289.                     }
  1290.                 },
  1291.                
  1292.                 "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  1293.                     var minimum, minimumCanEqual;
  1294.                     if (instance.getType() === "number") {
  1295.                         minimum = schema.getAttribute("minimum");
  1296.                         minimumCanEqual = schema.getAttribute("minimumCanEqual");
  1297.                         if (typeof minimum === "number" && (instance.getValue() < minimum || (minimumCanEqual === false && instance.getValue() === minimum))) {
  1298.                             report.addError(instance, schema, "minimum", "Number is less than the required minimum value", minimum);
  1299.                         }
  1300.                     }
  1301.                 }
  1302.             },
  1303.            
  1304.             "maximum" : {
  1305.                 "type" : "number",
  1306.                 "optional" : true,
  1307.                
  1308.                 "parser" : function (instance, self) {
  1309.                     if (instance.getType() === "number") {
  1310.                         return instance.getValue();
  1311.                     }
  1312.                 },
  1313.                
  1314.                 "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  1315.                     var maximum, maximumCanEqual;
  1316.                     if (instance.getType() === "number") {
  1317.                         maximum = schema.getAttribute("maximum");
  1318.                         maximumCanEqual = schema.getAttribute("maximumCanEqual");
  1319.                         if (typeof maximum === "number" && (instance.getValue() > maximum || (maximumCanEqual === false && instance.getValue() === maximum))) {
  1320.                             report.addError(instance, schema, "maximum", "Number is greater than the required maximum value", maximum);
  1321.                         }
  1322.                     }
  1323.                 }
  1324.             },
  1325.            
  1326.             "minimumCanEqual" : {
  1327.                 "type" : "boolean",
  1328.                 "optional" : true,
  1329.                 "requires" : "minimum",
  1330.                 "default" : true,
  1331.                
  1332.                 "parser" : function (instance, self) {
  1333.                     if (instance.getType() === "boolean") {
  1334.                         return instance.getValue();
  1335.                     }
  1336.                     //else
  1337.                     return true;
  1338.                 }
  1339.             },
  1340.            
  1341.             "maximumCanEqual" : {
  1342.                 "type" : "boolean",
  1343.                 "optional" : true,
  1344.                 "requires" : "maximum",
  1345.                 "default" : true,
  1346.                
  1347.                 "parser" : function (instance, self) {
  1348.                     if (instance.getType() === "boolean") {
  1349.                         return instance.getValue();
  1350.                     }
  1351.                     //else
  1352.                     return true;
  1353.                 }
  1354.             },
  1355.            
  1356.             "minItems" : {
  1357.                 "type" : "integer",
  1358.                 "optional" : true,
  1359.                 "minimum" : 0,
  1360.                 "default" : 0,
  1361.                
  1362.                 "parser" : function (instance, self) {
  1363.                     if (instance.getType() === "number") {
  1364.                         return instance.getValue();
  1365.                     }
  1366.                     //else
  1367.                     return 0;
  1368.                 },
  1369.                
  1370.                 "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  1371.                     var minItems;
  1372.                     if (instance.getType() === "array") {
  1373.                         minItems = schema.getAttribute("minItems");
  1374.                         if (typeof minItems === "number" && instance.getProperties().length < minItems) {
  1375.                             report.addError(instance, schema, "minItems", "The number of items is less than the required minimum", minItems);
  1376.                         }
  1377.                     }
  1378.                 }
  1379.             },
  1380.            
  1381.             "maxItems" : {
  1382.                 "type" : "integer",
  1383.                 "optional" : true,
  1384.                 "minimum" : 0,
  1385.                
  1386.                 "parser" : function (instance, self) {
  1387.                     if (instance.getType() === "number") {
  1388.                         return instance.getValue();
  1389.                     }
  1390.                 },
  1391.                
  1392.                 "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  1393.                     var maxItems;
  1394.                     if (instance.getType() === "array") {
  1395.                         maxItems = schema.getAttribute("maxItems");
  1396.                         if (typeof maxItems === "number" && instance.getProperties().length > maxItems) {
  1397.                             report.addError(instance, schema, "maxItems", "The number of items is greater than the required maximum", maxItems);
  1398.                         }
  1399.                     }
  1400.                 }
  1401.             },
  1402.            
  1403.             "uniqueItems" : {
  1404.                 "type" : "boolean",
  1405.                 "optional" : true,
  1406.                 "default" : false,
  1407.                
  1408.                 "parser" : function (instance, self) {
  1409.                     return !!instance.getValue();
  1410.                 },
  1411.                
  1412.                 "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  1413.                     var value, x, xl, y, yl;
  1414.                     if (instance.getType() === "array" && schema.getAttribute("uniqueItems")) {
  1415.                         value = instance.getProperties();
  1416.                         for (x = 0, xl = value.length - 1; x < xl; ++x) {
  1417.                             for (y = x + 1, yl = value.length; y < yl; ++y) {
  1418.                                 if (value[x].equals(value[y])) {
  1419.                                     report.addError(instance, schema, "uniqueItems", "Array can only contain unique items", { x : x, y : y });
  1420.                                 }
  1421.                             }
  1422.                         }
  1423.                     }
  1424.                 }
  1425.             },
  1426.            
  1427.             "pattern" : {
  1428.                 "type" : "string",
  1429.                 "optional" : true,
  1430.                 "format" : "regex",
  1431.                
  1432.                 "parser" : function (instance, self) {
  1433.                     if (instance.getType() === "string") {
  1434.                         return instance.getValue();
  1435.                     }
  1436.                 },
  1437.                
  1438.                 "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  1439.                     var pattern;
  1440.                     try {
  1441.                         pattern = new RegExp(schema.getAttribute("pattern"));
  1442.                         if (instance.getType() === "string" && pattern && !pattern.test(instance.getValue())) {
  1443.                             report.addError(instance, schema, "pattern", "String does not match pattern", pattern.toString());
  1444.                         }
  1445.                     } catch (e) {
  1446.                         report.addError(instance, schema, "pattern", "Invalid pattern", e);
  1447.                     }
  1448.                 }
  1449.             },
  1450.            
  1451.             "minLength" : {
  1452.                 "type" : "integer",
  1453.                 "optional" : true,
  1454.                 "minimum" : 0,
  1455.                 "default" : 0,
  1456.                
  1457.                 "parser" : function (instance, self) {
  1458.                     if (instance.getType() === "number") {
  1459.                         return instance.getValue();
  1460.                     }
  1461.                     //else
  1462.                     return 0;
  1463.                 },
  1464.                
  1465.                 "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  1466.                     var minLength;
  1467.                     if (instance.getType() === "string") {
  1468.                         minLength = schema.getAttribute("minLength");
  1469.                         if (typeof minLength === "number" && instance.getValue().length < minLength) {
  1470.                             report.addError(instance, schema, "minLength", "String is less than the required minimum length", minLength);
  1471.                         }
  1472.                     }
  1473.                 }
  1474.             },
  1475.            
  1476.             "maxLength" : {
  1477.                 "type" : "integer",
  1478.                 "optional" : true,
  1479.                
  1480.                 "parser" : function (instance, self) {
  1481.                     if (instance.getType() === "number") {
  1482.                         return instance.getValue();
  1483.                     }
  1484.                 },
  1485.                
  1486.                 "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  1487.                     var maxLength;
  1488.                     if (instance.getType() === "string") {
  1489.                         maxLength = schema.getAttribute("maxLength");
  1490.                         if (typeof maxLength === "number" && instance.getValue().length > maxLength) {
  1491.                             report.addError(instance, schema, "maxLength", "String is greater than the required maximum length", maxLength);
  1492.                         }
  1493.                     }
  1494.                 }
  1495.             },
  1496.            
  1497.             "enum" : {
  1498.                 "type" : "array",
  1499.                 "optional" : true,
  1500.                 "minItems" : 1,
  1501.                 "uniqueItems" : true,
  1502.                
  1503.                 "parser" : function (instance, self) {
  1504.                     if (instance.getType() === "array") {
  1505.                         return instance.getValue();
  1506.                     }
  1507.                 },
  1508.                
  1509.                 "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  1510.                     var enums, x, xl;
  1511.                     if (instance.getType() !== "undefined") {
  1512.                         enums = schema.getAttribute("enum");
  1513.                         if (enums) {
  1514.                             for (x = 0, xl = enums.length; x < xl; ++x) {
  1515.                                 if (instance.equals(enums[x])) {
  1516.                                     return true;
  1517.                                 }
  1518.                             }
  1519.                             report.addError(instance, schema, "enum", "Instance is not one of the possible values", enums);
  1520.                         }
  1521.                     }
  1522.                 }
  1523.             },
  1524.            
  1525.             "title" : {
  1526.                 "type" : "string",
  1527.                 "optional" : true
  1528.             },
  1529.            
  1530.             "description" : {
  1531.                 "type" : "string",
  1532.                 "optional" : true
  1533.             },
  1534.            
  1535.             "format" : {
  1536.                 "type" : "string",
  1537.                 "optional" : true,
  1538.                
  1539.                 "parser" : function (instance, self) {
  1540.                     if (instance.getType() === "string") {
  1541.                         return instance.getValue();
  1542.                     }
  1543.                 },
  1544.                
  1545.                 "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  1546.                     var format, formatValidators;
  1547.                     if (instance.getType() === "string") {
  1548.                         format = schema.getAttribute("format");
  1549.                         formatValidators = self.getValueOfProperty("formatValidators");
  1550.                         if (typeof format === "string" && formatValidators[format] !== O[format] && typeof formatValidators[format] === "function" && !formatValidators[format].call(this, instance, report)) {
  1551.                             report.addError(instance, schema, "format", "String is not in the required format", format);
  1552.                         }
  1553.                     }
  1554.                 },
  1555.                
  1556.                 "formatValidators" : {}
  1557.             },
  1558.            
  1559.             "contentEncoding" : {
  1560.                 "type" : "string",
  1561.                 "optional" : true
  1562.             },
  1563.            
  1564.             "default" : {
  1565.                 "type" : "any",
  1566.                 "optional" : true
  1567.             },
  1568.            
  1569.             "divisibleBy" : {
  1570.                 "type" : "number",
  1571.                 "minimum" : 0,
  1572.                 "minimumCanEqual" : false,
  1573.                 "optional" : true,
  1574.                
  1575.                 "parser" : function (instance, self) {
  1576.                     if (instance.getType() === "number") {
  1577.                         return instance.getValue();
  1578.                     }
  1579.                 },
  1580.                
  1581.                 "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  1582.                     var divisor;
  1583.                     if (instance.getType() === "number") {
  1584.                         divisor = schema.getAttribute("divisibleBy");
  1585.                         if (divisor === 0) {
  1586.                             report.addError(instance, schema, "divisibleBy", "Nothing is divisible by 0", divisor);
  1587.                         } else if (divisor !== 1 && ((instance.getValue() / divisor) % 1) !== 0) {
  1588.                             report.addError(instance, schema, "divisibleBy", "Number is not divisible by " + divisor, divisor);
  1589.                         }
  1590.                     }
  1591.                 }
  1592.             },
  1593.            
  1594.             "disallow" : {
  1595.                 "type" : ["string", "array"],
  1596.                 "items" : {"type" : "string"},
  1597.                 "optional" : true,
  1598.                 "uniqueItems" : true,
  1599.                
  1600.                 "parser" : function (instance, self) {
  1601.                     if (instance.getType() === "string" || instance.getType() === "array") {
  1602.                         return instance.getValue();
  1603.                     }
  1604.                 },
  1605.                
  1606.                 "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  1607.                     var disallowedTypes = JSV.toArray(schema.getAttribute("disallow")),
  1608.                         x, xl, key, typeValidators;
  1609.                    
  1610.                     //for instances that are required to be a certain type
  1611.                     if (instance.getType() !== "undefined" && disallowedTypes && disallowedTypes.length) {
  1612.                         typeValidators = self.getValueOfProperty("typeValidators") || {};
  1613.                        
  1614.                         //ensure that type matches for at least one of the required types
  1615.                         for (x = 0, xl = disallowedTypes.length; x < xl; ++x) {
  1616.                             key = disallowedTypes[x];
  1617.                             if (typeValidators[key] !== O[key] && typeof typeValidators[key] === "function") {
  1618.                                 if (typeValidators[key](instance, report)) {
  1619.                                     report.addError(instance, schema, "disallow", "Instance is a disallowed type", disallowedTypes);
  1620.                                     return false;
  1621.                                 }
  1622.                             }
  1623.                             /*
  1624.                             else {
  1625.                                 report.addError(instance, schema, "disallow", "Instance may be a disallowed type", disallowedTypes);
  1626.                                 return false;
  1627.                             }
  1628.                             */
  1629.                         }
  1630.                        
  1631.                         //if we get to this point, type is valid
  1632.                         return true;
  1633.                     }
  1634.                     //else, everything is allowed if no disallowed types are specified
  1635.                     return true;
  1636.                 },
  1637.                
  1638.                 "typeValidators" : TYPE_VALIDATORS
  1639.             },
  1640.        
  1641.             "extends" : {
  1642.                 "type" : [{"$ref" : "#"}, "array"],
  1643.                 "items" : {"$ref" : "#"},
  1644.                 "optional" : true,
  1645.                 "default" : {},
  1646.                
  1647.                 "parser" : function (instance, self) {
  1648.                     if (instance.getType() === "object") {
  1649.                         return instance.getEnvironment().createSchema(instance, self.getEnvironment().findSchema(self.resolveURI("#")));
  1650.                     } else if (instance.getType() === "array") {
  1651.                         return JSV.mapArray(instance.getProperties(), function (instance) {
  1652.                             return instance.getEnvironment().createSchema(instance, self.getEnvironment().findSchema(self.resolveURI("#")));
  1653.                         });
  1654.                     }
  1655.                 },
  1656.                
  1657.                 "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  1658.                     var extensions = schema.getAttribute("extends"), x, xl;
  1659.                     if (extensions) {
  1660.                         if (JSV.isJSONSchema(extensions)) {
  1661.                             extensions.validate(instance, report, parent, parentSchema, name);
  1662.                         } else if (JSV.typeOf(extensions) === "array") {
  1663.                             for (x = 0, xl = extensions.length; x < xl; ++x) {
  1664.                                 extensions[x].validate(instance, report, parent, parentSchema, name);
  1665.                             }
  1666.                         }
  1667.                     }
  1668.                 }
  1669.             }
  1670.         },
  1671.        
  1672.         "optional" : true,
  1673.         "default" : {},
  1674.         "fragmentResolution" : "slash-delimited",
  1675.        
  1676.         "parser" : function (instance, self) {
  1677.             if (instance.getType() === "object") {
  1678.                 return instance.getEnvironment().createSchema(instance, self);
  1679.             }
  1680.         },
  1681.        
  1682.         "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  1683.             var propNames = schema.getPropertyNames(),
  1684.                 x, xl,
  1685.                 attributeSchemas = self.getAttribute("properties"),
  1686.                 validator;
  1687.            
  1688.             for (x in attributeSchemas) {
  1689.                 if (attributeSchemas[x] !== O[x] && attributeSchemas[x].getValueOfProperty("validationRequired")) {
  1690.                     JSV.pushUnique(propNames, x);
  1691.                 }
  1692.             }
  1693.            
  1694.             for (x = 0, xl = propNames.length; x < xl; ++x) {
  1695.                 if (attributeSchemas[propNames[x]] !== O[propNames[x]]) {
  1696.                     validator = attributeSchemas[propNames[x]].getValueOfProperty("validator");
  1697.                     if (typeof validator === "function") {
  1698.                         validator(instance, schema, attributeSchemas[propNames[x]], report, parent, parentSchema, name);
  1699.                     }
  1700.                 }
  1701.             }
  1702.         },
  1703.                
  1704.         "initializer" : function (instance) {
  1705.             var link, extension, extended;
  1706.            
  1707.             //if there is a link to a different schema, set reference
  1708.             link = instance._schema.getLink("describedby", instance);
  1709.             if (link && instance._schema._uri !== link) {
  1710.                 instance.setReference("describedby", link);
  1711.             }
  1712.            
  1713.             //if instance has a URI link to itself, update it's own URI
  1714.             link = instance._schema.getLink("self", instance);
  1715.             if (JSV.typeOf(link) === "string") {
  1716.                 instance._uri = JSV.formatURI(link);
  1717.             }
  1718.            
  1719.             //if there is a link to the full representation, set reference
  1720.             link = instance._schema.getLink("full", instance);
  1721.             if (link && instance._uri !== link) {
  1722.                 instance.setReference("full", link);
  1723.             }
  1724.            
  1725.             //extend schema
  1726.             extension = instance.getAttribute("extends");
  1727.             if (JSV.isJSONSchema(extension)) {
  1728.                 extended = JSV.inherits(extension, instance, true);
  1729.                 instance = instance._env.createSchema(extended, instance._schema, instance._uri);
  1730.             }
  1731.            
  1732.             return instance;
  1733.         }
  1734.     }, true, "http://json-schema.org/schema#");
  1735.    
  1736.     HYPERSCHEMA = ENVIRONMENT.createSchema(JSV.inherits(SCHEMA, ENVIRONMENT.createSchema({
  1737.         "$schema" : "http://json-schema.org/hyper-schema#",
  1738.         "id" : "http://json-schema.org/hyper-schema#",
  1739.    
  1740.         "properties" : {
  1741.             "links" : {
  1742.                 "type" : "array",
  1743.                 "items" : {"$ref" : "links#"},
  1744.                 "optional" : true,
  1745.                
  1746.                 "parser" : function (instance, self, arg) {
  1747.                     var links,
  1748.                         linkSchemaURI = self.getValueOfProperty("items")["$ref"],
  1749.                         linkSchema = self.getEnvironment().findSchema(linkSchemaURI),
  1750.                         linkParser = linkSchema && linkSchema.getValueOfProperty("parser");
  1751.                     arg = JSV.toArray(arg);
  1752.                    
  1753.                     if (typeof linkParser === "function") {
  1754.                         links = JSV.mapArray(instance.getProperties(), function (link) {
  1755.                             return linkParser(link, linkSchema);
  1756.                         });
  1757.                     } else {
  1758.                         links = JSV.toArray(instance.getValue());
  1759.                     }
  1760.                    
  1761.                     if (arg[0]) {
  1762.                         links = JSV.filterArray(links, function (link) {
  1763.                             return link["rel"] === arg[0];
  1764.                         });
  1765.                     }
  1766.                    
  1767.                     if (arg[1]) {
  1768.                         links = JSV.mapArray(links, function (link) {
  1769.                             var instance = arg[1],
  1770.                                 href = link["href"];
  1771.                             href = href.replace(/\{(.+)\}/g, function (str, p1, offset, s) {
  1772.                                 var value;
  1773.                                 if (p1 === "-this") {
  1774.                                     value = instance.getValue();
  1775.                                 } else {
  1776.                                     value = instance.getValueOfProperty(p1);
  1777.                                 }
  1778.                                 return value !== undefined ? String(value) : "";
  1779.                             });
  1780.                             return href ? JSV.formatURI(instance.resolveURI(href)) : href;
  1781.                         });
  1782.                     }
  1783.                    
  1784.                     return links;
  1785.                 }
  1786.             },
  1787.            
  1788.             "fragmentResolution" : {
  1789.                 "type" : "string",
  1790.                 "optional" : true,
  1791.                 "default" : "slash-delimited"
  1792.             },
  1793.            
  1794.             "root" : {
  1795.                 "type" : "boolean",
  1796.                 "optional" : true,
  1797.                 "default" : false
  1798.             },
  1799.            
  1800.             "readonly" : {
  1801.                 "type" : "boolean",
  1802.                 "optional" : true,
  1803.                 "default" : false
  1804.             },
  1805.            
  1806.             "pathStart" : {
  1807.                 "type" : "string",
  1808.                 "optional" : true,
  1809.                 "format" : "uri",
  1810.                
  1811.                 "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  1812.                     var pathStart;
  1813.                     if (instance.getType() !== "undefined") {
  1814.                         pathStart = schema.getAttribute("pathStart");
  1815.                         if (typeof pathStart === "string") {
  1816.                             //TODO: Find out what pathStart is relative to
  1817.                             if (instance.getURI().indexOf(pathStart) !== 0) {
  1818.                                 report.addError(instance, schema, "pathStart", "Instance's URI does not start with " + pathStart, pathStart);
  1819.                             }
  1820.                         }
  1821.                     }
  1822.                 }
  1823.             },
  1824.            
  1825.             "mediaType" : {
  1826.                 "type" : "string",
  1827.                 "optional" : true,
  1828.                 "format" : "media-type"
  1829.             },
  1830.            
  1831.             "alternate" : {
  1832.                 "type" : "array",
  1833.                 "items" : {"$ref" : "#"},
  1834.                 "optional" : true
  1835.             }
  1836.         },
  1837.        
  1838.         "links" : [
  1839.             {
  1840.                 "href" : "{$ref}",
  1841.                 "rel" : "full"
  1842.             },
  1843.            
  1844.             {
  1845.                 "href" : "{$schema}",
  1846.                 "rel" : "describedby"
  1847.             },
  1848.            
  1849.             {
  1850.                 "href" : "{id}",
  1851.                 "rel" : "self"
  1852.             }
  1853.         ]//,
  1854.        
  1855.         //not needed as JSV.inherits does the job for us
  1856.         //"extends" : {"$ref" : "http://json-schema.org/schema#"}
  1857.     }, SCHEMA), true), true, "http://json-schema.org/hyper-schema#");
  1858.    
  1859.     ENVIRONMENT.setOption("defaultSchemaURI", "http://json-schema.org/hyper-schema#");
  1860.    
  1861.     LINKS = ENVIRONMENT.createSchema({
  1862.         "$schema" : "http://json-schema.org/hyper-schema#",
  1863.         "id" : "http://json-schema.org/links#",
  1864.         "type" : "object",
  1865.        
  1866.         "properties" : {
  1867.             "href" : {
  1868.                 "type" : "string"
  1869.             },
  1870.            
  1871.             "rel" : {
  1872.                 "type" : "string"
  1873.             },
  1874.            
  1875.             "targetSchema" : {
  1876.                 "$ref" : "hyper-schema#",
  1877.                
  1878.                 //need this here because parsers are run before links are resolved
  1879.                 "parser" : HYPERSCHEMA.getAttribute("parser")
  1880.             },
  1881.            
  1882.             "method" : {
  1883.                 "type" : "string",
  1884.                 "default" : "GET",
  1885.                 "optional" : true
  1886.             },
  1887.            
  1888.             "enctype" : {
  1889.                 "type" : "string",
  1890.                 "requires" : "method",
  1891.                 "optional" : true
  1892.             },
  1893.            
  1894.             "properties" : {
  1895.                 "type" : "object",
  1896.                 "additionalProperties" : {"$ref" : "hyper-schema#"},
  1897.                 "optional" : true,
  1898.                
  1899.                 "parser" : function (instance, self, arg) {
  1900.                     var env = instance.getEnvironment(),
  1901.                         selfEnv = self.getEnvironment(),
  1902.                         additionalPropertiesSchemaURI = self.getValueOfProperty("additionalProperties")["$ref"];
  1903.                     if (instance.getType() === "object") {
  1904.                         if (arg) {
  1905.                             return env.createSchema(instance.getProperty(arg), selfEnv.findSchema(self.resolveURI(additionalPropertiesSchemaURI)));
  1906.                         } else {
  1907.                             return JSV.mapObject(instance.getProperties(), function (instance) {
  1908.                                 return env.createSchema(instance, selfEnv.findSchema(self.resolveURI(additionalPropertiesSchemaURI)));
  1909.                             });
  1910.                         }
  1911.                     }
  1912.                 }
  1913.             }
  1914.         },
  1915.        
  1916.         "parser" : function (instance, self) {
  1917.             var selfProperties = self.getProperty("properties");
  1918.             if (instance.getType() === "object") {
  1919.                 return JSV.mapObject(instance.getProperties(), function (property, key) {
  1920.                     var propertySchema = selfProperties.getProperty(key),
  1921.                         parser = propertySchema && propertySchema.getValueOfProperty("parser");
  1922.                     if (typeof parser === "function") {
  1923.                         return parser(property, propertySchema);
  1924.                     }
  1925.                     //else
  1926.                     return property.getValue();
  1927.                 });
  1928.             }
  1929.             return instance.getValue();
  1930.         }
  1931.     }, HYPERSCHEMA, "http://json-schema.org/links#");
  1932.    
  1933.     JSV.registerEnvironment("json-schema-draft-02", ENVIRONMENT);
  1934.     if (!JSV.getDefaultEnvironmentID() || JSV.getDefaultEnvironmentID() === "json-schema-draft-01") {
  1935.         JSV.setDefaultEnvironmentID("json-schema-draft-02");
  1936.     }
  1937.    
  1938. }());
RAW Paste Data