Skip to content

Commit 006b3d4

Browse files
committed
fixed issue #19
1 parent f94622e commit 006b3d4

File tree

2 files changed

+119
-12
lines changed

2 files changed

+119
-12
lines changed

src/zod/index.ts

+27-12
Original file line numberDiff line numberDiff line change
@@ -91,50 +91,65 @@ const generateInputObjectFieldYupSchema = (
9191
field: InputValueDefinitionNode,
9292
indentCount: number
9393
): string => {
94-
let gen = generateInputObjectFieldTypeZodSchema(config, tsVisitor, schema, field.type);
95-
if (config.directives && field.directives) {
96-
const formatted = formatDirectiveConfig(config.directives);
97-
gen += buildApi(formatted, field.directives);
98-
}
94+
const gen = generateInputObjectFieldTypeZodSchema(config, tsVisitor, schema, field, field.type);
9995
return indent(`${field.name.value}: ${maybeLazy(field.type, gen)}`, indentCount);
10096
};
10197

10298
const generateInputObjectFieldTypeZodSchema = (
10399
config: ValidationSchemaPluginConfig,
104100
tsVisitor: TsVisitor,
105101
schema: GraphQLSchema,
102+
field: InputValueDefinitionNode,
106103
type: TypeNode,
107104
parentType?: TypeNode
108105
): string => {
109106
if (isListType(type)) {
110-
const gen = generateInputObjectFieldTypeZodSchema(config, tsVisitor, schema, type.type, type);
107+
const gen = generateInputObjectFieldTypeZodSchema(config, tsVisitor, schema, field, type.type, type)
111108
if (!isNonNullType(parentType)) {
112-
return `z.array(${maybeLazy(type.type, gen)}).nullish()`;
109+
const arrayGen = `z.array(${maybeLazy(type.type, gen)})`
110+
const maybeLazyGen = applyDirectives(config,field, arrayGen)
111+
return `${maybeLazyGen}.nullish()`;
113112
}
114113
return `z.array(${maybeLazy(type.type, gen)})`;
115114
}
116115
if (isNonNullType(type)) {
117-
const gen = generateInputObjectFieldTypeZodSchema(config, tsVisitor, schema, type.type, type);
116+
const gen = generateInputObjectFieldTypeZodSchema(config, tsVisitor, schema, field, type.type, type);
118117
return maybeLazy(type.type, gen);
119118
}
120119
if (isNamedType(type)) {
121-
const gen = generateNameNodeZodSchema(config, tsVisitor, schema, type.name);
120+
const gen = generateNameNodeZodSchema(config, tsVisitor, schema, type.name)
121+
if (isListType(parentType)) {
122+
return `${gen}.nullable()`;
123+
}
124+
const appliedDirectivesGen = applyDirectives(config, field, gen)
122125
if (isNonNullType(parentType)) {
123126
if (config.notAllowEmptyString === true) {
124127
const tsType = tsVisitor.scalars[type.name.value];
125128
if (tsType === 'string') return `${gen}.min(1)`;
126129
}
127-
return gen;
130+
return appliedDirectivesGen;
128131
}
129132
if (isListType(parentType)) {
130-
return `${gen}.nullable()`;
133+
return `${appliedDirectivesGen}.nullable()`;
131134
}
132-
return `${gen}.nullish()`;
135+
return `${appliedDirectivesGen}.nullish()`;
133136
}
134137
console.warn('unhandled type:', type);
135138
return '';
136139
};
137140

141+
const applyDirectives = (
142+
config: ValidationSchemaPluginConfig,
143+
field: InputValueDefinitionNode,
144+
gen: string,
145+
): string => {
146+
if (config.directives && field.directives) {
147+
const formatted = formatDirectiveConfig(config.directives);
148+
return gen + buildApi(formatted, field.directives);
149+
}
150+
return gen
151+
}
152+
138153
const generateNameNodeZodSchema = (
139154
config: ValidationSchemaPluginConfig,
140155
tsVisitor: TsVisitor,

tests/zod.spec.ts

+92
Original file line numberDiff line numberDiff line change
@@ -280,4 +280,96 @@ describe('zod', () => {
280280
expect(result.content).toContain(wantContain);
281281
}
282282
});
283+
describe('issues #19', () => {
284+
it('string field', async () => {
285+
const schema = buildSchema(/* GraphQL */ `
286+
input UserCreateInput {
287+
profile: String @constraint(minLength: 1, maxLength: 5000)
288+
}
289+
290+
directive @constraint(minLength: Int!, maxLength: Int!) on INPUT_FIELD_DEFINITION
291+
`);
292+
const result = await plugin(
293+
schema,
294+
[],
295+
{
296+
schema: 'zod',
297+
directives: {
298+
constraint: {
299+
minLength: ['min', "$1", "Please input more than $1"],
300+
maxLength: ['max', "$1", "Please input less than $1"]
301+
}
302+
}
303+
},
304+
{}
305+
);
306+
const wantContains = [
307+
'export function UserCreateInputSchema(): z.ZodObject<Properties<UserCreateInput>>',
308+
'profile: z.string().min(1, \"Please input more than 1\").max(5000, \"Please input less than 5000\").nullish()',
309+
];
310+
for (const wantContain of wantContains) {
311+
expect(result.content).toContain(wantContain);
312+
}
313+
})
314+
it('not null field', async () => {
315+
const schema = buildSchema(/* GraphQL */ `
316+
input UserCreateInput {
317+
profile: String! @constraint(minLength: 1, maxLength: 5000)
318+
}
319+
320+
directive @constraint(minLength: Int!, maxLength: Int!) on INPUT_FIELD_DEFINITION
321+
`);
322+
const result = await plugin(
323+
schema,
324+
[],
325+
{
326+
schema: 'zod',
327+
directives: {
328+
constraint: {
329+
minLength: ['min', "$1", "Please input more than $1"],
330+
maxLength: ['max', "$1", "Please input less than $1"]
331+
}
332+
}
333+
},
334+
{}
335+
);
336+
const wantContains = [
337+
'export function UserCreateInputSchema(): z.ZodObject<Properties<UserCreateInput>>',
338+
'profile: z.string().min(1, \"Please input more than 1\").max(5000, \"Please input less than 5000\")',
339+
];
340+
for (const wantContain of wantContains) {
341+
expect(result.content).toContain(wantContain);
342+
}
343+
})
344+
it('list field', async () => {
345+
const schema = buildSchema(/* GraphQL */ `
346+
input UserCreateInput {
347+
profile: [String] @constraint(minLength: 1, maxLength: 5000)
348+
}
349+
350+
directive @constraint(minLength: Int!, maxLength: Int!) on INPUT_FIELD_DEFINITION
351+
`);
352+
const result = await plugin(
353+
schema,
354+
[],
355+
{
356+
schema: 'zod',
357+
directives: {
358+
constraint: {
359+
minLength: ['min', "$1", "Please input more than $1"],
360+
maxLength: ['max', "$1", "Please input less than $1"]
361+
}
362+
}
363+
},
364+
{}
365+
);
366+
const wantContains = [
367+
'export function UserCreateInputSchema(): z.ZodObject<Properties<UserCreateInput>>',
368+
'profile: z.array(z.string().nullable()).min(1, "Please input more than 1").max(5000, "Please input less than 5000").nullish()',
369+
];
370+
for (const wantContain of wantContains) {
371+
expect(result.content).toContain(wantContain);
372+
}
373+
})
374+
});
283375
});

0 commit comments

Comments
 (0)