From d2eaf9e08d1c3566b68dec5dd2145f0473b9e8d5 Mon Sep 17 00:00:00 2001 From: Hiroki Osame Date: Tue, 19 Sep 2023 16:15:00 +0900 Subject: [PATCH] wip --- src/loaders.ts | 61 +++++++++++++++++++++++++++-------- tests/specs/typescript/jsx.ts | 17 ++++++++++ tests/specs/typescript/tsx.ts | 34 +++++++++++++++++++ 3 files changed, 98 insertions(+), 14 deletions(-) diff --git a/src/loaders.ts b/src/loaders.ts index 8891b99..ac118a0 100644 --- a/src/loaders.ts +++ b/src/loaders.ts @@ -7,7 +7,7 @@ import type { import { transform, transformDynamicImport, - resolveTsPath, + // resolveTsPath, compareNodeVersion, } from '@esbuild-kit/core-utils'; import type { TransformOptions } from 'esbuild'; @@ -23,6 +23,34 @@ import { type NodeError, } from './utils.js'; + + +const tsExtensions: Record = Object.create(null); +tsExtensions['.js'] = ['.ts', '.tsx', '.js', '.jsx']; +tsExtensions['.jsx'] = ['.tsx', '.ts', '.js', '.js']; +tsExtensions['.cjs'] = ['.cts']; +tsExtensions['.mjs'] = ['.mts']; + +const resolveTsPath = ( + filePath: string, +) => { + const extension = path.extname(filePath); + const [extensionNoQuery, query] = path.extname(filePath).split('?'); + const tsExtension = tsExtensions[extensionNoQuery]; + + if (tsExtension) { + const extensionlessPath = filePath.slice(0, -extension.length); + return tsExtension.map( + (tsExtension) => ( + extensionlessPath + + tsExtension + + (query ? `?${query}` : '') + ) + ); + } +}; + + const isDirectoryPattern = /\/(?:$|\?)/; type NextResolve = ( @@ -199,19 +227,24 @@ export const resolve: resolve = async function ( /** * Typescript gives .ts, .cts, or .mts priority over actual .js, .cjs, or .mjs extensions */ - if (tsExtensionsPattern.test(context.parentURL!)) { - const tsPath = resolveTsPath(specifier); - - if (tsPath) { - try { - return await resolveExplicitPath(defaultResolve, tsPath, context); - } catch (error) { - const { code } = error as NodeError; - if ( - code !== 'ERR_MODULE_NOT_FOUND' - && code !== 'ERR_PACKAGE_PATH_NOT_EXPORTED' - ) { - throw error; + if ( + // !recursiveCall && + tsExtensionsPattern.test(context.parentURL!) + ) { + const tsPaths = resolveTsPath(specifier); + if (tsPaths) { + for (const tsPath of tsPaths) { + try { + return await resolveExplicitPath(defaultResolve, tsPath, context); + // return await resolve(tsPath, context, defaultResolve, true); + } catch (error) { + const { code } = error as NodeError; + if ( + code !== 'ERR_MODULE_NOT_FOUND' + && code !== 'ERR_PACKAGE_PATH_NOT_EXPORTED' + ) { + throw error; + } } } } diff --git a/tests/specs/typescript/jsx.ts b/tests/specs/typescript/jsx.ts index 9d302c6..d8b13dd 100644 --- a/tests/specs/typescript/jsx.ts +++ b/tests/specs/typescript/jsx.ts @@ -35,6 +35,23 @@ export default testSuite(async ({ describe }, node: NodeApis) => { }); }); + // Does .js resolve .jsx? + + // describe('full path via .js', ({ test }) => { + // const importPath = './lib/ts-ext-jsx/index.js'; + + // test('Load', async () => { + // const nodeProcess = await node.load(importPath); + // assertResults(nodeProcess.stdout); + // }); + + // test('Import', async () => { + // const nodeProcess = await node.import(importPath); + // assertResults(nodeProcess.stdout); + // expect(nodeProcess.stdout).toMatch('{"default":["div",null,"hello world"]}'); + // }); + // }); + describe('extensionless', ({ test }) => { const importPath = './lib/ts-ext-jsx/index'; diff --git a/tests/specs/typescript/tsx.ts b/tests/specs/typescript/tsx.ts index 1241bc5..7c2796c 100644 --- a/tests/specs/typescript/tsx.ts +++ b/tests/specs/typescript/tsx.ts @@ -35,6 +35,40 @@ export default testSuite(async ({ describe }, node: NodeApis) => { }); }); + describe('full path via js', ({ test }) => { + const importPath = './lib/ts-ext-tsx/index.js'; + + test('Load - should not work', async () => { + const nodeProcess = await node.load(importPath); + assertNotFound(nodeProcess.stderr, importPath); + }); + + test('Import', async () => { + const nodeProcess = await node.import(importPath, { + typescript: true, + }); + assertResults(nodeProcess.stdout); + expect(nodeProcess.stdout).toMatch('{"default":["div",null,"hello world"]}'); + }); + }); + + describe('full path via jsx', ({ test }) => { + const importPath = './lib/ts-ext-tsx/index.jsx'; + + test('Load - should not work', async () => { + const nodeProcess = await node.load(importPath); + assertNotFound(nodeProcess.stderr, importPath); + }); + + test('Import', async () => { + const nodeProcess = await node.import(importPath, { + typescript: true, + }); + assertResults(nodeProcess.stdout); + expect(nodeProcess.stdout).toMatch('{"default":["div",null,"hello world"]}'); + }); + }); + describe('extensionless', ({ test }) => { const importPath = './lib/ts-ext-tsx/index';