z-schema 7.0.0 → 7.0.6

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