1
|
/* SPDX-License-Identifier: MIT
|
2
|
*
|
3
|
* jsonschema is licensed under MIT license.
|
4
|
*
|
5
|
* Copyright (C) 2012-2015 Tom de Grunt <tom@degrunt.nl>
|
6
|
*
|
7
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
8
|
* this software and associated documentation files (the "Software"), to deal in
|
9
|
* the Software without restriction, including without limitation the rights to
|
10
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
11
|
* of the Software, and to permit persons to whom the Software is furnished to do
|
12
|
* so, subject to the following conditions:
|
13
|
*
|
14
|
* The above copyright notice and this permission notice shall be included in all
|
15
|
* copies or substantial portions of the Software.
|
16
|
*
|
17
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
23
|
* SOFTWARE.
|
24
|
*/
|
25
|
|
26
|
#IMPORT common/jsonschema/urllib_mock.js AS uri
|
27
|
|
28
|
function ValidationError (message, instance, schema, path, name, argument) {
|
29
|
if(Array.isArray(path)){
|
30
|
this.path = path;
|
31
|
this.property = path.reduce(function(sum, item){
|
32
|
return sum + makeSuffix(item);
|
33
|
}, 'instance');
|
34
|
}else if(path !== undefined){
|
35
|
this.property = path;
|
36
|
}
|
37
|
if (message) {
|
38
|
this.message = message;
|
39
|
}
|
40
|
if (schema) {
|
41
|
var id = schema.$id || schema.id;
|
42
|
this.schema = id || schema;
|
43
|
}
|
44
|
if (instance !== undefined) {
|
45
|
this.instance = instance;
|
46
|
}
|
47
|
this.name = name;
|
48
|
this.argument = argument;
|
49
|
this.stack = this.toString();
|
50
|
};
|
51
|
#EXPORT ValidationError
|
52
|
|
53
|
ValidationError.prototype.toString = function toString() {
|
54
|
return this.property + ' ' + this.message;
|
55
|
};
|
56
|
|
57
|
function ValidatorResult(instance, schema, options, ctx) {
|
58
|
this.instance = instance;
|
59
|
this.schema = schema;
|
60
|
this.options = options;
|
61
|
this.path = ctx.path;
|
62
|
this.propertyPath = ctx.propertyPath;
|
63
|
this.errors = [];
|
64
|
this.throwError = options && options.throwError;
|
65
|
this.throwFirst = options && options.throwFirst;
|
66
|
this.throwAll = options && options.throwAll;
|
67
|
this.disableFormat = options && options.disableFormat === true;
|
68
|
};
|
69
|
|
70
|
ValidatorResult.prototype.addError = function addError(detail) {
|
71
|
var err;
|
72
|
if (typeof detail == 'string') {
|
73
|
err = new ValidationError(detail, this.instance, this.schema, this.path);
|
74
|
} else {
|
75
|
if (!detail) throw new Error('Missing error detail');
|
76
|
if (!detail.message) throw new Error('Missing error message');
|
77
|
if (!detail.name) throw new Error('Missing validator type');
|
78
|
err = new ValidationError(detail.message, this.instance, this.schema, this.path, detail.name, detail.argument);
|
79
|
}
|
80
|
|
81
|
this.errors.push(err);
|
82
|
if (this.throwFirst) {
|
83
|
throw new ValidatorResultError(this);
|
84
|
}else if(this.throwError){
|
85
|
throw err;
|
86
|
}
|
87
|
return err;
|
88
|
};
|
89
|
|
90
|
ValidatorResult.prototype.importErrors = function importErrors(res) {
|
91
|
if (typeof res == 'string' || (res && res.validatorType)) {
|
92
|
this.addError(res);
|
93
|
} else if (res && res.errors) {
|
94
|
Array.prototype.push.apply(this.errors, res.errors);
|
95
|
}
|
96
|
};
|
97
|
|
98
|
function stringizer (v,i){
|
99
|
return i+': '+v.toString()+'\n';
|
100
|
}
|
101
|
ValidatorResult.prototype.toString = function toString(res) {
|
102
|
return this.errors.map(stringizer).join('');
|
103
|
};
|
104
|
|
105
|
Object.defineProperty(ValidatorResult.prototype, "valid", { get: function() {
|
106
|
return !this.errors.length;
|
107
|
} });
|
108
|
|
109
|
#EXPORT ValidatorResult
|
110
|
|
111
|
function ValidatorResultError(result) {
|
112
|
if(Error.captureStackTrace){
|
113
|
Error.captureStackTrace(this, ValidatorResultError);
|
114
|
}
|
115
|
this.instance = result.instance;
|
116
|
this.schema = result.schema;
|
117
|
this.options = result.options;
|
118
|
this.errors = result.errors;
|
119
|
}
|
120
|
ValidatorResultError.prototype = new Error();
|
121
|
ValidatorResultError.prototype.constructor = ValidatorResultError;
|
122
|
ValidatorResultError.prototype.name = "Validation Error";
|
123
|
#EXPORT ValidatorResultError
|
124
|
|
125
|
/**
|
126
|
* Describes a problem with a Schema which prevents validation of an instance
|
127
|
* @name SchemaError
|
128
|
* @constructor
|
129
|
*/
|
130
|
function SchemaError (msg, schema) {
|
131
|
this.message = msg;
|
132
|
this.schema = schema;
|
133
|
Error.call(this, msg);
|
134
|
if(Error.captureStackTrace){
|
135
|
Error.captureStackTrace(this, SchemaError);
|
136
|
}
|
137
|
};
|
138
|
SchemaError.prototype = Object.create(Error.prototype,
|
139
|
{
|
140
|
constructor: {value: SchemaError, enumerable: false},
|
141
|
name: {value: 'SchemaError', enumerable: false},
|
142
|
});
|
143
|
#EXPORT SchemaError
|
144
|
|
145
|
function SchemaContext (schema, options, path, base, schemas) {
|
146
|
this.schema = schema;
|
147
|
this.options = options;
|
148
|
if(Array.isArray(path)){
|
149
|
this.path = path;
|
150
|
this.propertyPath = path.reduce(function(sum, item){
|
151
|
return sum + makeSuffix(item);
|
152
|
}, 'instance');
|
153
|
}else{
|
154
|
this.propertyPath = path;
|
155
|
}
|
156
|
this.base = base;
|
157
|
this.schemas = schemas;
|
158
|
};
|
159
|
|
160
|
SchemaContext.prototype.resolve = function resolve (target) {
|
161
|
return uri.resolve(this.base, target);
|
162
|
};
|
163
|
|
164
|
SchemaContext.prototype.makeChild = function makeChild(schema, propertyName){
|
165
|
var path = (propertyName===undefined) ? this.path : this.path.concat([propertyName]);
|
166
|
var id = schema.$id || schema.id;
|
167
|
var base = uri.resolve(this.base, id||'');
|
168
|
var ctx = new SchemaContext(schema, this.options, path, base, Object.create(this.schemas));
|
169
|
if(id && !ctx.schemas[base]){
|
170
|
ctx.schemas[base] = schema;
|
171
|
}
|
172
|
return ctx;
|
173
|
};
|
174
|
|
175
|
#EXPORT SchemaContext
|
176
|
|
177
|
const FORMAT_REGEXPS = {
|
178
|
// 7.3.1. Dates, Times, and Duration
|
179
|
'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]))$/,
|
180
|
'date': /^\d{4}-(?:0[0-9]{1}|1[0-2]{1})-(3[01]|0[1-9]|[12][0-9])$/,
|
181
|
'time': /^(2[0-4]|[01][0-9]):([0-5][0-9]):(60|[0-5][0-9])$/,
|
182
|
'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,
|
183
|
|
184
|
// 7.3.2. Email Addresses
|
185
|
// TODO: fix the email production
|
186
|
'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])\]))$/,
|
187
|
'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,
|
188
|
|
189
|
// 7.3.3. Hostnames
|
190
|
|
191
|
// 7.3.4. IP Addresses
|
192
|
'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]?)$/,
|
193
|
// FIXME whitespace is invalid
|
194
|
'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*$/,
|
195
|
|
196
|
// 7.3.5. Resource Identifiers
|
197
|
// TODO: A more accurate regular expression for "uri" goes:
|
198
|
// [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]+)\])?)?)?
|
199
|
'uri': /^[a-zA-Z][a-zA-Z0-9+.-]*:[^\s]*$/,
|
200
|
'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]*:?)?$/,
|
201
|
'iri': /^[a-zA-Z][a-zA-Z0-9+.-]*:[^\s]*$/,
|
202
|
'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,
|
203
|
'uuid': /^[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$/i,
|
204
|
|
205
|
// 7.3.6. uri-template
|
206
|
'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,
|
207
|
|
208
|
// 7.3.7. JSON Pointers
|
209
|
'json-pointer': /^(\/([\x00-\x2e0-@\[-}\x7f]|~[01])*)*$/iu,
|
210
|
'relative-json-pointer': /^\d+(#|(\/([\x00-\x2e0-@\[-}\x7f]|~[01])*)*)$/iu,
|
211
|
|
212
|
// hostname regex from: http://stackoverflow.com/a/1420225/5628
|
213
|
'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])?)*\.?$/,
|
214
|
'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])?)*\.?$/,
|
215
|
|
216
|
'utc-millisec': function (input) {
|
217
|
return (typeof input === 'string') && parseFloat(input) === parseInt(input, 10) && !isNaN(input);
|
218
|
},
|
219
|
|
220
|
// 7.3.8. regex
|
221
|
'regex': function (input) {
|
222
|
var result = true;
|
223
|
try {
|
224
|
new RegExp(input);
|
225
|
} catch (e) {
|
226
|
result = false;
|
227
|
}
|
228
|
return result;
|
229
|
},
|
230
|
|
231
|
// Other definitions
|
232
|
// "style" was removed from JSON Schema in draft-4 and is deprecated
|
233
|
'style': /[\r\n\t ]*[^\r\n\t ][^:]*:[\r\n\t ]*[^\r\n\t ;]*[\r\n\t ]*;?/,
|
234
|
// "color" was removed from JSON Schema in draft-4 and is deprecated
|
235
|
'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*\)))$/,
|
236
|
'phone': /^\+(?:[0-9] ?){6,14}[0-9]$/,
|
237
|
'alpha': /^[a-zA-Z]+$/,
|
238
|
'alphanumeric': /^[a-zA-Z0-9]+$/,
|
239
|
};
|
240
|
|
241
|
FORMAT_REGEXPS.regexp = FORMAT_REGEXPS.regex;
|
242
|
FORMAT_REGEXPS.pattern = FORMAT_REGEXPS.regex;
|
243
|
FORMAT_REGEXPS.ipv4 = FORMAT_REGEXPS['ip-address'];
|
244
|
|
245
|
#EXPORT FORMAT_REGEXPS
|
246
|
|
247
|
function isFormat (input, format, validator) {
|
248
|
if (typeof input === 'string' && FORMAT_REGEXPS[format] !== undefined) {
|
249
|
if (FORMAT_REGEXPS[format] instanceof RegExp) {
|
250
|
return FORMAT_REGEXPS[format].test(input);
|
251
|
}
|
252
|
if (typeof FORMAT_REGEXPS[format] === 'function') {
|
253
|
return FORMAT_REGEXPS[format](input);
|
254
|
}
|
255
|
} else if (validator && validator.customFormats &&
|
256
|
typeof validator.customFormats[format] === 'function') {
|
257
|
return validator.customFormats[format](input);
|
258
|
}
|
259
|
return true;
|
260
|
};
|
261
|
|
262
|
#EXPORT isFormat
|
263
|
|
264
|
function makeSuffix (key) {
|
265
|
key = key.toString();
|
266
|
// This function could be capable of outputting valid a ECMAScript string, but the
|
267
|
// resulting code for testing which form to use would be tens of thousands of characters long
|
268
|
// That means this will use the name form for some illegal forms
|
269
|
if (!key.match(/[.\s\[\]]/) && !key.match(/^[\d]/)) {
|
270
|
return '.' + key;
|
271
|
}
|
272
|
if (key.match(/^\d+$/)) {
|
273
|
return '[' + key + ']';
|
274
|
}
|
275
|
return '[' + JSON.stringify(key) + ']';
|
276
|
};
|
277
|
#EXPORT makeSuffix
|
278
|
|
279
|
function deepCompareStrict (a, b) {
|
280
|
if (typeof a !== typeof b) {
|
281
|
return false;
|
282
|
}
|
283
|
if (Array.isArray(a)) {
|
284
|
if (!Array.isArray(b)) {
|
285
|
return false;
|
286
|
}
|
287
|
if (a.length !== b.length) {
|
288
|
return false;
|
289
|
}
|
290
|
return a.every(function (v, i) {
|
291
|
return deepCompareStrict(a[i], b[i]);
|
292
|
});
|
293
|
}
|
294
|
if (typeof a === 'object') {
|
295
|
if (!a || !b) {
|
296
|
return a === b;
|
297
|
}
|
298
|
var aKeys = Object.keys(a);
|
299
|
var bKeys = Object.keys(b);
|
300
|
if (aKeys.length !== bKeys.length) {
|
301
|
return false;
|
302
|
}
|
303
|
return aKeys.every(function (v) {
|
304
|
return deepCompareStrict(a[v], b[v]);
|
305
|
});
|
306
|
}
|
307
|
return a === b;
|
308
|
};
|
309
|
#EXPORT deepCompareStrict
|
310
|
|
311
|
function deepMerger (target, dst, e, i) {
|
312
|
if (typeof e === 'object') {
|
313
|
dst[i] = deepMerge(target[i], e);
|
314
|
} else {
|
315
|
if (target.indexOf(e) === -1) {
|
316
|
dst.push(e);
|
317
|
}
|
318
|
}
|
319
|
}
|
320
|
|
321
|
function copyist (src, dst, key) {
|
322
|
dst[key] = src[key];
|
323
|
}
|
324
|
|
325
|
function copyistWithDeepMerge (target, src, dst, key) {
|
326
|
if (typeof src[key] !== 'object' || !src[key]) {
|
327
|
dst[key] = src[key];
|
328
|
}
|
329
|
else {
|
330
|
if (!target[key]) {
|
331
|
dst[key] = src[key];
|
332
|
} else {
|
333
|
dst[key] = deepMerge(target[key], src[key]);
|
334
|
}
|
335
|
}
|
336
|
}
|
337
|
|
338
|
function deepMerge (target, src) {
|
339
|
var array = Array.isArray(src);
|
340
|
var dst = array && [] || {};
|
341
|
|
342
|
if (array) {
|
343
|
target = target || [];
|
344
|
dst = dst.concat(target);
|
345
|
src.forEach(deepMerger.bind(null, target, dst));
|
346
|
} else {
|
347
|
if (target && typeof target === 'object') {
|
348
|
Object.keys(target).forEach(copyist.bind(null, target, dst));
|
349
|
}
|
350
|
Object.keys(src).forEach(copyistWithDeepMerge.bind(null, target, src, dst));
|
351
|
}
|
352
|
|
353
|
return dst;
|
354
|
}
|
355
|
#EXPORT deepMerge
|
356
|
|
357
|
/**
|
358
|
* Validates instance against the provided schema
|
359
|
* Implements URI+JSON Pointer encoding, e.g. "%7e"="~0"=>"~", "~1"="%2f"=>"/"
|
360
|
* @param o
|
361
|
* @param s The path to walk o along
|
362
|
* @return any
|
363
|
*/
|
364
|
function objectGetPath(o, s) {
|
365
|
var parts = s.split('/').slice(1);
|
366
|
var k;
|
367
|
while (typeof (k=parts.shift()) == 'string') {
|
368
|
var n = decodeURIComponent(k.replace(/~0/,'~').replace(/~1/g,'/'));
|
369
|
if (!(n in o)) return;
|
370
|
o = o[n];
|
371
|
}
|
372
|
return o;
|
373
|
};
|
374
|
#EXPORT objectGetPath
|
375
|
|
376
|
function pathEncoder (v) {
|
377
|
return '/'+encodeURIComponent(v).replace(/~/g,'%7E');
|
378
|
}
|
379
|
/**
|
380
|
* Accept an Array of property names and return a JSON Pointer URI fragment
|
381
|
* @param Array a
|
382
|
* @return {String}
|
383
|
*/
|
384
|
function encodePointer(a){
|
385
|
// ~ must be encoded explicitly because hacks
|
386
|
// the slash is encoded by encodeURIComponent
|
387
|
return a.map(pathEncoder).join('');
|
388
|
};
|
389
|
#EXPORT encodePointer AS encodePath
|
390
|
|
391
|
|
392
|
/**
|
393
|
* Calculate the number of decimal places a number uses
|
394
|
* We need this to get correct results out of multipleOf and divisibleBy
|
395
|
* when either figure is has decimal places, due to IEEE-754 float issues.
|
396
|
* @param number
|
397
|
* @returns {number}
|
398
|
*/
|
399
|
function getDecimalPlaces(number) {
|
400
|
|
401
|
var decimalPlaces = 0;
|
402
|
if (isNaN(number)) return decimalPlaces;
|
403
|
|
404
|
if (typeof number !== 'number') {
|
405
|
number = Number(number);
|
406
|
}
|
407
|
|
408
|
var parts = number.toString().split('e');
|
409
|
if (parts.length === 2) {
|
410
|
if (parts[1][0] !== '-') {
|
411
|
return decimalPlaces;
|
412
|
} else {
|
413
|
decimalPlaces = Number(parts[1].slice(1));
|
414
|
}
|
415
|
}
|
416
|
|
417
|
var decimalParts = parts[0].split('.');
|
418
|
if (decimalParts.length === 2) {
|
419
|
decimalPlaces += decimalParts[1].length;
|
420
|
}
|
421
|
|
422
|
return decimalPlaces;
|
423
|
};
|
424
|
#EXPORT getDecimalPlaces
|
425
|
|
426
|
function isSchema(val){
|
427
|
return (typeof val === 'object' && val) || (typeof val === 'boolean');
|
428
|
};
|
429
|
#EXPORT isSchema
|