From 4a8a2dcce25e1223dec65219659065901fd7620f Mon Sep 17 00:00:00 2001 From: Hiroki Osame Date: Mon, 6 May 2024 12:33:57 +0900 Subject: [PATCH] fix(cjs): support file url (#18) --- src/cjs/api/module-resolve-filename.ts | 7 +++++++ src/esm/hook/resolve.ts | 4 ++-- src/esm/hook/utils.ts | 2 -- src/utils/file-url.ts | 1 + tests/specs/smoke.ts | 15 ++++++++++++--- 5 files changed, 22 insertions(+), 7 deletions(-) create mode 100644 src/utils/file-url.ts diff --git a/src/cjs/api/module-resolve-filename.ts b/src/cjs/api/module-resolve-filename.ts index 8e1a3061c..70eee470d 100644 --- a/src/cjs/api/module-resolve-filename.ts +++ b/src/cjs/api/module-resolve-filename.ts @@ -1,9 +1,11 @@ import path from 'node:path'; import Module from 'node:module'; +import { fileURLToPath } from 'node:url'; import { createPathsMatcher } from 'get-tsconfig'; import { resolveTsPath } from '../../utils/resolve-ts-path.js'; import type { NodeError } from '../../types.js'; import { isRelativePath } from '../../utils/path-utils.js'; +import { fileUrlPrefix } from '../../utils/file-url.js'; import { isTsFilePatten, tsconfig, @@ -69,6 +71,11 @@ export const resolveFilename: ResolveFilename = ( request = request.slice(0, queryIndex); } + // Support file protocol + if (request.startsWith(fileUrlPrefix)) { + request = fileURLToPath(request); + } + if ( tsconfigPathsMatcher diff --git a/src/esm/hook/resolve.ts b/src/esm/hook/resolve.ts index 344272fe7..ef8ce40e3 100644 --- a/src/esm/hook/resolve.ts +++ b/src/esm/hook/resolve.ts @@ -6,11 +6,11 @@ import type { import { resolveTsPath } from '../../utils/resolve-ts-path.js'; import type { NodeError } from '../../types.js'; import { requestAcceptsQuery } from '../../utils/path-utils.js'; +import { fileUrlPrefix } from '../../utils/file-url.js'; import { tsconfigPathsMatcher, tsExtensionsPattern, getFormatFromFileUrl, - fileProtocol, allowJs, namespaceQuery, getNamespace, @@ -41,7 +41,7 @@ const resolveExplicitPath = async ( if ( !resolved.format - && resolved.url.startsWith(fileProtocol) + && resolved.url.startsWith(fileUrlPrefix) ) { resolved.format = await getFormatFromFileUrl(resolved.url); } diff --git a/src/esm/hook/utils.ts b/src/esm/hook/utils.ts index 37403600e..e9a6ecb1c 100644 --- a/src/esm/hook/utils.ts +++ b/src/esm/hook/utils.ts @@ -21,8 +21,6 @@ export const fileMatcher = tsconfig && createFilesMatcher(tsconfig); export const tsconfigPathsMatcher = tsconfig && createPathsMatcher(tsconfig); export const allowJs = tsconfig?.config.compilerOptions?.allowJs ?? false; -export const fileProtocol = 'file://'; - export const tsExtensionsPattern = /\.([cm]?ts|[tj]sx)($|\?)/; export const isJsonPattern = /\.json(?:$|\?)/; diff --git a/src/utils/file-url.ts b/src/utils/file-url.ts new file mode 100644 index 000000000..e3ea24e1b --- /dev/null +++ b/src/utils/file-url.ts @@ -0,0 +1 @@ +export const fileUrlPrefix = 'file://'; diff --git a/tests/specs/smoke.ts b/tests/specs/smoke.ts index 6a7a90bec..7b4bb5636 100644 --- a/tests/specs/smoke.ts +++ b/tests/specs/smoke.ts @@ -6,6 +6,8 @@ import outdent from 'outdent'; import type { NodeApis } from '../utils/tsx.js'; import { hasCoverageSourcesContent } from '../utils/coverage-sources-content.js'; +const isWindows = process.platform === 'win32'; + const cjsContextCheck = 'typeof module !== \'undefined\''; const tsCheck = '1 as number'; @@ -513,10 +515,17 @@ export default testSuite(async ({ describe }, { tsx }: NodeApis) => { import './js/index.js?query=123'; import './js/index'; import './js/'; + + // absolute path + ${ + isWindows + ? '' + : `import ${JSON.stringify(path.join(fixturePath, 'js/index.js'))};` + } + + // absolute file url import ${JSON.stringify( - packageType === 'module' - ? new URL('js/index.js', pathToFileURL(fixturePath)).toString() - : path.resolve(fixturePath, 'js/index.js'), + new URL('js/index.js', pathToFileURL(fixturePath)).toString(), )}; // No double .default.default in Dynamic Import