Skip to content

Commit

Permalink
Improve the quality of the source maps in some cases
Browse files Browse the repository at this point in the history
  • Loading branch information
sokra committed Aug 29, 2018
1 parent 89e8ebf commit cf11460
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 27 deletions.
83 changes: 63 additions & 20 deletions lib/ReplaceSource.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,38 @@ class ReplaceSource extends Source {
var replace = new ReplacementEnumerator(this.replacements);
var output = [];
var position = 0;
var sources = Object.create(null);
var sourcesInLines = Object.create(null);

// We build a new list of SourceNodes in "output"
// from the original mapping data

var replaceInStringNode = this._replaceInStringNode.bind(this, output, replace);
var result = new SourceNode();

// We need to add source contents manually
// because "walk" will not handle it
node.walkSourceContents(function(sourceFile, sourceContent) {
result.setSourceContent(sourceFile, sourceContent);
sources["$" + sourceFile] = sourceContent;
});

var replaceInStringNode = this._replaceInStringNode.bind(this, output, replace, function getOriginalSource(mapping) {
var key = "$" + mapping.source;
var lines = sourcesInLines[key];
if(!lines) {
var source = sources[key];
if(!source) return null;
lines = source.split("\n").map(function(line) {
return line + "\n";
});
sourcesInLines[key] = lines;
}
// line is 1-based
if(mapping.line > lines.length) return null;
var line = lines[mapping.line - 1];
return line.substr(mapping.column);
});

node.walk(function(chunk, mapping) {
position = replaceInStringNode(chunk, position, mapping);
});
Expand All @@ -95,12 +122,7 @@ class ReplaceSource extends Source {
output.push(remaining);
}

var result = new SourceNode(null, null, null, output);

// We need to add source contents afterwards
node.walkSourceContents(function(sourceFile, sourceContent) {
result.setSourceContent(sourceFile, sourceContent);
});
result.add(output);

return result;
}
Expand Down Expand Up @@ -161,7 +183,9 @@ class ReplaceSource extends Source {
return position <= 0 ? ["", str] : [str.substr(0, position), str.substr(position)];
}

_replaceInStringNode(output, replace, node, position, parent) {
_replaceInStringNode(output, replace, getOriginalSource, node, position, mapping) {
var original = undefined;

do {
var splitPosition = replace.position - position;
// If multiple replaces occur in the same location then the splitPosition may be
Expand All @@ -172,37 +196,56 @@ class ReplaceSource extends Source {
if(splitPosition >= node.length || replace.done) {
if(replace.emit) {
var nodeEnd = new SourceNode(
parent.line,
parent.column,
parent.source,
mapping.line,
mapping.column,
mapping.source,
node,
parent.name
mapping.name
);
output.push(nodeEnd);
}
return position + node.length;
}

var originalColumn = mapping.column;

// Try to figure out if generated code matches original code of this segement
// If this is the case we assume that it's allowed to move mapping.column
// Because getOriginalSource can be expensive we only do it when neccessary

var nodePart;
if(splitPosition > 0) {
nodePart = node.slice(0, splitPosition);
if(original === undefined) {
original = getOriginalSource(mapping);
}
if(original && original.length >= splitPosition && original.startsWith(nodePart)) {
mapping.column += splitPosition;
original = original.substr(splitPosition);
}
}

var emit = replace.next();
if(!emit) {
// Stop emitting when we have found the beginning of the string to replace.
// Emit the part of the string before splitPosition
if(splitPosition > 0) {
var nodeStart = new SourceNode(
parent.line,
parent.column,
parent.source,
node.substr(0, splitPosition),
parent.name
mapping.line,
originalColumn,
mapping.source,
nodePart,
mapping.name
);
output.push(nodeStart);
}

// Emit the replacement value
if(replace.value) {
output.push(new SourceNode(
parent.line,
parent.column,
parent.source,
mapping.line,
mapping.column,
mapping.source,
replace.value
));
}
Expand Down
18 changes: 11 additions & 7 deletions test/ReplaceSource.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ describe("ReplaceSource", function() {
resultListMap.map.version.should.be.eql(resultMap.map.version);
resultListMap.map.sources.should.be.eql(resultMap.map.sources);
resultListMap.map.sourcesContent.should.be.eql(resultMap.map.sourcesContent);
resultMap.map.mappings.should.be.eql("AAAA;AACA;AAAA;AAAA;AAIA,KACA");
resultListMap.map.mappings.should.be.eql(resultMap.map.mappings);
resultMap.map.mappings.should.be.eql("AAAA,CAAC,EAAI,KAAE,IAAC;AACR,CAAC;AAAA;AAAA;AAID,IAAI,CACJ");
resultListMap.map.mappings.should.be.eql("AAAA;AACA;AAAA;AAAA;AAIA,KACA");
});

it("should replace multiple items correctly", function() {
Expand All @@ -65,15 +65,16 @@ describe("ReplaceSource", function() {
var resultListMap = source.sourceAndMap({
columns: false
});

resultText.should.be.eql("Message: Hey Ad!");
resultMap.source.should.be.eql(resultText);
resultListMap.source.should.be.eql(resultText);
resultListMap.map.file.should.be.eql(resultMap.map.file);
resultListMap.map.version.should.be.eql(resultMap.map.version);
resultListMap.map.sources.should.be.eql(resultMap.map.sources);
resultListMap.map.sourcesContent.should.be.eql(resultMap.map.sourcesContent);
resultMap.map.mappings.should.be.eql("AAAA,cACA");
resultListMap.map.mappings.should.be.eql(resultMap.map.mappings);
resultMap.map.mappings.should.be.eql("AAAA,WAAE,GACE");
resultListMap.map.mappings.should.be.eql("AAAA,cACA");
});

it("should prepend items correctly", function() {
Expand All @@ -89,6 +90,7 @@ describe("ReplaceSource", function() {
var resultListMap = source.sourceAndMap({
columns: false
});

resultText.should.be.eql("Line -1\nLine 0\nLine 1");
resultMap.source.should.be.eql(resultText);
resultListMap.source.should.be.eql(resultText);
Expand All @@ -97,7 +99,7 @@ describe("ReplaceSource", function() {
resultListMap.map.sources.should.be.eql(resultMap.map.sources);
resultListMap.map.sourcesContent.should.be.eql(resultMap.map.sourcesContent);
resultMap.map.mappings.should.be.eql("AAAA;AAAA;AAAA");
resultListMap.map.mappings.should.be.eql(resultMap.map.mappings);
resultListMap.map.mappings.should.be.eql("AAAA;AAAA;AAAA");
});

it("should prepend items with replace at start correctly", function() {
Expand All @@ -116,15 +118,16 @@ describe("ReplaceSource", function() {
var resultListMap = source.sourceAndMap({
columns: false
});

resultText.should.be.eql("Line 0\nHello\nLine 2");
resultMap.source.should.be.eql(resultText);
resultListMap.source.should.be.eql(resultText);
resultListMap.map.file.should.be.eql(resultMap.map.file);
resultListMap.map.version.should.be.eql(resultMap.map.version);
resultListMap.map.sources.should.be.eql(resultMap.map.sources);
resultListMap.map.sourcesContent.should.be.eql(resultMap.map.sourcesContent);
resultMap.map.mappings.should.be.eql("AAAA;AAAA;AACA");
resultListMap.map.mappings.should.be.eql(resultMap.map.mappings);
resultMap.map.mappings.should.be.eql("AAAA;AAAA,KAAM;AACN");
resultListMap.map.mappings.should.be.eql("AAAA;AAAA;AACA");
});

it("should append items correctly", function() {
Expand All @@ -140,6 +143,7 @@ describe("ReplaceSource", function() {
var resultListMap = source.sourceAndMap({
columns: false
});

resultText.should.be.eql("Line 1\nLine 2\n");
resultMap.source.should.be.eql(resultText);
resultListMap.source.should.be.eql(resultText);
Expand Down

0 comments on commit cf11460

Please sign in to comment.