Skip to content

[visitor-plugin-common] fix: satisfy strict mode in utils and the remaining files (#4683) - #11039

Merged
eddeee888 merged 8 commits into
masterfrom
claude/great-davinci-qb65pc
Oct 8, 2026
Merged

eddeee888 merged 8 commits into
masterfrom
claude/great-davinci-qb65pc

Conversation

@eddeee888

@eddeee888 eddeee888 commented Oct 5, 2026 •

Copy link
Copy Markdown
Collaborator

Description

Part 3b, the last part of the strict-mode work tracked in #10985. It fixes the 46 errors left in visitor-plugin-common that strict: true raises, in utils, imports, naming, mappers, types, variables-to-object, convert-schema-enum-to-declaration-block-string, selection-set-processor/base and optimize-operations. With this PR, #10985's strict tsconfig.json typechecks with 0 errors.

Related #4683

As in #11030 and #11037, types are widened where they're declared, with no new as casts or !:

  • transformComment and block accept null/undefined, buildScalars accepts undefined, and DeclarationBlock.withBlock accepts null. Each already handles that value.
  • DeclarationBlock's fields initialised to null are typed as string | null.
  • ParsedEnumValuesMap's mappedValues, sourceIdentifier, sourceFile and importIdentifier accept null, which parseEnumValues already emits.
  • OperationVariablesToObject.getName/transform and BaseSelectionSetProcessor.buildSelectionSetFromStrings return string | null, which they already return.
  • buildTypeImport, buildEnumValuesBlock and optimizeOperations throw a descriptive error where they used to crash or emit undefined.
  • Optional AST fields (values, identifiers, @deprecated arguments) are treated as empty instead of throwing, and DeclarationBlock returns the block unchanged when blockTransformer is undefined.
  • naming.ts drops its as casts by holding namingConvention in a narrowed local. The only cast in the lines this PR touches is in isOneOfInputObjectType, with a comment: isOneOf exists only from graphql 16.9.
  • Now that transformComment accepts undefined, base-types-visitor drops the || '' it needed in [visitor-plugin-common] fix: satisfy strict mode in base-types-visitor (#4683) #11037.

The changeset lists every public signature and behaviour change. One change to emitted text: OperationVariablesToObject now emits '' instead of the text undefined/null when a variable has no name or type identifier. No current input reaches that case.

Type of change

  • Bug fix (non-breaking change which fixes an issue)

How Has This Been Tested?

  • Unit tests (visitor-plugin-common, typescript, operations, resolvers, document-nodes, typed-document-node, client-preset, graphql-modules-preset)
  • pnpm dev-test:generate gives no diff, so generated output for the dev-tests is unchanged
  • pnpm exec tsc --noEmit -p tsconfig.json with chore: enable strict: true in root tsconfig (#4683) #10985's strict tsconfig.json gives 0 errors (46 on master)

Further comments

Once this merges, every box in #10985's checklist is ticked, and #10985 can be rebased and merged to turn on strict: true.

Like #11030 and #11037, this is marked as a bug fix. The string | null return types only widen what these methods already return at runtime, but downstream TypeScript users with strictNullChecks may need to handle null where they call them.

🤖 Generated with Claude Code

claude added 4 commits October 5, 2026 22:10
…aining files (#4683)

Widen transformComment, buildScalars, buildTypeImport (now throws on a missing
identifier/source), DeclarationBlock fields/withBlock and ParsedEnumValuesMap to
accept nullish values; getName/transform/buildSelectionSetFromStrings may return null.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N2WHcqFc3QgDV5mTdEiuGv

eddeee888:oss:issue-fix
…angeset

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N2WHcqFc3QgDV5mTdEiuGv
…-types-visitor

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N2WHcqFc3QgDV5mTdEiuGv
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N2WHcqFc3QgDV5mTdEiuGv
@changeset-bot

changeset-bot Bot commented Oct 5, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: f6a1521

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

This PR includes changesets to release 1 package
Name Type
@graphql-codegen/visitor-plugin-common Patch

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

@github-actions

github-actions Bot commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

🚀 Snapshot Release (alpha)

The latest changes of this PR are available as alpha on npm (based on the declared changesets):

Package Version Info
@graphql-codegen/visitor-plugin-common 7.2.10-alpha-20261008113517-f6a15212900320001c38eab32d778f40b34618a9 npm ↗︎ unpkg ↗︎

.withContent(
'\n' +
node.values
(node.values || [])

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.

Note: values is optional on EnumTypeDefinitionNode, and this function is exported, so a caller can pass in a node that has none. That makes || [] real handling, which is why it has no comment. Each if branch returns early and reads node.values only once, so the fallback stays inline in each branch (same at L98, L133 and L167) instead of going in a local at the top.


Generated by Claude Code

? (schema.getType(typeName) as GraphQLEnumType)
: undefined;
const schemaType = schema?.getType(typeName);
const schemaEnumType = isEnumType(schemaType) ? schemaType : undefined;

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.

Note: This uses an isEnumType guard instead of the as GraphQLEnumType cast, so the narrowing is checked rather than asserted. If a schema type with this name isn't an enum, it's treated as having no schema enum instead of crashing on .getValue. That's also why isEnumType is now a value import, with inline type specifiers for the rest.


Generated by Claude Code

schemaEnumType && !ignoreEnumValuesFromSchema
? schemaEnumType.getValue(enumOption.name.value).value
: undefined;
let schemaEnumValue;

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.

Note: The ternary became a let and an if, because throwing on a missing enum value needs a statement. The let has no annotation: TypeScript infers its type from the assignment below.


Generated by Claude Code

Comment on lines +129 to +131
importIdentifier?: string | null;
sourceIdentifier?: string | null;
sourceFile?: string | null;

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.

Note: These are the params of the nested handleEnumValueMapper, not of the exported getEnumsImports, whose signature is unchanged. They're optional to match the ParsedEnumValuesMap fields that get passed straight in.


Generated by Claude Code

Comment thread packages/plugins/other/visitor-plugin-common/src/imports.ts

export function transformMappers(
rawMappers: RawResolversConfig['mappers'],
rawMappers: RawResolversConfig['mappers'] = {},

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.

Note: I gave the param a default instead of adding || {} inside the function, because mappers is optional in the raw config. Callers that pass undefined get an empty map, and the body stays as it was.


Generated by Claude Code


public get string(): string {
let result = '';
const blockTransformer = this._config.blockTransformer || (block => block);

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.

Note: The fallback is in the getter rather than the constructor's defaults. The constructor spreads the caller's config over the defaults, so an explicit blockTransformer: undefined still gets through. A single local here covers all three call sites below.


Generated by Claude Code

// dropping support for older graphql versions
(((namedType as unknown as Record<'isOneOf', boolean | undefined>).isOneOf ||
namedType.astNode?.directives?.some(d => d.name.value === 'oneOf')) ??
false);

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.

Note: The ?? false is needed because astNode?.directives?.some(...) gives undefined when there are no directives, and the cache is a Map<…, boolean>. Callers only check truthiness, so caching false doesn't change what they get.


Generated by Claude Code

export function unique<T>(
array: Array<T>,
key: (item: T) => string | number = item => item.toString(),
key: (item: T) => string | number = item => String(item),

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.

Note: T is unconstrained, so under strict TypeScript doesn't know item.toString() exists. String(item) gives the same key for the strings and numbers this is used with.


Generated by Claude Code

@eddeee888
eddeee888 marked this pull request as ready for review October 8, 2026 12:40
@eddeee888
eddeee888 merged commit 5078faf into master Oct 8, 2026
22 checks passed
@eddeee888
eddeee888 deleted the claude/great-davinci-qb65pc branch October 8, 2026 12:44
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