You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					205 lines
				
				8.3 KiB
			
		
		
			
		
	
	
					205 lines
				
				8.3 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								import { decodedMappings, traceSegment, TraceMap } from '@jridgewell/trace-mapping';
							 | 
						||
| 
								 | 
							
								import { GenMapping, addSegment, setSourceContent, decodedMap, encodedMap } from '@jridgewell/gen-mapping';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const SOURCELESS_MAPPING = {
							 | 
						||
| 
								 | 
							
								    source: null,
							 | 
						||
| 
								 | 
							
								    column: null,
							 | 
						||
| 
								 | 
							
								    line: null,
							 | 
						||
| 
								 | 
							
								    name: null,
							 | 
						||
| 
								 | 
							
								    content: null,
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								const EMPTY_SOURCES = [];
							 | 
						||
| 
								 | 
							
								function Source(map, sources, source, content) {
							 | 
						||
| 
								 | 
							
								    return {
							 | 
						||
| 
								 | 
							
								        map,
							 | 
						||
| 
								 | 
							
								        sources,
							 | 
						||
| 
								 | 
							
								        source,
							 | 
						||
| 
								 | 
							
								        content,
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * 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);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * A "leaf" node in the sourcemap tree, representing an original, unmodified source file. Recursive
							 | 
						||
| 
								 | 
							
								 * segment tracing ends at the `OriginalSource`.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function OriginalSource(source, content) {
							 | 
						||
| 
								 | 
							
								    return Source(null, EMPTY_SOURCES, source, content);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * 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) {
							 | 
						||
| 
								 | 
							
								    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];
							 | 
						||
| 
								 | 
							
								        let lastSource = null;
							 | 
						||
| 
								 | 
							
								        let lastSourceLine = null;
							 | 
						||
| 
								 | 
							
								        let lastSourceColumn = null;
							 | 
						||
| 
								 | 
							
								        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;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            // So we traced a segment down into its original source file. Now push a
							 | 
						||
| 
								 | 
							
								            // new segment pointing to this location.
							 | 
						||
| 
								 | 
							
								            const { column, line, name, content, source } = traced;
							 | 
						||
| 
								 | 
							
								            if (line === lastSourceLine && column === lastSourceColumn && source === lastSource) {
							 | 
						||
| 
								 | 
							
								                continue;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            lastSourceLine = line;
							 | 
						||
| 
								 | 
							
								            lastSourceColumn = column;
							 | 
						||
| 
								 | 
							
								            lastSource = source;
							 | 
						||
| 
								 | 
							
								            // Sigh, TypeScript can't figure out source/line/column are either all null, or all non-null...
							 | 
						||
| 
								 | 
							
								            addSegment(gen, i, genCol, source, line, column, name);
							 | 
						||
| 
								 | 
							
								            if (content != null)
							 | 
						||
| 
								 | 
							
								                setSourceContent(gen, source, content);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    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 { column, line, name, source: source.source, content: source.content };
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    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 } = 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,
							 | 
						||
| 
								 | 
							
								        };
							 | 
						||
| 
								 | 
							
								        // 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 } = 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 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;
							 | 
						||
| 
								 | 
							
								        return OriginalSource(source, sourceContent);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    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 ? decodedMap(map) : encodedMap(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.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
							 |