From 094e79a8b3c970ef4669372f2de89411f2424baa Mon Sep 17 00:00:00 2001 From: Eddy Nguyen Date: Fri, 25 Sep 2026 14:41:26 +1000 Subject: [PATCH 1/2] [time] fix: handle optional info and unset format under strict mode (#4683) (#10989) `PluginFunction` declares `info` optional, so destructuring `outputFile` from it fails TS2339 under `strictNullChecks`; read it with `info?.outputFile`. `format` is only assigned when `config.format` is set, so type it `string | undefined` (TS2454). Types only; generated output is unchanged. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_016PjJDfAYR1JPdgiQRvvZZy eddeee888:oss:issue-fix Co-authored-by: Claude --- packages/plugins/other/time/src/index.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/plugins/other/time/src/index.ts b/packages/plugins/other/time/src/index.ts index b180a255666..a2a804b4898 100644 --- a/packages/plugins/other/time/src/index.ts +++ b/packages/plugins/other/time/src/index.ts @@ -9,9 +9,10 @@ export const plugin: PluginFunction = async ( schema: GraphQLSchema, documents: Types.DocumentFile[], config: TimePluginConfig, - { outputFile }, + info, ): Promise => { - let format: string; + const outputFile = info?.outputFile; + let format: string | undefined; let message = 'Generated on '; if (config && typeof config === 'object') { From df288d8e047bbb7581a9bdc34c465a2988535e80 Mon Sep 17 00:00:00 2001 From: Eddy Nguyen Date: Fri, 25 Sep 2026 15:29:49 +1000 Subject: [PATCH 2/2] [document-nodes] fix: skip files without a document and annotate filter param under strict mode (#4683) (#10990) * [document-nodes] fix: assert document and annotate filter param under strict mode (#4683) `Types.DocumentFile.document` is optional, so `documents.map(v => v.document)` is `(DocumentNode | undefined)[]` and fails TS2345 under `strictNullChecks`. The CLI only passes files with a document and core already asserts `file.document!`, so assert it here too. `oldVisit()` returns `any`, so annotate the `filter` param as `unknown` (TS7006). Types only; generated output is unchanged. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_016PjJDfAYR1JPdgiQRvvZZy eddeee888:oss:issue-fix * [document-nodes] fix: filter out files without a document before concatAST (#4683) Replace the `v.document!` assertion with an inline type-guarded filter (`!!v.document`), so files without a `document` are skipped instead of reaching `concatAST`. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_016PjJDfAYR1JPdgiQRvvZZy eddeee888:oss:issue-fix --------- Co-authored-by: Claude --- .changeset/quiet-foxes-skip.md | 5 +++++ .../plugins/typescript/document-nodes/src/index.ts | 10 +++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 .changeset/quiet-foxes-skip.md diff --git a/.changeset/quiet-foxes-skip.md b/.changeset/quiet-foxes-skip.md new file mode 100644 index 00000000000..c8854ce8573 --- /dev/null +++ b/.changeset/quiet-foxes-skip.md @@ -0,0 +1,5 @@ +--- +'@graphql-codegen/typescript-document-nodes': patch +--- + +Skip documents without a `document` AST instead of throwing from `concatAST` when the plugin is called directly with one. Generated output from the CLI is unchanged. diff --git a/packages/plugins/typescript/document-nodes/src/index.ts b/packages/plugins/typescript/document-nodes/src/index.ts index e0602f26b9c..76d28ffbdef 100644 --- a/packages/plugins/typescript/document-nodes/src/index.ts +++ b/packages/plugins/typescript/document-nodes/src/index.ts @@ -1,4 +1,4 @@ -import { concatAST, FragmentDefinitionNode, GraphQLSchema, Kind } from 'graphql'; +import { concatAST, FragmentDefinitionNode, GraphQLSchema, Kind, type DocumentNode } from 'graphql'; import { oldVisit, PluginFunction, PluginValidateFn, Types } from '@graphql-codegen/plugin-helpers'; import { LoadedFragment, @@ -167,7 +167,11 @@ export const plugin: PluginFunction = ( documents: Types.DocumentFile[], config: TypeScriptDocumentNodesRawPluginConfig, ) => { - const allAst = concatAST(documents.map(v => v.document)); + const allAst = concatAST( + documents + .filter((v): v is Types.DocumentFile & { document: DocumentNode } => !!v.document) + .map(v => v.document), + ); const allFragments: LoadedFragment[] = [ ...( @@ -190,7 +194,7 @@ export const plugin: PluginFunction = ( prepend: visitor.getImports(), content: [ visitor.fragments, - ...visitorResult.definitions.filter(t => typeof t === 'string'), + ...visitorResult.definitions.filter((t: unknown) => typeof t === 'string'), ].join('\n'), }; };