test(sourcemap): consolidate source map regressions (#2034)

fix(sourcemap): retain named originals beside unknown source names

Co-authored-by: hhang <169027046+xu91102@users.noreply.github.com>
This commit is contained in:
hhangandhhang authored and GitHub committed 2026-10-12 12:44:58 +08:00
1 parent 783fcb06a4
commit 83a4445f44
2 files changed
+90 -11

No files matched your search

@@ -2,6 +2,7 @@ import { createHash } from "node:crypto";
import { readFile, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { TraceMap, originalPositionFor } from "@jridgewell/trace-mapping";
import { expect } from "vitest";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
import { cliTest } from "../../support/cli/cliFixture.js";
@@ -85,6 +86,13 @@ cliTest.for(["CLI", "stdio MCP"] as const)(
names: [],
mappings: "ACAA",
}),
"unnamed-empty.js.map": JSON.stringify({
version: 3,
sources: [null, "original.ts"],
sourcesContent: [null, original],
names: [],
mappings: "ACAA",
}),
};
await writeFixtureFiles(root, {
...maps,
@@ -92,13 +100,32 @@ cliTest.for(["CLI", "stdio MCP"] as const)(
"export const absent = 1;\n//# sourceMappingURL=absent.js.map\n",
"mixed.js":
"export const answer = 42;\n//# sourceMappingURL=mixed.js.map\n",
"unnamed-empty.js":
"export const answer = 42;\n//# sourceMappingURL=unnamed-empty.js.map\n",
});
for (const [mapPath, expectedSource] of [
["absent.js.map", "unembedded.ts"],
["mixed.js.map", "original.ts"],
["unnamed-empty.js.map", "original.ts"],
] as const)
expect(
originalPositionFor(new TraceMap(maps[mapPath], `file:///${mapPath}`), {
line: 1,
column: 0,
}).source,
).toBe(`file:///${expectedSource}`);
const { graph } = await analyzeJavaScriptDirectory(surface, cli, root);
const digest = (text: string) =>
createHash("sha256").update(text).digest("hex");
for (const [name, mapPath, content] of [
["unembedded.ts", "absent.js.map", null],
["original.ts", "mixed.js.map", original],
expect(
graph.nodes.filter(
(node) => node.identity.strategy === "source-map-original",
),
).toHaveLength(3);
for (const [name, mapPath, content, sourceIndex] of [
["unembedded.ts", "absent.js.map", null, 0],
["original.ts", "mixed.js.map", original, 1],
["original.ts", "unnamed-empty.js.map", original, 1],
] as const) {
const mapDigest = digest(maps[mapPath]);
expect(graph.nodes).toContainEqual(
@@ -117,6 +144,9 @@ cliTest.for(["CLI", "stdio MCP"] as const)(
map_path: mapPath,
}),
properties: expect.objectContaining({
source_index: sourceIndex,
declaration_index: sourceIndex,
source_name_available: true,
content_available: content !== null,
}),
evidence: expect.objectContaining({
@@ -127,27 +157,77 @@ cliTest.for(["CLI", "stdio MCP"] as const)(
}),
);
}
for (const [mapPath, content] of [
["mixed.js.map", unnamed],
["unnamed-empty.js.map", null],
] as const)
expect(graph.nodes).toContainEqual(
expect.objectContaining({
kind: "unknown",
observations: expect.arrayContaining([
expect.objectContaining({
source_map_reference: null,
properties: expect.objectContaining({
source_index: 0,
declaration_index: 0,
source_name_available: false,
content_available: content !== null,
content_sha256: content === null ? null : digest(content),
}),
evidence: expect.objectContaining({
artifact: expect.objectContaining({
sha256: digest(maps[mapPath]),
}),
}),
}),
]),
}),
);
expect(graph.coverage.status).toBe("complete");
for (const [path, text] of Object.entries(maps))
expect(await readFile(join(root, path), "utf8")).toBe(text);
},
);
cliTest.for(["CLI", "stdio MCP"] as const)(
"rejects non-string source-map names without inventing originals through %s",
async (surface, { cli }) => {
const root = await createTestTempDirectory("rea-invalid-map-source-");
const mapText = JSON.stringify({
version: 3,
sources: [42, "discarded.ts"],
sourcesContent: [null, "export const answer: number = 42;"],
names: [],
mappings: "ACAA",
});
await writeFixtureFiles(root, { "invalid.js.map": mapText });
const { graph } = await analyzeJavaScriptDirectory(surface, cli, root);
expect(graph.coverage.status).toBe("partial");
expect(
graph.nodes.some(
(node) => node.identity.strategy === "source-map-original",
),
).toBe(false);
expect(graph.nodes).toContainEqual(
expect.objectContaining({
kind: "unknown",
observations: expect.arrayContaining([
expect.objectContaining({
properties: expect.objectContaining({
source_name_available: false,
content_available: true,
content_sha256: digest(unnamed),
operation: "parse-local-source-map",
}),
evidence: expect.objectContaining({
artifact: expect.objectContaining({
sha256: digest(maps["mixed.js.map"]),
sha256: createHash("sha256").update(mapText).digest("hex"),
}),
limitations: expect.arrayContaining([
"Source map contains a non-string source name.",
]),
}),
}),
]),
}),
);
expect(graph.coverage.status).toBe("complete");
for (const [path, text] of Object.entries(maps))
expect(await readFile(join(root, path), "utf8")).toBe(text);
expect(await readFile(join(root, "invalid.js.map"), "utf8")).toBe(mapText);
},
);
@@ -136,7 +136,6 @@ it.each([
["a non-array sourcesContent value", { sourcesContent: "source" }],
["a non-string, non-null source entry", { sourcesContent: [42] }],
["a source-content array with the wrong length", { sourcesContent: [] }],
["a non-string source name", { sources: [42] }],
])(
"reports %s as an invalid local source map",
async (_description, content) => {