Files
rea/src/javascript/sourceMaps/TraceSourceMap.ts
T
morluto 5f702dd6cc fix(parsers): preserve format boundaries and query occurrence identity
Normalize parsed facts at their owning boundaries across PE exports and certificates, ELF section names, GPU bundles, IL2CPP generic types, dyld slice selection, source maps, environment replay, and JavaScript mapped arguments. Preserve partial facts and explicit unsupported cases; clarify the corresponding documentation.

Validation: 831 affected tests passed with one existing skip across 23 files; build, typecheck/lint, documentation, formatting, and 2133-file test discovery passed. Format controls are synthetic; real Unity, GPU, and ARM-device execution is unverified.

Fixes #6709
Fixes #6688
Fixes #6719
Fixes #6718
Fixes #6704
Fixes #6703
Fixes #6692
Fixes #6723
Fixes #6687
Fixes #6726
Fixes #6696
Fixes #6691
Fixes #6727
2026-10-23 22:01:16 +08:00

215 lines
7.1 KiB
TypeScript

import { createHash } from "node:crypto";
import { createRequire } from "node:module";
import { getHeapStatistics } from "node:v8";
import {
AnyMap,
TraceMap,
decodedMappings,
type SourceMapSegment,
} from "@jridgewell/trace-mapping";
import { z } from "zod";
import { javaScriptRuntime } from "../../domain/runtimeVersion.js";
import { javaScriptWorkerMemoryLimitBytes } from "../../process/JavaScriptWorkerMemoryLimit.js";
import { webSourceOffset } from "../../domain/webSourcePosition.js";
import { resolveJavaScriptSourceMapUrl } from "../../domain/javascript/javascriptSourceMapPaths.js";
import {
webSourceMapReportSchema,
type WebSourceMapReport,
WEB_SOURCE_MAP_LIMITS,
} from "../../domain/webSourceLocation.js";
import type { WebSourcePosition } from "../../domain/webSourcePosition.js";
import {
inspectSourceMap,
SourceMapFormatFailure,
type SourceMapSourceDeclaration,
} from "./SourceMapFormat.js";
import { decodeValidatedSourceMapLeaves } from "./DecodedSourceMap.js";
/** Decode with the pinned upstream codec; preserve every equal-position candidate. */
export const traceSourceMap = (
text: string,
url: string,
position: WebSourcePosition,
): WebSourceMapReport => {
const inspected = inspectSourceMap(text);
const decodedLeaves = decodeValidatedSourceMapLeaves(inspected.leaves, url);
let map: TraceMap;
if (inspected.format === "regular") {
const decoded = decodedLeaves[0];
if (decoded === undefined)
throw new SourceMapFormatFailure(
"format",
"Regular source map has no validated leaf.",
);
map = decoded.map;
} else {
map = new AnyMap(
{
version: 3,
sections: decodedLeaves.map(({ leaf, map: sectionMap }) => ({
offset: leaf.offset,
map: sectionMap,
})),
},
url,
);
}
const rows =
inspected.format === "regular"
? (decodedLeaves[0]?.rows ?? [])
: decodedMappings(map);
validateFlattenedRows(inspected, rows, map);
const matched = greatestPosition(rows, position);
const segments =
matched === null
? []
: (rows[matched.line - 1] ?? []).filter(
(segment) => segment[0] === matched.column,
);
let bytes = 0;
const matches: WebSourceMapReport["matches"] = [];
for (const segment of segments) {
const match = originalMatch(segment, map, url, inspected.declarations);
bytes += Buffer.byteLength(JSON.stringify(match)) + 1;
if (bytes > WEB_SOURCE_MAP_LIMITS.outputBytes)
throw new SourceMapFormatFailure(
"limit",
"Complete source-map point evidence exceeds the 32 MiB output budget; no partial evidence was returned.",
);
matches.push(match);
}
const metadata: unknown = createRequire(import.meta.url)(
"@jridgewell/trace-mapping/package.json",
);
const version = z
.object({ version: z.string().min(1) })
.parse(metadata).version;
const runtime = javaScriptRuntime(process.versions);
return webSourceMapReportSchema.parse({
source_map_sha256: createHash("sha256").update(text).digest("hex"),
url_context: url,
engine: { id: "jridgewell-trace-mapping", version },
// Bun reports V8-shaped heap statistics but ignores the codec's heap flags.
// Its launcher applies the same runtime policy, and the parent verifies it.
runtime:
runtime.id === "node"
? {
id: "node-v8",
version: process.version,
v8_heap_limit_bytes: getHeapStatistics().heap_size_limit,
}
: {
id: "bun",
version: runtime.version,
node_compatibility_version: runtime.nodeCompatibilityVersion,
v8_heap_limit_bytes: null,
process_memory_limit_bytes: javaScriptWorkerMemoryLimitBytes(
WEB_SOURCE_MAP_LIMITS.codecHeapMiB,
),
},
format: inspected.format,
reported_file: inspected.reportedFile,
lookup: {
requested: position,
matched_generated_position: matched,
semantics:
"greatest generated position <= requested, across lines; all equal-position segments",
location_units: "one-based lines; zero-based UTF-16 columns",
},
matches,
diagnostics: [],
});
};
const validateFlattenedRows = (
inspected: ReturnType<typeof inspectSourceMap>,
rows: ReturnType<typeof decodedMappings>,
map: ReturnType<typeof AnyMap>,
): void => {
for (const row of rows)
for (const segment of row) {
if (
(segment.length !== 1 && segment[1] >= inspected.declarations.length) ||
(segment.length === 5 && segment[4] >= map.names.length)
)
throw new SourceMapFormatFailure(
"format",
"Decoded mapping has invalid component count, position, source index or name index.",
);
}
};
const greatestPosition = (
rows: ReturnType<typeof decodedMappings>,
position: WebSourcePosition,
): WebSourcePosition | null => {
for (
let line = Math.min(position.line - 1, rows.length - 1);
line >= 0;
line -= 1
) {
let column: number | undefined;
for (const segment of rows[line] ?? [])
if (line < position.line - 1 || segment[0] <= position.column)
column = segment[0];
if (column !== undefined) return { line: line + 1, column };
}
return null;
};
const originalMatch = (
segment: Readonly<SourceMapSegment>,
map: TraceMap,
mapUrl: string,
declarations: readonly SourceMapSourceDeclaration[],
): WebSourceMapReport["matches"][number] => {
if (segment.length === 1) return { state: "generated-only" };
const declaration = declarations[segment[1]];
if (declaration === undefined)
throw new SourceMapFormatFailure(
"format",
"Mapping references an absent source declaration.",
);
const original = { line: segment[2] + 1, column: segment[3] };
const offset =
declaration.content === null
? undefined
: webSourceOffset(declaration.content, original);
return {
state: "mapped",
flattened_source_index: segment[1],
section_path: [...declaration.sectionPath],
source_index: declaration.sourceIndex,
reported_source: declaration.source,
reported_source_root: declaration.root,
resolved_url: resolveJavaScriptSourceMapUrl(
declaration.source,
declaration.root,
mapUrl,
),
ignored: declaration.ignored,
content:
declaration.content === null
? { state: "unavailable", reason: "sourcesContent-not-retained" }
: {
state: "embedded",
text: declaration.content,
utf8_sha256: createHash("sha256")
.update(declaration.content)
.digest("hex"),
utf8_bytes: Buffer.byteLength(declaration.content),
representation: "UTF-8 encoding of decoded sourcesContent text",
},
original_position: {
...original,
offset: offset ?? null,
content_position:
declaration.content === null
? "content-unavailable"
: offset === undefined
? "outside-embedded-text"
: "verified-in-embedded-text",
},
name: segment.length === 5 ? (map.names[segment[4]] ?? null) : null,
};
};