From e4b0124887c2e1b854be9b3f22ee856c61d70d21 Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Fri, 11 Oct 2024 12:08:10 -0700 Subject: [PATCH] Fix resolve self priority (#4704) --- ...esolve-self-priority-2024-9-11-11-38-15.md | 7 +++++ .gitignore | 2 ++ .../src/module-resolver/module-resolver.ts | 31 +++++++++---------- .../module-resolver/module-resolver.test.ts | 27 ++++++++++++++++ 4 files changed, 50 insertions(+), 17 deletions(-) create mode 100644 .chronus/changes/fix-resolve-self-priority-2024-9-11-11-38-15.md diff --git a/.chronus/changes/fix-resolve-self-priority-2024-9-11-11-38-15.md b/.chronus/changes/fix-resolve-self-priority-2024-9-11-11-38-15.md new file mode 100644 index 0000000000..ff20886b42 --- /dev/null +++ b/.chronus/changes/fix-resolve-self-priority-2024-9-11-11-38-15.md @@ -0,0 +1,7 @@ +--- +changeKind: fix +packages: + - "@typespec/compiler" +--- + +Fix order of resolution from node_modules and parent package \ No newline at end of file diff --git a/.gitignore b/.gitignore index b9058dd743..6f59196ba6 100644 --- a/.gitignore +++ b/.gitignore @@ -198,6 +198,8 @@ developer/ *.vsix *.zip +vite.config.ts.timestamp-* + # Api extractor packages/*/etc/ diff --git a/packages/compiler/src/module-resolver/module-resolver.ts b/packages/compiler/src/module-resolver/module-resolver.ts index 6b2b353150..e7fcbdfa68 100644 --- a/packages/compiler/src/module-resolver/module-resolver.ts +++ b/packages/compiler/src/module-resolver/module-resolver.ts @@ -6,7 +6,7 @@ import { InvalidPackageTargetError, NoMatchingConditionsError, } from "./esm/utils.js"; -import { parseNodeModuleSpecifier } from "./utils.js"; +import { NodeModuleSpecifier, parseNodeModuleSpecifier } from "./utils.js"; // Resolve algorithm of node https://nodejs.org/api/modules.html#modules_all_together @@ -126,10 +126,6 @@ export async function resolveModule( } } - // Try to resolve package itself. - const self = await resolveSelf(specifier, absoluteStart); - if (self) return self; - // Try to resolve as a node_module package. const module = await resolveAsNodeModule(specifier, absoluteStart); if (module) return module; @@ -154,19 +150,18 @@ export async function resolveModule( } /** - * Equivalent implementation to node LOAD_PACKAGE_SELF - * Resolve if the import is importing the current package. + * Try to import a package with that name in the current directory. */ - async function resolveSelf(name: string, baseDir: string): Promise { - for (const dir of listDirHierarchy(baseDir)) { - const pkgFile = resolvePath(dir, "package.json"); - if (!(await isFile(host, pkgFile))) continue; - const pkg = await readPackage(host, pkgFile); - // Node Spec says that you shouldn't lookup past the first package.json. However we used to support that so keeping this. - if (pkg.name !== name) continue; - return loadPackage(dir, pkg); - } - return undefined; + async function resolveSelf( + { packageName, subPath }: NodeModuleSpecifier, + dir: string, + ): Promise { + const pkgFile = resolvePath(dir, "package.json"); + if (!(await isFile(host, pkgFile))) return undefined; + const pkg = await readPackage(host, pkgFile); + // Node Spec says that you shouldn't lookup past the first package.json. However we used to support that so keeping this. + if (pkg.name !== packageName) return undefined; + return loadPackage(dir, pkg, subPath); } /** @@ -182,6 +177,8 @@ export async function resolveModule( const dirs = listDirHierarchy(baseDir); for (const dir of dirs) { + const self = await resolveSelf(module, dir); + if (self) return self; const n = await loadPackageAtPath( joinPaths(dir, "node_modules", module.packageName), module.subPath, diff --git a/packages/compiler/test/module-resolver/module-resolver.test.ts b/packages/compiler/test/module-resolver/module-resolver.test.ts index 76af657dbf..372b532f6f 100644 --- a/packages/compiler/test/module-resolver/module-resolver.test.ts +++ b/packages/compiler/test/module-resolver/module-resolver.test.ts @@ -399,4 +399,31 @@ describe("resolve self", () => { mainFile: "/ws/proj/entry.js", }); }); + + it("prioritize local node_modules over self from multiple parent up", async () => { + const { host } = mkFs({ + "/ws/proj/package.json": JSON.stringify({ name: "@scope/proj", main: "entry.js" }), + "/ws/proj/entry.js": "", + "/ws/proj/nested/index.js": "", + "/ws/proj/node_modules/test-lib/package.json": JSON.stringify({ main: "entry.js" }), + "/ws/proj/node_modules/test-lib/entry.js": "", + "/ws/proj/node_modules/test-lib/nested/index.js": "", + // @scope/proj installed locally + "/ws/proj/node_modules/test-lib/node_modules/@scope/proj/package.json": JSON.stringify({ + name: "@scope/proj", + main: "entry.js", + }), + "/ws/proj/node_modules/test-lib/node_modules/@scope/proj/entry.js": "", + }); + + const resolved = await resolveModule(host, "@scope/proj", { + baseDir: "/ws/proj/node_modules/test-lib/nested", + }); + const path = "/ws/proj/node_modules/test-lib/node_modules/@scope/proj"; + expect(resolved).toMatchObject({ + type: "module", + path, + mainFile: `${path}/entry.js`, + }); + }); });