Add options for import file extensions and type-only imports - #1830
Add options for import file extensions and type-only imports#1830Upgrade220 wants to merge 3 commits into
Conversation
Generated relative imports were extensionless and value-only, which
breaks moduleResolution node16/nodenext (needs .js), allowImportingTsExtensions
(needs .ts), and verbatimModuleSyntax (needs import type). Users had to
post-process the output by hand.
- importFileExtension ("" | ".js" | ".ts") appends an extension to
generated relative imports.
- typeOnlyImports emits `import type` for the wholly type-only
data-contracts import and inline `type` for the mixed http-client
import, keeping HttpClient a value import. ContentType is marked
`type` only for enumStyle "union".
Both are exposed as CLI flags. Defaults preserve current output.
Closes acacode#1829
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
🦋 Changeset detectedLatest commit: 4f0dcb2 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
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 |
There was a problem hiding this comment.
1 issue found across 10 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="index.ts">
<violation number="1" location="index.ts:364">
P2: When a CLI user passes a value other than `""`, `.js`, or `.ts`, this flag accepts it and the cast does not validate it at runtime. Validate and reject unsupported extensions before passing the value to `generateApi`, otherwise generation can produce imports that do not point to generated files.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| | "const" | ||
| | "const-enum" | ||
| | undefined, | ||
| importFileExtension: args["import-file-extension"] as |
There was a problem hiding this comment.
P2: When a CLI user passes a value other than "", .js, or .ts, this flag accepts it and the cast does not validate it at runtime. Validate and reject unsupported extensions before passing the value to generateApi, otherwise generation can produce imports that do not point to generated files.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At index.ts, line 364:
<comment>When a CLI user passes a value other than `""`, `.js`, or `.ts`, this flag accepts it and the cast does not validate it at runtime. Validate and reject unsupported extensions before passing the value to `generateApi`, otherwise generation can produce imports that do not point to generated files.</comment>
<file context>
@@ -349,6 +361,12 @@ const generateCommand = defineCommand({
| "const"
| "const-enum"
| undefined,
+ importFileExtension: args["import-file-extension"] as
+ | ""
+ | ".js"
</file context>
Address PR review feedback: - Reject unsupported importFileExtension values at runtime (in config update), so CLI/config-file callers that bypass the type get a clear error instead of broken imports. Explicit undefined normalizes to "". - Add route-type coverage (generateRouteTypes) asserting the extension and type-only import behavior of route-types.ejs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Thanks for the review — both addressed in 4f0dcb2:
|
Closes #1829
Problem
The generated client emits extensionless, value-only relative imports:
This breaks two increasingly common TypeScript setups, with no built-in option to change it — users must post-process the output by hand:
moduleResolution: "node16" | "nodenext"requires explicit extensions on relative imports; the generated./data-contracts/./http-clientfail to resolve at runtime (ESM) and are flagged by the compiler.allowImportingTsExtensionsneeds.tsinstead.verbatimModuleSyntax/isolatedModules. Type-only names (data contracts,RequestParams,HttpResponse, andContentTypeinenumStyle: "union") are imported as values, which is an error under those flags.The http-client import is mixed:
HttpClientis a runtime class and must stay a value import, whileRequestParams/HttpResponseare type-only — so it needs per-specifier inlinetype, not a whole-blockimport type.Solution
Two new options, both defaulting to current behavior (no change to existing output):
importFileExtension: "" | ".js" | ".ts"(default"") — appended to generated relative imports..jsfornode16/nodenext,.tsforallowImportingTsExtensions.typeOnlyImports: boolean(defaultfalse) — emitsimport typefor the wholly type-only data-contracts import, and inlinetypeon the mixed http-client import, keepingHttpClienta value import.ContentTypeis markedtypeonly forenumStyle: "union"(where it is a pure type); forenum/const/const-enumit stays a runtime value.Both are exposed as CLI flags (
--import-file-extension,--type-only-imports).Implemented at the template level (
templates/modular/api.ejs,templates/modular/route-types.ejs,templates/default/route-types.ejs) rather than as a post-processing pass, since the templates already know the import paths and which specifiers are types.Example — replacing a typical hand-rolled Node16 post-process:
Produces:
Verification
tests/spec/import-file-extension/(8 tests):.js/.tsextensions, default (no extension), whole-blockimport typefor data-contracts, inlinetypeon the mixed http-client import withHttpClientkept as a value,ContentTypevalue-vs-type per enum style, and the combined case.bun run buildpasses; no new lint warnings/errors introduced.Notes
minor)./.idea/and/.serena/to.gitignore.Summary by cubic
Adds
importFileExtensionandtypeOnlyImportsoptions so generated relative imports work withmoduleResolution: node16/nodenext,allowImportingTsExtensions, andverbatimModuleSyntax/isolatedModules. Both default to current behavior, so existing output is byte-identical.New Features
importFileExtension(""|".js"|".ts") appends an extension to generated relative imports; use.jsfornode16/nodenextand.tsforallowImportingTsExtensions.importFileExtensionvalues are rejected at runtime; explicitundefinednormalizes to"".typeOnlyImportsemits whole-blockimport typefor data-contracts and inlinetypeon the mixed http-client import, keepingHttpClientas a value import.ContentTypeis only markedtypeforenumStyle: "union", where it is a pure type.--import-file-extensionand--type-only-imports./.idea/and/.serena/to.gitignore.Written for commit 4f0dcb2. Summary will update on new commits.