@jarenjs/validate 0.8.3 → 0.9.2

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 (48) hide show
  1. package/ARCHITECTURE.md +1067 -0
  2. package/LICENSE +21 -0
  3. package/README.md +339 -2
  4. package/dist/types/array.d.ts +2 -0
  5. package/dist/types/bigint.d.ts +1 -0
  6. package/dist/types/combine.d.ts +1 -0
  7. package/dist/types/condition.d.ts +1 -0
  8. package/dist/types/content.d.ts +3 -0
  9. package/dist/types/data.d.ts +7 -0
  10. package/dist/types/dollar-data.d.ts +20 -0
  11. package/dist/types/dynamic-ref.d.ts +44 -0
  12. package/dist/types/enum.d.ts +1 -0
  13. package/dist/types/format.d.ts +21 -0
  14. package/dist/types/index.d.ts +874 -0
  15. package/dist/types/number.d.ts +1 -0
  16. package/dist/types/object.d.ts +3 -0
  17. package/dist/types/query-keyword.d.ts +19 -0
  18. package/dist/types/query.d.ts +29 -0
  19. package/dist/types/schema.d.ts +1 -0
  20. package/dist/types/string.d.ts +1 -0
  21. package/dist/types/tools.d.ts +51 -0
  22. package/dist/types/traverse.d.ts +32 -0
  23. package/dist/types/unevaluated.d.ts +12 -0
  24. package/package.json +32 -7
  25. package/src/array.js +565 -0
  26. package/src/bigint.js +97 -0
  27. package/src/combine.js +226 -0
  28. package/src/condition.js +109 -0
  29. package/src/content.js +83 -0
  30. package/src/data.js +477 -0
  31. package/src/dollar-data.js +629 -0
  32. package/src/dynamic-ref.js +121 -0
  33. package/src/enum.js +148 -0
  34. package/src/format.js +66 -0
  35. package/src/index.js +1854 -0
  36. package/src/number.js +159 -0
  37. package/src/object.js +755 -0
  38. package/src/query-keyword.js +99 -0
  39. package/src/query.js +59 -0
  40. package/src/schema.js +645 -0
  41. package/src/string.js +152 -0
  42. package/src/tools.js +205 -0
  43. package/src/traverse.js +433 -0
  44. package/src/unevaluated.js +151 -0
  45. package/dist/index.js +0 -1802
  46. package/dist/index.js.map +0 -7
  47. package/dist/index.min.js +0 -2
  48. package/dist/index.min.js.map +0 -7
@@ -0,0 +1,629 @@
1
+ //@ts-check
2
+
3
+ /**
4
+ * @fileoverview Ajv $data keyword implementation for referencing instance data.
5
+ *
6
+ * This implements the Ajv-style "$data" keyword, allowing constraint keyword values
7
+ * to be sourced from instance data at validation time using Relative JSON Pointers.
8
+ *
9
+ * Example:
10
+ * {
11
+ * "type": "object",
12
+ * "properties": {
13
+ * "smaller": {
14
+ * "type": "number",
15
+ * "maximum": { "$data": "1/larger" }
16
+ * },
17
+ * "larger": {
18
+ * "type": "number"
19
+ * }
20
+ * }
21
+ * }
22
+ *
23
+ * The "$data" value is a Relative JSON Pointer that resolves from the current data location.
24
+ * Format: <non-negative-integer>("#" | <json-pointer>)
25
+ * - "0" - The current value itself
26
+ * - "0#" - The property name/index of the current value
27
+ * - "0/foo" - The "foo" property of the current value
28
+ * - "1" - The parent value
29
+ * - "1/foo" - The "foo" property of the parent value
30
+ * - "2/bar" - Go up 2 levels, then look for "bar"
31
+ *
32
+ * @see https://github.com/ajv-validator/ajv/tree/master/spec/extras/%24data
33
+ * @see https://datatracker.ietf.org/doc/html/draft-luff-relative-json-pointer-00
34
+ */
35
+
36
+ import {
37
+ isObjectClass,
38
+ isStringType,
39
+ isNumberType,
40
+ isArrayClass,
41
+ isObjectType,
42
+ } from '@jarenjs/core';
43
+
44
+ import {
45
+ equalsDeep,
46
+ } from '@jarenjs/core/object';
47
+
48
+ import {
49
+ compileRelativeJSONPointer,
50
+ JSONPOINTER_NOTHING,
51
+ } from '@jarenjs/json';
52
+
53
+ // A ref that fails the strict compile keeps the lax keyword semantics:
54
+ // it resolves as not-found and the keyword asserts nothing.
55
+ const resolveNothing = () => JSONPOINTER_NOTHING;
56
+
57
+ function compileRefResolver(ref) {
58
+ try {
59
+ return compileRelativeJSONPointer(ref);
60
+ }
61
+ catch {
62
+ return resolveNothing;
63
+ }
64
+ }
65
+
66
+ /**
67
+ * Check if a value is a $data reference object
68
+ * @param {*} value - The value to check
69
+ * @returns {boolean} True if the value is a $data reference object
70
+ */
71
+ function isDollarDataRef(value) {
72
+ return isObjectClass(value) && isStringType(value.$data);
73
+ }
74
+
75
+
76
+ //#region Number Validators
77
+
78
+ /**
79
+ * Compile $data reference for minimum constraint
80
+ * @param {object} schemaObj - The validation object
81
+ * @param {string} ref - The $data reference (relative JSON Pointer)
82
+ * @returns {function|undefined} The compiled validator function
83
+ */
84
+ function compileDollarDataMinimum(schemaObj, ref) {
85
+ const addError = schemaObj.createErrorHandler(ref, 'minimum');
86
+ const resolveRef = compileRefResolver(ref);
87
+
88
+ return function validateDollarDataMinimum(data, dataPath, dataRoot) {
89
+ if (!isNumberType(data)) return true;
90
+
91
+ const minValue = resolveRef(dataRoot, dataPath);
92
+ if (minValue === JSONPOINTER_NOTHING || !isNumberType(minValue)) return true;
93
+
94
+ return data >= minValue || addError(minValue, data, dataPath);
95
+ };
96
+ }
97
+
98
+ /**
99
+ * Compile $data reference for maximum constraint
100
+ * @param {object} schemaObj - The validation object
101
+ * @param {string} ref - The $data reference (relative JSON Pointer)
102
+ * @returns {function|undefined} The compiled validator function
103
+ */
104
+ function compileDollarDataMaximum(schemaObj, ref) {
105
+ const addError = schemaObj.createErrorHandler(ref, 'maximum');
106
+ const resolveRef = compileRefResolver(ref);
107
+
108
+ return function validateDollarDataMaximum(data, dataPath, dataRoot) {
109
+ if (!isNumberType(data)) return true;
110
+
111
+ const maxValue = resolveRef(dataRoot, dataPath);
112
+ if (maxValue === JSONPOINTER_NOTHING || !isNumberType(maxValue)) return true;
113
+
114
+ return data <= maxValue || addError(maxValue, data, dataPath);
115
+ };
116
+ }
117
+
118
+ /**
119
+ * Compile $data reference for exclusiveMinimum constraint
120
+ * @param {object} schemaObj - The validation object
121
+ * @param {string} ref - The $data reference (relative JSON Pointer)
122
+ * @returns {function|undefined} The compiled validator function
123
+ */
124
+ function compileDollarDataExclusiveMinimum(schemaObj, ref) {
125
+ const addError = schemaObj.createErrorHandler(ref, 'exclusiveMinimum');
126
+ const resolveRef = compileRefResolver(ref);
127
+
128
+ return function validateDollarDataExclusiveMinimum(data, dataPath, dataRoot) {
129
+ if (!isNumberType(data)) return true;
130
+
131
+ const minValue = resolveRef(dataRoot, dataPath);
132
+ if (minValue === JSONPOINTER_NOTHING || !isNumberType(minValue)) return true;
133
+
134
+ return data > minValue || addError(minValue, data, dataPath);
135
+ };
136
+ }
137
+
138
+ /**
139
+ * Compile $data reference for exclusiveMaximum constraint
140
+ * @param {object} schemaObj - The validation object
141
+ * @param {string} ref - The $data reference (relative JSON Pointer)
142
+ * @returns {function|undefined} The compiled validator function
143
+ */
144
+ function compileDollarDataExclusiveMaximum(schemaObj, ref) {
145
+ const addError = schemaObj.createErrorHandler(ref, 'exclusiveMaximum');
146
+ const resolveRef = compileRefResolver(ref);
147
+
148
+ return function validateDollarDataExclusiveMaximum(data, dataPath, dataRoot) {
149
+ if (!isNumberType(data)) return true;
150
+
151
+ const maxValue = resolveRef(dataRoot, dataPath);
152
+ if (maxValue === JSONPOINTER_NOTHING || !isNumberType(maxValue)) return true;
153
+
154
+ return data < maxValue || addError(maxValue, data, dataPath);
155
+ };
156
+ }
157
+
158
+ /**
159
+ * Compile $data reference for multipleOf constraint
160
+ * @param {object} schemaObj - The validation object
161
+ * @param {string} ref - The $data reference (relative JSON Pointer)
162
+ * @returns {function|undefined} The compiled validator function
163
+ */
164
+ function compileDollarDataMultipleOf(schemaObj, ref) {
165
+ const addError = schemaObj.createErrorHandler(ref, 'multipleOf');
166
+ const resolveRef = compileRefResolver(ref);
167
+
168
+ return function validateDollarDataMultipleOf(data, dataPath, dataRoot) {
169
+ if (!isNumberType(data)) return true;
170
+
171
+ const multipleOf = resolveRef(dataRoot, dataPath);
172
+ if (multipleOf === JSONPOINTER_NOTHING || !isNumberType(multipleOf)) return true;
173
+
174
+ const q = data / multipleOf;
175
+ return Math.abs(q - Math.round(q)) < 1e-6 || addError(multipleOf, data, dataPath);
176
+ };
177
+ }
178
+
179
+ //#endregion
180
+
181
+ //#region String Validators
182
+
183
+ /**
184
+ * Compile $data reference for minLength constraint
185
+ * @param {object} schemaObj - The validation object
186
+ * @param {string} ref - The $data reference (relative JSON Pointer)
187
+ * @returns {function|undefined} The compiled validator function
188
+ */
189
+ function compileDollarDataMinLength(schemaObj, ref) {
190
+ const addError = schemaObj.createErrorHandler(ref, 'minLength');
191
+ const resolveRef = compileRefResolver(ref);
192
+
193
+ return function validateDollarDataMinLength(data, dataPath, dataRoot) {
194
+ if (typeof data !== 'string') return true;
195
+
196
+ const minLen = resolveRef(dataRoot, dataPath);
197
+ if (minLen === JSONPOINTER_NOTHING || !isNumberType(minLen)) return true;
198
+
199
+ return data.length >= minLen || addError(minLen, data, dataPath);
200
+ };
201
+ }
202
+
203
+ /**
204
+ * Compile $data reference for maxLength constraint
205
+ * @param {object} schemaObj - The validation object
206
+ * @param {string} ref - The $data reference (relative JSON Pointer)
207
+ * @returns {function|undefined} The compiled validator function
208
+ */
209
+ function compileDollarDataMaxLength(schemaObj, ref) {
210
+ const addError = schemaObj.createErrorHandler(ref, 'maxLength');
211
+ const resolveRef = compileRefResolver(ref);
212
+
213
+ return function validateDollarDataMaxLength(data, dataPath, dataRoot) {
214
+ if (typeof data !== 'string') return true;
215
+
216
+ const maxLen = resolveRef(dataRoot, dataPath);
217
+ if (maxLen === JSONPOINTER_NOTHING || !isNumberType(maxLen)) return true;
218
+
219
+ return data.length <= maxLen || addError(maxLen, data, dataPath);
220
+ };
221
+ }
222
+
223
+ /**
224
+ * Compile $data reference for pattern constraint
225
+ * @param {object} schemaObj - The validation object
226
+ * @param {string} ref - The $data reference (relative JSON Pointer)
227
+ * @returns {function|undefined} The compiled validator function
228
+ */
229
+ function compileDollarDataPattern(schemaObj, ref) {
230
+ const addError = schemaObj.createErrorHandler(ref, 'pattern');
231
+ const resolveRef = compileRefResolver(ref);
232
+
233
+ return function validateDollarDataPattern(data, dataPath, dataRoot) {
234
+ if (typeof data !== 'string') return true;
235
+
236
+ const pattern = resolveRef(dataRoot, dataPath);
237
+ if (pattern === JSONPOINTER_NOTHING || !isStringType(pattern)) return true;
238
+
239
+ const regex = new RegExp(pattern, 'u');
240
+ return regex.test(data) || addError(pattern, data, dataPath);
241
+ };
242
+ }
243
+
244
+ /**
245
+ * Compile $data reference for format constraint
246
+ * @param {object} schemaObj - The validation object
247
+ * @param {string} ref - The $data reference (relative JSON Pointer)
248
+ * @returns {function|undefined} The compiled validator function
249
+ */
250
+ function compileDollarDataFormat(schemaObj, ref) {
251
+ const formats = schemaObj.formats;
252
+ if (!formats) return undefined;
253
+
254
+ const addError = schemaObj.createErrorHandler(ref, 'format');
255
+ const resolveRef = compileRefResolver(ref);
256
+
257
+ return function validateDollarDataFormat(data, dataPath, dataRoot) {
258
+ if (typeof data !== 'string') return true;
259
+
260
+ const formatName = resolveRef(dataRoot, dataPath);
261
+ if (formatName === JSONPOINTER_NOTHING || !isStringType(formatName)) return true;
262
+
263
+ const formatCompiler = formats[formatName];
264
+ if (!formatCompiler) return true;
265
+
266
+ // The format compiler needs to be called to create the validator
267
+ // We pass a mock schemaObj that only has createErrorHandler
268
+ const mockSchemaObj = {
269
+ createErrorHandler: () => () => false,
270
+ options: { skipErrors: true }
271
+ };
272
+
273
+ try {
274
+ // Get the validator function from the compiler
275
+ const validator = formatCompiler(mockSchemaObj, { format: formatName });
276
+ if (typeof validator !== 'function') return true;
277
+
278
+ return validator(data, dataPath) || addError(formatName, data, dataPath);
279
+ } catch (e) {
280
+ // If compilation fails, skip validation
281
+ return true;
282
+ }
283
+ };
284
+ }
285
+
286
+ //#endregion
287
+
288
+ //#region Array Validators
289
+
290
+ /**
291
+ * Compile $data reference for minItems constraint
292
+ * @param {object} schemaObj - The validation object
293
+ * @param {string} ref - The $data reference (relative JSON Pointer)
294
+ * @returns {function|undefined} The compiled validator function
295
+ */
296
+ function compileDollarDataMinItems(schemaObj, ref) {
297
+ const addError = schemaObj.createErrorHandler(ref, 'minItems');
298
+ const resolveRef = compileRefResolver(ref);
299
+
300
+ return function validateDollarDataMinItems(data, dataPath, dataRoot) {
301
+ if (!Array.isArray(data)) return true;
302
+
303
+ const minItems = resolveRef(dataRoot, dataPath);
304
+ if (minItems === JSONPOINTER_NOTHING || !isNumberType(minItems)) return true;
305
+
306
+ return data.length >= minItems || addError(minItems, data, dataPath);
307
+ };
308
+ }
309
+
310
+ /**
311
+ * Compile $data reference for maxItems constraint
312
+ * @param {object} schemaObj - The validation object
313
+ * @param {string} ref - The $data reference (relative JSON Pointer)
314
+ * @returns {function|undefined} The compiled validator function
315
+ */
316
+ function compileDollarDataMaxItems(schemaObj, ref) {
317
+ const addError = schemaObj.createErrorHandler(ref, 'maxItems');
318
+ const resolveRef = compileRefResolver(ref);
319
+
320
+ return function validateDollarDataMaxItems(data, dataPath, dataRoot) {
321
+ if (!Array.isArray(data)) return true;
322
+
323
+ const maxItems = resolveRef(dataRoot, dataPath);
324
+ if (maxItems === JSONPOINTER_NOTHING || !isNumberType(maxItems)) return true;
325
+
326
+ return data.length <= maxItems || addError(maxItems, data, dataPath);
327
+ };
328
+ }
329
+
330
+ /**
331
+ * Compile $data reference for uniqueItems constraint
332
+ * @param {object} schemaObj - The validation object
333
+ * @param {string} ref - The $data reference (relative JSON Pointer)
334
+ * @returns {function|undefined} The compiled validator function
335
+ */
336
+ function compileDollarDataUniqueItems(schemaObj, ref) {
337
+ const addError = schemaObj.createErrorHandler(ref, 'uniqueItems');
338
+ const resolveRef = compileRefResolver(ref);
339
+
340
+ return function validateDollarDataUniqueItems(data, dataPath, dataRoot) {
341
+ if (!Array.isArray(data)) return true;
342
+
343
+ const shouldBeUnique = resolveRef(dataRoot, dataPath);
344
+ if (shouldBeUnique === JSONPOINTER_NOTHING || !shouldBeUnique) return true;
345
+
346
+ // Check for duplicates using deep equality
347
+ for (let i = 0; i < data.length; i++) {
348
+ for (let j = i + 1; j < data.length; j++) {
349
+ if (equalsDeep(data[i], data[j])) {
350
+ return addError(true, data, dataPath);
351
+ }
352
+ }
353
+ }
354
+ return true;
355
+ };
356
+ }
357
+
358
+ //#endregion
359
+
360
+ //#region Object Validators
361
+
362
+ /**
363
+ * Compile $data reference for minProperties constraint
364
+ * @param {object} schemaObj - The validation object
365
+ * @param {string} ref - The $data reference (relative JSON Pointer)
366
+ * @returns {function|undefined} The compiled validator function
367
+ */
368
+ function compileDollarDataMinProperties(schemaObj, ref) {
369
+ const addError = schemaObj.createErrorHandler(ref, 'minProperties');
370
+ const resolveRef = compileRefResolver(ref);
371
+
372
+ return function validateDollarDataMinProperties(data, dataPath, dataRoot) {
373
+ if (typeof data !== 'object' || data === null || Array.isArray(data)) return true;
374
+
375
+ const minProps = resolveRef(dataRoot, dataPath);
376
+ if (minProps === JSONPOINTER_NOTHING || !isNumberType(minProps)) return true;
377
+
378
+ const propCount = Object.keys(data).length;
379
+ return propCount >= minProps || addError(minProps, data, dataPath);
380
+ };
381
+ }
382
+
383
+ /**
384
+ * Compile $data reference for maxProperties constraint
385
+ * @param {object} schemaObj - The validation object
386
+ * @param {string} ref - The $data reference (relative JSON Pointer)
387
+ * @returns {function|undefined} The compiled validator function
388
+ */
389
+ function compileDollarDataMaxProperties(schemaObj, ref) {
390
+ const addError = schemaObj.createErrorHandler(ref, 'maxProperties');
391
+ const resolveRef = compileRefResolver(ref);
392
+
393
+ return function validateDollarDataMaxProperties(data, dataPath, dataRoot) {
394
+ if (typeof data !== 'object' || data === null || Array.isArray(data)) return true;
395
+
396
+ const maxProps = resolveRef(dataRoot, dataPath);
397
+ if (maxProps === JSONPOINTER_NOTHING || !isNumberType(maxProps)) return true;
398
+
399
+ const propCount = Object.keys(data).length;
400
+ return propCount <= maxProps || addError(maxProps, data, dataPath);
401
+ };
402
+ }
403
+
404
+ /**
405
+ * Compile $data reference for required constraint
406
+ * @param {object} schemaObj - The validation object
407
+ * @param {string} ref - The $data reference (relative JSON Pointer)
408
+ * @returns {function|undefined} The compiled validator function
409
+ */
410
+ function compileDollarDataRequired(schemaObj, ref) {
411
+ const addError = schemaObj.createErrorHandler(ref, 'required');
412
+ const resolveRef = compileRefResolver(ref);
413
+
414
+ return function validateDollarDataRequired(data, dataPath, dataRoot) {
415
+ if (typeof data !== 'object' || data === null || Array.isArray(data)) return true;
416
+
417
+ const requiredProps = resolveRef(dataRoot, dataPath);
418
+ if (requiredProps === JSONPOINTER_NOTHING || !Array.isArray(requiredProps)) return true;
419
+
420
+ for (const prop of requiredProps) {
421
+ if (!(prop in data)) {
422
+ return addError(prop, data, dataPath);
423
+ }
424
+ }
425
+ return true;
426
+ };
427
+ }
428
+
429
+ //#endregion
430
+
431
+ //#region Enum/Const Validators
432
+
433
+ /**
434
+ * Compile $data reference for enum constraint
435
+ * @param {object} schemaObj - The validation object
436
+ * @param {string} ref - The $data reference (relative JSON Pointer)
437
+ * @returns {function|undefined} The compiled validator function
438
+ */
439
+ function compileDollarDataEnum(schemaObj, ref) {
440
+ const addError = schemaObj.createErrorHandler(ref, 'enum');
441
+ const resolveRef = compileRefResolver(ref);
442
+
443
+ return function validateDollarDataEnum(data, dataPath, dataRoot) {
444
+ if (data === undefined) return true;
445
+
446
+ const enumValues = resolveRef(dataRoot, dataPath);
447
+ if (enumValues === JSONPOINTER_NOTHING || !Array.isArray(enumValues)) return true;
448
+
449
+ return enumValues.includes(data) || addError(enumValues, data, dataPath);
450
+ };
451
+ }
452
+
453
+ /**
454
+ * Compile $data reference for const constraint
455
+ * @param {object} schemaObj - The validation object
456
+ * @param {string} ref - The $data reference (relative JSON Pointer)
457
+ * @returns {function|undefined} The compiled validator function
458
+ */
459
+ function compileDollarDataConst(schemaObj, ref) {
460
+ const addError = schemaObj.createErrorHandler(ref, 'const');
461
+ const resolveRef = compileRefResolver(ref);
462
+
463
+ return function validateDollarDataConst(data, dataPath, dataRoot) {
464
+ if (data === undefined) return true;
465
+
466
+ const constValue = resolveRef(dataRoot, dataPath);
467
+ if (constValue === JSONPOINTER_NOTHING) return true;
468
+
469
+ return data === constValue || addError(constValue, data, dataPath);
470
+ };
471
+ }
472
+
473
+ //#endregion
474
+
475
+ //#region Main Compilation
476
+
477
+ /**
478
+ * Compile $data keyword validators for a schema object
479
+ * This detects when keyword values are { $data: "..." } objects and creates
480
+ * dynamic validators that resolve the reference at validation time.
481
+ *
482
+ * @param {object} schemaObj - The validation object
483
+ * @param {object} jsonSchema - The JSON schema to compile
484
+ * @returns {function|undefined} The compiled validator function or undefined
485
+ */
486
+ export function compileDollarDataSchema(schemaObj, jsonSchema) {
487
+ const validators = [];
488
+
489
+ // Number constraints
490
+ if (isDollarDataRef(jsonSchema.minimum)) {
491
+ const validator = compileDollarDataMinimum(schemaObj, jsonSchema.minimum.$data);
492
+ if (validator) validators.push(validator);
493
+ }
494
+
495
+ if (isDollarDataRef(jsonSchema.maximum)) {
496
+ const validator = compileDollarDataMaximum(schemaObj, jsonSchema.maximum.$data);
497
+ if (validator) validators.push(validator);
498
+ }
499
+
500
+ if (isDollarDataRef(jsonSchema.exclusiveMinimum)) {
501
+ const validator = compileDollarDataExclusiveMinimum(schemaObj, jsonSchema.exclusiveMinimum.$data);
502
+ if (validator) validators.push(validator);
503
+ }
504
+
505
+ if (isDollarDataRef(jsonSchema.exclusiveMaximum)) {
506
+ const validator = compileDollarDataExclusiveMaximum(schemaObj, jsonSchema.exclusiveMaximum.$data);
507
+ if (validator) validators.push(validator);
508
+ }
509
+
510
+ if (isDollarDataRef(jsonSchema.multipleOf)) {
511
+ const validator = compileDollarDataMultipleOf(schemaObj, jsonSchema.multipleOf.$data);
512
+ if (validator) validators.push(validator);
513
+ }
514
+
515
+ // String constraints
516
+ if (isDollarDataRef(jsonSchema.minLength)) {
517
+ const validator = compileDollarDataMinLength(schemaObj, jsonSchema.minLength.$data);
518
+ if (validator) validators.push(validator);
519
+ }
520
+
521
+ if (isDollarDataRef(jsonSchema.maxLength)) {
522
+ const validator = compileDollarDataMaxLength(schemaObj, jsonSchema.maxLength.$data);
523
+ if (validator) validators.push(validator);
524
+ }
525
+
526
+ if (isDollarDataRef(jsonSchema.pattern)) {
527
+ const validator = compileDollarDataPattern(schemaObj, jsonSchema.pattern.$data);
528
+ if (validator) validators.push(validator);
529
+ }
530
+
531
+ if (isDollarDataRef(jsonSchema.format)) {
532
+ const validator = compileDollarDataFormat(schemaObj, jsonSchema.format.$data);
533
+ if (validator) validators.push(validator);
534
+ }
535
+
536
+ // Array constraints
537
+ if (isDollarDataRef(jsonSchema.minItems)) {
538
+ const validator = compileDollarDataMinItems(schemaObj, jsonSchema.minItems.$data);
539
+ if (validator) validators.push(validator);
540
+ }
541
+
542
+ if (isDollarDataRef(jsonSchema.maxItems)) {
543
+ const validator = compileDollarDataMaxItems(schemaObj, jsonSchema.maxItems.$data);
544
+ if (validator) validators.push(validator);
545
+ }
546
+
547
+ if (isDollarDataRef(jsonSchema.uniqueItems)) {
548
+ const validator = compileDollarDataUniqueItems(schemaObj, jsonSchema.uniqueItems.$data);
549
+ if (validator) validators.push(validator);
550
+ }
551
+
552
+ // Object constraints
553
+ if (isDollarDataRef(jsonSchema.minProperties)) {
554
+ const validator = compileDollarDataMinProperties(schemaObj, jsonSchema.minProperties.$data);
555
+ if (validator) validators.push(validator);
556
+ }
557
+
558
+ if (isDollarDataRef(jsonSchema.maxProperties)) {
559
+ const validator = compileDollarDataMaxProperties(schemaObj, jsonSchema.maxProperties.$data);
560
+ if (validator) validators.push(validator);
561
+ }
562
+
563
+ if (isDollarDataRef(jsonSchema.required)) {
564
+ const validator = compileDollarDataRequired(schemaObj, jsonSchema.required.$data);
565
+ if (validator) validators.push(validator);
566
+ }
567
+
568
+ // Enum/Const constraints
569
+ if (isDollarDataRef(jsonSchema.enum)) {
570
+ const validator = compileDollarDataEnum(schemaObj, jsonSchema.enum.$data);
571
+ if (validator) validators.push(validator);
572
+ }
573
+
574
+ if (isDollarDataRef(jsonSchema.const)) {
575
+ const validator = compileDollarDataConst(schemaObj, jsonSchema.const.$data);
576
+ if (validator) validators.push(validator);
577
+ }
578
+
579
+ if (validators.length === 0) {
580
+ return undefined;
581
+ }
582
+
583
+ if (validators.length === 1) {
584
+ return validators[0];
585
+ }
586
+
587
+ return function validateDollarDataSchema(data, dataPath, dataRoot) {
588
+ for (let i = 0; i < validators.length; i++) {
589
+ if (!validators[i](data, dataPath, dataRoot)) {
590
+ return false;
591
+ }
592
+ }
593
+ return true;
594
+ };
595
+ }
596
+
597
+ /**
598
+ * Check if the schema has any $data references
599
+ * This is used to determine if we should use the $data-aware compilation path
600
+ * or the standard static compilation path.
601
+ *
602
+ * @param {object} jsonSchema - The JSON schema to check
603
+ * @returns {boolean} True if the schema has any $data references
604
+ */
605
+ export function hasDollarDataReferences(jsonSchema) {
606
+ if (!isObjectType(jsonSchema)) return false;
607
+
608
+ // Keywords that can have $data values
609
+ const keywords = [
610
+ 'minimum', 'maximum', 'exclusiveMinimum', 'exclusiveMaximum', 'multipleOf',
611
+ 'minLength', 'maxLength', 'pattern', 'format',
612
+ 'minItems', 'maxItems', 'uniqueItems',
613
+ 'minProperties', 'maxProperties', 'required',
614
+ 'enum', 'const'
615
+ ];
616
+
617
+ for (const keyword of keywords) {
618
+ if (isDollarDataRef(jsonSchema[keyword])) {
619
+ return true;
620
+ }
621
+ }
622
+
623
+ return false;
624
+ }
625
+
626
+ export function isDollarDataReference(jsonSchema) {
627
+ return (jsonSchema !== null && (isObjectType(jsonSchema) && jsonSchema.$data));
628
+ }
629
+ //#endregion