Skip to content

Commit c29326f

Browse files
committed
refactor: finalize conversion to Zod v4
BREAKING CHANGE: All Zod helpers now use v4
1 parent 8640897 commit c29326f

File tree

4 files changed

+212
-258
lines changed

4 files changed

+212
-258
lines changed

src/__tests__/zod.test.ts

Lines changed: 124 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,134 @@
1-
import * as module from 'node:module';
1+
/* eslint-disable @typescript-eslint/no-require-imports */
2+
import { describe, expect, expectTypeOf, it, test } from 'vitest';
3+
import { z as z3 } from 'zod/v3';
4+
import { z as z4 } from 'zod/v4';
25

3-
import { describe, expect, it } from 'vitest';
4-
import { z } from 'zod';
6+
import { $BooleanLike, $NumberLike, $Uint8ArrayLike, $UrlLike, isZodType, isZodTypeLike, safeParse } from '../zod.js';
57

6-
import { $BooleanLike, $NumberLike, $Uint8ArrayLike, $UrlLike, isZodType, safeParse } from '../zod.js';
8+
import type {
9+
ZodErrorLike,
10+
ZodIssueLike,
11+
ZodSafeParseErrorLike,
12+
ZodSafeParseResultLike,
13+
ZodSafeParseSuccessLike,
14+
ZodTypeLike
15+
} from '../zod.js';
716

8-
const require = module.createRequire(import.meta.url);
17+
test('ZodIssueLike', () => {
18+
expectTypeOf<z3.ZodIssue>().toMatchTypeOf<ZodIssueLike>();
19+
expectTypeOf<z4.core.$ZodIssue>().toMatchTypeOf<ZodIssueLike>();
20+
});
921

10-
/** since we use require here, the prototype chain in the cjs module will be different than the esm build */
11-
const { z: zCJS } = require('zod') as typeof import('zod');
22+
test('ZodErrorLike', () => {
23+
expectTypeOf<z3.ZodError>().toMatchTypeOf<ZodErrorLike>();
24+
expectTypeOf<z4.core.$ZodError>().toMatchTypeOf<ZodErrorLike>();
25+
});
1226

13-
describe('isZodType', () => {
14-
it('should return true for an instance of ZodNumber', () => {
15-
expect(isZodType(z.number())).toBe(true);
27+
test('ZodSafeParseSuccessLike', () => {
28+
expectTypeOf<z3.SafeParseSuccess<number>>().toMatchTypeOf<ZodSafeParseSuccessLike<number>>();
29+
expectTypeOf<z4.ZodSafeParseSuccess<number>>().toMatchTypeOf<ZodSafeParseSuccessLike<number>>();
30+
});
31+
32+
test('ZodSafeParseErrorLike', () => {
33+
expectTypeOf<z3.SafeParseError<number>>().toMatchTypeOf<ZodSafeParseErrorLike>();
34+
expectTypeOf<z4.ZodSafeParseError<number>>().toMatchTypeOf<ZodSafeParseErrorLike>();
35+
});
36+
37+
test('ZodSafeParseResultLike', () => {
38+
expectTypeOf<z3.SafeParseReturnType<number, number>>().toMatchTypeOf<ZodSafeParseResultLike<number>>();
39+
expectTypeOf<z4.ZodSafeParseResult<number>>().toMatchTypeOf<ZodSafeParseResultLike<number>>();
40+
});
41+
42+
test('ZodTypeLike', () => {
43+
expectTypeOf<z3.ZodTypeAny>().toMatchTypeOf<ZodTypeLike<any>>();
44+
expectTypeOf<z3.ZodTypeAny>().toMatchTypeOf<ZodTypeLike<unknown>>();
45+
expectTypeOf<z3.ZodNumber>().toMatchTypeOf<ZodTypeLike<unknown>>();
46+
expectTypeOf<z3.ZodNumber>().toMatchTypeOf<ZodTypeLike<number>>();
47+
expectTypeOf<z3.ZodNumber>().not.toMatchTypeOf<ZodTypeLike<string>>();
48+
expectTypeOf<z4.ZodType>().toMatchTypeOf<ZodTypeLike<any>>();
49+
expectTypeOf<z4.ZodType>().toMatchTypeOf<ZodTypeLike<unknown>>();
50+
expectTypeOf<z4.ZodNumber>().toMatchTypeOf<ZodTypeLike<unknown>>();
51+
expectTypeOf<z4.ZodNumber>().toMatchTypeOf<ZodTypeLike<number>>();
52+
expectTypeOf<z4.ZodNumber>().not.toMatchTypeOf<ZodTypeLike<string>>();
53+
});
54+
55+
describe('isZodTypeLike', () => {
56+
it('should return true for Zod v3 types', () => {
57+
expect(isZodTypeLike(z3.object({}))).toBe(true);
58+
expect(isZodTypeLike(z3.number())).toBe(true);
59+
expect(isZodTypeLike(z3.any())).toBe(true);
1660
});
17-
it('should return true for an instance of ZodObject', () => {
18-
expect(isZodType(z.object({}))).toBe(true);
61+
it('should return true for Zod v4 types', () => {
62+
expect(isZodTypeLike(z4.object({}))).toBe(true);
63+
expect(isZodTypeLike(z4.number())).toBe(true);
64+
expect(isZodTypeLike(z4.any())).toBe(true);
1965
});
20-
it('should return false for null', () => {
21-
expect(isZodType(null)).toBe(false);
66+
it('should return false for an object without a standard schema', () => {
67+
expect(isZodTypeLike({})).toBe(false);
2268
});
23-
it('should return false for any empty object', () => {
24-
expect(isZodType({})).toBe(false);
69+
it('should return false for an object with a standard schema, but the incorrect vendor name', () => {
70+
expect(isZodTypeLike({ '~standard': { vendor: 'DNP' } })).toBe(false);
2571
});
26-
it('should return false for an object with a null prototype', () => {
27-
expect(isZodType(Object.create(null))).toBe(false);
72+
});
73+
74+
describe('isZodType', () => {
75+
describe('v3', () => {
76+
// since we use require here, the prototype chain in the cjs module will be different than the esm build
77+
const { z: z3_2 } = require('zod/v3') as typeof import('zod/v3');
78+
79+
it('should return true for an instance of ZodNumber', () => {
80+
expect(isZodType(z3.number(), { version: 3 })).toBe(true);
81+
});
82+
it('should return true for an instance of ZodObject', () => {
83+
expect(isZodType(z3.object({}), { version: 3 })).toBe(true);
84+
});
85+
it('should return false for null', () => {
86+
expect(isZodType(null, { version: 3 })).toBe(false);
87+
});
88+
it('should return false for any empty object', () => {
89+
expect(isZodType({}, { version: 3 })).toBe(false);
90+
});
91+
it('should return false for an object with a null prototype', () => {
92+
expect(isZodType(Object.create(null), { version: 3 })).toBe(false);
93+
});
94+
it('should return false for a Zod v4 object', () => {
95+
expect(isZodType(z4.object({}), { version: 3 })).toBe(false);
96+
});
97+
it('should return true for a ZodObject created in a different context', () => {
98+
const input = z3_2.object({});
99+
expect(input).not.toBeInstanceOf(z3.ZodType);
100+
expect(isZodType(input, { version: 3 })).toBe(true);
101+
});
28102
});
29-
it('should return true for a ZodObject created in a different context', () => {
30-
const input = zCJS.object({});
31-
expect(input).not.toBeInstanceOf(z.ZodType);
32-
expect(isZodType(input)).toBe(true);
103+
describe('v4', () => {
104+
it('should return true for an instance of ZodNumber', () => {
105+
expect(isZodType(z4.number(), { version: 4 })).toBe(true);
106+
});
107+
it('should return true for an instance of ZodObject', () => {
108+
expect(isZodType(z4.object({}), { version: 4 })).toBe(true);
109+
});
110+
it('should return false for null', () => {
111+
expect(isZodType(null, { version: 4 })).toBe(false);
112+
});
113+
it('should return false for any empty object', () => {
114+
expect(isZodType({}, { version: 4 })).toBe(false);
115+
});
116+
it('should return false for a Zod v3 object', () => {
117+
expect(isZodType(z3.object({}), { version: 4 })).toBe(false);
118+
});
119+
it('should return true for a ZodObject created in a different context', () => {
120+
const base = z4.object({});
121+
const input = {
122+
_zod: {
123+
version: structuredClone(base._zod.version)
124+
},
125+
'~standard': {
126+
vendor: base['~standard'].vendor
127+
}
128+
};
129+
expect(input).not.toBeInstanceOf(z4.ZodType);
130+
expect(isZodType(input, { version: 4 })).toBe(true);
131+
});
33132
});
34133
});
35134

@@ -66,7 +165,7 @@ describe('$NumberLike', () => {
66165
expect($NumberLike.safeParse('').success).toBe(false);
67166
});
68167
it('should allow restricting the number through a pipe', () => {
69-
const $IntLike = $NumberLike.pipe(z.number().int());
168+
const $IntLike = $NumberLike.pipe(z4.number().int());
70169
expect($IntLike.safeParse('1.1').success).toBe(false);
71170
expect($IntLike.safeParse('1').data).toBe(1);
72171
});
@@ -118,7 +217,7 @@ describe('$Uint8ArrayLike', () => {
118217
});
119218

120219
describe('safeParse', () => {
121-
const $Schema = z.object({ foo: z.enum(['1', '2']).transform(Number) });
220+
const $Schema = z4.object({ foo: z4.enum(['1', '2']).transform(Number) });
122221
it('should return an Ok result with the parsed data if successful', () => {
123222
const result = safeParse({ foo: '1' }, $Schema);
124223
expect(result.isOk() && result.value).toStrictEqual({ foo: 1 });
@@ -132,7 +231,7 @@ describe('safeParse', () => {
132231
},
133232
issues: [
134233
expect.objectContaining({
135-
code: z.ZodIssueCode.invalid_enum_value,
234+
code: 'invalid_value',
136235
path: ['foo']
137236
})
138237
]

src/__tests__/zod4.test.ts

Lines changed: 0 additions & 133 deletions
This file was deleted.

0 commit comments

Comments
 (0)