| 1 | import { TraceMap, presortedDecodedMap, decodedMappings } from './trace-mapping';
|
|---|
| 2 | import {
|
|---|
| 3 | COLUMN,
|
|---|
| 4 | SOURCES_INDEX,
|
|---|
| 5 | SOURCE_LINE,
|
|---|
| 6 | SOURCE_COLUMN,
|
|---|
| 7 | NAMES_INDEX,
|
|---|
| 8 | } from './sourcemap-segment';
|
|---|
| 9 | import { parse } from './types';
|
|---|
| 10 |
|
|---|
| 11 | import type {
|
|---|
| 12 | DecodedSourceMap,
|
|---|
| 13 | DecodedSourceMapXInput,
|
|---|
| 14 | EncodedSourceMapXInput,
|
|---|
| 15 | SectionedSourceMapXInput,
|
|---|
| 16 | SectionedSourceMapInput,
|
|---|
| 17 | SectionXInput,
|
|---|
| 18 | Ro,
|
|---|
| 19 | } from './types';
|
|---|
| 20 | import type { SourceMapSegment } from './sourcemap-segment';
|
|---|
| 21 |
|
|---|
| 22 | type FlattenMap = {
|
|---|
| 23 | new (map: Ro<SectionedSourceMapInput>, mapUrl?: string | null): TraceMap;
|
|---|
| 24 | (map: Ro<SectionedSourceMapInput>, mapUrl?: string | null): TraceMap;
|
|---|
| 25 | };
|
|---|
| 26 |
|
|---|
| 27 | export const FlattenMap: FlattenMap = function (map, mapUrl) {
|
|---|
| 28 | const parsed = parse(map as SectionedSourceMapInput);
|
|---|
| 29 |
|
|---|
| 30 | if (!('sections' in parsed)) {
|
|---|
| 31 | return new TraceMap(parsed as DecodedSourceMapXInput | EncodedSourceMapXInput, mapUrl);
|
|---|
| 32 | }
|
|---|
| 33 |
|
|---|
| 34 | const mappings: SourceMapSegment[][] = [];
|
|---|
| 35 | const sources: string[] = [];
|
|---|
| 36 | const sourcesContent: (string | null)[] = [];
|
|---|
| 37 | const names: string[] = [];
|
|---|
| 38 | const ignoreList: number[] = [];
|
|---|
| 39 |
|
|---|
| 40 | recurse(
|
|---|
| 41 | parsed,
|
|---|
| 42 | mapUrl,
|
|---|
| 43 | mappings,
|
|---|
| 44 | sources,
|
|---|
| 45 | sourcesContent,
|
|---|
| 46 | names,
|
|---|
| 47 | ignoreList,
|
|---|
| 48 | 0,
|
|---|
| 49 | 0,
|
|---|
| 50 | Infinity,
|
|---|
| 51 | Infinity,
|
|---|
| 52 | );
|
|---|
| 53 |
|
|---|
| 54 | const joined: DecodedSourceMap = {
|
|---|
| 55 | version: 3,
|
|---|
| 56 | file: parsed.file,
|
|---|
| 57 | names,
|
|---|
| 58 | sources,
|
|---|
| 59 | sourcesContent,
|
|---|
| 60 | mappings,
|
|---|
| 61 | ignoreList,
|
|---|
| 62 | };
|
|---|
| 63 |
|
|---|
| 64 | return presortedDecodedMap(joined);
|
|---|
| 65 | } as FlattenMap;
|
|---|
| 66 |
|
|---|
| 67 | function recurse(
|
|---|
| 68 | input: SectionedSourceMapXInput,
|
|---|
| 69 | mapUrl: string | null | undefined,
|
|---|
| 70 | mappings: SourceMapSegment[][],
|
|---|
| 71 | sources: string[],
|
|---|
| 72 | sourcesContent: (string | null)[],
|
|---|
| 73 | names: string[],
|
|---|
| 74 | ignoreList: number[],
|
|---|
| 75 | lineOffset: number,
|
|---|
| 76 | columnOffset: number,
|
|---|
| 77 | stopLine: number,
|
|---|
| 78 | stopColumn: number,
|
|---|
| 79 | ) {
|
|---|
| 80 | const { sections } = input;
|
|---|
| 81 | for (let i = 0; i < sections.length; i++) {
|
|---|
| 82 | const { map, offset } = sections[i];
|
|---|
| 83 |
|
|---|
| 84 | let sl = stopLine;
|
|---|
| 85 | let sc = stopColumn;
|
|---|
| 86 | if (i + 1 < sections.length) {
|
|---|
| 87 | const nextOffset = sections[i + 1].offset;
|
|---|
| 88 | sl = Math.min(stopLine, lineOffset + nextOffset.line);
|
|---|
| 89 |
|
|---|
| 90 | if (sl === stopLine) {
|
|---|
| 91 | sc = Math.min(stopColumn, columnOffset + nextOffset.column);
|
|---|
| 92 | } else if (sl < stopLine) {
|
|---|
| 93 | sc = columnOffset + nextOffset.column;
|
|---|
| 94 | }
|
|---|
| 95 | }
|
|---|
| 96 |
|
|---|
| 97 | addSection(
|
|---|
| 98 | map,
|
|---|
| 99 | mapUrl,
|
|---|
| 100 | mappings,
|
|---|
| 101 | sources,
|
|---|
| 102 | sourcesContent,
|
|---|
| 103 | names,
|
|---|
| 104 | ignoreList,
|
|---|
| 105 | lineOffset + offset.line,
|
|---|
| 106 | columnOffset + offset.column,
|
|---|
| 107 | sl,
|
|---|
| 108 | sc,
|
|---|
| 109 | );
|
|---|
| 110 | }
|
|---|
| 111 | }
|
|---|
| 112 |
|
|---|
| 113 | function addSection(
|
|---|
| 114 | input: SectionXInput['map'],
|
|---|
| 115 | mapUrl: string | null | undefined,
|
|---|
| 116 | mappings: SourceMapSegment[][],
|
|---|
| 117 | sources: string[],
|
|---|
| 118 | sourcesContent: (string | null)[],
|
|---|
| 119 | names: string[],
|
|---|
| 120 | ignoreList: number[],
|
|---|
| 121 | lineOffset: number,
|
|---|
| 122 | columnOffset: number,
|
|---|
| 123 | stopLine: number,
|
|---|
| 124 | stopColumn: number,
|
|---|
| 125 | ) {
|
|---|
| 126 | const parsed = parse(input);
|
|---|
| 127 | if ('sections' in parsed) return recurse(...(arguments as unknown as Parameters<typeof recurse>));
|
|---|
| 128 |
|
|---|
| 129 | const map = new TraceMap(parsed, mapUrl);
|
|---|
| 130 | const sourcesOffset = sources.length;
|
|---|
| 131 | const namesOffset = names.length;
|
|---|
| 132 | const decoded = decodedMappings(map);
|
|---|
| 133 | const { resolvedSources, sourcesContent: contents, ignoreList: ignores } = map;
|
|---|
| 134 |
|
|---|
| 135 | append(sources, resolvedSources);
|
|---|
| 136 | append(names, map.names);
|
|---|
| 137 |
|
|---|
| 138 | if (contents) append(sourcesContent, contents);
|
|---|
| 139 | else for (let i = 0; i < resolvedSources.length; i++) sourcesContent.push(null);
|
|---|
| 140 |
|
|---|
| 141 | if (ignores) for (let i = 0; i < ignores.length; i++) ignoreList.push(ignores[i] + sourcesOffset);
|
|---|
| 142 |
|
|---|
| 143 | for (let i = 0; i < decoded.length; i++) {
|
|---|
| 144 | const lineI = lineOffset + i;
|
|---|
| 145 |
|
|---|
| 146 | // We can only add so many lines before we step into the range that the next section's map
|
|---|
| 147 | // controls. When we get to the last line, then we'll start checking the segments to see if
|
|---|
| 148 | // they've crossed into the column range. But it may not have any columns that overstep, so we
|
|---|
| 149 | // still need to check that we don't overstep lines, too.
|
|---|
| 150 | if (lineI > stopLine) return;
|
|---|
| 151 |
|
|---|
| 152 | // The out line may already exist in mappings (if we're continuing the line started by a
|
|---|
| 153 | // previous section). Or, we may have jumped ahead several lines to start this section.
|
|---|
| 154 | const out = getLine(mappings, lineI);
|
|---|
| 155 | // On the 0th loop, the section's column offset shifts us forward. On all other lines (since the
|
|---|
| 156 | // map can be multiple lines), it doesn't.
|
|---|
| 157 | const cOffset = i === 0 ? columnOffset : 0;
|
|---|
| 158 |
|
|---|
| 159 | const line = decoded[i];
|
|---|
| 160 | for (let j = 0; j < line.length; j++) {
|
|---|
| 161 | const seg = line[j];
|
|---|
| 162 | const column = cOffset + seg[COLUMN];
|
|---|
| 163 |
|
|---|
| 164 | // If this segment steps into the column range that the next section's map controls, we need
|
|---|
| 165 | // to stop early.
|
|---|
| 166 | if (lineI === stopLine && column >= stopColumn) return;
|
|---|
| 167 |
|
|---|
| 168 | if (seg.length === 1) {
|
|---|
| 169 | out.push([column]);
|
|---|
| 170 | continue;
|
|---|
| 171 | }
|
|---|
| 172 |
|
|---|
| 173 | const sourcesIndex = sourcesOffset + seg[SOURCES_INDEX];
|
|---|
| 174 | const sourceLine = seg[SOURCE_LINE];
|
|---|
| 175 | const sourceColumn = seg[SOURCE_COLUMN];
|
|---|
| 176 | out.push(
|
|---|
| 177 | seg.length === 4
|
|---|
| 178 | ? [column, sourcesIndex, sourceLine, sourceColumn]
|
|---|
| 179 | : [column, sourcesIndex, sourceLine, sourceColumn, namesOffset + seg[NAMES_INDEX]],
|
|---|
| 180 | );
|
|---|
| 181 | }
|
|---|
| 182 | }
|
|---|
| 183 | }
|
|---|
| 184 |
|
|---|
| 185 | function append<T>(arr: T[], other: T[]) {
|
|---|
| 186 | for (let i = 0; i < other.length; i++) arr.push(other[i]);
|
|---|
| 187 | }
|
|---|
| 188 |
|
|---|
| 189 | function getLine<T>(arr: T[][], index: number): T[] {
|
|---|
| 190 | for (let i = arr.length; i <= index; i++) arr[i] = [];
|
|---|
| 191 | return arr[index];
|
|---|
| 192 | }
|
|---|