1 | /*
|
---|
2 | MIT License http://www.opensource.org/licenses/mit-license.php
|
---|
3 | Author Tobias Koppers @sokra
|
---|
4 | */
|
---|
5 |
|
---|
6 | "use strict";
|
---|
7 |
|
---|
8 | var SourceNode = require("source-map").SourceNode;
|
---|
9 | var SourceMapConsumer = require("source-map").SourceMapConsumer;
|
---|
10 |
|
---|
11 | var applySourceMap = function(
|
---|
12 | sourceNode,
|
---|
13 | sourceMapConsumer,
|
---|
14 | sourceFile,
|
---|
15 | removeGeneratedCodeForSourceFile
|
---|
16 | ) {
|
---|
17 | // The following notations are used to name stuff:
|
---|
18 | // Left <------------> Middle <-------------------> Right
|
---|
19 | // Input arguments:
|
---|
20 | // sourceNode - Code mapping from Left to Middle
|
---|
21 | // sourceFile - Name of a Middle file
|
---|
22 | // sourceMapConsumer - Code mapping from Middle to Right
|
---|
23 | // Variables:
|
---|
24 | // l2m m2r
|
---|
25 | // Left <-----------------------------------------> Right
|
---|
26 | // Variables:
|
---|
27 | // l2r
|
---|
28 |
|
---|
29 | var l2rResult = new SourceNode();
|
---|
30 | var l2rOutput = [];
|
---|
31 |
|
---|
32 | var middleSourceContents = {};
|
---|
33 |
|
---|
34 | var m2rMappingsByLine = {};
|
---|
35 |
|
---|
36 | var rightSourceContentsSet = {};
|
---|
37 | var rightSourceContentsLines = {};
|
---|
38 |
|
---|
39 | // Store all mappings by generated line
|
---|
40 | sourceMapConsumer.eachMapping(
|
---|
41 | function(mapping) {
|
---|
42 | (m2rMappingsByLine[mapping.generatedLine] =
|
---|
43 | m2rMappingsByLine[mapping.generatedLine] || []).push(mapping);
|
---|
44 | },
|
---|
45 | null,
|
---|
46 | SourceMapConsumer.GENERATED_ORDER
|
---|
47 | );
|
---|
48 |
|
---|
49 | // Store all source contents
|
---|
50 | sourceNode.walkSourceContents(function(source, content) {
|
---|
51 | middleSourceContents["$" + source] = content;
|
---|
52 | });
|
---|
53 |
|
---|
54 | var middleSource = middleSourceContents["$" + sourceFile];
|
---|
55 | var middleSourceLines = middleSource ? middleSource.split("\n") : undefined;
|
---|
56 |
|
---|
57 | // Walk all left to middle mappings
|
---|
58 | sourceNode.walk(function(chunk, middleMapping) {
|
---|
59 | var source;
|
---|
60 |
|
---|
61 | // Find a mapping from middle to right
|
---|
62 | if(
|
---|
63 | middleMapping.source === sourceFile &&
|
---|
64 | middleMapping.line &&
|
---|
65 | m2rMappingsByLine[middleMapping.line]
|
---|
66 | ) {
|
---|
67 | var m2rBestFit;
|
---|
68 | var m2rMappings = m2rMappingsByLine[middleMapping.line];
|
---|
69 | // Note: if this becomes a performance problem, use binary search
|
---|
70 | for(var i = 0; i < m2rMappings.length; i++) {
|
---|
71 | if(m2rMappings[i].generatedColumn <= middleMapping.column) {
|
---|
72 | m2rBestFit = m2rMappings[i];
|
---|
73 | }
|
---|
74 | }
|
---|
75 | if(m2rBestFit) {
|
---|
76 | var allowMiddleName = false;
|
---|
77 | var middleLine;
|
---|
78 | var rightSourceContent;
|
---|
79 | var rightSourceContentLines;
|
---|
80 | var rightSource = m2rBestFit.source;
|
---|
81 | // Check if we have middle and right source for this mapping
|
---|
82 | // Then we could have an "identify" mapping
|
---|
83 | if(
|
---|
84 | middleSourceLines &&
|
---|
85 | rightSource &&
|
---|
86 | (middleLine = middleSourceLines[m2rBestFit.generatedLine - 1]) &&
|
---|
87 | ((rightSourceContentLines = rightSourceContentsLines[rightSource]) ||
|
---|
88 | (rightSourceContent = sourceMapConsumer.sourceContentFor(
|
---|
89 | rightSource,
|
---|
90 | true
|
---|
91 | )))
|
---|
92 | ) {
|
---|
93 | if(!rightSourceContentLines) {
|
---|
94 | rightSourceContentLines = rightSourceContentsLines[
|
---|
95 | rightSource
|
---|
96 | ] = rightSourceContent.split("\n");
|
---|
97 | }
|
---|
98 | var rightLine = rightSourceContentLines[m2rBestFit.originalLine - 1];
|
---|
99 | if(rightLine) {
|
---|
100 | var offset = middleMapping.column - m2rBestFit.generatedColumn;
|
---|
101 | if(offset > 0) {
|
---|
102 | var middlePart = middleLine.slice(
|
---|
103 | m2rBestFit.generatedColumn,
|
---|
104 | middleMapping.column
|
---|
105 | );
|
---|
106 | var rightPart = rightLine.slice(
|
---|
107 | m2rBestFit.originalColumn,
|
---|
108 | m2rBestFit.originalColumn + offset
|
---|
109 | );
|
---|
110 | if(middlePart === rightPart) {
|
---|
111 | // When original and generated code is equal we assume we have an "identity" mapping
|
---|
112 | // In this case we can offset the original position
|
---|
113 | m2rBestFit = Object.assign({}, m2rBestFit, {
|
---|
114 | originalColumn: m2rBestFit.originalColumn + offset,
|
---|
115 | generatedColumn: middleMapping.column
|
---|
116 | });
|
---|
117 | }
|
---|
118 | }
|
---|
119 | if(!m2rBestFit.name && middleMapping.name) {
|
---|
120 | allowMiddleName =
|
---|
121 | rightLine.slice(
|
---|
122 | m2rBestFit.originalColumn,
|
---|
123 | m2rBestFit.originalColumn + middleMapping.name.length
|
---|
124 | ) === middleMapping.name;
|
---|
125 | }
|
---|
126 | }
|
---|
127 | }
|
---|
128 |
|
---|
129 | // Construct a left to right node from the found middle to right mapping
|
---|
130 | source = m2rBestFit.source;
|
---|
131 | l2rOutput.push(
|
---|
132 | new SourceNode(
|
---|
133 | m2rBestFit.originalLine,
|
---|
134 | m2rBestFit.originalColumn,
|
---|
135 | source,
|
---|
136 | chunk,
|
---|
137 | allowMiddleName ? middleMapping.name : m2rBestFit.name
|
---|
138 | )
|
---|
139 | );
|
---|
140 |
|
---|
141 | // Set the source contents once
|
---|
142 | if(!("$" + source in rightSourceContentsSet)) {
|
---|
143 | rightSourceContentsSet["$" + source] = true;
|
---|
144 | var sourceContent = sourceMapConsumer.sourceContentFor(source, true);
|
---|
145 | if(sourceContent) {
|
---|
146 | l2rResult.setSourceContent(source, sourceContent);
|
---|
147 | }
|
---|
148 | }
|
---|
149 | return;
|
---|
150 | }
|
---|
151 | }
|
---|
152 |
|
---|
153 | if((removeGeneratedCodeForSourceFile && middleMapping.source === sourceFile) || !middleMapping.source) {
|
---|
154 | // Construct a left to middle node with only generated code
|
---|
155 | // Because user do not want mappings to middle sources
|
---|
156 | // Or this chunk has no mapping
|
---|
157 | l2rOutput.push(chunk);
|
---|
158 | return;
|
---|
159 | }
|
---|
160 |
|
---|
161 | // Construct a left to middle node
|
---|
162 | source = middleMapping.source;
|
---|
163 | l2rOutput.push(
|
---|
164 | new SourceNode(
|
---|
165 | middleMapping.line,
|
---|
166 | middleMapping.column,
|
---|
167 | source,
|
---|
168 | chunk,
|
---|
169 | middleMapping.name
|
---|
170 | )
|
---|
171 | );
|
---|
172 | if("$" + source in middleSourceContents) {
|
---|
173 | if(!("$" + source in rightSourceContentsSet)) {
|
---|
174 | l2rResult.setSourceContent(source, middleSourceContents["$" + source]);
|
---|
175 | delete middleSourceContents["$" + source];
|
---|
176 | }
|
---|
177 | }
|
---|
178 | });
|
---|
179 |
|
---|
180 | // Put output into the resulting SourceNode
|
---|
181 | l2rResult.add(l2rOutput);
|
---|
182 | return l2rResult;
|
---|
183 | };
|
---|
184 |
|
---|
185 | module.exports = applySourceMap;
|
---|