jsonform
Version:
Client-side JavaScript library that generates HTML forms from structured data models expressed using a JSON schema, possibly completed by a form layout description.
1,667 lines (1,428 loc) • 116 kB
JavaScript
// This is a build of https://github.com/garycourt/JSV at 0aa11852537069b0830569ef1eab11a36b65b3ab with jsv.js, schema03 and URI.js appended.
// The build contains a few lines of custom code to handle format validation.
// Custom code is wrapped in comments that start with "JOSHFIRE"
(function(global, require) {
var exports = {};
/**
* 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.2
* @see http://github.com/garycourt/uri-js
* @license URI.js v1.2 (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 = {};
/**
* 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];
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.Components = Components;
exports.URI = URI;
//name-safe export API
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
};
}());
/**
* JSV: JSON Schema Validator
*
* @fileOverview A JavaScript implementation of a extendable, fully compliant JSON Schema validator.
* @author <a href="mailto:gary.court@gmail.com">Gary Court</a>
* @version 3.5
* @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 */
var exports = exports || this,
require = require || function () {
return exports;
};
(function () {
var URI = require("./uri/uri").URI,
O = {},
I2H = "0123456789abcdef".split(""),
mapArray, filterArray, searchArray,
JSV;
//
// Utility functions
//
function typeOf(o) {
return o === undefined ? "undefined" : (o === null ? "null" : Object.prototype.toString.call(o).split(" ").pop().split("]").shift().toLowerCase());
}
/** @inner */
function F() {}
function createObject(proto) {
F.prototype = proto || {};
return new F();
}
function mapObject(obj, func, scope) {
var newObj = {}, key;
for (key in obj) {
if (obj[key] !== O[key]) {
newObj[key] = func.call(scope, obj[key], key, obj);
}
}
return newObj;
}
/** @ignore */
mapArray = function (arr, func, scope) {
var x = 0, xl = arr.length, newArr = new Array(xl);
for (; x < xl; ++x) {
newArr[x] = func.call(scope, arr[x], x, arr);
}
return newArr;
};
if (Array.prototype.map) {
/** @ignore */
mapArray = function (arr, func, scope) {
return Array.prototype.map.call(arr, func, scope);
};
}
/** @ignore */
filterArray = function (arr, func, scope) {
var x = 0, xl = arr.length, newArr = [];
for (; x < xl; ++x) {
if (func.call(scope, arr[x], x, arr)) {
newArr[newArr.length] = arr[x];
}
}
return newArr;
};
if (Array.prototype.filter) {
/** @ignore */
filterArray = function (arr, func, scope) {
return Array.prototype.filter.call(arr, func, scope);
};
}
/** @ignore */
searchArray = function (arr, o) {
var x = 0, xl = arr.length;
for (; x < xl; ++x) {
if (arr[x] === o) {
return x;
}
}
return -1;
};
if (Array.prototype.indexOf) {
/** @ignore */
searchArray = function (arr, o) {
return Array.prototype.indexOf.call(arr, o);
};
}
function toArray(o) {
return o !== undefined && o !== null ? (o instanceof Array && !o.callee ? o : (typeof o.length !== "number" || o.split || o.setInterval || o.call ? [ o ] : Array.prototype.slice.call(o))) : [];
}
function keys(o) {
var result = [], key;
switch (typeOf(o)) {
case "object":
for (key in o) {
if (o[key] !== O[key]) {
result[result.length] = key;
}
}
break;
case "array":
for (key = o.length - 1; key >= 0; --key) {
result[key] = key;
}
break;
}
return result;
}
function pushUnique(arr, o) {
if (searchArray(arr, o) === -1) {
arr.push(o);
}
return arr;
}
function popFirst(arr, o) {
var index = searchArray(arr, o);
if (index > -1) {
arr.splice(index, 1);
}
return arr;
}
function randomUUID() {
return [
I2H[Math.floor(Math.random() * 0x10)],
I2H[Math.floor(Math.random() * 0x10)],
I2H[Math.floor(Math.random() * 0x10)],
I2H[Math.floor(Math.random() * 0x10)],
I2H[Math.floor(Math.random() * 0x10)],
I2H[Math.floor(Math.random() * 0x10)],
I2H[Math.floor(Math.random() * 0x10)],
I2H[Math.floor(Math.random() * 0x10)],
"-",
I2H[Math.floor(Math.random() * 0x10)],
I2H[Math.floor(Math.random() * 0x10)],
I2H[Math.floor(Math.random() * 0x10)],
I2H[Math.floor(Math.random() * 0x10)],
"-4", //set 4 high bits of time_high field to version
I2H[Math.floor(Math.random() * 0x10)],
I2H[Math.floor(Math.random() * 0x10)],
I2H[Math.floor(Math.random() * 0x10)],
"-",
I2H[(Math.floor(Math.random() * 0x10) & 0x3) | 0x8], //specify 2 high bits of clock sequence
I2H[Math.floor(Math.random() * 0x10)],
I2H[Math.floor(Math.random() * 0x10)],
I2H[Math.floor(Math.random() * 0x10)],
"-",
I2H[Math.floor(Math.random() * 0x10)],
I2H[Math.floor(Math.random() * 0x10)],
I2H[Math.floor(Math.random() * 0x10)],
I2H[Math.floor(Math.random() * 0x10)],
I2H[Math.floor(Math.random() * 0x10)],
I2H[Math.floor(Math.random() * 0x10)],
I2H[Math.floor(Math.random() * 0x10)],
I2H[Math.floor(Math.random() * 0x10)],
I2H[Math.floor(Math.random() * 0x10)],
I2H[Math.floor(Math.random() * 0x10)],
I2H[Math.floor(Math.random() * 0x10)],
I2H[Math.floor(Math.random() * 0x10)]
].join("");
}
function escapeURIComponent(str) {
return encodeURIComponent(str).replace(/!/g, '%21').replace(/'/g, '%27').replace(/\(/g, '%28').replace(/\)/g, '%29').replace(/\*/g, '%2A');
}
function formatURI(uri) {
if (typeof uri === "string" && uri.indexOf("#") === -1) {
uri += "#";
}
return uri;
}
/**
* Defines an error, found by a schema, with an instance.
* This class can only be instantiated by {@link Report#addError}.
*
* @name ValidationError
* @class
* @see Report#addError
*/
/**
* The URI of the instance that has the error.
*
* @name ValidationError.prototype.uri
* @type String
*/
/**
* The URI of the schema that generated the error.
*
* @name ValidationError.prototype.schemaUri
* @type String
*/
/**
* The name of the schema attribute that generated the error.
*
* @name ValidationError.prototype.attribute
* @type String
*/
/**
* An user-friendly (English) message about what failed to validate.
*
* @name ValidationError.prototype.message
* @type String
*/
/**
* The value of the schema attribute that generated the error.
*
* @name ValidationError.prototype.details
* @type Any
*/
/**
* Reports are returned from validation methods to describe the result of a validation.
*
* @name Report
* @class
* @see JSONSchema#validate
* @see Environment#validate
*/
function Report() {
/**
* An array of {@link ValidationError} objects that define all the errors generated by the schema against the instance.
*
* @name Report.prototype.errors
* @type Array
* @see Report#addError
*/
this.errors = [];
/**
* A hash table of every instance and what schemas were validated against it.
* <p>
* The key of each item in the table is the URI of the instance that was validated.
* The value of this key is an array of strings of URIs of the schema that validated it.
* </p>
*
* @name Report.prototype.validated
* @type Object
* @see Report#registerValidation
* @see Report#isValidatedBy
*/
this.validated = {};
/**
* If the report is generated by {@link Environment#validate}, this field is the generated instance.
*
* @name Report.prototype.instance
* @type JSONInstance
* @see Environment#validate
*/
/**
* If the report is generated by {@link Environment#validate}, this field is the generated schema.
*
* @name Report.prototype.schema
* @type JSONSchema
* @see Environment#validate
*/
/**
* If the report is generated by {@link Environment#validate}, this field is the schema's schema.
* This value is the same as calling <code>schema.getSchema()</code>.
*
* @name Report.prototype.schemaSchema
* @type JSONSchema
* @see Environment#validate
* @see JSONSchema#getSchema
*/
}
/**
* Adds a {@link ValidationError} object to the <a href="#errors"><code>errors</code></a> field.
*
* @param {JSONInstance|String} instance The instance (or instance URI) that is invalid
* @param {JSONSchema|String} schema The schema (or schema URI) that was validating the instance
* @param {String} attr The attribute that failed to validated
* @param {String} message A user-friendly message on why the schema attribute failed to validate the instance
* @param {Any} details The value of the schema attribute
*/
Report.prototype.addError = function (instance, schema, attr, message, details) {
this.errors.push({
uri : instance instanceof JSONInstance ? instance.getURI() : instance,
schemaUri : schema instanceof JSONInstance ? schema.getURI() : schema,
attribute : attr,
message : message,
details : details
});
};
/**
* Registers that the provided instance URI has been validated by the provided schema URI.
* This is recorded in the <a href="#validated"><code>validated</code></a> field.
*
* @param {String} uri The URI of the instance that was validated
* @param {String} schemaUri The URI of the schema that validated the instance
*/
Report.prototype.registerValidation = function (uri, schemaUri) {
if (!this.validated[uri]) {
this.validated[uri] = [ schemaUri ];
} else {
this.validated[uri].push(schemaUri);
}
};
/**
* Returns if an instance with the provided URI has been validated by the schema with the provided URI.
*
* @param {String} uri The URI of the instance
* @param {String} schemaUri The URI of a schema
* @returns {Boolean} If the instance has been validated by the schema.
*/
Report.prototype.isValidatedBy = function (uri, schemaUri) {
return !!this.validated[uri] && searchArray(this.validated[uri], schemaUri) !== -1;
};
/**
* A wrapper class for binding an Environment, URI and helper methods to an instance.
* This class is most commonly instantiated with {@link Environment#createInstance}.
*
* @name JSONInstance
* @class
* @param {Environment} env The environment this instance belongs to
* @param {JSONInstance|Any} json The value of the instance
* @param {String} [uri] The URI of the instance. If undefined, the URI will be a randomly generated UUID.
* @param {String} [fd] The fragment delimiter for properties. If undefined, uses the environment default.
*/
function JSONInstance(env, json, uri, fd) {
if (json instanceof JSONInstance) {
if (typeof fd !== "string") {
fd = json._fd;
}
if (typeof uri !== "string") {
uri = json._uri;
}
json = json._value;
}
if (typeof uri !== "string") {
uri = "urn:uuid:" + randomUUID() + "#";
} else if (uri.indexOf(":") === -1) {
uri = formatURI(URI.resolve("urn:uuid:" + randomUUID() + "#", uri));
}
this._env = env;
this._value = json;
this._uri = uri;
this._fd = fd || this._env._options["defaultFragmentDelimiter"];
}
/**
* Returns the environment the instance is bound to.
*
* @returns {Environment} The environment of the instance
*/
JSONInstance.prototype.getEnvironment = function () {
return this._env;
};
/**
* Returns the name of the type of the instance.
*
* @returns {String} The name of the type of the instance
*/
JSONInstance.prototype.getType = function () {
return typeOf(this._value);
};
/**
* Returns the JSON value of the instance.
*
* @returns {Any} The actual JavaScript value of the instance
*/
JSONInstance.prototype.getValue = function () {
return this._value;
};
/**
* Returns the URI of the instance.
*
* @returns {String} The URI of the instance
*/
JSONInstance.prototype.getURI = function () {
return this._uri;
};
/**
* Returns a resolved URI of a provided relative URI against the URI of the instance.
*
* @param {String} uri The relative URI to resolve
* @returns {String} The resolved URI
*/
JSONInstance.prototype.resolveURI = function (uri) {
return formatURI(URI.resolve(this._uri, uri));
};
/**
* Returns an array of the names of all the properties.
*
* @returns {Array} An array of strings which are the names of all the properties
*/
JSONInstance.prototype.getPropertyNames = function () {
return keys(this._value);
};
/**
* Returns a {@link JSONInstance} of the value of the provided property name.
*
* @param {String} key The name of the property to fetch
* @returns {JSONInstance} The instance of the property value
*/
JSONInstance.prototype.getProperty = function (key) {
var value = this._value ? this._value[key] : undefined;
if (value instanceof JSONInstance) {
return value;
}
//else
return new JSONInstance(this._env, value, this._uri + this._fd + escapeURIComponent(key), this._fd);
};
/**
* Returns all the property instances of the target instance.
* <p>
* If the target instance is an Object, then the method will return a hash table of {@link JSONInstance}s of all the properties.
* If the target instance is an Array, then the method will return an array of {@link JSONInstance}s of all the items.
* </p>
*
* @returns {Object|Array|undefined} The list of instances for all the properties
*/
JSONInstance.prototype.getProperties = function () {
var type = typeOf(this._value),
self = this;
if (type === "object") {
return mapObject(this._value, function (value, key) {
if (value instanceof JSONInstance) {
return value;
}
return new JSONInstance(self._env, value, self._uri + self._fd + escapeURIComponent(key), self._fd);
});
} else if (type === "array") {
return mapArray(this._value, function (value, key) {
if (value instanceof JSONInstance) {
return value;
}
return new JSONInstance(self._env, value, self._uri + self._fd + escapeURIComponent(key), self._fd);
});
}
};
/**
* Returns the JSON value of the provided property name.
* This method is a faster version of calling <code>instance.getProperty(key).getValue()</code>.
*
* @param {String} key The name of the property
* @returns {Any} The JavaScript value of the instance
* @see JSONInstance#getProperty
* @see JSONInstance#getValue
*/
JSONInstance.prototype.getValueOfProperty = function (key) {
if (this._value) {
if (this._value[key] instanceof JSONInstance) {
return this._value[key]._value;
}
return this._value[key];
}
};
/**
* Return if the provided value is the same as the value of the instance.
*
* @param {JSONInstance|Any} instance The value to compare
* @returns {Boolean} If both the instance and the value match
*/
JSONInstance.prototype.equals = function (instance) {
if (instance instanceof JSONInstance) {
return this._value === instance._value;
}
//else
return this._value === instance;
};
/**
* Warning: Not a generic clone function
* Produces a JSV acceptable clone
*/
function clone(obj, deep) {
var newObj, x;
if (obj instanceof JSONInstance) {
obj = obj.getValue();
}
switch (typeOf(obj)) {
case "object":
if (deep) {
newObj = {};
for (x in obj) {
if (obj[x] !== O[x]) {
newObj[x] = clone(obj[x], deep);
}
}
return newObj;
} else {
return createObject(obj);
}
break;
case "array":
if (deep) {
newObj = new Array(obj.length);
x = obj.length;
while (--x >= 0) {
newObj[x] = clone(obj[x], deep);
}
return newObj;
} else {
return Array.prototype.slice.call(obj);
}
break;
default:
return obj;
}
}
/**
* This class binds a {@link JSONInstance} with a {@link JSONSchema} to provided context aware methods.
*
* @name JSONSchema
* @class
* @param {Environment} env The environment this schema belongs to
* @param {JSONInstance|Any} json The value of the schema
* @param {String} [uri] The URI of the schema. If undefined, the URI will be a randomly generated UUID.
* @param {JSONSchema|Boolean} [schema] The schema to bind to the instance. If <code>undefined</code>, the environment's default schema will be used. If <code>true</code>, the instance's schema will be itself.
* @extends JSONInstance
*/
function JSONSchema(env, json, uri, schema) {
var fr;
JSONInstance.call(this, env, json, uri);
if (schema === true) {
this._schema = this;
} else if (json instanceof JSONSchema && !(schema instanceof JSONSchema)) {
this._schema = json._schema; //TODO: Make sure cross environments don't mess everything up
} else {
this._schema = schema instanceof JSONSchema ? schema : this._env.getDefaultSchema() || JSONSchema.createEmptySchema(this._env);
}
//determine fragment delimiter from schema
fr = this._schema.getValueOfProperty("fragmentResolution");
if (fr === "dot-delimited") {
this._fd = ".";
} else if (fr === "slash-delimited") {
this._fd = "/";
}
}
JSONSchema.prototype = createObject(JSONInstance.prototype);
/**
* Creates an empty schema.
*
* @param {Environment} env The environment of the schema
* @returns {JSONSchema} The empty schema, who's schema is itself.
*/
JSONSchema.createEmptySchema = function (env) {
var schema = createObject(JSONSchema.prototype);
JSONInstance.call(schema, env, {}, undefined, undefined);
schema._schema = schema;
return schema;
};
/**
* Returns the schema of the schema.
*
* @returns {JSONSchema} The schema of the schema
*/
JSONSchema.prototype.getSchema = function () {
return this._schema;
};
/**
* Returns the value of the provided attribute name.
* <p>
* This method is different from {@link JSONInstance#getProperty} as the named property
* is converted using a parser defined by the schema's schema before being returned. This
* makes the return value of this method attribute dependent.
* </p>
*
* @param {String} key The name of the attribute
* @param {Any} [arg] Some attribute parsers accept special arguments for returning resolved values. This is attribute dependent.
* @returns {JSONSchema|Any} The value of the attribute
*/
JSONSchema.prototype.getAttribute = function (key, arg) {
var schemaProperty, parser, property, result;
if (!arg && this._attributes && this._attributes.hasOwnProperty(key)) {
return this._attributes[key];
}
schemaProperty = this._schema.getProperty("properties").getProperty(key);
parser = schemaProperty.getValueOfProperty("parser");
property = this.getProperty(key);
if (typeof parser === "function") {
result = parser(property, schemaProperty, arg);
if (!arg && this._attributes) {
this._attributes[key] = result;
}
return result;
}
//else
return property.getValue();
};
/**
* Returns all the attributes of the schema.
*
* @returns {Object} A map of all parsed attribute values
*/
JSONSchema.prototype.getAttributes = function () {
var properties, schemaProperties, key, schemaProperty, parser;
if (!this._attributes && this.getType() === "object") {
properties = this.getProperties();
schemaProperties = this._schema.getProperty("properties");
this._attributes = {};
for (key in properties) {
if (properties[key] !== O[key]) {
schemaProperty = schemaProperties && schemaProperties.getProperty(key);
parser = schemaProperty && schemaProperty.getValueOfProperty("parser");
if (typeof parser === "function") {
this._attributes[key] = parser(properties[key], schemaProperty);
} else {
this._attributes[key] = properties[key].getValue();
}
}
}
}
return clone(this._attributes, false);
};
/**
* Convenience method for retrieving a link or link object from a schema.
* This method is the same as calling <code>schema.getAttribute("links", [rel, instance])[0];</code>.
*
* @param {String} rel The link relationship
* @param {JSONInstance} [instance] The instance to resolve any URIs from
* @returns {String|Object|undefined} If <code>instance</code> is provided, a string containing the resolve URI of the link is returned.
* If <code>instance</code> is not provided, a link object is returned with details of the link.
* If no link with the provided relationship exists, <code>undefined</code> is returned.
* @see JSONSchema#getAttribute
*/
JSONSchema.prototype.getLink = function (rel, instance) {
var schemaLinks = this.getAttribute("links", [rel, instance]);
if (schemaLinks && schemaLinks.length && schemaLinks[schemaLinks.length - 1]) {
return schemaLinks[schemaLinks.length - 1];
}
};
/**
* Validates the provided instance against the target schema and returns a {@link Report}.
*
* @param {JSONInstance|Any} instance The instance to validate; may be a {@link JSONInstance} or any JavaScript value
* @param {Report} [report] A {@link Report} to concatenate the result of the validation to. If <code>undefined</code>, a new {@link Report} is created.
* @param {JSONInstance} [parent] The parent/containing instance of the provided instance
* @param {JSONSchema} [parentSchema] The schema of the parent/containing instance
* @param {String} [name] The name of the parent object's property that references the instance
* @returns {Report} The result of the validation
*/
JSONSchema.prototype.validate = function (instance, report, parent, parentSchema, name) {
var validator = this._schema.getValueOfProperty("validator");
if (!(instance instanceof JSONInstance)) {
instance = this.getEnvironment().createInstance(instance);
}
if (!(report instanceof Report)) {
report = new Report();
}
if (typeof validator === "function" && !report.isValidatedBy(instance.getURI(), this.getURI())) {
report.registerValidation(instance.getURI(), this.getURI());
validator(instance, this, this._schema, report, parent, parentSchema, name);
}
return report;
};
/**
* Merges two schemas/instances together.
*/
function inherits(base, extra, extension) {
var baseType = typeOf(base),
extraType = typeOf(extra),
child, x;
if (extraType === "undefined") {
return clone(base, true);
} else if (baseType === "undefined" || extraType !== baseType) {
return clone(extra, true);
} else if (extraType === "object") {
if (base instanceof JSONSchema) {
base = base.getAttributes();
}
if (extra instanceof JSONSchema) {
extra = extra.getAttributes();
if (extra["extends"] && extension && extra["extends"] instanceof JSONSchema) {
extra["extends"] = [ extra["extends"] ];
}
}
child = clone(base, true); //this could be optimized as some properties get overwritten
for (x in extra) {
if (extra[x] !== O[x]) {
child[x] = inherits(base[x], extra[x], extension);
}
}
return child;
} else {
return clone(extra, true);
}
}
/**
* An Environment is a sandbox of schemas thats behavior is different from other environments.
*
* @name Environment
* @class
*/
function Environment() {
this._id = randomUUID();
this._schemas = {};
this._options = {};
}
/**
* Returns a clone of the target environment.
*
* @returns {Environment} A new {@link Environment} that is a exact copy of the target environment
*/
Environment.prototype.clone = function () {
var env = new Environment();
env._schemas = createObject(this._schemas);
env._options = createObject(this._options);
return env;
};
/**
* Returns a new {@link JSONInstance} of the provided data.
*
* @param {JSONInstance|Any} data The value of the instance
* @param {String} [uri] The URI of the instance. If undefined, the URI will be a randomly generated UUID.
* @returns {JSONInstance} A new {@link JSONInstance} from the provided data
*/
Environment.prototype.createInstance = function (data, uri) {
var instance;
uri = formatURI(uri);
if (data instanceof JSONInstance && (!uri || data.getURI() === uri)) {
return data;
}
//else
instance = new JSONInstance(this, data, uri);
return instance;
};
/**
* Creates a new {@link JSONSchema} from the provided data, and registers it with the environment.
*
* @param {JSONInstance|Any} data The value of the schema
* @param {JSONSchema|Boolean} [schema] The schema to bind to the instance. If <code>undefined</code>, the environment's default schema will be used. If <code>true</code>, the instance's schema will be itself.
* @param {String} [uri] The URI of the schema. If undefined, the URI will be a randomly generated UUID.
* @returns {JSONSchema} A new {@link JSONSchema} from the provided data
* @throws {InitializationError} If a schema that is not registered with the environment is referenced
*/
Environment.prototype.createSchema = function (data, schema, uri) {
var instance,
initializer;
uri = formatURI(uri);
if (data instanceof JSONSchema && (!uri || data._uri === uri) && (!schema || data._schema.equals(schema))) {
return data;
}
instance = new JSONSchema(this, data, uri, schema);
initializer = instance.getSchema().getValueOfProperty("initializer");
if (typeof initializer === "function") {
instance = initializer(instance);
}
//register schema
this._schemas[instance._uri] = instance;
this._schemas[uri] = instance;
//build & cache the rest of the schema
instance.getAttributes();
return instance;
};
/**
* Creates an empty schema.
*
* @param {Environment} env The environment of the schema
* @returns {JSONSchema} The empty schema, who's schema is itself.
*/
Environment.prototype.createEmptySchema = function () {
var schema = JSONSchema.createEmptySchema(this);
this._schemas[schema._uri] = schema;
return schema;
};
/**
* Returns the schema registered with the provided URI.
*
* @param {String} uri The absolute URI of the required schema
* @returns {JSONSchema|undefined} The request schema, or <code>undefined</code> if not found
*/
Environment.prototype.findSchema = function (uri) {
return this._schemas[formatURI(uri)];
};
/**
* Sets the specified environment option to the specified value.
*
* @param {String} name The name of the environment option to set
* @param {Any} value The new value of the environment option
*/
Environment.prototype.setOption = function (name, value) {
this._options[name] = value;
};
/**
* Returns the specified environment option.
*
* @param {String} name The name of the environment option to set
* @returns {Any} The value of the environment option
*/
Environment.prototype.getOption = function (name) {
return this._options[name];
};
/**
* Sets the default fragment delimiter of the environment.
*
* @deprecated Use {@link Environment#setOption} with option "defaultFragmentDelimiter"
* @param {String} fd The fragment delimiter character
*/
Environment.prototype.setDefaultFragmentDelimiter = function (fd) {
if (typeof fd === "string" && fd.length > 0) {
this._options["defaultFragmentDelimiter"] = fd;
}
};
/**
* Returns the default fragment delimiter of the environment.
*
* @deprecated Use {@link Environment#getOption} with option "defaultFragmentDelimiter"
* @returns {String} The fragment delimiter character
*/
Environment.prototype.getDefaultFragmentDelimi