Skip to content

Commit

Permalink
feat(node-resolve): Resolve js/jsx/mjs/cjs imports from TypeScript files
Browse files Browse the repository at this point in the history
  • Loading branch information
meyfa committed May 17, 2023
1 parent baea9d9 commit e5a19b6
Show file tree
Hide file tree
Showing 10 changed files with 140 additions and 5 deletions.
17 changes: 12 additions & 5 deletions packages/node-resolve/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -146,11 +146,18 @@ export function nodeResolve(opts = {}) {
importSpecifierList.push(`./${importee}`);
}

// TypeScript files may import '.js' to refer to either '.ts' or '.tsx'
if (importer && importee.endsWith('.js')) {
for (const ext of ['.ts', '.tsx']) {
if (importer.endsWith(ext) && extensions.includes(ext)) {
importSpecifierList.push(importee.replace(/.js$/, ext));
// TypeScript files may import '.mjs' or '.cjs' to refer to either '.mts' or '.cts'.
// They may also import .js to refer to either .ts or .tsx, and .jsx to refer to .tsx.
if (importer && /\.(ts|mts|cts|tsx)$/.test(importer)) {
for (const [importeeExt, resolvedExt] of [
['.js', '.ts'],
['.js', '.tsx'],
['.jsx', '.tsx'],
['.mjs', '.mts'],
['.cjs', '.cts']
]) {
if (importee.endsWith(importeeExt) && extensions.includes(resolvedExt)) {
importSpecifierList.push(importee.slice(0, -importeeExt.length) + resolvedExt);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { main } from './main.cjs';
// This resolves as main.cts and _not_ main.cjs, despite the extension
const mainResult = main();
export default mainResult;
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// To make this very clearly TypeScript and not just CJS with a CTS extension
type TestType = string | string[];
interface Main {
(): string;
propertyCall(input?: TestType): TestType;
}

const main: Main = () => 'It works!';
main.propertyCall = () => '';

export { main };
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// To make this very clearly TypeScript and not just JS with a TS extension
type TestType = string | string[];
function MyComponent() {
return 'It works!';
}

export { MyComponent };
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { MyComponent } from './MyComponent.jsx';
// This resolves as MyComponent.tsx and _not_ MyComponent.jsx, despite the extension
const componentResult = MyComponent();
export default componentResult;
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { main } from './main.mjs';
// This resolves as main.mts and _not_ main.mjs, despite the extension
const mainResult = main();
export default mainResult;
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// To make this very clearly TypeScript and not just MJS with a MTS extension
type TestType = string | string[];
interface Main {
(): string;
propertyCall(input?: TestType): TestType;
}

const main: Main = () => 'It works!';
main.propertyCall = () => '';

export { main };
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// To make this very clearly TypeScript and not just JS with a TS extension
type TestType = string | string[];
function MyComponent() {
return 'It works!';
}

export { MyComponent };
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { MyComponent } from './MyComponent.js';
// This resolves as MyComponent.tsx and _not_ MyComponent.js, despite the extension
const componentResult = MyComponent();
export default componentResult;
76 changes: 76 additions & 0 deletions packages/node-resolve/test/test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,82 @@ test('supports JS extensions in TS when referring to TS imports', async (t) => {
t.is(module.exports, 'It works!');
});

test('supports JS extensions in TS when referring to TSX imports', async (t) => {
const bundle = await rollup({
input: 'tsx-import-js-extension/import-tsx-with-js-extension.ts',
onwarn: failOnWarn(t),
plugins: [
nodeResolve({
extensions: ['.js', '.ts', '.tsx']
}),
babel({
babelHelpers: 'bundled',
plugins: ['@babel/plugin-transform-typescript'],
extensions: ['.js', '.ts', '.tsx']
})
]
});
const { module } = await testBundle(t, bundle);
t.is(module.exports, 'It works!');
});

test('supports JSX extensions in TS when referring to TSX imports', async (t) => {
const bundle = await rollup({
input: 'ts-import-jsx-extension/import-tsx-with-jsx-extension.ts',
onwarn: failOnWarn(t),
plugins: [
nodeResolve({
extensions: ['.js', '.ts', '.tsx']
}),
babel({
babelHelpers: 'bundled',
plugins: ['@babel/plugin-transform-typescript'],
extensions: ['.js', '.ts', '.tsx']
})
]
});
const { module } = await testBundle(t, bundle);
t.is(module.exports, 'It works!');
});

test('supports MJS extensions in TS when referring to MTS imports', async (t) => {
const bundle = await rollup({
input: 'ts-import-mjs-extension/import-ts-with-mjs-extension.ts',
onwarn: failOnWarn(t),
plugins: [
nodeResolve({
extensions: ['.js', '.ts', '.mjs', '.mts']
}),
babel({
babelHelpers: 'bundled',
plugins: ['@babel/plugin-transform-typescript'],
extensions: ['.js', '.ts', '.mjs', '.mts']
})
]
});
const { module } = await testBundle(t, bundle);
t.is(module.exports, 'It works!');
});

test('supports CJS extensions in TS when referring to CTS imports', async (t) => {
const bundle = await rollup({
input: 'ts-import-cjs-extension/import-ts-with-cjs-extension.ts',
onwarn: failOnWarn(t),
plugins: [
nodeResolve({
extensions: ['.js', '.ts', '.cjs', '.cts']
}),
babel({
babelHelpers: 'bundled',
plugins: ['@babel/plugin-transform-typescript'],
extensions: ['.js', '.ts', '.cjs', '.cts']
})
]
});
const { module } = await testBundle(t, bundle);
t.is(module.exports, 'It works!');
});

test('supports JS extensions in TS actually importing JS with export map', async (t) => {
const bundle = await rollup({
input: 'ts-import-js-extension-for-js-file-export-map/import-js-with-js-extension.ts',
Expand Down

0 comments on commit e5a19b6

Please sign in to comment.