Skip to content

[typescript-operations] test: reproduce #10922 — unused schema-types import with combine fragments (failing) - #10953

Draft
eddeee888 wants to merge 1 commit into
masterfrom
claude/tender-lovelace-qc2nnq
Draft

eddeee888 wants to merge 1 commit into
masterfrom
claude/tender-lovelace-qc2nnq

Conversation

@eddeee888

@eddeee888 eddeee888 commented Sep 13, 2026

Copy link
Copy Markdown
Collaborator

Description

This is a checkpoint PR: it adds a failing test that proves the bug reported in
#10922 is real. It does not fix anything.

typescript-operations, when configured with both importSchemaTypesFrom and
inlineFragmentTypes: 'combine', emits an unused import type * as Types from '...'
in generated files whose document only spreads an external fragment (and never names
a schema type itself). Under noUnusedLocals/noUnusedImports this fails the
TypeScript build.

The root cause (per the issue) is in
TypeScriptDocumentsVisitor.getExternalSchemaTypeImports()
(packages/plugins/typescript/operations/src/visitor.ts): the import is gated on
_usedSchemaTypes, which tracks whether a schema type is used by the document
(including through fragments, since it also drives local enum/input generation) —
not whether the generated file itself ends up naming the Types namespace. Those
two only diverge when inlineFragmentTypes is 'combine' (or 'mask'), because
only then does a spread fragment collapse to a bare FooFragment reference instead
of inlining the referenced schema types.

Related #10922

Type of change

  • Bug fix (non-breaking change which fixes an issue) — test only, no fix yet

Screenshots/Sandbox (if appropriate/relevant):

Reporter's reproduction: https://stackblitz.com/edit/gdtmg1pc

How Has This Been Tested?

Added packages/plugins/typescript/operations/tests/ts-documents.import-schema-types-combine.spec.ts,
mirroring the issue's repro: a Category fragment that selects an enum field, and a
Book fragment (external-fragment style, own file) that only spreads ...Category.
With importSchemaTypesFrom + inlineFragmentTypes: 'combine', the generated
book.generated.ts output should not import Types at all, since it only ever
references CategoryFragment.

This currently fails as expected:

AssertionError: expected 'import type * as Types from \'./types…' not to contain 'Types'

- Expected
+ Received

- Types
+ import type * as Types from './types';
+
+
+ /** Internal type. DO NOT USE DIRECTLY. */
+ export type Incremental<T> = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never };
+ export type BookFragment = { id: string, category: CategoryFragment };

All 242 other existing tests in the typescript-operations package still pass.

  • Test A: ts-documents.import-schema-types-combine.spec.ts (new, failing — this is the point)

Test Environment:

  • OS: Linux
  • @graphql-codegen/typescript-operations: 6.1.6 (as reported)
  • NodeJS: 22

Checklist:

Further comments

This is intentionally left red. Nothing here should be "fixed" by skipping or
loosening the test — the next step is a separate PR that makes
getExternalSchemaTypeImports() (or equivalent) decide the import based on whether
the generated file itself names a schema type, not just whether the document
uses one.

🤖 Generated with Claude Code

https://claude.ai/code/session_01EefzkxyCDaB4zSdjEuGHou


Generated by Claude Code

…om + inlineFragmentTypes combine

eddeee888:oss:issue-verify
@changeset-bot

changeset-bot Bot commented Sep 13, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: bae0ea6

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

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

Comment on lines +49 to +52
const categoryFragmentDef = categoryFragmentDocument.definitions[0];
if (categoryFragmentDef.kind !== 'FragmentDefinition') {
throw new Error('Expected fragment definition');
}

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do this?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a type-narrowing guard, not new invention — it mirrors the same pattern already used a few lines above it in ts-documents.external-fragments-enum.spec.ts in this same directory.

categoryFragmentDocument.definitions[0] is typed as DefinitionNode, but externalFragments[].node on the plugin config requires FragmentDefinitionNode. Without the runtime kind check, categoryFragmentDef can't be passed as node below without a cast. The check both satisfies TS and fails loudly (rather than misconfiguring the repro silently) if parse() ever returns something unexpected.

Happy to switch it to a cast if you'd rather not have the extra guard — let me know which you prefer.


Generated by Claude Code

Comment on lines +65 to +69
const categoryResult = mergeOutputs([
await plugin(schema, [{ document: categoryFragmentDocument }], config, {
outputFile: './category.generated.ts',
}),
]);

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not put both documents together?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Intentional, and actually load-bearing for reproducing the bug: this is modeling two separate generated files, the way near-operation-file-preset actually produces them — one plugin() call per source document, where book.generated.ts only learns about the Category fragment through externalFragments (as a fragment defined and compiled elsewhere), not by having both documents in the same document set.

If I merged categoryFragmentDocument and bookFragmentDocument into a single plugin() call, the two fragments would be seen together as one document, _usedSchemaTypes would be computed once for that combined set, and the enum usage from Category would "leak" into the same _usedSchemaTypes — which is exactly the assumption the bug report says is the correct one at the document level (it's used by the document), but wrong at the generated file level. The whole bug only shows up when the file that actually gets written (book.generated.ts) never itself names the enum — which requires it to be generated from a document that only contains the spread, with the enum-selecting fragment external to it.

So the split into two plugin() calls with isExternal: true isn't incidental — it's what makes this reproduce near-operation-file-preset's actual per-file generation instead of a single merged-file case where the bug doesn't occur.


Generated by Claude Code

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.

2 participants