0no-co / GraphQLSP

TypeScript LSP plugin that finds GraphQL documents in your code and provides diagnostics, auto-complete and hover-information.
https://gql-tada.0no.co
MIT License
332 stars 13 forks source link

Source of persisted operation hash contains duplicate fragments #341

Closed felamaslen closed 2 weeks ago

felamaslen commented 2 weeks ago

There is an issue in the persisted document hash generator for graphqlsp.

When a document contains multiple copies of the same fragment, that fragment will appear in the hashed contents as many times as it is called in the query.

However, this isn't a valid query. Passing this to a standard GraphQL server will result in a runtime error:

query Foo {
  a {
    ...Bar
  }
  b {
    ...Bar
  }
}
fragment Bar on AOrB { id }
fragment Bar on AOrB { id } # duplicate fragment

Moreover, gql.tada generate-persisted -o operations.json will generate the correct set of documents, with fragments deduplicated.

Therefore, this is a bug in graphqlsp.

Reproduction steps

  1. Create a persisted query with two copies of the same fragment, e.g.
import { graphql } from 'graphql.persisted';

const FooDocument = graphql.persisted(
  '',
  graphql(`
    query Foo {
      a {
        ...Bar
      }
      b {
        ...Baz
      }
    }
  `, [BarDocument, BazDocument])
);

const BarDocument = graphql(`
  fragment Bar on AOrB {
    id
    ...Bak
  }
`, [BakDocument]);

const BazDocument = graphql(`
  fragment Baz on AOrB {
    otherProp
    ...Bak
  }
`, [BakDocument]);

const BakDocument = graphql(`
  fragment Bak on AOrB {
    something
  }
`);
  1. Apply tsserver code fix (generate ID) from graphqlsp on the above document

  2. Observe that the contents used to generate the hash in the above fix, include duplicate copies of fragment Bak on AOrB { ... }.

Expected behaviour

There is only one copy of each unique fragment in the contents used to generate the hash.