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.js CHANGED
@@ -26,7 +26,21 @@ __export(lib_exports, {
26
26
  module.exports = __toCommonJS(lib_exports);
27
27
 
28
28
  // lib/utils/main-utils.ts
29
+ var hasOwnPropertyIntrinsic = Object.prototype.hasOwnProperty;
30
+ var hasOwnPropertyCall = Function.prototype.call.bind(
31
+ hasOwnPropertyIntrinsic
32
+ );
33
+ function definePropertyOrThrow(target, key, descriptor) {
34
+ if (!Reflect.defineProperty(target, key, descriptor)) {
35
+ throw new TypeError(`Cannot define property "${String(key)}"`);
36
+ }
37
+ return target;
38
+ }
39
+ function hasOwn(target, key) {
40
+ return hasOwnPropertyCall(target, key);
41
+ }
29
42
  var ValidationError = class extends Error {
43
+ code;
30
44
  message;
31
45
  item;
32
46
  keyword;
@@ -39,42 +53,57 @@ var ValidationError = class extends Error {
39
53
  super(message);
40
54
  this.message = message;
41
55
  }
42
- _getCause(pointer = "#", instancePointer = "#") {
43
- let schemaPath = `${pointer}/${this.keyword}`;
44
- let instancePath = `${instancePointer}`;
45
- if (typeof this.item !== "undefined") {
46
- if (typeof this.item === "string" && this.schema && typeof this.schema === "object" && this.item in this.schema) {
47
- schemaPath += `/${this.item}`;
48
- }
49
- instancePath += `/${this.item}`;
50
- }
51
- this.instancePath = instancePath;
52
- this.schemaPath = schemaPath;
53
- if (!this.cause || !(this.cause instanceof ValidationError)) {
54
- return this;
55
- }
56
- return this.cause._getCause(schemaPath, instancePath);
57
- }
58
56
  getCause() {
59
- return this._getCause();
60
- }
61
- _getTree() {
62
- const tree = {
63
- message: this.message,
64
- keyword: this.keyword,
65
- item: this.item,
66
- schemaPath: this.schemaPath,
67
- instancePath: this.instancePath,
68
- data: this.data
69
- };
70
- if (this.cause) {
71
- tree.cause = this.cause._getTree();
57
+ let current = this;
58
+ let schemaPointer = "#";
59
+ let instancePointer = "#";
60
+ const seen = /* @__PURE__ */ new Set();
61
+ while (!seen.has(current)) {
62
+ seen.add(current);
63
+ let schemaPath = `${schemaPointer}/${current.keyword}`;
64
+ let instancePath = instancePointer;
65
+ if (typeof current.item !== "undefined") {
66
+ if (typeof current.item === "string" && current.schema && typeof current.schema === "object" && current.item in current.schema) {
67
+ schemaPath += `/${escapeJsonPointerToken(current.item)}`;
68
+ }
69
+ instancePath += `/${escapeJsonPointerToken(current.item)}`;
70
+ }
71
+ current.schemaPath = schemaPath;
72
+ current.instancePath = instancePath;
73
+ if (!(current.cause instanceof ValidationError) || seen.has(current.cause)) {
74
+ return current;
75
+ }
76
+ schemaPointer = schemaPath;
77
+ instancePointer = instancePath;
78
+ current = current.cause;
72
79
  }
73
- return tree;
80
+ return current;
74
81
  }
75
82
  getTree() {
76
83
  this.getCause();
77
- return this._getTree();
84
+ let current = this;
85
+ let root;
86
+ let target;
87
+ const seen = /* @__PURE__ */ new Set();
88
+ while (current && !seen.has(current)) {
89
+ seen.add(current);
90
+ const node = {
91
+ message: current.message,
92
+ keyword: current.keyword,
93
+ item: current.item,
94
+ schemaPath: current.schemaPath,
95
+ instancePath: current.instancePath,
96
+ data: current.data
97
+ };
98
+ if (!root) {
99
+ root = node;
100
+ } else if (target) {
101
+ target.cause = node;
102
+ }
103
+ target = node;
104
+ current = current.cause instanceof ValidationError ? current.cause : void 0;
105
+ }
106
+ return root;
78
107
  }
79
108
  getPath() {
80
109
  const cause = this.getCause();
@@ -94,8 +123,11 @@ function getDefinedErrorFunctionForKey(key, schema, failFast) {
94
123
  KeywordError.schema = schema;
95
124
  const defineError = (message, options = {}) => {
96
125
  KeywordError.message = message;
126
+ KeywordError.code = options.code;
97
127
  KeywordError.item = options.item;
98
- KeywordError.cause = options.cause && options.cause !== true ? options.cause : void 0;
128
+ if (options.cause !== KeywordError) {
129
+ KeywordError.cause = options.cause && options.cause !== true ? options.cause : void 0;
130
+ }
99
131
  KeywordError.data = options.data;
100
132
  return KeywordError;
101
133
  };
@@ -104,11 +136,14 @@ function getDefinedErrorFunctionForKey(key, schema, failFast) {
104
136
  defineError
105
137
  );
106
138
  }
139
+ function escapeJsonPointerToken(value) {
140
+ return String(value).replace(/~/g, "~0").replace(/\//g, "~1");
141
+ }
107
142
  function isCompiledSchema(subSchema) {
108
143
  return !!subSchema && typeof subSchema === "object" && !Array.isArray(subSchema) && "$validate" in subSchema;
109
144
  }
110
145
  function getNamedFunction(name, fn) {
111
- return Object.defineProperty(fn, "name", { value: name });
146
+ return definePropertyOrThrow(fn, "name", { value: name });
112
147
  }
113
148
  function resolvePath(root, path) {
114
149
  if (!path || path === "#") {
@@ -153,7 +188,6 @@ var DURATION_REGEX = /^P(?!$)((\d+Y)?(\d+M)?(\d+W)?(\d+D)?)(T(?=\d)(\d+H)?(\d+M)
153
188
  var URI_REGEX = /^[a-zA-Z][a-zA-Z0-9+\-.]*:[^\s]*$/;
154
189
  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;
155
190
  var HOSTNAME_REGEX = /^[a-z0-9][a-z0-9-]{0,62}(?:\.[a-z0-9][a-z0-9-]{0,62})*[a-z0-9]$/i;
156
- var DATE_REGEX = /^(\d{4})-(\d{2})-(\d{2})$/;
157
191
  var TIME_REGEX = /^([01]\d|2[0-3]):([0-5]\d):([0-5]\d)(\.\d+)?(Z|([+-])([01]\d|2[0-3]):([0-5]\d))$/;
158
192
  var URI_REFERENCE_REGEX = /^(([^:/?#]+):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#((?![^#]*\\)[^#]*))?/i;
159
193
  var IRI_REGEX = /^[a-zA-Z][a-zA-Z0-9+\-.]*:[^\s]*$/;
@@ -218,6 +252,22 @@ function isValidIpv4(data) {
218
252
  function isHexCharCode(code) {
219
253
  return code >= 48 && code <= 57 || code >= 65 && code <= 70 || code >= 97 && code <= 102;
220
254
  }
255
+ function hasValidPercentEncoding(data) {
256
+ for (let index = 0; index < data.length; index++) {
257
+ const code = data.charCodeAt(index);
258
+ if (code === 92) {
259
+ return false;
260
+ }
261
+ if (code !== 37) {
262
+ continue;
263
+ }
264
+ if (index + 2 >= data.length || !isHexCharCode(data.charCodeAt(index + 1)) || !isHexCharCode(data.charCodeAt(index + 2))) {
265
+ return false;
266
+ }
267
+ index += 2;
268
+ }
269
+ return true;
270
+ }
221
271
  function isValidIpv6(data) {
222
272
  const length = data.length;
223
273
  if (length === 0) {
@@ -322,7 +372,7 @@ function isValidJsonPointer(data) {
322
372
  }
323
373
  function isValidRelativeJsonPointer(data) {
324
374
  if (data.length === 0) {
325
- return true;
375
+ return false;
326
376
  }
327
377
  let i = 0;
328
378
  while (i < data.length) {
@@ -335,6 +385,9 @@ function isValidRelativeJsonPointer(data) {
335
385
  if (i === 0) {
336
386
  return false;
337
387
  }
388
+ if (i > 1 && data.charCodeAt(0) === 48) {
389
+ return false;
390
+ }
338
391
  if (i === data.length) {
339
392
  return true;
340
393
  }
@@ -461,7 +514,7 @@ var Formats = {
461
514
  return true;
462
515
  },
463
516
  uri(data) {
464
- return URI_REGEX.test(data);
517
+ return URI_REGEX.test(data) && hasValidPercentEncoding(data);
465
518
  },
466
519
  email(data) {
467
520
  return EMAIL_REGEX.test(data);
@@ -476,15 +529,13 @@ var Formats = {
476
529
  return HOSTNAME_REGEX.test(data);
477
530
  },
478
531
  date(data) {
479
- const match = DATE_REGEX.exec(data);
480
- if (!match) {
532
+ if (data.length !== 10 || data.charCodeAt(4) !== 45 || data.charCodeAt(7) !== 45) {
481
533
  return false;
482
534
  }
483
- const [, yearStr, monthStr, dayStr] = match;
484
- const year = Number(yearStr);
485
- const month = Number(monthStr);
486
- const day = Number(dayStr);
487
- if (month < 1 || month > 12) {
535
+ const year = parseFourDigits(data, 0);
536
+ const month = parseTwoDigits(data, 5);
537
+ const day = parseTwoDigits(data, 8);
538
+ if (year < 0 || month < 1 || month > 12) {
488
539
  return false;
489
540
  }
490
541
  if (day < 1) {
@@ -556,10 +607,10 @@ var Types = {
556
607
  return typeof data === "string";
557
608
  },
558
609
  number(data) {
559
- return typeof data === "number";
610
+ return typeof data === "number" && Number.isFinite(data);
560
611
  },
561
612
  integer(data) {
562
- return typeof data === "number" && data % 1 === 0;
613
+ return typeof data === "number" && Number.isFinite(data) && data % 1 === 0;
563
614
  },
564
615
  boolean(data) {
565
616
  return typeof data === "boolean";
@@ -784,7 +835,7 @@ var ArrayKeywords = {
784
835
  let tupleLength = schema._tupleItemsLength;
785
836
  if (tupleLength === void 0) {
786
837
  tupleLength = schema.items.length;
787
- Object.defineProperty(schema, "_tupleItemsLength", {
838
+ definePropertyOrThrow(schema, "_tupleItemsLength", {
788
839
  value: tupleLength,
789
840
  enumerable: false,
790
841
  configurable: false,
@@ -841,13 +892,23 @@ var ArrayKeywords = {
841
892
  }
842
893
  return;
843
894
  }
844
- const primitiveSeen = /* @__PURE__ */ new Set();
895
+ let hasFirstPrimitive = false;
896
+ let firstPrimitive;
897
+ let primitiveSeen;
845
898
  let primitiveArraySignatures;
846
899
  let arrayBuckets;
847
900
  let objectBuckets;
848
901
  for (let i = 0; i < len; i++) {
849
902
  const item = data[i];
850
903
  if (isUniquePrimitive(item)) {
904
+ if (!hasFirstPrimitive) {
905
+ hasFirstPrimitive = true;
906
+ firstPrimitive = item;
907
+ continue;
908
+ }
909
+ if (!primitiveSeen) {
910
+ primitiveSeen = /* @__PURE__ */ new Set([firstPrimitive]);
911
+ }
851
912
  if (primitiveSeen.has(item)) {
852
913
  return defineError("Array items are not unique", { data: item });
853
914
  }
@@ -933,7 +994,7 @@ function isPlainObject(value) {
933
994
  if (!value || typeof value !== "object") {
934
995
  return false;
935
996
  }
936
- const proto = Object.getPrototypeOf(value);
997
+ const proto = Reflect.getPrototypeOf(value);
937
998
  return proto === Object.prototype || proto === null;
938
999
  }
939
1000
  function canUseStructuredClone(value) {
@@ -1028,7 +1089,7 @@ function deepCloneUnfreeze(obj, cloneClassInstances = false, seen = /* @__PURE__
1028
1089
  seen.set(source, clone);
1029
1090
  return clone;
1030
1091
  }
1031
- clone = Object.create(Object.getPrototypeOf(source));
1092
+ clone = Object.create(Reflect.getPrototypeOf(source));
1032
1093
  seen.set(source, clone);
1033
1094
  break;
1034
1095
  }
@@ -1057,7 +1118,7 @@ function deepCloneUnfreeze(obj, cloneClassInstances = false, seen = /* @__PURE__
1057
1118
  seen
1058
1119
  );
1059
1120
  }
1060
- Object.defineProperty(clone, key, descriptor);
1121
+ definePropertyOrThrow(clone, key, descriptor);
1061
1122
  }
1062
1123
  return clone;
1063
1124
  }
@@ -1068,6 +1129,9 @@ var NumberKeywords = {
1068
1129
  if (typeof data !== "number") {
1069
1130
  return;
1070
1131
  }
1132
+ if (!Number.isFinite(data)) {
1133
+ return defineError("Value must be finite", { data });
1134
+ }
1071
1135
  let min = schema.minimum;
1072
1136
  if (typeof schema.exclusiveMinimum === "number") {
1073
1137
  min = schema.exclusiveMinimum + 1e-15;
@@ -1083,6 +1147,9 @@ var NumberKeywords = {
1083
1147
  if (typeof data !== "number") {
1084
1148
  return;
1085
1149
  }
1150
+ if (!Number.isFinite(data)) {
1151
+ return defineError("Value must be finite", { data });
1152
+ }
1086
1153
  let max = schema.maximum;
1087
1154
  if (typeof schema.exclusiveMaximum === "number") {
1088
1155
  max = schema.exclusiveMaximum - 1e-15;
@@ -1098,11 +1165,14 @@ var NumberKeywords = {
1098
1165
  if (typeof data !== "number") {
1099
1166
  return;
1100
1167
  }
1101
- const quotient = data / schema.multipleOf;
1102
- if (!isFinite(quotient)) {
1103
- return;
1168
+ if (!Number.isFinite(data) || !Number.isFinite(schema.multipleOf) || schema.multipleOf <= 0) {
1169
+ return defineError("Value must use a finite positive multipleOf", {
1170
+ data
1171
+ });
1104
1172
  }
1105
- if (!areCloseEnough(quotient, Math.round(quotient))) {
1173
+ const quotient = data / schema.multipleOf;
1174
+ const valid = Number.isFinite(quotient) ? areCloseEnough(quotient, Math.round(quotient)) : data % schema.multipleOf === 0;
1175
+ if (!valid) {
1106
1176
  return defineError("Value is not a multiple of the multipleOf", { data });
1107
1177
  }
1108
1178
  return;
@@ -1191,6 +1261,29 @@ function compilePatternMatcher(pattern) {
1191
1261
 
1192
1262
  // lib/keywords/object-keywords.ts
1193
1263
  var PATTERN_KEY_CACHE_LIMIT = 512;
1264
+ function createApplyPropertyDefaults(replaceEmpty) {
1265
+ return function applyPropertyDefaults2(schema, data, instance) {
1266
+ if (!data || typeof data !== "object" || Array.isArray(data)) {
1267
+ return;
1268
+ }
1269
+ const defaultKeys = schema._defaultKeys;
1270
+ for (let i = 0; i < defaultKeys.length; i++) {
1271
+ const key = defaultKeys[i];
1272
+ const hasOwnValue = hasOwn(data, key);
1273
+ const value = hasOwnValue ? data[key] : void 0;
1274
+ if (hasOwnValue && value !== void 0 && (!replaceEmpty || value !== null && value !== "")) {
1275
+ continue;
1276
+ }
1277
+ instance.setDefault(
1278
+ data,
1279
+ key,
1280
+ deepCloneUnfreeze(schema.properties[key].default)
1281
+ );
1282
+ }
1283
+ };
1284
+ }
1285
+ var applyPropertyDefaults = createApplyPropertyDefaults(false);
1286
+ var applyEmptyPropertyDefaults = createApplyPropertyDefaults(true);
1194
1287
  function getPatternPropertyEntries(schema) {
1195
1288
  let entries = schema._patternPropertyEntries;
1196
1289
  if (entries) {
@@ -1210,7 +1303,7 @@ function getPatternPropertyEntries(schema) {
1210
1303
  match
1211
1304
  };
1212
1305
  }
1213
- Object.defineProperty(schema, "_patternPropertyEntries", {
1306
+ definePropertyOrThrow(schema, "_patternPropertyEntries", {
1214
1307
  value: entries,
1215
1308
  enumerable: false,
1216
1309
  configurable: false,
@@ -1227,7 +1320,7 @@ function getPatternKeyMatchIndexes(schema, key, entries) {
1227
1320
  }
1228
1321
  } else {
1229
1322
  cache = /* @__PURE__ */ new Map();
1230
- Object.defineProperty(schema, "_patternKeyMatchIndexCache", {
1323
+ definePropertyOrThrow(schema, "_patternKeyMatchIndexCache", {
1231
1324
  value: cache,
1232
1325
  enumerable: false,
1233
1326
  configurable: false,
@@ -1252,7 +1345,7 @@ var ObjectKeywords = {
1252
1345
  }
1253
1346
  for (let i = 0; i < schema.required.length; i++) {
1254
1347
  const key = schema.required[i];
1255
- if (!Object.prototype.hasOwnProperty.call(data, key)) {
1348
+ if (!hasOwn(data, key)) {
1256
1349
  return defineError("Required property is missing", {
1257
1350
  item: key,
1258
1351
  data: data[key]
@@ -1261,45 +1354,15 @@ var ObjectKeywords = {
1261
1354
  }
1262
1355
  return;
1263
1356
  },
1264
- properties(schema, data, defineError) {
1357
+ properties(schema, data, defineError, instance) {
1265
1358
  if (!data || typeof data !== "object" || Array.isArray(data)) {
1266
1359
  return;
1267
1360
  }
1268
- let propKeys = schema._propKeys;
1269
- if (!propKeys) {
1270
- propKeys = Object.keys(schema.properties || {});
1271
- Object.defineProperty(schema, "_propKeys", {
1272
- value: propKeys,
1273
- enumerable: false,
1274
- configurable: false,
1275
- writable: false
1276
- });
1277
- }
1278
- let requiredSet = schema._requiredSet;
1279
- if (requiredSet === void 0) {
1280
- requiredSet = Array.isArray(schema.required) ? new Set(schema.required) : null;
1281
- Object.defineProperty(schema, "_requiredSet", {
1282
- value: requiredSet,
1283
- enumerable: false,
1284
- configurable: false,
1285
- writable: false
1286
- });
1287
- }
1361
+ const propKeys = schema._propKeys;
1288
1362
  for (let i = 0; i < propKeys.length; i++) {
1289
1363
  const key = propKeys[i];
1290
1364
  const schemaProp = schema.properties[key];
1291
- if (!Object.prototype.hasOwnProperty.call(data, key)) {
1292
- if (requiredSet && requiredSet.has(key) && schemaProp && typeof schemaProp === "object" && !Array.isArray(schemaProp) && "default" in schemaProp) {
1293
- const error = schemaProp.$validate(schemaProp.default);
1294
- if (error) {
1295
- return defineError("Default property is invalid", {
1296
- item: key,
1297
- cause: error,
1298
- data: schemaProp.default
1299
- });
1300
- }
1301
- data[key] = deepCloneUnfreeze(schemaProp.default);
1302
- }
1365
+ if (!hasOwn(data, key)) {
1303
1366
  continue;
1304
1367
  }
1305
1368
  if (typeof schemaProp === "boolean") {
@@ -1334,7 +1397,7 @@ var ObjectKeywords = {
1334
1397
  return;
1335
1398
  }
1336
1399
  for (const key in data) {
1337
- if (!Object.prototype.hasOwnProperty.call(data, key)) {
1400
+ if (!hasOwn(data, key)) {
1338
1401
  continue;
1339
1402
  }
1340
1403
  const error = validate(data[key]);
@@ -1353,7 +1416,7 @@ var ObjectKeywords = {
1353
1416
  }
1354
1417
  let count = 0;
1355
1418
  for (const key in data) {
1356
- if (!Object.prototype.hasOwnProperty.call(data, key)) {
1419
+ if (!hasOwn(data, key)) {
1357
1420
  continue;
1358
1421
  }
1359
1422
  count++;
@@ -1369,7 +1432,7 @@ var ObjectKeywords = {
1369
1432
  }
1370
1433
  let count = 0;
1371
1434
  for (const key in data) {
1372
- if (!Object.prototype.hasOwnProperty.call(data, key)) {
1435
+ if (!hasOwn(data, key)) {
1373
1436
  continue;
1374
1437
  }
1375
1438
  count++;
@@ -1386,7 +1449,7 @@ var ObjectKeywords = {
1386
1449
  let apValidate = schema._apValidate;
1387
1450
  if (apValidate === void 0) {
1388
1451
  apValidate = isCompiledSchema(schema.additionalProperties) ? schema.additionalProperties.$validate : null;
1389
- Object.defineProperty(schema, "_apValidate", {
1452
+ definePropertyOrThrow(schema, "_apValidate", {
1390
1453
  value: apValidate,
1391
1454
  enumerable: false,
1392
1455
  configurable: false,
@@ -1395,10 +1458,10 @@ var ObjectKeywords = {
1395
1458
  }
1396
1459
  const patternEntries = getPatternPropertyEntries(schema);
1397
1460
  for (const key in data) {
1398
- if (!Object.prototype.hasOwnProperty.call(data, key)) {
1461
+ if (!hasOwn(data, key)) {
1399
1462
  continue;
1400
1463
  }
1401
- if (schema.properties && Object.prototype.hasOwnProperty.call(schema.properties, key)) {
1464
+ if (schema.properties && hasOwn(schema.properties, key)) {
1402
1465
  continue;
1403
1466
  }
1404
1467
  if (patternEntries && patternEntries.length) {
@@ -1434,12 +1497,12 @@ var ObjectKeywords = {
1434
1497
  return;
1435
1498
  }
1436
1499
  for (const key in data) {
1437
- if (!Object.prototype.hasOwnProperty.call(data, key)) {
1500
+ if (!hasOwn(data, key)) {
1438
1501
  continue;
1439
1502
  }
1440
1503
  const matchingIndexes = getPatternKeyMatchIndexes(schema, key, patternEntries);
1441
1504
  if (matchingIndexes.length === 0) {
1442
- if (schema.additionalProperties === false && !(schema.properties && Object.prototype.hasOwnProperty.call(schema.properties, key))) {
1505
+ if (schema.additionalProperties === false && !(schema.properties && hasOwn(schema.properties, key))) {
1443
1506
  return defineError("Additional properties are not allowed", {
1444
1507
  item: key,
1445
1508
  data: data[key]
@@ -1480,7 +1543,7 @@ var ObjectKeywords = {
1480
1543
  if (typeof pn === "boolean") {
1481
1544
  if (pn === false) {
1482
1545
  for (const key in data) {
1483
- if (Object.prototype.hasOwnProperty.call(data, key)) {
1546
+ if (hasOwn(data, key)) {
1484
1547
  return defineError("Properties are not allowed", { data });
1485
1548
  }
1486
1549
  }
@@ -1492,7 +1555,7 @@ var ObjectKeywords = {
1492
1555
  return;
1493
1556
  }
1494
1557
  for (const key in data) {
1495
- if (!Object.prototype.hasOwnProperty.call(data, key)) {
1558
+ if (!hasOwn(data, key)) {
1496
1559
  continue;
1497
1560
  }
1498
1561
  const error = validate(key);
@@ -1591,7 +1654,7 @@ function getBranchEntries(schema, key) {
1591
1654
  for (let i = 0; i < source.length; i++) {
1592
1655
  entries.push(toBranchEntry(source[i]));
1593
1656
  }
1594
- Object.defineProperty(schema, cacheKey, {
1657
+ definePropertyOrThrow(schema, cacheKey, {
1595
1658
  value: entries,
1596
1659
  enumerable: false,
1597
1660
  configurable: false,
@@ -1599,6 +1662,147 @@ function getBranchEntries(schema, key) {
1599
1662
  });
1600
1663
  return entries;
1601
1664
  }
1665
+ function evaluateAllOf(branches, data, defineError) {
1666
+ for (let i = 0; i < branches.length; i++) {
1667
+ const branch = branches[i];
1668
+ if (branch.kind === "validate") {
1669
+ const error = branch.validate(data);
1670
+ if (error) {
1671
+ return defineError("Value is not valid", { cause: error, data });
1672
+ }
1673
+ continue;
1674
+ }
1675
+ if (branch.kind === "alwaysValid") {
1676
+ continue;
1677
+ }
1678
+ if (branch.kind === "alwaysInvalid" || data !== branch.value) {
1679
+ return defineError("Value is not valid", { data });
1680
+ }
1681
+ }
1682
+ }
1683
+ function evaluateAnyOf(branches, data, defineError) {
1684
+ for (let i = 0; i < branches.length; i++) {
1685
+ const branch = branches[i];
1686
+ if (branch.kind === "validate") {
1687
+ if (!branch.validate(data)) {
1688
+ return;
1689
+ }
1690
+ continue;
1691
+ }
1692
+ if (branch.kind === "alwaysValid") {
1693
+ return;
1694
+ }
1695
+ if (branch.kind === "literal" && data === branch.value) {
1696
+ return;
1697
+ }
1698
+ }
1699
+ return defineError("Value is not valid", { data });
1700
+ }
1701
+ function evaluateOneOf(branches, data, defineError) {
1702
+ let validCount = 0;
1703
+ let winnerIndex = -1;
1704
+ for (let i = 0; i < branches.length; i++) {
1705
+ const branch = branches[i];
1706
+ let isValid = false;
1707
+ if (branch.kind === "validate") {
1708
+ isValid = !branch.validate(data);
1709
+ } else if (branch.kind === "alwaysValid") {
1710
+ isValid = true;
1711
+ } else if (branch.kind === "literal") {
1712
+ isValid = data === branch.value;
1713
+ }
1714
+ if (isValid) {
1715
+ validCount++;
1716
+ winnerIndex = i;
1717
+ if (validCount > 1) {
1718
+ return {
1719
+ error: defineError("Value is not valid", { data }),
1720
+ winnerIndex: -1
1721
+ };
1722
+ }
1723
+ }
1724
+ }
1725
+ return {
1726
+ error: validCount === 1 ? void 0 : defineError("Value is not valid", { data }),
1727
+ winnerIndex: validCount === 1 ? winnerIndex : -1
1728
+ };
1729
+ }
1730
+ function createCombinatorValidator(key, schema, defineError, validateSubschema, transactions) {
1731
+ const sourceBranches = getBranchEntries(schema, key);
1732
+ const branches = validateSubschema ? sourceBranches.map(
1733
+ (branch, index) => branch.kind === "validate" ? {
1734
+ kind: "validate",
1735
+ validate: (data) => validateSubschema(schema[key][index], data)
1736
+ } : branch
1737
+ ) : sourceBranches;
1738
+ if (!transactions) {
1739
+ if (key === "allOf") {
1740
+ return (data) => evaluateAllOf(branches, data, defineError);
1741
+ }
1742
+ if (key === "anyOf") {
1743
+ return (data) => evaluateAnyOf(branches, data, defineError);
1744
+ }
1745
+ return (data) => evaluateOneOf(branches, data, defineError).error;
1746
+ }
1747
+ if (key === "allOf") {
1748
+ return (data) => {
1749
+ const savepoint = transactions.savepoint();
1750
+ try {
1751
+ const error = evaluateAllOf(branches, data, defineError);
1752
+ if (error) {
1753
+ transactions.rollback(savepoint);
1754
+ }
1755
+ return error;
1756
+ } catch (error) {
1757
+ transactions.rollback(savepoint);
1758
+ throw error;
1759
+ }
1760
+ };
1761
+ }
1762
+ if (key === "anyOf") {
1763
+ return (data) => evaluateAnyOf(branches, data, defineError);
1764
+ }
1765
+ return (data) => {
1766
+ const savepoint = transactions.savepoint();
1767
+ const defaultsByBranch = [];
1768
+ const isolatedBranches = branches.map(
1769
+ (branch, index) => branch.kind === "validate" ? {
1770
+ kind: "validate",
1771
+ validate: (value) => {
1772
+ const branchSavepoint = transactions.savepoint();
1773
+ const error = branch.validate(value);
1774
+ if (!error) {
1775
+ defaultsByBranch[index] = transactions.capture(branchSavepoint);
1776
+ }
1777
+ return error;
1778
+ }
1779
+ } : branch
1780
+ );
1781
+ try {
1782
+ const result = evaluateOneOf(isolatedBranches, data, defineError);
1783
+ if (result.error) {
1784
+ transactions.rollback(savepoint);
1785
+ return result.error;
1786
+ }
1787
+ transactions.restore(defaultsByBranch[result.winnerIndex] || []);
1788
+ return;
1789
+ } catch (error) {
1790
+ transactions.rollback(savepoint);
1791
+ throw error;
1792
+ }
1793
+ };
1794
+ }
1795
+ function prepareCombinatorEntries(schema) {
1796
+ if (Array.isArray(schema.allOf)) {
1797
+ getBranchEntries(schema, "allOf");
1798
+ }
1799
+ if (Array.isArray(schema.anyOf)) {
1800
+ getBranchEntries(schema, "anyOf");
1801
+ }
1802
+ if (Array.isArray(schema.oneOf)) {
1803
+ getBranchEntries(schema, "oneOf");
1804
+ }
1805
+ }
1602
1806
  var OtherKeywords = {
1603
1807
  enum(schema, data, defineError) {
1604
1808
  let enumCache = schema._enumCache;
@@ -1615,7 +1819,7 @@ var OtherKeywords = {
1615
1819
  }
1616
1820
  }
1617
1821
  enumCache = { primitiveSet, objectValues };
1618
- Object.defineProperty(schema, "_enumCache", {
1822
+ definePropertyOrThrow(schema, "_enumCache", {
1619
1823
  value: enumCache,
1620
1824
  enumerable: false,
1621
1825
  configurable: false,
@@ -1635,137 +1839,13 @@ var OtherKeywords = {
1635
1839
  return defineError("Value is not one of the allowed values", { data });
1636
1840
  },
1637
1841
  allOf(schema, data, defineError) {
1638
- const branches = getBranchEntries(schema, "allOf");
1639
- if (branches.length === 1) {
1640
- const onlyBranch = branches[0];
1641
- if (onlyBranch.kind === "validate") {
1642
- const error = onlyBranch.validate(data);
1643
- if (error) {
1644
- return defineError("Value is not valid", { cause: error, data });
1645
- }
1646
- return;
1647
- }
1648
- if (onlyBranch.kind === "alwaysValid") {
1649
- return;
1650
- }
1651
- if (onlyBranch.kind === "alwaysInvalid") {
1652
- return defineError("Value is not valid", { data });
1653
- }
1654
- if (data !== onlyBranch.value) {
1655
- return defineError("Value is not valid", { data });
1656
- }
1657
- return;
1658
- }
1659
- for (let i = 0; i < branches.length; i++) {
1660
- const branch = branches[i];
1661
- if (branch.kind === "validate") {
1662
- const error = branch.validate(data);
1663
- if (error) {
1664
- return defineError("Value is not valid", { cause: error, data });
1665
- }
1666
- continue;
1667
- }
1668
- if (branch.kind === "alwaysValid") {
1669
- continue;
1670
- }
1671
- if (branch.kind === "alwaysInvalid") {
1672
- return defineError("Value is not valid", { data });
1673
- }
1674
- if (data !== branch.value) {
1675
- return defineError("Value is not valid", { data });
1676
- }
1677
- }
1678
- return;
1842
+ return createCombinatorValidator("allOf", schema, defineError)(data);
1679
1843
  },
1680
1844
  anyOf(schema, data, defineError) {
1681
- const branches = getBranchEntries(schema, "anyOf");
1682
- if (branches.length === 1) {
1683
- const onlyBranch = branches[0];
1684
- if (onlyBranch.kind === "validate") {
1685
- const error = onlyBranch.validate(data);
1686
- if (!error) {
1687
- return;
1688
- }
1689
- return defineError("Value is not valid", { data });
1690
- }
1691
- if (onlyBranch.kind === "alwaysValid") {
1692
- return;
1693
- }
1694
- if (onlyBranch.kind === "alwaysInvalid") {
1695
- return defineError("Value is not valid", { data });
1696
- }
1697
- if (data === onlyBranch.value) {
1698
- return;
1699
- }
1700
- return defineError("Value is not valid", { data });
1701
- }
1702
- for (let i = 0; i < branches.length; i++) {
1703
- const branch = branches[i];
1704
- if (branch.kind === "validate") {
1705
- const error = branch.validate(data);
1706
- if (!error) {
1707
- return;
1708
- }
1709
- continue;
1710
- }
1711
- if (branch.kind === "alwaysValid") {
1712
- return;
1713
- }
1714
- if (branch.kind === "alwaysInvalid") {
1715
- continue;
1716
- }
1717
- if (data === branch.value) {
1718
- return;
1719
- }
1720
- }
1721
- return defineError("Value is not valid", { data });
1845
+ return createCombinatorValidator("anyOf", schema, defineError)(data);
1722
1846
  },
1723
1847
  oneOf(schema, data, defineError) {
1724
- const branches = getBranchEntries(schema, "oneOf");
1725
- if (branches.length === 1) {
1726
- const onlyBranch = branches[0];
1727
- if (onlyBranch.kind === "validate") {
1728
- const error = onlyBranch.validate(data);
1729
- if (!error) {
1730
- return;
1731
- }
1732
- return defineError("Value is not valid", { data });
1733
- }
1734
- if (onlyBranch.kind === "alwaysValid") {
1735
- return;
1736
- }
1737
- if (onlyBranch.kind === "alwaysInvalid") {
1738
- return defineError("Value is not valid", { data });
1739
- }
1740
- if (data === onlyBranch.value) {
1741
- return;
1742
- }
1743
- return defineError("Value is not valid", { data });
1744
- }
1745
- let validCount = 0;
1746
- for (let i = 0; i < branches.length; i++) {
1747
- const branch = branches[i];
1748
- let isValid = false;
1749
- if (branch.kind === "validate") {
1750
- isValid = !branch.validate(data);
1751
- } else if (branch.kind === "alwaysValid") {
1752
- isValid = true;
1753
- } else if (branch.kind === "alwaysInvalid") {
1754
- isValid = false;
1755
- } else {
1756
- isValid = data === branch.value;
1757
- }
1758
- if (isValid) {
1759
- validCount++;
1760
- if (validCount > 1) {
1761
- return defineError("Value is not valid", { data });
1762
- }
1763
- }
1764
- }
1765
- if (validCount === 1) {
1766
- return;
1767
- }
1768
- return defineError("Value is not valid", { data });
1848
+ return createCombinatorValidator("oneOf", schema, defineError)(data);
1769
1849
  },
1770
1850
  const(schema, data, defineError) {
1771
1851
  if (data === schema.const) {
@@ -1825,45 +1905,62 @@ var OtherKeywords = {
1825
1905
  }
1826
1906
  return defineError("Value is not valid", { data });
1827
1907
  },
1828
- $ref(schema, data, defineError, instance) {
1829
- if (schema._resolvedRef) {
1830
- if (schema.$validate !== schema._resolvedRef) {
1831
- schema.$validate = schema._resolvedRef;
1832
- }
1908
+ $ref(schema, data, defineError) {
1909
+ if (typeof schema._resolvedRef === "function") {
1833
1910
  return schema._resolvedRef(data);
1834
1911
  }
1835
- const refPath = schema.$ref;
1836
- let targetSchema = instance.getSchemaRef(refPath);
1837
- if (!targetSchema) {
1838
- targetSchema = instance.getSchemaById(refPath);
1839
- }
1840
- if (!targetSchema) {
1841
- return defineError(`Missing reference: ${refPath}`);
1842
- }
1843
- if (!targetSchema.$validate) {
1844
- return;
1845
- }
1846
- schema._resolvedRef = targetSchema.$validate;
1847
- schema.$validate = schema._resolvedRef;
1848
- return schema._resolvedRef(data);
1912
+ return defineError(`Missing reference: ${schema.$ref}`);
1849
1913
  }
1850
1914
  };
1851
1915
 
1852
1916
  // lib/keywords/string-keywords.ts
1853
1917
  var PATTERN_MATCH_CACHE_LIMIT = 512;
1854
1918
  var FORMAT_RESULT_CACHE_LIMIT = 512;
1919
+ function hasAtLeastCodePoints(value, limit) {
1920
+ let count = 0;
1921
+ for (let index = 0; index < value.length; index++) {
1922
+ const unit = value.charCodeAt(index);
1923
+ if (unit >= 55296 && unit <= 56319 && index + 1 < value.length) {
1924
+ const nextUnit = value.charCodeAt(index + 1);
1925
+ if (nextUnit >= 56320 && nextUnit <= 57343) {
1926
+ index++;
1927
+ }
1928
+ }
1929
+ count++;
1930
+ if (count >= limit) {
1931
+ return true;
1932
+ }
1933
+ }
1934
+ return count >= limit;
1935
+ }
1855
1936
  var StringKeywords = {
1856
1937
  minLength(schema, data, defineError) {
1857
- if (typeof data !== "string" || data.length >= schema.minLength) {
1938
+ if (typeof data !== "string") {
1939
+ return;
1940
+ }
1941
+ const units = data.length;
1942
+ const limit = schema.minLength;
1943
+ if (units < limit) {
1944
+ return defineError("Value is shorter than the minimum length", { data });
1945
+ }
1946
+ if (units - limit >= limit || hasAtLeastCodePoints(data, limit)) {
1858
1947
  return;
1859
1948
  }
1860
1949
  return defineError("Value is shorter than the minimum length", { data });
1861
1950
  },
1862
1951
  maxLength(schema, data, defineError) {
1863
- if (typeof data !== "string" || data.length <= schema.maxLength) {
1952
+ if (typeof data !== "string") {
1953
+ return;
1954
+ }
1955
+ const units = data.length;
1956
+ const limit = schema.maxLength;
1957
+ if (units <= limit) {
1864
1958
  return;
1865
1959
  }
1866
- return defineError("Value is longer than the maximum length", { data });
1960
+ if (units - limit > limit || hasAtLeastCodePoints(data, limit + 1)) {
1961
+ return defineError("Value is longer than the maximum length", { data });
1962
+ }
1963
+ return;
1867
1964
  },
1868
1965
  pattern(schema, data, defineError) {
1869
1966
  if (typeof data !== "string") {
@@ -1875,7 +1972,7 @@ var StringKeywords = {
1875
1972
  try {
1876
1973
  const compiled = compilePatternMatcher(schema.pattern);
1877
1974
  patternMatch = compiled instanceof RegExp ? (value) => compiled.test(value) : compiled;
1878
- Object.defineProperty(schema, "_patternMatch", {
1975
+ definePropertyOrThrow(schema, "_patternMatch", {
1879
1976
  value: patternMatch,
1880
1977
  enumerable: false,
1881
1978
  configurable: false,
@@ -1890,7 +1987,7 @@ var StringKeywords = {
1890
1987
  }
1891
1988
  if (!patternMatchCache) {
1892
1989
  patternMatchCache = /* @__PURE__ */ new Map();
1893
- Object.defineProperty(schema, "_patternMatchCache", {
1990
+ definePropertyOrThrow(schema, "_patternMatchCache", {
1894
1991
  value: patternMatchCache,
1895
1992
  enumerable: false,
1896
1993
  configurable: false,
@@ -1922,7 +2019,7 @@ var StringKeywords = {
1922
2019
  let formatResultCache = schema._formatResultCache;
1923
2020
  if (formatValidate === void 0) {
1924
2021
  formatValidate = instance.getFormat(schema.format);
1925
- Object.defineProperty(schema, "_formatValidate", {
2022
+ definePropertyOrThrow(schema, "_formatValidate", {
1926
2023
  value: formatValidate,
1927
2024
  enumerable: false,
1928
2025
  configurable: false,
@@ -1937,7 +2034,7 @@ var StringKeywords = {
1937
2034
  schema.format,
1938
2035
  formatValidate
1939
2036
  );
1940
- Object.defineProperty(schema, "_formatResultCacheEnabled", {
2037
+ definePropertyOrThrow(schema, "_formatResultCacheEnabled", {
1941
2038
  value: formatResultCacheEnabled,
1942
2039
  enumerable: false,
1943
2040
  configurable: false,
@@ -1952,7 +2049,7 @@ var StringKeywords = {
1952
2049
  }
1953
2050
  if (!formatResultCache) {
1954
2051
  formatResultCache = /* @__PURE__ */ new Map();
1955
- Object.defineProperty(schema, "_formatResultCache", {
2052
+ definePropertyOrThrow(schema, "_formatResultCache", {
1956
2053
  value: formatResultCache,
1957
2054
  enumerable: false,
1958
2055
  configurable: false,
@@ -1985,20 +2082,61 @@ var keywords = {
1985
2082
  };
1986
2083
 
1987
2084
  // lib/index.ts
2085
+ var MAX_COMPILE_DEPTH = 128;
2086
+ var LOCAL_SCHEMA_BASE = "schema-shield://local/root";
2087
+ var FAIL_FAST_TYPE_VALIDATORS = {
2088
+ object: (data) => data !== null && typeof data === "object" && !Array.isArray(data) ? void 0 : true,
2089
+ array: (data) => Array.isArray(data) ? void 0 : true,
2090
+ string: (data) => typeof data === "string" ? void 0 : true,
2091
+ number: (data) => typeof data === "number" && Number.isFinite(data) ? void 0 : true,
2092
+ integer: (data) => typeof data === "number" && Number.isFinite(data) && Number.isInteger(data) ? void 0 : true,
2093
+ boolean: (data) => typeof data === "boolean" ? void 0 : true,
2094
+ null: (data) => data === null ? void 0 : true
2095
+ };
2096
+ function createBuiltinTypeValidator(_type, defineError, fallback) {
2097
+ return (data) => {
2098
+ if (!fallback(data)) {
2099
+ return defineError("Invalid type", { data });
2100
+ }
2101
+ };
2102
+ }
1988
2103
  var SchemaShield = class {
1989
2104
  types = {};
1990
2105
  formats = {};
1991
2106
  keywords = {};
1992
2107
  immutable = false;
2108
+ useDefaults = false;
1993
2109
  rootSchema = null;
1994
- idRegistry = /* @__PURE__ */ new Map();
1995
2110
  failFast = true;
2111
+ maxDepth;
2112
+ validationContexts = [];
2113
+ compileCache = /* @__PURE__ */ new WeakMap();
2114
+ compilingRequiresContext = false;
2115
+ compilingMutableSchemas = /* @__PURE__ */ new WeakSet();
1996
2116
  constructor({
1997
2117
  immutable = false,
1998
- failFast = true
2118
+ failFast = true,
2119
+ maxDepth = 128,
2120
+ useDefaults = false
1999
2121
  } = {}) {
2122
+ if (!Number.isInteger(maxDepth) || maxDepth < 1 || maxDepth > 256) {
2123
+ const error = new ValidationError("maxDepth must be an integer from 1 to 256");
2124
+ error.code = "INVALID_MAX_DEPTH";
2125
+ error.keyword = "maxDepth";
2126
+ throw error;
2127
+ }
2128
+ if (useDefaults !== false && useDefaults !== true && useDefaults !== "empty") {
2129
+ const error = new ValidationError(
2130
+ 'useDefaults must be false, true, or "empty"'
2131
+ );
2132
+ error.code = "INVALID_USE_DEFAULTS";
2133
+ error.keyword = "useDefaults";
2134
+ throw error;
2135
+ }
2000
2136
  this.immutable = immutable;
2001
2137
  this.failFast = failFast;
2138
+ this.maxDepth = maxDepth;
2139
+ this.useDefaults = useDefaults;
2002
2140
  for (const [type, validator] of Object.entries(Types)) {
2003
2141
  if (validator) {
2004
2142
  this.addType(type, validator);
@@ -2013,6 +2151,50 @@ var SchemaShield = class {
2013
2151
  }
2014
2152
  }
2015
2153
  }
2154
+ setDefault(target, key, value) {
2155
+ const context = this.validationContexts[this.validationContexts.length - 1];
2156
+ if (context) {
2157
+ context.defaults.push({
2158
+ target,
2159
+ key,
2160
+ descriptor: Reflect.getOwnPropertyDescriptor(target, key)
2161
+ });
2162
+ }
2163
+ definePropertyOrThrow(target, key, {
2164
+ value,
2165
+ enumerable: true,
2166
+ configurable: true,
2167
+ writable: true
2168
+ });
2169
+ }
2170
+ #defaultSavepoint() {
2171
+ const context = this.validationContexts[this.validationContexts.length - 1];
2172
+ return context ? context.defaults.length : 0;
2173
+ }
2174
+ #rollbackDefaultSavepoint(savepoint) {
2175
+ const context = this.validationContexts[this.validationContexts.length - 1];
2176
+ if (context) {
2177
+ this.rollbackDefaults(context, savepoint);
2178
+ }
2179
+ }
2180
+ #captureDefaultSavepoint(savepoint) {
2181
+ const context = this.validationContexts[this.validationContexts.length - 1];
2182
+ if (!context || context.defaults.length === savepoint) {
2183
+ return [];
2184
+ }
2185
+ const mutations = context.defaults.slice(savepoint).map((entry) => ({
2186
+ ...entry,
2187
+ value: entry.target[entry.key]
2188
+ }));
2189
+ this.rollbackDefaults(context, savepoint);
2190
+ return mutations;
2191
+ }
2192
+ #restoreDefaults(mutations) {
2193
+ for (let index = 0; index < mutations.length; index++) {
2194
+ const mutation = mutations[index];
2195
+ this.setDefault(mutation.target, mutation.key, mutation.value);
2196
+ }
2197
+ }
2016
2198
  addType(name, validator, overwrite = false) {
2017
2199
  if (this.types[name] && !overwrite) {
2018
2200
  throw new ValidationError(`Type "${name}" already exists`);
@@ -2050,14 +2232,465 @@ var SchemaShield = class {
2050
2232
  return resolvePath(this.rootSchema, path);
2051
2233
  }
2052
2234
  getSchemaById(id) {
2053
- return this.idRegistry.get(id);
2235
+ if (!this.rootSchema) {
2236
+ return;
2237
+ }
2238
+ const stack = [this.rootSchema];
2239
+ const seen = /* @__PURE__ */ new WeakSet();
2240
+ while (stack.length > 0) {
2241
+ const node = stack.pop();
2242
+ if (seen.has(node)) {
2243
+ continue;
2244
+ }
2245
+ seen.add(node);
2246
+ if (node.$id === id) {
2247
+ return node;
2248
+ }
2249
+ const children = this.schemaChildren(node);
2250
+ for (let index = 0; index < children.length; index++) {
2251
+ stack.push(children[index]);
2252
+ }
2253
+ }
2254
+ return;
2255
+ }
2256
+ depthError(message = "Maximum schema depth exceeded") {
2257
+ if (this.failFast) {
2258
+ return true;
2259
+ }
2260
+ const error = new ValidationError(message);
2261
+ error.code = "MAX_DEPTH_EXCEEDED";
2262
+ error.keyword = "maxDepth";
2263
+ return error;
2264
+ }
2265
+ schemaChildEntries(schema) {
2266
+ const children = [];
2267
+ const mapKeys = [
2268
+ "properties",
2269
+ "patternProperties",
2270
+ "definitions",
2271
+ "$defs",
2272
+ "dependencies"
2273
+ ];
2274
+ const arrayKeys = ["allOf", "anyOf", "oneOf", "items"];
2275
+ const singleKeys = [
2276
+ "items",
2277
+ "additionalItems",
2278
+ "additionalProperties",
2279
+ "contains",
2280
+ "propertyNames",
2281
+ "values",
2282
+ "elements",
2283
+ "not",
2284
+ "if",
2285
+ "then",
2286
+ "else"
2287
+ ];
2288
+ for (const key of mapKeys) {
2289
+ const value = schema[key];
2290
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
2291
+ continue;
2292
+ }
2293
+ for (const childKey of Object.keys(value)) {
2294
+ const child = value[childKey];
2295
+ if (child && typeof child === "object") {
2296
+ children.push({
2297
+ value: child,
2298
+ pointer: `/${this.escapePointerToken(key)}/${this.escapePointerToken(
2299
+ childKey
2300
+ )}`
2301
+ });
2302
+ }
2303
+ }
2304
+ }
2305
+ for (const key of arrayKeys) {
2306
+ const value = schema[key];
2307
+ if (!Array.isArray(value)) {
2308
+ continue;
2309
+ }
2310
+ for (let index = 0; index < value.length; index++) {
2311
+ const child = value[index];
2312
+ if (child && typeof child === "object") {
2313
+ children.push({
2314
+ value: child,
2315
+ pointer: `/${this.escapePointerToken(key)}/${index}`
2316
+ });
2317
+ }
2318
+ }
2319
+ }
2320
+ for (const key of singleKeys) {
2321
+ const value = schema[key];
2322
+ if (value && typeof value === "object" && !Array.isArray(value)) {
2323
+ children.push({
2324
+ value,
2325
+ pointer: `/${this.escapePointerToken(key)}`
2326
+ });
2327
+ }
2328
+ }
2329
+ for (const key of Object.keys(schema)) {
2330
+ if (key === "enum" || key === "const" || key === "default" || key === "examples" || mapKeys.includes(key) || arrayKeys.includes(key) || singleKeys.includes(key)) {
2331
+ continue;
2332
+ }
2333
+ const keyword = this.getKeyword(key);
2334
+ const value = schema[key];
2335
+ if (keyword && keyword !== keywords[key] && value && typeof value === "object") {
2336
+ children.push({
2337
+ value,
2338
+ pointer: `/${this.escapePointerToken(key)}`
2339
+ });
2340
+ }
2341
+ }
2342
+ return children;
2343
+ }
2344
+ schemaChildren(schema) {
2345
+ return this.schemaChildEntries(schema).map((entry) => entry.value);
2346
+ }
2347
+ registrySubschemaEntries(schema) {
2348
+ const children = [];
2349
+ const mapKeys = ["properties", "patternProperties", "definitions"];
2350
+ const arrayKeys = ["allOf", "anyOf", "oneOf", "items"];
2351
+ const singleKeys = [
2352
+ "items",
2353
+ "additionalItems",
2354
+ "additionalProperties",
2355
+ "contains",
2356
+ "propertyNames",
2357
+ "not",
2358
+ "if",
2359
+ "then",
2360
+ "else"
2361
+ ];
2362
+ for (const key of mapKeys) {
2363
+ const value = schema[key];
2364
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
2365
+ continue;
2366
+ }
2367
+ for (const childKey of Object.keys(value)) {
2368
+ const child = value[childKey];
2369
+ if (child && typeof child === "object" && !Array.isArray(child)) {
2370
+ children.push({
2371
+ value: child,
2372
+ pointer: `/${this.escapePointerToken(key)}/${this.escapePointerToken(
2373
+ childKey
2374
+ )}`
2375
+ });
2376
+ }
2377
+ }
2378
+ }
2379
+ const dependencies = schema.dependencies;
2380
+ if (dependencies && typeof dependencies === "object" && !Array.isArray(dependencies)) {
2381
+ for (const dependencyKey of Object.keys(dependencies)) {
2382
+ const child = dependencies[dependencyKey];
2383
+ if (child && typeof child === "object" && !Array.isArray(child)) {
2384
+ children.push({
2385
+ value: child,
2386
+ pointer: `/dependencies/${this.escapePointerToken(dependencyKey)}`
2387
+ });
2388
+ }
2389
+ }
2390
+ }
2391
+ for (const key of arrayKeys) {
2392
+ const value = schema[key];
2393
+ if (!Array.isArray(value)) {
2394
+ continue;
2395
+ }
2396
+ for (let index = 0; index < value.length; index++) {
2397
+ const child = value[index];
2398
+ if (child && typeof child === "object" && !Array.isArray(child)) {
2399
+ children.push({
2400
+ value: child,
2401
+ pointer: `/${this.escapePointerToken(key)}/${index}`
2402
+ });
2403
+ }
2404
+ }
2405
+ }
2406
+ for (const key of singleKeys) {
2407
+ const value = schema[key];
2408
+ if (value && typeof value === "object" && !Array.isArray(value)) {
2409
+ children.push({
2410
+ value,
2411
+ pointer: `/${this.escapePointerToken(key)}`
2412
+ });
2413
+ }
2414
+ }
2415
+ return children;
2416
+ }
2417
+ escapePointerToken(value) {
2418
+ return value.replace(/~/g, "~0").replace(/\//g, "~1");
2419
+ }
2420
+ resolveUri(reference, baseUri, keyword) {
2421
+ try {
2422
+ return new URL(reference, baseUri).href;
2423
+ } catch {
2424
+ const error = new ValidationError(`Invalid ${keyword} URI: ${reference}`);
2425
+ error.code = keyword === "$id" ? "INVALID_SCHEMA_ID" : "REFERENCE_NOT_FOUND";
2426
+ error.keyword = keyword;
2427
+ throw error;
2428
+ }
2429
+ }
2430
+ resourceUri(uri) {
2431
+ const hashIndex = uri.indexOf("#");
2432
+ return hashIndex === -1 ? uri : uri.slice(0, hashIndex);
2433
+ }
2434
+ buildReferenceRegistry(schema) {
2435
+ const aliases = /* @__PURE__ */ new Map();
2436
+ const positions = [];
2437
+ const positionsByNode = /* @__PURE__ */ new WeakMap();
2438
+ if (!schema || typeof schema !== "object" || Array.isArray(schema)) {
2439
+ return Object.freeze({
2440
+ aliases,
2441
+ positions: Object.freeze(positions),
2442
+ positionsByNode
2443
+ });
2444
+ }
2445
+ const register = (uri, node) => {
2446
+ const existing = aliases.get(uri);
2447
+ if (existing && existing !== node) {
2448
+ const error = new ValidationError(`Duplicate schema identity: ${uri}`);
2449
+ error.code = "DUPLICATE_SCHEMA_ID";
2450
+ error.keyword = "$id";
2451
+ throw error;
2452
+ }
2453
+ aliases.set(uri, node);
2454
+ };
2455
+ register(LOCAL_SCHEMA_BASE, schema);
2456
+ const visited = /* @__PURE__ */ new WeakSet();
2457
+ const stack = [
2458
+ {
2459
+ node: schema,
2460
+ inheritedBase: LOCAL_SCHEMA_BASE,
2461
+ resourceRoot: schema,
2462
+ pointer: "#"
2463
+ }
2464
+ ];
2465
+ while (stack.length > 0) {
2466
+ const entry = stack.pop();
2467
+ if (visited.has(entry.node)) {
2468
+ continue;
2469
+ }
2470
+ visited.add(entry.node);
2471
+ let baseUri = entry.inheritedBase;
2472
+ let resourceRoot = entry.resourceRoot;
2473
+ if (typeof entry.node.$id === "string" && !("$ref" in entry.node)) {
2474
+ baseUri = this.resolveUri(entry.node.$id, entry.inheritedBase, "$id");
2475
+ register(baseUri, entry.node);
2476
+ if (baseUri.indexOf("#") === -1 || baseUri.endsWith("#")) {
2477
+ resourceRoot = entry.node;
2478
+ register(this.resourceUri(baseUri), entry.node);
2479
+ }
2480
+ }
2481
+ const position = {
2482
+ source: entry.node,
2483
+ baseUri,
2484
+ resourceRoot,
2485
+ pointer: entry.pointer
2486
+ };
2487
+ positions.push(position);
2488
+ positionsByNode.set(entry.node, position);
2489
+ const children = this.registrySubschemaEntries(entry.node);
2490
+ for (let index = children.length - 1; index >= 0; index--) {
2491
+ const child = children[index];
2492
+ if (Array.isArray(child.value)) {
2493
+ continue;
2494
+ }
2495
+ stack.push({
2496
+ node: child.value,
2497
+ inheritedBase: baseUri,
2498
+ resourceRoot,
2499
+ pointer: `${entry.pointer}${child.pointer}`
2500
+ });
2501
+ }
2502
+ }
2503
+ return Object.freeze({
2504
+ aliases,
2505
+ positions: Object.freeze(positions),
2506
+ positionsByNode
2507
+ });
2508
+ }
2509
+ resolveReferenceSource(ref, position, registry) {
2510
+ const resolvedUri = this.resolveUri(ref, position.baseUri, "$ref");
2511
+ const exactTarget = registry.aliases.get(resolvedUri);
2512
+ if (exactTarget) {
2513
+ return exactTarget;
2514
+ }
2515
+ const resourceRoot = registry.aliases.get(this.resourceUri(resolvedUri));
2516
+ if (!resourceRoot) {
2517
+ return;
2518
+ }
2519
+ const hashIndex = resolvedUri.indexOf("#");
2520
+ const fragment = hashIndex === -1 ? "" : resolvedUri.slice(hashIndex + 1);
2521
+ if (fragment.length === 0) {
2522
+ return resourceRoot;
2523
+ }
2524
+ if (fragment.startsWith("/")) {
2525
+ return resolvePath(resourceRoot, `#${fragment}`);
2526
+ }
2527
+ return;
2528
+ }
2529
+ analyzeSchema(schema, registry) {
2530
+ if (!schema || typeof schema !== "object") {
2531
+ return {
2532
+ requiresDepthGuard: false,
2533
+ requiresMutationJournal: false,
2534
+ mutableSchemas: /* @__PURE__ */ new WeakSet()
2535
+ };
2536
+ }
2537
+ const visiting = /* @__PURE__ */ new WeakSet();
2538
+ const visited = /* @__PURE__ */ new WeakSet();
2539
+ const stack = [{ value: schema, depth: 0, exit: false }];
2540
+ let requiresDepthGuard = false;
2541
+ let requiresMutationJournal = false;
2542
+ while (stack.length > 0) {
2543
+ const entry = stack.pop();
2544
+ if (entry.exit) {
2545
+ visiting.delete(entry.value);
2546
+ visited.add(entry.value);
2547
+ continue;
2548
+ }
2549
+ if (visited.has(entry.value)) {
2550
+ continue;
2551
+ }
2552
+ if (visiting.has(entry.value)) {
2553
+ const error = new ValidationError("Cyclic schema graph is not supported");
2554
+ error.code = "CYCLIC_SCHEMA_GRAPH";
2555
+ error.keyword = "compile";
2556
+ throw error;
2557
+ }
2558
+ if (entry.depth > MAX_COMPILE_DEPTH) {
2559
+ const error = new ValidationError("Maximum compile depth exceeded");
2560
+ error.code = "MAX_COMPILE_DEPTH_EXCEEDED";
2561
+ error.keyword = "compile";
2562
+ throw error;
2563
+ }
2564
+ if (entry.depth > this.maxDepth) {
2565
+ requiresDepthGuard = true;
2566
+ }
2567
+ visiting.add(entry.value);
2568
+ stack.push({ ...entry, exit: true });
2569
+ if (this.useDefaults !== false && this.hasPropertyDefaults(entry.value)) {
2570
+ requiresMutationJournal = true;
2571
+ }
2572
+ for (const key of Object.keys(entry.value)) {
2573
+ const keyword = this.getKeyword(key);
2574
+ if (keyword && keyword !== keywords[key]) {
2575
+ requiresDepthGuard = true;
2576
+ requiresMutationJournal = true;
2577
+ }
2578
+ }
2579
+ const children = this.schemaChildren(entry.value);
2580
+ for (let index = children.length - 1; index >= 0; index--) {
2581
+ stack.push({
2582
+ value: children[index],
2583
+ depth: entry.depth + 1,
2584
+ exit: false
2585
+ });
2586
+ }
2587
+ }
2588
+ const semanticState = /* @__PURE__ */ new WeakMap();
2589
+ const semanticStack = [{ value: schema, exit: false }];
2590
+ while (semanticStack.length > 0 && !requiresDepthGuard) {
2591
+ const entry = semanticStack.pop();
2592
+ if (entry.exit) {
2593
+ semanticState.set(entry.value, 2);
2594
+ continue;
2595
+ }
2596
+ const state = semanticState.get(entry.value);
2597
+ if (state === 1) {
2598
+ requiresDepthGuard = true;
2599
+ break;
2600
+ }
2601
+ if (state === 2) {
2602
+ continue;
2603
+ }
2604
+ semanticState.set(entry.value, 1);
2605
+ semanticStack.push({ value: entry.value, exit: true });
2606
+ const children = this.schemaChildren(entry.value);
2607
+ if (typeof entry.value.$ref === "string" && this.getKeyword("$ref") === keywords.$ref) {
2608
+ const position = registry.positionsByNode.get(entry.value);
2609
+ const target = position ? this.resolveReferenceSource(entry.value.$ref, position, registry) : void 0;
2610
+ if (target && typeof target === "object") {
2611
+ children.push(target);
2612
+ }
2613
+ }
2614
+ for (let index = children.length - 1; index >= 0; index--) {
2615
+ semanticStack.push({
2616
+ value: children[index],
2617
+ exit: false
2618
+ });
2619
+ }
2620
+ }
2621
+ const mutableSchemas = /* @__PURE__ */ new WeakSet();
2622
+ if (requiresMutationJournal) {
2623
+ const mutationStack = [{ value: schema, exit: false }];
2624
+ const mutationVisited = /* @__PURE__ */ new WeakSet();
2625
+ while (mutationStack.length > 0) {
2626
+ const entry = mutationStack.pop();
2627
+ if (entry.exit) {
2628
+ const children2 = this.schemaChildren(entry.value);
2629
+ const hasCustomKeyword = Object.keys(entry.value).some((key) => {
2630
+ const keyword = this.getKeyword(key);
2631
+ return !!keyword && keyword !== keywords[key];
2632
+ });
2633
+ if (this.useDefaults !== false && this.hasPropertyDefaults(entry.value) || hasCustomKeyword || typeof entry.value.$ref === "string" || children2.some((child) => mutableSchemas.has(child))) {
2634
+ mutableSchemas.add(entry.value);
2635
+ }
2636
+ continue;
2637
+ }
2638
+ if (mutationVisited.has(entry.value)) {
2639
+ continue;
2640
+ }
2641
+ mutationVisited.add(entry.value);
2642
+ mutationStack.push({ value: entry.value, exit: true });
2643
+ const children = this.schemaChildren(entry.value);
2644
+ for (let index = children.length - 1; index >= 0; index--) {
2645
+ mutationStack.push({
2646
+ value: children[index],
2647
+ exit: false
2648
+ });
2649
+ }
2650
+ }
2651
+ }
2652
+ return { requiresDepthGuard, requiresMutationJournal, mutableSchemas };
2054
2653
  }
2055
2654
  compile(schema) {
2056
- this.idRegistry.clear();
2655
+ const prepared = this.prepareSchema(schema);
2656
+ const compiledSchema = prepared.compiledSchema;
2657
+ if (!prepared.requiresDepthGuard && !prepared.requiresMutationJournal) {
2658
+ const directValidate = compiledSchema.$validate;
2659
+ const validate = this.immutable ? (data) => {
2660
+ const clonedData = deepCloneUnfreeze(data);
2661
+ const error = directValidate(clonedData);
2662
+ return error ? { data: clonedData, error, valid: false } : { data: clonedData, error: null, valid: true };
2663
+ } : (data) => {
2664
+ const error = directValidate(data);
2665
+ return error ? { data, error, valid: false } : { data, error: null, valid: true };
2666
+ };
2667
+ validate.compiledSchema = compiledSchema;
2668
+ return validate;
2669
+ }
2670
+ return this.createGuardedValidator(compiledSchema, prepared.depthGuardState);
2671
+ }
2672
+ prepareSchema(schema) {
2673
+ const referenceRegistry = this.buildReferenceRegistry(schema);
2674
+ const analysis = this.analyzeSchema(schema, referenceRegistry);
2675
+ this.compileCache = /* @__PURE__ */ new WeakMap();
2676
+ this.compilingRequiresContext = analysis.requiresDepthGuard || analysis.requiresMutationJournal;
2677
+ this.compilingMutableSchemas = analysis.mutableSchemas;
2057
2678
  const compiledSchema = this.compileSchema(schema);
2058
2679
  this.rootSchema = compiledSchema;
2680
+ let depthGuardState = null;
2681
+ if (analysis.requiresDepthGuard) {
2682
+ depthGuardState = this.installDepthGuards(compiledSchema);
2683
+ definePropertyOrThrow(compiledSchema, "_requiresDepthGuard", {
2684
+ value: true,
2685
+ enumerable: false,
2686
+ configurable: false,
2687
+ writable: false
2688
+ });
2689
+ } else if (analysis.requiresMutationJournal) {
2690
+ depthGuardState = { context: null };
2691
+ }
2059
2692
  if (compiledSchema._hasRef === true) {
2060
- this.linkReferences(compiledSchema);
2693
+ this.linkReferences(referenceRegistry);
2061
2694
  }
2062
2695
  if (!compiledSchema.$validate) {
2063
2696
  if (schema === false) {
@@ -2086,14 +2719,53 @@ var SchemaShield = class {
2086
2719
  );
2087
2720
  }
2088
2721
  }
2722
+ return {
2723
+ compiledSchema,
2724
+ requiresDepthGuard: analysis.requiresDepthGuard,
2725
+ requiresMutationJournal: analysis.requiresMutationJournal,
2726
+ depthGuardState
2727
+ };
2728
+ }
2729
+ createGuardedValidator(compiledSchema, depthGuardState) {
2730
+ const reusableContext = {
2731
+ active: false,
2732
+ depth: -1,
2733
+ depthExceeded: false,
2734
+ defaults: []
2735
+ };
2089
2736
  const validate = (data) => {
2090
2737
  this.rootSchema = compiledSchema;
2091
- const clonedData = this.immutable ? deepCloneUnfreeze(data) : data;
2092
- const res = compiledSchema.$validate(clonedData);
2093
- if (res) {
2094
- return { data: clonedData, error: res, valid: false };
2738
+ const context = reusableContext.active ? {
2739
+ active: false,
2740
+ depth: -1,
2741
+ depthExceeded: false,
2742
+ defaults: []
2743
+ } : reusableContext;
2744
+ context.active = true;
2745
+ context.depth = -1;
2746
+ context.depthExceeded = false;
2747
+ delete context.depthError;
2748
+ context.defaults.length = 0;
2749
+ this.validationContexts.push(context);
2750
+ const priorContext = depthGuardState.context;
2751
+ depthGuardState.context = context;
2752
+ let clonedData = data;
2753
+ try {
2754
+ clonedData = this.immutable ? deepCloneUnfreeze(data) : data;
2755
+ let error = compiledSchema.$validate(clonedData);
2756
+ if (this.isDepthError(error)) {
2757
+ this.rollbackDefaults(context, 0);
2758
+ error = context.depthError || this.depthError();
2759
+ }
2760
+ return error ? { data: clonedData, error, valid: false } : { data: clonedData, error: null, valid: true };
2761
+ } catch (error) {
2762
+ this.rollbackDefaults(context, 0);
2763
+ throw error;
2764
+ } finally {
2765
+ depthGuardState.context = priorContext;
2766
+ this.validationContexts.pop();
2767
+ context.active = false;
2095
2768
  }
2096
- return { data: clonedData, error: null, valid: true };
2097
2769
  };
2098
2770
  validate.compiledSchema = compiledSchema;
2099
2771
  return validate;
@@ -2196,7 +2868,7 @@ var SchemaShield = class {
2196
2868
  if (schema._hasRef === true) {
2197
2869
  return;
2198
2870
  }
2199
- Object.defineProperty(schema, "_hasRef", {
2871
+ definePropertyOrThrow(schema, "_hasRef", {
2200
2872
  value: true,
2201
2873
  enumerable: false,
2202
2874
  configurable: false,
@@ -2254,15 +2926,15 @@ var SchemaShield = class {
2254
2926
  return false;
2255
2927
  }
2256
2928
  }
2257
- hasRequiredDefaults(schema) {
2929
+ hasPropertyDefaults(schema) {
2258
2930
  const properties = schema.properties;
2259
2931
  if (!this.isPlainObject(properties)) {
2260
2932
  return false;
2261
2933
  }
2262
- const keys = Object.keys(properties);
2263
- for (let i = 0; i < keys.length; i++) {
2264
- const subSchema = properties[keys[i]];
2265
- if (this.isPlainObject(subSchema) && "default" in subSchema) {
2934
+ const propertyKeys = Object.keys(properties);
2935
+ for (let i = 0; i < propertyKeys.length; i++) {
2936
+ const subSchema = properties[propertyKeys[i]];
2937
+ if (this.isPlainObject(subSchema) && hasOwn(subSchema, "default")) {
2266
2938
  return true;
2267
2939
  }
2268
2940
  }
@@ -2271,24 +2943,134 @@ var SchemaShield = class {
2271
2943
  isDefaultTypeValidator(type, validator) {
2272
2944
  return Types[type] === validator;
2273
2945
  }
2274
- compileSchema(schema) {
2275
- if (!schema || typeof schema !== "object" || Array.isArray(schema)) {
2276
- if (schema === true) {
2277
- schema = { anyOf: [{}] };
2278
- } else if (schema === false) {
2279
- schema = { oneOf: [] };
2946
+ rollbackDefaults(context, start) {
2947
+ for (let index = context.defaults.length - 1; index >= start; index--) {
2948
+ const entry = context.defaults[index];
2949
+ if (entry.descriptor) {
2950
+ definePropertyOrThrow(entry.target, entry.key, entry.descriptor);
2280
2951
  } else {
2281
- schema = { oneOf: [schema] };
2952
+ delete entry.target[entry.key];
2282
2953
  }
2283
2954
  }
2955
+ context.defaults.length = start;
2956
+ }
2957
+ isDepthError(error) {
2958
+ const context = this.validationContexts[this.validationContexts.length - 1];
2959
+ if (context?.depthExceeded) {
2960
+ return true;
2961
+ }
2962
+ if (!(error instanceof ValidationError)) {
2963
+ return false;
2964
+ }
2965
+ return error.getCause().code === "MAX_DEPTH_EXCEEDED";
2966
+ }
2967
+ validateSubschema(schema, data) {
2968
+ if (!schema || typeof schema.$validate !== "function") {
2969
+ return;
2970
+ }
2971
+ const context = this.validationContexts[this.validationContexts.length - 1];
2972
+ const savepoint = context?.defaults.length || 0;
2973
+ try {
2974
+ const error = schema.$validate(data);
2975
+ if (error && context) {
2976
+ this.rollbackDefaults(context, savepoint);
2977
+ }
2978
+ return error;
2979
+ } catch (error) {
2980
+ if (context) {
2981
+ this.rollbackDefaults(context, savepoint);
2982
+ }
2983
+ throw error;
2984
+ }
2985
+ }
2986
+ installDepthGuards(root) {
2987
+ const state = { context: null };
2988
+ const stack = [root];
2989
+ const seen = /* @__PURE__ */ new WeakSet();
2990
+ while (stack.length > 0) {
2991
+ const schema = stack.pop();
2992
+ if (!schema || typeof schema !== "object" || seen.has(schema)) {
2993
+ continue;
2994
+ }
2995
+ seen.add(schema);
2996
+ if (typeof schema.$validate === "function") {
2997
+ const directValidate = schema.$validate;
2998
+ schema.$validate = getNamedFunction(directValidate.name, (data) => {
2999
+ const context = state.context;
3000
+ if (!context) {
3001
+ return directValidate(data);
3002
+ }
3003
+ const nextDepth = context.depth + 1;
3004
+ if (nextDepth > this.maxDepth) {
3005
+ context.depthExceeded = true;
3006
+ if (!context.depthError) {
3007
+ context.depthError = this.depthError();
3008
+ }
3009
+ return context.depthError;
3010
+ }
3011
+ context.depth = nextDepth;
3012
+ try {
3013
+ return directValidate(data);
3014
+ } finally {
3015
+ context.depth--;
3016
+ }
3017
+ });
3018
+ }
3019
+ const children = this.schemaChildren(schema);
3020
+ for (const child of children) {
3021
+ stack.push(child);
3022
+ }
3023
+ }
3024
+ return state;
3025
+ }
3026
+ compileSchema(schema) {
3027
+ if (schema === true) {
3028
+ return {
3029
+ $validate: getNamedFunction("Validate_True", () => {
3030
+ })
3031
+ };
3032
+ }
3033
+ if (schema === false) {
3034
+ const compiledFalse = {};
3035
+ const defineError = getDefinedErrorFunctionForKey(
3036
+ "oneOf",
3037
+ compiledFalse,
3038
+ this.failFast
3039
+ );
3040
+ compiledFalse.$validate = getNamedFunction(
3041
+ "Validate_False",
3042
+ (data) => defineError("Value is not valid", { data })
3043
+ );
3044
+ return compiledFalse;
3045
+ }
3046
+ const sourceSchema = schema && typeof schema === "object" && !Array.isArray(schema) ? schema : null;
3047
+ const schemaCanApplyDefaults = sourceSchema !== null && this.compilingMutableSchemas.has(sourceSchema);
3048
+ if (sourceSchema) {
3049
+ const cached = this.compileCache.get(sourceSchema);
3050
+ if (cached) {
3051
+ return cached;
3052
+ }
3053
+ }
3054
+ if (!schema || typeof schema !== "object" || Array.isArray(schema)) {
3055
+ schema = { oneOf: [schema] };
3056
+ }
2284
3057
  schema = this.normalizeSchemaForCompile(schema);
2285
3058
  const compiledSchema = deepCloneUnfreeze(
2286
3059
  schema
2287
3060
  );
2288
- let schemaHasRef = false;
2289
- if (typeof schema.$id === "string") {
2290
- this.idRegistry.set(schema.$id, compiledSchema);
3061
+ if (sourceSchema) {
3062
+ this.compileCache.set(sourceSchema, compiledSchema);
2291
3063
  }
3064
+ if (schemaCanApplyDefaults) {
3065
+ definePropertyOrThrow(compiledSchema, "_canApplyDefaults", {
3066
+ value: true,
3067
+ enumerable: false,
3068
+ configurable: false,
3069
+ writable: false
3070
+ });
3071
+ }
3072
+ const validateSubschema = this.compilingRequiresContext ? this.validateSubschema.bind(this) : void 0;
3073
+ let schemaHasRef = false;
2292
3074
  if ("$ref" in schema) {
2293
3075
  schemaHasRef = true;
2294
3076
  const refValidator = this.getKeyword("$ref");
@@ -2298,21 +3080,53 @@ var SchemaShield = class {
2298
3080
  schema["$ref"],
2299
3081
  this.failFast
2300
3082
  );
3083
+ const isBuiltinRef = refValidator === keywords.$ref;
2301
3084
  compiledSchema.$validate = getNamedFunction(
2302
- "Validate_Reference",
3085
+ isBuiltinRef ? "Validate_Reference" : refValidator.name || "$ref",
2303
3086
  (data) => refValidator(
2304
3087
  compiledSchema,
2305
3088
  data,
2306
3089
  defineError,
2307
- this
3090
+ this,
3091
+ validateSubschema
2308
3092
  )
2309
3093
  );
3094
+ if (!isBuiltinRef) {
3095
+ schemaHasRef = false;
3096
+ }
3097
+ }
3098
+ for (const key of ["definitions", "$defs"]) {
3099
+ const definitions = schema[key];
3100
+ if (!definitions || typeof definitions !== "object") {
3101
+ continue;
3102
+ }
3103
+ const compiledDefinitions = {};
3104
+ for (const definitionKey of Object.keys(definitions)) {
3105
+ compiledDefinitions[definitionKey] = this.compileSchema(
3106
+ definitions[definitionKey]
3107
+ );
3108
+ }
3109
+ compiledSchema[key] = compiledDefinitions;
3110
+ }
3111
+ if (schemaHasRef) {
3112
+ this.markSchemaHasRef(compiledSchema);
2310
3113
  }
2311
- this.markSchemaHasRef(compiledSchema);
2312
3114
  return compiledSchema;
2313
3115
  }
2314
3116
  const validators = [];
2315
3117
  const activeNames = [];
3118
+ const pendingCombinators = [];
3119
+ if (this.useDefaults !== false && this.getKeyword("properties") === keywords.properties && this.hasPropertyDefaults(schema)) {
3120
+ const applyDefaults = this.useDefaults === "empty" ? applyEmptyPropertyDefaults : applyPropertyDefaults;
3121
+ validators.push({
3122
+ name: applyDefaults.name,
3123
+ validate: getNamedFunction(
3124
+ applyDefaults.name,
3125
+ (data) => applyDefaults(compiledSchema, data, this)
3126
+ )
3127
+ });
3128
+ activeNames.push(applyDefaults.name);
3129
+ }
2316
3130
  if ("type" in schema) {
2317
3131
  const defineTypeError = getDefinedErrorFunctionForKey(
2318
3132
  "type",
@@ -2348,65 +3162,11 @@ var SchemaShield = class {
2348
3162
  if (typeFunctions.length === 1 && allTypesDefault) {
2349
3163
  const singleTypeName = defaultTypeNames[0];
2350
3164
  typeMethodName = singleTypeName;
2351
- switch (singleTypeName) {
2352
- case "object":
2353
- combinedTypeValidator = (data) => {
2354
- if (data === null || typeof data !== "object" || Array.isArray(data)) {
2355
- return defineTypeError("Invalid type", { data });
2356
- }
2357
- };
2358
- break;
2359
- case "array":
2360
- combinedTypeValidator = (data) => {
2361
- if (!Array.isArray(data)) {
2362
- return defineTypeError("Invalid type", { data });
2363
- }
2364
- };
2365
- break;
2366
- case "string":
2367
- combinedTypeValidator = (data) => {
2368
- if (typeof data !== "string") {
2369
- return defineTypeError("Invalid type", { data });
2370
- }
2371
- };
2372
- break;
2373
- case "number":
2374
- combinedTypeValidator = (data) => {
2375
- if (typeof data !== "number") {
2376
- return defineTypeError("Invalid type", { data });
2377
- }
2378
- };
2379
- break;
2380
- case "integer":
2381
- combinedTypeValidator = (data) => {
2382
- if (typeof data !== "number" || !Number.isInteger(data)) {
2383
- return defineTypeError("Invalid type", { data });
2384
- }
2385
- };
2386
- break;
2387
- case "boolean":
2388
- combinedTypeValidator = (data) => {
2389
- if (typeof data !== "boolean") {
2390
- return defineTypeError("Invalid type", { data });
2391
- }
2392
- };
2393
- break;
2394
- case "null":
2395
- combinedTypeValidator = (data) => {
2396
- if (data !== null) {
2397
- return defineTypeError("Invalid type", { data });
2398
- }
2399
- };
2400
- break;
2401
- default: {
2402
- const singleTypeFn = typeFunctions[0];
2403
- combinedTypeValidator = (data) => {
2404
- if (!singleTypeFn(data)) {
2405
- return defineTypeError("Invalid type", { data });
2406
- }
2407
- };
2408
- }
2409
- }
3165
+ combinedTypeValidator = this.failFast && FAIL_FAST_TYPE_VALIDATORS[singleTypeName] ? FAIL_FAST_TYPE_VALIDATORS[singleTypeName] : createBuiltinTypeValidator(
3166
+ singleTypeName,
3167
+ defineTypeError,
3168
+ typeFunctions[0]
3169
+ );
2410
3170
  } else if (typeFunctions.length > 1 && allTypesDefault) {
2411
3171
  typeMethodName = defaultTypeNames.join("_OR_");
2412
3172
  const allowsObject = defaultTypeNames.includes("object");
@@ -2419,6 +3179,9 @@ var SchemaShield = class {
2419
3179
  combinedTypeValidator = (data) => {
2420
3180
  const dataType = typeof data;
2421
3181
  if (dataType === "number") {
3182
+ if (!Number.isFinite(data)) {
3183
+ return defineTypeError("Invalid type", { data });
3184
+ }
2422
3185
  if (allowsNumber || allowsInteger && Number.isInteger(data)) {
2423
3186
  return;
2424
3187
  }
@@ -2482,7 +3245,8 @@ var SchemaShield = class {
2482
3245
  activeNames.push(typeMethodName);
2483
3246
  }
2484
3247
  const { type, $id, $ref, $validate, required, ...otherKeys } = schema;
2485
- const keyOrder = required ? this.hasRequiredDefaults(schema) ? [...Object.keys(otherKeys), "required"] : ["required", ...Object.keys(otherKeys)] : Object.keys(otherKeys);
3248
+ const otherKeyNames = Object.keys(otherKeys);
3249
+ const keyOrder = required ? ["required", ...otherKeyNames] : otherKeyNames;
2486
3250
  for (const key of keyOrder) {
2487
3251
  const keywordFn = this.getKeyword(key);
2488
3252
  if (!keywordFn) {
@@ -2497,12 +3261,33 @@ var SchemaShield = class {
2497
3261
  this.failFast
2498
3262
  );
2499
3263
  const fnName = keywordFn.name || key;
3264
+ if ((key === "allOf" || key === "anyOf" || key === "oneOf") && keywordFn === keywords[key]) {
3265
+ const item = {
3266
+ name: fnName,
3267
+ validate: () => {
3268
+ throw new ValidationError("Combinator validator was not prepared");
3269
+ }
3270
+ };
3271
+ validators.push(item);
3272
+ pendingCombinators.push({ item, key, defineError });
3273
+ activeNames.push(fnName);
3274
+ continue;
3275
+ }
3276
+ const keywordValidate = validateSubschema ? (data) => keywordFn(
3277
+ compiledSchema,
3278
+ data,
3279
+ defineError,
3280
+ this,
3281
+ validateSubschema
3282
+ ) : (data) => keywordFn(
3283
+ compiledSchema,
3284
+ data,
3285
+ defineError,
3286
+ this
3287
+ );
2500
3288
  validators.push({
2501
3289
  name: fnName,
2502
- validate: getNamedFunction(
2503
- fnName,
2504
- (data) => keywordFn(compiledSchema, data, defineError, this)
2505
- )
3290
+ validate: getNamedFunction(fnName, keywordValidate)
2506
3291
  });
2507
3292
  activeNames.push(fnName);
2508
3293
  }
@@ -2544,6 +3329,50 @@ var SchemaShield = class {
2544
3329
  continue;
2545
3330
  }
2546
3331
  }
3332
+ if (this.isPlainObject(schema.properties)) {
3333
+ definePropertyOrThrow(compiledSchema, "_propKeys", {
3334
+ value: Object.keys(schema.properties),
3335
+ enumerable: false,
3336
+ configurable: false,
3337
+ writable: false
3338
+ });
3339
+ }
3340
+ if (this.useDefaults !== false && this.isPlainObject(schema.properties) && this.hasPropertyDefaults(schema)) {
3341
+ const defaultKeys = Object.keys(schema.properties).filter(
3342
+ (key) => {
3343
+ const property = schema.properties[key];
3344
+ return property && typeof property === "object" && !Array.isArray(property) && hasOwn(property, "default");
3345
+ }
3346
+ );
3347
+ if (defaultKeys.length > 0) {
3348
+ definePropertyOrThrow(compiledSchema, "_defaultKeys", {
3349
+ value: defaultKeys,
3350
+ enumerable: false,
3351
+ configurable: false,
3352
+ writable: false
3353
+ });
3354
+ }
3355
+ }
3356
+ prepareCombinatorEntries(compiledSchema);
3357
+ for (let index = 0; index < pendingCombinators.length; index++) {
3358
+ const pending = pendingCombinators[index];
3359
+ const transactions = compiledSchema._canApplyDefaults === true ? {
3360
+ savepoint: () => this.#defaultSavepoint(),
3361
+ rollback: (savepoint) => this.#rollbackDefaultSavepoint(savepoint),
3362
+ capture: (savepoint) => this.#captureDefaultSavepoint(savepoint),
3363
+ restore: (mutations) => this.#restoreDefaults(mutations)
3364
+ } : void 0;
3365
+ pending.item.validate = getNamedFunction(
3366
+ pending.item.name,
3367
+ createCombinatorValidator(
3368
+ pending.key,
3369
+ compiledSchema,
3370
+ pending.defineError,
3371
+ validateSubschema,
3372
+ transactions
3373
+ )
3374
+ );
3375
+ }
2547
3376
  if (schemaHasRef) {
2548
3377
  this.markSchemaHasRef(compiledSchema);
2549
3378
  }
@@ -2585,54 +3414,80 @@ var SchemaShield = class {
2585
3414
  }
2586
3415
  return false;
2587
3416
  }
2588
- linkReferences(root) {
2589
- const stack = [root];
2590
- while (stack.length > 0) {
2591
- const node = stack.pop();
2592
- if (!node || typeof node !== "object")
3417
+ getCompiledReferenceTarget(ref, position, registry) {
3418
+ const resolvedUri = this.resolveUri(ref, position.baseUri, "$ref");
3419
+ const exactTarget = registry.aliases.get(resolvedUri);
3420
+ if (exactTarget) {
3421
+ return this.compileCache.get(exactTarget);
3422
+ }
3423
+ const resourceRoot = registry.aliases.get(this.resourceUri(resolvedUri));
3424
+ if (!resourceRoot) {
3425
+ return;
3426
+ }
3427
+ const compiledResource = this.compileCache.get(resourceRoot);
3428
+ if (!compiledResource) {
3429
+ return;
3430
+ }
3431
+ const hashIndex = resolvedUri.indexOf("#");
3432
+ const fragment = hashIndex === -1 ? "" : resolvedUri.slice(hashIndex + 1);
3433
+ if (fragment.length === 0) {
3434
+ return compiledResource;
3435
+ }
3436
+ if (fragment.startsWith("/")) {
3437
+ return resolvePath(compiledResource, `#${fragment}`);
3438
+ }
3439
+ return;
3440
+ }
3441
+ linkReferences(registry) {
3442
+ for (let index = 0; index < registry.positions.length; index++) {
3443
+ const position = registry.positions[index];
3444
+ if (typeof position.source.$ref !== "string" || this.getKeyword("$ref") !== keywords.$ref) {
2593
3445
  continue;
2594
- if (typeof node.$ref === "string" && typeof node.$validate === "function" && node.$validate.name === "Validate_Reference") {
2595
- const refPath = node.$ref;
2596
- let target = this.getSchemaRef(refPath);
2597
- if (typeof target === "undefined") {
2598
- target = this.getSchemaById(refPath);
2599
- }
2600
- if (typeof target === "boolean") {
2601
- if (target === true) {
2602
- node.$validate = getNamedFunction("Validate_Ref_True", () => {
2603
- });
2604
- } else {
2605
- const defineError = getDefinedErrorFunctionForKey(
2606
- "$ref",
2607
- node,
2608
- this.failFast
2609
- );
2610
- node.$validate = getNamedFunction(
2611
- "Validate_Ref_False",
2612
- (_data) => defineError("Value is not valid")
2613
- );
2614
- }
2615
- continue;
2616
- }
2617
- if (target && typeof target.$validate === "function") {
2618
- node.$validate = target.$validate;
2619
- }
2620
3446
  }
2621
- for (const key in node) {
2622
- const value = node[key];
2623
- if (!value)
2624
- continue;
2625
- if (Array.isArray(value)) {
2626
- for (let i = 0; i < value.length; i++) {
2627
- const v = value[i];
2628
- if (v && typeof v === "object") {
2629
- stack.push(v);
3447
+ const node = this.compileCache.get(position.source);
3448
+ const target = this.getCompiledReferenceTarget(
3449
+ position.source.$ref,
3450
+ position,
3451
+ registry
3452
+ );
3453
+ if (!node || typeof target === "undefined") {
3454
+ const error = new ValidationError(
3455
+ `Reference not found: ${position.source.$ref}`
3456
+ );
3457
+ error.code = "REFERENCE_NOT_FOUND";
3458
+ error.keyword = "$ref";
3459
+ throw error;
3460
+ }
3461
+ let targetValidate;
3462
+ if (target === true) {
3463
+ targetValidate = getNamedFunction("Validate_Ref_True", () => {
3464
+ });
3465
+ } else if (target === false) {
3466
+ const defineError = getDefinedErrorFunctionForKey(
3467
+ "$ref",
3468
+ node,
3469
+ this.failFast
3470
+ );
3471
+ targetValidate = getNamedFunction(
3472
+ "Validate_Ref_False",
3473
+ (data) => defineError("Value is not valid", { data })
3474
+ );
3475
+ } else {
3476
+ if (typeof target.$validate !== "function") {
3477
+ target.$validate = getNamedFunction(
3478
+ "Validate_Ref_Any",
3479
+ () => {
2630
3480
  }
2631
- }
2632
- } else if (typeof value === "object") {
2633
- stack.push(value);
3481
+ );
2634
3482
  }
3483
+ targetValidate = target.$validate;
2635
3484
  }
3485
+ definePropertyOrThrow(node, "_resolvedRef", {
3486
+ value: targetValidate,
3487
+ enumerable: false,
3488
+ configurable: false,
3489
+ writable: false
3490
+ });
2636
3491
  }
2637
3492
  }
2638
3493
  };