/* -*- Mode: js; js-indent-level: 2; -*- */ 
 | 
/* 
 | 
 * Copyright 2011 Mozilla Foundation and contributors 
 | 
 * Licensed under the New BSD license. See LICENSE or: 
 | 
 * http://opensource.org/licenses/BSD-3-Clause 
 | 
 */ 
 | 
  
 | 
const util = require("./util"); 
 | 
const binarySearch = require("./binary-search"); 
 | 
const ArraySet = require("./array-set").ArraySet; 
 | 
const base64VLQ = require("./base64-vlq"); // eslint-disable-line no-unused-vars 
 | 
const readWasm = require("../lib/read-wasm"); 
 | 
const wasm = require("./wasm"); 
 | 
  
 | 
const INTERNAL = Symbol("smcInternal"); 
 | 
  
 | 
class SourceMapConsumer { 
 | 
  constructor(aSourceMap, aSourceMapURL) { 
 | 
    // If the constructor was called by super(), just return Promise<this>. 
 | 
    // Yes, this is a hack to retain the pre-existing API of the base-class 
 | 
    // constructor also being an async factory function. 
 | 
    if (aSourceMap == INTERNAL) { 
 | 
      return Promise.resolve(this); 
 | 
    } 
 | 
  
 | 
    return _factory(aSourceMap, aSourceMapURL); 
 | 
  } 
 | 
  
 | 
  static initialize(opts) { 
 | 
    readWasm.initialize(opts["lib/mappings.wasm"]); 
 | 
  } 
 | 
  
 | 
  static fromSourceMap(aSourceMap, aSourceMapURL) { 
 | 
    return _factoryBSM(aSourceMap, aSourceMapURL); 
 | 
  } 
 | 
  
 | 
  /** 
 | 
   * Construct a new `SourceMapConsumer` from `rawSourceMap` and `sourceMapUrl` 
 | 
   * (see the `SourceMapConsumer` constructor for details. Then, invoke the `async 
 | 
   * function f(SourceMapConsumer) -> T` with the newly constructed consumer, wait 
 | 
   * for `f` to complete, call `destroy` on the consumer, and return `f`'s return 
 | 
   * value. 
 | 
   * 
 | 
   * You must not use the consumer after `f` completes! 
 | 
   * 
 | 
   * By using `with`, you do not have to remember to manually call `destroy` on 
 | 
   * the consumer, since it will be called automatically once `f` completes. 
 | 
   * 
 | 
   * ```js 
 | 
   * const xSquared = await SourceMapConsumer.with( 
 | 
   *   myRawSourceMap, 
 | 
   *   null, 
 | 
   *   async function (consumer) { 
 | 
   *     // Use `consumer` inside here and don't worry about remembering 
 | 
   *     // to call `destroy`. 
 | 
   * 
 | 
   *     const x = await whatever(consumer); 
 | 
   *     return x * x; 
 | 
   *   } 
 | 
   * ); 
 | 
   * 
 | 
   * // You may not use that `consumer` anymore out here; it has 
 | 
   * // been destroyed. But you can use `xSquared`. 
 | 
   * console.log(xSquared); 
 | 
   * ``` 
 | 
   */ 
 | 
  static async with(rawSourceMap, sourceMapUrl, f) { 
 | 
    const consumer = await new SourceMapConsumer(rawSourceMap, sourceMapUrl); 
 | 
    try { 
 | 
      return await f(consumer); 
 | 
    } finally { 
 | 
      consumer.destroy(); 
 | 
    } 
 | 
  } 
 | 
  
 | 
  /** 
 | 
   * Parse the mappings in a string in to a data structure which we can easily 
 | 
   * query (the ordered arrays in the `this.__generatedMappings` and 
 | 
   * `this.__originalMappings` properties). 
 | 
   */ 
 | 
  _parseMappings(aStr, aSourceRoot) { 
 | 
    throw new Error("Subclasses must implement _parseMappings"); 
 | 
  } 
 | 
  
 | 
  /** 
 | 
   * Iterate over each mapping between an original source/line/column and a 
 | 
   * generated line/column in this source map. 
 | 
   * 
 | 
   * @param Function aCallback 
 | 
   *        The function that is called with each mapping. 
 | 
   * @param Object aContext 
 | 
   *        Optional. If specified, this object will be the value of `this` every 
 | 
   *        time that `aCallback` is called. 
 | 
   * @param aOrder 
 | 
   *        Either `SourceMapConsumer.GENERATED_ORDER` or 
 | 
   *        `SourceMapConsumer.ORIGINAL_ORDER`. Specifies whether you want to 
 | 
   *        iterate over the mappings sorted by the generated file's line/column 
 | 
   *        order or the original's source/line/column order, respectively. Defaults to 
 | 
   *        `SourceMapConsumer.GENERATED_ORDER`. 
 | 
   */ 
 | 
  eachMapping(aCallback, aContext, aOrder) { 
 | 
    throw new Error("Subclasses must implement eachMapping"); 
 | 
  } 
 | 
  
 | 
  /** 
 | 
   * Returns all generated line and column information for the original source, 
 | 
   * line, and column provided. If no column is provided, returns all mappings 
 | 
   * corresponding to a either the line we are searching for or the next 
 | 
   * closest line that has any mappings. Otherwise, returns all mappings 
 | 
   * corresponding to the given line and either the column we are searching for 
 | 
   * or the next closest column that has any offsets. 
 | 
   * 
 | 
   * The only argument is an object with the following properties: 
 | 
   * 
 | 
   *   - source: The filename of the original source. 
 | 
   *   - line: The line number in the original source.  The line number is 1-based. 
 | 
   *   - column: Optional. the column number in the original source. 
 | 
   *    The column number is 0-based. 
 | 
   * 
 | 
   * and an array of objects is returned, each with the following properties: 
 | 
   * 
 | 
   *   - line: The line number in the generated source, or null.  The 
 | 
   *    line number is 1-based. 
 | 
   *   - column: The column number in the generated source, or null. 
 | 
   *    The column number is 0-based. 
 | 
   */ 
 | 
  allGeneratedPositionsFor(aArgs) { 
 | 
    throw new Error("Subclasses must implement allGeneratedPositionsFor"); 
 | 
  } 
 | 
  
 | 
  destroy() { 
 | 
    throw new Error("Subclasses must implement destroy"); 
 | 
  } 
 | 
} 
 | 
  
 | 
/** 
 | 
 * The version of the source mapping spec that we are consuming. 
 | 
 */ 
 | 
SourceMapConsumer.prototype._version = 3; 
 | 
SourceMapConsumer.GENERATED_ORDER = 1; 
 | 
SourceMapConsumer.ORIGINAL_ORDER = 2; 
 | 
  
 | 
SourceMapConsumer.GREATEST_LOWER_BOUND = 1; 
 | 
SourceMapConsumer.LEAST_UPPER_BOUND = 2; 
 | 
  
 | 
exports.SourceMapConsumer = SourceMapConsumer; 
 | 
  
 | 
/** 
 | 
 * A BasicSourceMapConsumer instance represents a parsed source map which we can 
 | 
 * query for information about the original file positions by giving it a file 
 | 
 * position in the generated source. 
 | 
 * 
 | 
 * The first parameter is the raw source map (either as a JSON string, or 
 | 
 * already parsed to an object). According to the spec, source maps have the 
 | 
 * following attributes: 
 | 
 * 
 | 
 *   - version: Which version of the source map spec this map is following. 
 | 
 *   - sources: An array of URLs to the original source files. 
 | 
 *   - names: An array of identifiers which can be referenced by individual mappings. 
 | 
 *   - sourceRoot: Optional. The URL root from which all sources are relative. 
 | 
 *   - sourcesContent: Optional. An array of contents of the original source files. 
 | 
 *   - mappings: A string of base64 VLQs which contain the actual mappings. 
 | 
 *   - file: Optional. The generated file this source map is associated with. 
 | 
 * 
 | 
 * Here is an example source map, taken from the source map spec[0]: 
 | 
 * 
 | 
 *     { 
 | 
 *       version : 3, 
 | 
 *       file: "out.js", 
 | 
 *       sourceRoot : "", 
 | 
 *       sources: ["foo.js", "bar.js"], 
 | 
 *       names: ["src", "maps", "are", "fun"], 
 | 
 *       mappings: "AA,AB;;ABCDE;" 
 | 
 *     } 
 | 
 * 
 | 
 * The second parameter, if given, is a string whose value is the URL 
 | 
 * at which the source map was found.  This URL is used to compute the 
 | 
 * sources array. 
 | 
 * 
 | 
 * [0]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit?pli=1# 
 | 
 */ 
 | 
class BasicSourceMapConsumer extends SourceMapConsumer { 
 | 
  constructor(aSourceMap, aSourceMapURL) { 
 | 
    return super(INTERNAL).then(that => { 
 | 
      let sourceMap = aSourceMap; 
 | 
      if (typeof aSourceMap === "string") { 
 | 
        sourceMap = util.parseSourceMapInput(aSourceMap); 
 | 
      } 
 | 
  
 | 
      const version = util.getArg(sourceMap, "version"); 
 | 
      let sources = util.getArg(sourceMap, "sources"); 
 | 
      // Sass 3.3 leaves out the 'names' array, so we deviate from the spec (which 
 | 
      // requires the array) to play nice here. 
 | 
      const names = util.getArg(sourceMap, "names", []); 
 | 
      let sourceRoot = util.getArg(sourceMap, "sourceRoot", null); 
 | 
      const sourcesContent = util.getArg(sourceMap, "sourcesContent", null); 
 | 
      const mappings = util.getArg(sourceMap, "mappings"); 
 | 
      const file = util.getArg(sourceMap, "file", null); 
 | 
  
 | 
      // Once again, Sass deviates from the spec and supplies the version as a 
 | 
      // string rather than a number, so we use loose equality checking here. 
 | 
      if (version != that._version) { 
 | 
        throw new Error("Unsupported version: " + version); 
 | 
      } 
 | 
  
 | 
      if (sourceRoot) { 
 | 
        sourceRoot = util.normalize(sourceRoot); 
 | 
      } 
 | 
  
 | 
      sources = sources 
 | 
        .map(String) 
 | 
        // Some source maps produce relative source paths like "./foo.js" instead of 
 | 
        // "foo.js".  Normalize these first so that future comparisons will succeed. 
 | 
        // See bugzil.la/1090768. 
 | 
        .map(util.normalize) 
 | 
        // Always ensure that absolute sources are internally stored relative to 
 | 
        // the source root, if the source root is absolute. Not doing this would 
 | 
        // be particularly problematic when the source root is a prefix of the 
 | 
        // source (valid, but why??). See github issue #199 and bugzil.la/1188982. 
 | 
        .map(function(source) { 
 | 
          return sourceRoot && util.isAbsolute(sourceRoot) && util.isAbsolute(source) 
 | 
            ? util.relative(sourceRoot, source) 
 | 
            : source; 
 | 
        }); 
 | 
  
 | 
      // Pass `true` below to allow duplicate names and sources. While source maps 
 | 
      // are intended to be compressed and deduplicated, the TypeScript compiler 
 | 
      // sometimes generates source maps with duplicates in them. See Github issue 
 | 
      // #72 and bugzil.la/889492. 
 | 
      that._names = ArraySet.fromArray(names.map(String), true); 
 | 
      that._sources = ArraySet.fromArray(sources, true); 
 | 
  
 | 
      that._absoluteSources = that._sources.toArray().map(function(s) { 
 | 
        return util.computeSourceURL(sourceRoot, s, aSourceMapURL); 
 | 
      }); 
 | 
  
 | 
      that.sourceRoot = sourceRoot; 
 | 
      that.sourcesContent = sourcesContent; 
 | 
      that._mappings = mappings; 
 | 
      that._sourceMapURL = aSourceMapURL; 
 | 
      that.file = file; 
 | 
  
 | 
      that._computedColumnSpans = false; 
 | 
      that._mappingsPtr = 0; 
 | 
      that._wasm = null; 
 | 
  
 | 
      return wasm().then(w => { 
 | 
        that._wasm = w; 
 | 
        return that; 
 | 
      }); 
 | 
    }); 
 | 
  } 
 | 
  
 | 
  /** 
 | 
   * Utility function to find the index of a source.  Returns -1 if not 
 | 
   * found. 
 | 
   */ 
 | 
  _findSourceIndex(aSource) { 
 | 
    let relativeSource = aSource; 
 | 
    if (this.sourceRoot != null) { 
 | 
      relativeSource = util.relative(this.sourceRoot, relativeSource); 
 | 
    } 
 | 
  
 | 
    if (this._sources.has(relativeSource)) { 
 | 
      return this._sources.indexOf(relativeSource); 
 | 
    } 
 | 
  
 | 
    // Maybe aSource is an absolute URL as returned by |sources|.  In 
 | 
    // this case we can't simply undo the transform. 
 | 
    for (let i = 0; i < this._absoluteSources.length; ++i) { 
 | 
      if (this._absoluteSources[i] == aSource) { 
 | 
        return i; 
 | 
      } 
 | 
    } 
 | 
  
 | 
    return -1; 
 | 
  } 
 | 
  
 | 
  /** 
 | 
   * Create a BasicSourceMapConsumer from a SourceMapGenerator. 
 | 
   * 
 | 
   * @param SourceMapGenerator aSourceMap 
 | 
   *        The source map that will be consumed. 
 | 
   * @param String aSourceMapURL 
 | 
   *        The URL at which the source map can be found (optional) 
 | 
   * @returns BasicSourceMapConsumer 
 | 
   */ 
 | 
  static fromSourceMap(aSourceMap, aSourceMapURL) { 
 | 
    return new BasicSourceMapConsumer(aSourceMap.toString()); 
 | 
  } 
 | 
  
 | 
  get sources() { 
 | 
    return this._absoluteSources.slice(); 
 | 
  } 
 | 
  
 | 
  _getMappingsPtr() { 
 | 
    if (this._mappingsPtr === 0) { 
 | 
      this._parseMappings(this._mappings, this.sourceRoot); 
 | 
    } 
 | 
  
 | 
    return this._mappingsPtr; 
 | 
  } 
 | 
  
 | 
  /** 
 | 
   * Parse the mappings in a string in to a data structure which we can easily 
 | 
   * query (the ordered arrays in the `this.__generatedMappings` and 
 | 
   * `this.__originalMappings` properties). 
 | 
   */ 
 | 
  _parseMappings(aStr, aSourceRoot) { 
 | 
    const size = aStr.length; 
 | 
  
 | 
    const mappingsBufPtr = this._wasm.exports.allocate_mappings(size); 
 | 
    const mappingsBuf = new Uint8Array(this._wasm.exports.memory.buffer, mappingsBufPtr, size); 
 | 
    for (let i = 0; i < size; i++) { 
 | 
      mappingsBuf[i] = aStr.charCodeAt(i); 
 | 
    } 
 | 
  
 | 
    const mappingsPtr = this._wasm.exports.parse_mappings(mappingsBufPtr); 
 | 
  
 | 
    if (!mappingsPtr) { 
 | 
      const error = this._wasm.exports.get_last_error(); 
 | 
      let msg = `Error parsing mappings (code ${error}): `; 
 | 
  
 | 
      // XXX: keep these error codes in sync with `fitzgen/source-map-mappings`. 
 | 
      switch (error) { 
 | 
        case 1: 
 | 
          msg += "the mappings contained a negative line, column, source index, or name index"; 
 | 
          break; 
 | 
        case 2: 
 | 
          msg += "the mappings contained a number larger than 2**32"; 
 | 
          break; 
 | 
        case 3: 
 | 
          msg += "reached EOF while in the middle of parsing a VLQ"; 
 | 
          break; 
 | 
        case 4: 
 | 
          msg += "invalid base 64 character while parsing a VLQ"; 
 | 
          break; 
 | 
        default: 
 | 
          msg += "unknown error code"; 
 | 
          break; 
 | 
      } 
 | 
  
 | 
      throw new Error(msg); 
 | 
    } 
 | 
  
 | 
    this._mappingsPtr = mappingsPtr; 
 | 
  } 
 | 
  
 | 
  eachMapping(aCallback, aContext, aOrder) { 
 | 
    const context = aContext || null; 
 | 
    const order = aOrder || SourceMapConsumer.GENERATED_ORDER; 
 | 
    const sourceRoot = this.sourceRoot; 
 | 
  
 | 
    this._wasm.withMappingCallback( 
 | 
      mapping => { 
 | 
        if (mapping.source !== null) { 
 | 
          mapping.source = this._sources.at(mapping.source); 
 | 
          mapping.source = util.computeSourceURL(sourceRoot, mapping.source, this._sourceMapURL); 
 | 
  
 | 
          if (mapping.name !== null) { 
 | 
            mapping.name = this._names.at(mapping.name); 
 | 
          } 
 | 
        } 
 | 
  
 | 
        aCallback.call(context, mapping); 
 | 
      }, 
 | 
      () => { 
 | 
        switch (order) { 
 | 
        case SourceMapConsumer.GENERATED_ORDER: 
 | 
          this._wasm.exports.by_generated_location(this._getMappingsPtr()); 
 | 
          break; 
 | 
        case SourceMapConsumer.ORIGINAL_ORDER: 
 | 
          this._wasm.exports.by_original_location(this._getMappingsPtr()); 
 | 
          break; 
 | 
        default: 
 | 
          throw new Error("Unknown order of iteration."); 
 | 
        } 
 | 
      } 
 | 
    ); 
 | 
  } 
 | 
  
 | 
  allGeneratedPositionsFor(aArgs) { 
 | 
    let source = util.getArg(aArgs, "source"); 
 | 
    const originalLine = util.getArg(aArgs, "line"); 
 | 
    const originalColumn = aArgs.column || 0; 
 | 
  
 | 
    source = this._findSourceIndex(source); 
 | 
    if (source < 0) { 
 | 
      return []; 
 | 
    } 
 | 
  
 | 
    if (originalLine < 1) { 
 | 
      throw new Error("Line numbers must be >= 1"); 
 | 
    } 
 | 
  
 | 
    if (originalColumn < 0) { 
 | 
      throw new Error("Column numbers must be >= 0"); 
 | 
    } 
 | 
  
 | 
    const mappings = []; 
 | 
  
 | 
    this._wasm.withMappingCallback( 
 | 
      m => { 
 | 
        let lastColumn = m.lastGeneratedColumn; 
 | 
        if (this._computedColumnSpans && lastColumn === null) { 
 | 
          lastColumn = Infinity; 
 | 
        } 
 | 
        mappings.push({ 
 | 
          line: m.generatedLine, 
 | 
          column: m.generatedColumn, 
 | 
          lastColumn, 
 | 
        }); 
 | 
      }, () => { 
 | 
        this._wasm.exports.all_generated_locations_for( 
 | 
          this._getMappingsPtr(), 
 | 
          source, 
 | 
          originalLine - 1, 
 | 
          "column" in aArgs, 
 | 
          originalColumn 
 | 
        ); 
 | 
      } 
 | 
    ); 
 | 
  
 | 
    return mappings; 
 | 
  } 
 | 
  
 | 
  destroy() { 
 | 
    if (this._mappingsPtr !== 0) { 
 | 
      this._wasm.exports.free_mappings(this._mappingsPtr); 
 | 
      this._mappingsPtr = 0; 
 | 
    } 
 | 
  } 
 | 
  
 | 
  /** 
 | 
   * Compute the last column for each generated mapping. The last column is 
 | 
   * inclusive. 
 | 
   */ 
 | 
  computeColumnSpans() { 
 | 
    if (this._computedColumnSpans) { 
 | 
      return; 
 | 
    } 
 | 
  
 | 
    this._wasm.exports.compute_column_spans(this._getMappingsPtr()); 
 | 
    this._computedColumnSpans = true; 
 | 
  } 
 | 
  
 | 
  /** 
 | 
   * Returns the original source, line, and column information for the generated 
 | 
   * source's line and column positions provided. The only argument is an object 
 | 
   * with the following properties: 
 | 
   * 
 | 
   *   - line: The line number in the generated source.  The line number 
 | 
   *     is 1-based. 
 | 
   *   - column: The column number in the generated source.  The column 
 | 
   *     number is 0-based. 
 | 
   *   - bias: Either 'SourceMapConsumer.GREATEST_LOWER_BOUND' or 
 | 
   *     'SourceMapConsumer.LEAST_UPPER_BOUND'. Specifies whether to return the 
 | 
   *     closest element that is smaller than or greater than the one we are 
 | 
   *     searching for, respectively, if the exact element cannot be found. 
 | 
   *     Defaults to 'SourceMapConsumer.GREATEST_LOWER_BOUND'. 
 | 
   * 
 | 
   * and an object is returned with the following properties: 
 | 
   * 
 | 
   *   - source: The original source file, or null. 
 | 
   *   - line: The line number in the original source, or null.  The 
 | 
   *     line number is 1-based. 
 | 
   *   - column: The column number in the original source, or null.  The 
 | 
   *     column number is 0-based. 
 | 
   *   - name: The original identifier, or null. 
 | 
   */ 
 | 
  originalPositionFor(aArgs) { 
 | 
    const needle = { 
 | 
      generatedLine: util.getArg(aArgs, "line"), 
 | 
      generatedColumn: util.getArg(aArgs, "column") 
 | 
    }; 
 | 
  
 | 
    if (needle.generatedLine < 1) { 
 | 
      throw new Error("Line numbers must be >= 1"); 
 | 
    } 
 | 
  
 | 
    if (needle.generatedColumn < 0) { 
 | 
      throw new Error("Column numbers must be >= 0"); 
 | 
    } 
 | 
  
 | 
    let bias = util.getArg(aArgs, "bias", SourceMapConsumer.GREATEST_LOWER_BOUND); 
 | 
    if (bias == null) { 
 | 
      bias = SourceMapConsumer.GREATEST_LOWER_BOUND; 
 | 
    } 
 | 
  
 | 
    let mapping; 
 | 
    this._wasm.withMappingCallback(m => mapping = m, () => { 
 | 
      this._wasm.exports.original_location_for( 
 | 
        this._getMappingsPtr(), 
 | 
        needle.generatedLine - 1, 
 | 
        needle.generatedColumn, 
 | 
        bias 
 | 
      ); 
 | 
    }); 
 | 
  
 | 
    if (mapping) { 
 | 
      if (mapping.generatedLine === needle.generatedLine) { 
 | 
        let source = util.getArg(mapping, "source", null); 
 | 
        if (source !== null) { 
 | 
          source = this._sources.at(source); 
 | 
          source = util.computeSourceURL(this.sourceRoot, source, this._sourceMapURL); 
 | 
        } 
 | 
  
 | 
        let name = util.getArg(mapping, "name", null); 
 | 
        if (name !== null) { 
 | 
          name = this._names.at(name); 
 | 
        } 
 | 
  
 | 
        return { 
 | 
          source, 
 | 
          line: util.getArg(mapping, "originalLine", null), 
 | 
          column: util.getArg(mapping, "originalColumn", null), 
 | 
          name 
 | 
        }; 
 | 
      } 
 | 
    } 
 | 
  
 | 
    return { 
 | 
      source: null, 
 | 
      line: null, 
 | 
      column: null, 
 | 
      name: null 
 | 
    }; 
 | 
  } 
 | 
  
 | 
  /** 
 | 
   * Return true if we have the source content for every source in the source 
 | 
   * map, false otherwise. 
 | 
   */ 
 | 
  hasContentsOfAllSources() { 
 | 
    if (!this.sourcesContent) { 
 | 
      return false; 
 | 
    } 
 | 
    return this.sourcesContent.length >= this._sources.size() && 
 | 
      !this.sourcesContent.some(function(sc) { return sc == null; }); 
 | 
  } 
 | 
  
 | 
  /** 
 | 
   * Returns the original source content. The only argument is the url of the 
 | 
   * original source file. Returns null if no original source content is 
 | 
   * available. 
 | 
   */ 
 | 
  sourceContentFor(aSource, nullOnMissing) { 
 | 
    if (!this.sourcesContent) { 
 | 
      return null; 
 | 
    } 
 | 
  
 | 
    const index = this._findSourceIndex(aSource); 
 | 
    if (index >= 0) { 
 | 
      return this.sourcesContent[index]; 
 | 
    } 
 | 
  
 | 
    let relativeSource = aSource; 
 | 
    if (this.sourceRoot != null) { 
 | 
      relativeSource = util.relative(this.sourceRoot, relativeSource); 
 | 
    } 
 | 
  
 | 
    let url; 
 | 
    if (this.sourceRoot != null 
 | 
        && (url = util.urlParse(this.sourceRoot))) { 
 | 
      // XXX: file:// URIs and absolute paths lead to unexpected behavior for 
 | 
      // many users. We can help them out when they expect file:// URIs to 
 | 
      // behave like it would if they were running a local HTTP server. See 
 | 
      // https://bugzilla.mozilla.org/show_bug.cgi?id=885597. 
 | 
      const fileUriAbsPath = relativeSource.replace(/^file:\/\//, ""); 
 | 
      if (url.scheme == "file" 
 | 
          && this._sources.has(fileUriAbsPath)) { 
 | 
        return this.sourcesContent[this._sources.indexOf(fileUriAbsPath)]; 
 | 
      } 
 | 
  
 | 
      if ((!url.path || url.path == "/") 
 | 
          && this._sources.has("/" + relativeSource)) { 
 | 
        return this.sourcesContent[this._sources.indexOf("/" + relativeSource)]; 
 | 
      } 
 | 
    } 
 | 
  
 | 
    // This function is used recursively from 
 | 
    // IndexedSourceMapConsumer.prototype.sourceContentFor. In that case, we 
 | 
    // don't want to throw if we can't find the source - we just want to 
 | 
    // return null, so we provide a flag to exit gracefully. 
 | 
    if (nullOnMissing) { 
 | 
      return null; 
 | 
    } 
 | 
  
 | 
    throw new Error('"' + relativeSource + '" is not in the SourceMap.'); 
 | 
  } 
 | 
  
 | 
  /** 
 | 
   * Returns the generated line and column information for the original source, 
 | 
   * line, and column positions provided. The only argument is an object with 
 | 
   * the following properties: 
 | 
   * 
 | 
   *   - source: The filename of the original source. 
 | 
   *   - line: The line number in the original source.  The line number 
 | 
   *     is 1-based. 
 | 
   *   - column: The column number in the original source.  The column 
 | 
   *     number is 0-based. 
 | 
   *   - bias: Either 'SourceMapConsumer.GREATEST_LOWER_BOUND' or 
 | 
   *     'SourceMapConsumer.LEAST_UPPER_BOUND'. Specifies whether to return the 
 | 
   *     closest element that is smaller than or greater than the one we are 
 | 
   *     searching for, respectively, if the exact element cannot be found. 
 | 
   *     Defaults to 'SourceMapConsumer.GREATEST_LOWER_BOUND'. 
 | 
   * 
 | 
   * and an object is returned with the following properties: 
 | 
   * 
 | 
   *   - line: The line number in the generated source, or null.  The 
 | 
   *     line number is 1-based. 
 | 
   *   - column: The column number in the generated source, or null. 
 | 
   *     The column number is 0-based. 
 | 
   */ 
 | 
  generatedPositionFor(aArgs) { 
 | 
    let source = util.getArg(aArgs, "source"); 
 | 
    source = this._findSourceIndex(source); 
 | 
    if (source < 0) { 
 | 
      return { 
 | 
        line: null, 
 | 
        column: null, 
 | 
        lastColumn: null 
 | 
      }; 
 | 
    } 
 | 
  
 | 
    const needle = { 
 | 
      source, 
 | 
      originalLine: util.getArg(aArgs, "line"), 
 | 
      originalColumn: util.getArg(aArgs, "column") 
 | 
    }; 
 | 
  
 | 
    if (needle.originalLine < 1) { 
 | 
      throw new Error("Line numbers must be >= 1"); 
 | 
    } 
 | 
  
 | 
    if (needle.originalColumn < 0) { 
 | 
      throw new Error("Column numbers must be >= 0"); 
 | 
    } 
 | 
  
 | 
    let bias = util.getArg(aArgs, "bias", SourceMapConsumer.GREATEST_LOWER_BOUND); 
 | 
    if (bias == null) { 
 | 
      bias = SourceMapConsumer.GREATEST_LOWER_BOUND; 
 | 
    } 
 | 
  
 | 
    let mapping; 
 | 
    this._wasm.withMappingCallback(m => mapping = m, () => { 
 | 
      this._wasm.exports.generated_location_for( 
 | 
        this._getMappingsPtr(), 
 | 
        needle.source, 
 | 
        needle.originalLine - 1, 
 | 
        needle.originalColumn, 
 | 
        bias 
 | 
      ); 
 | 
    }); 
 | 
  
 | 
    if (mapping) { 
 | 
      if (mapping.source === needle.source) { 
 | 
        let lastColumn = mapping.lastGeneratedColumn; 
 | 
        if (this._computedColumnSpans && lastColumn === null) { 
 | 
          lastColumn = Infinity; 
 | 
        } 
 | 
        return { 
 | 
          line: util.getArg(mapping, "generatedLine", null), 
 | 
          column: util.getArg(mapping, "generatedColumn", null), 
 | 
          lastColumn, 
 | 
        }; 
 | 
      } 
 | 
    } 
 | 
  
 | 
    return { 
 | 
      line: null, 
 | 
      column: null, 
 | 
      lastColumn: null 
 | 
    }; 
 | 
  } 
 | 
} 
 | 
  
 | 
BasicSourceMapConsumer.prototype.consumer = SourceMapConsumer; 
 | 
exports.BasicSourceMapConsumer = BasicSourceMapConsumer; 
 | 
  
 | 
/** 
 | 
 * An IndexedSourceMapConsumer instance represents a parsed source map which 
 | 
 * we can query for information. It differs from BasicSourceMapConsumer in 
 | 
 * that it takes "indexed" source maps (i.e. ones with a "sections" field) as 
 | 
 * input. 
 | 
 * 
 | 
 * The first parameter is a raw source map (either as a JSON string, or already 
 | 
 * parsed to an object). According to the spec for indexed source maps, they 
 | 
 * have the following attributes: 
 | 
 * 
 | 
 *   - version: Which version of the source map spec this map is following. 
 | 
 *   - file: Optional. The generated file this source map is associated with. 
 | 
 *   - sections: A list of section definitions. 
 | 
 * 
 | 
 * Each value under the "sections" field has two fields: 
 | 
 *   - offset: The offset into the original specified at which this section 
 | 
 *       begins to apply, defined as an object with a "line" and "column" 
 | 
 *       field. 
 | 
 *   - map: A source map definition. This source map could also be indexed, 
 | 
 *       but doesn't have to be. 
 | 
 * 
 | 
 * Instead of the "map" field, it's also possible to have a "url" field 
 | 
 * specifying a URL to retrieve a source map from, but that's currently 
 | 
 * unsupported. 
 | 
 * 
 | 
 * Here's an example source map, taken from the source map spec[0], but 
 | 
 * modified to omit a section which uses the "url" field. 
 | 
 * 
 | 
 *  { 
 | 
 *    version : 3, 
 | 
 *    file: "app.js", 
 | 
 *    sections: [{ 
 | 
 *      offset: {line:100, column:10}, 
 | 
 *      map: { 
 | 
 *        version : 3, 
 | 
 *        file: "section.js", 
 | 
 *        sources: ["foo.js", "bar.js"], 
 | 
 *        names: ["src", "maps", "are", "fun"], 
 | 
 *        mappings: "AAAA,E;;ABCDE;" 
 | 
 *      } 
 | 
 *    }], 
 | 
 *  } 
 | 
 * 
 | 
 * The second parameter, if given, is a string whose value is the URL 
 | 
 * at which the source map was found.  This URL is used to compute the 
 | 
 * sources array. 
 | 
 * 
 | 
 * [0]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit#heading=h.535es3xeprgt 
 | 
 */ 
 | 
class IndexedSourceMapConsumer extends SourceMapConsumer { 
 | 
  constructor(aSourceMap, aSourceMapURL) { 
 | 
    return super(INTERNAL).then(that => { 
 | 
      let sourceMap = aSourceMap; 
 | 
      if (typeof aSourceMap === "string") { 
 | 
        sourceMap = util.parseSourceMapInput(aSourceMap); 
 | 
      } 
 | 
  
 | 
      const version = util.getArg(sourceMap, "version"); 
 | 
      const sections = util.getArg(sourceMap, "sections"); 
 | 
  
 | 
      if (version != that._version) { 
 | 
        throw new Error("Unsupported version: " + version); 
 | 
      } 
 | 
  
 | 
      that._sources = new ArraySet(); 
 | 
      that._names = new ArraySet(); 
 | 
      that.__generatedMappings = null; 
 | 
      that.__originalMappings = null; 
 | 
      that.__generatedMappingsUnsorted = null; 
 | 
      that.__originalMappingsUnsorted = null; 
 | 
  
 | 
      let lastOffset = { 
 | 
        line: -1, 
 | 
        column: 0 
 | 
      }; 
 | 
      return Promise.all(sections.map(s => { 
 | 
        if (s.url) { 
 | 
          // The url field will require support for asynchronicity. 
 | 
          // See https://github.com/mozilla/source-map/issues/16 
 | 
          throw new Error("Support for url field in sections not implemented."); 
 | 
        } 
 | 
        const offset = util.getArg(s, "offset"); 
 | 
        const offsetLine = util.getArg(offset, "line"); 
 | 
        const offsetColumn = util.getArg(offset, "column"); 
 | 
  
 | 
        if (offsetLine < lastOffset.line || 
 | 
            (offsetLine === lastOffset.line && offsetColumn < lastOffset.column)) { 
 | 
          throw new Error("Section offsets must be ordered and non-overlapping."); 
 | 
        } 
 | 
        lastOffset = offset; 
 | 
  
 | 
        const cons = new SourceMapConsumer(util.getArg(s, "map"), aSourceMapURL); 
 | 
        return cons.then(consumer => { 
 | 
          return { 
 | 
            generatedOffset: { 
 | 
              // The offset fields are 0-based, but we use 1-based indices when 
 | 
              // encoding/decoding from VLQ. 
 | 
              generatedLine: offsetLine + 1, 
 | 
              generatedColumn: offsetColumn + 1 
 | 
            }, 
 | 
            consumer 
 | 
          }; 
 | 
        }); 
 | 
      })).then(s => { 
 | 
        that._sections = s; 
 | 
        return that; 
 | 
      }); 
 | 
    }); 
 | 
  } 
 | 
  
 | 
  // `__generatedMappings` and `__originalMappings` are arrays that hold the 
 | 
  // parsed mapping coordinates from the source map's "mappings" attribute. They 
 | 
  // are lazily instantiated, accessed via the `_generatedMappings` and 
 | 
  // `_originalMappings` getters respectively, and we only parse the mappings 
 | 
  // and create these arrays once queried for a source location. We jump through 
 | 
  // these hoops because there can be many thousands of mappings, and parsing 
 | 
  // them is expensive, so we only want to do it if we must. 
 | 
  // 
 | 
  // Each object in the arrays is of the form: 
 | 
  // 
 | 
  //     { 
 | 
  //       generatedLine: The line number in the generated code, 
 | 
  //       generatedColumn: The column number in the generated code, 
 | 
  //       source: The path to the original source file that generated this 
 | 
  //               chunk of code, 
 | 
  //       originalLine: The line number in the original source that 
 | 
  //                     corresponds to this chunk of generated code, 
 | 
  //       originalColumn: The column number in the original source that 
 | 
  //                       corresponds to this chunk of generated code, 
 | 
  //       name: The name of the original symbol which generated this chunk of 
 | 
  //             code. 
 | 
  //     } 
 | 
  // 
 | 
  // All properties except for `generatedLine` and `generatedColumn` can be 
 | 
  // `null`. 
 | 
  // 
 | 
  // `_generatedMappings` is ordered by the generated positions. 
 | 
  // 
 | 
  // `_originalMappings` is ordered by the original positions. 
 | 
  get _generatedMappings() { 
 | 
    if (!this.__generatedMappings) { 
 | 
      this._sortGeneratedMappings(); 
 | 
    } 
 | 
  
 | 
    return this.__generatedMappings; 
 | 
  } 
 | 
  
 | 
  get _originalMappings() { 
 | 
    if (!this.__originalMappings) { 
 | 
      this._sortOriginalMappings(); 
 | 
    } 
 | 
  
 | 
    return this.__originalMappings; 
 | 
  } 
 | 
  
 | 
  get _generatedMappingsUnsorted() { 
 | 
    if (!this.__generatedMappingsUnsorted) { 
 | 
      this._parseMappings(this._mappings, this.sourceRoot); 
 | 
    } 
 | 
  
 | 
    return this.__generatedMappingsUnsorted; 
 | 
  } 
 | 
  
 | 
  get _originalMappingsUnsorted() { 
 | 
    if (!this.__originalMappingsUnsorted) { 
 | 
      this._parseMappings(this._mappings, this.sourceRoot); 
 | 
    } 
 | 
  
 | 
    return this.__originalMappingsUnsorted; 
 | 
  } 
 | 
  
 | 
  _sortGeneratedMappings() { 
 | 
    const mappings = this._generatedMappingsUnsorted; 
 | 
    mappings.sort(util.compareByGeneratedPositionsDeflated); 
 | 
    this.__generatedMappings = mappings; 
 | 
  } 
 | 
  
 | 
  _sortOriginalMappings() { 
 | 
    const mappings = this._originalMappingsUnsorted; 
 | 
    mappings.sort(util.compareByOriginalPositions); 
 | 
    this.__originalMappings = mappings; 
 | 
  } 
 | 
  
 | 
  /** 
 | 
   * The list of original sources. 
 | 
   */ 
 | 
  get sources() { 
 | 
    const sources = []; 
 | 
    for (let i = 0; i < this._sections.length; i++) { 
 | 
      for (let j = 0; j < this._sections[i].consumer.sources.length; j++) { 
 | 
        sources.push(this._sections[i].consumer.sources[j]); 
 | 
      } 
 | 
    } 
 | 
    return sources; 
 | 
  } 
 | 
  
 | 
  /** 
 | 
   * Returns the original source, line, and column information for the generated 
 | 
   * source's line and column positions provided. The only argument is an object 
 | 
   * with the following properties: 
 | 
   * 
 | 
   *   - line: The line number in the generated source.  The line number 
 | 
   *     is 1-based. 
 | 
   *   - column: The column number in the generated source.  The column 
 | 
   *     number is 0-based. 
 | 
   * 
 | 
   * and an object is returned with the following properties: 
 | 
   * 
 | 
   *   - source: The original source file, or null. 
 | 
   *   - line: The line number in the original source, or null.  The 
 | 
   *     line number is 1-based. 
 | 
   *   - column: The column number in the original source, or null.  The 
 | 
   *     column number is 0-based. 
 | 
   *   - name: The original identifier, or null. 
 | 
   */ 
 | 
  originalPositionFor(aArgs) { 
 | 
    const needle = { 
 | 
      generatedLine: util.getArg(aArgs, "line"), 
 | 
      generatedColumn: util.getArg(aArgs, "column") 
 | 
    }; 
 | 
  
 | 
    // Find the section containing the generated position we're trying to map 
 | 
    // to an original position. 
 | 
    const sectionIndex = binarySearch.search(needle, this._sections, 
 | 
      function(aNeedle, section) { 
 | 
        const cmp = aNeedle.generatedLine - section.generatedOffset.generatedLine; 
 | 
        if (cmp) { 
 | 
          return cmp; 
 | 
        } 
 | 
  
 | 
        return (aNeedle.generatedColumn - 
 | 
                section.generatedOffset.generatedColumn); 
 | 
      }); 
 | 
    const section = this._sections[sectionIndex]; 
 | 
  
 | 
    if (!section) { 
 | 
      return { 
 | 
        source: null, 
 | 
        line: null, 
 | 
        column: null, 
 | 
        name: null 
 | 
      }; 
 | 
    } 
 | 
  
 | 
    return section.consumer.originalPositionFor({ 
 | 
      line: needle.generatedLine - 
 | 
        (section.generatedOffset.generatedLine - 1), 
 | 
      column: needle.generatedColumn - 
 | 
        (section.generatedOffset.generatedLine === needle.generatedLine 
 | 
         ? section.generatedOffset.generatedColumn - 1 
 | 
         : 0), 
 | 
      bias: aArgs.bias 
 | 
    }); 
 | 
  } 
 | 
  
 | 
  /** 
 | 
   * Return true if we have the source content for every source in the source 
 | 
   * map, false otherwise. 
 | 
   */ 
 | 
  hasContentsOfAllSources() { 
 | 
    return this._sections.every(function(s) { 
 | 
      return s.consumer.hasContentsOfAllSources(); 
 | 
    }); 
 | 
  } 
 | 
  
 | 
  /** 
 | 
   * Returns the original source content. The only argument is the url of the 
 | 
   * original source file. Returns null if no original source content is 
 | 
   * available. 
 | 
   */ 
 | 
  sourceContentFor(aSource, nullOnMissing) { 
 | 
    for (let i = 0; i < this._sections.length; i++) { 
 | 
      const section = this._sections[i]; 
 | 
  
 | 
      const content = section.consumer.sourceContentFor(aSource, true); 
 | 
      if (content) { 
 | 
        return content; 
 | 
      } 
 | 
    } 
 | 
    if (nullOnMissing) { 
 | 
      return null; 
 | 
    } 
 | 
    throw new Error('"' + aSource + '" is not in the SourceMap.'); 
 | 
  } 
 | 
  
 | 
  /** 
 | 
   * Returns the generated line and column information for the original source, 
 | 
   * line, and column positions provided. The only argument is an object with 
 | 
   * the following properties: 
 | 
   * 
 | 
   *   - source: The filename of the original source. 
 | 
   *   - line: The line number in the original source.  The line number 
 | 
   *     is 1-based. 
 | 
   *   - column: The column number in the original source.  The column 
 | 
   *     number is 0-based. 
 | 
   * 
 | 
   * and an object is returned with the following properties: 
 | 
   * 
 | 
   *   - line: The line number in the generated source, or null.  The 
 | 
   *     line number is 1-based. 
 | 
   *   - column: The column number in the generated source, or null. 
 | 
   *     The column number is 0-based. 
 | 
   */ 
 | 
  generatedPositionFor(aArgs) { 
 | 
    for (let i = 0; i < this._sections.length; i++) { 
 | 
      const section = this._sections[i]; 
 | 
  
 | 
      // Only consider this section if the requested source is in the list of 
 | 
      // sources of the consumer. 
 | 
      if (section.consumer._findSourceIndex(util.getArg(aArgs, "source")) === -1) { 
 | 
        continue; 
 | 
      } 
 | 
      const generatedPosition = section.consumer.generatedPositionFor(aArgs); 
 | 
      if (generatedPosition) { 
 | 
        const ret = { 
 | 
          line: generatedPosition.line + 
 | 
            (section.generatedOffset.generatedLine - 1), 
 | 
          column: generatedPosition.column + 
 | 
            (section.generatedOffset.generatedLine === generatedPosition.line 
 | 
             ? section.generatedOffset.generatedColumn - 1 
 | 
             : 0) 
 | 
        }; 
 | 
        return ret; 
 | 
      } 
 | 
    } 
 | 
  
 | 
    return { 
 | 
      line: null, 
 | 
      column: null 
 | 
    }; 
 | 
  } 
 | 
  
 | 
  /** 
 | 
   * Parse the mappings in a string in to a data structure which we can easily 
 | 
   * query (the ordered arrays in the `this.__generatedMappings` and 
 | 
   * `this.__originalMappings` properties). 
 | 
   */ 
 | 
  _parseMappings(aStr, aSourceRoot) { 
 | 
    const generatedMappings = this.__generatedMappingsUnsorted = []; 
 | 
    const originalMappings = this.__originalMappingsUnsorted = []; 
 | 
    for (let i = 0; i < this._sections.length; i++) { 
 | 
      const section = this._sections[i]; 
 | 
  
 | 
      const sectionMappings = []; 
 | 
      section.consumer.eachMapping(m => sectionMappings.push(m)); 
 | 
  
 | 
      for (let j = 0; j < sectionMappings.length; j++) { 
 | 
        const mapping = sectionMappings[j]; 
 | 
  
 | 
        // TODO: test if null is correct here.  The original code used 
 | 
        // `source`, which would actually have gotten used as null because 
 | 
        // var's get hoisted. 
 | 
        // See: https://github.com/mozilla/source-map/issues/333 
 | 
        let source = util.computeSourceURL(section.consumer.sourceRoot, null, this._sourceMapURL); 
 | 
        this._sources.add(source); 
 | 
        source = this._sources.indexOf(source); 
 | 
  
 | 
        let name = null; 
 | 
        if (mapping.name) { 
 | 
          this._names.add(mapping.name); 
 | 
          name = this._names.indexOf(mapping.name); 
 | 
        } 
 | 
  
 | 
        // The mappings coming from the consumer for the section have 
 | 
        // generated positions relative to the start of the section, so we 
 | 
        // need to offset them to be relative to the start of the concatenated 
 | 
        // generated file. 
 | 
        const adjustedMapping = { 
 | 
          source, 
 | 
          generatedLine: mapping.generatedLine + 
 | 
            (section.generatedOffset.generatedLine - 1), 
 | 
          generatedColumn: mapping.generatedColumn + 
 | 
            (section.generatedOffset.generatedLine === mapping.generatedLine 
 | 
            ? section.generatedOffset.generatedColumn - 1 
 | 
            : 0), 
 | 
          originalLine: mapping.originalLine, 
 | 
          originalColumn: mapping.originalColumn, 
 | 
          name 
 | 
        }; 
 | 
  
 | 
        generatedMappings.push(adjustedMapping); 
 | 
        if (typeof adjustedMapping.originalLine === "number") { 
 | 
          originalMappings.push(adjustedMapping); 
 | 
        } 
 | 
      } 
 | 
    } 
 | 
  } 
 | 
  
 | 
  eachMapping(aCallback, aContext, aOrder) { 
 | 
    const context = aContext || null; 
 | 
    const order = aOrder || SourceMapConsumer.GENERATED_ORDER; 
 | 
  
 | 
    let mappings; 
 | 
    switch (order) { 
 | 
    case SourceMapConsumer.GENERATED_ORDER: 
 | 
      mappings = this._generatedMappings; 
 | 
      break; 
 | 
    case SourceMapConsumer.ORIGINAL_ORDER: 
 | 
      mappings = this._originalMappings; 
 | 
      break; 
 | 
    default: 
 | 
      throw new Error("Unknown order of iteration."); 
 | 
    } 
 | 
  
 | 
    const sourceRoot = this.sourceRoot; 
 | 
    mappings.map(function(mapping) { 
 | 
      let source = null; 
 | 
      if (mapping.source !== null) { 
 | 
        source = this._sources.at(mapping.source); 
 | 
        source = util.computeSourceURL(sourceRoot, source, this._sourceMapURL); 
 | 
      } 
 | 
      return { 
 | 
        source, 
 | 
        generatedLine: mapping.generatedLine, 
 | 
        generatedColumn: mapping.generatedColumn, 
 | 
        originalLine: mapping.originalLine, 
 | 
        originalColumn: mapping.originalColumn, 
 | 
        name: mapping.name === null ? null : this._names.at(mapping.name) 
 | 
      }; 
 | 
    }, this).forEach(aCallback, context); 
 | 
  } 
 | 
  
 | 
  /** 
 | 
   * Find the mapping that best matches the hypothetical "needle" mapping that 
 | 
   * we are searching for in the given "haystack" of mappings. 
 | 
   */ 
 | 
  _findMapping(aNeedle, aMappings, aLineName, 
 | 
              aColumnName, aComparator, aBias) { 
 | 
    // To return the position we are searching for, we must first find the 
 | 
    // mapping for the given position and then return the opposite position it 
 | 
    // points to. Because the mappings are sorted, we can use binary search to 
 | 
    // find the best mapping. 
 | 
  
 | 
    if (aNeedle[aLineName] <= 0) { 
 | 
      throw new TypeError("Line must be greater than or equal to 1, got " 
 | 
                          + aNeedle[aLineName]); 
 | 
    } 
 | 
    if (aNeedle[aColumnName] < 0) { 
 | 
      throw new TypeError("Column must be greater than or equal to 0, got " 
 | 
                          + aNeedle[aColumnName]); 
 | 
    } 
 | 
  
 | 
    return binarySearch.search(aNeedle, aMappings, aComparator, aBias); 
 | 
  } 
 | 
  
 | 
  allGeneratedPositionsFor(aArgs) { 
 | 
    const line = util.getArg(aArgs, "line"); 
 | 
  
 | 
    // When there is no exact match, BasicSourceMapConsumer.prototype._findMapping 
 | 
    // returns the index of the closest mapping less than the needle. By 
 | 
    // setting needle.originalColumn to 0, we thus find the last mapping for 
 | 
    // the given line, provided such a mapping exists. 
 | 
    const needle = { 
 | 
      source: util.getArg(aArgs, "source"), 
 | 
      originalLine: line, 
 | 
      originalColumn: util.getArg(aArgs, "column", 0) 
 | 
    }; 
 | 
  
 | 
    needle.source = this._findSourceIndex(needle.source); 
 | 
    if (needle.source < 0) { 
 | 
      return []; 
 | 
    } 
 | 
  
 | 
    if (needle.originalLine < 1) { 
 | 
      throw new Error("Line numbers must be >= 1"); 
 | 
    } 
 | 
  
 | 
    if (needle.originalColumn < 0) { 
 | 
      throw new Error("Column numbers must be >= 0"); 
 | 
    } 
 | 
  
 | 
    const mappings = []; 
 | 
  
 | 
    let index = this._findMapping(needle, 
 | 
                                  this._originalMappings, 
 | 
                                  "originalLine", 
 | 
                                  "originalColumn", 
 | 
                                  util.compareByOriginalPositions, 
 | 
                                  binarySearch.LEAST_UPPER_BOUND); 
 | 
    if (index >= 0) { 
 | 
      let mapping = this._originalMappings[index]; 
 | 
  
 | 
      if (aArgs.column === undefined) { 
 | 
        const originalLine = mapping.originalLine; 
 | 
  
 | 
        // Iterate until either we run out of mappings, or we run into 
 | 
        // a mapping for a different line than the one we found. Since 
 | 
        // mappings are sorted, this is guaranteed to find all mappings for 
 | 
        // the line we found. 
 | 
        while (mapping && mapping.originalLine === originalLine) { 
 | 
          let lastColumn = mapping.lastGeneratedColumn; 
 | 
          if (this._computedColumnSpans && lastColumn === null) { 
 | 
            lastColumn = Infinity; 
 | 
          } 
 | 
          mappings.push({ 
 | 
            line: util.getArg(mapping, "generatedLine", null), 
 | 
            column: util.getArg(mapping, "generatedColumn", null), 
 | 
            lastColumn, 
 | 
          }); 
 | 
  
 | 
          mapping = this._originalMappings[++index]; 
 | 
        } 
 | 
      } else { 
 | 
        const originalColumn = mapping.originalColumn; 
 | 
  
 | 
        // Iterate until either we run out of mappings, or we run into 
 | 
        // a mapping for a different line than the one we were searching for. 
 | 
        // Since mappings are sorted, this is guaranteed to find all mappings for 
 | 
        // the line we are searching for. 
 | 
        while (mapping && 
 | 
               mapping.originalLine === line && 
 | 
               mapping.originalColumn == originalColumn) { 
 | 
          let lastColumn = mapping.lastGeneratedColumn; 
 | 
          if (this._computedColumnSpans && lastColumn === null) { 
 | 
            lastColumn = Infinity; 
 | 
          } 
 | 
          mappings.push({ 
 | 
            line: util.getArg(mapping, "generatedLine", null), 
 | 
            column: util.getArg(mapping, "generatedColumn", null), 
 | 
            lastColumn, 
 | 
          }); 
 | 
  
 | 
          mapping = this._originalMappings[++index]; 
 | 
        } 
 | 
      } 
 | 
    } 
 | 
  
 | 
    return mappings; 
 | 
  } 
 | 
  
 | 
  destroy() { 
 | 
    for (let i = 0; i < this._sections.length; i++) { 
 | 
      this._sections[i].consumer.destroy(); 
 | 
    } 
 | 
  } 
 | 
} 
 | 
exports.IndexedSourceMapConsumer = IndexedSourceMapConsumer; 
 | 
  
 | 
/* 
 | 
 * Cheat to get around inter-twingled classes.  `factory()` can be at the end 
 | 
 * where it has access to non-hoisted classes, but it gets hoisted itself. 
 | 
 */ 
 | 
function _factory(aSourceMap, aSourceMapURL) { 
 | 
  let sourceMap = aSourceMap; 
 | 
  if (typeof aSourceMap === "string") { 
 | 
    sourceMap = util.parseSourceMapInput(aSourceMap); 
 | 
  } 
 | 
  
 | 
  const consumer = sourceMap.sections != null 
 | 
      ? new IndexedSourceMapConsumer(sourceMap, aSourceMapURL) 
 | 
      : new BasicSourceMapConsumer(sourceMap, aSourceMapURL); 
 | 
  return Promise.resolve(consumer); 
 | 
} 
 | 
  
 | 
function _factoryBSM(aSourceMap, aSourceMapURL) { 
 | 
  return BasicSourceMapConsumer.fromSourceMap(aSourceMap, aSourceMapURL); 
 | 
} 
 |