123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192 |
- 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;
- // We can only add so many lines before we step into the range that the next section's map
- // controls. When we get to the last line, then we'll start checking the segments to see if
- // they've crossed into the column range. But it may not have any columns that overstep, so we
- // still need to check that we don't overstep lines, too.
- if (lineI > stopLine) return;
- // The out line may already exist in mappings (if we're continuing the line started by a
- // previous section). Or, we may have jumped ahead several lines to start this section.
- const out = getLine(mappings, lineI);
- // On the 0th loop, the section's column offset shifts us forward. On all other lines (since the
- // map can be multiple lines), it doesn't.
- 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 this segment steps into the column range that the next section's map controls, we need
- // to stop early.
- 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];
- }
|