| 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]; |
| } |
|
|