Spaces:
Sleeping
Sleeping
| import { GenMapping, maybeAddSegment, setIgnore, setSourceContent } from '@jridgewell/gen-mapping'; | |
| import { traceSegment, decodedMappings } from '@jridgewell/trace-mapping'; | |
| import type { TraceMap } from '@jridgewell/trace-mapping'; | |
| export type SourceMapSegmentObject = { | |
| column: number; | |
| line: number; | |
| name: string; | |
| source: string; | |
| content: string | null; | |
| ignore: boolean; | |
| }; | |
| export type OriginalSource = { | |
| map: null; | |
| sources: Sources[]; | |
| source: string; | |
| content: string | null; | |
| ignore: boolean; | |
| }; | |
| export type MapSource = { | |
| map: TraceMap; | |
| sources: Sources[]; | |
| source: string; | |
| content: null; | |
| ignore: false; | |
| }; | |
| export type Sources = OriginalSource | MapSource; | |
| const SOURCELESS_MAPPING = /* #__PURE__ */ SegmentObject('', -1, -1, '', null, false); | |
| const EMPTY_SOURCES: Sources[] = []; | |
| function SegmentObject( | |
| source: string, | |
| line: number, | |
| column: number, | |
| name: string, | |
| content: string | null, | |
| ignore: boolean, | |
| ): SourceMapSegmentObject { | |
| return { source, line, column, name, content, ignore }; | |
| } | |
| function Source( | |
| map: TraceMap, | |
| sources: Sources[], | |
| source: '', | |
| content: null, | |
| ignore: false, | |
| ): MapSource; | |
| function Source( | |
| map: null, | |
| sources: Sources[], | |
| source: string, | |
| content: string | null, | |
| ignore: boolean, | |
| ): OriginalSource; | |
| function Source( | |
| map: TraceMap | null, | |
| sources: Sources[], | |
| source: string | '', | |
| content: string | null, | |
| ignore: boolean, | |
| ): Sources { | |
| return { | |
| map, | |
| sources, | |
| source, | |
| content, | |
| ignore, | |
| } as any; | |
| } | |
| /** | |
| * MapSource represents a single sourcemap, with the ability to trace mappings into its child nodes | |
| * (which may themselves be SourceMapTrees). | |
| */ | |
| export function MapSource(map: TraceMap, sources: Sources[]): MapSource { | |
| return Source(map, sources, '', null, false); | |
| } | |
| /** | |
| * A "leaf" node in the sourcemap tree, representing an original, unmodified source file. Recursive | |
| * segment tracing ends at the `OriginalSource`. | |
| */ | |
| export function OriginalSource( | |
| source: string, | |
| content: string | null, | |
| ignore: boolean, | |
| ): OriginalSource { | |
| return Source(null, EMPTY_SOURCES, source, content, ignore); | |
| } | |
| /** | |
| * traceMappings is only called on the root level SourceMapTree, and begins the process of | |
| * resolving each mapping in terms of the original source files. | |
| */ | |
| export function traceMappings(tree: MapSource): GenMapping { | |
| // TODO: Eventually support sourceRoot, which has to be removed because the sources are already | |
| // fully resolved. We'll need to make sources relative to the sourceRoot before adding them. | |
| const gen = new GenMapping({ file: tree.map.file }); | |
| const { sources: rootSources, map } = tree; | |
| const rootNames = map.names; | |
| const rootMappings = decodedMappings(map); | |
| for (let i = 0; i < rootMappings.length; i++) { | |
| const segments = rootMappings[i]; | |
| for (let j = 0; j < segments.length; j++) { | |
| const segment = segments[j]; | |
| const genCol = segment[0]; | |
| let traced: SourceMapSegmentObject | null = SOURCELESS_MAPPING; | |
| // 1-length segments only move the current generated column, there's no source information | |
| // to gather from it. | |
| if (segment.length !== 1) { | |
| const source = rootSources[segment[1]]; | |
| traced = originalPositionFor( | |
| source, | |
| segment[2], | |
| segment[3], | |
| segment.length === 5 ? rootNames[segment[4]] : '', | |
| ); | |
| // If the trace is invalid, then the trace ran into a sourcemap that doesn't contain a | |
| // respective segment into an original source. | |
| if (traced == null) continue; | |
| } | |
| const { column, line, name, content, source, ignore } = traced; | |
| maybeAddSegment(gen, i, genCol, source, line, column, name); | |
| if (source && content != null) setSourceContent(gen, source, content); | |
| if (ignore) setIgnore(gen, source, true); | |
| } | |
| } | |
| return gen; | |
| } | |
| /** | |
| * originalPositionFor is only called on children SourceMapTrees. It recurses down into its own | |
| * child SourceMapTrees, until we find the original source map. | |
| */ | |
| export function originalPositionFor( | |
| source: Sources, | |
| line: number, | |
| column: number, | |
| name: string, | |
| ): SourceMapSegmentObject | null { | |
| if (!source.map) { | |
| return SegmentObject(source.source, line, column, name, source.content, source.ignore); | |
| } | |
| const segment = traceSegment(source.map, line, column); | |
| // If we couldn't find a segment, then this doesn't exist in the sourcemap. | |
| if (segment == null) return null; | |
| // 1-length segments only move the current generated column, there's no source information | |
| // to gather from it. | |
| if (segment.length === 1) return SOURCELESS_MAPPING; | |
| return originalPositionFor( | |
| source.sources[segment[1]], | |
| segment[2], | |
| segment[3], | |
| segment.length === 5 ? source.map.names[segment[4]] : name, | |
| ); | |
| } | |