applySourceMap.js
5.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
/*
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;