fix(source-maps): accept omitted names during browser collection (#2831)

This commit is contained in:
Yann Roberto 2026-10-13 22:17:09 +08:00 committed by GitHub
parent f0b8ae1fc8
commit 1016c96e6b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 98 additions and 5 deletions

View File

@ -267,11 +267,6 @@ const inspectLeaf = (
consumeRecords(budget, Array.isArray(rawNames) ? rawNames.length : 0);
consumeRecords(budget, Array.isArray(rawContents) ? rawContents.length : 0);
options.check?.();
if (options.profile === "browser-collection" && !Array.isArray(rawNames))
throw new SourceMapFormatFailure(
"format",
"Source-map leaf requires a names array.",
);
if (
options.profile === "browser-collection" &&
!hasValidSourceMapContents(

View File

@ -29,6 +29,104 @@ const expectInvalidIncludedSourceMaps = (result: WebSourceMaps): void => {
expectInvalidSourceMaps({ ...result, status: "unavailable" });
};
it.each(["regular", "indexed"])(
"collects an HTTP %s source map with omitted names without accepting invalid names",
async (format) => {
const leaf = {
version: 3,
sources: ["src/main.ts"],
sourcesContent: ["import './dependency.ts';"],
mappings: "AAAA",
};
const texts = [
leaf,
{ ...leaf, names: [] },
{ ...leaf, names: null },
{ ...leaf, names: 42 },
{ ...leaf, names: [42] },
{ ...leaf, mappings: "AAAAA" },
].map((map) =>
JSON.stringify(
format === "indexed"
? {
version: 3,
sections: [{ offset: { line: 2, column: 5 }, map }],
}
: map,
),
);
const server = createServer((incoming, response) => {
response.setHeader("content-type", "application/source-map+json");
response.end(texts[Number(incoming.url?.slice(1))]);
});
try {
await new Promise<void>((resolve, reject) => {
server.once("error", reject);
server.listen(0, "127.0.0.1", resolve);
});
const address = server.address();
if (address === null || typeof address === "string")
throw new TypeError("Expected a TCP listener address");
const localOrigin = `http://127.0.0.1:${String(address.port)}`;
const result = await fetchWebSourceMaps(
texts.map((_, index) => ({
...request,
fetchUrl: `${localOrigin}/${index}`,
declaredUrl: `${localOrigin}/${index}`,
})),
input({ allowed_origins: [localOrigin] }),
);
expect(result.items.map(({ status }) => status)).toEqual([
"included",
"included",
"invalid",
"invalid",
"invalid",
"invalid",
]);
for (const [index, text] of texts.slice(0, 2).entries())
expect(result.items[index]).toMatchObject({
artifact: {
text,
bytes: Buffer.byteLength(text),
sha256: createHash("sha256").update(text).digest("hex"),
},
original_sources: [{ source: `${localOrigin}/src/main.ts` }],
mappings: [
{
generated_line: format === "indexed" ? 3 : 1,
generated_column: format === "indexed" ? 5 : 0,
source: `${localOrigin}/src/main.ts`,
original_line: 1,
original_column: 0,
name: null,
},
],
original_module_edges: [
{
from_source: `${localOrigin}/src/main.ts`,
resolved_source: `${localOrigin}/src/dependency.ts`,
},
],
});
for (const item of result.items.slice(2))
expect(item).toMatchObject({
artifact: null,
mappings: [],
original_sources: [],
});
} finally {
server.closeAllConnections();
if (server.listening)
await new Promise<void>((resolve, reject) => {
server.close((error) =>
error === undefined ? resolve() : reject(error),
);
});
}
},
);
it("parses ECMA-426 HTTP source-map prefixes while retaining exact response evidence", async () => {
const map = JSON.stringify({
version: 3,