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.
Files changed (76) hide show
  1. package/README.md +7 -11
  2. package/bin/z-schema +0 -0
  3. package/cjs/index.d.ts +192 -117
  4. package/cjs/index.js +949 -998
  5. package/{src/FormatValidators.ts → dist/format-validators.js} +97 -65
  6. package/dist/index.js +1 -1
  7. package/dist/json-schema.js +40 -0
  8. package/dist/{JsonValidation.js → json-validation.js} +75 -69
  9. package/dist/{Report.js → report.js} +35 -45
  10. package/dist/schema-cache.js +109 -0
  11. package/dist/schema-compiler.js +255 -0
  12. package/dist/{SchemaValidation.js → schema-validator.js} +153 -149
  13. package/dist/types/{Errors.d.ts → errors.d.ts} +2 -0
  14. package/dist/types/format-validators.d.ts +10 -0
  15. package/dist/types/index.d.ts +10 -1
  16. package/dist/types/json-schema.d.ts +50 -0
  17. package/dist/types/json-validation.d.ts +7 -0
  18. package/dist/types/{Report.d.ts → report.d.ts} +22 -23
  19. package/dist/types/schema-cache.d.ts +17 -0
  20. package/dist/types/schema-compiler.d.ts +16 -0
  21. package/dist/types/schema-validator.d.ts +10 -0
  22. package/dist/types/utils/array.d.ts +2 -0
  23. package/dist/types/utils/clone.d.ts +2 -0
  24. package/dist/types/utils/json.d.ts +7 -0
  25. package/dist/types/utils/symbols.d.ts +2 -0
  26. package/dist/types/utils/unicode.d.ts +14 -0
  27. package/dist/types/utils/uri.d.ts +4 -0
  28. package/dist/types/utils/what-is.d.ts +3 -0
  29. package/dist/types/z-schema.d.ts +75 -0
  30. package/dist/utils/array.js +27 -0
  31. package/dist/utils/clone.js +61 -0
  32. package/dist/utils/json.js +59 -0
  33. package/dist/utils/symbols.js +2 -0
  34. package/dist/utils/unicode.js +45 -0
  35. package/dist/utils/uri.js +15 -0
  36. package/dist/utils/what-is.js +29 -0
  37. package/dist/{ZSchema.js → z-schema.js} +66 -77
  38. package/package.json +8 -4
  39. package/src/{Errors.ts → errors.ts} +4 -0
  40. package/src/format-validators.ts +191 -0
  41. package/src/index.ts +12 -1
  42. package/src/json-schema.ts +97 -0
  43. package/src/{JsonValidation.ts → json-validation.ts} +137 -127
  44. package/src/{Report.ts → report.ts} +60 -70
  45. package/src/schema-cache.ts +122 -0
  46. package/src/schema-compiler.ts +300 -0
  47. package/src/{SchemaValidation.ts → schema-validator.ts} +213 -215
  48. package/src/utils/array.ts +29 -0
  49. package/src/utils/clone.ts +63 -0
  50. package/src/utils/json.ts +74 -0
  51. package/src/utils/symbols.ts +3 -0
  52. package/src/utils/unicode.ts +43 -0
  53. package/src/utils/uri.ts +18 -0
  54. package/src/utils/what-is.ts +46 -0
  55. package/src/{ZSchema.ts → z-schema.ts} +108 -113
  56. package/umd/ZSchema.js +949 -998
  57. package/umd/ZSchema.min.js +1 -1
  58. package/dist/FormatValidators.js +0 -136
  59. package/dist/SchemaCache.js +0 -173
  60. package/dist/SchemaCompilation.js +0 -259
  61. package/dist/Utils.js +0 -266
  62. package/dist/types/FormatValidators.d.ts +0 -12
  63. package/dist/types/JsonValidation.d.ts +0 -37
  64. package/dist/types/SchemaCache.d.ts +0 -26
  65. package/dist/types/SchemaCompilation.d.ts +0 -1
  66. package/dist/types/SchemaValidation.d.ts +0 -6
  67. package/dist/types/Utils.d.ts +0 -64
  68. package/dist/types/ZSchema.d.ts +0 -97
  69. package/src/SchemaCache.ts +0 -189
  70. package/src/SchemaCompilation.ts +0 -293
  71. package/src/Utils.ts +0 -286
  72. /package/dist/{Errors.js → errors.js} +0 -0
  73. /package/dist/schemas/{hyper-schema.json → draft-04-hyper-schema.json} +0 -0
  74. /package/dist/schemas/{schema.json → draft-04-schema.json} +0 -0
  75. /package/src/schemas/{hyper-schema.json → draft-04-hyper-schema.json} +0 -0
  76. /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 jsonSymbol = Symbol.for('z-schema/json');
1005
- const schemaSymbol = Symbol.for('z-schema/schema');
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 (to === 'number') {
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 to; // undefined, boolean, string, function
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
- // NOT a deep version of clone
1162
- function clone(src) {
1163
- if (typeof src === 'undefined') {
1164
- return void 0;
1165
- }
1166
- if (typeof src !== 'object' || src === null) {
1167
- return src;
1168
- }
1169
- let res, idx;
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
- function cloneDeep(src) {
1189
- let vidx = 0;
1190
- const visited = new Map();
1191
- const cloned = [];
1192
- function cloneDeepInner(src) {
1193
- if (typeof src !== 'object' || src === null) {
1194
- return src;
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
- errors;
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
- function respond(asyncTaskResultProcessFn) {
1325
- return function (asyncTaskResult) {
1326
- if (timedOut) {
1327
- return;
1328
- }
1329
- asyncTaskResultProcessFn(asyncTaskResult);
1330
- if (--tasksCount === 0) {
1331
- finish();
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 null;
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(errorCode, params) {
1166
+ hasError(errCode, errParams) {
1399
1167
  let idx = this.errors.length;
1400
1168
  while (idx--) {
1401
- if (this.errors[idx].code === errorCode) {
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] !== 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(errorCode, params, subReports, schema) {
1420
- if (!errorCode) {
1187
+ addError(errCode, errParams, subReports, schema) {
1188
+ if (!errCode) {
1421
1189
  throw new Error('No errorCode passed into addError()');
1422
1190
  }
1423
- this.addCustomError(errorCode, Errors[errorCode], params, subReports, schema);
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 whatIs$1 = whatIs(params[idx]);
1445
- const param = whatIs$1 === 'object' || whatIs$1 === 'null' ? JSON.stringify(params[idx]) : params[idx];
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 FormatValidators = {
9387
- date: function (date) {
9388
- if (typeof date !== 'string') {
9389
- return true;
9390
- }
9391
- // full-date from http://tools.ietf.org/html/rfc3339#section-5.6
9392
- const matches = /^([0-9]{4})-([0-9]{2})-([0-9]{2})$/.exec(date);
9393
- if (matches === null) {
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
- // var year = matches[1];
9397
- // var month = matches[2];
9398
- // var day = matches[3];
9399
- if (matches[2] < '01' || matches[2] > '12' || matches[3] < '01' || matches[3] > '31') {
9400
- return false;
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
- 'date-time': function (dateTime) {
9405
- if (typeof dateTime !== 'string') {
9406
- return true;
9407
- }
9408
- // date-time from http://tools.ietf.org/html/rfc3339#section-5.6
9409
- const s = dateTime.toLowerCase().split('t');
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
- // var hour = matches[1];
9418
- // var minute = matches[2];
9419
- // var second = matches[3];
9420
- // var fraction = matches[4];
9421
- // var timezone = matches[5];
9422
- if (matches[1] > '23' || matches[2] > '59' || matches[3] > '59') {
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
- email: function (email) {
9428
- if (typeof email !== 'string') {
9429
- return true;
9430
- }
9431
- return validator.isEmail(email, { require_tld: true });
9432
- },
9433
- hostname: function (hostname) {
9434
- if (typeof hostname !== 'string') {
9435
- return true;
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
- http://json-schema.org/latest/json-schema-validation.html#anchor114
9439
- A string instance is valid against this attribute if it is a valid
9440
- representation for an Internet host name, as defined by RFC 1034, section 3.1 [RFC1034].
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
- // Each node has a label, which is zero to 63 octets in length
9475
- const labels = hostname.split('.');
9476
- for (let i = 0; i < labels.length; i++) {
9477
- if (labels[i].length > 63) {
9478
- return false;
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
- return valid;
9483
- },
9484
- 'host-name': function (hostname) {
9485
- return FormatValidators.hostname.call(this, hostname);
9486
- },
9487
- ipv4: function (ipv4) {
9488
- if (typeof ipv4 !== 'string') {
9489
- return true;
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
- return validator.isIP(ipv4, 4);
9492
- },
9493
- ipv6: function (ipv6) {
9494
- if (typeof ipv6 !== 'string') {
9495
- return true;
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
- return validator.isIP(ipv6, 6);
9498
- },
9499
- regex: function (str) {
9500
- try {
9501
- RegExp(str);
9502
- return true;
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
- catch (_e) {
9505
- return false;
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
- uri: function (...args) {
9509
- if (this.options.strictUris) {
9510
- return FormatValidators['strict-uri'].apply(this, args);
9511
- }
9512
- const [uri] = args;
9513
- // https://github.com/zaggino/z-schema/issues/18
9514
- // RegExp from http://tools.ietf.org/html/rfc3986#appendix-B
9515
- return typeof uri !== 'string' || RegExp('^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?').test(uri);
9516
- },
9517
- 'strict-uri': function (uri) {
9518
- return typeof uri !== 'string' || validator.isURL(uri);
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], null, schema);
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], null, schema);
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], null, schema);
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], null, schema);
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], null, schema);
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], null, schema);
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], null, schema);
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], null, schema);
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', null, null, schema);
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], null, schema);
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], null, schema);
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, null, schema);
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 (whatIs(json) !== 'object') {
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], null, schema);
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 (whatIs(json) !== 'object') {
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], null, schema);
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 (whatIs(json) !== 'object') {
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], null, schema);
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 (whatIs(json) !== 'object') {
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
- let idx3 = this.options.assumeAdditional.length;
9772
- if (idx3) {
9773
- while (idx3--) {
9774
- const io = s.indexOf(this.options.assumeAdditional[idx3]);
9775
- if (io !== -1) {
9776
- s.splice(io, 1);
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]], null, schema);
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 (whatIs(json) !== 'object') {
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 (whatIs(dependencyDefinition) === 'object') {
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], null, schema);
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], null, schema);
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], null, schema);
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], null, schema);
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', null, null, schema);
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', null, null, schema);
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 formatValidatorFn = FormatValidators[schema.format];
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 = clone(report.path);
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], null, schema);
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], null, schema);
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], null, schema);
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], null, schema);
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], null, schema);
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 (jsonType === 'array') {
10088
+ if (Array.isArray(json)) {
10098
10089
  recurseArray.call(this, report, schema, json);
10099
10090
  }
10100
- else if (jsonType === 'object') {
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
- function mergeReference(scope, ref) {
11980
- if (isAbsoluteUri(ref)) {
11981
- return ref;
11970
+ const findId = (schema, id) => {
11971
+ // process only arrays and objects
11972
+ if (typeof schema !== 'object' || schema === null) {
11973
+ return;
11982
11974
  }
11983
- let joinedScope = scope.join('');
11984
- const isScopeAbsolute = isAbsoluteUri(joinedScope);
11985
- const isScopeRelative = isRelativeUri(joinedScope);
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
- else if (isScopeRelative && isRefRelative) {
11995
- joinedScope = '';
11979
+ if (schema.id) {
11980
+ if (schema.id === id || (schema.id[0] === '#' && schema.id.substring(1) === id)) {
11981
+ return schema;
11982
+ }
11996
11983
  }
11997
- else {
11998
- toRemove = joinedScope.match(/[^#/]+$/);
11999
- if (toRemove) {
12000
- joinedScope = joinedScope.slice(0, toRemove.index);
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
- let res = joinedScope + ref;
12004
- res = res.replace(/##/, '#');
12005
- return res;
12006
- }
12007
- function collectReferences(obj, results, scope, path) {
12008
- results = results || [];
12009
- scope = scope || [];
12010
- path = path || [];
12011
- if (typeof obj !== 'object' || obj === null) {
12012
- return results;
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.toString());
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 compileArrayOfSchemasLoop = function (mainReport, arr) {
12061
- let idx = arr.length, compiledCount = 0;
12062
- while (idx--) {
12063
- // try to compile each schema separately
12064
- const report = new Report(mainReport);
12065
- const isValid = compileSchema.call(this, report, arr[idx]);
12066
- if (isValid) {
12067
- compiledCount++;
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
- return compiledCount;
12073
- };
12074
- function findId$1(arr, id) {
12075
- let idx = arr.length;
12076
- while (idx--) {
12077
- if (arr[idx].id === id) {
12078
- return arr[idx];
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
- return null;
12082
- }
12083
- const compileArrayOfSchemas = function (report, arr) {
12084
- let compiled = 0, lastLoopCompiled;
12085
- do {
12086
- // remove all UNRESOLVABLE_REFERENCE errors before compiling array again
12087
- let idx = report.errors.length;
12088
- while (idx--) {
12089
- if (report.errors[idx].code === 'UNRESOLVABLE_REFERENCE') {
12090
- report.errors.splice(idx, 1);
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
- // remember how many were compiled in the last loop
12094
- lastLoopCompiled = compiled;
12095
- // count how many are compiled now
12096
- compiled = compileArrayOfSchemasLoop.call(this, report, arr);
12097
- // fix __$missingReferences if possible
12098
- idx = arr.length;
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
- const sch = arr[idx];
12101
- if (sch.__$missingReferences) {
12102
- let idx2 = sch.__$missingReferences.length;
12103
- while (idx2--) {
12104
- const refObj = sch.__$missingReferences[idx2];
12105
- const response = findId$1(arr, refObj.ref);
12106
- if (response) {
12107
- // this might create circular references
12108
- refObj.obj['__' + refObj.key + 'Resolved'] = response;
12109
- // it's resolved now so delete it
12110
- sch.__$missingReferences.splice(idx2, 1);
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
- if (sch.__$missingReferences.length === 0) {
12114
- delete sch.__$missingReferences;
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
- // keep repeating if not all compiled and at least one more was compiled in the last loop
12119
- } while (compiled !== arr.length && compiled !== lastLoopCompiled);
12120
- return report.isValid();
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
- schema = loadedSchema;
12132
- }
12133
- // if schema is an array, assume it's an array of schemas
12134
- if (Array.isArray(schema)) {
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
- if (!response) {
12187
- const hasNotValid = report.hasError('REMOTE_NOT_VALID', [refObj.ref]);
12188
- const isAbsolute = isAbsoluteUri(refObj.ref);
12189
- let isDownloaded = false;
12190
- const ignoreUnresolvableRemotes = this.options.ignoreUnresolvableReferences === true;
12191
- if (isAbsolute) {
12192
- // we shouldn't add UNRESOLVABLE_REFERENCE for schemas we already have downloaded
12193
- // and set through setRemoteReference method
12194
- isDownloaded = checkCacheForUri.call(this, refObj.ref);
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
- if (hasNotValid) ;
12197
- else if (ignoreUnresolvableRemotes && isAbsolute) ;
12198
- else if (isDownloaded) ;
12199
- else {
12200
- Array.prototype.push.apply(report.path, refObj.path);
12201
- report.addError('UNRESOLVABLE_REFERENCE', [refObj.ref]);
12202
- report.path = report.path.slice(0, -refObj.path.length);
12203
- // pusblish unresolved references out
12204
- if (isValidExceptReferences) {
12205
- schema.__$missingReferences = schema.__$missingReferences || [];
12206
- schema.__$missingReferences.push(refObj);
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
- // this might create circular references
12211
- refObj.obj['__' + refObj.key + 'Resolved'] = response;
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
- else {
12218
- if (schema.id && typeof schema.id === 'string') {
12219
- // remove this schema from schemaCache because it failed to compile
12220
- removeFromCacheByUri.call(this, schema.id);
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 (type === 'object') {
12453
+ else if (isObject(schema.additionalItems)) {
12322
12454
  report.path.push('additionalItems');
12323
- validateSchema.call(this, report, schema.additionalItems);
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.call(this, report, schema.items);
12464
+ this.validateSchema(report, schema.items);
12333
12465
  report.path.pop();
12334
12466
  }
12335
- else if (type === 'array') {
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.toString());
12340
- validateSchema.call(this, report, schema.items[idx]);
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 (type === 'object') {
12557
+ else if (isObject(schema.additionalProperties)) {
12426
12558
  report.path.push('additionalProperties');
12427
- validateSchema.call(this, report, schema.additionalProperties);
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], val = schema.properties[key];
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.call(this, report, val);
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.toString());
12478
- validateSchema.call(this, report, val);
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], schemaDependency = schema.dependencies[schemaKey], type = whatIs(schemaDependency);
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.call(this, report, schemaDependency);
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'], primitiveTypeStr = primitiveTypes.join(','), isArray = Array.isArray(schema.type);
12539
- if (isArray) {
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.toString());
12634
- validateSchema.call(this, report, schema.allOf[idx]);
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.toString());
12653
- validateSchema.call(this, report, schema.anyOf[idx]);
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.toString());
12672
- validateSchema.call(this, report, schema.oneOf[idx]);
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.call(this, report, schema.not);
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.call(this, report, val);
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 (FormatValidators[schema.format] === undefined && this.options.ignoreUnknownFormats !== true) {
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 ( /* report, schema */) {
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
- * @param {Report} report
12743
- * @param {*[]} arr
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
- // do not revalidate schema that has already been validated once
12766
- if (schema.__$validated) {
12767
- return true;
12882
+ get options() {
12883
+ return this.validator.options;
12768
12884
  }
12769
- // if $schema is present, this schema should validate against that $schema
12770
- const hasParentSchema = schema.$schema && schema.id !== schema.$schema;
12771
- if (hasParentSchema) {
12772
- if (schema.__$schemaResolved && schema.__$schemaResolved !== schema) {
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
- if (this.options.noTypeless === true) {
12786
- // issue #36 - inherit type to anyOf, oneOf, allOf if noTypeless is defined
12787
- if (schema.type !== undefined) {
12788
- let schemas = [];
12789
- if (Array.isArray(schema.anyOf)) {
12790
- schemas = schemas.concat(schema.anyOf);
12791
- }
12792
- if (Array.isArray(schema.oneOf)) {
12793
- schemas = schemas.concat(schema.oneOf);
12794
- }
12795
- if (Array.isArray(schema.allOf)) {
12796
- schemas = schemas.concat(schema.allOf);
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
- schemas.forEach(function (sch) {
12799
- if (!sch.type) {
12800
- sch.type = schema.type;
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
- if (this.options.pedanticCheck === true) {
12831
- if (schema.enum) {
12832
- // break recursion
12833
- const tmpSchema = clone(schema);
12834
- delete tmpSchema.enum;
12835
- delete tmpSchema.default;
12836
- report.path.push('enum');
12837
- idx = schema.enum.length;
12838
- while (idx--) {
12839
- report.path.push(idx.toString());
12840
- validate.call(this, report, tmpSchema, schema.enum[idx]);
12841
- report.path.pop();
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
- report.path.pop();
12844
- }
12845
- if (schema.default) {
12846
- report.path.push('default');
12847
- validate.call(this, report, schema, schema.default);
12848
- report.path.pop();
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 k = keys[idx];
12904
- if (k.indexOf('__$') === 0) {
12950
+ const key = keys[idx];
12951
+ if (key.indexOf('__') === 0) {
12905
12952
  continue;
12906
12953
  }
12907
- result = findId(schema[k], id);
12908
- if (result) {
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
- if (result && queryPath) {
13011
- const parts = queryPath.split('/');
13012
- for (let idx = 0, lim = parts.length; result && idx < lim; idx++) {
13013
- const key = decodeJSONPointer(parts[idx]);
13014
- if (idx === 0) {
13015
- // it's an id
13016
- result = findId(result, key);
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
- else {
13019
- // it's a path behind id
13020
- result = result[key];
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 Draft4Schema = {
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 Draft4HyperSchema = {
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
- function normalizeOptions(options) {
13449
+ const normalizeOptions = (options) => {
13483
13450
  let normalized;
13484
13451
  // options
13485
13452
  if (typeof options === 'object') {
13486
- let keys = Object.keys(options), idx = keys.length, key;
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] = clone(defaultOptions[key]);
13469
+ options[key] = shallowClone(defaultOptions[key]);
13501
13470
  }
13502
13471
  }
13503
13472
  normalized = options;
13504
13473
  }
13505
13474
  else {
13506
- normalized = clone(defaultOptions);
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
- lastReport;
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
- delete FormatValidators[name];
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 Object.keys(FormatValidators);
13497
+ return getRegisteredFormats();
13550
13498
  }
13551
13499
  static getDefaultOptions() {
13552
- return cloneDeep(defaultOptions);
13500
+ return deepClone(defaultOptions);
13553
13501
  }
13554
- cache;
13555
- referenceCache;
13556
- validateOptions;
13502
+ lastReport;
13503
+ scache;
13504
+ sc;
13505
+ sv;
13506
+ validateOptions = {};
13557
13507
  options;
13558
13508
  constructor(options) {
13559
- this.cache = {};
13560
- this.referenceCache = [];
13561
- this.validateOptions = {};
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.call(this, report, schema);
13578
- const compiled = compileSchema.call(this, report, schema);
13523
+ schema = this.scache.getSchema(report, schema);
13524
+ const compiled = this.sc.compileSchema(report, schema);
13579
13525
  if (compiled) {
13580
- validateSchema.call(this, report, schema);
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 whatIs$1 = whatIs(schema);
13595
- if (whatIs$1 !== 'string' && whatIs$1 !== 'object') {
13596
- const e = new Error('Invalid .validate call - schema must be a string or object but ' + whatIs$1 + ' was passed!');
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
- schema = getSchema.call(this, report, schemaName);
13611
- if (!schema) {
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.call(this, report, schema);
13563
+ schema = this.scache.getSchema(report, schema);
13617
13564
  }
13618
13565
  let compiled = false;
13619
13566
  if (!foundError) {
13620
- compiled = compileSchema.call(this, report, schema);
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.call(this, report, schema);
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
- schema = JSON.parse(schema);
13628
+ _schema = JSON.parse(schema);
13678
13629
  }
13679
13630
  else {
13680
- schema = cloneDeep(schema);
13631
+ _schema = deepClone(schema);
13681
13632
  }
13682
13633
  if (validationOptions) {
13683
- schema.__$validationOptions = normalizeOptions(validationOptions);
13634
+ _schema.__$validationOptions = normalizeOptions(validationOptions);
13684
13635
  }
13685
- cacheSchemaByUri.call(this, uri, schema);
13636
+ this.scache.cacheSchemaByUri(uri, _schema);
13686
13637
  }
13687
13638
  compileSchema(schema) {
13688
13639
  const report = new Report(this.options);
13689
- schema = getSchema.call(this, report, schema);
13690
- compileSchema.call(this, report, schema);
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.errors;
13696
- let res = [], idx = arr.length;
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.call(this, report, schema);
13677
+ schema = this.scache.getSchema(report, schema);
13726
13678
  // clone before making any modifications
13727
- schema = cloneDeep(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);