feat: add 'Extract to fragment' refactor - #412
Open
JoviDeCroock wants to merge 1 commit into
Open
Conversation
When a selection inside a graphql() document's selection set covers one or more complete sibling field selections, offer an 'Extract to fragment' action under the existing 'GraphQL' refactor group. Applying it creates a new graphql() fragment document (named after the fields' parent type) above the current statement, replaces the selected fields with a fragment spread, and appends the new fragment variable to the call's fragment array (creating the array when the call has none). The refactor dispatch in getEditsForRefactor now switches on the refactor/action name, and getApplicableRefactors merges all applicable GraphQL actions into a single refactor group. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
🦋 Changeset detectedLatest commit: cc50966 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What/Why
Adds an "Extract to fragment" refactor to the language service. When a selection inside a
graphql()document's selection set covers one or more complete sibling field selections, the plugin offers an "Extract to fragment" action under the existing "GraphQL" refactor group. Applying it:const <parentType>Fields = graphql(…)fragment document above the statement containing the current call (above its leading comments), named<ParentType>Fieldsafter the selected fields' parent type, with a numeric suffix if that fragment name is already used by a document in the file (or the derived variable name already occurs in the file),...<FragmentName>spread, and, [<var>]when the call only has the document argument.This makes it much easier to progressively split large gql.tada documents into co-located fragments.
Implementation notes
packages/graphqlsp/src/extractFragment.tsimplements both applicability (canExtractFragment) and the edits (getExtractFragmentEdits). The TS selection range is mapped into the document text (getStart() + 1offset mapping, as indefinition.ts), trimmed of GraphQL ignored tokens (whitespace/commas), and validated against the parsed document AST: the trimmed range must start at a field selection and consecutive sibling fields must tile it exactly (a selection ending inside a field, crossing a selection-set boundary, or covering non-field selections is rejected).TypeInfo; the schema is resolved per document viagetSchemaForNameusing the document's schema name, the same waydiagnostics.tsdoes, so multi-schema setups pick the right schema.index.tsnow dispatchesgetEditsForRefactorby refactor/action name (instead of the previous early-return for the persisted-operations code fix) andgetApplicableRefactorsmerges all applicable actions into one "GraphQL" refactor group. Everything stays behind theguard()fallback so exceptions never propagate into tsserver.Test plan
test/e2e/extract-fragment.test.ts(new fixturetest/e2e/fixture-project-tada/fixtures/extract-fragment.ts), driving a real tsserver via thegetApplicableRefactors/getEditsForRefactorprotocol commands:<ParentType>Fieldsname collision resolving toPokemonFields2), extraction of a field with a nested selection set at the end of a run, and extraction from a call without a fragment array (adds, [pokemonFields2]).pnpm --filter @0no-co/graphqlsp run buildpasses.pnpm run test:e2e: 12 test files, 59 tests, all passing.Limitations
templateIsCallExpression: true, the default, i.e. gql.tada-stylegraphql()calls). Tagged-template mode is not supported, since fragments there aren't composed through a fragment-array argument.🤖 Generated with Claude Code