fix(es/transforms): avoid rewriting unknown relative extensions#11713
fix(es/transforms): avoid rewriting unknown relative extensions#11713
Conversation
🦋 Changeset detectedLatest commit: 15f192c The changes in this PR will be included in the next version bump. 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 |
Binary Sizes
Commit: 5f276f7 |
PR Review: fix(es/transforms): avoid rewriting unknown relative extensionsSummaryClean, well-scoped fix. The core change (2 lines in Code Quality
Test Coverage
Minor Observations
VerdictLooks good to merge. The fix is minimal, correct, well-tested, and aligned with both the TypeScript reference implementation and the existing runtime helper. |
PR ReviewOverall: Clean, well-scoped fix. The change correctly aligns SWC's Code QualityThe fix is minimal and correct. Changing the catch-all The match arms now explicitly enumerate every supported mapping, making the behavior self-documenting and easy to audit against the TypeScript reference implementation. Potential Issues
Test CoverageThe new fixture covers both key cases from the issue:
One minor suggestion: consider also covering PerformanceNo concerns — the change is a constant-time match arm adjustment with no new allocations or branching overhead. SecurityNo concerns. LGTM — this is a clean bug fix with appropriate test coverage. |
There was a problem hiding this comment.
Pull request overview
Fixes jsc.rewriteRelativeImportExtensions so unknown relative extensions are no longer rewritten to .js, aligning behavior with TypeScript (issue #11644).
Changes:
- Update TypeScript import rewriter to only rewrite a known set of extensions; unknown extensions now result in no rewrite.
- Add a regression fixture for
./index.legacy(unchanged) and./index.legacy.ts(rewritten to.js). - Add a changeset documenting the patch release.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| crates/swc_ecma_transforms_module/src/rewriter/import_rewriter_typescript.rs | Stop defaulting unknown extensions to .js; return None to skip rewrite. |
| crates/swc/tests/typescript/rewrite-relative-import-specifier/issue-11644/input/main.ts | New fixture input reproducing the problematic import specifiers. |
| crates/swc/tests/typescript/rewrite-relative-import-specifier/issue-11644/output/main.ts | New fixture output asserting correct rewrite/no-rewrite behavior. |
| crates/swc/tests/typescript/rewrite-relative-import-specifier/issue-11644/input/.swcrc | Fixture config enabling rewriteRelativeImportExtensions under nodenext. |
| .changeset/smooth-games-knock.md | Patch changeset for swc_core and transform crate. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| let ext = path.extension()?.to_str()?; | ||
| let ext = match ext { | ||
| "js" | "ts" => "js", | ||
| "json" => "json", | ||
| "jsx" | "tsx" => "jsx", | ||
| "mjs" | "mts" => "mjs", | ||
| "cjs" | "cts" => "cjs", | ||
| _ => "js", | ||
| _ => return None, | ||
| }; |
There was a problem hiding this comment.
If the intent is to match TypeScript behavior closely, consider normalizing ext to ASCII-lowercase before matching. As written, specifiers like ./foo.TS (or any mixed-case extension) will not be rewritten even though they are effectively the same extension on case-insensitive platforms.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 15f192c6fd
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| let ext = match ext { | ||
| "js" | "ts" => "js", | ||
| "json" => "json", | ||
| "jsx" | "tsx" => "jsx", | ||
| "mjs" | "mts" => "mjs", | ||
| "cjs" | "cts" => "cjs", | ||
| _ => "js", | ||
| _ => return None, |
There was a problem hiding this comment.
Keep mixed-case TS extensions rewriteable
With jsc.rewriteRelativeImportExtensions enabled, literal specifiers such as import "./foo.TS" or export * from "../bar.MTS" now hit _ => return None, so the emitted JS keeps the .TS/.MTS suffix instead of rewriting to .js/.mjs. That is a regression from the previous fallback behavior, and it also diverges from our dynamic-path helper in crates/swc_ecma_transforms_base/src/helpers/_ts_rewrite_relative_import_extension.js:3, which still matches these extensions case-insensitively via /...ts$/i.
Useful? React with 👍 / 👎.
Summary
This PR fixes
jsc.rewriteRelativeImportExtensionsrewriting unknown relative extensions to.js.Previously, specifiers like
./index.legacywere rewritten to./index.jsbecause unknown extensions fell through to a default rewrite. This diverged from TypeScript behavior.This change makes rewriting extension-aware and only rewrites supported extensions:
ts | js -> jstsx | jsx -> jsxmts | mjs -> mjscts | cjs -> cjsjson -> jsonAlso adds fixture coverage for issue
#11644to assert:import "./index.legacy"stays unchangedimport "./index.legacy.ts"rewrites toimport "./index.legacy.js"Closes #11644.
Testing
git submodule update --init --recursivecargo test -p swc --test projects ts_id_tests__typescript__rewrite_relative_import_specifier__issue_11644__input -- --exact --ignored --nocapturecargo test -p swc --test projects rewrite_relative_import_specifier -- --ignoredcargo fmt --allcargo clippy --all --all-targets -- -D warningscargo test -p swc_ecma_transforms_modulecargo test -p swcwas also run; unrelatedtests/source_mapcases failed in this environment because Node modulesourcemap-validatoris missing.