schema-shield 0.0.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.
package/dist/index.mjs ADDED
@@ -0,0 +1,1267 @@
1
+ // lib/utils.ts
2
+ var ValidationError = class extends Error {
3
+ name;
4
+ pointer;
5
+ message;
6
+ value;
7
+ code;
8
+ constructor(message, options = {
9
+ pointer: "",
10
+ value: null,
11
+ code: ""
12
+ }) {
13
+ super(message);
14
+ this.name = "ValidationError";
15
+ this.pointer = options.pointer;
16
+ this.message = message;
17
+ this.value = options.value;
18
+ this.code = options.code;
19
+ }
20
+ };
21
+ function deepEqual(obj, other) {
22
+ if (Array.isArray(obj) && Array.isArray(other)) {
23
+ if (obj.length !== other.length) {
24
+ return false;
25
+ }
26
+ for (let i = 0; i < obj.length; i++) {
27
+ if (!deepEqual(obj[i], other[i])) {
28
+ return false;
29
+ }
30
+ }
31
+ return true;
32
+ }
33
+ if (typeof obj === "object" && typeof other === "object") {
34
+ if (obj === null || other === null) {
35
+ return obj === other;
36
+ }
37
+ const keys = Object.keys(obj);
38
+ if (keys.length !== Object.keys(other).length) {
39
+ return false;
40
+ }
41
+ for (const key of keys) {
42
+ if (!deepEqual(obj[key], other[key])) {
43
+ return false;
44
+ }
45
+ }
46
+ return true;
47
+ }
48
+ return obj === other;
49
+ }
50
+ function isObject(data) {
51
+ return typeof data === "object" && data !== null && !Array.isArray(data);
52
+ }
53
+
54
+ // lib/formats.ts
55
+ var RegExps = {
56
+ "date-time": /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2})$/,
57
+ uri: /^[a-zA-Z][a-zA-Z0-9+\-.]*:[^\s]*$/,
58
+ email: /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/,
59
+ ipv4: /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/,
60
+ ipv6: /^(?:(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|(?=(?:[0-9a-fA-F]{0,4}:){0,7}[0-9a-fA-F]{0,4}(?![:.\w]))(([0-9a-fA-F]{1,4}:){1,7}|:)((:[0-9a-fA-F]{1,4}){1,7}|:))$/,
61
+ hostname: /^[a-zA-Z0-9][a-zA-Z0-9-]{0,62}(\.[a-zA-Z0-9][a-zA-Z0-9-]{0,62})*$/
62
+ };
63
+ function notImplementedFormat(data) {
64
+ throw new ValidationError(
65
+ `Format "${data}" is not implemented yet. Please open an issue on GitHub.`
66
+ );
67
+ return false;
68
+ }
69
+ var Formats = {
70
+ ["date-time"](data) {
71
+ return RegExps["date-time"].test(data);
72
+ },
73
+ uri(data) {
74
+ return RegExps.uri.test(data);
75
+ },
76
+ email(data) {
77
+ return RegExps.email.test(data);
78
+ },
79
+ ipv4(data) {
80
+ return RegExps.ipv4.test(data);
81
+ },
82
+ ipv6(data) {
83
+ return RegExps.ipv6.test(data);
84
+ },
85
+ hostname(data) {
86
+ return RegExps.hostname.test(data);
87
+ },
88
+ // Not supported yet
89
+ time: notImplementedFormat,
90
+ date: notImplementedFormat,
91
+ duration: notImplementedFormat,
92
+ "idn-email": notImplementedFormat,
93
+ "idn-hostname": notImplementedFormat,
94
+ uuid: notImplementedFormat,
95
+ "uri-reference": notImplementedFormat,
96
+ iri: notImplementedFormat,
97
+ "iri-reference": notImplementedFormat,
98
+ "uri-template": notImplementedFormat,
99
+ "json-pointer": notImplementedFormat,
100
+ "relative-json-pointer": notImplementedFormat,
101
+ regex: notImplementedFormat
102
+ };
103
+
104
+ // lib/types.ts
105
+ var Types = {
106
+ object(schema, data, pointer) {
107
+ if (typeof data === "object" && data !== null && !Array.isArray(data)) {
108
+ return {
109
+ valid: true,
110
+ errors: [],
111
+ data
112
+ };
113
+ }
114
+ return {
115
+ valid: false,
116
+ errors: [
117
+ new ValidationError("Data is not an object", {
118
+ pointer,
119
+ value: data,
120
+ code: "NOT_AN_OBJECT"
121
+ })
122
+ ],
123
+ data
124
+ };
125
+ },
126
+ array(schema, data, pointer) {
127
+ if (Array.isArray(data)) {
128
+ return {
129
+ valid: true,
130
+ errors: [],
131
+ data
132
+ };
133
+ }
134
+ if (typeof data === "object" && data !== null && "length" in data) {
135
+ const keys = Object.keys(data);
136
+ if (keys.length > 0 && (keys[0] !== "0" || keys.length !== data.length)) {
137
+ return {
138
+ valid: false,
139
+ errors: [
140
+ new ValidationError("Data is not an array", {
141
+ pointer,
142
+ value: data,
143
+ code: "NOT_AN_ARRAY"
144
+ })
145
+ ],
146
+ data
147
+ };
148
+ }
149
+ return {
150
+ valid: true,
151
+ errors: [],
152
+ data
153
+ };
154
+ }
155
+ return {
156
+ valid: false,
157
+ errors: [
158
+ new ValidationError("Data is not an array", {
159
+ pointer,
160
+ value: data,
161
+ code: "NOT_AN_ARRAY"
162
+ })
163
+ ],
164
+ data
165
+ };
166
+ },
167
+ string(schema, data, pointer) {
168
+ if (typeof data === "string") {
169
+ return {
170
+ valid: true,
171
+ errors: [],
172
+ data
173
+ };
174
+ }
175
+ return {
176
+ valid: false,
177
+ errors: [
178
+ new ValidationError("Data is not a string", {
179
+ pointer,
180
+ value: data,
181
+ code: "NOT_A_STRING"
182
+ })
183
+ ],
184
+ data
185
+ };
186
+ },
187
+ number(schema, data, pointer) {
188
+ if (typeof data === "number") {
189
+ return {
190
+ valid: true,
191
+ errors: [],
192
+ data
193
+ };
194
+ }
195
+ return {
196
+ valid: false,
197
+ errors: [
198
+ new ValidationError("Data is not a number", {
199
+ pointer,
200
+ value: data,
201
+ code: "NOT_A_NUMBER"
202
+ })
203
+ ],
204
+ data
205
+ };
206
+ },
207
+ integer(schema, data, pointer) {
208
+ if (typeof data === "number" && Number.isInteger(data)) {
209
+ return {
210
+ valid: true,
211
+ errors: [],
212
+ data
213
+ };
214
+ }
215
+ return {
216
+ valid: false,
217
+ errors: [
218
+ new ValidationError("Data is not an integer", {
219
+ pointer,
220
+ value: data,
221
+ code: "NOT_AN_INTEGER"
222
+ })
223
+ ],
224
+ data
225
+ };
226
+ },
227
+ boolean(schema, data, pointer) {
228
+ if (typeof data === "boolean") {
229
+ return {
230
+ valid: true,
231
+ errors: [],
232
+ data
233
+ };
234
+ }
235
+ return {
236
+ valid: false,
237
+ errors: [
238
+ new ValidationError("Data is not a boolean", {
239
+ pointer,
240
+ value: data,
241
+ code: "NOT_A_BOOLEAN"
242
+ })
243
+ ],
244
+ data
245
+ };
246
+ },
247
+ null(schema, data, pointer) {
248
+ if (data === null) {
249
+ return {
250
+ valid: true,
251
+ errors: [],
252
+ data
253
+ };
254
+ }
255
+ return {
256
+ valid: false,
257
+ errors: [
258
+ new ValidationError("Data is not null", {
259
+ pointer,
260
+ value: data,
261
+ code: "NOT_NULL"
262
+ })
263
+ ],
264
+ data
265
+ };
266
+ }
267
+ };
268
+
269
+ // lib/keywords/array-keywords.ts
270
+ var ArrayKeywords = {
271
+ items(schema, data, pointer, schemaShieldInstance) {
272
+ if (!Array.isArray(data)) {
273
+ return { valid: true, errors: [], data };
274
+ }
275
+ const errors = [];
276
+ let finalData = [...data];
277
+ if (Array.isArray(schema.items)) {
278
+ for (let i = 0; i < schema.items.length; i++) {
279
+ if (typeof schema.items[i] === "boolean") {
280
+ if (schema.items[i] === false && typeof data[i] !== "undefined") {
281
+ errors.push(
282
+ new ValidationError("Array item is not allowed", {
283
+ pointer: `${pointer}/${i}`,
284
+ value: data[i],
285
+ code: "ARRAY_ITEM_NOT_ALLOWED"
286
+ })
287
+ );
288
+ }
289
+ continue;
290
+ }
291
+ const { validator } = schema.items[i];
292
+ if (!validator) {
293
+ continue;
294
+ }
295
+ const validatorResult = validator(
296
+ schema.items[i],
297
+ finalData[i],
298
+ `${pointer}/${i}`,
299
+ schemaShieldInstance
300
+ );
301
+ finalData[i] = validatorResult.data;
302
+ if (!validatorResult.valid) {
303
+ errors.push(...validatorResult.errors);
304
+ }
305
+ }
306
+ } else if (typeof schema.items === "boolean") {
307
+ if (schema.items === false && data.length > 0) {
308
+ errors.push(
309
+ new ValidationError("Array is not allowed", {
310
+ pointer,
311
+ value: data,
312
+ code: "ARRAY_NOT_ALLOWED"
313
+ })
314
+ );
315
+ }
316
+ } else {
317
+ const { validator } = schema.items;
318
+ if (!validator) {
319
+ return { valid: true, errors: [], data };
320
+ }
321
+ for (let i = 0; i < finalData.length; i++) {
322
+ const validatorErrors = validator(
323
+ schema.items,
324
+ finalData[i],
325
+ `${pointer}/${i}`,
326
+ schemaShieldInstance
327
+ );
328
+ finalData[i] = validatorErrors.data;
329
+ if (!validatorErrors.valid) {
330
+ errors.push(...validatorErrors.errors);
331
+ }
332
+ }
333
+ }
334
+ return { valid: errors.length === 0, errors, data: finalData };
335
+ },
336
+ minItems(schema, data, pointer) {
337
+ if (!Array.isArray(data) || data.length >= schema.minItems) {
338
+ return { valid: true, errors: [], data };
339
+ }
340
+ return {
341
+ valid: false,
342
+ errors: [
343
+ new ValidationError("Array is too short", {
344
+ pointer,
345
+ value: data,
346
+ code: "ARRAY_TOO_SHORT"
347
+ })
348
+ ],
349
+ data
350
+ };
351
+ },
352
+ maxItems(schema, data, pointer) {
353
+ if (!Array.isArray(data) || data.length <= schema.maxItems) {
354
+ return { valid: true, errors: [], data };
355
+ }
356
+ return {
357
+ valid: false,
358
+ errors: [
359
+ new ValidationError("Array is too long", {
360
+ pointer,
361
+ value: data,
362
+ code: "ARRAY_TOO_LONG"
363
+ })
364
+ ],
365
+ data
366
+ };
367
+ },
368
+ additionalItems(schema, data, pointer, schemaShieldInstance) {
369
+ if (!Array.isArray(data) || !schema.items || !Array.isArray(schema.items)) {
370
+ return { valid: true, errors: [], data };
371
+ }
372
+ if (schema.additionalItems === false) {
373
+ if (data.length > schema.items.length) {
374
+ return {
375
+ valid: false,
376
+ errors: [
377
+ new ValidationError("Array has too many items", {
378
+ pointer,
379
+ value: data,
380
+ code: "ARRAY_TOO_MANY_ITEMS"
381
+ })
382
+ ],
383
+ data
384
+ };
385
+ }
386
+ return { valid: true, errors: [], data };
387
+ }
388
+ const errors = [];
389
+ let finalData = [...data];
390
+ if (typeof schema.additionalItems === "object") {
391
+ for (let i = schema.items.length; i < finalData.length; i++) {
392
+ const { validator } = schema.additionalItems;
393
+ const validatorResult = validator(
394
+ schema.additionalItems,
395
+ finalData[i],
396
+ `${pointer}/${i}`,
397
+ schemaShieldInstance
398
+ );
399
+ if (!validatorResult.valid) {
400
+ errors.push(...validatorResult.errors);
401
+ }
402
+ finalData[i] = validatorResult.data;
403
+ }
404
+ }
405
+ return { valid: errors.length === 0, errors, data: finalData };
406
+ },
407
+ uniqueItems(schema, data, pointer) {
408
+ if (!Array.isArray(data) || !schema.uniqueItems) {
409
+ return { valid: true, errors: [], data };
410
+ }
411
+ const unique = /* @__PURE__ */ new Set();
412
+ for (const item of data) {
413
+ let itemStr = item;
414
+ if (typeof item === "string") {
415
+ itemStr = `"${item}"`;
416
+ } else if (isObject(item)) {
417
+ const keys = Object.keys(item).sort();
418
+ const sorted = {};
419
+ for (let i = 0; i < keys.length; i++) {
420
+ sorted[keys[i]] = item[keys[i]];
421
+ }
422
+ itemStr = JSON.stringify(sorted);
423
+ } else if (Array.isArray(item)) {
424
+ itemStr = JSON.stringify(item);
425
+ }
426
+ if (unique.has(itemStr)) {
427
+ return {
428
+ valid: false,
429
+ errors: [
430
+ new ValidationError("Array items are not unique", {
431
+ pointer,
432
+ value: data,
433
+ code: "ARRAY_ITEMS_NOT_UNIQUE"
434
+ })
435
+ ],
436
+ data
437
+ };
438
+ } else {
439
+ unique.add(itemStr);
440
+ }
441
+ }
442
+ return { valid: true, errors: [], data };
443
+ }
444
+ };
445
+
446
+ // lib/keywords/number-keywords.ts
447
+ var NumberKeywords = {
448
+ minimum(schema, data, pointer) {
449
+ if (typeof data !== "number") {
450
+ return { valid: true, errors: [], data };
451
+ }
452
+ const min = schema.exclusiveMinimum ? schema.minimum + 1e-15 : schema.minimum;
453
+ const valid = data >= min;
454
+ return {
455
+ valid,
456
+ errors: valid ? [] : [
457
+ new ValidationError("Number is too small", {
458
+ pointer,
459
+ value: data,
460
+ code: "NUMBER_TOO_SMALL"
461
+ })
462
+ ],
463
+ data
464
+ };
465
+ },
466
+ maximum(schema, data, pointer) {
467
+ if (typeof data !== "number") {
468
+ return { valid: true, errors: [], data };
469
+ }
470
+ const max = schema.exclusiveMaximum ? schema.maximum - 1e-15 : schema.maximum;
471
+ const valid = data <= max;
472
+ return {
473
+ valid,
474
+ errors: valid ? [] : [
475
+ new ValidationError("Number is too large", {
476
+ pointer,
477
+ value: data,
478
+ code: "NUMBER_TOO_LARGE"
479
+ })
480
+ ],
481
+ data
482
+ };
483
+ },
484
+ multipleOf(schema, data, pointer) {
485
+ if (typeof data !== "number") {
486
+ return { valid: true, errors: [], data };
487
+ }
488
+ const quotient = data / schema.multipleOf;
489
+ const areMultiples = Math.abs(quotient - Math.round(quotient)) < 1e-15;
490
+ return {
491
+ valid: areMultiples,
492
+ errors: areMultiples ? [] : [
493
+ new ValidationError("Number is not a multiple of", {
494
+ pointer,
495
+ value: data,
496
+ code: "NUMBER_NOT_MULTIPLE_OF"
497
+ })
498
+ ],
499
+ data
500
+ };
501
+ }
502
+ };
503
+
504
+ // lib/keywords/object-keywords.ts
505
+ var ObjectKeywords = {
506
+ // Object
507
+ required(schema, data, pointer) {
508
+ if (!isObject(data)) {
509
+ return {
510
+ valid: true,
511
+ errors: [],
512
+ data
513
+ };
514
+ }
515
+ const errors = [];
516
+ for (let i = 0; i < schema.required.length; i++) {
517
+ const key = schema.required[i];
518
+ if (!data.hasOwnProperty(key)) {
519
+ errors.push(
520
+ new ValidationError("Missing required property", {
521
+ pointer: `${pointer}/${key}`,
522
+ value: data,
523
+ code: "MISSING_REQUIRED_PROPERTY"
524
+ })
525
+ );
526
+ }
527
+ }
528
+ return { valid: errors.length === 0, errors, data };
529
+ },
530
+ properties(schema, data, pointer, schemaShieldInstance) {
531
+ if (!isObject(data)) {
532
+ return { valid: true, errors: [], data };
533
+ }
534
+ const errors = [];
535
+ let finalData = { ...data };
536
+ for (let key in schema.properties) {
537
+ if (!data.hasOwnProperty(key) || typeof data[key] === "undefined") {
538
+ if (isObject(schema.properties[key]) && "default" in schema.properties[key]) {
539
+ finalData[key] = schema.properties[key].default;
540
+ }
541
+ continue;
542
+ }
543
+ if (typeof schema.properties[key] === "boolean") {
544
+ if (schema.properties[key] === false) {
545
+ errors.push(
546
+ new ValidationError("Property is not allowed", {
547
+ pointer: `${pointer}/${key}`,
548
+ value: data[key],
549
+ code: "PROPERTY_NOT_ALLOWED"
550
+ })
551
+ );
552
+ }
553
+ continue;
554
+ }
555
+ const { validator } = schema.properties[key];
556
+ if (!validator) {
557
+ continue;
558
+ }
559
+ const validatorResult = validator(
560
+ schema.properties[key],
561
+ finalData[key],
562
+ `${pointer}/${key}`,
563
+ schemaShieldInstance
564
+ );
565
+ finalData[key] = validatorResult.data;
566
+ if (!validatorResult.valid) {
567
+ errors.push(...validatorResult.errors);
568
+ }
569
+ }
570
+ return { valid: errors.length === 0, errors, data: finalData };
571
+ },
572
+ maxProperties(schema, data, pointer) {
573
+ if (!isObject(data) || Object.keys(data).length <= schema.maxProperties) {
574
+ return { valid: true, errors: [], data };
575
+ }
576
+ return {
577
+ valid: false,
578
+ errors: [
579
+ new ValidationError("Object has too many properties", {
580
+ pointer,
581
+ value: data,
582
+ code: "OBJECT_TOO_MANY_PROPERTIES"
583
+ })
584
+ ],
585
+ data
586
+ };
587
+ },
588
+ minProperties(schema, data, pointer) {
589
+ if (!isObject(data) || Object.keys(data).length >= schema.minProperties) {
590
+ return { valid: true, errors: [], data };
591
+ }
592
+ return {
593
+ valid: false,
594
+ errors: [
595
+ new ValidationError("Object has too few properties", {
596
+ pointer,
597
+ value: data,
598
+ code: "OBJECT_TOO_FEW_PROPERTIES"
599
+ })
600
+ ],
601
+ data
602
+ };
603
+ },
604
+ additionalProperties(schema, data, pointer, schemaShieldInstance) {
605
+ if (!isObject(data)) {
606
+ return { valid: true, errors: [], data };
607
+ }
608
+ const errors = [];
609
+ let finalData = { ...data };
610
+ for (let key in data) {
611
+ if (schema.properties && schema.properties.hasOwnProperty(key)) {
612
+ continue;
613
+ }
614
+ if (schema.patternProperties) {
615
+ let match = false;
616
+ for (let pattern in schema.patternProperties) {
617
+ if (new RegExp(pattern).test(key)) {
618
+ match = true;
619
+ break;
620
+ }
621
+ }
622
+ if (match) {
623
+ continue;
624
+ }
625
+ }
626
+ if (schema.additionalProperties === false) {
627
+ errors.push(
628
+ new ValidationError("Additional property not allowed", {
629
+ pointer: `${pointer}/${key}`,
630
+ value: data,
631
+ code: "ADDITIONAL_PROPERTY_NOT_ALLOWED"
632
+ })
633
+ );
634
+ continue;
635
+ }
636
+ const { validator } = schema.additionalProperties;
637
+ if (!validator) {
638
+ continue;
639
+ }
640
+ const validatorResult = validator(
641
+ schema.additionalProperties,
642
+ finalData[key],
643
+ `${pointer}/${key}`,
644
+ schemaShieldInstance
645
+ );
646
+ finalData[key] = validatorResult.data;
647
+ if (!validatorResult.valid) {
648
+ errors.push(...validatorResult.errors);
649
+ }
650
+ }
651
+ return { valid: errors.length === 0, errors, data: finalData };
652
+ },
653
+ patternProperties(schema, data, pointer, schemaShieldInstance) {
654
+ if (!isObject(data)) {
655
+ return { valid: true, errors: [], data };
656
+ }
657
+ const errors = [];
658
+ let finalData = { ...data };
659
+ for (let pattern in schema.patternProperties) {
660
+ if (typeof schema.patternProperties[pattern] === "boolean") {
661
+ if (schema.patternProperties[pattern] === false) {
662
+ for (let key in finalData) {
663
+ if (new RegExp(pattern).test(key)) {
664
+ errors.push(
665
+ new ValidationError("Property is not allowed", {
666
+ pointer: `${pointer}/${key}`,
667
+ value: data[key],
668
+ code: "PROPERTY_NOT_ALLOWED"
669
+ })
670
+ );
671
+ }
672
+ }
673
+ }
674
+ continue;
675
+ }
676
+ const { validator } = schema.patternProperties[pattern];
677
+ if (!validator) {
678
+ continue;
679
+ }
680
+ for (let key in finalData) {
681
+ if (new RegExp(pattern).test(key)) {
682
+ const validatorResult = validator(
683
+ schema.patternProperties[pattern],
684
+ finalData[key],
685
+ `${pointer}/${key}`,
686
+ schemaShieldInstance
687
+ );
688
+ finalData[key] = validatorResult.data;
689
+ if (!validatorResult.valid) {
690
+ errors.push(...validatorResult.errors);
691
+ }
692
+ }
693
+ }
694
+ }
695
+ return { valid: errors.length === 0, errors, data: finalData };
696
+ }
697
+ };
698
+
699
+ // lib/keywords/other-keywords.ts
700
+ var OtherKeywords = {
701
+ nullable(schema, data, pointer) {
702
+ if (schema.nullable && data !== null) {
703
+ return {
704
+ valid: false,
705
+ errors: [
706
+ new ValidationError("Value must be null to be empty", {
707
+ pointer,
708
+ value: data,
709
+ code: "VALUE_NOT_NULL"
710
+ })
711
+ ],
712
+ data
713
+ };
714
+ }
715
+ return { valid: true, errors: [], data };
716
+ },
717
+ oneOf(schema, data, pointer, schemaShieldInstance) {
718
+ const errors = [];
719
+ let validCount = 0;
720
+ let finalData = data;
721
+ for (let i = 0; i < schema.oneOf.length; i++) {
722
+ if (isObject(schema.oneOf[i])) {
723
+ const { validator } = schema.oneOf[i];
724
+ if (!validator) {
725
+ validCount++;
726
+ continue;
727
+ }
728
+ const validationResult = validator(
729
+ schema.oneOf[i],
730
+ finalData,
731
+ pointer,
732
+ schemaShieldInstance
733
+ );
734
+ if (validationResult.valid) {
735
+ validCount++;
736
+ } else {
737
+ errors.push(...validationResult.errors);
738
+ }
739
+ finalData = validationResult.data;
740
+ } else {
741
+ if (typeof schema.oneOf[i] === "boolean") {
742
+ if (Boolean(data) === schema.oneOf[i]) {
743
+ validCount++;
744
+ }
745
+ continue;
746
+ }
747
+ if (data === schema.oneOf[i]) {
748
+ validCount++;
749
+ }
750
+ }
751
+ }
752
+ if (validCount === 1) {
753
+ return { valid: true, errors: [], data: finalData };
754
+ }
755
+ return {
756
+ valid: false,
757
+ errors: [
758
+ new ValidationError(`Value must match exactly one schema in oneOf`, {
759
+ pointer,
760
+ value: data,
761
+ code: "VALUE_DOES_NOT_MATCH_ONE_OF"
762
+ })
763
+ ],
764
+ data: finalData
765
+ };
766
+ },
767
+ allOf(schema, data, pointer, schemaShieldInstance) {
768
+ const errors = [];
769
+ let finalData = data;
770
+ for (let i = 0; i < schema.allOf.length; i++) {
771
+ if (isObject(schema.allOf[i])) {
772
+ const { validator } = schema.allOf[i];
773
+ if (!validator) {
774
+ continue;
775
+ }
776
+ const validatorResult = validator(
777
+ schema.allOf[i],
778
+ finalData,
779
+ pointer,
780
+ schemaShieldInstance
781
+ );
782
+ if (!validatorResult.valid) {
783
+ errors.push(...validatorResult.errors);
784
+ }
785
+ finalData = validatorResult.data;
786
+ } else {
787
+ if (typeof schema.allOf[i] === "boolean") {
788
+ if (Boolean(data) !== schema.allOf[i]) {
789
+ errors.push(
790
+ new ValidationError(`Value must match all schemas in allOf`, {
791
+ pointer,
792
+ value: data,
793
+ code: "VALUE_DOES_NOT_MATCH_ALL_OF"
794
+ })
795
+ );
796
+ }
797
+ continue;
798
+ }
799
+ if (data !== schema.allOf[i]) {
800
+ errors.push(
801
+ new ValidationError(`Value must match all schemas in allOf`, {
802
+ pointer,
803
+ value: data,
804
+ code: "VALUE_DOES_NOT_MATCH_ALL_OF"
805
+ })
806
+ );
807
+ }
808
+ }
809
+ }
810
+ return { valid: errors.length === 0, errors, data: finalData };
811
+ },
812
+ anyOf(schema, data, pointer, schemaShieldInstance) {
813
+ let finalData = data;
814
+ for (let i = 0; i < schema.anyOf.length; i++) {
815
+ if (isObject(schema.anyOf[i])) {
816
+ const { validator } = schema.anyOf[i];
817
+ if (!validator) {
818
+ return { valid: true, errors: [], data };
819
+ }
820
+ const validationResult = validator(
821
+ schema.anyOf[i],
822
+ finalData,
823
+ pointer,
824
+ schemaShieldInstance
825
+ );
826
+ finalData = validationResult.data;
827
+ if (validationResult.valid) {
828
+ return { valid: true, errors: [], data: finalData };
829
+ }
830
+ } else {
831
+ if (typeof schema.anyOf[i] === "boolean") {
832
+ if (Boolean(data) === schema.anyOf[i]) {
833
+ return { valid: true, errors: [], data: finalData };
834
+ }
835
+ }
836
+ if (data === schema.anyOf[i]) {
837
+ return { valid: true, errors: [], data: finalData };
838
+ }
839
+ }
840
+ }
841
+ return {
842
+ valid: false,
843
+ errors: [
844
+ new ValidationError(`Value must match at least one schema in anyOf`, {
845
+ pointer,
846
+ value: data,
847
+ code: "VALUE_DOES_NOT_MATCH_ANY_OF"
848
+ })
849
+ ],
850
+ data
851
+ };
852
+ },
853
+ dependencies(schema, data, pointer, schemaShieldInstance) {
854
+ if (!isObject(data)) {
855
+ return { valid: true, errors: [], data };
856
+ }
857
+ const errors = [];
858
+ let finalData = data;
859
+ for (const key in schema.dependencies) {
860
+ if (key in data === false) {
861
+ continue;
862
+ }
863
+ const dependency = schema.dependencies[key];
864
+ if (Array.isArray(dependency)) {
865
+ for (let i = 0; i < dependency.length; i++) {
866
+ if (!(dependency[i] in data)) {
867
+ errors.push(
868
+ new ValidationError(`Dependency ${dependency[i]} is missing`, {
869
+ pointer,
870
+ value: data,
871
+ code: "DEPENDENCY_MISSING"
872
+ })
873
+ );
874
+ }
875
+ }
876
+ continue;
877
+ }
878
+ if (typeof dependency === "boolean") {
879
+ if (dependency) {
880
+ continue;
881
+ }
882
+ errors.push(
883
+ new ValidationError(`Dependency ${key} is missing`, {
884
+ pointer,
885
+ value: data,
886
+ code: "DEPENDENCY_MISSING"
887
+ })
888
+ );
889
+ continue;
890
+ }
891
+ if (typeof dependency === "string") {
892
+ if (dependency in data) {
893
+ continue;
894
+ }
895
+ errors.push(
896
+ new ValidationError(`Dependency ${dependency} is missing`, {
897
+ pointer,
898
+ value: data,
899
+ code: "DEPENDENCY_MISSING"
900
+ })
901
+ );
902
+ continue;
903
+ }
904
+ const { validator } = dependency;
905
+ if (!validator) {
906
+ continue;
907
+ }
908
+ const validatorResult = validator(
909
+ dependency,
910
+ finalData,
911
+ pointer,
912
+ schemaShieldInstance
913
+ );
914
+ if (!validatorResult.valid) {
915
+ errors.push(...validatorResult.errors);
916
+ }
917
+ finalData = validatorResult.data;
918
+ }
919
+ return { valid: errors.length === 0, errors, data: finalData };
920
+ }
921
+ };
922
+
923
+ // lib/keywords/string-keywords.ts
924
+ var StringKeywords = {
925
+ minLength(schema, data, pointer) {
926
+ if (typeof data !== "string" || data.length >= schema.minLength) {
927
+ return { valid: true, errors: [], data };
928
+ }
929
+ return {
930
+ valid: false,
931
+ errors: [
932
+ new ValidationError("String is too short", {
933
+ pointer,
934
+ value: data,
935
+ code: "STRING_TOO_SHORT"
936
+ })
937
+ ],
938
+ data
939
+ };
940
+ },
941
+ maxLength(schema, data, pointer) {
942
+ if (typeof data !== "string" || data.length <= schema.maxLength) {
943
+ return { valid: true, errors: [], data };
944
+ }
945
+ return {
946
+ valid: false,
947
+ errors: [
948
+ new ValidationError("String is too long", {
949
+ pointer,
950
+ value: data,
951
+ code: "STRING_TOO_LONG"
952
+ })
953
+ ],
954
+ data
955
+ };
956
+ },
957
+ pattern(schema, data, pointer) {
958
+ if (typeof data !== "string") {
959
+ return { valid: true, errors: [], data };
960
+ }
961
+ const patternRegexp = typeof schema.pattern === "string" ? new RegExp(schema.pattern) : schema.pattern;
962
+ if (patternRegexp instanceof RegExp === false) {
963
+ return {
964
+ valid: false,
965
+ errors: [
966
+ new ValidationError("Pattern is not a valid regular expression", {
967
+ pointer,
968
+ value: data,
969
+ code: "PATTERN_IS_NOT_REGEXP"
970
+ })
971
+ ],
972
+ data
973
+ };
974
+ }
975
+ const valid = patternRegexp.test(data);
976
+ return {
977
+ valid,
978
+ errors: valid ? [] : [
979
+ new ValidationError("String does not match pattern", {
980
+ pointer,
981
+ value: data,
982
+ code: "STRING_DOES_NOT_MATCH_PATTERN"
983
+ })
984
+ ],
985
+ data
986
+ };
987
+ },
988
+ format(schema, data, pointer, formatInstance) {
989
+ if (typeof data !== "string") {
990
+ return { valid: true, errors: [], data };
991
+ }
992
+ const formatValidate = formatInstance.formats.get(schema.format);
993
+ if (!formatValidate) {
994
+ return {
995
+ valid: false,
996
+ errors: [
997
+ new ValidationError(`Unknown format ${schema.format}`, {
998
+ pointer,
999
+ value: data,
1000
+ code: "UNKNOWN_FORMAT"
1001
+ })
1002
+ ],
1003
+ data
1004
+ };
1005
+ }
1006
+ const valid = formatValidate(data);
1007
+ return {
1008
+ valid,
1009
+ errors: valid ? [] : [
1010
+ new ValidationError(
1011
+ `String does not match format ${schema.format}`,
1012
+ {
1013
+ pointer,
1014
+ value: data,
1015
+ code: "STRING_DOES_NOT_MATCH_FORMAT"
1016
+ }
1017
+ )
1018
+ ],
1019
+ data
1020
+ };
1021
+ },
1022
+ enum(schema, data, pointer) {
1023
+ for (let i = 0; i < schema.enum.length; i++) {
1024
+ if (schema.enum[i] === data) {
1025
+ return { valid: true, errors: [], data };
1026
+ }
1027
+ }
1028
+ if (Array.isArray(data)) {
1029
+ for (let i = 0; i < schema.enum.length; i++) {
1030
+ if (Array.isArray(schema.enum[i])) {
1031
+ if (deepEqual(schema.enum[i], data)) {
1032
+ return { valid: true, errors: [], data };
1033
+ }
1034
+ }
1035
+ }
1036
+ }
1037
+ if (typeof data === "object" && data !== null) {
1038
+ for (let i = 0; i < schema.enum.length; i++) {
1039
+ if (typeof schema.enum[i] === "object" && schema.enum[i] !== null) {
1040
+ if (deepEqual(schema.enum[i], data)) {
1041
+ return { valid: true, errors: [], data };
1042
+ }
1043
+ }
1044
+ }
1045
+ }
1046
+ return {
1047
+ valid: false,
1048
+ errors: [
1049
+ new ValidationError(`Value must be one of ${schema.enum.join(", ")}`, {
1050
+ pointer,
1051
+ value: data,
1052
+ code: "VALUE_NOT_IN_ENUM"
1053
+ })
1054
+ ],
1055
+ data
1056
+ };
1057
+ }
1058
+ };
1059
+
1060
+ // lib/keywords.ts
1061
+ var keywords = {
1062
+ ...ObjectKeywords,
1063
+ ...ArrayKeywords,
1064
+ ...StringKeywords,
1065
+ ...NumberKeywords,
1066
+ ...OtherKeywords
1067
+ };
1068
+
1069
+ // lib/index.ts
1070
+ var SchemaShield = class {
1071
+ types = /* @__PURE__ */ new Map();
1072
+ formats = /* @__PURE__ */ new Map();
1073
+ keywords = /* @__PURE__ */ new Map();
1074
+ constructor() {
1075
+ for (const type in Types) {
1076
+ this.addType(type, Types[type]);
1077
+ }
1078
+ for (const keyword in keywords) {
1079
+ this.addKeyword(keyword, keywords[keyword]);
1080
+ }
1081
+ for (const format in Formats) {
1082
+ this.addFormat(format, Formats[format]);
1083
+ }
1084
+ }
1085
+ addType(name, validator) {
1086
+ this.types.set(name, validator);
1087
+ }
1088
+ addFormat(name, validator) {
1089
+ this.formats.set(name, validator);
1090
+ }
1091
+ addKeyword(name, validator) {
1092
+ this.keywords.set(name, validator);
1093
+ }
1094
+ compile(schema) {
1095
+ const compiledSchema = this.compileSchema(schema, "#");
1096
+ const schemaShield = this;
1097
+ function validate(data) {
1098
+ return compiledSchema.validator(compiledSchema, data, "#", schemaShield);
1099
+ }
1100
+ validate.compiledSchema = compiledSchema;
1101
+ return validate;
1102
+ }
1103
+ compileSchema(schema, pointer) {
1104
+ if (typeof schema !== "object" || schema === null) {
1105
+ throw new ValidationError("Schema is not an object", {
1106
+ pointer,
1107
+ value: schema,
1108
+ code: "SCHEMA_NOT_OBJECT"
1109
+ });
1110
+ }
1111
+ const compiledSchema = {
1112
+ ...schema,
1113
+ pointer
1114
+ };
1115
+ if ("type" in compiledSchema) {
1116
+ const types = Array.isArray(compiledSchema.type) ? compiledSchema.type : compiledSchema.type.split(",").map((t) => t.trim());
1117
+ compiledSchema.validators = types.filter((type) => this.types.has(type)).map((type) => this.types.get(type));
1118
+ }
1119
+ const validator = (schema2, data, pointer2) => {
1120
+ if (typeof data === "undefined") {
1121
+ if (pointer2 === "#") {
1122
+ return {
1123
+ valid: false,
1124
+ errors: [
1125
+ new ValidationError("Data is undefined", {
1126
+ pointer: pointer2,
1127
+ value: data,
1128
+ code: "DATA_UNDEFINED"
1129
+ })
1130
+ ],
1131
+ data
1132
+ };
1133
+ }
1134
+ }
1135
+ let finalData = data;
1136
+ const typeErrorsResult = this.validateTypes(schema2, finalData, pointer2);
1137
+ if (typeErrorsResult.valid === false) {
1138
+ return typeErrorsResult;
1139
+ }
1140
+ finalData = typeErrorsResult.data;
1141
+ return this.validateKeywords(schema2, finalData, pointer2);
1142
+ };
1143
+ compiledSchema.validator = validator;
1144
+ for (let key in schema) {
1145
+ if (key === "type") {
1146
+ continue;
1147
+ }
1148
+ if (this.keywords.has(key)) {
1149
+ const validator2 = this.keywords.get(key);
1150
+ compiledSchema.keywords = compiledSchema.keywords || {};
1151
+ compiledSchema.keywords[key] = validator2;
1152
+ }
1153
+ if (Array.isArray(schema[key])) {
1154
+ this.handleArraySchema(key, schema, pointer, compiledSchema);
1155
+ continue;
1156
+ }
1157
+ if (isObject(schema[key])) {
1158
+ this.handleObjectSchema(key, schema, pointer, compiledSchema);
1159
+ continue;
1160
+ }
1161
+ }
1162
+ return compiledSchema;
1163
+ }
1164
+ handleArraySchema(key, schema, pointer, compiledSchema) {
1165
+ compiledSchema[key] = schema[key].map((subSchema, index) => {
1166
+ if (typeof subSchema === "object" && subSchema !== null) {
1167
+ if ("type" in subSchema) {
1168
+ return this.compileSchema(subSchema, `${pointer}/${key}/${index}`);
1169
+ }
1170
+ for (let subKey in subSchema) {
1171
+ if (this.keywords.has(subKey)) {
1172
+ return this.compileSchema(subSchema, `${pointer}/${key}/${index}`);
1173
+ }
1174
+ }
1175
+ }
1176
+ return subSchema;
1177
+ });
1178
+ }
1179
+ handleObjectSchema(key, schema, pointer, compiledSchema) {
1180
+ if ("type" in schema[key]) {
1181
+ compiledSchema[key] = this.compileSchema(
1182
+ schema[key],
1183
+ `${pointer}/${key}`
1184
+ );
1185
+ return;
1186
+ }
1187
+ for (let subKey in schema[key]) {
1188
+ compiledSchema[key] = compiledSchema[key] || {};
1189
+ if (this.keywords.has(subKey)) {
1190
+ compiledSchema[key][subKey] = this.compileSchema(
1191
+ schema[key][subKey],
1192
+ `${pointer}/${subKey}`
1193
+ );
1194
+ continue;
1195
+ }
1196
+ if (typeof schema[key][subKey] === "object") {
1197
+ if ("type" in schema[key][subKey]) {
1198
+ compiledSchema[key][subKey] = this.compileSchema(
1199
+ schema[key][subKey],
1200
+ `${pointer}/${key}/${subKey}`
1201
+ );
1202
+ continue;
1203
+ }
1204
+ for (let subSubKey in schema[key][subKey]) {
1205
+ if (this.keywords.has(subSubKey)) {
1206
+ compiledSchema[key][subKey] = this.compileSchema(
1207
+ schema[key][subKey],
1208
+ `${pointer}/${key}/${subKey}`
1209
+ );
1210
+ continue;
1211
+ }
1212
+ }
1213
+ }
1214
+ }
1215
+ }
1216
+ validateTypes(schema, data, pointer) {
1217
+ if (typeof data === "undefined" || !Array.isArray(schema.validators) || schema.validators.length === 0) {
1218
+ return {
1219
+ valid: true,
1220
+ errors: [],
1221
+ data
1222
+ };
1223
+ }
1224
+ let errors = [];
1225
+ let finalData = data;
1226
+ for (let schemaValidator of schema.validators) {
1227
+ const schemaResult = schemaValidator(schema, data, pointer, this);
1228
+ finalData = schemaResult.data;
1229
+ if (schemaResult.valid) {
1230
+ return schemaResult;
1231
+ }
1232
+ errors = schemaResult.errors;
1233
+ }
1234
+ return {
1235
+ valid: errors.length === 0,
1236
+ errors,
1237
+ data: finalData
1238
+ };
1239
+ }
1240
+ validateKeywords(schema, data, pointer) {
1241
+ const errors = [];
1242
+ let finalData = data;
1243
+ if ("keywords" in schema) {
1244
+ for (let keyword in schema.keywords) {
1245
+ const keywordValidator = schema.keywords[keyword];
1246
+ const keywordResult = keywordValidator(
1247
+ schema,
1248
+ finalData,
1249
+ pointer,
1250
+ this
1251
+ );
1252
+ finalData = keywordResult.data;
1253
+ if (!keywordResult.valid) {
1254
+ errors.push(...keywordResult.errors);
1255
+ }
1256
+ }
1257
+ }
1258
+ return {
1259
+ valid: errors.length === 0,
1260
+ errors,
1261
+ data: finalData
1262
+ };
1263
+ }
1264
+ };
1265
+ export {
1266
+ SchemaShield
1267
+ };