Code-Hex/graphql-codegen-typescript-validation-schema

TypeError: Cannot read properties of undefined (reading 'input')

Giovanni-Schroevers opened this issue · 19 comments

 TypeError: Cannot read properties of undefined (reading 'input')
        at Visitor.getScalarType (graphcommerce/node_modules/graphql-codegen-typescript-validation-schema/dist/main/visitor.js:30:40)
        at generateFieldTypeZodSchema (graphcommerce/node_modules/graphql-codegen-typescript-validation-schema/dist/main/zod/index.js:146:40)
        at generateFieldTypeZodSchema (graphcommerce/node_modules/graphql-codegen-typescript-validation-schema/dist/main/zod/index.js:135:21)
        at generateFieldTypeZodSchema (graphcommerce/node_modules/graphql-codegen-typescript-validation-schema/dist/main/zod/index.js:126:21)
        at generateFieldTypeZodSchema (graphcommerce/node_modules/graphql-codegen-typescript-validation-schema/dist/main/zod/index.js:135:21)
        at generateFieldZodSchema (graphcommerce/node_modules/graphql-codegen-typescript-validation-schema/dist/main/zod/index.js:121:17)
        at graphcommerce/node_modules/graphql-codegen-typescript-validation-schema/dist/main/zod/index.js:46:103
        at Array.map (<anonymous>)
        at Object.leave (graphcommerce/node_modules/graphql-codegen-typescript-validation-schema/dist/main/zod/index.js:46:90)
        at visit (graphcommerce/node_modules/graphql/language/visitor.js:197:21) {
      source: '../../packagesDev/next-config/src/generated/config.ts'

It seems to be a problem with nested input types. To fix the issue the following patch seems to be working:

diff --git a/node_modules/graphql-codegen-typescript-validation-schema/dist/main/visitor.js b/node_modules/graphql-codegen-typescript-validation-schema/dist/main/visitor.js
index 82da858..f2088f0 100644
--- a/node_modules/graphql-codegen-typescript-validation-schema/dist/main/visitor.js
+++ b/node_modules/graphql-codegen-typescript-validation-schema/dist/main/visitor.js
@@ -26,6 +26,9 @@ class Visitor extends typescript_1.TsVisitor {
         if (this.scalarDirection === 'both') {
             return null;
         }
+        if (!this.scalars[scalarName]) {
+            return null;
+        }
         return this.scalars[scalarName][this.scalarDirection];
     }
 }

Fix works, but then the types don't get generated correctly

Are your scalars something like this?

 export type Scalars = {
  ID: { input: string | number; output: string; }
  String: { input: string; output: string; }
  Boolean: { input: boolean; output: boolean; }
  Int: { input: number; output: number; }
  Float: { input: number; output: number; }
  BooleanType: { input: any; output: any; }
  CustomData: { input: any; output: any; }
  DateTime: { input: any; output: any; }
  FloatType: { input: any; output: any; }
  IntType: { input: any; output: any; }
  ItemId: { input: any; output: any; }
  MetaTagAttributes: { input: any; output: any; }
  UploadId: { input: any; output: any; }
};

@Giovanni-Schroevers Thanks for reporting your issue!
Could you give me your GraphQL Schema and your configuration? I want to reproduce the issue.

Experiencing the same issue - seems to be erroring on all GraphQL Enums.

Also it is not depending on the configuration (I've tried disabling everything else apart from graphql-codegen-typescript-validation-schema and the recommended scalars config).

Example Enum:

enum Allergen {
    MILK
    EGGS
    PEANUTS
    SOY
    WHEAT
    TREE_NUTS
    SHELLFISH
    FISH
    SESAME
}

@maoosi I cannot reproduce this error:

enum Allergen {
    MILK
    EGGS
    PEANUTS
    SOY
    WHEAT
    TREE_NUTS
    SHELLFISH
    FISH
    SESAME
}

then I can generate this code:

import { z } from 'zod'
import { Allergen } from '../types'

type Properties<T> = Required<{
  [K in keyof T]: z.ZodType<T[K], any, T[K]>;
}>;

type definedNonNullAny = {};

export const isDefinedNonNullAny = (v: any): v is definedNonNullAny => v !== undefined && v !== null;

export const definedNonNullAnySchema = z.any().refine((v) => isDefinedNonNullAny(v));

export const AllergenSchema = z.nativeEnum(Allergen);

and run tsc --strict --noEmit example/zod/schemas.ts

I checked w/ ee78cf3

Colleague of @Giovanni-Schroevers here.

This schema gives me an error:

input InputOne {
  field: InputNested!
}

input InputNested {
  field: String
}

If I make InputNested optional, it doesn't anymore. Debugging now.

@paales mmm, I could generate validation schema w/o errors:

import { z } from 'zod'
import { InputNested, InputOne } from '../types'

type Properties<T> = Required<{
  [K in keyof T]: z.ZodType<T[K], any, T[K]>;
}>;

type definedNonNullAny = {};

export const isDefinedNonNullAny = (v: any): v is definedNonNullAny => v !== undefined && v !== null;

export const definedNonNullAnySchema = z.any().refine((v) => isDefinedNonNullAny(v));

export function InputNestedSchema(): z.ZodObject<Properties<InputNested>> {
  return z.object({
    field: z.string().nullish()
  })
}

export function InputOneSchema(): z.ZodObject<Properties<InputOne>> {
  return z.object({
    field: z.lazy(() => InputNestedSchema())
  })
}

Could you give me your configuration?

Digging in the code it seems related to notAllowEmptyString: true,

Code I'm using to generate

  await generate({
    silent: true,
    schema: ['graphql/**/Config.graphqls', ...schemaLocations],
    generates: {
      [targetTs]: {
        plugins: ['typescript', 'typescript-validation-schema', 'add'],
        config: {
          // enumsAsTypes: true,
          content: '/* eslint-disable */',
          schema: 'zod',
          notAllowEmptyString: true,
          enumsAsTypes: true,
          scalarSchemas: {
            Domain: 'z.string()',
            DateTime: 'z.date()',
            RichTextAST: 'z.object.json()',
          },
        },
      },
      // ...(isMonorepo() && {
      //   '../../docs/framework/config.md': {
      //     plugins: ['@graphcommerce/graphql-codegen-markdown-docs'],
      //   },
      // }),
    },
  })

Using it here: https://github.com/graphcommerce-org/graphcommerce/blob/canary/packagesDev/next-config/src/config/commands/generateConfig.ts#L19

@paales It looks to me like you didn't follow the quickstart. I want you to try it once.

generates:
  path/to/graphql.ts:
    plugins:
      - typescript
      - typescript-validation-schema # specify to use this plugin
    config:
      # You can put the config for typescript plugin here
      # see: https://www.graphql-code-generator.com/plugins/typescript
      strictScalars: true
      # Overrides built-in ID scalar to both input and output types as string.
      # see: https://the-guild.dev/graphql/codegen/plugins/typescript/typescript#scalars
      scalars:
        ID: string
      # You can also write the config for this plugin together
      schema: yup # or zod

If I follow the quickstart guide it works as expected!
If I remove notAllowEmptyString: true, it works as expected :) Not ideal, but good enough for now.

@paales I'm sorry, I didn't read your latest comment, I could reproduce this error 🙏
I will fix it ASAP

Award for fastest responder in a GitHub issue goes to @Code-Hex! ❤️

I just published the latest version as v0.11.0

@Code-Hex Thanks! Sadly the issue still persists on my end.

Here is a reproduction link:
https://codesandbox.io/p/sandbox/mystifying-thompson-z2h8m9?welcome=true

Just run pnpm run gen to see the error:
✖ Cannot read properties of undefined (reading 'input')

Few notes:

  • On my dev setup, I'm running a local GraphQL Yoga server and directly introspecting it via http://127.0.0.1:4444/graphql.
  • Weirdly enough, I wasn’t able to reproduce the issue simply by manually re-creating the schema.graphql file.
  • What I had to do, is output a JSON introspection file of my local GraphQL Yoga endpoint using https://the-guild.dev/graphql/codegen/plugins/other/introspection and then use this file in the reproduction environment. This way I was able to reproduce the exact same error.

@maoosi I understand why this is happening.

The generation logic relied on the schema passed from graphql-codegen. If this was a schema generated based on introspection, the astNode information was lost, so it seems that it was not possible to determine whether each schema was an enum or a scalar.

This issue was reported here:

graphql/graphql-js#1575

I will fix the logic to take this into consideration 🙏

I created a new issue #394
Close this issue one.

Awesome, thanks for looking into it!