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