| import { decodedMappings, traceSegment, TraceMap } from '@jridgewell/trace-mapping'; |
| import { GenMapping, maybeAddSegment, setSourceContent, setIgnore, toDecodedMap, toEncodedMap } from '@jridgewell/gen-mapping'; |
| |
| const SOURCELESS_MAPPING = /* #__PURE__ */ SegmentObject('', -1, -1, '', null, false); |
| const EMPTY_SOURCES = []; |
| function SegmentObject(source, line, column, name, content, ignore) { |
| return { source, line, column, name, content, ignore }; |
| } |
| function Source(map, sources, source, content, ignore) { |
| return { |
| map, |
| sources, |
| source, |
| content, |
| ignore, |
| }; |
| } |
| /** |
| * MapSource represents a single sourcemap, with the ability to trace mappings into its child nodes |
| * (which may themselves be SourceMapTrees). |
| */ |
| function MapSource(map, sources) { |
| 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`. |
| */ |
| function OriginalSource(source, content, ignore) { |
| 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. |
| */ |
| function traceMappings(tree) { |
| // 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 = 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. |
| */ |
| function originalPositionFor(source, line, column, name) { |
| 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); |
| } |
| |
| function asArray(value) { |
| if (Array.isArray(value)) |
| return value; |
| return [value]; |
| } |
| /** |
| * Recursively builds a tree structure out of sourcemap files, with each node |
| * being either an `OriginalSource` "leaf" or a `SourceMapTree` composed of |
| * `OriginalSource`s and `SourceMapTree`s. |
| * |
| * Every sourcemap is composed of a collection of source files and mappings |
| * into locations of those source files. When we generate a `SourceMapTree` for |
| * the sourcemap, we attempt to load each source file's own sourcemap. If it |
| * does not have an associated sourcemap, it is considered an original, |
| * unmodified source file. |
| */ |
| function buildSourceMapTree(input, loader) { |
| const maps = asArray(input).map((m) => new TraceMap(m, '')); |
| const map = maps.pop(); |
| for (let i = 0; i < maps.length; i++) { |
| if (maps[i].sources.length > 1) { |
| throw new Error(`Transformation map ${i} must have exactly one source file.\n` + |
| 'Did you specify these with the most recent transformation maps first?'); |
| } |
| } |
| let tree = build(map, loader, '', 0); |
| for (let i = maps.length - 1; i >= 0; i--) { |
| tree = MapSource(maps[i], [tree]); |
| } |
| return tree; |
| } |
| function build(map, loader, importer, importerDepth) { |
| const { resolvedSources, sourcesContent, ignoreList } = map; |
| const depth = importerDepth + 1; |
| const children = resolvedSources.map((sourceFile, i) => { |
| // The loading context gives the loader more information about why this file is being loaded |
| // (eg, from which importer). It also allows the loader to override the location of the loaded |
| // sourcemap/original source, or to override the content in the sourcesContent field if it's |
| // an unmodified source file. |
| const ctx = { |
| importer, |
| depth, |
| source: sourceFile || '', |
| content: undefined, |
| ignore: undefined, |
| }; |
| // Use the provided loader callback to retrieve the file's sourcemap. |
| // TODO: We should eventually support async loading of sourcemap files. |
| const sourceMap = loader(ctx.source, ctx); |
| const { source, content, ignore } = ctx; |
| // If there is a sourcemap, then we need to recurse into it to load its source files. |
| if (sourceMap) |
| return build(new TraceMap(sourceMap, source), loader, source, depth); |
| // Else, it's an unmodified source file. |
| // The contents of this unmodified source file can be overridden via the loader context, |
| // allowing it to be explicitly null or a string. If it remains undefined, we fall back to |
| // the importing sourcemap's `sourcesContent` field. |
| const sourceContent = content !== undefined ? content : sourcesContent ? sourcesContent[i] : null; |
| const ignored = ignore !== undefined ? ignore : ignoreList ? ignoreList.includes(i) : false; |
| return OriginalSource(source, sourceContent, ignored); |
| }); |
| return MapSource(map, children); |
| } |
| |
| /** |
| * A SourceMap v3 compatible sourcemap, which only includes fields that were |
| * provided to it. |
| */ |
| class SourceMap { |
| constructor(map, options) { |
| const out = options.decodedMappings ? toDecodedMap(map) : toEncodedMap(map); |
| this.version = out.version; // SourceMap spec says this should be first. |
| this.file = out.file; |
| this.mappings = out.mappings; |
| this.names = out.names; |
| this.ignoreList = out.ignoreList; |
| this.sourceRoot = out.sourceRoot; |
| this.sources = out.sources; |
| if (!options.excludeContent) { |
| this.sourcesContent = out.sourcesContent; |
| } |
| } |
| toString() { |
| return JSON.stringify(this); |
| } |
| } |
| |
| /** |
| * Traces through all the mappings in the root sourcemap, through the sources |
| * (and their sourcemaps), all the way back to the original source location. |
| * |
| * `loader` will be called every time we encounter a source file. If it returns |
| * a sourcemap, we will recurse into that sourcemap to continue the trace. If |
| * it returns a falsey value, that source file is treated as an original, |
| * unmodified source file. |
| * |
| * Pass `excludeContent` to exclude any self-containing source file content |
| * from the output sourcemap. |
| * |
| * Pass `decodedMappings` to receive a SourceMap with decoded (instead of |
| * VLQ encoded) mappings. |
| */ |
| function remapping(input, loader, options) { |
| const opts = typeof options === 'object' ? options : { excludeContent: !!options, decodedMappings: false }; |
| const tree = buildSourceMapTree(input, loader); |
| return new SourceMap(traceMappings(tree), opts); |
| } |
| |
| export { remapping as default }; |
| //# sourceMappingURL=remapping.mjs.map |