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);
       }
-    })
+    });
   });
 });