Skip to content
This repository was archived by the owner on Oct 9, 2020. It is now read-only.

Commit a49584b

Browse files
fix incorrect concatenation of source maps
1 parent 2649e18 commit a49584b

File tree

2 files changed

+48
-147
lines changed

2 files changed

+48
-147
lines changed

lib/output.js

Lines changed: 23 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -4,69 +4,39 @@ var fs = require('fs');
44
var Promise = require('bluebird');
55
var asp = require('bluebird').promisify;
66
var extend = require('./utils').extend;
7-
87
var fromFileURL = require('./utils').fromFileURL;
9-
var toFileURL = require('./utils').toFileURL;
108

119
function countLines(str) {
1210
return str.split(/\r\n|\r|\n/).length;
1311
}
1412

15-
// Process compiler outputs, gathering:
16-
//
17-
// concatOutputs: list of source strings to concatenate
18-
// sourceMapsWithOffsets: list of [absolute offset,
19-
// source map string] pairs
20-
//
21-
// Takes lists as empty references and populates via push.
22-
function processOutputs(outputs) {
23-
var removeSourceMaps = require('./sourcemaps').removeSourceMaps;
24-
25-
var offset = 0;
26-
27-
var outputObj = {};
28-
29-
var sources = outputObj.sources = [];
30-
var sourceMapsWithOffsets = outputObj.sourceMapsWithOffsets = [];
31-
32-
outputs.forEach(function(output) {
33-
var source;
34-
if (typeof output == 'object') {
35-
source = output.source || '';
36-
var offset_ = output.sourceMapOffset || 0;
37-
var map = output.sourceMap;
38-
if (map) {
39-
sourceMapsWithOffsets.push([offset + offset_, map]);
40-
}
41-
}
42-
// NB perhaps we should enforce output is always an object down the chain?
43-
else if (typeof output == 'string') {
44-
source = output;
45-
}
46-
else {
47-
throw "Unexpected output format: " + output.toString();
13+
function createOutput(outFile, outputs, basePath, sourceMaps, sourceMapContents) {
14+
var concatenate = require('./sourcemaps').concatenate;
15+
var files = outputs.map(function (el) {
16+
if (el.source) {
17+
//normalize source urls
18+
el.sourceMap.sources = el.sourceMap.sources.map(function (sourceURL) {
19+
return sourceURL.replace(/\\/g, "/");
20+
});
21+
return {
22+
code: el.source,
23+
map: el.sourceMap
24+
};
25+
} else {
26+
return {
27+
code: el,
28+
map: undefined
29+
};
4830
}
49-
source = removeSourceMaps(source || '');
50-
offset += countLines(source);
51-
sources.push(source);
5231
});
53-
54-
return outputObj;
55-
}
56-
57-
function createOutput(outFile, outputs, basePath, sourceMaps, sourceMapContents) {
58-
var concatenateSourceMaps = require('./sourcemaps').concatenateSourceMaps;
59-
60-
var outputObj = processOutputs(outputs);
61-
62-
if (sourceMaps)
63-
var sourceMap = concatenateSourceMaps(outFile, outputObj.sourceMapsWithOffsets, basePath, sourceMapContents);
64-
65-
var output = outputObj.sources.join('\n');
32+
//concatenates sources and appropriate source maps
33+
var concatenated = concatenate(files, outFile).toStringWithSourceMap({
34+
file: path.basename(outFile)
35+
});
6636

6737
return {
68-
source: output,
69-
sourceMap: sourceMap
38+
source: concatenated.code,
39+
sourceMap: concatenated.map.toString()
7040
};
7141
}
7242

lib/sourcemaps.js

Lines changed: 25 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -1,105 +1,36 @@
11
var sourceMap = require('source-map');
2+
var SourceNode = sourceMap.SourceNode;
3+
var SourceMapConsumer = sourceMap.SourceMapConsumer;
24
var path = require('path');
3-
var fs = require('fs');
45

5-
var toFileURL = require('./utils').toFileURL;
6-
var fromFileURL = require('./utils').fromFileURL;
6+
exports.concatenate = function(files, outFile) {
7+
var concatenated = new SourceNode();
78

8-
var wrapSourceMap = function(map) {
9-
return new sourceMap.SourceMapConsumer(map);
10-
};
11-
12-
var sourceMapRegEx = /\/\/[@#] ?(sourceURL|sourceMappingURL)=([^\n'"]+)/;
13-
exports.removeSourceMaps = function(source) {
14-
return source.replace(sourceMapRegEx, '');
15-
};
16-
17-
function getMapObject(map) {
18-
if (typeof map != 'string')
19-
return map;
20-
21-
try {
22-
return JSON.parse(map);
23-
}
24-
catch(error) {
25-
throw new Error('Invalid JSON: ' + map);
26-
}
27-
}
28-
29-
function isFileURL(url) {
30-
return url.substr(0, 8) == 'file:///';
31-
}
32-
33-
exports.concatenateSourceMaps = function(outFile, mapsWithOffsets, basePath, sourceMapContents) {
34-
var generated = new sourceMap.SourceMapGenerator({
35-
file: path.basename(outFile)
36-
});
37-
38-
var outPath = path.dirname(outFile);
39-
40-
var contentsBySource = sourceMapContents ? {} : null;
41-
42-
mapsWithOffsets.forEach(function(pair) {
43-
var offset = pair[0];
44-
var map = getMapObject(pair[1]);
45-
46-
if (sourceMapContents && map.sourcesContent) {
47-
for (var i=0; i<map.sources.length; i++) {
48-
var source = (map.sourceRoot || '') + map.sources[i];
49-
if (!source.match(/\/@traceur/)) {
50-
if (!contentsBySource[source]) {
51-
contentsBySource[source] = map.sourcesContent[i];
52-
} else {
53-
if (contentsBySource[source] != map.sourcesContent[i]) {
54-
throw new Error("Mismatched sourcesContent for: " + source);
55-
}
56-
}
57-
}
58-
}
9+
files.forEach(function (file, index) {
10+
if (index !== 0) {
11+
concatenated.add("\n");
5912
}
6013

61-
wrapSourceMap(map).eachMapping(function(mapping) {
62-
if (!mapping.originalLine || !mapping.originalColumn || !mapping.source || mapping.source.match(/(\/|^)@traceur/))
63-
return;
64-
65-
generated.addMapping({
66-
generated: {
67-
line: offset + mapping.generatedLine,
68-
column: mapping.generatedColumn
69-
},
70-
original: {
71-
line: mapping.originalLine,
72-
column: mapping.originalColumn
73-
},
74-
source: mapping.source,
75-
name: mapping.name
76-
});
77-
});
78-
});
79-
80-
// normalize source paths and inject sourcesContent if necessary
81-
var normalized = JSON.parse(JSON.stringify(generated));
82-
83-
if (sourceMapContents) {
84-
normalized.sourcesContent = normalized.sources.map(function(source) {
85-
if (contentsBySource[source])
86-
return contentsBySource[source];
87-
88-
try {
89-
return fs.readFileSync(path.resolve(basePath, source)).toString();
90-
}
91-
catch (e) {
92-
return "";
14+
var node;
15+
var map = file.map;
16+
if (map) {
17+
if (typeof map.toJSON === "function") {
18+
map = map.toJSON();
9319
}
94-
});
95-
}
96-
97-
normalized.sources = normalized.sources.map(function(source) {
98-
if (isFileURL(source))
99-
source = fromFileURL(source);
20+
node = SourceNode.fromStringWithSourceMap(
21+
file.code,
22+
new SourceMapConsumer(map),
23+
path.relative(
24+
path.dirname(outFile + ".map"),
25+
path.dirname(".")
26+
)
27+
);
28+
} else {
29+
node = new SourceNode(null, null, null, file.code);
30+
}
10031

101-
return path.relative(outPath, path.resolve(basePath, source)).replace(/\\/g, '/');
32+
concatenated.add(node);
10233
});
10334

104-
return JSON.stringify(normalized);
35+
return concatenated;
10536
};

0 commit comments

Comments
 (0)