Files
rea/tests/boundary/filesystem/referenceSourceTemplateRequire.test.ts
T
Hemang Varshney 4842f23765 fix(source): retain CommonJS requires spelled as exact no-substitution templates (#4511)
* 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>
2026-10-22 06:12:42 +08:00

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([]);
});