dotansimha / graphql-code-generator

A tool for generating code based on a GraphQL schema and GraphQL operations (query/mutation/subscription), with flexible support for custom plugins.
https://the-guild.dev/graphql/codegen/
MIT License
10.81k stars 1.32k forks source link

[Bug] codgen creates invalid operations when queries include fragment definitions #10026

Open ghost opened 3 months ago

ghost commented 3 months ago

Which packages are impacted by your issue?

@graphql-codegen/client-preset

Describe the bug

https://the-guild.dev/graphql/yoga-server/docs/features/persisted-operations

gives the advise to use https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#persisted-documents to create our persisted operations. the operation then generates a persisted.document.json like so:

{
    "b2c3d4e5f6g7h8i9j0a1": "query Hello { hello }",
    "kae4fe7f6g7h8i9ej0ag": "mutation echo($msg: String!) { echo(message: $msg) }"
}

however persistedDocument.js is using printExecutableGraphQLDocument https://www.npmjs.com/package/@graphql-tools/documents

this sorts all definitions alphabetically, including fragments, which creates an invalid root operation https://spec.graphql.org/October2021/#sec-Root-Operation-Types

Your Example Website or App

https:

Steps to Reproduce the Bug or Issue

create an operation that includes a fragment definition, where the fragment has a name that is earlier in alphabetical order than the query. generate persisted queries see that the fragment comes before the query. run the operation through graphql.parse https://graphql.org/graphql-js/language/#parse Enjoy failed parsing

Expected behavior

As a user, I expect any operation definitions to proceed fragment definitions regardless of alphabetical order.

Screenshots or Videos

query b { 
    User {
        ...a
    }
}

 fragment a on User {
     id
     name
     url
 }

results in :

"foobarbaz123": " fragment a on User { id name url } query b { User { ...a } }" // fails to be parsed later on expects: "foobarbaz123": "query b{ User { ...a } } fragment a on User { id name url }" // parses successfully with graphql.parse

Platform

Codegen Config File

{
  schema: '../service/schema.graphql',
  documents: [
    'app/**/*.ts',
    'app/**/*.tsx',
    'app/**/*.graphql',
    'app/**/*.gql',
  ],
  generates: {
    './app/__generated__/gql/': {
      config: {
        nonOptionalTypeName: true,
        reactApolloVersion: 3,
      },
      schema: './app/client.graphqls',
      preset: 'client',
      plugins: [],
      presetConfig: {
        gqlTagName: 'gql',
        persistedDocuments: true,
      },
    },
  },
  ignoreNoDocuments: true,
}

Additional context

No response