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