From 95d9147864861e426c5df249aea518b73a2aace8 Mon Sep 17 00:00:00 2001 From: Pooya Parsa Date: Wed, 21 Feb 2024 13:42:46 +0100 Subject: [PATCH 1/4] test: add test for links --- test.mjs | 1 + test/fixture/hello-linked.mjs | 1 + test/resolve.test.ts | 7 +++++++ 3 files changed, 9 insertions(+) create mode 100644 test.mjs create mode 120000 test/fixture/hello-linked.mjs diff --git a/test.mjs b/test.mjs new file mode 100644 index 0000000..11f474e --- /dev/null +++ b/test.mjs @@ -0,0 +1 @@ +console.log(import.meta.resolve.toString()) diff --git a/test/fixture/hello-linked.mjs b/test/fixture/hello-linked.mjs new file mode 120000 index 0000000..5d12f6b --- /dev/null +++ b/test/fixture/hello-linked.mjs @@ -0,0 +1 @@ +hello.mjs \ No newline at end of file diff --git a/test/resolve.test.ts b/test/resolve.test.ts index 75e5a02..d5d28fe 100644 --- a/test/resolve.test.ts +++ b/test/resolve.test.ts @@ -36,6 +36,13 @@ describe("resolveSync", () => { } }); } + + it("follows symlinks", () => { + const resolved = resolveSync("./fixture/hello-linked", { + url: import.meta.url, + }); + expect(fileURLToPath(resolved)).match(/fixture\/hello\.mjs$/); + }); }); describe("resolvePathSync", () => { From aa5882a1c3e40d238f9ef746dad665809bdee4aa Mon Sep 17 00:00:00 2001 From: Pooya Parsa Date: Wed, 21 Feb 2024 13:58:12 +0100 Subject: [PATCH 2/4] add test for non js modules --- test/fixture/{hello-linked.mjs => hello.link.mjs} | 0 test/fixture/test.link.txt | 1 + test/fixture/test.txt | 1 + test/resolve.test.ts | 7 ++++++- 4 files changed, 8 insertions(+), 1 deletion(-) rename test/fixture/{hello-linked.mjs => hello.link.mjs} (100%) create mode 120000 test/fixture/test.link.txt create mode 100644 test/fixture/test.txt diff --git a/test/fixture/hello-linked.mjs b/test/fixture/hello.link.mjs similarity index 100% rename from test/fixture/hello-linked.mjs rename to test/fixture/hello.link.mjs diff --git a/test/fixture/test.link.txt b/test/fixture/test.link.txt new file mode 120000 index 0000000..541cb64 --- /dev/null +++ b/test/fixture/test.link.txt @@ -0,0 +1 @@ +test.txt \ No newline at end of file diff --git a/test/fixture/test.txt b/test/fixture/test.txt new file mode 100644 index 0000000..524acff --- /dev/null +++ b/test/fixture/test.txt @@ -0,0 +1 @@ +Test file diff --git a/test/resolve.test.ts b/test/resolve.test.ts index d5d28fe..c1a2d50 100644 --- a/test/resolve.test.ts +++ b/test/resolve.test.ts @@ -38,10 +38,15 @@ describe("resolveSync", () => { } it("follows symlinks", () => { - const resolved = resolveSync("./fixture/hello-linked", { + const resolved = resolveSync("./fixture/hello.link", { url: import.meta.url, }); expect(fileURLToPath(resolved)).match(/fixture\/hello\.mjs$/); + + const resolved2 = resolveSync("./fixture/test.link.txt", { + url: import.meta.url, + }); + expect(fileURLToPath(resolved2)).match(/fixture\/test.txt$/); }); }); From 3f087904db4d346c16d66c628971b88393871247 Mon Sep 17 00:00:00 2001 From: Pooya Parsa Date: Wed, 21 Feb 2024 13:58:45 +0100 Subject: [PATCH 3/4] perf(resolver): stat absolute paths once in fast path --- src/resolve.ts | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/resolve.ts b/src/resolve.ts index df18f56..24bcdac 100644 --- a/src/resolve.ts +++ b/src/resolve.ts @@ -1,4 +1,4 @@ -import { existsSync, realpathSync } from "node:fs"; +import { statSync } from "node:fs"; import { pathToFileURL } from "node:url"; import { joinURL } from "ufo"; import { isAbsolute, normalize } from "pathe"; @@ -27,7 +27,7 @@ function _tryModuleResolve( id: string, url: URL, conditions: any, -): any | undefined { +): URL | undefined { try { return moduleResolve(id, url, conditions); } catch (error) { @@ -49,10 +49,17 @@ function _resolve(id: string, options: ResolveOptions = {}): string { } // Skip resolve for absolute paths - if (isAbsolute(id) && existsSync(id)) { - // Resolve realPath and normalize slash - const realPath = realpathSync(fileURLToPath(id)); - return pathToFileURL(realPath).toString(); + if (isAbsolute(id)) { + try { + const stat = statSync(id); + if (stat.isFile()) { + return pathToFileURL(id).toString(); + } + } catch (error) { + if (error.code !== "ENOENT") { + throw error; + } + } } // Condition set @@ -82,7 +89,7 @@ function _resolve(id: string, options: ResolveOptions = {}): string { } } - let resolved; + let resolved: URL | undefined; for (const url of urls) { // Try simple resolve resolved = _tryModuleResolve(id, url, conditionsSet); @@ -120,9 +127,8 @@ function _resolve(id: string, options: ResolveOptions = {}): string { throw error; } - // Resolve realPath and normalize slash - const realPath = realpathSync(fileURLToPath(resolved)); - return pathToFileURL(realPath).toString(); + // Normalize (TODO: simplify) + return pathToFileURL(fileURLToPath(resolved)).toString(); } export function resolveSync(id: string, options?: ResolveOptions): string { From 928133d44ff390134301755d584510f0c45ff4b5 Mon Sep 17 00:00:00 2001 From: Pooya Parsa Date: Wed, 21 Feb 2024 14:04:09 +0100 Subject: [PATCH 4/4] perf(resolve): remove intermediate pcall --- src/_utils.ts | 20 -------------------- src/resolve.ts | 14 +++++++++++--- 2 files changed, 11 insertions(+), 23 deletions(-) diff --git a/src/_utils.ts b/src/_utils.ts index a511257..87b9065 100644 --- a/src/_utils.ts +++ b/src/_utils.ts @@ -6,26 +6,6 @@ export function normalizeSlash(string_) { return string_.replace(/\\/g, "/"); } -export function pcall any>( - function_: TFn, - ...arguments_: Parameters -): Promise> { - try { - return Promise.resolve(function_(...arguments_)).catch((error) => - perr(error), - ); - } catch (error) { - return perr(error); - } -} - -export function perr(_error) { - const error = new Error(_error); - error.code = _error.code; - Error.captureStackTrace(error, pcall); - return Promise.reject(error); -} - export function isObject(value) { return value !== null && typeof value === "object"; } diff --git a/src/resolve.ts b/src/resolve.ts index 24bcdac..bd505d7 100644 --- a/src/resolve.ts +++ b/src/resolve.ts @@ -5,7 +5,7 @@ import { isAbsolute, normalize } from "pathe"; import { moduleResolve } from "import-meta-resolve"; import { PackageJson, readPackageJSON } from "pkg-types"; import { fileURLToPath, normalizeid } from "./utils"; -import { pcall, BUILTIN_MODULES } from "./_utils"; +import { BUILTIN_MODULES } from "./_utils"; const DEFAULT_CONDITIONS_SET = new Set(["node", "import"]); const DEFAULT_URL = pathToFileURL(process.cwd()); @@ -136,7 +136,11 @@ export function resolveSync(id: string, options?: ResolveOptions): string { } export function resolve(id: string, options?: ResolveOptions): Promise { - return pcall(resolveSync, id, options); + try { + return Promise.resolve(resolveSync(id, options)); + } catch (error) { + return Promise.reject(error); + } } export function resolvePathSync(id: string, options?: ResolveOptions): string { @@ -147,7 +151,11 @@ export function resolvePath( id: string, options?: ResolveOptions, ): Promise { - return pcall(resolvePathSync, id, options); + try { + return Promise.resolve(resolvePathSync(id, options)); + } catch (error) { + return Promise.reject(error); + } } export function createResolve(defaults?: ResolveOptions) {