.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / source-map / lib / source-map-consumer.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 util = require('./util');
9 var binarySearch = require('./binary-search');
10 var ArraySet = require('./array-set').ArraySet;
11 var base64VLQ = require('./base64-vlq');
12 var quickSort = require('./quick-sort').quickSort;
13
14 function SourceMapConsumer(aSourceMap, aSourceMapURL) {
15   var sourceMap = aSourceMap;
16   if (typeof aSourceMap === 'string') {
17     sourceMap = util.parseSourceMapInput(aSourceMap);
18   }
19
20   return sourceMap.sections != null
21     ? new IndexedSourceMapConsumer(sourceMap, aSourceMapURL)
22     : new BasicSourceMapConsumer(sourceMap, aSourceMapURL);
23 }
24
25 SourceMapConsumer.fromSourceMap = function(aSourceMap, aSourceMapURL) {
26   return BasicSourceMapConsumer.fromSourceMap(aSourceMap, aSourceMapURL);
27 }
28
29 /**
30  * The version of the source mapping spec that we are consuming.
31  */
32 SourceMapConsumer.prototype._version = 3;
33
34 // `__generatedMappings` and `__originalMappings` are arrays that hold the
35 // parsed mapping coordinates from the source map's "mappings" attribute. They
36 // are lazily instantiated, accessed via the `_generatedMappings` and
37 // `_originalMappings` getters respectively, and we only parse the mappings
38 // and create these arrays once queried for a source location. We jump through
39 // these hoops because there can be many thousands of mappings, and parsing
40 // them is expensive, so we only want to do it if we must.
41 //
42 // Each object in the arrays is of the form:
43 //
44 //     {
45 //       generatedLine: The line number in the generated code,
46 //       generatedColumn: The column number in the generated code,
47 //       source: The path to the original source file that generated this
48 //               chunk of code,
49 //       originalLine: The line number in the original source that
50 //                     corresponds to this chunk of generated code,
51 //       originalColumn: The column number in the original source that
52 //                       corresponds to this chunk of generated code,
53 //       name: The name of the original symbol which generated this chunk of
54 //             code.
55 //     }
56 //
57 // All properties except for `generatedLine` and `generatedColumn` can be
58 // `null`.
59 //
60 // `_generatedMappings` is ordered by the generated positions.
61 //
62 // `_originalMappings` is ordered by the original positions.
63
64 SourceMapConsumer.prototype.__generatedMappings = null;
65 Object.defineProperty(SourceMapConsumer.prototype, '_generatedMappings', {
66   configurable: true,
67   enumerable: true,
68   get: function () {
69     if (!this.__generatedMappings) {
70       this._parseMappings(this._mappings, this.sourceRoot);
71     }
72
73     return this.__generatedMappings;
74   }
75 });
76
77 SourceMapConsumer.prototype.__originalMappings = null;
78 Object.defineProperty(SourceMapConsumer.prototype, '_originalMappings', {
79   configurable: true,
80   enumerable: true,
81   get: function () {
82     if (!this.__originalMappings) {
83       this._parseMappings(this._mappings, this.sourceRoot);
84     }
85
86     return this.__originalMappings;
87   }
88 });
89
90 SourceMapConsumer.prototype._charIsMappingSeparator =
91   function SourceMapConsumer_charIsMappingSeparator(aStr, index) {
92     var c = aStr.charAt(index);
93     return c === ";" || c === ",";
94   };
95
96 /**
97  * Parse the mappings in a string in to a data structure which we can easily
98  * query (the ordered arrays in the `this.__generatedMappings` and
99  * `this.__originalMappings` properties).
100  */
101 SourceMapConsumer.prototype._parseMappings =
102   function SourceMapConsumer_parseMappings(aStr, aSourceRoot) {
103     throw new Error("Subclasses must implement _parseMappings");
104   };
105
106 SourceMapConsumer.GENERATED_ORDER = 1;
107 SourceMapConsumer.ORIGINAL_ORDER = 2;
108
109 SourceMapConsumer.GREATEST_LOWER_BOUND = 1;
110 SourceMapConsumer.LEAST_UPPER_BOUND = 2;
111
112 /**
113  * Iterate over each mapping between an original source/line/column and a
114  * generated line/column in this source map.
115  *
116  * @param Function aCallback
117  *        The function that is called with each mapping.
118  * @param Object aContext
119  *        Optional. If specified, this object will be the value of `this` every
120  *        time that `aCallback` is called.
121  * @param aOrder
122  *        Either `SourceMapConsumer.GENERATED_ORDER` or
123  *        `SourceMapConsumer.ORIGINAL_ORDER`. Specifies whether you want to
124  *        iterate over the mappings sorted by the generated file's line/column
125  *        order or the original's source/line/column order, respectively. Defaults to
126  *        `SourceMapConsumer.GENERATED_ORDER`.
127  */
128 SourceMapConsumer.prototype.eachMapping =
129   function SourceMapConsumer_eachMapping(aCallback, aContext, aOrder) {
130     var context = aContext || null;
131     var order = aOrder || SourceMapConsumer.GENERATED_ORDER;
132
133     var mappings;
134     switch (order) {
135     case SourceMapConsumer.GENERATED_ORDER:
136       mappings = this._generatedMappings;
137       break;
138     case SourceMapConsumer.ORIGINAL_ORDER:
139       mappings = this._originalMappings;
140       break;
141     default:
142       throw new Error("Unknown order of iteration.");
143     }
144
145     var sourceRoot = this.sourceRoot;
146     mappings.map(function (mapping) {
147       var source = mapping.source === null ? null : this._sources.at(mapping.source);
148       source = util.computeSourceURL(sourceRoot, source, this._sourceMapURL);
149       return {
150         source: source,
151         generatedLine: mapping.generatedLine,
152         generatedColumn: mapping.generatedColumn,
153         originalLine: mapping.originalLine,
154         originalColumn: mapping.originalColumn,
155         name: mapping.name === null ? null : this._names.at(mapping.name)
156       };
157     }, this).forEach(aCallback, context);
158   };
159
160 /**
161  * Returns all generated line and column information for the original source,
162  * line, and column provided. If no column is provided, returns all mappings
163  * corresponding to a either the line we are searching for or the next
164  * closest line that has any mappings. Otherwise, returns all mappings
165  * corresponding to the given line and either the column we are searching for
166  * or the next closest column that has any offsets.
167  *
168  * The only argument is an object with the following properties:
169  *
170  *   - source: The filename of the original source.
171  *   - line: The line number in the original source.  The line number is 1-based.
172  *   - column: Optional. the column number in the original source.
173  *    The column number is 0-based.
174  *
175  * and an array of objects is returned, each with the following properties:
176  *
177  *   - line: The line number in the generated source, or null.  The
178  *    line number is 1-based.
179  *   - column: The column number in the generated source, or null.
180  *    The column number is 0-based.
181  */
182 SourceMapConsumer.prototype.allGeneratedPositionsFor =
183   function SourceMapConsumer_allGeneratedPositionsFor(aArgs) {
184     var line = util.getArg(aArgs, 'line');
185
186     // When there is no exact match, BasicSourceMapConsumer.prototype._findMapping
187     // returns the index of the closest mapping less than the needle. By
188     // setting needle.originalColumn to 0, we thus find the last mapping for
189     // the given line, provided such a mapping exists.
190     var needle = {
191       source: util.getArg(aArgs, 'source'),
192       originalLine: line,
193       originalColumn: util.getArg(aArgs, 'column', 0)
194     };
195
196     needle.source = this._findSourceIndex(needle.source);
197     if (needle.source < 0) {
198       return [];
199     }
200
201     var mappings = [];
202
203     var index = this._findMapping(needle,
204                                   this._originalMappings,
205                                   "originalLine",
206                                   "originalColumn",
207                                   util.compareByOriginalPositions,
208                                   binarySearch.LEAST_UPPER_BOUND);
209     if (index >= 0) {
210       var mapping = this._originalMappings[index];
211
212       if (aArgs.column === undefined) {
213         var originalLine = mapping.originalLine;
214
215         // Iterate until either we run out of mappings, or we run into
216         // a mapping for a different line than the one we found. Since
217         // mappings are sorted, this is guaranteed to find all mappings for
218         // the line we found.
219         while (mapping && mapping.originalLine === originalLine) {
220           mappings.push({
221             line: util.getArg(mapping, 'generatedLine', null),
222             column: util.getArg(mapping, 'generatedColumn', null),
223             lastColumn: util.getArg(mapping, 'lastGeneratedColumn', null)
224           });
225
226           mapping = this._originalMappings[++index];
227         }
228       } else {
229         var originalColumn = mapping.originalColumn;
230
231         // Iterate until either we run out of mappings, or we run into
232         // a mapping for a different line than the one we were searching for.
233         // Since mappings are sorted, this is guaranteed to find all mappings for
234         // the line we are searching for.
235         while (mapping &&
236                mapping.originalLine === line &&
237                mapping.originalColumn == originalColumn) {
238           mappings.push({
239             line: util.getArg(mapping, 'generatedLine', null),
240             column: util.getArg(mapping, 'generatedColumn', null),
241             lastColumn: util.getArg(mapping, 'lastGeneratedColumn', null)
242           });
243
244           mapping = this._originalMappings[++index];
245         }
246       }
247     }
248
249     return mappings;
250   };
251
252 exports.SourceMapConsumer = SourceMapConsumer;
253
254 /**
255  * A BasicSourceMapConsumer instance represents a parsed source map which we can
256  * query for information about the original file positions by giving it a file
257  * position in the generated source.
258  *
259  * The first parameter is the raw source map (either as a JSON string, or
260  * already parsed to an object). According to the spec, source maps have the
261  * following attributes:
262  *
263  *   - version: Which version of the source map spec this map is following.
264  *   - sources: An array of URLs to the original source files.
265  *   - names: An array of identifiers which can be referrenced by individual mappings.
266  *   - sourceRoot: Optional. The URL root from which all sources are relative.
267  *   - sourcesContent: Optional. An array of contents of the original source files.
268  *   - mappings: A string of base64 VLQs which contain the actual mappings.
269  *   - file: Optional. The generated file this source map is associated with.
270  *
271  * Here is an example source map, taken from the source map spec[0]:
272  *
273  *     {
274  *       version : 3,
275  *       file: "out.js",
276  *       sourceRoot : "",
277  *       sources: ["foo.js", "bar.js"],
278  *       names: ["src", "maps", "are", "fun"],
279  *       mappings: "AA,AB;;ABCDE;"
280  *     }
281  *
282  * The second parameter, if given, is a string whose value is the URL
283  * at which the source map was found.  This URL is used to compute the
284  * sources array.
285  *
286  * [0]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit?pli=1#
287  */
288 function BasicSourceMapConsumer(aSourceMap, aSourceMapURL) {
289   var sourceMap = aSourceMap;
290   if (typeof aSourceMap === 'string') {
291     sourceMap = util.parseSourceMapInput(aSourceMap);
292   }
293
294   var version = util.getArg(sourceMap, 'version');
295   var sources = util.getArg(sourceMap, 'sources');
296   // Sass 3.3 leaves out the 'names' array, so we deviate from the spec (which
297   // requires the array) to play nice here.
298   var names = util.getArg(sourceMap, 'names', []);
299   var sourceRoot = util.getArg(sourceMap, 'sourceRoot', null);
300   var sourcesContent = util.getArg(sourceMap, 'sourcesContent', null);
301   var mappings = util.getArg(sourceMap, 'mappings');
302   var file = util.getArg(sourceMap, 'file', null);
303
304   // Once again, Sass deviates from the spec and supplies the version as a
305   // string rather than a number, so we use loose equality checking here.
306   if (version != this._version) {
307     throw new Error('Unsupported version: ' + version);
308   }
309
310   if (sourceRoot) {
311     sourceRoot = util.normalize(sourceRoot);
312   }
313
314   sources = sources
315     .map(String)
316     // Some source maps produce relative source paths like "./foo.js" instead of
317     // "foo.js".  Normalize these first so that future comparisons will succeed.
318     // See bugzil.la/1090768.
319     .map(util.normalize)
320     // Always ensure that absolute sources are internally stored relative to
321     // the source root, if the source root is absolute. Not doing this would
322     // be particularly problematic when the source root is a prefix of the
323     // source (valid, but why??). See github issue #199 and bugzil.la/1188982.
324     .map(function (source) {
325       return sourceRoot && util.isAbsolute(sourceRoot) && util.isAbsolute(source)
326         ? util.relative(sourceRoot, source)
327         : source;
328     });
329
330   // Pass `true` below to allow duplicate names and sources. While source maps
331   // are intended to be compressed and deduplicated, the TypeScript compiler
332   // sometimes generates source maps with duplicates in them. See Github issue
333   // #72 and bugzil.la/889492.
334   this._names = ArraySet.fromArray(names.map(String), true);
335   this._sources = ArraySet.fromArray(sources, true);
336
337   this._absoluteSources = this._sources.toArray().map(function (s) {
338     return util.computeSourceURL(sourceRoot, s, aSourceMapURL);
339   });
340
341   this.sourceRoot = sourceRoot;
342   this.sourcesContent = sourcesContent;
343   this._mappings = mappings;
344   this._sourceMapURL = aSourceMapURL;
345   this.file = file;
346 }
347
348 BasicSourceMapConsumer.prototype = Object.create(SourceMapConsumer.prototype);
349 BasicSourceMapConsumer.prototype.consumer = SourceMapConsumer;
350
351 /**
352  * Utility function to find the index of a source.  Returns -1 if not
353  * found.
354  */
355 BasicSourceMapConsumer.prototype._findSourceIndex = function(aSource) {
356   var relativeSource = aSource;
357   if (this.sourceRoot != null) {
358     relativeSource = util.relative(this.sourceRoot, relativeSource);
359   }
360
361   if (this._sources.has(relativeSource)) {
362     return this._sources.indexOf(relativeSource);
363   }
364
365   // Maybe aSource is an absolute URL as returned by |sources|.  In
366   // this case we can't simply undo the transform.
367   var i;
368   for (i = 0; i < this._absoluteSources.length; ++i) {
369     if (this._absoluteSources[i] == aSource) {
370       return i;
371     }
372   }
373
374   return -1;
375 };
376
377 /**
378  * Create a BasicSourceMapConsumer from a SourceMapGenerator.
379  *
380  * @param SourceMapGenerator aSourceMap
381  *        The source map that will be consumed.
382  * @param String aSourceMapURL
383  *        The URL at which the source map can be found (optional)
384  * @returns BasicSourceMapConsumer
385  */
386 BasicSourceMapConsumer.fromSourceMap =
387   function SourceMapConsumer_fromSourceMap(aSourceMap, aSourceMapURL) {
388     var smc = Object.create(BasicSourceMapConsumer.prototype);
389
390     var names = smc._names = ArraySet.fromArray(aSourceMap._names.toArray(), true);
391     var sources = smc._sources = ArraySet.fromArray(aSourceMap._sources.toArray(), true);
392     smc.sourceRoot = aSourceMap._sourceRoot;
393     smc.sourcesContent = aSourceMap._generateSourcesContent(smc._sources.toArray(),
394                                                             smc.sourceRoot);
395     smc.file = aSourceMap._file;
396     smc._sourceMapURL = aSourceMapURL;
397     smc._absoluteSources = smc._sources.toArray().map(function (s) {
398       return util.computeSourceURL(smc.sourceRoot, s, aSourceMapURL);
399     });
400
401     // Because we are modifying the entries (by converting string sources and
402     // names to indices into the sources and names ArraySets), we have to make
403     // a copy of the entry or else bad things happen. Shared mutable state
404     // strikes again! See github issue #191.
405
406     var generatedMappings = aSourceMap._mappings.toArray().slice();
407     var destGeneratedMappings = smc.__generatedMappings = [];
408     var destOriginalMappings = smc.__originalMappings = [];
409
410     for (var i = 0, length = generatedMappings.length; i < length; i++) {
411       var srcMapping = generatedMappings[i];
412       var destMapping = new Mapping;
413       destMapping.generatedLine = srcMapping.generatedLine;
414       destMapping.generatedColumn = srcMapping.generatedColumn;
415
416       if (srcMapping.source) {
417         destMapping.source = sources.indexOf(srcMapping.source);
418         destMapping.originalLine = srcMapping.originalLine;
419         destMapping.originalColumn = srcMapping.originalColumn;
420
421         if (srcMapping.name) {
422           destMapping.name = names.indexOf(srcMapping.name);
423         }
424
425         destOriginalMappings.push(destMapping);
426       }
427
428       destGeneratedMappings.push(destMapping);
429     }
430
431     quickSort(smc.__originalMappings, util.compareByOriginalPositions);
432
433     return smc;
434   };
435
436 /**
437  * The version of the source mapping spec that we are consuming.
438  */
439 BasicSourceMapConsumer.prototype._version = 3;
440
441 /**
442  * The list of original sources.
443  */
444 Object.defineProperty(BasicSourceMapConsumer.prototype, 'sources', {
445   get: function () {
446     return this._absoluteSources.slice();
447   }
448 });
449
450 /**
451  * Provide the JIT with a nice shape / hidden class.
452  */
453 function Mapping() {
454   this.generatedLine = 0;
455   this.generatedColumn = 0;
456   this.source = null;
457   this.originalLine = null;
458   this.originalColumn = null;
459   this.name = null;
460 }
461
462 /**
463  * Parse the mappings in a string in to a data structure which we can easily
464  * query (the ordered arrays in the `this.__generatedMappings` and
465  * `this.__originalMappings` properties).
466  */
467 BasicSourceMapConsumer.prototype._parseMappings =
468   function SourceMapConsumer_parseMappings(aStr, aSourceRoot) {
469     var generatedLine = 1;
470     var previousGeneratedColumn = 0;
471     var previousOriginalLine = 0;
472     var previousOriginalColumn = 0;
473     var previousSource = 0;
474     var previousName = 0;
475     var length = aStr.length;
476     var index = 0;
477     var cachedSegments = {};
478     var temp = {};
479     var originalMappings = [];
480     var generatedMappings = [];
481     var mapping, str, segment, end, value;
482
483     while (index < length) {
484       if (aStr.charAt(index) === ';') {
485         generatedLine++;
486         index++;
487         previousGeneratedColumn = 0;
488       }
489       else if (aStr.charAt(index) === ',') {
490         index++;
491       }
492       else {
493         mapping = new Mapping();
494         mapping.generatedLine = generatedLine;
495
496         // Because each offset is encoded relative to the previous one,
497         // many segments often have the same encoding. We can exploit this
498         // fact by caching the parsed variable length fields of each segment,
499         // allowing us to avoid a second parse if we encounter the same
500         // segment again.
501         for (end = index; end < length; end++) {
502           if (this._charIsMappingSeparator(aStr, end)) {
503             break;
504           }
505         }
506         str = aStr.slice(index, end);
507
508         segment = cachedSegments[str];
509         if (segment) {
510           index += str.length;
511         } else {
512           segment = [];
513           while (index < end) {
514             base64VLQ.decode(aStr, index, temp);
515             value = temp.value;
516             index = temp.rest;
517             segment.push(value);
518           }
519
520           if (segment.length === 2) {
521             throw new Error('Found a source, but no line and column');
522           }
523
524           if (segment.length === 3) {
525             throw new Error('Found a source and line, but no column');
526           }
527
528           cachedSegments[str] = segment;
529         }
530
531         // Generated column.
532         mapping.generatedColumn = previousGeneratedColumn + segment[0];
533         previousGeneratedColumn = mapping.generatedColumn;
534
535         if (segment.length > 1) {
536           // Original source.
537           mapping.source = previousSource + segment[1];
538           previousSource += segment[1];
539
540           // Original line.
541           mapping.originalLine = previousOriginalLine + segment[2];
542           previousOriginalLine = mapping.originalLine;
543           // Lines are stored 0-based
544           mapping.originalLine += 1;
545
546           // Original column.
547           mapping.originalColumn = previousOriginalColumn + segment[3];
548           previousOriginalColumn = mapping.originalColumn;
549
550           if (segment.length > 4) {
551             // Original name.
552             mapping.name = previousName + segment[4];
553             previousName += segment[4];
554           }
555         }
556
557         generatedMappings.push(mapping);
558         if (typeof mapping.originalLine === 'number') {
559           originalMappings.push(mapping);
560         }
561       }
562     }
563
564     quickSort(generatedMappings, util.compareByGeneratedPositionsDeflated);
565     this.__generatedMappings = generatedMappings;
566
567     quickSort(originalMappings, util.compareByOriginalPositions);
568     this.__originalMappings = originalMappings;
569   };
570
571 /**
572  * Find the mapping that best matches the hypothetical "needle" mapping that
573  * we are searching for in the given "haystack" of mappings.
574  */
575 BasicSourceMapConsumer.prototype._findMapping =
576   function SourceMapConsumer_findMapping(aNeedle, aMappings, aLineName,
577                                          aColumnName, aComparator, aBias) {
578     // To return the position we are searching for, we must first find the
579     // mapping for the given position and then return the opposite position it
580     // points to. Because the mappings are sorted, we can use binary search to
581     // find the best mapping.
582
583     if (aNeedle[aLineName] <= 0) {
584       throw new TypeError('Line must be greater than or equal to 1, got '
585                           + aNeedle[aLineName]);
586     }
587     if (aNeedle[aColumnName] < 0) {
588       throw new TypeError('Column must be greater than or equal to 0, got '
589                           + aNeedle[aColumnName]);
590     }
591
592     return binarySearch.search(aNeedle, aMappings, aComparator, aBias);
593   };
594
595 /**
596  * Compute the last column for each generated mapping. The last column is
597  * inclusive.
598  */
599 BasicSourceMapConsumer.prototype.computeColumnSpans =
600   function SourceMapConsumer_computeColumnSpans() {
601     for (var index = 0; index < this._generatedMappings.length; ++index) {
602       var mapping = this._generatedMappings[index];
603
604       // Mappings do not contain a field for the last generated columnt. We
605       // can come up with an optimistic estimate, however, by assuming that
606       // mappings are contiguous (i.e. given two consecutive mappings, the
607       // first mapping ends where the second one starts).
608       if (index + 1 < this._generatedMappings.length) {
609         var nextMapping = this._generatedMappings[index + 1];
610
611         if (mapping.generatedLine === nextMapping.generatedLine) {
612           mapping.lastGeneratedColumn = nextMapping.generatedColumn - 1;
613           continue;
614         }
615       }
616
617       // The last mapping for each line spans the entire line.
618       mapping.lastGeneratedColumn = Infinity;
619     }
620   };
621
622 /**
623  * Returns the original source, line, and column information for the generated
624  * source's line and column positions provided. The only argument is an object
625  * with the following properties:
626  *
627  *   - line: The line number in the generated source.  The line number
628  *     is 1-based.
629  *   - column: The column number in the generated source.  The column
630  *     number is 0-based.
631  *   - bias: Either 'SourceMapConsumer.GREATEST_LOWER_BOUND' or
632  *     'SourceMapConsumer.LEAST_UPPER_BOUND'. Specifies whether to return the
633  *     closest element that is smaller than or greater than the one we are
634  *     searching for, respectively, if the exact element cannot be found.
635  *     Defaults to 'SourceMapConsumer.GREATEST_LOWER_BOUND'.
636  *
637  * and an object is returned with the following properties:
638  *
639  *   - source: The original source file, or null.
640  *   - line: The line number in the original source, or null.  The
641  *     line number is 1-based.
642  *   - column: The column number in the original source, or null.  The
643  *     column number is 0-based.
644  *   - name: The original identifier, or null.
645  */
646 BasicSourceMapConsumer.prototype.originalPositionFor =
647   function SourceMapConsumer_originalPositionFor(aArgs) {
648     var needle = {
649       generatedLine: util.getArg(aArgs, 'line'),
650       generatedColumn: util.getArg(aArgs, 'column')
651     };
652
653     var index = this._findMapping(
654       needle,
655       this._generatedMappings,
656       "generatedLine",
657       "generatedColumn",
658       util.compareByGeneratedPositionsDeflated,
659       util.getArg(aArgs, 'bias', SourceMapConsumer.GREATEST_LOWER_BOUND)
660     );
661
662     if (index >= 0) {
663       var mapping = this._generatedMappings[index];
664
665       if (mapping.generatedLine === needle.generatedLine) {
666         var source = util.getArg(mapping, 'source', null);
667         if (source !== null) {
668           source = this._sources.at(source);
669           source = util.computeSourceURL(this.sourceRoot, source, this._sourceMapURL);
670         }
671         var name = util.getArg(mapping, 'name', null);
672         if (name !== null) {
673           name = this._names.at(name);
674         }
675         return {
676           source: source,
677           line: util.getArg(mapping, 'originalLine', null),
678           column: util.getArg(mapping, 'originalColumn', null),
679           name: name
680         };
681       }
682     }
683
684     return {
685       source: null,
686       line: null,
687       column: null,
688       name: null
689     };
690   };
691
692 /**
693  * Return true if we have the source content for every source in the source
694  * map, false otherwise.
695  */
696 BasicSourceMapConsumer.prototype.hasContentsOfAllSources =
697   function BasicSourceMapConsumer_hasContentsOfAllSources() {
698     if (!this.sourcesContent) {
699       return false;
700     }
701     return this.sourcesContent.length >= this._sources.size() &&
702       !this.sourcesContent.some(function (sc) { return sc == null; });
703   };
704
705 /**
706  * Returns the original source content. The only argument is the url of the
707  * original source file. Returns null if no original source content is
708  * available.
709  */
710 BasicSourceMapConsumer.prototype.sourceContentFor =
711   function SourceMapConsumer_sourceContentFor(aSource, nullOnMissing) {
712     if (!this.sourcesContent) {
713       return null;
714     }
715
716     var index = this._findSourceIndex(aSource);
717     if (index >= 0) {
718       return this.sourcesContent[index];
719     }
720
721     var relativeSource = aSource;
722     if (this.sourceRoot != null) {
723       relativeSource = util.relative(this.sourceRoot, relativeSource);
724     }
725
726     var url;
727     if (this.sourceRoot != null
728         && (url = util.urlParse(this.sourceRoot))) {
729       // XXX: file:// URIs and absolute paths lead to unexpected behavior for
730       // many users. We can help them out when they expect file:// URIs to
731       // behave like it would if they were running a local HTTP server. See
732       // https://bugzilla.mozilla.org/show_bug.cgi?id=885597.
733       var fileUriAbsPath = relativeSource.replace(/^file:\/\//, "");
734       if (url.scheme == "file"
735           && this._sources.has(fileUriAbsPath)) {
736         return this.sourcesContent[this._sources.indexOf(fileUriAbsPath)]
737       }
738
739       if ((!url.path || url.path == "/")
740           && this._sources.has("/" + relativeSource)) {
741         return this.sourcesContent[this._sources.indexOf("/" + relativeSource)];
742       }
743     }
744
745     // This function is used recursively from
746     // IndexedSourceMapConsumer.prototype.sourceContentFor. In that case, we
747     // don't want to throw if we can't find the source - we just want to
748     // return null, so we provide a flag to exit gracefully.
749     if (nullOnMissing) {
750       return null;
751     }
752     else {
753       throw new Error('"' + relativeSource + '" is not in the SourceMap.');
754     }
755   };
756
757 /**
758  * Returns the generated line and column information for the original source,
759  * line, and column positions provided. The only argument is an object with
760  * the following properties:
761  *
762  *   - source: The filename of the original source.
763  *   - line: The line number in the original source.  The line number
764  *     is 1-based.
765  *   - column: The column number in the original source.  The column
766  *     number is 0-based.
767  *   - bias: Either 'SourceMapConsumer.GREATEST_LOWER_BOUND' or
768  *     'SourceMapConsumer.LEAST_UPPER_BOUND'. Specifies whether to return the
769  *     closest element that is smaller than or greater than the one we are
770  *     searching for, respectively, if the exact element cannot be found.
771  *     Defaults to 'SourceMapConsumer.GREATEST_LOWER_BOUND'.
772  *
773  * and an object is returned with the following properties:
774  *
775  *   - line: The line number in the generated source, or null.  The
776  *     line number is 1-based.
777  *   - column: The column number in the generated source, or null.
778  *     The column number is 0-based.
779  */
780 BasicSourceMapConsumer.prototype.generatedPositionFor =
781   function SourceMapConsumer_generatedPositionFor(aArgs) {
782     var source = util.getArg(aArgs, 'source');
783     source = this._findSourceIndex(source);
784     if (source < 0) {
785       return {
786         line: null,
787         column: null,
788         lastColumn: null
789       };
790     }
791
792     var needle = {
793       source: source,
794       originalLine: util.getArg(aArgs, 'line'),
795       originalColumn: util.getArg(aArgs, 'column')
796     };
797
798     var index = this._findMapping(
799       needle,
800       this._originalMappings,
801       "originalLine",
802       "originalColumn",
803       util.compareByOriginalPositions,
804       util.getArg(aArgs, 'bias', SourceMapConsumer.GREATEST_LOWER_BOUND)
805     );
806
807     if (index >= 0) {
808       var mapping = this._originalMappings[index];
809
810       if (mapping.source === needle.source) {
811         return {
812           line: util.getArg(mapping, 'generatedLine', null),
813           column: util.getArg(mapping, 'generatedColumn', null),
814           lastColumn: util.getArg(mapping, 'lastGeneratedColumn', null)
815         };
816       }
817     }
818
819     return {
820       line: null,
821       column: null,
822       lastColumn: null
823     };
824   };
825
826 exports.BasicSourceMapConsumer = BasicSourceMapConsumer;
827
828 /**
829  * An IndexedSourceMapConsumer instance represents a parsed source map which
830  * we can query for information. It differs from BasicSourceMapConsumer in
831  * that it takes "indexed" source maps (i.e. ones with a "sections" field) as
832  * input.
833  *
834  * The first parameter is a raw source map (either as a JSON string, or already
835  * parsed to an object). According to the spec for indexed source maps, they
836  * have the following attributes:
837  *
838  *   - version: Which version of the source map spec this map is following.
839  *   - file: Optional. The generated file this source map is associated with.
840  *   - sections: A list of section definitions.
841  *
842  * Each value under the "sections" field has two fields:
843  *   - offset: The offset into the original specified at which this section
844  *       begins to apply, defined as an object with a "line" and "column"
845  *       field.
846  *   - map: A source map definition. This source map could also be indexed,
847  *       but doesn't have to be.
848  *
849  * Instead of the "map" field, it's also possible to have a "url" field
850  * specifying a URL to retrieve a source map from, but that's currently
851  * unsupported.
852  *
853  * Here's an example source map, taken from the source map spec[0], but
854  * modified to omit a section which uses the "url" field.
855  *
856  *  {
857  *    version : 3,
858  *    file: "app.js",
859  *    sections: [{
860  *      offset: {line:100, column:10},
861  *      map: {
862  *        version : 3,
863  *        file: "section.js",
864  *        sources: ["foo.js", "bar.js"],
865  *        names: ["src", "maps", "are", "fun"],
866  *        mappings: "AAAA,E;;ABCDE;"
867  *      }
868  *    }],
869  *  }
870  *
871  * The second parameter, if given, is a string whose value is the URL
872  * at which the source map was found.  This URL is used to compute the
873  * sources array.
874  *
875  * [0]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit#heading=h.535es3xeprgt
876  */
877 function IndexedSourceMapConsumer(aSourceMap, aSourceMapURL) {
878   var sourceMap = aSourceMap;
879   if (typeof aSourceMap === 'string') {
880     sourceMap = util.parseSourceMapInput(aSourceMap);
881   }
882
883   var version = util.getArg(sourceMap, 'version');
884   var sections = util.getArg(sourceMap, 'sections');
885
886   if (version != this._version) {
887     throw new Error('Unsupported version: ' + version);
888   }
889
890   this._sources = new ArraySet();
891   this._names = new ArraySet();
892
893   var lastOffset = {
894     line: -1,
895     column: 0
896   };
897   this._sections = sections.map(function (s) {
898     if (s.url) {
899       // The url field will require support for asynchronicity.
900       // See https://github.com/mozilla/source-map/issues/16
901       throw new Error('Support for url field in sections not implemented.');
902     }
903     var offset = util.getArg(s, 'offset');
904     var offsetLine = util.getArg(offset, 'line');
905     var offsetColumn = util.getArg(offset, 'column');
906
907     if (offsetLine < lastOffset.line ||
908         (offsetLine === lastOffset.line && offsetColumn < lastOffset.column)) {
909       throw new Error('Section offsets must be ordered and non-overlapping.');
910     }
911     lastOffset = offset;
912
913     return {
914       generatedOffset: {
915         // The offset fields are 0-based, but we use 1-based indices when
916         // encoding/decoding from VLQ.
917         generatedLine: offsetLine + 1,
918         generatedColumn: offsetColumn + 1
919       },
920       consumer: new SourceMapConsumer(util.getArg(s, 'map'), aSourceMapURL)
921     }
922   });
923 }
924
925 IndexedSourceMapConsumer.prototype = Object.create(SourceMapConsumer.prototype);
926 IndexedSourceMapConsumer.prototype.constructor = SourceMapConsumer;
927
928 /**
929  * The version of the source mapping spec that we are consuming.
930  */
931 IndexedSourceMapConsumer.prototype._version = 3;
932
933 /**
934  * The list of original sources.
935  */
936 Object.defineProperty(IndexedSourceMapConsumer.prototype, 'sources', {
937   get: function () {
938     var sources = [];
939     for (var i = 0; i < this._sections.length; i++) {
940       for (var j = 0; j < this._sections[i].consumer.sources.length; j++) {
941         sources.push(this._sections[i].consumer.sources[j]);
942       }
943     }
944     return sources;
945   }
946 });
947
948 /**
949  * Returns the original source, line, and column information for the generated
950  * source's line and column positions provided. The only argument is an object
951  * with the following properties:
952  *
953  *   - line: The line number in the generated source.  The line number
954  *     is 1-based.
955  *   - column: The column number in the generated source.  The column
956  *     number is 0-based.
957  *
958  * and an object is returned with the following properties:
959  *
960  *   - source: The original source file, or null.
961  *   - line: The line number in the original source, or null.  The
962  *     line number is 1-based.
963  *   - column: The column number in the original source, or null.  The
964  *     column number is 0-based.
965  *   - name: The original identifier, or null.
966  */
967 IndexedSourceMapConsumer.prototype.originalPositionFor =
968   function IndexedSourceMapConsumer_originalPositionFor(aArgs) {
969     var needle = {
970       generatedLine: util.getArg(aArgs, 'line'),
971       generatedColumn: util.getArg(aArgs, 'column')
972     };
973
974     // Find the section containing the generated position we're trying to map
975     // to an original position.
976     var sectionIndex = binarySearch.search(needle, this._sections,
977       function(needle, section) {
978         var cmp = needle.generatedLine - section.generatedOffset.generatedLine;
979         if (cmp) {
980           return cmp;
981         }
982
983         return (needle.generatedColumn -
984                 section.generatedOffset.generatedColumn);
985       });
986     var section = this._sections[sectionIndex];
987
988     if (!section) {
989       return {
990         source: null,
991         line: null,
992         column: null,
993         name: null
994       };
995     }
996
997     return section.consumer.originalPositionFor({
998       line: needle.generatedLine -
999         (section.generatedOffset.generatedLine - 1),
1000       column: needle.generatedColumn -
1001         (section.generatedOffset.generatedLine === needle.generatedLine
1002          ? section.generatedOffset.generatedColumn - 1
1003          : 0),
1004       bias: aArgs.bias
1005     });
1006   };
1007
1008 /**
1009  * Return true if we have the source content for every source in the source
1010  * map, false otherwise.
1011  */
1012 IndexedSourceMapConsumer.prototype.hasContentsOfAllSources =
1013   function IndexedSourceMapConsumer_hasContentsOfAllSources() {
1014     return this._sections.every(function (s) {
1015       return s.consumer.hasContentsOfAllSources();
1016     });
1017   };
1018
1019 /**
1020  * Returns the original source content. The only argument is the url of the
1021  * original source file. Returns null if no original source content is
1022  * available.
1023  */
1024 IndexedSourceMapConsumer.prototype.sourceContentFor =
1025   function IndexedSourceMapConsumer_sourceContentFor(aSource, nullOnMissing) {
1026     for (var i = 0; i < this._sections.length; i++) {
1027       var section = this._sections[i];
1028
1029       var content = section.consumer.sourceContentFor(aSource, true);
1030       if (content) {
1031         return content;
1032       }
1033     }
1034     if (nullOnMissing) {
1035       return null;
1036     }
1037     else {
1038       throw new Error('"' + aSource + '" is not in the SourceMap.');
1039     }
1040   };
1041
1042 /**
1043  * Returns the generated line and column information for the original source,
1044  * line, and column positions provided. The only argument is an object with
1045  * the following properties:
1046  *
1047  *   - source: The filename of the original source.
1048  *   - line: The line number in the original source.  The line number
1049  *     is 1-based.
1050  *   - column: The column number in the original source.  The column
1051  *     number is 0-based.
1052  *
1053  * and an object is returned with the following properties:
1054  *
1055  *   - line: The line number in the generated source, or null.  The
1056  *     line number is 1-based. 
1057  *   - column: The column number in the generated source, or null.
1058  *     The column number is 0-based.
1059  */
1060 IndexedSourceMapConsumer.prototype.generatedPositionFor =
1061   function IndexedSourceMapConsumer_generatedPositionFor(aArgs) {
1062     for (var i = 0; i < this._sections.length; i++) {
1063       var section = this._sections[i];
1064
1065       // Only consider this section if the requested source is in the list of
1066       // sources of the consumer.
1067       if (section.consumer._findSourceIndex(util.getArg(aArgs, 'source')) === -1) {
1068         continue;
1069       }
1070       var generatedPosition = section.consumer.generatedPositionFor(aArgs);
1071       if (generatedPosition) {
1072         var ret = {
1073           line: generatedPosition.line +
1074             (section.generatedOffset.generatedLine - 1),
1075           column: generatedPosition.column +
1076             (section.generatedOffset.generatedLine === generatedPosition.line
1077              ? section.generatedOffset.generatedColumn - 1
1078              : 0)
1079         };
1080         return ret;
1081       }
1082     }
1083
1084     return {
1085       line: null,
1086       column: null
1087     };
1088   };
1089
1090 /**
1091  * Parse the mappings in a string in to a data structure which we can easily
1092  * query (the ordered arrays in the `this.__generatedMappings` and
1093  * `this.__originalMappings` properties).
1094  */
1095 IndexedSourceMapConsumer.prototype._parseMappings =
1096   function IndexedSourceMapConsumer_parseMappings(aStr, aSourceRoot) {
1097     this.__generatedMappings = [];
1098     this.__originalMappings = [];
1099     for (var i = 0; i < this._sections.length; i++) {
1100       var section = this._sections[i];
1101       var sectionMappings = section.consumer._generatedMappings;
1102       for (var j = 0; j < sectionMappings.length; j++) {
1103         var mapping = sectionMappings[j];
1104
1105         var source = section.consumer._sources.at(mapping.source);
1106         source = util.computeSourceURL(section.consumer.sourceRoot, source, this._sourceMapURL);
1107         this._sources.add(source);
1108         source = this._sources.indexOf(source);
1109
1110         var name = null;
1111         if (mapping.name) {
1112           name = section.consumer._names.at(mapping.name);
1113           this._names.add(name);
1114           name = this._names.indexOf(name);
1115         }
1116
1117         // The mappings coming from the consumer for the section have
1118         // generated positions relative to the start of the section, so we
1119         // need to offset them to be relative to the start of the concatenated
1120         // generated file.
1121         var adjustedMapping = {
1122           source: source,
1123           generatedLine: mapping.generatedLine +
1124             (section.generatedOffset.generatedLine - 1),
1125           generatedColumn: mapping.generatedColumn +
1126             (section.generatedOffset.generatedLine === mapping.generatedLine
1127             ? section.generatedOffset.generatedColumn - 1
1128             : 0),
1129           originalLine: mapping.originalLine,
1130           originalColumn: mapping.originalColumn,
1131           name: name
1132         };
1133
1134         this.__generatedMappings.push(adjustedMapping);
1135         if (typeof adjustedMapping.originalLine === 'number') {
1136           this.__originalMappings.push(adjustedMapping);
1137         }
1138       }
1139     }
1140
1141     quickSort(this.__generatedMappings, util.compareByGeneratedPositionsDeflated);
1142     quickSort(this.__originalMappings, util.compareByOriginalPositions);
1143   };
1144
1145 exports.IndexedSourceMapConsumer = IndexedSourceMapConsumer;