dotansimha / graphql-code-generator-community

MIT License
117 stars 152 forks source link

typescript-operations plugin duplicates fragment type when document is matched twice #862

Open ertrzyiks opened 6 days ago

ertrzyiks commented 6 days ago

originally reported as: https://github.com/dotansimha/graphql-code-generator/issues/10170

Which packages are impacted by your issue?

@graphql-codegen/near-operation-file-preset

Describe the bug

When typescript-operations plugin is used with @graphql-codegen/near-operation-file-preset and the documents config has overlapping patterns meaning a file is matched by more than a single pattern the generated file contains multiple type exports with conflicting name.

Your Example Website or App

https://stackblitz.com/edit/github-kq5wbr?file=codegen.ts,src%2Ffragment.generated.ts

Steps to Reproduce the Bug or Issue

  1. Go to src/fragment.generated.ts and see MyExampleFragment is duplicated
  2. Go to codegen.ts
  3. Comment out 'src/fragment.graphql', from the documents config
  4. Run yarn generate
  5. See that src/fragment.generated.ts has no duplication

Expected behavior

There is no duplication regardless of overlapping documents configuration

Screenshots or Videos

No response

Platform

Codegen Config File

import { CodegenConfig } from '@graphql-codegen/cli';

const config: CodegenConfig = {
  schema: 'schema.graphql',
  documents: [
    'document.graphql',
    'src/*.graphql',
    // Enforce duplication, fragment is already matched by the rule above
    // comment out the next line to prevent duplication
    'src/fragment.graphql',
  ],
  generates: {
    'types.ts': {
      plugins: ['typescript'],
    },
    src: {
      preset: 'near-operation-file',
      plugins: ['typescript-operations'],
      presetConfig: {
        baseTypesPath: '../types.ts',
      },
    },
  },
};

export default config;

Additional context

Symptoms

The generated file:

import * as Types from '../types';

export type MyExampleFragment = { __typename?: 'User', id: string, username: string };

export type MyExampleFragment = { __typename?: 'User', id: string, username: string };

Research

Documents here https://github.com/dotansimha/graphql-code-generator/blob/a23505180ac2f275a55ece27162ec9bfcdc52e03/packages/plugins/typescript/operations/src/index.ts#L14

carry the duplicated fragment SDL

[
  {
    rawSDL: 'fragment MyExample on User {\n' +
      '  id\n' +
      '  username\n' +
      '}fragment MyExample on User {\n' +
      '  id\n' +
      '  username\n' +
      '}',
    document: { kind: 'Document', definitions: [Array] },
    location: '...'
  }
]

without the preset they are 2 documents:

[
  {
    location: '...',
    document: { kind: 'Document', definitions: [Array] },
    rawSDL: 'fragment MyExample on User {\n  id\n  username\n}',
    hash: '...'
  },
  {
    location: '....',
    document: { kind: 'Document', definitions: [] },
    rawSDL: 'fragment MyExample on User {\n  id\n  username\n}',
    hash: '...'
  }
]
ertrzyiks commented 6 days ago

I added a failing test in https://github.com/ertrzyiks/graphql-code-generator-community/commit/eb448b2d4a04ce8d257b05ab5b3b8af29da39235

It's interesting that it breaks only if patterns are different. When the test is defined with the same path duplicated it works properly:

documents: [
  path.join(__dirname, 'fixtures/issue-new-pattern.ts'),
  path.join(__dirname, 'fixtures/issue-new-pattern.ts'),
]

There must be some deduplication in place on the pattern level, but it fails to deduplicate when patterns are different:

documents: [
   path.join(__dirname, 'fixtures/issue-new-pattern.ts'),
   path.join(__dirname, 'fixtures/issue-*-pattern.ts'), // <- notice the * in the pattern
]