@scalar/validation 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,1158 +0,0 @@
1
- import { describe, expect, it } from 'vitest'
2
-
3
- import { coerce } from '@/coerce'
4
- import {
5
- any,
6
- array,
7
- boolean,
8
- evaluate,
9
- intersection,
10
- lazy,
11
- literal,
12
- notDefined,
13
- nullable,
14
- number,
15
- object,
16
- optional,
17
- record,
18
- string,
19
- union,
20
- } from '@/schema'
21
-
22
- describe('any', () => {
23
- const T = any()
24
- it('Should upcast from string', () => {
25
- const value = 'hello'
26
- const result = coerce(T, value)
27
- expect(result).toBe(value)
28
- })
29
- it('Should upcast from number', () => {
30
- const value = 1
31
- const result = coerce(T, value)
32
- expect(result).toBe(value)
33
- })
34
- it('Should upcast from boolean', () => {
35
- const value = false
36
- const result = coerce(T, value)
37
- expect(result).toBe(value)
38
- })
39
- it('Should upcast from object', () => {
40
- const value = {}
41
- const result = coerce(T, value)
42
- expect(result).toBe(value)
43
- })
44
- it('Should upcast from array', () => {
45
- const value = [1]
46
- const result = coerce(T, value)
47
- expect(result).toBe(value)
48
- })
49
- it('Should upcast from undefined', () => {
50
- const value = undefined
51
- const result = coerce(T, value)
52
- expect(result).toBe(value)
53
- })
54
- it('Should upcast from null', () => {
55
- const value = null
56
- const result = coerce(T, value)
57
- expect(result).toBe(value)
58
- })
59
- it('Should preserve', () => {
60
- const value = { a: 1, b: 2 }
61
- const result = coerce(T, value)
62
- expect(result).toEqual({ a: 1, b: 2 })
63
- })
64
- })
65
-
66
- describe('array', () => {
67
- const T = array(number())
68
- const E: number[] = []
69
- it('Should upcast from string', () => {
70
- const value = 'hello'
71
- const result = coerce(T, value)
72
- expect(result).toEqual(E)
73
- })
74
- it('Should upcast from number', () => {
75
- const value = 1
76
- const result = coerce(T, value)
77
- expect(result).toEqual(E)
78
- })
79
- it('Should upcast from boolean', () => {
80
- const value = true
81
- const result = coerce(T, value)
82
- expect(result).toEqual(E)
83
- })
84
- it('Should upcast from object', () => {
85
- const value = {}
86
- const result = coerce(T, value)
87
- expect(result).toEqual(E)
88
- })
89
- it('Should upcast from array', () => {
90
- const value = [1]
91
- const result = coerce(T, value)
92
- expect(result).toEqual([1])
93
- })
94
- it('Should upcast from undefined', () => {
95
- const value = undefined
96
- const result = coerce(T, value)
97
- expect(result).toEqual(E)
98
- })
99
- it('Should upcast from null', () => {
100
- const value = null
101
- const result = coerce(T, value)
102
- expect(result).toEqual(E)
103
- })
104
- it('Should upcast from date', () => {
105
- const value = new Date(100)
106
- const result = coerce(T, value)
107
- expect(result).toEqual(E)
108
- })
109
- it('Should preserve', () => {
110
- const value = [6, 7, 8]
111
- const result = coerce(T, value)
112
- expect(result).toEqual([6, 7, 8])
113
- })
114
- })
115
-
116
- describe('boolean', () => {
117
- const T = boolean()
118
- const E = false
119
- it('Should upcast from string', () => {
120
- const value = 'hello'
121
- const result = coerce(T, value)
122
- expect(result).toBe(E)
123
- })
124
- it('Should upcast from number', () => {
125
- const value = 0
126
- const result = coerce(T, value)
127
- expect(result).toBe(E)
128
- })
129
- it('Should upcast from boolean', () => {
130
- const value = true
131
- const result = coerce(T, value)
132
- expect(result).toBe(true)
133
- })
134
- it('Should upcast from object', () => {
135
- const value = {}
136
- const result = coerce(T, value)
137
- expect(result).toBe(E)
138
- })
139
- it('Should upcast from array', () => {
140
- const value = [1]
141
- const result = coerce(T, value)
142
- expect(result).toBe(E)
143
- })
144
- it('Should upcast from undefined', () => {
145
- const value = undefined
146
- const result = coerce(T, value)
147
- expect(result).toBe(E)
148
- })
149
- it('Should upcast from null', () => {
150
- const value = null
151
- const result = coerce(T, value)
152
- expect(result).toBe(E)
153
- })
154
- it('Should upcast from date', () => {
155
- const value = new Date(100)
156
- const result = coerce(T, value)
157
- expect(result).toBe(E)
158
- })
159
- it('Should preserve', () => {
160
- const value = true
161
- const result = coerce(T, value)
162
- expect(result).toBe(true)
163
- })
164
- })
165
-
166
- describe('literal', () => {
167
- const T = literal('hello')
168
- const E = 'hello'
169
- it('Should upcast from string', () => {
170
- const value = 'world'
171
- const result = coerce(T, value)
172
- expect(result).toBe(E)
173
- })
174
- it('Should upcast from number', () => {
175
- const value = 1
176
- const result = coerce(T, value)
177
- expect(result).toBe(E)
178
- })
179
- it('Should upcast from boolean', () => {
180
- const value = true
181
- const result = coerce(T, value)
182
- expect(result).toBe(E)
183
- })
184
- it('Should upcast from object', () => {
185
- const value = {}
186
- const result = coerce(T, value)
187
- expect(result).toBe(E)
188
- })
189
- it('Should upcast from array', () => {
190
- const value = [1]
191
- const result = coerce(T, value)
192
- expect(result).toBe(E)
193
- })
194
- it('Should upcast from undefined', () => {
195
- const value = undefined
196
- const result = coerce(T, value)
197
- expect(result).toBe(E)
198
- })
199
- it('Should upcast from null', () => {
200
- const value = null
201
- const result = coerce(T, value)
202
- expect(result).toBe(E)
203
- })
204
- it('Should upcast from date', () => {
205
- const value = new Date(100)
206
- const result = coerce(T, value)
207
- expect(result).toBe(E)
208
- })
209
- it('Should preseve', () => {
210
- const value = 'hello'
211
- const result = coerce(T, value)
212
- expect(result).toBe('hello')
213
- })
214
- })
215
-
216
- describe('null', () => {
217
- const T = nullable()
218
- const E = null
219
- it('Should upcast from string', () => {
220
- const value = 'world'
221
- const result = coerce(T, value)
222
- expect(result).toBe(E)
223
- })
224
- it('Should upcast from number', () => {
225
- const value = 1
226
- const result = coerce(T, value)
227
- expect(result).toBe(E)
228
- })
229
- it('Should upcast from boolean', () => {
230
- const value = true
231
- const result = coerce(T, value)
232
- expect(result).toBe(E)
233
- })
234
- it('Should upcast from object', () => {
235
- const value = {}
236
- const result = coerce(T, value)
237
- expect(result).toBe(E)
238
- })
239
- it('Should upcast from array', () => {
240
- const value = [1]
241
- const result = coerce(T, value)
242
- expect(result).toBe(E)
243
- })
244
- it('Should upcast from undefined', () => {
245
- const value = undefined
246
- const result = coerce(T, value)
247
- expect(result).toBe(E)
248
- })
249
- it('Should upcast from null', () => {
250
- const value = null
251
- const result = coerce(T, value)
252
- expect(result).toBe(E)
253
- })
254
- it('Should upcast from date', () => {
255
- const value = new Date(100)
256
- const result = coerce(T, value)
257
- expect(result).toBe(E)
258
- })
259
- it('Should preseve', () => {
260
- const value = null
261
- const result = coerce(T, value)
262
- expect(result).toBe(null)
263
- })
264
- })
265
-
266
- describe('number', () => {
267
- const T = number()
268
- const E = 0
269
- it('Should upcast from string', () => {
270
- const value = 'world'
271
- const result = coerce(T, value)
272
- expect(result).toBe(E)
273
- })
274
- it('Should upcast from number', () => {
275
- const value = 1
276
- const result = coerce(T, value)
277
- expect(result).toBe(1)
278
- })
279
- it('Should upcast from object', () => {
280
- const value = {}
281
- const result = coerce(T, value)
282
- expect(result).toBe(E)
283
- })
284
- it('Should upcast from array', () => {
285
- const value = [1]
286
- const result = coerce(T, value)
287
- expect(result).toBe(E)
288
- })
289
- it('Should upcast from undefined', () => {
290
- const value = undefined
291
- const result = coerce(T, value)
292
- expect(result).toBe(E)
293
- })
294
- it('Should upcast from null', () => {
295
- const value = null
296
- const result = coerce(T, value)
297
- expect(result).toBe(E)
298
- })
299
- it('Should upcast from date', () => {
300
- const value = new Date(100)
301
- const result = coerce(T, value)
302
- expect(result).toBe(E)
303
- })
304
- it('Should preseve', () => {
305
- const value = 123
306
- const result = coerce(T, value)
307
- expect(result).toBe(123)
308
- })
309
- })
310
-
311
- describe('object', () => {
312
- const T = object({
313
- a: number(),
314
- b: number(),
315
- c: number(),
316
- x: number(),
317
- y: number(),
318
- z: number(),
319
- })
320
- const E = {
321
- x: 0,
322
- y: 0,
323
- z: 0,
324
- a: 0,
325
- b: 0,
326
- c: 0,
327
- }
328
- it('Should upcast from string', () => {
329
- const value = 'hello'
330
- const result = coerce(T, value)
331
- expect(result).toEqual(E)
332
- })
333
- it('Should upcast from number', () => {
334
- const value = E
335
- const result = coerce(T, value)
336
- expect(result).toEqual(E)
337
- })
338
- it('Should upcast from boolean', () => {
339
- const value = true
340
- const result = coerce(T, value)
341
- expect(result).toEqual(E)
342
- })
343
- it('Should upcast from object', () => {
344
- const value = {}
345
- const result = coerce(T, value)
346
- expect(result).toEqual(E)
347
- })
348
- it('Should upcast from array', () => {
349
- const value = [1]
350
- const result = coerce(T, value)
351
- expect(result).toEqual(E)
352
- })
353
- it('Should upcast from undefined', () => {
354
- const value = undefined
355
- const result = coerce(T, value)
356
- expect(result).toEqual(E)
357
- })
358
- it('Should upcast from null', () => {
359
- const value = null
360
- const result = coerce(T, value)
361
- expect(result).toEqual(E)
362
- })
363
- it('Should upcast from date', () => {
364
- const value = new Date(100)
365
- const result = coerce(T, value)
366
- expect(result).toEqual(E)
367
- })
368
- it('Should preserve', () => {
369
- const value = { x: 7, y: 8, z: 9, a: 10, b: 11, c: 12 }
370
- const result = coerce(T, value)
371
- expect(result).toEqual({
372
- x: 7,
373
- y: 8,
374
- z: 9,
375
- a: 10,
376
- b: 11,
377
- c: 12,
378
- })
379
- })
380
- it('Should upcast partial object with incorrect properties', () => {
381
- const value = { x: {}, y: 8, z: 9 }
382
- const result = coerce(T, value)
383
- expect(result).toEqual({
384
- x: 0,
385
- y: 8,
386
- z: 9,
387
- a: 0,
388
- b: 0,
389
- c: 0,
390
- })
391
- })
392
- it('Should upcast and preserve partial object and omit unknown properties', () => {
393
- const value = { x: 7, y: 8, z: 9, unknown: 'foo' }
394
- const result = coerce(T, value)
395
- expect(result).toEqual({
396
- x: 7,
397
- y: 8,
398
- z: 9,
399
- a: 0,
400
- b: 0,
401
- c: 0,
402
- })
403
- })
404
- it('Should upcast and remove additional properties', () => {
405
- const result = coerce(
406
- object({
407
- x: number(),
408
- y: number(),
409
- }),
410
- {
411
- x: 1,
412
- y: 2,
413
- z: { b: 1 },
414
- },
415
- )
416
- expect(result).toEqual({
417
- x: 1,
418
- y: 2,
419
- })
420
- })
421
- it('omits optional properties when the value is undefined', () => {
422
- const T = object({
423
- id: number(),
424
- name: optional(string()),
425
- })
426
- expect(coerce(T, { id: 1 })).toEqual({ id: 1 })
427
- expect(coerce(T, { id: 1, name: undefined })).toEqual({ id: 1 })
428
- expect(coerce(T, { id: 1, name: 'x' })).toEqual({ id: 1, name: 'x' })
429
- })
430
- })
431
-
432
- describe('record', () => {
433
- const T = record(
434
- string(),
435
- object({
436
- x: number(),
437
- y: number(),
438
- z: number(),
439
- }),
440
- )
441
- const E = {}
442
- it('Should upcast from string', () => {
443
- const value = 'hello'
444
- const result = coerce(T, value)
445
- expect(result).toEqual(E)
446
- })
447
- it('Should upcast from number', () => {
448
- const value = E
449
- const result = coerce(T, value)
450
- expect(result).toEqual(E)
451
- })
452
- it('Should upcast from boolean', () => {
453
- const value = true
454
- const result = coerce(T, value)
455
- expect(result).toEqual(E)
456
- })
457
- it('Should upcast from object', () => {
458
- const value = {}
459
- const result = coerce(T, value)
460
- expect(result).toEqual(E)
461
- })
462
- it('Should upcast from array', () => {
463
- const value = [1]
464
- const result = coerce(T, value)
465
- expect(result).toEqual(E)
466
- })
467
- it('Should upcast from undefined', () => {
468
- const value = undefined
469
- const result = coerce(T, value)
470
- expect(result).toEqual(E)
471
- })
472
- it('Should upcast from null', () => {
473
- const value = null
474
- const result = coerce(T, value)
475
- expect(result).toEqual(E)
476
- })
477
- it('Should upcast from date', () => {
478
- const value = new Date(100)
479
- const result = coerce(T, value)
480
- expect(result).toEqual(E)
481
- })
482
- it('Should preserve', () => {
483
- const value = {
484
- a: { x: 1, y: 2, z: 3 },
485
- b: { x: 4, y: 5, z: 6 },
486
- }
487
- const result = coerce(T, value)
488
- expect(result).toEqual(value)
489
- })
490
- it('Should preserve and patch invalid records', () => {
491
- const value = {
492
- a: { x: 1, y: 2, z: 3 },
493
- b: { x: 4, y: 5, z: {} },
494
- c: [1, 2, 3],
495
- d: 1,
496
- e: { x: 1, y: 2, w: 9000 },
497
- }
498
- const result = coerce(T, value)
499
- expect(result).toEqual({
500
- a: { x: 1, y: 2, z: 3 },
501
- b: { x: 4, y: 5, z: 0 },
502
- c: { x: 0, y: 0, z: 0 },
503
- d: { x: 0, y: 0, z: 0 },
504
- e: { x: 1, y: 2, z: 0 },
505
- })
506
- })
507
- })
508
-
509
- describe('string', () => {
510
- const T = string()
511
- const E = ''
512
- it('Should upcast from string', () => {
513
- const value = 'hello'
514
- const result = coerce(T, value)
515
- expect(result).toBe('hello')
516
- })
517
- it('Should upcast from object', () => {
518
- const value = {}
519
- const result = coerce(T, value)
520
- expect(result).toBe(E)
521
- })
522
- it('Should upcast from array', () => {
523
- const value = [1]
524
- const result = coerce(T, value)
525
- expect(result).toBe(E)
526
- })
527
- it('Should upcast from undefined', () => {
528
- const value = undefined
529
- const result = coerce(T, value)
530
- expect(result).toBe(E)
531
- })
532
- it('Should upcast from null', () => {
533
- const value = null
534
- const result = coerce(T, value)
535
- expect(result).toBe(E)
536
- })
537
- it('Should upcast from date', () => {
538
- const value = new Date(100)
539
- const result = coerce(T, value)
540
- expect(result).toBe(E)
541
- })
542
- it('Should preserve', () => {
543
- const value = 'foo'
544
- const result = coerce(T, value)
545
- expect(result).toBe(value)
546
- })
547
- })
548
-
549
- describe('union', () => {
550
- const A = object({
551
- type: literal('A'),
552
- x: number(),
553
- y: number(),
554
- z: number(),
555
- })
556
- const B = object({
557
- type: literal('B'),
558
- a: string(),
559
- b: string(),
560
- c: string(),
561
- })
562
- const T = union([A, B])
563
- const E = {
564
- type: 'A',
565
- x: 0,
566
- y: 0,
567
- z: 0,
568
- }
569
- it('Should upcast from string', () => {
570
- const value = 'hello'
571
- const result = coerce(T, value)
572
- expect(result).toEqual(E)
573
- })
574
- it('Should upcast from number', () => {
575
- const value = 1
576
- const result = coerce(T, value)
577
- expect(result).toEqual(E)
578
- })
579
- it('Should upcast from boolean', () => {
580
- const value = true
581
- const result = coerce(T, value)
582
- expect(result).toEqual(E)
583
- })
584
- it('Should upcast from object', () => {
585
- const value = {}
586
- const result = coerce(T, value)
587
- expect(result).toEqual(E)
588
- })
589
- it('Should upcast from array', () => {
590
- const value = [1]
591
- const result = coerce(T, value)
592
- expect(result).toEqual(E)
593
- })
594
- it('Should upcast from undefined', () => {
595
- const value = undefined
596
- const result = coerce(T, value)
597
- expect(result).toEqual(E)
598
- })
599
- it('Should upcast from null', () => {
600
- const value = null
601
- const result = coerce(T, value)
602
- expect(result).toEqual(E)
603
- })
604
- it('Should upcast from date', () => {
605
- const value = new Date(100)
606
- const result = coerce(T, value)
607
- expect(result).toEqual(E)
608
- })
609
- it('Should preserve A', () => {
610
- const value = { type: 'A', x: 1, y: 2, z: 3 }
611
- const result = coerce(T, value)
612
- expect(result).toEqual(value)
613
- })
614
- it('Should preserve B', () => {
615
- const value = { type: 'B', a: 'a', b: 'b', c: 'c' }
616
- const result = coerce(T, value)
617
- expect(result).toEqual(value)
618
- })
619
- it('Should infer through heuristics #1', () => {
620
- const value = { type: 'A', a: 'a', b: 'b', c: 'c' }
621
- const result = coerce(T, value)
622
- expect(result).toEqual({ type: 'A', x: 0, y: 0, z: 0 })
623
- })
624
- it('Should infer through heuristics #2', () => {
625
- const value = { type: 'B', x: 1, y: 2, z: 3 }
626
- const result = coerce(T, value)
627
- expect(result).toEqual({ type: 'B', a: '', b: '', c: '' })
628
- })
629
- it('Should infer through heuristics #3', () => {
630
- const value = { type: 'A', a: 'a', b: 'b', c: null }
631
- const result = coerce(T, value)
632
- expect(result).toEqual({ type: 'A', x: 0, y: 0, z: 0 })
633
- })
634
- it('Should infer through heuristics #4', () => {
635
- const value = { type: 'B', x: 1, y: 2, z: {} }
636
- const result = coerce(T, value)
637
- expect(result).toEqual({ type: 'B', a: '', b: '', c: '' })
638
- })
639
- it('Should infer through heuristics #5', () => {
640
- const value = { type: 'B', x: 1, y: 2, z: null }
641
- const result = coerce(T, value)
642
- expect(result).toEqual({ type: 'B', a: '', b: '', c: '' })
643
- })
644
- it('Should infer through heuristics #6', () => {
645
- const value = { x: 1 }
646
- const result = coerce(T, value)
647
- expect(result).toEqual({ type: 'A', x: 1, y: 0, z: 0 })
648
- })
649
- it('Should infer through heuristics #7', () => {
650
- const value = { a: null } // property existing should contribute
651
- const result = coerce(T, value)
652
- expect(result).toEqual({ type: 'B', a: '', b: '', c: '' })
653
- })
654
- it('should correctly score nested union types #1', () => {
655
- const A = union([
656
- union([
657
- object({
658
- type: literal('a'),
659
- name: string(),
660
- in: string(),
661
- }),
662
- object({
663
- type: literal('b'),
664
- description: optional(string()),
665
- nested: object({
666
- a: string(),
667
- b: optional(string()),
668
- }),
669
- }),
670
- ]),
671
- object({
672
- $ref: string(),
673
- description: optional(string()),
674
- }),
675
- ])
676
-
677
- expect(
678
- coerce(A, {
679
- type: 'b',
680
- description: 'Hello World',
681
- nested: {
682
- b: 'hello',
683
- },
684
- }),
685
- ).toEqual({
686
- type: 'b',
687
- description: 'Hello World',
688
- nested: { a: '', b: 'hello' },
689
- })
690
- })
691
-
692
- it('should correctly score nested union types #2', () => {
693
- const A = union([
694
- union([
695
- object({
696
- prop1: string(),
697
- prop2: string(),
698
- prop3: string(),
699
- }),
700
- object({
701
- prop1: string(),
702
- prop4: string(),
703
- prop5: string(),
704
- }),
705
- ]),
706
- union([
707
- object({
708
- prop6: string(),
709
- prop7: string(),
710
- prop8: string(),
711
- }),
712
- object({
713
- prop1: string(),
714
- prop9: string(),
715
- prop10: string(),
716
- }),
717
- ]),
718
- ])
719
-
720
- // Picks the first union variant when the score is equal
721
- expect(
722
- coerce(A, {
723
- prop1: '',
724
- }),
725
- ).toEqual({
726
- prop1: '',
727
- prop2: '',
728
- prop3: '',
729
- })
730
-
731
- expect(
732
- coerce(A, {
733
- prop1: '',
734
- prop4: '',
735
- }),
736
- ).toEqual({
737
- prop1: '',
738
- prop4: '',
739
- prop5: '',
740
- })
741
-
742
- expect(
743
- coerce(A, {
744
- prop6: '',
745
- }),
746
- ).toEqual({
747
- prop6: '',
748
- prop7: '',
749
- prop8: '',
750
- })
751
- })
752
-
753
- it('should correctly score nested union types #3', () => {
754
- const A = union([
755
- object({
756
- prop1: string(),
757
- prop2: string(),
758
- prop3: string(),
759
- }),
760
- object({
761
- prop4: string(),
762
- prop5: string(),
763
- prop6: string(),
764
- }),
765
- union([
766
- object({
767
- prop4: string(),
768
- prop5: string(),
769
- prop6: string(),
770
- }),
771
- object({
772
- prop1: string(),
773
- prop2: string(),
774
- prop7: string(),
775
- prop8: string(),
776
- }),
777
- ]),
778
- ])
779
-
780
- expect(
781
- coerce(A, {
782
- prop1: '',
783
- prop2: '',
784
- prop7: '',
785
- }),
786
- ).toEqual({
787
- prop1: '',
788
- prop2: '',
789
- prop7: '',
790
- prop8: '',
791
- })
792
- })
793
-
794
- it('should correctly score nested union types #4', () => {
795
- const A = union([
796
- object({
797
- prop1: string(),
798
- prop2: string(),
799
- prop3: string(),
800
- }),
801
- union([
802
- object({
803
- prop4: string(),
804
- prop5: string(),
805
- prop6: string(),
806
- }),
807
- union([
808
- object({
809
- prop1: string(),
810
- prop2: string(),
811
- prop7: string(),
812
- prop8: string(),
813
- }),
814
- union([
815
- object({
816
- prop1: string(),
817
- prop2: string(),
818
- prop9: string(),
819
- prop10: string(),
820
- }),
821
- object({
822
- prop1: string(),
823
- prop2: string(),
824
- prop11: string(),
825
- prop12: string(),
826
- }),
827
- ]),
828
- ]),
829
- ]),
830
- ])
831
-
832
- expect(
833
- coerce(A, {
834
- prop1: '',
835
- prop2: '',
836
- prop9: '',
837
- }),
838
- ).toEqual({
839
- prop1: '',
840
- prop2: '',
841
- prop9: '',
842
- prop10: '',
843
- })
844
- })
845
-
846
- it('should correctly score object unions with shared properties #1', () => {
847
- const schema = union([
848
- object({
849
- summary: optional(string()),
850
- description: optional(string()),
851
- parameters: optional(array(any())),
852
- responses: optional(record(string(), any())),
853
- requestBody: optional(any()),
854
- }),
855
- object({
856
- $ref: string(),
857
- summary: optional(string()),
858
- }),
859
- ])
860
-
861
- expect(
862
- coerce(schema, {
863
- summary: 'Test Summary',
864
- parameters: {},
865
- }),
866
- ).toEqual({
867
- summary: 'Test Summary',
868
- parameters: [],
869
- })
870
- })
871
-
872
- it('should correctly score object unions with shared properties #2', () => {
873
- const A = union([
874
- object({
875
- prop1: string(),
876
- prop2: string(),
877
- prop3: string(),
878
- }),
879
- object({
880
- prop1: string(),
881
- prop2: string(),
882
- prop4: string(),
883
- prop5: string(),
884
- prop6: string(),
885
- prop7: string(),
886
- prop8: string(),
887
- prop9: string(),
888
- prop10: string(),
889
- }),
890
- ])
891
-
892
- expect(
893
- coerce(A, {
894
- prop1: '',
895
- prop2: '',
896
- prop7: '',
897
- }),
898
- ).toEqual({
899
- prop1: '',
900
- prop2: '',
901
- prop4: '',
902
- prop5: '',
903
- prop6: '',
904
- prop7: '',
905
- prop8: '',
906
- prop9: '',
907
- prop10: '',
908
- })
909
- })
910
-
911
- it('should correctly score object union for objects with all optional properties', () => {
912
- const A = union([
913
- object({
914
- prop1: optional(string()),
915
- prop2: optional(string()),
916
- prop3: optional(string()),
917
- }),
918
- object({
919
- $ref: string(),
920
- }),
921
- ])
922
-
923
- expect(
924
- coerce(A, {
925
- $ref: 'https://example.com/schema',
926
- }),
927
- ).toEqual({
928
- $ref: 'https://example.com/schema',
929
- })
930
- })
931
-
932
- it('picks the branch whose type discriminator matches a union of literals', () => {
933
- const T = union([
934
- object({
935
- type: literal('a'),
936
- a: string(),
937
- }),
938
- object({
939
- type: union([literal('b'), literal('c')]),
940
- b: string(),
941
- }),
942
- ])
943
- expect(coerce(T, { type: 'a' })).toEqual({ type: 'a', a: '' })
944
- expect(coerce(T, { type: 'b' })).toEqual({ type: 'b', b: '' })
945
- expect(coerce(T, { type: 'c' })).toEqual({ type: 'c', b: '' })
946
- })
947
- })
948
-
949
- describe('intersection', () => {
950
- const T = intersection([
951
- object({
952
- a: number(),
953
- b: number(),
954
- }),
955
- object({
956
- c: string(),
957
- d: string(),
958
- }),
959
- ])
960
- it('merges coerced properties from each object schema', () => {
961
- const result = coerce(T, { a: 1, b: 2, c: 'x', d: 'y' })
962
- expect(result).toEqual({ a: 1, b: 2, c: 'x', d: 'y' })
963
- })
964
- it('fills missing keys per branch from the same input value', () => {
965
- const result = coerce(T, { a: 'nope', c: 123 })
966
- expect(result).toEqual({ a: 0, b: 0, c: '', d: '' })
967
- })
968
- it('later branch wins on overlapping keys', () => {
969
- const overlap = intersection([object({ x: number() }), object({ x: string() })])
970
- const result = coerce(overlap, { x: 1 })
971
- expect(result).toEqual({ x: '' })
972
- })
973
- it('wins in a union when every member validates and summed score beats narrower members', () => {
974
- const A = object({ type: literal('A'), onlyA: number() })
975
- const B = object({ type: literal('B'), onlyB: string() })
976
- const both = intersection([
977
- object({ type: literal('A'), shared: number() }),
978
- object({ shared: number(), extra: string() }),
979
- ])
980
- const T = union([A, B, both])
981
- // Intersection merges only its declared keys; it outscores A here because both sub-objects validate.
982
- expect(coerce(T, { type: 'A', onlyA: 1, shared: 2, extra: 'ok' })).toEqual({
983
- type: 'A',
984
- shared: 2,
985
- extra: 'ok',
986
- })
987
- })
988
- it('correctly picks the branch on an intersection with nested unions #1', () => {
989
- const T = intersection([
990
- union([object({ type: literal('a'), a: string() }), object({ type: literal('b'), b: string() })]),
991
- object({ c: string() }),
992
- ])
993
- expect(coerce(T, { type: 'a', a: 'x', c: 'y' })).toEqual({ type: 'a', a: 'x', c: 'y' })
994
- expect(coerce(T, { type: 'b', b: 'x', c: 'y' })).toEqual({ type: 'b', b: 'x', c: 'y' })
995
- expect(coerce(T, { c: 'y' })).toEqual({ type: 'a', a: '', c: 'y' })
996
- })
997
- it('correctly picks the branch on an intersection with nested unions #2', () => {
998
- const T = intersection([
999
- union([
1000
- object({ type: literal('a'), a: optional(string()) }),
1001
- object({ type: literal('b'), b: optional(string()) }),
1002
- ]),
1003
- object({ c: optional(string()), d: optional(string()) }),
1004
- ])
1005
- expect(coerce(T, { a: 'a' })).toEqual({ type: 'a', a: 'a' })
1006
- expect(coerce(T, { a: 'a', c: 'c' })).toEqual({ type: 'a', a: 'a', c: 'c' })
1007
- })
1008
- })
1009
-
1010
- describe('notDefined', () => {
1011
- const T = notDefined()
1012
- const E = undefined
1013
- it('Should upcast from string', () => {
1014
- const value = 'hello'
1015
- const result = coerce(T, value)
1016
- expect(result).toBe(E)
1017
- })
1018
- it('Should upcast from number', () => {
1019
- const value = 1
1020
- const result = coerce(T, value)
1021
- expect(result).toBe(E)
1022
- })
1023
- it('Should upcast from boolean', () => {
1024
- const value = true
1025
- const result = coerce(T, value)
1026
- expect(result).toBe(E)
1027
- })
1028
- it('Should upcast from object', () => {
1029
- const value = {}
1030
- const result = coerce(T, value)
1031
- expect(result).toBe(E)
1032
- })
1033
- it('Should upcast from array', () => {
1034
- const value = [1]
1035
- const result = coerce(T, value)
1036
- expect(result).toBe(E)
1037
- })
1038
- it('Should upcast from undefined', () => {
1039
- const value = undefined
1040
- const result = coerce(T, value)
1041
- expect(result).toBe(E)
1042
- })
1043
- it('Should upcast from null', () => {
1044
- const value = null
1045
- const result = coerce(T, value)
1046
- expect(result).toBe(E)
1047
- })
1048
- it('Should upcast from date', () => {
1049
- const value = new Date(100)
1050
- const result = coerce(T, value)
1051
- expect(result).toBe(E)
1052
- })
1053
- it('Should preserve', () => {
1054
- const value = undefined
1055
- const result = coerce(T, value)
1056
- expect(result).toBe(undefined)
1057
- })
1058
- })
1059
-
1060
- describe('lazy', () => {
1061
- const T = lazy(() => object({ x: number() }))
1062
- const E = { x: 0 }
1063
- it('Should upcast from string', () => {
1064
- const value = 'hello'
1065
- const result = coerce(T, value)
1066
- expect(result).toEqual(E)
1067
- })
1068
- it('Should upcast from number', () => {
1069
- const value = 1
1070
- const result = coerce(T, value)
1071
- expect(result).toEqual(E)
1072
- })
1073
- it('Should upcast from boolean', () => {
1074
- const value = true
1075
- const result = coerce(T, value)
1076
- expect(result).toEqual(E)
1077
- })
1078
- it('Should upcast from object', () => {
1079
- const value = {}
1080
- const result = coerce(T, value)
1081
- expect(result).toEqual(E)
1082
- })
1083
- it('Should upcast from array', () => {
1084
- const value = [1]
1085
- const result = coerce(T, value)
1086
- expect(result).toEqual(E)
1087
- })
1088
- it('Should upcast from undefined', () => {
1089
- const value = undefined
1090
- const result = coerce(T, value)
1091
- expect(result).toEqual(E)
1092
- })
1093
- it('Should upcast from null', () => {
1094
- const value = null
1095
- const result = coerce(T, value)
1096
- expect(result).toEqual(E)
1097
- })
1098
- it('Should upcast from date', () => {
1099
- const value = new Date(100)
1100
- const result = coerce(T, value)
1101
- expect(result).toEqual(E)
1102
- })
1103
- it('Should preserve', () => {
1104
- const value = { x: 1 }
1105
- const result = coerce(T, value)
1106
- expect(result).toEqual(value)
1107
- })
1108
- })
1109
-
1110
- describe('evaluate', () => {
1111
- const T = evaluate((value) => value, object({ x: number() }))
1112
- const E = { x: 0 }
1113
- it('Should upcast from string', () => {
1114
- const value = 'hello'
1115
- const result = coerce(T, value)
1116
- expect(result).toEqual(E)
1117
- })
1118
- it('Should upcast from number', () => {
1119
- const value = 1
1120
- const result = coerce(T, value)
1121
- expect(result).toEqual(E)
1122
- })
1123
- it('Should upcast from boolean', () => {
1124
- const value = true
1125
- const result = coerce(T, value)
1126
- expect(result).toEqual(E)
1127
- })
1128
- it('Should upcast from object', () => {
1129
- const value = {}
1130
- const result = coerce(T, value)
1131
- expect(result).toEqual(E)
1132
- })
1133
- it('Should upcast from array', () => {
1134
- const value = [1]
1135
- const result = coerce(T, value)
1136
- expect(result).toEqual(E)
1137
- })
1138
- it('Should upcast from undefined', () => {
1139
- const value = undefined
1140
- const result = coerce(T, value)
1141
- expect(result).toEqual(E)
1142
- })
1143
- it('Should upcast from null', () => {
1144
- const value = null
1145
- const result = coerce(T, value)
1146
- expect(result).toEqual(E)
1147
- })
1148
- it('Should upcast from date', () => {
1149
- const value = new Date(100)
1150
- const result = coerce(T, value)
1151
- expect(result).toEqual(E)
1152
- })
1153
- it('Should preserve', () => {
1154
- const value = { x: 1 }
1155
- const result = coerce(T, value)
1156
- expect(result).toEqual(value)
1157
- })
1158
- })