1import * as Str from "effect/String"
2import assert from "node:assert/strict"
3import * as z from "zod/v4"
4
5const person = () => z.object({ name: z.string(), age: z.number(), active: z.boolean() })
6const input = { name: "Ada", age: 37, active: true }
7const small = person()
8const nestedSchema = z.object({ user: person(), tags: z.array(z.string()) })
9const arraySchema = z.array(person())
10const arrayInput = Array.from({ length: 32 }, () => ({ ...input }))
11const recordSchema = z.record(z.string(), person())
12const recordInput = Object.fromEntries(arrayInput.map((value, i) => [String(i), value]))
13const transformedKeyRecordSchema = z.record(
14 z.string().overwrite(Str.snakeToCamel),
15 z.string()
16)
17const transformedKeyRecordInput = Object.fromEntries(
18 Array.from({ length: 32 }, (_, i) => [`field_${i}_value`, String(i)])
19)
20const transformedKeyRecordOutput = Object.fromEntries(
21 Array.from({ length: 32 }, (_, i) => [`field${i}Value`, String(i)])
22)
23const unionSchema = z.union(
24 Array.from({ length: 8 }, (_, i) => z.object({ tag: z.literal(i), value: z.number() })) as [
25 z.ZodObject,
26 z.ZodObject,
27 ...Array<z.ZodObject>
28 ]
29)
30const fields = Object.fromEntries(
31 Array.from({ length: 32 }, (_, i) => [`v${i}`, z.string().transform(Number)])
32)
33const transformedSchema = z.object(fields)
34const transformedInput = Object.fromEntries(Array.from({ length: 32 }, (_, i) => [`v${i}`, String(i)]))
35const transformedOutput = Object.fromEntries(Array.from({ length: 32 }, (_, i) => [`v${i}`, i]))
36const checkedTransform = z.string().transform(Number).pipe(z.number().positive())
37const declarationSchema = z.set(person())
38const declarationInput = new Set(arrayInput)
39const defaultsSchema = z.object(
40 Object.fromEntries(Array.from({ length: 32 }, (_, i) => [`v${i}`, z.number().default(i)]))
41)
42
43type Case = {
44 readonly schema: z.ZodType
45 readonly input: unknown
46 readonly expected: unknown
47 readonly operation?: "is" | "make" | "encode"
48 readonly invalid?: boolean
49}
50
51const cases: Record<string, Case> = {
52 parseValid: { schema: small, input, expected: input },
53 parseExtra: { schema: small, input: { ...input, extra: 1 }, expected: input },
54 parseInvalid: { schema: small, input: { ...input, age: "bad" }, expected: true, invalid: true },
55 isValid: { schema: small, input, expected: true, operation: "is" },
56 isInvalid: { schema: small, input: { ...input, age: "bad" }, expected: false, operation: "is" },
57 encode: { schema: small, input, expected: input, operation: "encode" },
58 strict: {
59 schema: z.strictObject({ name: z.string(), age: z.number(), active: z.boolean() }),
60 input,
61 expected: input
62 },
63 nested: {
64 schema: nestedSchema,
65 input: { user: input, tags: ["a", "b"] },
66 expected: { user: input, tags: ["a", "b"] }
67 },
68 array: { schema: arraySchema, input: arrayInput, expected: arrayInput },
69 arrayInvalid: {
70 schema: arraySchema,
71 input: [...arrayInput, { ...input, age: "bad" }],
72 expected: true,
73 invalid: true
74 },
75 record: { schema: recordSchema, input: recordInput, expected: recordInput },
76 recordTransformedKeys: {
77 schema: transformedKeyRecordSchema,
78 input: transformedKeyRecordInput,
79 expected: transformedKeyRecordOutput
80 },
81 union: { schema: unionSchema, input: { tag: 7, value: 1 }, expected: { tag: 7, value: 1 } },
82 transform: { schema: transformedSchema, input: transformedInput, expected: transformedOutput },
83 transformInvalid: { schema: checkedTransform, input: "-1", expected: true, invalid: true },
84 declaration: { schema: declarationSchema, input: declarationInput, expected: declarationInput },
85 makeStruct: { schema: defaultsSchema, input: {}, expected: transformedOutput, operation: "make" },
86 makeArray: { schema: arraySchema, input: arrayInput, expected: arrayInput, operation: "make" },
87 makeUnion: {
88 schema: unionSchema,
89 input: { tag: 7, value: 1 },
90 expected: { tag: 7, value: 1 },
91 operation: "make"
92 }
93}
94
95const makeFixture = (
96 { input, expected, invalid }: Case,
97 parse: (input: unknown) => unknown
98) => {
99 return {
100 run: invalid ?
101 () => {
102 try {
103 parse(input)
104 return false
105 } catch {
106 return true
107 }
108 } :
109 () => parse(input),
110 validate: (result: unknown) => assert.deepEqual(result, expected)
111 }
112}
113
114export const compiledFixture = (name: string) => {
115 const value = cases[name]
116 const schema = z.compile(value.schema, { strict: true })
117 const parse = value.operation === "is" ?
118 (input: unknown) => z.validate(schema, input)
119 : value.operation === "encode" ?
120 (input: unknown) => z.encode(schema, input)
121 : (input: unknown) => schema.parse(input)
122 return makeFixture(value, parse)
123}
124
125export const jitlessFixture = (name: string) => {
126 const value = cases[name]
127 const parse = value.operation === "is" ?
128 (input: unknown) => z.validate(value.schema, input, { jitless: true })
129 : value.operation === "encode" ?
130 (input: unknown) => z.encode(value.schema, input, { jitless: true })
131 : (input: unknown) => value.schema.parse(input, { jitless: true })
132 return makeFixture(value, parse)
133}