Socket
Socket
Sign inDemoInstall

source-map

Package Overview
Dependencies
5
Maintainers
8
Versions
68
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.7.3 to 0.8.0-beta.0

lib/read-wasm-browser.js

35

CHANGELOG.md
# Change Log
## 0.8.0-beta.0
### Breaking changes
* [#350](https://github.com/mozilla/source-map/pull/350) -
Change browser detection logic for WASM loading.
* [#363](https://github.com/mozilla/source-map/pull/363) -
Change WASM loading detection to rely on `package.json#browser` field.
* [#362](https://github.com/mozilla/source-map/pull/362) -
Remove the `dist/` bundle.
* [#371](https://github.com/mozilla/source-map/pull/371) -
Reimplement sourcemap URL processing using the WHATWG URL API.
### Nonbreaking changes:
* [#339](https://github.com/mozilla/source-map/pull/339) -
Allow initializing the consumer `mappings.wasm` file as an `ArrayBuffer`.
### Internal Improvements:
* [#347](https://github.com/mozilla/source-map/pull/347) -
Improve tests.
* [#352](https://github.com/mozilla/source-map/pull/352) -
Improve documentation.
* [#361](https://github.com/mozilla/source-map/pull/361) -
Use newer Webpack CLI when bundling.
* [#364](https://github.com/mozilla/source-map/pull/364) -
Convert `IndexedSourceMapConsumer` implementation to pass more through
to `BasicSourceMapConsumer`.
* [#366](https://github.com/mozilla/source-map/pull/366) -
Normalize internal URL representation to be easier to follow.
* [#341](https://github.com/mozilla/source-map/pull/341) -
Use async functions to simplify `SourceMapConsumer.with` implementation.
## 0.7.3

@@ -4,0 +39,0 @@

53

lib/read-wasm.js

@@ -1,40 +0,25 @@

if (typeof fetch === "function") {
// Web version of reading a wasm file into an array buffer.
"use strict";
let mappingsWasmUrl = null;
// Note: This file is replaced with "read-wasm-browser.js" when this module is
// bundled with a packager that takes package.json#browser fields into account.
module.exports = function readWasm() {
if (typeof mappingsWasmUrl !== "string") {
throw new Error("You must provide the URL of lib/mappings.wasm by calling " +
"SourceMapConsumer.initialize({ 'lib/mappings.wasm': ... }) " +
"before using SourceMapConsumer");
}
const fs = require("fs");
const path = require("path");
return fetch(mappingsWasmUrl)
.then(response => response.arrayBuffer());
};
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;
}
module.exports.initialize = url => mappingsWasmUrl = url;
} 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);
});
resolve(data.buffer);
});
};
});
};
module.exports.initialize = _ => {
console.debug("SourceMapConsumer.initialize is a no-op when running in node.js");
};
}
module.exports.initialize = _ => {
console.debug("SourceMapConsumer.initialize is a no-op when running in node.js");
};

@@ -67,38 +67,12 @@ /* -*- Mode: js; js-indent-level: 2; -*- */

*/
static with(rawSourceMap, sourceMapUrl, f) {
// Note: The `acorn` version that `webpack` currently depends on doesn't
// support `async` functions, and the nodes that we support don't all have
// `.finally`. Therefore, this is written a bit more convolutedly than it
// should really be.
let consumer = null;
const promise = new SourceMapConsumer(rawSourceMap, sourceMapUrl);
return promise
.then(c => {
consumer = c;
return f(c);
})
.then(x => {
if (consumer) {
consumer.destroy();
}
return x;
}, e => {
if (consumer) {
consumer.destroy();
}
throw e;
});
static async with(rawSourceMap, sourceMapUrl, f) {
const consumer = await new SourceMapConsumer(rawSourceMap, sourceMapUrl);
try {
return await f(consumer);
} finally {
consumer.destroy();
}
}
/**
* Parse the mappings in a string in to a data structure which we can easily
* query (the ordered arrays in the `this.__generatedMappings` and
* `this.__originalMappings` properties).
*/
_parseMappings(aStr, aSourceRoot) {
throw new Error("Subclasses must implement _parseMappings");
}
/**
* Iterate over each mapping between an original source/line/column and a

@@ -209,7 +183,7 @@ * generated line/column in this source map.

const version = util.getArg(sourceMap, "version");
let sources = util.getArg(sourceMap, "sources");
const sources = util.getArg(sourceMap, "sources").map(String);
// 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 sourceRoot = util.getArg(sourceMap, "sourceRoot", null);
const sourcesContent = util.getArg(sourceMap, "sourcesContent", null);

@@ -225,22 +199,4 @@ const mappings = util.getArg(sourceMap, "mappings");

if (sourceRoot) {
sourceRoot = util.normalize(sourceRoot);
}
that._sourceLookupCache = new Map();
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

@@ -253,5 +209,5 @@ // are intended to be compressed and deduplicated, the TypeScript compiler

that._absoluteSources = that._sources.toArray().map(function(s) {
that._absoluteSources = ArraySet.fromArray(that._sources.toArray().map(function(s) {
return util.computeSourceURL(sourceRoot, s, aSourceMapURL);
});
}), true);

@@ -280,19 +236,26 @@ that.sourceRoot = sourceRoot;

_findSourceIndex(aSource) {
let relativeSource = aSource;
if (this.sourceRoot != null) {
relativeSource = util.relative(this.sourceRoot, relativeSource);
// In the most common usecases, we'll be constantly looking up the index for the same source
// files, so we cache the index lookup to avoid constantly recomputing the full URLs.
const cachedIndex = this._sourceLookupCache.get(aSource);
if (typeof cachedIndex === "number") {
return cachedIndex;
}
if (this._sources.has(relativeSource)) {
return this._sources.indexOf(relativeSource);
// Treat the source as map-relative overall by default.
const sourceAsMapRelative = util.computeSourceURL(null, aSource, this._sourceMapURL);
if (this._absoluteSources.has(sourceAsMapRelative)) {
const index = this._absoluteSources.indexOf(sourceAsMapRelative);
this._sourceLookupCache.set(aSource, index);
return index;
}
// 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;
}
// Fall back to treating the source as sourceRoot-relative.
const sourceAsSourceRootRelative = util.computeSourceURL(this.sourceRoot, aSource, this._sourceMapURL);
if (this._absoluteSources.has(sourceAsSourceRootRelative)) {
const index = this._absoluteSources.indexOf(sourceAsSourceRootRelative);
this._sourceLookupCache.set(aSource, index);
return index;
}
// To avoid this cache growing forever, we do not cache lookup misses.
return -1;

@@ -315,3 +278,3 @@ }

get sources() {
return this._absoluteSources.slice();
return this._absoluteSources.toArray();
}

@@ -321,3 +284,3 @@

if (this._mappingsPtr === 0) {
this._parseMappings(this._mappings, this.sourceRoot);
this._parseMappings();
}

@@ -333,3 +296,4 @@

*/
_parseMappings(aStr, aSourceRoot) {
_parseMappings() {
const aStr = this._mappings;
const size = aStr.length;

@@ -377,3 +341,2 @@

const order = aOrder || SourceMapConsumer.GENERATED_ORDER;
const sourceRoot = this.sourceRoot;

@@ -383,4 +346,3 @@ this._wasm.withMappingCallback(

if (mapping.source !== null) {
mapping.source = this._sources.at(mapping.source);
mapping.source = util.computeSourceURL(sourceRoot, mapping.source, this._sourceMapURL);
mapping.source = this._absoluteSources.at(mapping.source);

@@ -391,2 +353,5 @@ if (mapping.name !== null) {

}
if (this._computedColumnSpans && mapping.lastGeneratedColumn === null) {
mapping.lastGeneratedColumn = Infinity;
}

@@ -532,4 +497,3 @@ aCallback.call(context, mapping);

if (source !== null) {
source = this._sources.at(source);
source = util.computeSourceURL(this.sourceRoot, source, this._sourceMapURL);
source = this._absoluteSources.at(source);
}

@@ -586,26 +550,2 @@

let relativeSource = aSource;
if (this.sourceRoot != null) {
relativeSource = util.relative(this.sourceRoot, relativeSource);
}
let url;
if (this.sourceRoot != null
&& (url = util.urlParse(this.sourceRoot))) {
// XXX: file:// URIs and absolute paths lead to unexpected behavior for
// many users. We can help them out when they expect file:// URIs to
// behave like it would if they were running a local HTTP server. See
// https://bugzilla.mozilla.org/show_bug.cgi?id=885597.
const fileUriAbsPath = relativeSource.replace(/^file:\/\//, "");
if (url.scheme == "file"
&& this._sources.has(fileUriAbsPath)) {
return this.sourcesContent[this._sources.indexOf(fileUriAbsPath)];
}
if ((!url.path || url.path == "/")
&& this._sources.has("/" + relativeSource)) {
return this.sourcesContent[this._sources.indexOf("/" + relativeSource)];
}
}
// This function is used recursively from

@@ -619,3 +559,3 @@ // IndexedSourceMapConsumer.prototype.sourceContentFor. In that case, we

throw new Error('"' + relativeSource + '" is not in the SourceMap.');
throw new Error('"' + aSource + '" is not in the SourceMap.');
}

@@ -776,9 +716,2 @@

that._sources = new ArraySet();
that._names = new ArraySet();
that.__generatedMappings = null;
that.__originalMappings = null;
that.__generatedMappingsUnsorted = null;
that.__originalMappingsUnsorted = null;
let lastOffset = {

@@ -823,75 +756,2 @@ line: -1,

// `__generatedMappings` and `__originalMappings` are arrays that hold the
// parsed mapping coordinates from the source map's "mappings" attribute. They
// are lazily instantiated, accessed via the `_generatedMappings` and
// `_originalMappings` getters respectively, and we only parse the mappings
// and create these arrays once queried for a source location. We jump through
// these hoops because there can be many thousands of mappings, and parsing
// them is expensive, so we only want to do it if we must.
//
// Each object in the arrays is of the form:
//
// {
// generatedLine: The line number in the generated code,
// generatedColumn: The column number in the generated code,
// source: The path to the original source file that generated this
// chunk of code,
// originalLine: The line number in the original source that
// corresponds to this chunk of generated code,
// originalColumn: The column number in the original source that
// corresponds to this chunk of generated code,
// name: The name of the original symbol which generated this chunk of
// code.
// }
//
// All properties except for `generatedLine` and `generatedColumn` can be
// `null`.
//
// `_generatedMappings` is ordered by the generated positions.
//
// `_originalMappings` is ordered by the original positions.
get _generatedMappings() {
if (!this.__generatedMappings) {
this._sortGeneratedMappings();
}
return this.__generatedMappings;
}
get _originalMappings() {
if (!this.__originalMappings) {
this._sortOriginalMappings();
}
return this.__originalMappings;
}
get _generatedMappingsUnsorted() {
if (!this.__generatedMappingsUnsorted) {
this._parseMappings(this._mappings, this.sourceRoot);
}
return this.__generatedMappingsUnsorted;
}
get _originalMappingsUnsorted() {
if (!this.__originalMappingsUnsorted) {
this._parseMappings(this._mappings, this.sourceRoot);
}
return this.__originalMappingsUnsorted;
}
_sortGeneratedMappings() {
const mappings = this._generatedMappingsUnsorted;
mappings.sort(util.compareByGeneratedPositionsDeflated);
this.__generatedMappings = mappings;
}
_sortOriginalMappings() {
const mappings = this._originalMappingsUnsorted;
mappings.sort(util.compareByOriginalPositions);
this.__originalMappings = mappings;
}
/**

@@ -999,2 +859,12 @@ * The list of original sources.

_findSectionIndex(source) {
for (let i = 0; i < this._sections.length; i++) {
const { consumer } = this._sections[i];
if (consumer._findSourceIndex(source) !== -1) {
return i;
}
}
return -1;
}
/**

@@ -1019,22 +889,33 @@ * Returns the generated line and column information for the original source,

generatedPositionFor(aArgs) {
for (let i = 0; i < this._sections.length; i++) {
const section = this._sections[i];
const index = this._findSectionIndex(util.getArg(aArgs, "source"));
const section = index >= 0 ? this._sections[index] : null;
const nextSection =
index >= 0 && index + 1 < this._sections.length
? this._sections[index + 1]
: null;
// Only consider this section if the requested source is in the list of
// sources of the consumer.
if (section.consumer._findSourceIndex(util.getArg(aArgs, "source")) === -1) {
continue;
const generatedPosition =
section && section.consumer.generatedPositionFor(aArgs);
if (generatedPosition && generatedPosition.line !== null) {
const lineShift = section.generatedOffset.generatedLine - 1;
const columnShift = section.generatedOffset.generatedColumn - 1;
if (generatedPosition.line === 1) {
generatedPosition.column += columnShift;
if (typeof generatedPosition.lastColumn === "number") {
generatedPosition.lastColumn += columnShift;
}
}
const generatedPosition = section.consumer.generatedPositionFor(aArgs);
if (generatedPosition) {
const ret = {
line: generatedPosition.line +
(section.generatedOffset.generatedLine - 1),
column: generatedPosition.column +
(section.generatedOffset.generatedLine === generatedPosition.line
? section.generatedOffset.generatedColumn - 1
: 0)
};
return ret;
if (
generatedPosition.lastColumn === Infinity &&
nextSection &&
generatedPosition.line === nextSection.generatedOffset.generatedLine
) {
generatedPosition.lastColumn =
nextSection.generatedOffset.generatedColumn - 2;
}
generatedPosition.line += lineShift;
return generatedPosition;
}

@@ -1044,202 +925,83 @@

line: null,
column: null
column: null,
lastColumn: null
};
}
/**
* Parse the mappings in a string in to a data structure which we can easily
* query (the ordered arrays in the `this.__generatedMappings` and
* `this.__originalMappings` properties).
*/
_parseMappings(aStr, aSourceRoot) {
const generatedMappings = this.__generatedMappingsUnsorted = [];
const originalMappings = this.__originalMappingsUnsorted = [];
for (let i = 0; i < this._sections.length; i++) {
const section = this._sections[i];
allGeneratedPositionsFor(aArgs) {
const index = this._findSectionIndex(util.getArg(aArgs, "source"));
const section = index >= 0 ? this._sections[index] : null;
const nextSection =
index >= 0 && index + 1 < this._sections.length
? this._sections[index + 1]
: null;
const sectionMappings = [];
section.consumer.eachMapping(m => sectionMappings.push(m));
if (!section) return [];
for (let j = 0; j < sectionMappings.length; j++) {
const mapping = sectionMappings[j];
return section.consumer.allGeneratedPositionsFor(aArgs).map(
generatedPosition => {
const lineShift = section.generatedOffset.generatedLine - 1;
const columnShift = section.generatedOffset.generatedColumn - 1;
// 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);
if (generatedPosition.line === 1) {
generatedPosition.column += columnShift;
if (typeof generatedPosition.lastColumn === "number") {
generatedPosition.lastColumn += columnShift;
}
}
let name = null;
if (mapping.name) {
this._names.add(mapping.name);
name = this._names.indexOf(mapping.name);
if (
generatedPosition.lastColumn === Infinity &&
nextSection &&
generatedPosition.line === nextSection.generatedOffset.generatedLine
) {
generatedPosition.lastColumn =
nextSection.generatedOffset.generatedColumn - 2;
}
generatedPosition.line += lineShift;
// The mappings coming from the consumer for the section have
// generated positions relative to the start of the section, so we
// need to offset them to be relative to the start of the concatenated
// generated file.
const adjustedMapping = {
source,
generatedLine: mapping.generatedLine +
(section.generatedOffset.generatedLine - 1),
generatedColumn: mapping.generatedColumn +
(section.generatedOffset.generatedLine === mapping.generatedLine
? section.generatedOffset.generatedColumn - 1
: 0),
originalLine: mapping.originalLine,
originalColumn: mapping.originalColumn,
name
};
generatedMappings.push(adjustedMapping);
if (typeof adjustedMapping.originalLine === "number") {
originalMappings.push(adjustedMapping);
}
return generatedPosition;
}
}
);
}
eachMapping(aCallback, aContext, aOrder) {
const context = aContext || null;
const order = aOrder || SourceMapConsumer.GENERATED_ORDER;
this._sections.forEach((section, index) => {
const nextSection =
index + 1 < this._sections.length
? this._sections[index + 1]
: null;
const { generatedOffset } = section;
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 lineShift = generatedOffset.generatedLine - 1;
const columnShift = generatedOffset.generatedColumn - 1;
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);
}
section.consumer.eachMapping(function(mapping) {
if (mapping.generatedLine === 1) {
mapping.generatedColumn += columnShift;
/**
* 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;
if (typeof mapping.lastGeneratedColumn === "number") {
mapping.lastGeneratedColumn += columnShift;
}
mappings.push({
line: util.getArg(mapping, "generatedLine", null),
column: util.getArg(mapping, "generatedColumn", null),
lastColumn,
});
}
mapping = this._originalMappings[++index];
if (
mapping.lastGeneratedColumn === Infinity &&
nextSection &&
mapping.generatedLine === nextSection.generatedOffset.generatedLine
) {
mapping.lastGeneratedColumn =
nextSection.generatedOffset.generatedColumn - 2;
}
} else {
const originalColumn = mapping.originalColumn;
mapping.generatedLine += lineShift;
// 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,
});
aCallback.call(this, mapping);
}, aContext, aOrder);
});
}
mapping = this._originalMappings[++index];
}
}
computeColumnSpans() {
for (let i = 0; i < this._sections.length; i++) {
this._sections[i].consumer.computeColumnSpans();
}
return mappings;
}

@@ -1246,0 +1008,0 @@

@@ -8,2 +8,4 @@ /* -*- Mode: js; js-indent-level: 2; -*- */

const URL = require("./url");
/**

@@ -30,257 +32,2 @@ * This is a helper function for getting values from parameter/options

const urlRegexp = /^(?:([\w+\-.]+):)?\/\/(?:(\w+:\w+)@)?([\w.-]*)(?::(\d+))?(.*)$/;
const dataUrlRegexp = /^data:.+\,.+$/;
function urlParse(aUrl) {
const match = aUrl.match(urlRegexp);
if (!match) {
return null;
}
return {
scheme: match[1],
auth: match[2],
host: match[3],
port: match[4],
path: match[5]
};
}
exports.urlParse = urlParse;
function urlGenerate(aParsedUrl) {
let url = "";
if (aParsedUrl.scheme) {
url += aParsedUrl.scheme + ":";
}
url += "//";
if (aParsedUrl.auth) {
url += aParsedUrl.auth + "@";
}
if (aParsedUrl.host) {
url += aParsedUrl.host;
}
if (aParsedUrl.port) {
url += ":" + aParsedUrl.port;
}
if (aParsedUrl.path) {
url += aParsedUrl.path;
}
return url;
}
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:
*
* - Replaces consecutive slashes with one slash.
* - Removes unnecessary '.' parts.
* - Removes unnecessary '<dir>/..' parts.
*
* Based on code in the Node.js 'path' core module.
*
* @param aPath The path or url to normalize.
*/
const normalize = lruMemoize(function normalize(aPath) {
let path = aPath;
const url = urlParse(aPath);
if (url) {
if (!url.path) {
return aPath;
}
path = url.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++;
}
}
}
let up = 0;
for (i = parts.length - 1; i >= 0; i--) {
const part = parts[i];
if (part === ".") {
parts.splice(i, 1);
} else if (part === "..") {
up++;
} else if (up > 0) {
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.
parts.splice(i + 1, up);
up = 0;
} else {
parts.splice(i, 2);
up--;
}
}
}
path = parts.join("/");
if (path === "") {
path = isAbsolute ? "/" : ".";
}
if (url) {
url.path = path;
return urlGenerate(url);
}
return path;
});
exports.normalize = normalize;
/**
* Joins two paths/URLs.
*
* @param aRoot The root path or URL.
* @param aPath The path or URL to be joined with the root.
*
* - If aPath is a URL or a data URI, aPath is returned, unless aPath is a
* scheme-relative URL: Then the scheme of aRoot, if any, is prepended
* first.
* - Otherwise aPath is a path. If aRoot is a URL, then its path portion
* is updated with the result and aRoot is returned. Otherwise the result
* is returned.
* - If aPath is absolute, the result is aPath.
* - Otherwise the two paths are joined with a slash.
* - Joining for example 'http://' and 'www.example.com' is also supported.
*/
function join(aRoot, aPath) {
if (aRoot === "") {
aRoot = ".";
}
if (aPath === "") {
aPath = ".";
}
const aPathUrl = urlParse(aPath);
const aRootUrl = urlParse(aRoot);
if (aRootUrl) {
aRoot = aRootUrl.path || "/";
}
// `join(foo, '//www.example.org')`
if (aPathUrl && !aPathUrl.scheme) {
if (aRootUrl) {
aPathUrl.scheme = aRootUrl.scheme;
}
return urlGenerate(aPathUrl);
}
if (aPathUrl || aPath.match(dataUrlRegexp)) {
return aPath;
}
// `join('http://', 'www.example.com')`
if (aRootUrl && !aRootUrl.host && !aRootUrl.path) {
aRootUrl.host = aPath;
return urlGenerate(aRootUrl);
}
const joined = aPath.charAt(0) === "/"
? aPath
: normalize(aRoot.replace(/\/+$/, "") + "/" + aPath);
if (aRootUrl) {
aRootUrl.path = joined;
return urlGenerate(aRootUrl);
}
return joined;
}
exports.join = join;
exports.isAbsolute = function(aPath) {
return aPath.charAt(0) === "/" || urlRegexp.test(aPath);
};
/**
* Make a path relative to a URL or another path.
*
* @param aRoot The root path or URL.
* @param aPath The path or URL to be made relative to aRoot.
*/
function relative(aRoot, aPath) {
if (aRoot === "") {
aRoot = ".";
}
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.
let level = 0;
while (aPath.indexOf(aRoot + "/") !== 0) {
const index = aRoot.lastIndexOf("/");
if (index < 0) {
return aPath;
}
// If the only part of the root that is left is the scheme (i.e. http://,
// file:///, etc.), one or more slashes (/), or simply nothing at all, we
// have exhausted all components, so the path is not relative to the root.
aRoot = aRoot.slice(0, index);
if (aRoot.match(/^([^\/]+:\/)?\/*$/)) {
return aPath;
}
++level;
}
// Make sure we add a "../" for each component we removed from the root.
return Array(level + 1).join("../") + aPath.substr(aRoot.length + 1);
}
exports.relative = relative;
const supportsNullProto = (function() {

@@ -356,50 +103,27 @@ const obj = Object.create(null);

/**
* Comparator between two mappings where the original positions are compared.
*
* Optionally pass in `true` as `onlyCompareGenerated` to consider two
* mappings with the same original source/line/column, but different generated
* line and column the same. Useful when searching for a mapping with a
* stubbed out mapping.
*/
function compareByOriginalPositions(mappingA, mappingB, onlyCompareOriginal) {
let cmp = strcmp(mappingA.source, mappingB.source);
if (cmp !== 0) {
return cmp;
function strcmp(aStr1, aStr2) {
if (aStr1 === aStr2) {
return 0;
}
cmp = mappingA.originalLine - mappingB.originalLine;
if (cmp !== 0) {
return cmp;
if (aStr1 === null) {
return 1; // aStr2 !== null
}
cmp = mappingA.originalColumn - mappingB.originalColumn;
if (cmp !== 0 || onlyCompareOriginal) {
return cmp;
if (aStr2 === null) {
return -1; // aStr1 !== null
}
cmp = mappingA.generatedColumn - mappingB.generatedColumn;
if (cmp !== 0) {
return cmp;
if (aStr1 > aStr2) {
return 1;
}
cmp = mappingA.generatedLine - mappingB.generatedLine;
if (cmp !== 0) {
return cmp;
}
return strcmp(mappingA.name, mappingB.name);
return -1;
}
exports.compareByOriginalPositions = compareByOriginalPositions;
/**
* Comparator between two mappings with deflated source and name indices where
* Comparator between two mappings with inflated source and name strings where
* the generated positions are compared.
*
* Optionally pass in `true` as `onlyCompareGenerated` to consider two
* mappings with the same generated line and column, but different
* source/name/original line and column the same. Useful when searching for a
* mapping with a stubbed out mapping.
*/
function compareByGeneratedPositionsDeflated(mappingA, mappingB, onlyCompareGenerated) {
function compareByGeneratedPositionsInflated(mappingA, mappingB) {
let cmp = mappingA.generatedLine - mappingB.generatedLine;

@@ -411,3 +135,3 @@ if (cmp !== 0) {

cmp = mappingA.generatedColumn - mappingB.generatedColumn;
if (cmp !== 0 || onlyCompareGenerated) {
if (cmp !== 0) {
return cmp;

@@ -433,68 +157,252 @@ }

}
exports.compareByGeneratedPositionsDeflated = compareByGeneratedPositionsDeflated;
exports.compareByGeneratedPositionsInflated = compareByGeneratedPositionsInflated;
function strcmp(aStr1, aStr2) {
if (aStr1 === aStr2) {
return 0;
}
/**
* Strip any JSON XSSI avoidance prefix from the string (as documented
* in the source maps specification), and then parse the string as
* JSON.
*/
function parseSourceMapInput(str) {
return JSON.parse(str.replace(/^\)]}'[^\n]*\n/, ""));
}
exports.parseSourceMapInput = parseSourceMapInput;
if (aStr1 === null) {
return 1; // aStr2 !== null
}
// We use 'http' as the base here because we want URLs processed relative
// to the safe base to be treated as "special" URLs during parsing using
// the WHATWG URL parsing. This ensures that backslash normalization
// applies to the path and such.
const PROTOCOL = "http:";
const PROTOCOL_AND_HOST = `${PROTOCOL}//host`;
if (aStr2 === null) {
return -1; // aStr1 !== null
/**
* Make it easy to create small utilities that tweak a URL's path.
*/
function createSafeHandler(cb) {
return input => {
const type = getURLType(input);
const base = buildSafeBase(input);
const url = new URL(input, base);
cb(url);
const result = url.toString();
if (type === "absolute") {
return result;
} else if (type === "scheme-relative") {
return result.slice(PROTOCOL.length);
} else if (type === "path-absolute") {
return result.slice(PROTOCOL_AND_HOST.length);
}
// This assumes that the callback will only change
// the path, search and hash values.
return computeRelativeURL(base, result);
};
}
function withBase(url, base) {
return new URL(url, base).toString();
}
function buildUniqueSegment(prefix, str) {
let id = 0;
do {
const ident = prefix + (id++);
if (str.indexOf(ident) === -1) return ident;
} while (true);
}
function buildSafeBase(str) {
const maxDotParts = str.split("..").length - 1;
// If we used a segment that also existed in `str`, then we would be unable
// to compute relative paths. For example, if `segment` were just "a":
//
// const url = "../../a/"
// const base = buildSafeBase(url); // http://host/a/a/
// const joined = "http://host/a/";
// const result = relative(base, joined);
//
// Expected: "../../a/";
// Actual: "a/"
//
const segment = buildUniqueSegment("p", str);
let base = `${PROTOCOL_AND_HOST}/`;
for (let i = 0; i < maxDotParts; i++) {
base += `${segment}/`;
}
return base;
}
if (aStr1 > aStr2) {
return 1;
const ABSOLUTE_SCHEME = /^[A-Za-z0-9\+\-\.]+:/;
function getURLType(url) {
if (url[0] === "/") {
if (url[1] === "/") return "scheme-relative";
return "path-absolute";
}
return -1;
return ABSOLUTE_SCHEME.test(url) ? "absolute" : "path-relative";
}
/**
* Comparator between two mappings with inflated source and name strings where
* the generated positions are compared.
* Given two URLs that are assumed to be on the same
* protocol/host/user/password build a relative URL from the
* path, params, and hash values.
*
* @param rootURL The root URL that the target will be relative to.
* @param targetURL The target that the relative URL points to.
* @return A rootURL-relative, normalized URL value.
*/
function compareByGeneratedPositionsInflated(mappingA, mappingB) {
let cmp = mappingA.generatedLine - mappingB.generatedLine;
if (cmp !== 0) {
return cmp;
function computeRelativeURL(rootURL, targetURL) {
if (typeof rootURL === "string") rootURL = new URL(rootURL);
if (typeof targetURL === "string") targetURL = new URL(targetURL);
const targetParts = targetURL.pathname.split("/");
const rootParts = rootURL.pathname.split("/");
// If we've got a URL path ending with a "/", we remove it since we'd
// otherwise be relative to the wrong location.
if (rootParts.length > 0 && !rootParts[rootParts.length - 1]) {
rootParts.pop();
}
cmp = mappingA.generatedColumn - mappingB.generatedColumn;
if (cmp !== 0) {
return cmp;
while (
targetParts.length > 0 &&
rootParts.length > 0 &&
targetParts[0] === rootParts[0]
) {
targetParts.shift();
rootParts.shift();
}
cmp = strcmp(mappingA.source, mappingB.source);
if (cmp !== 0) {
return cmp;
const relativePath = rootParts
.map(() => "..")
.concat(targetParts)
.join("/");
return relativePath + targetURL.search + targetURL.hash;
}
/**
* Given a URL, ensure that it is treated as a directory URL.
*
* @param url
* @return A normalized URL value.
*/
const ensureDirectory = createSafeHandler(url => {
url.pathname = url.pathname.replace(/\/?$/, "/");
});
/**
* Given a URL, strip off any filename if one is present.
*
* @param url
* @return A normalized URL value.
*/
const trimFilename = createSafeHandler(url => {
url.href = new URL(".", url.toString()).toString();
});
/**
* Normalize a given URL.
* * Convert backslashes.
* * Remove any ".." and "." segments.
*
* @param url
* @return A normalized URL value.
*/
const normalize = createSafeHandler(url => {});
exports.normalize = normalize;
/**
* Joins two paths/URLs.
*
* All returned URLs will be normalized.
*
* @param aRoot The root path or URL. Assumed to reference a directory.
* @param aPath The path or URL to be joined with the root.
* @return A joined and normalized URL value.
*/
function join(aRoot, aPath) {
const pathType = getURLType(aPath);
const rootType = getURLType(aRoot);
aRoot = ensureDirectory(aRoot);
if (pathType === "absolute") {
return withBase(aPath, undefined);
}
if (rootType === "absolute") {
return withBase(aPath, aRoot);
}
cmp = mappingA.originalLine - mappingB.originalLine;
if (cmp !== 0) {
return cmp;
if (pathType === "scheme-relative") {
return normalize(aPath);
}
if (rootType === "scheme-relative") {
return withBase(aPath, withBase(aRoot, PROTOCOL_AND_HOST)).slice(PROTOCOL.length);
}
cmp = mappingA.originalColumn - mappingB.originalColumn;
if (cmp !== 0) {
return cmp;
if (pathType === "path-absolute") {
return normalize(aPath);
}
if (rootType === "path-absolute") {
return withBase(aPath, withBase(aRoot, PROTOCOL_AND_HOST)).slice(PROTOCOL_AND_HOST.length);
}
return strcmp(mappingA.name, mappingB.name);
const base = buildSafeBase(aPath + aRoot);
const newPath = withBase(aPath, withBase(aRoot, base));
return computeRelativeURL(base, newPath);
}
exports.compareByGeneratedPositionsInflated = compareByGeneratedPositionsInflated;
exports.join = join;
/**
* Strip any JSON XSSI avoidance prefix from the string (as documented
* in the source maps specification), and then parse the string as
* JSON.
* Make a path relative to a URL or another path. If returning a
* relative URL is not possible, the original target will be returned.
* All returned URLs will be normalized.
*
* @param aRoot The root path or URL.
* @param aPath The path or URL to be made relative to aRoot.
* @return A rootURL-relative (if possible), normalized URL value.
*/
function parseSourceMapInput(str) {
return JSON.parse(str.replace(/^\)]}'[^\n]*\n/, ""));
function relative(rootURL, targetURL) {
const result = relativeIfPossible(rootURL, targetURL);
return typeof result === "string" ? result : normalize(targetURL);
}
exports.parseSourceMapInput = parseSourceMapInput;
exports.relative = relative;
function relativeIfPossible(rootURL, targetURL) {
const urlType = getURLType(rootURL);
if (urlType !== getURLType(targetURL)) {
return null;
}
const base = buildSafeBase(rootURL + targetURL);
const root = new URL(rootURL, base);
const target = new URL(targetURL, base);
try {
new URL("", target.toString());
} catch (err) {
// Bail if the URL doesn't support things being relative to it,
// For example, data: and blob: URLs.
return null;
}
if (
target.protocol !== root.protocol ||
target.user !== root.user ||
target.password !== root.password ||
target.hostname !== root.hostname ||
target.port !== root.port
) {
return null;
}
return computeRelativeURL(root, target);
}
/**

@@ -505,48 +413,32 @@ * Compute the URL of a source given the the source root, the source's

function computeSourceURL(sourceRoot, sourceURL, sourceMapURL) {
sourceURL = sourceURL || "";
if (sourceRoot) {
// This follows what Chrome does.
if (sourceRoot[sourceRoot.length - 1] !== "/" && sourceURL[0] !== "/") {
sourceRoot += "/";
}
// The spec says:
// Line 4: An optional source root, useful for relocating source
// files on a server or removing repeated values in the
// “sources” entry. This value is prepended to the individual
// entries in the “source” field.
sourceURL = sourceRoot + sourceURL;
}
// Historically, SourceMapConsumer did not take the sourceMapURL as
// a parameter. This mode is still somewhat supported, which is why
// this code block is conditional. However, it's preferable to pass
// the source map URL to SourceMapConsumer, so that this function
// can implement the source URL resolution algorithm as outlined in
// the spec. This block is basically the equivalent of:
// new URL(sourceURL, sourceMapURL).toString()
// ... except it avoids using URL, which wasn't available in the
// older releases of node still supported by this library.
// The source map spec states that "sourceRoot" and "sources" entries are to be appended. While
// that is a little vague, implementations have generally interpreted that as joining the
// URLs with a `/` between then, assuming the "sourceRoot" doesn't already end with one.
// For example,
//
// The spec says:
// If the sources are not absolute URLs after prepending of the
// “sourceRoot”, the sources are resolved relative to the
// SourceMap (like resolving script src in a html document).
if (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 "/".
const index = parsed.path.lastIndexOf("/");
if (index >= 0) {
parsed.path = parsed.path.substring(0, index + 1);
}
}
sourceURL = join(urlGenerate(parsed), sourceURL);
// sourceRoot: "some-dir",
// sources: ["/some-path.js"]
//
// and
//
// sourceRoot: "some-dir/",
// sources: ["/some-path.js"]
//
// must behave as "some-dir/some-path.js".
//
// With this library's the transition to a more URL-focused implementation, that behavior is
// preserved here. To acheive that, we trim the "/" from absolute-path when a sourceRoot value
// is present in order to make the sources entries behave as if they are relative to the
// "sourceRoot", as they would have if the two strings were simply concated.
if (sourceRoot && getURLType(sourceURL) === "path-absolute") {
sourceURL = sourceURL.replace(/^\//, "");
}
return normalize(sourceURL);
let url = normalize(sourceURL || "");
// Parsing URLs can be expensive, so we only perform these joins when needed.
if (sourceRoot) url = join(sourceRoot, url);
if (sourceMapURL) url = join(trimFilename(sourceMapURL), url);
return url;
}
exports.computeSourceURL = computeSourceURL;
{
"name": "source-map",
"description": "Generates and consumes source maps",
"version": "0.7.3",
"version": "0.8.0-beta.0",
"homepage": "https://github.com/mozilla/source-map",

@@ -51,8 +51,14 @@ "author": "Nick Fitzgerald <nfitzgerald@mozilla.com>",

"types": "./source-map.d.ts",
"browser": {
"./lib/url.js": "./lib/url-browser.js",
"./lib/read-wasm.js": "./lib/read-wasm-browser.js"
},
"files": [
"source-map.js",
"source-map.d.ts",
"lib/",
"dist/source-map.js"
"lib/"
],
"publishConfig": {
"tag": "next"
},
"engines": {

@@ -65,6 +71,3 @@ "node": ">= 8"

"prebuild": "npm run lint",
"build": "webpack --color",
"pretest": "npm run build",
"test": "node test/run-tests.js",
"precoverage": "npm run build",
"coverage": "nyc node test/run-tests.js",

@@ -80,3 +83,3 @@ "setup": "mkdir -p coverage && cp -n .waiting.html coverage/index.html || true",

"devDependencies": {
"doctoc": "^0.15.0",
"doctoc": "^1.3.1",
"eslint": "^4.19.1",

@@ -86,4 +89,3 @@ "live-server": "^1.2.0",

"nyc": "^11.7.1",
"watch": "^1.0.2",
"webpack": "^3.10"
"watch": "^1.0.2"
},

@@ -93,3 +95,6 @@ "nyc": {

},
"typings": "source-map"
"typings": "source-map",
"dependencies": {
"whatwg-url": "^7.0.0"
}
}

@@ -211,3 +211,3 @@ # Source Map

* `"lib/mappings.wasm"`: A `String` containing the URL of the
`lib/mappings.wasm` file.
`lib/mappings.wasm` file, or an `ArrayBuffer` with the contents of `lib/mappings.wasm`.

@@ -214,0 +214,0 @@ ```js

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc