Skip to content

fix(index): resolve source maps with root-relative paths correctly #68

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ module.exports = function(input, inputMap) {
map = JSON.parse(mapStr)
} catch (e) {
emitWarning("Cannot parse inline SourceMap '" + mapBase64.substr(0, 50) + "': " + e);
return untouched();
return untouched();
}
processMap(map, this.context, callback);
} else {
resolve(this.context, loaderUtils.urlToRequest(url), function(err, result) {
resolve(this.context, loaderUtils.urlToRequest(url, true), function(err, result) {
if(err) {
emitWarning("Cannot find SourceMap '" + url + "': " + err);
return untouched();
Expand Down Expand Up @@ -69,7 +69,7 @@ module.exports = function(input, inputMap) {
delete map.sourceRoot;
var missingSources = map.sourcesContent ? map.sources.slice(map.sourcesContent.length) : map.sources;
async.map(missingSources, function(source, callback) {
resolve(context, loaderUtils.urlToRequest(source), function(err, result) {
resolve(context, loaderUtils.urlToRequest(source, true), function(err, result) {
if(err) {
emitWarning("Cannot find source file '" + source + "': " + err);
return callback(null, null);
Expand Down
1 change: 1 addition & 0 deletions test/fixtures/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
absolute-sourceRoot-source-map.map
3 changes: 3 additions & 0 deletions test/fixtures/absolute-sourceRoot-source-map.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
with SourceMap
//#sourceMappingURL=absolute-sourceRoot-source-map.map
// comment
2 changes: 2 additions & 0 deletions test/fixtures/absolute-sourceRoot-source-map.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
with SourceMap
// comment
2 changes: 2 additions & 0 deletions test/fixtures/data/relative-sourceRoot-source-map.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
with SourceMap
// comment
3 changes: 3 additions & 0 deletions test/fixtures/relative-sourceRoot-source-map.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
with SourceMap
//#sourceMappingURL=relative-sourceRoot-source-map.map
// comment
1 change: 1 addition & 0 deletions test/fixtures/relative-sourceRoot-source-map.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

119 changes: 103 additions & 16 deletions test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ function execLoader(filename, callback) {
context: path.dirname(filename),
resolve: function(context, request, callback) {
process.nextTick(function() {
var p = path.join(context, request);
var p = path.isAbsolute(request) ? request : path.resolve(context, request);
if(fs.existsSync(p))
callback(null, p);
else
Expand Down Expand Up @@ -40,8 +40,11 @@ function execLoader(filename, callback) {
}

describe("source-map-loader", function() {
const fixturesPath = path.join(__dirname, "fixtures");
const dataPath = path.join(fixturesPath, "data");

it("should leave normal files untouched", function(done) {
execLoader(path.join(__dirname, "fixtures", "normal-file.js"), function(err, res, map, deps, warns) {
execLoader(path.join(fixturesPath, "normal-file.js"), function(err, res, map, deps, warns) {
should.equal(err, null);
warns.should.be.eql([]);
should.equal(res, "without SourceMap"),
Expand All @@ -50,8 +53,9 @@ describe("source-map-loader", function() {
done();
});
});

it("should process inlined SourceMaps", function(done) {
execLoader(path.join(__dirname, "fixtures", "inline-source-map.js"), function(err, res, map, deps, warns) {
execLoader(path.join(fixturesPath, "inline-source-map.js"), function(err, res, map, deps, warns) {
should.equal(err, null);
warns.should.be.eql([]);
should.equal(res, "with SourceMap\n// comment"),
Expand All @@ -68,8 +72,9 @@ describe("source-map-loader", function() {
done();
});
});

it("should process external SourceMaps", function(done) {
execLoader(path.join(__dirname, "fixtures", "external-source-map.js"), function(err, res, map, deps, warns) {
execLoader(path.join(fixturesPath, "external-source-map.js"), function(err, res, map, deps, warns) {
should.equal(err, null);
warns.should.be.eql([]);
should.equal(res, "with SourceMap\n// comment"),
Expand All @@ -83,34 +88,36 @@ describe("source-map-loader", function() {
"mappings":"AAAA"
});
deps.should.be.eql([
path.join(__dirname, "fixtures", "external-source-map.map")
path.join(fixturesPath, "external-source-map.map")
]);
done();
});
});

it("should process external SourceMaps (external sources)", function(done) {
execLoader(path.join(__dirname, "fixtures", "external-source-map2.js"), function(err, res, map, deps, warns) {
execLoader(path.join(fixturesPath, "external-source-map2.js"), function(err, res, map, deps, warns) {
should.equal(err, null);
warns.should.be.eql([]);
should.equal(res, "with SourceMap\n// comment"),
map.should.be.eql({
"version":3,
"file":"external-source-map2.js",
"sources":[
path.join(__dirname, "fixtures", "external-source-map2.txt")
path.join(fixturesPath, "external-source-map2.txt")
],
"sourcesContent":["with SourceMap"],
"mappings":"AAAA"
});
deps.should.be.eql([
path.join(__dirname, "fixtures", "data", "external-source-map2.map"),
path.join(__dirname, "fixtures", "external-source-map2.txt")
path.join(dataPath, "external-source-map2.map"),
path.join(fixturesPath, "external-source-map2.txt")
]);
done();
});
});

it("should use last SourceMap directive", function (done) {
execLoader(path.join(__dirname, "fixtures", "multi-source-map.js"), function (err, res, map, deps, warns) {
execLoader(path.join(fixturesPath, "multi-source-map.js"), function (err, res, map, deps, warns) {
should.equal(err, null);
warns.should.be.eql([]);
should.equal(res, "with SourceMap\nanInvalidDirective = \"\\n/*# sourceMappingURL=data:application/json;base64,\"+btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap))))+\" */\";\n// comment"),
Expand All @@ -127,8 +134,9 @@ describe("source-map-loader", function() {
done();
});
});

it("should skip invalid base64 SourceMap", function (done) {
execLoader(path.join(__dirname, "fixtures", "invalid-inline-source-map.js"), function (err, res, map, deps, warns) {
execLoader(path.join(fixturesPath, "invalid-inline-source-map.js"), function (err, res, map, deps, warns) {
should.equal(err, null);
warns.should.be.eql([]);
should.equal(res, "without SourceMap\n// @sourceMappingURL=data:application/source-map;base64,\"something invalid\"\n// comment");
Expand All @@ -138,7 +146,7 @@ describe("source-map-loader", function() {
});
});
it("should warn on invalid base64 SourceMap", function (done) {
execLoader(path.join(__dirname, "fixtures", "invalid-inline-source-map2.js"), function (err, res, map, deps, warns) {
execLoader(path.join(fixturesPath, "invalid-inline-source-map2.js"), function (err, res, map, deps, warns) {
should.equal(err, null);
warns.should.matchEach(
new RegExp("Cannot parse inline SourceMap 'invalid\/base64=': SyntaxError: Unexpected token")
Expand All @@ -149,8 +157,9 @@ describe("source-map-loader", function() {
done();
});
});

it("should warn on missing SourceMap", function(done) {
execLoader(path.join(__dirname, "fixtures", "missing-source-map.js"), function(err, res, map, deps, warns) {
execLoader(path.join(fixturesPath, "missing-source-map.js"), function(err, res, map, deps, warns) {
should.equal(err, null);
warns.should.be.eql([
"Cannot find SourceMap 'missing-source-map.map': Error: File not found"
Expand All @@ -161,8 +170,9 @@ describe("source-map-loader", function() {
done();
});
});

it("should warn on missing source file", function(done) {
execLoader(path.join(__dirname, "fixtures", "missing-source-map2.js"), function(err, res, map, deps, warns) {
execLoader(path.join(fixturesPath, "missing-source-map2.js"), function(err, res, map, deps, warns) {
should.equal(err, null);
warns.should.be.eql([
"Cannot find source file 'missing-source-map2.txt': Error: File not found"
Expand All @@ -178,14 +188,14 @@ describe("source-map-loader", function() {
"mappings":"AAAA"
});
deps.should.be.eql([
path.join(__dirname, "fixtures", "missing-source-map2.map")
path.join(fixturesPath, "missing-source-map2.map")
]);
done();
});
});

it("should process inlined SourceMaps with charset", function(done) {
execLoader(path.join(__dirname, "fixtures", "charset-inline-source-map.js"), function(err, res, map, deps, warns) {
execLoader(path.join(fixturesPath, "charset-inline-source-map.js"), function(err, res, map, deps, warns) {
should.equal(err, null);
warns.should.be.eql([]);
should.equal(res, "with SourceMap\n// comment"),
Expand All @@ -202,4 +212,81 @@ describe("source-map-loader", function() {
done();
});
});

it("should support absolute sourceRoot paths in sourcemaps", (done) => {
const sourceRoot = path.join(fixturesPath);
const javaScriptFilename = "absolute-sourceRoot-source-map.js";
const sourceFilename = "absolute-sourceRoot-source-map.txt";
const rootRelativeSourcePath = path.join(sourceRoot, sourceFilename);
const sourceMapPath = path.join(sourceRoot, "absolute-sourceRoot-source-map.map");

// Create the sourcemap file
const rawSourceMap = {
"version": 3,
"file": javaScriptFilename,
"sourceRoot": sourceRoot,
"sources": [
sourceFilename
],
"mappings": "AAAA"
};
fs.writeFileSync(sourceMapPath, JSON.stringify(rawSourceMap));

execLoader(
path.join(fixturesPath, javaScriptFilename),
(err, res, map, deps, warns) => {
should.equal(err, null);
warns.should.be.eql([]);
should.equal(res, "with SourceMap\n// comment"),
map.should.be.eql({
"version": 3,
"file": javaScriptFilename,
"sources": [
rootRelativeSourcePath
],
"sourcesContent": [
"with SourceMap\n// comment"
],
"mappings": "AAAA"
});
deps.should.be.eql([
sourceMapPath,
rootRelativeSourcePath
]);
done();
}
);
});

it("should support relative sourceRoot paths in sourcemaps", (done) => {
const javaScriptFilename = "relative-sourceRoot-source-map.js";
const sourceFilename = "relative-sourceRoot-source-map.txt";
const rootRelativeSourcePath = path.join(dataPath, sourceFilename);
const sourceMapPath = path.join(fixturesPath, "relative-sourceRoot-source-map.map");

execLoader(
path.join(fixturesPath, javaScriptFilename),
(err, res, map, deps, warns) => {
should.equal(err, null);
warns.should.be.eql([]);
should.equal(res, "with SourceMap\n// comment"),
map.should.be.eql({
"version": 3,
"file": javaScriptFilename,
"sources": [
rootRelativeSourcePath
],
"sourcesContent": [
"with SourceMap\n// comment"
],
"mappings": "AAAA"
});
deps.should.be.eql([
sourceMapPath,
rootRelativeSourcePath
]);
done();
}
);
});
});