add support for sourcesContent, closes #25

This commit is contained in:
Evan Wallace 2014-04-26 12:15:02 -07:00
parent 095d0ae63b
commit f0354b662a
2 changed files with 58 additions and 6 deletions

View File

@ -45,7 +45,8 @@ function retrieveFile(path) {
// Support URLs relative to a directory, but be careful about a protocol prefix
// in case we are in the browser (i.e. directories may start with "http://")
function supportRelativeURL(dir, url) {
function supportRelativeURL(file, url) {
var dir = path.dirname(file);
var match = /^\w+:\/\/[^\/]*/.exec(dir);
var protocol = match ? match[0] : '';
return protocol + path.resolve(dir.slice(protocol.length), url);
@ -71,8 +72,7 @@ function retrieveSourceMap(source) {
sourceMapData = new Buffer(sourceMappingURL.slice(dataUrlPrefix.length), "base64").toString();
} else {
// Support source map URLs relative to the source URL
var dir = path.dirname(source);
sourceMappingURL = supportRelativeURL(dir, sourceMappingURL);
sourceMappingURL = supportRelativeURL(source, sourceMappingURL);
sourceMapData = retrieveFile(sourceMappingURL, 'utf8');
}
@ -96,6 +96,18 @@ function mapSourcePosition(position) {
url: urlAndMap.url,
map: new SourceMapConsumer(urlAndMap.map)
};
// Load all sources stored inline with the source map into the file cache
// to pretend like they are already loaded. They may not exist on disk.
if (sourceMap.map.sourcesContent) {
sourceMap.map.sources.forEach(function(source, i) {
var contents = sourceMap.map.sourcesContent[i];
if (contents) {
var url = supportRelativeURL(sourceMap.url, source);
fileContentsCache[url] = contents;
}
});
}
}
}
@ -111,7 +123,7 @@ function mapSourcePosition(position) {
if (originalPosition.source !== null) {
if (sourceMap.url) {
originalPosition.source = supportRelativeURL(
path.dirname(sourceMap.url), originalPosition.source);
sourceMap.url, originalPosition.source);
}
return originalPosition;
}
@ -198,8 +210,17 @@ function getErrorSource(error) {
var source = match[1];
var line = +match[2];
var column = +match[3];
if (fs.existsSync(source)) {
var contents = fs.readFileSync(source, 'utf8');
// Support the inline sourceContents inside the source map
var contents = fileContentsCache[source];
// Support files on disk
if (!contents && fs.existsSync(source)) {
contents = fs.readFileSync(source, 'utf8');
}
// Format the line from the original source code like node does
if (contents) {
var code = contents.split(/(?:\r\n|\r|\n)/)[line - 1];
if (code) {
return '\n' + source + ':' + line + '\n' + code + '\n' +

31
test.js
View File

@ -58,6 +58,21 @@ function createMultiLineSourceMap() {
return sourceMap;
}
function createMultiLineSourceMapWithSourcesContent() {
var sourceMap = createEmptySourceMap();
var original = new Array(1001).join('\n');
for (var i = 1; i <= 100; i++) {
sourceMap.addMapping({
generated: { line: i, column: 0 },
original: { line: 1000 + i, column: 4 },
source: 'original.js'
});
original += ' line ' + i + '\n';
}
sourceMap.setSourceContent('original.js', original);
return sourceMap;
}
function compareStackTrace(sourceMap, source, expected) {
// Check once with a separate source map
fs.writeFileSync('.generated.js.map', sourceMap);
@ -317,3 +332,19 @@ it('specifically requested error source', function(done) {
'^'
]);
});
it('sourcesContent', function(done) {
compareStdout(done, createMultiLineSourceMapWithSourcesContent(), [
'',
'function foo() { throw new Error("this is the error"); }',
'require("./source-map-support").install();',
'process.nextTick(foo);',
'process.nextTick(function() { process.exit(1); });'
], [
/\/original\.js:1002$/,
' line 2',
' ^',
'Error: this is the error',
/^ at foo \(.*\/original\.js:1002:5\)$/
]);
});