| | import { encode, decode } from '@jridgewell/sourcemap-codec'; |
| |
|
| | import resolver from './resolve'; |
| | import maybeSort from './sort'; |
| | import buildBySources from './by-source'; |
| | import { |
| | memoizedState, |
| | memoizedBinarySearch, |
| | upperBound, |
| | lowerBound, |
| | found as bsFound, |
| | } from './binary-search'; |
| | import { |
| | COLUMN, |
| | SOURCES_INDEX, |
| | SOURCE_LINE, |
| | SOURCE_COLUMN, |
| | NAMES_INDEX, |
| | REV_GENERATED_LINE, |
| | REV_GENERATED_COLUMN, |
| | } from './sourcemap-segment'; |
| | import { parse } from './types'; |
| |
|
| | import type { SourceMapSegment, ReverseSegment } from './sourcemap-segment'; |
| | import type { |
| | SourceMapV3, |
| | DecodedSourceMap, |
| | EncodedSourceMap, |
| | InvalidOriginalMapping, |
| | OriginalMapping, |
| | InvalidGeneratedMapping, |
| | GeneratedMapping, |
| | SourceMapInput, |
| | Needle, |
| | SourceNeedle, |
| | SourceMap, |
| | EachMapping, |
| | Bias, |
| | XInput, |
| | SectionedSourceMap, |
| | Ro, |
| | } from './types'; |
| | import type { Source } from './by-source'; |
| | import type { MemoState } from './binary-search'; |
| |
|
| | export type { SourceMapSegment } from './sourcemap-segment'; |
| | export type { |
| | SourceMap, |
| | DecodedSourceMap, |
| | EncodedSourceMap, |
| | Section, |
| | SectionedSourceMap, |
| | SourceMapV3, |
| | Bias, |
| | EachMapping, |
| | GeneratedMapping, |
| | InvalidGeneratedMapping, |
| | InvalidOriginalMapping, |
| | Needle, |
| | OriginalMapping, |
| | OriginalMapping as Mapping, |
| | SectionedSourceMapInput, |
| | SourceMapInput, |
| | SourceNeedle, |
| | XInput, |
| | EncodedSourceMapXInput, |
| | DecodedSourceMapXInput, |
| | SectionedSourceMapXInput, |
| | SectionXInput, |
| | } from './types'; |
| |
|
| | interface PublicMap { |
| | _encoded: TraceMap['_encoded']; |
| | _decoded: TraceMap['_decoded']; |
| | _decodedMemo: TraceMap['_decodedMemo']; |
| | _bySources: TraceMap['_bySources']; |
| | _bySourceMemos: TraceMap['_bySourceMemos']; |
| | } |
| |
|
| | const LINE_GTR_ZERO = '`line` must be greater than 0 (lines start at line 1)'; |
| | const COL_GTR_EQ_ZERO = '`column` must be greater than or equal to 0 (columns start at column 0)'; |
| |
|
| | export const LEAST_UPPER_BOUND = -1; |
| | export const GREATEST_LOWER_BOUND = 1; |
| |
|
| | export { FlattenMap, FlattenMap as AnyMap } from './flatten-map'; |
| |
|
| | export class TraceMap implements SourceMap { |
| | declare version: SourceMapV3['version']; |
| | declare file: SourceMapV3['file']; |
| | declare names: SourceMapV3['names']; |
| | declare sourceRoot: SourceMapV3['sourceRoot']; |
| | declare sources: SourceMapV3['sources']; |
| | declare sourcesContent: SourceMapV3['sourcesContent']; |
| | declare ignoreList: SourceMapV3['ignoreList']; |
| |
|
| | declare resolvedSources: string[]; |
| | declare private _encoded: string | undefined; |
| |
|
| | declare private _decoded: SourceMapSegment[][] | undefined; |
| | declare private _decodedMemo: MemoState; |
| |
|
| | declare private _bySources: Source[] | undefined; |
| | declare private _bySourceMemos: MemoState[] | undefined; |
| |
|
| | constructor(map: Ro<SourceMapInput>, mapUrl?: string | null) { |
| | const isString = typeof map === 'string'; |
| | if (!isString && (map as unknown as { _decodedMemo: any })._decodedMemo) return map as TraceMap; |
| |
|
| | const parsed = parse(map as Exclude<SourceMapInput, TraceMap>); |
| |
|
| | const { version, file, names, sourceRoot, sources, sourcesContent } = parsed; |
| | this.version = version; |
| | this.file = file; |
| | this.names = names || []; |
| | this.sourceRoot = sourceRoot; |
| | this.sources = sources; |
| | this.sourcesContent = sourcesContent; |
| | this.ignoreList = parsed.ignoreList || (parsed as XInput).x_google_ignoreList || undefined; |
| |
|
| | const resolve = resolver(mapUrl, sourceRoot); |
| | this.resolvedSources = sources.map(resolve); |
| |
|
| | const { mappings } = parsed; |
| | if (typeof mappings === 'string') { |
| | this._encoded = mappings; |
| | this._decoded = undefined; |
| | } else if (Array.isArray(mappings)) { |
| | this._encoded = undefined; |
| | this._decoded = maybeSort(mappings, isString); |
| | } else if ((parsed as unknown as SectionedSourceMap).sections) { |
| | throw new Error(`TraceMap passed sectioned source map, please use FlattenMap export instead`); |
| | } else { |
| | throw new Error(`invalid source map: ${JSON.stringify(parsed)}`); |
| | } |
| |
|
| | this._decodedMemo = memoizedState(); |
| | this._bySources = undefined; |
| | this._bySourceMemos = undefined; |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | function cast(map: unknown): PublicMap { |
| | return map as any; |
| | } |
| |
|
| | |
| | |
| | |
| | export function encodedMappings(map: TraceMap): EncodedSourceMap['mappings'] { |
| | return (cast(map)._encoded ??= encode(cast(map)._decoded!)); |
| | } |
| |
|
| | |
| | |
| | |
| | export function decodedMappings(map: TraceMap): Readonly<DecodedSourceMap['mappings']> { |
| | return (cast(map)._decoded ||= decode(cast(map)._encoded!)); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | export function traceSegment( |
| | map: TraceMap, |
| | line: number, |
| | column: number, |
| | ): Readonly<SourceMapSegment> | null { |
| | const decoded = decodedMappings(map); |
| |
|
| | |
| | |
| | if (line >= decoded.length) return null; |
| |
|
| | const segments = decoded[line]; |
| | const index = traceSegmentInternal( |
| | segments, |
| | cast(map)._decodedMemo, |
| | line, |
| | column, |
| | GREATEST_LOWER_BOUND, |
| | ); |
| |
|
| | return index === -1 ? null : segments[index]; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | export function originalPositionFor( |
| | map: TraceMap, |
| | needle: Needle, |
| | ): OriginalMapping | InvalidOriginalMapping { |
| | let { line, column, bias } = needle; |
| | line--; |
| | if (line < 0) throw new Error(LINE_GTR_ZERO); |
| | if (column < 0) throw new Error(COL_GTR_EQ_ZERO); |
| |
|
| | const decoded = decodedMappings(map); |
| |
|
| | |
| | |
| | if (line >= decoded.length) return OMapping(null, null, null, null); |
| |
|
| | const segments = decoded[line]; |
| | const index = traceSegmentInternal( |
| | segments, |
| | cast(map)._decodedMemo, |
| | line, |
| | column, |
| | bias || GREATEST_LOWER_BOUND, |
| | ); |
| |
|
| | if (index === -1) return OMapping(null, null, null, null); |
| |
|
| | const segment = segments[index]; |
| | if (segment.length === 1) return OMapping(null, null, null, null); |
| |
|
| | const { names, resolvedSources } = map; |
| | return OMapping( |
| | resolvedSources[segment[SOURCES_INDEX]], |
| | segment[SOURCE_LINE] + 1, |
| | segment[SOURCE_COLUMN], |
| | segment.length === 5 ? names[segment[NAMES_INDEX]] : null, |
| | ); |
| | } |
| |
|
| | |
| | |
| | |
| | export function generatedPositionFor( |
| | map: TraceMap, |
| | needle: SourceNeedle, |
| | ): GeneratedMapping | InvalidGeneratedMapping { |
| | const { source, line, column, bias } = needle; |
| | return generatedPosition(map, source, line, column, bias || GREATEST_LOWER_BOUND, false); |
| | } |
| |
|
| | |
| | |
| | |
| | export function allGeneratedPositionsFor(map: TraceMap, needle: SourceNeedle): GeneratedMapping[] { |
| | const { source, line, column, bias } = needle; |
| | |
| | return generatedPosition(map, source, line, column, bias || LEAST_UPPER_BOUND, true); |
| | } |
| |
|
| | |
| | |
| | |
| | export function eachMapping(map: TraceMap, cb: (mapping: EachMapping) => void): void { |
| | const decoded = decodedMappings(map); |
| | const { names, resolvedSources } = map; |
| |
|
| | for (let i = 0; i < decoded.length; i++) { |
| | const line = decoded[i]; |
| | for (let j = 0; j < line.length; j++) { |
| | const seg = line[j]; |
| |
|
| | const generatedLine = i + 1; |
| | const generatedColumn = seg[0]; |
| | let source = null; |
| | let originalLine = null; |
| | let originalColumn = null; |
| | let name = null; |
| | if (seg.length !== 1) { |
| | source = resolvedSources[seg[1]]; |
| | originalLine = seg[2] + 1; |
| | originalColumn = seg[3]; |
| | } |
| | if (seg.length === 5) name = names[seg[4]]; |
| |
|
| | cb({ |
| | generatedLine, |
| | generatedColumn, |
| | source, |
| | originalLine, |
| | originalColumn, |
| | name, |
| | } as EachMapping); |
| | } |
| | } |
| | } |
| |
|
| | function sourceIndex(map: TraceMap, source: string): number { |
| | const { sources, resolvedSources } = map; |
| | let index = sources.indexOf(source); |
| | if (index === -1) index = resolvedSources.indexOf(source); |
| | return index; |
| | } |
| |
|
| | |
| | |
| | |
| | export function sourceContentFor(map: TraceMap, source: string): string | null { |
| | const { sourcesContent } = map; |
| | if (sourcesContent == null) return null; |
| | const index = sourceIndex(map, source); |
| | return index === -1 ? null : sourcesContent[index]; |
| | } |
| |
|
| | |
| | |
| | |
| | export function isIgnored(map: TraceMap, source: string): boolean { |
| | const { ignoreList } = map; |
| | if (ignoreList == null) return false; |
| | const index = sourceIndex(map, source); |
| | return index === -1 ? false : ignoreList.includes(index); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | export function presortedDecodedMap(map: DecodedSourceMap, mapUrl?: string): TraceMap { |
| | const tracer = new TraceMap(clone(map, []), mapUrl); |
| | cast(tracer)._decoded = map.mappings; |
| | return tracer; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | export function decodedMap( |
| | map: TraceMap, |
| | ): Omit<DecodedSourceMap, 'mappings'> & { mappings: readonly SourceMapSegment[][] } { |
| | return clone(map, decodedMappings(map)); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | export function encodedMap(map: TraceMap): EncodedSourceMap { |
| | return clone(map, encodedMappings(map)); |
| | } |
| |
|
| | function clone<T extends string | readonly SourceMapSegment[][]>( |
| | map: TraceMap | DecodedSourceMap, |
| | mappings: T, |
| | ): T extends string ? EncodedSourceMap : DecodedSourceMap { |
| | return { |
| | version: map.version, |
| | file: map.file, |
| | names: map.names, |
| | sourceRoot: map.sourceRoot, |
| | sources: map.sources, |
| | sourcesContent: map.sourcesContent, |
| | mappings, |
| | ignoreList: map.ignoreList || (map as XInput).x_google_ignoreList, |
| | } as any; |
| | } |
| |
|
| | function OMapping(source: null, line: null, column: null, name: null): InvalidOriginalMapping; |
| | function OMapping( |
| | source: string, |
| | line: number, |
| | column: number, |
| | name: string | null, |
| | ): OriginalMapping; |
| | function OMapping( |
| | source: string | null, |
| | line: number | null, |
| | column: number | null, |
| | name: string | null, |
| | ): OriginalMapping | InvalidOriginalMapping { |
| | return { source, line, column, name } as any; |
| | } |
| |
|
| | function GMapping(line: null, column: null): InvalidGeneratedMapping; |
| | function GMapping(line: number, column: number): GeneratedMapping; |
| | function GMapping( |
| | line: number | null, |
| | column: number | null, |
| | ): GeneratedMapping | InvalidGeneratedMapping { |
| | return { line, column } as any; |
| | } |
| |
|
| | function traceSegmentInternal( |
| | segments: SourceMapSegment[], |
| | memo: MemoState, |
| | line: number, |
| | column: number, |
| | bias: Bias, |
| | ): number; |
| | function traceSegmentInternal( |
| | segments: ReverseSegment[], |
| | memo: MemoState, |
| | line: number, |
| | column: number, |
| | bias: Bias, |
| | ): number; |
| | function traceSegmentInternal( |
| | segments: SourceMapSegment[] | ReverseSegment[], |
| | memo: MemoState, |
| | line: number, |
| | column: number, |
| | bias: Bias, |
| | ): number { |
| | let index = memoizedBinarySearch(segments, column, memo, line); |
| | if (bsFound) { |
| | index = (bias === LEAST_UPPER_BOUND ? upperBound : lowerBound)(segments, column, index); |
| | } else if (bias === LEAST_UPPER_BOUND) index++; |
| |
|
| | if (index === -1 || index === segments.length) return -1; |
| | return index; |
| | } |
| |
|
| | function sliceGeneratedPositions( |
| | segments: ReverseSegment[], |
| | memo: MemoState, |
| | line: number, |
| | column: number, |
| | bias: Bias, |
| | ): GeneratedMapping[] { |
| | let min = traceSegmentInternal(segments, memo, line, column, GREATEST_LOWER_BOUND); |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | if (!bsFound && bias === LEAST_UPPER_BOUND) min++; |
| |
|
| | if (min === -1 || min === segments.length) return []; |
| |
|
| | |
| | |
| | |
| | const matchedColumn = bsFound ? column : segments[min][COLUMN]; |
| |
|
| | |
| | if (!bsFound) min = lowerBound(segments, matchedColumn, min); |
| | const max = upperBound(segments, matchedColumn, min); |
| |
|
| | const result = []; |
| | for (; min <= max; min++) { |
| | const segment = segments[min]; |
| | result.push(GMapping(segment[REV_GENERATED_LINE] + 1, segment[REV_GENERATED_COLUMN])); |
| | } |
| | return result; |
| | } |
| |
|
| | function generatedPosition( |
| | map: TraceMap, |
| | source: string, |
| | line: number, |
| | column: number, |
| | bias: Bias, |
| | all: false, |
| | ): GeneratedMapping | InvalidGeneratedMapping; |
| | function generatedPosition( |
| | map: TraceMap, |
| | source: string, |
| | line: number, |
| | column: number, |
| | bias: Bias, |
| | all: true, |
| | ): GeneratedMapping[]; |
| | function generatedPosition( |
| | map: TraceMap, |
| | source: string, |
| | line: number, |
| | column: number, |
| | bias: Bias, |
| | all: boolean, |
| | ): GeneratedMapping | InvalidGeneratedMapping | GeneratedMapping[] { |
| | line--; |
| | if (line < 0) throw new Error(LINE_GTR_ZERO); |
| | if (column < 0) throw new Error(COL_GTR_EQ_ZERO); |
| |
|
| | const { sources, resolvedSources } = map; |
| | let sourceIndex = sources.indexOf(source); |
| | if (sourceIndex === -1) sourceIndex = resolvedSources.indexOf(source); |
| | if (sourceIndex === -1) return all ? [] : GMapping(null, null); |
| |
|
| | const bySourceMemos = (cast(map)._bySourceMemos ||= sources.map(memoizedState)); |
| | const generated = (cast(map)._bySources ||= buildBySources(decodedMappings(map), bySourceMemos)); |
| |
|
| | const segments = generated[sourceIndex][line]; |
| | if (segments == null) return all ? [] : GMapping(null, null); |
| |
|
| | const memo = bySourceMemos[sourceIndex]; |
| |
|
| | if (all) return sliceGeneratedPositions(segments, memo, line, column, bias); |
| |
|
| | const index = traceSegmentInternal(segments, memo, line, column, bias); |
| | if (index === -1) return GMapping(null, null); |
| |
|
| | const segment = segments[index]; |
| | return GMapping(segment[REV_GENERATED_LINE] + 1, segment[REV_GENERATED_COLUMN]); |
| | } |
| |
|