Bug 1076887 - Update the tree's copy of the mozilla/source-map library to 0.1.40. r=past

This commit is contained in:
Nick Fitzgerald 2014-10-02 08:44:00 +02:00
parent cedc62cb8d
commit 43b1ddc3df
8 changed files with 1326 additions and 219 deletions

View File

@ -1,4 +1,4 @@
/* -*- js-indent-level: 2; indent-tabs-mode: nil -*- */
/* -*- Mode: js; js-indent-level: 2; -*- */
/*
* Copyright 2011 Mozilla Foundation and contributors
* Licensed under the New BSD license. See LICENSE or:
@ -46,7 +46,7 @@ define('source-map/source-map-consumer', ['require', 'exports', 'module' , 'sou
* - sourceRoot: Optional. The URL root from which all sources are relative.
* - sourcesContent: Optional. An array of contents of the original source files.
* - mappings: A string of base64 VLQs which contain the actual mappings.
* - file: The generated file this source map is associated with.
* - file: Optional. The generated file this source map is associated with.
*
* Here is an example source map, taken from the source map spec[0]:
*
@ -133,7 +133,7 @@ define('source-map/source-map-consumer', ['require', 'exports', 'module' , 'sou
Object.defineProperty(SourceMapConsumer.prototype, 'sources', {
get: function () {
return this._sources.toArray().map(function (s) {
return this.sourceRoot ? util.join(this.sourceRoot, s) : s;
return this.sourceRoot != null ? util.join(this.sourceRoot, s) : s;
}, this);
}
});
@ -194,6 +194,12 @@ define('source-map/source-map-consumer', ['require', 'exports', 'module' , 'sou
}
});
SourceMapConsumer.prototype._nextCharIsMappingSeparator =
function SourceMapConsumer_nextCharIsMappingSeparator(aStr) {
var c = aStr.charAt(0);
return c === ";" || c === ",";
};
/**
* Parse the mappings in a string in to a data structure which we can easily
* query (the ordered arrays in the `this.__generatedMappings` and
@ -207,10 +213,9 @@ define('source-map/source-map-consumer', ['require', 'exports', 'module' , 'sou
var previousOriginalColumn = 0;
var previousSource = 0;
var previousName = 0;
var mappingSeparator = /^[,;]/;
var str = aStr;
var temp = {};
var mapping;
var temp;
while (str.length > 0) {
if (str.charAt(0) === ';') {
@ -226,41 +231,41 @@ define('source-map/source-map-consumer', ['require', 'exports', 'module' , 'sou
mapping.generatedLine = generatedLine;
// Generated column.
temp = base64VLQ.decode(str);
base64VLQ.decode(str, temp);
mapping.generatedColumn = previousGeneratedColumn + temp.value;
previousGeneratedColumn = mapping.generatedColumn;
str = temp.rest;
if (str.length > 0 && !mappingSeparator.test(str.charAt(0))) {
if (str.length > 0 && !this._nextCharIsMappingSeparator(str)) {
// Original source.
temp = base64VLQ.decode(str);
base64VLQ.decode(str, temp);
mapping.source = this._sources.at(previousSource + temp.value);
previousSource += temp.value;
str = temp.rest;
if (str.length === 0 || mappingSeparator.test(str.charAt(0))) {
if (str.length === 0 || this._nextCharIsMappingSeparator(str)) {
throw new Error('Found a source, but no line and column');
}
// Original line.
temp = base64VLQ.decode(str);
base64VLQ.decode(str, temp);
mapping.originalLine = previousOriginalLine + temp.value;
previousOriginalLine = mapping.originalLine;
// Lines are stored 0-based
mapping.originalLine += 1;
str = temp.rest;
if (str.length === 0 || mappingSeparator.test(str.charAt(0))) {
if (str.length === 0 || this._nextCharIsMappingSeparator(str)) {
throw new Error('Found a source and line, but no column');
}
// Original column.
temp = base64VLQ.decode(str);
base64VLQ.decode(str, temp);
mapping.originalColumn = previousOriginalColumn + temp.value;
previousOriginalColumn = mapping.originalColumn;
str = temp.rest;
if (str.length > 0 && !mappingSeparator.test(str.charAt(0))) {
if (str.length > 0 && !this._nextCharIsMappingSeparator(str)) {
// Original name.
temp = base64VLQ.decode(str);
base64VLQ.decode(str, temp);
mapping.name = this._names.at(previousName + temp.value);
previousName += temp.value;
str = temp.rest;
@ -274,6 +279,7 @@ define('source-map/source-map-consumer', ['require', 'exports', 'module' , 'sou
}
}
this.__generatedMappings.sort(util.compareByGeneratedPositions);
this.__originalMappings.sort(util.compareByOriginalPositions);
};
@ -329,9 +335,9 @@ define('source-map/source-map-consumer', ['require', 'exports', 'module' , 'sou
"generatedColumn",
util.compareByGeneratedPositions);
if (mapping) {
if (mapping && mapping.generatedLine === needle.generatedLine) {
var source = util.getArg(mapping, 'source', null);
if (source && this.sourceRoot) {
if (source != null && this.sourceRoot != null) {
source = util.join(this.sourceRoot, source);
}
return {
@ -361,7 +367,7 @@ define('source-map/source-map-consumer', ['require', 'exports', 'module' , 'sou
return null;
}
if (this.sourceRoot) {
if (this.sourceRoot != null) {
aSource = util.relative(this.sourceRoot, aSource);
}
@ -370,7 +376,7 @@ define('source-map/source-map-consumer', ['require', 'exports', 'module' , 'sou
}
var url;
if (this.sourceRoot
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
@ -413,7 +419,7 @@ define('source-map/source-map-consumer', ['require', 'exports', 'module' , 'sou
originalColumn: util.getArg(aArgs, 'column')
};
if (this.sourceRoot) {
if (this.sourceRoot != null) {
needle.source = util.relative(this.sourceRoot, needle.source);
}
@ -475,7 +481,7 @@ define('source-map/source-map-consumer', ['require', 'exports', 'module' , 'sou
var sourceRoot = this.sourceRoot;
mappings.map(function (mapping) {
var source = mapping.source;
if (source && sourceRoot) {
if (source != null && sourceRoot != null) {
source = util.join(sourceRoot, source);
}
return {
@ -521,8 +527,8 @@ define('source-map/util', ['require', 'exports', 'module' , ], function(require,
}
exports.getArg = getArg;
var urlRegexp = /([\w+\-.]+):\/\/((\w+:\w+)@)?([\w.]+)?(:(\d+))?(\S+)?/;
var dataUrlRegexp = /^data:.+\,.+/;
var urlRegexp = /^(?:([\w+\-.]+):)?\/\/(?:(\w+:\w+)@)?([\w.]*)(?::(\d+))?(\S*)$/;
var dataUrlRegexp = /^data:.+\,.+$/;
function urlParse(aUrl) {
var match = aUrl.match(urlRegexp);
@ -531,18 +537,22 @@ define('source-map/util', ['require', 'exports', 'module' , ], function(require,
}
return {
scheme: match[1],
auth: match[3],
host: match[4],
port: match[6],
path: match[7]
auth: match[2],
host: match[3],
port: match[4],
path: match[5]
};
}
exports.urlParse = urlParse;
function urlGenerate(aParsedUrl) {
var url = aParsedUrl.scheme + "://";
var url = '';
if (aParsedUrl.scheme) {
url += aParsedUrl.scheme + ':';
}
url += '//';
if (aParsedUrl.auth) {
url += aParsedUrl.auth + "@"
url += aParsedUrl.auth + '@';
}
if (aParsedUrl.host) {
url += aParsedUrl.host;
@ -557,22 +567,146 @@ define('source-map/util', ['require', 'exports', 'module' , ], function(require,
}
exports.urlGenerate = urlGenerate;
function join(aRoot, aPath) {
var url;
/**
* Normalizes a path, or the path portion of a URL:
*
* - Replaces consequtive 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.
*/
function normalize(aPath) {
var path = aPath;
var url = urlParse(aPath);
if (url) {
if (!url.path) {
return aPath;
}
path = url.path;
}
var isAbsolute = (path.charAt(0) === '/');
if (aPath.match(urlRegexp) || aPath.match(dataUrlRegexp)) {
var parts = path.split(/\/+/);
for (var part, up = 0, i = parts.length - 1; i >= 0; i--) {
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 = ".";
}
var aPathUrl = urlParse(aPath);
var 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;
}
if (aPath.charAt(0) === '/' && (url = urlParse(aRoot))) {
url.path = aPath;
return urlGenerate(url);
// `join('http://', 'www.example.com')`
if (aRootUrl && !aRootUrl.host && !aRootUrl.path) {
aRootUrl.host = aPath;
return urlGenerate(aRootUrl);
}
return aRoot.replace(/\/$/, '') + '/' + aPath;
var joined = aPath.charAt(0) === '/'
? aPath
: normalize(aRoot.replace(/\/+$/, '') + '/' + aPath);
if (aRootUrl) {
aRootUrl.path = joined;
return urlGenerate(aRootUrl);
}
return joined;
}
exports.join = join;
/**
* 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(/\/$/, '');
// XXX: It is possible to remove this block, and the tests still pass!
var url = urlParse(aRoot);
if (aPath.charAt(0) == "/" && url && url.path == "/") {
return aPath.slice(1);
}
return aPath.indexOf(aRoot + '/') === 0
? aPath.substr(aRoot.length + 1)
: aPath;
}
exports.relative = relative;
/**
* Because behavior goes wacky when you set `__proto__` on objects, we
* have to prefix all the strings in our set with an arbitrary character.
@ -592,20 +726,6 @@ define('source-map/util', ['require', 'exports', 'module' , ], function(require,
}
exports.fromSetString = fromSetString;
function relative(aRoot, aPath) {
aRoot = aRoot.replace(/\/$/, '');
var url = urlParse(aRoot);
if (aPath.charAt(0) == "/" && url && url.path == "/") {
return aPath.slice(1);
}
return aPath.indexOf(aRoot + '/') === 0
? aPath.substr(aRoot.length + 1)
: aPath;
}
exports.relative = relative;
function strcmp(aStr1, aStr2) {
var s1 = aStr1 || "";
var s2 = aStr2 || "";
@ -980,9 +1100,9 @@ define('source-map/base64-vlq', ['require', 'exports', 'module' , 'source-map/b
/**
* Decodes the next base 64 VLQ value from the given string and returns the
* value and the rest of the string.
* value and the rest of the string via the out parameter.
*/
exports.decode = function base64VLQ_decode(aStr) {
exports.decode = function base64VLQ_decode(aStr, aOutParam) {
var i = 0;
var strLen = aStr.length;
var result = 0;
@ -1000,10 +1120,8 @@ define('source-map/base64-vlq', ['require', 'exports', 'module' , 'source-map/b
shift += VLQ_BASE_SHIFT;
} while (continuation);
return {
value: fromVLQSigned(result),
rest: aStr.slice(i)
};
aOutParam.value = fromVLQSigned(result);
aOutParam.rest = aStr.slice(i);
};
});
@ -1060,14 +1178,17 @@ define('source-map/source-map-generator', ['require', 'exports', 'module' , 'so
/**
* An instance of the SourceMapGenerator represents a source map which is
* being built incrementally. To create a new one, you must pass an object
* with the following properties:
* being built incrementally. You may pass an object with the following
* properties:
*
* - file: The filename of the generated source.
* - sourceRoot: An optional root for all URLs in this source map.
* - sourceRoot: A root for all relative URLs in this source map.
*/
function SourceMapGenerator(aArgs) {
this._file = util.getArg(aArgs, 'file');
if (!aArgs) {
aArgs = {};
}
this._file = util.getArg(aArgs, 'file', null);
this._sourceRoot = util.getArg(aArgs, 'sourceRoot', null);
this._sources = new ArraySet();
this._names = new ArraySet();
@ -1097,9 +1218,9 @@ define('source-map/source-map-generator', ['require', 'exports', 'module' , 'so
}
};
if (mapping.source) {
if (mapping.source != null) {
newMapping.source = mapping.source;
if (sourceRoot) {
if (sourceRoot != null) {
newMapping.source = util.relative(sourceRoot, newMapping.source);
}
@ -1108,7 +1229,7 @@ define('source-map/source-map-generator', ['require', 'exports', 'module' , 'so
column: mapping.originalColumn
};
if (mapping.name) {
if (mapping.name != null) {
newMapping.name = mapping.name;
}
}
@ -1117,7 +1238,7 @@ define('source-map/source-map-generator', ['require', 'exports', 'module' , 'so
});
aSourceMapConsumer.sources.forEach(function (sourceFile) {
var content = aSourceMapConsumer.sourceContentFor(sourceFile);
if (content) {
if (content != null) {
generator.setSourceContent(sourceFile, content);
}
});
@ -1143,11 +1264,11 @@ define('source-map/source-map-generator', ['require', 'exports', 'module' , 'so
this._validateMapping(generated, original, source, name);
if (source && !this._sources.has(source)) {
if (source != null && !this._sources.has(source)) {
this._sources.add(source);
}
if (name && !this._names.has(name)) {
if (name != null && !this._names.has(name)) {
this._names.add(name);
}
@ -1167,18 +1288,18 @@ define('source-map/source-map-generator', ['require', 'exports', 'module' , 'so
SourceMapGenerator.prototype.setSourceContent =
function SourceMapGenerator_setSourceContent(aSourceFile, aSourceContent) {
var source = aSourceFile;
if (this._sourceRoot) {
if (this._sourceRoot != null) {
source = util.relative(this._sourceRoot, source);
}
if (aSourceContent !== null) {
if (aSourceContent != null) {
// Add the source content to the _sourcesContents map.
// Create a new _sourcesContents map if the property is null.
if (!this._sourcesContents) {
this._sourcesContents = {};
}
this._sourcesContents[util.toSetString(source)] = aSourceContent;
} else {
} else if (this._sourcesContents) {
// Remove the source file from the _sourcesContents map.
// If the _sourcesContents map is empty, set the property to null.
delete this._sourcesContents[util.toSetString(source)];
@ -1197,55 +1318,68 @@ define('source-map/source-map-generator', ['require', 'exports', 'module' , 'so
* @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) {
function SourceMapGenerator_applySourceMap(aSourceMapConsumer, aSourceFile, aSourceMapPath) {
var sourceFile = aSourceFile;
// If aSourceFile is omitted, we will use the file property of the SourceMap
if (!aSourceFile) {
aSourceFile = aSourceMapConsumer.file;
if (aSourceFile == null) {
if (aSourceMapConsumer.file == null) {
throw new Error(
'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;
// Make "aSourceFile" relative if an absolute Url is passed.
if (sourceRoot) {
aSourceFile = util.relative(sourceRoot, aSourceFile);
// 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();
// Find mappings for the "aSourceFile"
// Find mappings for the "sourceFile"
this._mappings.forEach(function (mapping) {
if (mapping.source === aSourceFile && mapping.originalLine) {
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({
line: mapping.originalLine,
column: mapping.originalColumn
});
if (original.source !== null) {
if (original.source != null) {
// Copy mapping
if (sourceRoot) {
mapping.source = util.relative(sourceRoot, original.source);
} else {
mapping.source = original.source;
mapping.source = original.source;
if (aSourceMapPath != null) {
mapping.source = util.join(aSourceMapPath, mapping.source)
}
if (sourceRoot != null) {
mapping.source = util.relative(sourceRoot, mapping.source);
}
mapping.originalLine = original.line;
mapping.originalColumn = original.column;
if (original.name !== null && mapping.name !== null) {
// Only use the identifier name if it's an identifier
// in both SourceMaps
if (original.name != null) {
mapping.name = original.name;
}
}
}
var source = mapping.source;
if (source && !newSources.has(source)) {
if (source != null && !newSources.has(source)) {
newSources.add(source);
}
var name = mapping.name;
if (name && !newNames.has(name)) {
if (name != null && !newNames.has(name)) {
newNames.add(name);
}
@ -1256,8 +1390,11 @@ define('source-map/source-map-generator', ['require', 'exports', 'module' , 'so
// Copy sourcesContents of applied map.
aSourceMapConsumer.sources.forEach(function (sourceFile) {
var content = aSourceMapConsumer.sourceContentFor(sourceFile);
if (content) {
if (sourceRoot) {
if (content != null) {
if (aSourceMapPath != null) {
sourceFile = util.join(aSourceMapPath, sourceFile);
}
if (sourceRoot != null) {
sourceFile = util.relative(sourceRoot, sourceFile);
}
this.setSourceContent(sourceFile, content);
@ -1348,7 +1485,7 @@ define('source-map/source-map-generator', ['require', 'exports', 'module' , 'so
- previousGeneratedColumn);
previousGeneratedColumn = mapping.generatedColumn;
if (mapping.source) {
if (mapping.source != null) {
result += base64VLQ.encode(this._sources.indexOf(mapping.source)
- previousSource);
previousSource = this._sources.indexOf(mapping.source);
@ -1362,7 +1499,7 @@ define('source-map/source-map-generator', ['require', 'exports', 'module' , 'so
- previousOriginalColumn);
previousOriginalColumn = mapping.originalColumn;
if (mapping.name) {
if (mapping.name != null) {
result += base64VLQ.encode(this._names.indexOf(mapping.name)
- previousName);
previousName = this._names.indexOf(mapping.name);
@ -1379,7 +1516,7 @@ define('source-map/source-map-generator', ['require', 'exports', 'module' , 'so
if (!this._sourcesContents) {
return null;
}
if (aSourceRoot) {
if (aSourceRoot != null) {
source = util.relative(aSourceRoot, source);
}
var key = util.toSetString(source);
@ -1397,17 +1534,18 @@ define('source-map/source-map-generator', ['require', 'exports', 'module' , 'so
function SourceMapGenerator_toJSON() {
var map = {
version: this._version,
file: this._file,
sources: this._sources.toArray(),
names: this._names.toArray(),
mappings: this._serializeMappings()
};
if (this._sourceRoot) {
if (this._file != null) {
map.file = this._file;
}
if (this._sourceRoot != null) {
map.sourceRoot = this._sourceRoot;
}
if (this._sourcesContents) {
map.sourcesContent = this._generateSourcesContent(map.sources,
map.sourceRoot || undefined);
map.sourcesContent = this._generateSourcesContent(map.sources, map.sourceRoot);
}
return map;
@ -1435,6 +1573,13 @@ define('source-map/source-node', ['require', 'exports', 'module' , 'source-map/
var SourceMapGenerator = require('source-map/source-map-generator').SourceMapGenerator;
var util = require('source-map/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)/;
// Matches a Windows-style newline, or any character.
var REGEX_CHARACTER = /\r\n|[\s\S]/g;
/**
* SourceNodes provide a way to abstract over interpolating/concatenating
* snippets of generated JavaScript source code while maintaining the line and
@ -1450,10 +1595,10 @@ define('source-map/source-node', ['require', 'exports', 'module' , 'source-map/
function SourceNode(aLine, aColumn, aSource, aChunks, aName) {
this.children = [];
this.sourceContents = {};
this.line = aLine === undefined ? null : aLine;
this.column = aColumn === undefined ? null : aColumn;
this.source = aSource === undefined ? null : aSource;
this.name = aName === undefined ? null : aName;
this.line = aLine == null ? null : aLine;
this.column = aColumn == null ? null : aColumn;
this.source = aSource == null ? null : aSource;
this.name = aName == null ? null : aName;
if (aChunks != null) this.add(aChunks);
}
@ -1462,16 +1607,26 @@ define('source-map/source-node', ['require', 'exports', 'module' , 'source-map/
*
* @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) {
function SourceNode_fromStringWithSourceMap(aGeneratedCode, aSourceMapConsumer, aRelativePath) {
// The SourceNode we want to fill with the generated code
// and the SourceMap
var node = new SourceNode();
// The generated code
// Processed fragments are removed from this array.
var remainingLines = aGeneratedCode.split('\n');
// 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 removed from this array, by calling `shiftNextLine`.
var remainingLines = aGeneratedCode.split(REGEX_NEWLINE);
var shiftNextLine = function() {
var lineContents = remainingLines.shift();
// The last line of a file might not have a newline.
var newLine = remainingLines.shift() || "";
return lineContents + newLine;
};
// We need to remember the position of "remainingLines"
var lastGeneratedLine = 1, lastGeneratedColumn = 0;
@ -1482,41 +1637,16 @@ define('source-map/source-node', ['require', 'exports', 'module' , 'source-map/
var lastMapping = null;
aSourceMapConsumer.eachMapping(function (mapping) {
if (lastMapping === null) {
// We add the generated code until the first mapping
// to the SourceNode without any mapping.
// Each line is added as separate string.
while (lastGeneratedLine < mapping.generatedLine) {
node.add(remainingLines.shift() + "\n");
lastGeneratedLine++;
}
if (lastGeneratedColumn < mapping.generatedColumn) {
var nextLine = remainingLines[0];
node.add(nextLine.substr(0, mapping.generatedColumn));
remainingLines[0] = nextLine.substr(mapping.generatedColumn);
lastGeneratedColumn = mapping.generatedColumn;
}
} else {
if (lastMapping !== null) {
// We add the code from "lastMapping" to "mapping":
// First check if there is a new line in between.
if (lastGeneratedLine < mapping.generatedLine) {
var code = "";
// Associate full lines with "lastMapping"
do {
code += remainingLines.shift() + "\n";
lastGeneratedLine++;
lastGeneratedColumn = 0;
} while (lastGeneratedLine < mapping.generatedLine);
// When we reached the correct line, we add code until we
// reach the correct column too.
if (lastGeneratedColumn < mapping.generatedColumn) {
var nextLine = remainingLines[0];
code += nextLine.substr(0, mapping.generatedColumn);
remainingLines[0] = nextLine.substr(mapping.generatedColumn);
lastGeneratedColumn = mapping.generatedColumn;
}
// Create the SourceNode.
addMappingWithCode(lastMapping, code);
// Associate first line with "lastMapping"
addMappingWithCode(lastMapping, shiftNextLine());
lastGeneratedLine++;
lastGeneratedColumn = 0;
// The remaining code is added without mapping
} else {
// There is no new line in between.
// Associate the code between "lastGeneratedColumn" and
@ -1528,19 +1658,43 @@ define('source-map/source-node', ['require', 'exports', 'module' , 'source-map/
lastGeneratedColumn);
lastGeneratedColumn = mapping.generatedColumn;
addMappingWithCode(lastMapping, code);
// No more remaining code, continue
lastMapping = mapping;
return;
}
}
// We add the generated code until the first mapping
// to the SourceNode without any mapping.
// Each line is added as separate string.
while (lastGeneratedLine < mapping.generatedLine) {
node.add(shiftNextLine());
lastGeneratedLine++;
}
if (lastGeneratedColumn < mapping.generatedColumn) {
var nextLine = remainingLines[0];
node.add(nextLine.substr(0, mapping.generatedColumn));
remainingLines[0] = nextLine.substr(mapping.generatedColumn);
lastGeneratedColumn = mapping.generatedColumn;
}
lastMapping = mapping;
}, this);
// We have processed all mappings.
// Associate the remaining code in the current line with "lastMapping"
// and add the remaining lines without any mapping
addMappingWithCode(lastMapping, remainingLines.join("\n"));
if (remainingLines.length > 0) {
if (lastMapping) {
// Associate the remaining code in the current line with "lastMapping"
addMappingWithCode(lastMapping, shiftNextLine());
}
// and add the remaining lines without any mapping
node.add(remainingLines.join(""));
}
// Copy sourcesContent into SourceNode
aSourceMapConsumer.sources.forEach(function (sourceFile) {
var content = aSourceMapConsumer.sourceContentFor(sourceFile);
if (content) {
if (content != null) {
if (aRelativePath != null) {
sourceFile = util.join(aRelativePath, sourceFile);
}
node.setSourceContent(sourceFile, content);
}
});
@ -1551,9 +1705,12 @@ define('source-map/source-node', ['require', 'exports', 'module' , 'source-map/
if (mapping === null || mapping.source === undefined) {
node.add(code);
} else {
var source = aRelativePath
? util.join(aRelativePath, mapping.source)
: mapping.source;
node.add(new SourceNode(mapping.originalLine,
mapping.originalColumn,
mapping.source,
source,
code,
mapping.name));
}
@ -1773,12 +1930,30 @@ define('source-map/source-node', ['require', 'exports', 'module' , 'source-map/
lastOriginalSource = null;
sourceMappingActive = false;
}
chunk.split('').forEach(function (ch) {
if (ch === '\n') {
chunk.match(REGEX_CHARACTER).forEach(function (ch, idx, array) {
if (REGEX_NEWLINE.test(ch)) {
generated.line++;
generated.column = 0;
// Mappings end at eol
if (idx + 1 === array.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++;
generated.column += ch.length;
}
});
});

View File

@ -1,4 +1,4 @@
/* -*- js-indent-level: 2; indent-tabs-mode: nil -*- */
/* -*- Mode: js; js-indent-level: 2; -*- */
/*
* Copyright 2011 Mozilla Foundation and contributors
* Licensed under the New BSD license. See LICENSE or:
@ -111,6 +111,21 @@ define('test/source-map/util', ['require', 'exports', 'module' , 'lib/source-ma
sourceRoot: '/the/root',
mappings: 'CAAC,IAAI,IAAM,SAAUA,GAClB,OAAOC,IAAID;CCDb,IAAI,IAAM,SAAUE,GAClB,OAAOA'
};
exports.testMapNoSourceRoot = {
version: 3,
file: 'min.js',
names: ['bar', 'baz', 'n'],
sources: ['one.js', 'two.js'],
mappings: 'CAAC,IAAI,IAAM,SAAUA,GAClB,OAAOC,IAAID;CCDb,IAAI,IAAM,SAAUE,GAClB,OAAOA'
};
exports.testMapEmptySourceRoot = {
version: 3,
file: 'min.js',
names: ['bar', 'baz', 'n'],
sources: ['one.js', 'two.js'],
sourceRoot: '',
mappings: 'CAAC,IAAI,IAAM,SAAUA,GAClB,OAAOC,IAAID;CCDb,IAAI,IAAM,SAAUE,GAClB,OAAOA'
};
exports.testMapWithSourcesContent = {
version: 3,
file: 'min.js',
@ -259,8 +274,8 @@ define('lib/source-map/util', ['require', 'exports', 'module' , ], function(requ
}
exports.getArg = getArg;
var urlRegexp = /([\w+\-.]+):\/\/((\w+:\w+)@)?([\w.]+)?(:(\d+))?(\S+)?/;
var dataUrlRegexp = /^data:.+\,.+/;
var urlRegexp = /^(?:([\w+\-.]+):)?\/\/(?:(\w+:\w+)@)?([\w.]*)(?::(\d+))?(\S*)$/;
var dataUrlRegexp = /^data:.+\,.+$/;
function urlParse(aUrl) {
var match = aUrl.match(urlRegexp);
@ -269,18 +284,22 @@ define('lib/source-map/util', ['require', 'exports', 'module' , ], function(requ
}
return {
scheme: match[1],
auth: match[3],
host: match[4],
port: match[6],
path: match[7]
auth: match[2],
host: match[3],
port: match[4],
path: match[5]
};
}
exports.urlParse = urlParse;
function urlGenerate(aParsedUrl) {
var url = aParsedUrl.scheme + "://";
var url = '';
if (aParsedUrl.scheme) {
url += aParsedUrl.scheme + ':';
}
url += '//';
if (aParsedUrl.auth) {
url += aParsedUrl.auth + "@"
url += aParsedUrl.auth + '@';
}
if (aParsedUrl.host) {
url += aParsedUrl.host;
@ -295,22 +314,146 @@ define('lib/source-map/util', ['require', 'exports', 'module' , ], function(requ
}
exports.urlGenerate = urlGenerate;
function join(aRoot, aPath) {
var url;
/**
* Normalizes a path, or the path portion of a URL:
*
* - Replaces consequtive 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.
*/
function normalize(aPath) {
var path = aPath;
var url = urlParse(aPath);
if (url) {
if (!url.path) {
return aPath;
}
path = url.path;
}
var isAbsolute = (path.charAt(0) === '/');
if (aPath.match(urlRegexp) || aPath.match(dataUrlRegexp)) {
var parts = path.split(/\/+/);
for (var part, up = 0, i = parts.length - 1; i >= 0; i--) {
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 = ".";
}
var aPathUrl = urlParse(aPath);
var 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;
}
if (aPath.charAt(0) === '/' && (url = urlParse(aRoot))) {
url.path = aPath;
return urlGenerate(url);
// `join('http://', 'www.example.com')`
if (aRootUrl && !aRootUrl.host && !aRootUrl.path) {
aRootUrl.host = aPath;
return urlGenerate(aRootUrl);
}
return aRoot.replace(/\/$/, '') + '/' + aPath;
var joined = aPath.charAt(0) === '/'
? aPath
: normalize(aRoot.replace(/\/+$/, '') + '/' + aPath);
if (aRootUrl) {
aRootUrl.path = joined;
return urlGenerate(aRootUrl);
}
return joined;
}
exports.join = join;
/**
* 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(/\/$/, '');
// XXX: It is possible to remove this block, and the tests still pass!
var url = urlParse(aRoot);
if (aPath.charAt(0) == "/" && url && url.path == "/") {
return aPath.slice(1);
}
return aPath.indexOf(aRoot + '/') === 0
? aPath.substr(aRoot.length + 1)
: aPath;
}
exports.relative = relative;
/**
* Because behavior goes wacky when you set `__proto__` on objects, we
* have to prefix all the strings in our set with an arbitrary character.
@ -330,20 +473,6 @@ define('lib/source-map/util', ['require', 'exports', 'module' , ], function(requ
}
exports.fromSetString = fromSetString;
function relative(aRoot, aPath) {
aRoot = aRoot.replace(/\/$/, '');
var url = urlParse(aRoot);
if (aPath.charAt(0) == "/" && url && url.path == "/") {
return aPath.slice(1);
}
return aPath.indexOf(aRoot + '/') === 0
? aPath.substr(aRoot.length + 1)
: aPath;
}
exports.relative = relative;
function strcmp(aStr1, aStr2) {
var s1 = aStr1 || "";
var s2 = aStr2 || "";

View File

@ -17,10 +17,9 @@ define("test/source-map/test-base64-vlq", ["require", "exports", "module"], func
var base64VLQ = require('source-map/base64-vlq');
exports['test normal encoding and decoding'] = function (assert, util) {
var result;
var result = {};
for (var i = -255; i < 256; i++) {
result = base64VLQ.decode(base64VLQ.encode(i));
assert.ok(result);
base64VLQ.decode(base64VLQ.encode(i), result);
assert.equal(result.value, i);
assert.equal(result.rest, "");
}

View File

@ -47,6 +47,12 @@ define("test/source-map/test-dog-fooding", ["require", "exports", "module"], fun
generated: { line: 5, column: 2 }
});
smg.addMapping({
source: 'gza.coffee',
original: { line: 5, column: 10 },
generated: { line: 6, column: 12 }
});
var smc = new SourceMapConsumer(smg.toString());
// Exact
@ -54,24 +60,30 @@ define("test/source-map/test-dog-fooding", ["require", "exports", "module"], fun
util.assertMapping(3, 2, '/wu/tang/gza.coffee', 2, 0, null, smc, assert);
util.assertMapping(4, 2, '/wu/tang/gza.coffee', 3, 0, null, smc, assert);
util.assertMapping(5, 2, '/wu/tang/gza.coffee', 4, 0, null, smc, assert);
util.assertMapping(6, 12, '/wu/tang/gza.coffee', 5, 10, null, smc, assert);
// Fuzzy
// Original to generated
// Generated to original
util.assertMapping(2, 0, null, null, null, null, smc, assert, true);
util.assertMapping(2, 9, '/wu/tang/gza.coffee', 1, 0, null, smc, assert, true);
util.assertMapping(3, 0, '/wu/tang/gza.coffee', 1, 0, null, smc, assert, true);
util.assertMapping(3, 0, null, null, null, null, smc, assert, true);
util.assertMapping(3, 9, '/wu/tang/gza.coffee', 2, 0, null, smc, assert, true);
util.assertMapping(4, 0, '/wu/tang/gza.coffee', 2, 0, null, smc, assert, true);
util.assertMapping(4, 0, null, null, null, null, smc, assert, true);
util.assertMapping(4, 9, '/wu/tang/gza.coffee', 3, 0, null, smc, assert, true);
util.assertMapping(5, 0, '/wu/tang/gza.coffee', 3, 0, null, smc, assert, true);
util.assertMapping(5, 0, null, null, null, null, smc, assert, true);
util.assertMapping(5, 9, '/wu/tang/gza.coffee', 4, 0, null, smc, assert, true);
util.assertMapping(6, 0, null, null, null, null, smc, assert, true);
util.assertMapping(6, 9, null, null, null, null, smc, assert, true);
util.assertMapping(6, 13, '/wu/tang/gza.coffee', 5, 10, null, smc, assert, true);
// Generated to original
// Original to generated
util.assertMapping(2, 2, '/wu/tang/gza.coffee', 1, 1, null, smc, assert, null, true);
util.assertMapping(3, 2, '/wu/tang/gza.coffee', 2, 3, null, smc, assert, null, true);
util.assertMapping(4, 2, '/wu/tang/gza.coffee', 3, 6, null, smc, assert, null, true);
util.assertMapping(5, 2, '/wu/tang/gza.coffee', 4, 9, null, smc, assert, null, true);
util.assertMapping(5, 2, '/wu/tang/gza.coffee', 5, 9, null, smc, assert, null, true);
util.assertMapping(6, 12, '/wu/tang/gza.coffee', 6, 19, null, smc, assert, null, true);
};
});

View File

@ -17,7 +17,7 @@ define("test/source-map/test-source-map-consumer", ["require", "exports", "modul
var SourceMapConsumer = require('source-map/source-map-consumer').SourceMapConsumer;
var SourceMapGenerator = require('source-map/source-map-generator').SourceMapGenerator;
exports['test that we can instantiate with a string or an objects'] = function (assert, util) {
exports['test that we can instantiate with a string or an object'] = function (assert, util) {
assert.doesNotThrow(function () {
var map = new SourceMapConsumer(util.testMap);
});
@ -27,18 +27,34 @@ define("test/source-map/test-source-map-consumer", ["require", "exports", "modul
};
exports['test that the `sources` field has the original sources'] = function (assert, util) {
var map = new SourceMapConsumer(util.testMap);
var sources = map.sources;
var map;
var sources;
map = new SourceMapConsumer(util.testMap);
sources = map.sources;
assert.equal(sources[0], '/the/root/one.js');
assert.equal(sources[1], '/the/root/two.js');
assert.equal(sources.length, 2);
map = new SourceMapConsumer(util.testMapNoSourceRoot);
sources = map.sources;
assert.equal(sources[0], 'one.js');
assert.equal(sources[1], 'two.js');
assert.equal(sources.length, 2);
map = new SourceMapConsumer(util.testMapEmptySourceRoot);
sources = map.sources;
assert.equal(sources[0], 'one.js');
assert.equal(sources[1], 'two.js');
assert.equal(sources.length, 2);
};
exports['test that the source root is reflected in a mapping\'s source field'] = function (assert, util) {
var map = new SourceMapConsumer(util.testMap);
var map;
var mapping;
map = new SourceMapConsumer(util.testMap);
mapping = map.originalPositionFor({
line: 2,
column: 1
@ -50,6 +66,36 @@ define("test/source-map/test-source-map-consumer", ["require", "exports", "modul
column: 1
});
assert.equal(mapping.source, '/the/root/one.js');
map = new SourceMapConsumer(util.testMapNoSourceRoot);
mapping = map.originalPositionFor({
line: 2,
column: 1
});
assert.equal(mapping.source, 'two.js');
mapping = map.originalPositionFor({
line: 1,
column: 1
});
assert.equal(mapping.source, 'one.js');
map = new SourceMapConsumer(util.testMapEmptySourceRoot);
mapping = map.originalPositionFor({
line: 2,
column: 1
});
assert.equal(mapping.source, 'two.js');
mapping = map.originalPositionFor({
line: 1,
column: 1
});
assert.equal(mapping.source, 'one.js');
};
exports['test mapping tokens back exactly'] = function (assert, util) {
@ -85,6 +131,30 @@ define("test/source-map/test-source-map-consumer", ["require", "exports", "modul
util.assertMapping(2, 9, '/the/root/two.js', 1, 16, null, map, assert, null, true);
};
exports['test mappings and end of lines'] = function (assert, util) {
var smg = new SourceMapGenerator({
file: 'foo.js'
});
smg.addMapping({
original: { line: 1, column: 1 },
generated: { line: 1, column: 1 },
source: 'bar.js'
});
smg.addMapping({
original: { line: 2, column: 2 },
generated: { line: 2, column: 2 },
source: 'bar.js'
});
var map = SourceMapConsumer.fromSourceMap(smg);
// When finding original positions, mappings end at the end of the line.
util.assertMapping(2, 1, null, null, null, null, map, assert, true)
// When finding generated positions, mappings do not end at the end of the line.
util.assertMapping(1, 1, 'bar.js', 2, 1, null, map, assert, null, true);
};
exports['test creating source map consumers with )]}\' prefix'] = function (assert, util) {
assert.doesNotThrow(function () {
var map = new SourceMapConsumer(")]}'" + JSON.stringify(util.testMap));
@ -92,15 +162,15 @@ define("test/source-map/test-source-map-consumer", ["require", "exports", "modul
};
exports['test eachMapping'] = function (assert, util) {
var map = new SourceMapConsumer(util.testMap);
var map;
map = new SourceMapConsumer(util.testMap);
var previousLine = -Infinity;
var previousColumn = -Infinity;
map.eachMapping(function (mapping) {
assert.ok(mapping.generatedLine >= previousLine);
if (mapping.source) {
assert.equal(mapping.source.indexOf(util.testMap.sourceRoot), 0);
}
assert.ok(mapping.source === '/the/root/one.js' || mapping.source === '/the/root/two.js');
if (mapping.generatedLine === previousLine) {
assert.ok(mapping.generatedColumn >= previousColumn);
@ -111,6 +181,16 @@ define("test/source-map/test-source-map-consumer", ["require", "exports", "modul
previousColumn = -Infinity;
}
});
map = new SourceMapConsumer(util.testMapNoSourceRoot);
map.eachMapping(function (mapping) {
assert.ok(mapping.source === 'one.js' || mapping.source === 'two.js');
});
map = new SourceMapConsumer(util.testMapEmptySourceRoot);
map.eachMapping(function (mapping) {
assert.ok(mapping.source === 'one.js' || mapping.source === 'two.js');
});
};
exports['test iterating over mappings in a different order'] = function (assert, util) {

View File

@ -25,6 +25,10 @@ define("test/source-map/test-source-map-generator", ["require", "exports", "modu
sourceRoot: '.'
});
assert.ok(true);
var map = new SourceMapGenerator().toJSON();
assert.ok(!('file' in map));
assert.ok(!('sourceRoot' in map));
};
exports['test JSON serialization'] = function (assert, util) {
@ -182,6 +186,24 @@ define("test/source-map/test-source-map-generator", ["require", "exports", "modu
util.assertEqualMaps(assert, map, util.testMap);
};
exports['test that adding a mapping with an empty string name does not break generation'] = function (assert, util) {
var map = new SourceMapGenerator({
file: 'generated-foo.js',
sourceRoot: '.'
});
map.addMapping({
generated: { line: 1, column: 1 },
source: 'bar.js',
original: { line: 1, column: 1 },
name: ''
});
assert.doesNotThrow(function () {
JSON.parse(map.toString());
});
};
exports['test that source content can be set'] = function (assert, util) {
var map = new SourceMapGenerator({
file: 'min.js',
@ -274,6 +296,218 @@ define("test/source-map/test-source-map-generator", ["require", "exports", "modu
util.assertEqualMaps(assert, actualMap, expectedMap);
};
exports['test applySourceMap throws when file is missing'] = function (assert, util) {
var map = new SourceMapGenerator({
file: 'test.js'
});
var map2 = new SourceMapGenerator();
assert.throws(function() {
map.applySourceMap(new SourceMapConsumer(map2.toJSON()));
});
};
exports['test the two additional parameters of applySourceMap'] = function (assert, util) {
// Assume the following directory structure:
//
// http://foo.org/
// bar.coffee
// app/
// coffee/
// foo.coffee
// temp/
// bundle.js
// temp_maps/
// bundle.js.map
// public/
// bundle.min.js
// bundle.min.js.map
//
// http://www.example.com/
// baz.coffee
var bundleMap = new SourceMapGenerator({
file: 'bundle.js'
});
bundleMap.addMapping({
generated: { line: 3, column: 3 },
original: { line: 2, column: 2 },
source: '../../coffee/foo.coffee'
});
bundleMap.setSourceContent('../../coffee/foo.coffee', 'foo coffee');
bundleMap.addMapping({
generated: { line: 13, column: 13 },
original: { line: 12, column: 12 },
source: '/bar.coffee'
});
bundleMap.setSourceContent('/bar.coffee', 'bar coffee');
bundleMap.addMapping({
generated: { line: 23, column: 23 },
original: { line: 22, column: 22 },
source: 'http://www.example.com/baz.coffee'
});
bundleMap.setSourceContent(
'http://www.example.com/baz.coffee',
'baz coffee'
);
bundleMap = new SourceMapConsumer(bundleMap.toJSON());
var minifiedMap = new SourceMapGenerator({
file: 'bundle.min.js',
sourceRoot: '..'
});
minifiedMap.addMapping({
generated: { line: 1, column: 1 },
original: { line: 3, column: 3 },
source: 'temp/bundle.js'
});
minifiedMap.addMapping({
generated: { line: 11, column: 11 },
original: { line: 13, column: 13 },
source: 'temp/bundle.js'
});
minifiedMap.addMapping({
generated: { line: 21, column: 21 },
original: { line: 23, column: 23 },
source: 'temp/bundle.js'
});
minifiedMap = new SourceMapConsumer(minifiedMap.toJSON());
var expectedMap = function (sources) {
var map = new SourceMapGenerator({
file: 'bundle.min.js',
sourceRoot: '..'
});
map.addMapping({
generated: { line: 1, column: 1 },
original: { line: 2, column: 2 },
source: sources[0]
});
map.setSourceContent(sources[0], 'foo coffee');
map.addMapping({
generated: { line: 11, column: 11 },
original: { line: 12, column: 12 },
source: sources[1]
});
map.setSourceContent(sources[1], 'bar coffee');
map.addMapping({
generated: { line: 21, column: 21 },
original: { line: 22, column: 22 },
source: sources[2]
});
map.setSourceContent(sources[2], 'baz coffee');
return map.toJSON();
}
var actualMap = function (aSourceMapPath) {
var map = SourceMapGenerator.fromSourceMap(minifiedMap);
// Note that relying on `bundleMap.file` (which is simply 'bundle.js')
// instead of supplying the second parameter wouldn't work here.
map.applySourceMap(bundleMap, '../temp/bundle.js', aSourceMapPath);
return map.toJSON();
}
util.assertEqualMaps(assert, actualMap('../temp/temp_maps'), expectedMap([
'coffee/foo.coffee',
'/bar.coffee',
'http://www.example.com/baz.coffee'
]));
util.assertEqualMaps(assert, actualMap('/app/temp/temp_maps'), expectedMap([
'/app/coffee/foo.coffee',
'/bar.coffee',
'http://www.example.com/baz.coffee'
]));
util.assertEqualMaps(assert, actualMap('http://foo.org/app/temp/temp_maps'), expectedMap([
'http://foo.org/app/coffee/foo.coffee',
'http://foo.org/bar.coffee',
'http://www.example.com/baz.coffee'
]));
// If the third parameter is omitted or set to the current working
// directory we get incorrect source paths:
util.assertEqualMaps(assert, actualMap(), expectedMap([
'../coffee/foo.coffee',
'/bar.coffee',
'http://www.example.com/baz.coffee'
]));
util.assertEqualMaps(assert, actualMap(''), expectedMap([
'../coffee/foo.coffee',
'/bar.coffee',
'http://www.example.com/baz.coffee'
]));
util.assertEqualMaps(assert, actualMap('.'), expectedMap([
'../coffee/foo.coffee',
'/bar.coffee',
'http://www.example.com/baz.coffee'
]));
util.assertEqualMaps(assert, actualMap('./'), expectedMap([
'../coffee/foo.coffee',
'/bar.coffee',
'http://www.example.com/baz.coffee'
]));
};
exports['test applySourceMap name handling'] = function (assert, util) {
// Imagine some CoffeeScript code being compiled into JavaScript and then
// minified.
var assertName = function(coffeeName, jsName, expectedName) {
var minifiedMap = new SourceMapGenerator({
file: 'test.js.min'
});
minifiedMap.addMapping({
generated: { line: 1, column: 4 },
original: { line: 1, column: 4 },
source: 'test.js',
name: jsName
});
var coffeeMap = new SourceMapGenerator({
file: 'test.js'
});
coffeeMap.addMapping({
generated: { line: 1, column: 4 },
original: { line: 1, column: 0 },
source: 'test.coffee',
name: coffeeName
});
minifiedMap.applySourceMap(new SourceMapConsumer(coffeeMap.toJSON()));
new SourceMapConsumer(minifiedMap.toJSON()).eachMapping(function(mapping) {
assert.equal(mapping.name, expectedName);
});
};
// `foo = 1` -> `var foo = 1;` -> `var a=1`
// CoffeeScript doesnt rename variables, so theres no need for it to
// provide names in its source maps. Minifiers do rename variables and
// therefore do provide names in their source maps. So that name should be
// retained if the original map lacks names.
assertName(null, 'foo', 'foo');
// `foo = 1` -> `var coffee$foo = 1;` -> `var a=1`
// Imagine that CoffeeScript prefixed all variables with `coffee$`. Even
// though the minifier then also provides a name, the original name is
// what corresponds to the source.
assertName('foo', 'coffee$foo', 'foo');
// `foo = 1` -> `var coffee$foo = 1;` -> `var coffee$foo=1`
// Minifiers can turn off variable mangling. Then theres no need to
// provide names in the source map, but the names from the original map are
// still needed.
assertName('foo', null, 'foo');
// `foo = 1` -> `var foo = 1;` -> `var foo=1`
// No renaming at all.
assertName(null, null, null);
};
exports['test sorting with duplicate generated mappings'] = function (assert, util) {
var map = new SourceMapGenerator({
file: 'test.js'
@ -419,6 +653,13 @@ define("test/source-map/test-source-map-generator", ["require", "exports", "modu
});
};
exports['test setting sourcesContent to null when already null'] = function (assert, util) {
var smg = new SourceMapGenerator({ file: "foo.js" });
assert.doesNotThrow(function() {
smg.setSourceContent("bar.js", null);
});
};
});
function run_test() {
runSourceMapTests('test/source-map/test-source-map-generator', do_throw);

View File

@ -18,6 +18,12 @@ define("test/source-map/test-source-node", ["require", "exports", "module"], fun
var SourceMapConsumer = require('source-map/source-map-consumer').SourceMapConsumer;
var SourceNode = require('source-map/source-node').SourceNode;
function forEachNewline(fn) {
return function (assert, util) {
['\n', '\r\n'].forEach(fn.bind(null, assert, util));
}
}
exports['test .add()'] = function (assert, util) {
var node = new SourceNode(null, null, null);
@ -133,20 +139,35 @@ define("test/source-map/test-source-node", ["require", "exports", "module"], fun
assert.equal(node.toString(), 'hey sexy mama, want to watch Futurama?');
};
exports['test .toStringWithSourceMap()'] = function (assert, util) {
exports['test .toStringWithSourceMap()'] = forEachNewline(function (assert, util, nl) {
var node = new SourceNode(null, null, null,
['(function () {\n',
['(function () {' + nl,
' ',
new SourceNode(1, 0, 'a.js', 'someCall', 'originalCall'),
new SourceNode(1, 8, 'a.js', '()'),
';\n',
' ', new SourceNode(2, 0, 'b.js', ['if (foo) bar()']), ';\n',
';' + nl,
' ', new SourceNode(2, 0, 'b.js', ['if (foo) bar()']), ';' + nl,
'}());']);
var map = node.toStringWithSourceMap({
var result = node.toStringWithSourceMap({
file: 'foo.js'
}).map;
});
assert.equal(result.code, [
'(function () {',
' someCall();',
' if (foo) bar();',
'}());'
].join(nl));
var map = result.map;
var mapWithoutOptions = node.toStringWithSourceMap().map;
assert.ok(map instanceof SourceMapGenerator, 'map instanceof SourceMapGenerator');
assert.ok(mapWithoutOptions instanceof SourceMapGenerator, 'mapWithoutOptions instanceof SourceMapGenerator');
assert.ok(!('file' in mapWithoutOptions));
mapWithoutOptions._file = 'foo.js';
util.assertEqualMaps(assert, map.toJSON(), mapWithoutOptions.toJSON());
map = new SourceMapConsumer(map.toString());
var actual;
@ -191,11 +212,12 @@ define("test/source-map/test-source-node", ["require", "exports", "module"], fun
assert.equal(actual.source, null);
assert.equal(actual.line, null);
assert.equal(actual.column, null);
};
});
exports['test .fromStringWithSourceMap()'] = function (assert, util) {
exports['test .fromStringWithSourceMap()'] = forEachNewline(function (assert, util, nl) {
var testCode = util.testGeneratedCode.replace(/\n/g, nl);
var node = SourceNode.fromStringWithSourceMap(
util.testGeneratedCode,
testCode,
new SourceMapConsumer(util.testMap));
var result = node.toStringWithSourceMap({
@ -204,17 +226,17 @@ define("test/source-map/test-source-node", ["require", "exports", "module"], fun
var map = result.map;
var code = result.code;
assert.equal(code, util.testGeneratedCode);
assert.equal(code, testCode);
assert.ok(map instanceof SourceMapGenerator, 'map instanceof SourceMapGenerator');
map = map.toJSON();
assert.equal(map.version, util.testMap.version);
assert.equal(map.file, util.testMap.file);
assert.equal(map.mappings, util.testMap.mappings);
};
});
exports['test .fromStringWithSourceMap() empty map'] = function (assert, util) {
exports['test .fromStringWithSourceMap() empty map'] = forEachNewline(function (assert, util, nl) {
var node = SourceNode.fromStringWithSourceMap(
util.testGeneratedCode,
util.testGeneratedCode.replace(/\n/g, nl),
new SourceMapConsumer(util.emptyMap));
var result = node.toStringWithSourceMap({
file: 'min.js'
@ -222,22 +244,22 @@ define("test/source-map/test-source-node", ["require", "exports", "module"], fun
var map = result.map;
var code = result.code;
assert.equal(code, util.testGeneratedCode);
assert.equal(code, util.testGeneratedCode.replace(/\n/g, nl));
assert.ok(map instanceof SourceMapGenerator, 'map instanceof SourceMapGenerator');
map = map.toJSON();
assert.equal(map.version, util.emptyMap.version);
assert.equal(map.file, util.emptyMap.file);
assert.equal(map.mappings.length, util.emptyMap.mappings.length);
assert.equal(map.mappings, util.emptyMap.mappings);
};
});
exports['test .fromStringWithSourceMap() complex version'] = function (assert, util) {
exports['test .fromStringWithSourceMap() complex version'] = forEachNewline(function (assert, util, nl) {
var input = new SourceNode(null, null, null, [
"(function() {\n",
" var Test = {};\n",
" ", new SourceNode(1, 0, "a.js", "Test.A = { value: 1234 };\n"),
" ", new SourceNode(2, 0, "a.js", "Test.A.x = 'xyz';"), "\n",
"}());\n",
"(function() {" + nl,
" var Test = {};" + nl,
" ", new SourceNode(1, 0, "a.js", "Test.A = { value: 1234 };" + nl),
" ", new SourceNode(2, 0, "a.js", "Test.A.x = 'xyz';"), nl,
"}());" + nl,
"/* Generated Source */"]);
input = input.toStringWithSourceMap({
file: 'foo.js'
@ -258,25 +280,123 @@ define("test/source-map/test-source-node", ["require", "exports", "module"], fun
map = map.toJSON();
var inputMap = input.map.toJSON();
util.assertEqualMaps(assert, map, inputMap);
});
exports['test .fromStringWithSourceMap() third argument'] = function (assert, util) {
// Assume the following directory structure:
//
// http://foo.org/
// bar.coffee
// app/
// coffee/
// foo.coffee
// coffeeBundle.js # Made from {foo,bar,baz}.coffee
// maps/
// coffeeBundle.js.map
// js/
// foo.js
// public/
// app.js # Made from {foo,coffeeBundle}.js
// app.js.map
//
// http://www.example.com/
// baz.coffee
var coffeeBundle = new SourceNode(1, 0, 'foo.coffee', 'foo(coffee);\n');
coffeeBundle.setSourceContent('foo.coffee', 'foo coffee');
coffeeBundle.add(new SourceNode(2, 0, '/bar.coffee', 'bar(coffee);\n'));
coffeeBundle.add(new SourceNode(3, 0, 'http://www.example.com/baz.coffee', 'baz(coffee);'));
coffeeBundle = coffeeBundle.toStringWithSourceMap({
file: 'foo.js',
sourceRoot: '..'
});
var foo = new SourceNode(1, 0, 'foo.js', 'foo(js);');
var test = function(relativePath, expectedSources) {
var app = new SourceNode();
app.add(SourceNode.fromStringWithSourceMap(
coffeeBundle.code,
new SourceMapConsumer(coffeeBundle.map.toString()),
relativePath));
app.add(foo);
var i = 0;
app.walk(function (chunk, loc) {
assert.equal(loc.source, expectedSources[i]);
i++;
});
app.walkSourceContents(function (sourceFile, sourceContent) {
assert.equal(sourceFile, expectedSources[0]);
assert.equal(sourceContent, 'foo coffee');
})
};
test('../coffee/maps', [
'../coffee/foo.coffee',
'/bar.coffee',
'http://www.example.com/baz.coffee',
'foo.js'
]);
// If the third parameter is omitted or set to the current working
// directory we get incorrect source paths:
test(undefined, [
'../foo.coffee',
'/bar.coffee',
'http://www.example.com/baz.coffee',
'foo.js'
]);
test('', [
'../foo.coffee',
'/bar.coffee',
'http://www.example.com/baz.coffee',
'foo.js'
]);
test('.', [
'../foo.coffee',
'/bar.coffee',
'http://www.example.com/baz.coffee',
'foo.js'
]);
test('./', [
'../foo.coffee',
'/bar.coffee',
'http://www.example.com/baz.coffee',
'foo.js'
]);
};
exports['test .fromStringWithSourceMap() merging duplicate mappings'] = function (assert, util) {
exports['test .toStringWithSourceMap() merging duplicate mappings'] = forEachNewline(function (assert, util, nl) {
var input = new SourceNode(null, null, null, [
new SourceNode(1, 0, "a.js", "(function"),
new SourceNode(1, 0, "a.js", "() {\n"),
new SourceNode(1, 0, "a.js", "() {" + nl),
" ",
new SourceNode(1, 0, "a.js", "var Test = "),
new SourceNode(1, 0, "b.js", "{};\n"),
new SourceNode(1, 0, "b.js", "{};" + nl),
new SourceNode(2, 0, "b.js", "Test"),
new SourceNode(2, 0, "b.js", ".A", "A"),
new SourceNode(2, 20, "b.js", " = { value: 1234 };\n", "A"),
"}());\n",
new SourceNode(2, 20, "b.js", " = { value: ", "A"),
"1234",
new SourceNode(2, 40, "b.js", " };" + nl, "A"),
"}());" + nl,
"/* Generated Source */"
]);
input = input.toStringWithSourceMap({
file: 'foo.js'
});
assert.equal(input.code, [
"(function() {",
" var Test = {};",
"Test.A = { value: 1234 };",
"}());",
"/* Generated Source */"
].join(nl))
var correctMap = new SourceMapGenerator({
file: 'foo.js'
});
@ -285,9 +405,8 @@ define("test/source-map/test-source-node", ["require", "exports", "module"], fun
source: 'a.js',
original: { line: 1, column: 0 }
});
correctMap.addMapping({
generated: { line: 2, column: 0 }
});
// Here is no need for a empty mapping,
// because mappings ends at eol
correctMap.addMapping({
generated: { line: 2, column: 2 },
source: 'a.js',
@ -315,15 +434,143 @@ define("test/source-map/test-source-node", ["require", "exports", "module"], fun
name: 'A',
original: { line: 2, column: 20 }
});
// This empty mapping is required,
// because there is a hole in the middle of the line
correctMap.addMapping({
generated: { line: 4, column: 0 }
generated: { line: 3, column: 18 }
});
correctMap.addMapping({
generated: { line: 3, column: 22 },
source: 'b.js',
name: 'A',
original: { line: 2, column: 40 }
});
// Here is no need for a empty mapping,
// because mappings ends at eol
var inputMap = input.map.toJSON();
correctMap = correctMap.toJSON();
util.assertEqualMaps(assert, inputMap, correctMap);
});
exports['test .toStringWithSourceMap() multi-line SourceNodes'] = forEachNewline(function (assert, util, nl) {
var input = new SourceNode(null, null, null, [
new SourceNode(1, 0, "a.js", "(function() {" + nl + "var nextLine = 1;" + nl + "anotherLine();" + nl),
new SourceNode(2, 2, "b.js", "Test.call(this, 123);" + nl),
new SourceNode(2, 2, "b.js", "this['stuff'] = 'v';" + nl),
new SourceNode(2, 2, "b.js", "anotherLine();" + nl),
"/*" + nl + "Generated" + nl + "Source" + nl + "*/" + nl,
new SourceNode(3, 4, "c.js", "anotherLine();" + nl),
"/*" + nl + "Generated" + nl + "Source" + nl + "*/"
]);
input = input.toStringWithSourceMap({
file: 'foo.js'
});
assert.equal(input.code, [
"(function() {",
"var nextLine = 1;",
"anotherLine();",
"Test.call(this, 123);",
"this['stuff'] = 'v';",
"anotherLine();",
"/*",
"Generated",
"Source",
"*/",
"anotherLine();",
"/*",
"Generated",
"Source",
"*/"
].join(nl));
var correctMap = new SourceMapGenerator({
file: 'foo.js'
});
correctMap.addMapping({
generated: { line: 1, column: 0 },
source: 'a.js',
original: { line: 1, column: 0 }
});
correctMap.addMapping({
generated: { line: 2, column: 0 },
source: 'a.js',
original: { line: 1, column: 0 }
});
correctMap.addMapping({
generated: { line: 3, column: 0 },
source: 'a.js',
original: { line: 1, column: 0 }
});
correctMap.addMapping({
generated: { line: 4, column: 0 },
source: 'b.js',
original: { line: 2, column: 2 }
});
correctMap.addMapping({
generated: { line: 5, column: 0 },
source: 'b.js',
original: { line: 2, column: 2 }
});
correctMap.addMapping({
generated: { line: 6, column: 0 },
source: 'b.js',
original: { line: 2, column: 2 }
});
correctMap.addMapping({
generated: { line: 11, column: 0 },
source: 'c.js',
original: { line: 3, column: 4 }
});
var inputMap = input.map.toJSON();
correctMap = correctMap.toJSON();
util.assertEqualMaps(assert, correctMap, inputMap);
util.assertEqualMaps(assert, inputMap, correctMap);
});
exports['test .toStringWithSourceMap() with empty string'] = function (assert, util) {
var node = new SourceNode(1, 0, 'empty.js', '');
var result = node.toStringWithSourceMap();
assert.equal(result.code, '');
};
exports['test .toStringWithSourceMap() with consecutive newlines'] = forEachNewline(function (assert, util, nl) {
var input = new SourceNode(null, null, null, [
"/***/" + nl + nl,
new SourceNode(1, 0, "a.js", "'use strict';" + nl),
new SourceNode(2, 0, "a.js", "a();"),
]);
input = input.toStringWithSourceMap({
file: 'foo.js'
});
assert.equal(input.code, [
"/***/",
"",
"'use strict';",
"a();",
].join(nl));
var correctMap = new SourceMapGenerator({
file: 'foo.js'
});
correctMap.addMapping({
generated: { line: 3, column: 0 },
source: 'a.js',
original: { line: 1, column: 0 }
});
correctMap.addMapping({
generated: { line: 4, column: 0 },
source: 'a.js',
original: { line: 2, column: 0 }
});
var inputMap = input.map.toJSON();
correctMap = correctMap.toJSON();
util.assertEqualMaps(assert, inputMap, correctMap);
});
exports['test setSourceContent with toStringWithSourceMap'] = function (assert, util) {
var aNode = new SourceNode(1, 1, 'a.js', 'a');
aNode.setSourceContent('a.js', 'someContent');

View File

@ -0,0 +1,224 @@
/*
* WARNING!
*
* Do not edit this file directly, it is built from the sources at
* https://github.com/mozilla/source-map/
*/
Components.utils.import('resource://test/Utils.jsm');
/* -*- Mode: js; js-indent-level: 2; -*- */
/*
* Copyright 2014 Mozilla Foundation and contributors
* Licensed under the New BSD license. See LICENSE or:
* http://opensource.org/licenses/BSD-3-Clause
*/
define("test/source-map/test-util", ["require", "exports", "module"], function (require, exports, module) {
var libUtil = require('source-map/util');
exports['test urls'] = function (assert, util) {
var assertUrl = function (url) {
assert.equal(url, libUtil.urlGenerate(libUtil.urlParse(url)));
};
assertUrl('http://');
assertUrl('http://www.example.com');
assertUrl('http://user:pass@www.example.com');
assertUrl('http://www.example.com:80');
assertUrl('http://www.example.com/');
assertUrl('http://www.example.com/foo/bar');
assertUrl('http://www.example.com/foo/bar/');
assertUrl('http://user:pass@www.example.com:80/foo/bar/');
assertUrl('//');
assertUrl('//www.example.com');
assertUrl('file:///www.example.com');
assert.equal(libUtil.urlParse(''), null);
assert.equal(libUtil.urlParse('.'), null);
assert.equal(libUtil.urlParse('..'), null);
assert.equal(libUtil.urlParse('a'), null);
assert.equal(libUtil.urlParse('a/b'), null);
assert.equal(libUtil.urlParse('a//b'), null);
assert.equal(libUtil.urlParse('/a'), null);
assert.equal(libUtil.urlParse('data:foo,bar'), null);
};
exports['test normalize()'] = function (assert, util) {
assert.equal(libUtil.normalize('/..'), '/');
assert.equal(libUtil.normalize('/../'), '/');
assert.equal(libUtil.normalize('/../../../..'), '/');
assert.equal(libUtil.normalize('/../../../../a/b/c'), '/a/b/c');
assert.equal(libUtil.normalize('/a/b/c/../../../d/../../e'), '/e');
assert.equal(libUtil.normalize('..'), '..');
assert.equal(libUtil.normalize('../'), '../');
assert.equal(libUtil.normalize('../../a/'), '../../a/');
assert.equal(libUtil.normalize('a/..'), '.');
assert.equal(libUtil.normalize('a/../../..'), '../..');
assert.equal(libUtil.normalize('/.'), '/');
assert.equal(libUtil.normalize('/./'), '/');
assert.equal(libUtil.normalize('/./././.'), '/');
assert.equal(libUtil.normalize('/././././a/b/c'), '/a/b/c');
assert.equal(libUtil.normalize('/a/b/c/./././d/././e'), '/a/b/c/d/e');
assert.equal(libUtil.normalize(''), '.');
assert.equal(libUtil.normalize('.'), '.');
assert.equal(libUtil.normalize('./'), '.');
assert.equal(libUtil.normalize('././a'), 'a');
assert.equal(libUtil.normalize('a/./'), 'a/');
assert.equal(libUtil.normalize('a/././.'), 'a');
assert.equal(libUtil.normalize('/a/b//c////d/////'), '/a/b/c/d/');
assert.equal(libUtil.normalize('///a/b//c////d/////'), '///a/b/c/d/');
assert.equal(libUtil.normalize('a/b//c////d'), 'a/b/c/d');
assert.equal(libUtil.normalize('.///.././../a/b//./..'), '../../a')
assert.equal(libUtil.normalize('http://www.example.com'), 'http://www.example.com');
assert.equal(libUtil.normalize('http://www.example.com/'), 'http://www.example.com/');
assert.equal(libUtil.normalize('http://www.example.com/./..//a/b/c/.././d//'), 'http://www.example.com/a/b/d/');
};
exports['test join()'] = function (assert, util) {
assert.equal(libUtil.join('a', 'b'), 'a/b');
assert.equal(libUtil.join('a/', 'b'), 'a/b');
assert.equal(libUtil.join('a//', 'b'), 'a/b');
assert.equal(libUtil.join('a', 'b/'), 'a/b/');
assert.equal(libUtil.join('a', 'b//'), 'a/b/');
assert.equal(libUtil.join('a/', '/b'), '/b');
assert.equal(libUtil.join('a//', '//b'), '//b');
assert.equal(libUtil.join('a', '..'), '.');
assert.equal(libUtil.join('a', '../b'), 'b');
assert.equal(libUtil.join('a/b', '../c'), 'a/c');
assert.equal(libUtil.join('a', '.'), 'a');
assert.equal(libUtil.join('a', './b'), 'a/b');
assert.equal(libUtil.join('a/b', './c'), 'a/b/c');
assert.equal(libUtil.join('a', 'http://www.example.com'), 'http://www.example.com');
assert.equal(libUtil.join('a', 'data:foo,bar'), 'data:foo,bar');
assert.equal(libUtil.join('', 'b'), 'b');
assert.equal(libUtil.join('.', 'b'), 'b');
assert.equal(libUtil.join('', 'b/'), 'b/');
assert.equal(libUtil.join('.', 'b/'), 'b/');
assert.equal(libUtil.join('', 'b//'), 'b/');
assert.equal(libUtil.join('.', 'b//'), 'b/');
assert.equal(libUtil.join('', '..'), '..');
assert.equal(libUtil.join('.', '..'), '..');
assert.equal(libUtil.join('', '../b'), '../b');
assert.equal(libUtil.join('.', '../b'), '../b');
assert.equal(libUtil.join('', '.'), '.');
assert.equal(libUtil.join('.', '.'), '.');
assert.equal(libUtil.join('', './b'), 'b');
assert.equal(libUtil.join('.', './b'), 'b');
assert.equal(libUtil.join('', 'http://www.example.com'), 'http://www.example.com');
assert.equal(libUtil.join('.', 'http://www.example.com'), 'http://www.example.com');
assert.equal(libUtil.join('', 'data:foo,bar'), 'data:foo,bar');
assert.equal(libUtil.join('.', 'data:foo,bar'), 'data:foo,bar');
assert.equal(libUtil.join('..', 'b'), '../b');
assert.equal(libUtil.join('..', 'b/'), '../b/');
assert.equal(libUtil.join('..', 'b//'), '../b/');
assert.equal(libUtil.join('..', '..'), '../..');
assert.equal(libUtil.join('..', '../b'), '../../b');
assert.equal(libUtil.join('..', '.'), '..');
assert.equal(libUtil.join('..', './b'), '../b');
assert.equal(libUtil.join('..', 'http://www.example.com'), 'http://www.example.com');
assert.equal(libUtil.join('..', 'data:foo,bar'), 'data:foo,bar');
assert.equal(libUtil.join('a', ''), 'a');
assert.equal(libUtil.join('a', '.'), 'a');
assert.equal(libUtil.join('a/', ''), 'a');
assert.equal(libUtil.join('a/', '.'), 'a');
assert.equal(libUtil.join('a//', ''), 'a');
assert.equal(libUtil.join('a//', '.'), 'a');
assert.equal(libUtil.join('/a', ''), '/a');
assert.equal(libUtil.join('/a', '.'), '/a');
assert.equal(libUtil.join('', ''), '.');
assert.equal(libUtil.join('.', ''), '.');
assert.equal(libUtil.join('.', ''), '.');
assert.equal(libUtil.join('.', '.'), '.');
assert.equal(libUtil.join('..', ''), '..');
assert.equal(libUtil.join('..', '.'), '..');
assert.equal(libUtil.join('http://foo.org/a', ''), 'http://foo.org/a');
assert.equal(libUtil.join('http://foo.org/a', '.'), 'http://foo.org/a');
assert.equal(libUtil.join('http://foo.org/a/', ''), 'http://foo.org/a');
assert.equal(libUtil.join('http://foo.org/a/', '.'), 'http://foo.org/a');
assert.equal(libUtil.join('http://foo.org/a//', ''), 'http://foo.org/a');
assert.equal(libUtil.join('http://foo.org/a//', '.'), 'http://foo.org/a');
assert.equal(libUtil.join('http://foo.org', ''), 'http://foo.org/');
assert.equal(libUtil.join('http://foo.org', '.'), 'http://foo.org/');
assert.equal(libUtil.join('http://foo.org/', ''), 'http://foo.org/');
assert.equal(libUtil.join('http://foo.org/', '.'), 'http://foo.org/');
assert.equal(libUtil.join('http://foo.org//', ''), 'http://foo.org/');
assert.equal(libUtil.join('http://foo.org//', '.'), 'http://foo.org/');
assert.equal(libUtil.join('//www.example.com', ''), '//www.example.com/');
assert.equal(libUtil.join('//www.example.com', '.'), '//www.example.com/');
assert.equal(libUtil.join('http://foo.org/a', 'b'), 'http://foo.org/a/b');
assert.equal(libUtil.join('http://foo.org/a/', 'b'), 'http://foo.org/a/b');
assert.equal(libUtil.join('http://foo.org/a//', 'b'), 'http://foo.org/a/b');
assert.equal(libUtil.join('http://foo.org/a', 'b/'), 'http://foo.org/a/b/');
assert.equal(libUtil.join('http://foo.org/a', 'b//'), 'http://foo.org/a/b/');
assert.equal(libUtil.join('http://foo.org/a/', '/b'), 'http://foo.org/b');
assert.equal(libUtil.join('http://foo.org/a//', '//b'), 'http://b');
assert.equal(libUtil.join('http://foo.org/a', '..'), 'http://foo.org/');
assert.equal(libUtil.join('http://foo.org/a', '../b'), 'http://foo.org/b');
assert.equal(libUtil.join('http://foo.org/a/b', '../c'), 'http://foo.org/a/c');
assert.equal(libUtil.join('http://foo.org/a', '.'), 'http://foo.org/a');
assert.equal(libUtil.join('http://foo.org/a', './b'), 'http://foo.org/a/b');
assert.equal(libUtil.join('http://foo.org/a/b', './c'), 'http://foo.org/a/b/c');
assert.equal(libUtil.join('http://foo.org/a', 'http://www.example.com'), 'http://www.example.com');
assert.equal(libUtil.join('http://foo.org/a', 'data:foo,bar'), 'data:foo,bar');
assert.equal(libUtil.join('http://foo.org', 'a'), 'http://foo.org/a');
assert.equal(libUtil.join('http://foo.org/', 'a'), 'http://foo.org/a');
assert.equal(libUtil.join('http://foo.org//', 'a'), 'http://foo.org/a');
assert.equal(libUtil.join('http://foo.org', '/a'), 'http://foo.org/a');
assert.equal(libUtil.join('http://foo.org/', '/a'), 'http://foo.org/a');
assert.equal(libUtil.join('http://foo.org//', '/a'), 'http://foo.org/a');
assert.equal(libUtil.join('http://', 'www.example.com'), 'http://www.example.com');
assert.equal(libUtil.join('file:///', 'www.example.com'), 'file:///www.example.com');
assert.equal(libUtil.join('http://', 'ftp://example.com'), 'ftp://example.com');
assert.equal(libUtil.join('http://www.example.com', '//foo.org/bar'), 'http://foo.org/bar');
assert.equal(libUtil.join('//www.example.com', '//foo.org/bar'), '//foo.org/bar');
};
// TODO Issue #128: Define and test this function properly.
exports['test relative()'] = function (assert, util) {
assert.equal(libUtil.relative('/the/root', '/the/root/one.js'), 'one.js');
assert.equal(libUtil.relative('/the/root', '/the/rootone.js'), '/the/rootone.js');
assert.equal(libUtil.relative('', '/the/root/one.js'), '/the/root/one.js');
assert.equal(libUtil.relative('.', '/the/root/one.js'), '/the/root/one.js');
assert.equal(libUtil.relative('', 'the/root/one.js'), 'the/root/one.js');
assert.equal(libUtil.relative('.', 'the/root/one.js'), 'the/root/one.js');
assert.equal(libUtil.relative('/', '/the/root/one.js'), 'the/root/one.js');
assert.equal(libUtil.relative('/', 'the/root/one.js'), 'the/root/one.js');
};
});
function run_test() {
runSourceMapTests('test/source-map/test-util', do_throw);
}