1 | /*
|
---|
2 | MIT License http://www.opensource.org/licenses/mit-license.php
|
---|
3 | Author Tobias Koppers @sokra
|
---|
4 | */
|
---|
5 |
|
---|
6 | "use strict";
|
---|
7 |
|
---|
8 | const streamChunksOfSourceMap = require("./streamChunksOfSourceMap");
|
---|
9 | const splitIntoLines = require("./splitIntoLines");
|
---|
10 |
|
---|
11 | const streamChunksOfCombinedSourceMap = (
|
---|
12 | source,
|
---|
13 | sourceMap,
|
---|
14 | innerSourceName,
|
---|
15 | innerSource,
|
---|
16 | innerSourceMap,
|
---|
17 | removeInnerSource,
|
---|
18 | onChunk,
|
---|
19 | onSource,
|
---|
20 | onName,
|
---|
21 | finalSource,
|
---|
22 | columns
|
---|
23 | ) => {
|
---|
24 | let sourceMapping = new Map();
|
---|
25 | let nameMapping = new Map();
|
---|
26 | const sourceIndexMapping = [];
|
---|
27 | const nameIndexMapping = [];
|
---|
28 | const nameIndexValueMapping = [];
|
---|
29 | let innerSourceIndex = -2;
|
---|
30 | const innerSourceIndexMapping = [];
|
---|
31 | const innerSourceIndexValueMapping = [];
|
---|
32 | const innerSourceContents = [];
|
---|
33 | const innerSourceContentLines = [];
|
---|
34 | const innerNameIndexMapping = [];
|
---|
35 | const innerNameIndexValueMapping = [];
|
---|
36 | const innerSourceMapLineData = [];
|
---|
37 | const findInnerMapping = (line, column) => {
|
---|
38 | if (line > innerSourceMapLineData.length) return -1;
|
---|
39 | const { mappingsData } = innerSourceMapLineData[line - 1];
|
---|
40 | let l = 0;
|
---|
41 | let r = mappingsData.length / 5;
|
---|
42 | while (l < r) {
|
---|
43 | let m = (l + r) >> 1;
|
---|
44 | if (mappingsData[m * 5] <= column) {
|
---|
45 | l = m + 1;
|
---|
46 | } else {
|
---|
47 | r = m;
|
---|
48 | }
|
---|
49 | }
|
---|
50 | if (l === 0) return -1;
|
---|
51 | return l - 1;
|
---|
52 | };
|
---|
53 | return streamChunksOfSourceMap(
|
---|
54 | source,
|
---|
55 | sourceMap,
|
---|
56 | (
|
---|
57 | chunk,
|
---|
58 | generatedLine,
|
---|
59 | generatedColumn,
|
---|
60 | sourceIndex,
|
---|
61 | originalLine,
|
---|
62 | originalColumn,
|
---|
63 | nameIndex
|
---|
64 | ) => {
|
---|
65 | // Check if this is a mapping to the inner source
|
---|
66 | if (sourceIndex === innerSourceIndex) {
|
---|
67 | // Check if there is a mapping in the inner source
|
---|
68 | const idx = findInnerMapping(originalLine, originalColumn);
|
---|
69 | if (idx !== -1) {
|
---|
70 | const { chunks, mappingsData } = innerSourceMapLineData[
|
---|
71 | originalLine - 1
|
---|
72 | ];
|
---|
73 | const mi = idx * 5;
|
---|
74 | const innerSourceIndex = mappingsData[mi + 1];
|
---|
75 | const innerOriginalLine = mappingsData[mi + 2];
|
---|
76 | let innerOriginalColumn = mappingsData[mi + 3];
|
---|
77 | let innerNameIndex = mappingsData[mi + 4];
|
---|
78 | if (innerSourceIndex >= 0) {
|
---|
79 | // Check for an identity mapping
|
---|
80 | // where we are allowed to adjust the original column
|
---|
81 | const innerChunk = chunks[idx];
|
---|
82 | const innerGeneratedColumn = mappingsData[mi];
|
---|
83 | const locationInChunk = originalColumn - innerGeneratedColumn;
|
---|
84 | if (locationInChunk > 0) {
|
---|
85 | let originalSourceLines =
|
---|
86 | innerSourceIndex < innerSourceContentLines.length
|
---|
87 | ? innerSourceContentLines[innerSourceIndex]
|
---|
88 | : null;
|
---|
89 | if (originalSourceLines === undefined) {
|
---|
90 | const originalSource = innerSourceContents[innerSourceIndex];
|
---|
91 | originalSourceLines = originalSource
|
---|
92 | ? splitIntoLines(originalSource)
|
---|
93 | : null;
|
---|
94 | innerSourceContentLines[innerSourceIndex] = originalSourceLines;
|
---|
95 | }
|
---|
96 | if (originalSourceLines !== null) {
|
---|
97 | const originalChunk =
|
---|
98 | innerOriginalLine <= originalSourceLines.length
|
---|
99 | ? originalSourceLines[innerOriginalLine - 1].slice(
|
---|
100 | innerOriginalColumn,
|
---|
101 | innerOriginalColumn + locationInChunk
|
---|
102 | )
|
---|
103 | : "";
|
---|
104 | if (innerChunk.slice(0, locationInChunk) === originalChunk) {
|
---|
105 | innerOriginalColumn += locationInChunk;
|
---|
106 | innerNameIndex = -1;
|
---|
107 | }
|
---|
108 | }
|
---|
109 | }
|
---|
110 |
|
---|
111 | // We have a inner mapping to original source
|
---|
112 |
|
---|
113 | // emit source when needed and compute global source index
|
---|
114 | let sourceIndex =
|
---|
115 | innerSourceIndex < innerSourceIndexMapping.length
|
---|
116 | ? innerSourceIndexMapping[innerSourceIndex]
|
---|
117 | : -2;
|
---|
118 | if (sourceIndex === -2) {
|
---|
119 | const [source, sourceContent] =
|
---|
120 | innerSourceIndex < innerSourceIndexValueMapping.length
|
---|
121 | ? innerSourceIndexValueMapping[innerSourceIndex]
|
---|
122 | : [null, undefined];
|
---|
123 | let globalIndex = sourceMapping.get(source);
|
---|
124 | if (globalIndex === undefined) {
|
---|
125 | sourceMapping.set(source, (globalIndex = sourceMapping.size));
|
---|
126 | onSource(globalIndex, source, sourceContent);
|
---|
127 | }
|
---|
128 | sourceIndex = globalIndex;
|
---|
129 | innerSourceIndexMapping[innerSourceIndex] = sourceIndex;
|
---|
130 | }
|
---|
131 |
|
---|
132 | // emit name when needed and compute global name index
|
---|
133 | let finalNameIndex = -1;
|
---|
134 | if (innerNameIndex >= 0) {
|
---|
135 | // when we have a inner name
|
---|
136 | finalNameIndex =
|
---|
137 | innerNameIndex < innerNameIndexMapping.length
|
---|
138 | ? innerNameIndexMapping[innerNameIndex]
|
---|
139 | : -2;
|
---|
140 | if (finalNameIndex === -2) {
|
---|
141 | const name =
|
---|
142 | innerNameIndex < innerNameIndexValueMapping.length
|
---|
143 | ? innerNameIndexValueMapping[innerNameIndex]
|
---|
144 | : undefined;
|
---|
145 | if (name) {
|
---|
146 | let globalIndex = nameMapping.get(name);
|
---|
147 | if (globalIndex === undefined) {
|
---|
148 | nameMapping.set(name, (globalIndex = nameMapping.size));
|
---|
149 | onName(globalIndex, name);
|
---|
150 | }
|
---|
151 | finalNameIndex = globalIndex;
|
---|
152 | } else {
|
---|
153 | finalNameIndex = -1;
|
---|
154 | }
|
---|
155 | innerNameIndexMapping[innerNameIndex] = finalNameIndex;
|
---|
156 | }
|
---|
157 | } else if (nameIndex >= 0) {
|
---|
158 | // when we don't have an inner name,
|
---|
159 | // but we have an outer name
|
---|
160 | // it can be used when inner original code equals to the name
|
---|
161 | let originalSourceLines =
|
---|
162 | innerSourceContentLines[innerSourceIndex];
|
---|
163 | if (originalSourceLines === undefined) {
|
---|
164 | const originalSource = innerSourceContents[innerSourceIndex];
|
---|
165 | originalSourceLines = originalSource
|
---|
166 | ? splitIntoLines(originalSource)
|
---|
167 | : null;
|
---|
168 | innerSourceContentLines[innerSourceIndex] = originalSourceLines;
|
---|
169 | }
|
---|
170 | if (originalSourceLines !== null) {
|
---|
171 | const name = nameIndexValueMapping[nameIndex];
|
---|
172 | const originalName =
|
---|
173 | innerOriginalLine <= originalSourceLines.length
|
---|
174 | ? originalSourceLines[innerOriginalLine - 1].slice(
|
---|
175 | innerOriginalColumn,
|
---|
176 | innerOriginalColumn + name.length
|
---|
177 | )
|
---|
178 | : "";
|
---|
179 | if (name === originalName) {
|
---|
180 | finalNameIndex =
|
---|
181 | nameIndex < nameIndexMapping.length
|
---|
182 | ? nameIndexMapping[nameIndex]
|
---|
183 | : -2;
|
---|
184 | if (finalNameIndex === -2) {
|
---|
185 | const name = nameIndexValueMapping[nameIndex];
|
---|
186 | if (name) {
|
---|
187 | let globalIndex = nameMapping.get(name);
|
---|
188 | if (globalIndex === undefined) {
|
---|
189 | nameMapping.set(name, (globalIndex = nameMapping.size));
|
---|
190 | onName(globalIndex, name);
|
---|
191 | }
|
---|
192 | finalNameIndex = globalIndex;
|
---|
193 | } else {
|
---|
194 | finalNameIndex = -1;
|
---|
195 | }
|
---|
196 | nameIndexMapping[nameIndex] = finalNameIndex;
|
---|
197 | }
|
---|
198 | }
|
---|
199 | }
|
---|
200 | }
|
---|
201 | onChunk(
|
---|
202 | chunk,
|
---|
203 | generatedLine,
|
---|
204 | generatedColumn,
|
---|
205 | sourceIndex,
|
---|
206 | innerOriginalLine,
|
---|
207 | innerOriginalColumn,
|
---|
208 | finalNameIndex
|
---|
209 | );
|
---|
210 | return;
|
---|
211 | }
|
---|
212 | }
|
---|
213 |
|
---|
214 | // We have a mapping to the inner source, but no inner mapping
|
---|
215 | if (removeInnerSource) {
|
---|
216 | onChunk(chunk, generatedLine, generatedColumn, -1, -1, -1, -1);
|
---|
217 | return;
|
---|
218 | } else {
|
---|
219 | if (sourceIndexMapping[sourceIndex] === -2) {
|
---|
220 | let globalIndex = sourceMapping.get(innerSourceName);
|
---|
221 | if (globalIndex === undefined) {
|
---|
222 | sourceMapping.set(source, (globalIndex = sourceMapping.size));
|
---|
223 | onSource(globalIndex, innerSourceName, innerSource);
|
---|
224 | }
|
---|
225 | sourceIndexMapping[sourceIndex] = globalIndex;
|
---|
226 | }
|
---|
227 | }
|
---|
228 | }
|
---|
229 |
|
---|
230 | const finalSourceIndex =
|
---|
231 | sourceIndex < 0 || sourceIndex >= sourceIndexMapping.length
|
---|
232 | ? -1
|
---|
233 | : sourceIndexMapping[sourceIndex];
|
---|
234 | if (finalSourceIndex < 0) {
|
---|
235 | // no source, so we make it a generated chunk
|
---|
236 | onChunk(chunk, generatedLine, generatedColumn, -1, -1, -1, -1);
|
---|
237 | } else {
|
---|
238 | // Pass through the chunk with mapping
|
---|
239 | let finalNameIndex = -1;
|
---|
240 | if (nameIndex >= 0 && nameIndex < nameIndexMapping.length) {
|
---|
241 | finalNameIndex = nameIndexMapping[nameIndex];
|
---|
242 | if (finalNameIndex === -2) {
|
---|
243 | const name = nameIndexValueMapping[nameIndex];
|
---|
244 | let globalIndex = nameMapping.get(name);
|
---|
245 | if (globalIndex === undefined) {
|
---|
246 | nameMapping.set(name, (globalIndex = nameMapping.size));
|
---|
247 | onName(globalIndex, name);
|
---|
248 | }
|
---|
249 | finalNameIndex = globalIndex;
|
---|
250 | nameIndexMapping[nameIndex] = finalNameIndex;
|
---|
251 | }
|
---|
252 | }
|
---|
253 | onChunk(
|
---|
254 | chunk,
|
---|
255 | generatedLine,
|
---|
256 | generatedColumn,
|
---|
257 | finalSourceIndex,
|
---|
258 | originalLine,
|
---|
259 | originalColumn,
|
---|
260 | finalNameIndex
|
---|
261 | );
|
---|
262 | }
|
---|
263 | },
|
---|
264 | (i, source, sourceContent) => {
|
---|
265 | if (source === innerSourceName) {
|
---|
266 | innerSourceIndex = i;
|
---|
267 | if (innerSource !== undefined) sourceContent = innerSource;
|
---|
268 | else innerSource = sourceContent;
|
---|
269 | sourceIndexMapping[i] = -2;
|
---|
270 | streamChunksOfSourceMap(
|
---|
271 | sourceContent,
|
---|
272 | innerSourceMap,
|
---|
273 | (
|
---|
274 | chunk,
|
---|
275 | generatedLine,
|
---|
276 | generatedColumn,
|
---|
277 | sourceIndex,
|
---|
278 | originalLine,
|
---|
279 | originalColumn,
|
---|
280 | nameIndex
|
---|
281 | ) => {
|
---|
282 | while (innerSourceMapLineData.length < generatedLine) {
|
---|
283 | innerSourceMapLineData.push({
|
---|
284 | mappingsData: [],
|
---|
285 | chunks: []
|
---|
286 | });
|
---|
287 | }
|
---|
288 | const data = innerSourceMapLineData[generatedLine - 1];
|
---|
289 | data.mappingsData.push(
|
---|
290 | generatedColumn,
|
---|
291 | sourceIndex,
|
---|
292 | originalLine,
|
---|
293 | originalColumn,
|
---|
294 | nameIndex
|
---|
295 | );
|
---|
296 | data.chunks.push(chunk);
|
---|
297 | },
|
---|
298 | (i, source, sourceContent) => {
|
---|
299 | innerSourceContents[i] = sourceContent;
|
---|
300 | innerSourceContentLines[i] = undefined;
|
---|
301 | innerSourceIndexMapping[i] = -2;
|
---|
302 | innerSourceIndexValueMapping[i] = [source, sourceContent];
|
---|
303 | },
|
---|
304 | (i, name) => {
|
---|
305 | innerNameIndexMapping[i] = -2;
|
---|
306 | innerNameIndexValueMapping[i] = name;
|
---|
307 | },
|
---|
308 | false,
|
---|
309 | columns
|
---|
310 | );
|
---|
311 | } else {
|
---|
312 | let globalIndex = sourceMapping.get(source);
|
---|
313 | if (globalIndex === undefined) {
|
---|
314 | sourceMapping.set(source, (globalIndex = sourceMapping.size));
|
---|
315 | onSource(globalIndex, source, sourceContent);
|
---|
316 | }
|
---|
317 | sourceIndexMapping[i] = globalIndex;
|
---|
318 | }
|
---|
319 | },
|
---|
320 | (i, name) => {
|
---|
321 | nameIndexMapping[i] = -2;
|
---|
322 | nameIndexValueMapping[i] = name;
|
---|
323 | },
|
---|
324 | finalSource,
|
---|
325 | columns
|
---|
326 | );
|
---|
327 | };
|
---|
328 |
|
---|
329 | module.exports = streamChunksOfCombinedSourceMap;
|
---|