|
|
- /*
- MIT License http://www.opensource.org/licenses/mit-license.php
- Author Tobias Koppers @sokra
- */
-
- "use strict";
-
- var SourceNode = require("source-map").SourceNode;
- var SourceMapConsumer = require("source-map").SourceMapConsumer;
-
- var applySourceMap = function(
- sourceNode,
- sourceMapConsumer,
- sourceFile,
- removeGeneratedCodeForSourceFile
- ) {
- // The following notations are used to name stuff:
- // Left <------------> Middle <-------------------> Right
- // Input arguments:
- // sourceNode - Code mapping from Left to Middle
- // sourceFile - Name of a Middle file
- // sourceMapConsumer - Code mapping from Middle to Right
- // Variables:
- // l2m m2r
- // Left <-----------------------------------------> Right
- // Variables:
- // l2r
-
- var l2rResult = new SourceNode();
- var l2rOutput = [];
-
- var middleSourceContents = {};
-
- var m2rMappingsByLine = {};
-
- var rightSourceContentsSet = {};
- var rightSourceContentsLines = {};
-
- // Store all mappings by generated line
- sourceMapConsumer.eachMapping(
- function(mapping) {
- (m2rMappingsByLine[mapping.generatedLine] =
- m2rMappingsByLine[mapping.generatedLine] || []).push(mapping);
- },
- null,
- SourceMapConsumer.GENERATED_ORDER
- );
-
- // Store all source contents
- sourceNode.walkSourceContents(function(source, content) {
- middleSourceContents["$" + source] = content;
- });
-
- var middleSource = middleSourceContents["$" + sourceFile];
- var middleSourceLines = middleSource ? middleSource.split("\n") : undefined;
-
- // Walk all left to middle mappings
- sourceNode.walk(function(chunk, middleMapping) {
- var source;
-
- // Find a mapping from middle to right
- if(
- middleMapping.source === sourceFile &&
- middleMapping.line &&
- m2rMappingsByLine[middleMapping.line]
- ) {
- var m2rBestFit;
- var m2rMappings = m2rMappingsByLine[middleMapping.line];
- // Note: if this becomes a performance problem, use binary search
- for(var i = 0; i < m2rMappings.length; i++) {
- if(m2rMappings[i].generatedColumn <= middleMapping.column) {
- m2rBestFit = m2rMappings[i];
- }
- }
- if(m2rBestFit) {
- var allowMiddleName = false;
- var middleLine;
- var rightSourceContent;
- var rightSourceContentLines;
- var rightSource = m2rBestFit.source;
- // Check if we have middle and right source for this mapping
- // Then we could have an "identify" mapping
- if(
- middleSourceLines &&
- rightSource &&
- (middleLine = middleSourceLines[m2rBestFit.generatedLine - 1]) &&
- ((rightSourceContentLines = rightSourceContentsLines[rightSource]) ||
- (rightSourceContent = sourceMapConsumer.sourceContentFor(
- rightSource,
- true
- )))
- ) {
- if(!rightSourceContentLines) {
- rightSourceContentLines = rightSourceContentsLines[
- rightSource
- ] = rightSourceContent.split("\n");
- }
- var rightLine = rightSourceContentLines[m2rBestFit.originalLine - 1];
- if(rightLine) {
- var offset = middleMapping.column - m2rBestFit.generatedColumn;
- if(offset > 0) {
- var middlePart = middleLine.slice(
- m2rBestFit.generatedColumn,
- middleMapping.column
- );
- var rightPart = rightLine.slice(
- m2rBestFit.originalColumn,
- m2rBestFit.originalColumn + offset
- );
- if(middlePart === rightPart) {
- // When original and generated code is equal we assume we have an "identity" mapping
- // In this case we can offset the original position
- m2rBestFit = Object.assign({}, m2rBestFit, {
- originalColumn: m2rBestFit.originalColumn + offset,
- generatedColumn: middleMapping.column
- });
- }
- }
- if(!m2rBestFit.name && middleMapping.name) {
- allowMiddleName =
- rightLine.slice(
- m2rBestFit.originalColumn,
- m2rBestFit.originalColumn + middleMapping.name.length
- ) === middleMapping.name;
- }
- }
- }
-
- // Construct a left to right node from the found middle to right mapping
- source = m2rBestFit.source;
- l2rOutput.push(
- new SourceNode(
- m2rBestFit.originalLine,
- m2rBestFit.originalColumn,
- source,
- chunk,
- allowMiddleName ? middleMapping.name : m2rBestFit.name
- )
- );
-
- // Set the source contents once
- if(!("$" + source in rightSourceContentsSet)) {
- rightSourceContentsSet["$" + source] = true;
- var sourceContent = sourceMapConsumer.sourceContentFor(source, true);
- if(sourceContent) {
- l2rResult.setSourceContent(source, sourceContent);
- }
- }
- return;
- }
- }
-
- if((removeGeneratedCodeForSourceFile && middleMapping.source === sourceFile) || !middleMapping.source) {
- // Construct a left to middle node with only generated code
- // Because user do not want mappings to middle sources
- // Or this chunk has no mapping
- l2rOutput.push(chunk);
- return;
- }
-
- // Construct a left to middle node
- source = middleMapping.source;
- l2rOutput.push(
- new SourceNode(
- middleMapping.line,
- middleMapping.column,
- source,
- chunk,
- middleMapping.name
- )
- );
- if("$" + source in middleSourceContents) {
- if(!("$" + source in rightSourceContentsSet)) {
- l2rResult.setSourceContent(source, middleSourceContents["$" + source]);
- delete middleSourceContents["$" + source];
- }
- }
- });
-
- // Put output into the resulting SourceNode
- l2rResult.add(l2rOutput);
- return l2rResult;
- };
-
- module.exports = applySourceMap;
|