Skelleton extended.
This commit is contained in:
+3
@@ -0,0 +1,3 @@
|
||||
require("./json-schema-draft-01");
|
||||
require("./json-schema-draft-02");
|
||||
require("./json-schema-draft-03");
|
||||
+953
@@ -0,0 +1,953 @@
|
||||
/**
|
||||
* json-schema-draft-01 Environment
|
||||
*
|
||||
* @fileOverview Implementation of the first revision of the JSON Schema specification draft.
|
||||
* @author <a href="mailto:gary.court@gmail.com">Gary Court</a>
|
||||
* @version 1.7.1
|
||||
* @see http://github.com/garycourt/JSV
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2010 Gary Court. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY GARY COURT ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GARY COURT OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of Gary Court or the JSON Schema specification.
|
||||
*/
|
||||
|
||||
/*jslint white: true, sub: true, onevar: true, undef: true, eqeqeq: true, newcap: true, immed: true, indent: 4 */
|
||||
/*global require */
|
||||
|
||||
(function () {
|
||||
var O = {},
|
||||
JSV = require('./jsv').JSV,
|
||||
ENVIRONMENT,
|
||||
TYPE_VALIDATORS,
|
||||
SCHEMA,
|
||||
HYPERSCHEMA,
|
||||
LINKS;
|
||||
|
||||
TYPE_VALIDATORS = {
|
||||
"string" : function (instance, report) {
|
||||
return instance.getType() === "string";
|
||||
},
|
||||
|
||||
"number" : function (instance, report) {
|
||||
return instance.getType() === "number";
|
||||
},
|
||||
|
||||
"integer" : function (instance, report) {
|
||||
return instance.getType() === "number" && instance.getValue() % 1 === 0;
|
||||
},
|
||||
|
||||
"boolean" : function (instance, report) {
|
||||
return instance.getType() === "boolean";
|
||||
},
|
||||
|
||||
"object" : function (instance, report) {
|
||||
return instance.getType() === "object";
|
||||
},
|
||||
|
||||
"array" : function (instance, report) {
|
||||
return instance.getType() === "array";
|
||||
},
|
||||
|
||||
"null" : function (instance, report) {
|
||||
return instance.getType() === "null";
|
||||
},
|
||||
|
||||
"any" : function (instance, report) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
ENVIRONMENT = new JSV.Environment();
|
||||
ENVIRONMENT.setOption("defaultFragmentDelimiter", ".");
|
||||
ENVIRONMENT.setOption("defaultSchemaURI", "http://json-schema.org/schema#"); //updated later
|
||||
|
||||
SCHEMA = ENVIRONMENT.createSchema({
|
||||
"$schema" : "http://json-schema.org/hyper-schema#",
|
||||
"id" : "http://json-schema.org/schema#",
|
||||
"type" : "object",
|
||||
|
||||
"properties" : {
|
||||
"type" : {
|
||||
"type" : ["string", "array"],
|
||||
"items" : {
|
||||
"type" : ["string", {"$ref" : "#"}]
|
||||
},
|
||||
"optional" : true,
|
||||
"uniqueItems" : true,
|
||||
"default" : "any",
|
||||
|
||||
"parser" : function (instance, self) {
|
||||
var parser;
|
||||
|
||||
if (instance.getType() === "string") {
|
||||
return instance.getValue();
|
||||
} else if (instance.getType() === "object") {
|
||||
return instance.getEnvironment().createSchema(
|
||||
instance,
|
||||
self.getEnvironment().findSchema(self.resolveURI("#"))
|
||||
);
|
||||
} else if (instance.getType() === "array") {
|
||||
parser = self.getValueOfProperty("parser");
|
||||
return JSV.mapArray(instance.getProperties(), function (prop) {
|
||||
return parser(prop, self);
|
||||
});
|
||||
}
|
||||
//else
|
||||
return "any";
|
||||
},
|
||||
|
||||
"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
|
||||
var requiredTypes = JSV.toArray(schema.getAttribute("type")),
|
||||
x, xl, type, subreport, typeValidators;
|
||||
|
||||
//for instances that are required to be a certain type
|
||||
if (instance.getType() !== "undefined" && requiredTypes && requiredTypes.length) {
|
||||
typeValidators = self.getValueOfProperty("typeValidators") || {};
|
||||
|
||||
//ensure that type matches for at least one of the required types
|
||||
for (x = 0, xl = requiredTypes.length; x < xl; ++x) {
|
||||
type = requiredTypes[x];
|
||||
if (JSV.isJSONSchema(type)) {
|
||||
subreport = JSV.createObject(report);
|
||||
subreport.errors = [];
|
||||
subreport.validated = JSV.clone(report.validated);
|
||||
if (type.validate(instance, subreport, parent, parentSchema, name).errors.length === 0) {
|
||||
return true; //instance matches this schema
|
||||
}
|
||||
} else {
|
||||
if (typeValidators[type] !== O[type] && typeof typeValidators[type] === "function") {
|
||||
if (typeValidators[type](instance, report)) {
|
||||
return true; //type is valid
|
||||
}
|
||||
} else {
|
||||
return true; //unknown types are assumed valid
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//if we get to this point, type is invalid
|
||||
report.addError(instance, schema, "type", "Instance is not a required type", requiredTypes);
|
||||
return false;
|
||||
}
|
||||
//else, anything is allowed if no type is specified
|
||||
return true;
|
||||
},
|
||||
|
||||
"typeValidators" : TYPE_VALIDATORS
|
||||
},
|
||||
|
||||
"properties" : {
|
||||
"type" : "object",
|
||||
"additionalProperties" : {"$ref" : "#"},
|
||||
"optional" : true,
|
||||
"default" : {},
|
||||
|
||||
"parser" : function (instance, self, arg) {
|
||||
var env = instance.getEnvironment(),
|
||||
selfEnv = self.getEnvironment();
|
||||
if (instance.getType() === "object") {
|
||||
if (arg) {
|
||||
return env.createSchema(instance.getProperty(arg), selfEnv.findSchema(self.resolveURI("#")));
|
||||
} else {
|
||||
return JSV.mapObject(instance.getProperties(), function (instance) {
|
||||
return env.createSchema(instance, selfEnv.findSchema(self.resolveURI("#")));
|
||||
});
|
||||
}
|
||||
}
|
||||
//else
|
||||
return {};
|
||||
},
|
||||
|
||||
"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
|
||||
var propertySchemas, key;
|
||||
//this attribute is for object type instances only
|
||||
if (instance.getType() === "object") {
|
||||
//for each property defined in the schema
|
||||
propertySchemas = schema.getAttribute("properties");
|
||||
for (key in propertySchemas) {
|
||||
if (propertySchemas[key] !== O[key] && propertySchemas[key]) {
|
||||
//ensure that instance property is valid
|
||||
propertySchemas[key].validate(instance.getProperty(key), report, instance, schema, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"items" : {
|
||||
"type" : [{"$ref" : "#"}, "array"],
|
||||
"items" : {"$ref" : "#"},
|
||||
"optional" : true,
|
||||
"default" : {},
|
||||
|
||||
"parser" : function (instance, self) {
|
||||
if (instance.getType() === "object") {
|
||||
return instance.getEnvironment().createSchema(instance, self.getEnvironment().findSchema(self.resolveURI("#")));
|
||||
} else if (instance.getType() === "array") {
|
||||
return JSV.mapArray(instance.getProperties(), function (instance) {
|
||||
return instance.getEnvironment().createSchema(instance, self.getEnvironment().findSchema(self.resolveURI("#")));
|
||||
});
|
||||
}
|
||||
//else
|
||||
return instance.getEnvironment().createEmptySchema();
|
||||
},
|
||||
|
||||
"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
|
||||
var properties, items, x, xl, itemSchema, additionalProperties;
|
||||
|
||||
if (instance.getType() === "array") {
|
||||
properties = instance.getProperties();
|
||||
items = schema.getAttribute("items");
|
||||
additionalProperties = schema.getAttribute("additionalProperties");
|
||||
|
||||
if (JSV.typeOf(items) === "array") {
|
||||
for (x = 0, xl = properties.length; x < xl; ++x) {
|
||||
itemSchema = items[x] || additionalProperties;
|
||||
if (itemSchema !== false) {
|
||||
itemSchema.validate(properties[x], report, instance, schema, x);
|
||||
} else {
|
||||
report.addError(instance, schema, "additionalProperties", "Additional items are not allowed", itemSchema);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
itemSchema = items || additionalProperties;
|
||||
for (x = 0, xl = properties.length; x < xl; ++x) {
|
||||
itemSchema.validate(properties[x], report, instance, schema, x);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"optional" : {
|
||||
"type" : "boolean",
|
||||
"optional" : true,
|
||||
"default" : false,
|
||||
|
||||
"parser" : function (instance, self) {
|
||||
return !!instance.getValue();
|
||||
},
|
||||
|
||||
"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
|
||||
if (instance.getType() === "undefined" && !schema.getAttribute("optional")) {
|
||||
report.addError(instance, schema, "optional", "Property is required", false);
|
||||
}
|
||||
},
|
||||
|
||||
"validationRequired" : true
|
||||
},
|
||||
|
||||
"additionalProperties" : {
|
||||
"type" : [{"$ref" : "#"}, "boolean"],
|
||||
"optional" : true,
|
||||
"default" : {},
|
||||
|
||||
"parser" : function (instance, self) {
|
||||
if (instance.getType() === "object") {
|
||||
return instance.getEnvironment().createSchema(instance, self.getEnvironment().findSchema(self.resolveURI("#")));
|
||||
} else if (instance.getType() === "boolean" && instance.getValue() === false) {
|
||||
return false;
|
||||
}
|
||||
//else
|
||||
return instance.getEnvironment().createEmptySchema();
|
||||
},
|
||||
|
||||
"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
|
||||
var additionalProperties, propertySchemas, properties, key;
|
||||
//we only need to check against object types as arrays do their own checking on this property
|
||||
if (instance.getType() === "object") {
|
||||
additionalProperties = schema.getAttribute("additionalProperties");
|
||||
propertySchemas = schema.getAttribute("properties") || {};
|
||||
properties = instance.getProperties();
|
||||
for (key in properties) {
|
||||
if (properties[key] !== O[key] && properties[key] && !propertySchemas[key]) {
|
||||
if (JSV.isJSONSchema(additionalProperties)) {
|
||||
additionalProperties.validate(properties[key], report, instance, schema, key);
|
||||
} else if (additionalProperties === false) {
|
||||
report.addError(instance, schema, "additionalProperties", "Additional properties are not allowed", additionalProperties);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"requires" : {
|
||||
"type" : ["string", {"$ref" : "#"}],
|
||||
"optional" : true,
|
||||
|
||||
"parser" : function (instance, self) {
|
||||
if (instance.getType() === "string") {
|
||||
return instance.getValue();
|
||||
} else if (instance.getType() === "object") {
|
||||
return instance.getEnvironment().createSchema(instance, self.getEnvironment().findSchema(self.resolveURI("#")));
|
||||
}
|
||||
},
|
||||
|
||||
"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
|
||||
var requires;
|
||||
if (instance.getType() !== "undefined" && parent && parent.getType() !== "undefined") {
|
||||
requires = schema.getAttribute("requires");
|
||||
if (typeof requires === "string") {
|
||||
if (parent.getProperty(requires).getType() === "undefined") {
|
||||
report.addError(instance, schema, "requires", 'Property requires sibling property "' + requires + '"', requires);
|
||||
}
|
||||
} else if (JSV.isJSONSchema(requires)) {
|
||||
requires.validate(parent, report); //WATCH: A "requires" schema does not support the "requires" attribute
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"minimum" : {
|
||||
"type" : "number",
|
||||
"optional" : true,
|
||||
|
||||
"parser" : function (instance, self) {
|
||||
if (instance.getType() === "number") {
|
||||
return instance.getValue();
|
||||
}
|
||||
},
|
||||
|
||||
"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
|
||||
var minimum, minimumCanEqual;
|
||||
if (instance.getType() === "number") {
|
||||
minimum = schema.getAttribute("minimum");
|
||||
minimumCanEqual = schema.getAttribute("minimumCanEqual");
|
||||
if (typeof minimum === "number" && (instance.getValue() < minimum || (minimumCanEqual === false && instance.getValue() === minimum))) {
|
||||
report.addError(instance, schema, "minimum", "Number is less than the required minimum value", minimum);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"maximum" : {
|
||||
"type" : "number",
|
||||
"optional" : true,
|
||||
|
||||
"parser" : function (instance, self) {
|
||||
if (instance.getType() === "number") {
|
||||
return instance.getValue();
|
||||
}
|
||||
},
|
||||
|
||||
"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
|
||||
var maximum, maximumCanEqual;
|
||||
if (instance.getType() === "number") {
|
||||
maximum = schema.getAttribute("maximum");
|
||||
maximumCanEqual = schema.getAttribute("maximumCanEqual");
|
||||
if (typeof maximum === "number" && (instance.getValue() > maximum || (maximumCanEqual === false && instance.getValue() === maximum))) {
|
||||
report.addError(instance, schema, "maximum", "Number is greater than the required maximum value", maximum);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"minimumCanEqual" : {
|
||||
"type" : "boolean",
|
||||
"optional" : true,
|
||||
"requires" : "minimum",
|
||||
"default" : true,
|
||||
|
||||
"parser" : function (instance, self) {
|
||||
if (instance.getType() === "boolean") {
|
||||
return instance.getValue();
|
||||
}
|
||||
//else
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
"maximumCanEqual" : {
|
||||
"type" : "boolean",
|
||||
"optional" : true,
|
||||
"requires" : "maximum",
|
||||
"default" : true,
|
||||
|
||||
"parser" : function (instance, self) {
|
||||
if (instance.getType() === "boolean") {
|
||||
return instance.getValue();
|
||||
}
|
||||
//else
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
"minItems" : {
|
||||
"type" : "integer",
|
||||
"optional" : true,
|
||||
"minimum" : 0,
|
||||
"default" : 0,
|
||||
|
||||
"parser" : function (instance, self) {
|
||||
if (instance.getType() === "number") {
|
||||
return instance.getValue();
|
||||
}
|
||||
//else
|
||||
return 0;
|
||||
},
|
||||
|
||||
"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
|
||||
var minItems;
|
||||
if (instance.getType() === "array") {
|
||||
minItems = schema.getAttribute("minItems");
|
||||
if (typeof minItems === "number" && instance.getProperties().length < minItems) {
|
||||
report.addError(instance, schema, "minItems", "The number of items is less than the required minimum", minItems);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"maxItems" : {
|
||||
"type" : "integer",
|
||||
"optional" : true,
|
||||
"minimum" : 0,
|
||||
|
||||
"parser" : function (instance, self) {
|
||||
if (instance.getType() === "number") {
|
||||
return instance.getValue();
|
||||
}
|
||||
},
|
||||
|
||||
"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
|
||||
var maxItems;
|
||||
if (instance.getType() === "array") {
|
||||
maxItems = schema.getAttribute("maxItems");
|
||||
if (typeof maxItems === "number" && instance.getProperties().length > maxItems) {
|
||||
report.addError(instance, schema, "maxItems", "The number of items is greater than the required maximum", maxItems);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"pattern" : {
|
||||
"type" : "string",
|
||||
"optional" : true,
|
||||
"format" : "regex",
|
||||
|
||||
"parser" : function (instance, self) {
|
||||
if (instance.getType() === "string") {
|
||||
return instance.getValue();
|
||||
}
|
||||
},
|
||||
|
||||
"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
|
||||
var pattern;
|
||||
try {
|
||||
pattern = new RegExp(schema.getAttribute("pattern"));
|
||||
if (instance.getType() === "string" && pattern && !pattern.test(instance.getValue())) {
|
||||
report.addError(instance, schema, "pattern", "String does not match pattern", pattern.toString());
|
||||
}
|
||||
} catch (e) {
|
||||
report.addError(instance, schema, "pattern", "Invalid pattern", e);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"minLength" : {
|
||||
"type" : "integer",
|
||||
"optional" : true,
|
||||
"minimum" : 0,
|
||||
"default" : 0,
|
||||
|
||||
"parser" : function (instance, self) {
|
||||
if (instance.getType() === "number") {
|
||||
return instance.getValue();
|
||||
}
|
||||
//else
|
||||
return 0;
|
||||
},
|
||||
|
||||
"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
|
||||
var minLength;
|
||||
if (instance.getType() === "string") {
|
||||
minLength = schema.getAttribute("minLength");
|
||||
if (typeof minLength === "number" && instance.getValue().length < minLength) {
|
||||
report.addError(instance, schema, "minLength", "String is less than the required minimum length", minLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"maxLength" : {
|
||||
"type" : "integer",
|
||||
"optional" : true,
|
||||
|
||||
"parser" : function (instance, self) {
|
||||
if (instance.getType() === "number") {
|
||||
return instance.getValue();
|
||||
}
|
||||
},
|
||||
|
||||
"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
|
||||
var maxLength;
|
||||
if (instance.getType() === "string") {
|
||||
maxLength = schema.getAttribute("maxLength");
|
||||
if (typeof maxLength === "number" && instance.getValue().length > maxLength) {
|
||||
report.addError(instance, schema, "maxLength", "String is greater than the required maximum length", maxLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"enum" : {
|
||||
"type" : "array",
|
||||
"optional" : true,
|
||||
"minItems" : 1,
|
||||
"uniqueItems" : true,
|
||||
|
||||
"parser" : function (instance, self) {
|
||||
if (instance.getType() === "array") {
|
||||
return instance.getValue();
|
||||
}
|
||||
},
|
||||
|
||||
"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
|
||||
var enums, x, xl;
|
||||
if (instance.getType() !== "undefined") {
|
||||
enums = schema.getAttribute("enum");
|
||||
if (enums) {
|
||||
for (x = 0, xl = enums.length; x < xl; ++x) {
|
||||
if (instance.equals(enums[x])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
report.addError(instance, schema, "enum", "Instance is not one of the possible values", enums);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"title" : {
|
||||
"type" : "string",
|
||||
"optional" : true
|
||||
},
|
||||
|
||||
"description" : {
|
||||
"type" : "string",
|
||||
"optional" : true
|
||||
},
|
||||
|
||||
"format" : {
|
||||
"type" : "string",
|
||||
"optional" : true,
|
||||
|
||||
"parser" : function (instance, self) {
|
||||
if (instance.getType() === "string") {
|
||||
return instance.getValue();
|
||||
}
|
||||
},
|
||||
|
||||
"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
|
||||
var format, formatValidators;
|
||||
if (instance.getType() === "string") {
|
||||
format = schema.getAttribute("format");
|
||||
formatValidators = self.getValueOfProperty("formatValidators");
|
||||
if (typeof format === "string" && formatValidators[format] !== O[format] && typeof formatValidators[format] === "function" && !formatValidators[format].call(this, instance, report)) {
|
||||
report.addError(instance, schema, "format", "String is not in the required format", format);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"formatValidators" : {}
|
||||
},
|
||||
|
||||
"contentEncoding" : {
|
||||
"type" : "string",
|
||||
"optional" : true
|
||||
},
|
||||
|
||||
"default" : {
|
||||
"type" : "any",
|
||||
"optional" : true
|
||||
},
|
||||
|
||||
"maxDecimal" : {
|
||||
"type" : "integer",
|
||||
"optional" : true,
|
||||
"minimum" : 0,
|
||||
|
||||
"parser" : function (instance, self) {
|
||||
if (instance.getType() === "number") {
|
||||
return instance.getValue();
|
||||
}
|
||||
},
|
||||
|
||||
"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
|
||||
var maxDecimal, decimals;
|
||||
if (instance.getType() === "number") {
|
||||
maxDecimal = schema.getAttribute("maxDecimal");
|
||||
if (typeof maxDecimal === "number") {
|
||||
decimals = instance.getValue().toString(10).split('.')[1];
|
||||
if (decimals && decimals.length > maxDecimal) {
|
||||
report.addError(instance, schema, "maxDecimal", "The number of decimal places is greater than the allowed maximum", maxDecimal);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"disallow" : {
|
||||
"type" : ["string", "array"],
|
||||
"items" : {"type" : "string"},
|
||||
"optional" : true,
|
||||
"uniqueItems" : true,
|
||||
|
||||
"parser" : function (instance, self) {
|
||||
if (instance.getType() === "string" || instance.getType() === "array") {
|
||||
return instance.getValue();
|
||||
}
|
||||
},
|
||||
|
||||
"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
|
||||
var disallowedTypes = JSV.toArray(schema.getAttribute("disallow")),
|
||||
x, xl, key, typeValidators;
|
||||
|
||||
//for instances that are required to be a certain type
|
||||
if (instance.getType() !== "undefined" && disallowedTypes && disallowedTypes.length) {
|
||||
typeValidators = self.getValueOfProperty("typeValidators") || {};
|
||||
|
||||
//ensure that type matches for at least one of the required types
|
||||
for (x = 0, xl = disallowedTypes.length; x < xl; ++x) {
|
||||
key = disallowedTypes[x];
|
||||
if (typeValidators[key] !== O[key] && typeof typeValidators[key] === "function") {
|
||||
if (typeValidators[key](instance, report)) {
|
||||
report.addError(instance, schema, "disallow", "Instance is a disallowed type", disallowedTypes);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/*
|
||||
else {
|
||||
report.addError(instance, schema, "disallow", "Instance may be a disallowed type", disallowedTypes);
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
//if we get to this point, type is valid
|
||||
return true;
|
||||
}
|
||||
//else, everything is allowed if no disallowed types are specified
|
||||
return true;
|
||||
},
|
||||
|
||||
"typeValidators" : TYPE_VALIDATORS
|
||||
},
|
||||
|
||||
"extends" : {
|
||||
"type" : [{"$ref" : "#"}, "array"],
|
||||
"items" : {"$ref" : "#"},
|
||||
"optional" : true,
|
||||
"default" : {},
|
||||
|
||||
"parser" : function (instance, self) {
|
||||
if (instance.getType() === "object") {
|
||||
return instance.getEnvironment().createSchema(instance, self.getEnvironment().findSchema(self.resolveURI("#")));
|
||||
} else if (instance.getType() === "array") {
|
||||
return JSV.mapArray(instance.getProperties(), function (instance) {
|
||||
return instance.getEnvironment().createSchema(instance, self.getEnvironment().findSchema(self.resolveURI("#")));
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
|
||||
var extensions = schema.getAttribute("extends"), x, xl;
|
||||
if (extensions) {
|
||||
if (JSV.isJSONSchema(extensions)) {
|
||||
extensions.validate(instance, report, parent, parentSchema, name);
|
||||
} else if (JSV.typeOf(extensions) === "array") {
|
||||
for (x = 0, xl = extensions.length; x < xl; ++x) {
|
||||
extensions[x].validate(instance, report, parent, parentSchema, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"optional" : true,
|
||||
"default" : {},
|
||||
"fragmentResolution" : "dot-delimited",
|
||||
|
||||
"parser" : function (instance, self) {
|
||||
if (instance.getType() === "object") {
|
||||
return instance.getEnvironment().createSchema(instance, self);
|
||||
}
|
||||
},
|
||||
|
||||
"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
|
||||
var propNames = schema.getPropertyNames(),
|
||||
x, xl,
|
||||
attributeSchemas = self.getAttribute("properties"),
|
||||
validator;
|
||||
|
||||
for (x in attributeSchemas) {
|
||||
if (attributeSchemas[x] !== O[x] && attributeSchemas[x].getValueOfProperty("validationRequired")) {
|
||||
JSV.pushUnique(propNames, x);
|
||||
}
|
||||
}
|
||||
|
||||
for (x = 0, xl = propNames.length; x < xl; ++x) {
|
||||
if (attributeSchemas[propNames[x]] !== O[propNames[x]]) {
|
||||
validator = attributeSchemas[propNames[x]].getValueOfProperty("validator");
|
||||
if (typeof validator === "function") {
|
||||
validator(instance, schema, attributeSchemas[propNames[x]], report, parent, parentSchema, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"initializer" : function (instance) {
|
||||
var link, extension, extended;
|
||||
|
||||
//if there is a link to a different schema, set reference
|
||||
link = instance._schema.getLink("describedby", instance);
|
||||
if (link && instance._schema._uri !== link) {
|
||||
instance.setReference("describedby", link);
|
||||
}
|
||||
|
||||
//if instance has a URI link to itself, update it's own URI
|
||||
link = instance._schema.getLink("self", instance);
|
||||
if (JSV.typeOf(link) === "string") {
|
||||
instance._uri = JSV.formatURI(link);
|
||||
}
|
||||
|
||||
//if there is a link to the full representation, set reference
|
||||
link = instance._schema.getLink("full", instance);
|
||||
if (link && instance._uri !== link) {
|
||||
instance.setReference("full", link);
|
||||
}
|
||||
|
||||
//extend schema
|
||||
extension = instance.getAttribute("extends");
|
||||
if (JSV.isJSONSchema(extension)) {
|
||||
extended = JSV.inherits(extension, instance, true);
|
||||
instance = instance._env.createSchema(extended, instance._schema, instance._uri);
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
}, true, "http://json-schema.org/schema#");
|
||||
|
||||
HYPERSCHEMA = ENVIRONMENT.createSchema(JSV.inherits(SCHEMA, ENVIRONMENT.createSchema({
|
||||
"$schema" : "http://json-schema.org/hyper-schema#",
|
||||
"id" : "http://json-schema.org/hyper-schema#",
|
||||
|
||||
"properties" : {
|
||||
"links" : {
|
||||
"type" : "array",
|
||||
"items" : {"$ref" : "links#"},
|
||||
"optional" : true,
|
||||
|
||||
"parser" : function (instance, self, arg) {
|
||||
var links,
|
||||
linkSchemaURI = self.getValueOfProperty("items")["$ref"],
|
||||
linkSchema = self.getEnvironment().findSchema(linkSchemaURI),
|
||||
linkParser = linkSchema && linkSchema.getValueOfProperty("parser");
|
||||
arg = JSV.toArray(arg);
|
||||
|
||||
if (typeof linkParser === "function") {
|
||||
links = JSV.mapArray(instance.getProperties(), function (link) {
|
||||
return linkParser(link, linkSchema);
|
||||
});
|
||||
} else {
|
||||
links = JSV.toArray(instance.getValue());
|
||||
}
|
||||
|
||||
if (arg[0]) {
|
||||
links = JSV.filterArray(links, function (link) {
|
||||
return link["rel"] === arg[0];
|
||||
});
|
||||
}
|
||||
|
||||
if (arg[1]) {
|
||||
links = JSV.mapArray(links, function (link) {
|
||||
var instance = arg[1],
|
||||
href = link["href"];
|
||||
href = href.replace(/\{(.+)\}/g, function (str, p1, offset, s) {
|
||||
var value;
|
||||
if (p1 === "-this") {
|
||||
value = instance.getValue();
|
||||
} else {
|
||||
value = instance.getValueOfProperty(p1);
|
||||
}
|
||||
return value !== undefined ? String(value) : "";
|
||||
});
|
||||
return href ? JSV.formatURI(instance.resolveURI(href)) : href;
|
||||
});
|
||||
}
|
||||
|
||||
return links;
|
||||
}
|
||||
},
|
||||
|
||||
"fragmentResolution" : {
|
||||
"type" : "string",
|
||||
"optional" : true,
|
||||
"default" : "dot-delimited"
|
||||
},
|
||||
|
||||
"root" : {
|
||||
"type" : "boolean",
|
||||
"optional" : true,
|
||||
"default" : false
|
||||
},
|
||||
|
||||
"readonly" : {
|
||||
"type" : "boolean",
|
||||
"optional" : true,
|
||||
"default" : false
|
||||
},
|
||||
|
||||
"pathStart" : {
|
||||
"type" : "string",
|
||||
"optional" : true,
|
||||
"format" : "uri",
|
||||
|
||||
"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
|
||||
var pathStart;
|
||||
if (instance.getType() !== "undefined") {
|
||||
pathStart = schema.getAttribute("pathStart");
|
||||
if (typeof pathStart === "string") {
|
||||
//TODO: Find out what pathStart is relative to
|
||||
if (instance.getURI().indexOf(pathStart) !== 0) {
|
||||
report.addError(instance, schema, "pathStart", "Instance's URI does not start with " + pathStart, pathStart);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"mediaType" : {
|
||||
"type" : "string",
|
||||
"optional" : true,
|
||||
"format" : "media-type"
|
||||
},
|
||||
|
||||
"alternate" : {
|
||||
"type" : "array",
|
||||
"items" : {"$ref" : "#"},
|
||||
"optional" : true
|
||||
}
|
||||
},
|
||||
|
||||
"links" : [
|
||||
{
|
||||
"href" : "{$ref}",
|
||||
"rel" : "full"
|
||||
},
|
||||
|
||||
{
|
||||
"href" : "{$schema}",
|
||||
"rel" : "describedby"
|
||||
},
|
||||
|
||||
{
|
||||
"href" : "{id}",
|
||||
"rel" : "self"
|
||||
}
|
||||
]//,
|
||||
|
||||
//not needed as JSV.inherits does the job for us
|
||||
//"extends" : {"$ref" : "http://json-schema.org/schema#"}
|
||||
}, SCHEMA), true), true, "http://json-schema.org/hyper-schema#");
|
||||
|
||||
ENVIRONMENT.setOption("defaultSchemaURI", "http://json-schema.org/hyper-schema#");
|
||||
|
||||
LINKS = ENVIRONMENT.createSchema({
|
||||
"$schema" : "http://json-schema.org/hyper-schema#",
|
||||
"id" : "http://json-schema.org/links#",
|
||||
"type" : "object",
|
||||
|
||||
"properties" : {
|
||||
"href" : {
|
||||
"type" : "string"
|
||||
},
|
||||
|
||||
"rel" : {
|
||||
"type" : "string"
|
||||
},
|
||||
|
||||
"method" : {
|
||||
"type" : "string",
|
||||
"default" : "GET",
|
||||
"optional" : true
|
||||
},
|
||||
|
||||
"enctype" : {
|
||||
"type" : "string",
|
||||
"requires" : "method",
|
||||
"optional" : true
|
||||
},
|
||||
|
||||
"properties" : {
|
||||
"type" : "object",
|
||||
"additionalProperties" : {"$ref" : "hyper-schema#"},
|
||||
"optional" : true,
|
||||
|
||||
"parser" : function (instance, self, arg) {
|
||||
var env = instance.getEnvironment(),
|
||||
selfEnv = self.getEnvironment(),
|
||||
additionalPropertiesSchemaURI = self.getValueOfProperty("additionalProperties")["$ref"];
|
||||
if (instance.getType() === "object") {
|
||||
if (arg) {
|
||||
return env.createSchema(instance.getProperty(arg), selfEnv.findSchema(self.resolveURI(additionalPropertiesSchemaURI)));
|
||||
} else {
|
||||
return JSV.mapObject(instance.getProperties(), function (instance) {
|
||||
return env.createSchema(instance, selfEnv.findSchema(self.resolveURI(additionalPropertiesSchemaURI)));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"parser" : function (instance, self) {
|
||||
var selfProperties = self.getProperty("properties");
|
||||
if (instance.getType() === "object") {
|
||||
return JSV.mapObject(instance.getProperties(), function (property, key) {
|
||||
var propertySchema = selfProperties.getProperty(key),
|
||||
parser = propertySchema && propertySchema.getValueOfProperty("parser");
|
||||
if (typeof parser === "function") {
|
||||
return parser(property, propertySchema);
|
||||
}
|
||||
//else
|
||||
return property.getValue();
|
||||
});
|
||||
}
|
||||
return instance.getValue();
|
||||
}
|
||||
}, HYPERSCHEMA, "http://json-schema.org/links#");
|
||||
|
||||
JSV.registerEnvironment("json-schema-draft-00", ENVIRONMENT);
|
||||
JSV.registerEnvironment("json-schema-draft-01", JSV.createEnvironment("json-schema-draft-00"));
|
||||
|
||||
if (!JSV.getDefaultEnvironmentID()) {
|
||||
JSV.setDefaultEnvironmentID("json-schema-draft-01");
|
||||
}
|
||||
|
||||
}());
|
||||
+982
@@ -0,0 +1,982 @@
|
||||
/**
|
||||
* json-schema-draft-02 Environment
|
||||
*
|
||||
* @fileOverview Implementation of the second revision of the JSON Schema specification draft.
|
||||
* @author <a href="mailto:gary.court@gmail.com">Gary Court</a>
|
||||
* @version 1.7.1
|
||||
* @see http://github.com/garycourt/JSV
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2010 Gary Court. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY GARY COURT ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GARY COURT OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of Gary Court or the JSON Schema specification.
|
||||
*/
|
||||
|
||||
/*jslint white: true, sub: true, onevar: true, undef: true, eqeqeq: true, newcap: true, immed: true, indent: 4 */
|
||||
/*global require */
|
||||
|
||||
(function () {
|
||||
var O = {},
|
||||
JSV = require('./jsv').JSV,
|
||||
ENVIRONMENT,
|
||||
TYPE_VALIDATORS,
|
||||
SCHEMA,
|
||||
HYPERSCHEMA,
|
||||
LINKS;
|
||||
|
||||
TYPE_VALIDATORS = {
|
||||
"string" : function (instance, report) {
|
||||
return instance.getType() === "string";
|
||||
},
|
||||
|
||||
"number" : function (instance, report) {
|
||||
return instance.getType() === "number";
|
||||
},
|
||||
|
||||
"integer" : function (instance, report) {
|
||||
return instance.getType() === "number" && instance.getValue() % 1 === 0;
|
||||
},
|
||||
|
||||
"boolean" : function (instance, report) {
|
||||
return instance.getType() === "boolean";
|
||||
},
|
||||
|
||||
"object" : function (instance, report) {
|
||||
return instance.getType() === "object";
|
||||
},
|
||||
|
||||
"array" : function (instance, report) {
|
||||
return instance.getType() === "array";
|
||||
},
|
||||
|
||||
"null" : function (instance, report) {
|
||||
return instance.getType() === "null";
|
||||
},
|
||||
|
||||
"any" : function (instance, report) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
ENVIRONMENT = new JSV.Environment();
|
||||
ENVIRONMENT.setOption("defaultFragmentDelimiter", "/");
|
||||
ENVIRONMENT.setOption("defaultSchemaURI", "http://json-schema.org/schema#"); //updated later
|
||||
|
||||
SCHEMA = ENVIRONMENT.createSchema({
|
||||
"$schema" : "http://json-schema.org/hyper-schema#",
|
||||
"id" : "http://json-schema.org/schema#",
|
||||
"type" : "object",
|
||||
|
||||
"properties" : {
|
||||
"type" : {
|
||||
"type" : ["string", "array"],
|
||||
"items" : {
|
||||
"type" : ["string", {"$ref" : "#"}]
|
||||
},
|
||||
"optional" : true,
|
||||
"uniqueItems" : true,
|
||||
"default" : "any",
|
||||
|
||||
"parser" : function (instance, self) {
|
||||
var parser;
|
||||
|
||||
if (instance.getType() === "string") {
|
||||
return instance.getValue();
|
||||
} else if (instance.getType() === "object") {
|
||||
return instance.getEnvironment().createSchema(
|
||||
instance,
|
||||
self.getEnvironment().findSchema(self.resolveURI("#"))
|
||||
);
|
||||
} else if (instance.getType() === "array") {
|
||||
parser = self.getValueOfProperty("parser");
|
||||
return JSV.mapArray(instance.getProperties(), function (prop) {
|
||||
return parser(prop, self);
|
||||
});
|
||||
}
|
||||
//else
|
||||
return "any";
|
||||
},
|
||||
|
||||
"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
|
||||
var requiredTypes = JSV.toArray(schema.getAttribute("type")),
|
||||
x, xl, type, subreport, typeValidators;
|
||||
|
||||
//for instances that are required to be a certain type
|
||||
if (instance.getType() !== "undefined" && requiredTypes && requiredTypes.length) {
|
||||
typeValidators = self.getValueOfProperty("typeValidators") || {};
|
||||
|
||||
//ensure that type matches for at least one of the required types
|
||||
for (x = 0, xl = requiredTypes.length; x < xl; ++x) {
|
||||
type = requiredTypes[x];
|
||||
if (JSV.isJSONSchema(type)) {
|
||||
subreport = JSV.createObject(report);
|
||||
subreport.errors = [];
|
||||
subreport.validated = JSV.clone(report.validated);
|
||||
if (type.validate(instance, subreport, parent, parentSchema, name).errors.length === 0) {
|
||||
return true; //instance matches this schema
|
||||
}
|
||||
} else {
|
||||
if (typeValidators[type] !== O[type] && typeof typeValidators[type] === "function") {
|
||||
if (typeValidators[type](instance, report)) {
|
||||
return true; //type is valid
|
||||
}
|
||||
} else {
|
||||
return true; //unknown types are assumed valid
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//if we get to this point, type is invalid
|
||||
report.addError(instance, schema, "type", "Instance is not a required type", requiredTypes);
|
||||
return false;
|
||||
}
|
||||
//else, anything is allowed if no type is specified
|
||||
return true;
|
||||
},
|
||||
|
||||
"typeValidators" : TYPE_VALIDATORS
|
||||
},
|
||||
|
||||
"properties" : {
|
||||
"type" : "object",
|
||||
"additionalProperties" : {"$ref" : "#"},
|
||||
"optional" : true,
|
||||
"default" : {},
|
||||
|
||||
"parser" : function (instance, self, arg) {
|
||||
var env = instance.getEnvironment(),
|
||||
selfEnv = self.getEnvironment();
|
||||
if (instance.getType() === "object") {
|
||||
if (arg) {
|
||||
return env.createSchema(instance.getProperty(arg), selfEnv.findSchema(self.resolveURI("#")));
|
||||
} else {
|
||||
return JSV.mapObject(instance.getProperties(), function (instance) {
|
||||
return env.createSchema(instance, selfEnv.findSchema(self.resolveURI("#")));
|
||||
});
|
||||
}
|
||||
}
|
||||
//else
|
||||
return {};
|
||||
},
|
||||
|
||||
"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
|
||||
var propertySchemas, key;
|
||||
//this attribute is for object type instances only
|
||||
if (instance.getType() === "object") {
|
||||
//for each property defined in the schema
|
||||
propertySchemas = schema.getAttribute("properties");
|
||||
for (key in propertySchemas) {
|
||||
if (propertySchemas[key] !== O[key] && propertySchemas[key]) {
|
||||
//ensure that instance property is valid
|
||||
propertySchemas[key].validate(instance.getProperty(key), report, instance, schema, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"items" : {
|
||||
"type" : [{"$ref" : "#"}, "array"],
|
||||
"items" : {"$ref" : "#"},
|
||||
"optional" : true,
|
||||
"default" : {},
|
||||
|
||||
"parser" : function (instance, self) {
|
||||
if (instance.getType() === "object") {
|
||||
return instance.getEnvironment().createSchema(instance, self.getEnvironment().findSchema(self.resolveURI("#")));
|
||||
} else if (instance.getType() === "array") {
|
||||
return JSV.mapArray(instance.getProperties(), function (instance) {
|
||||
return instance.getEnvironment().createSchema(instance, self.getEnvironment().findSchema(self.resolveURI("#")));
|
||||
});
|
||||
}
|
||||
//else
|
||||
return instance.getEnvironment().createEmptySchema();
|
||||
},
|
||||
|
||||
"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
|
||||
var properties, items, x, xl, itemSchema, additionalProperties;
|
||||
|
||||
if (instance.getType() === "array") {
|
||||
properties = instance.getProperties();
|
||||
items = schema.getAttribute("items");
|
||||
additionalProperties = schema.getAttribute("additionalProperties");
|
||||
|
||||
if (JSV.typeOf(items) === "array") {
|
||||
for (x = 0, xl = properties.length; x < xl; ++x) {
|
||||
itemSchema = items[x] || additionalProperties;
|
||||
if (itemSchema !== false) {
|
||||
itemSchema.validate(properties[x], report, instance, schema, x);
|
||||
} else {
|
||||
report.addError(instance, schema, "additionalProperties", "Additional items are not allowed", itemSchema);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
itemSchema = items || additionalProperties;
|
||||
for (x = 0, xl = properties.length; x < xl; ++x) {
|
||||
itemSchema.validate(properties[x], report, instance, schema, x);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"optional" : {
|
||||
"type" : "boolean",
|
||||
"optional" : true,
|
||||
"default" : false,
|
||||
|
||||
"parser" : function (instance, self) {
|
||||
return !!instance.getValue();
|
||||
},
|
||||
|
||||
"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
|
||||
if (instance.getType() === "undefined" && !schema.getAttribute("optional")) {
|
||||
report.addError(instance, schema, "optional", "Property is required", false);
|
||||
}
|
||||
},
|
||||
|
||||
"validationRequired" : true
|
||||
},
|
||||
|
||||
"additionalProperties" : {
|
||||
"type" : [{"$ref" : "#"}, "boolean"],
|
||||
"optional" : true,
|
||||
"default" : {},
|
||||
|
||||
"parser" : function (instance, self) {
|
||||
if (instance.getType() === "object") {
|
||||
return instance.getEnvironment().createSchema(instance, self.getEnvironment().findSchema(self.resolveURI("#")));
|
||||
} else if (instance.getType() === "boolean" && instance.getValue() === false) {
|
||||
return false;
|
||||
}
|
||||
//else
|
||||
return instance.getEnvironment().createEmptySchema();
|
||||
},
|
||||
|
||||
"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
|
||||
var additionalProperties, propertySchemas, properties, key;
|
||||
//we only need to check against object types as arrays do their own checking on this property
|
||||
if (instance.getType() === "object") {
|
||||
additionalProperties = schema.getAttribute("additionalProperties");
|
||||
propertySchemas = schema.getAttribute("properties") || {};
|
||||
properties = instance.getProperties();
|
||||
for (key in properties) {
|
||||
if (properties[key] !== O[key] && properties[key] && !propertySchemas[key]) {
|
||||
if (JSV.isJSONSchema(additionalProperties)) {
|
||||
additionalProperties.validate(properties[key], report, instance, schema, key);
|
||||
} else if (additionalProperties === false) {
|
||||
report.addError(instance, schema, "additionalProperties", "Additional properties are not allowed", additionalProperties);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"requires" : {
|
||||
"type" : ["string", {"$ref" : "#"}],
|
||||
"optional" : true,
|
||||
|
||||
"parser" : function (instance, self) {
|
||||
if (instance.getType() === "string") {
|
||||
return instance.getValue();
|
||||
} else if (instance.getType() === "object") {
|
||||
return instance.getEnvironment().createSchema(instance, self.getEnvironment().findSchema(self.resolveURI("#")));
|
||||
}
|
||||
},
|
||||
|
||||
"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
|
||||
var requires;
|
||||
if (instance.getType() !== "undefined" && parent && parent.getType() !== "undefined") {
|
||||
requires = schema.getAttribute("requires");
|
||||
if (typeof requires === "string") {
|
||||
if (parent.getProperty(requires).getType() === "undefined") {
|
||||
report.addError(instance, schema, "requires", 'Property requires sibling property "' + requires + '"', requires);
|
||||
}
|
||||
} else if (JSV.isJSONSchema(requires)) {
|
||||
requires.validate(parent, report); //WATCH: A "requires" schema does not support the "requires" attribute
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"minimum" : {
|
||||
"type" : "number",
|
||||
"optional" : true,
|
||||
|
||||
"parser" : function (instance, self) {
|
||||
if (instance.getType() === "number") {
|
||||
return instance.getValue();
|
||||
}
|
||||
},
|
||||
|
||||
"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
|
||||
var minimum, minimumCanEqual;
|
||||
if (instance.getType() === "number") {
|
||||
minimum = schema.getAttribute("minimum");
|
||||
minimumCanEqual = schema.getAttribute("minimumCanEqual");
|
||||
if (typeof minimum === "number" && (instance.getValue() < minimum || (minimumCanEqual === false && instance.getValue() === minimum))) {
|
||||
report.addError(instance, schema, "minimum", "Number is less than the required minimum value", minimum);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"maximum" : {
|
||||
"type" : "number",
|
||||
"optional" : true,
|
||||
|
||||
"parser" : function (instance, self) {
|
||||
if (instance.getType() === "number") {
|
||||
return instance.getValue();
|
||||
}
|
||||
},
|
||||
|
||||
"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
|
||||
var maximum, maximumCanEqual;
|
||||
if (instance.getType() === "number") {
|
||||
maximum = schema.getAttribute("maximum");
|
||||
maximumCanEqual = schema.getAttribute("maximumCanEqual");
|
||||
if (typeof maximum === "number" && (instance.getValue() > maximum || (maximumCanEqual === false && instance.getValue() === maximum))) {
|
||||
report.addError(instance, schema, "maximum", "Number is greater than the required maximum value", maximum);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"minimumCanEqual" : {
|
||||
"type" : "boolean",
|
||||
"optional" : true,
|
||||
"requires" : "minimum",
|
||||
"default" : true,
|
||||
|
||||
"parser" : function (instance, self) {
|
||||
if (instance.getType() === "boolean") {
|
||||
return instance.getValue();
|
||||
}
|
||||
//else
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
"maximumCanEqual" : {
|
||||
"type" : "boolean",
|
||||
"optional" : true,
|
||||
"requires" : "maximum",
|
||||
"default" : true,
|
||||
|
||||
"parser" : function (instance, self) {
|
||||
if (instance.getType() === "boolean") {
|
||||
return instance.getValue();
|
||||
}
|
||||
//else
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
"minItems" : {
|
||||
"type" : "integer",
|
||||
"optional" : true,
|
||||
"minimum" : 0,
|
||||
"default" : 0,
|
||||
|
||||
"parser" : function (instance, self) {
|
||||
if (instance.getType() === "number") {
|
||||
return instance.getValue();
|
||||
}
|
||||
//else
|
||||
return 0;
|
||||
},
|
||||
|
||||
"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
|
||||
var minItems;
|
||||
if (instance.getType() === "array") {
|
||||
minItems = schema.getAttribute("minItems");
|
||||
if (typeof minItems === "number" && instance.getProperties().length < minItems) {
|
||||
report.addError(instance, schema, "minItems", "The number of items is less than the required minimum", minItems);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"maxItems" : {
|
||||
"type" : "integer",
|
||||
"optional" : true,
|
||||
"minimum" : 0,
|
||||
|
||||
"parser" : function (instance, self) {
|
||||
if (instance.getType() === "number") {
|
||||
return instance.getValue();
|
||||
}
|
||||
},
|
||||
|
||||
"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
|
||||
var maxItems;
|
||||
if (instance.getType() === "array") {
|
||||
maxItems = schema.getAttribute("maxItems");
|
||||
if (typeof maxItems === "number" && instance.getProperties().length > maxItems) {
|
||||
report.addError(instance, schema, "maxItems", "The number of items is greater than the required maximum", maxItems);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"uniqueItems" : {
|
||||
"type" : "boolean",
|
||||
"optional" : true,
|
||||
"default" : false,
|
||||
|
||||
"parser" : function (instance, self) {
|
||||
return !!instance.getValue();
|
||||
},
|
||||
|
||||
"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
|
||||
var value, x, xl, y, yl;
|
||||
if (instance.getType() === "array" && schema.getAttribute("uniqueItems")) {
|
||||
value = instance.getProperties();
|
||||
for (x = 0, xl = value.length - 1; x < xl; ++x) {
|
||||
for (y = x + 1, yl = value.length; y < yl; ++y) {
|
||||
if (value[x].equals(value[y])) {
|
||||
report.addError(instance, schema, "uniqueItems", "Array can only contain unique items", { x : x, y : y });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"pattern" : {
|
||||
"type" : "string",
|
||||
"optional" : true,
|
||||
"format" : "regex",
|
||||
|
||||
"parser" : function (instance, self) {
|
||||
if (instance.getType() === "string") {
|
||||
return instance.getValue();
|
||||
}
|
||||
},
|
||||
|
||||
"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
|
||||
var pattern;
|
||||
try {
|
||||
pattern = new RegExp(schema.getAttribute("pattern"));
|
||||
if (instance.getType() === "string" && pattern && !pattern.test(instance.getValue())) {
|
||||
report.addError(instance, schema, "pattern", "String does not match pattern", pattern.toString());
|
||||
}
|
||||
} catch (e) {
|
||||
report.addError(instance, schema, "pattern", "Invalid pattern", e);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"minLength" : {
|
||||
"type" : "integer",
|
||||
"optional" : true,
|
||||
"minimum" : 0,
|
||||
"default" : 0,
|
||||
|
||||
"parser" : function (instance, self) {
|
||||
if (instance.getType() === "number") {
|
||||
return instance.getValue();
|
||||
}
|
||||
//else
|
||||
return 0;
|
||||
},
|
||||
|
||||
"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
|
||||
var minLength;
|
||||
if (instance.getType() === "string") {
|
||||
minLength = schema.getAttribute("minLength");
|
||||
if (typeof minLength === "number" && instance.getValue().length < minLength) {
|
||||
report.addError(instance, schema, "minLength", "String is less than the required minimum length", minLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"maxLength" : {
|
||||
"type" : "integer",
|
||||
"optional" : true,
|
||||
|
||||
"parser" : function (instance, self) {
|
||||
if (instance.getType() === "number") {
|
||||
return instance.getValue();
|
||||
}
|
||||
},
|
||||
|
||||
"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
|
||||
var maxLength;
|
||||
if (instance.getType() === "string") {
|
||||
maxLength = schema.getAttribute("maxLength");
|
||||
if (typeof maxLength === "number" && instance.getValue().length > maxLength) {
|
||||
report.addError(instance, schema, "maxLength", "String is greater than the required maximum length", maxLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"enum" : {
|
||||
"type" : "array",
|
||||
"optional" : true,
|
||||
"minItems" : 1,
|
||||
"uniqueItems" : true,
|
||||
|
||||
"parser" : function (instance, self) {
|
||||
if (instance.getType() === "array") {
|
||||
return instance.getValue();
|
||||
}
|
||||
},
|
||||
|
||||
"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
|
||||
var enums, x, xl;
|
||||
if (instance.getType() !== "undefined") {
|
||||
enums = schema.getAttribute("enum");
|
||||
if (enums) {
|
||||
for (x = 0, xl = enums.length; x < xl; ++x) {
|
||||
if (instance.equals(enums[x])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
report.addError(instance, schema, "enum", "Instance is not one of the possible values", enums);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"title" : {
|
||||
"type" : "string",
|
||||
"optional" : true
|
||||
},
|
||||
|
||||
"description" : {
|
||||
"type" : "string",
|
||||
"optional" : true
|
||||
},
|
||||
|
||||
"format" : {
|
||||
"type" : "string",
|
||||
"optional" : true,
|
||||
|
||||
"parser" : function (instance, self) {
|
||||
if (instance.getType() === "string") {
|
||||
return instance.getValue();
|
||||
}
|
||||
},
|
||||
|
||||
"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
|
||||
var format, formatValidators;
|
||||
if (instance.getType() === "string") {
|
||||
format = schema.getAttribute("format");
|
||||
formatValidators = self.getValueOfProperty("formatValidators");
|
||||
if (typeof format === "string" && formatValidators[format] !== O[format] && typeof formatValidators[format] === "function" && !formatValidators[format].call(this, instance, report)) {
|
||||
report.addError(instance, schema, "format", "String is not in the required format", format);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"formatValidators" : {}
|
||||
},
|
||||
|
||||
"contentEncoding" : {
|
||||
"type" : "string",
|
||||
"optional" : true
|
||||
},
|
||||
|
||||
"default" : {
|
||||
"type" : "any",
|
||||
"optional" : true
|
||||
},
|
||||
|
||||
"divisibleBy" : {
|
||||
"type" : "number",
|
||||
"minimum" : 0,
|
||||
"minimumCanEqual" : false,
|
||||
"optional" : true,
|
||||
|
||||
"parser" : function (instance, self) {
|
||||
if (instance.getType() === "number") {
|
||||
return instance.getValue();
|
||||
}
|
||||
},
|
||||
|
||||
"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
|
||||
var divisor;
|
||||
if (instance.getType() === "number") {
|
||||
divisor = schema.getAttribute("divisibleBy");
|
||||
if (divisor === 0) {
|
||||
report.addError(instance, schema, "divisibleBy", "Nothing is divisible by 0", divisor);
|
||||
} else if (divisor !== 1 && ((instance.getValue() / divisor) % 1) !== 0) {
|
||||
report.addError(instance, schema, "divisibleBy", "Number is not divisible by " + divisor, divisor);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"disallow" : {
|
||||
"type" : ["string", "array"],
|
||||
"items" : {"type" : "string"},
|
||||
"optional" : true,
|
||||
"uniqueItems" : true,
|
||||
|
||||
"parser" : function (instance, self) {
|
||||
if (instance.getType() === "string" || instance.getType() === "array") {
|
||||
return instance.getValue();
|
||||
}
|
||||
},
|
||||
|
||||
"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
|
||||
var disallowedTypes = JSV.toArray(schema.getAttribute("disallow")),
|
||||
x, xl, key, typeValidators;
|
||||
|
||||
//for instances that are required to be a certain type
|
||||
if (instance.getType() !== "undefined" && disallowedTypes && disallowedTypes.length) {
|
||||
typeValidators = self.getValueOfProperty("typeValidators") || {};
|
||||
|
||||
//ensure that type matches for at least one of the required types
|
||||
for (x = 0, xl = disallowedTypes.length; x < xl; ++x) {
|
||||
key = disallowedTypes[x];
|
||||
if (typeValidators[key] !== O[key] && typeof typeValidators[key] === "function") {
|
||||
if (typeValidators[key](instance, report)) {
|
||||
report.addError(instance, schema, "disallow", "Instance is a disallowed type", disallowedTypes);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/*
|
||||
else {
|
||||
report.addError(instance, schema, "disallow", "Instance may be a disallowed type", disallowedTypes);
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
//if we get to this point, type is valid
|
||||
return true;
|
||||
}
|
||||
//else, everything is allowed if no disallowed types are specified
|
||||
return true;
|
||||
},
|
||||
|
||||
"typeValidators" : TYPE_VALIDATORS
|
||||
},
|
||||
|
||||
"extends" : {
|
||||
"type" : [{"$ref" : "#"}, "array"],
|
||||
"items" : {"$ref" : "#"},
|
||||
"optional" : true,
|
||||
"default" : {},
|
||||
|
||||
"parser" : function (instance, self) {
|
||||
if (instance.getType() === "object") {
|
||||
return instance.getEnvironment().createSchema(instance, self.getEnvironment().findSchema(self.resolveURI("#")));
|
||||
} else if (instance.getType() === "array") {
|
||||
return JSV.mapArray(instance.getProperties(), function (instance) {
|
||||
return instance.getEnvironment().createSchema(instance, self.getEnvironment().findSchema(self.resolveURI("#")));
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
|
||||
var extensions = schema.getAttribute("extends"), x, xl;
|
||||
if (extensions) {
|
||||
if (JSV.isJSONSchema(extensions)) {
|
||||
extensions.validate(instance, report, parent, parentSchema, name);
|
||||
} else if (JSV.typeOf(extensions) === "array") {
|
||||
for (x = 0, xl = extensions.length; x < xl; ++x) {
|
||||
extensions[x].validate(instance, report, parent, parentSchema, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"optional" : true,
|
||||
"default" : {},
|
||||
"fragmentResolution" : "slash-delimited",
|
||||
|
||||
"parser" : function (instance, self) {
|
||||
if (instance.getType() === "object") {
|
||||
return instance.getEnvironment().createSchema(instance, self);
|
||||
}
|
||||
},
|
||||
|
||||
"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
|
||||
var propNames = schema.getPropertyNames(),
|
||||
x, xl,
|
||||
attributeSchemas = self.getAttribute("properties"),
|
||||
validator;
|
||||
|
||||
for (x in attributeSchemas) {
|
||||
if (attributeSchemas[x] !== O[x] && attributeSchemas[x].getValueOfProperty("validationRequired")) {
|
||||
JSV.pushUnique(propNames, x);
|
||||
}
|
||||
}
|
||||
|
||||
for (x = 0, xl = propNames.length; x < xl; ++x) {
|
||||
if (attributeSchemas[propNames[x]] !== O[propNames[x]]) {
|
||||
validator = attributeSchemas[propNames[x]].getValueOfProperty("validator");
|
||||
if (typeof validator === "function") {
|
||||
validator(instance, schema, attributeSchemas[propNames[x]], report, parent, parentSchema, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"initializer" : function (instance) {
|
||||
var link, extension, extended;
|
||||
|
||||
//if there is a link to a different schema, set reference
|
||||
link = instance._schema.getLink("describedby", instance);
|
||||
if (link && instance._schema._uri !== link) {
|
||||
instance.setReference("describedby", link);
|
||||
}
|
||||
|
||||
//if instance has a URI link to itself, update it's own URI
|
||||
link = instance._schema.getLink("self", instance);
|
||||
if (JSV.typeOf(link) === "string") {
|
||||
instance._uri = JSV.formatURI(link);
|
||||
}
|
||||
|
||||
//if there is a link to the full representation, set reference
|
||||
link = instance._schema.getLink("full", instance);
|
||||
if (link && instance._uri !== link) {
|
||||
instance.setReference("full", link);
|
||||
}
|
||||
|
||||
//extend schema
|
||||
extension = instance.getAttribute("extends");
|
||||
if (JSV.isJSONSchema(extension)) {
|
||||
extended = JSV.inherits(extension, instance, true);
|
||||
instance = instance._env.createSchema(extended, instance._schema, instance._uri);
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
}, true, "http://json-schema.org/schema#");
|
||||
|
||||
HYPERSCHEMA = ENVIRONMENT.createSchema(JSV.inherits(SCHEMA, ENVIRONMENT.createSchema({
|
||||
"$schema" : "http://json-schema.org/hyper-schema#",
|
||||
"id" : "http://json-schema.org/hyper-schema#",
|
||||
|
||||
"properties" : {
|
||||
"links" : {
|
||||
"type" : "array",
|
||||
"items" : {"$ref" : "links#"},
|
||||
"optional" : true,
|
||||
|
||||
"parser" : function (instance, self, arg) {
|
||||
var links,
|
||||
linkSchemaURI = self.getValueOfProperty("items")["$ref"],
|
||||
linkSchema = self.getEnvironment().findSchema(linkSchemaURI),
|
||||
linkParser = linkSchema && linkSchema.getValueOfProperty("parser");
|
||||
arg = JSV.toArray(arg);
|
||||
|
||||
if (typeof linkParser === "function") {
|
||||
links = JSV.mapArray(instance.getProperties(), function (link) {
|
||||
return linkParser(link, linkSchema);
|
||||
});
|
||||
} else {
|
||||
links = JSV.toArray(instance.getValue());
|
||||
}
|
||||
|
||||
if (arg[0]) {
|
||||
links = JSV.filterArray(links, function (link) {
|
||||
return link["rel"] === arg[0];
|
||||
});
|
||||
}
|
||||
|
||||
if (arg[1]) {
|
||||
links = JSV.mapArray(links, function (link) {
|
||||
var instance = arg[1],
|
||||
href = link["href"];
|
||||
href = href.replace(/\{(.+)\}/g, function (str, p1, offset, s) {
|
||||
var value;
|
||||
if (p1 === "-this") {
|
||||
value = instance.getValue();
|
||||
} else {
|
||||
value = instance.getValueOfProperty(p1);
|
||||
}
|
||||
return value !== undefined ? String(value) : "";
|
||||
});
|
||||
return href ? JSV.formatURI(instance.resolveURI(href)) : href;
|
||||
});
|
||||
}
|
||||
|
||||
return links;
|
||||
}
|
||||
},
|
||||
|
||||
"fragmentResolution" : {
|
||||
"type" : "string",
|
||||
"optional" : true,
|
||||
"default" : "slash-delimited"
|
||||
},
|
||||
|
||||
"root" : {
|
||||
"type" : "boolean",
|
||||
"optional" : true,
|
||||
"default" : false
|
||||
},
|
||||
|
||||
"readonly" : {
|
||||
"type" : "boolean",
|
||||
"optional" : true,
|
||||
"default" : false
|
||||
},
|
||||
|
||||
"pathStart" : {
|
||||
"type" : "string",
|
||||
"optional" : true,
|
||||
"format" : "uri",
|
||||
|
||||
"validator" : function (instance, schema, self, report, parent, parentSchema, name) {
|
||||
var pathStart;
|
||||
if (instance.getType() !== "undefined") {
|
||||
pathStart = schema.getAttribute("pathStart");
|
||||
if (typeof pathStart === "string") {
|
||||
//TODO: Find out what pathStart is relative to
|
||||
if (instance.getURI().indexOf(pathStart) !== 0) {
|
||||
report.addError(instance, schema, "pathStart", "Instance's URI does not start with " + pathStart, pathStart);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"mediaType" : {
|
||||
"type" : "string",
|
||||
"optional" : true,
|
||||
"format" : "media-type"
|
||||
},
|
||||
|
||||
"alternate" : {
|
||||
"type" : "array",
|
||||
"items" : {"$ref" : "#"},
|
||||
"optional" : true
|
||||
}
|
||||
},
|
||||
|
||||
"links" : [
|
||||
{
|
||||
"href" : "{$ref}",
|
||||
"rel" : "full"
|
||||
},
|
||||
|
||||
{
|
||||
"href" : "{$schema}",
|
||||
"rel" : "describedby"
|
||||
},
|
||||
|
||||
{
|
||||
"href" : "{id}",
|
||||
"rel" : "self"
|
||||
}
|
||||
]//,
|
||||
|
||||
//not needed as JSV.inherits does the job for us
|
||||
//"extends" : {"$ref" : "http://json-schema.org/schema#"}
|
||||
}, SCHEMA), true), true, "http://json-schema.org/hyper-schema#");
|
||||
|
||||
ENVIRONMENT.setOption("defaultSchemaURI", "http://json-schema.org/hyper-schema#");
|
||||
|
||||
LINKS = ENVIRONMENT.createSchema({
|
||||
"$schema" : "http://json-schema.org/hyper-schema#",
|
||||
"id" : "http://json-schema.org/links#",
|
||||
"type" : "object",
|
||||
|
||||
"properties" : {
|
||||
"href" : {
|
||||
"type" : "string"
|
||||
},
|
||||
|
||||
"rel" : {
|
||||
"type" : "string"
|
||||
},
|
||||
|
||||
"targetSchema" : {
|
||||
"$ref" : "hyper-schema#",
|
||||
|
||||
//need this here because parsers are run before links are resolved
|
||||
"parser" : HYPERSCHEMA.getAttribute("parser")
|
||||
},
|
||||
|
||||
"method" : {
|
||||
"type" : "string",
|
||||
"default" : "GET",
|
||||
"optional" : true
|
||||
},
|
||||
|
||||
"enctype" : {
|
||||
"type" : "string",
|
||||
"requires" : "method",
|
||||
"optional" : true
|
||||
},
|
||||
|
||||
"properties" : {
|
||||
"type" : "object",
|
||||
"additionalProperties" : {"$ref" : "hyper-schema#"},
|
||||
"optional" : true,
|
||||
|
||||
"parser" : function (instance, self, arg) {
|
||||
var env = instance.getEnvironment(),
|
||||
selfEnv = self.getEnvironment(),
|
||||
additionalPropertiesSchemaURI = self.getValueOfProperty("additionalProperties")["$ref"];
|
||||
if (instance.getType() === "object") {
|
||||
if (arg) {
|
||||
return env.createSchema(instance.getProperty(arg), selfEnv.findSchema(self.resolveURI(additionalPropertiesSchemaURI)));
|
||||
} else {
|
||||
return JSV.mapObject(instance.getProperties(), function (instance) {
|
||||
return env.createSchema(instance, selfEnv.findSchema(self.resolveURI(additionalPropertiesSchemaURI)));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"parser" : function (instance, self) {
|
||||
var selfProperties = self.getProperty("properties");
|
||||
if (instance.getType() === "object") {
|
||||
return JSV.mapObject(instance.getProperties(), function (property, key) {
|
||||
var propertySchema = selfProperties.getProperty(key),
|
||||
parser = propertySchema && propertySchema.getValueOfProperty("parser");
|
||||
if (typeof parser === "function") {
|
||||
return parser(property, propertySchema);
|
||||
}
|
||||
//else
|
||||
return property.getValue();
|
||||
});
|
||||
}
|
||||
return instance.getValue();
|
||||
}
|
||||
}, HYPERSCHEMA, "http://json-schema.org/links#");
|
||||
|
||||
JSV.registerEnvironment("json-schema-draft-02", ENVIRONMENT);
|
||||
if (!JSV.getDefaultEnvironmentID() || JSV.getDefaultEnvironmentID() === "json-schema-draft-01") {
|
||||
JSV.setDefaultEnvironmentID("json-schema-draft-02");
|
||||
}
|
||||
|
||||
}());
|
||||
+1552
File diff suppressed because it is too large
Load Diff
+1497
File diff suppressed because it is too large
Load Diff
+86
@@ -0,0 +1,86 @@
|
||||
(function () {
|
||||
var URI_NS = require("../uri"),
|
||||
URI = URI_NS.URI,
|
||||
pctEncChar = URI_NS.pctEncChar,
|
||||
NID$ = "(?:[0-9A-Za-z][0-9A-Za-z\\-]{1,31})",
|
||||
PCT_ENCODED$ = "(?:\\%[0-9A-Fa-f]{2})",
|
||||
TRANS$$ = "[0-9A-Za-z\\(\\)\\+\\,\\-\\.\\:\\=\\@\\;\\$\\_\\!\\*\\'\\/\\?\\#]",
|
||||
NSS$ = "(?:(?:" + PCT_ENCODED$ + "|" + TRANS$$ + ")+)",
|
||||
URN_SCHEME = new RegExp("^urn\\:(" + NID$ + ")$"),
|
||||
URN_PATH = new RegExp("^(" + NID$ + ")\\:(" + NSS$ + ")$"),
|
||||
URN_PARSE = /^([^\:]+)\:(.*)/,
|
||||
URN_EXCLUDED = /[\x00-\x20\\\"\&\<\>\[\]\^\`\{\|\}\~\x7F-\xFF]/g,
|
||||
UUID = /^[0-9A-Fa-f]{8}(?:\-[0-9A-Fa-f]{4}){3}\-[0-9A-Fa-f]{12}$/;
|
||||
|
||||
//RFC 2141
|
||||
URI.SCHEMES["urn"] = {
|
||||
parse : function (components, options) {
|
||||
var matches = components.path.match(URN_PATH),
|
||||
scheme, schemeHandler;
|
||||
|
||||
if (!matches) {
|
||||
if (!options.tolerant) {
|
||||
components.errors.push("URN is not strictly valid.");
|
||||
}
|
||||
|
||||
matches = components.path.match(URN_PARSE);
|
||||
}
|
||||
|
||||
if (matches) {
|
||||
scheme = "urn:" + matches[1].toLowerCase();
|
||||
schemeHandler = URI.SCHEMES[scheme];
|
||||
|
||||
//in order to serialize properly,
|
||||
//every URN must have a serializer that calls the URN serializer
|
||||
if (!schemeHandler) {
|
||||
schemeHandler = URI.SCHEMES[scheme] = {};
|
||||
}
|
||||
if (!schemeHandler.serialize) {
|
||||
schemeHandler.serialize = URI.SCHEMES["urn"].serialize;
|
||||
}
|
||||
|
||||
components.scheme = scheme;
|
||||
components.path = matches[2];
|
||||
|
||||
if (schemeHandler.parse) {
|
||||
schemeHandler.parse(components, options);
|
||||
}
|
||||
} else {
|
||||
components.errors.push("URN can not be parsed.");
|
||||
}
|
||||
|
||||
return components;
|
||||
},
|
||||
|
||||
serialize : function (components, options) {
|
||||
var scheme = components.scheme || options.scheme,
|
||||
matches;
|
||||
|
||||
if (scheme && scheme !== "urn") {
|
||||
var matches = scheme.match(URN_SCHEME);
|
||||
|
||||
if (!matches) {
|
||||
matches = ["urn:" + scheme, scheme];
|
||||
}
|
||||
|
||||
components.scheme = "urn";
|
||||
components.path = matches[1] + ":" + (components.path ? components.path.replace(URN_EXCLUDED, pctEncChar) : "");
|
||||
}
|
||||
|
||||
return components;
|
||||
}
|
||||
};
|
||||
|
||||
//RFC 4122
|
||||
URI.SCHEMES["urn:uuid"] = {
|
||||
serialize : function (components, options) {
|
||||
//ensure UUID is valid
|
||||
if (!options.tolerant && (!components.path || !components.path.match(UUID))) {
|
||||
//invalid UUIDs can not have this scheme
|
||||
components.scheme = undefined;
|
||||
}
|
||||
|
||||
return URI.SCHEMES["urn"].serialize(components, options);
|
||||
}
|
||||
};
|
||||
}());
|
||||
+710
@@ -0,0 +1,710 @@
|
||||
/**
|
||||
* URI.js
|
||||
*
|
||||
* @fileoverview An RFC 3986 compliant, scheme extendable URI parsing/validating/resolving library for JavaScript.
|
||||
* @author <a href="mailto:gary.court@gmail.com">Gary Court</a>
|
||||
* @version 1.3
|
||||
* @see http://github.com/garycourt/uri-js
|
||||
* @license URI.js v1.3 (c) 2010 Gary Court. License: http://github.com/garycourt/uri-js
|
||||
*/
|
||||
|
||||
/**
|
||||
* Copyright 2010 Gary Court. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY GARY COURT ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GARY COURT OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of Gary Court.
|
||||
*/
|
||||
|
||||
/*jslint white: true, sub: true, onevar: true, undef: true, eqeqeq: true, newcap: true, immed: true, indent: 4 */
|
||||
/*global exports:true, require:true */
|
||||
|
||||
if (typeof exports === "undefined") {
|
||||
exports = {};
|
||||
}
|
||||
if (typeof require !== "function") {
|
||||
require = function (id) {
|
||||
return exports;
|
||||
};
|
||||
}
|
||||
(function () {
|
||||
var
|
||||
/**
|
||||
* @param {...string} sets
|
||||
* @return {string}
|
||||
*/
|
||||
mergeSet = function (sets) {
|
||||
var set = arguments[0],
|
||||
x = 1,
|
||||
nextSet = arguments[x];
|
||||
|
||||
while (nextSet) {
|
||||
set = set.slice(0, -1) + nextSet.slice(1);
|
||||
nextSet = arguments[++x];
|
||||
}
|
||||
|
||||
return set;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {string} str
|
||||
* @return {string}
|
||||
*/
|
||||
subexp = function (str) {
|
||||
return "(?:" + str + ")";
|
||||
},
|
||||
|
||||
ALPHA$$ = "[A-Za-z]",
|
||||
CR$ = "[\\x0D]",
|
||||
DIGIT$$ = "[0-9]",
|
||||
DQUOTE$$ = "[\\x22]",
|
||||
HEXDIG$$ = mergeSet(DIGIT$$, "[A-Fa-f]"), //case-insensitive
|
||||
LF$$ = "[\\x0A]",
|
||||
SP$$ = "[\\x20]",
|
||||
PCT_ENCODED$ = subexp("%" + HEXDIG$$ + HEXDIG$$),
|
||||
GEN_DELIMS$$ = "[\\:\\/\\?\\#\\[\\]\\@]",
|
||||
SUB_DELIMS$$ = "[\\!\\$\\&\\'\\(\\)\\*\\+\\,\\;\\=]",
|
||||
RESERVED$$ = mergeSet(GEN_DELIMS$$, SUB_DELIMS$$),
|
||||
UNRESERVED$$ = mergeSet(ALPHA$$, DIGIT$$, "[\\-\\.\\_\\~]"),
|
||||
SCHEME$ = subexp(ALPHA$$ + mergeSet(ALPHA$$, DIGIT$$, "[\\+\\-\\.]") + "*"),
|
||||
USERINFO$ = subexp(subexp(PCT_ENCODED$ + "|" + mergeSet(UNRESERVED$$, SUB_DELIMS$$, "[\\:]")) + "*"),
|
||||
DEC_OCTET$ = subexp(subexp("25[0-5]") + "|" + subexp("2[0-4]" + DIGIT$$) + "|" + subexp("1" + DIGIT$$ + DIGIT$$) + "|" + subexp("[1-9]" + DIGIT$$) + "|" + DIGIT$$),
|
||||
IPV4ADDRESS$ = subexp(DEC_OCTET$ + "\\." + DEC_OCTET$ + "\\." + DEC_OCTET$ + "\\." + DEC_OCTET$),
|
||||
H16$ = subexp(HEXDIG$$ + "{1,4}"),
|
||||
LS32$ = subexp(subexp(H16$ + "\\:" + H16$) + "|" + IPV4ADDRESS$),
|
||||
IPV6ADDRESS$ = subexp(mergeSet(UNRESERVED$$, SUB_DELIMS$$, "[\\:]") + "+"), //FIXME
|
||||
IPVFUTURE$ = subexp("v" + HEXDIG$$ + "+\\." + mergeSet(UNRESERVED$$, SUB_DELIMS$$, "[\\:]") + "+"),
|
||||
IP_LITERAL$ = subexp("\\[" + subexp(IPV6ADDRESS$ + "|" + IPVFUTURE$) + "\\]"),
|
||||
REG_NAME$ = subexp(subexp(PCT_ENCODED$ + "|" + mergeSet(UNRESERVED$$, SUB_DELIMS$$)) + "*"),
|
||||
HOST$ = subexp(IP_LITERAL$ + "|" + IPV4ADDRESS$ + "|" + REG_NAME$),
|
||||
PORT$ = subexp(DIGIT$$ + "*"),
|
||||
AUTHORITY$ = subexp(subexp(USERINFO$ + "@") + "?" + HOST$ + subexp("\\:" + PORT$) + "?"),
|
||||
PCHAR$ = subexp(PCT_ENCODED$ + "|" + mergeSet(UNRESERVED$$, SUB_DELIMS$$, "[\\:\\@]")),
|
||||
SEGMENT$ = subexp(PCHAR$ + "*"),
|
||||
SEGMENT_NZ$ = subexp(PCHAR$ + "+"),
|
||||
SEGMENT_NZ_NC$ = subexp(subexp(PCT_ENCODED$ + "|" + mergeSet(UNRESERVED$$, SUB_DELIMS$$, "[\\@]")) + "+"),
|
||||
PATH_ABEMPTY$ = subexp(subexp("\\/" + SEGMENT$) + "*"),
|
||||
PATH_ABSOLUTE$ = subexp("\\/" + subexp(SEGMENT_NZ$ + PATH_ABEMPTY$) + "?"), //simplified
|
||||
PATH_NOSCHEME$ = subexp(SEGMENT_NZ_NC$ + PATH_ABEMPTY$), //simplified
|
||||
PATH_ROOTLESS$ = subexp(SEGMENT_NZ$ + PATH_ABEMPTY$), //simplified
|
||||
PATH_EMPTY$ = subexp(""), //simplified
|
||||
PATH$ = subexp(PATH_ABEMPTY$ + "|" + PATH_ABSOLUTE$ + "|" + PATH_NOSCHEME$ + "|" + PATH_ROOTLESS$ + "|" + PATH_EMPTY$),
|
||||
QUERY$ = subexp(subexp(PCHAR$ + "|[\\/\\?]") + "*"),
|
||||
FRAGMENT$ = subexp(subexp(PCHAR$ + "|[\\/\\?]") + "*"),
|
||||
HIER_PART$ = subexp(subexp("\\/\\/" + AUTHORITY$ + PATH_ABEMPTY$) + "|" + PATH_ABSOLUTE$ + "|" + PATH_ROOTLESS$ + "|" + PATH_EMPTY$),
|
||||
URI$ = subexp(SCHEME$ + "\\:" + HIER_PART$ + subexp("\\?" + QUERY$) + "?" + subexp("\\#" + FRAGMENT$) + "?"),
|
||||
RELATIVE_PART$ = subexp(subexp("\\/\\/" + AUTHORITY$ + PATH_ABEMPTY$) + "|" + PATH_ABSOLUTE$ + "|" + PATH_NOSCHEME$ + "|" + PATH_EMPTY$),
|
||||
RELATIVE_REF$ = subexp(RELATIVE_PART$ + subexp("\\?" + QUERY$) + "?" + subexp("\\#" + FRAGMENT$) + "?"),
|
||||
URI_REFERENCE$ = subexp(URI$ + "|" + RELATIVE_REF$),
|
||||
ABSOLUTE_URI$ = subexp(SCHEME$ + "\\:" + HIER_PART$ + subexp("\\?" + QUERY$) + "?"),
|
||||
|
||||
URI_REF = new RegExp("^" + subexp("(" + URI$ + ")|(" + RELATIVE_REF$ + ")") + "$"),
|
||||
GENERIC_REF = new RegExp("^(" + SCHEME$ + ")\\:" + subexp(subexp("\\/\\/(" + subexp("(" + USERINFO$ + ")@") + "?(" + HOST$ + ")" + subexp("\\:(" + PORT$ + ")") + "?)") + "?(" + PATH_ABEMPTY$ + "|" + PATH_ABSOLUTE$ + "|" + PATH_ROOTLESS$ + "|" + PATH_EMPTY$ + ")") + subexp("\\?(" + QUERY$ + ")") + "?" + subexp("\\#(" + FRAGMENT$ + ")") + "?$"),
|
||||
RELATIVE_REF = new RegExp("^(){0}" + subexp(subexp("\\/\\/(" + subexp("(" + USERINFO$ + ")@") + "?(" + HOST$ + ")" + subexp("\\:(" + PORT$ + ")") + "?)") + "?(" + PATH_ABEMPTY$ + "|" + PATH_ABSOLUTE$ + "|" + PATH_NOSCHEME$ + "|" + PATH_EMPTY$ + ")") + subexp("\\?(" + QUERY$ + ")") + "?" + subexp("\\#(" + FRAGMENT$ + ")") + "?$"),
|
||||
ABSOLUTE_REF = new RegExp("^(" + SCHEME$ + ")\\:" + subexp(subexp("\\/\\/(" + subexp("(" + USERINFO$ + ")@") + "?(" + HOST$ + ")" + subexp("\\:(" + PORT$ + ")") + "?)") + "?(" + PATH_ABEMPTY$ + "|" + PATH_ABSOLUTE$ + "|" + PATH_ROOTLESS$ + "|" + PATH_EMPTY$ + ")") + subexp("\\?(" + QUERY$ + ")") + "?$"),
|
||||
SAMEDOC_REF = new RegExp("^" + subexp("\\#(" + FRAGMENT$ + ")") + "?$"),
|
||||
AUTHORITY = new RegExp("^" + subexp("(" + USERINFO$ + ")@") + "?(" + HOST$ + ")" + subexp("\\:(" + PORT$ + ")") + "?$"),
|
||||
|
||||
NOT_SCHEME = new RegExp(mergeSet("[^]", ALPHA$$, DIGIT$$, "[\\+\\-\\.]"), "g"),
|
||||
NOT_USERINFO = new RegExp(mergeSet("[^\\%\\:]", UNRESERVED$$, SUB_DELIMS$$), "g"),
|
||||
NOT_HOST = new RegExp(mergeSet("[^\\%]", UNRESERVED$$, SUB_DELIMS$$), "g"),
|
||||
NOT_PATH = new RegExp(mergeSet("[^\\%\\/\\:\\@]", UNRESERVED$$, SUB_DELIMS$$), "g"),
|
||||
NOT_PATH_NOSCHEME = new RegExp(mergeSet("[^\\%\\/\\@]", UNRESERVED$$, SUB_DELIMS$$), "g"),
|
||||
NOT_QUERY = new RegExp(mergeSet("[^\\%]", UNRESERVED$$, SUB_DELIMS$$, "[\\:\\@\\/\\?]"), "g"),
|
||||
NOT_FRAGMENT = NOT_QUERY,
|
||||
ESCAPE = new RegExp(mergeSet("[^]", UNRESERVED$$, SUB_DELIMS$$), "g"),
|
||||
UNRESERVED = new RegExp(UNRESERVED$$, "g"),
|
||||
OTHER_CHARS = new RegExp(mergeSet("[^\\%]", UNRESERVED$$, RESERVED$$), "g"),
|
||||
PCT_ENCODEDS = new RegExp(PCT_ENCODED$ + "+", "g"),
|
||||
URI_PARSE = /^(?:([^:\/?#]+):)?(?:\/\/((?:([^\/?#@]*)@)?([^\/?#:]*)(?:\:(\d*))?))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?/i,
|
||||
RDS1 = /^\.\.?\//,
|
||||
RDS2 = /^\/\.(\/|$)/,
|
||||
RDS3 = /^\/\.\.(\/|$)/,
|
||||
RDS4 = /^\.\.?$/,
|
||||
RDS5 = /^\/?.*?(?=\/|$)/,
|
||||
NO_MATCH_IS_UNDEFINED = ("").match(/(){0}/)[1] === undefined,
|
||||
|
||||
/**
|
||||
* @param {string} chr
|
||||
* @return {string}
|
||||
*/
|
||||
pctEncChar = function (chr) {
|
||||
var c = chr.charCodeAt(0);
|
||||
|
||||
if (c < 128) {
|
||||
return "%" + c.toString(16).toUpperCase();
|
||||
}
|
||||
else if ((c > 127) && (c < 2048)) {
|
||||
return "%" + ((c >> 6) | 192).toString(16).toUpperCase() + "%" + ((c & 63) | 128).toString(16).toUpperCase();
|
||||
}
|
||||
else {
|
||||
return "%" + ((c >> 12) | 224).toString(16).toUpperCase() + "%" + (((c >> 6) & 63) | 128).toString(16).toUpperCase() + "%" + ((c & 63) | 128).toString(16).toUpperCase();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {string} str
|
||||
* @return {string}
|
||||
*/
|
||||
pctDecUnreserved = function (str) {
|
||||
var newStr = "",
|
||||
i = 0,
|
||||
c, s;
|
||||
|
||||
while (i < str.length) {
|
||||
c = parseInt(str.substr(i + 1, 2), 16);
|
||||
|
||||
if (c < 128) {
|
||||
s = String.fromCharCode(c);
|
||||
if (s.match(UNRESERVED)) {
|
||||
newStr += s;
|
||||
} else {
|
||||
newStr += str.substr(i, 3);
|
||||
}
|
||||
i += 3;
|
||||
}
|
||||
else if ((c > 191) && (c < 224)) {
|
||||
newStr += str.substr(i, 6);
|
||||
i += 6;
|
||||
}
|
||||
else {
|
||||
newStr += str.substr(i, 9);
|
||||
i += 9;
|
||||
}
|
||||
}
|
||||
|
||||
return newStr;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {string} str
|
||||
* @return {string}
|
||||
*/
|
||||
pctDecChars = function (str) {
|
||||
var newStr = "",
|
||||
i = 0,
|
||||
c, c2, c3;
|
||||
|
||||
while (i < str.length) {
|
||||
c = parseInt(str.substr(i + 1, 2), 16);
|
||||
|
||||
if (c < 128) {
|
||||
newStr += String.fromCharCode(c);
|
||||
i += 3;
|
||||
}
|
||||
else if ((c > 191) && (c < 224)) {
|
||||
c2 = parseInt(str.substr(i + 4, 2), 16);
|
||||
newStr += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
|
||||
i += 6;
|
||||
}
|
||||
else {
|
||||
c2 = parseInt(str.substr(i + 4, 2), 16);
|
||||
c3 = parseInt(str.substr(i + 7, 2), 16);
|
||||
newStr += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
|
||||
i += 9;
|
||||
}
|
||||
}
|
||||
|
||||
return newStr;
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {string}
|
||||
*/
|
||||
typeOf = function (o) {
|
||||
return o === undefined ? "undefined" : (o === null ? "null" : Object.prototype.toString.call(o).split(" ").pop().split("]").shift().toLowerCase());
|
||||
},
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @implements URIComponents
|
||||
*/
|
||||
Components = function () {
|
||||
this.errors = [];
|
||||
},
|
||||
|
||||
/** @namespace */
|
||||
URI = exports;
|
||||
|
||||
/**
|
||||
* Components
|
||||
*/
|
||||
|
||||
Components.prototype = {
|
||||
/**
|
||||
* @type String
|
||||
*/
|
||||
|
||||
scheme : undefined,
|
||||
|
||||
/**
|
||||
* @type String
|
||||
*/
|
||||
|
||||
authority : undefined,
|
||||
|
||||
/**
|
||||
* @type String
|
||||
*/
|
||||
|
||||
userinfo : undefined,
|
||||
|
||||
/**
|
||||
* @type String
|
||||
*/
|
||||
|
||||
host : undefined,
|
||||
|
||||
/**
|
||||
* @type number
|
||||
*/
|
||||
|
||||
port : undefined,
|
||||
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
|
||||
path : undefined,
|
||||
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
|
||||
query : undefined,
|
||||
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
|
||||
fragment : undefined,
|
||||
|
||||
/**
|
||||
* @type string
|
||||
* @values "uri", "absolute", "relative", "same-document"
|
||||
*/
|
||||
|
||||
reference : undefined,
|
||||
|
||||
/**
|
||||
* @type Array
|
||||
*/
|
||||
|
||||
errors : undefined
|
||||
};
|
||||
|
||||
/**
|
||||
* URI
|
||||
*/
|
||||
|
||||
/**
|
||||
* @namespace
|
||||
*/
|
||||
|
||||
URI.SCHEMES = {};
|
||||
|
||||
/**
|
||||
* @param {string} uriString
|
||||
* @param {Options} [options]
|
||||
* @returns {URIComponents}
|
||||
*/
|
||||
|
||||
URI.parse = function (uriString, options) {
|
||||
var matches,
|
||||
components = new Components(),
|
||||
schemeHandler;
|
||||
|
||||
uriString = uriString ? uriString.toString() : "";
|
||||
options = options || {};
|
||||
|
||||
if (options.reference === "suffix") {
|
||||
uriString = (options.scheme ? options.scheme + ":" : "") + "//" + uriString;
|
||||
}
|
||||
|
||||
matches = uriString.match(URI_REF);
|
||||
|
||||
if (matches) {
|
||||
if (matches[1]) {
|
||||
//generic URI
|
||||
matches = uriString.match(GENERIC_REF);
|
||||
} else {
|
||||
//relative URI
|
||||
matches = uriString.match(RELATIVE_REF);
|
||||
}
|
||||
}
|
||||
|
||||
if (!matches) {
|
||||
if (!options.tolerant) {
|
||||
components.errors.push("URI is not strictly valid.");
|
||||
}
|
||||
matches = uriString.match(URI_PARSE);
|
||||
}
|
||||
|
||||
if (matches) {
|
||||
if (NO_MATCH_IS_UNDEFINED) {
|
||||
//store each component
|
||||
components.scheme = matches[1];
|
||||
components.authority = matches[2];
|
||||
components.userinfo = matches[3];
|
||||
components.host = matches[4];
|
||||
components.port = parseInt(matches[5], 10);
|
||||
components.path = matches[6] || "";
|
||||
components.query = matches[7];
|
||||
components.fragment = matches[8];
|
||||
|
||||
//fix port number
|
||||
if (isNaN(components.port)) {
|
||||
components.port = matches[5];
|
||||
}
|
||||
} else { //IE FIX for improper RegExp matching
|
||||
//store each component
|
||||
components.scheme = matches[1] || undefined;
|
||||
components.authority = (uriString.indexOf("//") !== -1 ? matches[2] : undefined);
|
||||
components.userinfo = (uriString.indexOf("@") !== -1 ? matches[3] : undefined);
|
||||
components.host = (uriString.indexOf("//") !== -1 ? matches[4] : undefined);
|
||||
components.port = parseInt(matches[5], 10);
|
||||
components.path = matches[6] || "";
|
||||
components.query = (uriString.indexOf("?") !== -1 ? matches[7] : undefined);
|
||||
components.fragment = (uriString.indexOf("#") !== -1 ? matches[8] : undefined);
|
||||
|
||||
//fix port number
|
||||
if (isNaN(components.port)) {
|
||||
components.port = (uriString.match(/\/\/.*\:(?:\/|\?|\#|$)/) ? matches[4] : undefined);
|
||||
}
|
||||
}
|
||||
|
||||
//determine reference type
|
||||
if (!components.scheme && !components.authority && !components.path && !components.query) {
|
||||
components.reference = "same-document";
|
||||
} else if (!components.scheme) {
|
||||
components.reference = "relative";
|
||||
} else if (!components.fragment) {
|
||||
components.reference = "absolute";
|
||||
} else {
|
||||
components.reference = "uri";
|
||||
}
|
||||
|
||||
//check for reference errors
|
||||
if (options.reference && options.reference !== "suffix" && options.reference !== components.reference) {
|
||||
components.errors.push("URI is not a " + options.reference + " reference.");
|
||||
}
|
||||
|
||||
//check if a handler for the scheme exists
|
||||
schemeHandler = URI.SCHEMES[(components.scheme || options.scheme || "").toLowerCase()];
|
||||
if (schemeHandler && schemeHandler.parse) {
|
||||
//perform extra parsing
|
||||
schemeHandler.parse(components, options);
|
||||
}
|
||||
} else {
|
||||
components.errors.push("URI can not be parsed.");
|
||||
}
|
||||
|
||||
return components;
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {URIComponents} components
|
||||
* @returns {string|undefined}
|
||||
*/
|
||||
|
||||
URI._recomposeAuthority = function (components) {
|
||||
var uriTokens = [];
|
||||
|
||||
if (components.userinfo !== undefined || components.host !== undefined || typeof components.port === "number") {
|
||||
if (components.userinfo !== undefined) {
|
||||
uriTokens.push(components.userinfo.toString().replace(NOT_USERINFO, pctEncChar));
|
||||
uriTokens.push("@");
|
||||
}
|
||||
if (components.host !== undefined) {
|
||||
uriTokens.push(components.host.toString().toLowerCase().replace(NOT_HOST, pctEncChar));
|
||||
}
|
||||
if (typeof components.port === "number") {
|
||||
uriTokens.push(":");
|
||||
uriTokens.push(components.port.toString(10));
|
||||
}
|
||||
}
|
||||
|
||||
return uriTokens.length ? uriTokens.join("") : undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @returns {string}
|
||||
*/
|
||||
|
||||
URI.removeDotSegments = function (input) {
|
||||
var output = [], s;
|
||||
|
||||
while (input.length) {
|
||||
if (input.match(RDS1)) {
|
||||
input = input.replace(RDS1, "");
|
||||
} else if (input.match(RDS2)) {
|
||||
input = input.replace(RDS2, "/");
|
||||
} else if (input.match(RDS3)) {
|
||||
input = input.replace(RDS3, "/");
|
||||
output.pop();
|
||||
} else if (input === "." || input === "..") {
|
||||
input = "";
|
||||
} else {
|
||||
s = input.match(RDS5)[0];
|
||||
input = input.slice(s.length);
|
||||
output.push(s);
|
||||
}
|
||||
}
|
||||
|
||||
return output.join("");
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {URIComponents} components
|
||||
* @param {Options} [options]
|
||||
* @returns {string}
|
||||
*/
|
||||
|
||||
URI.serialize = function (components, options) {
|
||||
var uriTokens = [],
|
||||
schemeHandler,
|
||||
s;
|
||||
options = options || {};
|
||||
|
||||
//check if a handler for the scheme exists
|
||||
schemeHandler = URI.SCHEMES[components.scheme || options.scheme];
|
||||
if (schemeHandler && schemeHandler.serialize) {
|
||||
//perform extra serialization
|
||||
schemeHandler.serialize(components, options);
|
||||
}
|
||||
|
||||
if (options.reference !== "suffix" && components.scheme) {
|
||||
uriTokens.push(components.scheme.toString().toLowerCase().replace(NOT_SCHEME, ""));
|
||||
uriTokens.push(":");
|
||||
}
|
||||
|
||||
components.authority = URI._recomposeAuthority(components);
|
||||
if (components.authority !== undefined) {
|
||||
if (options.reference !== "suffix") {
|
||||
uriTokens.push("//");
|
||||
}
|
||||
|
||||
uriTokens.push(components.authority);
|
||||
|
||||
if (components.path && components.path.charAt(0) !== "/") {
|
||||
uriTokens.push("/");
|
||||
}
|
||||
}
|
||||
|
||||
if (components.path) {
|
||||
s = URI.removeDotSegments(components.path.toString().replace(/%2E/ig, "."));
|
||||
|
||||
if (components.scheme) {
|
||||
s = s.replace(NOT_PATH, pctEncChar);
|
||||
} else {
|
||||
s = s.replace(NOT_PATH_NOSCHEME, pctEncChar);
|
||||
}
|
||||
|
||||
if (components.authority === undefined) {
|
||||
s = s.replace(/^\/\//, "/%2F"); //don't allow the path to start with "//"
|
||||
}
|
||||
uriTokens.push(s);
|
||||
}
|
||||
|
||||
if (components.query) {
|
||||
uriTokens.push("?");
|
||||
uriTokens.push(components.query.toString().replace(NOT_QUERY, pctEncChar));
|
||||
}
|
||||
|
||||
if (components.fragment) {
|
||||
uriTokens.push("#");
|
||||
uriTokens.push(components.fragment.toString().replace(NOT_FRAGMENT, pctEncChar));
|
||||
}
|
||||
|
||||
return uriTokens
|
||||
.join('') //merge tokens into a string
|
||||
.replace(PCT_ENCODEDS, pctDecUnreserved) //undecode unreserved characters
|
||||
//.replace(OTHER_CHARS, pctEncChar) //replace non-URI characters
|
||||
.replace(/%[0-9A-Fa-f]{2}/g, function (str) { //uppercase percent encoded characters
|
||||
return str.toUpperCase();
|
||||
})
|
||||
;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {URIComponents} base
|
||||
* @param {URIComponents} relative
|
||||
* @param {Options} [options]
|
||||
* @param {boolean} [skipNormalization]
|
||||
* @returns {URIComponents}
|
||||
*/
|
||||
|
||||
URI.resolveComponents = function (base, relative, options, skipNormalization) {
|
||||
var target = new Components();
|
||||
|
||||
if (!skipNormalization) {
|
||||
base = URI.parse(URI.serialize(base, options), options); //normalize base components
|
||||
relative = URI.parse(URI.serialize(relative, options), options); //normalize relative components
|
||||
}
|
||||
options = options || {};
|
||||
|
||||
if (!options.tolerant && relative.scheme) {
|
||||
target.scheme = relative.scheme;
|
||||
target.authority = relative.authority;
|
||||
target.userinfo = relative.userinfo;
|
||||
target.host = relative.host;
|
||||
target.port = relative.port;
|
||||
target.path = URI.removeDotSegments(relative.path);
|
||||
target.query = relative.query;
|
||||
} else {
|
||||
if (relative.authority !== undefined) {
|
||||
target.authority = relative.authority;
|
||||
target.userinfo = relative.userinfo;
|
||||
target.host = relative.host;
|
||||
target.port = relative.port;
|
||||
target.path = URI.removeDotSegments(relative.path);
|
||||
target.query = relative.query;
|
||||
} else {
|
||||
if (!relative.path) {
|
||||
target.path = base.path;
|
||||
if (relative.query !== undefined) {
|
||||
target.query = relative.query;
|
||||
} else {
|
||||
target.query = base.query;
|
||||
}
|
||||
} else {
|
||||
if (relative.path.charAt(0) === "/") {
|
||||
target.path = URI.removeDotSegments(relative.path);
|
||||
} else {
|
||||
if (base.authority !== undefined && !base.path) {
|
||||
target.path = "/" + relative.path;
|
||||
} else if (!base.path) {
|
||||
target.path = relative.path;
|
||||
} else {
|
||||
target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative.path;
|
||||
}
|
||||
target.path = URI.removeDotSegments(target.path);
|
||||
}
|
||||
target.query = relative.query;
|
||||
}
|
||||
target.authority = base.authority;
|
||||
target.userinfo = base.userinfo;
|
||||
target.host = base.host;
|
||||
target.port = base.port;
|
||||
}
|
||||
target.scheme = base.scheme;
|
||||
}
|
||||
|
||||
target.fragment = relative.fragment;
|
||||
|
||||
return target;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string} baseURI
|
||||
* @param {string} relativeURI
|
||||
* @param {Options} [options]
|
||||
* @returns {string}
|
||||
*/
|
||||
|
||||
URI.resolve = function (baseURI, relativeURI, options) {
|
||||
return URI.serialize(URI.resolveComponents(URI.parse(baseURI, options), URI.parse(relativeURI, options), options, true), options);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string|URIComponents} uri
|
||||
* @param {Options} options
|
||||
* @returns {string|URIComponents}
|
||||
*/
|
||||
|
||||
URI.normalize = function (uri, options) {
|
||||
if (typeof uri === "string") {
|
||||
return URI.serialize(URI.parse(uri, options), options);
|
||||
} else if (typeOf(uri) === "object") {
|
||||
return URI.parse(URI.serialize(uri, options), options);
|
||||
}
|
||||
|
||||
return uri;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string|URIComponents} uriA
|
||||
* @param {string|URIComponents} uriB
|
||||
* @param {Options} options
|
||||
*/
|
||||
|
||||
URI.equal = function (uriA, uriB, options) {
|
||||
if (typeof uriA === "string") {
|
||||
uriA = URI.serialize(URI.parse(uriA, options), options);
|
||||
} else if (typeOf(uriA) === "object") {
|
||||
uriA = URI.serialize(uriA, options);
|
||||
}
|
||||
|
||||
if (typeof uriB === "string") {
|
||||
uriB = URI.serialize(URI.parse(uriB, options), options);
|
||||
} else if (typeOf(uriB) === "object") {
|
||||
uriB = URI.serialize(uriB, options);
|
||||
}
|
||||
|
||||
return uriA === uriB;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string} str
|
||||
* @returns {string}
|
||||
*/
|
||||
|
||||
URI.escapeComponent = function (str) {
|
||||
return str && str.toString().replace(ESCAPE, pctEncChar);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string} str
|
||||
* @returns {string}
|
||||
*/
|
||||
|
||||
URI.unescapeComponent = function (str) {
|
||||
return str && str.toString().replace(PCT_ENCODEDS, pctDecChars);
|
||||
};
|
||||
|
||||
//export API
|
||||
exports.pctEncChar = pctEncChar;
|
||||
exports.pctDecChars = pctDecChars;
|
||||
exports.Components = Components;
|
||||
exports.URI = URI;
|
||||
|
||||
//name-safe export API
|
||||
exports["pctEncChar"] = pctEncChar;
|
||||
exports["pctDecChars"] = pctDecChars;
|
||||
exports["Components"] = Components;
|
||||
exports["URI"] = {
|
||||
"SCHEMES" : URI.SCHEMES,
|
||||
"parse" : URI.parse,
|
||||
"removeDotSegments" : URI.removeDotSegments,
|
||||
"serialize" : URI.serialize,
|
||||
"resolveComponents" : URI.resolveComponents,
|
||||
"resolve" : URI.resolve,
|
||||
"normalize" : URI.normalize,
|
||||
"equal" : URI.equal,
|
||||
"escapeComponent" : URI.escapeComponent,
|
||||
"unescapeComponent" : URI.unescapeComponent
|
||||
};
|
||||
|
||||
}());
|
||||
Reference in New Issue
Block a user