schema-shield 0.0.6 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +219 -65
  2. package/dist/formats.d.ts.map +1 -1
  3. package/dist/index.d.ts +25 -6
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +1837 -484
  6. package/dist/index.min.js +1 -1
  7. package/dist/index.min.js.map +1 -1
  8. package/dist/index.mjs +1837 -484
  9. package/dist/keywords/array-keywords.d.ts.map +1 -1
  10. package/dist/keywords/object-keywords.d.ts.map +1 -1
  11. package/dist/keywords/other-keywords.d.ts.map +1 -1
  12. package/dist/keywords/string-keywords.d.ts.map +1 -1
  13. package/dist/types.d.ts.map +1 -1
  14. package/dist/utils/deep-freeze.d.ts +5 -0
  15. package/dist/utils/deep-freeze.d.ts.map +1 -0
  16. package/dist/utils/has-changed.d.ts +2 -0
  17. package/dist/utils/has-changed.d.ts.map +1 -0
  18. package/dist/utils/index.d.ts +5 -0
  19. package/dist/utils/index.d.ts.map +1 -0
  20. package/dist/{utils.d.ts → utils/main-utils.d.ts} +7 -9
  21. package/dist/utils/main-utils.d.ts.map +1 -0
  22. package/dist/utils/pattern-matcher.d.ts +3 -0
  23. package/dist/utils/pattern-matcher.d.ts.map +1 -0
  24. package/lib/formats.ts +468 -155
  25. package/lib/index.ts +702 -107
  26. package/lib/keywords/array-keywords.ts +260 -52
  27. package/lib/keywords/number-keywords.ts +1 -1
  28. package/lib/keywords/object-keywords.ts +295 -88
  29. package/lib/keywords/other-keywords.ts +263 -70
  30. package/lib/keywords/string-keywords.ts +123 -7
  31. package/lib/types.ts +5 -18
  32. package/lib/utils/deep-freeze.ts +208 -0
  33. package/lib/utils/has-changed.ts +51 -0
  34. package/lib/utils/index.ts +4 -0
  35. package/lib/{utils.ts → utils/main-utils.ts} +63 -77
  36. package/lib/utils/pattern-matcher.ts +66 -0
  37. package/package.json +2 -2
  38. package/tsconfig.json +4 -4
  39. package/dist/utils.d.ts.map +0 -1
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- // lib/utils.ts
1
+ // lib/utils/main-utils.ts
2
2
  var ValidationError = class extends Error {
3
3
  message;
4
4
  item;
@@ -53,14 +53,18 @@ var ValidationError = class extends Error {
53
53
  };
54
54
  }
55
55
  };
56
- function getDefinedErrorFunctionForKey(key, schema) {
56
+ var FAIL_FAST_DEFINE_ERROR = () => true;
57
+ function getDefinedErrorFunctionForKey(key, schema, failFast) {
58
+ if (failFast) {
59
+ return FAIL_FAST_DEFINE_ERROR;
60
+ }
57
61
  const KeywordError = new ValidationError(`Invalid ${key}`);
58
62
  KeywordError.keyword = key;
59
63
  KeywordError.schema = schema;
60
64
  const defineError = (message, options = {}) => {
61
65
  KeywordError.message = message;
62
66
  KeywordError.item = options.item;
63
- KeywordError.cause = options.cause;
67
+ KeywordError.cause = options.cause && options.cause !== true ? options.cause : void 0;
64
68
  KeywordError.data = options.data;
65
69
  return KeywordError;
66
70
  };
@@ -69,216 +73,394 @@ function getDefinedErrorFunctionForKey(key, schema) {
69
73
  defineError
70
74
  );
71
75
  }
72
- function deepEqual(obj, other) {
73
- if (Array.isArray(obj) && Array.isArray(other)) {
74
- if (obj.length !== other.length) {
75
- return false;
76
+ function isCompiledSchema(subSchema) {
77
+ return !!subSchema && typeof subSchema === "object" && !Array.isArray(subSchema) && "$validate" in subSchema;
78
+ }
79
+ function getNamedFunction(name, fn) {
80
+ return Object.defineProperty(fn, "name", { value: name });
81
+ }
82
+ function resolvePath(root, path) {
83
+ if (!path || path === "#") {
84
+ return root;
85
+ }
86
+ if (path.startsWith("#/")) {
87
+ const parts = path.split("/").slice(1);
88
+ let current = root;
89
+ for (const part of parts) {
90
+ const decodedUriPart = decodeURIComponent(part);
91
+ const key = decodedUriPart.replace(/~1/g, "/").replace(/~0/g, "~");
92
+ if (current && typeof current === "object" && key in current) {
93
+ current = current[key];
94
+ } else {
95
+ return;
96
+ }
76
97
  }
77
- for (let i = 0; i < obj.length; i++) {
78
- if (!deepEqual(obj[i], other[i])) {
79
- return false;
98
+ return current;
99
+ }
100
+ if (!path.includes("#")) {
101
+ if (root.definitions && root.definitions[path]) {
102
+ return root.definitions[path];
103
+ }
104
+ if (root.defs && root.defs[path]) {
105
+ return root.defs[path];
106
+ }
107
+ if (root.$id && typeof root.$id === "string") {
108
+ if (root.$id === path || root.$id.endsWith("/" + path)) {
109
+ return root;
80
110
  }
81
111
  }
82
- return true;
83
112
  }
84
- if (typeof obj === "object" && typeof other === "object") {
85
- if (obj === null || other === null) {
86
- return obj === other;
113
+ return;
114
+ }
115
+ function areCloseEnough(a, b, epsilon = 1e-15) {
116
+ return Math.abs(a - b) <= epsilon * Math.max(Math.abs(a), Math.abs(b));
117
+ }
118
+
119
+ // lib/formats.ts
120
+ var UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
121
+ var DURATION_REGEX = /^P(?!$)((\d+Y)?(\d+M)?(\d+W)?(\d+D)?)(T(?=\d)(\d+H)?(\d+M)?(\d+S)?)?$/;
122
+ var URI_REGEX = /^[a-zA-Z][a-zA-Z0-9+\-.]*:[^\s]*$/;
123
+ var EMAIL_REGEX = /^(?!\.)(?!.*\.$)[a-z0-9!#$%&'*+/=?^_`{|}~-]{1,20}(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]{1,21}){0,2}@[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,60}[a-z0-9])?){0,3}$/i;
124
+ var HOSTNAME_REGEX = /^[a-z0-9][a-z0-9-]{0,62}(?:\.[a-z0-9][a-z0-9-]{0,62})*[a-z0-9]$/i;
125
+ var DATE_REGEX = /^(\d{4})-(\d{2})-(\d{2})$/;
126
+ var TIME_REGEX = /^([01]\d|2[0-3]):([0-5]\d):([0-5]\d)(\.\d+)?(Z|([+-])([01]\d|2[0-3]):([0-5]\d))$/;
127
+ var URI_REFERENCE_REGEX = /^(([^:/?#]+):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#((?![^#]*\\)[^#]*))?/i;
128
+ var IRI_REGEX = /^[a-zA-Z][a-zA-Z0-9+\-.]*:[^\s]*$/;
129
+ var IRI_REFERENCE_REGEX = /^(([^:/?#]+):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#((?![^#]*\\)[^#]*))?/i;
130
+ var IDN_EMAIL_REGEX = /^[^@\s]+@[^@\s]+\.[^@\s]+$/;
131
+ var IDN_HOSTNAME_REGEX = /^[^\s!@#$%^&*()_+\=\[\]{};':"\\|,<>\/?]+$/;
132
+ var DAYS_IN_MONTH = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
133
+ function isDigitCharCode(code) {
134
+ return code >= 48 && code <= 57;
135
+ }
136
+ function parseTwoDigits(data, index) {
137
+ const first = data.charCodeAt(index) - 48;
138
+ const second = data.charCodeAt(index + 1) - 48;
139
+ if (first < 0 || first > 9 || second < 0 || second > 9) {
140
+ return -1;
141
+ }
142
+ return first * 10 + second;
143
+ }
144
+ function parseFourDigits(data, index) {
145
+ const a = data.charCodeAt(index) - 48;
146
+ const b = data.charCodeAt(index + 1) - 48;
147
+ const c = data.charCodeAt(index + 2) - 48;
148
+ const d = data.charCodeAt(index + 3) - 48;
149
+ if (a < 0 || a > 9 || b < 0 || b > 9 || c < 0 || c > 9 || d < 0 || d > 9) {
150
+ return -1;
151
+ }
152
+ return a * 1e3 + b * 100 + c * 10 + d;
153
+ }
154
+ function isValidIpv4Range(data, start, end) {
155
+ let segmentCount = 0;
156
+ let segmentStart = start;
157
+ for (let i = start; i <= end; i++) {
158
+ if (i !== end && data.charCodeAt(i) !== 46) {
159
+ continue;
160
+ }
161
+ const segmentLength = i - segmentStart;
162
+ if (segmentLength < 1 || segmentLength > 3) {
163
+ return false;
87
164
  }
88
- const keys = Object.keys(obj);
89
- if (keys.length !== Object.keys(other).length) {
165
+ if (segmentLength > 1 && data.charCodeAt(segmentStart) === 48) {
90
166
  return false;
91
167
  }
92
- for (const key of keys) {
93
- if (!deepEqual(obj[key], other[key])) {
168
+ let value = 0;
169
+ for (let j = segmentStart; j < i; j++) {
170
+ const digit = data.charCodeAt(j) - 48;
171
+ if (digit < 0 || digit > 9) {
94
172
  return false;
95
173
  }
174
+ value = value * 10 + digit;
96
175
  }
97
- return true;
176
+ if (value > 255) {
177
+ return false;
178
+ }
179
+ segmentCount++;
180
+ segmentStart = i + 1;
98
181
  }
99
- return obj === other;
182
+ return segmentCount === 4;
100
183
  }
101
- function isObject(data) {
102
- return typeof data === "object" && data !== null && !Array.isArray(data);
184
+ function isValidIpv4(data) {
185
+ return isValidIpv4Range(data, 0, data.length);
103
186
  }
104
- function areCloseEnough(a, b, epsilon = 1e-15) {
105
- return Math.abs(a - b) <= epsilon * Math.max(Math.abs(a), Math.abs(b));
187
+ function isHexCharCode(code) {
188
+ return code >= 48 && code <= 57 || code >= 65 && code <= 70 || code >= 97 && code <= 102;
106
189
  }
107
- function deepClone(obj) {
108
- if (Array.isArray(obj)) {
109
- const result = [];
110
- for (let i = 0; i < obj.length; i++) {
111
- result[i] = deepClone(obj[i]);
190
+ function isValidIpv6(data) {
191
+ const length = data.length;
192
+ if (length === 0) {
193
+ return false;
194
+ }
195
+ let hasColon = false;
196
+ let hasDoubleColon = false;
197
+ let hextetCount = 0;
198
+ let i = 0;
199
+ while (i < length) {
200
+ if (data.charCodeAt(i) === 58) {
201
+ hasColon = true;
202
+ if (i + 1 < length && data.charCodeAt(i + 1) === 58) {
203
+ if (hasDoubleColon) {
204
+ return false;
205
+ }
206
+ hasDoubleColon = true;
207
+ i += 2;
208
+ if (i === length) {
209
+ break;
210
+ }
211
+ continue;
212
+ }
213
+ return false;
214
+ }
215
+ const segmentStart = i;
216
+ let segmentLength = 0;
217
+ while (i < length && isHexCharCode(data.charCodeAt(i))) {
218
+ segmentLength++;
219
+ if (segmentLength > 4) {
220
+ return false;
221
+ }
222
+ i++;
223
+ }
224
+ if (segmentLength === 0) {
225
+ return false;
226
+ }
227
+ if (i < length && data.charCodeAt(i) === 46) {
228
+ if (!hasColon) {
229
+ return false;
230
+ }
231
+ if (!isValidIpv4Range(data, segmentStart, length)) {
232
+ return false;
233
+ }
234
+ if (hasDoubleColon) {
235
+ return hextetCount < 6;
236
+ }
237
+ return hextetCount === 6;
238
+ }
239
+ hextetCount++;
240
+ if (hextetCount > 8) {
241
+ return false;
242
+ }
243
+ if (i === length) {
244
+ break;
245
+ }
246
+ if (data.charCodeAt(i) !== 58) {
247
+ return false;
248
+ }
249
+ hasColon = true;
250
+ i++;
251
+ if (i === length) {
252
+ return false;
253
+ }
254
+ if (data.charCodeAt(i) === 58) {
255
+ if (hasDoubleColon) {
256
+ return false;
257
+ }
258
+ hasDoubleColon = true;
259
+ i++;
260
+ if (i === length) {
261
+ break;
262
+ }
112
263
  }
113
- return result;
114
264
  }
115
- if (obj && obj.constructor && obj.constructor.name !== "Object") {
116
- return obj;
265
+ if (!hasColon) {
266
+ return false;
117
267
  }
118
- if (isObject(obj)) {
119
- const result = {
120
- ...obj
121
- };
122
- for (const key in obj) {
123
- result[key] = deepClone(obj[key]);
268
+ if (hasDoubleColon) {
269
+ return hextetCount < 8;
270
+ }
271
+ return hextetCount === 8;
272
+ }
273
+ function isValidJsonPointer(data) {
274
+ if (data === "") {
275
+ return true;
276
+ }
277
+ if (data.charCodeAt(0) !== 47) {
278
+ return false;
279
+ }
280
+ for (let i = 1; i < data.length; i++) {
281
+ if (data.charCodeAt(i) !== 126) {
282
+ continue;
283
+ }
284
+ const next = data.charCodeAt(i + 1);
285
+ if (next !== 48 && next !== 49) {
286
+ return false;
124
287
  }
125
- return result;
288
+ i++;
126
289
  }
127
- return obj;
290
+ return true;
128
291
  }
129
- function isCompiledSchema(subSchema) {
130
- return isObject(subSchema) && "$validate" in subSchema;
292
+ function isValidRelativeJsonPointer(data) {
293
+ if (data.length === 0) {
294
+ return true;
295
+ }
296
+ let i = 0;
297
+ while (i < data.length) {
298
+ const code = data.charCodeAt(i);
299
+ if (code < 48 || code > 57) {
300
+ break;
301
+ }
302
+ i++;
303
+ }
304
+ if (i === 0) {
305
+ return false;
306
+ }
307
+ if (i === data.length) {
308
+ return true;
309
+ }
310
+ if (data.charCodeAt(i) === 35) {
311
+ return i + 1 === data.length;
312
+ }
313
+ if (data.charCodeAt(i) !== 47) {
314
+ return false;
315
+ }
316
+ for (i = i + 1; i < data.length; i++) {
317
+ if (data.charCodeAt(i) !== 126) {
318
+ continue;
319
+ }
320
+ const next = data.charCodeAt(i + 1);
321
+ if (next !== 48 && next !== 49) {
322
+ return false;
323
+ }
324
+ i++;
325
+ }
326
+ return true;
131
327
  }
132
- function getNamedFunction(name, fn) {
133
- return Object.defineProperty(fn, "name", { value: name });
328
+ function isValidUriTemplate(data) {
329
+ for (let i = 0; i < data.length; i++) {
330
+ const code = data.charCodeAt(i);
331
+ if (code === 125) {
332
+ return false;
333
+ }
334
+ if (code !== 123) {
335
+ continue;
336
+ }
337
+ const closeIndex = data.indexOf("}", i + 1);
338
+ if (closeIndex === -1 || closeIndex === i + 1) {
339
+ return false;
340
+ }
341
+ i = closeIndex;
342
+ }
343
+ return true;
134
344
  }
135
-
136
- // lib/formats.ts
137
345
  var Formats = {
138
346
  ["date-time"](data) {
139
- const match = data.match(
140
- /^(\d{4})-(0[0-9]|1[0-2])-(\d{2})T(0[0-9]|1\d|2[0-3]):([0-5]\d):((?:[0-5]\d|60))(?:.\d+)?(?:([+-])(0[0-9]|1\d|2[0-3]):([0-5]\d)|Z)?$/i
141
- );
142
- if (!match) {
347
+ const length = data.length;
348
+ if (length < 19) {
349
+ return false;
350
+ }
351
+ if (data.charCodeAt(4) !== 45 || data.charCodeAt(7) !== 45 || data.charCodeAt(13) !== 58 || data.charCodeAt(16) !== 58) {
352
+ return false;
353
+ }
354
+ const tCode = data.charCodeAt(10);
355
+ if (tCode !== 84 && tCode !== 116) {
143
356
  return false;
144
357
  }
145
- let day = Number(match[3]);
146
- if (match[2] === "02" && day > 29) {
358
+ const year = parseFourDigits(data, 0);
359
+ const month = parseTwoDigits(data, 5);
360
+ const day = parseTwoDigits(data, 8);
361
+ const hour = parseTwoDigits(data, 11);
362
+ const minute = parseTwoDigits(data, 14);
363
+ const second = parseTwoDigits(data, 17);
364
+ if (year < 0 || month < 0 || day < 0 || hour < 0 || minute < 0 || second < 0) {
147
365
  return false;
148
366
  }
149
- const [
150
- ,
151
- yearStr,
152
- monthStr,
153
- ,
154
- hourStr,
155
- minuteStr,
156
- secondStr,
157
- timezoneSign,
158
- timezoneHourStr,
159
- timezoneMinuteStr
160
- ] = match;
161
- let year = Number(yearStr);
162
- let month = Number(monthStr);
163
- let hour = Number(hourStr);
164
- let minute = Number(minuteStr);
165
- let second = Number(secondStr);
166
- if (timezoneSign === "-" || timezoneSign === "+") {
167
- const timezoneHour = Number(timezoneHourStr);
168
- const timezoneMinute = Number(timezoneMinuteStr);
169
- if (timezoneSign === "-") {
170
- hour += timezoneHour;
171
- minute += timezoneMinute;
172
- } else if (timezoneSign === "+") {
173
- hour -= timezoneHour;
174
- minute -= timezoneMinute;
175
- }
176
- if (minute > 59) {
177
- hour += 1;
178
- minute -= 60;
179
- } else if (minute < 0) {
180
- hour -= 1;
181
- minute += 60;
182
- }
183
- if (hour > 23) {
184
- day += 1;
185
- hour -= 24;
186
- } else if (hour < 0) {
187
- day -= 1;
188
- hour += 24;
189
- }
190
- if (day > 31) {
191
- month += 1;
192
- day -= 31;
193
- } else if (day < 1) {
194
- month -= 1;
195
- day += 31;
196
- }
197
- if (month > 12) {
198
- year += 1;
199
- month -= 12;
200
- } else if (month < 1) {
201
- year -= 1;
202
- month += 12;
203
- }
204
- if (year < 0) {
367
+ if (hour > 23 || minute > 59 || second > 60) {
368
+ return false;
369
+ }
370
+ let cursor = 19;
371
+ let offsetSign = null;
372
+ let offsetHour = 0;
373
+ let offsetMinute = 0;
374
+ if (cursor < length && data.charCodeAt(cursor) === 46) {
375
+ cursor++;
376
+ const fracStart = cursor;
377
+ while (cursor < length && isDigitCharCode(data.charCodeAt(cursor))) {
378
+ cursor++;
379
+ }
380
+ if (cursor === fracStart) {
381
+ return false;
382
+ }
383
+ }
384
+ if (cursor < length) {
385
+ const tzCode = data.charCodeAt(cursor);
386
+ if (tzCode === 90 || tzCode === 122) {
387
+ cursor++;
388
+ } else if (tzCode === 43 || tzCode === 45) {
389
+ offsetSign = tzCode === 43 ? "+" : "-";
390
+ if (cursor + 6 > length || data.charCodeAt(cursor + 3) !== 58) {
391
+ return false;
392
+ }
393
+ offsetHour = parseTwoDigits(data, cursor + 1);
394
+ offsetMinute = parseTwoDigits(data, cursor + 4);
395
+ if (offsetHour < 0 || offsetMinute < 0 || offsetHour > 23 || offsetMinute > 59) {
396
+ return false;
397
+ }
398
+ cursor += 6;
399
+ } else {
205
400
  return false;
206
401
  }
207
402
  }
208
- const daysInMonth = [31, , 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
209
- const maxDays = month === 2 ? year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0) ? 29 : 28 : daysInMonth[month - 1];
210
- if (day > maxDays) {
403
+ if (cursor !== length) {
404
+ return false;
405
+ }
406
+ if (month < 1 || month > 12) {
211
407
  return false;
212
408
  }
213
- if (second === 60 && (minute !== 59 || hour !== 23)) {
409
+ if (day < 1) {
214
410
  return false;
215
411
  }
412
+ const maxDays = month === 2 ? year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0) ? 29 : 28 : DAYS_IN_MONTH[month - 1];
413
+ if (!maxDays || day > maxDays) {
414
+ return false;
415
+ }
416
+ if (second === 60) {
417
+ let utcTotalMinutes = hour * 60 + minute;
418
+ if (offsetSign) {
419
+ const offsetTotalMinutes = offsetHour * 60 + offsetMinute;
420
+ utcTotalMinutes += offsetSign === "+" ? -offsetTotalMinutes : offsetTotalMinutes;
421
+ utcTotalMinutes %= 24 * 60;
422
+ if (utcTotalMinutes < 0) {
423
+ utcTotalMinutes += 24 * 60;
424
+ }
425
+ }
426
+ if (utcTotalMinutes !== 23 * 60 + 59) {
427
+ return false;
428
+ }
429
+ }
216
430
  return true;
217
431
  },
218
432
  uri(data) {
219
- return /^[a-zA-Z][a-zA-Z0-9+\-.]*:[^\s]*$/.test(data);
433
+ return URI_REGEX.test(data);
220
434
  },
221
435
  email(data) {
222
- return /^(?!\.)(?!.*\.$)[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.test(
223
- data
224
- );
436
+ return EMAIL_REGEX.test(data);
225
437
  },
226
438
  ipv4(data) {
227
- return /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])$/.test(
228
- data
229
- );
439
+ return isValidIpv4(data);
230
440
  },
231
- // ipv6: isMyIpValid({ version: 6 }),
232
441
  ipv6(data) {
233
- if (data === "::") {
234
- return true;
235
- }
236
- if (data.indexOf(":") === -1 || /(?:\s+|:::+|^\w{5,}|\w{5}$|^:{1}\w|\w:{1}$)/.test(data)) {
237
- return false;
238
- }
239
- const hasIpv4 = data.indexOf(".") !== -1;
240
- let addressParts = data;
241
- if (hasIpv4) {
242
- addressParts = data.split(":");
243
- const ipv4Part = addressParts.pop();
244
- if (!/^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])$/.test(
245
- ipv4Part
246
- )) {
247
- return false;
248
- }
249
- }
250
- const isShortened = data.indexOf("::") !== -1;
251
- const ipv6Part = hasIpv4 ? addressParts.join(":") : data;
252
- if (isShortened) {
253
- if (ipv6Part.split("::").length - 1 > 1) {
254
- return false;
255
- }
256
- if (!/^[0-9a-fA-F:.]*$/.test(ipv6Part)) {
257
- return false;
258
- }
259
- return /^(?:(?:(?:[0-9a-fA-F]{1,4}(?::|$)){1,6}))|(?:::(?:[0-9a-fA-F]{1,4})){0,5}$/.test(
260
- ipv6Part
261
- );
262
- }
263
- const isIpv6Valid = /^(?:(?:[0-9a-fA-F]{1,4}:){7}(?:[0-9a-fA-F]{1,4}|:))$/.test(ipv6Part);
264
- const hasInvalidChar = /(?:[0-9a-fA-F]{5,}|\D[0-9a-fA-F]{3}:)/.test(
265
- ipv6Part
266
- );
267
- if (hasIpv4) {
268
- return isIpv6Valid || !hasInvalidChar;
269
- }
270
- return isIpv6Valid && !hasInvalidChar;
442
+ return isValidIpv6(data);
271
443
  },
272
444
  hostname(data) {
273
- return /^[a-z0-9][a-z0-9-]{0,62}(?:\.[a-z0-9][a-z0-9-]{0,62})*[a-z0-9]$/i.test(
274
- data
275
- );
445
+ return HOSTNAME_REGEX.test(data);
276
446
  },
277
447
  date(data) {
278
- if (/^(\d{4})-(\d{2})-(\d{2})$/.test(data) === false) {
448
+ const match = DATE_REGEX.exec(data);
449
+ if (!match) {
279
450
  return false;
280
451
  }
281
- return !isNaN(new Date(data).getTime());
452
+ const [, yearStr, monthStr, dayStr] = match;
453
+ const year = Number(yearStr);
454
+ const month = Number(monthStr);
455
+ const day = Number(dayStr);
456
+ if (month < 1 || month > 12) {
457
+ return false;
458
+ }
459
+ if (day < 1) {
460
+ return false;
461
+ }
462
+ const maxDays = month === 2 ? year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0) ? 29 : 28 : DAYS_IN_MONTH[month - 1];
463
+ return !!maxDays && day <= maxDays;
282
464
  },
283
465
  regex(data) {
284
466
  try {
@@ -289,54 +471,55 @@ var Formats = {
289
471
  }
290
472
  },
291
473
  "json-pointer"(data) {
292
- if (data === "") {
293
- return true;
294
- }
295
- return /^\/(?:[^~]|~0|~1)*$/.test(data);
474
+ return isValidJsonPointer(data);
296
475
  },
297
476
  "relative-json-pointer"(data) {
298
- if (data === "") {
299
- return true;
300
- }
301
- return /^([0-9]+)(#|\/(?:[^~]|~0|~1)*)?$/.test(data);
477
+ return isValidRelativeJsonPointer(data);
302
478
  },
303
479
  time(data) {
304
- return /^(\d{2}):(\d{2}):(\d{2})(\.\d+)?(Z|([+-])(\d{2}):(\d{2}))$/.test(
305
- data
306
- );
480
+ return TIME_REGEX.test(data);
307
481
  },
308
482
  "uri-reference"(data) {
309
- if (/\\/.test(data)) {
483
+ if (data.includes("\\")) {
310
484
  return false;
311
485
  }
312
- return /^(([^:/?#]+):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#((?![^#]*\\)[^#]*))?/i.test(
313
- data
314
- );
486
+ return URI_REFERENCE_REGEX.test(data);
315
487
  },
316
488
  "uri-template"(data) {
317
- return /^(?:(?:https?:\/\/[\w.-]+)?\/?)?[\w- ;,.\/?%&=]*(?:\{[\w-]+(?::\d+)?\}[\w- ;,.\/?%&=]*)*\/?$/.test(
318
- data
319
- );
489
+ return isValidUriTemplate(data);
490
+ },
491
+ duration(data) {
492
+ return DURATION_REGEX.test(data);
493
+ },
494
+ uuid(data) {
495
+ return UUID_REGEX.test(data);
320
496
  },
321
- // Not supported yet
322
- duration: false,
323
- uuid: false,
324
- "idn-email": false,
325
- "idn-hostname": false,
326
- iri: false,
327
- "iri-reference": false
497
+ // IRI is like URI but allows Unicode. We reuse a permissive logic.
498
+ iri(data) {
499
+ return IRI_REGEX.test(data);
500
+ },
501
+ "iri-reference"(data) {
502
+ if (data.includes("\\")) {
503
+ return false;
504
+ }
505
+ return IRI_REFERENCE_REGEX.test(data);
506
+ },
507
+ // Best-effort structural validation for IDN (no punycode/tables)
508
+ "idn-email"(data) {
509
+ return IDN_EMAIL_REGEX.test(data);
510
+ },
511
+ "idn-hostname"(data) {
512
+ return IDN_HOSTNAME_REGEX.test(data);
513
+ }
328
514
  };
329
515
 
330
516
  // lib/types.ts
331
517
  var Types = {
332
518
  object(data) {
333
- return isObject(data);
519
+ return data !== null && typeof data === "object" && !Array.isArray(data);
334
520
  },
335
521
  array(data) {
336
- if (Array.isArray(data)) {
337
- return true;
338
- }
339
- return typeof data === "object" && data !== null && "length" in data && "0" in data && Object.keys(data).length - 1 === data.length;
522
+ return Array.isArray(data);
340
523
  },
341
524
  string(data) {
342
525
  return typeof data === "string";
@@ -356,17 +539,126 @@ var Types = {
356
539
  // Not implemented yet
357
540
  timestamp: false,
358
541
  int8: false,
359
- unit8: false,
542
+ uint8: false,
360
543
  int16: false,
361
- unit16: false,
544
+ uint16: false,
362
545
  int32: false,
363
- unit32: false,
546
+ uint32: false,
364
547
  float32: false,
365
548
  float64: false
366
549
  };
367
550
 
551
+ // lib/utils/has-changed.ts
552
+ function hasChanged(prev, current) {
553
+ if (Object.is(prev, current)) {
554
+ return false;
555
+ }
556
+ if (Array.isArray(prev)) {
557
+ if (Array.isArray(current) === false) {
558
+ return true;
559
+ }
560
+ if (prev.length !== current.length) {
561
+ return true;
562
+ }
563
+ for (let i = 0; i < current.length; i++) {
564
+ if (hasChanged(prev[i], current[i])) {
565
+ return true;
566
+ }
567
+ }
568
+ return false;
569
+ }
570
+ if (typeof prev === "object" && prev !== null) {
571
+ if (typeof current !== "object" || current === null) {
572
+ return true;
573
+ }
574
+ for (const key in current) {
575
+ if (hasChanged(prev[key], current[key])) {
576
+ return true;
577
+ }
578
+ }
579
+ for (const key in prev) {
580
+ if (key in current) {
581
+ continue;
582
+ }
583
+ if (hasChanged(prev[key], void 0)) {
584
+ return true;
585
+ }
586
+ }
587
+ return false;
588
+ }
589
+ return true;
590
+ }
591
+
368
592
  // lib/keywords/array-keywords.ts
593
+ function isUniquePrimitive(value) {
594
+ return value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean";
595
+ }
596
+ function getArrayBucketKey(value) {
597
+ const length = value.length;
598
+ if (length === 0) {
599
+ return "0";
600
+ }
601
+ const first = value[0];
602
+ const last = value[length - 1];
603
+ const firstType = first === null ? "null" : typeof first;
604
+ const lastType = last === null ? "null" : typeof last;
605
+ let firstArrayMarker = "";
606
+ if (Array.isArray(first)) {
607
+ const firstSignature = getPrimitiveArraySignature(first);
608
+ firstArrayMarker = firstSignature === null ? `a:${first.length}` : firstSignature;
609
+ }
610
+ let lastArrayMarker = "";
611
+ if (Array.isArray(last)) {
612
+ const lastSignature = getPrimitiveArraySignature(last);
613
+ lastArrayMarker = lastSignature === null ? `a:${last.length}` : lastSignature;
614
+ }
615
+ return `${length}:${firstType}:${firstArrayMarker}:${lastType}:${lastArrayMarker}`;
616
+ }
617
+ function getObjectShapeKey(value) {
618
+ const keys = Object.keys(value).sort();
619
+ return `${keys.length}:${keys.join("")}`;
620
+ }
621
+ function getPrimitiveArraySignature(value) {
622
+ const length = value.length;
623
+ if (length === 0) {
624
+ return "a:0";
625
+ }
626
+ if (!isUniquePrimitive(value[0]) || !isUniquePrimitive(value[length - 1])) {
627
+ return null;
628
+ }
629
+ let signature = `a:${length}:`;
630
+ for (let i = 0; i < length; i++) {
631
+ const item = value[i];
632
+ if (item === null) {
633
+ signature += "l;";
634
+ continue;
635
+ }
636
+ if (typeof item === "string") {
637
+ signature += `s${item.length}:${item};`;
638
+ continue;
639
+ }
640
+ if (typeof item === "number") {
641
+ if (Number.isNaN(item)) {
642
+ signature += "n:NaN;";
643
+ continue;
644
+ }
645
+ if (Object.is(item, -0)) {
646
+ signature += "n:-0;";
647
+ continue;
648
+ }
649
+ signature += `n:${item};`;
650
+ continue;
651
+ }
652
+ if (typeof item === "boolean") {
653
+ signature += item ? "b:1;" : "b:0;";
654
+ continue;
655
+ }
656
+ return null;
657
+ }
658
+ return signature;
659
+ }
369
660
  var ArrayKeywords = {
661
+ // lib/keywords/array-keywords.ts
370
662
  items(schema, data, defineError) {
371
663
  if (!Array.isArray(data)) {
372
664
  return;
@@ -381,11 +673,11 @@ var ArrayKeywords = {
381
673
  }
382
674
  if (Array.isArray(schemaItems)) {
383
675
  const schemaItemsLength = schemaItems.length;
384
- const itemsLength = Math.min(schemaItemsLength, dataLength);
676
+ const itemsLength = schemaItemsLength < dataLength ? schemaItemsLength : dataLength;
385
677
  for (let i = 0; i < itemsLength; i++) {
386
678
  const schemaItem = schemaItems[i];
387
679
  if (typeof schemaItem === "boolean") {
388
- if (schemaItem === false && typeof data[i] !== "undefined") {
680
+ if (schemaItem === false && data[i] !== void 0) {
389
681
  return defineError("Array item is not allowed", {
390
682
  item: i,
391
683
  data: data[i]
@@ -393,8 +685,9 @@ var ArrayKeywords = {
393
685
  }
394
686
  continue;
395
687
  }
396
- if (isCompiledSchema(schemaItem)) {
397
- const error = schemaItem.$validate(data[i]);
688
+ const validate2 = schemaItem && schemaItem.$validate;
689
+ if (typeof validate2 === "function") {
690
+ const error = validate2(data[i]);
398
691
  if (error) {
399
692
  return defineError("Array item is invalid", {
400
693
  item: i,
@@ -406,26 +699,32 @@ var ArrayKeywords = {
406
699
  }
407
700
  return;
408
701
  }
409
- if (isCompiledSchema(schemaItems)) {
410
- for (let i = 0; i < dataLength; i++) {
411
- const error = schemaItems.$validate(data[i]);
412
- if (error) {
413
- return defineError("Array item is invalid", {
414
- item: i,
415
- cause: error,
416
- data: data[i]
417
- });
418
- }
702
+ const validate = schemaItems && schemaItems.$validate;
703
+ if (typeof validate !== "function") {
704
+ return;
705
+ }
706
+ for (let i = 0; i < dataLength; i++) {
707
+ const error = validate(data[i]);
708
+ if (error) {
709
+ return defineError("Array item is invalid", {
710
+ item: i,
711
+ cause: error,
712
+ data: data[i]
713
+ });
419
714
  }
420
715
  }
421
- return;
422
716
  },
423
717
  elements(schema, data, defineError) {
424
- if (!Array.isArray(data) || !isCompiledSchema(schema.elements)) {
718
+ if (!Array.isArray(data)) {
719
+ return;
720
+ }
721
+ const elementsSchema = schema.elements;
722
+ const validate = elementsSchema && elementsSchema.$validate;
723
+ if (typeof validate !== "function") {
425
724
  return;
426
725
  }
427
726
  for (let i = 0; i < data.length; i++) {
428
- const error = schema.elements.$validate(data[i]);
727
+ const error = validate(data[i]);
429
728
  if (error) {
430
729
  return defineError("Array item is invalid", {
431
730
  item: i,
@@ -434,7 +733,6 @@ var ArrayKeywords = {
434
733
  });
435
734
  }
436
735
  }
437
- return;
438
736
  },
439
737
  minItems(schema, data, defineError) {
440
738
  if (!Array.isArray(data) || data.length >= schema.minItems) {
@@ -449,18 +747,28 @@ var ArrayKeywords = {
449
747
  return defineError("Array is too long", { data });
450
748
  },
451
749
  additionalItems(schema, data, defineError) {
452
- if (!schema.items || isObject(schema.items)) {
750
+ if (!Array.isArray(data) || !Array.isArray(schema.items)) {
453
751
  return;
454
752
  }
455
- if (schema.additionalItems === false) {
456
- if (data.length > schema.items.length) {
457
- return defineError("Array is too long", { data });
458
- }
753
+ let tupleLength = schema._tupleItemsLength;
754
+ if (tupleLength === void 0) {
755
+ tupleLength = schema.items.length;
756
+ Object.defineProperty(schema, "_tupleItemsLength", {
757
+ value: tupleLength,
758
+ enumerable: false,
759
+ configurable: false,
760
+ writable: false
761
+ });
762
+ }
763
+ if (data.length <= tupleLength) {
459
764
  return;
460
765
  }
461
- if (isObject(schema.additionalItems)) {
766
+ if (schema.additionalItems === false) {
767
+ return defineError("Array is too long", { data });
768
+ }
769
+ if (schema.additionalItems && typeof schema.additionalItems === "object" && !Array.isArray(schema.additionalItems)) {
462
770
  if (isCompiledSchema(schema.additionalItems)) {
463
- for (let i = schema.items.length; i < data.length; i++) {
771
+ for (let i = tupleLength; i < data.length; i++) {
464
772
  const error = schema.additionalItems.$validate(data[i]);
465
773
  if (error) {
466
774
  return defineError("Array item is invalid", {
@@ -480,28 +788,89 @@ var ArrayKeywords = {
480
788
  if (!Array.isArray(data) || !schema.uniqueItems) {
481
789
  return;
482
790
  }
483
- const unique = /* @__PURE__ */ new Set();
484
- for (const item of data) {
485
- let itemStr;
486
- if (typeof item === "string") {
487
- itemStr = `s:${item}`;
488
- } else if (isObject(item)) {
489
- itemStr = `o:${JSON.stringify(
490
- Object.fromEntries(
491
- Object.entries(item).sort(([a], [b]) => a.localeCompare(b))
492
- )
493
- )}`;
494
- } else if (Array.isArray(item)) {
495
- itemStr = JSON.stringify(item);
496
- } else {
497
- itemStr = String(item);
791
+ const len = data.length;
792
+ if (len <= 1) {
793
+ return;
794
+ }
795
+ if (len <= 8) {
796
+ for (let i = 0; i < len; i++) {
797
+ const left = data[i];
798
+ for (let j = i + 1; j < len; j++) {
799
+ const right = data[j];
800
+ if (left === right) {
801
+ return defineError("Array items are not unique", { data: right });
802
+ }
803
+ if (typeof left === "number" && typeof right === "number" && Number.isNaN(left) && Number.isNaN(right)) {
804
+ return defineError("Array items are not unique", { data: right });
805
+ }
806
+ if (left && right && typeof left === "object" && typeof right === "object" && !hasChanged(left, right)) {
807
+ return defineError("Array items are not unique", { data: right });
808
+ }
809
+ }
810
+ }
811
+ return;
812
+ }
813
+ const primitiveSeen = /* @__PURE__ */ new Set();
814
+ let primitiveArraySignatures;
815
+ let arrayBuckets;
816
+ let objectBuckets;
817
+ for (let i = 0; i < len; i++) {
818
+ const item = data[i];
819
+ if (isUniquePrimitive(item)) {
820
+ if (primitiveSeen.has(item)) {
821
+ return defineError("Array items are not unique", { data: item });
822
+ }
823
+ primitiveSeen.add(item);
824
+ continue;
498
825
  }
499
- if (unique.has(itemStr)) {
500
- return defineError("Array items are not unique", { data: item });
826
+ if (!item || typeof item !== "object") {
827
+ continue;
501
828
  }
502
- unique.add(itemStr);
829
+ if (Array.isArray(item)) {
830
+ const signature = getPrimitiveArraySignature(item);
831
+ if (signature !== null) {
832
+ if (!primitiveArraySignatures) {
833
+ primitiveArraySignatures = /* @__PURE__ */ new Set();
834
+ }
835
+ if (primitiveArraySignatures.has(signature)) {
836
+ return defineError("Array items are not unique", { data: item });
837
+ }
838
+ primitiveArraySignatures.add(signature);
839
+ continue;
840
+ }
841
+ if (!arrayBuckets) {
842
+ arrayBuckets = /* @__PURE__ */ new Map();
843
+ }
844
+ const bucketKey2 = getArrayBucketKey(item);
845
+ let candidates2 = arrayBuckets.get(bucketKey2);
846
+ if (!candidates2) {
847
+ candidates2 = [];
848
+ arrayBuckets.set(bucketKey2, candidates2);
849
+ }
850
+ for (let j = 0; j < candidates2.length; j++) {
851
+ if (!hasChanged(candidates2[j], item)) {
852
+ return defineError("Array items are not unique", { data: item });
853
+ }
854
+ }
855
+ candidates2.push(item);
856
+ continue;
857
+ }
858
+ if (!objectBuckets) {
859
+ objectBuckets = /* @__PURE__ */ new Map();
860
+ }
861
+ const bucketKey = getObjectShapeKey(item);
862
+ let candidates = objectBuckets.get(bucketKey);
863
+ if (!candidates) {
864
+ candidates = [];
865
+ objectBuckets.set(bucketKey, candidates);
866
+ }
867
+ for (let j = 0; j < candidates.length; j++) {
868
+ if (!hasChanged(candidates[j], item)) {
869
+ return defineError("Array items are not unique", { data: item });
870
+ }
871
+ }
872
+ candidates.push(item);
503
873
  }
504
- return;
505
874
  },
506
875
  contains(schema, data, defineError) {
507
876
  if (!Array.isArray(data)) {
@@ -516,8 +885,9 @@ var ArrayKeywords = {
516
885
  }
517
886
  return defineError("Array must not contain any items", { data });
518
887
  }
888
+ const containsValidate = schema.contains.$validate;
519
889
  for (let i = 0; i < data.length; i++) {
520
- const error = schema.contains.$validate(data[i]);
890
+ const error = containsValidate(data[i]);
521
891
  if (!error) {
522
892
  return;
523
893
  }
@@ -527,6 +897,140 @@ var ArrayKeywords = {
527
897
  }
528
898
  };
529
899
 
900
+ // lib/utils/deep-freeze.ts
901
+ function isPlainObject(value) {
902
+ if (!value || typeof value !== "object") {
903
+ return false;
904
+ }
905
+ const proto = Object.getPrototypeOf(value);
906
+ return proto === Object.prototype || proto === null;
907
+ }
908
+ function canUseStructuredClone(value) {
909
+ if (typeof structuredClone !== "function") {
910
+ return false;
911
+ }
912
+ if (typeof Buffer !== "undefined" && value instanceof Buffer) {
913
+ return false;
914
+ }
915
+ return Array.isArray(value) || isPlainObject(value) || value instanceof Date || value instanceof RegExp || value instanceof Map || value instanceof Set || value instanceof ArrayBuffer || ArrayBuffer.isView(value);
916
+ }
917
+ function deepCloneUnfreeze(obj, cloneClassInstances = false, seen = /* @__PURE__ */ new WeakMap()) {
918
+ if (typeof obj === "undefined" || obj === null || typeof obj !== "object") {
919
+ return obj;
920
+ }
921
+ const source = obj;
922
+ if (seen.has(source)) {
923
+ return seen.get(source);
924
+ }
925
+ if (canUseStructuredClone(source)) {
926
+ const cloned = structuredClone(source);
927
+ seen.set(source, cloned);
928
+ return cloned;
929
+ }
930
+ let clone;
931
+ switch (true) {
932
+ case Array.isArray(source): {
933
+ clone = [];
934
+ seen.set(source, clone);
935
+ for (let i = 0, l = source.length; i < l; i++) {
936
+ clone[i] = deepCloneUnfreeze(source[i], cloneClassInstances, seen);
937
+ }
938
+ return clone;
939
+ }
940
+ case source instanceof Date: {
941
+ clone = new Date(source.getTime());
942
+ seen.set(source, clone);
943
+ return clone;
944
+ }
945
+ case source instanceof RegExp: {
946
+ clone = new RegExp(source.source, source.flags);
947
+ seen.set(source, clone);
948
+ return clone;
949
+ }
950
+ case source instanceof Map: {
951
+ clone = /* @__PURE__ */ new Map();
952
+ seen.set(source, clone);
953
+ for (const [key, value] of source.entries()) {
954
+ clone.set(
955
+ deepCloneUnfreeze(key, cloneClassInstances, seen),
956
+ deepCloneUnfreeze(value, cloneClassInstances, seen)
957
+ );
958
+ }
959
+ return clone;
960
+ }
961
+ case source instanceof Set: {
962
+ clone = /* @__PURE__ */ new Set();
963
+ seen.set(source, clone);
964
+ for (const value of source.values()) {
965
+ clone.add(deepCloneUnfreeze(value, cloneClassInstances, seen));
966
+ }
967
+ return clone;
968
+ }
969
+ case source instanceof ArrayBuffer: {
970
+ clone = source.slice(0);
971
+ seen.set(source, clone);
972
+ return clone;
973
+ }
974
+ case ArrayBuffer.isView(source): {
975
+ clone = new source.constructor(source.buffer.slice(0));
976
+ seen.set(source, clone);
977
+ return clone;
978
+ }
979
+ case (typeof Buffer !== "undefined" && source instanceof Buffer): {
980
+ clone = Buffer.from(source);
981
+ seen.set(source, clone);
982
+ return clone;
983
+ }
984
+ case source instanceof Error: {
985
+ clone = new source.constructor(source.message);
986
+ seen.set(source, clone);
987
+ break;
988
+ }
989
+ case (source instanceof Promise || source instanceof WeakMap || source instanceof WeakSet): {
990
+ clone = source;
991
+ seen.set(source, clone);
992
+ return clone;
993
+ }
994
+ case (source.constructor && source.constructor !== Object): {
995
+ if (!cloneClassInstances) {
996
+ clone = source;
997
+ seen.set(source, clone);
998
+ return clone;
999
+ }
1000
+ clone = Object.create(Object.getPrototypeOf(source));
1001
+ seen.set(source, clone);
1002
+ break;
1003
+ }
1004
+ default: {
1005
+ clone = {};
1006
+ seen.set(source, clone);
1007
+ const keys = Reflect.ownKeys(source);
1008
+ for (let i = 0, l = keys.length; i < l; i++) {
1009
+ const key = keys[i];
1010
+ clone[key] = deepCloneUnfreeze(
1011
+ source[key],
1012
+ cloneClassInstances,
1013
+ seen
1014
+ );
1015
+ }
1016
+ return clone;
1017
+ }
1018
+ }
1019
+ const descriptors = Object.getOwnPropertyDescriptors(source);
1020
+ for (const key of Reflect.ownKeys(descriptors)) {
1021
+ const descriptor = descriptors[key];
1022
+ if ("value" in descriptor) {
1023
+ descriptor.value = deepCloneUnfreeze(
1024
+ descriptor.value,
1025
+ cloneClassInstances,
1026
+ seen
1027
+ );
1028
+ }
1029
+ Object.defineProperty(clone, key, descriptor);
1030
+ }
1031
+ return clone;
1032
+ }
1033
+
530
1034
  // lib/keywords/number-keywords.ts
531
1035
  var NumberKeywords = {
532
1036
  minimum(schema, data, defineError, instance) {
@@ -595,16 +1099,129 @@ var NumberKeywords = {
595
1099
  }
596
1100
  };
597
1101
 
1102
+ // lib/utils/pattern-matcher.ts
1103
+ var REGEX_META_CHARS = /[\\.^$*+?()[\]{}|]/;
1104
+ function hasRegexMeta(value) {
1105
+ return REGEX_META_CHARS.test(value);
1106
+ }
1107
+ var PATTERN_CACHE = /* @__PURE__ */ new Map();
1108
+ function compilePatternMatcher(pattern) {
1109
+ const cached = PATTERN_CACHE.get(pattern);
1110
+ if (cached) {
1111
+ return cached;
1112
+ }
1113
+ let compiled;
1114
+ if (pattern.length === 0) {
1115
+ compiled = (_value) => true;
1116
+ } else if (!hasRegexMeta(pattern)) {
1117
+ compiled = (value) => value.includes(pattern);
1118
+ } else {
1119
+ const patternLength = pattern.length;
1120
+ if (patternLength >= 2 && pattern[0] === "^" && pattern[patternLength - 1] === "$") {
1121
+ const inner = pattern.slice(1, -1);
1122
+ if (!hasRegexMeta(inner)) {
1123
+ if (inner.length === 0) {
1124
+ compiled = (value) => value.length === 0;
1125
+ } else {
1126
+ compiled = (value) => value === inner;
1127
+ }
1128
+ } else {
1129
+ compiled = new RegExp(pattern, "u");
1130
+ }
1131
+ } else if (pattern[0] === "^") {
1132
+ const inner = pattern.slice(1);
1133
+ if (!hasRegexMeta(inner)) {
1134
+ if (inner.length === 0) {
1135
+ compiled = (_value) => true;
1136
+ } else {
1137
+ compiled = (value) => value.startsWith(inner);
1138
+ }
1139
+ } else {
1140
+ compiled = new RegExp(pattern, "u");
1141
+ }
1142
+ } else if (pattern[patternLength - 1] === "$") {
1143
+ const inner = pattern.slice(0, -1);
1144
+ if (!hasRegexMeta(inner)) {
1145
+ if (inner.length === 0) {
1146
+ compiled = (_value) => true;
1147
+ } else {
1148
+ compiled = (value) => value.endsWith(inner);
1149
+ }
1150
+ } else {
1151
+ compiled = new RegExp(pattern, "u");
1152
+ }
1153
+ } else {
1154
+ compiled = new RegExp(pattern, "u");
1155
+ }
1156
+ }
1157
+ PATTERN_CACHE.set(pattern, compiled);
1158
+ return compiled;
1159
+ }
1160
+
598
1161
  // lib/keywords/object-keywords.ts
1162
+ var PATTERN_KEY_CACHE_LIMIT = 512;
1163
+ function getPatternPropertyEntries(schema) {
1164
+ let entries = schema._patternPropertyEntries;
1165
+ if (entries) {
1166
+ return entries;
1167
+ }
1168
+ if (!schema.patternProperties || typeof schema.patternProperties !== "object" || Array.isArray(schema.patternProperties)) {
1169
+ return void 0;
1170
+ }
1171
+ const patternKeys = Object.keys(schema.patternProperties);
1172
+ entries = new Array(patternKeys.length);
1173
+ for (let i = 0; i < patternKeys.length; i++) {
1174
+ const key = patternKeys[i];
1175
+ const compiledMatcher = compilePatternMatcher(key);
1176
+ const match = compiledMatcher instanceof RegExp ? (value) => compiledMatcher.test(value) : compiledMatcher;
1177
+ entries[i] = {
1178
+ schemaProp: schema.patternProperties[key],
1179
+ match
1180
+ };
1181
+ }
1182
+ Object.defineProperty(schema, "_patternPropertyEntries", {
1183
+ value: entries,
1184
+ enumerable: false,
1185
+ configurable: false,
1186
+ writable: false
1187
+ });
1188
+ return entries;
1189
+ }
1190
+ function getPatternKeyMatchIndexes(schema, key, entries) {
1191
+ let cache = schema._patternKeyMatchIndexCache;
1192
+ if (cache) {
1193
+ const cached = cache.get(key);
1194
+ if (cached) {
1195
+ return cached;
1196
+ }
1197
+ } else {
1198
+ cache = /* @__PURE__ */ new Map();
1199
+ Object.defineProperty(schema, "_patternKeyMatchIndexCache", {
1200
+ value: cache,
1201
+ enumerable: false,
1202
+ configurable: false,
1203
+ writable: false
1204
+ });
1205
+ }
1206
+ const indexes = [];
1207
+ for (let i = 0; i < entries.length; i++) {
1208
+ if (entries[i].match(key)) {
1209
+ indexes.push(i);
1210
+ }
1211
+ }
1212
+ if (cache.size < PATTERN_KEY_CACHE_LIMIT) {
1213
+ cache.set(key, indexes);
1214
+ }
1215
+ return indexes;
1216
+ }
599
1217
  var ObjectKeywords = {
600
- // Object
601
1218
  required(schema, data, defineError) {
602
- if (!isObject(data)) {
1219
+ if (!data || typeof data !== "object" || Array.isArray(data)) {
603
1220
  return;
604
1221
  }
605
1222
  for (let i = 0; i < schema.required.length; i++) {
606
1223
  const key = schema.required[i];
607
- if (!data.hasOwnProperty(key)) {
1224
+ if (!Object.prototype.hasOwnProperty.call(data, key)) {
608
1225
  return defineError("Required property is missing", {
609
1226
  item: key,
610
1227
  data: data[key]
@@ -614,19 +1231,48 @@ var ObjectKeywords = {
614
1231
  return;
615
1232
  },
616
1233
  properties(schema, data, defineError) {
617
- if (!isObject(data)) {
1234
+ if (!data || typeof data !== "object" || Array.isArray(data)) {
618
1235
  return;
619
1236
  }
620
- for (const key of Object.keys(schema.properties)) {
621
- if (!data.hasOwnProperty(key)) {
622
- const schemaProp = schema.properties[key];
623
- if (isObject(schemaProp) && "default" in schemaProp) {
624
- data[key] = schemaProp.default;
1237
+ let propKeys = schema._propKeys;
1238
+ if (!propKeys) {
1239
+ propKeys = Object.keys(schema.properties || {});
1240
+ Object.defineProperty(schema, "_propKeys", {
1241
+ value: propKeys,
1242
+ enumerable: false,
1243
+ configurable: false,
1244
+ writable: false
1245
+ });
1246
+ }
1247
+ let requiredSet = schema._requiredSet;
1248
+ if (requiredSet === void 0) {
1249
+ requiredSet = Array.isArray(schema.required) ? new Set(schema.required) : null;
1250
+ Object.defineProperty(schema, "_requiredSet", {
1251
+ value: requiredSet,
1252
+ enumerable: false,
1253
+ configurable: false,
1254
+ writable: false
1255
+ });
1256
+ }
1257
+ for (let i = 0; i < propKeys.length; i++) {
1258
+ const key = propKeys[i];
1259
+ const schemaProp = schema.properties[key];
1260
+ if (!Object.prototype.hasOwnProperty.call(data, key)) {
1261
+ if (requiredSet && requiredSet.has(key) && schemaProp && typeof schemaProp === "object" && !Array.isArray(schemaProp) && "default" in schemaProp) {
1262
+ const error = schemaProp.$validate(schemaProp.default);
1263
+ if (error) {
1264
+ return defineError("Default property is invalid", {
1265
+ item: key,
1266
+ cause: error,
1267
+ data: schemaProp.default
1268
+ });
1269
+ }
1270
+ data[key] = deepCloneUnfreeze(schemaProp.default);
625
1271
  }
626
1272
  continue;
627
1273
  }
628
- if (typeof schema.properties[key] === "boolean") {
629
- if (schema.properties[key] === false) {
1274
+ if (typeof schemaProp === "boolean") {
1275
+ if (schemaProp === false) {
630
1276
  return defineError("Property is not allowed", {
631
1277
  item: key,
632
1278
  data: data[key]
@@ -634,8 +1280,8 @@ var ObjectKeywords = {
634
1280
  }
635
1281
  continue;
636
1282
  }
637
- if ("$validate" in schema.properties[key]) {
638
- const error = schema.properties[key].$validate(data[key]);
1283
+ if (schemaProp && "$validate" in schemaProp) {
1284
+ const error = schemaProp.$validate(data[key]);
639
1285
  if (error) {
640
1286
  return defineError("Property is invalid", {
641
1287
  item: key,
@@ -648,12 +1294,19 @@ var ObjectKeywords = {
648
1294
  return;
649
1295
  },
650
1296
  values(schema, data, defineError) {
651
- if (!isObject(data) || !isCompiledSchema(schema.values)) {
1297
+ if (!data || typeof data !== "object" || Array.isArray(data)) {
1298
+ return;
1299
+ }
1300
+ const valueSchema = schema.values;
1301
+ const validate = valueSchema && valueSchema.$validate;
1302
+ if (typeof validate !== "function") {
652
1303
  return;
653
1304
  }
654
- const keys = Object.keys(data);
655
- for (const key of keys) {
656
- const error = schema.values.$validate(data[key]);
1305
+ for (const key in data) {
1306
+ if (!Object.prototype.hasOwnProperty.call(data, key)) {
1307
+ continue;
1308
+ }
1309
+ const error = validate(data[key]);
657
1310
  if (error) {
658
1311
  return defineError("Property is invalid", {
659
1312
  item: key,
@@ -662,39 +1315,63 @@ var ObjectKeywords = {
662
1315
  });
663
1316
  }
664
1317
  }
665
- return;
666
1318
  },
667
1319
  maxProperties(schema, data, defineError) {
668
- if (!isObject(data) || Object.keys(data).length <= schema.maxProperties) {
1320
+ if (!data || typeof data !== "object" || Array.isArray(data)) {
669
1321
  return;
670
1322
  }
671
- return defineError("Too many properties", { data });
1323
+ let count = 0;
1324
+ for (const key in data) {
1325
+ if (!Object.prototype.hasOwnProperty.call(data, key)) {
1326
+ continue;
1327
+ }
1328
+ count++;
1329
+ if (count > schema.maxProperties) {
1330
+ return defineError("Too many properties", { data });
1331
+ }
1332
+ }
1333
+ return;
672
1334
  },
673
1335
  minProperties(schema, data, defineError) {
674
- if (!isObject(data) || Object.keys(data).length >= schema.minProperties) {
1336
+ if (!data || typeof data !== "object" || Array.isArray(data)) {
675
1337
  return;
676
1338
  }
1339
+ let count = 0;
1340
+ for (const key in data) {
1341
+ if (!Object.prototype.hasOwnProperty.call(data, key)) {
1342
+ continue;
1343
+ }
1344
+ count++;
1345
+ if (count >= schema.minProperties) {
1346
+ return;
1347
+ }
1348
+ }
677
1349
  return defineError("Too few properties", { data });
678
1350
  },
679
1351
  additionalProperties(schema, data, defineError) {
680
- if (!isObject(data)) {
1352
+ if (!data || typeof data !== "object" || Array.isArray(data)) {
681
1353
  return;
682
1354
  }
683
- const keys = Object.keys(data);
684
- const isCompiled = isCompiledSchema(schema.additionalProperties);
685
- for (const key of keys) {
686
- if (schema.properties && schema.properties.hasOwnProperty(key)) {
1355
+ let apValidate = schema._apValidate;
1356
+ if (apValidate === void 0) {
1357
+ apValidate = isCompiledSchema(schema.additionalProperties) ? schema.additionalProperties.$validate : null;
1358
+ Object.defineProperty(schema, "_apValidate", {
1359
+ value: apValidate,
1360
+ enumerable: false,
1361
+ configurable: false,
1362
+ writable: false
1363
+ });
1364
+ }
1365
+ const patternEntries = getPatternPropertyEntries(schema);
1366
+ for (const key in data) {
1367
+ if (!Object.prototype.hasOwnProperty.call(data, key)) {
687
1368
  continue;
688
1369
  }
689
- if (schema.patternProperties) {
690
- let match = false;
691
- for (const pattern in schema.patternProperties) {
692
- if (new RegExp(pattern, "u").test(key)) {
693
- match = true;
694
- break;
695
- }
696
- }
697
- if (match) {
1370
+ if (schema.properties && Object.prototype.hasOwnProperty.call(schema.properties, key)) {
1371
+ continue;
1372
+ }
1373
+ if (patternEntries && patternEntries.length) {
1374
+ if (getPatternKeyMatchIndexes(schema, key, patternEntries).length > 0) {
698
1375
  continue;
699
1376
  }
700
1377
  }
@@ -704,8 +1381,8 @@ var ObjectKeywords = {
704
1381
  data: data[key]
705
1382
  });
706
1383
  }
707
- if (isCompiled) {
708
- const error = schema.additionalProperties.$validate(data[key]);
1384
+ if (apValidate) {
1385
+ const error = apValidate(data[key]);
709
1386
  if (error) {
710
1387
  return defineError("Additional properties are invalid", {
711
1388
  item: key,
@@ -718,39 +1395,46 @@ var ObjectKeywords = {
718
1395
  return;
719
1396
  },
720
1397
  patternProperties(schema, data, defineError) {
721
- if (!isObject(data)) {
1398
+ if (!data || typeof data !== "object" || Array.isArray(data)) {
722
1399
  return;
723
1400
  }
724
- const patterns = Object.keys(schema.patternProperties);
725
- for (const pattern of patterns) {
726
- const regex = new RegExp(pattern, "u");
727
- if (typeof schema.patternProperties[pattern] === "boolean") {
728
- if (schema.patternProperties[pattern] === false) {
729
- for (const key in data) {
730
- if (regex.test(key)) {
731
- return defineError("Property is not allowed", {
732
- item: key,
733
- data: data[key]
734
- });
735
- }
736
- }
1401
+ const patternEntries = getPatternPropertyEntries(schema);
1402
+ if (!patternEntries || patternEntries.length === 0) {
1403
+ return;
1404
+ }
1405
+ for (const key in data) {
1406
+ if (!Object.prototype.hasOwnProperty.call(data, key)) {
1407
+ continue;
1408
+ }
1409
+ const matchingIndexes = getPatternKeyMatchIndexes(schema, key, patternEntries);
1410
+ if (matchingIndexes.length === 0) {
1411
+ if (schema.additionalProperties === false && !(schema.properties && Object.prototype.hasOwnProperty.call(schema.properties, key))) {
1412
+ return defineError("Additional properties are not allowed", {
1413
+ item: key,
1414
+ data: data[key]
1415
+ });
737
1416
  }
738
1417
  continue;
739
1418
  }
740
- const keys = Object.keys(data);
741
- for (const key of keys) {
742
- if (regex.test(key)) {
743
- if ("$validate" in schema.patternProperties[pattern]) {
744
- const error = schema.patternProperties[pattern].$validate(
745
- data[key]
746
- );
747
- if (error) {
748
- return defineError("Property is invalid", {
749
- item: key,
750
- cause: error,
751
- data: data[key]
752
- });
753
- }
1419
+ for (let j = 0; j < matchingIndexes.length; j++) {
1420
+ const schemaProp = patternEntries[matchingIndexes[j]].schemaProp;
1421
+ if (typeof schemaProp === "boolean") {
1422
+ if (schemaProp === false) {
1423
+ return defineError("Property is not allowed", {
1424
+ item: key,
1425
+ data: data[key]
1426
+ });
1427
+ }
1428
+ continue;
1429
+ }
1430
+ if ("$validate" in schemaProp) {
1431
+ const error = schemaProp.$validate(data[key]);
1432
+ if (error) {
1433
+ return defineError("Property is invalid", {
1434
+ item: key,
1435
+ cause: error,
1436
+ data: data[key]
1437
+ });
754
1438
  }
755
1439
  }
756
1440
  }
@@ -758,30 +1442,40 @@ var ObjectKeywords = {
758
1442
  return;
759
1443
  },
760
1444
  propertyNames(schema, data, defineError) {
761
- if (!isObject(data)) {
1445
+ if (!data || typeof data !== "object" || Array.isArray(data)) {
762
1446
  return;
763
1447
  }
764
- if (typeof schema.propertyNames === "boolean") {
765
- if (schema.propertyNames === false && Object.keys(data).length > 0) {
766
- return defineError("Properties are not allowed", { data });
1448
+ const pn = schema.propertyNames;
1449
+ if (typeof pn === "boolean") {
1450
+ if (pn === false) {
1451
+ for (const key in data) {
1452
+ if (Object.prototype.hasOwnProperty.call(data, key)) {
1453
+ return defineError("Properties are not allowed", { data });
1454
+ }
1455
+ }
767
1456
  }
1457
+ return;
768
1458
  }
769
- if (isCompiledSchema(schema.propertyNames)) {
770
- for (let key in data) {
771
- const error = schema.propertyNames.$validate(key);
772
- if (error) {
773
- return defineError("Property name is invalid", {
774
- item: key,
775
- cause: error,
776
- data: data[key]
777
- });
778
- }
1459
+ const validate = pn && pn.$validate;
1460
+ if (typeof validate !== "function") {
1461
+ return;
1462
+ }
1463
+ for (const key in data) {
1464
+ if (!Object.prototype.hasOwnProperty.call(data, key)) {
1465
+ continue;
1466
+ }
1467
+ const error = validate(key);
1468
+ if (error) {
1469
+ return defineError("Property name is invalid", {
1470
+ item: key,
1471
+ cause: error,
1472
+ data: data[key]
1473
+ });
779
1474
  }
780
1475
  }
781
- return;
782
1476
  },
783
1477
  dependencies(schema, data, defineError) {
784
- if (!isObject(data)) {
1478
+ if (!data || typeof data !== "object" || Array.isArray(data)) {
785
1479
  return;
786
1480
  }
787
1481
  for (const key in schema.dependencies) {
@@ -827,7 +1521,6 @@ var ObjectKeywords = {
827
1521
  else: false,
828
1522
  default: false,
829
1523
  // Not implemented yet
830
- $ref: false,
831
1524
  definitions: false,
832
1525
  $id: false,
833
1526
  $schema: false,
@@ -844,17 +1537,66 @@ var ObjectKeywords = {
844
1537
  };
845
1538
 
846
1539
  // lib/keywords/other-keywords.ts
1540
+ function toBranchEntry(item) {
1541
+ if (item && typeof item === "object" && !Array.isArray(item)) {
1542
+ if ("$validate" in item && typeof item.$validate === "function") {
1543
+ return { kind: "validate", validate: item.$validate };
1544
+ }
1545
+ return { kind: "alwaysValid" };
1546
+ }
1547
+ if (typeof item === "boolean") {
1548
+ return { kind: item ? "alwaysValid" : "alwaysInvalid" };
1549
+ }
1550
+ return { kind: "literal", value: item };
1551
+ }
1552
+ function getBranchEntries(schema, key) {
1553
+ const cacheKey = `_${key}BranchEntries`;
1554
+ let entries = schema[cacheKey];
1555
+ if (entries) {
1556
+ return entries;
1557
+ }
1558
+ const source = schema[key] || [];
1559
+ entries = [];
1560
+ for (let i = 0; i < source.length; i++) {
1561
+ entries.push(toBranchEntry(source[i]));
1562
+ }
1563
+ Object.defineProperty(schema, cacheKey, {
1564
+ value: entries,
1565
+ enumerable: false,
1566
+ configurable: false,
1567
+ writable: false
1568
+ });
1569
+ return entries;
1570
+ }
847
1571
  var OtherKeywords = {
848
1572
  enum(schema, data, defineError) {
849
- const isArray = Array.isArray(data);
850
- const isObject2 = typeof data === "object" && data !== null;
851
- for (let i = 0; i < schema.enum.length; i++) {
852
- const enumItem = schema.enum[i];
853
- if (enumItem === data) {
854
- return;
1573
+ let enumCache = schema._enumCache;
1574
+ if (!enumCache) {
1575
+ const primitiveSet = /* @__PURE__ */ new Set();
1576
+ const objectValues = [];
1577
+ const list = schema.enum;
1578
+ for (let i = 0; i < list.length; i++) {
1579
+ const enumItem = list[i];
1580
+ if (enumItem !== null && typeof enumItem === "object") {
1581
+ objectValues.push(enumItem);
1582
+ } else {
1583
+ primitiveSet.add(enumItem);
1584
+ }
855
1585
  }
856
- if (isArray && Array.isArray(enumItem) || isObject2 && typeof enumItem === "object" && enumItem !== null) {
857
- if (deepEqual(enumItem, data)) {
1586
+ enumCache = { primitiveSet, objectValues };
1587
+ Object.defineProperty(schema, "_enumCache", {
1588
+ value: enumCache,
1589
+ enumerable: false,
1590
+ configurable: false,
1591
+ writable: false
1592
+ });
1593
+ }
1594
+ if (!(typeof data === "number" && Number.isNaN(data)) && enumCache.primitiveSet.has(data)) {
1595
+ return;
1596
+ }
1597
+ if (data !== null && typeof data === "object") {
1598
+ for (let i = 0; i < enumCache.objectValues.length; i++) {
1599
+ if (!hasChanged(enumCache.objectValues[i], data)) {
858
1600
  return;
859
1601
  }
860
1602
  }
@@ -862,74 +1604,130 @@ var OtherKeywords = {
862
1604
  return defineError("Value is not one of the allowed values", { data });
863
1605
  },
864
1606
  allOf(schema, data, defineError) {
865
- for (let i = 0; i < schema.allOf.length; i++) {
866
- if (isObject(schema.allOf[i])) {
867
- if ("$validate" in schema.allOf[i]) {
868
- const error = schema.allOf[i].$validate(data);
869
- if (error) {
870
- return defineError("Value is not valid", { cause: error, data });
871
- }
1607
+ const branches = getBranchEntries(schema, "allOf");
1608
+ if (branches.length === 1) {
1609
+ const onlyBranch = branches[0];
1610
+ if (onlyBranch.kind === "validate") {
1611
+ const error = onlyBranch.validate(data);
1612
+ if (error) {
1613
+ return defineError("Value is not valid", { cause: error, data });
872
1614
  }
873
- continue;
1615
+ return;
874
1616
  }
875
- if (typeof schema.allOf[i] === "boolean") {
876
- if (Boolean(data) !== schema.allOf[i]) {
877
- return defineError("Value is not valid", { data });
1617
+ if (onlyBranch.kind === "alwaysValid") {
1618
+ return;
1619
+ }
1620
+ if (onlyBranch.kind === "alwaysInvalid") {
1621
+ return defineError("Value is not valid", { data });
1622
+ }
1623
+ if (data !== onlyBranch.value) {
1624
+ return defineError("Value is not valid", { data });
1625
+ }
1626
+ return;
1627
+ }
1628
+ for (let i = 0; i < branches.length; i++) {
1629
+ const branch = branches[i];
1630
+ if (branch.kind === "validate") {
1631
+ const error = branch.validate(data);
1632
+ if (error) {
1633
+ return defineError("Value is not valid", { cause: error, data });
878
1634
  }
879
1635
  continue;
880
1636
  }
881
- if (data !== schema.allOf[i]) {
1637
+ if (branch.kind === "alwaysValid") {
1638
+ continue;
1639
+ }
1640
+ if (branch.kind === "alwaysInvalid") {
1641
+ return defineError("Value is not valid", { data });
1642
+ }
1643
+ if (data !== branch.value) {
882
1644
  return defineError("Value is not valid", { data });
883
1645
  }
884
1646
  }
885
1647
  return;
886
1648
  },
887
1649
  anyOf(schema, data, defineError) {
888
- for (let i = 0; i < schema.anyOf.length; i++) {
889
- if (isObject(schema.anyOf[i])) {
890
- if ("$validate" in schema.anyOf[i]) {
891
- const error = schema.anyOf[i].$validate(data);
892
- if (!error) {
893
- return;
894
- }
895
- continue;
1650
+ const branches = getBranchEntries(schema, "anyOf");
1651
+ if (branches.length === 1) {
1652
+ const onlyBranch = branches[0];
1653
+ if (onlyBranch.kind === "validate") {
1654
+ const error = onlyBranch.validate(data);
1655
+ if (!error) {
1656
+ return;
896
1657
  }
1658
+ return defineError("Value is not valid", { data });
1659
+ }
1660
+ if (onlyBranch.kind === "alwaysValid") {
897
1661
  return;
898
- } else {
899
- if (typeof schema.anyOf[i] === "boolean") {
900
- if (Boolean(data) === schema.anyOf[i]) {
901
- return;
902
- }
903
- }
904
- if (data === schema.anyOf[i]) {
1662
+ }
1663
+ if (onlyBranch.kind === "alwaysInvalid") {
1664
+ return defineError("Value is not valid", { data });
1665
+ }
1666
+ if (data === onlyBranch.value) {
1667
+ return;
1668
+ }
1669
+ return defineError("Value is not valid", { data });
1670
+ }
1671
+ for (let i = 0; i < branches.length; i++) {
1672
+ const branch = branches[i];
1673
+ if (branch.kind === "validate") {
1674
+ const error = branch.validate(data);
1675
+ if (!error) {
905
1676
  return;
906
1677
  }
1678
+ continue;
1679
+ }
1680
+ if (branch.kind === "alwaysValid") {
1681
+ return;
1682
+ }
1683
+ if (branch.kind === "alwaysInvalid") {
1684
+ continue;
1685
+ }
1686
+ if (data === branch.value) {
1687
+ return;
907
1688
  }
908
1689
  }
909
1690
  return defineError("Value is not valid", { data });
910
1691
  },
911
1692
  oneOf(schema, data, defineError) {
912
- let validCount = 0;
913
- for (let i = 0; i < schema.oneOf.length; i++) {
914
- if (isObject(schema.oneOf[i])) {
915
- if ("$validate" in schema.oneOf[i]) {
916
- const error = schema.oneOf[i].$validate(data);
917
- if (!error) {
918
- validCount++;
919
- }
920
- continue;
1693
+ const branches = getBranchEntries(schema, "oneOf");
1694
+ if (branches.length === 1) {
1695
+ const onlyBranch = branches[0];
1696
+ if (onlyBranch.kind === "validate") {
1697
+ const error = onlyBranch.validate(data);
1698
+ if (!error) {
1699
+ return;
921
1700
  }
922
- validCount++;
923
- continue;
1701
+ return defineError("Value is not valid", { data });
1702
+ }
1703
+ if (onlyBranch.kind === "alwaysValid") {
1704
+ return;
1705
+ }
1706
+ if (onlyBranch.kind === "alwaysInvalid") {
1707
+ return defineError("Value is not valid", { data });
1708
+ }
1709
+ if (data === onlyBranch.value) {
1710
+ return;
1711
+ }
1712
+ return defineError("Value is not valid", { data });
1713
+ }
1714
+ let validCount = 0;
1715
+ for (let i = 0; i < branches.length; i++) {
1716
+ const branch = branches[i];
1717
+ let isValid = false;
1718
+ if (branch.kind === "validate") {
1719
+ isValid = !branch.validate(data);
1720
+ } else if (branch.kind === "alwaysValid") {
1721
+ isValid = true;
1722
+ } else if (branch.kind === "alwaysInvalid") {
1723
+ isValid = false;
924
1724
  } else {
925
- if (typeof schema.oneOf[i] === "boolean") {
926
- if (Boolean(data) === schema.oneOf[i]) {
927
- validCount++;
928
- }
929
- continue;
930
- }
931
- if (data === schema.oneOf[i]) {
932
- validCount++;
1725
+ isValid = data === branch.value;
1726
+ }
1727
+ if (isValid) {
1728
+ validCount++;
1729
+ if (validCount > 1) {
1730
+ return defineError("Value is not valid", { data });
933
1731
  }
934
1732
  }
935
1733
  }
@@ -939,12 +1737,15 @@ var OtherKeywords = {
939
1737
  return defineError("Value is not valid", { data });
940
1738
  },
941
1739
  const(schema, data, defineError) {
942
- if (data === schema.const || isObject(data) && isObject(schema.const) && deepEqual(data, schema.const) || Array.isArray(data) && Array.isArray(schema.const) && deepEqual(data, schema.const)) {
1740
+ if (data === schema.const) {
1741
+ return;
1742
+ }
1743
+ if (data && typeof data === "object" && !Array.isArray(data) && schema.const && typeof schema.const === "object" && !Array.isArray(schema.const) && !hasChanged(data, schema.const) || Array.isArray(data) && Array.isArray(schema.const) && !hasChanged(data, schema.const)) {
943
1744
  return;
944
1745
  }
945
1746
  return defineError("Value is not valid", { data });
946
1747
  },
947
- if(schema, data, defineError) {
1748
+ if(schema, data) {
948
1749
  if ("then" in schema === false && "else" in schema === false) {
949
1750
  return;
950
1751
  }
@@ -981,21 +1782,45 @@ var OtherKeywords = {
981
1782
  }
982
1783
  return;
983
1784
  }
984
- if (isObject(schema.not)) {
1785
+ if (schema.not && typeof schema.not === "object" && !Array.isArray(schema.not)) {
985
1786
  if ("$validate" in schema.not) {
986
1787
  const error = schema.not.$validate(data);
987
1788
  if (!error) {
988
- return defineError("Value is not valid", { cause: error, data });
1789
+ return defineError("Value is not valid", { data });
989
1790
  }
990
1791
  return;
991
1792
  }
992
1793
  return defineError("Value is not valid", { data });
993
1794
  }
994
1795
  return defineError("Value is not valid", { data });
1796
+ },
1797
+ $ref(schema, data, defineError, instance) {
1798
+ if (schema._resolvedRef) {
1799
+ if (schema.$validate !== schema._resolvedRef) {
1800
+ schema.$validate = schema._resolvedRef;
1801
+ }
1802
+ return schema._resolvedRef(data);
1803
+ }
1804
+ const refPath = schema.$ref;
1805
+ let targetSchema = instance.getSchemaRef(refPath);
1806
+ if (!targetSchema) {
1807
+ targetSchema = instance.getSchemaById(refPath);
1808
+ }
1809
+ if (!targetSchema) {
1810
+ return defineError(`Missing reference: ${refPath}`);
1811
+ }
1812
+ if (!targetSchema.$validate) {
1813
+ return;
1814
+ }
1815
+ schema._resolvedRef = targetSchema.$validate;
1816
+ schema.$validate = schema._resolvedRef;
1817
+ return schema._resolvedRef(data);
995
1818
  }
996
1819
  };
997
1820
 
998
1821
  // lib/keywords/string-keywords.ts
1822
+ var PATTERN_MATCH_CACHE_LIMIT = 512;
1823
+ var FORMAT_RESULT_CACHE_LIMIT = 512;
999
1824
  var StringKeywords = {
1000
1825
  minLength(schema, data, defineError) {
1001
1826
  if (typeof data !== "string" || data.length >= schema.minLength) {
@@ -1013,11 +1838,44 @@ var StringKeywords = {
1013
1838
  if (typeof data !== "string") {
1014
1839
  return;
1015
1840
  }
1016
- const patternRegexp = new RegExp(schema.pattern, "u");
1017
- if (patternRegexp instanceof RegExp === false) {
1018
- return defineError("Invalid regular expression", { data });
1841
+ let patternMatch = schema._patternMatch;
1842
+ let patternMatchCache = schema._patternMatchCache;
1843
+ if (!patternMatch) {
1844
+ try {
1845
+ const compiled = compilePatternMatcher(schema.pattern);
1846
+ patternMatch = compiled instanceof RegExp ? (value) => compiled.test(value) : compiled;
1847
+ Object.defineProperty(schema, "_patternMatch", {
1848
+ value: patternMatch,
1849
+ enumerable: false,
1850
+ configurable: false,
1851
+ writable: false
1852
+ });
1853
+ } catch (error) {
1854
+ return defineError("Invalid regular expression", {
1855
+ data,
1856
+ cause: error
1857
+ });
1858
+ }
1859
+ }
1860
+ if (!patternMatchCache) {
1861
+ patternMatchCache = /* @__PURE__ */ new Map();
1862
+ Object.defineProperty(schema, "_patternMatchCache", {
1863
+ value: patternMatchCache,
1864
+ enumerable: false,
1865
+ configurable: false,
1866
+ writable: false
1867
+ });
1868
+ } else if (patternMatchCache.has(data)) {
1869
+ if (patternMatchCache.get(data)) {
1870
+ return;
1871
+ }
1872
+ return defineError("Value does not match the pattern", { data });
1873
+ }
1874
+ const isMatch = patternMatch(data);
1875
+ if (patternMatchCache.size < PATTERN_MATCH_CACHE_LIMIT) {
1876
+ patternMatchCache.set(data, isMatch);
1019
1877
  }
1020
- if (patternRegexp.test(data)) {
1878
+ if (isMatch) {
1021
1879
  return;
1022
1880
  }
1023
1881
  return defineError("Value does not match the pattern", { data });
@@ -1028,8 +1886,58 @@ var StringKeywords = {
1028
1886
  if (typeof data !== "string") {
1029
1887
  return;
1030
1888
  }
1031
- const formatValidate = instance.getFormat(schema.format);
1032
- if (!formatValidate || formatValidate(data)) {
1889
+ let formatValidate = schema._formatValidate;
1890
+ let formatResultCacheEnabled = schema._formatResultCacheEnabled;
1891
+ let formatResultCache = schema._formatResultCache;
1892
+ if (formatValidate === void 0) {
1893
+ formatValidate = instance.getFormat(schema.format);
1894
+ Object.defineProperty(schema, "_formatValidate", {
1895
+ value: formatValidate,
1896
+ enumerable: false,
1897
+ configurable: false,
1898
+ writable: false
1899
+ });
1900
+ }
1901
+ if (!formatValidate) {
1902
+ return;
1903
+ }
1904
+ if (formatResultCacheEnabled === void 0) {
1905
+ formatResultCacheEnabled = instance.isDefaultFormatValidator(
1906
+ schema.format,
1907
+ formatValidate
1908
+ );
1909
+ Object.defineProperty(schema, "_formatResultCacheEnabled", {
1910
+ value: formatResultCacheEnabled,
1911
+ enumerable: false,
1912
+ configurable: false,
1913
+ writable: false
1914
+ });
1915
+ }
1916
+ if (!formatResultCacheEnabled) {
1917
+ if (formatValidate(data)) {
1918
+ return;
1919
+ }
1920
+ return defineError("Value does not match the format", { data });
1921
+ }
1922
+ if (!formatResultCache) {
1923
+ formatResultCache = /* @__PURE__ */ new Map();
1924
+ Object.defineProperty(schema, "_formatResultCache", {
1925
+ value: formatResultCache,
1926
+ enumerable: false,
1927
+ configurable: false,
1928
+ writable: false
1929
+ });
1930
+ } else if (formatResultCache.has(data)) {
1931
+ if (formatResultCache.get(data)) {
1932
+ return;
1933
+ }
1934
+ return defineError("Value does not match the format", { data });
1935
+ }
1936
+ const isValid = formatValidate(data);
1937
+ if (formatResultCache.size < FORMAT_RESULT_CACHE_LIMIT) {
1938
+ formatResultCache.set(data, isValid);
1939
+ }
1940
+ if (isValid) {
1033
1941
  return;
1034
1942
  }
1035
1943
  return defineError("Value does not match the format", { data });
@@ -1051,10 +1959,15 @@ var SchemaShield = class {
1051
1959
  formats = {};
1052
1960
  keywords = {};
1053
1961
  immutable = false;
1962
+ rootSchema = null;
1963
+ idRegistry = /* @__PURE__ */ new Map();
1964
+ failFast = true;
1054
1965
  constructor({
1055
- immutable = false
1966
+ immutable = false,
1967
+ failFast = true
1056
1968
  } = {}) {
1057
1969
  this.immutable = immutable;
1970
+ this.failFast = failFast;
1058
1971
  for (const [type, validator] of Object.entries(Types)) {
1059
1972
  if (validator) {
1060
1973
  this.addType(type, validator);
@@ -1087,6 +2000,9 @@ var SchemaShield = class {
1087
2000
  getFormat(format) {
1088
2001
  return this.formats[format];
1089
2002
  }
2003
+ isDefaultFormatValidator(format, validator) {
2004
+ return Formats[format] === validator;
2005
+ }
1090
2006
  addKeyword(name, validator, overwrite = false) {
1091
2007
  if (this.keywords[name] && !overwrite) {
1092
2008
  throw new ValidationError(`Keyword "${name}" already exists`);
@@ -1096,150 +2012,537 @@ var SchemaShield = class {
1096
2012
  getKeyword(keyword) {
1097
2013
  return this.keywords[keyword];
1098
2014
  }
2015
+ getSchemaRef(path) {
2016
+ if (!this.rootSchema) {
2017
+ return;
2018
+ }
2019
+ return resolvePath(this.rootSchema, path);
2020
+ }
2021
+ getSchemaById(id) {
2022
+ return this.idRegistry.get(id);
2023
+ }
1099
2024
  compile(schema) {
2025
+ this.idRegistry.clear();
1100
2026
  const compiledSchema = this.compileSchema(schema);
2027
+ this.rootSchema = compiledSchema;
2028
+ if (compiledSchema._hasRef === true) {
2029
+ this.linkReferences(compiledSchema);
2030
+ }
1101
2031
  if (!compiledSchema.$validate) {
1102
- if (this.isSchemaLike(schema) === false) {
2032
+ if (schema === false) {
2033
+ const defineError = getDefinedErrorFunctionForKey(
2034
+ "oneOf",
2035
+ compiledSchema,
2036
+ this.failFast
2037
+ );
2038
+ compiledSchema.$validate = getNamedFunction(
2039
+ "Validate_False",
2040
+ (data) => defineError("Value is not valid", { data })
2041
+ );
2042
+ } else if (schema === true) {
2043
+ compiledSchema.$validate = getNamedFunction(
2044
+ "Validate_Any",
2045
+ () => {
2046
+ }
2047
+ );
2048
+ } else if (this.isSchemaLike(schema) === false) {
1103
2049
  throw new ValidationError("Invalid schema");
2050
+ } else {
2051
+ compiledSchema.$validate = getNamedFunction(
2052
+ "Validate_Any",
2053
+ () => {
2054
+ }
2055
+ );
1104
2056
  }
1105
- compiledSchema.$validate = getNamedFunction(
1106
- "any",
1107
- () => {
1108
- }
1109
- );
1110
2057
  }
1111
2058
  const validate = (data) => {
1112
- const clonedData = this.immutable ? deepClone(data) : data;
1113
- const error = compiledSchema.$validate(clonedData);
1114
- return {
1115
- data: clonedData,
1116
- error: error ? error : null,
1117
- valid: !error
1118
- };
2059
+ this.rootSchema = compiledSchema;
2060
+ const clonedData = this.immutable ? deepCloneUnfreeze(data) : data;
2061
+ const res = compiledSchema.$validate(clonedData);
2062
+ if (res) {
2063
+ return { data: clonedData, error: res, valid: false };
2064
+ }
2065
+ return { data: clonedData, error: null, valid: true };
1119
2066
  };
1120
2067
  validate.compiledSchema = compiledSchema;
1121
2068
  return validate;
1122
2069
  }
2070
+ isPlainObject(value) {
2071
+ return !!value && typeof value === "object" && !Array.isArray(value);
2072
+ }
2073
+ isTrivialAlwaysValidSubschema(value) {
2074
+ return value === true || this.isPlainObject(value) && Object.keys(value).length === 0;
2075
+ }
2076
+ shallowArrayEquals(a, b) {
2077
+ if (a === b) {
2078
+ return true;
2079
+ }
2080
+ if (a.length !== b.length) {
2081
+ return false;
2082
+ }
2083
+ for (let i = 0; i < a.length; i++) {
2084
+ if (a[i] !== b[i]) {
2085
+ return false;
2086
+ }
2087
+ }
2088
+ return true;
2089
+ }
2090
+ flattenAssociativeBranches(key, branches) {
2091
+ const out = [];
2092
+ for (let i = 0; i < branches.length; i++) {
2093
+ const item = branches[i];
2094
+ if (this.isPlainObject(item) && Object.keys(item).length === 1 && Array.isArray(item[key])) {
2095
+ const nested = this.flattenAssociativeBranches(key, item[key]);
2096
+ for (let j = 0; j < nested.length; j++) {
2097
+ out.push(nested[j]);
2098
+ }
2099
+ continue;
2100
+ }
2101
+ out.push(item);
2102
+ }
2103
+ return out;
2104
+ }
2105
+ flattenSingleWrapperOneOf(branches) {
2106
+ let current = branches;
2107
+ while (current.length === 1) {
2108
+ const item = current[0];
2109
+ if (this.isPlainObject(item) && Object.keys(item).length === 1 && Array.isArray(item.oneOf)) {
2110
+ current = item.oneOf;
2111
+ continue;
2112
+ }
2113
+ break;
2114
+ }
2115
+ return current;
2116
+ }
2117
+ normalizeSchemaForCompile(schema) {
2118
+ let normalized = schema;
2119
+ const schemaKeys = Object.keys(schema);
2120
+ const hasOnlyKey = (key) => schemaKeys.length === 1 && schemaKeys[0] === key;
2121
+ const setNormalized = (key, value) => {
2122
+ if (normalized === schema) {
2123
+ normalized = { ...schema };
2124
+ }
2125
+ normalized[key] = value;
2126
+ };
2127
+ if (Array.isArray(schema.allOf)) {
2128
+ const flattenedAllOf = this.flattenAssociativeBranches(
2129
+ "allOf",
2130
+ schema.allOf
2131
+ ).filter(
2132
+ (item) => !(this.isPlainObject(item) && Object.keys(item).length === 0)
2133
+ );
2134
+ if (hasOnlyKey("allOf") && flattenedAllOf.length === 1 && this.isPlainObject(flattenedAllOf[0])) {
2135
+ return flattenedAllOf[0];
2136
+ }
2137
+ if (!this.shallowArrayEquals(flattenedAllOf, schema.allOf)) {
2138
+ setNormalized("allOf", flattenedAllOf);
2139
+ }
2140
+ }
2141
+ if (Array.isArray(schema.anyOf)) {
2142
+ const flattenedAnyOf = this.flattenAssociativeBranches(
2143
+ "anyOf",
2144
+ schema.anyOf
2145
+ );
2146
+ if (hasOnlyKey("anyOf") && flattenedAnyOf.length === 1 && this.isPlainObject(flattenedAnyOf[0])) {
2147
+ return flattenedAnyOf[0];
2148
+ }
2149
+ if (!this.shallowArrayEquals(flattenedAnyOf, schema.anyOf)) {
2150
+ setNormalized("anyOf", flattenedAnyOf);
2151
+ }
2152
+ }
2153
+ if (Array.isArray(schema.oneOf)) {
2154
+ const flattenedOneOf = this.flattenSingleWrapperOneOf(schema.oneOf);
2155
+ if (hasOnlyKey("oneOf") && flattenedOneOf.length === 1 && this.isPlainObject(flattenedOneOf[0])) {
2156
+ return flattenedOneOf[0];
2157
+ }
2158
+ if (!this.shallowArrayEquals(flattenedOneOf, schema.oneOf)) {
2159
+ setNormalized("oneOf", flattenedOneOf);
2160
+ }
2161
+ }
2162
+ return normalized;
2163
+ }
2164
+ markSchemaHasRef(schema) {
2165
+ if (schema._hasRef === true) {
2166
+ return;
2167
+ }
2168
+ Object.defineProperty(schema, "_hasRef", {
2169
+ value: true,
2170
+ enumerable: false,
2171
+ configurable: false,
2172
+ writable: false
2173
+ });
2174
+ }
2175
+ shouldSkipKeyword(schema, key) {
2176
+ const value = schema[key];
2177
+ switch (key) {
2178
+ case "required":
2179
+ return Array.isArray(value) && value.length === 0;
2180
+ case "uniqueItems":
2181
+ return value === false;
2182
+ case "properties":
2183
+ case "patternProperties":
2184
+ case "dependencies":
2185
+ return this.isPlainObject(value) && Object.keys(value).length === 0;
2186
+ case "propertyNames":
2187
+ case "items":
2188
+ return value === true;
2189
+ case "additionalProperties":
2190
+ if (value === true) {
2191
+ return true;
2192
+ }
2193
+ return value === false && this.isPlainObject(schema.patternProperties) && Object.keys(schema.patternProperties).length > 0;
2194
+ case "additionalItems":
2195
+ return value === true || !Array.isArray(schema.items);
2196
+ case "allOf": {
2197
+ if (!Array.isArray(value)) {
2198
+ return false;
2199
+ }
2200
+ if (value.length === 0) {
2201
+ return true;
2202
+ }
2203
+ for (let i = 0; i < value.length; i++) {
2204
+ if (this.isTrivialAlwaysValidSubschema(value[i])) {
2205
+ continue;
2206
+ }
2207
+ return false;
2208
+ }
2209
+ return true;
2210
+ }
2211
+ case "anyOf": {
2212
+ if (!Array.isArray(value)) {
2213
+ return false;
2214
+ }
2215
+ for (let i = 0; i < value.length; i++) {
2216
+ if (this.isTrivialAlwaysValidSubschema(value[i])) {
2217
+ return true;
2218
+ }
2219
+ }
2220
+ return false;
2221
+ }
2222
+ default:
2223
+ return false;
2224
+ }
2225
+ }
2226
+ hasRequiredDefaults(schema) {
2227
+ const properties = schema.properties;
2228
+ if (!this.isPlainObject(properties)) {
2229
+ return false;
2230
+ }
2231
+ const keys = Object.keys(properties);
2232
+ for (let i = 0; i < keys.length; i++) {
2233
+ const subSchema = properties[keys[i]];
2234
+ if (this.isPlainObject(subSchema) && "default" in subSchema) {
2235
+ return true;
2236
+ }
2237
+ }
2238
+ return false;
2239
+ }
2240
+ isDefaultTypeValidator(type, validator) {
2241
+ return Types[type] === validator;
2242
+ }
1123
2243
  compileSchema(schema) {
1124
- if (!isObject(schema)) {
2244
+ if (!schema || typeof schema !== "object" || Array.isArray(schema)) {
1125
2245
  if (schema === true) {
1126
- schema = {
1127
- anyOf: [{}]
1128
- };
2246
+ schema = { anyOf: [{}] };
1129
2247
  } else if (schema === false) {
1130
- schema = {
1131
- oneOf: []
1132
- };
2248
+ schema = { oneOf: [] };
1133
2249
  } else {
1134
- schema = {
1135
- oneOf: [schema]
1136
- };
2250
+ schema = { oneOf: [schema] };
1137
2251
  }
1138
2252
  }
1139
- const compiledSchema = deepClone(schema);
1140
- const defineTypeError = getDefinedErrorFunctionForKey("type", schema);
1141
- const typeValidations = [];
1142
- let methodName = "";
2253
+ schema = this.normalizeSchemaForCompile(schema);
2254
+ const compiledSchema = deepCloneUnfreeze(
2255
+ schema
2256
+ );
2257
+ let schemaHasRef = false;
2258
+ if (typeof schema.$id === "string") {
2259
+ this.idRegistry.set(schema.$id, compiledSchema);
2260
+ }
2261
+ if ("$ref" in schema) {
2262
+ schemaHasRef = true;
2263
+ const refValidator = this.getKeyword("$ref");
2264
+ if (refValidator) {
2265
+ const defineError = getDefinedErrorFunctionForKey(
2266
+ "$ref",
2267
+ schema["$ref"],
2268
+ this.failFast
2269
+ );
2270
+ compiledSchema.$validate = getNamedFunction(
2271
+ "Validate_Reference",
2272
+ (data) => refValidator(
2273
+ compiledSchema,
2274
+ data,
2275
+ defineError,
2276
+ this
2277
+ )
2278
+ );
2279
+ }
2280
+ this.markSchemaHasRef(compiledSchema);
2281
+ return compiledSchema;
2282
+ }
2283
+ const validators = [];
2284
+ const activeNames = [];
1143
2285
  if ("type" in schema) {
2286
+ const defineTypeError = getDefinedErrorFunctionForKey(
2287
+ "type",
2288
+ schema,
2289
+ this.failFast
2290
+ );
1144
2291
  const types = Array.isArray(schema.type) ? schema.type : schema.type.split(",").map((t) => t.trim());
1145
- for (const type of types) {
1146
- const validator = this.getType(type);
2292
+ const typeFunctions = [];
2293
+ const typeNames = [];
2294
+ const defaultTypeNames = [];
2295
+ let allTypesDefault = true;
2296
+ for (const type2 of types) {
2297
+ const validator = this.getType(type2);
1147
2298
  if (validator) {
1148
- typeValidations.push(validator);
1149
- methodName += (methodName ? "_OR_" : "") + validator.name;
2299
+ typeFunctions.push(validator);
2300
+ typeNames.push(validator.name);
2301
+ if (this.isDefaultTypeValidator(type2, validator)) {
2302
+ defaultTypeNames.push(type2);
2303
+ } else {
2304
+ allTypesDefault = false;
2305
+ }
1150
2306
  }
1151
2307
  }
1152
- const typeValidationsLength = typeValidations.length;
1153
- if (typeValidationsLength === 0) {
1154
- throw defineTypeError("Invalid type for schema", { data: schema.type });
1155
- }
1156
- if (typeValidationsLength === 1) {
1157
- const typeValidation = typeValidations[0];
1158
- compiledSchema.$validate = getNamedFunction(
1159
- methodName,
1160
- (data) => {
1161
- if (!typeValidation(data)) {
1162
- return defineTypeError("Invalid type", { data });
2308
+ if (typeFunctions.length === 0) {
2309
+ throw getDefinedErrorFunctionForKey(
2310
+ "type",
2311
+ schema,
2312
+ this.failFast
2313
+ )("Invalid type for schema", { data: schema.type });
2314
+ }
2315
+ let combinedTypeValidator;
2316
+ let typeMethodName = "";
2317
+ if (typeFunctions.length === 1 && allTypesDefault) {
2318
+ const singleTypeName = defaultTypeNames[0];
2319
+ typeMethodName = singleTypeName;
2320
+ switch (singleTypeName) {
2321
+ case "object":
2322
+ combinedTypeValidator = (data) => {
2323
+ if (data === null || typeof data !== "object" || Array.isArray(data)) {
2324
+ return defineTypeError("Invalid type", { data });
2325
+ }
2326
+ };
2327
+ break;
2328
+ case "array":
2329
+ combinedTypeValidator = (data) => {
2330
+ if (!Array.isArray(data)) {
2331
+ return defineTypeError("Invalid type", { data });
2332
+ }
2333
+ };
2334
+ break;
2335
+ case "string":
2336
+ combinedTypeValidator = (data) => {
2337
+ if (typeof data !== "string") {
2338
+ return defineTypeError("Invalid type", { data });
2339
+ }
2340
+ };
2341
+ break;
2342
+ case "number":
2343
+ combinedTypeValidator = (data) => {
2344
+ if (typeof data !== "number") {
2345
+ return defineTypeError("Invalid type", { data });
2346
+ }
2347
+ };
2348
+ break;
2349
+ case "integer":
2350
+ combinedTypeValidator = (data) => {
2351
+ if (typeof data !== "number" || !Number.isInteger(data)) {
2352
+ return defineTypeError("Invalid type", { data });
2353
+ }
2354
+ };
2355
+ break;
2356
+ case "boolean":
2357
+ combinedTypeValidator = (data) => {
2358
+ if (typeof data !== "boolean") {
2359
+ return defineTypeError("Invalid type", { data });
2360
+ }
2361
+ };
2362
+ break;
2363
+ case "null":
2364
+ combinedTypeValidator = (data) => {
2365
+ if (data !== null) {
2366
+ return defineTypeError("Invalid type", { data });
2367
+ }
2368
+ };
2369
+ break;
2370
+ default: {
2371
+ const singleTypeFn = typeFunctions[0];
2372
+ combinedTypeValidator = (data) => {
2373
+ if (!singleTypeFn(data)) {
2374
+ return defineTypeError("Invalid type", { data });
2375
+ }
2376
+ };
2377
+ }
2378
+ }
2379
+ } else if (typeFunctions.length > 1 && allTypesDefault) {
2380
+ typeMethodName = defaultTypeNames.join("_OR_");
2381
+ const allowsObject = defaultTypeNames.includes("object");
2382
+ const allowsArray = defaultTypeNames.includes("array");
2383
+ const allowsString = defaultTypeNames.includes("string");
2384
+ const allowsNumber = defaultTypeNames.includes("number");
2385
+ const allowsInteger = defaultTypeNames.includes("integer");
2386
+ const allowsBoolean = defaultTypeNames.includes("boolean");
2387
+ const allowsNull = defaultTypeNames.includes("null");
2388
+ combinedTypeValidator = (data) => {
2389
+ const dataType = typeof data;
2390
+ if (dataType === "number") {
2391
+ if (allowsNumber || allowsInteger && Number.isInteger(data)) {
2392
+ return;
1163
2393
  }
2394
+ return defineTypeError("Invalid type", { data });
1164
2395
  }
1165
- );
1166
- } else if (typeValidationsLength > 1) {
1167
- compiledSchema.$validate = getNamedFunction(
1168
- methodName,
1169
- (data) => {
1170
- for (let i = 0; i < typeValidationsLength; i++) {
1171
- if (typeValidations[i](data)) {
2396
+ if (dataType === "string") {
2397
+ if (allowsString) {
2398
+ return;
2399
+ }
2400
+ return defineTypeError("Invalid type", { data });
2401
+ }
2402
+ if (dataType === "boolean") {
2403
+ if (allowsBoolean) {
2404
+ return;
2405
+ }
2406
+ return defineTypeError("Invalid type", { data });
2407
+ }
2408
+ if (dataType === "object") {
2409
+ if (data === null) {
2410
+ if (allowsNull) {
2411
+ return;
2412
+ }
2413
+ return defineTypeError("Invalid type", { data });
2414
+ }
2415
+ if (Array.isArray(data)) {
2416
+ if (allowsArray) {
1172
2417
  return;
1173
2418
  }
2419
+ return defineTypeError("Invalid type", { data });
2420
+ }
2421
+ if (allowsObject) {
2422
+ return;
1174
2423
  }
1175
2424
  return defineTypeError("Invalid type", { data });
1176
2425
  }
1177
- );
2426
+ return defineTypeError("Invalid type", { data });
2427
+ };
2428
+ } else if (typeFunctions.length === 1) {
2429
+ typeMethodName = typeNames[0];
2430
+ const singleTypeFn = typeFunctions[0];
2431
+ combinedTypeValidator = (data) => {
2432
+ if (!singleTypeFn(data)) {
2433
+ return defineTypeError("Invalid type", { data });
2434
+ }
2435
+ };
2436
+ } else {
2437
+ typeMethodName = typeNames.join("_OR_");
2438
+ combinedTypeValidator = (data) => {
2439
+ for (let i = 0; i < typeFunctions.length; i++) {
2440
+ if (typeFunctions[i](data)) {
2441
+ return;
2442
+ }
2443
+ }
2444
+ return defineTypeError("Invalid type", { data });
2445
+ };
1178
2446
  }
1179
- }
1180
- for (const key of Object.keys(schema)) {
1181
- if (key === "type") {
1182
- compiledSchema.type = schema.type;
2447
+ validators.push({
2448
+ name: typeMethodName,
2449
+ validate: getNamedFunction(typeMethodName, combinedTypeValidator)
2450
+ });
2451
+ activeNames.push(typeMethodName);
2452
+ }
2453
+ const { type, $id, $ref, $validate, required, ...otherKeys } = schema;
2454
+ const keyOrder = required ? this.hasRequiredDefaults(schema) ? [...Object.keys(otherKeys), "required"] : ["required", ...Object.keys(otherKeys)] : Object.keys(otherKeys);
2455
+ for (const key of keyOrder) {
2456
+ const keywordFn = this.getKeyword(key);
2457
+ if (!keywordFn) {
1183
2458
  continue;
1184
2459
  }
1185
- const keywordValidator = this.getKeyword(key);
1186
- if (keywordValidator) {
1187
- const defineError = getDefinedErrorFunctionForKey(key, schema[key]);
1188
- if (compiledSchema.$validate) {
1189
- const prevValidator = compiledSchema.$validate;
1190
- methodName += `_AND_${keywordValidator.name}`;
1191
- compiledSchema.$validate = getNamedFunction(
1192
- methodName,
1193
- (data) => {
1194
- const error = prevValidator(data);
1195
- if (error) {
1196
- return error;
1197
- }
1198
- return keywordValidator(
1199
- compiledSchema,
1200
- data,
1201
- defineError,
1202
- this
1203
- );
1204
- }
1205
- );
1206
- } else {
1207
- methodName = keywordValidator.name;
1208
- compiledSchema.$validate = getNamedFunction(
1209
- methodName,
1210
- (data) => keywordValidator(
1211
- compiledSchema,
1212
- data,
1213
- defineError,
1214
- this
1215
- )
1216
- );
1217
- }
2460
+ if (this.shouldSkipKeyword(schema, key)) {
2461
+ continue;
2462
+ }
2463
+ const defineError = getDefinedErrorFunctionForKey(
2464
+ key,
2465
+ schema[key],
2466
+ this.failFast
2467
+ );
2468
+ const fnName = keywordFn.name || key;
2469
+ validators.push({
2470
+ name: fnName,
2471
+ validate: getNamedFunction(
2472
+ fnName,
2473
+ (data) => keywordFn(compiledSchema, data, defineError, this)
2474
+ )
2475
+ });
2476
+ activeNames.push(fnName);
2477
+ }
2478
+ const literalKeywords = ["enum", "const", "default", "examples"];
2479
+ for (const key of keyOrder) {
2480
+ if (literalKeywords.includes(key)) {
2481
+ continue;
1218
2482
  }
1219
- if (isObject(schema[key])) {
2483
+ if (schema[key] && typeof schema[key] === "object" && !Array.isArray(schema[key])) {
1220
2484
  if (key === "properties") {
1221
2485
  for (const subKey of Object.keys(schema[key])) {
1222
- compiledSchema[key][subKey] = this.compileSchema(
2486
+ const compiledSubSchema2 = this.compileSchema(
1223
2487
  schema[key][subKey]
1224
2488
  );
2489
+ if (compiledSubSchema2._hasRef === true) {
2490
+ schemaHasRef = true;
2491
+ }
2492
+ compiledSchema[key][subKey] = compiledSubSchema2;
1225
2493
  }
1226
2494
  continue;
1227
2495
  }
1228
- compiledSchema[key] = this.compileSchema(schema[key]);
2496
+ const compiledSubSchema = this.compileSchema(schema[key]);
2497
+ if (compiledSubSchema._hasRef === true) {
2498
+ schemaHasRef = true;
2499
+ }
2500
+ compiledSchema[key] = compiledSubSchema;
1229
2501
  continue;
1230
2502
  }
1231
2503
  if (Array.isArray(schema[key])) {
1232
- compiledSchema[key] = schema[key].map(
1233
- (subSchema, index) => this.isSchemaLike(subSchema) ? this.compileSchema(subSchema) : subSchema
1234
- );
2504
+ for (let i = 0; i < schema[key].length; i++) {
2505
+ if (this.isSchemaLike(schema[key][i])) {
2506
+ const compiledSubSchema = this.compileSchema(schema[key][i]);
2507
+ if (compiledSubSchema._hasRef === true) {
2508
+ schemaHasRef = true;
2509
+ }
2510
+ compiledSchema[key][i] = compiledSubSchema;
2511
+ }
2512
+ }
1235
2513
  continue;
1236
2514
  }
1237
- compiledSchema[key] = schema[key];
2515
+ }
2516
+ if (schemaHasRef) {
2517
+ this.markSchemaHasRef(compiledSchema);
2518
+ }
2519
+ if (validators.length === 0) {
2520
+ return compiledSchema;
2521
+ }
2522
+ if (validators.length === 1) {
2523
+ const v = validators[0];
2524
+ compiledSchema.$validate = getNamedFunction(v.name, v.validate);
2525
+ } else {
2526
+ const compositeName = "Validate_" + activeNames.join("_AND_");
2527
+ const masterValidator = (data) => {
2528
+ for (let i = 0; i < validators.length; i++) {
2529
+ const v = validators[i];
2530
+ const error = v.validate(data);
2531
+ if (error) {
2532
+ return error;
2533
+ }
2534
+ }
2535
+ return;
2536
+ };
2537
+ compiledSchema.$validate = getNamedFunction(
2538
+ compositeName,
2539
+ masterValidator
2540
+ );
1238
2541
  }
1239
2542
  return compiledSchema;
1240
2543
  }
1241
2544
  isSchemaLike(subSchema) {
1242
- if (isObject(subSchema)) {
2545
+ if (subSchema && typeof subSchema === "object" && !Array.isArray(subSchema)) {
1243
2546
  if ("type" in subSchema) {
1244
2547
  return true;
1245
2548
  }
@@ -1251,9 +2554,59 @@ var SchemaShield = class {
1251
2554
  }
1252
2555
  return false;
1253
2556
  }
2557
+ linkReferences(root) {
2558
+ const stack = [root];
2559
+ while (stack.length > 0) {
2560
+ const node = stack.pop();
2561
+ if (!node || typeof node !== "object")
2562
+ continue;
2563
+ if (typeof node.$ref === "string" && typeof node.$validate === "function" && node.$validate.name === "Validate_Reference") {
2564
+ const refPath = node.$ref;
2565
+ let target = this.getSchemaRef(refPath);
2566
+ if (typeof target === "undefined") {
2567
+ target = this.getSchemaById(refPath);
2568
+ }
2569
+ if (typeof target === "boolean") {
2570
+ if (target === true) {
2571
+ node.$validate = getNamedFunction("Validate_Ref_True", () => {
2572
+ });
2573
+ } else {
2574
+ const defineError = getDefinedErrorFunctionForKey(
2575
+ "$ref",
2576
+ node,
2577
+ this.failFast
2578
+ );
2579
+ node.$validate = getNamedFunction(
2580
+ "Validate_Ref_False",
2581
+ (_data) => defineError("Value is not valid")
2582
+ );
2583
+ }
2584
+ continue;
2585
+ }
2586
+ if (target && typeof target.$validate === "function") {
2587
+ node.$validate = target.$validate;
2588
+ }
2589
+ }
2590
+ for (const key in node) {
2591
+ const value = node[key];
2592
+ if (!value)
2593
+ continue;
2594
+ if (Array.isArray(value)) {
2595
+ for (let i = 0; i < value.length; i++) {
2596
+ const v = value[i];
2597
+ if (v && typeof v === "object") {
2598
+ stack.push(v);
2599
+ }
2600
+ }
2601
+ } else if (typeof value === "object") {
2602
+ stack.push(value);
2603
+ }
2604
+ }
2605
+ }
2606
+ }
1254
2607
  };
1255
2608
  export {
1256
2609
  SchemaShield,
1257
2610
  ValidationError,
1258
- deepClone
2611
+ deepCloneUnfreeze as deepClone
1259
2612
  };