fix(js): a JavaScript file's import of a TypeScript module links that module (#2674)

An extensionless import from a `.js` or `.jsx` file of a TypeScript module,
like mastodon's `import AudioModal from './audio_modal'` in modal_root.jsx
beside audio_modal.tsx, never resolved by path: the import resolver's
javascript and jsx extension lists held only JavaScript extensions, while
the typescript and tsx lists already try `.js`/`.jsx`. In a codebase
moving to TypeScript those imports were matched by name instead, so an
import under another name linked nothing, and a repeated name could link
the wrong file (mastodon's `<IconButton>` and `<Status>` tags rendered
other same-named components than the ones each file imports).

The javascript and jsx lists now try `.ts`/`.tsx` (and their index files)
after their own extensions, as a bundler and tsc's allowJs resolve them.
JavaScript stays first, so a `helpers.ts` beside `helpers.js` does not
take its importers, and never `.d.ts`, which is no module a JavaScript
file runs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Colby Mchenry
2026-10-19 19:12:04 +00:00
committed by GitHub
co-authored by Claude Opus 5.5
parent ab6ec218ff
commit bf6995e911
3 changed files with 145 additions and 2 deletions
+7 -2
View File
@@ -42,9 +42,14 @@ const EXTENSION_RESOLUTION: Record<string, string[]> = {
// module-entry convention, hit when a bare workspace import ("data") is
// rewritten to the member's directory; lowercase variants for safety.
arkts: ['.ets', '.ts', '.d.ts', '.js', '/Index.ets', '/index.ets', '/index.ts', '/index.js'],
javascript: ['.js', '.jsx', '.mjs', '.cjs', '.xsjs', '.xsjslib', '/index.js', '/index.jsx'],
// A JavaScript file imports TypeScript modules too, as the bundler and
// tsc's `allowJs` read it: mastodon's `modal_root.jsx` imports
// `./audio_modal`, which is `audio_modal.tsx`. JavaScript comes first, so a
// `helpers.ts` beside `helpers.js` doesn't take its importers. Never `.d.ts`:
// a declaration file is not the module a JavaScript file runs.
javascript: ['.js', '.jsx', '.mjs', '.cjs', '.xsjs', '.xsjslib', '.ts', '.tsx', '/index.js', '/index.jsx', '/index.ts', '/index.tsx'],
tsx: ['.tsx', '.ts', '.d.ts', '.js', '.jsx', '/index.tsx', '/index.ts', '/index.js', '/index.jsx'],
jsx: ['.jsx', '.js', '/index.jsx', '/index.js'],
jsx: ['.jsx', '.js', '.tsx', '.ts', '/index.jsx', '/index.js', '/index.tsx', '/index.ts'],
// SFC consumers import plain TS/JS, sibling components, and barrels
// (`./lib` → `./lib/index.ts`). Without a list, relative imports from a
// `.svelte`/`.vue` file resolve to nothing, so barrel callers vanish (#629).