1import assert from "node:assert/strict"
2import * as z from "zod/v4"
3import { invalidData, validData, validDataWithExtras } from "./data.ts"
4
5const makeShape = () => ({
6 number: z.number(),
7 negNumber: z.number(),
8 maxNumber: z.number(),
9 string: z.string(),
10 longString: z.string(),
11 boolean: z.boolean(),
12 deeplyNested: z.object({
13 foo: z.string(),
14 num: z.number(),
15 bool: z.boolean()
16 })
17})
18
19const makeParseSchema = () => z.object(makeShape())
20const makeGuardSchema = () => {
21 const shape = makeShape()
22 return z.object({ ...shape, deeplyNested: shape.deeplyNested.passthrough() }).passthrough()
23}
24
25const parseCase = (
26 compile: (schema: ReturnType<typeof makeParseSchema>) => (input: unknown) => unknown,
27 input: unknown,
28 invalid = false
29) =>
30() => {
31 const parse = compile(makeParseSchema())
32 return {
33 run: invalid
34 ? () => {
35 try {
36 parse(input)
37 return false
38 } catch {
39 return true
40 }
41 }
42 : () => parse(input),
43 validate: invalid
44 ? (result: unknown) => assert.equal(result, true)
45 : (result: unknown) => assert.deepEqual(result, validData)
46 }
47}
48
49const guardCase = (
50 compile: (schema: ReturnType<typeof makeGuardSchema>) => (input: unknown) => boolean,
51 input: unknown,
52 expected: boolean
53) =>
54() => {
55 const validate = compile(makeGuardSchema())
56 return {
57 run: expected
58 ? () => {
59 if (!validate(input)) throw new Error("Invalid")
60 return true
61 }
62 : () => validate(input),
63 validate: (result: unknown) => assert.equal(result, expected)
64 }
65}
66
67const assertParseCase = (
68 compile: (schema: ReturnType<typeof makeGuardSchema>) => (input: unknown) => unknown,
69 input: unknown
70) =>
71() => {
72 const parse = compile(makeGuardSchema())
73 return {
74 run: () => {
75 parse(input)
76 return true
77 },
78 validate: (result: unknown) => assert.equal(result, true)
79 }
80}
81
82const parse = (schema: ReturnType<typeof makeParseSchema>) => (input: unknown) => schema.parse(input)
83const parseJitless = (schema: ReturnType<typeof makeParseSchema>) => (input: unknown) =>
84 schema.parse(input, { jitless: true })
85const parseCompiled = (schema: ReturnType<typeof makeParseSchema>) => {
86 const compiled = z.compile(schema, { strict: true })
87 return (input: unknown) => compiled.parse(input)
88}
89const validate = (schema: ReturnType<typeof makeGuardSchema>) => (input: unknown) => z.validate(schema, input)
90const validateJitless = (schema: ReturnType<typeof makeGuardSchema>) => (input: unknown) =>
91 z.validate(schema, input, { jitless: true })
92const validateCompiled = (schema: ReturnType<typeof makeGuardSchema>) => {
93 const compiled = z.compile(schema, { strict: true })
94 return (input: unknown) => z.validate(compiled, input)
95}
96const assertParse = (schema: ReturnType<typeof makeGuardSchema>) => (input: unknown) => schema.parse(input)
97
98export const parseValid = parseCase(parse, validData)
99export const parseExtraValid = parseCase(parse, validDataWithExtras)
100export const parseInvalid = parseCase(parse, invalidData, true)
101export const parseJitlessValid = parseCase(parseJitless, validData)
102export const parseJitlessExtraValid = parseCase(parseJitless, validDataWithExtras)
103export const parseJitlessInvalid = parseCase(parseJitless, invalidData, true)
104export const parseCompiledValid = parseCase(parseCompiled, validData)
105export const parseCompiledExtraValid = parseCase(parseCompiled, validDataWithExtras)
106export const parseCompiledInvalid = parseCase(parseCompiled, invalidData, true)
107export const isValid = guardCase(validate, validData, true)
108export const isExtraValid = guardCase(validate, validDataWithExtras, true)
109export const isInvalid = guardCase(validate, invalidData, false)
110export const isJitlessValid = guardCase(validateJitless, validData, true)
111export const isJitlessExtraValid = guardCase(validateJitless, validDataWithExtras, true)
112export const isJitlessInvalid = guardCase(validateJitless, invalidData, false)
113export const isCompiledValid = guardCase(validateCompiled, validData, true)
114export const isCompiledExtraValid = guardCase(validateCompiled, validDataWithExtras, true)
115export const isCompiledInvalid = guardCase(validateCompiled, invalidData, false)
116export const assertParseValid = assertParseCase(assertParse, validData)
117export const assertParseExtraValid = assertParseCase(assertParse, validDataWithExtras)