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;
|