mirror of
https://github.com/morluto/rea
synced 2026-10-25 22:08:11 -04:00
fix(javascript): retain NodeNext artifact source facts (#1087)
* test(javascript): reproduce omitted NodeNext artifact sources Tests only: qualify current .mts/.cts artifact selection through real directory and ASAR reconstruction and the built public CLI. Signed-off-by: Rudy Celekli <rudy@gradiahq.com> * fix(javascript): retain NodeNext artifact source facts Read .mts and .cts artifact files through the existing inert TypeScript parser, preserving selected file identities and analysis facts in directory and ASAR inputs. Document source selection and format the existing regression assertion. Signed-off-by: Rudy Celekli <rudy@gradiahq.com> --------- Signed-off-by: Rudy Celekli <rudy@gradiahq.com> Co-authored-by: N0zoM1z0 <1705004398@qq.com>
This commit is contained in:
committed by
GitHub
parent
5a67c7fc54
commit
c1b370ce0d
@@ -125,6 +125,10 @@ SHA-256 digests, inventory IDs, ASAR container identity, and `.asar.unpacked`
|
||||
status. Direct ASAR inputs and filesystem-backed ASAR files nested beneath a
|
||||
directory are supported.
|
||||
|
||||
JavaScript sources (`.js`, `.jsx`, `.mjs`, and `.cjs`) and TypeScript sources
|
||||
(`.ts`, `.tsx`, `.mts`, and `.cts`) are parsed as inert text; analysis does not
|
||||
execute them.
|
||||
|
||||
JavaScript and HTML source ranges retain an initial UTF-8 BOM as one UTF-16
|
||||
code unit, matching the original bytes identified by the artifact digest.
|
||||
|
||||
|
||||
@@ -330,7 +330,7 @@ const relevantKind = (path: string): JavaScriptArtifactFileKind | undefined => {
|
||||
if (lower === "package.json" || lower.endsWith("/package.json"))
|
||||
return "package-json";
|
||||
if (lower.endsWith(".json")) return "json";
|
||||
if (/\.(?:cjs|mjs|js|jsx|ts|tsx)$/u.test(lower)) return "javascript";
|
||||
if (/\.(?:cjs|cts|mjs|mts|js|jsx|ts|tsx)$/u.test(lower)) return "javascript";
|
||||
if (/\.html?$/u.test(lower)) return "html";
|
||||
if (lower.endsWith(".map")) return "source-map";
|
||||
if (lower.endsWith(".node")) return "native-addon";
|
||||
|
||||
@@ -72,6 +72,40 @@ cliTest(
|
||||
},
|
||||
);
|
||||
|
||||
for (const extension of ["mts", "cts"]) {
|
||||
for (const command of ["analyze-javascript-application", "analyze"]) {
|
||||
cliTest(
|
||||
`${command} returns facts for a selected ${extension} source`,
|
||||
async ({ cli }) => {
|
||||
const root = await createTestTempDirectory("rea-nodenext-cli-");
|
||||
const path = `selected.${extension}`;
|
||||
await writeFile(
|
||||
join(root, path),
|
||||
"export function selected_feature(value: string) { return { value }; }",
|
||||
);
|
||||
const output = await cli.run({ arguments: [command, root, "--json"] });
|
||||
expect(output.exitCode).toBe(0);
|
||||
const evidence = parseEvidence(output.json);
|
||||
const result = javascriptApplicationAnalysisResultSchema.parse(
|
||||
evidence.normalized_result,
|
||||
);
|
||||
expect(result.statistics).toMatchObject({
|
||||
relevant_files: 1,
|
||||
parsed_javascript_files: 1,
|
||||
parse_failures: 0,
|
||||
});
|
||||
expect(
|
||||
result.graph.nodes.some(
|
||||
({ kind, observations }) =>
|
||||
kind === "javascript-asset" &&
|
||||
observations.some(({ properties }) => properties.path === path),
|
||||
),
|
||||
).toBe(true);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for (const command of ["analyze-javascript-application", "analyze"]) {
|
||||
cliTest(
|
||||
`${command} retains HTML source ranges after a bare carriage return`,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { createHash } from "node:crypto";
|
||||
import { mkdir, rm, writeFile } from "node:fs/promises";
|
||||
import { join } from "node:path";
|
||||
|
||||
@@ -453,3 +454,66 @@ const fixtureDirectory = async (): Promise<string> => {
|
||||
await writeJavaScriptArtifactFixture(root);
|
||||
return root;
|
||||
};
|
||||
|
||||
for (const extension of ["ts", "tsx", "mts", "cts", "js", "mjs", "cjs"]) {
|
||||
it.each(["directory", "asar"] as const)(
|
||||
`retains ${extension} source facts from a real %s artifact`,
|
||||
async (format) => {
|
||||
const root = await createTestTempDirectory("rea-nodenext-artifacts-");
|
||||
const directory = join(root, "source");
|
||||
await mkdir(directory);
|
||||
const path = `selected.${extension}`;
|
||||
const parameter = ["ts", "tsx", "mts", "cts"].includes(extension)
|
||||
? "value: string"
|
||||
: "value";
|
||||
const source = `
|
||||
globalThis.__rea_nodenext_executed = true;
|
||||
throw new Error("fixture must remain inert");
|
||||
export function selected_feature(${parameter}) { return { value }; }
|
||||
`;
|
||||
await writeFile(join(directory, path), source);
|
||||
let inputPath = directory;
|
||||
if (format === "asar") {
|
||||
inputPath = join(root, "application.asar");
|
||||
await createPackageWithOptions(directory, inputPath, {});
|
||||
}
|
||||
Reflect.deleteProperty(globalThis, "__rea_nodenext_executed");
|
||||
const result = await reconstructJavaScriptArtifact({
|
||||
input_path: inputPath,
|
||||
format,
|
||||
});
|
||||
expect(
|
||||
Reflect.get(globalThis, "__rea_nodenext_executed"),
|
||||
).toBeUndefined();
|
||||
expect(result.statistics).toMatchObject({
|
||||
relevant_files: 1,
|
||||
parsed_javascript_files: 1,
|
||||
text_bytes_read: Buffer.byteLength(source),
|
||||
parse_failures: 0,
|
||||
});
|
||||
const asset = result.graph.nodes.find(
|
||||
({ kind, observations }) =>
|
||||
kind === "javascript-asset" &&
|
||||
observations.some(({ properties }) => properties.path === path),
|
||||
);
|
||||
expect(asset?.identity).toMatchObject({
|
||||
sha256: createHash("sha256").update(source).digest("hex"),
|
||||
});
|
||||
expect(asset?.observations[0]?.properties).toMatchObject({
|
||||
path,
|
||||
bytes: Buffer.byteLength(source),
|
||||
file_kind: "javascript",
|
||||
parse_status: "complete",
|
||||
});
|
||||
expect(
|
||||
result.semantic_graph.nodes.some(
|
||||
({ identity }) => identity.module_path === path,
|
||||
),
|
||||
).toBe(true);
|
||||
expect(result.graph.coverage).toMatchObject({
|
||||
status: "complete",
|
||||
truncated: false,
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user