Merge pull request babel/babel-eslint#94 from hzoo/support-templates
support template strings - Fixes babel/babel-eslint#31
This commit is contained in:
parent
527287aa29
commit
d84fc559f2
@ -58,10 +58,82 @@ exports.toAST = function (ast) {
|
|||||||
traverse(ast, astTransformVisitor);
|
traverse(ast, astTransformVisitor);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
exports.toTokens = function (tokens) {
|
||||||
|
// transform tokens to type "Template"
|
||||||
|
convertTemplateType(tokens);
|
||||||
|
|
||||||
|
return tokens.map(exports.toToken);
|
||||||
|
};
|
||||||
|
|
||||||
function isCompatTag(tagName) {
|
function isCompatTag(tagName) {
|
||||||
return tagName && /^[a-z]|\-/.test(tagName);
|
return tagName && /^[a-z]|\-/.test(tagName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function convertTemplateType(tokens) {
|
||||||
|
var startingToken = 0;
|
||||||
|
var currentToken = 0;
|
||||||
|
var numBraces = 0;
|
||||||
|
|
||||||
|
function isTemplateStarter(token) {
|
||||||
|
return tokens[token].type === tt.backQuote ||
|
||||||
|
tokens[token].type === tt.braceR;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isTemplateEnder(token) {
|
||||||
|
return tokens[token].type === tt.dollarBraceL ||
|
||||||
|
tokens[token].type === tt.backQuote;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createTemplateValue(start, end) {
|
||||||
|
var value = "";
|
||||||
|
while (start <= end) {
|
||||||
|
if (tokens[start].value) {
|
||||||
|
value += tokens[start].value;
|
||||||
|
} else if (tokens[start].type !== tt.template) {
|
||||||
|
value += tokens[start].type.label;
|
||||||
|
}
|
||||||
|
start++;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function replaceWithTemplateType(start, end) {
|
||||||
|
var templateToken = {
|
||||||
|
type: 'Template',
|
||||||
|
value: createTemplateValue(start, end),
|
||||||
|
range: [tokens[start].start, tokens[end].end],
|
||||||
|
loc: {
|
||||||
|
start: tokens[start].loc.start,
|
||||||
|
end: tokens[end].loc.end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tokens.splice(start, end - start + 1, templateToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkNumBraces(token) {
|
||||||
|
if (tokens[token].type === tt.braceL) {
|
||||||
|
numBraces++;
|
||||||
|
} else if (tokens[token].type === tt.braceR) {
|
||||||
|
numBraces--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (startingToken < tokens.length) {
|
||||||
|
if (isTemplateStarter(startingToken) && numBraces === 0) {
|
||||||
|
currentToken = startingToken + 1;
|
||||||
|
while (currentToken < tokens.length - 1 && !isTemplateEnder(currentToken)) {
|
||||||
|
checkNumBraces(currentToken);
|
||||||
|
currentToken++;
|
||||||
|
}
|
||||||
|
replaceWithTemplateType(startingToken, currentToken);
|
||||||
|
startingToken++;
|
||||||
|
} else {
|
||||||
|
checkNumBraces(startingToken);
|
||||||
|
startingToken++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var astTransformVisitor = {
|
var astTransformVisitor = {
|
||||||
noScope: true,
|
noScope: true,
|
||||||
exit: function (node, parent) {
|
exit: function (node, parent) {
|
||||||
@ -117,5 +189,24 @@ var astTransformVisitor = {
|
|||||||
node.delegate = node.all;
|
node.delegate = node.all;
|
||||||
delete node.all;
|
delete node.all;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// template strings
|
||||||
|
|
||||||
|
if (t.isTemplateLiteral(node)) {
|
||||||
|
node.quasis.forEach(function (q) {
|
||||||
|
q.range[0] -= 1;
|
||||||
|
if (q.tail) {
|
||||||
|
q.range[1] += 1;
|
||||||
|
} else {
|
||||||
|
q.range[1] += 2;
|
||||||
|
}
|
||||||
|
q.loc.start.column -= 1;
|
||||||
|
if (q.tail) {
|
||||||
|
q.loc.end.column += 1;
|
||||||
|
} else {
|
||||||
|
q.loc.end.column += 2;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -56,7 +56,7 @@ function monkeypatch() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.attachComments = function(ast, comments, tokens) {
|
exports.attachComments = function (ast, comments, tokens) {
|
||||||
estraverse.attachComments(ast, comments, tokens);
|
estraverse.attachComments(ast, comments, tokens);
|
||||||
|
|
||||||
if (comments.length) {
|
if (comments.length) {
|
||||||
@ -82,7 +82,7 @@ exports.attachComments = function(ast, comments, tokens) {
|
|||||||
node.leadingComments = [];
|
node.leadingComments = [];
|
||||||
var firstTokenStart = token.range[0];
|
var firstTokenStart = token.range[0];
|
||||||
var len = comments.length;
|
var len = comments.length;
|
||||||
for(var i = 0; i < len && comments[i].start < firstTokenStart; i++ ) {
|
for (var i = 0; i < len && comments[i].start < firstTokenStart; i++) {
|
||||||
node.leadingComments.push(comments[i]);
|
node.leadingComments.push(comments[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -138,7 +138,7 @@ exports.parse = function (code) {
|
|||||||
tokens.pop();
|
tokens.pop();
|
||||||
|
|
||||||
// convert tokens
|
// convert tokens
|
||||||
ast.tokens = tokens.map(acornToEsprima.toToken);
|
ast.tokens = acornToEsprima.toTokens(tokens);
|
||||||
|
|
||||||
// add comments
|
// add comments
|
||||||
ast.comments = comments;
|
ast.comments = comments;
|
||||||
|
|||||||
@ -20,7 +20,7 @@ function assertImplementsAST(target, source, path) {
|
|||||||
error("have different types (" + typeA + " !== " + typeB + ")");
|
error("have different types (" + typeA + " !== " + typeB + ")");
|
||||||
} else if (typeA === "object") {
|
} else if (typeA === "object") {
|
||||||
var keysTarget = Object.keys(target);
|
var keysTarget = Object.keys(target);
|
||||||
for(var i in keysTarget) {
|
for (var i in keysTarget) {
|
||||||
var key = keysTarget[i];
|
var key = keysTarget[i];
|
||||||
path.push(key);
|
path.push(key);
|
||||||
assertImplementsAST(target[key], source[key], path);
|
assertImplementsAST(target[key], source[key], path);
|
||||||
@ -34,6 +34,7 @@ function assertImplementsAST(target, source, path) {
|
|||||||
function parseAndAssertSame(code) {
|
function parseAndAssertSame(code) {
|
||||||
var esAST = espree.parse(code, {
|
var esAST = espree.parse(code, {
|
||||||
ecmaFeatures: {
|
ecmaFeatures: {
|
||||||
|
templateStrings: true,
|
||||||
modules: true,
|
modules: true,
|
||||||
classes: true,
|
classes: true,
|
||||||
jsx: true
|
jsx: true
|
||||||
@ -50,14 +51,60 @@ function parseAndAssertSame(code) {
|
|||||||
} catch(err) {
|
} catch(err) {
|
||||||
err.message +=
|
err.message +=
|
||||||
"\nespree:\n" +
|
"\nespree:\n" +
|
||||||
util.inspect(esAST, {depth: err.depth}) +
|
util.inspect(esAST, {depth: err.depth, colors: true}) +
|
||||||
"\nbabel-eslint:\n" +
|
"\nbabel-eslint:\n" +
|
||||||
util.inspect(acornAST, {depth: err.depth});
|
util.inspect(acornAST, {depth: err.depth, colors: true});
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
describe("acorn-to-esprima", function () {
|
describe("acorn-to-esprima", function () {
|
||||||
|
describe("templates", function () {
|
||||||
|
it("empty template string", function () {
|
||||||
|
parseAndAssertSame("``");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("template string", function () {
|
||||||
|
parseAndAssertSame("`test`");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("template string using $", function () {
|
||||||
|
parseAndAssertSame("`$`");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("template string with expression", function () {
|
||||||
|
parseAndAssertSame("`${a}`");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("template string with multiple expressions", function () {
|
||||||
|
parseAndAssertSame("`${a}${b}${c}`");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("template string with expression and strings", function () {
|
||||||
|
parseAndAssertSame("`a${a}a`");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("template string with binary expression", function () {
|
||||||
|
parseAndAssertSame("`a${a + b}a`");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("tagged template", function () {
|
||||||
|
parseAndAssertSame("jsx`<Button>Click</Button>`");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("tagged template with expression", function () {
|
||||||
|
parseAndAssertSame("jsx`<Button>Hi ${name}</Button>`");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("tagged template with new operator", function () {
|
||||||
|
parseAndAssertSame("new raw`42`");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("template with nested function/object", function () {
|
||||||
|
parseAndAssertSame("`outer${{x: {y: 10}}}bar${`nested${function(){return 1;}}endnest`}end`");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it("simple expression", function () {
|
it("simple expression", function () {
|
||||||
parseAndAssertSame("a = 1");
|
parseAndAssertSame("a = 1");
|
||||||
});
|
});
|
||||||
|
|||||||
@ -139,4 +139,14 @@ describe("verify", function () {
|
|||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("template strings #31", function () {
|
||||||
|
verifyAndAssertMessages(
|
||||||
|
"console.log(`${a}, b`);",
|
||||||
|
{ "comma-spacing": 1 },
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user