schematox 1.2.0 → 1.2.2-alpha

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/dist/constants.d.ts +20 -0
  2. package/dist/constants.d.ts.map +1 -0
  3. package/dist/constants.js +22 -0
  4. package/dist/constants.js.map +1 -0
  5. package/dist/index.d.ts +10 -0
  6. package/dist/index.d.ts.map +1 -0
  7. package/dist/index.js +9 -0
  8. package/dist/index.js.map +1 -0
  9. package/dist/parse.d.ts +5 -0
  10. package/dist/parse.d.ts.map +1 -0
  11. package/dist/parse.js +328 -0
  12. package/dist/parse.js.map +1 -0
  13. package/dist/struct.d.ts +48 -0
  14. package/dist/struct.d.ts.map +1 -0
  15. package/dist/struct.js +111 -0
  16. package/dist/struct.js.map +1 -0
  17. package/dist/types/extensions.d.ts +13 -0
  18. package/dist/types/extensions.d.ts.map +1 -0
  19. package/dist/types/extensions.js +2 -0
  20. package/dist/types/extensions.js.map +1 -0
  21. package/dist/types/infer.d.ts +35 -0
  22. package/dist/types/infer.d.ts.map +1 -0
  23. package/dist/types/infer.js +2 -0
  24. package/dist/types/infer.js.map +1 -0
  25. package/dist/types/schema.d.ts +93 -0
  26. package/dist/types/schema.d.ts.map +1 -0
  27. package/dist/types/schema.js +2 -0
  28. package/dist/types/schema.js.map +1 -0
  29. package/dist/types/standard-schema.d.ts +35 -0
  30. package/dist/types/standard-schema.d.ts.map +1 -0
  31. package/dist/types/standard-schema.js +2 -0
  32. package/dist/types/standard-schema.js.map +1 -0
  33. package/dist/types/struct.d.ts +52 -0
  34. package/dist/types/struct.d.ts.map +1 -0
  35. package/dist/types/struct.js +2 -0
  36. package/dist/types/struct.js.map +1 -0
  37. package/dist/types/utils.d.ts +41 -0
  38. package/dist/types/utils.d.ts.map +1 -0
  39. package/dist/types/utils.js +2 -0
  40. package/dist/types/utils.js.map +1 -0
  41. package/dist/utils.d.ts +9 -0
  42. package/dist/utils.d.ts.map +1 -0
  43. package/dist/utils.js +14 -0
  44. package/dist/utils.js.map +1 -0
  45. package/package.json +16 -4
  46. package/src/tests/README.md +390 -0
  47. package/src/tests/by-struct/array.test.ts +1684 -0
  48. package/src/tests/by-struct/boolean.test.ts +741 -0
  49. package/src/tests/by-struct/literal.test.ts +755 -0
  50. package/src/tests/by-struct/number.test.ts +1234 -0
  51. package/src/tests/by-struct/object.test.ts +1484 -0
  52. package/src/tests/by-struct/record.test.ts +1802 -0
  53. package/src/tests/by-struct/string.test.ts +1252 -0
  54. package/src/tests/by-struct/tuple.test.ts +1341 -0
  55. package/src/tests/by-struct/union.test.ts +1284 -0
  56. package/src/tests/fixtures.ts +52 -0
  57. package/src/tests/fold-constants.ts +247 -0
  58. package/src/tests/fold-morph.ts +49 -0
  59. package/src/tests/type.ts +1 -0
  60. package/src/tests/types/extensions.test.ts +117 -0
  61. package/src/tests/types/infer.test.ts +1410 -0
  62. package/src/tests/utils.test.ts +191 -0
  63. package/CHANGELOG.md +0 -48
@@ -0,0 +1,1234 @@
1
+ import * as x from '../../'
2
+ import * as fixture from '../fixtures'
3
+
4
+ import type { StructSharedKeys } from '../type'
5
+
6
+ describe('Type inference and parse by schema/construct/struct (foldA)', () => {
7
+ it('required', () => {
8
+ const schema = { type: 'number' } as const satisfies x.Schema
9
+ const struct = x.number()
10
+
11
+ type ExpectedSubj = number
12
+
13
+ const subjects: Array<ExpectedSubj> = fixture.DATA_VARIANTS_BY_TYPE.number
14
+
15
+ foldA: {
16
+ const construct = x.makeStruct(schema)
17
+
18
+ /* ensure that schema/construct/struct/~standard subject types are identical */
19
+
20
+ type ConstructSchemaSubj = x.Infer<typeof construct.__schema>
21
+
22
+ x.tCh<ConstructSchemaSubj, ExpectedSubj>()
23
+ x.tCh<ExpectedSubj, ConstructSchemaSubj>()
24
+
25
+ type SchemaSubj = x.Infer<typeof schema>
26
+
27
+ x.tCh<SchemaSubj, ExpectedSubj>()
28
+ x.tCh<ExpectedSubj, SchemaSubj>()
29
+
30
+ type StructSubj = x.Infer<typeof struct.__schema>
31
+
32
+ x.tCh<StructSubj, ExpectedSubj>()
33
+ x.tCh<ExpectedSubj, StructSubj>()
34
+
35
+ type StandardSubj = NonNullable<
36
+ (typeof struct)['~standard']['types']
37
+ >['output']
38
+
39
+ x.tCh<StandardSubj, ExpectedSubj>()
40
+ x.tCh<ExpectedSubj, StandardSubj>()
41
+
42
+ /* parsed either type check */
43
+
44
+ type ExpectedParsed = x.ParseResult<ExpectedSubj>
45
+
46
+ const parsed = x.parse(schema, undefined)
47
+
48
+ type SchemaParsed = typeof parsed
49
+
50
+ x.tCh<SchemaParsed, ExpectedParsed>()
51
+ x.tCh<ExpectedParsed, SchemaParsed>()
52
+
53
+ type ConstructParsed = ReturnType<typeof construct.parse>
54
+
55
+ x.tCh<ConstructParsed, ExpectedParsed>()
56
+ x.tCh<ExpectedParsed, ConstructParsed>()
57
+
58
+ type StructParsed = ReturnType<typeof struct.parse>
59
+
60
+ x.tCh<StructParsed, ExpectedParsed>()
61
+ x.tCh<ExpectedParsed, StructParsed>()
62
+
63
+ type StandardParsed = Extract<
64
+ ReturnType<(typeof struct)['~standard']['validate']>,
65
+ { value: unknown }
66
+ >['value']
67
+
68
+ x.tCh<StandardParsed, ExpectedSubj>()
69
+ x.tCh<ExpectedSubj, StandardParsed>()
70
+
71
+ /* runtime schema check */
72
+
73
+ expect(struct.__schema).toStrictEqual(schema)
74
+ expect(construct.__schema).toStrictEqual(schema)
75
+ expect(construct.__schema === schema).toBe(false)
76
+
77
+ /* parse result check */
78
+
79
+ for (const subj of subjects) {
80
+ const schemaParsed = x.parse(schema, subj)
81
+
82
+ expect(schemaParsed.error).toBe(undefined)
83
+ expect(schemaParsed.data).toStrictEqual(subj)
84
+
85
+ const constructParsed = construct.parse(subj)
86
+
87
+ expect(constructParsed.error).toBe(undefined)
88
+ expect(constructParsed.data).toStrictEqual(subj)
89
+
90
+ const structParsed = struct.parse(subj)
91
+
92
+ expect(structParsed.error).toBe(undefined)
93
+ expect(structParsed.data).toStrictEqual(subj)
94
+
95
+ const standardParsed = struct['~standard'].validate(subj)
96
+
97
+ if (standardParsed instanceof Promise) {
98
+ throw Error('Not expected')
99
+ }
100
+
101
+ if (standardParsed.issues !== undefined) {
102
+ throw Error('not expected')
103
+ }
104
+
105
+ expect(standardParsed.value).toStrictEqual(subj)
106
+ }
107
+ }
108
+ })
109
+
110
+ it('optional', () => {
111
+ const schema = {
112
+ type: 'number',
113
+ optional: true,
114
+ } as const satisfies x.Schema
115
+
116
+ const struct = x.number().optional()
117
+
118
+ type ExpectedSubj = number | undefined
119
+
120
+ const subjects: Array<ExpectedSubj> = [
121
+ ...fixture.DATA_VARIANTS_BY_TYPE.number,
122
+ undefined,
123
+ ]
124
+
125
+ foldA: {
126
+ const construct = x.makeStruct(schema)
127
+
128
+ /* ensure that schema/construct/struct/~standard subject types are identical */
129
+
130
+ type ConstructSchemaSubj = x.Infer<typeof construct.__schema>
131
+
132
+ x.tCh<ConstructSchemaSubj, ExpectedSubj>()
133
+ x.tCh<ExpectedSubj, ConstructSchemaSubj>()
134
+
135
+ type SchemaSubj = x.Infer<typeof schema>
136
+
137
+ x.tCh<SchemaSubj, ExpectedSubj>()
138
+ x.tCh<ExpectedSubj, SchemaSubj>()
139
+
140
+ type StructSubj = x.Infer<typeof struct.__schema>
141
+
142
+ x.tCh<StructSubj, ExpectedSubj>()
143
+ x.tCh<ExpectedSubj, StructSubj>()
144
+
145
+ type StandardSubj = NonNullable<
146
+ (typeof struct)['~standard']['types']
147
+ >['output']
148
+
149
+ x.tCh<StandardSubj, ExpectedSubj>()
150
+ x.tCh<ExpectedSubj, StandardSubj>()
151
+
152
+ /* parsed either type check */
153
+
154
+ type ExpectedParsed = x.ParseResult<ExpectedSubj>
155
+
156
+ const parsed = x.parse(schema, undefined)
157
+
158
+ type SchemaParsed = typeof parsed
159
+
160
+ x.tCh<SchemaParsed, ExpectedParsed>()
161
+ x.tCh<ExpectedParsed, SchemaParsed>()
162
+
163
+ type ConstructParsed = ReturnType<typeof construct.parse>
164
+
165
+ x.tCh<ConstructParsed, ExpectedParsed>()
166
+ x.tCh<ExpectedParsed, ConstructParsed>()
167
+
168
+ type StructParsed = ReturnType<typeof struct.parse>
169
+
170
+ x.tCh<StructParsed, ExpectedParsed>()
171
+ x.tCh<ExpectedParsed, StructParsed>()
172
+
173
+ type StandardParsed = Extract<
174
+ ReturnType<(typeof struct)['~standard']['validate']>,
175
+ { value: unknown }
176
+ >['value']
177
+
178
+ x.tCh<StandardParsed, ExpectedSubj>()
179
+ x.tCh<ExpectedSubj, StandardParsed>()
180
+
181
+ /* runtime schema check */
182
+
183
+ expect(struct.__schema).toStrictEqual(schema)
184
+ expect(construct.__schema).toStrictEqual(schema)
185
+ expect(construct.__schema === schema).toBe(false)
186
+
187
+ /* parse result check */
188
+
189
+ for (const subj of subjects) {
190
+ const schemaParsed = x.parse(schema, subj)
191
+
192
+ expect(schemaParsed.error).toBe(undefined)
193
+ expect(schemaParsed.data).toStrictEqual(subj)
194
+
195
+ const constructParsed = construct.parse(subj)
196
+
197
+ expect(constructParsed.error).toBe(undefined)
198
+ expect(constructParsed.data).toStrictEqual(subj)
199
+
200
+ const structParsed = struct.parse(subj)
201
+
202
+ expect(structParsed.error).toBe(undefined)
203
+ expect(structParsed.data).toStrictEqual(subj)
204
+
205
+ const standardParsed = struct['~standard'].validate(subj)
206
+
207
+ if (standardParsed instanceof Promise) {
208
+ throw Error('Not expected')
209
+ }
210
+
211
+ if (standardParsed.issues !== undefined) {
212
+ throw Error('not expected')
213
+ }
214
+
215
+ expect(standardParsed.value).toStrictEqual(subj)
216
+ }
217
+ }
218
+ })
219
+
220
+ it('nullable', () => {
221
+ const schema = {
222
+ type: 'number',
223
+ nullable: true,
224
+ } as const satisfies x.Schema
225
+
226
+ const struct = x.number().nullable()
227
+
228
+ type ExpectedSubj = number | null
229
+
230
+ const subjects: Array<ExpectedSubj> = [
231
+ ...fixture.DATA_VARIANTS_BY_TYPE.number,
232
+ null,
233
+ ]
234
+
235
+ foldA: {
236
+ const construct = x.makeStruct(schema)
237
+
238
+ /* ensure that schema/construct/struct/~standard subject types are identical */
239
+
240
+ type ConstructSchemaSubj = x.Infer<typeof construct.__schema>
241
+
242
+ x.tCh<ConstructSchemaSubj, ExpectedSubj>()
243
+ x.tCh<ExpectedSubj, ConstructSchemaSubj>()
244
+
245
+ type SchemaSubj = x.Infer<typeof schema>
246
+
247
+ x.tCh<SchemaSubj, ExpectedSubj>()
248
+ x.tCh<ExpectedSubj, SchemaSubj>()
249
+
250
+ type StructSubj = x.Infer<typeof struct.__schema>
251
+
252
+ x.tCh<StructSubj, ExpectedSubj>()
253
+ x.tCh<ExpectedSubj, StructSubj>()
254
+
255
+ type StandardSubj = NonNullable<
256
+ (typeof struct)['~standard']['types']
257
+ >['output']
258
+
259
+ x.tCh<StandardSubj, ExpectedSubj>()
260
+ x.tCh<ExpectedSubj, StandardSubj>()
261
+
262
+ /* parsed either type check */
263
+
264
+ type ExpectedParsed = x.ParseResult<ExpectedSubj>
265
+
266
+ const parsed = x.parse(schema, undefined)
267
+
268
+ type SchemaParsed = typeof parsed
269
+
270
+ x.tCh<SchemaParsed, ExpectedParsed>()
271
+ x.tCh<ExpectedParsed, SchemaParsed>()
272
+
273
+ type ConstructParsed = ReturnType<typeof construct.parse>
274
+
275
+ x.tCh<ConstructParsed, ExpectedParsed>()
276
+ x.tCh<ExpectedParsed, ConstructParsed>()
277
+
278
+ type StructParsed = ReturnType<typeof struct.parse>
279
+
280
+ x.tCh<StructParsed, ExpectedParsed>()
281
+ x.tCh<ExpectedParsed, StructParsed>()
282
+
283
+ type StandardParsed = Extract<
284
+ ReturnType<(typeof struct)['~standard']['validate']>,
285
+ { value: unknown }
286
+ >['value']
287
+
288
+ x.tCh<StandardParsed, ExpectedSubj>()
289
+ x.tCh<ExpectedSubj, StandardParsed>()
290
+
291
+ /* runtime schema check */
292
+
293
+ expect(struct.__schema).toStrictEqual(schema)
294
+ expect(construct.__schema).toStrictEqual(schema)
295
+ expect(construct.__schema === schema).toBe(false)
296
+
297
+ /* parse result check */
298
+
299
+ for (const subj of subjects) {
300
+ const schemaParsed = x.parse(schema, subj)
301
+
302
+ expect(schemaParsed.error).toBe(undefined)
303
+ expect(schemaParsed.data).toStrictEqual(subj)
304
+
305
+ const constructParsed = construct.parse(subj)
306
+
307
+ expect(constructParsed.error).toBe(undefined)
308
+ expect(constructParsed.data).toStrictEqual(subj)
309
+
310
+ const structParsed = struct.parse(subj)
311
+
312
+ expect(structParsed.error).toBe(undefined)
313
+ expect(structParsed.data).toStrictEqual(subj)
314
+
315
+ const standardParsed = struct['~standard'].validate(subj)
316
+
317
+ if (standardParsed instanceof Promise) {
318
+ throw Error('Not expected')
319
+ }
320
+
321
+ if (standardParsed.issues !== undefined) {
322
+ throw Error('not expected')
323
+ }
324
+
325
+ expect(standardParsed.value).toStrictEqual(subj)
326
+ }
327
+ }
328
+ })
329
+
330
+ it('min', () => {
331
+ const schema = {
332
+ type: 'number',
333
+ min: 0,
334
+ } as const satisfies x.Schema
335
+
336
+ const struct = x.number().min(schema.min)
337
+
338
+ type ExpectedSubj = number
339
+
340
+ const subjects: Array<ExpectedSubj> = [-0, 0, 1]
341
+
342
+ foldA: {
343
+ const construct = x.makeStruct(schema)
344
+
345
+ /* ensure that schema/construct/struct/~standard subject types are identical */
346
+
347
+ type ConstructSchemaSubj = x.Infer<typeof construct.__schema>
348
+
349
+ x.tCh<ConstructSchemaSubj, ExpectedSubj>()
350
+ x.tCh<ExpectedSubj, ConstructSchemaSubj>()
351
+
352
+ type SchemaSubj = x.Infer<typeof schema>
353
+
354
+ x.tCh<SchemaSubj, ExpectedSubj>()
355
+ x.tCh<ExpectedSubj, SchemaSubj>()
356
+
357
+ type StructSubj = x.Infer<typeof struct.__schema>
358
+
359
+ x.tCh<StructSubj, ExpectedSubj>()
360
+ x.tCh<ExpectedSubj, StructSubj>()
361
+
362
+ type StandardSubj = NonNullable<
363
+ (typeof struct)['~standard']['types']
364
+ >['output']
365
+
366
+ x.tCh<StandardSubj, ExpectedSubj>()
367
+ x.tCh<ExpectedSubj, StandardSubj>()
368
+
369
+ /* parsed either type check */
370
+
371
+ type ExpectedParsed = x.ParseResult<ExpectedSubj>
372
+
373
+ const parsed = x.parse(schema, undefined)
374
+
375
+ type SchemaParsed = typeof parsed
376
+
377
+ x.tCh<SchemaParsed, ExpectedParsed>()
378
+ x.tCh<ExpectedParsed, SchemaParsed>()
379
+
380
+ type ConstructParsed = ReturnType<typeof construct.parse>
381
+
382
+ x.tCh<ConstructParsed, ExpectedParsed>()
383
+ x.tCh<ExpectedParsed, ConstructParsed>()
384
+
385
+ type StructParsed = ReturnType<typeof struct.parse>
386
+
387
+ x.tCh<StructParsed, ExpectedParsed>()
388
+ x.tCh<ExpectedParsed, StructParsed>()
389
+
390
+ type StandardParsed = Extract<
391
+ ReturnType<(typeof struct)['~standard']['validate']>,
392
+ { value: unknown }
393
+ >['value']
394
+
395
+ x.tCh<StandardParsed, ExpectedSubj>()
396
+ x.tCh<ExpectedSubj, StandardParsed>()
397
+
398
+ /* runtime schema check */
399
+
400
+ expect(struct.__schema).toStrictEqual(schema)
401
+ expect(construct.__schema).toStrictEqual(schema)
402
+ expect(construct.__schema === schema).toBe(false)
403
+
404
+ /* parse result check */
405
+
406
+ for (const subj of subjects) {
407
+ const schemaParsed = x.parse(schema, subj)
408
+
409
+ expect(schemaParsed.error).toBe(undefined)
410
+ expect(schemaParsed.data).toStrictEqual(subj)
411
+
412
+ const constructParsed = construct.parse(subj)
413
+
414
+ expect(constructParsed.error).toBe(undefined)
415
+ expect(constructParsed.data).toStrictEqual(subj)
416
+
417
+ const structParsed = struct.parse(subj)
418
+
419
+ expect(structParsed.error).toBe(undefined)
420
+ expect(structParsed.data).toStrictEqual(subj)
421
+
422
+ const standardParsed = struct['~standard'].validate(subj)
423
+
424
+ if (standardParsed instanceof Promise) {
425
+ throw Error('Not expected')
426
+ }
427
+
428
+ if (standardParsed.issues !== undefined) {
429
+ throw Error('not expected')
430
+ }
431
+
432
+ expect(standardParsed.value).toStrictEqual(subj)
433
+ }
434
+ }
435
+ })
436
+
437
+ it('max', () => {
438
+ const schema = {
439
+ type: 'number',
440
+ max: 0,
441
+ } as const satisfies x.Schema
442
+
443
+ const struct = x.number().max(schema.max)
444
+
445
+ type ExpectedSubj = number
446
+
447
+ const subjects: Array<ExpectedSubj> = [-1, -2]
448
+
449
+ foldA: {
450
+ const construct = x.makeStruct(schema)
451
+
452
+ /* ensure that schema/construct/struct/~standard subject types are identical */
453
+
454
+ type ConstructSchemaSubj = x.Infer<typeof construct.__schema>
455
+
456
+ x.tCh<ConstructSchemaSubj, ExpectedSubj>()
457
+ x.tCh<ExpectedSubj, ConstructSchemaSubj>()
458
+
459
+ type SchemaSubj = x.Infer<typeof schema>
460
+
461
+ x.tCh<SchemaSubj, ExpectedSubj>()
462
+ x.tCh<ExpectedSubj, SchemaSubj>()
463
+
464
+ type StructSubj = x.Infer<typeof struct.__schema>
465
+
466
+ x.tCh<StructSubj, ExpectedSubj>()
467
+ x.tCh<ExpectedSubj, StructSubj>()
468
+
469
+ type StandardSubj = NonNullable<
470
+ (typeof struct)['~standard']['types']
471
+ >['output']
472
+
473
+ x.tCh<StandardSubj, ExpectedSubj>()
474
+ x.tCh<ExpectedSubj, StandardSubj>()
475
+
476
+ /* parsed either type check */
477
+
478
+ type ExpectedParsed = x.ParseResult<ExpectedSubj>
479
+
480
+ const parsed = x.parse(schema, undefined)
481
+
482
+ type SchemaParsed = typeof parsed
483
+
484
+ x.tCh<SchemaParsed, ExpectedParsed>()
485
+ x.tCh<ExpectedParsed, SchemaParsed>()
486
+
487
+ type ConstructParsed = ReturnType<typeof construct.parse>
488
+
489
+ x.tCh<ConstructParsed, ExpectedParsed>()
490
+ x.tCh<ExpectedParsed, ConstructParsed>()
491
+
492
+ type StructParsed = ReturnType<typeof struct.parse>
493
+
494
+ x.tCh<StructParsed, ExpectedParsed>()
495
+ x.tCh<ExpectedParsed, StructParsed>()
496
+
497
+ type StandardParsed = Extract<
498
+ ReturnType<(typeof struct)['~standard']['validate']>,
499
+ { value: unknown }
500
+ >['value']
501
+
502
+ x.tCh<StandardParsed, ExpectedSubj>()
503
+ x.tCh<ExpectedSubj, StandardParsed>()
504
+
505
+ /* runtime schema check */
506
+
507
+ expect(struct.__schema).toStrictEqual(schema)
508
+ expect(construct.__schema).toStrictEqual(schema)
509
+ expect(construct.__schema === schema).toBe(false)
510
+
511
+ /* parse result check */
512
+
513
+ for (const subj of subjects) {
514
+ const schemaParsed = x.parse(schema, subj)
515
+
516
+ expect(schemaParsed.error).toBe(undefined)
517
+ expect(schemaParsed.data).toStrictEqual(subj)
518
+
519
+ const constructParsed = construct.parse(subj)
520
+
521
+ expect(constructParsed.error).toBe(undefined)
522
+ expect(constructParsed.data).toStrictEqual(subj)
523
+
524
+ const structParsed = struct.parse(subj)
525
+
526
+ expect(structParsed.error).toBe(undefined)
527
+ expect(structParsed.data).toStrictEqual(subj)
528
+
529
+ const standardParsed = struct['~standard'].validate(subj)
530
+
531
+ if (standardParsed instanceof Promise) {
532
+ throw Error('Not expected')
533
+ }
534
+
535
+ if (standardParsed.issues !== undefined) {
536
+ throw Error('not expected')
537
+ }
538
+
539
+ expect(standardParsed.value).toStrictEqual(subj)
540
+ }
541
+ }
542
+ })
543
+
544
+ it('optional + nullable + min + max ', () => {
545
+ const schema = {
546
+ type: 'number',
547
+ optional: true,
548
+ nullable: true,
549
+ min: 0,
550
+ max: 1,
551
+ } as const satisfies x.Schema
552
+
553
+ const struct = x
554
+ .number()
555
+ .optional()
556
+ .nullable()
557
+ .min(schema.min)
558
+ .max(schema.max)
559
+
560
+ type ExpectedSubj = number | undefined | null
561
+
562
+ const subjects: Array<ExpectedSubj> = [0, 1, null, undefined]
563
+
564
+ foldA: {
565
+ const construct = x.makeStruct(schema)
566
+
567
+ /* ensure that schema/construct/struct/~standard subject types are identical */
568
+
569
+ type ConstructSchemaSubj = x.Infer<typeof construct.__schema>
570
+
571
+ x.tCh<ConstructSchemaSubj, ExpectedSubj>()
572
+ x.tCh<ExpectedSubj, ConstructSchemaSubj>()
573
+
574
+ type SchemaSubj = x.Infer<typeof schema>
575
+
576
+ x.tCh<SchemaSubj, ExpectedSubj>()
577
+ x.tCh<ExpectedSubj, SchemaSubj>()
578
+
579
+ type StructSubj = x.Infer<typeof struct.__schema>
580
+
581
+ x.tCh<StructSubj, ExpectedSubj>()
582
+ x.tCh<ExpectedSubj, StructSubj>()
583
+
584
+ type StandardSubj = NonNullable<
585
+ (typeof struct)['~standard']['types']
586
+ >['output']
587
+
588
+ x.tCh<StandardSubj, ExpectedSubj>()
589
+ x.tCh<ExpectedSubj, StandardSubj>()
590
+
591
+ /* parsed either type check */
592
+
593
+ type ExpectedParsed = x.ParseResult<ExpectedSubj>
594
+
595
+ const parsed = x.parse(schema, undefined)
596
+
597
+ type SchemaParsed = typeof parsed
598
+
599
+ x.tCh<SchemaParsed, ExpectedParsed>()
600
+ x.tCh<ExpectedParsed, SchemaParsed>()
601
+
602
+ type ConstructParsed = ReturnType<typeof construct.parse>
603
+
604
+ x.tCh<ConstructParsed, ExpectedParsed>()
605
+ x.tCh<ExpectedParsed, ConstructParsed>()
606
+
607
+ type StructParsed = ReturnType<typeof struct.parse>
608
+
609
+ x.tCh<StructParsed, ExpectedParsed>()
610
+ x.tCh<ExpectedParsed, StructParsed>()
611
+
612
+ type StandardParsed = Extract<
613
+ ReturnType<(typeof struct)['~standard']['validate']>,
614
+ { value: unknown }
615
+ >['value']
616
+
617
+ x.tCh<StandardParsed, ExpectedSubj>()
618
+ x.tCh<ExpectedSubj, StandardParsed>()
619
+
620
+ /* runtime schema check */
621
+
622
+ expect(struct.__schema).toStrictEqual(schema)
623
+ expect(construct.__schema).toStrictEqual(schema)
624
+ expect(construct.__schema === schema).toBe(false)
625
+
626
+ /* parse result check */
627
+
628
+ for (const subj of subjects) {
629
+ const schemaParsed = x.parse(schema, subj)
630
+
631
+ expect(schemaParsed.error).toBe(undefined)
632
+ expect(schemaParsed.data).toStrictEqual(subj)
633
+
634
+ const constructParsed = construct.parse(subj)
635
+
636
+ expect(constructParsed.error).toBe(undefined)
637
+ expect(constructParsed.data).toStrictEqual(subj)
638
+
639
+ const structParsed = struct.parse(subj)
640
+
641
+ expect(structParsed.error).toBe(undefined)
642
+ expect(structParsed.data).toStrictEqual(subj)
643
+
644
+ const standardParsed = struct['~standard'].validate(subj)
645
+
646
+ if (standardParsed instanceof Promise) {
647
+ throw Error('Not expected')
648
+ }
649
+
650
+ if (standardParsed.issues !== undefined) {
651
+ throw Error('not expected')
652
+ }
653
+
654
+ expect(standardParsed.value).toStrictEqual(subj)
655
+ }
656
+ }
657
+ })
658
+ })
659
+
660
+ describe('Struct parameter keys reduction and schema immutability (foldB)', () => {
661
+ it('optional', () => {
662
+ const schema = {
663
+ type: 'number',
664
+ optional: true,
665
+ } as const satisfies x.Schema
666
+
667
+ const prevStruct = x.number()
668
+ const struct = prevStruct.optional()
669
+
670
+ type ExpectedKeys =
671
+ | StructSharedKeys
672
+ | 'brand'
673
+ | 'description'
674
+ | 'max'
675
+ | 'min'
676
+ | 'nullable'
677
+
678
+ foldB: {
679
+ const construct = x.makeStruct(schema)
680
+
681
+ /* ensure that struct keys are reduced after application */
682
+
683
+ type StructKeys = keyof typeof struct
684
+
685
+ x.tCh<StructKeys, ExpectedKeys>()
686
+ x.tCh<ExpectedKeys, StructKeys>()
687
+
688
+ type ConstructKeys = keyof typeof construct
689
+
690
+ x.tCh<ConstructKeys, ExpectedKeys>()
691
+ x.tCh<ExpectedKeys, ConstructKeys>()
692
+
693
+ /* ensure that construct/struct schema types are identical */
694
+
695
+ type ExpectedSchema = typeof schema
696
+ type StructSchema = typeof struct.__schema
697
+
698
+ x.tCh<StructSchema, ExpectedSchema>()
699
+ x.tCh<ExpectedSchema, StructSchema>()
700
+
701
+ type ConstructSchema = typeof struct.__schema
702
+
703
+ x.tCh<ConstructSchema, ExpectedSchema>()
704
+ x.tCh<ExpectedSchema, ConstructSchema>()
705
+
706
+ /* runtime schema check */
707
+
708
+ expect(struct.__schema).toStrictEqual(schema)
709
+ expect(construct.__schema).toStrictEqual(schema)
710
+ expect(construct.__schema === schema).toBe(false)
711
+
712
+ /* runtime schema parameter application immutability check */
713
+
714
+ expect(prevStruct.__schema === struct.__schema).toBe(false)
715
+ }
716
+ })
717
+
718
+ it('optional + nullable', () => {
719
+ const schema = {
720
+ type: 'number',
721
+ optional: true,
722
+ nullable: true,
723
+ } as const satisfies x.Schema
724
+
725
+ const prevStruct = x.number().optional()
726
+ const struct = prevStruct.nullable()
727
+
728
+ type ExpectedKeys =
729
+ | StructSharedKeys
730
+ | 'brand'
731
+ | 'description'
732
+ | 'max'
733
+ | 'min'
734
+
735
+ foldB: {
736
+ const construct = x.makeStruct(schema)
737
+
738
+ /* ensure that struct keys are reduced after application */
739
+
740
+ type StructKeys = keyof typeof struct
741
+
742
+ x.tCh<StructKeys, ExpectedKeys>()
743
+ x.tCh<ExpectedKeys, StructKeys>()
744
+
745
+ type ConstructKeys = keyof typeof construct
746
+
747
+ x.tCh<ConstructKeys, ExpectedKeys>()
748
+ x.tCh<ExpectedKeys, ConstructKeys>()
749
+
750
+ /* ensure that construct/struct schema types are identical */
751
+
752
+ type ExpectedSchema = typeof schema
753
+ type StructSchema = typeof struct.__schema
754
+
755
+ x.tCh<StructSchema, ExpectedSchema>()
756
+ x.tCh<ExpectedSchema, StructSchema>()
757
+
758
+ type ConstructSchema = typeof struct.__schema
759
+
760
+ x.tCh<ConstructSchema, ExpectedSchema>()
761
+ x.tCh<ExpectedSchema, ConstructSchema>()
762
+
763
+ /* runtime schema check */
764
+
765
+ expect(struct.__schema).toStrictEqual(schema)
766
+ expect(construct.__schema).toStrictEqual(schema)
767
+ expect(construct.__schema === schema).toBe(false)
768
+
769
+ /* runtime schema parameter application immutability check */
770
+
771
+ expect(prevStruct.__schema === struct.__schema).toBe(false)
772
+ }
773
+ })
774
+
775
+ it('optional + nullable + brand', () => {
776
+ const schema = {
777
+ type: 'number',
778
+ optional: true,
779
+ nullable: true,
780
+ brand: ['x', 'y'],
781
+ } as const satisfies x.Schema
782
+
783
+ const prevStruct = x.number().optional().nullable()
784
+ const struct = prevStruct.brand('x', 'y')
785
+
786
+ type ExpectedKeys = StructSharedKeys | 'description' | 'min' | 'max'
787
+
788
+ foldB: {
789
+ const construct = x.makeStruct(schema)
790
+
791
+ /* ensure that struct keys are reduced after application */
792
+
793
+ type StructKeys = keyof typeof struct
794
+
795
+ x.tCh<StructKeys, ExpectedKeys>()
796
+ x.tCh<ExpectedKeys, StructKeys>()
797
+
798
+ type ConstructKeys = keyof typeof construct
799
+
800
+ x.tCh<ConstructKeys, ExpectedKeys>()
801
+ x.tCh<ExpectedKeys, ConstructKeys>()
802
+
803
+ /* ensure that construct/struct schema types are identical */
804
+
805
+ type ExpectedSchema = typeof schema
806
+ type StructSchema = typeof struct.__schema
807
+
808
+ x.tCh<StructSchema, ExpectedSchema>()
809
+ x.tCh<ExpectedSchema, StructSchema>()
810
+
811
+ type ConstructSchema = typeof struct.__schema
812
+
813
+ x.tCh<ConstructSchema, ExpectedSchema>()
814
+ x.tCh<ExpectedSchema, ConstructSchema>()
815
+
816
+ /* runtime schema check */
817
+
818
+ expect(struct.__schema).toStrictEqual(schema)
819
+ expect(construct.__schema).toStrictEqual(schema)
820
+ expect(construct.__schema === schema).toBe(false)
821
+
822
+ /* runtime schema parameter application immutability check */
823
+
824
+ expect(prevStruct.__schema === struct.__schema).toBe(false)
825
+ }
826
+ })
827
+
828
+ it('optional + nullable + brand + min', () => {
829
+ const schema = {
830
+ type: 'number',
831
+ optional: true,
832
+ nullable: true,
833
+ brand: ['x', 'y'],
834
+ min: 0,
835
+ } as const satisfies x.Schema
836
+
837
+ const prevStruct = x.number().optional().nullable().min(schema.min)
838
+ const struct = prevStruct.brand('x', 'y')
839
+
840
+ type ExpectedKeys = StructSharedKeys | 'description' | 'max'
841
+
842
+ foldB: {
843
+ const construct = x.makeStruct(schema)
844
+
845
+ /* ensure that struct keys are reduced after application */
846
+
847
+ type StructKeys = keyof typeof struct
848
+
849
+ x.tCh<StructKeys, ExpectedKeys>()
850
+ x.tCh<ExpectedKeys, StructKeys>()
851
+
852
+ type ConstructKeys = keyof typeof construct
853
+
854
+ x.tCh<ConstructKeys, ExpectedKeys>()
855
+ x.tCh<ExpectedKeys, ConstructKeys>()
856
+
857
+ /* ensure that construct/struct schema types are identical */
858
+
859
+ type ExpectedSchema = typeof schema
860
+ type StructSchema = typeof struct.__schema
861
+
862
+ x.tCh<StructSchema, ExpectedSchema>()
863
+ x.tCh<ExpectedSchema, StructSchema>()
864
+
865
+ type ConstructSchema = typeof struct.__schema
866
+
867
+ x.tCh<ConstructSchema, ExpectedSchema>()
868
+ x.tCh<ExpectedSchema, ConstructSchema>()
869
+
870
+ /* runtime schema check */
871
+
872
+ expect(struct.__schema).toStrictEqual(schema)
873
+ expect(construct.__schema).toStrictEqual(schema)
874
+ expect(construct.__schema === schema).toBe(false)
875
+
876
+ /* runtime schema parameter application immutability check */
877
+
878
+ expect(prevStruct.__schema === struct.__schema).toBe(false)
879
+ }
880
+ })
881
+
882
+ it('optional + nullable + brand + min + max', () => {
883
+ const schema = {
884
+ type: 'number',
885
+ optional: true,
886
+ nullable: true,
887
+ brand: ['x', 'y'],
888
+ min: 0,
889
+ max: 0,
890
+ } as const satisfies x.Schema
891
+
892
+ const prevStruct = x
893
+ .number()
894
+ .optional()
895
+ .nullable()
896
+ .min(schema.min)
897
+ .max(schema.max)
898
+
899
+ const struct = prevStruct.brand('x', 'y')
900
+
901
+ type ExpectedKeys = StructSharedKeys | 'description'
902
+
903
+ foldB: {
904
+ const construct = x.makeStruct(schema)
905
+
906
+ /* ensure that struct keys are reduced after application */
907
+
908
+ type StructKeys = keyof typeof struct
909
+
910
+ x.tCh<StructKeys, ExpectedKeys>()
911
+ x.tCh<ExpectedKeys, StructKeys>()
912
+
913
+ type ConstructKeys = keyof typeof construct
914
+
915
+ x.tCh<ConstructKeys, ExpectedKeys>()
916
+ x.tCh<ExpectedKeys, ConstructKeys>()
917
+
918
+ /* ensure that construct/struct schema types are identical */
919
+
920
+ type ExpectedSchema = typeof schema
921
+ type StructSchema = typeof struct.__schema
922
+
923
+ x.tCh<StructSchema, ExpectedSchema>()
924
+ x.tCh<ExpectedSchema, StructSchema>()
925
+
926
+ type ConstructSchema = typeof struct.__schema
927
+
928
+ x.tCh<ConstructSchema, ExpectedSchema>()
929
+ x.tCh<ExpectedSchema, ConstructSchema>()
930
+
931
+ /* runtime schema check */
932
+
933
+ expect(struct.__schema).toStrictEqual(schema)
934
+ expect(construct.__schema).toStrictEqual(schema)
935
+ expect(construct.__schema === schema).toBe(false)
936
+
937
+ /* runtime schema parameter application immutability check */
938
+
939
+ expect(prevStruct.__schema === struct.__schema).toBe(false)
940
+ }
941
+ })
942
+
943
+ it('optional + nullable + brand + min + max + description', () => {
944
+ const schema = {
945
+ type: 'number',
946
+ optional: true,
947
+ nullable: true,
948
+ brand: ['x', 'y'],
949
+ min: 0,
950
+ max: 0,
951
+ description: 'x',
952
+ } as const satisfies x.Schema
953
+
954
+ const prevStruct = x
955
+ .number()
956
+ .optional()
957
+ .nullable()
958
+ .min(schema.min)
959
+ .max(schema.max)
960
+ .description('x')
961
+
962
+ const struct = prevStruct.brand('x', 'y')
963
+
964
+ type ExpectedKeys = StructSharedKeys
965
+
966
+ foldB: {
967
+ const construct = x.makeStruct(schema)
968
+
969
+ /* ensure that struct keys are reduced after application */
970
+
971
+ type StructKeys = keyof typeof struct
972
+
973
+ x.tCh<StructKeys, ExpectedKeys>()
974
+ x.tCh<ExpectedKeys, StructKeys>()
975
+
976
+ type ConstructKeys = keyof typeof construct
977
+
978
+ x.tCh<ConstructKeys, ExpectedKeys>()
979
+ x.tCh<ExpectedKeys, ConstructKeys>()
980
+
981
+ /* ensure that construct/struct schema types are identical */
982
+
983
+ type ExpectedSchema = typeof schema
984
+ type StructSchema = typeof struct.__schema
985
+
986
+ x.tCh<StructSchema, ExpectedSchema>()
987
+ x.tCh<ExpectedSchema, StructSchema>()
988
+
989
+ type ConstructSchema = typeof struct.__schema
990
+
991
+ x.tCh<ConstructSchema, ExpectedSchema>()
992
+ x.tCh<ExpectedSchema, ConstructSchema>()
993
+
994
+ /* runtime schema check */
995
+
996
+ expect(struct.__schema).toStrictEqual(schema)
997
+ expect(construct.__schema).toStrictEqual(schema)
998
+ expect(construct.__schema === schema).toBe(false)
999
+
1000
+ /* runtime schema parameter application immutability check */
1001
+
1002
+ expect(prevStruct.__schema === struct.__schema).toBe(false)
1003
+ }
1004
+ })
1005
+
1006
+ it('description + max + min + brand + nullable + optional', () => {
1007
+ const schema = {
1008
+ type: 'number',
1009
+ optional: true,
1010
+ nullable: true,
1011
+ brand: ['x', 'y'],
1012
+ description: 'x',
1013
+ min: 0,
1014
+ max: 0,
1015
+ } as const satisfies x.Schema
1016
+
1017
+ const prevStruct = x
1018
+ .number()
1019
+ .description('x')
1020
+ .max(schema.max)
1021
+ .min(schema.min)
1022
+ .brand('x', 'y')
1023
+ .nullable()
1024
+
1025
+ const struct = prevStruct.optional()
1026
+
1027
+ type ExpectedKeys = StructSharedKeys
1028
+
1029
+ foldB: {
1030
+ const construct = x.makeStruct(schema)
1031
+
1032
+ /* ensure that struct keys are reduced after application */
1033
+
1034
+ type StructKeys = keyof typeof struct
1035
+
1036
+ x.tCh<StructKeys, ExpectedKeys>()
1037
+ x.tCh<ExpectedKeys, StructKeys>()
1038
+
1039
+ type ConstructKeys = keyof typeof construct
1040
+
1041
+ x.tCh<ConstructKeys, ExpectedKeys>()
1042
+ x.tCh<ExpectedKeys, ConstructKeys>()
1043
+
1044
+ /* ensure that construct/struct schema types are identical */
1045
+
1046
+ type ExpectedSchema = typeof schema
1047
+ type StructSchema = typeof struct.__schema
1048
+
1049
+ x.tCh<StructSchema, ExpectedSchema>()
1050
+ x.tCh<ExpectedSchema, StructSchema>()
1051
+
1052
+ type ConstructSchema = typeof struct.__schema
1053
+
1054
+ x.tCh<ConstructSchema, ExpectedSchema>()
1055
+ x.tCh<ExpectedSchema, ConstructSchema>()
1056
+
1057
+ /* runtime schema check */
1058
+
1059
+ expect(struct.__schema).toStrictEqual(schema)
1060
+ expect(construct.__schema).toStrictEqual(schema)
1061
+ expect(construct.__schema === schema).toBe(false)
1062
+
1063
+ /* runtime schema parameter application immutability check */
1064
+
1065
+ expect(prevStruct.__schema === struct.__schema).toBe(false)
1066
+ }
1067
+ })
1068
+ })
1069
+
1070
+ describe('ERROR_CODE.invalidType (foldC)', () => {
1071
+ it('iterate over fixture.DATA_TYPE', () => {
1072
+ const schema = { type: 'number' } satisfies x.Schema
1073
+ const struct = x.number()
1074
+ const source = fixture.DATA_TYPE
1075
+
1076
+ foldC: {
1077
+ const construct = x.makeStruct(schema)
1078
+
1079
+ for (const [kind, types] of source) {
1080
+ if (kind === schema.type) {
1081
+ continue
1082
+ }
1083
+
1084
+ for (const subject of types) {
1085
+ const expectedError = [
1086
+ {
1087
+ code: x.ERROR_CODE.invalidType,
1088
+ schema: schema,
1089
+ subject: subject,
1090
+ path: [],
1091
+ },
1092
+ ]
1093
+
1094
+ const parsedSchema = x.parse(schema, subject)
1095
+ const parsedConstruct = construct.parse(subject)
1096
+ const parsedStruct = struct.parse(subject)
1097
+
1098
+ expect(parsedSchema.error).toStrictEqual(expectedError)
1099
+ expect(parsedConstruct.error).toStrictEqual(expectedError)
1100
+ expect(parsedStruct.error).toStrictEqual(expectedError)
1101
+
1102
+ const parsedStandard = struct['~standard'].validate(subject)
1103
+
1104
+ if (parsedStandard instanceof Promise) {
1105
+ throw Error('Not expected')
1106
+ }
1107
+
1108
+ expect(parsedStandard.issues).toStrictEqual([
1109
+ { message: x.ERROR_CODE.invalidType, path: [] },
1110
+ ])
1111
+ }
1112
+ }
1113
+ }
1114
+ })
1115
+ })
1116
+
1117
+ describe('ERROR_CODE.invalidRange (foldD)', () => {
1118
+ it('min', () => {
1119
+ const schema = { type: 'number', min: 0 } satisfies x.Schema
1120
+ const struct = x.number().min(schema.min)
1121
+ const subjects = [-1, -2, -3]
1122
+
1123
+ foldD: {
1124
+ const construct = x.makeStruct(schema)
1125
+
1126
+ for (const subject of subjects) {
1127
+ const expectedError = [
1128
+ {
1129
+ code: x.ERROR_CODE.invalidRange,
1130
+ schema: schema,
1131
+ subject: subject,
1132
+ path: [],
1133
+ },
1134
+ ]
1135
+
1136
+ const parsedSchema = x.parse(schema, subject)
1137
+ const parsedConstruct = construct.parse(subject)
1138
+ const parsedStruct = struct.parse(subject)
1139
+
1140
+ expect(parsedSchema.error).toStrictEqual(expectedError)
1141
+ expect(parsedConstruct.error).toStrictEqual(expectedError)
1142
+ expect(parsedStruct.error).toStrictEqual(expectedError)
1143
+
1144
+ const parsedStandard = struct['~standard'].validate(subject)
1145
+
1146
+ if (parsedStandard instanceof Promise) {
1147
+ throw Error('Not expected')
1148
+ }
1149
+
1150
+ expect(parsedStandard.issues).toStrictEqual([
1151
+ { message: x.ERROR_CODE.invalidRange, path: [] },
1152
+ ])
1153
+ }
1154
+ }
1155
+ })
1156
+
1157
+ it('max', () => {
1158
+ const schema = { type: 'number', max: 0 } satisfies x.Schema
1159
+ const struct = x.number().max(schema.max)
1160
+ const subjects = [1, 2, 3]
1161
+
1162
+ foldD: {
1163
+ const construct = x.makeStruct(schema)
1164
+
1165
+ for (const subject of subjects) {
1166
+ const expectedError = [
1167
+ {
1168
+ code: x.ERROR_CODE.invalidRange,
1169
+ schema: schema,
1170
+ subject: subject,
1171
+ path: [],
1172
+ },
1173
+ ]
1174
+
1175
+ const parsedSchema = x.parse(schema, subject)
1176
+ const parsedConstruct = construct.parse(subject)
1177
+ const parsedStruct = struct.parse(subject)
1178
+
1179
+ expect(parsedSchema.error).toStrictEqual(expectedError)
1180
+ expect(parsedConstruct.error).toStrictEqual(expectedError)
1181
+ expect(parsedStruct.error).toStrictEqual(expectedError)
1182
+
1183
+ const parsedStandard = struct['~standard'].validate(subject)
1184
+
1185
+ if (parsedStandard instanceof Promise) {
1186
+ throw Error('Not expected')
1187
+ }
1188
+
1189
+ expect(parsedStandard.issues).toStrictEqual([
1190
+ { message: x.ERROR_CODE.invalidRange, path: [] },
1191
+ ])
1192
+ }
1193
+ }
1194
+ })
1195
+
1196
+ it('min + max', () => {
1197
+ const schema = { type: 'number', min: 0, max: 0 } satisfies x.Schema
1198
+ const struct = x.number().min(schema.min).max(schema.max)
1199
+ const subjects = [-1, 1]
1200
+
1201
+ foldD: {
1202
+ const construct = x.makeStruct(schema)
1203
+
1204
+ for (const subject of subjects) {
1205
+ const expectedError = [
1206
+ {
1207
+ code: x.ERROR_CODE.invalidRange,
1208
+ schema: schema,
1209
+ subject: subject,
1210
+ path: [],
1211
+ },
1212
+ ]
1213
+
1214
+ const parsedSchema = x.parse(schema, subject)
1215
+ const parsedConstruct = construct.parse(subject)
1216
+ const parsedStruct = struct.parse(subject)
1217
+
1218
+ expect(parsedSchema.error).toStrictEqual(expectedError)
1219
+ expect(parsedConstruct.error).toStrictEqual(expectedError)
1220
+ expect(parsedStruct.error).toStrictEqual(expectedError)
1221
+
1222
+ const parsedStandard = struct['~standard'].validate(subject)
1223
+
1224
+ if (parsedStandard instanceof Promise) {
1225
+ throw Error('Not expected')
1226
+ }
1227
+
1228
+ expect(parsedStandard.issues).toStrictEqual([
1229
+ { message: x.ERROR_CODE.invalidRange, path: [] },
1230
+ ])
1231
+ }
1232
+ }
1233
+ })
1234
+ })