Repository navigation
[plugin-helpers] fix: satisfy strict mode in plugin-helpers (#4683) - #11019
Merged
Merged
Conversation
Fixes 20 of the 23 errors `utils/plugins-helpers` hits once the root
tsconfig enables `strict: true`, without casts:
- federation: `getDirectivesByName` accepts `null | undefined`, since
graphql's `astNode` is `Maybe<FieldDefinitionNode>` (TS2345). `.reduce`
calls get explicit type args instead of starting from an untyped `[]`/`{}`
(TS2769, TS2488, TS7053). `|| []` fallbacks for graphql's optional
`directives`/`arguments` (TS18048). A `@key`/`@requires`/`@provides`
without a `fields` argument, or a `fields` value without a query, throws
an explicit Error instead of the TypeError it hits today (TS18048).
- helpers: `normalizeConfig` reduces into `Types.ConfiguredPlugin[]`
(TS2322, TS2769). `isUsingTypes`'s `SelectionSet` enter takes
`parent` as `... | undefined` like graphql's visit fn, with a guard
(TS2769). A missing Query/Mutation/Subscription root type throws an
explicit Error instead of a TypeError (TS2533). `schema.getType` is only
called with a type name (TS2345).
- utils: `mergeOutputs` collects into local `prepend`/`append` arrays, so
the public `ComplexPluginOutput` fields stay optional (TS18048, TS2488).
Exported types changed:
- `ProfilerEvent.cat` is optional: the Trace Event format makes it
optional and `Profiler.run(fn, name, cat?)` passes it through as-is
(TS2322). Trace JSON is unchanged, since `JSON.stringify` drops the
undefined `cat` as before.
- `FederationMeta`'s `ReferenceSelectionSet` is
`{ [field: string]: true | ReferenceSelectionSet }`, which is what the
`SelectionSet` leave visitor returns for nested selections such as
`company { taxCode }`; `DirectiveSelectionSet.selection` matches. Its only
consumers (visitor-plugin-common's base-resolvers-visitor and
typescript-resolvers) read `referenceSelectionSetsString`, not the sets.
The remaining 3 errors (TS7006 on the untyped `oldVisit` callbacks in
federation) are fixed by typing `oldVisit`'s visitor.
Generated output is unchanged. The strict typecheck goes from 228 to 208 errors.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UcXG2hnduGFaXB3oCtb8UX
eddeee888:oss:issue-fix
`oldVisit`'s `visitor` param is typed as the exported `OldVisitor`
instead of `any`: `enter`/`leave` maps keyed by AST node kind
(graphql's `ASTKindToNode` keys), whose callbacks take
`(node: ASTKindToNode[K], key: string | number | undefined, parent: any,
path: ReadonlyArray<string | number>,
ancestors: ReadonlyArray<ASTNode | ReadonlyArray<ASTNode>>) => unknown`,
matching graphql's `ASTVisitFn`. This types the federation leave
callbacks' `node` param (TS7006).
The callbacks are declared with method syntax so their params are checked
bivariantly: the visitor classes passed as `{ leave: visitor }` declare
`ancestors: ASTNode[]` and a required `key: string | number`, which a
strict function type would reject.
typescript and typescript-operations: `InputValueDefinition` takes `path`
and `ancestors` (and, in operations, `key` and `parent`) as required
params, since the visitor always passes them. Optional params there
include `undefined`, which the readonly/mutable array mismatch leaves no
bivariant direction to accept under strict mode (TS2769 at the
`oldVisit(..., { leave: visitor })` calls). Operations' `path` is
`ReadonlyArray<string | number>` like graphql's.
Adds the changeset for both commits.
Generated output is unchanged. The strict typecheck goes from 208 to 205 errors.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UcXG2hnduGFaXB3oCtb8UX
eddeee888:oss:issue-fix
🦋 Changeset detectedLatest commit: db315f7 The changes in this PR will be included in the next version bump. This PR includes changesets to release 3 packages
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 |
Contributor
🚀 Snapshot Release (
|
| Package | Version | Info |
|---|---|---|
@graphql-codegen/time |
7.1.1-alpha-20261001102714-db315f7d811d91a74e4b24f6d73df1b0fcb44619 |
npm ↗︎ unpkg ↗︎ |
@graphql-codegen/visitor-plugin-common |
7.2.8-alpha-20261001102714-db315f7d811d91a74e4b24f6d73df1b0fcb44619 |
npm ↗︎ unpkg ↗︎ |
@graphql-codegen/typescript-operations |
6.1.10-alpha-20261001102714-db315f7d811d91a74e4b24f6d73df1b0fcb44619 |
npm ↗︎ unpkg ↗︎ |
@graphql-codegen/typescript |
6.1.1-alpha-20261001102714-db315f7d811d91a74e4b24f6d73df1b0fcb44619 |
npm ↗︎ unpkg ↗︎ |
@graphql-codegen/client-preset |
6.2.1-alpha-20261001102714-db315f7d811d91a74e4b24f6d73df1b0fcb44619 |
npm ↗︎ unpkg ↗︎ |
@graphql-codegen/plugin-helpers |
7.4.1-alpha-20261001102714-db315f7d811d91a74e4b24f6d73df1b0fcb44619 |
npm ↗︎ unpkg ↗︎ |
eddeee888
commented
Oct 1, 2026
eddeee888
commented
Oct 1, 2026
eddeee888
commented
Oct 1, 2026
eddeee888
commented
Oct 1, 2026
eddeee888
commented
Oct 1, 2026
…s be inferred (#4683) graphql's visit already types node as SelectionSetNode and parent as ASTNode | ReadonlyArray<ASTNode> | undefined from context. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UcXG2hnduGFaXB3oCtb8UX
…FederationReferencesToSchema (#4683) base is already ReferenceSelectionSet[], so reduce(cb, {}) infers it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UcXG2hnduGFaXB3oCtb8UX
…4683) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UcXG2hnduGFaXB3oCtb8UX
eddeee888
commented
Oct 1, 2026
Comment on lines
+35
to
+41
| /** | ||
| * The `visitor` argument of `oldVisit`: `enter` and `leave` visitor maps keyed by AST node kind. | ||
| */ | ||
| export interface OldVisitor { | ||
| enter?: OldVisitorKindMap; | ||
| leave?: OldVisitorKindMap; | ||
| } |
Collaborator
Author
There was a problem hiding this comment.
What's the difference between visit vs oldVisit? Keep it short dotpoints
Collaborator
Author
There was a problem hiding this comment.
- Visitor shape:
visit(graphql, 17.0.2 here) groups handlers by kind first:{ Field: { enter, leave } }. A top-levelenter/leaveis a single function that runs for every node.oldVisittakes the older "parallel" shape, whereenter/leaveare maps by kind:{ leave: { Field() {}, Document() {} } }. graphql-js v16 dropped that shape (it was the 4th form in the v15visitdocs). - What
oldVisitdoes: it reshapes{ enter: { K }, leave: { K } }into{ K: { enter, leave } }and callsvisit(oldVisit.ts#L55-L72). It passes any other keys straight through. Traversal, replacing nodes with whatleavereturns, and the(node, key, parent, path, ancestors)args are allvisit's own. - Why it's kept: every visitor class is used as
oldVisit(ast, { leave: visitor }). The class's methods are named after the kinds (FieldDefinition,NamedType, …), so a class instance works directly as a by-kindleavemap. - Types:
visitis typed by graphql'sASTVisitor.oldVisit's visitor is nowOldVisitor(this PR).
Generated by Claude Code
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.
Description
Part of the
strict: truetracker #10985. This fixes the 23 errorsutils/plugins-helpershits under strict mode, corrects two exported types that were wrong, and typesoldVisit'svisitorparam.Local fixes, no new casts
federation.tsreducecalls get a type argument (reduce<string[]>,reduce<ReferenceSelectionSet>) instead of an untyped[]/{}start value (TS2769, TS2488, TS7053).getDirectivesByNameaccepts graphql'sMaybe<FieldDefinitionNode>(TS2345).directives/argumentsget|| []fallbacks (TS18048).fieldsargument, or with afieldsvalue that doesn't parse to a query, throws a descriptive error. It used to throw aTypeError.helpers.tsnormalizeConfigusesreduce<Types.ConfiguredPlugin[]>(TS2322, TS2769).isUsingTypes'sparentparam allowsundefinedlike graphql's visitor does (TS2769).TypeError(TS2533).nulltype name no longer goes togetType(TS2345).utils.ts:mergeOutputsbuilds localprepend/appendarrays instead of reusingComplexPluginOutput, whose fields are optional (TS18048, TS2488).Exported types corrected
ProfilerEvent.catis optional. It matchesProfiler.run's optionalcatand the Trace Event format (TS2322). Trace files are unchanged.ReferenceSelectionSet(exposed throughFederationMeta) is recursive:{ [field: string]: true | ReferenceSelectionSet }. It used to beRecord<string, boolean>, but nested selections likecompany { taxCode }produce objects, not booleans.DirectiveSelectionSet.selectionchanges to match.oldVisittypedvisitorparam is the new exportedOldVisitortype:enter/leavemaps keyed by AST node kind. Their callbacks get the typed node plus graphql'skey,parent,pathandancestors(TS7006 on the federation visitor callbacks).@types/react'sbivarianceHack. That way visitor class instances whose methods declare narrower param types (such asancestors: ASTNode[]) are still accepted without casts.typescript's andtypescript-operations'InputValueDefinitionvisitor methods takepathandancestorsas required. graphql'svisitalways passes them.Generated output is unchanged. The strict typecheck goes from 228 to 205 errors: 0 in
plugins-helpers, and no package's count goes up.This is the most thorough of the three options discussed. The other two were "local fixes only" and "also correct the two exported types". We picked it so the exported types and
oldVisitget typed properly instead of worked around.Related #4683
Type of change
How Has This Been Tested?
tsc --noEmit -p tsconfig.jsonwith the tracker's stricttsconfig.json: 0 errors underpackages/utils/plugins-helpers, and no other package's count goes up.pnpm types:check(the current non-strict config) is clean.vitestforplugin-helpers,typescript,typescript-operations,typescript-resolvers,typescript-document-nodes,typed-document-node,visitor-plugin-commonandcorepasses. Thecliproject has 72 failures about plugin/preset resolution in this environment. The same tests fail on a cleanmastercheckout.🤖 Generated with Claude Code
https://claude.ai/code/session_01UcXG2hnduGFaXB3oCtb8UX
Generated by Claude Code