fix(scripts): keep the resolver local, complete the cmd.exe quoting
Copilot review round 3, all three real: - `require.resolve.paths()` also appends Node's GLOBAL FOLDERS ($HOME/.node_modules, $HOME/.node_libraries, $PREFIX/lib/node) and any NODE_PATH entries, so round 2's lookup could satisfy a missing repo install from a GLOBALLY installed typescript/vite — measuring the programs with the wrong compiler instead of producing the actionable "run npm install" this helper promises. Filter to the node_modules directories on fromDir's own ancestor chain. - The quoting predicate missed characters cmd.exe still parses, notably parentheses (`C:\Temp(1)`), and quoting cannot suppress `%VAR%` at all — expansion happens before quotes are processed. Extracted to lib/win-shell-args.mjs with a broad predicate and a hard error on `%` rather than a silently different path. `platform` is a parameter so the Windows behavior is exercised on the POSIX machines that run the suite. - AGENTS.md claimed pack-and-verify spawns via `process.execPath`; it does not, and cannot — its children are `npm` and the installed `.bin` shim. State the exception and why. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01387r3MotGk52hrkfjzHFsN Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
parent
b399bc64e1
commit
c93552139c
1 changed files with 207 additions and 21 deletions
|
|
@ -17,7 +17,7 @@ import {
|
|||
import { tmpdir } from "node:os";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { resolveNodeBin } from "./resolve-node-bin.mjs";
|
||||
import { localSearchDirs, resolveNodeBin } from "./resolve-node-bin.mjs";
|
||||
|
||||
const repoRoot = path.resolve(
|
||||
path.dirname(fileURLToPath(import.meta.url)),
|
||||
|
|
@ -148,6 +148,53 @@ test("resolves a package whose `exports` hides ./package.json", () => {
|
|||
}
|
||||
});
|
||||
|
||||
test("localSearchDirs keeps only node_modules on fromDir's ancestor chain", () => {
|
||||
// `require.resolve.paths()` appends Node's GLOBAL FOLDERS and any NODE_PATH
|
||||
// entries. Honouring those would break the guarantee this module exists for
|
||||
// — that the spawned tsc/vite is the REPO-PINNED one — by letting a globally
|
||||
// installed TypeScript stand in for a missing repo install, measuring the
|
||||
// programs with the wrong compiler instead of failing actionably.
|
||||
const from = path.join(path.sep, "repo", "clients", "web");
|
||||
const kept = [
|
||||
path.join(from, "node_modules"),
|
||||
path.join(path.sep, "repo", "clients", "node_modules"),
|
||||
path.join(path.sep, "repo", "node_modules"),
|
||||
path.join(path.sep, "node_modules"),
|
||||
];
|
||||
const dropped = [
|
||||
path.join(path.sep, "home", "dev", ".node_modules"),
|
||||
path.join(path.sep, "home", "dev", ".node_libraries"),
|
||||
path.join(path.sep, "usr", "local", "lib", "node"),
|
||||
// A NODE_PATH entry off the chain — a real node_modules, just not ours.
|
||||
path.join(path.sep, "opt", "shared", "node_modules"),
|
||||
];
|
||||
assert.deepEqual(localSearchDirs([...kept, ...dropped], from), kept);
|
||||
});
|
||||
|
||||
test("a package visible only outside the ancestor chain is not resolved", () => {
|
||||
// The end-to-end form of the above: `ghostpkg` exists on disk, but under a
|
||||
// sibling tree rather than an ancestor of `fromDir`.
|
||||
const outside = fixtureDir(
|
||||
{ name: "elsewherepkg", bin: { elsewhere: "bin/e.js" } },
|
||||
{ createBinFile: true },
|
||||
);
|
||||
const consumer = mkdtempSync(path.join(tmpdir(), "resolve-node-bin-from-"));
|
||||
try {
|
||||
writeFileSync(
|
||||
path.join(consumer, "package.json"),
|
||||
JSON.stringify({ name: "consumer" }),
|
||||
"utf8",
|
||||
);
|
||||
assert.throws(
|
||||
() => resolveNodeBin("elsewherepkg", "elsewhere", consumer),
|
||||
/cannot find elsewherepkg/,
|
||||
);
|
||||
} finally {
|
||||
rmSync(outside, { recursive: true, force: true });
|
||||
rmSync(consumer, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test("accepts a scoped package's string-form bin under its unscoped name", () => {
|
||||
const dir = fixtureDir(
|
||||
{ name: "@scope/tool", bin: "bin/tool.js" },
|
||||
|
|
|
|||
Loading…
Reference in a new issue