Skip to content

feat: find-references and rename for GraphQL fragments#409

Open
JoviDeCroock wants to merge 1 commit into
mainfrom
feat/fragment-rename-references
Open

feat: find-references and rename for GraphQL fragments#409
JoviDeCroock wants to merge 1 commit into
mainfrom
feat/fragment-rename-references

Conversation

@JoviDeCroock

Copy link
Copy Markdown
Member

What/Why

GraphQL fragments are the unit of composition (gql.tada pushes fragment co-location), but until now you couldn't see where a fragment is spread, nor rename it. This PR adds:

  • Find references: with the cursor on a fragment name — either at its definition (fragment PokemonFields on Pokemon) or at a spread (...PokemonFields) — the editor lists the definition and every spread of that fragment, across all of the project's source files.
  • Rename: renaming from the definition or from any spread updates every occurrence (the bare name tokens, no ... prefix), including fragments defined in another graphql() call in the same file and fragments imported from other files.

Implementation notes

  • New packages/graphqlsp/src/references.ts resolves the cursor to a fragment name token the same way definition.ts does (findNode → bubble up to the graphql()/gql() call or tagged template → parse the document → hit-test FragmentDefinition/FragmentSpread name locations), then scans the program's source files for matching definitions/spreads.
  • Cross-file search skips declaration files and node_modules, and prefilters with a plain-text source.getText().includes(fragmentName) scan before any GraphQL parsing, so the cost is bounded on explicit user actions only.
  • GraphQL AST offsets are mapped back to TS offsets via documentNode.getStart() + 1 + loc.start, using the raw (unescaped) literal text so offsets map 1:1 (same approach as resolveTemplate).
  • findReferences (used by the tsserver references command), getReferencesAtPosition, getRenameInfo and findRenameLocations are proxied in index.ts with the existing guard() log-and-fall-back pattern; when the cursor is not on a fragment name, the original language service result is returned unchanged.
  • In gql.tada multi-schema setups, only documents branded with the same schema name as the originating document are matched, so same-named fragments of different schemas don't collide.

Limitations

  • Tagged-template mode is supported for plain templates (gql\...`) only; templates with ${...}interpolations are skipped, since interpolation shifts GraphQL offsets away from TS file offsets (the same restrictiondefinition.ts` has).
  • Fragments are matched by name (per schema); references inside interpolated template combinations aren't tracked.

Test plan

  • New test/e2e/references.test.ts against fixture-project-tada with two new fixture files: references-fragment.ts (fragment definition + a spread in a second graphql() call in the same file) and references-usage.ts (spread of the imported fragment in another file). It forks a real tsserver and asserts, via the references and rename protocol commands:
    • references from the definition and from a cross-file spread return exactly the 3 expected file/line/offset spans, with isDefinition set on the definition entry;
    • rename from a spread and from the definition reports canRename, the right displayName/triggerSpan, and rename locations covering every occurrence (definition + both spreads, cross-file);
    • references on a plain TypeScript identifier still fall back to the original language service.
  • pnpm --filter @0no-co/graphqlsp run build passes.
  • Full pnpm run test:e2e passes: 12 test files, 57 tests, 0 failures.

🤖 Generated with Claude Code

Proxy findReferences/getReferencesAtPosition and
getRenameInfo/findRenameLocations so that a cursor on a fragment name -
at its definition or at any spread - lists and renames the definition
plus every spread across the project's source files. Files are cheaply
prefiltered with a plain-text scan before their GraphQL documents are
parsed, and gql.tada multi-schema setups only match documents belonging
to the same schema.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@changeset-bot

changeset-bot Bot commented Jul 4, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: c69ceed

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@0no-co/graphqlsp Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant