Files
rea/tests/acceptance/applications/packageMainLookupCli.test.ts
morluto b58adafa4f fix(javascript): align module lookup and source evidence
Preserve CommonJS literal paths and confined ESM URL semantics, including package main fallback, directory intent, Unicode identity, and present opaque modules. Parse extraction inputs at their AST/source owner, retain skipped HTML and source-map coverage, and distinguish endpoint candidates from proven receiver facts. Version structural fingerprints with computed literal contents and propagate them through worker contracts.

Reviewed fixes include #1810, #1840, #2642, #2700, #2702, #2714, #2803, #2960, #2968, #2986, #3035, and #3036.

Validation: 158 resolver tests passed; public CLI/MCP module lookup controls, package-main/Unicode workflows, and six builtin workflows passed in the current compiled lane. Worker schema/fingerprint regressions passed. Large public pdf.js completion and real Electron analysis remain unverified.
2026-10-14 08:46:50 +08:00

285 lines
10 KiB
TypeScript

import { expect } from "vitest";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
import { cliTest } from "../../support/cli/cliFixture.js";
import {
analyzeJavaScriptDirectory,
runNodeJsonControl,
} from "../../support/cli/javascriptApplication.js";
import { writeFixtureFiles } from "../../support/javascriptApplicationFixture.js";
const cases = [
{ name: "null-main", metadata: { main: null } },
{ name: "false-main", metadata: { main: false } },
{ name: "zero-main", metadata: { main: 0 } },
{ name: "true-main", metadata: { main: true } },
{ name: "object-main", metadata: { main: {} } },
{ name: "empty-main", metadata: { main: "" } },
{ name: "missing-main", metadata: {} },
{ name: "string-main", metadata: { main: "./index.js" } },
] as const;
cliTest.for(["CLI", "stdio MCP"] as const)(
"matches Node package main interpretation through %s",
async (surface, { cli }) => {
const root = await createTestTempDirectory("rea-package-main-");
const files: Record<string, string> = {
"package.json": JSON.stringify({ type: "commonjs" }),
"entry.cjs": cases
.map(({ name }) => `require(${JSON.stringify(name)});`)
.join("\n"),
"entry.mjs": cases
.map(({ name }) => `import ${JSON.stringify(name)};`)
.join("\n"),
"control.cjs": [
`const specifiers = ${JSON.stringify(cases.map(({ name }) => name))};`,
"console.log(JSON.stringify(specifiers.map((specifier) => require(specifier))));",
].join("\n"),
"control.mjs": [
`const specifiers = ${JSON.stringify(cases.map(({ name }) => name))};`,
"console.log(JSON.stringify(await Promise.all(specifiers.map(async (specifier) => (await import(specifier)).default))));",
].join("\n"),
};
for (const { name, metadata } of cases) {
files[`node_modules/${name}/package.json`] = JSON.stringify(metadata);
files[`node_modules/${name}/index.js`] =
`module.exports = ${JSON.stringify(`node_modules/${name}/index.js`)};`;
}
await writeFixtureFiles(root, files);
for (const filename of ["control.cjs", "control.mjs"]) {
expect(await runNodeJsonControl(root, filename)).toEqual(
cases.map(({ name }) => `node_modules/${name}/index.js`),
);
}
const { graph } = await analyzeJavaScriptDirectory(surface, cli, root);
for (const kind of ["require", "import"])
for (const { name } of cases)
expect(
graph.edges
.filter(({ relation }) => relation === "imports")
.map(({ properties }) => properties),
).toContainEqual(
expect.objectContaining({
module_link_kind: kind,
specifier: name,
resolved_path: `node_modules/${name}/index.js`,
resolution_status: "resolved",
}),
);
},
);
cliTest.for(["CLI", "stdio MCP"] as const)(
"preserves loader-specific package main probes and finalization through %s",
async (surface, { cli }) => {
const root = await createTestTempDirectory("rea-package-main-path-");
const packages = [
{
name: "dot-slash-main",
main: "./lib/",
files: ["lib.js", "lib/index.js", "index.js"],
require: "lib.js",
import: null,
},
{
name: "slash-main",
main: "lib/",
files: ["lib.js", "lib/index.js", "index.js"],
require: "lib.js",
import: null,
},
{
name: "plain-main",
main: "./lib",
files: ["lib.js", "lib/index.js"],
require: "lib.js",
import: "lib.js",
},
{
name: "directory-main",
main: "./lib/",
files: ["lib/index.js", "index.js"],
require: "lib/index.js",
import: "lib/index.js",
},
{
name: "fallback-main",
main: "./missing/",
files: ["index.js"],
require: "index.js",
import: "index.js",
},
{
name: "exact-main",
main: "./lib.js/",
files: ["lib.js", "index.js"],
require: "lib.js",
import: "lib.js",
},
{
name: "finalized-directory-main",
main: "./lib/",
files: ["lib.js", "lib/.js/child.js"],
require: "lib.js",
import: null,
importError: "ERR_UNSUPPORTED_DIR_IMPORT",
},
{
name: "finalized-main",
main: "./lib/",
files: ["lib.js", "lib/.js", "lib/index.js"],
require: "lib.js",
import: "lib/.js",
},
] as const;
const files: Record<string, string> = {
"package.json": JSON.stringify({ type: "commonjs" }),
"entry.cjs": [
...packages.map(({ name }) => `require(${JSON.stringify(name)});`),
'require("./local/");',
].join("\n"),
"entry.mjs": packages
.map(({ name }) => `import ${JSON.stringify(name)};`)
.join("\n"),
"local.js": 'module.exports = "local.js";',
"local/index.js": 'module.exports = "local/index.js";',
};
for (const item of packages) {
files[`node_modules/${item.name}/package.json`] = JSON.stringify({
main: item.main,
});
for (const path of item.files) {
const target = `node_modules/${item.name}/${path}`;
files[target] = `module.exports = ${JSON.stringify(target)};`;
}
}
for (const kind of ["require", "import"] as const) {
const filename = `control.${kind === "require" ? "cjs" : "mjs"}`;
files[filename] = [
`const specifiers = ${JSON.stringify(packages.map(({ name }) => name))};`,
"const results = [];",
"for (const specifier of specifiers) {",
` try { results.push({ path: ${kind === "require" ? "require(specifier)" : "(await import(specifier)).default"} }); }`,
" catch (error) { results.push({ code: error.code }); }",
"}",
"console.log(JSON.stringify(results));",
].join("\n");
}
files["local-control.cjs"] =
'console.log(JSON.stringify(require("./local/")));';
await writeFixtureFiles(root, files);
for (const kind of ["require", "import"] as const) {
const control = await runNodeJsonControl(
root,
`control.${kind === "require" ? "cjs" : "mjs"}`,
);
expect(control).toEqual(
packages.map((item) =>
item[kind] === null
? {
code:
"importError" in item
? item.importError
: "ERR_MODULE_NOT_FOUND",
}
: { path: `node_modules/${item.name}/${item[kind]}` },
),
);
}
expect(await runNodeJsonControl(root, "local-control.cjs")).toBe(
"local/index.js",
);
const { graph } = await analyzeJavaScriptDirectory(surface, cli, root);
const relationships = graph.edges
.filter(({ relation }) => relation === "imports")
.map(({ properties }) => properties);
for (const kind of ["require", "import"] as const)
for (const item of packages)
expect(relationships).toContainEqual(
expect.objectContaining({
module_link_kind: kind,
specifier: item.name,
resolved_path:
item[kind] === null
? null
: `node_modules/${item.name}/${item[kind]}`,
resolution_status:
item[kind] === null
? "importError" in item
? "rejected"
: "not-found"
: "resolved",
}),
);
expect(relationships).toContainEqual(
expect.objectContaining({
module_link_kind: "require",
specifier: "./local/",
resolved_path: "local/index.js",
resolution_status: "resolved",
}),
);
},
);
cliTest.for(["CLI", "stdio MCP"] as const)(
"resolves package mains that name the artifact root through %s",
async (surface, { cli }) => {
const mains = ["../..", "../../", "../../."];
const names = mains.map((_, index) => `root-main-${index}`);
const requires = names.map((name) => `require("${name}")`);
for (const rootIndex of ["index.js", "index.json", null]) {
const root = await createTestTempDirectory("rea-package-main-root-");
const importOptions =
rootIndex === "index.json" ? ', { with: { type: "json" } }' : "";
const imports = names.map(
(name) =>
`import("${name}"${importOptions}).then(module => module.default)`,
);
const files: Record<string, string> = {
"package.json": '{"type":"commonjs"}',
"entry.cjs": requires.join(";\n"),
"entry.mjs": names.map((name) => `import "${name}";`).join("\n"),
".js": 'module.exports = ".js decoy";',
".json": '".json decoy"',
"control.cjs": `console.log(JSON.stringify([${requires.join(",")}]));`,
"control.mjs": `console.log(JSON.stringify(await Promise.all([${imports.join(",")}])));`,
};
if (rootIndex !== null)
files[rootIndex] =
rootIndex === "index.js"
? 'module.exports = "index.js";'
: '"index.json"';
for (const [index, main] of mains.entries()) {
const directory = `node_modules/${names[index]}`;
files[`${directory}/package.json`] = JSON.stringify({ main });
files[`${directory}/index.js`] =
`module.exports = "${directory}/index.js";`;
}
await writeFixtureFiles(root, files);
const expected = names.map(
(name) => rootIndex ?? `node_modules/${name}/index.js`,
);
for (const filename of ["control.cjs", "control.mjs"])
expect(await runNodeJsonControl(root, filename)).toEqual(expected);
const { graph } = await analyzeJavaScriptDirectory(surface, cli, root);
const relationships = graph.edges
.filter(({ relation }) => relation === "imports")
.map(({ properties }) => properties);
for (const kind of ["require", "import"])
for (const [index, name] of names.entries())
expect(relationships).toContainEqual(
expect.objectContaining({
module_link_kind: kind,
specifier: name,
resolved_path: expected[index],
resolution_status: "resolved",
}),
);
}
},
);