z-schema 7.0.5 → 7.0.7

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