UNPKG

8.1 kBJavaScriptView Raw
1'use strict';
2
3function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
4
5var _require = require('source-map');
6
7const SourceMapConsumer = _require.SourceMapConsumer,
8 SourceMapGenerator = _require.SourceMapGenerator;
9
10const lineCounter = require('./utils/lineCounter');
11
12class SourceMap {
13 constructor(mappings, sources) {
14 this.mappings = this.purifyMappings(mappings);
15 this.sources = sources || {};
16 this.lineCount = null;
17 }
18
19 purifyMappings(mappings) {
20 if (Array.isArray(mappings)) {
21 return mappings.filter(mapping => {
22 return mapping && mapping.source && mapping.original && typeof mapping.original.line === 'number' && mapping.original.line > 0 && typeof mapping.original.column === 'number' && mapping.generated && typeof mapping.generated.line === 'number' && mapping.generated.line > 0 && typeof mapping.generated.column === 'number';
23 });
24 }
25
26 return [];
27 }
28
29 getConsumer(map) {
30 return _asyncToGenerator(function* () {
31 if (map instanceof SourceMapConsumer) {
32 return map;
33 }
34 map = typeof map === 'string' ? JSON.parse(map) : map;
35 return yield new SourceMapConsumer(map);
36 })();
37 }
38
39 addMap(map, lineOffset = 0, columnOffset = 0) {
40 var _this = this;
41
42 return _asyncToGenerator(function* () {
43 if (!(map instanceof SourceMap) && map.version) {
44 let consumer = yield _this.getConsumer(map);
45
46 consumer.eachMapping(function (mapping) {
47 _this.addConsumerMapping(mapping, lineOffset, columnOffset);
48 if (!_this.sources[mapping.source]) {
49 _this.sources[mapping.source] = consumer.sourceContentFor(mapping.source, true);
50 }
51 });
52
53 if (consumer.destroy) {
54 // Only needs to happen in source-map 0.7
55 consumer.destroy();
56 }
57 } else {
58 if (!map.eachMapping) {
59 map = new SourceMap(map.mappings, map.sources);
60 }
61
62 if (lineOffset === 0 && columnOffset === 0) {
63 _this.mappings = _this.mappings.concat(map.mappings);
64 } else {
65 map.eachMapping(function (mapping) {
66 _this.addMapping(mapping, lineOffset, columnOffset);
67 });
68 }
69
70 Object.keys(map.sources).forEach(function (sourceName) {
71 if (!_this.sources[sourceName]) {
72 _this.sources[sourceName] = map.sources[sourceName];
73 }
74 });
75 }
76
77 return _this;
78 })();
79 }
80
81 addMapping(mapping, lineOffset = 0, columnOffset = 0) {
82 mapping.generated = {
83 line: mapping.generated.line + lineOffset,
84 column: mapping.generated.column + columnOffset
85 };
86
87 this.mappings.push(mapping);
88 }
89
90 addConsumerMapping(mapping, lineOffset = 0, columnOffset = 0) {
91 if (!mapping.source || !mapping.originalLine || !mapping.originalColumn && mapping.originalColumn !== 0) {
92 return;
93 }
94
95 this.mappings.push({
96 source: mapping.source,
97 original: {
98 line: mapping.originalLine,
99 column: mapping.originalColumn
100 },
101 generated: {
102 line: mapping.generatedLine + lineOffset,
103 column: mapping.generatedColumn + columnOffset
104 },
105 name: mapping.name
106 });
107 }
108
109 eachMapping(callback) {
110 this.mappings.forEach(callback);
111 }
112
113 generateEmptyMap(sourceName, sourceContent) {
114 this.sources[sourceName] = sourceContent;
115
116 this.lineCount = lineCounter(sourceContent);
117 for (let line = 1; line < this.lineCount + 1; line++) {
118 this.addMapping({
119 source: sourceName,
120 original: {
121 line: line,
122 column: 0
123 },
124 generated: {
125 line: line,
126 column: 0
127 }
128 });
129 }
130
131 return this;
132 }
133
134 extendSourceMap(original, extension) {
135 var _this2 = this;
136
137 return _asyncToGenerator(function* () {
138 if (!(extension instanceof SourceMap)) {
139 extension = yield new SourceMap().addMap(extension);
140 }
141 if (!(original instanceof SourceMap)) {
142 original = yield _this2.getConsumer(original);
143 }
144
145 extension.eachMapping(function (mapping) {
146 let originalMapping = original.originalPositionFor({
147 line: mapping.original.line,
148 column: mapping.original.column
149 });
150
151 if (!originalMapping.line) {
152 return false;
153 }
154
155 _this2.addMapping({
156 source: originalMapping.source,
157 name: originalMapping.name,
158 original: {
159 line: originalMapping.line,
160 column: originalMapping.column
161 },
162 generated: {
163 line: mapping.generated.line,
164 column: mapping.generated.column
165 }
166 });
167
168 if (!_this2.sources[originalMapping.source]) {
169 _this2.sources[originalMapping.source] = original.sourceContentFor(originalMapping.source, true);
170 }
171 });
172
173 if (original.destroy) {
174 // Only needs to happen in source-map 0.7
175 original.destroy();
176 }
177
178 return _this2;
179 })();
180 }
181
182 findClosest(line, column, key = 'original') {
183 if (line < 1) {
184 throw new Error('Line numbers must be >= 1');
185 }
186
187 if (column < 0) {
188 throw new Error('Column numbers must be >= 0');
189 }
190
191 if (this.mappings.length < 1) {
192 return undefined;
193 }
194
195 let startIndex = 0;
196 let stopIndex = this.mappings.length - 1;
197 let middleIndex = Math.floor((stopIndex + startIndex) / 2);
198
199 while (startIndex < stopIndex && this.mappings[middleIndex][key].line !== line) {
200 if (line < this.mappings[middleIndex][key].line) {
201 stopIndex = middleIndex - 1;
202 } else if (line > this.mappings[middleIndex][key].line) {
203 startIndex = middleIndex + 1;
204 }
205 middleIndex = Math.floor((stopIndex + startIndex) / 2);
206 }
207
208 let mapping = this.mappings[middleIndex];
209 if (!mapping || mapping[key].line !== line) {
210 return this.mappings.length - 1;
211 }
212
213 while (middleIndex >= 1 && this.mappings[middleIndex - 1][key].line === line) {
214 middleIndex--;
215 }
216
217 while (middleIndex < this.mappings.length - 1 && this.mappings[middleIndex + 1][key].line === line && column > this.mappings[middleIndex][key].column) {
218 middleIndex++;
219 }
220
221 return middleIndex;
222 }
223
224 originalPositionFor(generatedPosition) {
225 let index = this.findClosest(generatedPosition.line, generatedPosition.column, 'generated');
226 return {
227 source: this.mappings[index].source,
228 name: this.mappings[index].name,
229 line: this.mappings[index].original.line,
230 column: this.mappings[index].original.column
231 };
232 }
233
234 generatedPositionFor(originalPosition) {
235 let index = this.findClosest(originalPosition.line, originalPosition.column, 'original');
236 return {
237 source: this.mappings[index].source,
238 name: this.mappings[index].name,
239 line: this.mappings[index].generated.line,
240 column: this.mappings[index].generated.column
241 };
242 }
243
244 sourceContentFor(fileName) {
245 return this.sources[fileName];
246 }
247
248 offset(lineOffset = 0, columnOffset = 0) {
249 this.mappings.map(mapping => {
250 mapping.generated.line = mapping.generated.line + lineOffset;
251 mapping.generated.column = mapping.generated.column + columnOffset;
252 return mapping;
253 });
254
255 if (this.lineCount != null) {
256 this.lineCount += lineOffset;
257 }
258 }
259
260 stringify(file) {
261 let generator = new SourceMapGenerator({
262 file: file
263 });
264
265 this.eachMapping(mapping => generator.addMapping(mapping));
266 Object.keys(this.sources).forEach(sourceName => generator.setSourceContent(sourceName, this.sources[sourceName]));
267
268 return generator.toString();
269 }
270}
271
272module.exports = SourceMap;
\No newline at end of file