|
|
import { TraceMap, presortedDecodedMap, decodedMappings } from './trace-mapping'; |
|
|
import { |
|
|
COLUMN, |
|
|
SOURCES_INDEX, |
|
|
SOURCE_LINE, |
|
|
SOURCE_COLUMN, |
|
|
NAMES_INDEX, |
|
|
} from './sourcemap-segment'; |
|
|
import { parse } from './types'; |
|
|
|
|
|
import type { |
|
|
DecodedSourceMap, |
|
|
DecodedSourceMapXInput, |
|
|
EncodedSourceMapXInput, |
|
|
SectionedSourceMapXInput, |
|
|
SectionedSourceMapInput, |
|
|
SectionXInput, |
|
|
Ro, |
|
|
} from './types'; |
|
|
import type { SourceMapSegment } from './sourcemap-segment'; |
|
|
|
|
|
type FlattenMap = { |
|
|
new (map: Ro<SectionedSourceMapInput>, mapUrl?: string | null): TraceMap; |
|
|
(map: Ro<SectionedSourceMapInput>, mapUrl?: string | null): TraceMap; |
|
|
}; |
|
|
|
|
|
export const FlattenMap: FlattenMap = function (map, mapUrl) { |
|
|
const parsed = parse(map as SectionedSourceMapInput); |
|
|
|
|
|
if (!('sections' in parsed)) { |
|
|
return new TraceMap(parsed as DecodedSourceMapXInput | EncodedSourceMapXInput, mapUrl); |
|
|
} |
|
|
|
|
|
const mappings: SourceMapSegment[][] = []; |
|
|
const sources: string[] = []; |
|
|
const sourcesContent: (string | null)[] = []; |
|
|
const names: string[] = []; |
|
|
const ignoreList: number[] = []; |
|
|
|
|
|
recurse( |
|
|
parsed, |
|
|
mapUrl, |
|
|
mappings, |
|
|
sources, |
|
|
sourcesContent, |
|
|
names, |
|
|
ignoreList, |
|
|
0, |
|
|
0, |
|
|
Infinity, |
|
|
Infinity, |
|
|
); |
|
|
|
|
|
const joined: DecodedSourceMap = { |
|
|
version: 3, |
|
|
file: parsed.file, |
|
|
names, |
|
|
sources, |
|
|
sourcesContent, |
|
|
mappings, |
|
|
ignoreList, |
|
|
}; |
|
|
|
|
|
return presortedDecodedMap(joined); |
|
|
} as FlattenMap; |
|
|
|
|
|
function recurse( |
|
|
input: SectionedSourceMapXInput, |
|
|
mapUrl: string | null | undefined, |
|
|
mappings: SourceMapSegment[][], |
|
|
sources: string[], |
|
|
sourcesContent: (string | null)[], |
|
|
names: string[], |
|
|
ignoreList: number[], |
|
|
lineOffset: number, |
|
|
columnOffset: number, |
|
|
stopLine: number, |
|
|
stopColumn: number, |
|
|
) { |
|
|
const { sections } = input; |
|
|
for (let i = 0; i < sections.length; i++) { |
|
|
const { map, offset } = sections[i]; |
|
|
|
|
|
let sl = stopLine; |
|
|
let sc = stopColumn; |
|
|
if (i + 1 < sections.length) { |
|
|
const nextOffset = sections[i + 1].offset; |
|
|
sl = Math.min(stopLine, lineOffset + nextOffset.line); |
|
|
|
|
|
if (sl === stopLine) { |
|
|
sc = Math.min(stopColumn, columnOffset + nextOffset.column); |
|
|
} else if (sl < stopLine) { |
|
|
sc = columnOffset + nextOffset.column; |
|
|
} |
|
|
} |
|
|
|
|
|
addSection( |
|
|
map, |
|
|
mapUrl, |
|
|
mappings, |
|
|
sources, |
|
|
sourcesContent, |
|
|
names, |
|
|
ignoreList, |
|
|
lineOffset + offset.line, |
|
|
columnOffset + offset.column, |
|
|
sl, |
|
|
sc, |
|
|
); |
|
|
} |
|
|
} |
|
|
|
|
|
function addSection( |
|
|
input: SectionXInput['map'], |
|
|
mapUrl: string | null | undefined, |
|
|
mappings: SourceMapSegment[][], |
|
|
sources: string[], |
|
|
sourcesContent: (string | null)[], |
|
|
names: string[], |
|
|
ignoreList: number[], |
|
|
lineOffset: number, |
|
|
columnOffset: number, |
|
|
stopLine: number, |
|
|
stopColumn: number, |
|
|
) { |
|
|
const parsed = parse(input); |
|
|
if ('sections' in parsed) return recurse(...(arguments as unknown as Parameters<typeof recurse>)); |
|
|
|
|
|
const map = new TraceMap(parsed, mapUrl); |
|
|
const sourcesOffset = sources.length; |
|
|
const namesOffset = names.length; |
|
|
const decoded = decodedMappings(map); |
|
|
const { resolvedSources, sourcesContent: contents, ignoreList: ignores } = map; |
|
|
|
|
|
append(sources, resolvedSources); |
|
|
append(names, map.names); |
|
|
|
|
|
if (contents) append(sourcesContent, contents); |
|
|
else for (let i = 0; i < resolvedSources.length; i++) sourcesContent.push(null); |
|
|
|
|
|
if (ignores) for (let i = 0; i < ignores.length; i++) ignoreList.push(ignores[i] + sourcesOffset); |
|
|
|
|
|
for (let i = 0; i < decoded.length; i++) { |
|
|
const lineI = lineOffset + i; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (lineI > stopLine) return; |
|
|
|
|
|
|
|
|
|
|
|
const out = getLine(mappings, lineI); |
|
|
|
|
|
|
|
|
const cOffset = i === 0 ? columnOffset : 0; |
|
|
|
|
|
const line = decoded[i]; |
|
|
for (let j = 0; j < line.length; j++) { |
|
|
const seg = line[j]; |
|
|
const column = cOffset + seg[COLUMN]; |
|
|
|
|
|
|
|
|
|
|
|
if (lineI === stopLine && column >= stopColumn) return; |
|
|
|
|
|
if (seg.length === 1) { |
|
|
out.push([column]); |
|
|
continue; |
|
|
} |
|
|
|
|
|
const sourcesIndex = sourcesOffset + seg[SOURCES_INDEX]; |
|
|
const sourceLine = seg[SOURCE_LINE]; |
|
|
const sourceColumn = seg[SOURCE_COLUMN]; |
|
|
out.push( |
|
|
seg.length === 4 |
|
|
? [column, sourcesIndex, sourceLine, sourceColumn] |
|
|
: [column, sourcesIndex, sourceLine, sourceColumn, namesOffset + seg[NAMES_INDEX]], |
|
|
); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
function append<T>(arr: T[], other: T[]) { |
|
|
for (let i = 0; i < other.length; i++) arr.push(other[i]); |
|
|
} |
|
|
|
|
|
function getLine<T>(arr: T[][], index: number): T[] { |
|
|
for (let i = arr.length; i <= index; i++) arr[i] = []; |
|
|
return arr[index]; |
|
|
} |
|
|
|