Skip to content

Commit

Permalink
fix(index): resolve source maps with root-relative paths correctly (#68)
Browse files Browse the repository at this point in the history
  • Loading branch information
iclanton authored and michael-ciniawsky committed Aug 14, 2018
1 parent 78ad469 commit e2fdbfd
Show file tree
Hide file tree
Showing 8 changed files with 121 additions and 21 deletions.
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 @@ -76,7 +76,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.

124 changes: 106 additions & 18 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,22 +157,24 @@ describe("source-map-loader", function() {
done();
});
});

it("should warn on invalid SourceMap", function (done) {
execLoader(path.join(__dirname, "fixtures", "invalid-source-map.js"), function (err, res, map, deps, warns) {
execLoader(path.join(fixturesPath, "invalid-source-map.js"), function (err, res, map, deps, warns) {
should.equal(err, null);
warns.should.matchEach(
new RegExp("Cannot parse SourceMap 'invalid-source-map.map': SyntaxError: Unexpected string in JSON at position 102")
);
should.equal(res, "with SourceMap\n//#sourceMappingURL=invalid-source-map.map\n// comment");
should.equal(map, null);
deps.should.be.eql([
path.join(__dirname, "fixtures", "invalid-source-map.map")
path.join(fixturesPath, "invalid-source-map.map")
]);
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 @@ -175,8 +185,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 @@ -192,14 +203,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 @@ -216,4 +227,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();
}
);
});
});

0 comments on commit e2fdbfd

Please sign in to comment.