Skip to content

Commit

Permalink
Fix faulty .loc information for children of TemplateLiteral nodes.
Browse files Browse the repository at this point in the history
Helps fix #216.
  • Loading branch information
benjamn committed Nov 20, 2015
1 parent 826f93a commit f45c3c0
Showing 1 changed file with 73 additions and 11 deletions.
84 changes: 73 additions & 11 deletions lib/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,9 +127,22 @@ exports.getTrueLoc = function(node, lines) {
return { start: start, end: end };
};

exports.fixFaultyLocations = function(node) {
if ((n.MethodDefinition && n.MethodDefinition.check(node)) ||
(n.Property.check(node) && (node.method || node.shorthand))) {
exports.fixFaultyLocations = function(node, lines) {
var loc = node.loc;
if (loc) {
if (loc.start.line < 1) {
loc.start.line = 1;
}

if (loc.end.line < 1) {
loc.end.line = 1;
}
}

if (node.type === "TemplateLiteral") {
fixTemplateLiteral(node, lines);
} else if ((n.MethodDefinition && n.MethodDefinition.check(node)) ||
(n.Property.check(node) && (node.method || node.shorthand))) {
// If the node is a MethodDefinition or a .method or .shorthand
// Property, then the location information stored in
// node.value.loc is very likely untrustworthy (just the {body}
Expand All @@ -144,15 +157,64 @@ exports.fixFaultyLocations = function(node) {
node.value.id = null;
}
}
};

var loc = node.loc;
if (loc) {
if (loc.start.line < 1) {
loc.start.line = 1;
function fixTemplateLiteral(node, lines) {
assert.strictEqual(node.type, "TemplateLiteral");

if (node.quasis.length === 0) {
// If there are no quasi elements, then there is nothing to fix.
return;
}

// First we need to exclude the opening ` from the .loc of the first
// quasi element, in case the parser accidentally decided to include it.
var afterLeftBackTickPos = copyPos(node.loc.start);
assert.strictEqual(lines.charAt(afterLeftBackTickPos), "`");
assert.ok(lines.nextPos(afterLeftBackTickPos));
var firstQuasi = node.quasis[0];
if (comparePos(firstQuasi.loc.start, afterLeftBackTickPos) < 0) {
firstQuasi.loc.start = afterLeftBackTickPos;
}

// Next we need to exclude the closing ` from the .loc of the last quasi
// element, in case the parser accidentally decided to include it.
var rightBackTickPos = copyPos(node.loc.end);
assert.ok(lines.prevPos(rightBackTickPos));
assert.strictEqual(lines.charAt(rightBackTickPos), "`");
var lastQuasi = node.quasis[node.quasis.length - 1];
if (comparePos(rightBackTickPos, lastQuasi.loc.end) < 0) {
lastQuasi.loc.end = rightBackTickPos;
}

// Now we need to exclude ${ and } characters from the .loc's of all
// quasi elements, since some parsers accidentally include them.
node.expressions.forEach(function (expr, i) {
// Rewind from expr.loc.start over any whitespace and the ${ that
// precedes the expression. The position of the $ should be the same
// as the .loc.end of the preceding quasi element, but some parsers
// accidentally include the ${ in the .loc of the quasi element.
var dollarCurlyPos = lines.skipSpaces(expr.loc.start, true, false);
if (lines.prevPos(dollarCurlyPos) &&
lines.charAt(dollarCurlyPos) === "{" &&
lines.prevPos(dollarCurlyPos) &&
lines.charAt(dollarCurlyPos) === "$") {
var quasiBefore = node.quasis[i];
if (comparePos(dollarCurlyPos, quasiBefore.loc.end) < 0) {
quasiBefore.loc.end = dollarCurlyPos;
}
}

if (loc.end.line < 1) {
loc.end.line = 1;
// Likewise, some parsers accidentally include the } that follows
// the expression in the .loc of the following quasi element.
var rightCurlyPos = lines.skipSpaces(expr.loc.end, false, false);
if (lines.charAt(rightCurlyPos) === "}") {
assert.ok(lines.nextPos(rightCurlyPos));
// Now rightCurlyPos is technically the position just after the }.
var quasiAfter = node.quasis[i + 1];
if (comparePos(quasiAfter.loc.start, rightCurlyPos) < 0) {
quasiAfter.loc.start = rightCurlyPos;
}
}
}
};
});
}

0 comments on commit f45c3c0

Please sign in to comment.