diff options
| author | littleblack111 <littleblack11111@gmail.com> | 2024-08-30 17:21:18 +0800 |
|---|---|---|
| committer | littleblack111 <littleblack11111@gmail.com> | 2024-08-30 17:21:18 +0800 |
| commit | efbc2ffe6a1ee5ec38a4396305561d6515d0943e (patch) | |
| tree | 2b4c94f18f2c792dfda813050755d5c0273fae22 /node_modules/source-map/lib | |
| parent | 43acceb75957c880a5ba5a31aae221394a36d5f6 (diff) | |
node fixes, updates
Diffstat (limited to 'node_modules/source-map/lib')
| -rw-r--r-- | node_modules/source-map/lib/array-set.js | 159 | ||||
| -rw-r--r-- | node_modules/source-map/lib/base64-vlq.js | 51 | ||||
| -rw-r--r-- | node_modules/source-map/lib/base64.js | 53 | ||||
| -rw-r--r-- | node_modules/source-map/lib/binary-search.js | 34 | ||||
| -rw-r--r-- | node_modules/source-map/lib/mapping-list.js | 99 | ||||
| -rw-r--r-- | node_modules/source-map/lib/mappings.wasm | bin | 0 -> 48693 bytes | |||
| -rw-r--r-- | node_modules/source-map/lib/quick-sort.js | 114 | ||||
| -rw-r--r-- | node_modules/source-map/lib/read-wasm.js | 49 | ||||
| -rw-r--r-- | node_modules/source-map/lib/source-map-consumer.js | 1672 | ||||
| -rw-r--r-- | node_modules/source-map/lib/source-map-generator.js | 326 | ||||
| -rw-r--r-- | node_modules/source-map/lib/source-node.js | 479 | ||||
| -rw-r--r-- | node_modules/source-map/lib/util.js | 160 | ||||
| -rw-r--r-- | node_modules/source-map/lib/wasm.js | 107 |
13 files changed, 1686 insertions, 1617 deletions
diff --git a/node_modules/source-map/lib/array-set.js b/node_modules/source-map/lib/array-set.js index fbd5c81c..40171b9a 100644 --- a/node_modules/source-map/lib/array-set.js +++ b/node_modules/source-map/lib/array-set.js @@ -5,117 +5,96 @@ * http://opensource.org/licenses/BSD-3-Clause */ -var util = require('./util'); -var has = Object.prototype.hasOwnProperty; -var hasNativeMap = typeof Map !== "undefined"; - /** * A data structure which is a combination of an array and a set. Adding a new * member is O(1), testing for membership is O(1), and finding the index of an * element is O(1). Removing elements from the set is not supported. Only * strings are supported for membership. */ -function ArraySet() { - this._array = []; - this._set = hasNativeMap ? new Map() : Object.create(null); -} - -/** - * Static method for creating ArraySet instances from an existing array. - */ -ArraySet.fromArray = function ArraySet_fromArray(aArray, aAllowDuplicates) { - var set = new ArraySet(); - for (var i = 0, len = aArray.length; i < len; i++) { - set.add(aArray[i], aAllowDuplicates); +class ArraySet { + constructor() { + this._array = []; + this._set = new Map(); } - return set; -}; -/** - * Return how many unique items are in this ArraySet. If duplicates have been - * added, than those do not count towards the size. - * - * @returns Number - */ -ArraySet.prototype.size = function ArraySet_size() { - return hasNativeMap ? this._set.size : Object.getOwnPropertyNames(this._set).length; -}; + /** + * Static method for creating ArraySet instances from an existing array. + */ + static fromArray(aArray, aAllowDuplicates) { + const set = new ArraySet(); + for (let i = 0, len = aArray.length; i < len; i++) { + set.add(aArray[i], aAllowDuplicates); + } + return set; + } -/** - * Add the given string to this set. - * - * @param String aStr - */ -ArraySet.prototype.add = function ArraySet_add(aStr, aAllowDuplicates) { - var sStr = hasNativeMap ? aStr : util.toSetString(aStr); - var isDuplicate = hasNativeMap ? this.has(aStr) : has.call(this._set, sStr); - var idx = this._array.length; - if (!isDuplicate || aAllowDuplicates) { - this._array.push(aStr); + /** + * Return how many unique items are in this ArraySet. If duplicates have been + * added, than those do not count towards the size. + * + * @returns Number + */ + size() { + return this._set.size; } - if (!isDuplicate) { - if (hasNativeMap) { + + /** + * Add the given string to this set. + * + * @param String aStr + */ + add(aStr, aAllowDuplicates) { + const isDuplicate = this.has(aStr); + const idx = this._array.length; + if (!isDuplicate || aAllowDuplicates) { + this._array.push(aStr); + } + if (!isDuplicate) { this._set.set(aStr, idx); - } else { - this._set[sStr] = idx; } } -}; -/** - * Is the given string a member of this set? - * - * @param String aStr - */ -ArraySet.prototype.has = function ArraySet_has(aStr) { - if (hasNativeMap) { - return this._set.has(aStr); - } else { - var sStr = util.toSetString(aStr); - return has.call(this._set, sStr); + /** + * Is the given string a member of this set? + * + * @param String aStr + */ + has(aStr) { + return this._set.has(aStr); } -}; -/** - * What is the index of the given string in the array? - * - * @param String aStr - */ -ArraySet.prototype.indexOf = function ArraySet_indexOf(aStr) { - if (hasNativeMap) { - var idx = this._set.get(aStr); + /** + * What is the index of the given string in the array? + * + * @param String aStr + */ + indexOf(aStr) { + const idx = this._set.get(aStr); if (idx >= 0) { return idx; } - } else { - var sStr = util.toSetString(aStr); - if (has.call(this._set, sStr)) { - return this._set[sStr]; - } + throw new Error('"' + aStr + '" is not in the set.'); } - throw new Error('"' + aStr + '" is not in the set.'); -}; - -/** - * What is the element at the given index? - * - * @param Number aIdx - */ -ArraySet.prototype.at = function ArraySet_at(aIdx) { - if (aIdx >= 0 && aIdx < this._array.length) { - return this._array[aIdx]; + /** + * What is the element at the given index? + * + * @param Number aIdx + */ + at(aIdx) { + if (aIdx >= 0 && aIdx < this._array.length) { + return this._array[aIdx]; + } + throw new Error("No element indexed by " + aIdx); } - throw new Error('No element indexed by ' + aIdx); -}; - -/** - * Returns the array representation of this set (which has the proper indices - * indicated by indexOf). Note that this is a copy of the internal array used - * for storing the members so that no one can mess with internal state. - */ -ArraySet.prototype.toArray = function ArraySet_toArray() { - return this._array.slice(); -}; + /** + * Returns the array representation of this set (which has the proper indices + * indicated by indexOf). Note that this is a copy of the internal array used + * for storing the members so that no one can mess with internal state. + */ + toArray() { + return this._array.slice(); + } +} exports.ArraySet = ArraySet; diff --git a/node_modules/source-map/lib/base64-vlq.js b/node_modules/source-map/lib/base64-vlq.js index 612b4040..fc1049c8 100644 --- a/node_modules/source-map/lib/base64-vlq.js +++ b/node_modules/source-map/lib/base64-vlq.js @@ -35,7 +35,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -var base64 = require('./base64'); +const base64 = require("./base64"); // A single base 64 digit can contain 6 bits of data. For the base 64 variable // length quantities we use in the source map spec, the first bit is the sign, @@ -49,16 +49,16 @@ var base64 = require('./base64'); // V V // 101011 -var VLQ_BASE_SHIFT = 5; +const VLQ_BASE_SHIFT = 5; // binary: 100000 -var VLQ_BASE = 1 << VLQ_BASE_SHIFT; +const VLQ_BASE = 1 << VLQ_BASE_SHIFT; // binary: 011111 -var VLQ_BASE_MASK = VLQ_BASE - 1; +const VLQ_BASE_MASK = VLQ_BASE - 1; // binary: 100000 -var VLQ_CONTINUATION_BIT = VLQ_BASE; +const VLQ_CONTINUATION_BIT = VLQ_BASE; /** * Converts from a two-complement value to a value where the sign bit is @@ -78,9 +78,10 @@ function toVLQSigned(aValue) { * 2 (10 binary) becomes 1, 3 (11 binary) becomes -1 * 4 (100 binary) becomes 2, 5 (101 binary) becomes -2 */ +// eslint-disable-next-line no-unused-vars function fromVLQSigned(aValue) { - var isNegative = (aValue & 1) === 1; - var shifted = aValue >> 1; + const isNegative = (aValue & 1) === 1; + const shifted = aValue >> 1; return isNegative ? -shifted : shifted; @@ -90,10 +91,10 @@ function fromVLQSigned(aValue) { * Returns the base 64 VLQ encoded value. */ exports.encode = function base64VLQ_encode(aValue) { - var encoded = ""; - var digit; + let encoded = ""; + let digit; - var vlq = toVLQSigned(aValue); + let vlq = toVLQSigned(aValue); do { digit = vlq & VLQ_BASE_MASK; @@ -108,33 +109,3 @@ exports.encode = function base64VLQ_encode(aValue) { return encoded; }; - -/** - * Decodes the next base 64 VLQ value from the given string and returns the - * value and the rest of the string via the out parameter. - */ -exports.decode = function base64VLQ_decode(aStr, aIndex, aOutParam) { - var strLen = aStr.length; - var result = 0; - var shift = 0; - var continuation, digit; - - do { - if (aIndex >= strLen) { - throw new Error("Expected more digits in base 64 VLQ value."); - } - - digit = base64.decode(aStr.charCodeAt(aIndex++)); - if (digit === -1) { - throw new Error("Invalid base64 digit: " + aStr.charAt(aIndex - 1)); - } - - continuation = !!(digit & VLQ_CONTINUATION_BIT); - digit &= VLQ_BASE_MASK; - result = result + (digit << shift); - shift += VLQ_BASE_SHIFT; - } while (continuation); - - aOutParam.value = fromVLQSigned(result); - aOutParam.rest = aIndex; -}; diff --git a/node_modules/source-map/lib/base64.js b/node_modules/source-map/lib/base64.js index 8aa86b30..b9ca3199 100644 --- a/node_modules/source-map/lib/base64.js +++ b/node_modules/source-map/lib/base64.js @@ -5,63 +5,14 @@ * http://opensource.org/licenses/BSD-3-Clause */ -var intToCharMap = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split(''); +const intToCharMap = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split(""); /** * Encode an integer in the range of 0 to 63 to a single base 64 digit. */ -exports.encode = function (number) { +exports.encode = function(number) { if (0 <= number && number < intToCharMap.length) { return intToCharMap[number]; } throw new TypeError("Must be between 0 and 63: " + number); }; - -/** - * Decode a single base 64 character code digit to an integer. Returns -1 on - * failure. - */ -exports.decode = function (charCode) { - var bigA = 65; // 'A' - var bigZ = 90; // 'Z' - - var littleA = 97; // 'a' - var littleZ = 122; // 'z' - - var zero = 48; // '0' - var nine = 57; // '9' - - var plus = 43; // '+' - var slash = 47; // '/' - - var littleOffset = 26; - var numberOffset = 52; - - // 0 - 25: ABCDEFGHIJKLMNOPQRSTUVWXYZ - if (bigA <= charCode && charCode <= bigZ) { - return (charCode - bigA); - } - - // 26 - 51: abcdefghijklmnopqrstuvwxyz - if (littleA <= charCode && charCode <= littleZ) { - return (charCode - littleA + littleOffset); - } - - // 52 - 61: 0123456789 - if (zero <= charCode && charCode <= nine) { - return (charCode - zero + numberOffset); - } - - // 62: + - if (charCode == plus) { - return 62; - } - - // 63: / - if (charCode == slash) { - return 63; - } - - // Invalid base64 digit. - return -1; -}; diff --git a/node_modules/source-map/lib/binary-search.js b/node_modules/source-map/lib/binary-search.js index 010ac941..d6f898ea 100644 --- a/node_modules/source-map/lib/binary-search.js +++ b/node_modules/source-map/lib/binary-search.js @@ -31,13 +31,12 @@ function recursiveSearch(aLow, aHigh, aNeedle, aHaystack, aCompare, aBias) { // // 3. We did not find the exact element, and there is no next-closest // element than the one we are searching for, so we return -1. - var mid = Math.floor((aHigh - aLow) / 2) + aLow; - var cmp = aCompare(aNeedle, aHaystack[mid], true); + const mid = Math.floor((aHigh - aLow) / 2) + aLow; + const cmp = aCompare(aNeedle, aHaystack[mid], true); if (cmp === 0) { // Found the element we are looking for. return mid; - } - else if (cmp > 0) { + } else if (cmp > 0) { // Our needle is greater than aHaystack[mid]. if (aHigh - mid > 1) { // The element is in the upper half. @@ -48,24 +47,21 @@ function recursiveSearch(aLow, aHigh, aNeedle, aHaystack, aCompare, aBias) { // we are in termination case (3) or (2) and return the appropriate thing. if (aBias == exports.LEAST_UPPER_BOUND) { return aHigh < aHaystack.length ? aHigh : -1; - } else { - return mid; } + return mid; } - else { - // Our needle is less than aHaystack[mid]. - if (mid - aLow > 1) { - // The element is in the lower half. - return recursiveSearch(aLow, mid, aNeedle, aHaystack, aCompare, aBias); - } - // we are in termination case (3) or (2) and return the appropriate thing. - if (aBias == exports.LEAST_UPPER_BOUND) { - return mid; - } else { - return aLow < 0 ? -1 : aLow; - } + // Our needle is less than aHaystack[mid]. + if (mid - aLow > 1) { + // The element is in the lower half. + return recursiveSearch(aLow, mid, aNeedle, aHaystack, aCompare, aBias); + } + + // we are in termination case (3) or (2) and return the appropriate thing. + if (aBias == exports.LEAST_UPPER_BOUND) { + return mid; } + return aLow < 0 ? -1 : aLow; } /** @@ -91,7 +87,7 @@ exports.search = function search(aNeedle, aHaystack, aCompare, aBias) { return -1; } - var index = recursiveSearch(-1, aHaystack.length, aNeedle, aHaystack, + let index = recursiveSearch(-1, aHaystack.length, aNeedle, aHaystack, aCompare, aBias || exports.GREATEST_LOWER_BOUND); if (index < 0) { return -1; diff --git a/node_modules/source-map/lib/mapping-list.js b/node_modules/source-map/lib/mapping-list.js index 06d1274a..70568610 100644 --- a/node_modules/source-map/lib/mapping-list.js +++ b/node_modules/source-map/lib/mapping-list.js @@ -5,7 +5,7 @@ * http://opensource.org/licenses/BSD-3-Clause */ -var util = require('./util'); +const util = require("./util"); /** * Determine whether mappingB is after mappingA with respect to generated @@ -13,67 +13,68 @@ var util = require('./util'); */ function generatedPositionAfter(mappingA, mappingB) { // Optimized for most common case - var lineA = mappingA.generatedLine; - var lineB = mappingB.generatedLine; - var columnA = mappingA.generatedColumn; - var columnB = mappingB.generatedColumn; + const lineA = mappingA.generatedLine; + const lineB = mappingB.generatedLine; + const columnA = mappingA.generatedColumn; + const columnB = mappingB.generatedColumn; return lineB > lineA || lineB == lineA && columnB >= columnA || util.compareByGeneratedPositionsInflated(mappingA, mappingB) <= 0; } /** * A data structure to provide a sorted view of accumulated mappings in a - * performance conscious manner. It trades a neglibable overhead in general + * performance conscious manner. It trades a negligible overhead in general * case for a large speedup in case of mappings being added in order. */ -function MappingList() { - this._array = []; - this._sorted = true; - // Serves as infimum - this._last = {generatedLine: -1, generatedColumn: 0}; -} +class MappingList { + constructor() { + this._array = []; + this._sorted = true; + // Serves as infimum + this._last = {generatedLine: -1, generatedColumn: 0}; + } -/** - * Iterate through internal items. This method takes the same arguments that - * `Array.prototype.forEach` takes. - * - * NOTE: The order of the mappings is NOT guaranteed. - */ -MappingList.prototype.unsortedForEach = - function MappingList_forEach(aCallback, aThisArg) { + /** + * Iterate through internal items. This method takes the same arguments that + * `Array.prototype.forEach` takes. + * + * NOTE: The order of the mappings is NOT guaranteed. + */ + unsortedForEach(aCallback, aThisArg) { this._array.forEach(aCallback, aThisArg); - }; + } -/** - * Add the given source mapping. - * - * @param Object aMapping - */ -MappingList.prototype.add = function MappingList_add(aMapping) { - if (generatedPositionAfter(this._last, aMapping)) { - this._last = aMapping; - this._array.push(aMapping); - } else { - this._sorted = false; - this._array.push(aMapping); + /** + * Add the given source mapping. + * + * @param Object aMapping + */ + add(aMapping) { + if (generatedPositionAfter(this._last, aMapping)) { + this._last = aMapping; + this._array.push(aMapping); + } else { + this._sorted = false; + this._array.push(aMapping); + } } -}; -/** - * Returns the flat, sorted array of mappings. The mappings are sorted by - * generated position. - * - * WARNING: This method returns internal data without copying, for - * performance. The return value must NOT be mutated, and should be treated as - * an immutable borrow. If you want to take ownership, you must make your own - * copy. - */ -MappingList.prototype.toArray = function MappingList_toArray() { - if (!this._sorted) { - this._array.sort(util.compareByGeneratedPositionsInflated); - this._sorted = true; + /** + * Returns the flat, sorted array of mappings. The mappings are sorted by + * generated position. + * + * WARNING: This method returns internal data without copying, for + * performance. The return value must NOT be mutated, and should be treated as + * an immutable borrow. If you want to take ownership, you must make your own + * copy. + */ + toArray() { + if (!this._sorted) { + this._array.sort(util.compareByGeneratedPositionsInflated); + this._sorted = true; + } + return this._array; } - return this._array; -}; +} exports.MappingList = MappingList; diff --git a/node_modules/source-map/lib/mappings.wasm b/node_modules/source-map/lib/mappings.wasm Binary files differnew file mode 100644 index 00000000..35153707 --- /dev/null +++ b/node_modules/source-map/lib/mappings.wasm diff --git a/node_modules/source-map/lib/quick-sort.js b/node_modules/source-map/lib/quick-sort.js deleted file mode 100644 index 6a7caadb..00000000 --- a/node_modules/source-map/lib/quick-sort.js +++ /dev/null @@ -1,114 +0,0 @@ -/* -*- 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 - */ - -// It turns out that some (most?) JavaScript engines don't self-host -// `Array.prototype.sort`. This makes sense because C++ will likely remain -// faster than JS when doing raw CPU-intensive sorting. However, when using a -// custom comparator function, calling back and forth between the VM's C++ and -// JIT'd JS is rather slow *and* loses JIT type information, resulting in -// worse generated code for the comparator function than would be optimal. In -// fact, when sorting with a comparator, these costs outweigh the benefits of -// sorting in C++. By using our own JS-implemented Quick Sort (below), we get -// a ~3500ms mean speed-up in `bench/bench.html`. - -/** - * Swap the elements indexed by `x` and `y` in the array `ary`. - * - * @param {Array} ary - * The array. - * @param {Number} x - * The index of the first item. - * @param {Number} y - * The index of the second item. - */ -function swap(ary, x, y) { - var temp = ary[x]; - ary[x] = ary[y]; - ary[y] = temp; -} - -/** - * Returns a random integer within the range `low .. high` inclusive. - * - * @param {Number} low - * The lower bound on the range. - * @param {Number} high - * The upper bound on the range. - */ -function randomIntInRange(low, high) { - return Math.round(low + (Math.random() * (high - low))); -} - -/** - * The Quick Sort algorithm. - * - * @param {Array} ary - * An array to sort. - * @param {function} comparator - * Function to use to compare two items. - * @param {Number} p - * Start index of the array - * @param {Number} r - * End index of the array - */ -function doQuickSort(ary, comparator, p, r) { - // If our lower bound is less than our upper bound, we (1) partition the - // array into two pieces and (2) recurse on each half. If it is not, this is - // the empty array and our base case. - - if (p < r) { - // (1) Partitioning. - // - // The partitioning chooses a pivot between `p` and `r` and moves all - // elements that are less than or equal to the pivot to the before it, and - // all the elements that are greater than it after it. The effect is that - // once partition is done, the pivot is in the exact place it will be when - // the array is put in sorted order, and it will not need to be moved - // again. This runs in O(n) time. - - // Always choose a random pivot so that an input array which is reverse - // sorted does not cause O(n^2) running time. - var pivotIndex = randomIntInRange(p, r); - var i = p - 1; - - swap(ary, pivotIndex, r); - var pivot = ary[r]; - - // Immediately after `j` is incremented in this loop, the following hold - // true: - // - // * Every element in `ary[p .. i]` is less than or equal to the pivot. - // - // * Every element in `ary[i+1 .. j-1]` is greater than the pivot. - for (var j = p; j < r; j++) { - if (comparator(ary[j], pivot) <= 0) { - i += 1; - swap(ary, i, j); - } - } - - swap(ary, i + 1, j); - var q = i + 1; - - // (2) Recurse on each half. - - doQuickSort(ary, comparator, p, q - 1); - doQuickSort(ary, comparator, q + 1, r); - } -} - -/** - * Sort the given array in-place with the given comparator function. - * - * @param {Array} ary - * An array to sort. - * @param {function} comparator - * Function to use to compare two items. - */ -exports.quickSort = function (ary, comparator) { - doQuickSort(ary, comparator, 0, ary.length - 1); -}; diff --git a/node_modules/source-map/lib/read-wasm.js b/node_modules/source-map/lib/read-wasm.js new file mode 100644 index 00000000..e81c1772 --- /dev/null +++ b/node_modules/source-map/lib/read-wasm.js @@ -0,0 +1,49 @@ +/* Determine browser vs node environment by testing the default top level context. Solution courtesy of: https://stackoverflow.com/questions/17575790/environment-detection-node-js-or-browser */ +const isBrowserEnvironment = (function() { + // eslint-disable-next-line no-undef + return (typeof window !== "undefined") && (this === window); +}).call(); + +if (isBrowserEnvironment) { + // Web version of reading a wasm file into an array buffer. + + let mappingsWasm = null; + + module.exports = function readWasm() { + if (typeof mappingsWasm === "string") { + return fetch(mappingsWasm) + .then(response => response.arrayBuffer()); + } + if (mappingsWasm instanceof ArrayBuffer) { + return Promise.resolve(mappingsWasm); + } + throw new Error("You must provide the string URL or ArrayBuffer contents " + + "of lib/mappings.wasm by calling " + + "SourceMapConsumer.initialize({ 'lib/mappings.wasm': ... }) " + + "before using SourceMapConsumer"); + }; + + module.exports.initialize = input => mappingsWasm = input; +} else { + // Node version of reading a wasm file into an array buffer. + const fs = require("fs"); + const path = require("path"); + + module.exports = function readWasm() { + return new Promise((resolve, reject) => { + const wasmPath = path.join(__dirname, "mappings.wasm"); + fs.readFile(wasmPath, null, (error, data) => { + if (error) { + reject(error); + return; + } + + resolve(data.buffer); + }); + }); + }; + + module.exports.initialize = _ => { + console.debug("SourceMapConsumer.initialize is a no-op when running in node.js"); + }; +} diff --git a/node_modules/source-map/lib/source-map-consumer.js b/node_modules/source-map/lib/source-map-consumer.js index 7b99d1da..9aaf92f5 100644 --- a/node_modules/source-map/lib/source-map-consumer.js +++ b/node_modules/source-map/lib/source-map-consumer.js @@ -5,250 +5,144 @@ * http://opensource.org/licenses/BSD-3-Clause */ -var util = require('./util'); -var binarySearch = require('./binary-search'); -var ArraySet = require('./array-set').ArraySet; -var base64VLQ = require('./base64-vlq'); -var quickSort = require('./quick-sort').quickSort; - -function SourceMapConsumer(aSourceMap, aSourceMapURL) { - var sourceMap = aSourceMap; - if (typeof aSourceMap === 'string') { - sourceMap = util.parseSourceMapInput(aSourceMap); - } +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 sourceMap.sections != null - ? new IndexedSourceMapConsumer(sourceMap, aSourceMapURL) - : new BasicSourceMapConsumer(sourceMap, aSourceMapURL); -} + return _factory(aSourceMap, aSourceMapURL); + } -SourceMapConsumer.fromSourceMap = function(aSourceMap, aSourceMapURL) { - return BasicSourceMapConsumer.fromSourceMap(aSourceMap, aSourceMapURL); -} + static initialize(opts) { + readWasm.initialize(opts["lib/mappings.wasm"]); + } -/** - * The version of the source mapping spec that we are consuming. - */ -SourceMapConsumer.prototype._version = 3; + static fromSourceMap(aSourceMap, aSourceMapURL) { + return _factoryBSM(aSourceMap, aSourceMapURL); + } -// `__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. - -SourceMapConsumer.prototype.__generatedMappings = null; -Object.defineProperty(SourceMapConsumer.prototype, '_generatedMappings', { - configurable: true, - enumerable: true, - get: function () { - if (!this.__generatedMappings) { - this._parseMappings(this._mappings, this.sourceRoot); + /** + * 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(); } + } - return this.__generatedMappings; + /** + * 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"); } -}); -SourceMapConsumer.prototype.__originalMappings = null; -Object.defineProperty(SourceMapConsumer.prototype, '_originalMappings', { - configurable: true, - enumerable: true, - get: function () { - if (!this.__originalMappings) { - this._parseMappings(this._mappings, this.sourceRoot); - } + /** + * 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"); + } - return this.__originalMappings; + /** + * 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"); } -}); -SourceMapConsumer.prototype._charIsMappingSeparator = - function SourceMapConsumer_charIsMappingSeparator(aStr, index) { - var c = aStr.charAt(index); - return c === ";" || c === ","; - }; + destroy() { + throw new Error("Subclasses must implement 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). + * The version of the source mapping spec that we are consuming. */ -SourceMapConsumer.prototype._parseMappings = - function SourceMapConsumer_parseMappings(aStr, aSourceRoot) { - throw new Error("Subclasses must implement _parseMappings"); - }; - +SourceMapConsumer.prototype._version = 3; SourceMapConsumer.GENERATED_ORDER = 1; SourceMapConsumer.ORIGINAL_ORDER = 2; SourceMapConsumer.GREATEST_LOWER_BOUND = 1; SourceMapConsumer.LEAST_UPPER_BOUND = 2; -/** - * 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`. - */ -SourceMapConsumer.prototype.eachMapping = - function SourceMapConsumer_eachMapping(aCallback, aContext, aOrder) { - var context = aContext || null; - var order = aOrder || SourceMapConsumer.GENERATED_ORDER; - - var 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."); - } - - var sourceRoot = this.sourceRoot; - mappings.map(function (mapping) { - var source = mapping.source === null ? null : this._sources.at(mapping.source); - source = util.computeSourceURL(sourceRoot, source, this._sourceMapURL); - return { - source: 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); - }; - -/** - * 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. - */ -SourceMapConsumer.prototype.allGeneratedPositionsFor = - function SourceMapConsumer_allGeneratedPositionsFor(aArgs) { - var 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. - var 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 []; - } - - var mappings = []; - - var index = this._findMapping(needle, - this._originalMappings, - "originalLine", - "originalColumn", - util.compareByOriginalPositions, - binarySearch.LEAST_UPPER_BOUND); - if (index >= 0) { - var mapping = this._originalMappings[index]; - - if (aArgs.column === undefined) { - var 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) { - mappings.push({ - line: util.getArg(mapping, 'generatedLine', null), - column: util.getArg(mapping, 'generatedColumn', null), - lastColumn: util.getArg(mapping, 'lastGeneratedColumn', null) - }); - - mapping = this._originalMappings[++index]; - } - } else { - var 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) { - mappings.push({ - line: util.getArg(mapping, 'generatedLine', null), - column: util.getArg(mapping, 'generatedColumn', null), - lastColumn: util.getArg(mapping, 'lastGeneratedColumn', null) - }); - - mapping = this._originalMappings[++index]; - } - } - } - - return mappings; - }; - exports.SourceMapConsumer = SourceMapConsumer; /** @@ -262,7 +156,7 @@ exports.SourceMapConsumer = SourceMapConsumer; * * - 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 referrenced by individual mappings. + * - 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. @@ -285,398 +179,342 @@ exports.SourceMapConsumer = SourceMapConsumer; * * [0]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit?pli=1# */ -function BasicSourceMapConsumer(aSourceMap, aSourceMapURL) { - var sourceMap = aSourceMap; - if (typeof aSourceMap === 'string') { - sourceMap = util.parseSourceMapInput(aSourceMap); - } +class BasicSourceMapConsumer extends SourceMapConsumer { + constructor(aSourceMap, aSourceMapURL) { + return super(INTERNAL).then(that => { + let sourceMap = aSourceMap; + if (typeof aSourceMap === "string") { + sourceMap = util.parseSourceMapInput(aSourceMap); + } - var version = util.getArg(sourceMap, 'version'); - var 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. - var names = util.getArg(sourceMap, 'names', []); - var sourceRoot = util.getArg(sourceMap, 'sourceRoot', null); - var sourcesContent = util.getArg(sourceMap, 'sourcesContent', null); - var mappings = util.getArg(sourceMap, 'mappings'); - var 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 != this._version) { - throw new Error('Unsupported version: ' + version); - } + 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); - } + 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; - }); + 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); + }); - // 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. - this._names = ArraySet.fromArray(names.map(String), true); - this._sources = ArraySet.fromArray(sources, true); - - this._absoluteSources = this._sources.toArray().map(function (s) { - return util.computeSourceURL(sourceRoot, s, aSourceMapURL); - }); - - this.sourceRoot = sourceRoot; - this.sourcesContent = sourcesContent; - this._mappings = mappings; - this._sourceMapURL = aSourceMapURL; - this.file = file; -} + that.sourceRoot = sourceRoot; + that.sourcesContent = sourcesContent; + that._mappings = mappings; + that._sourceMapURL = aSourceMapURL; + that.file = file; -BasicSourceMapConsumer.prototype = Object.create(SourceMapConsumer.prototype); -BasicSourceMapConsumer.prototype.consumer = SourceMapConsumer; + that._computedColumnSpans = false; + that._mappingsPtr = 0; + that._wasm = null; -/** - * Utility function to find the index of a source. Returns -1 if not - * found. - */ -BasicSourceMapConsumer.prototype._findSourceIndex = function(aSource) { - var relativeSource = aSource; - if (this.sourceRoot != null) { - relativeSource = util.relative(this.sourceRoot, relativeSource); + return wasm().then(w => { + that._wasm = w; + return that; + }); + }); } - if (this._sources.has(relativeSource)) { - return this._sources.indexOf(relativeSource); - } + /** + * 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); + } - // Maybe aSource is an absolute URL as returned by |sources|. In - // this case we can't simply undo the transform. - var i; - for (i = 0; i < this._absoluteSources.length; ++i) { - if (this._absoluteSources[i] == aSource) { - return i; + if (this._sources.has(relativeSource)) { + return this._sources.indexOf(relativeSource); } - } - return -1; -}; + // 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; + } + } -/** - * 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 - */ -BasicSourceMapConsumer.fromSourceMap = - function SourceMapConsumer_fromSourceMap(aSourceMap, aSourceMapURL) { - var smc = Object.create(BasicSourceMapConsumer.prototype); - - var names = smc._names = ArraySet.fromArray(aSourceMap._names.toArray(), true); - var sources = smc._sources = ArraySet.fromArray(aSourceMap._sources.toArray(), true); - smc.sourceRoot = aSourceMap._sourceRoot; - smc.sourcesContent = aSourceMap._generateSourcesContent(smc._sources.toArray(), - smc.sourceRoot); - smc.file = aSourceMap._file; - smc._sourceMapURL = aSourceMapURL; - smc._absoluteSources = smc._sources.toArray().map(function (s) { - return util.computeSourceURL(smc.sourceRoot, s, aSourceMapURL); - }); + return -1; + } - // Because we are modifying the entries (by converting string sources and - // names to indices into the sources and names ArraySets), we have to make - // a copy of the entry or else bad things happen. Shared mutable state - // strikes again! See github issue #191. + /** + * 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()); + } - var generatedMappings = aSourceMap._mappings.toArray().slice(); - var destGeneratedMappings = smc.__generatedMappings = []; - var destOriginalMappings = smc.__originalMappings = []; + get sources() { + return this._absoluteSources.slice(); + } - for (var i = 0, length = generatedMappings.length; i < length; i++) { - var srcMapping = generatedMappings[i]; - var destMapping = new Mapping; - destMapping.generatedLine = srcMapping.generatedLine; - destMapping.generatedColumn = srcMapping.generatedColumn; + _getMappingsPtr() { + if (this._mappingsPtr === 0) { + this._parseMappings(this._mappings, this.sourceRoot); + } - if (srcMapping.source) { - destMapping.source = sources.indexOf(srcMapping.source); - destMapping.originalLine = srcMapping.originalLine; - destMapping.originalColumn = srcMapping.originalColumn; + return this._mappingsPtr; + } - if (srcMapping.name) { - destMapping.name = names.indexOf(srcMapping.name); - } + /** + * 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); + } - destOriginalMappings.push(destMapping); + 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; } - destGeneratedMappings.push(destMapping); + throw new Error(msg); } - quickSort(smc.__originalMappings, util.compareByOriginalPositions); - - return smc; - }; - -/** - * The version of the source mapping spec that we are consuming. - */ -BasicSourceMapConsumer.prototype._version = 3; - -/** - * The list of original sources. - */ -Object.defineProperty(BasicSourceMapConsumer.prototype, 'sources', { - get: function () { - return this._absoluteSources.slice(); + this._mappingsPtr = mappingsPtr; } -}); -/** - * Provide the JIT with a nice shape / hidden class. - */ -function Mapping() { - this.generatedLine = 0; - this.generatedColumn = 0; - this.source = null; - this.originalLine = null; - this.originalColumn = null; - this.name = 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). - */ -BasicSourceMapConsumer.prototype._parseMappings = - function SourceMapConsumer_parseMappings(aStr, aSourceRoot) { - var generatedLine = 1; - var previousGeneratedColumn = 0; - var previousOriginalLine = 0; - var previousOriginalColumn = 0; - var previousSource = 0; - var previousName = 0; - var length = aStr.length; - var index = 0; - var cachedSegments = {}; - var temp = {}; - var originalMappings = []; - var generatedMappings = []; - var mapping, str, segment, end, value; - - while (index < length) { - if (aStr.charAt(index) === ';') { - generatedLine++; - index++; - previousGeneratedColumn = 0; - } - else if (aStr.charAt(index) === ',') { - index++; - } - else { - mapping = new Mapping(); - mapping.generatedLine = generatedLine; - - // Because each offset is encoded relative to the previous one, - // many segments often have the same encoding. We can exploit this - // fact by caching the parsed variable length fields of each segment, - // allowing us to avoid a second parse if we encounter the same - // segment again. - for (end = index; end < length; end++) { - if (this._charIsMappingSeparator(aStr, end)) { - break; - } - } - str = aStr.slice(index, end); - - segment = cachedSegments[str]; - if (segment) { - index += str.length; - } else { - segment = []; - while (index < end) { - base64VLQ.decode(aStr, index, temp); - value = temp.value; - index = temp.rest; - segment.push(value); - } - - if (segment.length === 2) { - throw new Error('Found a source, but no line and column'); - } + eachMapping(aCallback, aContext, aOrder) { + const context = aContext || null; + const order = aOrder || SourceMapConsumer.GENERATED_ORDER; + const sourceRoot = this.sourceRoot; - if (segment.length === 3) { - throw new Error('Found a source and line, but no column'); - } - - cachedSegments[str] = segment; - } + this._wasm.withMappingCallback( + mapping => { + if (mapping.source !== null) { + mapping.source = this._sources.at(mapping.source); + mapping.source = util.computeSourceURL(sourceRoot, mapping.source, this._sourceMapURL); - // Generated column. - mapping.generatedColumn = previousGeneratedColumn + segment[0]; - previousGeneratedColumn = mapping.generatedColumn; - - if (segment.length > 1) { - // Original source. - mapping.source = previousSource + segment[1]; - previousSource += segment[1]; - - // Original line. - mapping.originalLine = previousOriginalLine + segment[2]; - previousOriginalLine = mapping.originalLine; - // Lines are stored 0-based - mapping.originalLine += 1; - - // Original column. - mapping.originalColumn = previousOriginalColumn + segment[3]; - previousOriginalColumn = mapping.originalColumn; - - if (segment.length > 4) { - // Original name. - mapping.name = previousName + segment[4]; - previousName += segment[4]; + if (mapping.name !== null) { + mapping.name = this._names.at(mapping.name); } } - generatedMappings.push(mapping); - if (typeof mapping.originalLine === 'number') { - originalMappings.push(mapping); + 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."); } } - } - - quickSort(generatedMappings, util.compareByGeneratedPositionsDeflated); - this.__generatedMappings = generatedMappings; + ); + } - quickSort(originalMappings, util.compareByOriginalPositions); - this.__originalMappings = originalMappings; - }; + allGeneratedPositionsFor(aArgs) { + let source = util.getArg(aArgs, "source"); + const originalLine = util.getArg(aArgs, "line"); + const originalColumn = aArgs.column || 0; -/** - * Find the mapping that best matches the hypothetical "needle" mapping that - * we are searching for in the given "haystack" of mappings. - */ -BasicSourceMapConsumer.prototype._findMapping = - function SourceMapConsumer_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. + source = this._findSourceIndex(source); + if (source < 0) { + return []; + } - if (aNeedle[aLineName] <= 0) { - throw new TypeError('Line must be greater than or equal to 1, got ' - + aNeedle[aLineName]); + if (originalLine < 1) { + throw new Error("Line numbers must be >= 1"); } - if (aNeedle[aColumnName] < 0) { - throw new TypeError('Column must be greater than or equal to 0, got ' - + aNeedle[aColumnName]); + + if (originalColumn < 0) { + throw new Error("Column numbers must be >= 0"); } - return binarySearch.search(aNeedle, aMappings, aComparator, aBias); - }; + const mappings = []; -/** - * Compute the last column for each generated mapping. The last column is - * inclusive. - */ -BasicSourceMapConsumer.prototype.computeColumnSpans = - function SourceMapConsumer_computeColumnSpans() { - for (var index = 0; index < this._generatedMappings.length; ++index) { - var mapping = this._generatedMappings[index]; - - // Mappings do not contain a field for the last generated columnt. We - // can come up with an optimistic estimate, however, by assuming that - // mappings are contiguous (i.e. given two consecutive mappings, the - // first mapping ends where the second one starts). - if (index + 1 < this._generatedMappings.length) { - var nextMapping = this._generatedMappings[index + 1]; - - if (mapping.generatedLine === nextMapping.generatedLine) { - mapping.lastGeneratedColumn = nextMapping.generatedColumn - 1; - continue; + 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; + } - // The last mapping for each line spans the entire line. - mapping.lastGeneratedColumn = Infinity; + destroy() { + if (this._mappingsPtr !== 0) { + this._wasm.exports.free_mappings(this._mappingsPtr); + this._mappingsPtr = 0; } - }; + } -/** - * 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. - */ -BasicSourceMapConsumer.prototype.originalPositionFor = - function SourceMapConsumer_originalPositionFor(aArgs) { - var needle = { - generatedLine: util.getArg(aArgs, 'line'), - generatedColumn: util.getArg(aArgs, 'column') + /** + * 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") }; - var index = this._findMapping( - needle, - this._generatedMappings, - "generatedLine", - "generatedColumn", - util.compareByGeneratedPositionsDeflated, - util.getArg(aArgs, 'bias', SourceMapConsumer.GREATEST_LOWER_BOUND) - ); + if (needle.generatedLine < 1) { + throw new Error("Line numbers must be >= 1"); + } - if (index >= 0) { - var mapping = this._generatedMappings[index]; + 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) { - var source = util.getArg(mapping, 'source', null); + let source = util.getArg(mapping, "source", null); if (source !== null) { source = this._sources.at(source); source = util.computeSourceURL(this.sourceRoot, source, this._sourceMapURL); } - var name = util.getArg(mapping, 'name', null); + + let name = util.getArg(mapping, "name", null); if (name !== null) { name = this._names.at(name); } + return { - source: source, - line: util.getArg(mapping, 'originalLine', null), - column: util.getArg(mapping, 'originalColumn', null), - name: name + source, + line: util.getArg(mapping, "originalLine", null), + column: util.getArg(mapping, "originalColumn", null), + name }; } } @@ -687,53 +525,51 @@ BasicSourceMapConsumer.prototype.originalPositionFor = column: null, name: null }; - }; + } -/** - * Return true if we have the source content for every source in the source - * map, false otherwise. - */ -BasicSourceMapConsumer.prototype.hasContentsOfAllSources = - function BasicSourceMapConsumer_hasContentsOfAllSources() { + /** + * 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; }); - }; + !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. - */ -BasicSourceMapConsumer.prototype.sourceContentFor = - function SourceMapConsumer_sourceContentFor(aSource, nullOnMissing) { + /** + * 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; } - var index = this._findSourceIndex(aSource); + const index = this._findSourceIndex(aSource); if (index >= 0) { return this.sourcesContent[index]; } - var relativeSource = aSource; + let relativeSource = aSource; if (this.sourceRoot != null) { relativeSource = util.relative(this.sourceRoot, relativeSource); } - var url; + 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. - var fileUriAbsPath = relativeSource.replace(/^file:\/\//, ""); + const fileUriAbsPath = relativeSource.replace(/^file:\/\//, ""); if (url.scheme == "file" && this._sources.has(fileUriAbsPath)) { - return this.sourcesContent[this._sources.indexOf(fileUriAbsPath)] + return this.sourcesContent[this._sources.indexOf(fileUriAbsPath)]; } if ((!url.path || url.path == "/") @@ -749,37 +585,35 @@ BasicSourceMapConsumer.prototype.sourceContentFor = if (nullOnMissing) { return null; } - else { - 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. - */ -BasicSourceMapConsumer.prototype.generatedPositionFor = - function SourceMapConsumer_generatedPositionFor(aArgs) { - var source = util.getArg(aArgs, 'source'); + 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 { @@ -789,29 +623,46 @@ BasicSourceMapConsumer.prototype.generatedPositionFor = }; } - var needle = { - source: source, - originalLine: util.getArg(aArgs, 'line'), - originalColumn: util.getArg(aArgs, 'column') + const needle = { + source, + originalLine: util.getArg(aArgs, "line"), + originalColumn: util.getArg(aArgs, "column") }; - var index = this._findMapping( - needle, - this._originalMappings, - "originalLine", - "originalColumn", - util.compareByOriginalPositions, - util.getArg(aArgs, 'bias', SourceMapConsumer.GREATEST_LOWER_BOUND) - ); + if (needle.originalLine < 1) { + throw new Error("Line numbers must be >= 1"); + } - if (index >= 0) { - var mapping = this._originalMappings[index]; + 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: util.getArg(mapping, 'lastGeneratedColumn', null) + line: util.getArg(mapping, "generatedLine", null), + column: util.getArg(mapping, "generatedColumn", null), + lastColumn, }; } } @@ -821,8 +672,10 @@ BasicSourceMapConsumer.prototype.generatedPositionFor = column: null, lastColumn: null }; - }; + } +} +BasicSourceMapConsumer.prototype.consumer = SourceMapConsumer; exports.BasicSourceMapConsumer = BasicSourceMapConsumer; /** @@ -874,116 +727,191 @@ exports.BasicSourceMapConsumer = BasicSourceMapConsumer; * * [0]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit#heading=h.535es3xeprgt */ -function IndexedSourceMapConsumer(aSourceMap, aSourceMapURL) { - var sourceMap = aSourceMap; - if (typeof aSourceMap === 'string') { - sourceMap = util.parseSourceMapInput(aSourceMap); +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; + }); + }); } - var version = util.getArg(sourceMap, 'version'); - var sections = util.getArg(sourceMap, 'sections'); + // `__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(); + } - if (version != this._version) { - throw new Error('Unsupported version: ' + version); + return this.__generatedMappings; } - this._sources = new ArraySet(); - this._names = new ArraySet(); - - var lastOffset = { - line: -1, - column: 0 - }; - this._sections = sections.map(function (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.'); + get _originalMappings() { + if (!this.__originalMappings) { + this._sortOriginalMappings(); } - var offset = util.getArg(s, 'offset'); - var offsetLine = util.getArg(offset, 'line'); - var 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.'); + return this.__originalMappings; + } + + get _generatedMappingsUnsorted() { + if (!this.__generatedMappingsUnsorted) { + this._parseMappings(this._mappings, this.sourceRoot); } - lastOffset = offset; - 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: new SourceMapConsumer(util.getArg(s, 'map'), aSourceMapURL) + return this.__generatedMappingsUnsorted; + } + + get _originalMappingsUnsorted() { + if (!this.__originalMappingsUnsorted) { + this._parseMappings(this._mappings, this.sourceRoot); } - }); -} -IndexedSourceMapConsumer.prototype = Object.create(SourceMapConsumer.prototype); -IndexedSourceMapConsumer.prototype.constructor = SourceMapConsumer; + return this.__originalMappingsUnsorted; + } -/** - * The version of the source mapping spec that we are consuming. - */ -IndexedSourceMapConsumer.prototype._version = 3; + _sortGeneratedMappings() { + const mappings = this._generatedMappingsUnsorted; + mappings.sort(util.compareByGeneratedPositionsDeflated); + this.__generatedMappings = mappings; + } -/** - * The list of original sources. - */ -Object.defineProperty(IndexedSourceMapConsumer.prototype, 'sources', { - get: function () { - var sources = []; - for (var i = 0; i < this._sections.length; i++) { - for (var j = 0; j < this._sections[i].consumer.sources.length; j++) { + _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. - */ -IndexedSourceMapConsumer.prototype.originalPositionFor = - function IndexedSourceMapConsumer_originalPositionFor(aArgs) { - var needle = { - generatedLine: util.getArg(aArgs, 'line'), - generatedColumn: util.getArg(aArgs, 'column') + /** + * 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. - var sectionIndex = binarySearch.search(needle, this._sections, - function(needle, section) { - var cmp = needle.generatedLine - section.generatedOffset.generatedLine; + const sectionIndex = binarySearch.search(needle, this._sections, + function(aNeedle, section) { + const cmp = aNeedle.generatedLine - section.generatedOffset.generatedLine; if (cmp) { return cmp; } - return (needle.generatedColumn - + return (aNeedle.generatedColumn - section.generatedOffset.generatedColumn); }); - var section = this._sections[sectionIndex]; + const section = this._sections[sectionIndex]; if (!section) { return { @@ -1003,30 +931,28 @@ IndexedSourceMapConsumer.prototype.originalPositionFor = : 0), bias: aArgs.bias }); - }; + } -/** - * Return true if we have the source content for every source in the source - * map, false otherwise. - */ -IndexedSourceMapConsumer.prototype.hasContentsOfAllSources = - function IndexedSourceMapConsumer_hasContentsOfAllSources() { - return this._sections.every(function (s) { + /** + * 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. - */ -IndexedSourceMapConsumer.prototype.sourceContentFor = - function IndexedSourceMapConsumer_sourceContentFor(aSource, nullOnMissing) { - for (var i = 0; i < this._sections.length; i++) { - var section = this._sections[i]; + /** + * 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]; - var content = section.consumer.sourceContentFor(aSource, true); + const content = section.consumer.sourceContentFor(aSource, true); if (content) { return content; } @@ -1034,42 +960,39 @@ IndexedSourceMapConsumer.prototype.sourceContentFor = if (nullOnMissing) { return null; } - else { - throw new Error('"' + aSource + '" is not in the SourceMap.'); - } - }; + 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. - */ -IndexedSourceMapConsumer.prototype.generatedPositionFor = - function IndexedSourceMapConsumer_generatedPositionFor(aArgs) { - for (var i = 0; i < this._sections.length; i++) { - var section = this._sections[i]; + /** + * 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) { + if (section.consumer._findSourceIndex(util.getArg(aArgs, "source")) === -1) { continue; } - var generatedPosition = section.consumer.generatedPositionFor(aArgs); + const generatedPosition = section.consumer.generatedPositionFor(aArgs); if (generatedPosition) { - var ret = { + const ret = { line: generatedPosition.line + (section.generatedOffset.generatedLine - 1), column: generatedPosition.column + @@ -1085,41 +1008,45 @@ IndexedSourceMapConsumer.prototype.generatedPositionFor = 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). - */ -IndexedSourceMapConsumer.prototype._parseMappings = - function IndexedSourceMapConsumer_parseMappings(aStr, aSourceRoot) { - this.__generatedMappings = []; - this.__originalMappings = []; - for (var i = 0; i < this._sections.length; i++) { - var section = this._sections[i]; - var sectionMappings = section.consumer._generatedMappings; - for (var j = 0; j < sectionMappings.length; j++) { - var mapping = sectionMappings[j]; - - var source = section.consumer._sources.at(mapping.source); - source = util.computeSourceURL(section.consumer.sourceRoot, source, this._sourceMapURL); + /** + * 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); - var name = null; + let name = null; if (mapping.name) { - name = section.consumer._names.at(mapping.name); - this._names.add(name); - name = this._names.indexOf(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. - var adjustedMapping = { - source: source, + const adjustedMapping = { + source, generatedLine: mapping.generatedLine + (section.generatedOffset.generatedLine - 1), generatedColumn: mapping.generatedColumn + @@ -1128,18 +1055,183 @@ IndexedSourceMapConsumer.prototype._parseMappings = : 0), originalLine: mapping.originalLine, originalColumn: mapping.originalColumn, - name: name + name }; - this.__generatedMappings.push(adjustedMapping); - if (typeof adjustedMapping.originalLine === 'number') { - this.__originalMappings.push(adjustedMapping); + generatedMappings.push(adjustedMapping); + if (typeof adjustedMapping.originalLine === "number") { + originalMappings.push(adjustedMapping); } } } + } - quickSort(this.__generatedMappings, util.compareByGeneratedPositionsDeflated); - quickSort(this.__originalMappings, util.compareByOriginalPositions); - }; + 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); +} diff --git a/node_modules/source-map/lib/source-map-generator.js b/node_modules/source-map/lib/source-map-generator.js index 508bcfbb..8111e061 100644 --- a/node_modules/source-map/lib/source-map-generator.js +++ b/node_modules/source-map/lib/source-map-generator.js @@ -5,10 +5,10 @@ * http://opensource.org/licenses/BSD-3-Clause */ -var base64VLQ = require('./base64-vlq'); -var util = require('./util'); -var ArraySet = require('./array-set').ArraySet; -var MappingList = require('./mapping-list').MappingList; +const base64VLQ = require("./base64-vlq"); +const util = require("./util"); +const ArraySet = require("./array-set").ArraySet; +const MappingList = require("./mapping-list").MappingList; /** * An instance of the SourceMapGenerator represents a source map which is @@ -18,35 +18,33 @@ var MappingList = require('./mapping-list').MappingList; * - file: The filename of the generated source. * - sourceRoot: A root for all relative URLs in this source map. */ -function SourceMapGenerator(aArgs) { - if (!aArgs) { - aArgs = {}; +class SourceMapGenerator { + constructor(aArgs) { + if (!aArgs) { + aArgs = {}; + } + this._file = util.getArg(aArgs, "file", null); + this._sourceRoot = util.getArg(aArgs, "sourceRoot", null); + this._skipValidation = util.getArg(aArgs, "skipValidation", false); + this._sources = new ArraySet(); + this._names = new ArraySet(); + this._mappings = new MappingList(); + this._sourcesContents = null; } - this._file = util.getArg(aArgs, 'file', null); - this._sourceRoot = util.getArg(aArgs, 'sourceRoot', null); - this._skipValidation = util.getArg(aArgs, 'skipValidation', false); - this._sources = new ArraySet(); - this._names = new ArraySet(); - this._mappings = new MappingList(); - this._sourcesContents = null; -} - -SourceMapGenerator.prototype._version = 3; -/** - * Creates a new SourceMapGenerator based on a SourceMapConsumer - * - * @param aSourceMapConsumer The SourceMap. - */ -SourceMapGenerator.fromSourceMap = - function SourceMapGenerator_fromSourceMap(aSourceMapConsumer) { - var sourceRoot = aSourceMapConsumer.sourceRoot; - var generator = new SourceMapGenerator({ + /** + * Creates a new SourceMapGenerator based on a SourceMapConsumer + * + * @param aSourceMapConsumer The SourceMap. + */ + static fromSourceMap(aSourceMapConsumer) { + const sourceRoot = aSourceMapConsumer.sourceRoot; + const generator = new SourceMapGenerator({ file: aSourceMapConsumer.file, - sourceRoot: sourceRoot + sourceRoot }); - aSourceMapConsumer.eachMapping(function (mapping) { - var newMapping = { + aSourceMapConsumer.eachMapping(function(mapping) { + const newMapping = { generated: { line: mapping.generatedLine, column: mapping.generatedColumn @@ -71,8 +69,8 @@ SourceMapGenerator.fromSourceMap = generator.addMapping(newMapping); }); - aSourceMapConsumer.sources.forEach(function (sourceFile) { - var sourceRelative = sourceFile; + aSourceMapConsumer.sources.forEach(function(sourceFile) { + let sourceRelative = sourceFile; if (sourceRoot !== null) { sourceRelative = util.relative(sourceRoot, sourceFile); } @@ -81,30 +79,29 @@ SourceMapGenerator.fromSourceMap = generator._sources.add(sourceRelative); } - var content = aSourceMapConsumer.sourceContentFor(sourceFile); + const content = aSourceMapConsumer.sourceContentFor(sourceFile); if (content != null) { generator.setSourceContent(sourceFile, content); } }); return generator; - }; + } -/** - * Add a single mapping from original source line and column to the generated - * source's line and column for this source map being created. The mapping - * object should have the following properties: - * - * - generated: An object with the generated line and column positions. - * - original: An object with the original line and column positions. - * - source: The original source file (relative to the sourceRoot). - * - name: An optional original token name for this mapping. - */ -SourceMapGenerator.prototype.addMapping = - function SourceMapGenerator_addMapping(aArgs) { - var generated = util.getArg(aArgs, 'generated'); - var original = util.getArg(aArgs, 'original', null); - var source = util.getArg(aArgs, 'source', null); - var name = util.getArg(aArgs, 'name', null); + /** + * Add a single mapping from original source line and column to the generated + * source's line and column for this source map being created. The mapping + * object should have the following properties: + * + * - generated: An object with the generated line and column positions. + * - original: An object with the original line and column positions. + * - source: The original source file (relative to the sourceRoot). + * - name: An optional original token name for this mapping. + */ + addMapping(aArgs) { + const generated = util.getArg(aArgs, "generated"); + const original = util.getArg(aArgs, "original", null); + let source = util.getArg(aArgs, "source", null); + let name = util.getArg(aArgs, "name", null); if (!this._skipValidation) { this._validateMapping(generated, original, source, name); @@ -129,17 +126,16 @@ SourceMapGenerator.prototype.addMapping = generatedColumn: generated.column, originalLine: original != null && original.line, originalColumn: original != null && original.column, - source: source, - name: name + source, + name }); - }; + } -/** - * Set the source content for a source file. - */ -SourceMapGenerator.prototype.setSourceContent = - function SourceMapGenerator_setSourceContent(aSourceFile, aSourceContent) { - var source = aSourceFile; + /** + * Set the source content for a source file. + */ + setSourceContent(aSourceFile, aSourceContent) { + let source = aSourceFile; if (this._sourceRoot != null) { source = util.relative(this._sourceRoot, source); } @@ -159,52 +155,53 @@ SourceMapGenerator.prototype.setSourceContent = this._sourcesContents = null; } } - }; + } -/** - * Applies the mappings of a sub-source-map for a specific source file to the - * source map being generated. Each mapping to the supplied source file is - * rewritten using the supplied source map. Note: The resolution for the - * resulting mappings is the minimium of this map and the supplied map. - * - * @param aSourceMapConsumer The source map to be applied. - * @param aSourceFile Optional. The filename of the source file. - * If omitted, SourceMapConsumer's file property will be used. - * @param aSourceMapPath Optional. The dirname of the path to the source map - * to be applied. If relative, it is relative to the SourceMapConsumer. - * This parameter is needed when the two source maps aren't in the same - * directory, and the source map to be applied contains relative source - * paths. If so, those relative source paths need to be rewritten - * relative to the SourceMapGenerator. - */ -SourceMapGenerator.prototype.applySourceMap = - function SourceMapGenerator_applySourceMap(aSourceMapConsumer, aSourceFile, aSourceMapPath) { - var sourceFile = aSourceFile; + /** + * Applies the mappings of a sub-source-map for a specific source file to the + * source map being generated. Each mapping to the supplied source file is + * rewritten using the supplied source map. Note: The resolution for the + * resulting mappings is the minimium of this map and the supplied map. + * + * @param aSourceMapConsumer The source map to be applied. + * @param aSourceFile Optional. The filename of the source file. + * If omitted, SourceMapConsumer's file property will be used. + * @param aSourceMapPath Optional. The dirname of the path to the source map + * to be applied. If relative, it is relative to the SourceMapConsumer. + * This parameter is needed when the two source maps aren't in the same + * directory, and the source map to be applied contains relative source + * paths. If so, those relative source paths need to be rewritten + * relative to the SourceMapGenerator. + */ + applySourceMap(aSourceMapConsumer, aSourceFile, aSourceMapPath) { + let sourceFile = aSourceFile; // If aSourceFile is omitted, we will use the file property of the SourceMap if (aSourceFile == null) { if (aSourceMapConsumer.file == null) { throw new Error( - 'SourceMapGenerator.prototype.applySourceMap requires either an explicit source file, ' + + "SourceMapGenerator.prototype.applySourceMap requires either an explicit source file, " + 'or the source map\'s "file" property. Both were omitted.' ); } sourceFile = aSourceMapConsumer.file; } - var sourceRoot = this._sourceRoot; + const sourceRoot = this._sourceRoot; // Make "sourceFile" relative if an absolute Url is passed. if (sourceRoot != null) { sourceFile = util.relative(sourceRoot, sourceFile); } // Applying the SourceMap can add and remove items from the sources and // the names array. - var newSources = new ArraySet(); - var newNames = new ArraySet(); + const newSources = this._mappings.toArray().length > 0 + ? new ArraySet() + : this._sources; + const newNames = new ArraySet(); // Find mappings for the "sourceFile" - this._mappings.unsortedForEach(function (mapping) { + this._mappings.unsortedForEach(function(mapping) { if (mapping.source === sourceFile && mapping.originalLine != null) { // Check if it can be mapped by the source map, then update the mapping. - var original = aSourceMapConsumer.originalPositionFor({ + const original = aSourceMapConsumer.originalPositionFor({ line: mapping.originalLine, column: mapping.originalColumn }); @@ -212,7 +209,7 @@ SourceMapGenerator.prototype.applySourceMap = // Copy mapping mapping.source = original.source; if (aSourceMapPath != null) { - mapping.source = util.join(aSourceMapPath, mapping.source) + mapping.source = util.join(aSourceMapPath, mapping.source); } if (sourceRoot != null) { mapping.source = util.relative(sourceRoot, mapping.source); @@ -225,12 +222,12 @@ SourceMapGenerator.prototype.applySourceMap = } } - var source = mapping.source; + const source = mapping.source; if (source != null && !newSources.has(source)) { newSources.add(source); } - var name = mapping.name; + const name = mapping.name; if (name != null && !newNames.has(name)) { newNames.add(name); } @@ -240,107 +237,99 @@ SourceMapGenerator.prototype.applySourceMap = this._names = newNames; // Copy sourcesContents of applied map. - aSourceMapConsumer.sources.forEach(function (sourceFile) { - var content = aSourceMapConsumer.sourceContentFor(sourceFile); + aSourceMapConsumer.sources.forEach(function(srcFile) { + const content = aSourceMapConsumer.sourceContentFor(srcFile); if (content != null) { if (aSourceMapPath != null) { - sourceFile = util.join(aSourceMapPath, sourceFile); + srcFile = util.join(aSourceMapPath, srcFile); } if (sourceRoot != null) { - sourceFile = util.relative(sourceRoot, sourceFile); + srcFile = util.relative(sourceRoot, srcFile); } - this.setSourceContent(sourceFile, content); + this.setSourceContent(srcFile, content); } }, this); - }; + } -/** - * A mapping can have one of the three levels of data: - * - * 1. Just the generated position. - * 2. The Generated position, original position, and original source. - * 3. Generated and original position, original source, as well as a name - * token. - * - * To maintain consistency, we validate that any new mapping being added falls - * in to one of these categories. - */ -SourceMapGenerator.prototype._validateMapping = - function SourceMapGenerator_validateMapping(aGenerated, aOriginal, aSource, - aName) { + /** + * A mapping can have one of the three levels of data: + * + * 1. Just the generated position. + * 2. The Generated position, original position, and original source. + * 3. Generated and original position, original source, as well as a name + * token. + * + * To maintain consistency, we validate that any new mapping being added falls + * in to one of these categories. + */ + _validateMapping(aGenerated, aOriginal, aSource, aName) { // When aOriginal is truthy but has empty values for .line and .column, // it is most likely a programmer error. In this case we throw a very // specific error message to try to guide them the right way. // For example: https://github.com/Polymer/polymer-bundler/pull/519 - if (aOriginal && typeof aOriginal.line !== 'number' && typeof aOriginal.column !== 'number') { + if (aOriginal && typeof aOriginal.line !== "number" && typeof aOriginal.column !== "number") { throw new Error( - 'original.line and original.column are not numbers -- you probably meant to omit ' + - 'the original mapping entirely and only map the generated position. If so, pass ' + - 'null for the original mapping instead of an object with empty or null values.' + "original.line and original.column are not numbers -- you probably meant to omit " + + "the original mapping entirely and only map the generated position. If so, pass " + + "null for the original mapping instead of an object with empty or null values." ); } - if (aGenerated && 'line' in aGenerated && 'column' in aGenerated + if (aGenerated && "line" in aGenerated && "column" in aGenerated && aGenerated.line > 0 && aGenerated.column >= 0 && !aOriginal && !aSource && !aName) { // Case 1. - return; - } - else if (aGenerated && 'line' in aGenerated && 'column' in aGenerated - && aOriginal && 'line' in aOriginal && 'column' in aOriginal + + } else if (aGenerated && "line" in aGenerated && "column" in aGenerated + && aOriginal && "line" in aOriginal && "column" in aOriginal && aGenerated.line > 0 && aGenerated.column >= 0 && aOriginal.line > 0 && aOriginal.column >= 0 && aSource) { // Cases 2 and 3. - return; - } - else { - throw new Error('Invalid mapping: ' + JSON.stringify({ + + } else { + throw new Error("Invalid mapping: " + JSON.stringify({ generated: aGenerated, source: aSource, original: aOriginal, name: aName })); } - }; + } -/** - * Serialize the accumulated mappings in to the stream of base 64 VLQs - * specified by the source map format. - */ -SourceMapGenerator.prototype._serializeMappings = - function SourceMapGenerator_serializeMappings() { - var previousGeneratedColumn = 0; - var previousGeneratedLine = 1; - var previousOriginalColumn = 0; - var previousOriginalLine = 0; - var previousName = 0; - var previousSource = 0; - var result = ''; - var next; - var mapping; - var nameIdx; - var sourceIdx; - - var mappings = this._mappings.toArray(); - for (var i = 0, len = mappings.length; i < len; i++) { + /** + * Serialize the accumulated mappings in to the stream of base 64 VLQs + * specified by the source map format. + */ + _serializeMappings() { + let previousGeneratedColumn = 0; + let previousGeneratedLine = 1; + let previousOriginalColumn = 0; + let previousOriginalLine = 0; + let previousName = 0; + let previousSource = 0; + let result = ""; + let next; + let mapping; + let nameIdx; + let sourceIdx; + + const mappings = this._mappings.toArray(); + for (let i = 0, len = mappings.length; i < len; i++) { mapping = mappings[i]; - next = '' + next = ""; if (mapping.generatedLine !== previousGeneratedLine) { previousGeneratedColumn = 0; while (mapping.generatedLine !== previousGeneratedLine) { - next += ';'; + next += ";"; previousGeneratedLine++; } - } - else { - if (i > 0) { - if (!util.compareByGeneratedPositionsInflated(mapping, mappings[i - 1])) { - continue; - } - next += ','; + } else if (i > 0) { + if (!util.compareByGeneratedPositionsInflated(mapping, mappings[i - 1])) { + continue; } + next += ","; } next += base64VLQ.encode(mapping.generatedColumn @@ -372,30 +361,28 @@ SourceMapGenerator.prototype._serializeMappings = } return result; - }; + } -SourceMapGenerator.prototype._generateSourcesContent = - function SourceMapGenerator_generateSourcesContent(aSources, aSourceRoot) { - return aSources.map(function (source) { + _generateSourcesContent(aSources, aSourceRoot) { + return aSources.map(function(source) { if (!this._sourcesContents) { return null; } if (aSourceRoot != null) { source = util.relative(aSourceRoot, source); } - var key = util.toSetString(source); + const key = util.toSetString(source); return Object.prototype.hasOwnProperty.call(this._sourcesContents, key) ? this._sourcesContents[key] : null; }, this); - }; + } -/** - * Externalize the source map. - */ -SourceMapGenerator.prototype.toJSON = - function SourceMapGenerator_toJSON() { - var map = { + /** + * Externalize the source map. + */ + toJSON() { + const map = { version: this._version, sources: this._sources.toArray(), names: this._names.toArray(), @@ -412,14 +399,15 @@ SourceMapGenerator.prototype.toJSON = } return map; - }; + } -/** - * Render the source map being generated to a string. - */ -SourceMapGenerator.prototype.toString = - function SourceMapGenerator_toString() { + /** + * Render the source map being generated to a string. + */ + toString() { return JSON.stringify(this.toJSON()); - }; + } +} +SourceMapGenerator.prototype._version = 3; exports.SourceMapGenerator = SourceMapGenerator; diff --git a/node_modules/source-map/lib/source-node.js b/node_modules/source-map/lib/source-node.js index 8bcdbe38..8a7a157e 100644 --- a/node_modules/source-map/lib/source-node.js +++ b/node_modules/source-map/lib/source-node.js @@ -5,20 +5,20 @@ * http://opensource.org/licenses/BSD-3-Clause */ -var SourceMapGenerator = require('./source-map-generator').SourceMapGenerator; -var util = require('./util'); +const SourceMapGenerator = require("./source-map-generator").SourceMapGenerator; +const util = require("./util"); // Matches a Windows-style `\r\n` newline or a `\n` newline used by all other // operating systems these days (capturing the result). -var REGEX_NEWLINE = /(\r?\n)/; +const REGEX_NEWLINE = /(\r?\n)/; // Newline character code for charCodeAt() comparisons -var NEWLINE_CODE = 10; +const NEWLINE_CODE = 10; // Private symbol for identifying `SourceNode`s when multiple versions of // the source-map library are loaded. This MUST NOT CHANGE across // versions! -var isSourceNode = "$$$isSourceNode$$$"; +const isSourceNode = "$$$isSourceNode$$$"; /** * SourceNodes provide a way to abstract over interpolating/concatenating @@ -32,41 +32,41 @@ var isSourceNode = "$$$isSourceNode$$$"; * generated JS, or other SourceNodes. * @param aName The original identifier. */ -function SourceNode(aLine, aColumn, aSource, aChunks, aName) { - this.children = []; - this.sourceContents = {}; - this.line = aLine == null ? null : aLine; - this.column = aColumn == null ? null : aColumn; - this.source = aSource == null ? null : aSource; - this.name = aName == null ? null : aName; - this[isSourceNode] = true; - if (aChunks != null) this.add(aChunks); -} +class SourceNode { + constructor(aLine, aColumn, aSource, aChunks, aName) { + this.children = []; + this.sourceContents = {}; + this.line = aLine == null ? null : aLine; + this.column = aColumn == null ? null : aColumn; + this.source = aSource == null ? null : aSource; + this.name = aName == null ? null : aName; + this[isSourceNode] = true; + if (aChunks != null) this.add(aChunks); + } -/** - * Creates a SourceNode from generated code and a SourceMapConsumer. - * - * @param aGeneratedCode The generated code - * @param aSourceMapConsumer The SourceMap for the generated code - * @param aRelativePath Optional. The path that relative sources in the - * SourceMapConsumer should be relative to. - */ -SourceNode.fromStringWithSourceMap = - function SourceNode_fromStringWithSourceMap(aGeneratedCode, aSourceMapConsumer, aRelativePath) { + /** + * Creates a SourceNode from generated code and a SourceMapConsumer. + * + * @param aGeneratedCode The generated code + * @param aSourceMapConsumer The SourceMap for the generated code + * @param aRelativePath Optional. The path that relative sources in the + * SourceMapConsumer should be relative to. + */ + static fromStringWithSourceMap(aGeneratedCode, aSourceMapConsumer, aRelativePath) { // The SourceNode we want to fill with the generated code // and the SourceMap - var node = new SourceNode(); + const node = new SourceNode(); // All even indices of this array are one line of the generated code, // while all odd indices are the newlines between two adjacent lines // (since `REGEX_NEWLINE` captures its match). // Processed fragments are accessed by calling `shiftNextLine`. - var remainingLines = aGeneratedCode.split(REGEX_NEWLINE); - var remainingLinesIndex = 0; - var shiftNextLine = function() { - var lineContents = getNextLine(); + const remainingLines = aGeneratedCode.split(REGEX_NEWLINE); + let remainingLinesIndex = 0; + const shiftNextLine = function() { + const lineContents = getNextLine(); // The last line of a file might not have a newline. - var newLine = getNextLine() || ""; + const newLine = getNextLine() || ""; return lineContents + newLine; function getNextLine() { @@ -76,14 +76,15 @@ SourceNode.fromStringWithSourceMap = }; // We need to remember the position of "remainingLines" - var lastGeneratedLine = 1, lastGeneratedColumn = 0; + let lastGeneratedLine = 1, lastGeneratedColumn = 0; // The generate SourceNodes we need a code range. // To extract it current and last mapping is used. // Here we store the last mapping. - var lastMapping = null; + let lastMapping = null; + let nextLine; - aSourceMapConsumer.eachMapping(function (mapping) { + aSourceMapConsumer.eachMapping(function(mapping) { if (lastMapping !== null) { // We add the code from "lastMapping" to "mapping": // First check if there is a new line in between. @@ -97,8 +98,8 @@ SourceNode.fromStringWithSourceMap = // There is no new line in between. // Associate the code between "lastGeneratedColumn" and // "mapping.generatedColumn" with "lastMapping" - var nextLine = remainingLines[remainingLinesIndex] || ''; - var code = nextLine.substr(0, mapping.generatedColumn - + nextLine = remainingLines[remainingLinesIndex] || ""; + const code = nextLine.substr(0, mapping.generatedColumn - lastGeneratedColumn); remainingLines[remainingLinesIndex] = nextLine.substr(mapping.generatedColumn - lastGeneratedColumn); @@ -117,7 +118,7 @@ SourceNode.fromStringWithSourceMap = lastGeneratedLine++; } if (lastGeneratedColumn < mapping.generatedColumn) { - var nextLine = remainingLines[remainingLinesIndex] || ''; + nextLine = remainingLines[remainingLinesIndex] || ""; node.add(nextLine.substr(0, mapping.generatedColumn)); remainingLines[remainingLinesIndex] = nextLine.substr(mapping.generatedColumn); lastGeneratedColumn = mapping.generatedColumn; @@ -135,8 +136,8 @@ SourceNode.fromStringWithSourceMap = } // Copy sourcesContent into SourceNode - aSourceMapConsumer.sources.forEach(function (sourceFile) { - var content = aSourceMapConsumer.sourceContentFor(sourceFile); + aSourceMapConsumer.sources.forEach(function(sourceFile) { + const content = aSourceMapConsumer.sourceContentFor(sourceFile); if (content != null) { if (aRelativePath != null) { sourceFile = util.join(aRelativePath, sourceFile); @@ -151,7 +152,7 @@ SourceNode.fromStringWithSourceMap = if (mapping === null || mapping.source === undefined) { node.add(code); } else { - var source = aRelativePath + const source = aRelativePath ? util.join(aRelativePath, mapping.source) : mapping.source; node.add(new SourceNode(mapping.originalLine, @@ -161,230 +162,182 @@ SourceNode.fromStringWithSourceMap = mapping.name)); } } - }; - -/** - * Add a chunk of generated JS to this source node. - * - * @param aChunk A string snippet of generated JS code, another instance of - * SourceNode, or an array where each member is one of those things. - */ -SourceNode.prototype.add = function SourceNode_add(aChunk) { - if (Array.isArray(aChunk)) { - aChunk.forEach(function (chunk) { - this.add(chunk); - }, this); } - else if (aChunk[isSourceNode] || typeof aChunk === "string") { - if (aChunk) { - this.children.push(aChunk); + + /** + * Add a chunk of generated JS to this source node. + * + * @param aChunk A string snippet of generated JS code, another instance of + * SourceNode, or an array where each member is one of those things. + */ + add(aChunk) { + if (Array.isArray(aChunk)) { + aChunk.forEach(function(chunk) { + this.add(chunk); + }, this); + } else if (aChunk[isSourceNode] || typeof aChunk === "string") { + if (aChunk) { + this.children.push(aChunk); + } + } else { + throw new TypeError( + "Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk + ); } + return this; } - else { - throw new TypeError( - "Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk - ); - } - return this; -}; -/** - * Add a chunk of generated JS to the beginning of this source node. - * - * @param aChunk A string snippet of generated JS code, another instance of - * SourceNode, or an array where each member is one of those things. - */ -SourceNode.prototype.prepend = function SourceNode_prepend(aChunk) { - if (Array.isArray(aChunk)) { - for (var i = aChunk.length-1; i >= 0; i--) { - this.prepend(aChunk[i]); + /** + * Add a chunk of generated JS to the beginning of this source node. + * + * @param aChunk A string snippet of generated JS code, another instance of + * SourceNode, or an array where each member is one of those things. + */ + prepend(aChunk) { + if (Array.isArray(aChunk)) { + for (let i = aChunk.length - 1; i >= 0; i--) { + this.prepend(aChunk[i]); + } + } else if (aChunk[isSourceNode] || typeof aChunk === "string") { + this.children.unshift(aChunk); + } else { + throw new TypeError( + "Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk + ); } + return this; } - else if (aChunk[isSourceNode] || typeof aChunk === "string") { - this.children.unshift(aChunk); - } - else { - throw new TypeError( - "Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk - ); - } - return this; -}; -/** - * Walk over the tree of JS snippets in this node and its children. The - * walking function is called once for each snippet of JS and is passed that - * snippet and the its original associated source's line/column location. - * - * @param aFn The traversal function. - */ -SourceNode.prototype.walk = function SourceNode_walk(aFn) { - var chunk; - for (var i = 0, len = this.children.length; i < len; i++) { - chunk = this.children[i]; - if (chunk[isSourceNode]) { - chunk.walk(aFn); - } - else { - if (chunk !== '') { + /** + * Walk over the tree of JS snippets in this node and its children. The + * walking function is called once for each snippet of JS and is passed that + * snippet and the its original associated source's line/column location. + * + * @param aFn The traversal function. + */ + walk(aFn) { + let chunk; + for (let i = 0, len = this.children.length; i < len; i++) { + chunk = this.children[i]; + if (chunk[isSourceNode]) { + chunk.walk(aFn); + } else if (chunk !== "") { aFn(chunk, { source: this.source, - line: this.line, - column: this.column, - name: this.name }); + line: this.line, + column: this.column, + name: this.name }); } } } -}; -/** - * Like `String.prototype.join` except for SourceNodes. Inserts `aStr` between - * each of `this.children`. - * - * @param aSep The separator. - */ -SourceNode.prototype.join = function SourceNode_join(aSep) { - var newChildren; - var i; - var len = this.children.length; - if (len > 0) { - newChildren = []; - for (i = 0; i < len-1; i++) { + /** + * Like `String.prototype.join` except for SourceNodes. Inserts `aStr` between + * each of `this.children`. + * + * @param aSep The separator. + */ + join(aSep) { + let newChildren; + let i; + const len = this.children.length; + if (len > 0) { + newChildren = []; + for (i = 0; i < len - 1; i++) { + newChildren.push(this.children[i]); + newChildren.push(aSep); + } newChildren.push(this.children[i]); - newChildren.push(aSep); + this.children = newChildren; } - newChildren.push(this.children[i]); - this.children = newChildren; + return this; } - return this; -}; -/** - * Call String.prototype.replace on the very right-most source snippet. Useful - * for trimming whitespace from the end of a source node, etc. - * - * @param aPattern The pattern to replace. - * @param aReplacement The thing to replace the pattern with. - */ -SourceNode.prototype.replaceRight = function SourceNode_replaceRight(aPattern, aReplacement) { - var lastChild = this.children[this.children.length - 1]; - if (lastChild[isSourceNode]) { - lastChild.replaceRight(aPattern, aReplacement); - } - else if (typeof lastChild === 'string') { - this.children[this.children.length - 1] = lastChild.replace(aPattern, aReplacement); - } - else { - this.children.push(''.replace(aPattern, aReplacement)); + /** + * Call String.prototype.replace on the very right-most source snippet. Useful + * for trimming whitespace from the end of a source node, etc. + * + * @param aPattern The pattern to replace. + * @param aReplacement The thing to replace the pattern with. + */ + replaceRight(aPattern, aReplacement) { + const lastChild = this.children[this.children.length - 1]; + if (lastChild[isSourceNode]) { + lastChild.replaceRight(aPattern, aReplacement); + } else if (typeof lastChild === "string") { + this.children[this.children.length - 1] = lastChild.replace(aPattern, aReplacement); + } else { + this.children.push("".replace(aPattern, aReplacement)); + } + return this; } - return this; -}; -/** - * Set the source content for a source file. This will be added to the SourceMapGenerator - * in the sourcesContent field. - * - * @param aSourceFile The filename of the source file - * @param aSourceContent The content of the source file - */ -SourceNode.prototype.setSourceContent = - function SourceNode_setSourceContent(aSourceFile, aSourceContent) { + /** + * Set the source content for a source file. This will be added to the SourceMapGenerator + * in the sourcesContent field. + * + * @param aSourceFile The filename of the source file + * @param aSourceContent The content of the source file + */ + setSourceContent(aSourceFile, aSourceContent) { this.sourceContents[util.toSetString(aSourceFile)] = aSourceContent; - }; + } -/** - * Walk over the tree of SourceNodes. The walking function is called for each - * source file content and is passed the filename and source content. - * - * @param aFn The traversal function. - */ -SourceNode.prototype.walkSourceContents = - function SourceNode_walkSourceContents(aFn) { - for (var i = 0, len = this.children.length; i < len; i++) { + /** + * Walk over the tree of SourceNodes. The walking function is called for each + * source file content and is passed the filename and source content. + * + * @param aFn The traversal function. + */ + walkSourceContents(aFn) { + for (let i = 0, len = this.children.length; i < len; i++) { if (this.children[i][isSourceNode]) { this.children[i].walkSourceContents(aFn); } } - var sources = Object.keys(this.sourceContents); - for (var i = 0, len = sources.length; i < len; i++) { + const sources = Object.keys(this.sourceContents); + for (let i = 0, len = sources.length; i < len; i++) { aFn(util.fromSetString(sources[i]), this.sourceContents[sources[i]]); } - }; + } -/** - * Return the string representation of this source node. Walks over the tree - * and concatenates all the various snippets together to one string. - */ -SourceNode.prototype.toString = function SourceNode_toString() { - var str = ""; - this.walk(function (chunk) { - str += chunk; - }); - return str; -}; + /** + * Return the string representation of this source node. Walks over the tree + * and concatenates all the various snippets together to one string. + */ + toString() { + let str = ""; + this.walk(function(chunk) { + str += chunk; + }); + return str; + } -/** - * Returns the string representation of this source node along with a source - * map. - */ -SourceNode.prototype.toStringWithSourceMap = function SourceNode_toStringWithSourceMap(aArgs) { - var generated = { - code: "", - line: 1, - column: 0 - }; - var map = new SourceMapGenerator(aArgs); - var sourceMappingActive = false; - var lastOriginalSource = null; - var lastOriginalLine = null; - var lastOriginalColumn = null; - var lastOriginalName = null; - this.walk(function (chunk, original) { - generated.code += chunk; - if (original.source !== null - && original.line !== null - && original.column !== null) { - if(lastOriginalSource !== original.source - || lastOriginalLine !== original.line - || lastOriginalColumn !== original.column - || lastOriginalName !== original.name) { - map.addMapping({ - source: original.source, - original: { - line: original.line, - column: original.column - }, - generated: { - line: generated.line, - column: generated.column - }, - name: original.name - }); - } - lastOriginalSource = original.source; - lastOriginalLine = original.line; - lastOriginalColumn = original.column; - lastOriginalName = original.name; - sourceMappingActive = true; - } else if (sourceMappingActive) { - map.addMapping({ - generated: { - line: generated.line, - column: generated.column - } - }); - lastOriginalSource = null; - sourceMappingActive = false; - } - for (var idx = 0, length = chunk.length; idx < length; idx++) { - if (chunk.charCodeAt(idx) === NEWLINE_CODE) { - generated.line++; - generated.column = 0; - // Mappings end at eol - if (idx + 1 === length) { - lastOriginalSource = null; - sourceMappingActive = false; - } else if (sourceMappingActive) { + /** + * Returns the string representation of this source node along with a source + * map. + */ + toStringWithSourceMap(aArgs) { + const generated = { + code: "", + line: 1, + column: 0 + }; + const map = new SourceMapGenerator(aArgs); + let sourceMappingActive = false; + let lastOriginalSource = null; + let lastOriginalLine = null; + let lastOriginalColumn = null; + let lastOriginalName = null; + this.walk(function(chunk, original) { + generated.code += chunk; + if (original.source !== null + && original.line !== null + && original.column !== null) { + if (lastOriginalSource !== original.source + || lastOriginalLine !== original.line + || lastOriginalColumn !== original.column + || lastOriginalName !== original.name) { map.addMapping({ source: original.source, original: { @@ -398,16 +351,54 @@ SourceNode.prototype.toStringWithSourceMap = function SourceNode_toStringWithSou name: original.name }); } - } else { - generated.column++; + lastOriginalSource = original.source; + lastOriginalLine = original.line; + lastOriginalColumn = original.column; + lastOriginalName = original.name; + sourceMappingActive = true; + } else if (sourceMappingActive) { + map.addMapping({ + generated: { + line: generated.line, + column: generated.column + } + }); + lastOriginalSource = null; + sourceMappingActive = false; } - } - }); - this.walkSourceContents(function (sourceFile, sourceContent) { - map.setSourceContent(sourceFile, sourceContent); - }); + for (let idx = 0, length = chunk.length; idx < length; idx++) { + if (chunk.charCodeAt(idx) === NEWLINE_CODE) { + generated.line++; + generated.column = 0; + // Mappings end at eol + if (idx + 1 === length) { + lastOriginalSource = null; + sourceMappingActive = false; + } else if (sourceMappingActive) { + map.addMapping({ + source: original.source, + original: { + line: original.line, + column: original.column + }, + generated: { + line: generated.line, + column: generated.column + }, + name: original.name + }); + } + } else { + generated.column++; + } + } + }); + this.walkSourceContents(function(sourceFile, sourceContent) { + map.setSourceContent(sourceFile, sourceContent); + }); - return { code: generated.code, map: map }; -}; + return { code: generated.code, map }; + } +} exports.SourceNode = SourceNode; diff --git a/node_modules/source-map/lib/util.js b/node_modules/source-map/lib/util.js index 3ca92e56..35bd93d6 100644 --- a/node_modules/source-map/lib/util.js +++ b/node_modules/source-map/lib/util.js @@ -20,17 +20,17 @@ function getArg(aArgs, aName, aDefaultValue) { return aArgs[aName]; } else if (arguments.length === 3) { return aDefaultValue; - } else { - throw new Error('"' + aName + '" is a required argument.'); } + throw new Error('"' + aName + '" is a required argument.'); + } exports.getArg = getArg; -var urlRegexp = /^(?:([\w+\-.]+):)?\/\/(?:(\w+:\w+)@)?([\w.-]*)(?::(\d+))?(.*)$/; -var dataUrlRegexp = /^data:.+\,.+$/; +const urlRegexp = /^(?:([\w+\-.]+):)?\/\/(?:(\w+:\w+)@)?([\w.-]*)(?::(\d+))?(.*)$/; +const dataUrlRegexp = /^data:.+\,.+$/; function urlParse(aUrl) { - var match = aUrl.match(urlRegexp); + const match = aUrl.match(urlRegexp); if (!match) { return null; } @@ -45,19 +45,19 @@ function urlParse(aUrl) { exports.urlParse = urlParse; function urlGenerate(aParsedUrl) { - var url = ''; + let url = ""; if (aParsedUrl.scheme) { - url += aParsedUrl.scheme + ':'; + url += aParsedUrl.scheme + ":"; } - url += '//'; + url += "//"; if (aParsedUrl.auth) { - url += aParsedUrl.auth + '@'; + url += aParsedUrl.auth + "@"; } if (aParsedUrl.host) { url += aParsedUrl.host; } if (aParsedUrl.port) { - url += ":" + aParsedUrl.port + url += ":" + aParsedUrl.port; } if (aParsedUrl.path) { url += aParsedUrl.path; @@ -66,6 +66,43 @@ function urlGenerate(aParsedUrl) { } exports.urlGenerate = urlGenerate; +const MAX_CACHED_INPUTS = 32; + +/** + * Takes some function `f(input) -> result` and returns a memoized version of + * `f`. + * + * We keep at most `MAX_CACHED_INPUTS` memoized results of `f` alive. The + * memoization is a dumb-simple, linear least-recently-used cache. + */ +function lruMemoize(f) { + const cache = []; + + return function(input) { + for (let i = 0; i < cache.length; i++) { + if (cache[i].input === input) { + const temp = cache[0]; + cache[0] = cache[i]; + cache[i] = temp; + return cache[0].result; + } + } + + const result = f(input); + + cache.unshift({ + input, + result, + }); + + if (cache.length > MAX_CACHED_INPUTS) { + cache.pop(); + } + + return result; + }; +} + /** * Normalizes a path, or the path portion of a URL: * @@ -77,26 +114,45 @@ exports.urlGenerate = urlGenerate; * * @param aPath The path or url to normalize. */ -function normalize(aPath) { - var path = aPath; - var url = urlParse(aPath); +const normalize = lruMemoize(function normalize(aPath) { + let path = aPath; + const url = urlParse(aPath); if (url) { if (!url.path) { return aPath; } path = url.path; } - var isAbsolute = exports.isAbsolute(path); + const isAbsolute = exports.isAbsolute(path); + + // Split the path into parts between `/` characters. This is much faster than + // using `.split(/\/+/g)`. + const parts = []; + let start = 0; + let i = 0; + while (true) { + start = i; + i = path.indexOf("/", start); + if (i === -1) { + parts.push(path.slice(start)); + break; + } else { + parts.push(path.slice(start, i)); + while (i < path.length && path[i] === "/") { + i++; + } + } + } - var parts = path.split(/\/+/); - for (var part, up = 0, i = parts.length - 1; i >= 0; i--) { - part = parts[i]; - if (part === '.') { + let up = 0; + for (i = parts.length - 1; i >= 0; i--) { + const part = parts[i]; + if (part === ".") { parts.splice(i, 1); - } else if (part === '..') { + } else if (part === "..") { up++; } else if (up > 0) { - if (part === '') { + if (part === "") { // The first part is blank if the path is absolute. Trying to go // above the root is a no-op. Therefore we can remove all '..' parts // directly after the root. @@ -108,10 +164,10 @@ function normalize(aPath) { } } } - path = parts.join('/'); + path = parts.join("/"); - if (path === '') { - path = isAbsolute ? '/' : '.'; + if (path === "") { + path = isAbsolute ? "/" : "."; } if (url) { @@ -119,7 +175,7 @@ function normalize(aPath) { return urlGenerate(url); } return path; -} +}); exports.normalize = normalize; /** @@ -145,10 +201,10 @@ function join(aRoot, aPath) { if (aPath === "") { aPath = "."; } - var aPathUrl = urlParse(aPath); - var aRootUrl = urlParse(aRoot); + const aPathUrl = urlParse(aPath); + const aRootUrl = urlParse(aRoot); if (aRootUrl) { - aRoot = aRootUrl.path || '/'; + aRoot = aRootUrl.path || "/"; } // `join(foo, '//www.example.org')` @@ -169,9 +225,9 @@ function join(aRoot, aPath) { return urlGenerate(aRootUrl); } - var joined = aPath.charAt(0) === '/' + const joined = aPath.charAt(0) === "/" ? aPath - : normalize(aRoot.replace(/\/+$/, '') + '/' + aPath); + : normalize(aRoot.replace(/\/+$/, "") + "/" + aPath); if (aRootUrl) { aRootUrl.path = joined; @@ -181,8 +237,8 @@ function join(aRoot, aPath) { } exports.join = join; -exports.isAbsolute = function (aPath) { - return aPath.charAt(0) === '/' || urlRegexp.test(aPath); +exports.isAbsolute = function(aPath) { + return aPath.charAt(0) === "/" || urlRegexp.test(aPath); }; /** @@ -196,15 +252,15 @@ function relative(aRoot, aPath) { aRoot = "."; } - aRoot = aRoot.replace(/\/$/, ''); + aRoot = aRoot.replace(/\/$/, ""); // It is possible for the path to be above the root. In this case, simply // checking whether the root is a prefix of the path won't work. Instead, we // need to remove components from the root one by one, until either we find // a prefix that fits, or we run out of components to remove. - var level = 0; - while (aPath.indexOf(aRoot + '/') !== 0) { - var index = aRoot.lastIndexOf("/"); + let level = 0; + while (aPath.indexOf(aRoot + "/") !== 0) { + const index = aRoot.lastIndexOf("/"); if (index < 0) { return aPath; } @@ -225,12 +281,12 @@ function relative(aRoot, aPath) { } exports.relative = relative; -var supportsNullProto = (function () { - var obj = Object.create(null); - return !('__proto__' in obj); +const supportsNullProto = (function() { + const obj = Object.create(null); + return !("__proto__" in obj); }()); -function identity (s) { +function identity(s) { return s; } @@ -245,7 +301,7 @@ function identity (s) { */ function toSetString(aStr) { if (isProtoString(aStr)) { - return '$' + aStr; + return "$" + aStr; } return aStr; @@ -266,12 +322,13 @@ function isProtoString(s) { return false; } - var length = s.length; + const length = s.length; if (length < 9 /* "__proto__".length */) { return false; } + /* eslint-disable no-multi-spaces */ if (s.charCodeAt(length - 1) !== 95 /* '_' */ || s.charCodeAt(length - 2) !== 95 /* '_' */ || s.charCodeAt(length - 3) !== 111 /* 'o' */ || @@ -283,8 +340,9 @@ function isProtoString(s) { s.charCodeAt(length - 9) !== 95 /* '_' */) { return false; } + /* eslint-enable no-multi-spaces */ - for (var i = length - 10; i >= 0; i--) { + for (let i = length - 10; i >= 0; i--) { if (s.charCodeAt(i) !== 36 /* '$' */) { return false; } @@ -302,7 +360,7 @@ function isProtoString(s) { * stubbed out mapping. */ function compareByOriginalPositions(mappingA, mappingB, onlyCompareOriginal) { - var cmp = strcmp(mappingA.source, mappingB.source); + let cmp = strcmp(mappingA.source, mappingB.source); if (cmp !== 0) { return cmp; } @@ -341,7 +399,7 @@ exports.compareByOriginalPositions = compareByOriginalPositions; * mapping with a stubbed out mapping. */ function compareByGeneratedPositionsDeflated(mappingA, mappingB, onlyCompareGenerated) { - var cmp = mappingA.generatedLine - mappingB.generatedLine; + let cmp = mappingA.generatedLine - mappingB.generatedLine; if (cmp !== 0) { return cmp; } @@ -395,7 +453,7 @@ function strcmp(aStr1, aStr2) { * the generated positions are compared. */ function compareByGeneratedPositionsInflated(mappingA, mappingB) { - var cmp = mappingA.generatedLine - mappingB.generatedLine; + let cmp = mappingA.generatedLine - mappingB.generatedLine; if (cmp !== 0) { return cmp; } @@ -430,7 +488,7 @@ exports.compareByGeneratedPositionsInflated = compareByGeneratedPositionsInflate * JSON. */ function parseSourceMapInput(str) { - return JSON.parse(str.replace(/^\)]}'[^\n]*\n/, '')); + return JSON.parse(str.replace(/^\)]}'[^\n]*\n/, "")); } exports.parseSourceMapInput = parseSourceMapInput; @@ -439,12 +497,12 @@ exports.parseSourceMapInput = parseSourceMapInput; * URL, and the source map's URL. */ function computeSourceURL(sourceRoot, sourceURL, sourceMapURL) { - sourceURL = sourceURL || ''; + sourceURL = sourceURL || ""; if (sourceRoot) { // This follows what Chrome does. - if (sourceRoot[sourceRoot.length - 1] !== '/' && sourceURL[0] !== '/') { - sourceRoot += '/'; + if (sourceRoot[sourceRoot.length - 1] !== "/" && sourceURL[0] !== "/") { + sourceRoot += "/"; } // The spec says: // Line 4: An optional source root, useful for relocating source @@ -469,13 +527,13 @@ function computeSourceURL(sourceRoot, sourceURL, sourceMapURL) { // “sourceRoot”, the sources are resolved relative to the // SourceMap (like resolving script src in a html document). if (sourceMapURL) { - var parsed = urlParse(sourceMapURL); + const parsed = urlParse(sourceMapURL); if (!parsed) { throw new Error("sourceMapURL could not be parsed"); } if (parsed.path) { // Strip the last path component, but keep the "/". - var index = parsed.path.lastIndexOf('/'); + const index = parsed.path.lastIndexOf("/"); if (index >= 0) { parsed.path = parsed.path.substring(0, index + 1); } diff --git a/node_modules/source-map/lib/wasm.js b/node_modules/source-map/lib/wasm.js new file mode 100644 index 00000000..88b18bea --- /dev/null +++ b/node_modules/source-map/lib/wasm.js @@ -0,0 +1,107 @@ +const readWasm = require("../lib/read-wasm"); + +/** + * Provide the JIT with a nice shape / hidden class. + */ +function Mapping() { + this.generatedLine = 0; + this.generatedColumn = 0; + this.lastGeneratedColumn = null; + this.source = null; + this.originalLine = null; + this.originalColumn = null; + this.name = null; +} + +let cachedWasm = null; + +module.exports = function wasm() { + if (cachedWasm) { + return cachedWasm; + } + + const callbackStack = []; + + cachedWasm = readWasm().then(buffer => { + return WebAssembly.instantiate(buffer, { + env: { + mapping_callback( + generatedLine, + generatedColumn, + + hasLastGeneratedColumn, + lastGeneratedColumn, + + hasOriginal, + source, + originalLine, + originalColumn, + + hasName, + name + ) { + const mapping = new Mapping(); + // JS uses 1-based line numbers, wasm uses 0-based. + mapping.generatedLine = generatedLine + 1; + mapping.generatedColumn = generatedColumn; + + if (hasLastGeneratedColumn) { + // JS uses inclusive last generated column, wasm uses exclusive. + mapping.lastGeneratedColumn = lastGeneratedColumn - 1; + } + + if (hasOriginal) { + mapping.source = source; + // JS uses 1-based line numbers, wasm uses 0-based. + mapping.originalLine = originalLine + 1; + mapping.originalColumn = originalColumn; + + if (hasName) { + mapping.name = name; + } + } + + callbackStack[callbackStack.length - 1](mapping); + }, + + start_all_generated_locations_for() { console.time("all_generated_locations_for"); }, + end_all_generated_locations_for() { console.timeEnd("all_generated_locations_for"); }, + + start_compute_column_spans() { console.time("compute_column_spans"); }, + end_compute_column_spans() { console.timeEnd("compute_column_spans"); }, + + start_generated_location_for() { console.time("generated_location_for"); }, + end_generated_location_for() { console.timeEnd("generated_location_for"); }, + + start_original_location_for() { console.time("original_location_for"); }, + end_original_location_for() { console.timeEnd("original_location_for"); }, + + start_parse_mappings() { console.time("parse_mappings"); }, + end_parse_mappings() { console.timeEnd("parse_mappings"); }, + + start_sort_by_generated_location() { console.time("sort_by_generated_location"); }, + end_sort_by_generated_location() { console.timeEnd("sort_by_generated_location"); }, + + start_sort_by_original_location() { console.time("sort_by_original_location"); }, + end_sort_by_original_location() { console.timeEnd("sort_by_original_location"); }, + } + }); + }).then(Wasm => { + return { + exports: Wasm.instance.exports, + withMappingCallback: (mappingCallback, f) => { + callbackStack.push(mappingCallback); + try { + f(); + } finally { + callbackStack.pop(); + } + } + }; + }).then(null, e => { + cachedWasm = null; + throw e; + }); + + return cachedWasm; +}; |
