aboutsummaryrefslogtreecommitdiff
path: root/common/jsonschema/helpers.js
diff options
context:
space:
mode:
Diffstat (limited to 'common/jsonschema/helpers.js')
-rw-r--r--common/jsonschema/helpers.js429
1 files changed, 429 insertions, 0 deletions
diff --git a/common/jsonschema/helpers.js b/common/jsonschema/helpers.js
new file mode 100644
index 0000000..f6a72a6
--- /dev/null
+++ b/common/jsonschema/helpers.js
@@ -0,0 +1,429 @@
+/* SPDX-License-Identifier: MIT
+ *
+ * jsonschema is licensed under MIT license.
+ *
+ * Copyright (C) 2012-2015 Tom de Grunt <tom@degrunt.nl>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#IMPORT common/jsonschema/urllib_mock.js AS uri
+
+function ValidationError (message, instance, schema, path, name, argument) {
+ if(Array.isArray(path)){
+ this.path = path;
+ this.property = path.reduce(function(sum, item){
+ return sum + makeSuffix(item);
+ }, 'instance');
+ }else if(path !== undefined){
+ this.property = path;
+ }
+ if (message) {
+ this.message = message;
+ }
+ if (schema) {
+ var id = schema.$id || schema.id;
+ this.schema = id || schema;
+ }
+ if (instance !== undefined) {
+ this.instance = instance;
+ }
+ this.name = name;
+ this.argument = argument;
+ this.stack = this.toString();
+};
+#EXPORT ValidationError
+
+ValidationError.prototype.toString = function toString() {
+ return this.property + ' ' + this.message;
+};
+
+function ValidatorResult(instance, schema, options, ctx) {
+ this.instance = instance;
+ this.schema = schema;
+ this.options = options;
+ this.path = ctx.path;
+ this.propertyPath = ctx.propertyPath;
+ this.errors = [];
+ this.throwError = options && options.throwError;
+ this.throwFirst = options && options.throwFirst;
+ this.throwAll = options && options.throwAll;
+ this.disableFormat = options && options.disableFormat === true;
+};
+
+ValidatorResult.prototype.addError = function addError(detail) {
+ var err;
+ if (typeof detail == 'string') {
+ err = new ValidationError(detail, this.instance, this.schema, this.path);
+ } else {
+ if (!detail) throw new Error('Missing error detail');
+ if (!detail.message) throw new Error('Missing error message');
+ if (!detail.name) throw new Error('Missing validator type');
+ err = new ValidationError(detail.message, this.instance, this.schema, this.path, detail.name, detail.argument);
+ }
+
+ this.errors.push(err);
+ if (this.throwFirst) {
+ throw new ValidatorResultError(this);
+ }else if(this.throwError){
+ throw err;
+ }
+ return err;
+};
+
+ValidatorResult.prototype.importErrors = function importErrors(res) {
+ if (typeof res == 'string' || (res && res.validatorType)) {
+ this.addError(res);
+ } else if (res && res.errors) {
+ Array.prototype.push.apply(this.errors, res.errors);
+ }
+};
+
+function stringizer (v,i){
+ return i+': '+v.toString()+'\n';
+}
+ValidatorResult.prototype.toString = function toString(res) {
+ return this.errors.map(stringizer).join('');
+};
+
+Object.defineProperty(ValidatorResult.prototype, "valid", { get: function() {
+ return !this.errors.length;
+} });
+
+#EXPORT ValidatorResult
+
+function ValidatorResultError(result) {
+ if(Error.captureStackTrace){
+ Error.captureStackTrace(this, ValidatorResultError);
+ }
+ this.instance = result.instance;
+ this.schema = result.schema;
+ this.options = result.options;
+ this.errors = result.errors;
+}
+ValidatorResultError.prototype = new Error();
+ValidatorResultError.prototype.constructor = ValidatorResultError;
+ValidatorResultError.prototype.name = "Validation Error";
+#EXPORT ValidatorResultError
+
+/**
+ * Describes a problem with a Schema which prevents validation of an instance
+ * @name SchemaError
+ * @constructor
+ */
+function SchemaError (msg, schema) {
+ this.message = msg;
+ this.schema = schema;
+ Error.call(this, msg);
+ if(Error.captureStackTrace){
+ Error.captureStackTrace(this, SchemaError);
+ }
+};
+SchemaError.prototype = Object.create(Error.prototype,
+ {
+ constructor: {value: SchemaError, enumerable: false},
+ name: {value: 'SchemaError', enumerable: false},
+ });
+#EXPORT SchemaError
+
+function SchemaContext (schema, options, path, base, schemas) {
+ this.schema = schema;
+ this.options = options;
+ if(Array.isArray(path)){
+ this.path = path;
+ this.propertyPath = path.reduce(function(sum, item){
+ return sum + makeSuffix(item);
+ }, 'instance');
+ }else{
+ this.propertyPath = path;
+ }
+ this.base = base;
+ this.schemas = schemas;
+};
+
+SchemaContext.prototype.resolve = function resolve (target) {
+ return uri.resolve(this.base, target);
+};
+
+SchemaContext.prototype.makeChild = function makeChild(schema, propertyName){
+ var path = (propertyName===undefined) ? this.path : this.path.concat([propertyName]);
+ var id = schema.$id || schema.id;
+ var base = uri.resolve(this.base, id||'');
+ var ctx = new SchemaContext(schema, this.options, path, base, Object.create(this.schemas));
+ if(id && !ctx.schemas[base]){
+ ctx.schemas[base] = schema;
+ }
+ return ctx;
+};
+
+#EXPORT SchemaContext
+
+const FORMAT_REGEXPS = {
+ // 7.3.1. Dates, Times, and Duration
+ 'date-time': /^\d{4}-(?:0[0-9]{1}|1[0-2]{1})-(3[01]|0[1-9]|[12][0-9])[tT ](2[0-4]|[01][0-9]):([0-5][0-9]):(60|[0-5][0-9])(\.\d+)?([zZ]|[+-]([0-5][0-9]):(60|[0-5][0-9]))$/,
+ 'date': /^\d{4}-(?:0[0-9]{1}|1[0-2]{1})-(3[01]|0[1-9]|[12][0-9])$/,
+ 'time': /^(2[0-4]|[01][0-9]):([0-5][0-9]):(60|[0-5][0-9])$/,
+ 'duration': /P(T\d+(H(\d+M(\d+S)?)?|M(\d+S)?|S)|\d+(D|M(\d+D)?|Y(\d+M(\d+D)?)?)(T\d+(H(\d+M(\d+S)?)?|M(\d+S)?|S))?|\d+W)/i,
+
+ // 7.3.2. Email Addresses
+ // TODO: fix the email production
+ 'email': /^(?:[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+\.)*[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+@(?:(?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9\-](?!\.)){0,61}[a-zA-Z0-9]?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9\-](?!$)){0,61}[a-zA-Z0-9]?)|(?:\[(?:(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\]))$/,
+ 'idn-email': /^("(?:[!#-\[\]-\u{10FFFF}]|\\[\t -\u{10FFFF}])*"|[!#-'*+\-/-9=?A-Z\^-\u{10FFFF}](?:\.?[!#-'*+\-/-9=?A-Z\^-\u{10FFFF}])*)@([!#-'*+\-/-9=?A-Z\^-\u{10FFFF}](?:\.?[!#-'*+\-/-9=?A-Z\^-\u{10FFFF}])*|\[[!-Z\^-\u{10FFFF}]*\])$/u,
+
+ // 7.3.3. Hostnames
+
+ // 7.3.4. IP Addresses
+ 'ip-address': /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/,
+ // FIXME whitespace is invalid
+ 'ipv6': /^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/,
+
+ // 7.3.5. Resource Identifiers
+ // TODO: A more accurate regular expression for "uri" goes:
+ // [A-Za-z][+\-.0-9A-Za-z]*:((/(/((%[0-9A-Fa-f]{2}|[!$&-.0-9;=A-Z_a-z~])+|(\[(([Vv][0-9A-Fa-f]+\.[!$&-.0-;=A-Z_a-z~]+)?|[.0-:A-Fa-f]+)\])?)(:\d*)?)?)?#(%[0-9A-Fa-f]{2}|[!$&-;=?-Z_a-z~])*|(/(/((%[0-9A-Fa-f]{2}|[!$&-.0-9;=A-Z_a-z~])+|(\[(([Vv][0-9A-Fa-f]+\.[!$&-.0-;=A-Z_a-z~]+)?|[.0-:A-Fa-f]+)\])?)(:\d*)?[/?]|[!$&-.0-;=?-Z_a-z~])|/?%[0-9A-Fa-f]{2}|[!$&-.0-;=?-Z_a-z~])(%[0-9A-Fa-f]{2}|[!$&-;=?-Z_a-z~])*(#(%[0-9A-Fa-f]{2}|[!$&-;=?-Z_a-z~])*)?|/(/((%[0-9A-Fa-f]{2}|[!$&-.0-9;=A-Z_a-z~])+(:\d*)?|(\[(([Vv][0-9A-Fa-f]+\.[!$&-.0-;=A-Z_a-z~]+)?|[.0-:A-Fa-f]+)\])?:\d*|\[(([Vv][0-9A-Fa-f]+\.[!$&-.0-;=A-Z_a-z~]+)?|[.0-:A-Fa-f]+)\])?)?)?
+ 'uri': /^[a-zA-Z][a-zA-Z0-9+.-]*:[^\s]*$/,
+ 'uri-reference': /^(((([A-Za-z][+\-.0-9A-Za-z]*(:%[0-9A-Fa-f]{2}|:[!$&-.0-;=?-Z_a-z~]|[/?])|\?)(%[0-9A-Fa-f]{2}|[!$&-;=?-Z_a-z~])*|([A-Za-z][+\-.0-9A-Za-z]*:?)?)|([A-Za-z][+\-.0-9A-Za-z]*:)?\/((%[0-9A-Fa-f]{2}|\/((%[0-9A-Fa-f]{2}|[!$&-.0-9;=A-Z_a-z~])+|(\[(([Vv][0-9A-Fa-f]+\.[!$&-.0-;=A-Z_a-z~]+)?|[.0-:A-Fa-f]+)\])?)(:\d*)?[/?]|[!$&-.0-;=?-Z_a-z~])(%[0-9A-Fa-f]{2}|[!$&-;=?-Z_a-z~])*|(\/((%[0-9A-Fa-f]{2}|[!$&-.0-9;=A-Z_a-z~])+|(\[(([Vv][0-9A-Fa-f]+\.[!$&-.0-;=A-Z_a-z~]+)?|[.0-:A-Fa-f]+)\])?)(:\d*)?)?))#(%[0-9A-Fa-f]{2}|[!$&-;=?-Z_a-z~])*|(([A-Za-z][+\-.0-9A-Za-z]*)?%[0-9A-Fa-f]{2}|[!$&-.0-9;=@_~]|[A-Za-z][+\-.0-9A-Za-z]*[!$&-*,;=@_~])(%[0-9A-Fa-f]{2}|[!$&-.0-9;=@-Z_a-z~])*((([/?](%[0-9A-Fa-f]{2}|[!$&-;=?-Z_a-z~])*)?#|[/?])(%[0-9A-Fa-f]{2}|[!$&-;=?-Z_a-z~])*)?|([A-Za-z][+\-.0-9A-Za-z]*(:%[0-9A-Fa-f]{2}|:[!$&-.0-;=?-Z_a-z~]|[/?])|\?)(%[0-9A-Fa-f]{2}|[!$&-;=?-Z_a-z~])*|([A-Za-z][+\-.0-9A-Za-z]*:)?\/((%[0-9A-Fa-f]{2}|\/((%[0-9A-Fa-f]{2}|[!$&-.0-9;=A-Z_a-z~])+|(\[(([Vv][0-9A-Fa-f]+\.[!$&-.0-;=A-Z_a-z~]+)?|[.0-:A-Fa-f]+)\])?)(:\d*)?[/?]|[!$&-.0-;=?-Z_a-z~])(%[0-9A-Fa-f]{2}|[!$&-;=?-Z_a-z~])*|\/((%[0-9A-Fa-f]{2}|[!$&-.0-9;=A-Z_a-z~])+(:\d*)?|(\[(([Vv][0-9A-Fa-f]+\.[!$&-.0-;=A-Z_a-z~]+)?|[.0-:A-Fa-f]+)\])?:\d*|\[(([Vv][0-9A-Fa-f]+\.[!$&-.0-;=A-Z_a-z~]+)?|[.0-:A-Fa-f]+)\])?)?|[A-Za-z][+\-.0-9A-Za-z]*:?)?$/,
+ 'iri': /^[a-zA-Z][a-zA-Z0-9+.-]*:[^\s]*$/,
+ 'iri-reference': /^(((([A-Za-z][+\-.0-9A-Za-z]*(:%[0-9A-Fa-f]{2}|:[!$&-.0-;=?-Z_a-z~-\u{10FFFF}]|[/?])|\?)(%[0-9A-Fa-f]{2}|[!$&-;=?-Z_a-z~-\u{10FFFF}])*|([A-Za-z][+\-.0-9A-Za-z]*:?)?)|([A-Za-z][+\-.0-9A-Za-z]*:)?\/((%[0-9A-Fa-f]{2}|\/((%[0-9A-Fa-f]{2}|[!$&-.0-9;=A-Z_a-z~-\u{10FFFF}])+|(\[(([Vv][0-9A-Fa-f]+\.[!$&-.0-;=A-Z_a-z~-\u{10FFFF}]+)?|[.0-:A-Fa-f]+)\])?)(:\d*)?[/?]|[!$&-.0-;=?-Z_a-z~-\u{10FFFF}])(%[0-9A-Fa-f]{2}|[!$&-;=?-Z_a-z~-\u{10FFFF}])*|(\/((%[0-9A-Fa-f]{2}|[!$&-.0-9;=A-Z_a-z~-\u{10FFFF}])+|(\[(([Vv][0-9A-Fa-f]+\.[!$&-.0-;=A-Z_a-z~-\u{10FFFF}]+)?|[.0-:A-Fa-f]+)\])?)(:\d*)?)?))#(%[0-9A-Fa-f]{2}|[!$&-;=?-Z_a-z~-\u{10FFFF}])*|(([A-Za-z][+\-.0-9A-Za-z]*)?%[0-9A-Fa-f]{2}|[!$&-.0-9;=@_~-\u{10FFFF}]|[A-Za-z][+\-.0-9A-Za-z]*[!$&-*,;=@_~-\u{10FFFF}])(%[0-9A-Fa-f]{2}|[!$&-.0-9;=@-Z_a-z~-\u{10FFFF}])*((([/?](%[0-9A-Fa-f]{2}|[!$&-;=?-Z_a-z~-\u{10FFFF}])*)?#|[/?])(%[0-9A-Fa-f]{2}|[!$&-;=?-Z_a-z~-\u{10FFFF}])*)?|([A-Za-z][+\-.0-9A-Za-z]*(:%[0-9A-Fa-f]{2}|:[!$&-.0-;=?-Z_a-z~-\u{10FFFF}]|[/?])|\?)(%[0-9A-Fa-f]{2}|[!$&-;=?-Z_a-z~-\u{10FFFF}])*|([A-Za-z][+\-.0-9A-Za-z]*:)?\/((%[0-9A-Fa-f]{2}|\/((%[0-9A-Fa-f]{2}|[!$&-.0-9;=A-Z_a-z~-\u{10FFFF}])+|(\[(([Vv][0-9A-Fa-f]+\.[!$&-.0-;=A-Z_a-z~-\u{10FFFF}]+)?|[.0-:A-Fa-f]+)\])?)(:\d*)?[/?]|[!$&-.0-;=?-Z_a-z~-\u{10FFFF}])(%[0-9A-Fa-f]{2}|[!$&-;=?-Z_a-z~-\u{10FFFF}])*|\/((%[0-9A-Fa-f]{2}|[!$&-.0-9;=A-Z_a-z~-\u{10FFFF}])+(:\d*)?|(\[(([Vv][0-9A-Fa-f]+\.[!$&-.0-;=A-Z_a-z~-\u{10FFFF}]+)?|[.0-:A-Fa-f]+)\])?:\d*|\[(([Vv][0-9A-Fa-f]+\.[!$&-.0-;=A-Z_a-z~-\u{10FFFF}]+)?|[.0-:A-Fa-f]+)\])?)?|[A-Za-z][+\-.0-9A-Za-z]*:?)?$/u,
+ 'uuid': /^[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$/i,
+
+ // 7.3.6. uri-template
+ 'uri-template': /(%[0-9a-f]{2}|[!#$&(-;=?@\[\]_a-z~]|\{[!#&+,./;=?@|]?(%[0-9a-f]{2}|[0-9_a-z])(\.?(%[0-9a-f]{2}|[0-9_a-z]))*(:[1-9]\d{0,3}|\*)?(,(%[0-9a-f]{2}|[0-9_a-z])(\.?(%[0-9a-f]{2}|[0-9_a-z]))*(:[1-9]\d{0,3}|\*)?)*\})*/iu,
+
+ // 7.3.7. JSON Pointers
+ 'json-pointer': /^(\/([\x00-\x2e0-@\[-}\x7f]|~[01])*)*$/iu,
+ 'relative-json-pointer': /^\d+(#|(\/([\x00-\x2e0-@\[-}\x7f]|~[01])*)*)$/iu,
+
+ // hostname regex from: http://stackoverflow.com/a/1420225/5628
+ 'hostname': /^(?=.{1,255}$)[0-9A-Za-z](?:(?:[0-9A-Za-z]|-){0,61}[0-9A-Za-z])?(?:\.[0-9A-Za-z](?:(?:[0-9A-Za-z]|-){0,61}[0-9A-Za-z])?)*\.?$/,
+ 'host-name': /^(?=.{1,255}$)[0-9A-Za-z](?:(?:[0-9A-Za-z]|-){0,61}[0-9A-Za-z])?(?:\.[0-9A-Za-z](?:(?:[0-9A-Za-z]|-){0,61}[0-9A-Za-z])?)*\.?$/,
+
+ 'utc-millisec': function (input) {
+ return (typeof input === 'string') && parseFloat(input) === parseInt(input, 10) && !isNaN(input);
+ },
+
+ // 7.3.8. regex
+ 'regex': function (input) {
+ var result = true;
+ try {
+ new RegExp(input);
+ } catch (e) {
+ result = false;
+ }
+ return result;
+ },
+
+ // Other definitions
+ // "style" was removed from JSON Schema in draft-4 and is deprecated
+ 'style': /[\r\n\t ]*[^\r\n\t ][^:]*:[\r\n\t ]*[^\r\n\t ;]*[\r\n\t ]*;?/,
+ // "color" was removed from JSON Schema in draft-4 and is deprecated
+ 'color': /^(#?([0-9A-Fa-f]{3}){1,2}\b|aqua|black|blue|fuchsia|gray|green|lime|maroon|navy|olive|orange|purple|red|silver|teal|white|yellow|(rgb\(\s*\b([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\b\s*,\s*\b([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\b\s*,\s*\b([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\b\s*\))|(rgb\(\s*(\d?\d%|100%)+\s*,\s*(\d?\d%|100%)+\s*,\s*(\d?\d%|100%)+\s*\)))$/,
+ 'phone': /^\+(?:[0-9] ?){6,14}[0-9]$/,
+ 'alpha': /^[a-zA-Z]+$/,
+ 'alphanumeric': /^[a-zA-Z0-9]+$/,
+};
+
+FORMAT_REGEXPS.regexp = FORMAT_REGEXPS.regex;
+FORMAT_REGEXPS.pattern = FORMAT_REGEXPS.regex;
+FORMAT_REGEXPS.ipv4 = FORMAT_REGEXPS['ip-address'];
+
+#EXPORT FORMAT_REGEXPS
+
+function isFormat (input, format, validator) {
+ if (typeof input === 'string' && FORMAT_REGEXPS[format] !== undefined) {
+ if (FORMAT_REGEXPS[format] instanceof RegExp) {
+ return FORMAT_REGEXPS[format].test(input);
+ }
+ if (typeof FORMAT_REGEXPS[format] === 'function') {
+ return FORMAT_REGEXPS[format](input);
+ }
+ } else if (validator && validator.customFormats &&
+ typeof validator.customFormats[format] === 'function') {
+ return validator.customFormats[format](input);
+ }
+ return true;
+};
+
+#EXPORT isFormat
+
+function makeSuffix (key) {
+ key = key.toString();
+ // This function could be capable of outputting valid a ECMAScript string, but the
+ // resulting code for testing which form to use would be tens of thousands of characters long
+ // That means this will use the name form for some illegal forms
+ if (!key.match(/[.\s\[\]]/) && !key.match(/^[\d]/)) {
+ return '.' + key;
+ }
+ if (key.match(/^\d+$/)) {
+ return '[' + key + ']';
+ }
+ return '[' + JSON.stringify(key) + ']';
+};
+#EXPORT makeSuffix
+
+function deepCompareStrict (a, b) {
+ if (typeof a !== typeof b) {
+ return false;
+ }
+ if (Array.isArray(a)) {
+ if (!Array.isArray(b)) {
+ return false;
+ }
+ if (a.length !== b.length) {
+ return false;
+ }
+ return a.every(function (v, i) {
+ return deepCompareStrict(a[i], b[i]);
+ });
+ }
+ if (typeof a === 'object') {
+ if (!a || !b) {
+ return a === b;
+ }
+ var aKeys = Object.keys(a);
+ var bKeys = Object.keys(b);
+ if (aKeys.length !== bKeys.length) {
+ return false;
+ }
+ return aKeys.every(function (v) {
+ return deepCompareStrict(a[v], b[v]);
+ });
+ }
+ return a === b;
+};
+#EXPORT deepCompareStrict
+
+function deepMerger (target, dst, e, i) {
+ if (typeof e === 'object') {
+ dst[i] = deepMerge(target[i], e);
+ } else {
+ if (target.indexOf(e) === -1) {
+ dst.push(e);
+ }
+ }
+}
+
+function copyist (src, dst, key) {
+ dst[key] = src[key];
+}
+
+function copyistWithDeepMerge (target, src, dst, key) {
+ if (typeof src[key] !== 'object' || !src[key]) {
+ dst[key] = src[key];
+ }
+ else {
+ if (!target[key]) {
+ dst[key] = src[key];
+ } else {
+ dst[key] = deepMerge(target[key], src[key]);
+ }
+ }
+}
+
+function deepMerge (target, src) {
+ var array = Array.isArray(src);
+ var dst = array && [] || {};
+
+ if (array) {
+ target = target || [];
+ dst = dst.concat(target);
+ src.forEach(deepMerger.bind(null, target, dst));
+ } else {
+ if (target && typeof target === 'object') {
+ Object.keys(target).forEach(copyist.bind(null, target, dst));
+ }
+ Object.keys(src).forEach(copyistWithDeepMerge.bind(null, target, src, dst));
+ }
+
+ return dst;
+}
+#EXPORT deepMerge
+
+/**
+ * Validates instance against the provided schema
+ * Implements URI+JSON Pointer encoding, e.g. "%7e"="~0"=>"~", "~1"="%2f"=>"/"
+ * @param o
+ * @param s The path to walk o along
+ * @return any
+ */
+function objectGetPath(o, s) {
+ var parts = s.split('/').slice(1);
+ var k;
+ while (typeof (k=parts.shift()) == 'string') {
+ var n = decodeURIComponent(k.replace(/~0/,'~').replace(/~1/g,'/'));
+ if (!(n in o)) return;
+ o = o[n];
+ }
+ return o;
+};
+#EXPORT objectGetPath
+
+function pathEncoder (v) {
+ return '/'+encodeURIComponent(v).replace(/~/g,'%7E');
+}
+/**
+ * Accept an Array of property names and return a JSON Pointer URI fragment
+ * @param Array a
+ * @return {String}
+ */
+function encodePointer(a){
+ // ~ must be encoded explicitly because hacks
+ // the slash is encoded by encodeURIComponent
+ return a.map(pathEncoder).join('');
+};
+#EXPORT encodePointer AS encodePath
+
+
+/**
+ * Calculate the number of decimal places a number uses
+ * We need this to get correct results out of multipleOf and divisibleBy
+ * when either figure is has decimal places, due to IEEE-754 float issues.
+ * @param number
+ * @returns {number}
+ */
+function getDecimalPlaces(number) {
+
+ var decimalPlaces = 0;
+ if (isNaN(number)) return decimalPlaces;
+
+ if (typeof number !== 'number') {
+ number = Number(number);
+ }
+
+ var parts = number.toString().split('e');
+ if (parts.length === 2) {
+ if (parts[1][0] !== '-') {
+ return decimalPlaces;
+ } else {
+ decimalPlaces = Number(parts[1].slice(1));
+ }
+ }
+
+ var decimalParts = parts[0].split('.');
+ if (decimalParts.length === 2) {
+ decimalPlaces += decimalParts[1].length;
+ }
+
+ return decimalPlaces;
+};
+#EXPORT getDecimalPlaces
+
+function isSchema(val){
+ return (typeof val === 'object' && val) || (typeof val === 'boolean');
+};
+#EXPORT isSchema