schema-shield 1.0.4 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,5 +1,19 @@
1
1
  // lib/utils/main-utils.ts
2
+ var hasOwnPropertyIntrinsic = Object.prototype.hasOwnProperty;
3
+ var hasOwnPropertyCall = Function.prototype.call.bind(
4
+ hasOwnPropertyIntrinsic
5
+ );
6
+ function definePropertyOrThrow(target, key, descriptor) {
7
+ if (!Reflect.defineProperty(target, key, descriptor)) {
8
+ throw new TypeError(`Cannot define property "${String(key)}"`);
9
+ }
10
+ return target;
11
+ }
12
+ function hasOwn(target, key) {
13
+ return hasOwnPropertyCall(target, key);
14
+ }
2
15
  var ValidationError = class extends Error {
16
+ code;
3
17
  message;
4
18
  item;
5
19
  keyword;
@@ -8,42 +22,61 @@ var ValidationError = class extends Error {
8
22
  instancePath = "";
9
23
  data;
10
24
  schema;
11
- _getCause(pointer = "#", instancePointer = "#") {
12
- let schemaPath = `${pointer}/${this.keyword}`;
13
- let instancePath = `${instancePointer}`;
14
- if (typeof this.item !== "undefined") {
15
- if (typeof this.item === "string" && this.item in this.schema) {
16
- schemaPath += `/${this.item}`;
17
- }
18
- instancePath += `/${this.item}`;
19
- }
20
- this.instancePath = instancePath;
21
- this.schemaPath = schemaPath;
22
- if (!this.cause || !(this.cause instanceof ValidationError)) {
23
- return this;
24
- }
25
- return this.cause._getCause(schemaPath, instancePath);
25
+ constructor(message) {
26
+ super(message);
27
+ this.message = message;
26
28
  }
27
29
  getCause() {
28
- return this._getCause();
29
- }
30
- _getTree() {
31
- const tree = {
32
- message: this.message,
33
- keyword: this.keyword,
34
- item: this.item,
35
- schemaPath: this.schemaPath,
36
- instancePath: this.instancePath,
37
- data: this.data
38
- };
39
- if (this.cause) {
40
- tree.cause = this.cause._getTree();
30
+ let current = this;
31
+ let schemaPointer = "#";
32
+ let instancePointer = "#";
33
+ const seen = /* @__PURE__ */ new Set();
34
+ while (!seen.has(current)) {
35
+ seen.add(current);
36
+ let schemaPath = `${schemaPointer}/${current.keyword}`;
37
+ let instancePath = instancePointer;
38
+ if (typeof current.item !== "undefined") {
39
+ if (typeof current.item === "string" && current.schema && typeof current.schema === "object" && current.item in current.schema) {
40
+ schemaPath += `/${escapeJsonPointerToken(current.item)}`;
41
+ }
42
+ instancePath += `/${escapeJsonPointerToken(current.item)}`;
43
+ }
44
+ current.schemaPath = schemaPath;
45
+ current.instancePath = instancePath;
46
+ if (!(current.cause instanceof ValidationError) || seen.has(current.cause)) {
47
+ return current;
48
+ }
49
+ schemaPointer = schemaPath;
50
+ instancePointer = instancePath;
51
+ current = current.cause;
41
52
  }
42
- return tree;
53
+ return current;
43
54
  }
44
55
  getTree() {
45
56
  this.getCause();
46
- return this._getTree();
57
+ let current = this;
58
+ let root;
59
+ let target;
60
+ const seen = /* @__PURE__ */ new Set();
61
+ while (current && !seen.has(current)) {
62
+ seen.add(current);
63
+ const node = {
64
+ message: current.message,
65
+ keyword: current.keyword,
66
+ item: current.item,
67
+ schemaPath: current.schemaPath,
68
+ instancePath: current.instancePath,
69
+ data: current.data
70
+ };
71
+ if (!root) {
72
+ root = node;
73
+ } else if (target) {
74
+ target.cause = node;
75
+ }
76
+ target = node;
77
+ current = current.cause instanceof ValidationError ? current.cause : void 0;
78
+ }
79
+ return root;
47
80
  }
48
81
  getPath() {
49
82
  const cause = this.getCause();
@@ -63,8 +96,11 @@ function getDefinedErrorFunctionForKey(key, schema, failFast) {
63
96
  KeywordError.schema = schema;
64
97
  const defineError = (message, options = {}) => {
65
98
  KeywordError.message = message;
99
+ KeywordError.code = options.code;
66
100
  KeywordError.item = options.item;
67
- KeywordError.cause = options.cause && options.cause !== true ? options.cause : void 0;
101
+ if (options.cause !== KeywordError) {
102
+ KeywordError.cause = options.cause && options.cause !== true ? options.cause : void 0;
103
+ }
68
104
  KeywordError.data = options.data;
69
105
  return KeywordError;
70
106
  };
@@ -73,11 +109,14 @@ function getDefinedErrorFunctionForKey(key, schema, failFast) {
73
109
  defineError
74
110
  );
75
111
  }
112
+ function escapeJsonPointerToken(value) {
113
+ return String(value).replace(/~/g, "~0").replace(/\//g, "~1");
114
+ }
76
115
  function isCompiledSchema(subSchema) {
77
116
  return !!subSchema && typeof subSchema === "object" && !Array.isArray(subSchema) && "$validate" in subSchema;
78
117
  }
79
118
  function getNamedFunction(name, fn) {
80
- return Object.defineProperty(fn, "name", { value: name });
119
+ return definePropertyOrThrow(fn, "name", { value: name });
81
120
  }
82
121
  function resolvePath(root, path) {
83
122
  if (!path || path === "#") {
@@ -122,7 +161,6 @@ var DURATION_REGEX = /^P(?!$)((\d+Y)?(\d+M)?(\d+W)?(\d+D)?)(T(?=\d)(\d+H)?(\d+M)
122
161
  var URI_REGEX = /^[a-zA-Z][a-zA-Z0-9+\-.]*:[^\s]*$/;
123
162
  var EMAIL_REGEX = /^(?!\.)(?!.*\.$)[a-z0-9!#$%&'*+/=?^_`{|}~-]{1,20}(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]{1,21}){0,2}@[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,60}[a-z0-9])?){0,3}$/i;
124
163
  var HOSTNAME_REGEX = /^[a-z0-9][a-z0-9-]{0,62}(?:\.[a-z0-9][a-z0-9-]{0,62})*[a-z0-9]$/i;
125
- var DATE_REGEX = /^(\d{4})-(\d{2})-(\d{2})$/;
126
164
  var TIME_REGEX = /^([01]\d|2[0-3]):([0-5]\d):([0-5]\d)(\.\d+)?(Z|([+-])([01]\d|2[0-3]):([0-5]\d))$/;
127
165
  var URI_REFERENCE_REGEX = /^(([^:/?#]+):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#((?![^#]*\\)[^#]*))?/i;
128
166
  var IRI_REGEX = /^[a-zA-Z][a-zA-Z0-9+\-.]*:[^\s]*$/;
@@ -187,6 +225,22 @@ function isValidIpv4(data) {
187
225
  function isHexCharCode(code) {
188
226
  return code >= 48 && code <= 57 || code >= 65 && code <= 70 || code >= 97 && code <= 102;
189
227
  }
228
+ function hasValidPercentEncoding(data) {
229
+ for (let index = 0; index < data.length; index++) {
230
+ const code = data.charCodeAt(index);
231
+ if (code === 92) {
232
+ return false;
233
+ }
234
+ if (code !== 37) {
235
+ continue;
236
+ }
237
+ if (index + 2 >= data.length || !isHexCharCode(data.charCodeAt(index + 1)) || !isHexCharCode(data.charCodeAt(index + 2))) {
238
+ return false;
239
+ }
240
+ index += 2;
241
+ }
242
+ return true;
243
+ }
190
244
  function isValidIpv6(data) {
191
245
  const length = data.length;
192
246
  if (length === 0) {
@@ -291,7 +345,7 @@ function isValidJsonPointer(data) {
291
345
  }
292
346
  function isValidRelativeJsonPointer(data) {
293
347
  if (data.length === 0) {
294
- return true;
348
+ return false;
295
349
  }
296
350
  let i = 0;
297
351
  while (i < data.length) {
@@ -304,6 +358,9 @@ function isValidRelativeJsonPointer(data) {
304
358
  if (i === 0) {
305
359
  return false;
306
360
  }
361
+ if (i > 1 && data.charCodeAt(0) === 48) {
362
+ return false;
363
+ }
307
364
  if (i === data.length) {
308
365
  return true;
309
366
  }
@@ -430,7 +487,7 @@ var Formats = {
430
487
  return true;
431
488
  },
432
489
  uri(data) {
433
- return URI_REGEX.test(data);
490
+ return URI_REGEX.test(data) && hasValidPercentEncoding(data);
434
491
  },
435
492
  email(data) {
436
493
  return EMAIL_REGEX.test(data);
@@ -445,15 +502,13 @@ var Formats = {
445
502
  return HOSTNAME_REGEX.test(data);
446
503
  },
447
504
  date(data) {
448
- const match = DATE_REGEX.exec(data);
449
- if (!match) {
505
+ if (data.length !== 10 || data.charCodeAt(4) !== 45 || data.charCodeAt(7) !== 45) {
450
506
  return false;
451
507
  }
452
- const [, yearStr, monthStr, dayStr] = match;
453
- const year = Number(yearStr);
454
- const month = Number(monthStr);
455
- const day = Number(dayStr);
456
- if (month < 1 || month > 12) {
508
+ const year = parseFourDigits(data, 0);
509
+ const month = parseTwoDigits(data, 5);
510
+ const day = parseTwoDigits(data, 8);
511
+ if (year < 0 || month < 1 || month > 12) {
457
512
  return false;
458
513
  }
459
514
  if (day < 1) {
@@ -525,10 +580,10 @@ var Types = {
525
580
  return typeof data === "string";
526
581
  },
527
582
  number(data) {
528
- return typeof data === "number";
583
+ return typeof data === "number" && Number.isFinite(data);
529
584
  },
530
585
  integer(data) {
531
- return typeof data === "number" && data % 1 === 0;
586
+ return typeof data === "number" && Number.isFinite(data) && data % 1 === 0;
532
587
  },
533
588
  boolean(data) {
534
589
  return typeof data === "boolean";
@@ -753,7 +808,7 @@ var ArrayKeywords = {
753
808
  let tupleLength = schema._tupleItemsLength;
754
809
  if (tupleLength === void 0) {
755
810
  tupleLength = schema.items.length;
756
- Object.defineProperty(schema, "_tupleItemsLength", {
811
+ definePropertyOrThrow(schema, "_tupleItemsLength", {
757
812
  value: tupleLength,
758
813
  enumerable: false,
759
814
  configurable: false,
@@ -810,13 +865,23 @@ var ArrayKeywords = {
810
865
  }
811
866
  return;
812
867
  }
813
- const primitiveSeen = /* @__PURE__ */ new Set();
868
+ let hasFirstPrimitive = false;
869
+ let firstPrimitive;
870
+ let primitiveSeen;
814
871
  let primitiveArraySignatures;
815
872
  let arrayBuckets;
816
873
  let objectBuckets;
817
874
  for (let i = 0; i < len; i++) {
818
875
  const item = data[i];
819
876
  if (isUniquePrimitive(item)) {
877
+ if (!hasFirstPrimitive) {
878
+ hasFirstPrimitive = true;
879
+ firstPrimitive = item;
880
+ continue;
881
+ }
882
+ if (!primitiveSeen) {
883
+ primitiveSeen = /* @__PURE__ */ new Set([firstPrimitive]);
884
+ }
820
885
  if (primitiveSeen.has(item)) {
821
886
  return defineError("Array items are not unique", { data: item });
822
887
  }
@@ -902,7 +967,7 @@ function isPlainObject(value) {
902
967
  if (!value || typeof value !== "object") {
903
968
  return false;
904
969
  }
905
- const proto = Object.getPrototypeOf(value);
970
+ const proto = Reflect.getPrototypeOf(value);
906
971
  return proto === Object.prototype || proto === null;
907
972
  }
908
973
  function canUseStructuredClone(value) {
@@ -997,7 +1062,7 @@ function deepCloneUnfreeze(obj, cloneClassInstances = false, seen = /* @__PURE__
997
1062
  seen.set(source, clone);
998
1063
  return clone;
999
1064
  }
1000
- clone = Object.create(Object.getPrototypeOf(source));
1065
+ clone = Object.create(Reflect.getPrototypeOf(source));
1001
1066
  seen.set(source, clone);
1002
1067
  break;
1003
1068
  }
@@ -1026,7 +1091,7 @@ function deepCloneUnfreeze(obj, cloneClassInstances = false, seen = /* @__PURE__
1026
1091
  seen
1027
1092
  );
1028
1093
  }
1029
- Object.defineProperty(clone, key, descriptor);
1094
+ definePropertyOrThrow(clone, key, descriptor);
1030
1095
  }
1031
1096
  return clone;
1032
1097
  }
@@ -1037,6 +1102,9 @@ var NumberKeywords = {
1037
1102
  if (typeof data !== "number") {
1038
1103
  return;
1039
1104
  }
1105
+ if (!Number.isFinite(data)) {
1106
+ return defineError("Value must be finite", { data });
1107
+ }
1040
1108
  let min = schema.minimum;
1041
1109
  if (typeof schema.exclusiveMinimum === "number") {
1042
1110
  min = schema.exclusiveMinimum + 1e-15;
@@ -1052,6 +1120,9 @@ var NumberKeywords = {
1052
1120
  if (typeof data !== "number") {
1053
1121
  return;
1054
1122
  }
1123
+ if (!Number.isFinite(data)) {
1124
+ return defineError("Value must be finite", { data });
1125
+ }
1055
1126
  let max = schema.maximum;
1056
1127
  if (typeof schema.exclusiveMaximum === "number") {
1057
1128
  max = schema.exclusiveMaximum - 1e-15;
@@ -1067,11 +1138,14 @@ var NumberKeywords = {
1067
1138
  if (typeof data !== "number") {
1068
1139
  return;
1069
1140
  }
1070
- const quotient = data / schema.multipleOf;
1071
- if (!isFinite(quotient)) {
1072
- return;
1141
+ if (!Number.isFinite(data) || !Number.isFinite(schema.multipleOf) || schema.multipleOf <= 0) {
1142
+ return defineError("Value must use a finite positive multipleOf", {
1143
+ data
1144
+ });
1073
1145
  }
1074
- if (!areCloseEnough(quotient, Math.round(quotient))) {
1146
+ const quotient = data / schema.multipleOf;
1147
+ const valid = Number.isFinite(quotient) ? areCloseEnough(quotient, Math.round(quotient)) : data % schema.multipleOf === 0;
1148
+ if (!valid) {
1075
1149
  return defineError("Value is not a multiple of the multipleOf", { data });
1076
1150
  }
1077
1151
  return;
@@ -1160,6 +1234,29 @@ function compilePatternMatcher(pattern) {
1160
1234
 
1161
1235
  // lib/keywords/object-keywords.ts
1162
1236
  var PATTERN_KEY_CACHE_LIMIT = 512;
1237
+ function createApplyPropertyDefaults(replaceEmpty) {
1238
+ return function applyPropertyDefaults2(schema, data, instance) {
1239
+ if (!data || typeof data !== "object" || Array.isArray(data)) {
1240
+ return;
1241
+ }
1242
+ const defaultKeys = schema._defaultKeys;
1243
+ for (let i = 0; i < defaultKeys.length; i++) {
1244
+ const key = defaultKeys[i];
1245
+ const hasOwnValue = hasOwn(data, key);
1246
+ const value = hasOwnValue ? data[key] : void 0;
1247
+ if (hasOwnValue && value !== void 0 && (!replaceEmpty || value !== null && value !== "")) {
1248
+ continue;
1249
+ }
1250
+ instance.setDefault(
1251
+ data,
1252
+ key,
1253
+ deepCloneUnfreeze(schema.properties[key].default)
1254
+ );
1255
+ }
1256
+ };
1257
+ }
1258
+ var applyPropertyDefaults = createApplyPropertyDefaults(false);
1259
+ var applyEmptyPropertyDefaults = createApplyPropertyDefaults(true);
1163
1260
  function getPatternPropertyEntries(schema) {
1164
1261
  let entries = schema._patternPropertyEntries;
1165
1262
  if (entries) {
@@ -1179,7 +1276,7 @@ function getPatternPropertyEntries(schema) {
1179
1276
  match
1180
1277
  };
1181
1278
  }
1182
- Object.defineProperty(schema, "_patternPropertyEntries", {
1279
+ definePropertyOrThrow(schema, "_patternPropertyEntries", {
1183
1280
  value: entries,
1184
1281
  enumerable: false,
1185
1282
  configurable: false,
@@ -1196,7 +1293,7 @@ function getPatternKeyMatchIndexes(schema, key, entries) {
1196
1293
  }
1197
1294
  } else {
1198
1295
  cache = /* @__PURE__ */ new Map();
1199
- Object.defineProperty(schema, "_patternKeyMatchIndexCache", {
1296
+ definePropertyOrThrow(schema, "_patternKeyMatchIndexCache", {
1200
1297
  value: cache,
1201
1298
  enumerable: false,
1202
1299
  configurable: false,
@@ -1221,7 +1318,7 @@ var ObjectKeywords = {
1221
1318
  }
1222
1319
  for (let i = 0; i < schema.required.length; i++) {
1223
1320
  const key = schema.required[i];
1224
- if (!Object.prototype.hasOwnProperty.call(data, key)) {
1321
+ if (!hasOwn(data, key)) {
1225
1322
  return defineError("Required property is missing", {
1226
1323
  item: key,
1227
1324
  data: data[key]
@@ -1230,45 +1327,15 @@ var ObjectKeywords = {
1230
1327
  }
1231
1328
  return;
1232
1329
  },
1233
- properties(schema, data, defineError) {
1330
+ properties(schema, data, defineError, instance) {
1234
1331
  if (!data || typeof data !== "object" || Array.isArray(data)) {
1235
1332
  return;
1236
1333
  }
1237
- let propKeys = schema._propKeys;
1238
- if (!propKeys) {
1239
- propKeys = Object.keys(schema.properties || {});
1240
- Object.defineProperty(schema, "_propKeys", {
1241
- value: propKeys,
1242
- enumerable: false,
1243
- configurable: false,
1244
- writable: false
1245
- });
1246
- }
1247
- let requiredSet = schema._requiredSet;
1248
- if (requiredSet === void 0) {
1249
- requiredSet = Array.isArray(schema.required) ? new Set(schema.required) : null;
1250
- Object.defineProperty(schema, "_requiredSet", {
1251
- value: requiredSet,
1252
- enumerable: false,
1253
- configurable: false,
1254
- writable: false
1255
- });
1256
- }
1334
+ const propKeys = schema._propKeys;
1257
1335
  for (let i = 0; i < propKeys.length; i++) {
1258
1336
  const key = propKeys[i];
1259
1337
  const schemaProp = schema.properties[key];
1260
- if (!Object.prototype.hasOwnProperty.call(data, key)) {
1261
- if (requiredSet && requiredSet.has(key) && schemaProp && typeof schemaProp === "object" && !Array.isArray(schemaProp) && "default" in schemaProp) {
1262
- const error = schemaProp.$validate(schemaProp.default);
1263
- if (error) {
1264
- return defineError("Default property is invalid", {
1265
- item: key,
1266
- cause: error,
1267
- data: schemaProp.default
1268
- });
1269
- }
1270
- data[key] = deepCloneUnfreeze(schemaProp.default);
1271
- }
1338
+ if (!hasOwn(data, key)) {
1272
1339
  continue;
1273
1340
  }
1274
1341
  if (typeof schemaProp === "boolean") {
@@ -1303,7 +1370,7 @@ var ObjectKeywords = {
1303
1370
  return;
1304
1371
  }
1305
1372
  for (const key in data) {
1306
- if (!Object.prototype.hasOwnProperty.call(data, key)) {
1373
+ if (!hasOwn(data, key)) {
1307
1374
  continue;
1308
1375
  }
1309
1376
  const error = validate(data[key]);
@@ -1322,7 +1389,7 @@ var ObjectKeywords = {
1322
1389
  }
1323
1390
  let count = 0;
1324
1391
  for (const key in data) {
1325
- if (!Object.prototype.hasOwnProperty.call(data, key)) {
1392
+ if (!hasOwn(data, key)) {
1326
1393
  continue;
1327
1394
  }
1328
1395
  count++;
@@ -1338,7 +1405,7 @@ var ObjectKeywords = {
1338
1405
  }
1339
1406
  let count = 0;
1340
1407
  for (const key in data) {
1341
- if (!Object.prototype.hasOwnProperty.call(data, key)) {
1408
+ if (!hasOwn(data, key)) {
1342
1409
  continue;
1343
1410
  }
1344
1411
  count++;
@@ -1355,7 +1422,7 @@ var ObjectKeywords = {
1355
1422
  let apValidate = schema._apValidate;
1356
1423
  if (apValidate === void 0) {
1357
1424
  apValidate = isCompiledSchema(schema.additionalProperties) ? schema.additionalProperties.$validate : null;
1358
- Object.defineProperty(schema, "_apValidate", {
1425
+ definePropertyOrThrow(schema, "_apValidate", {
1359
1426
  value: apValidate,
1360
1427
  enumerable: false,
1361
1428
  configurable: false,
@@ -1364,10 +1431,10 @@ var ObjectKeywords = {
1364
1431
  }
1365
1432
  const patternEntries = getPatternPropertyEntries(schema);
1366
1433
  for (const key in data) {
1367
- if (!Object.prototype.hasOwnProperty.call(data, key)) {
1434
+ if (!hasOwn(data, key)) {
1368
1435
  continue;
1369
1436
  }
1370
- if (schema.properties && Object.prototype.hasOwnProperty.call(schema.properties, key)) {
1437
+ if (schema.properties && hasOwn(schema.properties, key)) {
1371
1438
  continue;
1372
1439
  }
1373
1440
  if (patternEntries && patternEntries.length) {
@@ -1403,12 +1470,12 @@ var ObjectKeywords = {
1403
1470
  return;
1404
1471
  }
1405
1472
  for (const key in data) {
1406
- if (!Object.prototype.hasOwnProperty.call(data, key)) {
1473
+ if (!hasOwn(data, key)) {
1407
1474
  continue;
1408
1475
  }
1409
1476
  const matchingIndexes = getPatternKeyMatchIndexes(schema, key, patternEntries);
1410
1477
  if (matchingIndexes.length === 0) {
1411
- if (schema.additionalProperties === false && !(schema.properties && Object.prototype.hasOwnProperty.call(schema.properties, key))) {
1478
+ if (schema.additionalProperties === false && !(schema.properties && hasOwn(schema.properties, key))) {
1412
1479
  return defineError("Additional properties are not allowed", {
1413
1480
  item: key,
1414
1481
  data: data[key]
@@ -1449,7 +1516,7 @@ var ObjectKeywords = {
1449
1516
  if (typeof pn === "boolean") {
1450
1517
  if (pn === false) {
1451
1518
  for (const key in data) {
1452
- if (Object.prototype.hasOwnProperty.call(data, key)) {
1519
+ if (hasOwn(data, key)) {
1453
1520
  return defineError("Properties are not allowed", { data });
1454
1521
  }
1455
1522
  }
@@ -1461,7 +1528,7 @@ var ObjectKeywords = {
1461
1528
  return;
1462
1529
  }
1463
1530
  for (const key in data) {
1464
- if (!Object.prototype.hasOwnProperty.call(data, key)) {
1531
+ if (!hasOwn(data, key)) {
1465
1532
  continue;
1466
1533
  }
1467
1534
  const error = validate(key);
@@ -1560,7 +1627,7 @@ function getBranchEntries(schema, key) {
1560
1627
  for (let i = 0; i < source.length; i++) {
1561
1628
  entries.push(toBranchEntry(source[i]));
1562
1629
  }
1563
- Object.defineProperty(schema, cacheKey, {
1630
+ definePropertyOrThrow(schema, cacheKey, {
1564
1631
  value: entries,
1565
1632
  enumerable: false,
1566
1633
  configurable: false,
@@ -1568,6 +1635,147 @@ function getBranchEntries(schema, key) {
1568
1635
  });
1569
1636
  return entries;
1570
1637
  }
1638
+ function evaluateAllOf(branches, data, defineError) {
1639
+ for (let i = 0; i < branches.length; i++) {
1640
+ const branch = branches[i];
1641
+ if (branch.kind === "validate") {
1642
+ const error = branch.validate(data);
1643
+ if (error) {
1644
+ return defineError("Value is not valid", { cause: error, data });
1645
+ }
1646
+ continue;
1647
+ }
1648
+ if (branch.kind === "alwaysValid") {
1649
+ continue;
1650
+ }
1651
+ if (branch.kind === "alwaysInvalid" || data !== branch.value) {
1652
+ return defineError("Value is not valid", { data });
1653
+ }
1654
+ }
1655
+ }
1656
+ function evaluateAnyOf(branches, data, defineError) {
1657
+ for (let i = 0; i < branches.length; i++) {
1658
+ const branch = branches[i];
1659
+ if (branch.kind === "validate") {
1660
+ if (!branch.validate(data)) {
1661
+ return;
1662
+ }
1663
+ continue;
1664
+ }
1665
+ if (branch.kind === "alwaysValid") {
1666
+ return;
1667
+ }
1668
+ if (branch.kind === "literal" && data === branch.value) {
1669
+ return;
1670
+ }
1671
+ }
1672
+ return defineError("Value is not valid", { data });
1673
+ }
1674
+ function evaluateOneOf(branches, data, defineError) {
1675
+ let validCount = 0;
1676
+ let winnerIndex = -1;
1677
+ for (let i = 0; i < branches.length; i++) {
1678
+ const branch = branches[i];
1679
+ let isValid = false;
1680
+ if (branch.kind === "validate") {
1681
+ isValid = !branch.validate(data);
1682
+ } else if (branch.kind === "alwaysValid") {
1683
+ isValid = true;
1684
+ } else if (branch.kind === "literal") {
1685
+ isValid = data === branch.value;
1686
+ }
1687
+ if (isValid) {
1688
+ validCount++;
1689
+ winnerIndex = i;
1690
+ if (validCount > 1) {
1691
+ return {
1692
+ error: defineError("Value is not valid", { data }),
1693
+ winnerIndex: -1
1694
+ };
1695
+ }
1696
+ }
1697
+ }
1698
+ return {
1699
+ error: validCount === 1 ? void 0 : defineError("Value is not valid", { data }),
1700
+ winnerIndex: validCount === 1 ? winnerIndex : -1
1701
+ };
1702
+ }
1703
+ function createCombinatorValidator(key, schema, defineError, validateSubschema, transactions) {
1704
+ const sourceBranches = getBranchEntries(schema, key);
1705
+ const branches = validateSubschema ? sourceBranches.map(
1706
+ (branch, index) => branch.kind === "validate" ? {
1707
+ kind: "validate",
1708
+ validate: (data) => validateSubschema(schema[key][index], data)
1709
+ } : branch
1710
+ ) : sourceBranches;
1711
+ if (!transactions) {
1712
+ if (key === "allOf") {
1713
+ return (data) => evaluateAllOf(branches, data, defineError);
1714
+ }
1715
+ if (key === "anyOf") {
1716
+ return (data) => evaluateAnyOf(branches, data, defineError);
1717
+ }
1718
+ return (data) => evaluateOneOf(branches, data, defineError).error;
1719
+ }
1720
+ if (key === "allOf") {
1721
+ return (data) => {
1722
+ const savepoint = transactions.savepoint();
1723
+ try {
1724
+ const error = evaluateAllOf(branches, data, defineError);
1725
+ if (error) {
1726
+ transactions.rollback(savepoint);
1727
+ }
1728
+ return error;
1729
+ } catch (error) {
1730
+ transactions.rollback(savepoint);
1731
+ throw error;
1732
+ }
1733
+ };
1734
+ }
1735
+ if (key === "anyOf") {
1736
+ return (data) => evaluateAnyOf(branches, data, defineError);
1737
+ }
1738
+ return (data) => {
1739
+ const savepoint = transactions.savepoint();
1740
+ const defaultsByBranch = [];
1741
+ const isolatedBranches = branches.map(
1742
+ (branch, index) => branch.kind === "validate" ? {
1743
+ kind: "validate",
1744
+ validate: (value) => {
1745
+ const branchSavepoint = transactions.savepoint();
1746
+ const error = branch.validate(value);
1747
+ if (!error) {
1748
+ defaultsByBranch[index] = transactions.capture(branchSavepoint);
1749
+ }
1750
+ return error;
1751
+ }
1752
+ } : branch
1753
+ );
1754
+ try {
1755
+ const result = evaluateOneOf(isolatedBranches, data, defineError);
1756
+ if (result.error) {
1757
+ transactions.rollback(savepoint);
1758
+ return result.error;
1759
+ }
1760
+ transactions.restore(defaultsByBranch[result.winnerIndex] || []);
1761
+ return;
1762
+ } catch (error) {
1763
+ transactions.rollback(savepoint);
1764
+ throw error;
1765
+ }
1766
+ };
1767
+ }
1768
+ function prepareCombinatorEntries(schema) {
1769
+ if (Array.isArray(schema.allOf)) {
1770
+ getBranchEntries(schema, "allOf");
1771
+ }
1772
+ if (Array.isArray(schema.anyOf)) {
1773
+ getBranchEntries(schema, "anyOf");
1774
+ }
1775
+ if (Array.isArray(schema.oneOf)) {
1776
+ getBranchEntries(schema, "oneOf");
1777
+ }
1778
+ }
1571
1779
  var OtherKeywords = {
1572
1780
  enum(schema, data, defineError) {
1573
1781
  let enumCache = schema._enumCache;
@@ -1584,7 +1792,7 @@ var OtherKeywords = {
1584
1792
  }
1585
1793
  }
1586
1794
  enumCache = { primitiveSet, objectValues };
1587
- Object.defineProperty(schema, "_enumCache", {
1795
+ definePropertyOrThrow(schema, "_enumCache", {
1588
1796
  value: enumCache,
1589
1797
  enumerable: false,
1590
1798
  configurable: false,
@@ -1604,137 +1812,13 @@ var OtherKeywords = {
1604
1812
  return defineError("Value is not one of the allowed values", { data });
1605
1813
  },
1606
1814
  allOf(schema, data, defineError) {
1607
- const branches = getBranchEntries(schema, "allOf");
1608
- if (branches.length === 1) {
1609
- const onlyBranch = branches[0];
1610
- if (onlyBranch.kind === "validate") {
1611
- const error = onlyBranch.validate(data);
1612
- if (error) {
1613
- return defineError("Value is not valid", { cause: error, data });
1614
- }
1615
- return;
1616
- }
1617
- if (onlyBranch.kind === "alwaysValid") {
1618
- return;
1619
- }
1620
- if (onlyBranch.kind === "alwaysInvalid") {
1621
- return defineError("Value is not valid", { data });
1622
- }
1623
- if (data !== onlyBranch.value) {
1624
- return defineError("Value is not valid", { data });
1625
- }
1626
- return;
1627
- }
1628
- for (let i = 0; i < branches.length; i++) {
1629
- const branch = branches[i];
1630
- if (branch.kind === "validate") {
1631
- const error = branch.validate(data);
1632
- if (error) {
1633
- return defineError("Value is not valid", { cause: error, data });
1634
- }
1635
- continue;
1636
- }
1637
- if (branch.kind === "alwaysValid") {
1638
- continue;
1639
- }
1640
- if (branch.kind === "alwaysInvalid") {
1641
- return defineError("Value is not valid", { data });
1642
- }
1643
- if (data !== branch.value) {
1644
- return defineError("Value is not valid", { data });
1645
- }
1646
- }
1647
- return;
1815
+ return createCombinatorValidator("allOf", schema, defineError)(data);
1648
1816
  },
1649
1817
  anyOf(schema, data, defineError) {
1650
- const branches = getBranchEntries(schema, "anyOf");
1651
- if (branches.length === 1) {
1652
- const onlyBranch = branches[0];
1653
- if (onlyBranch.kind === "validate") {
1654
- const error = onlyBranch.validate(data);
1655
- if (!error) {
1656
- return;
1657
- }
1658
- return defineError("Value is not valid", { data });
1659
- }
1660
- if (onlyBranch.kind === "alwaysValid") {
1661
- return;
1662
- }
1663
- if (onlyBranch.kind === "alwaysInvalid") {
1664
- return defineError("Value is not valid", { data });
1665
- }
1666
- if (data === onlyBranch.value) {
1667
- return;
1668
- }
1669
- return defineError("Value is not valid", { data });
1670
- }
1671
- for (let i = 0; i < branches.length; i++) {
1672
- const branch = branches[i];
1673
- if (branch.kind === "validate") {
1674
- const error = branch.validate(data);
1675
- if (!error) {
1676
- return;
1677
- }
1678
- continue;
1679
- }
1680
- if (branch.kind === "alwaysValid") {
1681
- return;
1682
- }
1683
- if (branch.kind === "alwaysInvalid") {
1684
- continue;
1685
- }
1686
- if (data === branch.value) {
1687
- return;
1688
- }
1689
- }
1690
- return defineError("Value is not valid", { data });
1818
+ return createCombinatorValidator("anyOf", schema, defineError)(data);
1691
1819
  },
1692
1820
  oneOf(schema, data, defineError) {
1693
- const branches = getBranchEntries(schema, "oneOf");
1694
- if (branches.length === 1) {
1695
- const onlyBranch = branches[0];
1696
- if (onlyBranch.kind === "validate") {
1697
- const error = onlyBranch.validate(data);
1698
- if (!error) {
1699
- return;
1700
- }
1701
- return defineError("Value is not valid", { data });
1702
- }
1703
- if (onlyBranch.kind === "alwaysValid") {
1704
- return;
1705
- }
1706
- if (onlyBranch.kind === "alwaysInvalid") {
1707
- return defineError("Value is not valid", { data });
1708
- }
1709
- if (data === onlyBranch.value) {
1710
- return;
1711
- }
1712
- return defineError("Value is not valid", { data });
1713
- }
1714
- let validCount = 0;
1715
- for (let i = 0; i < branches.length; i++) {
1716
- const branch = branches[i];
1717
- let isValid = false;
1718
- if (branch.kind === "validate") {
1719
- isValid = !branch.validate(data);
1720
- } else if (branch.kind === "alwaysValid") {
1721
- isValid = true;
1722
- } else if (branch.kind === "alwaysInvalid") {
1723
- isValid = false;
1724
- } else {
1725
- isValid = data === branch.value;
1726
- }
1727
- if (isValid) {
1728
- validCount++;
1729
- if (validCount > 1) {
1730
- return defineError("Value is not valid", { data });
1731
- }
1732
- }
1733
- }
1734
- if (validCount === 1) {
1735
- return;
1736
- }
1737
- return defineError("Value is not valid", { data });
1821
+ return createCombinatorValidator("oneOf", schema, defineError)(data);
1738
1822
  },
1739
1823
  const(schema, data, defineError) {
1740
1824
  if (data === schema.const) {
@@ -1794,45 +1878,62 @@ var OtherKeywords = {
1794
1878
  }
1795
1879
  return defineError("Value is not valid", { data });
1796
1880
  },
1797
- $ref(schema, data, defineError, instance) {
1798
- if (schema._resolvedRef) {
1799
- if (schema.$validate !== schema._resolvedRef) {
1800
- schema.$validate = schema._resolvedRef;
1801
- }
1881
+ $ref(schema, data, defineError) {
1882
+ if (typeof schema._resolvedRef === "function") {
1802
1883
  return schema._resolvedRef(data);
1803
1884
  }
1804
- const refPath = schema.$ref;
1805
- let targetSchema = instance.getSchemaRef(refPath);
1806
- if (!targetSchema) {
1807
- targetSchema = instance.getSchemaById(refPath);
1808
- }
1809
- if (!targetSchema) {
1810
- return defineError(`Missing reference: ${refPath}`);
1811
- }
1812
- if (!targetSchema.$validate) {
1813
- return;
1814
- }
1815
- schema._resolvedRef = targetSchema.$validate;
1816
- schema.$validate = schema._resolvedRef;
1817
- return schema._resolvedRef(data);
1885
+ return defineError(`Missing reference: ${schema.$ref}`);
1818
1886
  }
1819
1887
  };
1820
1888
 
1821
1889
  // lib/keywords/string-keywords.ts
1822
1890
  var PATTERN_MATCH_CACHE_LIMIT = 512;
1823
1891
  var FORMAT_RESULT_CACHE_LIMIT = 512;
1892
+ function hasAtLeastCodePoints(value, limit) {
1893
+ let count = 0;
1894
+ for (let index = 0; index < value.length; index++) {
1895
+ const unit = value.charCodeAt(index);
1896
+ if (unit >= 55296 && unit <= 56319 && index + 1 < value.length) {
1897
+ const nextUnit = value.charCodeAt(index + 1);
1898
+ if (nextUnit >= 56320 && nextUnit <= 57343) {
1899
+ index++;
1900
+ }
1901
+ }
1902
+ count++;
1903
+ if (count >= limit) {
1904
+ return true;
1905
+ }
1906
+ }
1907
+ return count >= limit;
1908
+ }
1824
1909
  var StringKeywords = {
1825
1910
  minLength(schema, data, defineError) {
1826
- if (typeof data !== "string" || data.length >= schema.minLength) {
1911
+ if (typeof data !== "string") {
1912
+ return;
1913
+ }
1914
+ const units = data.length;
1915
+ const limit = schema.minLength;
1916
+ if (units < limit) {
1917
+ return defineError("Value is shorter than the minimum length", { data });
1918
+ }
1919
+ if (units - limit >= limit || hasAtLeastCodePoints(data, limit)) {
1827
1920
  return;
1828
1921
  }
1829
1922
  return defineError("Value is shorter than the minimum length", { data });
1830
1923
  },
1831
1924
  maxLength(schema, data, defineError) {
1832
- if (typeof data !== "string" || data.length <= schema.maxLength) {
1925
+ if (typeof data !== "string") {
1926
+ return;
1927
+ }
1928
+ const units = data.length;
1929
+ const limit = schema.maxLength;
1930
+ if (units <= limit) {
1833
1931
  return;
1834
1932
  }
1835
- return defineError("Value is longer than the maximum length", { data });
1933
+ if (units - limit > limit || hasAtLeastCodePoints(data, limit + 1)) {
1934
+ return defineError("Value is longer than the maximum length", { data });
1935
+ }
1936
+ return;
1836
1937
  },
1837
1938
  pattern(schema, data, defineError) {
1838
1939
  if (typeof data !== "string") {
@@ -1844,7 +1945,7 @@ var StringKeywords = {
1844
1945
  try {
1845
1946
  const compiled = compilePatternMatcher(schema.pattern);
1846
1947
  patternMatch = compiled instanceof RegExp ? (value) => compiled.test(value) : compiled;
1847
- Object.defineProperty(schema, "_patternMatch", {
1948
+ definePropertyOrThrow(schema, "_patternMatch", {
1848
1949
  value: patternMatch,
1849
1950
  enumerable: false,
1850
1951
  configurable: false,
@@ -1859,7 +1960,7 @@ var StringKeywords = {
1859
1960
  }
1860
1961
  if (!patternMatchCache) {
1861
1962
  patternMatchCache = /* @__PURE__ */ new Map();
1862
- Object.defineProperty(schema, "_patternMatchCache", {
1963
+ definePropertyOrThrow(schema, "_patternMatchCache", {
1863
1964
  value: patternMatchCache,
1864
1965
  enumerable: false,
1865
1966
  configurable: false,
@@ -1891,7 +1992,7 @@ var StringKeywords = {
1891
1992
  let formatResultCache = schema._formatResultCache;
1892
1993
  if (formatValidate === void 0) {
1893
1994
  formatValidate = instance.getFormat(schema.format);
1894
- Object.defineProperty(schema, "_formatValidate", {
1995
+ definePropertyOrThrow(schema, "_formatValidate", {
1895
1996
  value: formatValidate,
1896
1997
  enumerable: false,
1897
1998
  configurable: false,
@@ -1906,7 +2007,7 @@ var StringKeywords = {
1906
2007
  schema.format,
1907
2008
  formatValidate
1908
2009
  );
1909
- Object.defineProperty(schema, "_formatResultCacheEnabled", {
2010
+ definePropertyOrThrow(schema, "_formatResultCacheEnabled", {
1910
2011
  value: formatResultCacheEnabled,
1911
2012
  enumerable: false,
1912
2013
  configurable: false,
@@ -1921,7 +2022,7 @@ var StringKeywords = {
1921
2022
  }
1922
2023
  if (!formatResultCache) {
1923
2024
  formatResultCache = /* @__PURE__ */ new Map();
1924
- Object.defineProperty(schema, "_formatResultCache", {
2025
+ definePropertyOrThrow(schema, "_formatResultCache", {
1925
2026
  value: formatResultCache,
1926
2027
  enumerable: false,
1927
2028
  configurable: false,
@@ -1954,20 +2055,61 @@ var keywords = {
1954
2055
  };
1955
2056
 
1956
2057
  // lib/index.ts
2058
+ var MAX_COMPILE_DEPTH = 128;
2059
+ var LOCAL_SCHEMA_BASE = "schema-shield://local/root";
2060
+ var FAIL_FAST_TYPE_VALIDATORS = {
2061
+ object: (data) => data !== null && typeof data === "object" && !Array.isArray(data) ? void 0 : true,
2062
+ array: (data) => Array.isArray(data) ? void 0 : true,
2063
+ string: (data) => typeof data === "string" ? void 0 : true,
2064
+ number: (data) => typeof data === "number" && Number.isFinite(data) ? void 0 : true,
2065
+ integer: (data) => typeof data === "number" && Number.isFinite(data) && Number.isInteger(data) ? void 0 : true,
2066
+ boolean: (data) => typeof data === "boolean" ? void 0 : true,
2067
+ null: (data) => data === null ? void 0 : true
2068
+ };
2069
+ function createBuiltinTypeValidator(_type, defineError, fallback) {
2070
+ return (data) => {
2071
+ if (!fallback(data)) {
2072
+ return defineError("Invalid type", { data });
2073
+ }
2074
+ };
2075
+ }
1957
2076
  var SchemaShield = class {
1958
2077
  types = {};
1959
2078
  formats = {};
1960
2079
  keywords = {};
1961
2080
  immutable = false;
2081
+ useDefaults = false;
1962
2082
  rootSchema = null;
1963
- idRegistry = /* @__PURE__ */ new Map();
1964
2083
  failFast = true;
2084
+ maxDepth;
2085
+ validationContexts = [];
2086
+ compileCache = /* @__PURE__ */ new WeakMap();
2087
+ compilingRequiresContext = false;
2088
+ compilingMutableSchemas = /* @__PURE__ */ new WeakSet();
1965
2089
  constructor({
1966
2090
  immutable = false,
1967
- failFast = true
2091
+ failFast = true,
2092
+ maxDepth = 128,
2093
+ useDefaults = false
1968
2094
  } = {}) {
2095
+ if (!Number.isInteger(maxDepth) || maxDepth < 1 || maxDepth > 256) {
2096
+ const error = new ValidationError("maxDepth must be an integer from 1 to 256");
2097
+ error.code = "INVALID_MAX_DEPTH";
2098
+ error.keyword = "maxDepth";
2099
+ throw error;
2100
+ }
2101
+ if (useDefaults !== false && useDefaults !== true && useDefaults !== "empty") {
2102
+ const error = new ValidationError(
2103
+ 'useDefaults must be false, true, or "empty"'
2104
+ );
2105
+ error.code = "INVALID_USE_DEFAULTS";
2106
+ error.keyword = "useDefaults";
2107
+ throw error;
2108
+ }
1969
2109
  this.immutable = immutable;
1970
2110
  this.failFast = failFast;
2111
+ this.maxDepth = maxDepth;
2112
+ this.useDefaults = useDefaults;
1971
2113
  for (const [type, validator] of Object.entries(Types)) {
1972
2114
  if (validator) {
1973
2115
  this.addType(type, validator);
@@ -1982,6 +2124,50 @@ var SchemaShield = class {
1982
2124
  }
1983
2125
  }
1984
2126
  }
2127
+ setDefault(target, key, value) {
2128
+ const context = this.validationContexts[this.validationContexts.length - 1];
2129
+ if (context) {
2130
+ context.defaults.push({
2131
+ target,
2132
+ key,
2133
+ descriptor: Reflect.getOwnPropertyDescriptor(target, key)
2134
+ });
2135
+ }
2136
+ definePropertyOrThrow(target, key, {
2137
+ value,
2138
+ enumerable: true,
2139
+ configurable: true,
2140
+ writable: true
2141
+ });
2142
+ }
2143
+ #defaultSavepoint() {
2144
+ const context = this.validationContexts[this.validationContexts.length - 1];
2145
+ return context ? context.defaults.length : 0;
2146
+ }
2147
+ #rollbackDefaultSavepoint(savepoint) {
2148
+ const context = this.validationContexts[this.validationContexts.length - 1];
2149
+ if (context) {
2150
+ this.rollbackDefaults(context, savepoint);
2151
+ }
2152
+ }
2153
+ #captureDefaultSavepoint(savepoint) {
2154
+ const context = this.validationContexts[this.validationContexts.length - 1];
2155
+ if (!context || context.defaults.length === savepoint) {
2156
+ return [];
2157
+ }
2158
+ const mutations = context.defaults.slice(savepoint).map((entry) => ({
2159
+ ...entry,
2160
+ value: entry.target[entry.key]
2161
+ }));
2162
+ this.rollbackDefaults(context, savepoint);
2163
+ return mutations;
2164
+ }
2165
+ #restoreDefaults(mutations) {
2166
+ for (let index = 0; index < mutations.length; index++) {
2167
+ const mutation = mutations[index];
2168
+ this.setDefault(mutation.target, mutation.key, mutation.value);
2169
+ }
2170
+ }
1985
2171
  addType(name, validator, overwrite = false) {
1986
2172
  if (this.types[name] && !overwrite) {
1987
2173
  throw new ValidationError(`Type "${name}" already exists`);
@@ -2019,14 +2205,465 @@ var SchemaShield = class {
2019
2205
  return resolvePath(this.rootSchema, path);
2020
2206
  }
2021
2207
  getSchemaById(id) {
2022
- return this.idRegistry.get(id);
2208
+ if (!this.rootSchema) {
2209
+ return;
2210
+ }
2211
+ const stack = [this.rootSchema];
2212
+ const seen = /* @__PURE__ */ new WeakSet();
2213
+ while (stack.length > 0) {
2214
+ const node = stack.pop();
2215
+ if (seen.has(node)) {
2216
+ continue;
2217
+ }
2218
+ seen.add(node);
2219
+ if (node.$id === id) {
2220
+ return node;
2221
+ }
2222
+ const children = this.schemaChildren(node);
2223
+ for (let index = 0; index < children.length; index++) {
2224
+ stack.push(children[index]);
2225
+ }
2226
+ }
2227
+ return;
2228
+ }
2229
+ depthError(message = "Maximum schema depth exceeded") {
2230
+ if (this.failFast) {
2231
+ return true;
2232
+ }
2233
+ const error = new ValidationError(message);
2234
+ error.code = "MAX_DEPTH_EXCEEDED";
2235
+ error.keyword = "maxDepth";
2236
+ return error;
2237
+ }
2238
+ schemaChildEntries(schema) {
2239
+ const children = [];
2240
+ const mapKeys = [
2241
+ "properties",
2242
+ "patternProperties",
2243
+ "definitions",
2244
+ "$defs",
2245
+ "dependencies"
2246
+ ];
2247
+ const arrayKeys = ["allOf", "anyOf", "oneOf", "items"];
2248
+ const singleKeys = [
2249
+ "items",
2250
+ "additionalItems",
2251
+ "additionalProperties",
2252
+ "contains",
2253
+ "propertyNames",
2254
+ "values",
2255
+ "elements",
2256
+ "not",
2257
+ "if",
2258
+ "then",
2259
+ "else"
2260
+ ];
2261
+ for (const key of mapKeys) {
2262
+ const value = schema[key];
2263
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
2264
+ continue;
2265
+ }
2266
+ for (const childKey of Object.keys(value)) {
2267
+ const child = value[childKey];
2268
+ if (child && typeof child === "object") {
2269
+ children.push({
2270
+ value: child,
2271
+ pointer: `/${this.escapePointerToken(key)}/${this.escapePointerToken(
2272
+ childKey
2273
+ )}`
2274
+ });
2275
+ }
2276
+ }
2277
+ }
2278
+ for (const key of arrayKeys) {
2279
+ const value = schema[key];
2280
+ if (!Array.isArray(value)) {
2281
+ continue;
2282
+ }
2283
+ for (let index = 0; index < value.length; index++) {
2284
+ const child = value[index];
2285
+ if (child && typeof child === "object") {
2286
+ children.push({
2287
+ value: child,
2288
+ pointer: `/${this.escapePointerToken(key)}/${index}`
2289
+ });
2290
+ }
2291
+ }
2292
+ }
2293
+ for (const key of singleKeys) {
2294
+ const value = schema[key];
2295
+ if (value && typeof value === "object" && !Array.isArray(value)) {
2296
+ children.push({
2297
+ value,
2298
+ pointer: `/${this.escapePointerToken(key)}`
2299
+ });
2300
+ }
2301
+ }
2302
+ for (const key of Object.keys(schema)) {
2303
+ if (key === "enum" || key === "const" || key === "default" || key === "examples" || mapKeys.includes(key) || arrayKeys.includes(key) || singleKeys.includes(key)) {
2304
+ continue;
2305
+ }
2306
+ const keyword = this.getKeyword(key);
2307
+ const value = schema[key];
2308
+ if (keyword && keyword !== keywords[key] && value && typeof value === "object") {
2309
+ children.push({
2310
+ value,
2311
+ pointer: `/${this.escapePointerToken(key)}`
2312
+ });
2313
+ }
2314
+ }
2315
+ return children;
2316
+ }
2317
+ schemaChildren(schema) {
2318
+ return this.schemaChildEntries(schema).map((entry) => entry.value);
2319
+ }
2320
+ registrySubschemaEntries(schema) {
2321
+ const children = [];
2322
+ const mapKeys = ["properties", "patternProperties", "definitions"];
2323
+ const arrayKeys = ["allOf", "anyOf", "oneOf", "items"];
2324
+ const singleKeys = [
2325
+ "items",
2326
+ "additionalItems",
2327
+ "additionalProperties",
2328
+ "contains",
2329
+ "propertyNames",
2330
+ "not",
2331
+ "if",
2332
+ "then",
2333
+ "else"
2334
+ ];
2335
+ for (const key of mapKeys) {
2336
+ const value = schema[key];
2337
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
2338
+ continue;
2339
+ }
2340
+ for (const childKey of Object.keys(value)) {
2341
+ const child = value[childKey];
2342
+ if (child && typeof child === "object" && !Array.isArray(child)) {
2343
+ children.push({
2344
+ value: child,
2345
+ pointer: `/${this.escapePointerToken(key)}/${this.escapePointerToken(
2346
+ childKey
2347
+ )}`
2348
+ });
2349
+ }
2350
+ }
2351
+ }
2352
+ const dependencies = schema.dependencies;
2353
+ if (dependencies && typeof dependencies === "object" && !Array.isArray(dependencies)) {
2354
+ for (const dependencyKey of Object.keys(dependencies)) {
2355
+ const child = dependencies[dependencyKey];
2356
+ if (child && typeof child === "object" && !Array.isArray(child)) {
2357
+ children.push({
2358
+ value: child,
2359
+ pointer: `/dependencies/${this.escapePointerToken(dependencyKey)}`
2360
+ });
2361
+ }
2362
+ }
2363
+ }
2364
+ for (const key of arrayKeys) {
2365
+ const value = schema[key];
2366
+ if (!Array.isArray(value)) {
2367
+ continue;
2368
+ }
2369
+ for (let index = 0; index < value.length; index++) {
2370
+ const child = value[index];
2371
+ if (child && typeof child === "object" && !Array.isArray(child)) {
2372
+ children.push({
2373
+ value: child,
2374
+ pointer: `/${this.escapePointerToken(key)}/${index}`
2375
+ });
2376
+ }
2377
+ }
2378
+ }
2379
+ for (const key of singleKeys) {
2380
+ const value = schema[key];
2381
+ if (value && typeof value === "object" && !Array.isArray(value)) {
2382
+ children.push({
2383
+ value,
2384
+ pointer: `/${this.escapePointerToken(key)}`
2385
+ });
2386
+ }
2387
+ }
2388
+ return children;
2389
+ }
2390
+ escapePointerToken(value) {
2391
+ return value.replace(/~/g, "~0").replace(/\//g, "~1");
2392
+ }
2393
+ resolveUri(reference, baseUri, keyword) {
2394
+ try {
2395
+ return new URL(reference, baseUri).href;
2396
+ } catch {
2397
+ const error = new ValidationError(`Invalid ${keyword} URI: ${reference}`);
2398
+ error.code = keyword === "$id" ? "INVALID_SCHEMA_ID" : "REFERENCE_NOT_FOUND";
2399
+ error.keyword = keyword;
2400
+ throw error;
2401
+ }
2402
+ }
2403
+ resourceUri(uri) {
2404
+ const hashIndex = uri.indexOf("#");
2405
+ return hashIndex === -1 ? uri : uri.slice(0, hashIndex);
2406
+ }
2407
+ buildReferenceRegistry(schema) {
2408
+ const aliases = /* @__PURE__ */ new Map();
2409
+ const positions = [];
2410
+ const positionsByNode = /* @__PURE__ */ new WeakMap();
2411
+ if (!schema || typeof schema !== "object" || Array.isArray(schema)) {
2412
+ return Object.freeze({
2413
+ aliases,
2414
+ positions: Object.freeze(positions),
2415
+ positionsByNode
2416
+ });
2417
+ }
2418
+ const register = (uri, node) => {
2419
+ const existing = aliases.get(uri);
2420
+ if (existing && existing !== node) {
2421
+ const error = new ValidationError(`Duplicate schema identity: ${uri}`);
2422
+ error.code = "DUPLICATE_SCHEMA_ID";
2423
+ error.keyword = "$id";
2424
+ throw error;
2425
+ }
2426
+ aliases.set(uri, node);
2427
+ };
2428
+ register(LOCAL_SCHEMA_BASE, schema);
2429
+ const visited = /* @__PURE__ */ new WeakSet();
2430
+ const stack = [
2431
+ {
2432
+ node: schema,
2433
+ inheritedBase: LOCAL_SCHEMA_BASE,
2434
+ resourceRoot: schema,
2435
+ pointer: "#"
2436
+ }
2437
+ ];
2438
+ while (stack.length > 0) {
2439
+ const entry = stack.pop();
2440
+ if (visited.has(entry.node)) {
2441
+ continue;
2442
+ }
2443
+ visited.add(entry.node);
2444
+ let baseUri = entry.inheritedBase;
2445
+ let resourceRoot = entry.resourceRoot;
2446
+ if (typeof entry.node.$id === "string" && !("$ref" in entry.node)) {
2447
+ baseUri = this.resolveUri(entry.node.$id, entry.inheritedBase, "$id");
2448
+ register(baseUri, entry.node);
2449
+ if (baseUri.indexOf("#") === -1 || baseUri.endsWith("#")) {
2450
+ resourceRoot = entry.node;
2451
+ register(this.resourceUri(baseUri), entry.node);
2452
+ }
2453
+ }
2454
+ const position = {
2455
+ source: entry.node,
2456
+ baseUri,
2457
+ resourceRoot,
2458
+ pointer: entry.pointer
2459
+ };
2460
+ positions.push(position);
2461
+ positionsByNode.set(entry.node, position);
2462
+ const children = this.registrySubschemaEntries(entry.node);
2463
+ for (let index = children.length - 1; index >= 0; index--) {
2464
+ const child = children[index];
2465
+ if (Array.isArray(child.value)) {
2466
+ continue;
2467
+ }
2468
+ stack.push({
2469
+ node: child.value,
2470
+ inheritedBase: baseUri,
2471
+ resourceRoot,
2472
+ pointer: `${entry.pointer}${child.pointer}`
2473
+ });
2474
+ }
2475
+ }
2476
+ return Object.freeze({
2477
+ aliases,
2478
+ positions: Object.freeze(positions),
2479
+ positionsByNode
2480
+ });
2481
+ }
2482
+ resolveReferenceSource(ref, position, registry) {
2483
+ const resolvedUri = this.resolveUri(ref, position.baseUri, "$ref");
2484
+ const exactTarget = registry.aliases.get(resolvedUri);
2485
+ if (exactTarget) {
2486
+ return exactTarget;
2487
+ }
2488
+ const resourceRoot = registry.aliases.get(this.resourceUri(resolvedUri));
2489
+ if (!resourceRoot) {
2490
+ return;
2491
+ }
2492
+ const hashIndex = resolvedUri.indexOf("#");
2493
+ const fragment = hashIndex === -1 ? "" : resolvedUri.slice(hashIndex + 1);
2494
+ if (fragment.length === 0) {
2495
+ return resourceRoot;
2496
+ }
2497
+ if (fragment.startsWith("/")) {
2498
+ return resolvePath(resourceRoot, `#${fragment}`);
2499
+ }
2500
+ return;
2501
+ }
2502
+ analyzeSchema(schema, registry) {
2503
+ if (!schema || typeof schema !== "object") {
2504
+ return {
2505
+ requiresDepthGuard: false,
2506
+ requiresMutationJournal: false,
2507
+ mutableSchemas: /* @__PURE__ */ new WeakSet()
2508
+ };
2509
+ }
2510
+ const visiting = /* @__PURE__ */ new WeakSet();
2511
+ const visited = /* @__PURE__ */ new WeakSet();
2512
+ const stack = [{ value: schema, depth: 0, exit: false }];
2513
+ let requiresDepthGuard = false;
2514
+ let requiresMutationJournal = false;
2515
+ while (stack.length > 0) {
2516
+ const entry = stack.pop();
2517
+ if (entry.exit) {
2518
+ visiting.delete(entry.value);
2519
+ visited.add(entry.value);
2520
+ continue;
2521
+ }
2522
+ if (visited.has(entry.value)) {
2523
+ continue;
2524
+ }
2525
+ if (visiting.has(entry.value)) {
2526
+ const error = new ValidationError("Cyclic schema graph is not supported");
2527
+ error.code = "CYCLIC_SCHEMA_GRAPH";
2528
+ error.keyword = "compile";
2529
+ throw error;
2530
+ }
2531
+ if (entry.depth > MAX_COMPILE_DEPTH) {
2532
+ const error = new ValidationError("Maximum compile depth exceeded");
2533
+ error.code = "MAX_COMPILE_DEPTH_EXCEEDED";
2534
+ error.keyword = "compile";
2535
+ throw error;
2536
+ }
2537
+ if (entry.depth > this.maxDepth) {
2538
+ requiresDepthGuard = true;
2539
+ }
2540
+ visiting.add(entry.value);
2541
+ stack.push({ ...entry, exit: true });
2542
+ if (this.useDefaults !== false && this.hasPropertyDefaults(entry.value)) {
2543
+ requiresMutationJournal = true;
2544
+ }
2545
+ for (const key of Object.keys(entry.value)) {
2546
+ const keyword = this.getKeyword(key);
2547
+ if (keyword && keyword !== keywords[key]) {
2548
+ requiresDepthGuard = true;
2549
+ requiresMutationJournal = true;
2550
+ }
2551
+ }
2552
+ const children = this.schemaChildren(entry.value);
2553
+ for (let index = children.length - 1; index >= 0; index--) {
2554
+ stack.push({
2555
+ value: children[index],
2556
+ depth: entry.depth + 1,
2557
+ exit: false
2558
+ });
2559
+ }
2560
+ }
2561
+ const semanticState = /* @__PURE__ */ new WeakMap();
2562
+ const semanticStack = [{ value: schema, exit: false }];
2563
+ while (semanticStack.length > 0 && !requiresDepthGuard) {
2564
+ const entry = semanticStack.pop();
2565
+ if (entry.exit) {
2566
+ semanticState.set(entry.value, 2);
2567
+ continue;
2568
+ }
2569
+ const state = semanticState.get(entry.value);
2570
+ if (state === 1) {
2571
+ requiresDepthGuard = true;
2572
+ break;
2573
+ }
2574
+ if (state === 2) {
2575
+ continue;
2576
+ }
2577
+ semanticState.set(entry.value, 1);
2578
+ semanticStack.push({ value: entry.value, exit: true });
2579
+ const children = this.schemaChildren(entry.value);
2580
+ if (typeof entry.value.$ref === "string" && this.getKeyword("$ref") === keywords.$ref) {
2581
+ const position = registry.positionsByNode.get(entry.value);
2582
+ const target = position ? this.resolveReferenceSource(entry.value.$ref, position, registry) : void 0;
2583
+ if (target && typeof target === "object") {
2584
+ children.push(target);
2585
+ }
2586
+ }
2587
+ for (let index = children.length - 1; index >= 0; index--) {
2588
+ semanticStack.push({
2589
+ value: children[index],
2590
+ exit: false
2591
+ });
2592
+ }
2593
+ }
2594
+ const mutableSchemas = /* @__PURE__ */ new WeakSet();
2595
+ if (requiresMutationJournal) {
2596
+ const mutationStack = [{ value: schema, exit: false }];
2597
+ const mutationVisited = /* @__PURE__ */ new WeakSet();
2598
+ while (mutationStack.length > 0) {
2599
+ const entry = mutationStack.pop();
2600
+ if (entry.exit) {
2601
+ const children2 = this.schemaChildren(entry.value);
2602
+ const hasCustomKeyword = Object.keys(entry.value).some((key) => {
2603
+ const keyword = this.getKeyword(key);
2604
+ return !!keyword && keyword !== keywords[key];
2605
+ });
2606
+ if (this.useDefaults !== false && this.hasPropertyDefaults(entry.value) || hasCustomKeyword || typeof entry.value.$ref === "string" || children2.some((child) => mutableSchemas.has(child))) {
2607
+ mutableSchemas.add(entry.value);
2608
+ }
2609
+ continue;
2610
+ }
2611
+ if (mutationVisited.has(entry.value)) {
2612
+ continue;
2613
+ }
2614
+ mutationVisited.add(entry.value);
2615
+ mutationStack.push({ value: entry.value, exit: true });
2616
+ const children = this.schemaChildren(entry.value);
2617
+ for (let index = children.length - 1; index >= 0; index--) {
2618
+ mutationStack.push({
2619
+ value: children[index],
2620
+ exit: false
2621
+ });
2622
+ }
2623
+ }
2624
+ }
2625
+ return { requiresDepthGuard, requiresMutationJournal, mutableSchemas };
2023
2626
  }
2024
2627
  compile(schema) {
2025
- this.idRegistry.clear();
2628
+ const prepared = this.prepareSchema(schema);
2629
+ const compiledSchema = prepared.compiledSchema;
2630
+ if (!prepared.requiresDepthGuard && !prepared.requiresMutationJournal) {
2631
+ const directValidate = compiledSchema.$validate;
2632
+ const validate = this.immutable ? (data) => {
2633
+ const clonedData = deepCloneUnfreeze(data);
2634
+ const error = directValidate(clonedData);
2635
+ return error ? { data: clonedData, error, valid: false } : { data: clonedData, error: null, valid: true };
2636
+ } : (data) => {
2637
+ const error = directValidate(data);
2638
+ return error ? { data, error, valid: false } : { data, error: null, valid: true };
2639
+ };
2640
+ validate.compiledSchema = compiledSchema;
2641
+ return validate;
2642
+ }
2643
+ return this.createGuardedValidator(compiledSchema, prepared.depthGuardState);
2644
+ }
2645
+ prepareSchema(schema) {
2646
+ const referenceRegistry = this.buildReferenceRegistry(schema);
2647
+ const analysis = this.analyzeSchema(schema, referenceRegistry);
2648
+ this.compileCache = /* @__PURE__ */ new WeakMap();
2649
+ this.compilingRequiresContext = analysis.requiresDepthGuard || analysis.requiresMutationJournal;
2650
+ this.compilingMutableSchemas = analysis.mutableSchemas;
2026
2651
  const compiledSchema = this.compileSchema(schema);
2027
2652
  this.rootSchema = compiledSchema;
2653
+ let depthGuardState = null;
2654
+ if (analysis.requiresDepthGuard) {
2655
+ depthGuardState = this.installDepthGuards(compiledSchema);
2656
+ definePropertyOrThrow(compiledSchema, "_requiresDepthGuard", {
2657
+ value: true,
2658
+ enumerable: false,
2659
+ configurable: false,
2660
+ writable: false
2661
+ });
2662
+ } else if (analysis.requiresMutationJournal) {
2663
+ depthGuardState = { context: null };
2664
+ }
2028
2665
  if (compiledSchema._hasRef === true) {
2029
- this.linkReferences(compiledSchema);
2666
+ this.linkReferences(referenceRegistry);
2030
2667
  }
2031
2668
  if (!compiledSchema.$validate) {
2032
2669
  if (schema === false) {
@@ -2055,14 +2692,53 @@ var SchemaShield = class {
2055
2692
  );
2056
2693
  }
2057
2694
  }
2695
+ return {
2696
+ compiledSchema,
2697
+ requiresDepthGuard: analysis.requiresDepthGuard,
2698
+ requiresMutationJournal: analysis.requiresMutationJournal,
2699
+ depthGuardState
2700
+ };
2701
+ }
2702
+ createGuardedValidator(compiledSchema, depthGuardState) {
2703
+ const reusableContext = {
2704
+ active: false,
2705
+ depth: -1,
2706
+ depthExceeded: false,
2707
+ defaults: []
2708
+ };
2058
2709
  const validate = (data) => {
2059
2710
  this.rootSchema = compiledSchema;
2060
- const clonedData = this.immutable ? deepCloneUnfreeze(data) : data;
2061
- const res = compiledSchema.$validate(clonedData);
2062
- if (res) {
2063
- return { data: clonedData, error: res, valid: false };
2711
+ const context = reusableContext.active ? {
2712
+ active: false,
2713
+ depth: -1,
2714
+ depthExceeded: false,
2715
+ defaults: []
2716
+ } : reusableContext;
2717
+ context.active = true;
2718
+ context.depth = -1;
2719
+ context.depthExceeded = false;
2720
+ delete context.depthError;
2721
+ context.defaults.length = 0;
2722
+ this.validationContexts.push(context);
2723
+ const priorContext = depthGuardState.context;
2724
+ depthGuardState.context = context;
2725
+ let clonedData = data;
2726
+ try {
2727
+ clonedData = this.immutable ? deepCloneUnfreeze(data) : data;
2728
+ let error = compiledSchema.$validate(clonedData);
2729
+ if (this.isDepthError(error)) {
2730
+ this.rollbackDefaults(context, 0);
2731
+ error = context.depthError || this.depthError();
2732
+ }
2733
+ return error ? { data: clonedData, error, valid: false } : { data: clonedData, error: null, valid: true };
2734
+ } catch (error) {
2735
+ this.rollbackDefaults(context, 0);
2736
+ throw error;
2737
+ } finally {
2738
+ depthGuardState.context = priorContext;
2739
+ this.validationContexts.pop();
2740
+ context.active = false;
2064
2741
  }
2065
- return { data: clonedData, error: null, valid: true };
2066
2742
  };
2067
2743
  validate.compiledSchema = compiledSchema;
2068
2744
  return validate;
@@ -2165,7 +2841,7 @@ var SchemaShield = class {
2165
2841
  if (schema._hasRef === true) {
2166
2842
  return;
2167
2843
  }
2168
- Object.defineProperty(schema, "_hasRef", {
2844
+ definePropertyOrThrow(schema, "_hasRef", {
2169
2845
  value: true,
2170
2846
  enumerable: false,
2171
2847
  configurable: false,
@@ -2223,15 +2899,15 @@ var SchemaShield = class {
2223
2899
  return false;
2224
2900
  }
2225
2901
  }
2226
- hasRequiredDefaults(schema) {
2902
+ hasPropertyDefaults(schema) {
2227
2903
  const properties = schema.properties;
2228
2904
  if (!this.isPlainObject(properties)) {
2229
2905
  return false;
2230
2906
  }
2231
- const keys = Object.keys(properties);
2232
- for (let i = 0; i < keys.length; i++) {
2233
- const subSchema = properties[keys[i]];
2234
- if (this.isPlainObject(subSchema) && "default" in subSchema) {
2907
+ const propertyKeys = Object.keys(properties);
2908
+ for (let i = 0; i < propertyKeys.length; i++) {
2909
+ const subSchema = properties[propertyKeys[i]];
2910
+ if (this.isPlainObject(subSchema) && hasOwn(subSchema, "default")) {
2235
2911
  return true;
2236
2912
  }
2237
2913
  }
@@ -2240,24 +2916,134 @@ var SchemaShield = class {
2240
2916
  isDefaultTypeValidator(type, validator) {
2241
2917
  return Types[type] === validator;
2242
2918
  }
2243
- compileSchema(schema) {
2244
- if (!schema || typeof schema !== "object" || Array.isArray(schema)) {
2245
- if (schema === true) {
2246
- schema = { anyOf: [{}] };
2247
- } else if (schema === false) {
2248
- schema = { oneOf: [] };
2919
+ rollbackDefaults(context, start) {
2920
+ for (let index = context.defaults.length - 1; index >= start; index--) {
2921
+ const entry = context.defaults[index];
2922
+ if (entry.descriptor) {
2923
+ definePropertyOrThrow(entry.target, entry.key, entry.descriptor);
2249
2924
  } else {
2250
- schema = { oneOf: [schema] };
2925
+ delete entry.target[entry.key];
2926
+ }
2927
+ }
2928
+ context.defaults.length = start;
2929
+ }
2930
+ isDepthError(error) {
2931
+ const context = this.validationContexts[this.validationContexts.length - 1];
2932
+ if (context?.depthExceeded) {
2933
+ return true;
2934
+ }
2935
+ if (!(error instanceof ValidationError)) {
2936
+ return false;
2937
+ }
2938
+ return error.getCause().code === "MAX_DEPTH_EXCEEDED";
2939
+ }
2940
+ validateSubschema(schema, data) {
2941
+ if (!schema || typeof schema.$validate !== "function") {
2942
+ return;
2943
+ }
2944
+ const context = this.validationContexts[this.validationContexts.length - 1];
2945
+ const savepoint = context?.defaults.length || 0;
2946
+ try {
2947
+ const error = schema.$validate(data);
2948
+ if (error && context) {
2949
+ this.rollbackDefaults(context, savepoint);
2950
+ }
2951
+ return error;
2952
+ } catch (error) {
2953
+ if (context) {
2954
+ this.rollbackDefaults(context, savepoint);
2955
+ }
2956
+ throw error;
2957
+ }
2958
+ }
2959
+ installDepthGuards(root) {
2960
+ const state = { context: null };
2961
+ const stack = [root];
2962
+ const seen = /* @__PURE__ */ new WeakSet();
2963
+ while (stack.length > 0) {
2964
+ const schema = stack.pop();
2965
+ if (!schema || typeof schema !== "object" || seen.has(schema)) {
2966
+ continue;
2967
+ }
2968
+ seen.add(schema);
2969
+ if (typeof schema.$validate === "function") {
2970
+ const directValidate = schema.$validate;
2971
+ schema.$validate = getNamedFunction(directValidate.name, (data) => {
2972
+ const context = state.context;
2973
+ if (!context) {
2974
+ return directValidate(data);
2975
+ }
2976
+ const nextDepth = context.depth + 1;
2977
+ if (nextDepth > this.maxDepth) {
2978
+ context.depthExceeded = true;
2979
+ if (!context.depthError) {
2980
+ context.depthError = this.depthError();
2981
+ }
2982
+ return context.depthError;
2983
+ }
2984
+ context.depth = nextDepth;
2985
+ try {
2986
+ return directValidate(data);
2987
+ } finally {
2988
+ context.depth--;
2989
+ }
2990
+ });
2991
+ }
2992
+ const children = this.schemaChildren(schema);
2993
+ for (const child of children) {
2994
+ stack.push(child);
2251
2995
  }
2252
2996
  }
2997
+ return state;
2998
+ }
2999
+ compileSchema(schema) {
3000
+ if (schema === true) {
3001
+ return {
3002
+ $validate: getNamedFunction("Validate_True", () => {
3003
+ })
3004
+ };
3005
+ }
3006
+ if (schema === false) {
3007
+ const compiledFalse = {};
3008
+ const defineError = getDefinedErrorFunctionForKey(
3009
+ "oneOf",
3010
+ compiledFalse,
3011
+ this.failFast
3012
+ );
3013
+ compiledFalse.$validate = getNamedFunction(
3014
+ "Validate_False",
3015
+ (data) => defineError("Value is not valid", { data })
3016
+ );
3017
+ return compiledFalse;
3018
+ }
3019
+ const sourceSchema = schema && typeof schema === "object" && !Array.isArray(schema) ? schema : null;
3020
+ const schemaCanApplyDefaults = sourceSchema !== null && this.compilingMutableSchemas.has(sourceSchema);
3021
+ if (sourceSchema) {
3022
+ const cached = this.compileCache.get(sourceSchema);
3023
+ if (cached) {
3024
+ return cached;
3025
+ }
3026
+ }
3027
+ if (!schema || typeof schema !== "object" || Array.isArray(schema)) {
3028
+ schema = { oneOf: [schema] };
3029
+ }
2253
3030
  schema = this.normalizeSchemaForCompile(schema);
2254
3031
  const compiledSchema = deepCloneUnfreeze(
2255
3032
  schema
2256
3033
  );
2257
- let schemaHasRef = false;
2258
- if (typeof schema.$id === "string") {
2259
- this.idRegistry.set(schema.$id, compiledSchema);
3034
+ if (sourceSchema) {
3035
+ this.compileCache.set(sourceSchema, compiledSchema);
2260
3036
  }
3037
+ if (schemaCanApplyDefaults) {
3038
+ definePropertyOrThrow(compiledSchema, "_canApplyDefaults", {
3039
+ value: true,
3040
+ enumerable: false,
3041
+ configurable: false,
3042
+ writable: false
3043
+ });
3044
+ }
3045
+ const validateSubschema = this.compilingRequiresContext ? this.validateSubschema.bind(this) : void 0;
3046
+ let schemaHasRef = false;
2261
3047
  if ("$ref" in schema) {
2262
3048
  schemaHasRef = true;
2263
3049
  const refValidator = this.getKeyword("$ref");
@@ -2267,21 +3053,53 @@ var SchemaShield = class {
2267
3053
  schema["$ref"],
2268
3054
  this.failFast
2269
3055
  );
3056
+ const isBuiltinRef = refValidator === keywords.$ref;
2270
3057
  compiledSchema.$validate = getNamedFunction(
2271
- "Validate_Reference",
3058
+ isBuiltinRef ? "Validate_Reference" : refValidator.name || "$ref",
2272
3059
  (data) => refValidator(
2273
3060
  compiledSchema,
2274
3061
  data,
2275
3062
  defineError,
2276
- this
3063
+ this,
3064
+ validateSubschema
2277
3065
  )
2278
3066
  );
3067
+ if (!isBuiltinRef) {
3068
+ schemaHasRef = false;
3069
+ }
3070
+ }
3071
+ for (const key of ["definitions", "$defs"]) {
3072
+ const definitions = schema[key];
3073
+ if (!definitions || typeof definitions !== "object") {
3074
+ continue;
3075
+ }
3076
+ const compiledDefinitions = {};
3077
+ for (const definitionKey of Object.keys(definitions)) {
3078
+ compiledDefinitions[definitionKey] = this.compileSchema(
3079
+ definitions[definitionKey]
3080
+ );
3081
+ }
3082
+ compiledSchema[key] = compiledDefinitions;
3083
+ }
3084
+ if (schemaHasRef) {
3085
+ this.markSchemaHasRef(compiledSchema);
2279
3086
  }
2280
- this.markSchemaHasRef(compiledSchema);
2281
3087
  return compiledSchema;
2282
3088
  }
2283
3089
  const validators = [];
2284
3090
  const activeNames = [];
3091
+ const pendingCombinators = [];
3092
+ if (this.useDefaults !== false && this.getKeyword("properties") === keywords.properties && this.hasPropertyDefaults(schema)) {
3093
+ const applyDefaults = this.useDefaults === "empty" ? applyEmptyPropertyDefaults : applyPropertyDefaults;
3094
+ validators.push({
3095
+ name: applyDefaults.name,
3096
+ validate: getNamedFunction(
3097
+ applyDefaults.name,
3098
+ (data) => applyDefaults(compiledSchema, data, this)
3099
+ )
3100
+ });
3101
+ activeNames.push(applyDefaults.name);
3102
+ }
2285
3103
  if ("type" in schema) {
2286
3104
  const defineTypeError = getDefinedErrorFunctionForKey(
2287
3105
  "type",
@@ -2317,65 +3135,11 @@ var SchemaShield = class {
2317
3135
  if (typeFunctions.length === 1 && allTypesDefault) {
2318
3136
  const singleTypeName = defaultTypeNames[0];
2319
3137
  typeMethodName = singleTypeName;
2320
- switch (singleTypeName) {
2321
- case "object":
2322
- combinedTypeValidator = (data) => {
2323
- if (data === null || typeof data !== "object" || Array.isArray(data)) {
2324
- return defineTypeError("Invalid type", { data });
2325
- }
2326
- };
2327
- break;
2328
- case "array":
2329
- combinedTypeValidator = (data) => {
2330
- if (!Array.isArray(data)) {
2331
- return defineTypeError("Invalid type", { data });
2332
- }
2333
- };
2334
- break;
2335
- case "string":
2336
- combinedTypeValidator = (data) => {
2337
- if (typeof data !== "string") {
2338
- return defineTypeError("Invalid type", { data });
2339
- }
2340
- };
2341
- break;
2342
- case "number":
2343
- combinedTypeValidator = (data) => {
2344
- if (typeof data !== "number") {
2345
- return defineTypeError("Invalid type", { data });
2346
- }
2347
- };
2348
- break;
2349
- case "integer":
2350
- combinedTypeValidator = (data) => {
2351
- if (typeof data !== "number" || !Number.isInteger(data)) {
2352
- return defineTypeError("Invalid type", { data });
2353
- }
2354
- };
2355
- break;
2356
- case "boolean":
2357
- combinedTypeValidator = (data) => {
2358
- if (typeof data !== "boolean") {
2359
- return defineTypeError("Invalid type", { data });
2360
- }
2361
- };
2362
- break;
2363
- case "null":
2364
- combinedTypeValidator = (data) => {
2365
- if (data !== null) {
2366
- return defineTypeError("Invalid type", { data });
2367
- }
2368
- };
2369
- break;
2370
- default: {
2371
- const singleTypeFn = typeFunctions[0];
2372
- combinedTypeValidator = (data) => {
2373
- if (!singleTypeFn(data)) {
2374
- return defineTypeError("Invalid type", { data });
2375
- }
2376
- };
2377
- }
2378
- }
3138
+ combinedTypeValidator = this.failFast && FAIL_FAST_TYPE_VALIDATORS[singleTypeName] ? FAIL_FAST_TYPE_VALIDATORS[singleTypeName] : createBuiltinTypeValidator(
3139
+ singleTypeName,
3140
+ defineTypeError,
3141
+ typeFunctions[0]
3142
+ );
2379
3143
  } else if (typeFunctions.length > 1 && allTypesDefault) {
2380
3144
  typeMethodName = defaultTypeNames.join("_OR_");
2381
3145
  const allowsObject = defaultTypeNames.includes("object");
@@ -2388,6 +3152,9 @@ var SchemaShield = class {
2388
3152
  combinedTypeValidator = (data) => {
2389
3153
  const dataType = typeof data;
2390
3154
  if (dataType === "number") {
3155
+ if (!Number.isFinite(data)) {
3156
+ return defineTypeError("Invalid type", { data });
3157
+ }
2391
3158
  if (allowsNumber || allowsInteger && Number.isInteger(data)) {
2392
3159
  return;
2393
3160
  }
@@ -2451,7 +3218,8 @@ var SchemaShield = class {
2451
3218
  activeNames.push(typeMethodName);
2452
3219
  }
2453
3220
  const { type, $id, $ref, $validate, required, ...otherKeys } = schema;
2454
- const keyOrder = required ? this.hasRequiredDefaults(schema) ? [...Object.keys(otherKeys), "required"] : ["required", ...Object.keys(otherKeys)] : Object.keys(otherKeys);
3221
+ const otherKeyNames = Object.keys(otherKeys);
3222
+ const keyOrder = required ? ["required", ...otherKeyNames] : otherKeyNames;
2455
3223
  for (const key of keyOrder) {
2456
3224
  const keywordFn = this.getKeyword(key);
2457
3225
  if (!keywordFn) {
@@ -2466,12 +3234,33 @@ var SchemaShield = class {
2466
3234
  this.failFast
2467
3235
  );
2468
3236
  const fnName = keywordFn.name || key;
3237
+ if ((key === "allOf" || key === "anyOf" || key === "oneOf") && keywordFn === keywords[key]) {
3238
+ const item = {
3239
+ name: fnName,
3240
+ validate: () => {
3241
+ throw new ValidationError("Combinator validator was not prepared");
3242
+ }
3243
+ };
3244
+ validators.push(item);
3245
+ pendingCombinators.push({ item, key, defineError });
3246
+ activeNames.push(fnName);
3247
+ continue;
3248
+ }
3249
+ const keywordValidate = validateSubschema ? (data) => keywordFn(
3250
+ compiledSchema,
3251
+ data,
3252
+ defineError,
3253
+ this,
3254
+ validateSubschema
3255
+ ) : (data) => keywordFn(
3256
+ compiledSchema,
3257
+ data,
3258
+ defineError,
3259
+ this
3260
+ );
2469
3261
  validators.push({
2470
3262
  name: fnName,
2471
- validate: getNamedFunction(
2472
- fnName,
2473
- (data) => keywordFn(compiledSchema, data, defineError, this)
2474
- )
3263
+ validate: getNamedFunction(fnName, keywordValidate)
2475
3264
  });
2476
3265
  activeNames.push(fnName);
2477
3266
  }
@@ -2513,6 +3302,50 @@ var SchemaShield = class {
2513
3302
  continue;
2514
3303
  }
2515
3304
  }
3305
+ if (this.isPlainObject(schema.properties)) {
3306
+ definePropertyOrThrow(compiledSchema, "_propKeys", {
3307
+ value: Object.keys(schema.properties),
3308
+ enumerable: false,
3309
+ configurable: false,
3310
+ writable: false
3311
+ });
3312
+ }
3313
+ if (this.useDefaults !== false && this.isPlainObject(schema.properties) && this.hasPropertyDefaults(schema)) {
3314
+ const defaultKeys = Object.keys(schema.properties).filter(
3315
+ (key) => {
3316
+ const property = schema.properties[key];
3317
+ return property && typeof property === "object" && !Array.isArray(property) && hasOwn(property, "default");
3318
+ }
3319
+ );
3320
+ if (defaultKeys.length > 0) {
3321
+ definePropertyOrThrow(compiledSchema, "_defaultKeys", {
3322
+ value: defaultKeys,
3323
+ enumerable: false,
3324
+ configurable: false,
3325
+ writable: false
3326
+ });
3327
+ }
3328
+ }
3329
+ prepareCombinatorEntries(compiledSchema);
3330
+ for (let index = 0; index < pendingCombinators.length; index++) {
3331
+ const pending = pendingCombinators[index];
3332
+ const transactions = compiledSchema._canApplyDefaults === true ? {
3333
+ savepoint: () => this.#defaultSavepoint(),
3334
+ rollback: (savepoint) => this.#rollbackDefaultSavepoint(savepoint),
3335
+ capture: (savepoint) => this.#captureDefaultSavepoint(savepoint),
3336
+ restore: (mutations) => this.#restoreDefaults(mutations)
3337
+ } : void 0;
3338
+ pending.item.validate = getNamedFunction(
3339
+ pending.item.name,
3340
+ createCombinatorValidator(
3341
+ pending.key,
3342
+ compiledSchema,
3343
+ pending.defineError,
3344
+ validateSubschema,
3345
+ transactions
3346
+ )
3347
+ );
3348
+ }
2516
3349
  if (schemaHasRef) {
2517
3350
  this.markSchemaHasRef(compiledSchema);
2518
3351
  }
@@ -2554,54 +3387,80 @@ var SchemaShield = class {
2554
3387
  }
2555
3388
  return false;
2556
3389
  }
2557
- linkReferences(root) {
2558
- const stack = [root];
2559
- while (stack.length > 0) {
2560
- const node = stack.pop();
2561
- if (!node || typeof node !== "object")
3390
+ getCompiledReferenceTarget(ref, position, registry) {
3391
+ const resolvedUri = this.resolveUri(ref, position.baseUri, "$ref");
3392
+ const exactTarget = registry.aliases.get(resolvedUri);
3393
+ if (exactTarget) {
3394
+ return this.compileCache.get(exactTarget);
3395
+ }
3396
+ const resourceRoot = registry.aliases.get(this.resourceUri(resolvedUri));
3397
+ if (!resourceRoot) {
3398
+ return;
3399
+ }
3400
+ const compiledResource = this.compileCache.get(resourceRoot);
3401
+ if (!compiledResource) {
3402
+ return;
3403
+ }
3404
+ const hashIndex = resolvedUri.indexOf("#");
3405
+ const fragment = hashIndex === -1 ? "" : resolvedUri.slice(hashIndex + 1);
3406
+ if (fragment.length === 0) {
3407
+ return compiledResource;
3408
+ }
3409
+ if (fragment.startsWith("/")) {
3410
+ return resolvePath(compiledResource, `#${fragment}`);
3411
+ }
3412
+ return;
3413
+ }
3414
+ linkReferences(registry) {
3415
+ for (let index = 0; index < registry.positions.length; index++) {
3416
+ const position = registry.positions[index];
3417
+ if (typeof position.source.$ref !== "string" || this.getKeyword("$ref") !== keywords.$ref) {
2562
3418
  continue;
2563
- if (typeof node.$ref === "string" && typeof node.$validate === "function" && node.$validate.name === "Validate_Reference") {
2564
- const refPath = node.$ref;
2565
- let target = this.getSchemaRef(refPath);
2566
- if (typeof target === "undefined") {
2567
- target = this.getSchemaById(refPath);
2568
- }
2569
- if (typeof target === "boolean") {
2570
- if (target === true) {
2571
- node.$validate = getNamedFunction("Validate_Ref_True", () => {
2572
- });
2573
- } else {
2574
- const defineError = getDefinedErrorFunctionForKey(
2575
- "$ref",
2576
- node,
2577
- this.failFast
2578
- );
2579
- node.$validate = getNamedFunction(
2580
- "Validate_Ref_False",
2581
- (_data) => defineError("Value is not valid")
2582
- );
2583
- }
2584
- continue;
2585
- }
2586
- if (target && typeof target.$validate === "function") {
2587
- node.$validate = target.$validate;
2588
- }
2589
3419
  }
2590
- for (const key in node) {
2591
- const value = node[key];
2592
- if (!value)
2593
- continue;
2594
- if (Array.isArray(value)) {
2595
- for (let i = 0; i < value.length; i++) {
2596
- const v = value[i];
2597
- if (v && typeof v === "object") {
2598
- stack.push(v);
3420
+ const node = this.compileCache.get(position.source);
3421
+ const target = this.getCompiledReferenceTarget(
3422
+ position.source.$ref,
3423
+ position,
3424
+ registry
3425
+ );
3426
+ if (!node || typeof target === "undefined") {
3427
+ const error = new ValidationError(
3428
+ `Reference not found: ${position.source.$ref}`
3429
+ );
3430
+ error.code = "REFERENCE_NOT_FOUND";
3431
+ error.keyword = "$ref";
3432
+ throw error;
3433
+ }
3434
+ let targetValidate;
3435
+ if (target === true) {
3436
+ targetValidate = getNamedFunction("Validate_Ref_True", () => {
3437
+ });
3438
+ } else if (target === false) {
3439
+ const defineError = getDefinedErrorFunctionForKey(
3440
+ "$ref",
3441
+ node,
3442
+ this.failFast
3443
+ );
3444
+ targetValidate = getNamedFunction(
3445
+ "Validate_Ref_False",
3446
+ (data) => defineError("Value is not valid", { data })
3447
+ );
3448
+ } else {
3449
+ if (typeof target.$validate !== "function") {
3450
+ target.$validate = getNamedFunction(
3451
+ "Validate_Ref_Any",
3452
+ () => {
2599
3453
  }
2600
- }
2601
- } else if (typeof value === "object") {
2602
- stack.push(value);
3454
+ );
2603
3455
  }
3456
+ targetValidate = target.$validate;
2604
3457
  }
3458
+ definePropertyOrThrow(node, "_resolvedRef", {
3459
+ value: targetValidate,
3460
+ enumerable: false,
3461
+ configurable: false,
3462
+ writable: false
3463
+ });
2605
3464
  }
2606
3465
  }
2607
3466
  };