Skip to content

Commit 8709b69

Browse files
committed
Support for Zod 4
1 parent 694e6e8 commit 8709b69

File tree

14 files changed

+3123
-7
lines changed

14 files changed

+3123
-7
lines changed

README.md

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
- [x] support [yup](https://github.com/jquense/yup)
88
- [x] support [zod](https://github.com/colinhacks/zod)
9+
- [x] support [zod v4](https://github.com/colinhacks/zod) (zodv4)
910
- [x] support [myzod](https://github.com/davidmdm/myzod)
1011
- [x] support [valibot](https://valibot.dev/)
1112

@@ -49,7 +50,7 @@ type: `ValidationSchema` default: `'yup'`
4950

5051
Specify generete validation schema you want.
5152

52-
You can specify `yup` or `zod` or `myzod`.
53+
You can specify `yup` or `zod` or `zodv4` or `myzod` or `valibot`.
5354

5455
```yml
5556
generates:
@@ -61,6 +62,26 @@ generates:
6162
schema: yup
6263
```
6364

65+
### `zodImportPath`
66+
67+
type: `string` default: `'zod'`
68+
69+
Specifies a custom import path for the zod package. This is useful when you want to use a specific
70+
version or subpath of zod, such as the v3 compatibility layer in zod v4 ('zod/v3').
71+
Only applies when schema is set to 'zod'.
72+
73+
```yml
74+
generates:
75+
path/to/schemas.ts:
76+
plugins:
77+
- typescript
78+
- typescript-validation-schema
79+
config:
80+
schema: zod
81+
# Use zod v3 compatibility layer when using zod v4
82+
zodImportPath: zod/v3
83+
```
84+
6485
### `importFrom`
6586

6687
type: `string`
@@ -215,6 +236,16 @@ config:
215236
Email: z.string().email()
216237
```
217238

239+
#### zodv4 schema
240+
241+
```yml
242+
config:
243+
schema: zodv4
244+
scalarSchemas:
245+
Date: z.date()
246+
Email: z.string().email()
247+
```
248+
218249
### `defaultScalarTypeSchema`
219250

220251
type: `string`
@@ -235,6 +266,13 @@ config:
235266
defaultScalarSchema: z.unknown()
236267
```
237268

269+
#### zodv4 schema
270+
```yml
271+
config:
272+
schema: zodv4
273+
defaultScalarSchema: z.unknown()
274+
```
275+
238276
### `withObjectType`
239277

240278
type: `boolean` default: `false`
@@ -360,6 +398,38 @@ export function ExampleInputSchema(): z.ZodSchema<ExampleInput> {
360398
}
361399
```
362400

401+
#### zodv4 schema
402+
403+
```yml
404+
generates:
405+
path/to/graphql.ts:
406+
plugins:
407+
- typescript
408+
- typescript-validation-schema
409+
config:
410+
schema: zodv4
411+
directives:
412+
constraint:
413+
minLength: min
414+
# Replace $1 with specified `startsWith` argument value of the constraint directive
415+
startsWith: [regex, /^$1/, message]
416+
format:
417+
# This example means `validation-schema: directive-arg`
418+
# directive-arg is supported String and Enum.
419+
email: email
420+
```
421+
422+
Then generates zodv4 validation schema like below.
423+
424+
```ts
425+
export function ExampleInputSchema(): z.ZodObject<Properties<ExampleInput>> {
426+
return z.object({
427+
email: z.string().min(50).email(),
428+
message: z.string().regex(/^Hello/, 'message')
429+
})
430+
}
431+
```
432+
363433
#### other schema
364434

365435
Please see [example](https://github.com/Code-Hex/graphql-codegen-typescript-validation-schema/tree/main/example) directory.

codegen.yml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,30 @@ generates:
4747
plugins:
4848
- ./dist/cjs/index.js:
4949
schema: zod
50+
zodImportPath: zod/v3
51+
importFrom: ../types
52+
withObjectType: true
53+
directives:
54+
# Write directives like
55+
#
56+
# directive:
57+
# arg1: schemaApi
58+
# arg2: ["schemaApi2", "Hello $1"]
59+
#
60+
# See more examples in `./tests/directive.spec.ts`
61+
# https://github.com/Code-Hex/graphql-codegen-typescript-validation-schema/blob/main/tests/directive.spec.ts
62+
constraint:
63+
minLength: min
64+
# Replace $1 with specified `startsWith` argument value of the constraint directive
65+
startsWith: [regex, /^$1/, message]
66+
format:
67+
email: email
68+
scalars:
69+
ID: string
70+
example/zodv4/schemas.ts:
71+
plugins:
72+
- ./dist/cjs/index.js:
73+
schema: zodv4
5074
importFrom: ../types
5175
withObjectType: true
5276
directives:

example/zod/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
## How to overwrite generated schema?
44

5-
You can use zod [extend API](https://github.com/colinhacks/zod#extend).
5+
You can use zod [extend API](https://v3.zod.dev/?id=extend).
66

77
```ts
88
const AttributeInputSchemaWithCUID = AttributeInputSchema().extend({

example/zod/schemas.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { z } from 'zod'
1+
import { z } from 'zod/v3'
22
import { Admin, AttributeInput, ButtonComponentType, ComponentInput, DropDownComponentInput, EventArgumentInput, EventInput, EventOptionType, Guest, HttpInput, HttpMethod, LayoutInput, MyType, MyTypeFooArgs, Namer, PageInput, PageType, User } from '../types'
33

44
type Properties<T> = Required<{

example/zodv4/README.md

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
# Tips for zod v4 schema
2+
3+
## Overview
4+
5+
The `zodv4` schema type is designed to work with Zod v4, which introduces significant changes to the type system and API. This implementation uses the updated type definitions and APIs that are compatible with Zod v4.
6+
7+
## Key Differences from Zod v3
8+
9+
### Type System Changes
10+
11+
Zod v4 introduces changes to the `ZodType` generic parameters:
12+
13+
```ts
14+
// Zod v3
15+
z.ZodType<Output, Def extends z.ZodTypeDef, Input = Output>
16+
17+
// Zod v4
18+
z.ZodType<Output = unknown, Input = unknown>
19+
```
20+
21+
The `Properties` type definition has been updated accordingly:
22+
23+
```ts
24+
// Updated for Zod v4
25+
type Properties<T> = Required<{
26+
[K in keyof T]: z.ZodType<T[K]>;
27+
}>;
28+
```
29+
30+
### Enum Handling
31+
32+
Zod v4 changes how enums are handled:
33+
34+
```ts
35+
// Zod v3
36+
z.nativeEnum(ButtonComponentType)
37+
38+
// Zod v4
39+
z.enum(ButtonComponentType)
40+
```
41+
42+
## How to overwrite generated schema?
43+
44+
You can use zod [extend API](https://zod.dev/api#extend), same as with Zod v3:
45+
46+
```ts
47+
const AttributeInputSchemaWithCUID = AttributeInputSchema().extend({
48+
key: z.string().cuid(),
49+
});
50+
```
51+
52+
## Apply input validator via ts decorator
53+
54+
Validate the input object via typescript decorators when implementing resolvers. The implementation is compatible with Zod v4's type system:
55+
56+
### Usage
57+
58+
```ts
59+
class Mutation {
60+
@validateInput(SignupInputSchema)
61+
async signup(
62+
_root: Record<string, never>,
63+
{ input: { email, password } }: MutationSignupArgs,
64+
context: Context
65+
): Promise<SignupPayload> {
66+
// The input here is automatically valid to adhere to SignupInputSchema
67+
}
68+
}
69+
```
70+
71+
### Implementation:
72+
73+
```ts
74+
type ZodResolver<T extends ZodType<any, any>> = ResolverFn<
75+
any,
76+
any,
77+
any,
78+
{ input: TypeOf<T> }
79+
>
80+
81+
/**
82+
* Method decorator that validates the argument of the target function against the given schema.
83+
* Updated for Zod v4 type system.
84+
*
85+
* @export
86+
* @template T The type of the zod schema.
87+
* @param {T} arg The zod schema used for the validation.
88+
* @return {MethodDecorator} A {@link MethodDecorator}.
89+
*/
90+
export function validateInput<T extends AnyZodObject>(
91+
arg: T | (() => T)
92+
): MethodDecorator<ZodResolver<T>> {
93+
return function (_target, _propertyKey, descriptor) {
94+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
95+
const originalMethod = descriptor.value!
96+
// @ts-expect-error: should be fine
97+
descriptor.value = function (root, { input }, context, info) {
98+
const schema = typeof arg === 'function' ? arg() : arg
99+
const result = schema.safeParse(input)
100+
101+
if (result.success) {
102+
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
103+
return originalMethod.call(
104+
this,
105+
root,
106+
{ input: result.data },
107+
context,
108+
info
109+
)
110+
} else {
111+
return { problems: result.error.issues }
112+
}
113+
}
114+
return descriptor
115+
}
116+
}
117+
```
118+
119+
## Migration from Zod v3
120+
121+
If you're migrating from Zod v3 to v4, consider the following:
122+
123+
### 1. Using Zod v4 with v3 compatibility layer
124+
125+
You can use the `zodImportPath` option to import from Zod v4's v3 compatibility layer:
126+
127+
```yml
128+
generates:
129+
path/to/schemas.ts:
130+
plugins:
131+
- graphql-codegen-validation-schema
132+
config:
133+
schema: zod
134+
zodImportPath: zod/v3 # Use v3 compatibility layer
135+
```
136+
137+
### 2. Using zodv4 schema type
138+
139+
Alternatively, use the `zodv4` schema type for full Zod v4 compatibility:
140+
141+
```yml
142+
generates:
143+
path/to/schemas.ts:
144+
plugins:
145+
- graphql-codegen-validation-schema
146+
config:
147+
schema: zodv4 # Use zodv4 schema type
148+
```
149+
150+
## Performance and Type Safety
151+
152+
Zod v4 provides improvements in:
153+
154+
1. **Stricter Type Checking**: Enhanced type safety with simplified generic parameters
155+
2. **Better API Design**: More intuitive and consistent API
156+
3. **Internal Optimizations**: Performance improvements in validation logic
157+
158+
These changes result in more reliable and maintainable validation code.

0 commit comments

Comments
 (0)