mirror of
https://github.com/morluto/rea.git
synced 2026-10-30 19:35:56 +00:00
fix(javascript): distinguish prefix-only builtins from packages
This commit is contained in:
1 parent
9367dc13bd
commit
2b4abbf1cc
2 files changed
+68
-9
No files matched your search
@@ -1,4 +1,4 @@
|
||||
import { builtinModules } from "node:module";
|
||||
import { isBuiltin } from "node:module";
|
||||
import { posix } from "node:path";
|
||||
|
||||
import type { JavaScriptArtifactFile } from "../../domain/javascript/javascriptArtifactFiles.js";
|
||||
@@ -63,9 +63,6 @@ const EXTENSIONS = [
|
||||
".html",
|
||||
".node",
|
||||
];
|
||||
const NODE_BUILTINS = new Set(
|
||||
builtinModules.map((name) => name.replace(/^node:/u, "")),
|
||||
);
|
||||
|
||||
type CandidateResolution =
|
||||
| {
|
||||
@@ -194,11 +191,7 @@ const bareModuleCandidate = (
|
||||
declared: string,
|
||||
): string | ArtifactPathResolution => {
|
||||
const packageName = barePackageName(declared);
|
||||
if (
|
||||
packageName === null ||
|
||||
NODE_BUILTINS.has(packageName) ||
|
||||
declared.startsWith("#")
|
||||
)
|
||||
if (packageName === null || isBuiltin(declared) || declared.startsWith("#"))
|
||||
return unresolvedOutcome(input, "external", [
|
||||
"The bare specifier is a Node builtin, package import map, or invalid package name.",
|
||||
]);
|
||||
|
||||
@@ -27,6 +27,72 @@ const filesFor = (paths: readonly string[]) =>
|
||||
]),
|
||||
);
|
||||
|
||||
describe("prefix-only Node builtins", () => {
|
||||
it.each(["import", "require"] as const)(
|
||||
"resolves ordinary packages named test, sqlite and sea for %s",
|
||||
async (moduleKind) => {
|
||||
const root = await createTestTempDirectory("rea-prefix-only-builtins-");
|
||||
const names = ["test", "sqlite", "sea"];
|
||||
for (const name of [...names, "fs"]) {
|
||||
const directory = join(root, "node_modules", name);
|
||||
await mkdir(directory, { recursive: true });
|
||||
await writeFile(
|
||||
join(directory, "index.js"),
|
||||
`module.exports = ${JSON.stringify(name)};`,
|
||||
);
|
||||
}
|
||||
const main = join(
|
||||
root,
|
||||
moduleKind === "import" ? "main.mjs" : "main.cjs",
|
||||
);
|
||||
await writeFile(
|
||||
main,
|
||||
names
|
||||
.map((name, index) =>
|
||||
moduleKind === "import"
|
||||
? `import value${index} from ${JSON.stringify(name)}; console.log(value${index});`
|
||||
: `console.log(require(${JSON.stringify(name)}));`,
|
||||
)
|
||||
.join("\n") +
|
||||
(moduleKind === "import"
|
||||
? '\nimport "fs"; import "node:test";'
|
||||
: '\nrequire("fs"); require("node:test");'),
|
||||
);
|
||||
const native = await promisify(execFile)(process.execPath, [main], {
|
||||
timeout: 5_000,
|
||||
});
|
||||
expect(native.stdout.trim().split("\n").slice(0, 3)).toEqual(names);
|
||||
const result = await analyzeJavaScriptApplication({
|
||||
input_path: root,
|
||||
format: "directory",
|
||||
});
|
||||
if (!result.ok) throw result.error;
|
||||
const { graph } = javascriptApplicationAnalysisResultSchema.parse(
|
||||
result.value.normalized_result,
|
||||
);
|
||||
const imports = graph.edges.filter((edge) => edge.relation === "imports");
|
||||
for (const name of names) {
|
||||
const matches = imports.filter(
|
||||
(edge) => edge.properties.specifier === name,
|
||||
);
|
||||
expect(matches.length).toBeGreaterThan(0);
|
||||
for (const edge of matches)
|
||||
expect(edge.properties.resolved_path).toBe(
|
||||
`node_modules/${name}/index.js`,
|
||||
);
|
||||
}
|
||||
for (const name of ["fs", "node:test"]) {
|
||||
const matches = imports.filter(
|
||||
(edge) => edge.properties.specifier === name,
|
||||
);
|
||||
expect(matches.length).toBeGreaterThan(0);
|
||||
for (const edge of matches)
|
||||
expect(edge.properties.resolved_path).toBeNull();
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
describe("module specifier punctuation", () => {
|
||||
it.each(["#", "?"])(
|
||||
"keeps CommonJS punctuation and strips URL suffixes for ESM (%s)",
|
||||
|
||||
Reference in new issue
Block a user