Skip to content

map.sources converted to absolute paths + other changes #75

New issue

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

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

Already on GitHub? # to your account

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all 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
2 changes: 2 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[*.js]
indent_style = tab
127 changes: 79 additions & 48 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
*/
var fs = require("fs");
var path = require("path");
var async = require("async");
var loaderUtils = require("loader-utils");
var urlUtils = require("url");

// Matches only the last occurrence of sourceMappingURL
var baseRegex = "\\s*[@#]\\s*sourceMappingURL\\s*=\\s*([^\\s]*)(?![\\S\\s]*sourceMappingURL)",
Expand All @@ -14,98 +14,129 @@ var baseRegex = "\\s*[@#]\\s*sourceMappingURL\\s*=\\s*([^\\s]*)(?![\\S\\s]*sourc
// Matches // .... comments
regex2 = new RegExp("//"+baseRegex+"($|\n|\r\n?)"),
// Matches DataUrls
regexDataUrl = /data:[^;\n]+(?:;charset=[^;\n]+)?;base64,([a-zA-Z0-9+/]+={0,2})/;
regexDataUrl = /data:[^;\n]+(?:;charset=[^;\n]+)?;base64,([a-zA-Z0-9+/]+={0,2})/,
// Matches url with scheme, doesn't match Windows disk
regexUrl = /[a-zA-Z]{2,}:/;

const FILE_SCHEME = "file:";

const DEFAULT_OPTIONS = {
// Prevent the loader to rewrite all sources as absolute paths
keepRelativeSources: false
};

module.exports = function(input, inputMap) {
const options = Object.assign({}, DEFAULT_OPTIONS, loaderUtils.getOptions(this));
this.cacheable && this.cacheable();
var resolve = this.resolve;
var addDependency = this.addDependency;
var emitWarning = this.emitWarning || function() {};
var match = input.match(regex1) || input.match(regex2);
var callback;
if(match) {
var url = match[1];
var dataUrlMatch = regexDataUrl.exec(url);
var callback = this.async();
callback = this.async();
if(dataUrlMatch) {
var mapBase64 = dataUrlMatch[1];
var mapStr = (new Buffer(mapBase64, "base64")).toString();
var mapStr = Buffer.from(mapBase64, "base64").toString();
var map;
try {
map = JSON.parse(mapStr)
} catch (e) {
emitWarning("Cannot parse inline SourceMap '" + mapBase64.substr(0, 50) + "': " + e);
emitWarning(new Error("Cannot parse inline SourceMap '"
+ mapBase64.substr(0, 50) + "': " + e));
return untouched();
}
processMap(map, this.context, callback);
} else {
resolve(this.context, loaderUtils.urlToRequest(url, true), function(err, result) {
resolveAbsolutePath(this.context, url, function(err, absoluteFilepath) {
if(err) {
emitWarning("Cannot find SourceMap '" + url + "': " + err);
emitWarning(new Error("Cannot find SourceMap '" + url + "': " + err));
return untouched();
}
addDependency(result);
fs.readFile(result, "utf-8", function(err, content) {
fs.readFile(absoluteFilepath, "utf-8", function(err, content) {
if(err) {
emitWarning("Cannot open SourceMap '" + result + "': " + err);
emitWarning(new Error("Cannot open SourceMap '" + absoluteFilepath + "': " + err));
return untouched();
}
addDependency(absoluteFilepath);
var map;
try {
map = JSON.parse(content);
} catch (e) {
emitWarning("Cannot parse SourceMap '" + url + "': " + e);
emitWarning(new Error("Cannot parse SourceMap '" + url + "': " + e));
return untouched();
}
processMap(map, path.dirname(result), callback);
processMap(map, path.dirname(absoluteFilepath), callback);
});
}.bind(this));
return;
}
} else {
var callback = this.callback;
callback = this.callback;
return untouched();
}
function untouched() {
callback(null, input, inputMap);
}
function resolveAbsolutePath(context, url, resolveAbsolutePathCallback) {
let filepath = url;
if(regexUrl.test(filepath) && !filepath.startsWith(FILE_SCHEME)) {
resolveAbsolutePathCallback("URL scheme not supported");
return;
}
if(filepath.startsWith(FILE_SCHEME)) {
if(urlUtils.fileURLToPath) {
filepath = urlUtils.fileURLToPath(filepath);
} else {
resolveAbsolutePathCallback("file URL scheme support requires node 10.x");
return;
}
}
resolveAbsolutePathCallback(null, path.resolve(context, filepath));
}
function processMap(map, context, callback) {
if(!map.sourcesContent || map.sourcesContent.length < map.sources.length) {
var sourcePrefix = map.sourceRoot ? map.sourceRoot + "/" : "";
map.sources = map.sources.map(function(s) { return sourcePrefix + s; });
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, true), function(err, result) {
const sourcePrefix = map.sourceRoot ? map.sourceRoot + "/" : "";
const sources = map.sources.map(function(s) { return sourcePrefix + s; });
delete map.sourceRoot;
const sourcesContent = map.sourcesContent || [];
const sourcesPromises = sources.map((source, sourceIndex) => new Promise((resolveSource) => {
resolveAbsolutePath(context, source, function(err, absoluteFilepath) {
if(err) {
emitWarning(new Error("Cannot find source file '" + source + "': " + err));
return resolveSource({
source: source,
content: sourcesContent[sourceIndex] != null ? sourcesContent[sourceIndex] : null
});
}
if(sourcesContent[sourceIndex] != null) {
return resolveSource({
source: absoluteFilepath,
content: sourcesContent[sourceIndex]
});
}
fs.readFile(absoluteFilepath, "utf-8", function(err, content) {
if(err) {
emitWarning("Cannot find source file '" + source + "': " + err);
return callback(null, null);
}
addDependency(result);
fs.readFile(result, "utf-8", function(err, content) {
if(err) {
emitWarning("Cannot open source file '" + result + "': " + err);
return callback(null, null);
}
callback(null, {
source: result,
content: content
emitWarning(new Error("Cannot open source file '" + absoluteFilepath + "': " + err));
return resolveSource({
source: absoluteFilepath,
content: null
});
});
});
}, function(err, info) {
map.sourcesContent = map.sourcesContent || [];
info.forEach(function(res) {
if(res) {
map.sources[map.sourcesContent.length] = res.source;
map.sourcesContent.push(res.content);
} else {
map.sourcesContent.push(null);
}
addDependency(absoluteFilepath);
resolveSource({
source: absoluteFilepath,
content: content
});
});
processMap(map, context, callback);
});
return;
}
callback(null, input.replace(match[0], ''), map);
}));
Promise.all(sourcesPromises)
.then((results) => {
if (!options.keepRelativeSources) {
map.sources = results.map(res => res.source);
}
map.sourcesContent = results.map(res => res.content);
callback(null, input.replace(match[0], ""), map);
});
}
}
13 changes: 3 additions & 10 deletions package-lock.json

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

1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
"release": "standard-version"
},
"dependencies": {
"async": "^2.5.0",
"loader-utils": "^1.1.0"
},
"devDependencies": {
Expand Down
2 changes: 2 additions & 0 deletions test/fixtures/null-sourcesContent-source-map.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
with SourceMap
//#sourceMappingURL=null-sourcesContent-source-map.map
1 change: 1 addition & 0 deletions test/fixtures/null-sourcesContent-source-map.map

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

1 change: 1 addition & 0 deletions test/fixtures/null-sourcesContent-source-map.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
with SourceMap
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
with SourceMap
//#sourceMappingURL=relative-sourceRoot-sourcesContent-source-map.map

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

Loading