z-schema 7.0.0 → 7.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -11
- package/bin/z-schema +0 -0
- package/cjs/index.d.ts +192 -117
- package/cjs/index.js +949 -998
- package/{src/FormatValidators.ts → dist/format-validators.js} +97 -65
- package/dist/index.js +1 -1
- package/dist/json-schema.js +40 -0
- package/dist/{JsonValidation.js → json-validation.js} +75 -69
- package/dist/{Report.js → report.js} +35 -45
- package/dist/schema-cache.js +109 -0
- package/dist/schema-compiler.js +255 -0
- package/dist/{SchemaValidation.js → schema-validator.js} +153 -149
- package/dist/types/{Errors.d.ts → errors.d.ts} +2 -0
- package/dist/types/format-validators.d.ts +10 -0
- package/dist/types/index.d.ts +10 -1
- package/dist/types/json-schema.d.ts +50 -0
- package/dist/types/json-validation.d.ts +7 -0
- package/dist/types/{Report.d.ts → report.d.ts} +22 -23
- package/dist/types/schema-cache.d.ts +17 -0
- package/dist/types/schema-compiler.d.ts +16 -0
- package/dist/types/schema-validator.d.ts +10 -0
- package/dist/types/utils/array.d.ts +2 -0
- package/dist/types/utils/clone.d.ts +2 -0
- package/dist/types/utils/json.d.ts +7 -0
- package/dist/types/utils/symbols.d.ts +2 -0
- package/dist/types/utils/unicode.d.ts +14 -0
- package/dist/types/utils/uri.d.ts +4 -0
- package/dist/types/utils/what-is.d.ts +3 -0
- package/dist/types/z-schema.d.ts +75 -0
- package/dist/utils/array.js +27 -0
- package/dist/utils/clone.js +61 -0
- package/dist/utils/json.js +59 -0
- package/dist/utils/symbols.js +2 -0
- package/dist/utils/unicode.js +45 -0
- package/dist/utils/uri.js +15 -0
- package/dist/utils/what-is.js +29 -0
- package/dist/{ZSchema.js → z-schema.js} +66 -77
- package/package.json +8 -4
- package/src/{Errors.ts → errors.ts} +4 -0
- package/src/format-validators.ts +191 -0
- package/src/index.ts +12 -1
- package/src/json-schema.ts +97 -0
- package/src/{JsonValidation.ts → json-validation.ts} +137 -127
- package/src/{Report.ts → report.ts} +60 -70
- package/src/schema-cache.ts +122 -0
- package/src/schema-compiler.ts +300 -0
- package/src/{SchemaValidation.ts → schema-validator.ts} +213 -215
- package/src/utils/array.ts +29 -0
- package/src/utils/clone.ts +63 -0
- package/src/utils/json.ts +74 -0
- package/src/utils/symbols.ts +3 -0
- package/src/utils/unicode.ts +43 -0
- package/src/utils/uri.ts +18 -0
- package/src/utils/what-is.ts +46 -0
- package/src/{ZSchema.ts → z-schema.ts} +108 -113
- package/umd/ZSchema.js +949 -998
- package/umd/ZSchema.min.js +1 -1
- package/dist/FormatValidators.js +0 -136
- package/dist/SchemaCache.js +0 -173
- package/dist/SchemaCompilation.js +0 -259
- package/dist/Utils.js +0 -266
- package/dist/types/FormatValidators.d.ts +0 -12
- package/dist/types/JsonValidation.d.ts +0 -37
- package/dist/types/SchemaCache.d.ts +0 -26
- package/dist/types/SchemaCompilation.d.ts +0 -1
- package/dist/types/SchemaValidation.d.ts +0 -6
- package/dist/types/Utils.d.ts +0 -64
- package/dist/types/ZSchema.d.ts +0 -97
- package/src/SchemaCache.ts +0 -189
- package/src/SchemaCompilation.ts +0 -293
- package/src/Utils.ts +0 -286
- /package/dist/{Errors.js → errors.js} +0 -0
- /package/dist/schemas/{hyper-schema.json → draft-04-hyper-schema.json} +0 -0
- /package/dist/schemas/{schema.json → draft-04-schema.json} +0 -0
- /package/src/schemas/{hyper-schema.json → draft-04-hyper-schema.json} +0 -0
- /package/src/schemas/{schema.json → draft-04-schema.json} +0 -0
package/umd/ZSchema.js
CHANGED
|
@@ -1001,38 +1001,8 @@
|
|
|
1001
1001
|
REMOTE_NOT_VALID: "Remote reference didn't compile successfully: {0}",
|
|
1002
1002
|
};
|
|
1003
1003
|
|
|
1004
|
-
const
|
|
1005
|
-
|
|
1006
|
-
/**
|
|
1007
|
-
* @param {object} obj
|
|
1008
|
-
*
|
|
1009
|
-
* @returns {string[]}
|
|
1010
|
-
*/
|
|
1011
|
-
function sortedKeys(obj) {
|
|
1012
|
-
return Object.keys(obj).sort();
|
|
1013
|
-
}
|
|
1014
|
-
/**
|
|
1015
|
-
*
|
|
1016
|
-
* @param {string} uri
|
|
1017
|
-
*
|
|
1018
|
-
* @returns {boolean}
|
|
1019
|
-
*/
|
|
1020
|
-
function isAbsoluteUri(uri) {
|
|
1021
|
-
return /^https?:\/\//.test(uri);
|
|
1022
|
-
}
|
|
1023
|
-
/**
|
|
1024
|
-
*
|
|
1025
|
-
* @param {string} uri
|
|
1026
|
-
*
|
|
1027
|
-
* @returns {boolean}
|
|
1028
|
-
*/
|
|
1029
|
-
function isRelativeUri(uri) {
|
|
1030
|
-
// relative URIs that end with a hash sign, issue #56
|
|
1031
|
-
return /.+#/.test(uri);
|
|
1032
|
-
}
|
|
1033
|
-
function whatIs(what) {
|
|
1034
|
-
const to = typeof what;
|
|
1035
|
-
if (to === 'object') {
|
|
1004
|
+
const whatIs = (what) => {
|
|
1005
|
+
if (typeof what === 'object') {
|
|
1036
1006
|
if (what === null) {
|
|
1037
1007
|
return 'null';
|
|
1038
1008
|
}
|
|
@@ -1041,7 +1011,7 @@
|
|
|
1041
1011
|
}
|
|
1042
1012
|
return 'object'; // typeof what === 'object' && what === Object(what) && !Array.isArray(what);
|
|
1043
1013
|
}
|
|
1044
|
-
if (
|
|
1014
|
+
if (typeof what === 'number') {
|
|
1045
1015
|
if (Number.isFinite(what)) {
|
|
1046
1016
|
if (what % 1 === 0) {
|
|
1047
1017
|
return 'integer';
|
|
@@ -1055,242 +1025,45 @@
|
|
|
1055
1025
|
}
|
|
1056
1026
|
return 'unknown-number';
|
|
1057
1027
|
}
|
|
1058
|
-
return
|
|
1059
|
-
}
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
* @param {*} json1
|
|
1063
|
-
* @param {*} json2
|
|
1064
|
-
* @param {*} [options]
|
|
1065
|
-
*
|
|
1066
|
-
* @returns {boolean}
|
|
1067
|
-
*/
|
|
1068
|
-
function areEqual(json1, json2, options) {
|
|
1069
|
-
options = options || {};
|
|
1070
|
-
const caseInsensitiveComparison = options.caseInsensitiveComparison || false;
|
|
1071
|
-
// http://json-schema.org/latest/json-schema-core.html#rfc.section.3.6
|
|
1072
|
-
// Two JSON values are said to be equal if and only if:
|
|
1073
|
-
// both are nulls; or
|
|
1074
|
-
// both are booleans, and have the same value; or
|
|
1075
|
-
// both are strings, and have the same value; or
|
|
1076
|
-
// both are numbers, and have the same mathematical value; or
|
|
1077
|
-
if (json1 === json2) {
|
|
1078
|
-
return true;
|
|
1079
|
-
}
|
|
1080
|
-
if (caseInsensitiveComparison === true &&
|
|
1081
|
-
typeof json1 === 'string' &&
|
|
1082
|
-
typeof json2 === 'string' &&
|
|
1083
|
-
json1.toUpperCase() === json2.toUpperCase()) {
|
|
1084
|
-
return true;
|
|
1085
|
-
}
|
|
1086
|
-
let i, len;
|
|
1087
|
-
// both are arrays, and:
|
|
1088
|
-
if (Array.isArray(json1) && Array.isArray(json2)) {
|
|
1089
|
-
// have the same number of items; and
|
|
1090
|
-
if (json1.length !== json2.length) {
|
|
1091
|
-
return false;
|
|
1092
|
-
}
|
|
1093
|
-
// items at the same index are equal according to this definition; or
|
|
1094
|
-
len = json1.length;
|
|
1095
|
-
for (i = 0; i < len; i++) {
|
|
1096
|
-
if (!areEqual(json1[i], json2[i], { caseInsensitiveComparison: caseInsensitiveComparison })) {
|
|
1097
|
-
return false;
|
|
1098
|
-
}
|
|
1099
|
-
}
|
|
1100
|
-
return true;
|
|
1101
|
-
}
|
|
1102
|
-
// both are objects, and:
|
|
1103
|
-
if (whatIs(json1) === 'object' && whatIs(json2) === 'object') {
|
|
1104
|
-
// have the same set of property names; and
|
|
1105
|
-
const keys1 = sortedKeys(json1);
|
|
1106
|
-
const keys2 = sortedKeys(json2);
|
|
1107
|
-
if (!areEqual(keys1, keys2, { caseInsensitiveComparison: caseInsensitiveComparison })) {
|
|
1108
|
-
return false;
|
|
1109
|
-
}
|
|
1110
|
-
// values for a same property name are equal according to this definition.
|
|
1111
|
-
len = keys1.length;
|
|
1112
|
-
for (i = 0; i < len; i++) {
|
|
1113
|
-
if (!areEqual(json1[keys1[i]], json2[keys1[i]], { caseInsensitiveComparison: caseInsensitiveComparison })) {
|
|
1114
|
-
return false;
|
|
1115
|
-
}
|
|
1116
|
-
}
|
|
1117
|
-
return true;
|
|
1118
|
-
}
|
|
1119
|
-
return false;
|
|
1120
|
-
}
|
|
1121
|
-
/**
|
|
1122
|
-
*
|
|
1123
|
-
* @param {*[]} arr
|
|
1124
|
-
* @param {number[]} [indexes]
|
|
1125
|
-
*
|
|
1126
|
-
* @returns {boolean}
|
|
1127
|
-
*/
|
|
1128
|
-
function isUniqueArray(arr, indexes) {
|
|
1129
|
-
let i;
|
|
1130
|
-
let j;
|
|
1131
|
-
const l = arr.length;
|
|
1132
|
-
for (i = 0; i < l; i++) {
|
|
1133
|
-
for (j = i + 1; j < l; j++) {
|
|
1134
|
-
if (areEqual(arr[i], arr[j])) {
|
|
1135
|
-
if (indexes) {
|
|
1136
|
-
indexes.push(i, j);
|
|
1137
|
-
}
|
|
1138
|
-
return false;
|
|
1139
|
-
}
|
|
1140
|
-
}
|
|
1141
|
-
}
|
|
1142
|
-
return true;
|
|
1143
|
-
}
|
|
1144
|
-
/**
|
|
1145
|
-
*
|
|
1146
|
-
* @param {*} bigSet
|
|
1147
|
-
* @param {*} subSet
|
|
1148
|
-
*
|
|
1149
|
-
* @returns {*[]}
|
|
1150
|
-
*/
|
|
1151
|
-
function difference(bigSet, subSet) {
|
|
1152
|
-
const arr = [];
|
|
1153
|
-
let idx = bigSet.length;
|
|
1154
|
-
while (idx--) {
|
|
1155
|
-
if (subSet.indexOf(bigSet[idx]) === -1) {
|
|
1156
|
-
arr.push(bigSet[idx]);
|
|
1157
|
-
}
|
|
1158
|
-
}
|
|
1159
|
-
return arr;
|
|
1028
|
+
return typeof what; // undefined, boolean, string, function
|
|
1029
|
+
};
|
|
1030
|
+
function isObject(value) {
|
|
1031
|
+
return whatIs(value) === 'object';
|
|
1160
1032
|
}
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
if (Array.isArray(src)) {
|
|
1171
|
-
res = [];
|
|
1172
|
-
idx = src.length;
|
|
1173
|
-
while (idx--) {
|
|
1174
|
-
res[idx] = src[idx];
|
|
1175
|
-
}
|
|
1176
|
-
}
|
|
1177
|
-
else {
|
|
1178
|
-
res = {};
|
|
1179
|
-
const keys = Object.keys(src);
|
|
1180
|
-
idx = keys.length;
|
|
1181
|
-
while (idx--) {
|
|
1182
|
-
const key = keys[idx];
|
|
1183
|
-
res[key] = src[key];
|
|
1184
|
-
}
|
|
1185
|
-
}
|
|
1033
|
+
|
|
1034
|
+
const jsonSymbol = Symbol.for('z-schema/json');
|
|
1035
|
+
const schemaSymbol = Symbol.for('z-schema/schema');
|
|
1036
|
+
|
|
1037
|
+
const getQueryPath = (uri) => {
|
|
1038
|
+
const io = uri.indexOf('#');
|
|
1039
|
+
const res = io === -1 ? undefined : uri.slice(io + 1);
|
|
1040
|
+
// WARN: do not slice slash, #/ means take root and go down from it
|
|
1041
|
+
// if (res && res[0] === "/") { res = res.slice(1); }
|
|
1186
1042
|
return res;
|
|
1187
|
-
}
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
let res;
|
|
1197
|
-
let idx;
|
|
1198
|
-
const cidx = visited.get(src);
|
|
1199
|
-
if (cidx !== undefined) {
|
|
1200
|
-
return cloned[cidx];
|
|
1201
|
-
}
|
|
1202
|
-
visited.set(src, vidx++);
|
|
1203
|
-
if (Array.isArray(src)) {
|
|
1204
|
-
res = [];
|
|
1205
|
-
cloned.push(res);
|
|
1206
|
-
idx = src.length;
|
|
1207
|
-
while (idx--) {
|
|
1208
|
-
res[idx] = cloneDeepInner(src[idx]);
|
|
1209
|
-
}
|
|
1210
|
-
}
|
|
1211
|
-
else {
|
|
1212
|
-
res = {};
|
|
1213
|
-
cloned.push(res);
|
|
1214
|
-
const keys = Object.keys(src);
|
|
1215
|
-
idx = keys.length;
|
|
1216
|
-
while (idx--) {
|
|
1217
|
-
const key = keys[idx];
|
|
1218
|
-
res[key] = cloneDeepInner(src[key]);
|
|
1219
|
-
}
|
|
1220
|
-
}
|
|
1221
|
-
return res;
|
|
1222
|
-
}
|
|
1223
|
-
return cloneDeepInner(src);
|
|
1224
|
-
}
|
|
1225
|
-
/*
|
|
1226
|
-
following function comes from punycode.js library
|
|
1227
|
-
see: https://github.com/bestiejs/punycode.js
|
|
1228
|
-
*/
|
|
1229
|
-
/**
|
|
1230
|
-
* Creates an array containing the numeric code points of each Unicode
|
|
1231
|
-
* character in the string. While JavaScript uses UCS-2 internally,
|
|
1232
|
-
* this function will convert a pair of surrogate halves (each of which
|
|
1233
|
-
* UCS-2 exposes as separate characters) into a single code point,
|
|
1234
|
-
* matching UTF-16.
|
|
1235
|
-
* @see `punycode.ucs2.encode`
|
|
1236
|
-
* @see <https://mathiasbynens.be/notes/javascript-encoding>
|
|
1237
|
-
* @memberOf punycode.ucs2
|
|
1238
|
-
* @name decode
|
|
1239
|
-
* @param {String} string The Unicode input string (UCS-2).
|
|
1240
|
-
* @returns {Array} The new array of code points.
|
|
1241
|
-
*/
|
|
1242
|
-
function ucs2decode(string) {
|
|
1243
|
-
const output = [];
|
|
1244
|
-
let counter = 0;
|
|
1245
|
-
const length = string.length;
|
|
1246
|
-
let value;
|
|
1247
|
-
let extra;
|
|
1248
|
-
while (counter < length) {
|
|
1249
|
-
value = string.charCodeAt(counter++);
|
|
1250
|
-
if (value >= 0xd800 && value <= 0xdbff && counter < length) {
|
|
1251
|
-
// high surrogate, and there is a next character
|
|
1252
|
-
extra = string.charCodeAt(counter++);
|
|
1253
|
-
if ((extra & 0xfc00) == 0xdc00) {
|
|
1254
|
-
// low surrogate
|
|
1255
|
-
output.push(((value & 0x3ff) << 10) + (extra & 0x3ff) + 0x10000);
|
|
1256
|
-
}
|
|
1257
|
-
else {
|
|
1258
|
-
// unmatched surrogate; only append this code unit, in case the next
|
|
1259
|
-
// code unit is the high surrogate of a surrogate pair
|
|
1260
|
-
output.push(value);
|
|
1261
|
-
counter--;
|
|
1262
|
-
}
|
|
1263
|
-
}
|
|
1264
|
-
else {
|
|
1265
|
-
output.push(value);
|
|
1266
|
-
}
|
|
1267
|
-
}
|
|
1268
|
-
return output;
|
|
1269
|
-
}
|
|
1043
|
+
};
|
|
1044
|
+
const getRemotePath = (uri) => {
|
|
1045
|
+
const io = uri.indexOf('#');
|
|
1046
|
+
return io === -1 ? uri : uri.slice(0, io);
|
|
1047
|
+
};
|
|
1048
|
+
const isAbsoluteUri = (uri) => /^https?:\/\//.test(uri);
|
|
1049
|
+
const isRelativeUri = (uri) =>
|
|
1050
|
+
// relative URIs that end with a hash sign, issue #56
|
|
1051
|
+
/.+#/.test(uri);
|
|
1270
1052
|
|
|
1271
1053
|
class Report {
|
|
1272
|
-
|
|
1054
|
+
asyncTasks = [];
|
|
1055
|
+
commonErrorMessage;
|
|
1056
|
+
errors = [];
|
|
1057
|
+
json;
|
|
1058
|
+
path = [];
|
|
1059
|
+
rootSchema;
|
|
1273
1060
|
parentReport;
|
|
1274
1061
|
options;
|
|
1275
1062
|
reportOptions;
|
|
1276
|
-
path;
|
|
1277
|
-
asyncTasks;
|
|
1278
|
-
rootSchema;
|
|
1279
|
-
commonErrorMessage;
|
|
1280
|
-
json;
|
|
1281
1063
|
constructor(parentOrOptions, reportOptions) {
|
|
1282
1064
|
this.parentReport = parentOrOptions instanceof Report ? parentOrOptions : undefined;
|
|
1283
1065
|
this.options = parentOrOptions instanceof Report ? parentOrOptions.options : parentOrOptions || {};
|
|
1284
1066
|
this.reportOptions = reportOptions || {};
|
|
1285
|
-
this.errors = [];
|
|
1286
|
-
/**
|
|
1287
|
-
* @type {string[]}
|
|
1288
|
-
*/
|
|
1289
|
-
this.path = [];
|
|
1290
|
-
this.asyncTasks = [];
|
|
1291
|
-
this.rootSchema = undefined;
|
|
1292
|
-
this.commonErrorMessage = undefined;
|
|
1293
|
-
this.json = undefined;
|
|
1294
1067
|
}
|
|
1295
1068
|
isValid() {
|
|
1296
1069
|
if (this.asyncTasks.length > 0) {
|
|
@@ -1321,17 +1094,15 @@
|
|
|
1321
1094
|
callback(err, valid);
|
|
1322
1095
|
}, 0);
|
|
1323
1096
|
};
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
};
|
|
1334
|
-
}
|
|
1097
|
+
const respond = (asyncTaskResultProcessFn) => (asyncTaskResult) => {
|
|
1098
|
+
if (timedOut) {
|
|
1099
|
+
return;
|
|
1100
|
+
}
|
|
1101
|
+
asyncTaskResultProcessFn(asyncTaskResult);
|
|
1102
|
+
if (--tasksCount === 0) {
|
|
1103
|
+
finish();
|
|
1104
|
+
}
|
|
1105
|
+
};
|
|
1335
1106
|
// finish if tasks are completed or there are any errors and breaking on first error was requested
|
|
1336
1107
|
if (tasksCount === 0 || (this.errors.length > 0 && this.options.breakOnFirstError)) {
|
|
1337
1108
|
finish();
|
|
@@ -1351,9 +1122,6 @@
|
|
|
1351
1122
|
}, validationTimeout);
|
|
1352
1123
|
}
|
|
1353
1124
|
getPath(returnPathAsString) {
|
|
1354
|
-
/**
|
|
1355
|
-
* @type {string[]|string}
|
|
1356
|
-
*/
|
|
1357
1125
|
let path = [];
|
|
1358
1126
|
if (this.parentReport) {
|
|
1359
1127
|
path = path.concat(this.parentReport.path);
|
|
@@ -1376,7 +1144,7 @@
|
|
|
1376
1144
|
}
|
|
1377
1145
|
getSchemaId() {
|
|
1378
1146
|
if (!this.rootSchema) {
|
|
1379
|
-
return
|
|
1147
|
+
return undefined;
|
|
1380
1148
|
}
|
|
1381
1149
|
// get the error path as an array
|
|
1382
1150
|
let path = [];
|
|
@@ -1395,16 +1163,16 @@
|
|
|
1395
1163
|
// return id of the root
|
|
1396
1164
|
return this.rootSchema.id;
|
|
1397
1165
|
}
|
|
1398
|
-
hasError(
|
|
1166
|
+
hasError(errCode, errParams) {
|
|
1399
1167
|
let idx = this.errors.length;
|
|
1400
1168
|
while (idx--) {
|
|
1401
|
-
if (this.errors[idx].code ===
|
|
1169
|
+
if (this.errors[idx].code === errCode) {
|
|
1402
1170
|
// assume match
|
|
1403
1171
|
let match = true;
|
|
1404
1172
|
// check the params too
|
|
1405
1173
|
let idx2 = this.errors[idx].params.length;
|
|
1406
1174
|
while (idx2--) {
|
|
1407
|
-
if (this.errors[idx].params[idx2] !==
|
|
1175
|
+
if (this.errors[idx].params[idx2] !== errParams[idx2]) {
|
|
1408
1176
|
match = false;
|
|
1409
1177
|
}
|
|
1410
1178
|
}
|
|
@@ -1416,12 +1184,13 @@
|
|
|
1416
1184
|
}
|
|
1417
1185
|
return false;
|
|
1418
1186
|
}
|
|
1419
|
-
addError(
|
|
1420
|
-
if (!
|
|
1187
|
+
addError(errCode, errParams, subReports, schema) {
|
|
1188
|
+
if (!errCode) {
|
|
1421
1189
|
throw new Error('No errorCode passed into addError()');
|
|
1422
1190
|
}
|
|
1423
|
-
this.addCustomError(
|
|
1191
|
+
this.addCustomError(errCode, Errors[errCode], errParams, subReports, schema);
|
|
1424
1192
|
}
|
|
1193
|
+
// this returns the root object being validated (the one passed into validator.validate)
|
|
1425
1194
|
getJson() {
|
|
1426
1195
|
if (this.json) {
|
|
1427
1196
|
return this.json;
|
|
@@ -1432,7 +1201,7 @@
|
|
|
1432
1201
|
return undefined;
|
|
1433
1202
|
}
|
|
1434
1203
|
addCustomError(errorCode, errorMessage, params, subReports, schema) {
|
|
1435
|
-
if (this.errors.length >= this.reportOptions.maxErrors) {
|
|
1204
|
+
if (typeof this.reportOptions.maxErrors === 'number' && this.errors.length >= this.reportOptions.maxErrors) {
|
|
1436
1205
|
return;
|
|
1437
1206
|
}
|
|
1438
1207
|
if (!errorMessage) {
|
|
@@ -1441,9 +1210,9 @@
|
|
|
1441
1210
|
params = params || [];
|
|
1442
1211
|
let idx = params.length;
|
|
1443
1212
|
while (idx--) {
|
|
1444
|
-
const
|
|
1445
|
-
const param =
|
|
1446
|
-
errorMessage = errorMessage.replace('{' + idx + '}', param);
|
|
1213
|
+
const paramType = whatIs(params[idx]);
|
|
1214
|
+
const param = paramType === 'object' || paramType === 'null' ? JSON.stringify(params[idx]) : params[idx];
|
|
1215
|
+
errorMessage = errorMessage.replace('{' + idx + '}', param.toString());
|
|
1447
1216
|
}
|
|
1448
1217
|
const err = {
|
|
1449
1218
|
code: errorCode,
|
|
@@ -1452,6 +1221,7 @@
|
|
|
1452
1221
|
path: this.getPath(this.options.reportPathAsArray),
|
|
1453
1222
|
schemaId: this.getSchemaId(),
|
|
1454
1223
|
};
|
|
1224
|
+
// TODO v8: remove Symbol usage
|
|
1455
1225
|
err[schemaSymbol] = schema;
|
|
1456
1226
|
err[jsonSymbol] = this.getJson();
|
|
1457
1227
|
if (schema && typeof schema === 'string') {
|
|
@@ -1983,7 +1753,7 @@
|
|
|
1983
1753
|
return matches.exports;
|
|
1984
1754
|
}
|
|
1985
1755
|
|
|
1986
|
-
var isEmail = {exports: {}};
|
|
1756
|
+
var isEmail$1 = {exports: {}};
|
|
1987
1757
|
|
|
1988
1758
|
var checkHost = {exports: {}};
|
|
1989
1759
|
|
|
@@ -2141,12 +1911,12 @@
|
|
|
2141
1911
|
return isFQDN.exports;
|
|
2142
1912
|
}
|
|
2143
1913
|
|
|
2144
|
-
var isIP = {exports: {}};
|
|
1914
|
+
var isIP$1 = {exports: {}};
|
|
2145
1915
|
|
|
2146
1916
|
var hasRequiredIsIP;
|
|
2147
1917
|
|
|
2148
1918
|
function requireIsIP () {
|
|
2149
|
-
if (hasRequiredIsIP) return isIP.exports;
|
|
1919
|
+
if (hasRequiredIsIP) return isIP$1.exports;
|
|
2150
1920
|
hasRequiredIsIP = 1;
|
|
2151
1921
|
(function (module, exports$1) {
|
|
2152
1922
|
|
|
@@ -2215,14 +1985,14 @@
|
|
|
2215
1985
|
}
|
|
2216
1986
|
module.exports = exports$1.default;
|
|
2217
1987
|
module.exports.default = exports$1.default;
|
|
2218
|
-
} (isIP, isIP.exports));
|
|
2219
|
-
return isIP.exports;
|
|
1988
|
+
} (isIP$1, isIP$1.exports));
|
|
1989
|
+
return isIP$1.exports;
|
|
2220
1990
|
}
|
|
2221
1991
|
|
|
2222
1992
|
var hasRequiredIsEmail;
|
|
2223
1993
|
|
|
2224
1994
|
function requireIsEmail () {
|
|
2225
|
-
if (hasRequiredIsEmail) return isEmail.exports;
|
|
1995
|
+
if (hasRequiredIsEmail) return isEmail$1.exports;
|
|
2226
1996
|
hasRequiredIsEmail = 1;
|
|
2227
1997
|
(function (module, exports$1) {
|
|
2228
1998
|
|
|
@@ -2398,11 +2168,11 @@
|
|
|
2398
2168
|
}
|
|
2399
2169
|
module.exports = exports$1.default;
|
|
2400
2170
|
module.exports.default = exports$1.default;
|
|
2401
|
-
} (isEmail, isEmail.exports));
|
|
2402
|
-
return isEmail.exports;
|
|
2171
|
+
} (isEmail$1, isEmail$1.exports));
|
|
2172
|
+
return isEmail$1.exports;
|
|
2403
2173
|
}
|
|
2404
2174
|
|
|
2405
|
-
var isURL = {exports: {}};
|
|
2175
|
+
var isURL$1 = {exports: {}};
|
|
2406
2176
|
|
|
2407
2177
|
var includesString = {exports: {}};
|
|
2408
2178
|
|
|
@@ -2430,7 +2200,7 @@
|
|
|
2430
2200
|
var hasRequiredIsURL;
|
|
2431
2201
|
|
|
2432
2202
|
function requireIsURL () {
|
|
2433
|
-
if (hasRequiredIsURL) return isURL.exports;
|
|
2203
|
+
if (hasRequiredIsURL) return isURL$1.exports;
|
|
2434
2204
|
hasRequiredIsURL = 1;
|
|
2435
2205
|
(function (module, exports$1) {
|
|
2436
2206
|
|
|
@@ -2681,8 +2451,8 @@
|
|
|
2681
2451
|
}
|
|
2682
2452
|
module.exports = exports$1.default;
|
|
2683
2453
|
module.exports.default = exports$1.default;
|
|
2684
|
-
} (isURL, isURL.exports));
|
|
2685
|
-
return isURL.exports;
|
|
2454
|
+
} (isURL$1, isURL$1.exports));
|
|
2455
|
+
return isURL$1.exports;
|
|
2686
2456
|
}
|
|
2687
2457
|
|
|
2688
2458
|
var isMACAddress = {exports: {}};
|
|
@@ -9383,140 +9153,359 @@
|
|
|
9383
9153
|
var validatorExports = /*@__PURE__*/ requireValidator();
|
|
9384
9154
|
var validator = /*@__PURE__*/getDefaultExportFromCjs(validatorExports);
|
|
9385
9155
|
|
|
9386
|
-
const
|
|
9387
|
-
|
|
9388
|
-
|
|
9389
|
-
|
|
9390
|
-
|
|
9391
|
-
|
|
9392
|
-
|
|
9393
|
-
|
|
9156
|
+
const areEqual = (json1, json2, options) => {
|
|
9157
|
+
options = options || {};
|
|
9158
|
+
const caseInsensitiveComparison = options.caseInsensitiveComparison || false;
|
|
9159
|
+
// http://json-schema.org/latest/json-schema-core.html#rfc.section.3.6
|
|
9160
|
+
// Two JSON values are said to be equal if and only if:
|
|
9161
|
+
// both are nulls; or
|
|
9162
|
+
// both are booleans, and have the same value; or
|
|
9163
|
+
// both are strings, and have the same value; or
|
|
9164
|
+
// both are numbers, and have the same mathematical value; or
|
|
9165
|
+
if (json1 === json2) {
|
|
9166
|
+
return true;
|
|
9167
|
+
}
|
|
9168
|
+
if (caseInsensitiveComparison === true &&
|
|
9169
|
+
typeof json1 === 'string' &&
|
|
9170
|
+
typeof json2 === 'string' &&
|
|
9171
|
+
json1.toUpperCase() === json2.toUpperCase()) {
|
|
9172
|
+
return true;
|
|
9173
|
+
}
|
|
9174
|
+
let i, len;
|
|
9175
|
+
// both are arrays, and:
|
|
9176
|
+
if (Array.isArray(json1) && Array.isArray(json2)) {
|
|
9177
|
+
// have the same number of items; and
|
|
9178
|
+
if (json1.length !== json2.length) {
|
|
9394
9179
|
return false;
|
|
9395
9180
|
}
|
|
9396
|
-
//
|
|
9397
|
-
|
|
9398
|
-
|
|
9399
|
-
|
|
9400
|
-
|
|
9181
|
+
// items at the same index are equal according to this definition; or
|
|
9182
|
+
len = json1.length;
|
|
9183
|
+
for (i = 0; i < len; i++) {
|
|
9184
|
+
if (!areEqual(json1[i], json2[i], { caseInsensitiveComparison: caseInsensitiveComparison })) {
|
|
9185
|
+
return false;
|
|
9186
|
+
}
|
|
9401
9187
|
}
|
|
9402
9188
|
return true;
|
|
9403
|
-
}
|
|
9404
|
-
|
|
9405
|
-
|
|
9406
|
-
|
|
9407
|
-
|
|
9408
|
-
|
|
9409
|
-
|
|
9410
|
-
if (!FormatValidators.date(s[0])) {
|
|
9411
|
-
return false;
|
|
9412
|
-
}
|
|
9413
|
-
const matches = /^([0-9]{2}):([0-9]{2}):([0-9]{2})(.[0-9]+)?(z|([+-][0-9]{2}:[0-9]{2}))$/.exec(s[1]);
|
|
9414
|
-
if (matches === null) {
|
|
9189
|
+
}
|
|
9190
|
+
// both are objects, and:
|
|
9191
|
+
if (isObject(json1) && isObject(json2)) {
|
|
9192
|
+
// have the same set of property names; and
|
|
9193
|
+
const keys1 = sortedKeys(json1);
|
|
9194
|
+
const keys2 = sortedKeys(json2);
|
|
9195
|
+
if (!areEqual(keys1, keys2, { caseInsensitiveComparison: caseInsensitiveComparison })) {
|
|
9415
9196
|
return false;
|
|
9416
9197
|
}
|
|
9417
|
-
//
|
|
9418
|
-
|
|
9419
|
-
|
|
9420
|
-
|
|
9421
|
-
|
|
9422
|
-
|
|
9423
|
-
return false;
|
|
9198
|
+
// values for a same property name are equal according to this definition.
|
|
9199
|
+
len = keys1.length;
|
|
9200
|
+
for (i = 0; i < len; i++) {
|
|
9201
|
+
if (!areEqual(json1[keys1[i]], json2[keys1[i]], { caseInsensitiveComparison: caseInsensitiveComparison })) {
|
|
9202
|
+
return false;
|
|
9203
|
+
}
|
|
9424
9204
|
}
|
|
9425
9205
|
return true;
|
|
9426
|
-
}
|
|
9427
|
-
|
|
9428
|
-
|
|
9429
|
-
|
|
9430
|
-
|
|
9431
|
-
|
|
9432
|
-
|
|
9433
|
-
|
|
9434
|
-
|
|
9435
|
-
|
|
9206
|
+
}
|
|
9207
|
+
return false;
|
|
9208
|
+
};
|
|
9209
|
+
const decodeJSONPointer = (str) => {
|
|
9210
|
+
// http://tools.ietf.org/html/draft-ietf-appsawg-json-pointer-07#section-3
|
|
9211
|
+
return decodeURIComponent(str).replace(/~[0-1]/g, (x) => (x === '~1' ? '/' : '~'));
|
|
9212
|
+
};
|
|
9213
|
+
const sortedKeys = (obj) => Object.keys(obj).sort();
|
|
9214
|
+
|
|
9215
|
+
const { isEmail, isIP, isURL } = validator;
|
|
9216
|
+
const dateValidator = (date) => {
|
|
9217
|
+
if (typeof date !== 'string') {
|
|
9218
|
+
return true;
|
|
9219
|
+
}
|
|
9220
|
+
// full-date from http://tools.ietf.org/html/rfc3339#section-5.6
|
|
9221
|
+
const matches = /^([0-9]{4})-([0-9]{2})-([0-9]{2})$/.exec(date);
|
|
9222
|
+
if (matches === null) {
|
|
9223
|
+
return false;
|
|
9224
|
+
}
|
|
9225
|
+
// var year = matches[1];
|
|
9226
|
+
// var month = matches[2];
|
|
9227
|
+
// var day = matches[3];
|
|
9228
|
+
if (matches[2] < '01' || matches[2] > '12' || matches[3] < '01' || matches[3] > '31') {
|
|
9229
|
+
return false;
|
|
9230
|
+
}
|
|
9231
|
+
return true;
|
|
9232
|
+
};
|
|
9233
|
+
const dateTimeValidator = (dateTime) => {
|
|
9234
|
+
if (typeof dateTime !== 'string') {
|
|
9235
|
+
return true;
|
|
9236
|
+
}
|
|
9237
|
+
// date-time from http://tools.ietf.org/html/rfc3339#section-5.6
|
|
9238
|
+
const s = dateTime.toLowerCase().split('t');
|
|
9239
|
+
if (!dateValidator(s[0])) {
|
|
9240
|
+
return false;
|
|
9241
|
+
}
|
|
9242
|
+
const matches = /^([0-9]{2}):([0-9]{2}):([0-9]{2})(.[0-9]+)?(z|([+-][0-9]{2}:[0-9]{2}))$/.exec(s[1]);
|
|
9243
|
+
if (matches === null) {
|
|
9244
|
+
return false;
|
|
9245
|
+
}
|
|
9246
|
+
// var hour = matches[1];
|
|
9247
|
+
// var minute = matches[2];
|
|
9248
|
+
// var second = matches[3];
|
|
9249
|
+
// var fraction = matches[4];
|
|
9250
|
+
// var timezone = matches[5];
|
|
9251
|
+
if (matches[1] > '23' || matches[2] > '59' || matches[3] > '59') {
|
|
9252
|
+
return false;
|
|
9253
|
+
}
|
|
9254
|
+
return true;
|
|
9255
|
+
};
|
|
9256
|
+
const emailValidator = (email) => {
|
|
9257
|
+
if (typeof email !== 'string') {
|
|
9258
|
+
return true;
|
|
9259
|
+
}
|
|
9260
|
+
return isEmail(email, { require_tld: true });
|
|
9261
|
+
};
|
|
9262
|
+
const hostnameValidator = (hostname) => {
|
|
9263
|
+
if (typeof hostname !== 'string') {
|
|
9264
|
+
return true;
|
|
9265
|
+
}
|
|
9266
|
+
/*
|
|
9267
|
+
http://json-schema.org/latest/json-schema-validation.html#anchor114
|
|
9268
|
+
A string instance is valid against this attribute if it is a valid
|
|
9269
|
+
representation for an Internet host name, as defined by RFC 1034, section 3.1 [RFC1034].
|
|
9270
|
+
|
|
9271
|
+
http://tools.ietf.org/html/rfc1034#section-3.5
|
|
9272
|
+
|
|
9273
|
+
<digit> ::= any one of the ten digits 0 through 9
|
|
9274
|
+
var digit = /[0-9]/;
|
|
9275
|
+
|
|
9276
|
+
<letter> ::= any one of the 52 alphabetic characters A through Z in upper case and a through z in lower case
|
|
9277
|
+
var letter = /[a-zA-Z]/;
|
|
9278
|
+
|
|
9279
|
+
<let-dig> ::= <letter> | <digit>
|
|
9280
|
+
var letDig = /[0-9a-zA-Z]/;
|
|
9281
|
+
|
|
9282
|
+
<let-dig-hyp> ::= <let-dig> | "-"
|
|
9283
|
+
var letDigHyp = /[-0-9a-zA-Z]/;
|
|
9284
|
+
|
|
9285
|
+
<ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
|
|
9286
|
+
var ldhStr = /[-0-9a-zA-Z]+/;
|
|
9287
|
+
|
|
9288
|
+
<label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]
|
|
9289
|
+
var label = /[a-zA-Z](([-0-9a-zA-Z]+)?[0-9a-zA-Z])?/;
|
|
9290
|
+
|
|
9291
|
+
<subdomain> ::= <label> | <subdomain> "." <label>
|
|
9292
|
+
var subdomain = /^[a-zA-Z](([-0-9a-zA-Z]+)?[0-9a-zA-Z])?(\.[a-zA-Z](([-0-9a-zA-Z]+)?[0-9a-zA-Z])?)*$/;
|
|
9293
|
+
|
|
9294
|
+
<domain> ::= <subdomain> | " "
|
|
9295
|
+
var domain = null;
|
|
9296
|
+
*/
|
|
9297
|
+
const valid = /^[a-zA-Z](([-0-9a-zA-Z]+)?[0-9a-zA-Z])?(\.[a-zA-Z](([-0-9a-zA-Z]+)?[0-9a-zA-Z])?)*$/.test(hostname);
|
|
9298
|
+
if (valid) {
|
|
9299
|
+
// the sum of all label octets and label lengths is limited to 255.
|
|
9300
|
+
if (hostname.length > 255) {
|
|
9301
|
+
return false;
|
|
9436
9302
|
}
|
|
9437
|
-
|
|
9438
|
-
|
|
9439
|
-
|
|
9440
|
-
|
|
9441
|
-
|
|
9442
|
-
http://tools.ietf.org/html/rfc1034#section-3.5
|
|
9443
|
-
|
|
9444
|
-
<digit> ::= any one of the ten digits 0 through 9
|
|
9445
|
-
var digit = /[0-9]/;
|
|
9446
|
-
|
|
9447
|
-
<letter> ::= any one of the 52 alphabetic characters A through Z in upper case and a through z in lower case
|
|
9448
|
-
var letter = /[a-zA-Z]/;
|
|
9449
|
-
|
|
9450
|
-
<let-dig> ::= <letter> | <digit>
|
|
9451
|
-
var letDig = /[0-9a-zA-Z]/;
|
|
9452
|
-
|
|
9453
|
-
<let-dig-hyp> ::= <let-dig> | "-"
|
|
9454
|
-
var letDigHyp = /[-0-9a-zA-Z]/;
|
|
9455
|
-
|
|
9456
|
-
<ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
|
|
9457
|
-
var ldhStr = /[-0-9a-zA-Z]+/;
|
|
9458
|
-
|
|
9459
|
-
<label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]
|
|
9460
|
-
var label = /[a-zA-Z](([-0-9a-zA-Z]+)?[0-9a-zA-Z])?/;
|
|
9461
|
-
|
|
9462
|
-
<subdomain> ::= <label> | <subdomain> "." <label>
|
|
9463
|
-
var subdomain = /^[a-zA-Z](([-0-9a-zA-Z]+)?[0-9a-zA-Z])?(\.[a-zA-Z](([-0-9a-zA-Z]+)?[0-9a-zA-Z])?)*$/;
|
|
9464
|
-
|
|
9465
|
-
<domain> ::= <subdomain> | " "
|
|
9466
|
-
var domain = null;
|
|
9467
|
-
*/
|
|
9468
|
-
const valid = /^[a-zA-Z](([-0-9a-zA-Z]+)?[0-9a-zA-Z])?(\.[a-zA-Z](([-0-9a-zA-Z]+)?[0-9a-zA-Z])?)*$/.test(hostname);
|
|
9469
|
-
if (valid) {
|
|
9470
|
-
// the sum of all label octets and label lengths is limited to 255.
|
|
9471
|
-
if (hostname.length > 255) {
|
|
9303
|
+
// Each node has a label, which is zero to 63 octets in length
|
|
9304
|
+
const labels = hostname.split('.');
|
|
9305
|
+
for (let i = 0; i < labels.length; i++) {
|
|
9306
|
+
if (labels[i].length > 63) {
|
|
9472
9307
|
return false;
|
|
9473
9308
|
}
|
|
9474
|
-
|
|
9475
|
-
|
|
9476
|
-
|
|
9477
|
-
|
|
9478
|
-
|
|
9309
|
+
}
|
|
9310
|
+
}
|
|
9311
|
+
return valid;
|
|
9312
|
+
};
|
|
9313
|
+
const ipv4Validator = (ipv4) => {
|
|
9314
|
+
if (typeof ipv4 !== 'string') {
|
|
9315
|
+
return true;
|
|
9316
|
+
}
|
|
9317
|
+
return isIP(ipv4, 4);
|
|
9318
|
+
};
|
|
9319
|
+
const ipv6Validator = (ipv6) => {
|
|
9320
|
+
if (typeof ipv6 !== 'string') {
|
|
9321
|
+
return true;
|
|
9322
|
+
}
|
|
9323
|
+
return isIP(ipv6, 6);
|
|
9324
|
+
};
|
|
9325
|
+
const regexValidator = (input) => {
|
|
9326
|
+
if (typeof input !== 'string') {
|
|
9327
|
+
return false;
|
|
9328
|
+
}
|
|
9329
|
+
try {
|
|
9330
|
+
RegExp(input);
|
|
9331
|
+
return true;
|
|
9332
|
+
}
|
|
9333
|
+
catch (_e) {
|
|
9334
|
+
return false;
|
|
9335
|
+
}
|
|
9336
|
+
};
|
|
9337
|
+
const strictUriValidator = (uri) => typeof uri !== 'string' || isURL(uri);
|
|
9338
|
+
const uriValidator = function (uri) {
|
|
9339
|
+
// https://github.com/zaggino/z-schema/issues/18
|
|
9340
|
+
// RegExp from http://tools.ietf.org/html/rfc3986#appendix-B
|
|
9341
|
+
return typeof uri !== 'string' || RegExp('^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?').test(uri);
|
|
9342
|
+
};
|
|
9343
|
+
const inbuiltValidators = {
|
|
9344
|
+
date: dateValidator,
|
|
9345
|
+
'date-time': dateTimeValidator,
|
|
9346
|
+
email: emailValidator,
|
|
9347
|
+
hostname: hostnameValidator,
|
|
9348
|
+
'host-name': hostnameValidator,
|
|
9349
|
+
ipv4: ipv4Validator,
|
|
9350
|
+
ipv6: ipv6Validator,
|
|
9351
|
+
regex: regexValidator,
|
|
9352
|
+
uri: uriValidator,
|
|
9353
|
+
'strict-uri': strictUriValidator,
|
|
9354
|
+
};
|
|
9355
|
+
const customValidators = {};
|
|
9356
|
+
function getFormatValidators(options) {
|
|
9357
|
+
return {
|
|
9358
|
+
...inbuiltValidators,
|
|
9359
|
+
...(options?.strictUris ? { uri: strictUriValidator } : {}),
|
|
9360
|
+
...customValidators,
|
|
9361
|
+
};
|
|
9362
|
+
}
|
|
9363
|
+
function registerFormat(name, validatorFunction) {
|
|
9364
|
+
customValidators[name] = validatorFunction;
|
|
9365
|
+
}
|
|
9366
|
+
function unregisterFormat(name) {
|
|
9367
|
+
delete customValidators[name];
|
|
9368
|
+
}
|
|
9369
|
+
function isFormatSupported(name) {
|
|
9370
|
+
return inbuiltValidators[name] != null || customValidators[name] != null;
|
|
9371
|
+
}
|
|
9372
|
+
function getRegisteredFormats() {
|
|
9373
|
+
return sortedKeys(customValidators);
|
|
9374
|
+
}
|
|
9375
|
+
|
|
9376
|
+
/*
|
|
9377
|
+
following function comes from punycode.js library
|
|
9378
|
+
see: https://github.com/bestiejs/punycode.js
|
|
9379
|
+
*/
|
|
9380
|
+
/**
|
|
9381
|
+
* Creates an array containing the numeric code points of each Unicode
|
|
9382
|
+
* character in the string. While JavaScript uses UCS-2 internally,
|
|
9383
|
+
* this function will convert a pair of surrogate halves (each of which
|
|
9384
|
+
* UCS-2 exposes as separate characters) into a single code point,
|
|
9385
|
+
* matching UTF-16.
|
|
9386
|
+
* @see `punycode.ucs2.encode`
|
|
9387
|
+
* @see <https://mathiasbynens.be/notes/javascript-encoding>
|
|
9388
|
+
* @memberOf punycode.ucs2
|
|
9389
|
+
* @name decode
|
|
9390
|
+
* @param {String} string The Unicode input string (UCS-2).
|
|
9391
|
+
* @returns {Array} The new array of code points.
|
|
9392
|
+
*/
|
|
9393
|
+
function ucs2decode(string) {
|
|
9394
|
+
const output = [];
|
|
9395
|
+
let counter = 0;
|
|
9396
|
+
const length = string.length;
|
|
9397
|
+
let value;
|
|
9398
|
+
let extra;
|
|
9399
|
+
while (counter < length) {
|
|
9400
|
+
value = string.charCodeAt(counter++);
|
|
9401
|
+
if (value >= 0xd800 && value <= 0xdbff && counter < length) {
|
|
9402
|
+
// high surrogate, and there is a next character
|
|
9403
|
+
extra = string.charCodeAt(counter++);
|
|
9404
|
+
if ((extra & 0xfc00) == 0xdc00) {
|
|
9405
|
+
// low surrogate
|
|
9406
|
+
output.push(((value & 0x3ff) << 10) + (extra & 0x3ff) + 0x10000);
|
|
9407
|
+
}
|
|
9408
|
+
else {
|
|
9409
|
+
// unmatched surrogate; only append this code unit, in case the next
|
|
9410
|
+
// code unit is the high surrogate of a surrogate pair
|
|
9411
|
+
output.push(value);
|
|
9412
|
+
counter--;
|
|
9413
|
+
}
|
|
9414
|
+
}
|
|
9415
|
+
else {
|
|
9416
|
+
output.push(value);
|
|
9417
|
+
}
|
|
9418
|
+
}
|
|
9419
|
+
return output;
|
|
9420
|
+
}
|
|
9421
|
+
|
|
9422
|
+
const isUniqueArray = (arr, indexes) => {
|
|
9423
|
+
let i;
|
|
9424
|
+
let j;
|
|
9425
|
+
const l = arr.length;
|
|
9426
|
+
for (i = 0; i < l; i++) {
|
|
9427
|
+
for (j = i + 1; j < l; j++) {
|
|
9428
|
+
if (areEqual(arr[i], arr[j])) {
|
|
9429
|
+
if (indexes) {
|
|
9430
|
+
indexes.push(i, j);
|
|
9479
9431
|
}
|
|
9432
|
+
return false;
|
|
9480
9433
|
}
|
|
9481
9434
|
}
|
|
9482
|
-
|
|
9483
|
-
|
|
9484
|
-
|
|
9485
|
-
|
|
9486
|
-
|
|
9487
|
-
|
|
9488
|
-
|
|
9489
|
-
|
|
9435
|
+
}
|
|
9436
|
+
return true;
|
|
9437
|
+
};
|
|
9438
|
+
const difference = (bigSet, subSet) => {
|
|
9439
|
+
const arr = [];
|
|
9440
|
+
let idx = bigSet.length;
|
|
9441
|
+
while (idx--) {
|
|
9442
|
+
if (subSet.indexOf(bigSet[idx]) === -1) {
|
|
9443
|
+
arr.push(bigSet[idx]);
|
|
9490
9444
|
}
|
|
9491
|
-
|
|
9492
|
-
|
|
9493
|
-
|
|
9494
|
-
|
|
9495
|
-
|
|
9445
|
+
}
|
|
9446
|
+
return arr;
|
|
9447
|
+
};
|
|
9448
|
+
|
|
9449
|
+
const shallowClone = (src) => {
|
|
9450
|
+
if (src == null || typeof src !== 'object') {
|
|
9451
|
+
return src;
|
|
9452
|
+
}
|
|
9453
|
+
let res;
|
|
9454
|
+
let idx;
|
|
9455
|
+
if (Array.isArray(src)) {
|
|
9456
|
+
res = [];
|
|
9457
|
+
idx = src.length;
|
|
9458
|
+
while (idx--) {
|
|
9459
|
+
res[idx] = src[idx];
|
|
9496
9460
|
}
|
|
9497
|
-
|
|
9498
|
-
|
|
9499
|
-
|
|
9500
|
-
|
|
9501
|
-
|
|
9502
|
-
|
|
9461
|
+
}
|
|
9462
|
+
else {
|
|
9463
|
+
res = {};
|
|
9464
|
+
const keys = Object.keys(src);
|
|
9465
|
+
idx = keys.length;
|
|
9466
|
+
while (idx--) {
|
|
9467
|
+
const key = keys[idx];
|
|
9468
|
+
res[key] = src[key];
|
|
9503
9469
|
}
|
|
9504
|
-
|
|
9505
|
-
|
|
9470
|
+
}
|
|
9471
|
+
return res;
|
|
9472
|
+
};
|
|
9473
|
+
const deepClone = (src) => {
|
|
9474
|
+
let vidx = 0;
|
|
9475
|
+
const visited = new Map();
|
|
9476
|
+
const cloned = [];
|
|
9477
|
+
const cloneDeepInner = (src) => {
|
|
9478
|
+
if (typeof src !== 'object' || src === null) {
|
|
9479
|
+
return src;
|
|
9506
9480
|
}
|
|
9507
|
-
|
|
9508
|
-
|
|
9509
|
-
|
|
9510
|
-
|
|
9511
|
-
|
|
9512
|
-
|
|
9513
|
-
|
|
9514
|
-
|
|
9515
|
-
|
|
9516
|
-
|
|
9517
|
-
|
|
9518
|
-
|
|
9519
|
-
|
|
9481
|
+
let res;
|
|
9482
|
+
let idx;
|
|
9483
|
+
const cidx = visited.get(src);
|
|
9484
|
+
if (cidx !== undefined) {
|
|
9485
|
+
return cloned[cidx];
|
|
9486
|
+
}
|
|
9487
|
+
visited.set(src, vidx++);
|
|
9488
|
+
if (Array.isArray(src)) {
|
|
9489
|
+
res = [];
|
|
9490
|
+
cloned.push(res);
|
|
9491
|
+
idx = src.length;
|
|
9492
|
+
while (idx--) {
|
|
9493
|
+
res[idx] = cloneDeepInner(src[idx]);
|
|
9494
|
+
}
|
|
9495
|
+
}
|
|
9496
|
+
else {
|
|
9497
|
+
res = {};
|
|
9498
|
+
cloned.push(res);
|
|
9499
|
+
const keys = Object.keys(src);
|
|
9500
|
+
idx = keys.length;
|
|
9501
|
+
while (idx--) {
|
|
9502
|
+
const key = keys[idx];
|
|
9503
|
+
res[key] = cloneDeepInner(src[key]);
|
|
9504
|
+
}
|
|
9505
|
+
}
|
|
9506
|
+
return res;
|
|
9507
|
+
};
|
|
9508
|
+
return cloneDeepInner(src);
|
|
9520
9509
|
};
|
|
9521
9510
|
|
|
9522
9511
|
const shouldSkipValidate = function (options, errors) {
|
|
@@ -9528,6 +9517,12 @@
|
|
|
9528
9517
|
}));
|
|
9529
9518
|
};
|
|
9530
9519
|
const JsonValidators = {
|
|
9520
|
+
id: () => { },
|
|
9521
|
+
$ref: () => { },
|
|
9522
|
+
$schema: () => { },
|
|
9523
|
+
title: () => { },
|
|
9524
|
+
description: () => { },
|
|
9525
|
+
default: () => { },
|
|
9531
9526
|
multipleOf: function (report, schema, json) {
|
|
9532
9527
|
// http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.1.1.2
|
|
9533
9528
|
if (shouldSkipValidate(this.validateOptions, ['MULTIPLE_OF'])) {
|
|
@@ -9539,7 +9534,7 @@
|
|
|
9539
9534
|
const stringMultipleOf = String(schema.multipleOf);
|
|
9540
9535
|
const scale = Math.pow(10, stringMultipleOf.length - stringMultipleOf.indexOf('.') - 1);
|
|
9541
9536
|
if (whatIs((json * scale) / (schema.multipleOf * scale)) !== 'integer') {
|
|
9542
|
-
report.addError('MULTIPLE_OF', [json, schema.multipleOf],
|
|
9537
|
+
report.addError('MULTIPLE_OF', [json, schema.multipleOf], undefined, schema);
|
|
9543
9538
|
}
|
|
9544
9539
|
},
|
|
9545
9540
|
maximum: function (report, schema, json) {
|
|
@@ -9552,12 +9547,12 @@
|
|
|
9552
9547
|
}
|
|
9553
9548
|
if (schema.exclusiveMaximum !== true) {
|
|
9554
9549
|
if (json > schema.maximum) {
|
|
9555
|
-
report.addError('MAXIMUM', [json, schema.maximum],
|
|
9550
|
+
report.addError('MAXIMUM', [json, schema.maximum], undefined, schema);
|
|
9556
9551
|
}
|
|
9557
9552
|
}
|
|
9558
9553
|
else {
|
|
9559
9554
|
if (json >= schema.maximum) {
|
|
9560
|
-
report.addError('MAXIMUM_EXCLUSIVE', [json, schema.maximum],
|
|
9555
|
+
report.addError('MAXIMUM_EXCLUSIVE', [json, schema.maximum], undefined, schema);
|
|
9561
9556
|
}
|
|
9562
9557
|
}
|
|
9563
9558
|
},
|
|
@@ -9574,12 +9569,12 @@
|
|
|
9574
9569
|
}
|
|
9575
9570
|
if (schema.exclusiveMinimum !== true) {
|
|
9576
9571
|
if (json < schema.minimum) {
|
|
9577
|
-
report.addError('MINIMUM', [json, schema.minimum],
|
|
9572
|
+
report.addError('MINIMUM', [json, schema.minimum], undefined, schema);
|
|
9578
9573
|
}
|
|
9579
9574
|
}
|
|
9580
9575
|
else {
|
|
9581
9576
|
if (json <= schema.minimum) {
|
|
9582
|
-
report.addError('MINIMUM_EXCLUSIVE', [json, schema.minimum],
|
|
9577
|
+
report.addError('MINIMUM_EXCLUSIVE', [json, schema.minimum], undefined, schema);
|
|
9583
9578
|
}
|
|
9584
9579
|
}
|
|
9585
9580
|
},
|
|
@@ -9595,7 +9590,7 @@
|
|
|
9595
9590
|
return;
|
|
9596
9591
|
}
|
|
9597
9592
|
if (ucs2decode(json).length > schema.maxLength) {
|
|
9598
|
-
report.addError('MAX_LENGTH', [json.length, schema.maxLength],
|
|
9593
|
+
report.addError('MAX_LENGTH', [json.length, schema.maxLength], undefined, schema);
|
|
9599
9594
|
}
|
|
9600
9595
|
},
|
|
9601
9596
|
minLength: function (report, schema, json) {
|
|
@@ -9607,7 +9602,7 @@
|
|
|
9607
9602
|
return;
|
|
9608
9603
|
}
|
|
9609
9604
|
if (ucs2decode(json).length < schema.minLength) {
|
|
9610
|
-
report.addError('MIN_LENGTH', [json.length, schema.minLength],
|
|
9605
|
+
report.addError('MIN_LENGTH', [json.length, schema.minLength], undefined, schema);
|
|
9611
9606
|
}
|
|
9612
9607
|
},
|
|
9613
9608
|
pattern: function (report, schema, json) {
|
|
@@ -9619,7 +9614,7 @@
|
|
|
9619
9614
|
return;
|
|
9620
9615
|
}
|
|
9621
9616
|
if (RegExp(schema.pattern).test(json) === false) {
|
|
9622
|
-
report.addError('PATTERN', [schema.pattern, json],
|
|
9617
|
+
report.addError('PATTERN', [schema.pattern, json], undefined, schema);
|
|
9623
9618
|
}
|
|
9624
9619
|
},
|
|
9625
9620
|
additionalItems: function (report, schema, json) {
|
|
@@ -9634,12 +9629,12 @@
|
|
|
9634
9629
|
// the json is valid if its size is less than, or equal to, the size of "items".
|
|
9635
9630
|
if (schema.additionalItems === false && Array.isArray(schema.items)) {
|
|
9636
9631
|
if (json.length > schema.items.length) {
|
|
9637
|
-
report.addError('ARRAY_ADDITIONAL_ITEMS',
|
|
9632
|
+
report.addError('ARRAY_ADDITIONAL_ITEMS', undefined, undefined, schema);
|
|
9638
9633
|
}
|
|
9639
9634
|
}
|
|
9640
9635
|
},
|
|
9641
9636
|
items: function () {
|
|
9642
|
-
/*report, schema, json*/
|
|
9637
|
+
/*report: Report, schema: JsonSchemaInternal, json: unknown*/
|
|
9643
9638
|
// covered in additionalItems
|
|
9644
9639
|
},
|
|
9645
9640
|
maxItems: function (report, schema, json) {
|
|
@@ -9651,7 +9646,7 @@
|
|
|
9651
9646
|
return;
|
|
9652
9647
|
}
|
|
9653
9648
|
if (json.length > schema.maxItems) {
|
|
9654
|
-
report.addError('ARRAY_LENGTH_LONG', [json.length, schema.maxItems],
|
|
9649
|
+
report.addError('ARRAY_LENGTH_LONG', [json.length, schema.maxItems], undefined, schema);
|
|
9655
9650
|
}
|
|
9656
9651
|
},
|
|
9657
9652
|
minItems: function (report, schema, json) {
|
|
@@ -9663,7 +9658,7 @@
|
|
|
9663
9658
|
return;
|
|
9664
9659
|
}
|
|
9665
9660
|
if (json.length < schema.minItems) {
|
|
9666
|
-
report.addError('ARRAY_LENGTH_SHORT', [json.length, schema.minItems],
|
|
9661
|
+
report.addError('ARRAY_LENGTH_SHORT', [json.length, schema.minItems], undefined, schema);
|
|
9667
9662
|
}
|
|
9668
9663
|
},
|
|
9669
9664
|
uniqueItems: function (report, schema, json) {
|
|
@@ -9677,7 +9672,7 @@
|
|
|
9677
9672
|
if (schema.uniqueItems === true) {
|
|
9678
9673
|
const matches = [];
|
|
9679
9674
|
if (isUniqueArray(json, matches) === false) {
|
|
9680
|
-
report.addError('ARRAY_UNIQUE', matches,
|
|
9675
|
+
report.addError('ARRAY_UNIQUE', matches, undefined, schema);
|
|
9681
9676
|
}
|
|
9682
9677
|
}
|
|
9683
9678
|
},
|
|
@@ -9686,12 +9681,12 @@
|
|
|
9686
9681
|
if (shouldSkipValidate(this.validateOptions, ['OBJECT_PROPERTIES_MAXIMUM'])) {
|
|
9687
9682
|
return;
|
|
9688
9683
|
}
|
|
9689
|
-
if (
|
|
9684
|
+
if (!isObject(json)) {
|
|
9690
9685
|
return;
|
|
9691
9686
|
}
|
|
9692
9687
|
const keysCount = Object.keys(json).length;
|
|
9693
9688
|
if (keysCount > schema.maxProperties) {
|
|
9694
|
-
report.addError('OBJECT_PROPERTIES_MAXIMUM', [keysCount, schema.maxProperties],
|
|
9689
|
+
report.addError('OBJECT_PROPERTIES_MAXIMUM', [keysCount, schema.maxProperties], undefined, schema);
|
|
9695
9690
|
}
|
|
9696
9691
|
},
|
|
9697
9692
|
minProperties: function (report, schema, json) {
|
|
@@ -9699,12 +9694,12 @@
|
|
|
9699
9694
|
if (shouldSkipValidate(this.validateOptions, ['OBJECT_PROPERTIES_MINIMUM'])) {
|
|
9700
9695
|
return;
|
|
9701
9696
|
}
|
|
9702
|
-
if (
|
|
9697
|
+
if (!isObject(json)) {
|
|
9703
9698
|
return;
|
|
9704
9699
|
}
|
|
9705
9700
|
const keysCount = Object.keys(json).length;
|
|
9706
9701
|
if (keysCount < schema.minProperties) {
|
|
9707
|
-
report.addError('OBJECT_PROPERTIES_MINIMUM', [keysCount, schema.minProperties],
|
|
9702
|
+
report.addError('OBJECT_PROPERTIES_MINIMUM', [keysCount, schema.minProperties], undefined, schema);
|
|
9708
9703
|
}
|
|
9709
9704
|
},
|
|
9710
9705
|
required: function (report, schema, json) {
|
|
@@ -9712,14 +9707,14 @@
|
|
|
9712
9707
|
if (shouldSkipValidate(this.validateOptions, ['OBJECT_MISSING_REQUIRED_PROPERTY'])) {
|
|
9713
9708
|
return;
|
|
9714
9709
|
}
|
|
9715
|
-
if (
|
|
9710
|
+
if (!isObject(json)) {
|
|
9716
9711
|
return;
|
|
9717
9712
|
}
|
|
9718
9713
|
let idx = schema.required.length;
|
|
9719
9714
|
while (idx--) {
|
|
9720
9715
|
const requiredPropertyName = schema.required[idx];
|
|
9721
9716
|
if (json[requiredPropertyName] === undefined) {
|
|
9722
|
-
report.addError('OBJECT_MISSING_REQUIRED_PROPERTY', [requiredPropertyName],
|
|
9717
|
+
report.addError('OBJECT_MISSING_REQUIRED_PROPERTY', [requiredPropertyName], undefined, schema);
|
|
9723
9718
|
}
|
|
9724
9719
|
}
|
|
9725
9720
|
},
|
|
@@ -9740,7 +9735,7 @@
|
|
|
9740
9735
|
if (shouldSkipValidate(this.validateOptions, ['OBJECT_ADDITIONAL_PROPERTIES'])) {
|
|
9741
9736
|
return;
|
|
9742
9737
|
}
|
|
9743
|
-
if (
|
|
9738
|
+
if (!isObject(json)) {
|
|
9744
9739
|
return;
|
|
9745
9740
|
}
|
|
9746
9741
|
const properties = schema.properties !== undefined ? schema.properties : {};
|
|
@@ -9768,19 +9763,21 @@
|
|
|
9768
9763
|
// Validation of the json succeeds if, after these two steps, set "s" is empty.
|
|
9769
9764
|
if (s.length > 0) {
|
|
9770
9765
|
// assumeAdditional can be an array of allowed properties
|
|
9771
|
-
|
|
9772
|
-
|
|
9773
|
-
|
|
9774
|
-
|
|
9775
|
-
|
|
9776
|
-
|
|
9766
|
+
if (Array.isArray(this.options.assumeAdditional)) {
|
|
9767
|
+
let idx3 = this.options.assumeAdditional.length;
|
|
9768
|
+
if (idx3) {
|
|
9769
|
+
while (idx3--) {
|
|
9770
|
+
const io = s.indexOf(this.options.assumeAdditional[idx3]);
|
|
9771
|
+
if (io !== -1) {
|
|
9772
|
+
s.splice(io, 1);
|
|
9773
|
+
}
|
|
9777
9774
|
}
|
|
9778
9775
|
}
|
|
9779
9776
|
}
|
|
9780
9777
|
let idx4 = s.length;
|
|
9781
9778
|
if (idx4) {
|
|
9782
9779
|
while (idx4--) {
|
|
9783
|
-
report.addError('OBJECT_ADDITIONAL_PROPERTIES', [s[idx4]],
|
|
9780
|
+
report.addError('OBJECT_ADDITIONAL_PROPERTIES', [s[idx4]], undefined, schema);
|
|
9784
9781
|
}
|
|
9785
9782
|
}
|
|
9786
9783
|
}
|
|
@@ -9791,7 +9788,7 @@
|
|
|
9791
9788
|
if (shouldSkipValidate(this.validateOptions, ['OBJECT_DEPENDENCY_KEY'])) {
|
|
9792
9789
|
return;
|
|
9793
9790
|
}
|
|
9794
|
-
if (
|
|
9791
|
+
if (!isObject(json)) {
|
|
9795
9792
|
return;
|
|
9796
9793
|
}
|
|
9797
9794
|
const keys = Object.keys(schema.dependencies);
|
|
@@ -9801,21 +9798,21 @@
|
|
|
9801
9798
|
const dependencyName = keys[idx];
|
|
9802
9799
|
if (json[dependencyName]) {
|
|
9803
9800
|
const dependencyDefinition = schema.dependencies[dependencyName];
|
|
9804
|
-
if (
|
|
9805
|
-
// if dependency is a schema, validate against this schema
|
|
9806
|
-
validate.call(this, report, dependencyDefinition, json);
|
|
9807
|
-
}
|
|
9808
|
-
else {
|
|
9801
|
+
if (Array.isArray(dependencyDefinition)) {
|
|
9809
9802
|
// Array
|
|
9810
9803
|
// if dependency is an array, object needs to have all properties in this array
|
|
9811
9804
|
let idx2 = dependencyDefinition.length;
|
|
9812
9805
|
while (idx2--) {
|
|
9813
9806
|
const requiredPropertyName = dependencyDefinition[idx2];
|
|
9814
9807
|
if (json[requiredPropertyName] === undefined) {
|
|
9815
|
-
report.addError('OBJECT_DEPENDENCY_KEY', [requiredPropertyName, dependencyName],
|
|
9808
|
+
report.addError('OBJECT_DEPENDENCY_KEY', [requiredPropertyName, dependencyName], undefined, schema);
|
|
9816
9809
|
}
|
|
9817
9810
|
}
|
|
9818
9811
|
}
|
|
9812
|
+
else {
|
|
9813
|
+
// if dependency is a schema, validate against this schema
|
|
9814
|
+
validate.call(this, report, dependencyDefinition, json);
|
|
9815
|
+
}
|
|
9819
9816
|
}
|
|
9820
9817
|
}
|
|
9821
9818
|
},
|
|
@@ -9836,7 +9833,7 @@
|
|
|
9836
9833
|
}
|
|
9837
9834
|
if (match === false) {
|
|
9838
9835
|
const error = caseInsensitiveMatch && this.options.enumCaseInsensitiveComparison ? 'ENUM_CASE_MISMATCH' : 'ENUM_MISMATCH';
|
|
9839
|
-
report.addError(error, [json],
|
|
9836
|
+
report.addError(error, [JSON.stringify(json)], undefined, schema);
|
|
9840
9837
|
}
|
|
9841
9838
|
},
|
|
9842
9839
|
type: function (report, schema, json) {
|
|
@@ -9847,12 +9844,12 @@
|
|
|
9847
9844
|
const jsonType = whatIs(json);
|
|
9848
9845
|
if (typeof schema.type === 'string') {
|
|
9849
9846
|
if (jsonType !== schema.type && (jsonType !== 'integer' || schema.type !== 'number')) {
|
|
9850
|
-
report.addError('INVALID_TYPE', [schema.type, jsonType],
|
|
9847
|
+
report.addError('INVALID_TYPE', [schema.type, jsonType], undefined, schema);
|
|
9851
9848
|
}
|
|
9852
9849
|
}
|
|
9853
9850
|
else {
|
|
9854
9851
|
if (schema.type.indexOf(jsonType) === -1 && (jsonType !== 'integer' || schema.type.indexOf('number') === -1)) {
|
|
9855
|
-
report.addError('INVALID_TYPE', [schema.type, jsonType],
|
|
9852
|
+
report.addError('INVALID_TYPE', [JSON.stringify(schema.type), jsonType], undefined, schema);
|
|
9856
9853
|
}
|
|
9857
9854
|
}
|
|
9858
9855
|
},
|
|
@@ -9896,24 +9893,25 @@
|
|
|
9896
9893
|
report.addError('ONE_OF_MISSING', undefined, subReports, schema);
|
|
9897
9894
|
}
|
|
9898
9895
|
else if (passes > 1) {
|
|
9899
|
-
report.addError('ONE_OF_MULTIPLE',
|
|
9896
|
+
report.addError('ONE_OF_MULTIPLE', undefined, undefined, schema);
|
|
9900
9897
|
}
|
|
9901
9898
|
},
|
|
9902
9899
|
not: function (report, schema, json) {
|
|
9903
9900
|
// http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.5.6.2
|
|
9904
9901
|
const subReport = new Report(report);
|
|
9905
9902
|
if (validate.call(this, subReport, schema.not, json) === true) {
|
|
9906
|
-
report.addError('NOT_PASSED',
|
|
9903
|
+
report.addError('NOT_PASSED', undefined, undefined, schema);
|
|
9907
9904
|
}
|
|
9908
9905
|
},
|
|
9909
9906
|
definitions: function () {
|
|
9910
|
-
/*report, schema, json*/
|
|
9907
|
+
/*report: Report, schema: JsonSchemaInternal, json: unknown*/
|
|
9911
9908
|
// http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.5.7.2
|
|
9912
9909
|
// nothing to do here
|
|
9913
9910
|
},
|
|
9914
9911
|
format: function (report, schema, json) {
|
|
9915
9912
|
// http://json-schema.org/latest/json-schema-validation.html#rfc.section.7.2
|
|
9916
|
-
const
|
|
9913
|
+
const formatValidators = getFormatValidators(this.options);
|
|
9914
|
+
const formatValidatorFn = formatValidators[schema.format];
|
|
9917
9915
|
if (typeof formatValidatorFn === 'function') {
|
|
9918
9916
|
if (shouldSkipValidate(this.validateOptions, ['INVALID_FORMAT'])) {
|
|
9919
9917
|
return;
|
|
@@ -9923,12 +9921,12 @@
|
|
|
9923
9921
|
}
|
|
9924
9922
|
if (formatValidatorFn.length === 2) {
|
|
9925
9923
|
// async - need to clone the path here, because it will change by the time async function reports back
|
|
9926
|
-
const pathBeforeAsync =
|
|
9924
|
+
const pathBeforeAsync = shallowClone(report.path);
|
|
9927
9925
|
report.addAsyncTask(formatValidatorFn, [json], function (result) {
|
|
9928
9926
|
if (result !== true) {
|
|
9929
9927
|
const backup = report.path;
|
|
9930
9928
|
report.path = pathBeforeAsync;
|
|
9931
|
-
report.addError('INVALID_FORMAT', [schema.format, json],
|
|
9929
|
+
report.addError('INVALID_FORMAT', [schema.format, JSON.stringify(json)], undefined, schema);
|
|
9932
9930
|
report.path = backup;
|
|
9933
9931
|
}
|
|
9934
9932
|
});
|
|
@@ -9936,12 +9934,12 @@
|
|
|
9936
9934
|
else {
|
|
9937
9935
|
// sync
|
|
9938
9936
|
if (formatValidatorFn.call(this, json) !== true) {
|
|
9939
|
-
report.addError('INVALID_FORMAT', [schema.format, json],
|
|
9937
|
+
report.addError('INVALID_FORMAT', [schema.format, JSON.stringify(json)], undefined, schema);
|
|
9940
9938
|
}
|
|
9941
9939
|
}
|
|
9942
9940
|
}
|
|
9943
9941
|
else if (this.options.ignoreUnknownFormats !== true) {
|
|
9944
|
-
report.addError('UNKNOWN_FORMAT', [schema.format],
|
|
9942
|
+
report.addError('UNKNOWN_FORMAT', [schema.format], undefined, schema);
|
|
9945
9943
|
}
|
|
9946
9944
|
},
|
|
9947
9945
|
};
|
|
@@ -10027,18 +10025,12 @@
|
|
|
10027
10025
|
}
|
|
10028
10026
|
}
|
|
10029
10027
|
};
|
|
10030
|
-
/**
|
|
10031
|
-
*
|
|
10032
|
-
* @param {Report} report
|
|
10033
|
-
* @param {*} schema
|
|
10034
|
-
* @param {*} json
|
|
10035
|
-
*/
|
|
10036
10028
|
function validate(report, schema, json) {
|
|
10037
10029
|
report.commonErrorMessage = 'JSON_OBJECT_VALIDATION_FAILED';
|
|
10038
10030
|
// check if schema is an object
|
|
10039
10031
|
const to = whatIs(schema);
|
|
10040
10032
|
if (to !== 'object') {
|
|
10041
|
-
report.addError('SCHEMA_NOT_AN_OBJECT', [to],
|
|
10033
|
+
report.addError('SCHEMA_NOT_AN_OBJECT', [to], undefined, schema);
|
|
10042
10034
|
return false;
|
|
10043
10035
|
}
|
|
10044
10036
|
// check if schema is empty, everything is valid against empty schema
|
|
@@ -10058,7 +10050,7 @@
|
|
|
10058
10050
|
let maxRefs = 99;
|
|
10059
10051
|
while (schema.$ref && maxRefs > 0) {
|
|
10060
10052
|
if (!schema.__$refResolved) {
|
|
10061
|
-
report.addError('REF_UNRESOLVED', [schema.$ref],
|
|
10053
|
+
report.addError('REF_UNRESOLVED', [schema.$ref], undefined, schema);
|
|
10062
10054
|
break;
|
|
10063
10055
|
}
|
|
10064
10056
|
else if (schema.__$refResolved === schema) {
|
|
@@ -10075,7 +10067,6 @@
|
|
|
10075
10067
|
}
|
|
10076
10068
|
}
|
|
10077
10069
|
// type checking first
|
|
10078
|
-
const jsonType = whatIs(json);
|
|
10079
10070
|
if (schema.type) {
|
|
10080
10071
|
keys.splice(keys.indexOf('type'), 1);
|
|
10081
10072
|
JsonValidators.type.call(this, report, schema, json);
|
|
@@ -10094,10 +10085,10 @@
|
|
|
10094
10085
|
}
|
|
10095
10086
|
}
|
|
10096
10087
|
if (report.errors.length === 0 || this.options.breakOnFirstError === false) {
|
|
10097
|
-
if (
|
|
10088
|
+
if (Array.isArray(json)) {
|
|
10098
10089
|
recurseArray.call(this, report, schema, json);
|
|
10099
10090
|
}
|
|
10100
|
-
else if (
|
|
10091
|
+
else if (isObject(json)) {
|
|
10101
10092
|
recurseObject.call(this, report, schema, json);
|
|
10102
10093
|
}
|
|
10103
10094
|
}
|
|
@@ -11976,40 +11967,156 @@
|
|
|
11976
11967
|
var lodash_isequalExports = requireLodash_isequal();
|
|
11977
11968
|
var isequal = /*@__PURE__*/getDefaultExportFromCjs(lodash_isequalExports);
|
|
11978
11969
|
|
|
11979
|
-
|
|
11980
|
-
|
|
11981
|
-
|
|
11970
|
+
const findId = (schema, id) => {
|
|
11971
|
+
// process only arrays and objects
|
|
11972
|
+
if (typeof schema !== 'object' || schema === null) {
|
|
11973
|
+
return;
|
|
11982
11974
|
}
|
|
11983
|
-
|
|
11984
|
-
|
|
11985
|
-
|
|
11986
|
-
const isRefRelative = isRelativeUri(ref);
|
|
11987
|
-
let toRemove;
|
|
11988
|
-
if (isScopeAbsolute && isRefRelative) {
|
|
11989
|
-
toRemove = joinedScope.match(/\/[^/]*$/);
|
|
11990
|
-
if (toRemove) {
|
|
11991
|
-
joinedScope = joinedScope.slice(0, toRemove.index + 1);
|
|
11992
|
-
}
|
|
11975
|
+
// no id means root so return itself
|
|
11976
|
+
if (!id) {
|
|
11977
|
+
return schema;
|
|
11993
11978
|
}
|
|
11994
|
-
|
|
11995
|
-
|
|
11979
|
+
if (schema.id) {
|
|
11980
|
+
if (schema.id === id || (schema.id[0] === '#' && schema.id.substring(1) === id)) {
|
|
11981
|
+
return schema;
|
|
11982
|
+
}
|
|
11996
11983
|
}
|
|
11997
|
-
|
|
11998
|
-
|
|
11999
|
-
|
|
12000
|
-
|
|
11984
|
+
let idx, result;
|
|
11985
|
+
if (Array.isArray(schema)) {
|
|
11986
|
+
idx = schema.length;
|
|
11987
|
+
while (idx--) {
|
|
11988
|
+
result = findId(schema[idx], id);
|
|
11989
|
+
if (result) {
|
|
11990
|
+
return result;
|
|
11991
|
+
}
|
|
12001
11992
|
}
|
|
12002
11993
|
}
|
|
12003
|
-
|
|
12004
|
-
|
|
12005
|
-
|
|
12006
|
-
|
|
12007
|
-
|
|
12008
|
-
|
|
12009
|
-
|
|
12010
|
-
|
|
12011
|
-
|
|
12012
|
-
|
|
11994
|
+
if (isObject(schema)) {
|
|
11995
|
+
const keys = Object.keys(schema);
|
|
11996
|
+
idx = keys.length;
|
|
11997
|
+
while (idx--) {
|
|
11998
|
+
const k = keys[idx];
|
|
11999
|
+
if (k.indexOf('__$') === 0) {
|
|
12000
|
+
continue;
|
|
12001
|
+
}
|
|
12002
|
+
result = findId(schema[k], id);
|
|
12003
|
+
if (result) {
|
|
12004
|
+
return result;
|
|
12005
|
+
}
|
|
12006
|
+
}
|
|
12007
|
+
}
|
|
12008
|
+
};
|
|
12009
|
+
|
|
12010
|
+
class SchemaCache {
|
|
12011
|
+
validator;
|
|
12012
|
+
cache = {};
|
|
12013
|
+
referenceCache = [];
|
|
12014
|
+
constructor(validator) {
|
|
12015
|
+
this.validator = validator;
|
|
12016
|
+
}
|
|
12017
|
+
cacheSchemaByUri(uri, schema) {
|
|
12018
|
+
const remotePath = getRemotePath(uri);
|
|
12019
|
+
if (remotePath) {
|
|
12020
|
+
this.cache[remotePath] = schema;
|
|
12021
|
+
}
|
|
12022
|
+
}
|
|
12023
|
+
removeFromCacheByUri(uri) {
|
|
12024
|
+
const remotePath = getRemotePath(uri);
|
|
12025
|
+
if (remotePath) {
|
|
12026
|
+
delete this.cache[remotePath];
|
|
12027
|
+
}
|
|
12028
|
+
}
|
|
12029
|
+
checkCacheForUri(uri) {
|
|
12030
|
+
const remotePath = getRemotePath(uri);
|
|
12031
|
+
return remotePath ? this.cache[remotePath] != null : false;
|
|
12032
|
+
}
|
|
12033
|
+
getSchema(report, refOrSchema) {
|
|
12034
|
+
if (typeof refOrSchema === 'string') {
|
|
12035
|
+
// ref input
|
|
12036
|
+
return this.getSchemaByUri(report, refOrSchema);
|
|
12037
|
+
}
|
|
12038
|
+
if (typeof refOrSchema === 'object') {
|
|
12039
|
+
// schema obj input
|
|
12040
|
+
return this.getSchemaByReference(report, refOrSchema);
|
|
12041
|
+
}
|
|
12042
|
+
throw new Error(`unexpected code reached`);
|
|
12043
|
+
}
|
|
12044
|
+
getSchemaByUri(report, uri, root) {
|
|
12045
|
+
const remotePath = getRemotePath(uri);
|
|
12046
|
+
const queryPath = getQueryPath(uri);
|
|
12047
|
+
let result = remotePath ? this.cache[remotePath] : root;
|
|
12048
|
+
if (result && remotePath) {
|
|
12049
|
+
// we need to avoid compiling schemas in a recursive loop
|
|
12050
|
+
const compileRemote = result !== root;
|
|
12051
|
+
// now we need to compile and validate resolved schema (in case it's not already)
|
|
12052
|
+
if (compileRemote) {
|
|
12053
|
+
report.path.push(remotePath);
|
|
12054
|
+
let remoteReport;
|
|
12055
|
+
const anscestorReport = result.id ? report.getAncestor(result.id) : undefined;
|
|
12056
|
+
if (anscestorReport) {
|
|
12057
|
+
remoteReport = anscestorReport;
|
|
12058
|
+
}
|
|
12059
|
+
else {
|
|
12060
|
+
remoteReport = new Report(report);
|
|
12061
|
+
if (this.validator.sc.compileSchema(remoteReport, result)) {
|
|
12062
|
+
const savedOptions = this.validator.options;
|
|
12063
|
+
try {
|
|
12064
|
+
// If custom validationOptions were provided to setRemoteReference(),
|
|
12065
|
+
// use them instead of the default options
|
|
12066
|
+
this.validator.options = result.__$validationOptions || this.validator.options;
|
|
12067
|
+
this.validator.sv.validateSchema(remoteReport, result);
|
|
12068
|
+
}
|
|
12069
|
+
finally {
|
|
12070
|
+
this.validator.options = savedOptions;
|
|
12071
|
+
}
|
|
12072
|
+
}
|
|
12073
|
+
}
|
|
12074
|
+
const remoteReportIsValid = remoteReport.isValid();
|
|
12075
|
+
if (!remoteReportIsValid) {
|
|
12076
|
+
report.addError('REMOTE_NOT_VALID', [uri], remoteReport);
|
|
12077
|
+
}
|
|
12078
|
+
report.path.pop();
|
|
12079
|
+
if (!remoteReportIsValid) {
|
|
12080
|
+
return undefined;
|
|
12081
|
+
}
|
|
12082
|
+
}
|
|
12083
|
+
}
|
|
12084
|
+
if (result && queryPath) {
|
|
12085
|
+
const parts = queryPath.split('/');
|
|
12086
|
+
for (let idx = 0, lim = parts.length; result && idx < lim; idx++) {
|
|
12087
|
+
const key = decodeJSONPointer(parts[idx]);
|
|
12088
|
+
if (idx === 0) {
|
|
12089
|
+
// it's an id
|
|
12090
|
+
result = findId(result, key);
|
|
12091
|
+
}
|
|
12092
|
+
else {
|
|
12093
|
+
// it's a path behind id
|
|
12094
|
+
result = result[key];
|
|
12095
|
+
}
|
|
12096
|
+
}
|
|
12097
|
+
}
|
|
12098
|
+
return result;
|
|
12099
|
+
}
|
|
12100
|
+
getSchemaByReference(report, schema) {
|
|
12101
|
+
let i = this.referenceCache.length;
|
|
12102
|
+
while (i--) {
|
|
12103
|
+
if (isequal(this.referenceCache[i][0], schema)) {
|
|
12104
|
+
return this.referenceCache[i][1];
|
|
12105
|
+
}
|
|
12106
|
+
}
|
|
12107
|
+
// not found
|
|
12108
|
+
const schemaClone = deepClone(schema);
|
|
12109
|
+
this.referenceCache.push([schema, schemaClone]);
|
|
12110
|
+
return schemaClone;
|
|
12111
|
+
}
|
|
12112
|
+
}
|
|
12113
|
+
|
|
12114
|
+
const collectReferences = (obj, results, scope, path) => {
|
|
12115
|
+
results = results || [];
|
|
12116
|
+
scope = scope || [];
|
|
12117
|
+
path = path || [];
|
|
12118
|
+
if (typeof obj !== 'object' || obj === null) {
|
|
12119
|
+
return results;
|
|
12013
12120
|
}
|
|
12014
12121
|
if (typeof obj.id === 'string') {
|
|
12015
12122
|
scope.push(obj.id);
|
|
@@ -12034,7 +12141,7 @@
|
|
|
12034
12141
|
if (Array.isArray(obj)) {
|
|
12035
12142
|
idx = obj.length;
|
|
12036
12143
|
while (idx--) {
|
|
12037
|
-
path.push(idx
|
|
12144
|
+
path.push(idx);
|
|
12038
12145
|
collectReferences(obj[idx], results, scope, path);
|
|
12039
12146
|
path.pop();
|
|
12040
12147
|
}
|
|
@@ -12056,175 +12163,200 @@
|
|
|
12056
12163
|
scope.pop();
|
|
12057
12164
|
}
|
|
12058
12165
|
return results;
|
|
12059
|
-
}
|
|
12060
|
-
const
|
|
12061
|
-
|
|
12062
|
-
|
|
12063
|
-
|
|
12064
|
-
|
|
12065
|
-
|
|
12066
|
-
|
|
12067
|
-
|
|
12166
|
+
};
|
|
12167
|
+
const mergeReference = (scope, ref) => {
|
|
12168
|
+
if (isAbsoluteUri(ref)) {
|
|
12169
|
+
return ref;
|
|
12170
|
+
}
|
|
12171
|
+
let joinedScope = scope.join('');
|
|
12172
|
+
const isScopeAbsolute = isAbsoluteUri(joinedScope);
|
|
12173
|
+
const isScopeRelative = isRelativeUri(joinedScope);
|
|
12174
|
+
const isRefRelative = isRelativeUri(ref);
|
|
12175
|
+
let toRemove;
|
|
12176
|
+
if (isScopeAbsolute && isRefRelative) {
|
|
12177
|
+
toRemove = joinedScope.match(/\/[^/]*$/);
|
|
12178
|
+
if (toRemove) {
|
|
12179
|
+
joinedScope = joinedScope.slice(0, toRemove.index + 1);
|
|
12068
12180
|
}
|
|
12069
|
-
// copy errors to report
|
|
12070
|
-
mainReport.errors = mainReport.errors.concat(report.errors);
|
|
12071
12181
|
}
|
|
12072
|
-
|
|
12073
|
-
|
|
12074
|
-
|
|
12075
|
-
|
|
12076
|
-
|
|
12077
|
-
if (
|
|
12078
|
-
|
|
12182
|
+
else if (isScopeRelative && isRefRelative) {
|
|
12183
|
+
joinedScope = '';
|
|
12184
|
+
}
|
|
12185
|
+
else {
|
|
12186
|
+
toRemove = joinedScope.match(/[^#/]+$/);
|
|
12187
|
+
if (toRemove) {
|
|
12188
|
+
joinedScope = joinedScope.slice(0, toRemove.index);
|
|
12079
12189
|
}
|
|
12080
12190
|
}
|
|
12081
|
-
|
|
12082
|
-
|
|
12083
|
-
|
|
12084
|
-
|
|
12085
|
-
|
|
12086
|
-
|
|
12087
|
-
|
|
12088
|
-
|
|
12089
|
-
|
|
12090
|
-
|
|
12191
|
+
let res = joinedScope + ref;
|
|
12192
|
+
res = res.replace(/##/, '#');
|
|
12193
|
+
return res;
|
|
12194
|
+
};
|
|
12195
|
+
class SchemaCompiler {
|
|
12196
|
+
validator;
|
|
12197
|
+
constructor(validator) {
|
|
12198
|
+
this.validator = validator;
|
|
12199
|
+
}
|
|
12200
|
+
compileSchema(report, schema) {
|
|
12201
|
+
report.commonErrorMessage = 'SCHEMA_COMPILATION_FAILED';
|
|
12202
|
+
// if schema is a string, assume it's a uri
|
|
12203
|
+
if (typeof schema === 'string') {
|
|
12204
|
+
const loadedSchema = this.validator.scache.getSchemaByUri(report, schema);
|
|
12205
|
+
if (!loadedSchema) {
|
|
12206
|
+
report.addError('SCHEMA_NOT_REACHABLE', [schema]);
|
|
12207
|
+
return false;
|
|
12091
12208
|
}
|
|
12209
|
+
schema = loadedSchema;
|
|
12210
|
+
}
|
|
12211
|
+
// if schema is an array, assume it's an array of schemas
|
|
12212
|
+
if (Array.isArray(schema)) {
|
|
12213
|
+
return this.compileArrayOfSchemas(report, schema);
|
|
12214
|
+
}
|
|
12215
|
+
// if we have an id than it should be cached already (if this instance has compiled it)
|
|
12216
|
+
if (schema.__$compiled && schema.id && this.validator.scache.checkCacheForUri(schema.id) === false) {
|
|
12217
|
+
schema.__$compiled = undefined;
|
|
12218
|
+
}
|
|
12219
|
+
// do not re-compile schemas
|
|
12220
|
+
if (schema.__$compiled) {
|
|
12221
|
+
return true;
|
|
12092
12222
|
}
|
|
12093
|
-
|
|
12094
|
-
|
|
12095
|
-
|
|
12096
|
-
|
|
12097
|
-
//
|
|
12098
|
-
|
|
12223
|
+
if (schema.id && typeof schema.id === 'string') {
|
|
12224
|
+
// add this to our schemaCache (before compilation in case we have references including id)
|
|
12225
|
+
this.validator.scache.cacheSchemaByUri(schema.id, schema);
|
|
12226
|
+
}
|
|
12227
|
+
// this method can be called recursively, so we need to remember our root
|
|
12228
|
+
let isRoot = false;
|
|
12229
|
+
if (!report.rootSchema) {
|
|
12230
|
+
report.rootSchema = schema;
|
|
12231
|
+
isRoot = true;
|
|
12232
|
+
}
|
|
12233
|
+
// delete all __$missingReferences from previous compilation attempts
|
|
12234
|
+
const isValidExceptReferences = report.isValid();
|
|
12235
|
+
delete schema.__$missingReferences;
|
|
12236
|
+
// collect all references that need to be resolved - $ref and $schema
|
|
12237
|
+
const refs = collectReferences(schema);
|
|
12238
|
+
let idx = refs.length;
|
|
12099
12239
|
while (idx--) {
|
|
12100
|
-
|
|
12101
|
-
|
|
12102
|
-
|
|
12103
|
-
|
|
12104
|
-
|
|
12105
|
-
|
|
12106
|
-
|
|
12107
|
-
|
|
12108
|
-
|
|
12109
|
-
|
|
12110
|
-
|
|
12240
|
+
// resolve all the collected references into __xxxResolved pointer
|
|
12241
|
+
const refObj = refs[idx];
|
|
12242
|
+
let response = this.validator.scache.getSchemaByUri(report, refObj.ref, schema);
|
|
12243
|
+
// we can try to use custom schemaReader if available
|
|
12244
|
+
if (!response) {
|
|
12245
|
+
const schemaReader = this.validator.getSchemaReader();
|
|
12246
|
+
if (schemaReader) {
|
|
12247
|
+
// it's supposed to return a valid schema
|
|
12248
|
+
const s = schemaReader(refObj.ref);
|
|
12249
|
+
if (s) {
|
|
12250
|
+
// it needs to have the id
|
|
12251
|
+
s.id = refObj.ref;
|
|
12252
|
+
// try to compile the schema
|
|
12253
|
+
const subreport = new Report(report);
|
|
12254
|
+
if (!this.compileSchema(subreport, s)) {
|
|
12255
|
+
// copy errors to report
|
|
12256
|
+
report.errors = report.errors.concat(subreport.errors);
|
|
12257
|
+
}
|
|
12258
|
+
else {
|
|
12259
|
+
response = this.validator.scache.getSchemaByUri(report, refObj.ref, schema);
|
|
12260
|
+
}
|
|
12111
12261
|
}
|
|
12112
12262
|
}
|
|
12113
|
-
|
|
12114
|
-
|
|
12263
|
+
}
|
|
12264
|
+
if (!response) {
|
|
12265
|
+
const hasNotValid = report.hasError('REMOTE_NOT_VALID', [refObj.ref]);
|
|
12266
|
+
const isAbsolute = isAbsoluteUri(refObj.ref);
|
|
12267
|
+
let isDownloaded = false;
|
|
12268
|
+
const ignoreUnresolvableRemotes = this.validator.options.ignoreUnresolvableReferences === true;
|
|
12269
|
+
if (isAbsolute) {
|
|
12270
|
+
// we shouldn't add UNRESOLVABLE_REFERENCE for schemas we already have downloaded
|
|
12271
|
+
// and set through setRemoteReference method
|
|
12272
|
+
isDownloaded = this.validator.scache.checkCacheForUri(refObj.ref);
|
|
12273
|
+
}
|
|
12274
|
+
if (hasNotValid) ;
|
|
12275
|
+
else if (ignoreUnresolvableRemotes && isAbsolute) ;
|
|
12276
|
+
else if (isDownloaded) ;
|
|
12277
|
+
else {
|
|
12278
|
+
report.path.push(...refObj.path);
|
|
12279
|
+
report.addError('UNRESOLVABLE_REFERENCE', [refObj.ref]);
|
|
12280
|
+
report.path = report.path.slice(0, -refObj.path.length);
|
|
12281
|
+
// pusblish unresolved references out
|
|
12282
|
+
if (isValidExceptReferences) {
|
|
12283
|
+
schema.__$missingReferences = schema.__$missingReferences || [];
|
|
12284
|
+
schema.__$missingReferences.push(refObj);
|
|
12285
|
+
}
|
|
12115
12286
|
}
|
|
12116
12287
|
}
|
|
12288
|
+
// this might create circular references
|
|
12289
|
+
refObj.obj[`__${refObj.key}Resolved`] = response;
|
|
12117
12290
|
}
|
|
12118
|
-
|
|
12119
|
-
|
|
12120
|
-
|
|
12121
|
-
};
|
|
12122
|
-
function compileSchema(report, schema) {
|
|
12123
|
-
report.commonErrorMessage = 'SCHEMA_COMPILATION_FAILED';
|
|
12124
|
-
// if schema is a string, assume it's a uri
|
|
12125
|
-
if (typeof schema === 'string') {
|
|
12126
|
-
const loadedSchema = getSchemaByUri.call(this, report, schema);
|
|
12127
|
-
if (!loadedSchema) {
|
|
12128
|
-
report.addError('SCHEMA_NOT_REACHABLE', [schema]);
|
|
12129
|
-
return false;
|
|
12291
|
+
const isValid = report.isValid();
|
|
12292
|
+
if (isValid) {
|
|
12293
|
+
schema.__$compiled = true;
|
|
12130
12294
|
}
|
|
12131
|
-
|
|
12132
|
-
|
|
12133
|
-
|
|
12134
|
-
|
|
12135
|
-
return compileArrayOfSchemas.call(this, report, schema);
|
|
12136
|
-
}
|
|
12137
|
-
// if we have an id than it should be cached already (if this instance has compiled it)
|
|
12138
|
-
if (schema.__$compiled && schema.id && checkCacheForUri.call(this, schema.id) === false) {
|
|
12139
|
-
schema.__$compiled = undefined;
|
|
12140
|
-
}
|
|
12141
|
-
// do not re-compile schemas
|
|
12142
|
-
if (schema.__$compiled) {
|
|
12143
|
-
return true;
|
|
12144
|
-
}
|
|
12145
|
-
if (schema.id && typeof schema.id === 'string') {
|
|
12146
|
-
// add this to our schemaCache (before compilation in case we have references including id)
|
|
12147
|
-
cacheSchemaByUri.call(this, schema.id, schema);
|
|
12148
|
-
}
|
|
12149
|
-
// this method can be called recursively, so we need to remember our root
|
|
12150
|
-
let isRoot = false;
|
|
12151
|
-
if (!report.rootSchema) {
|
|
12152
|
-
report.rootSchema = schema;
|
|
12153
|
-
isRoot = true;
|
|
12154
|
-
}
|
|
12155
|
-
// delete all __$missingReferences from previous compilation attempts
|
|
12156
|
-
const isValidExceptReferences = report.isValid();
|
|
12157
|
-
delete schema.__$missingReferences;
|
|
12158
|
-
// collect all references that need to be resolved - $ref and $schema
|
|
12159
|
-
const refs = collectReferences.call(this, schema);
|
|
12160
|
-
let idx = refs.length;
|
|
12161
|
-
while (idx--) {
|
|
12162
|
-
// resolve all the collected references into __xxxResolved pointer
|
|
12163
|
-
const refObj = refs[idx];
|
|
12164
|
-
let response = getSchemaByUri.call(this, report, refObj.ref, schema);
|
|
12165
|
-
// we can try to use custom schemaReader if available
|
|
12166
|
-
if (!response) {
|
|
12167
|
-
const schemaReader = this.getSchemaReader();
|
|
12168
|
-
if (schemaReader) {
|
|
12169
|
-
// it's supposed to return a valid schema
|
|
12170
|
-
const s = schemaReader(refObj.ref);
|
|
12171
|
-
if (s) {
|
|
12172
|
-
// it needs to have the id
|
|
12173
|
-
s.id = refObj.ref;
|
|
12174
|
-
// try to compile the schema
|
|
12175
|
-
const subreport = new Report(report);
|
|
12176
|
-
if (!compileSchema.call(this, subreport, s)) {
|
|
12177
|
-
// copy errors to report
|
|
12178
|
-
report.errors = report.errors.concat(subreport.errors);
|
|
12179
|
-
}
|
|
12180
|
-
else {
|
|
12181
|
-
response = getSchemaByUri.call(this, report, refObj.ref, schema);
|
|
12182
|
-
}
|
|
12183
|
-
}
|
|
12295
|
+
else {
|
|
12296
|
+
if (schema.id && typeof schema.id === 'string') {
|
|
12297
|
+
// remove this schema from schemaCache because it failed to compile
|
|
12298
|
+
this.validator.scache.removeFromCacheByUri(schema.id);
|
|
12184
12299
|
}
|
|
12185
12300
|
}
|
|
12186
|
-
|
|
12187
|
-
|
|
12188
|
-
|
|
12189
|
-
|
|
12190
|
-
|
|
12191
|
-
|
|
12192
|
-
|
|
12193
|
-
|
|
12194
|
-
|
|
12301
|
+
// we don't need the root pointer anymore
|
|
12302
|
+
if (isRoot) {
|
|
12303
|
+
report.rootSchema = undefined;
|
|
12304
|
+
}
|
|
12305
|
+
return isValid;
|
|
12306
|
+
}
|
|
12307
|
+
compileArrayOfSchemas(report, arr) {
|
|
12308
|
+
let compiled = 0, lastLoopCompiled;
|
|
12309
|
+
do {
|
|
12310
|
+
// remove all UNRESOLVABLE_REFERENCE errors before compiling array again
|
|
12311
|
+
let idx = report.errors.length;
|
|
12312
|
+
while (idx--) {
|
|
12313
|
+
if (report.errors[idx].code === 'UNRESOLVABLE_REFERENCE') {
|
|
12314
|
+
report.errors.splice(idx, 1);
|
|
12315
|
+
}
|
|
12195
12316
|
}
|
|
12196
|
-
|
|
12197
|
-
|
|
12198
|
-
|
|
12199
|
-
|
|
12200
|
-
|
|
12201
|
-
|
|
12202
|
-
|
|
12203
|
-
|
|
12204
|
-
if (
|
|
12205
|
-
|
|
12206
|
-
|
|
12317
|
+
// remember how many were compiled in the last loop
|
|
12318
|
+
lastLoopCompiled = compiled;
|
|
12319
|
+
// count how many are compiled now
|
|
12320
|
+
compiled = this.compileArrayOfSchemasLoop(report, arr);
|
|
12321
|
+
// fix __$missingReferences if possible
|
|
12322
|
+
idx = arr.length;
|
|
12323
|
+
while (idx--) {
|
|
12324
|
+
const sch = arr[idx];
|
|
12325
|
+
if (sch.__$missingReferences) {
|
|
12326
|
+
let idx2 = sch.__$missingReferences.length;
|
|
12327
|
+
while (idx2--) {
|
|
12328
|
+
const refObj = sch.__$missingReferences[idx2];
|
|
12329
|
+
const response = arr.find((x) => x.id === refObj.ref);
|
|
12330
|
+
if (response) {
|
|
12331
|
+
// this might create circular references
|
|
12332
|
+
refObj.obj[`__${refObj.key}Resolved`] = response;
|
|
12333
|
+
// it's resolved now so delete it
|
|
12334
|
+
sch.__$missingReferences.splice(idx2, 1);
|
|
12335
|
+
}
|
|
12336
|
+
}
|
|
12337
|
+
if (sch.__$missingReferences.length === 0) {
|
|
12338
|
+
delete sch.__$missingReferences;
|
|
12339
|
+
}
|
|
12207
12340
|
}
|
|
12208
12341
|
}
|
|
12209
|
-
|
|
12210
|
-
|
|
12211
|
-
|
|
12212
|
-
}
|
|
12213
|
-
const isValid = report.isValid();
|
|
12214
|
-
if (isValid) {
|
|
12215
|
-
schema.__$compiled = true;
|
|
12342
|
+
// keep repeating if not all compiled and at least one more was compiled in the last loop
|
|
12343
|
+
} while (compiled !== arr.length && compiled !== lastLoopCompiled);
|
|
12344
|
+
return report.isValid();
|
|
12216
12345
|
}
|
|
12217
|
-
|
|
12218
|
-
|
|
12219
|
-
|
|
12220
|
-
|
|
12346
|
+
compileArrayOfSchemasLoop(mainReport, arr) {
|
|
12347
|
+
let idx = arr.length, compiledCount = 0;
|
|
12348
|
+
while (idx--) {
|
|
12349
|
+
// try to compile each schema separately
|
|
12350
|
+
const report = new Report(mainReport);
|
|
12351
|
+
const isValid = this.compileSchema(report, arr[idx]);
|
|
12352
|
+
if (isValid) {
|
|
12353
|
+
compiledCount++;
|
|
12354
|
+
}
|
|
12355
|
+
// copy errors to report
|
|
12356
|
+
mainReport.errors = mainReport.errors.concat(report.errors);
|
|
12221
12357
|
}
|
|
12358
|
+
return compiledCount;
|
|
12222
12359
|
}
|
|
12223
|
-
// we don't need the root pointer anymore
|
|
12224
|
-
if (isRoot) {
|
|
12225
|
-
report.rootSchema = undefined;
|
|
12226
|
-
}
|
|
12227
|
-
return isValid;
|
|
12228
12360
|
}
|
|
12229
12361
|
|
|
12230
12362
|
const SchemaValidators = {
|
|
@@ -12318,9 +12450,9 @@
|
|
|
12318
12450
|
if (type !== 'boolean' && type !== 'object') {
|
|
12319
12451
|
report.addError('KEYWORD_TYPE_EXPECTED', ['additionalItems', ['boolean', 'object']]);
|
|
12320
12452
|
}
|
|
12321
|
-
else if (
|
|
12453
|
+
else if (isObject(schema.additionalItems)) {
|
|
12322
12454
|
report.path.push('additionalItems');
|
|
12323
|
-
validateSchema
|
|
12455
|
+
this.validateSchema(report, schema.additionalItems);
|
|
12324
12456
|
report.path.pop();
|
|
12325
12457
|
}
|
|
12326
12458
|
},
|
|
@@ -12329,15 +12461,15 @@
|
|
|
12329
12461
|
const type = whatIs(schema.items);
|
|
12330
12462
|
if (type === 'object') {
|
|
12331
12463
|
report.path.push('items');
|
|
12332
|
-
validateSchema
|
|
12464
|
+
this.validateSchema(report, schema.items);
|
|
12333
12465
|
report.path.pop();
|
|
12334
12466
|
}
|
|
12335
|
-
else if (
|
|
12467
|
+
else if (Array.isArray(schema.items)) {
|
|
12336
12468
|
let idx = schema.items.length;
|
|
12337
12469
|
while (idx--) {
|
|
12338
12470
|
report.path.push('items');
|
|
12339
|
-
report.path.push(idx
|
|
12340
|
-
validateSchema
|
|
12471
|
+
report.path.push(idx);
|
|
12472
|
+
this.validateSchema(report, schema.items[idx]);
|
|
12341
12473
|
report.path.pop();
|
|
12342
12474
|
report.path.pop();
|
|
12343
12475
|
}
|
|
@@ -12422,9 +12554,9 @@
|
|
|
12422
12554
|
if (type !== 'boolean' && type !== 'object') {
|
|
12423
12555
|
report.addError('KEYWORD_TYPE_EXPECTED', ['additionalProperties', ['boolean', 'object']]);
|
|
12424
12556
|
}
|
|
12425
|
-
else if (
|
|
12557
|
+
else if (isObject(schema.additionalProperties)) {
|
|
12426
12558
|
report.path.push('additionalProperties');
|
|
12427
|
-
validateSchema
|
|
12559
|
+
this.validateSchema(report, schema.additionalProperties);
|
|
12428
12560
|
report.path.pop();
|
|
12429
12561
|
}
|
|
12430
12562
|
},
|
|
@@ -12437,10 +12569,11 @@
|
|
|
12437
12569
|
const keys = Object.keys(schema.properties);
|
|
12438
12570
|
let idx = keys.length;
|
|
12439
12571
|
while (idx--) {
|
|
12440
|
-
const key = keys[idx]
|
|
12572
|
+
const key = keys[idx];
|
|
12573
|
+
const val = schema.properties[key];
|
|
12441
12574
|
report.path.push('properties');
|
|
12442
12575
|
report.path.push(key);
|
|
12443
|
-
validateSchema
|
|
12576
|
+
this.validateSchema(report, val);
|
|
12444
12577
|
report.path.pop();
|
|
12445
12578
|
report.path.pop();
|
|
12446
12579
|
}
|
|
@@ -12474,8 +12607,8 @@
|
|
|
12474
12607
|
report.addError('KEYWORD_PATTERN', ['patternProperties', key]);
|
|
12475
12608
|
}
|
|
12476
12609
|
report.path.push('patternProperties');
|
|
12477
|
-
report.path.push(key
|
|
12478
|
-
validateSchema
|
|
12610
|
+
report.path.push(key);
|
|
12611
|
+
this.validateSchema(report, val);
|
|
12479
12612
|
report.path.pop();
|
|
12480
12613
|
report.path.pop();
|
|
12481
12614
|
}
|
|
@@ -12493,11 +12626,13 @@
|
|
|
12493
12626
|
const keys = Object.keys(schema.dependencies);
|
|
12494
12627
|
let idx = keys.length;
|
|
12495
12628
|
while (idx--) {
|
|
12496
|
-
const schemaKey = keys[idx]
|
|
12629
|
+
const schemaKey = keys[idx];
|
|
12630
|
+
const schemaDependency = schema.dependencies[schemaKey];
|
|
12631
|
+
const type = whatIs(schemaDependency);
|
|
12497
12632
|
if (type === 'object') {
|
|
12498
12633
|
report.path.push('dependencies');
|
|
12499
12634
|
report.path.push(schemaKey);
|
|
12500
|
-
validateSchema
|
|
12635
|
+
this.validateSchema(report, schemaDependency);
|
|
12501
12636
|
report.path.pop();
|
|
12502
12637
|
report.path.pop();
|
|
12503
12638
|
}
|
|
@@ -12535,8 +12670,10 @@
|
|
|
12535
12670
|
},
|
|
12536
12671
|
type: function (report, schema) {
|
|
12537
12672
|
// http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.5.2.1
|
|
12538
|
-
const primitiveTypes = ['array', 'boolean', 'integer', 'number', 'null', 'object', 'string']
|
|
12539
|
-
|
|
12673
|
+
const primitiveTypes = ['array', 'boolean', 'integer', 'number', 'null', 'object', 'string'];
|
|
12674
|
+
const primitiveTypeStr = primitiveTypes.join(',');
|
|
12675
|
+
const isArray = Array.isArray(schema.type);
|
|
12676
|
+
if (Array.isArray(schema.type)) {
|
|
12540
12677
|
let idx = schema.type.length;
|
|
12541
12678
|
while (idx--) {
|
|
12542
12679
|
if (primitiveTypes.indexOf(schema.type[idx]) === -1) {
|
|
@@ -12630,8 +12767,8 @@
|
|
|
12630
12767
|
let idx = schema.allOf.length;
|
|
12631
12768
|
while (idx--) {
|
|
12632
12769
|
report.path.push('allOf');
|
|
12633
|
-
report.path.push(idx
|
|
12634
|
-
validateSchema
|
|
12770
|
+
report.path.push(idx);
|
|
12771
|
+
this.validateSchema(report, schema.allOf[idx]);
|
|
12635
12772
|
report.path.pop();
|
|
12636
12773
|
report.path.pop();
|
|
12637
12774
|
}
|
|
@@ -12649,8 +12786,8 @@
|
|
|
12649
12786
|
let idx = schema.anyOf.length;
|
|
12650
12787
|
while (idx--) {
|
|
12651
12788
|
report.path.push('anyOf');
|
|
12652
|
-
report.path.push(idx
|
|
12653
|
-
validateSchema
|
|
12789
|
+
report.path.push(idx);
|
|
12790
|
+
this.validateSchema(report, schema.anyOf[idx]);
|
|
12654
12791
|
report.path.pop();
|
|
12655
12792
|
report.path.pop();
|
|
12656
12793
|
}
|
|
@@ -12668,8 +12805,8 @@
|
|
|
12668
12805
|
let idx = schema.oneOf.length;
|
|
12669
12806
|
while (idx--) {
|
|
12670
12807
|
report.path.push('oneOf');
|
|
12671
|
-
report.path.push(idx
|
|
12672
|
-
validateSchema
|
|
12808
|
+
report.path.push(idx);
|
|
12809
|
+
this.validateSchema(report, schema.oneOf[idx]);
|
|
12673
12810
|
report.path.pop();
|
|
12674
12811
|
report.path.pop();
|
|
12675
12812
|
}
|
|
@@ -12682,7 +12819,7 @@
|
|
|
12682
12819
|
}
|
|
12683
12820
|
else {
|
|
12684
12821
|
report.path.push('not');
|
|
12685
|
-
validateSchema
|
|
12822
|
+
this.validateSchema(report, schema.not);
|
|
12686
12823
|
report.path.pop();
|
|
12687
12824
|
}
|
|
12688
12825
|
},
|
|
@@ -12698,7 +12835,7 @@
|
|
|
12698
12835
|
const key = keys[idx], val = schema.definitions[key];
|
|
12699
12836
|
report.path.push('definitions');
|
|
12700
12837
|
report.path.push(key);
|
|
12701
|
-
validateSchema
|
|
12838
|
+
this.validateSchema(report, val);
|
|
12702
12839
|
report.path.pop();
|
|
12703
12840
|
report.path.pop();
|
|
12704
12841
|
}
|
|
@@ -12709,7 +12846,7 @@
|
|
|
12709
12846
|
report.addError('KEYWORD_TYPE_EXPECTED', ['format', 'string']);
|
|
12710
12847
|
}
|
|
12711
12848
|
else {
|
|
12712
|
-
if (
|
|
12849
|
+
if (!isFormatSupported(schema.format) && this.options.ignoreUnknownFormats !== true) {
|
|
12713
12850
|
report.addError('UNKNOWN_FORMAT', [schema.format]);
|
|
12714
12851
|
}
|
|
12715
12852
|
}
|
|
@@ -12732,296 +12869,124 @@
|
|
|
12732
12869
|
report.addError('KEYWORD_TYPE_EXPECTED', ['description', 'string']);
|
|
12733
12870
|
}
|
|
12734
12871
|
},
|
|
12735
|
-
default: function (
|
|
12872
|
+
default: function () {
|
|
12736
12873
|
// http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.2
|
|
12737
12874
|
// There are no restrictions placed on the value of this keyword.
|
|
12738
12875
|
},
|
|
12739
12876
|
};
|
|
12740
|
-
|
|
12741
|
-
|
|
12742
|
-
|
|
12743
|
-
|
|
12744
|
-
*
|
|
12745
|
-
* @returns {boolean}
|
|
12746
|
-
*/
|
|
12747
|
-
const validateArrayOfSchemas = function (report, arr) {
|
|
12748
|
-
let idx = arr.length;
|
|
12749
|
-
while (idx--) {
|
|
12750
|
-
validateSchema.call(this, report, arr[idx]);
|
|
12751
|
-
}
|
|
12752
|
-
return report.isValid();
|
|
12753
|
-
};
|
|
12754
|
-
/**
|
|
12755
|
-
*
|
|
12756
|
-
* @param {Report} report
|
|
12757
|
-
* @param {*} schema
|
|
12758
|
-
*/
|
|
12759
|
-
function validateSchema(report, schema) {
|
|
12760
|
-
report.commonErrorMessage = 'SCHEMA_VALIDATION_FAILED';
|
|
12761
|
-
// if schema is an array, assume it's an array of schemas
|
|
12762
|
-
if (Array.isArray(schema)) {
|
|
12763
|
-
return validateArrayOfSchemas.call(this, report, schema);
|
|
12877
|
+
class SchemaValidator {
|
|
12878
|
+
validator;
|
|
12879
|
+
constructor(validator) {
|
|
12880
|
+
this.validator = validator;
|
|
12764
12881
|
}
|
|
12765
|
-
|
|
12766
|
-
|
|
12767
|
-
return true;
|
|
12882
|
+
get options() {
|
|
12883
|
+
return this.validator.options;
|
|
12768
12884
|
}
|
|
12769
|
-
|
|
12770
|
-
|
|
12771
|
-
|
|
12772
|
-
|
|
12773
|
-
const subReport = new Report(report);
|
|
12774
|
-
const valid = validate.call(this, subReport, schema.__$schemaResolved, schema);
|
|
12775
|
-
if (valid === false) {
|
|
12776
|
-
report.addError('PARENT_SCHEMA_VALIDATION_FAILED', null, subReport);
|
|
12777
|
-
}
|
|
12778
|
-
}
|
|
12779
|
-
else {
|
|
12780
|
-
if (this.options.ignoreUnresolvableReferences !== true) {
|
|
12781
|
-
report.addError('REF_UNRESOLVED', [schema.$schema]);
|
|
12782
|
-
}
|
|
12885
|
+
validateArrayOfSchemas(report, arr) {
|
|
12886
|
+
let idx = arr.length;
|
|
12887
|
+
while (idx--) {
|
|
12888
|
+
this.validateSchema(report, arr[idx]);
|
|
12783
12889
|
}
|
|
12890
|
+
return report.isValid();
|
|
12784
12891
|
}
|
|
12785
|
-
|
|
12786
|
-
|
|
12787
|
-
if
|
|
12788
|
-
|
|
12789
|
-
|
|
12790
|
-
|
|
12791
|
-
|
|
12792
|
-
|
|
12793
|
-
|
|
12794
|
-
|
|
12795
|
-
|
|
12796
|
-
|
|
12892
|
+
validateSchema(report, schema) {
|
|
12893
|
+
report.commonErrorMessage = 'SCHEMA_VALIDATION_FAILED';
|
|
12894
|
+
// if schema is an array, assume it's an array of schemas
|
|
12895
|
+
if (Array.isArray(schema)) {
|
|
12896
|
+
return this.validateArrayOfSchemas(report, schema);
|
|
12897
|
+
}
|
|
12898
|
+
// do not revalidate schema that has already been validated once
|
|
12899
|
+
if (schema.__$validated) {
|
|
12900
|
+
return true;
|
|
12901
|
+
}
|
|
12902
|
+
// if $schema is present, this schema should validate against that $schema
|
|
12903
|
+
const hasParentSchema = schema.$schema && schema.id !== schema.$schema;
|
|
12904
|
+
if (hasParentSchema) {
|
|
12905
|
+
if (schema.__$schemaResolved && schema.__$schemaResolved !== schema) {
|
|
12906
|
+
const subReport = new Report(report);
|
|
12907
|
+
const valid = validate.call(this.validator, subReport, schema.__$schemaResolved, schema);
|
|
12908
|
+
if (valid === false) {
|
|
12909
|
+
report.addError('PARENT_SCHEMA_VALIDATION_FAILED', undefined, subReport);
|
|
12910
|
+
}
|
|
12797
12911
|
}
|
|
12798
|
-
|
|
12799
|
-
if (
|
|
12800
|
-
|
|
12912
|
+
else {
|
|
12913
|
+
if (this.validator.options.ignoreUnresolvableReferences !== true) {
|
|
12914
|
+
report.addError('REF_UNRESOLVED', [schema.$schema]);
|
|
12801
12915
|
}
|
|
12802
|
-
});
|
|
12803
|
-
}
|
|
12804
|
-
// end issue #36
|
|
12805
|
-
if (schema.enum === undefined &&
|
|
12806
|
-
schema.type === undefined &&
|
|
12807
|
-
schema.anyOf === undefined &&
|
|
12808
|
-
schema.oneOf === undefined &&
|
|
12809
|
-
schema.not === undefined &&
|
|
12810
|
-
schema.$ref === undefined) {
|
|
12811
|
-
report.addError('KEYWORD_UNDEFINED_STRICT', ['type']);
|
|
12812
|
-
}
|
|
12813
|
-
}
|
|
12814
|
-
const keys = Object.keys(schema);
|
|
12815
|
-
let idx = keys.length;
|
|
12816
|
-
while (idx--) {
|
|
12817
|
-
const key = keys[idx];
|
|
12818
|
-
if (key.indexOf('__') === 0) {
|
|
12819
|
-
continue;
|
|
12820
|
-
}
|
|
12821
|
-
if (SchemaValidators[key] !== undefined) {
|
|
12822
|
-
SchemaValidators[key].call(this, report, schema);
|
|
12823
|
-
}
|
|
12824
|
-
else if (!hasParentSchema) {
|
|
12825
|
-
if (this.options.noExtraKeywords === true) {
|
|
12826
|
-
report.addError('KEYWORD_UNEXPECTED', [key]);
|
|
12827
12916
|
}
|
|
12828
12917
|
}
|
|
12829
|
-
|
|
12830
|
-
|
|
12831
|
-
|
|
12832
|
-
|
|
12833
|
-
|
|
12834
|
-
|
|
12835
|
-
|
|
12836
|
-
|
|
12837
|
-
|
|
12838
|
-
|
|
12839
|
-
|
|
12840
|
-
|
|
12841
|
-
|
|
12918
|
+
if (this.validator.options.noTypeless === true) {
|
|
12919
|
+
// issue #36 - inherit type to anyOf, oneOf, allOf if noTypeless is defined
|
|
12920
|
+
if (schema.type !== undefined) {
|
|
12921
|
+
let schemas = [];
|
|
12922
|
+
if (Array.isArray(schema.anyOf)) {
|
|
12923
|
+
schemas = schemas.concat(schema.anyOf);
|
|
12924
|
+
}
|
|
12925
|
+
if (Array.isArray(schema.oneOf)) {
|
|
12926
|
+
schemas = schemas.concat(schema.oneOf);
|
|
12927
|
+
}
|
|
12928
|
+
if (Array.isArray(schema.allOf)) {
|
|
12929
|
+
schemas = schemas.concat(schema.allOf);
|
|
12930
|
+
}
|
|
12931
|
+
schemas.forEach(function (sch) {
|
|
12932
|
+
if (!sch.type) {
|
|
12933
|
+
sch.type = schema.type;
|
|
12934
|
+
}
|
|
12935
|
+
});
|
|
12842
12936
|
}
|
|
12843
|
-
|
|
12844
|
-
|
|
12845
|
-
|
|
12846
|
-
|
|
12847
|
-
|
|
12848
|
-
|
|
12849
|
-
|
|
12850
|
-
|
|
12851
|
-
const isValid = report.isValid();
|
|
12852
|
-
if (isValid) {
|
|
12853
|
-
schema.__$validated = true;
|
|
12854
|
-
}
|
|
12855
|
-
return isValid;
|
|
12856
|
-
}
|
|
12857
|
-
|
|
12858
|
-
function decodeJSONPointer(str) {
|
|
12859
|
-
// http://tools.ietf.org/html/draft-ietf-appsawg-json-pointer-07#section-3
|
|
12860
|
-
return decodeURIComponent(str).replace(/~[0-1]/g, function (x) {
|
|
12861
|
-
return x === '~1' ? '/' : '~';
|
|
12862
|
-
});
|
|
12863
|
-
}
|
|
12864
|
-
function getRemotePath(uri) {
|
|
12865
|
-
const io = uri.indexOf('#');
|
|
12866
|
-
return io === -1 ? uri : uri.slice(0, io);
|
|
12867
|
-
}
|
|
12868
|
-
function getQueryPath(uri) {
|
|
12869
|
-
const io = uri.indexOf('#');
|
|
12870
|
-
const res = io === -1 ? undefined : uri.slice(io + 1);
|
|
12871
|
-
// WARN: do not slice slash, #/ means take root and go down from it
|
|
12872
|
-
// if (res && res[0] === "/") { res = res.slice(1); }
|
|
12873
|
-
return res;
|
|
12874
|
-
}
|
|
12875
|
-
function findId(schema, id) {
|
|
12876
|
-
// process only arrays and objects
|
|
12877
|
-
if (typeof schema !== 'object' || schema === null) {
|
|
12878
|
-
return;
|
|
12879
|
-
}
|
|
12880
|
-
// no id means root so return itself
|
|
12881
|
-
if (!id) {
|
|
12882
|
-
return schema;
|
|
12883
|
-
}
|
|
12884
|
-
if (schema.id) {
|
|
12885
|
-
if (schema.id === id || (schema.id[0] === '#' && schema.id.substring(1) === id)) {
|
|
12886
|
-
return schema;
|
|
12887
|
-
}
|
|
12888
|
-
}
|
|
12889
|
-
let idx, result;
|
|
12890
|
-
if (Array.isArray(schema)) {
|
|
12891
|
-
idx = schema.length;
|
|
12892
|
-
while (idx--) {
|
|
12893
|
-
result = findId(schema[idx], id);
|
|
12894
|
-
if (result) {
|
|
12895
|
-
return result;
|
|
12937
|
+
// end issue #36
|
|
12938
|
+
if (schema.enum === undefined &&
|
|
12939
|
+
schema.type === undefined &&
|
|
12940
|
+
schema.anyOf === undefined &&
|
|
12941
|
+
schema.oneOf === undefined &&
|
|
12942
|
+
schema.not === undefined &&
|
|
12943
|
+
schema.$ref === undefined) {
|
|
12944
|
+
report.addError('KEYWORD_UNDEFINED_STRICT', ['type']);
|
|
12896
12945
|
}
|
|
12897
12946
|
}
|
|
12898
|
-
}
|
|
12899
|
-
else {
|
|
12900
12947
|
const keys = Object.keys(schema);
|
|
12901
|
-
idx = keys.length;
|
|
12948
|
+
let idx = keys.length;
|
|
12902
12949
|
while (idx--) {
|
|
12903
|
-
const
|
|
12904
|
-
if (
|
|
12950
|
+
const key = keys[idx];
|
|
12951
|
+
if (key.indexOf('__') === 0) {
|
|
12905
12952
|
continue;
|
|
12906
12953
|
}
|
|
12907
|
-
|
|
12908
|
-
|
|
12909
|
-
return result;
|
|
12954
|
+
if (Object.prototype.hasOwnProperty.call(SchemaValidators, key)) {
|
|
12955
|
+
SchemaValidators[key].call(this, report, schema);
|
|
12910
12956
|
}
|
|
12911
|
-
|
|
12912
|
-
|
|
12913
|
-
|
|
12914
|
-
/**
|
|
12915
|
-
*
|
|
12916
|
-
* @param {*} uri
|
|
12917
|
-
* @param {*} schema
|
|
12918
|
-
*
|
|
12919
|
-
* @returns {void}
|
|
12920
|
-
*/
|
|
12921
|
-
function cacheSchemaByUri(uri, schema) {
|
|
12922
|
-
const remotePath = getRemotePath(uri);
|
|
12923
|
-
if (remotePath) {
|
|
12924
|
-
this.cache[remotePath] = schema;
|
|
12925
|
-
}
|
|
12926
|
-
}
|
|
12927
|
-
/**
|
|
12928
|
-
*
|
|
12929
|
-
* @param {*} uri
|
|
12930
|
-
*
|
|
12931
|
-
* @returns {void}
|
|
12932
|
-
*/
|
|
12933
|
-
function removeFromCacheByUri(uri) {
|
|
12934
|
-
const remotePath = getRemotePath(uri);
|
|
12935
|
-
if (remotePath) {
|
|
12936
|
-
delete this.cache[remotePath];
|
|
12937
|
-
}
|
|
12938
|
-
}
|
|
12939
|
-
/**
|
|
12940
|
-
*
|
|
12941
|
-
* @param {*} uri
|
|
12942
|
-
*
|
|
12943
|
-
* @returns {boolean}
|
|
12944
|
-
*/
|
|
12945
|
-
function checkCacheForUri(uri) {
|
|
12946
|
-
const remotePath = getRemotePath(uri);
|
|
12947
|
-
return remotePath ? this.cache[remotePath] != null : false;
|
|
12948
|
-
}
|
|
12949
|
-
function getSchema(report, schema) {
|
|
12950
|
-
if (typeof schema === 'object') {
|
|
12951
|
-
schema = getSchemaByReference.call(this, report, schema);
|
|
12952
|
-
}
|
|
12953
|
-
if (typeof schema === 'string') {
|
|
12954
|
-
schema = getSchemaByUri.call(this, report, schema);
|
|
12955
|
-
}
|
|
12956
|
-
return schema;
|
|
12957
|
-
}
|
|
12958
|
-
function getSchemaByReference(report, key) {
|
|
12959
|
-
let i = this.referenceCache.length;
|
|
12960
|
-
while (i--) {
|
|
12961
|
-
if (isequal(this.referenceCache[i][0], key)) {
|
|
12962
|
-
return this.referenceCache[i][1];
|
|
12963
|
-
}
|
|
12964
|
-
}
|
|
12965
|
-
// not found
|
|
12966
|
-
const schema = cloneDeep(key);
|
|
12967
|
-
this.referenceCache.push([key, schema]);
|
|
12968
|
-
return schema;
|
|
12969
|
-
}
|
|
12970
|
-
function getSchemaByUri(report, uri, root) {
|
|
12971
|
-
const remotePath = getRemotePath(uri);
|
|
12972
|
-
const queryPath = getQueryPath(uri);
|
|
12973
|
-
let result = remotePath ? this.cache[remotePath] : root;
|
|
12974
|
-
if (result && remotePath) {
|
|
12975
|
-
// we need to avoid compiling schemas in a recursive loop
|
|
12976
|
-
const compileRemote = result !== root;
|
|
12977
|
-
// now we need to compile and validate resolved schema (in case it's not already)
|
|
12978
|
-
if (compileRemote) {
|
|
12979
|
-
report.path.push(remotePath);
|
|
12980
|
-
let remoteReport;
|
|
12981
|
-
const anscestorReport = report.getAncestor(result.id);
|
|
12982
|
-
if (anscestorReport) {
|
|
12983
|
-
remoteReport = anscestorReport;
|
|
12984
|
-
}
|
|
12985
|
-
else {
|
|
12986
|
-
remoteReport = new Report(report);
|
|
12987
|
-
if (compileSchema.call(this, remoteReport, result)) {
|
|
12988
|
-
const savedOptions = this.options;
|
|
12989
|
-
try {
|
|
12990
|
-
// If custom validationOptions were provided to setRemoteReference(),
|
|
12991
|
-
// use them instead of the default options
|
|
12992
|
-
this.options = result.__$validationOptions || this.options;
|
|
12993
|
-
validateSchema.call(this, remoteReport, result);
|
|
12994
|
-
}
|
|
12995
|
-
finally {
|
|
12996
|
-
this.options = savedOptions;
|
|
12997
|
-
}
|
|
12957
|
+
else if (!hasParentSchema) {
|
|
12958
|
+
if (this.validator.options.noExtraKeywords === true) {
|
|
12959
|
+
report.addError('KEYWORD_UNEXPECTED', [key]);
|
|
12998
12960
|
}
|
|
12999
12961
|
}
|
|
13000
|
-
const remoteReportIsValid = remoteReport.isValid();
|
|
13001
|
-
if (!remoteReportIsValid) {
|
|
13002
|
-
report.addError('REMOTE_NOT_VALID', [uri], remoteReport);
|
|
13003
|
-
}
|
|
13004
|
-
report.path.pop();
|
|
13005
|
-
if (!remoteReportIsValid) {
|
|
13006
|
-
return undefined;
|
|
13007
|
-
}
|
|
13008
12962
|
}
|
|
13009
|
-
|
|
13010
|
-
|
|
13011
|
-
|
|
13012
|
-
|
|
13013
|
-
|
|
13014
|
-
|
|
13015
|
-
|
|
13016
|
-
|
|
12963
|
+
if (this.validator.options.pedanticCheck === true) {
|
|
12964
|
+
if (schema.enum) {
|
|
12965
|
+
// break recursion
|
|
12966
|
+
const tmpSchema = shallowClone(schema);
|
|
12967
|
+
delete tmpSchema.enum;
|
|
12968
|
+
delete tmpSchema.default;
|
|
12969
|
+
report.path.push('enum');
|
|
12970
|
+
idx = schema.enum.length;
|
|
12971
|
+
while (idx--) {
|
|
12972
|
+
report.path.push(idx);
|
|
12973
|
+
validate.call(this.validator, report, tmpSchema, schema.enum[idx]);
|
|
12974
|
+
report.path.pop();
|
|
12975
|
+
}
|
|
12976
|
+
report.path.pop();
|
|
13017
12977
|
}
|
|
13018
|
-
|
|
13019
|
-
|
|
13020
|
-
|
|
12978
|
+
if (schema.default) {
|
|
12979
|
+
report.path.push('default');
|
|
12980
|
+
validate.call(this.validator, report, schema, schema.default);
|
|
12981
|
+
report.path.pop();
|
|
13021
12982
|
}
|
|
13022
12983
|
}
|
|
12984
|
+
const isValid = report.isValid();
|
|
12985
|
+
if (isValid) {
|
|
12986
|
+
schema.__$validated = true;
|
|
12987
|
+
}
|
|
12988
|
+
return isValid;
|
|
13023
12989
|
}
|
|
13024
|
-
return result;
|
|
13025
12990
|
}
|
|
13026
12991
|
|
|
13027
12992
|
var id$1 = "http://json-schema.org/draft-04/schema#";
|
|
@@ -13252,7 +13217,7 @@
|
|
|
13252
13217
|
"minimum"
|
|
13253
13218
|
]
|
|
13254
13219
|
};
|
|
13255
|
-
var
|
|
13220
|
+
var _Draft4Schema = {
|
|
13256
13221
|
id: id$1,
|
|
13257
13222
|
$schema: $schema$1,
|
|
13258
13223
|
description: description,
|
|
@@ -13421,7 +13386,7 @@
|
|
|
13421
13386
|
}
|
|
13422
13387
|
}
|
|
13423
13388
|
};
|
|
13424
|
-
var
|
|
13389
|
+
var _Draft4HyperSchema = {
|
|
13425
13390
|
$schema: $schema,
|
|
13426
13391
|
id: id,
|
|
13427
13392
|
title: title,
|
|
@@ -13430,6 +13395,8 @@
|
|
|
13430
13395
|
definitions: definitions
|
|
13431
13396
|
};
|
|
13432
13397
|
|
|
13398
|
+
const Draft4Schema = _Draft4Schema;
|
|
13399
|
+
const Draft4HyperSchema = _Draft4HyperSchema;
|
|
13433
13400
|
/**
|
|
13434
13401
|
* default options
|
|
13435
13402
|
*/
|
|
@@ -13479,11 +13446,13 @@
|
|
|
13479
13446
|
// function to be called on every schema
|
|
13480
13447
|
customValidator: null,
|
|
13481
13448
|
};
|
|
13482
|
-
|
|
13449
|
+
const normalizeOptions = (options) => {
|
|
13483
13450
|
let normalized;
|
|
13484
13451
|
// options
|
|
13485
13452
|
if (typeof options === 'object') {
|
|
13486
|
-
let keys = Object.keys(options)
|
|
13453
|
+
let keys = Object.keys(options);
|
|
13454
|
+
let idx = keys.length;
|
|
13455
|
+
let key;
|
|
13487
13456
|
// check that the options are correctly configured
|
|
13488
13457
|
while (idx--) {
|
|
13489
13458
|
key = keys[idx];
|
|
@@ -13497,13 +13466,13 @@
|
|
|
13497
13466
|
while (idx--) {
|
|
13498
13467
|
key = keys[idx];
|
|
13499
13468
|
if (options[key] === undefined) {
|
|
13500
|
-
options[key] =
|
|
13469
|
+
options[key] = shallowClone(defaultOptions[key]);
|
|
13501
13470
|
}
|
|
13502
13471
|
}
|
|
13503
13472
|
normalized = options;
|
|
13504
13473
|
}
|
|
13505
13474
|
else {
|
|
13506
|
-
normalized =
|
|
13475
|
+
normalized = shallowClone(defaultOptions);
|
|
13507
13476
|
}
|
|
13508
13477
|
if (normalized.strictMode === true) {
|
|
13509
13478
|
normalized.forceAdditional = true;
|
|
@@ -13516,68 +13485,45 @@
|
|
|
13516
13485
|
normalized.noEmptyArrays = true;
|
|
13517
13486
|
}
|
|
13518
13487
|
return normalized;
|
|
13519
|
-
}
|
|
13488
|
+
};
|
|
13520
13489
|
class ZSchema {
|
|
13521
|
-
|
|
13522
|
-
|
|
13523
|
-
* Register a custom format.
|
|
13524
|
-
*
|
|
13525
|
-
* @param name - name of the custom format
|
|
13526
|
-
* @param validatorFunction - custom format validator function.
|
|
13527
|
-
* Returns `true` if `value` matches the custom format.
|
|
13528
|
-
*/
|
|
13529
|
-
static registerFormat(formatName, validatorFunction) {
|
|
13530
|
-
FormatValidators[formatName] = validatorFunction;
|
|
13490
|
+
static registerFormat(name, validatorFunction) {
|
|
13491
|
+
return registerFormat(name, validatorFunction);
|
|
13531
13492
|
}
|
|
13532
|
-
/**
|
|
13533
|
-
* Unregister a format.
|
|
13534
|
-
*
|
|
13535
|
-
* @param name - name of the custom format
|
|
13536
|
-
*/
|
|
13537
13493
|
static unregisterFormat(name) {
|
|
13538
|
-
|
|
13494
|
+
return unregisterFormat(name);
|
|
13539
13495
|
}
|
|
13540
|
-
/**
|
|
13541
|
-
* Get the list of all registered formats.
|
|
13542
|
-
*
|
|
13543
|
-
* Both the names of the burned-in formats and the custom format names are
|
|
13544
|
-
* returned by this function.
|
|
13545
|
-
*
|
|
13546
|
-
* @returns {string[]} the list of all registered format names.
|
|
13547
|
-
*/
|
|
13548
13496
|
static getRegisteredFormats() {
|
|
13549
|
-
return
|
|
13497
|
+
return getRegisteredFormats();
|
|
13550
13498
|
}
|
|
13551
13499
|
static getDefaultOptions() {
|
|
13552
|
-
return
|
|
13500
|
+
return deepClone(defaultOptions);
|
|
13553
13501
|
}
|
|
13554
|
-
|
|
13555
|
-
|
|
13556
|
-
|
|
13502
|
+
lastReport;
|
|
13503
|
+
scache;
|
|
13504
|
+
sc;
|
|
13505
|
+
sv;
|
|
13506
|
+
validateOptions = {};
|
|
13557
13507
|
options;
|
|
13558
13508
|
constructor(options) {
|
|
13559
|
-
this.
|
|
13560
|
-
this.
|
|
13561
|
-
this.
|
|
13509
|
+
this.scache = new SchemaCache(this);
|
|
13510
|
+
this.sc = new SchemaCompiler(this);
|
|
13511
|
+
this.sv = new SchemaValidator(this);
|
|
13562
13512
|
this.options = normalizeOptions(options);
|
|
13563
13513
|
// Disable strict validation for the built-in schemas
|
|
13564
13514
|
const metaschemaOptions = normalizeOptions({});
|
|
13565
13515
|
this.setRemoteReference('http://json-schema.org/draft-04/schema', Draft4Schema, metaschemaOptions);
|
|
13566
13516
|
this.setRemoteReference('http://json-schema.org/draft-04/hyper-schema', Draft4HyperSchema, metaschemaOptions);
|
|
13567
13517
|
}
|
|
13568
|
-
/**
|
|
13569
|
-
* @param schema - JSON object representing schema
|
|
13570
|
-
* @returns {boolean} true if schema is valid.
|
|
13571
|
-
*/
|
|
13572
13518
|
validateSchema(schema) {
|
|
13573
13519
|
if (Array.isArray(schema) && schema.length === 0) {
|
|
13574
13520
|
throw new Error('.validateSchema was called with an empty array');
|
|
13575
13521
|
}
|
|
13576
13522
|
const report = new Report(this.options);
|
|
13577
|
-
schema = getSchema
|
|
13578
|
-
const compiled = compileSchema
|
|
13523
|
+
schema = this.scache.getSchema(report, schema);
|
|
13524
|
+
const compiled = this.sc.compileSchema(report, schema);
|
|
13579
13525
|
if (compiled) {
|
|
13580
|
-
validateSchema
|
|
13526
|
+
this.sv.validateSchema(report, schema);
|
|
13581
13527
|
}
|
|
13582
13528
|
this.lastReport = report;
|
|
13583
13529
|
return report.isValid();
|
|
@@ -13591,9 +13537,9 @@
|
|
|
13591
13537
|
options = {};
|
|
13592
13538
|
}
|
|
13593
13539
|
this.validateOptions = options;
|
|
13594
|
-
const
|
|
13595
|
-
if (
|
|
13596
|
-
const e = new Error('Invalid .validate call - schema must be a string or object but ' +
|
|
13540
|
+
const schemaType = whatIs(schema);
|
|
13541
|
+
if (schemaType !== 'string' && schemaType !== 'object') {
|
|
13542
|
+
const e = new Error('Invalid .validate call - schema must be a string or object but ' + schemaType + ' was passed!');
|
|
13597
13543
|
if (callback) {
|
|
13598
13544
|
setTimeout(function () {
|
|
13599
13545
|
callback(e, false);
|
|
@@ -13607,17 +13553,18 @@
|
|
|
13607
13553
|
report.json = json;
|
|
13608
13554
|
if (typeof schema === 'string') {
|
|
13609
13555
|
const schemaName = schema;
|
|
13610
|
-
|
|
13611
|
-
if (!
|
|
13556
|
+
const _schema = this.scache.getSchema(report, schemaName);
|
|
13557
|
+
if (!_schema) {
|
|
13612
13558
|
throw new Error("Schema with id '" + schemaName + "' wasn't found in the validator cache!");
|
|
13613
13559
|
}
|
|
13560
|
+
schema = _schema;
|
|
13614
13561
|
}
|
|
13615
13562
|
else {
|
|
13616
|
-
schema = getSchema
|
|
13563
|
+
schema = this.scache.getSchema(report, schema);
|
|
13617
13564
|
}
|
|
13618
13565
|
let compiled = false;
|
|
13619
13566
|
if (!foundError) {
|
|
13620
|
-
compiled = compileSchema
|
|
13567
|
+
compiled = this.sc.compileSchema(report, schema);
|
|
13621
13568
|
}
|
|
13622
13569
|
if (!compiled) {
|
|
13623
13570
|
this.lastReport = report;
|
|
@@ -13625,7 +13572,7 @@
|
|
|
13625
13572
|
}
|
|
13626
13573
|
let validated = false;
|
|
13627
13574
|
if (!foundError) {
|
|
13628
|
-
validated = validateSchema
|
|
13575
|
+
validated = this.sv.validateSchema(report, schema);
|
|
13629
13576
|
}
|
|
13630
13577
|
if (!validated) {
|
|
13631
13578
|
this.lastReport = report;
|
|
@@ -13656,6 +13603,9 @@
|
|
|
13656
13603
|
* Returns an Error object for the most recent failed validation, or null if the validation was successful.
|
|
13657
13604
|
*/
|
|
13658
13605
|
getLastError() {
|
|
13606
|
+
if (!this.lastReport) {
|
|
13607
|
+
throw new Error(`getLastError() called before doing any validation!`);
|
|
13608
|
+
}
|
|
13659
13609
|
if (this.lastReport.errors.length === 0) {
|
|
13660
13610
|
return null;
|
|
13661
13611
|
}
|
|
@@ -13673,27 +13623,29 @@
|
|
|
13673
13623
|
return this.lastReport && this.lastReport.errors.length > 0 ? this.lastReport.errors : null;
|
|
13674
13624
|
}
|
|
13675
13625
|
setRemoteReference(uri, schema, validationOptions) {
|
|
13626
|
+
let _schema;
|
|
13676
13627
|
if (typeof schema === 'string') {
|
|
13677
|
-
|
|
13628
|
+
_schema = JSON.parse(schema);
|
|
13678
13629
|
}
|
|
13679
13630
|
else {
|
|
13680
|
-
|
|
13631
|
+
_schema = deepClone(schema);
|
|
13681
13632
|
}
|
|
13682
13633
|
if (validationOptions) {
|
|
13683
|
-
|
|
13634
|
+
_schema.__$validationOptions = normalizeOptions(validationOptions);
|
|
13684
13635
|
}
|
|
13685
|
-
cacheSchemaByUri
|
|
13636
|
+
this.scache.cacheSchemaByUri(uri, _schema);
|
|
13686
13637
|
}
|
|
13687
13638
|
compileSchema(schema) {
|
|
13688
13639
|
const report = new Report(this.options);
|
|
13689
|
-
schema = getSchema
|
|
13690
|
-
compileSchema
|
|
13640
|
+
schema = this.scache.getSchema(report, schema);
|
|
13641
|
+
this.sc.compileSchema(report, schema);
|
|
13691
13642
|
this.lastReport = report;
|
|
13692
13643
|
return report.isValid();
|
|
13693
13644
|
}
|
|
13694
13645
|
getMissingReferences(arr) {
|
|
13695
|
-
arr = arr || this.lastReport
|
|
13696
|
-
let res = []
|
|
13646
|
+
arr = arr || this.lastReport?.errors || [];
|
|
13647
|
+
let res = [];
|
|
13648
|
+
let idx = arr.length;
|
|
13697
13649
|
while (idx--) {
|
|
13698
13650
|
const error = arr[idx];
|
|
13699
13651
|
if (error.code === 'UNRESOLVABLE_REFERENCE') {
|
|
@@ -13722,11 +13674,10 @@
|
|
|
13722
13674
|
}
|
|
13723
13675
|
getResolvedSchema(schema) {
|
|
13724
13676
|
const report = new Report(this.options);
|
|
13725
|
-
schema = getSchema
|
|
13677
|
+
schema = this.scache.getSchema(report, schema);
|
|
13726
13678
|
// clone before making any modifications
|
|
13727
|
-
schema =
|
|
13679
|
+
schema = deepClone(schema);
|
|
13728
13680
|
const visited = [];
|
|
13729
|
-
// clean-up the schema and resolve references
|
|
13730
13681
|
const cleanup = function (schema) {
|
|
13731
13682
|
let key;
|
|
13732
13683
|
const typeOf = whatIs(schema);
|