.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / source-map / lib / source-map-generator.js
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
8 var base64VLQ = require('./base64-vlq');
9 var util = require('./util');
10 var ArraySet = require('./array-set').ArraySet;
11 var 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  */
21 function 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
34 SourceMapGenerator.prototype._version = 3;
35
36 /**
37  * Creates a new SourceMapGenerator based on a SourceMapConsumer
38  *
39  * @param aSourceMapConsumer The SourceMap.
40  */
41 SourceMapGenerator.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  */
102 SourceMapGenerator.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  */
140 SourceMapGenerator.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  */
180 SourceMapGenerator.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  */
268 SourceMapGenerator.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  */
311 SourceMapGenerator.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
377 SourceMapGenerator.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  */
396 SourceMapGenerator.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  */
420 SourceMapGenerator.prototype.toString =
421   function SourceMapGenerator_toString() {
422     return JSON.stringify(this.toJSON());
423   };
424
425 exports.SourceMapGenerator = SourceMapGenerator;