Graphql-code-generator: Cannot read property 'forEach' of undefined when running the "programmatic usage" sample

Created on 11 Jun 2019  路  15Comments  路  Source: dotansimha/graphql-code-generator

Describe the bug

Cannot read property 'forEach' of undefined when running the "programmatic usage" sample. Seems to be caused by documents being required by the codegen function.

To Reproduce
Steps to reproduce the behavior:

Code is more or less copy pasted from https://graphql-code-generator.com/docs/getting-started/programmatic-usage

import fs from "fs";
import path from "path";

import { codegen } from "@graphql-codegen/core";
import { plugin as typescriptPlugin } from "@graphql-codegen/typescript";

import { buildSchema, printSchema, parse } from "graphql";

const schemaText = `

type DeletionResultInfo {
  success: Boolean
  Meta: MutationResultInfo
}

type MutationResultInfo {
  transaction: Boolean
  elapsedTime: Int
}

`;

async function createTypeScriptTypes(outputFile) {
  const schema = buildSchema(schemaText);

  const config = {
    // used by a plugin internally, although the 'typescript' plugin currently
    // returns the string output, rather than writing to a file
    filename: outputFile,
    schema: parse(printSchema(schema)),
    plugins: {
      typescript: {} // Here you can pass configuration to the plugin
    },
    pluginMap: {
      typescript: {
        plugin: typescriptPlugin
      }
    }
  };

  const output = await codegen(config);
  fs.writeFile(path.join(__dirname, outputFile), output, () => {
    console.log("Outputs generated!");
  });
}

createTypeScriptTypes("test.ts");

Running this via the esm package produces the error:

(node:51651) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'forEach' of undefined
at validateDocuments (/Users/adam.rackis/Documents/git/mongo-graphql-starter/node_modules/@graphql-codegen/core/dist/commonjs/codegen.js:83:11)
at codegen (/Users/adam.rackis/Documents/git/mongo-graphql-starter/node_modules/@graphql-codegen/core/dist/commonjs/codegen.js:10:5)
at createTypeScriptTypes (/Users/adam.rackis/Documents/git/mongo-graphql-starter/src/codeGen/createTypeScriptTypes.js:41:24)
at Object. (/Users/adam.rackis/Documents/git/mongo-graphql-starter/src/codeGen/createTypeScriptTypes.js:47:1)
at Generator.next ()

Looking in the code, it seems this is a result of validateDocuments being called and passed options.documents as the second argument, which has forEach called on it directly (which is undefined in the code above).

Expected behavior

Should produce ts typings.

Environment:

  • OS: MacOS High Sierra
  • @graphql-codegen/...: 1.2.1
  • @graphql-codegen/typescript: 1.2.1
  • NodeJS: 10.15.0

Additional context

bug core waiting-for-release

Most helpful comment

Fixed in 1.4.0 馃帀

All 15 comments

Seeing a similar error trying to call codegen programmatically with a custom config.

Error output:

Cannot read property 'forEach' of undefined
    at validateDocuments (/Users/mhankin/Code/sched/scheduling-framework/node_modules/@graphql-codegen/core/dist/commonjs/codegen.js:83:11)
    at codegen (/Users/mhankin/Code/sched/scheduling-framework/node_modules/@graphql-codegen/core/dist/commonjs/codegen.js:10:5)
    at Object.<anonymous> (/Users/mhankin/Code/sched/scheduling-framework/scripts/generate-backend-types.js:35:1)
    at Module._compile (module.js:653:30)
    at Object.Module._extensions..js (module.js:664:10)
    at Module.load (module.js:566:32)
    at tryModuleLoad (module.js:506:12)
    at Function.Module._load (module.js:498:3)
    at Function.Module.runMain (module.js:694:10)
    at startup (bootstrap_node.js:204:16)

Code:

const fs = require('fs');
const path = require('path');
const codegen = require('@graphql-codegen/core').codegen;
const typescriptPlugin = require('@graphql-codegen/typescript').plugin;
const typescriptOperationsPlugin = require('@graphql-codegen/typescript-operations')
    .plugin;
const typescriptReactApolloPlugin = require('@graphql-codegen/typescript-react-apollo')
    .plugin;

const schemaUrl = 'http://localhost:10033/v1/graphql';
const outputFilename = '../src/generated/scheduling-framework-backend.tsx';

const codegenConfig = {
    filename: outputFilename,
    schema: schemaUrl,
    plugins: {
        typescript: {},
        typescriptOperations: {},
        typescriptReactApollo: {},
    },
    pluginMap: {
        typescript: {
            plugin: typescriptPlugin,
        },
        typescriptOperations: {
            plugin: typescriptOperationsPlugin,
        },
        typescriptReactApollo: {
            plugin: typescriptReactApolloPlugin,
        },
    },
};

const generateTypes = async (config, filename) => {
    try {
        const output = await codegen(config);
        await fs.writeFile(path.join(__dirname, filename), output);
        console.log('Types generated!');
    } catch (error) {
        console.error('Error generating types:', error);
    }
};

generateTypes(codegenConfig, outputFilename);

Environment:

  • OS: MacOS Mojave
  • @graphql-codegen/...: 1.2.1
  • @graphql-codegen/typescript: 1.2.0
  • @graphql-codegen/typescript-operations: 1.2.0
  • @graphql-codegen/typescript-react-apollo: 1.2.0

Hi @arackaf @mhank , thank you for reporting it.
Why not adding documents: [] as a workaround at the moment?

I fixed it in: https://github.com/dotansimha/graphql-code-generator/pull/2015

@dotansimha thanks for the response. After adding documents: [] to the config object, I begin to see a different error:

TypeError: options.plugins is not iterable
    at codegen (/Users/mhankin/Code/sched/scheduling-framework/node_modules/@graphql-codegen/core/dist/commonjs/codegen.js:18:34)
    at generateTypes (/Users/mhankin/Code/sched/scheduling-framework/scripts/generate-backend-types.js:38:24)
    at Object.<anonymous> (/Users/mhankin/Code/sched/scheduling-framework/scripts/generate-backend-types.js:46:1)
    at Module._compile (module.js:653:30)
    at Object.Module._extensions..js (module.js:664:10)
    at Module.load (module.js:566:32)
    at tryModuleLoad (module.js:506:12)
    at Function.Module._load (module.js:498:3)
    at Function.Module.runMain (module.js:694:10)
    at startup (bootstrap_node.js:204:16)

I can put this into a new issue if necessary.

@mhank it should be an array of objects:

    plugins: [
        {typescript: {}},
        {typescriptOperations: {}}
        {typescriptReactApollo: {}}
    ],

I know it's not ideal, but we tried to make the programatic usage as pure as possible, without doing any validations or transformations (because the CLI does that for it). The reason for using an Array of objects is because of the YML structure.
We'll try to improve that.

@dotansimha thanks again for the response. You may want to get this doc page updated to reflect that format. I'd be more than happy to submit a PR if you could point me in the right direction. But unfortunately, resolving that error led another to arise:

Error: Must provide valid Document AST
    at invariant (/Users/mhankin/Code/sched/scheduling-framework/node_modules/graphql/jsutils/invariant.js:21:11)
    at Object.buildASTSchema (/Users/mhankin/Code/sched/scheduling-framework/node_modules/graphql/utilities/buildASTSchema.js:75:88)
    at Object.executePlugin (/Users/mhankin/Code/sched/scheduling-framework/node_modules/@graphql-codegen/core/dist/commonjs/execute-plugin.js:20:36)
    at codegen (/Users/mhankin/Code/sched/scheduling-framework/node_modules/@graphql-codegen/core/dist/commonjs/codegen.js:22:47)
    at generateTypes (/Users/mhankin/Code/sched/scheduling-framework/scripts/generate-backend-types.js:38:24)
    at Object.<anonymous> (/Users/mhankin/Code/sched/scheduling-framework/scripts/generate-backend-types.js:46:1)
    at Module._compile (module.js:653:30)
    at Object.Module._extensions..js (module.js:664:10)
    at Module.load (module.js:566:32)
    at tryModuleLoad (module.js:506:12)

@dotansimha thanks a ton for the reply!

I, too, tried the workaround you suggested, and then tried patching the plugins array, and then wound up with the very error @mhank found, so I figured the docs page was just wildly out of date (an understandable thing for an OSS project).

I forked your repo in the hopes that I might be able to see where the breakage happened, so I might PR, but no luck.

Anyway, thanks a ton for the project - eager to see what the resolution is, here - I'm planning on integrating this into my MongoDB GraphQL endpoint generator

Regarding the docs, you are right, we have an issue about that, we'll fix that soon.

@mhank can you please share how you created your documents? it's just an empty array?

@dotansimha yes. Here's what my updated config object looks like:

const codegenConfig = {
    filename: outputFilename,
    schema: schemaUrl,
    plugins: [
        { typescript: {} },
        { typescriptOperations: {} },
        { typescriptReactApollo: {} },
    ],
    pluginMap: {
        typescript: {
            plugin: typescriptPlugin,
        },
        typescriptOperations: {
            plugin: typescriptOperationsPlugin,
        },
        typescriptReactApollo: {
            plugin: typescriptReactApolloPlugin,
        },
    },
    documents: [],
};

@mhank - can you show your imports too, please? I鈥檇 like to test whatever solution we come up with here, too, and wanna make sure I have everything right.

@arackaf here's the full script:

const fs = require('fs');
const path = require('path');
const codegen = require('@graphql-codegen/core').codegen;
const typescriptPlugin = require('@graphql-codegen/typescript').plugin;
const typescriptOperationsPlugin = require('@graphql-codegen/typescript-operations')
    .plugin;
const typescriptReactApolloPlugin = require('@graphql-codegen/typescript-react-apollo')
    .plugin;

const schemaUrl = 'http://localhost:10033/v1/graphql';
const outputFilename = '../src/generated/scheduling-framework-backend.tsx';

const codegenConfig = {
    filename: outputFilename,
    schema: schemaUrl,
    plugins: [
        { typescript: {} },
        { typescriptOperations: {} },
        { typescriptReactApollo: {} },
    ],
    pluginMap: {
        typescript: {
            plugin: typescriptPlugin,
        },
        typescriptOperations: {
            plugin: typescriptOperationsPlugin,
        },
        typescriptReactApollo: {
            plugin: typescriptReactApolloPlugin,
        },
    },
    documents: [],
};

const generateTypes = async (config, filename) => {
    try {
        const output = await codegen(config);
        await fs.writeFile(path.join(__dirname, filename), output);
        console.log('Types generated!');
    } catch (error) {
        console.error('Error generating types:', error);
    }
};

generateTypes(codegenConfig, outputFilename);

@dotansimha looks like 1.3 fixes this! Thank you _SO MUCH_ for all your hard work.

Here's my full code (I'm using esm to handle the ESM imports).

Only blemish left is that

documents: [], //needed, for now

is needed, but I can live with that easily. Feel free close this - not sure if you're keeping it open until the docs are updated, or whatever.

Thanks again!!!!

import fs from "fs";
import path from "path";
import { buildSchema, printSchema, parse } from "graphql";

import { codegen } from "@graphql-codegen/core";
import { plugin as typescriptPlugin } from "@graphql-codegen/typescript";
import { plugin as typescriptOperationsPlugin } from "@graphql-codegen/typescript-operations";

const schemaText = `

type DeletionResultInfo {
  success: Boolean
  Meta: MutationResultInfo
}

type MutationResultInfo {
  transaction: Boolean
  elapsedTime: Int
}

`;

async function createTypeScriptTypes(outputFile) {
  const schema = buildSchema(schemaText);

  const config = {
    // used by a plugin internally, although the 'typescript' plugin currently
    // returns the string output, rather than writing to a file
    filename: outputFile,
    schema: parse(printSchema(schema)),
    plugins: [{ typescript: {} }, { typescriptOperations: {} }],
    documents: [], //needed, for now
    pluginMap: {
      typescript: {
        plugin: typescriptPlugin
      },
      typescriptOperations: {
        plugin: typescriptOperationsPlugin
      }
    }
  };

  const output = await codegen(config);
  fs.writeFile(path.join(__dirname, outputFile), output, () => {
    console.log("Outputs generated!");
  });
}

createTypeScriptTypes("test.ts");

@arackaf
Fixed in 1.3.1, now you no longer must specify documents: [].

@dotansimha fyi, even with 1.3.1, without the documents empty array, I'm seeing

TypeError: Cannot read property 'length' of undefined
at Object.executePlugin (/Users/adam.rackis/Documents/git/mongo-graphql-starter/node_modules/@graphql-codegen/core/src/execute-plugin.ts:35:41)
at codegen (/Users/adam.rackis/Documents/git/mongo-graphql-starter/node_modules/@graphql-codegen/core/src/codegen.ts:31:26)
at createTypeScriptTypes (/Users/adam.rackis/Documents/git/mongo-graphql-starter/src/codeGen/createTypeScriptTypes.js:27:24)
at Promise.resolve.then.graphqlMetadata (/Users/adam.rackis/Documents/git/mongo-graphql-starter/src/createGraphqlSchema.js:120:14)
at process._tickCallback (internal/process/next_tick.js:68:7)

@arackaf oops sorry, fixed in https://github.com/dotansimha/graphql-code-generator/commit/d38dde47dad9f8314d8ef782f722f57ba3feeaea

Available as alpha 1.3.1-alpha-d38dde47.18.

Fixed in 1.4.0 馃帀

Was this page helpful?
0 / 5 - 0 ratings