From 006b3d4893262fdba739d6a133573e0e38f10075 Mon Sep 17 00:00:00 2001 From: Kei Kamikawa <code-hex@users.noreply.github.com> Date: Sun, 27 Mar 2022 13:29:10 +0900 Subject: [PATCH 1/3] fixed issue #19 --- src/zod/index.ts | 39 +++++++++++++------- tests/zod.spec.ts | 92 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+), 12 deletions(-) diff --git a/src/zod/index.ts b/src/zod/index.ts index 1e1d030f..6a5578c5 100644 --- a/src/zod/index.ts +++ b/src/zod/index.ts @@ -91,11 +91,7 @@ const generateInputObjectFieldYupSchema = ( field: InputValueDefinitionNode, indentCount: number ): string => { - let gen = generateInputObjectFieldTypeZodSchema(config, tsVisitor, schema, field.type); - if (config.directives && field.directives) { - const formatted = formatDirectiveConfig(config.directives); - gen += buildApi(formatted, field.directives); - } + const gen = generateInputObjectFieldTypeZodSchema(config, tsVisitor, schema, field, field.type); return indent(`${field.name.value}: ${maybeLazy(field.type, gen)}`, indentCount); }; @@ -103,38 +99,57 @@ const generateInputObjectFieldTypeZodSchema = ( config: ValidationSchemaPluginConfig, tsVisitor: TsVisitor, schema: GraphQLSchema, + field: InputValueDefinitionNode, type: TypeNode, parentType?: TypeNode ): string => { if (isListType(type)) { - const gen = generateInputObjectFieldTypeZodSchema(config, tsVisitor, schema, type.type, type); + const gen = generateInputObjectFieldTypeZodSchema(config, tsVisitor, schema, field, type.type, type) if (!isNonNullType(parentType)) { - return `z.array(${maybeLazy(type.type, gen)}).nullish()`; + const arrayGen = `z.array(${maybeLazy(type.type, gen)})` + const maybeLazyGen = applyDirectives(config,field, arrayGen) + return `${maybeLazyGen}.nullish()`; } return `z.array(${maybeLazy(type.type, gen)})`; } if (isNonNullType(type)) { - const gen = generateInputObjectFieldTypeZodSchema(config, tsVisitor, schema, type.type, type); + const gen = generateInputObjectFieldTypeZodSchema(config, tsVisitor, schema, field, type.type, type); return maybeLazy(type.type, gen); } if (isNamedType(type)) { - const gen = generateNameNodeZodSchema(config, tsVisitor, schema, type.name); + const gen = generateNameNodeZodSchema(config, tsVisitor, schema, type.name) + if (isListType(parentType)) { + return `${gen}.nullable()`; + } + const appliedDirectivesGen = applyDirectives(config, field, gen) if (isNonNullType(parentType)) { if (config.notAllowEmptyString === true) { const tsType = tsVisitor.scalars[type.name.value]; if (tsType === 'string') return `${gen}.min(1)`; } - return gen; + return appliedDirectivesGen; } if (isListType(parentType)) { - return `${gen}.nullable()`; + return `${appliedDirectivesGen}.nullable()`; } - return `${gen}.nullish()`; + return `${appliedDirectivesGen}.nullish()`; } console.warn('unhandled type:', type); return ''; }; +const applyDirectives = ( + config: ValidationSchemaPluginConfig, + field: InputValueDefinitionNode, + gen: string, +): string => { + if (config.directives && field.directives) { + const formatted = formatDirectiveConfig(config.directives); + return gen + buildApi(formatted, field.directives); + } + return gen +} + const generateNameNodeZodSchema = ( config: ValidationSchemaPluginConfig, tsVisitor: TsVisitor, diff --git a/tests/zod.spec.ts b/tests/zod.spec.ts index ba21e604..ab6aceb1 100644 --- a/tests/zod.spec.ts +++ b/tests/zod.spec.ts @@ -280,4 +280,96 @@ describe('zod', () => { expect(result.content).toContain(wantContain); } }); + describe('issues #19', () => { + it('string field', async () => { + const schema = buildSchema(/* GraphQL */ ` + input UserCreateInput { + profile: String @constraint(minLength: 1, maxLength: 5000) + } + + directive @constraint(minLength: Int!, maxLength: Int!) on INPUT_FIELD_DEFINITION + `); + const result = await plugin( + schema, + [], + { + schema: 'zod', + directives: { + constraint: { + minLength: ['min', "$1", "Please input more than $1"], + maxLength: ['max', "$1", "Please input less than $1"] + } + } + }, + {} + ); + const wantContains = [ + 'export function UserCreateInputSchema(): z.ZodObject<Properties<UserCreateInput>>', + 'profile: z.string().min(1, \"Please input more than 1\").max(5000, \"Please input less than 5000\").nullish()', + ]; + for (const wantContain of wantContains) { + expect(result.content).toContain(wantContain); + } + }) + it('not null field', async () => { + const schema = buildSchema(/* GraphQL */ ` + input UserCreateInput { + profile: String! @constraint(minLength: 1, maxLength: 5000) + } + + directive @constraint(minLength: Int!, maxLength: Int!) on INPUT_FIELD_DEFINITION + `); + const result = await plugin( + schema, + [], + { + schema: 'zod', + directives: { + constraint: { + minLength: ['min', "$1", "Please input more than $1"], + maxLength: ['max', "$1", "Please input less than $1"] + } + } + }, + {} + ); + const wantContains = [ + 'export function UserCreateInputSchema(): z.ZodObject<Properties<UserCreateInput>>', + 'profile: z.string().min(1, \"Please input more than 1\").max(5000, \"Please input less than 5000\")', + ]; + for (const wantContain of wantContains) { + expect(result.content).toContain(wantContain); + } + }) + it('list field', async () => { + const schema = buildSchema(/* GraphQL */ ` + input UserCreateInput { + profile: [String] @constraint(minLength: 1, maxLength: 5000) + } + + directive @constraint(minLength: Int!, maxLength: Int!) on INPUT_FIELD_DEFINITION + `); + const result = await plugin( + schema, + [], + { + schema: 'zod', + directives: { + constraint: { + minLength: ['min', "$1", "Please input more than $1"], + maxLength: ['max', "$1", "Please input less than $1"] + } + } + }, + {} + ); + const wantContains = [ + 'export function UserCreateInputSchema(): z.ZodObject<Properties<UserCreateInput>>', + 'profile: z.array(z.string().nullable()).min(1, "Please input more than 1").max(5000, "Please input less than 5000").nullish()', + ]; + for (const wantContain of wantContains) { + expect(result.content).toContain(wantContain); + } + }) + }); }); From cd09334e368b526a81cf12bce4862cd6c1d87372 Mon Sep 17 00:00:00 2001 From: Kei Kamikawa <code-hex@users.noreply.github.com> Date: Sun, 27 Mar 2022 13:31:20 +0900 Subject: [PATCH 2/3] removed unnecessary escapes --- tests/zod.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/zod.spec.ts b/tests/zod.spec.ts index ab6aceb1..8bd31895 100644 --- a/tests/zod.spec.ts +++ b/tests/zod.spec.ts @@ -305,7 +305,7 @@ describe('zod', () => { ); const wantContains = [ 'export function UserCreateInputSchema(): z.ZodObject<Properties<UserCreateInput>>', - 'profile: z.string().min(1, \"Please input more than 1\").max(5000, \"Please input less than 5000\").nullish()', + 'profile: z.string().min(1, "Please input more than 1").max(5000, "Please input less than 5000").nullish()', ]; for (const wantContain of wantContains) { expect(result.content).toContain(wantContain); @@ -335,7 +335,7 @@ describe('zod', () => { ); const wantContains = [ 'export function UserCreateInputSchema(): z.ZodObject<Properties<UserCreateInput>>', - 'profile: z.string().min(1, \"Please input more than 1\").max(5000, \"Please input less than 5000\")', + 'profile: z.string().min(1, "Please input more than 1").max(5000, "Please input less than 5000")', ]; for (const wantContain of wantContains) { expect(result.content).toContain(wantContain); From ca445a515c80e3f182b90b8c89d4a944404e9ba6 Mon Sep 17 00:00:00 2001 From: Code-Hex <Code-Hex@users.noreply.github.com> Date: Sun, 27 Mar 2022 04:31:50 +0000 Subject: [PATCH 3/3] Apply auto lint-fix changes --- src/zod/index.ts | 16 ++++++++-------- tests/zod.spec.ts | 30 +++++++++++++++--------------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/zod/index.ts b/src/zod/index.ts index 6a5578c5..21b90747 100644 --- a/src/zod/index.ts +++ b/src/zod/index.ts @@ -104,10 +104,10 @@ const generateInputObjectFieldTypeZodSchema = ( parentType?: TypeNode ): string => { if (isListType(type)) { - const gen = generateInputObjectFieldTypeZodSchema(config, tsVisitor, schema, field, type.type, type) + const gen = generateInputObjectFieldTypeZodSchema(config, tsVisitor, schema, field, type.type, type); if (!isNonNullType(parentType)) { - const arrayGen = `z.array(${maybeLazy(type.type, gen)})` - const maybeLazyGen = applyDirectives(config,field, arrayGen) + const arrayGen = `z.array(${maybeLazy(type.type, gen)})`; + const maybeLazyGen = applyDirectives(config, field, arrayGen); return `${maybeLazyGen}.nullish()`; } return `z.array(${maybeLazy(type.type, gen)})`; @@ -117,11 +117,11 @@ const generateInputObjectFieldTypeZodSchema = ( return maybeLazy(type.type, gen); } if (isNamedType(type)) { - const gen = generateNameNodeZodSchema(config, tsVisitor, schema, type.name) + const gen = generateNameNodeZodSchema(config, tsVisitor, schema, type.name); if (isListType(parentType)) { return `${gen}.nullable()`; } - const appliedDirectivesGen = applyDirectives(config, field, gen) + const appliedDirectivesGen = applyDirectives(config, field, gen); if (isNonNullType(parentType)) { if (config.notAllowEmptyString === true) { const tsType = tsVisitor.scalars[type.name.value]; @@ -141,14 +141,14 @@ const generateInputObjectFieldTypeZodSchema = ( const applyDirectives = ( config: ValidationSchemaPluginConfig, field: InputValueDefinitionNode, - gen: string, + gen: string ): string => { if (config.directives && field.directives) { const formatted = formatDirectiveConfig(config.directives); return gen + buildApi(formatted, field.directives); } - return gen -} + return gen; +}; const generateNameNodeZodSchema = ( config: ValidationSchemaPluginConfig, diff --git a/tests/zod.spec.ts b/tests/zod.spec.ts index 8bd31895..7f9be47c 100644 --- a/tests/zod.spec.ts +++ b/tests/zod.spec.ts @@ -296,10 +296,10 @@ describe('zod', () => { schema: 'zod', directives: { constraint: { - minLength: ['min', "$1", "Please input more than $1"], - maxLength: ['max', "$1", "Please input less than $1"] - } - } + minLength: ['min', '$1', 'Please input more than $1'], + maxLength: ['max', '$1', 'Please input less than $1'], + }, + }, }, {} ); @@ -310,7 +310,7 @@ describe('zod', () => { for (const wantContain of wantContains) { expect(result.content).toContain(wantContain); } - }) + }); it('not null field', async () => { const schema = buildSchema(/* GraphQL */ ` input UserCreateInput { @@ -326,10 +326,10 @@ describe('zod', () => { schema: 'zod', directives: { constraint: { - minLength: ['min', "$1", "Please input more than $1"], - maxLength: ['max', "$1", "Please input less than $1"] - } - } + minLength: ['min', '$1', 'Please input more than $1'], + maxLength: ['max', '$1', 'Please input less than $1'], + }, + }, }, {} ); @@ -340,7 +340,7 @@ describe('zod', () => { for (const wantContain of wantContains) { expect(result.content).toContain(wantContain); } - }) + }); it('list field', async () => { const schema = buildSchema(/* GraphQL */ ` input UserCreateInput { @@ -356,10 +356,10 @@ describe('zod', () => { schema: 'zod', directives: { constraint: { - minLength: ['min', "$1", "Please input more than $1"], - maxLength: ['max', "$1", "Please input less than $1"] - } - } + minLength: ['min', '$1', 'Please input more than $1'], + maxLength: ['max', '$1', 'Please input less than $1'], + }, + }, }, {} ); @@ -370,6 +370,6 @@ describe('zod', () => { for (const wantContain of wantContains) { expect(result.content).toContain(wantContain); } - }) + }); }); });