Skip to content

Commit

Permalink
Fix util.relative for the case where the path is above the root.
Browse files Browse the repository at this point in the history
Currently, util.relative simply checks if the root is a prefix of the path. This
works fine when the path is below the root, but won't work if the path is above
the root.

To fix this, we should remove components from the root one by one, until either
we find a prefix that fits, or we run out of components to match.
  • Loading branch information
ejpbruel committed May 8, 2015
1 parent 22388a5 commit 7becc8e
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 8 deletions.
29 changes: 22 additions & 7 deletions lib/source-map/util.js
Expand Up @@ -198,15 +198,30 @@ define(function (require, exports, module) {

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);
// It is possible for the path to be above the root. In this case, simply
// checking whether the root is a prefix of the path won't work. Instead, we
// need to remove components from the root one by one, until either we find
// a prefix that fits, or we run out of components to remove.
var level = 0;
while (aPath.indexOf(aRoot + '/') !== 0) {
var index = aRoot.lastIndexOf("/");
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;
}

return aPath.indexOf(aRoot + '/') === 0
? aPath.substr(aRoot.length + 1)
: aPath;
// 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;

Expand Down
23 changes: 23 additions & 0 deletions test/source-map/test-source-map-consumer.js
Expand Up @@ -495,6 +495,29 @@ define(function (require, exports, module) {
assert.equal(pos.column, 2);
};

exports['test sourceRoot + generatedPositionFor for path above the root'] = function (assert, util) {
var map = new SourceMapGenerator({
sourceRoot: 'foo/bar',
file: 'baz.js'
});
map.addMapping({
original: { line: 1, column: 1 },
generated: { line: 2, column: 2 },
source: '../bang.coffee'
});
map = new SourceMapConsumer(map.toString());

// Should handle with sourceRoot.
var pos = map.generatedPositionFor({
line: 1,
column: 1,
source: 'foo/bang.coffee'
});

assert.equal(pos.line, 2);
assert.equal(pos.column, 2);
};

exports['test allGeneratedPositionsFor for line'] = function (assert, util) {
var map = new SourceMapGenerator({
file: 'generated.js'
Expand Down
6 changes: 5 additions & 1 deletion test/source-map/test-util.js
Expand Up @@ -202,7 +202,11 @@ define(function (require, exports, module) {
// 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('http://the/root', 'http://the/root/one.js'), 'one.js');
assert.equal(libUtil.relative('/the/root', '/the/rootone.js'), '../rootone.js');
assert.equal(libUtil.relative('http://the/root', 'http://the/rootone.js'), '../rootone.js');
assert.equal(libUtil.relative('/the/root', '/therootone.js'), '/therootone.js');
assert.equal(libUtil.relative('http://the/root', '/therootone.js'), '/therootone.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');
Expand Down

0 comments on commit 7becc8e

Please sign in to comment.