mirror of
https://github.com/morluto/rea
synced 2026-10-26 06:16:17 -04:00
4842f23765
* fix(source): retain CommonJS requires spelled as exact no-substitution templates Admit expression-free template arguments at the CommonJS require gate and read their single cooked quasi through the shared exact-literal reader. Scope is the require path only: static ESM template declarations keep their parse failures and dynamic import() keeps the explicit unknown/partial <dynamic-import> relationship with no invented target. Refs: #4382 * fix(source): admit TypeScript-wrapped exact require arguments via the shared literal reader Address review: the require gate matched the outer AST node, so runtime-transparent TS wrappers (as const, !, satisfies) around exact strings or expression-free templates were still silently omitted even though readExactJavaScriptLiteral unwraps them. Remove the gate and let the shared exact-literal reader own argument exactness; computed arguments remain silent and dynamic import() behavior is unchanged. Refs: #4382 --------- Co-authored-by: Hemang Varshney <218273197+hemv-857@users.noreply.github.com>
98 lines
2.7 KiB
TypeScript
98 lines
2.7 KiB
TypeScript
import { writeFile } from "node:fs/promises";
|
|
import { join } from "node:path";
|
|
|
|
import { expect, it } from "vitest";
|
|
|
|
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
|
|
import { importReferenceSource } from "../../support/referenceSourceResourceScope.js";
|
|
|
|
it("retains CommonJS requires spelled as exact no-substitution templates", async () => {
|
|
const root = await createTestTempDirectory("rea-reference-template-require-");
|
|
await writeFile(
|
|
join(root, "main.cjs"),
|
|
[
|
|
'require("quoted");',
|
|
"require(`templated`);",
|
|
'const name = "dep";',
|
|
"require(`./${name}.js`);",
|
|
"import(`./${name}.js`);",
|
|
].join("\n"),
|
|
);
|
|
|
|
const result = await importReferenceSource({
|
|
root,
|
|
caller: "reference-template-require-test",
|
|
policy: { secretPatterns: [] },
|
|
});
|
|
if (!result.ok) throw result.error;
|
|
expect(result.value.parse_failures).toEqual([]);
|
|
for (const to of ["quoted", "templated"]) {
|
|
expect(result.value.relationships).toContainEqual({
|
|
from_path: "main.cjs",
|
|
to,
|
|
kind: "requires",
|
|
resolution: "external",
|
|
parse_state: "parsed",
|
|
});
|
|
}
|
|
expect(
|
|
result.value.relationships.filter((relationship) =>
|
|
relationship.to.includes("dep"),
|
|
),
|
|
).toEqual([]);
|
|
expect(result.value.relationships).toContainEqual({
|
|
from_path: "main.cjs",
|
|
to: "<dynamic-import>",
|
|
kind: "imports",
|
|
resolution: "unknown",
|
|
parse_state: "partial",
|
|
});
|
|
});
|
|
|
|
it("retains TypeScript-wrapped exact requires through the shared literal reader", async () => {
|
|
const root = await createTestTempDirectory(
|
|
"rea-reference-ts-template-require-",
|
|
);
|
|
await writeFile(
|
|
join(root, "main.ts"),
|
|
[
|
|
'import { createRequire } from "node:module";',
|
|
"const require = createRequire(import.meta.url);",
|
|
'require("wrapped");',
|
|
"require(`wrapped-template`);",
|
|
"require(`wrapped-as-const` as const);",
|
|
'require("wrapped-string" as const);',
|
|
"require(`wrapped-bang`!);",
|
|
"require(`wrapped-${name}` as const);",
|
|
].join("\n"),
|
|
);
|
|
|
|
const result = await importReferenceSource({
|
|
root,
|
|
caller: "reference-ts-template-require-test",
|
|
policy: { secretPatterns: [] },
|
|
});
|
|
if (!result.ok) throw result.error;
|
|
expect(result.value.parse_failures).toEqual([]);
|
|
for (const to of [
|
|
"wrapped",
|
|
"wrapped-template",
|
|
"wrapped-as-const",
|
|
"wrapped-string",
|
|
"wrapped-bang",
|
|
]) {
|
|
expect(result.value.relationships).toContainEqual({
|
|
from_path: "main.ts",
|
|
to,
|
|
kind: "requires",
|
|
resolution: "external",
|
|
parse_state: "parsed",
|
|
});
|
|
}
|
|
expect(
|
|
result.value.relationships.filter((relationship) =>
|
|
relationship.to.includes("${"),
|
|
),
|
|
).toEqual([]);
|
|
});
|