schema-shield 1.0.5 → 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;
@@ -12,42 +26,57 @@ var ValidationError = class extends Error {
12
26
  super(message);
13
27
  this.message = message;
14
28
  }
15
- _getCause(pointer = "#", instancePointer = "#") {
16
- let schemaPath = `${pointer}/${this.keyword}`;
17
- let instancePath = `${instancePointer}`;
18
- if (typeof this.item !== "undefined") {
19
- if (typeof this.item === "string" && this.schema && typeof this.schema === "object" && this.item in this.schema) {
20
- schemaPath += `/${this.item}`;
21
- }
22
- instancePath += `/${this.item}`;
23
- }
24
- this.instancePath = instancePath;
25
- this.schemaPath = schemaPath;
26
- if (!this.cause || !(this.cause instanceof ValidationError)) {
27
- return this;
28
- }
29
- return this.cause._getCause(schemaPath, instancePath);
30
- }
31
29
  getCause() {
32
- return this._getCause();
33
- }
34
- _getTree() {
35
- const tree = {
36
- message: this.message,
37
- keyword: this.keyword,
38
- item: this.item,
39
- schemaPath: this.schemaPath,
40
- instancePath: this.instancePath,
41
- data: this.data
42
- };
43
- if (this.cause) {
44
- 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;
45
52
  }
46
- return tree;
53
+ return current;
47
54
  }
48
55
  getTree() {
49
56
  this.getCause();
50
- 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;
51
80
  }
52
81
  getPath() {
53
82
  const cause = this.getCause();
@@ -67,8 +96,11 @@ function getDefinedErrorFunctionForKey(key, schema, failFast) {
67
96
  KeywordError.schema = schema;
68
97
  const defineError = (message, options = {}) => {
69
98
  KeywordError.message = message;
99
+ KeywordError.code = options.code;
70
100
  KeywordError.item = options.item;
71
- 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
+ }
72
104
  KeywordError.data = options.data;
73
105
  return KeywordError;
74
106
  };
@@ -77,11 +109,14 @@ function getDefinedErrorFunctionForKey(key, schema, failFast) {
77
109
  defineError
78
110
  );
79
111
  }
112
+ function escapeJsonPointerToken(value) {
113
+ return String(value).replace(/~/g, "~0").replace(/\//g, "~1");
114
+ }
80
115
  function isCompiledSchema(subSchema) {
81
116
  return !!subSchema && typeof subSchema === "object" && !Array.isArray(subSchema) && "$validate" in subSchema;
82
117
  }
83
118
  function getNamedFunction(name, fn) {
84
- return Object.defineProperty(fn, "name", { value: name });
119
+ return definePropertyOrThrow(fn, "name", { value: name });
85
120
  }
86
121
  function resolvePath(root, path) {
87
122
  if (!path || path === "#") {
@@ -126,7 +161,6 @@ var DURATION_REGEX = /^P(?!$)((\d+Y)?(\d+M)?(\d+W)?(\d+D)?)(T(?=\d)(\d+H)?(\d+M)
126
161
  var URI_REGEX = /^[a-zA-Z][a-zA-Z0-9+\-.]*:[^\s]*$/;
127
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;
128
163
  var HOSTNAME_REGEX = /^[a-z0-9][a-z0-9-]{0,62}(?:\.[a-z0-9][a-z0-9-]{0,62})*[a-z0-9]$/i;
129
- var DATE_REGEX = /^(\d{4})-(\d{2})-(\d{2})$/;
130
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))$/;
131
165
  var URI_REFERENCE_REGEX = /^(([^:/?#]+):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#((?![^#]*\\)[^#]*))?/i;
132
166
  var IRI_REGEX = /^[a-zA-Z][a-zA-Z0-9+\-.]*:[^\s]*$/;
@@ -191,6 +225,22 @@ function isValidIpv4(data) {
191
225
  function isHexCharCode(code) {
192
226
  return code >= 48 && code <= 57 || code >= 65 && code <= 70 || code >= 97 && code <= 102;
193
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
+ }
194
244
  function isValidIpv6(data) {
195
245
  const length = data.length;
196
246
  if (length === 0) {
@@ -295,7 +345,7 @@ function isValidJsonPointer(data) {
295
345
  }
296
346
  function isValidRelativeJsonPointer(data) {
297
347
  if (data.length === 0) {
298
- return true;
348
+ return false;
299
349
  }
300
350
  let i = 0;
301
351
  while (i < data.length) {
@@ -308,6 +358,9 @@ function isValidRelativeJsonPointer(data) {
308
358
  if (i === 0) {
309
359
  return false;
310
360
  }
361
+ if (i > 1 && data.charCodeAt(0) === 48) {
362
+ return false;
363
+ }
311
364
  if (i === data.length) {
312
365
  return true;
313
366
  }
@@ -434,7 +487,7 @@ var Formats = {
434
487
  return true;
435
488
  },
436
489
  uri(data) {
437
- return URI_REGEX.test(data);
490
+ return URI_REGEX.test(data) && hasValidPercentEncoding(data);
438
491
  },
439
492
  email(data) {
440
493
  return EMAIL_REGEX.test(data);
@@ -449,15 +502,13 @@ var Formats = {
449
502
  return HOSTNAME_REGEX.test(data);
450
503
  },
451
504
  date(data) {
452
- const match = DATE_REGEX.exec(data);
453
- if (!match) {
505
+ if (data.length !== 10 || data.charCodeAt(4) !== 45 || data.charCodeAt(7) !== 45) {
454
506
  return false;
455
507
  }
456
- const [, yearStr, monthStr, dayStr] = match;
457
- const year = Number(yearStr);
458
- const month = Number(monthStr);
459
- const day = Number(dayStr);
460
- 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) {
461
512
  return false;
462
513
  }
463
514
  if (day < 1) {
@@ -529,10 +580,10 @@ var Types = {
529
580
  return typeof data === "string";
530
581
  },
531
582
  number(data) {
532
- return typeof data === "number";
583
+ return typeof data === "number" && Number.isFinite(data);
533
584
  },
534
585
  integer(data) {
535
- return typeof data === "number" && data % 1 === 0;
586
+ return typeof data === "number" && Number.isFinite(data) && data % 1 === 0;
536
587
  },
537
588
  boolean(data) {
538
589
  return typeof data === "boolean";
@@ -757,7 +808,7 @@ var ArrayKeywords = {
757
808
  let tupleLength = schema._tupleItemsLength;
758
809
  if (tupleLength === void 0) {
759
810
  tupleLength = schema.items.length;
760
- Object.defineProperty(schema, "_tupleItemsLength", {
811
+ definePropertyOrThrow(schema, "_tupleItemsLength", {
761
812
  value: tupleLength,
762
813
  enumerable: false,
763
814
  configurable: false,
@@ -814,13 +865,23 @@ var ArrayKeywords = {
814
865
  }
815
866
  return;
816
867
  }
817
- const primitiveSeen = /* @__PURE__ */ new Set();
868
+ let hasFirstPrimitive = false;
869
+ let firstPrimitive;
870
+ let primitiveSeen;
818
871
  let primitiveArraySignatures;
819
872
  let arrayBuckets;
820
873
  let objectBuckets;
821
874
  for (let i = 0; i < len; i++) {
822
875
  const item = data[i];
823
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
+ }
824
885
  if (primitiveSeen.has(item)) {
825
886
  return defineError("Array items are not unique", { data: item });
826
887
  }
@@ -906,7 +967,7 @@ function isPlainObject(value) {
906
967
  if (!value || typeof value !== "object") {
907
968
  return false;
908
969
  }
909
- const proto = Object.getPrototypeOf(value);
970
+ const proto = Reflect.getPrototypeOf(value);
910
971
  return proto === Object.prototype || proto === null;
911
972
  }
912
973
  function canUseStructuredClone(value) {
@@ -1001,7 +1062,7 @@ function deepCloneUnfreeze(obj, cloneClassInstances = false, seen = /* @__PURE__
1001
1062
  seen.set(source, clone);
1002
1063
  return clone;
1003
1064
  }
1004
- clone = Object.create(Object.getPrototypeOf(source));
1065
+ clone = Object.create(Reflect.getPrototypeOf(source));
1005
1066
  seen.set(source, clone);
1006
1067
  break;
1007
1068
  }
@@ -1030,7 +1091,7 @@ function deepCloneUnfreeze(obj, cloneClassInstances = false, seen = /* @__PURE__
1030
1091
  seen
1031
1092
  );
1032
1093
  }
1033
- Object.defineProperty(clone, key, descriptor);
1094
+ definePropertyOrThrow(clone, key, descriptor);
1034
1095
  }
1035
1096
  return clone;
1036
1097
  }
@@ -1041,6 +1102,9 @@ var NumberKeywords = {
1041
1102
  if (typeof data !== "number") {
1042
1103
  return;
1043
1104
  }
1105
+ if (!Number.isFinite(data)) {
1106
+ return defineError("Value must be finite", { data });
1107
+ }
1044
1108
  let min = schema.minimum;
1045
1109
  if (typeof schema.exclusiveMinimum === "number") {
1046
1110
  min = schema.exclusiveMinimum + 1e-15;
@@ -1056,6 +1120,9 @@ var NumberKeywords = {
1056
1120
  if (typeof data !== "number") {
1057
1121
  return;
1058
1122
  }
1123
+ if (!Number.isFinite(data)) {
1124
+ return defineError("Value must be finite", { data });
1125
+ }
1059
1126
  let max = schema.maximum;
1060
1127
  if (typeof schema.exclusiveMaximum === "number") {
1061
1128
  max = schema.exclusiveMaximum - 1e-15;
@@ -1071,11 +1138,14 @@ var NumberKeywords = {
1071
1138
  if (typeof data !== "number") {
1072
1139
  return;
1073
1140
  }
1074
- const quotient = data / schema.multipleOf;
1075
- if (!isFinite(quotient)) {
1076
- 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
+ });
1077
1145
  }
1078
- 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) {
1079
1149
  return defineError("Value is not a multiple of the multipleOf", { data });
1080
1150
  }
1081
1151
  return;
@@ -1164,6 +1234,29 @@ function compilePatternMatcher(pattern) {
1164
1234
 
1165
1235
  // lib/keywords/object-keywords.ts
1166
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);
1167
1260
  function getPatternPropertyEntries(schema) {
1168
1261
  let entries = schema._patternPropertyEntries;
1169
1262
  if (entries) {
@@ -1183,7 +1276,7 @@ function getPatternPropertyEntries(schema) {
1183
1276
  match
1184
1277
  };
1185
1278
  }
1186
- Object.defineProperty(schema, "_patternPropertyEntries", {
1279
+ definePropertyOrThrow(schema, "_patternPropertyEntries", {
1187
1280
  value: entries,
1188
1281
  enumerable: false,
1189
1282
  configurable: false,
@@ -1200,7 +1293,7 @@ function getPatternKeyMatchIndexes(schema, key, entries) {
1200
1293
  }
1201
1294
  } else {
1202
1295
  cache = /* @__PURE__ */ new Map();
1203
- Object.defineProperty(schema, "_patternKeyMatchIndexCache", {
1296
+ definePropertyOrThrow(schema, "_patternKeyMatchIndexCache", {
1204
1297
  value: cache,
1205
1298
  enumerable: false,
1206
1299
  configurable: false,
@@ -1225,7 +1318,7 @@ var ObjectKeywords = {
1225
1318
  }
1226
1319
  for (let i = 0; i < schema.required.length; i++) {
1227
1320
  const key = schema.required[i];
1228
- if (!Object.prototype.hasOwnProperty.call(data, key)) {
1321
+ if (!hasOwn(data, key)) {
1229
1322
  return defineError("Required property is missing", {
1230
1323
  item: key,
1231
1324
  data: data[key]
@@ -1234,45 +1327,15 @@ var ObjectKeywords = {
1234
1327
  }
1235
1328
  return;
1236
1329
  },
1237
- properties(schema, data, defineError) {
1330
+ properties(schema, data, defineError, instance) {
1238
1331
  if (!data || typeof data !== "object" || Array.isArray(data)) {
1239
1332
  return;
1240
1333
  }
1241
- let propKeys = schema._propKeys;
1242
- if (!propKeys) {
1243
- propKeys = Object.keys(schema.properties || {});
1244
- Object.defineProperty(schema, "_propKeys", {
1245
- value: propKeys,
1246
- enumerable: false,
1247
- configurable: false,
1248
- writable: false
1249
- });
1250
- }
1251
- let requiredSet = schema._requiredSet;
1252
- if (requiredSet === void 0) {
1253
- requiredSet = Array.isArray(schema.required) ? new Set(schema.required) : null;
1254
- Object.defineProperty(schema, "_requiredSet", {
1255
- value: requiredSet,
1256
- enumerable: false,
1257
- configurable: false,
1258
- writable: false
1259
- });
1260
- }
1334
+ const propKeys = schema._propKeys;
1261
1335
  for (let i = 0; i < propKeys.length; i++) {
1262
1336
  const key = propKeys[i];
1263
1337
  const schemaProp = schema.properties[key];
1264
- if (!Object.prototype.hasOwnProperty.call(data, key)) {
1265
- if (requiredSet && requiredSet.has(key) && schemaProp && typeof schemaProp === "object" && !Array.isArray(schemaProp) && "default" in schemaProp) {
1266
- const error = schemaProp.$validate(schemaProp.default);
1267
- if (error) {
1268
- return defineError("Default property is invalid", {
1269
- item: key,
1270
- cause: error,
1271
- data: schemaProp.default
1272
- });
1273
- }
1274
- data[key] = deepCloneUnfreeze(schemaProp.default);
1275
- }
1338
+ if (!hasOwn(data, key)) {
1276
1339
  continue;
1277
1340
  }
1278
1341
  if (typeof schemaProp === "boolean") {
@@ -1307,7 +1370,7 @@ var ObjectKeywords = {
1307
1370
  return;
1308
1371
  }
1309
1372
  for (const key in data) {
1310
- if (!Object.prototype.hasOwnProperty.call(data, key)) {
1373
+ if (!hasOwn(data, key)) {
1311
1374
  continue;
1312
1375
  }
1313
1376
  const error = validate(data[key]);
@@ -1326,7 +1389,7 @@ var ObjectKeywords = {
1326
1389
  }
1327
1390
  let count = 0;
1328
1391
  for (const key in data) {
1329
- if (!Object.prototype.hasOwnProperty.call(data, key)) {
1392
+ if (!hasOwn(data, key)) {
1330
1393
  continue;
1331
1394
  }
1332
1395
  count++;
@@ -1342,7 +1405,7 @@ var ObjectKeywords = {
1342
1405
  }
1343
1406
  let count = 0;
1344
1407
  for (const key in data) {
1345
- if (!Object.prototype.hasOwnProperty.call(data, key)) {
1408
+ if (!hasOwn(data, key)) {
1346
1409
  continue;
1347
1410
  }
1348
1411
  count++;
@@ -1359,7 +1422,7 @@ var ObjectKeywords = {
1359
1422
  let apValidate = schema._apValidate;
1360
1423
  if (apValidate === void 0) {
1361
1424
  apValidate = isCompiledSchema(schema.additionalProperties) ? schema.additionalProperties.$validate : null;
1362
- Object.defineProperty(schema, "_apValidate", {
1425
+ definePropertyOrThrow(schema, "_apValidate", {
1363
1426
  value: apValidate,
1364
1427
  enumerable: false,
1365
1428
  configurable: false,
@@ -1368,10 +1431,10 @@ var ObjectKeywords = {
1368
1431
  }
1369
1432
  const patternEntries = getPatternPropertyEntries(schema);
1370
1433
  for (const key in data) {
1371
- if (!Object.prototype.hasOwnProperty.call(data, key)) {
1434
+ if (!hasOwn(data, key)) {
1372
1435
  continue;
1373
1436
  }
1374
- if (schema.properties && Object.prototype.hasOwnProperty.call(schema.properties, key)) {
1437
+ if (schema.properties && hasOwn(schema.properties, key)) {
1375
1438
  continue;
1376
1439
  }
1377
1440
  if (patternEntries && patternEntries.length) {
@@ -1407,12 +1470,12 @@ var ObjectKeywords = {
1407
1470
  return;
1408
1471
  }
1409
1472
  for (const key in data) {
1410
- if (!Object.prototype.hasOwnProperty.call(data, key)) {
1473
+ if (!hasOwn(data, key)) {
1411
1474
  continue;
1412
1475
  }
1413
1476
  const matchingIndexes = getPatternKeyMatchIndexes(schema, key, patternEntries);
1414
1477
  if (matchingIndexes.length === 0) {
1415
- if (schema.additionalProperties === false && !(schema.properties && Object.prototype.hasOwnProperty.call(schema.properties, key))) {
1478
+ if (schema.additionalProperties === false && !(schema.properties && hasOwn(schema.properties, key))) {
1416
1479
  return defineError("Additional properties are not allowed", {
1417
1480
  item: key,
1418
1481
  data: data[key]
@@ -1453,7 +1516,7 @@ var ObjectKeywords = {
1453
1516
  if (typeof pn === "boolean") {
1454
1517
  if (pn === false) {
1455
1518
  for (const key in data) {
1456
- if (Object.prototype.hasOwnProperty.call(data, key)) {
1519
+ if (hasOwn(data, key)) {
1457
1520
  return defineError("Properties are not allowed", { data });
1458
1521
  }
1459
1522
  }
@@ -1465,7 +1528,7 @@ var ObjectKeywords = {
1465
1528
  return;
1466
1529
  }
1467
1530
  for (const key in data) {
1468
- if (!Object.prototype.hasOwnProperty.call(data, key)) {
1531
+ if (!hasOwn(data, key)) {
1469
1532
  continue;
1470
1533
  }
1471
1534
  const error = validate(key);
@@ -1564,7 +1627,7 @@ function getBranchEntries(schema, key) {
1564
1627
  for (let i = 0; i < source.length; i++) {
1565
1628
  entries.push(toBranchEntry(source[i]));
1566
1629
  }
1567
- Object.defineProperty(schema, cacheKey, {
1630
+ definePropertyOrThrow(schema, cacheKey, {
1568
1631
  value: entries,
1569
1632
  enumerable: false,
1570
1633
  configurable: false,
@@ -1572,6 +1635,147 @@ function getBranchEntries(schema, key) {
1572
1635
  });
1573
1636
  return entries;
1574
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
+ }
1575
1779
  var OtherKeywords = {
1576
1780
  enum(schema, data, defineError) {
1577
1781
  let enumCache = schema._enumCache;
@@ -1588,7 +1792,7 @@ var OtherKeywords = {
1588
1792
  }
1589
1793
  }
1590
1794
  enumCache = { primitiveSet, objectValues };
1591
- Object.defineProperty(schema, "_enumCache", {
1795
+ definePropertyOrThrow(schema, "_enumCache", {
1592
1796
  value: enumCache,
1593
1797
  enumerable: false,
1594
1798
  configurable: false,
@@ -1608,137 +1812,13 @@ var OtherKeywords = {
1608
1812
  return defineError("Value is not one of the allowed values", { data });
1609
1813
  },
1610
1814
  allOf(schema, data, defineError) {
1611
- const branches = getBranchEntries(schema, "allOf");
1612
- if (branches.length === 1) {
1613
- const onlyBranch = branches[0];
1614
- if (onlyBranch.kind === "validate") {
1615
- const error = onlyBranch.validate(data);
1616
- if (error) {
1617
- return defineError("Value is not valid", { cause: error, data });
1618
- }
1619
- return;
1620
- }
1621
- if (onlyBranch.kind === "alwaysValid") {
1622
- return;
1623
- }
1624
- if (onlyBranch.kind === "alwaysInvalid") {
1625
- return defineError("Value is not valid", { data });
1626
- }
1627
- if (data !== onlyBranch.value) {
1628
- return defineError("Value is not valid", { data });
1629
- }
1630
- return;
1631
- }
1632
- for (let i = 0; i < branches.length; i++) {
1633
- const branch = branches[i];
1634
- if (branch.kind === "validate") {
1635
- const error = branch.validate(data);
1636
- if (error) {
1637
- return defineError("Value is not valid", { cause: error, data });
1638
- }
1639
- continue;
1640
- }
1641
- if (branch.kind === "alwaysValid") {
1642
- continue;
1643
- }
1644
- if (branch.kind === "alwaysInvalid") {
1645
- return defineError("Value is not valid", { data });
1646
- }
1647
- if (data !== branch.value) {
1648
- return defineError("Value is not valid", { data });
1649
- }
1650
- }
1651
- return;
1815
+ return createCombinatorValidator("allOf", schema, defineError)(data);
1652
1816
  },
1653
1817
  anyOf(schema, data, defineError) {
1654
- const branches = getBranchEntries(schema, "anyOf");
1655
- if (branches.length === 1) {
1656
- const onlyBranch = branches[0];
1657
- if (onlyBranch.kind === "validate") {
1658
- const error = onlyBranch.validate(data);
1659
- if (!error) {
1660
- return;
1661
- }
1662
- return defineError("Value is not valid", { data });
1663
- }
1664
- if (onlyBranch.kind === "alwaysValid") {
1665
- return;
1666
- }
1667
- if (onlyBranch.kind === "alwaysInvalid") {
1668
- return defineError("Value is not valid", { data });
1669
- }
1670
- if (data === onlyBranch.value) {
1671
- return;
1672
- }
1673
- return defineError("Value is not valid", { data });
1674
- }
1675
- for (let i = 0; i < branches.length; i++) {
1676
- const branch = branches[i];
1677
- if (branch.kind === "validate") {
1678
- const error = branch.validate(data);
1679
- if (!error) {
1680
- return;
1681
- }
1682
- continue;
1683
- }
1684
- if (branch.kind === "alwaysValid") {
1685
- return;
1686
- }
1687
- if (branch.kind === "alwaysInvalid") {
1688
- continue;
1689
- }
1690
- if (data === branch.value) {
1691
- return;
1692
- }
1693
- }
1694
- return defineError("Value is not valid", { data });
1818
+ return createCombinatorValidator("anyOf", schema, defineError)(data);
1695
1819
  },
1696
1820
  oneOf(schema, data, defineError) {
1697
- const branches = getBranchEntries(schema, "oneOf");
1698
- if (branches.length === 1) {
1699
- const onlyBranch = branches[0];
1700
- if (onlyBranch.kind === "validate") {
1701
- const error = onlyBranch.validate(data);
1702
- if (!error) {
1703
- return;
1704
- }
1705
- return defineError("Value is not valid", { data });
1706
- }
1707
- if (onlyBranch.kind === "alwaysValid") {
1708
- return;
1709
- }
1710
- if (onlyBranch.kind === "alwaysInvalid") {
1711
- return defineError("Value is not valid", { data });
1712
- }
1713
- if (data === onlyBranch.value) {
1714
- return;
1715
- }
1716
- return defineError("Value is not valid", { data });
1717
- }
1718
- let validCount = 0;
1719
- for (let i = 0; i < branches.length; i++) {
1720
- const branch = branches[i];
1721
- let isValid = false;
1722
- if (branch.kind === "validate") {
1723
- isValid = !branch.validate(data);
1724
- } else if (branch.kind === "alwaysValid") {
1725
- isValid = true;
1726
- } else if (branch.kind === "alwaysInvalid") {
1727
- isValid = false;
1728
- } else {
1729
- isValid = data === branch.value;
1730
- }
1731
- if (isValid) {
1732
- validCount++;
1733
- if (validCount > 1) {
1734
- return defineError("Value is not valid", { data });
1735
- }
1736
- }
1737
- }
1738
- if (validCount === 1) {
1739
- return;
1740
- }
1741
- return defineError("Value is not valid", { data });
1821
+ return createCombinatorValidator("oneOf", schema, defineError)(data);
1742
1822
  },
1743
1823
  const(schema, data, defineError) {
1744
1824
  if (data === schema.const) {
@@ -1798,45 +1878,62 @@ var OtherKeywords = {
1798
1878
  }
1799
1879
  return defineError("Value is not valid", { data });
1800
1880
  },
1801
- $ref(schema, data, defineError, instance) {
1802
- if (schema._resolvedRef) {
1803
- if (schema.$validate !== schema._resolvedRef) {
1804
- schema.$validate = schema._resolvedRef;
1805
- }
1881
+ $ref(schema, data, defineError) {
1882
+ if (typeof schema._resolvedRef === "function") {
1806
1883
  return schema._resolvedRef(data);
1807
1884
  }
1808
- const refPath = schema.$ref;
1809
- let targetSchema = instance.getSchemaRef(refPath);
1810
- if (!targetSchema) {
1811
- targetSchema = instance.getSchemaById(refPath);
1812
- }
1813
- if (!targetSchema) {
1814
- return defineError(`Missing reference: ${refPath}`);
1815
- }
1816
- if (!targetSchema.$validate) {
1817
- return;
1818
- }
1819
- schema._resolvedRef = targetSchema.$validate;
1820
- schema.$validate = schema._resolvedRef;
1821
- return schema._resolvedRef(data);
1885
+ return defineError(`Missing reference: ${schema.$ref}`);
1822
1886
  }
1823
1887
  };
1824
1888
 
1825
1889
  // lib/keywords/string-keywords.ts
1826
1890
  var PATTERN_MATCH_CACHE_LIMIT = 512;
1827
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
+ }
1828
1909
  var StringKeywords = {
1829
1910
  minLength(schema, data, defineError) {
1830
- 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)) {
1831
1920
  return;
1832
1921
  }
1833
1922
  return defineError("Value is shorter than the minimum length", { data });
1834
1923
  },
1835
1924
  maxLength(schema, data, defineError) {
1836
- 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) {
1837
1931
  return;
1838
1932
  }
1839
- 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;
1840
1937
  },
1841
1938
  pattern(schema, data, defineError) {
1842
1939
  if (typeof data !== "string") {
@@ -1848,7 +1945,7 @@ var StringKeywords = {
1848
1945
  try {
1849
1946
  const compiled = compilePatternMatcher(schema.pattern);
1850
1947
  patternMatch = compiled instanceof RegExp ? (value) => compiled.test(value) : compiled;
1851
- Object.defineProperty(schema, "_patternMatch", {
1948
+ definePropertyOrThrow(schema, "_patternMatch", {
1852
1949
  value: patternMatch,
1853
1950
  enumerable: false,
1854
1951
  configurable: false,
@@ -1863,7 +1960,7 @@ var StringKeywords = {
1863
1960
  }
1864
1961
  if (!patternMatchCache) {
1865
1962
  patternMatchCache = /* @__PURE__ */ new Map();
1866
- Object.defineProperty(schema, "_patternMatchCache", {
1963
+ definePropertyOrThrow(schema, "_patternMatchCache", {
1867
1964
  value: patternMatchCache,
1868
1965
  enumerable: false,
1869
1966
  configurable: false,
@@ -1895,7 +1992,7 @@ var StringKeywords = {
1895
1992
  let formatResultCache = schema._formatResultCache;
1896
1993
  if (formatValidate === void 0) {
1897
1994
  formatValidate = instance.getFormat(schema.format);
1898
- Object.defineProperty(schema, "_formatValidate", {
1995
+ definePropertyOrThrow(schema, "_formatValidate", {
1899
1996
  value: formatValidate,
1900
1997
  enumerable: false,
1901
1998
  configurable: false,
@@ -1910,7 +2007,7 @@ var StringKeywords = {
1910
2007
  schema.format,
1911
2008
  formatValidate
1912
2009
  );
1913
- Object.defineProperty(schema, "_formatResultCacheEnabled", {
2010
+ definePropertyOrThrow(schema, "_formatResultCacheEnabled", {
1914
2011
  value: formatResultCacheEnabled,
1915
2012
  enumerable: false,
1916
2013
  configurable: false,
@@ -1925,7 +2022,7 @@ var StringKeywords = {
1925
2022
  }
1926
2023
  if (!formatResultCache) {
1927
2024
  formatResultCache = /* @__PURE__ */ new Map();
1928
- Object.defineProperty(schema, "_formatResultCache", {
2025
+ definePropertyOrThrow(schema, "_formatResultCache", {
1929
2026
  value: formatResultCache,
1930
2027
  enumerable: false,
1931
2028
  configurable: false,
@@ -1958,20 +2055,61 @@ var keywords = {
1958
2055
  };
1959
2056
 
1960
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
+ }
1961
2076
  var SchemaShield = class {
1962
2077
  types = {};
1963
2078
  formats = {};
1964
2079
  keywords = {};
1965
2080
  immutable = false;
2081
+ useDefaults = false;
1966
2082
  rootSchema = null;
1967
- idRegistry = /* @__PURE__ */ new Map();
1968
2083
  failFast = true;
2084
+ maxDepth;
2085
+ validationContexts = [];
2086
+ compileCache = /* @__PURE__ */ new WeakMap();
2087
+ compilingRequiresContext = false;
2088
+ compilingMutableSchemas = /* @__PURE__ */ new WeakSet();
1969
2089
  constructor({
1970
2090
  immutable = false,
1971
- failFast = true
2091
+ failFast = true,
2092
+ maxDepth = 128,
2093
+ useDefaults = false
1972
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
+ }
1973
2109
  this.immutable = immutable;
1974
2110
  this.failFast = failFast;
2111
+ this.maxDepth = maxDepth;
2112
+ this.useDefaults = useDefaults;
1975
2113
  for (const [type, validator] of Object.entries(Types)) {
1976
2114
  if (validator) {
1977
2115
  this.addType(type, validator);
@@ -1986,6 +2124,50 @@ var SchemaShield = class {
1986
2124
  }
1987
2125
  }
1988
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
+ }
1989
2171
  addType(name, validator, overwrite = false) {
1990
2172
  if (this.types[name] && !overwrite) {
1991
2173
  throw new ValidationError(`Type "${name}" already exists`);
@@ -2023,14 +2205,465 @@ var SchemaShield = class {
2023
2205
  return resolvePath(this.rootSchema, path);
2024
2206
  }
2025
2207
  getSchemaById(id) {
2026
- 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 };
2027
2626
  }
2028
2627
  compile(schema) {
2029
- 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;
2030
2651
  const compiledSchema = this.compileSchema(schema);
2031
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
+ }
2032
2665
  if (compiledSchema._hasRef === true) {
2033
- this.linkReferences(compiledSchema);
2666
+ this.linkReferences(referenceRegistry);
2034
2667
  }
2035
2668
  if (!compiledSchema.$validate) {
2036
2669
  if (schema === false) {
@@ -2059,14 +2692,53 @@ var SchemaShield = class {
2059
2692
  );
2060
2693
  }
2061
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
+ };
2062
2709
  const validate = (data) => {
2063
2710
  this.rootSchema = compiledSchema;
2064
- const clonedData = this.immutable ? deepCloneUnfreeze(data) : data;
2065
- const res = compiledSchema.$validate(clonedData);
2066
- if (res) {
2067
- 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;
2068
2741
  }
2069
- return { data: clonedData, error: null, valid: true };
2070
2742
  };
2071
2743
  validate.compiledSchema = compiledSchema;
2072
2744
  return validate;
@@ -2169,7 +2841,7 @@ var SchemaShield = class {
2169
2841
  if (schema._hasRef === true) {
2170
2842
  return;
2171
2843
  }
2172
- Object.defineProperty(schema, "_hasRef", {
2844
+ definePropertyOrThrow(schema, "_hasRef", {
2173
2845
  value: true,
2174
2846
  enumerable: false,
2175
2847
  configurable: false,
@@ -2227,15 +2899,15 @@ var SchemaShield = class {
2227
2899
  return false;
2228
2900
  }
2229
2901
  }
2230
- hasRequiredDefaults(schema) {
2902
+ hasPropertyDefaults(schema) {
2231
2903
  const properties = schema.properties;
2232
2904
  if (!this.isPlainObject(properties)) {
2233
2905
  return false;
2234
2906
  }
2235
- const keys = Object.keys(properties);
2236
- for (let i = 0; i < keys.length; i++) {
2237
- const subSchema = properties[keys[i]];
2238
- 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")) {
2239
2911
  return true;
2240
2912
  }
2241
2913
  }
@@ -2244,24 +2916,134 @@ var SchemaShield = class {
2244
2916
  isDefaultTypeValidator(type, validator) {
2245
2917
  return Types[type] === validator;
2246
2918
  }
2247
- compileSchema(schema) {
2248
- if (!schema || typeof schema !== "object" || Array.isArray(schema)) {
2249
- if (schema === true) {
2250
- schema = { anyOf: [{}] };
2251
- } else if (schema === false) {
2252
- 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);
2253
2924
  } else {
2254
- schema = { oneOf: [schema] };
2925
+ delete entry.target[entry.key];
2255
2926
  }
2256
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);
2995
+ }
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
+ }
2257
3030
  schema = this.normalizeSchemaForCompile(schema);
2258
3031
  const compiledSchema = deepCloneUnfreeze(
2259
3032
  schema
2260
3033
  );
2261
- let schemaHasRef = false;
2262
- if (typeof schema.$id === "string") {
2263
- this.idRegistry.set(schema.$id, compiledSchema);
3034
+ if (sourceSchema) {
3035
+ this.compileCache.set(sourceSchema, compiledSchema);
2264
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;
2265
3047
  if ("$ref" in schema) {
2266
3048
  schemaHasRef = true;
2267
3049
  const refValidator = this.getKeyword("$ref");
@@ -2271,21 +3053,53 @@ var SchemaShield = class {
2271
3053
  schema["$ref"],
2272
3054
  this.failFast
2273
3055
  );
3056
+ const isBuiltinRef = refValidator === keywords.$ref;
2274
3057
  compiledSchema.$validate = getNamedFunction(
2275
- "Validate_Reference",
3058
+ isBuiltinRef ? "Validate_Reference" : refValidator.name || "$ref",
2276
3059
  (data) => refValidator(
2277
3060
  compiledSchema,
2278
3061
  data,
2279
3062
  defineError,
2280
- this
3063
+ this,
3064
+ validateSubschema
2281
3065
  )
2282
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);
2283
3086
  }
2284
- this.markSchemaHasRef(compiledSchema);
2285
3087
  return compiledSchema;
2286
3088
  }
2287
3089
  const validators = [];
2288
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
+ }
2289
3103
  if ("type" in schema) {
2290
3104
  const defineTypeError = getDefinedErrorFunctionForKey(
2291
3105
  "type",
@@ -2321,65 +3135,11 @@ var SchemaShield = class {
2321
3135
  if (typeFunctions.length === 1 && allTypesDefault) {
2322
3136
  const singleTypeName = defaultTypeNames[0];
2323
3137
  typeMethodName = singleTypeName;
2324
- switch (singleTypeName) {
2325
- case "object":
2326
- combinedTypeValidator = (data) => {
2327
- if (data === null || typeof data !== "object" || Array.isArray(data)) {
2328
- return defineTypeError("Invalid type", { data });
2329
- }
2330
- };
2331
- break;
2332
- case "array":
2333
- combinedTypeValidator = (data) => {
2334
- if (!Array.isArray(data)) {
2335
- return defineTypeError("Invalid type", { data });
2336
- }
2337
- };
2338
- break;
2339
- case "string":
2340
- combinedTypeValidator = (data) => {
2341
- if (typeof data !== "string") {
2342
- return defineTypeError("Invalid type", { data });
2343
- }
2344
- };
2345
- break;
2346
- case "number":
2347
- combinedTypeValidator = (data) => {
2348
- if (typeof data !== "number") {
2349
- return defineTypeError("Invalid type", { data });
2350
- }
2351
- };
2352
- break;
2353
- case "integer":
2354
- combinedTypeValidator = (data) => {
2355
- if (typeof data !== "number" || !Number.isInteger(data)) {
2356
- return defineTypeError("Invalid type", { data });
2357
- }
2358
- };
2359
- break;
2360
- case "boolean":
2361
- combinedTypeValidator = (data) => {
2362
- if (typeof data !== "boolean") {
2363
- return defineTypeError("Invalid type", { data });
2364
- }
2365
- };
2366
- break;
2367
- case "null":
2368
- combinedTypeValidator = (data) => {
2369
- if (data !== null) {
2370
- return defineTypeError("Invalid type", { data });
2371
- }
2372
- };
2373
- break;
2374
- default: {
2375
- const singleTypeFn = typeFunctions[0];
2376
- combinedTypeValidator = (data) => {
2377
- if (!singleTypeFn(data)) {
2378
- return defineTypeError("Invalid type", { data });
2379
- }
2380
- };
2381
- }
2382
- }
3138
+ combinedTypeValidator = this.failFast && FAIL_FAST_TYPE_VALIDATORS[singleTypeName] ? FAIL_FAST_TYPE_VALIDATORS[singleTypeName] : createBuiltinTypeValidator(
3139
+ singleTypeName,
3140
+ defineTypeError,
3141
+ typeFunctions[0]
3142
+ );
2383
3143
  } else if (typeFunctions.length > 1 && allTypesDefault) {
2384
3144
  typeMethodName = defaultTypeNames.join("_OR_");
2385
3145
  const allowsObject = defaultTypeNames.includes("object");
@@ -2392,6 +3152,9 @@ var SchemaShield = class {
2392
3152
  combinedTypeValidator = (data) => {
2393
3153
  const dataType = typeof data;
2394
3154
  if (dataType === "number") {
3155
+ if (!Number.isFinite(data)) {
3156
+ return defineTypeError("Invalid type", { data });
3157
+ }
2395
3158
  if (allowsNumber || allowsInteger && Number.isInteger(data)) {
2396
3159
  return;
2397
3160
  }
@@ -2455,7 +3218,8 @@ var SchemaShield = class {
2455
3218
  activeNames.push(typeMethodName);
2456
3219
  }
2457
3220
  const { type, $id, $ref, $validate, required, ...otherKeys } = schema;
2458
- 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;
2459
3223
  for (const key of keyOrder) {
2460
3224
  const keywordFn = this.getKeyword(key);
2461
3225
  if (!keywordFn) {
@@ -2470,12 +3234,33 @@ var SchemaShield = class {
2470
3234
  this.failFast
2471
3235
  );
2472
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
+ );
2473
3261
  validators.push({
2474
3262
  name: fnName,
2475
- validate: getNamedFunction(
2476
- fnName,
2477
- (data) => keywordFn(compiledSchema, data, defineError, this)
2478
- )
3263
+ validate: getNamedFunction(fnName, keywordValidate)
2479
3264
  });
2480
3265
  activeNames.push(fnName);
2481
3266
  }
@@ -2517,6 +3302,50 @@ var SchemaShield = class {
2517
3302
  continue;
2518
3303
  }
2519
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
+ }
2520
3349
  if (schemaHasRef) {
2521
3350
  this.markSchemaHasRef(compiledSchema);
2522
3351
  }
@@ -2558,54 +3387,80 @@ var SchemaShield = class {
2558
3387
  }
2559
3388
  return false;
2560
3389
  }
2561
- linkReferences(root) {
2562
- const stack = [root];
2563
- while (stack.length > 0) {
2564
- const node = stack.pop();
2565
- 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) {
2566
3418
  continue;
2567
- if (typeof node.$ref === "string" && typeof node.$validate === "function" && node.$validate.name === "Validate_Reference") {
2568
- const refPath = node.$ref;
2569
- let target = this.getSchemaRef(refPath);
2570
- if (typeof target === "undefined") {
2571
- target = this.getSchemaById(refPath);
2572
- }
2573
- if (typeof target === "boolean") {
2574
- if (target === true) {
2575
- node.$validate = getNamedFunction("Validate_Ref_True", () => {
2576
- });
2577
- } else {
2578
- const defineError = getDefinedErrorFunctionForKey(
2579
- "$ref",
2580
- node,
2581
- this.failFast
2582
- );
2583
- node.$validate = getNamedFunction(
2584
- "Validate_Ref_False",
2585
- (_data) => defineError("Value is not valid")
2586
- );
2587
- }
2588
- continue;
2589
- }
2590
- if (target && typeof target.$validate === "function") {
2591
- node.$validate = target.$validate;
2592
- }
2593
3419
  }
2594
- for (const key in node) {
2595
- const value = node[key];
2596
- if (!value)
2597
- continue;
2598
- if (Array.isArray(value)) {
2599
- for (let i = 0; i < value.length; i++) {
2600
- const v = value[i];
2601
- if (v && typeof v === "object") {
2602
- 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
+ () => {
2603
3453
  }
2604
- }
2605
- } else if (typeof value === "object") {
2606
- stack.push(value);
3454
+ );
2607
3455
  }
3456
+ targetValidate = target.$validate;
2608
3457
  }
3458
+ definePropertyOrThrow(node, "_resolvedRef", {
3459
+ value: targetValidate,
3460
+ enumerable: false,
3461
+ configurable: false,
3462
+ writable: false
3463
+ });
2609
3464
  }
2610
3465
  }
2611
3466
  };