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