Repository navigation
[cli] fix: satisfy strict mode in cli (#4683) - #11020
Conversation
🦋 Changeset detectedLatest commit: ab81a7a The changes in this PR will be included in the next version bump. This PR includes changesets to release 2 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 |
🚀 Snapshot Release (
|
| Package | Version | Info |
|---|---|---|
@graphql-codegen/cli |
7.4.4-alpha-20261003115436-ab81a7a7be052e891d8b91b917f9289469c34d81 |
npm ↗︎ unpkg ↗︎ |
@graphql-codegen/time |
7.1.1-alpha-20261003115436-ab81a7a7be052e891d8b91b917f9289469c34d81 |
npm ↗︎ unpkg ↗︎ |
@graphql-codegen/visitor-plugin-common |
7.2.8-alpha-20261003115436-ab81a7a7be052e891d8b91b917f9289469c34d81 |
npm ↗︎ unpkg ↗︎ |
@graphql-codegen/typescript-operations |
6.1.10-alpha-20261003115436-ab81a7a7be052e891d8b91b917f9289469c34d81 |
npm ↗︎ unpkg ↗︎ |
@graphql-codegen/typescript |
6.1.1-alpha-20261003115436-ab81a7a7be052e891d8b91b917f9289469c34d81 |
npm ↗︎ unpkg ↗︎ |
@graphql-codegen/client-preset |
6.2.1-alpha-20261003115436-ab81a7a7be052e891d8b91b917f9289469c34d81 |
npm ↗︎ unpkg ↗︎ |
@graphql-codegen/plugin-helpers |
7.4.1-alpha-20261003115436-ab81a7a7be052e891d8b91b917f9289469c34d81 |
npm ↗︎ unpkg ↗︎ |
| "@types/js-yaml": "4.0.9", | ||
| "@types/micromatch": "^4.0.2", | ||
| "@types/shell-quote": "1.7.5", | ||
| "@types/yargs": "^17.0.35", |
There was a problem hiding this comment.
Note: @types/yargs 17 is used with yargs 18 because there is no 18 line of the types, and yargs 18 doesn't ship types for its root entry. The cli only calls yargs(argv).version().options().parse(), and that result is still as any, so the 17 typings cover what's used.
Generated by Claude Code
| "@types/babel__generator": "7.27.0", | ||
| "@types/babel__template": "7.4.4", |
There was a problem hiding this comment.
Note: pinned to the exact versions the lockfile already resolves for the other packages using them, so adding them brings in no new Babel type versions.
Generated by Claude Code
| 'ignore-no-documents'?: boolean; | ||
| 'emit-legacy-common-js-imports'?: boolean; | ||
| 'import-extension'?: '' | `.${string}`; |
There was a problem hiding this comment.
Note: added the kebab-case keys to the type instead of switching updateContextWithCliFlags to read the camelCase ones. Those reads have their own handling for the 'false' string value, and changing which key they read is a runtime change this typing-only fix shouldn't make.
Generated by Claude Code
| getConfig(): Types.Config; | ||
| getConfig<T>(extraConfig: T): T & Types.Config; | ||
| getConfig<T>(extraConfig?: T): Types.Config | (T & Types.Config) { |
There was a problem hiding this comment.
Note: overloads rather than a cast on the return. The no-argument calls (updateConfig, makeGlobalPatternSet) get plain Types.Config, while getConfig(defaultSchemaLoadOptions) keeps the T & Types.Config intersection, and neither call site changes.
Generated by Claude Code
| let queue: Array<{ | ||
| message: string; | ||
| meta?: any[]; | ||
| meta: any[]; |
There was a problem hiding this comment.
Why need this change?
There was a problem hiding this comment.
Under strict mode, printLogs spreads ...log.meta (debugging.ts#L17). With `meta?: any[]` that's `any[] | undefined`, and spreading it fails with TS2488. `meta` is never actually missing: `debugLog` always pushes its rest param `...meta: any[]` ([L8-L12](https://github.com/dotansimha/graphql-code-generator/blob/ab81a7a7be052e891d8b91b917f9289469c34d81/packages/graphql-codegen-cli/src/utils/debugging.ts#L8-L12)),`` which is [] when no extra args are passed. Making it required matches what's stored, needs no || [] fallback, and doesn't change runtime behaviour.
Generated by Claude Code
| ...(typeof config.watch === 'boolean' | ||
| ? [] | ||
| : normalizeInstanceOrArray<string>(config.watch ?? [])), | ||
| relative(process.cwd(), initialContext.filepath), |
There was a problem hiding this comment.
This seems to change runtime behaviour?
Explain why needed
There was a problem hiding this comment.
Yes, it changes runtime behaviour, but only when filepath is undefined. If there is a filepath, the pattern list is the same as before.
filepath is undefined when generate() is called programmatically with a config object instead of a config file. In that case:
ensureContextbuildsnew CodegenContext({ config: input })with nofilepath(config.ts#L507).- With
watchset,generate()callscreateWatcher(context, …)(generate-and-save.ts#L188-L189),and that calls `makeGlobalPatternSet(initialContext)` ([watcher.ts#L55](https://github.com/dotansimha/graphql-code-generator/blob/ab81a7a7be052e891d8b91b917f9289469c34d81/packages/graphql-codegen-cli/src/utils/watcher.ts#L55)).`` - Before this PR, that ran
relative(process.cwd(), undefined), which throwsTypeError [ERR_INVALID_ARG_TYPE]: The "to" argument must be of type string. Received undefined(Nodepath.relativedocs: "A TypeError is thrown if either from or to is not a string").
So the only behaviour change is that programmatic watch mode without a config file now watches the schema and document patterns instead of crashing. There's no config file to watch in that case.
It's needed because filepath is now typed string | undefined, and relative() won't accept that under strict mode. The other ways to satisfy the type are:
initialContext.filepath || '': adds an empty pattern, which is also a runtime change.- Throwing a descriptive error when
filepathis missing: keeps the "fails" behaviour, like the descriptive throws in [plugin-helpers] fix: satisfy strict mode in plugin-helpers (#4683) #11019, but programmatic watch mode still can't be used.
If you'd rather this PR not change behaviour at all, I can switch to the descriptive throw.
Generated by Claude Code
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JcaAHEYKgZnuJ894vm8nRe eddeee888:oss:issue-fix
e566a64 to
ab81a7a
Compare
Description
Part of the
strict: truetracker #10985. This fixes the 32 errorsgraphql-codegen-clihits under strict mode, corrects the cli's exported types that didn't match runtime, and widens twoplugin-helpershelpers so cli call sites need no fallbacks.Missing type packages
@types/yargs,@types/babel__generatorand@types/babel__templateas cli devDeps (TS7016 undernoImplicitAny). The two Babel ones are already in the lockfile at these versions through other packages.Shared helpers widened
normalizeInstanceOrArrayandnormalizeConfiginplugin-helpersacceptnull/undefinedand return[].normalizeInstanceOrArray's body already did this.normalizeConfignow checksconfig &&beforeObject.keys, which threw onnullbefore (TS2345 at 9 call sites incodegen.ts).patterns.tsdrops its!assertions, a?? []fallback and the explicit generic arguments on these calls.Exported types corrected
loadCodegenConfigreturnsPromise<LoadCodegenConfigResult | null>. It already resolved tonullwhen no config file is found, andloadContextalready handled that (TS2322). The now-redundantresult.config as Types.Configcast is removed.CodegenContext.filepathis optional. A context created programmatically, likegenerate()without a config file, has none. Watch mode used to callrelative(process.cwd(), undefined)on it and threwERR_INVALID_ARG_TYPE. It now only watches the config file when there is one.YamlCliFlagsincludes the kebab-caseignore-no-documents,emit-legacy-common-js-importsandimport-extensionkeys thatupdateContextWithCliFlagsreads. yargs sets them (TS2551).CodegenContext.getConfig()has overloads: no argument returnsTypes.Config, andgetConfig(extraConfig)returnsT & Types.Config(TS2322).CodegenContext.checkModeStaleFilesisstring[]instead of an inferrednever[](TS2345 ingenerate-and-save.ts).Local fixes
codegen.ts: the preset ternary testsoutputConfig.presetdirectly, so TypeScript narrows it. The unusedhasPresetis removed.config.ts: the private_config/configfields are optional. A context without eitherconfigor a GraphQL Config gets a commentedgenerates: {}default, so it still fails with codegen's missing "generates" error.getCustomConfigPathreturnsundefinedinstead ofnull.graphql-config.ts:isGraphQLConfigacceptsundefined. It already checked for it.init/questions.ts:pluginsstarts as[], so client-preset answers getplugins: []instead ofundefined. Both consumers treat these the same.utils/debugging.ts:metais required, sincedebugLogalways sets it.utils/file-system.ts:unlinkFile's callback is required and typed asfs.unlink's(err: Error | null) => void. Without one,fs.unlinkthrows. The only caller always passes one.No new
ascasts or!assertions. Generated output is unchanged. The strict typecheck goes from 205 to 173 errors: 0 ingraphql-codegen-cli, and no other package's count changes.This is the middle of three options discussed. The others were "local fixes only", which left
loadCodegenConfigandfilepathmistyped, and "also deriveYamlCliFlagsfrom the yargs options and splitCodegenContextconstruction", which could be breaking. We picked this one so the exported types match runtime without a breaking change.pnpm-lock.yaml: besides the new@typespackages,pnpm dedupe(the repo's pre-commit step) collapses duplicatepostcssandtinyglobbycopies onto8.5.28and0.2.17. Both versions were already in the lockfile.Related #4683
Type of change
How Has This Been Tested?
tsc --noEmit -p tsconfig.jsonwith the tracker's stricttsconfig.json: 0 errors underpackages/graphql-codegen-cli, and no other package's count changes.pnpm types:check(the current non-strict config) is clean.vitestforcliandplugin-helpers: 114 pass. The same 72clitests about plugin/preset resolution fail in this environment on a cleanmastercheckout too.pnpm dedupe --checkwere run by hand on the changed files and are clean. The commit skipped the pre-commit hook, because in this container itspnpm deduperecreatesnode_moduleswhile eslint and prettier are running alongside it.🤖 Generated with Claude Code
https://claude.ai/code/session_01JcaAHEYKgZnuJ894vm8nRe
Generated by Claude Code