source: imaps-frontend/node_modules/source-map/lib/source-map-generator.js

main
Last change on this file was d565449, checked in by stefan toskovski <stefantoska84@…>, 4 weeks ago

Update repo after prototype presentation

  • Property mode set to 100644
File size: 14.0 KB
Line 
1/* -*- Mode: js; js-indent-level: 2; -*- */
2/*
3 * Copyright 2011 Mozilla Foundation and contributors
4 * Licensed under the New BSD license. See LICENSE or:
5 * http://opensource.org/licenses/BSD-3-Clause
6 */
7
8var base64VLQ = require('./base64-vlq');
9var util = require('./util');
10var ArraySet = require('./array-set').ArraySet;
11var MappingList = require('./mapping-list').MappingList;
12
13/**
14 * An instance of the SourceMapGenerator represents a source map which is
15 * being built incrementally. You may pass an object with the following
16 * properties:
17 *
18 * - file: The filename of the generated source.
19 * - sourceRoot: A root for all relative URLs in this source map.
20 */
21function SourceMapGenerator(aArgs) {
22 if (!aArgs) {
23 aArgs = {};
24 }
25 this._file = util.getArg(aArgs, 'file', null);
26 this._sourceRoot = util.getArg(aArgs, 'sourceRoot', null);
27 this._skipValidation = util.getArg(aArgs, 'skipValidation', false);
28 this._sources = new ArraySet();
29 this._names = new ArraySet();
30 this._mappings = new MappingList();
31 this._sourcesContents = null;
32}
33
34SourceMapGenerator.prototype._version = 3;
35
36/**
37 * Creates a new SourceMapGenerator based on a SourceMapConsumer
38 *
39 * @param aSourceMapConsumer The SourceMap.
40 */
41SourceMapGenerator.fromSourceMap =
42 function SourceMapGenerator_fromSourceMap(aSourceMapConsumer) {
43 var sourceRoot = aSourceMapConsumer.sourceRoot;
44 var generator = new SourceMapGenerator({
45 file: aSourceMapConsumer.file,
46 sourceRoot: sourceRoot
47 });
48 aSourceMapConsumer.eachMapping(function (mapping) {
49 var newMapping = {
50 generated: {
51 line: mapping.generatedLine,
52 column: mapping.generatedColumn
53 }
54 };
55
56 if (mapping.source != null) {
57 newMapping.source = mapping.source;
58 if (sourceRoot != null) {
59 newMapping.source = util.relative(sourceRoot, newMapping.source);
60 }
61
62 newMapping.original = {
63 line: mapping.originalLine,
64 column: mapping.originalColumn
65 };
66
67 if (mapping.name != null) {
68 newMapping.name = mapping.name;
69 }
70 }
71
72 generator.addMapping(newMapping);
73 });
74 aSourceMapConsumer.sources.forEach(function (sourceFile) {
75 var sourceRelative = sourceFile;
76 if (sourceRoot !== null) {
77 sourceRelative = util.relative(sourceRoot, sourceFile);
78 }
79
80 if (!generator._sources.has(sourceRelative)) {
81 generator._sources.add(sourceRelative);
82 }
83
84 var content = aSourceMapConsumer.sourceContentFor(sourceFile);
85 if (content != null) {
86 generator.setSourceContent(sourceFile, content);
87 }
88 });
89 return generator;
90 };
91
92/**
93 * Add a single mapping from original source line and column to the generated
94 * source's line and column for this source map being created. The mapping
95 * object should have the following properties:
96 *
97 * - generated: An object with the generated line and column positions.
98 * - original: An object with the original line and column positions.
99 * - source: The original source file (relative to the sourceRoot).
100 * - name: An optional original token name for this mapping.
101 */
102SourceMapGenerator.prototype.addMapping =
103 function SourceMapGenerator_addMapping(aArgs) {
104 var generated = util.getArg(aArgs, 'generated');
105 var original = util.getArg(aArgs, 'original', null);
106 var source = util.getArg(aArgs, 'source', null);
107 var name = util.getArg(aArgs, 'name', null);
108
109 if (!this._skipValidation) {
110 this._validateMapping(generated, original, source, name);
111 }
112
113 if (source != null) {
114 source = String(source);
115 if (!this._sources.has(source)) {
116 this._sources.add(source);
117 }
118 }
119
120 if (name != null) {
121 name = String(name);
122 if (!this._names.has(name)) {
123 this._names.add(name);
124 }
125 }
126
127 this._mappings.add({
128 generatedLine: generated.line,
129 generatedColumn: generated.column,
130 originalLine: original != null && original.line,
131 originalColumn: original != null && original.column,
132 source: source,
133 name: name
134 });
135 };
136
137/**
138 * Set the source content for a source file.
139 */
140SourceMapGenerator.prototype.setSourceContent =
141 function SourceMapGenerator_setSourceContent(aSourceFile, aSourceContent) {
142 var source = aSourceFile;
143 if (this._sourceRoot != null) {
144 source = util.relative(this._sourceRoot, source);
145 }
146
147 if (aSourceContent != null) {
148 // Add the source content to the _sourcesContents map.
149 // Create a new _sourcesContents map if the property is null.
150 if (!this._sourcesContents) {
151 this._sourcesContents = Object.create(null);
152 }
153 this._sourcesContents[util.toSetString(source)] = aSourceContent;
154 } else if (this._sourcesContents) {
155 // Remove the source file from the _sourcesContents map.
156 // If the _sourcesContents map is empty, set the property to null.
157 delete this._sourcesContents[util.toSetString(source)];
158 if (Object.keys(this._sourcesContents).length === 0) {
159 this._sourcesContents = null;
160 }
161 }
162 };
163
164/**
165 * Applies the mappings of a sub-source-map for a specific source file to the
166 * source map being generated. Each mapping to the supplied source file is
167 * rewritten using the supplied source map. Note: The resolution for the
168 * resulting mappings is the minimium of this map and the supplied map.
169 *
170 * @param aSourceMapConsumer The source map to be applied.
171 * @param aSourceFile Optional. The filename of the source file.
172 * If omitted, SourceMapConsumer's file property will be used.
173 * @param aSourceMapPath Optional. The dirname of the path to the source map
174 * to be applied. If relative, it is relative to the SourceMapConsumer.
175 * This parameter is needed when the two source maps aren't in the same
176 * directory, and the source map to be applied contains relative source
177 * paths. If so, those relative source paths need to be rewritten
178 * relative to the SourceMapGenerator.
179 */
180SourceMapGenerator.prototype.applySourceMap =
181 function SourceMapGenerator_applySourceMap(aSourceMapConsumer, aSourceFile, aSourceMapPath) {
182 var sourceFile = aSourceFile;
183 // If aSourceFile is omitted, we will use the file property of the SourceMap
184 if (aSourceFile == null) {
185 if (aSourceMapConsumer.file == null) {
186 throw new Error(
187 'SourceMapGenerator.prototype.applySourceMap requires either an explicit source file, ' +
188 'or the source map\'s "file" property. Both were omitted.'
189 );
190 }
191 sourceFile = aSourceMapConsumer.file;
192 }
193 var sourceRoot = this._sourceRoot;
194 // Make "sourceFile" relative if an absolute Url is passed.
195 if (sourceRoot != null) {
196 sourceFile = util.relative(sourceRoot, sourceFile);
197 }
198 // Applying the SourceMap can add and remove items from the sources and
199 // the names array.
200 var newSources = new ArraySet();
201 var newNames = new ArraySet();
202
203 // Find mappings for the "sourceFile"
204 this._mappings.unsortedForEach(function (mapping) {
205 if (mapping.source === sourceFile && mapping.originalLine != null) {
206 // Check if it can be mapped by the source map, then update the mapping.
207 var original = aSourceMapConsumer.originalPositionFor({
208 line: mapping.originalLine,
209 column: mapping.originalColumn
210 });
211 if (original.source != null) {
212 // Copy mapping
213 mapping.source = original.source;
214 if (aSourceMapPath != null) {
215 mapping.source = util.join(aSourceMapPath, mapping.source)
216 }
217 if (sourceRoot != null) {
218 mapping.source = util.relative(sourceRoot, mapping.source);
219 }
220 mapping.originalLine = original.line;
221 mapping.originalColumn = original.column;
222 if (original.name != null) {
223 mapping.name = original.name;
224 }
225 }
226 }
227
228 var source = mapping.source;
229 if (source != null && !newSources.has(source)) {
230 newSources.add(source);
231 }
232
233 var name = mapping.name;
234 if (name != null && !newNames.has(name)) {
235 newNames.add(name);
236 }
237
238 }, this);
239 this._sources = newSources;
240 this._names = newNames;
241
242 // Copy sourcesContents of applied map.
243 aSourceMapConsumer.sources.forEach(function (sourceFile) {
244 var content = aSourceMapConsumer.sourceContentFor(sourceFile);
245 if (content != null) {
246 if (aSourceMapPath != null) {
247 sourceFile = util.join(aSourceMapPath, sourceFile);
248 }
249 if (sourceRoot != null) {
250 sourceFile = util.relative(sourceRoot, sourceFile);
251 }
252 this.setSourceContent(sourceFile, content);
253 }
254 }, this);
255 };
256
257/**
258 * A mapping can have one of the three levels of data:
259 *
260 * 1. Just the generated position.
261 * 2. The Generated position, original position, and original source.
262 * 3. Generated and original position, original source, as well as a name
263 * token.
264 *
265 * To maintain consistency, we validate that any new mapping being added falls
266 * in to one of these categories.
267 */
268SourceMapGenerator.prototype._validateMapping =
269 function SourceMapGenerator_validateMapping(aGenerated, aOriginal, aSource,
270 aName) {
271 // When aOriginal is truthy but has empty values for .line and .column,
272 // it is most likely a programmer error. In this case we throw a very
273 // specific error message to try to guide them the right way.
274 // For example: https://github.com/Polymer/polymer-bundler/pull/519
275 if (aOriginal && typeof aOriginal.line !== 'number' && typeof aOriginal.column !== 'number') {
276 throw new Error(
277 'original.line and original.column are not numbers -- you probably meant to omit ' +
278 'the original mapping entirely and only map the generated position. If so, pass ' +
279 'null for the original mapping instead of an object with empty or null values.'
280 );
281 }
282
283 if (aGenerated && 'line' in aGenerated && 'column' in aGenerated
284 && aGenerated.line > 0 && aGenerated.column >= 0
285 && !aOriginal && !aSource && !aName) {
286 // Case 1.
287 return;
288 }
289 else if (aGenerated && 'line' in aGenerated && 'column' in aGenerated
290 && aOriginal && 'line' in aOriginal && 'column' in aOriginal
291 && aGenerated.line > 0 && aGenerated.column >= 0
292 && aOriginal.line > 0 && aOriginal.column >= 0
293 && aSource) {
294 // Cases 2 and 3.
295 return;
296 }
297 else {
298 throw new Error('Invalid mapping: ' + JSON.stringify({
299 generated: aGenerated,
300 source: aSource,
301 original: aOriginal,
302 name: aName
303 }));
304 }
305 };
306
307/**
308 * Serialize the accumulated mappings in to the stream of base 64 VLQs
309 * specified by the source map format.
310 */
311SourceMapGenerator.prototype._serializeMappings =
312 function SourceMapGenerator_serializeMappings() {
313 var previousGeneratedColumn = 0;
314 var previousGeneratedLine = 1;
315 var previousOriginalColumn = 0;
316 var previousOriginalLine = 0;
317 var previousName = 0;
318 var previousSource = 0;
319 var result = '';
320 var next;
321 var mapping;
322 var nameIdx;
323 var sourceIdx;
324
325 var mappings = this._mappings.toArray();
326 for (var i = 0, len = mappings.length; i < len; i++) {
327 mapping = mappings[i];
328 next = ''
329
330 if (mapping.generatedLine !== previousGeneratedLine) {
331 previousGeneratedColumn = 0;
332 while (mapping.generatedLine !== previousGeneratedLine) {
333 next += ';';
334 previousGeneratedLine++;
335 }
336 }
337 else {
338 if (i > 0) {
339 if (!util.compareByGeneratedPositionsInflated(mapping, mappings[i - 1])) {
340 continue;
341 }
342 next += ',';
343 }
344 }
345
346 next += base64VLQ.encode(mapping.generatedColumn
347 - previousGeneratedColumn);
348 previousGeneratedColumn = mapping.generatedColumn;
349
350 if (mapping.source != null) {
351 sourceIdx = this._sources.indexOf(mapping.source);
352 next += base64VLQ.encode(sourceIdx - previousSource);
353 previousSource = sourceIdx;
354
355 // lines are stored 0-based in SourceMap spec version 3
356 next += base64VLQ.encode(mapping.originalLine - 1
357 - previousOriginalLine);
358 previousOriginalLine = mapping.originalLine - 1;
359
360 next += base64VLQ.encode(mapping.originalColumn
361 - previousOriginalColumn);
362 previousOriginalColumn = mapping.originalColumn;
363
364 if (mapping.name != null) {
365 nameIdx = this._names.indexOf(mapping.name);
366 next += base64VLQ.encode(nameIdx - previousName);
367 previousName = nameIdx;
368 }
369 }
370
371 result += next;
372 }
373
374 return result;
375 };
376
377SourceMapGenerator.prototype._generateSourcesContent =
378 function SourceMapGenerator_generateSourcesContent(aSources, aSourceRoot) {
379 return aSources.map(function (source) {
380 if (!this._sourcesContents) {
381 return null;
382 }
383 if (aSourceRoot != null) {
384 source = util.relative(aSourceRoot, source);
385 }
386 var key = util.toSetString(source);
387 return Object.prototype.hasOwnProperty.call(this._sourcesContents, key)
388 ? this._sourcesContents[key]
389 : null;
390 }, this);
391 };
392
393/**
394 * Externalize the source map.
395 */
396SourceMapGenerator.prototype.toJSON =
397 function SourceMapGenerator_toJSON() {
398 var map = {
399 version: this._version,
400 sources: this._sources.toArray(),
401 names: this._names.toArray(),
402 mappings: this._serializeMappings()
403 };
404 if (this._file != null) {
405 map.file = this._file;
406 }
407 if (this._sourceRoot != null) {
408 map.sourceRoot = this._sourceRoot;
409 }
410 if (this._sourcesContents) {
411 map.sourcesContent = this._generateSourcesContent(map.sources, map.sourceRoot);
412 }
413
414 return map;
415 };
416
417/**
418 * Render the source map being generated to a string.
419 */
420SourceMapGenerator.prototype.toString =
421 function SourceMapGenerator_toString() {
422 return JSON.stringify(this.toJSON());
423 };
424
425exports.SourceMapGenerator = SourceMapGenerator;
Note: See TracBrowser for help on using the repository browser.