diff --git a/eslint/babel-eslint-parser/.prettierignore b/eslint/babel-eslint-parser/.prettierignore new file mode 100644 index 0000000000..a6c57f5fb2 --- /dev/null +++ b/eslint/babel-eslint-parser/.prettierignore @@ -0,0 +1 @@ +*.json diff --git a/eslint/babel-eslint-parser/lib/babylon-to-espree/convertTemplateType.js b/eslint/babel-eslint-parser/lib/babylon-to-espree/convertTemplateType.js index d8892f9972..accde61e56 100644 --- a/eslint/babel-eslint-parser/lib/babylon-to-espree/convertTemplateType.js +++ b/eslint/babel-eslint-parser/lib/babylon-to-espree/convertTemplateType.js @@ -1,99 +1,92 @@ "use strict"; module.exports = function(tokens, tt) { - var startingToken = 0; - var currentToken = 0; - var numBraces = 0; // track use of {} - var numBackQuotes = 0; // track number of nested templates + let curlyBrace = null; + let templateTokens = []; + const result = []; - function isBackQuote(token) { - return tokens[token].type === tt.backQuote; - } + function addTemplateType() { + const start = templateTokens[0]; + const end = templateTokens[templateTokens.length - 1]; - function isTemplateStarter(token) { - return ( - isBackQuote(token) || - // only can be a template starter when in a template already - (tokens[token].type === tt.braceR && numBackQuotes > 0) - ); - } - - function isTemplateEnder(token) { - return isBackQuote(token) || tokens[token].type === tt.dollarBraceL; - } - - // append the values between start and end - 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; + const value = templateTokens.reduce((result, token) => { + if (token.value) { + result += token.value; + } else if (token.type !== tt.template) { + result += token.type.label; } - start++; - } - return value; - } - // create Template token - function replaceWithTemplateType(start, end) { - var templateToken = { + return result; + }, ""); + + result.push({ type: "Template", - value: createTemplateValue(start, end), - start: tokens[start].start, - end: tokens[end].end, + value: value, + start: start.start, + end: end.end, loc: { - start: tokens[start].loc.start, - end: tokens[end].loc.end, + start: start.loc.start, + end: end.loc.end, }, - }; + }); - // put new token in place of old tokens - tokens.splice(start, end - start + 1, templateToken); + templateTokens = []; } - function trackNumBraces(token) { - if (tokens[token].type === tt.braceL) { - numBraces++; - } else if (tokens[token].type === tt.braceR) { - numBraces--; - } - } - - while (startingToken < tokens.length) { - // template start: check if ` or } - if (isTemplateStarter(startingToken) && numBraces === 0) { - if (isBackQuote(startingToken)) { - numBackQuotes++; - } - - currentToken = startingToken + 1; - - // check if token after template start is "template" - if ( - currentToken >= tokens.length - 1 || - tokens[currentToken].type !== tt.template - ) { - break; - } - - // template end: find ` or ${ - while (!isTemplateEnder(currentToken)) { - if (currentToken >= tokens.length - 1) { - break; + tokens.forEach(token => { + switch (token.type) { + case tt.backQuote: + if (curlyBrace) { + result.push(curlyBrace); + curlyBrace = null; } - currentToken++; - } - if (isBackQuote(currentToken)) { - numBackQuotes--; - } - // template start and end found: create new token - replaceWithTemplateType(startingToken, currentToken); - } else if (numBackQuotes > 0) { - trackNumBraces(startingToken); + templateTokens.push(token); + + if (templateTokens.length > 1) { + addTemplateType(); + } + + break; + + case tt.dollarBraceL: + templateTokens.push(token); + addTemplateType(); + break; + + case tt.braceR: + if (curlyBrace) { + result.push(curlyBrace); + } + + curlyBrace = token; + break; + + case tt.template: + if (curlyBrace) { + templateTokens.push(curlyBrace); + curlyBrace = null; + } + + templateTokens.push(token); + break; + + case tt.eof: + if (curlyBrace) { + result.push(curlyBrace); + } + + break; + + default: + if (curlyBrace) { + result.push(curlyBrace); + curlyBrace = null; + } + + result.push(token); } - startingToken++; - } + }); + + return result; }; diff --git a/eslint/babel-eslint-parser/lib/babylon-to-espree/index.js b/eslint/babel-eslint-parser/lib/babylon-to-espree/index.js index ecd8eee6f1..6d6e12bfc0 100644 --- a/eslint/babel-eslint-parser/lib/babylon-to-espree/index.js +++ b/eslint/babel-eslint-parser/lib/babylon-to-espree/index.js @@ -6,11 +6,6 @@ var toTokens = require("./toTokens"); var toAST = require("./toAST"); module.exports = function(ast, traverse, tt, code) { - // remove EOF token, eslint doesn't use this for anything and it interferes - // with some rules see https://github.com/babel/babel-eslint/issues/2 - // todo: find a more elegant way to do this - ast.tokens.pop(); - // convert tokens ast.tokens = toTokens(ast.tokens, tt, code); diff --git a/eslint/babel-eslint-parser/lib/babylon-to-espree/toTokens.js b/eslint/babel-eslint-parser/lib/babylon-to-espree/toTokens.js index a863b871b0..bb30819bac 100644 --- a/eslint/babel-eslint-parser/lib/babylon-to-espree/toTokens.js +++ b/eslint/babel-eslint-parser/lib/babylon-to-espree/toTokens.js @@ -4,16 +4,7 @@ var convertTemplateType = require("./convertTemplateType"); var toToken = require("./toToken"); module.exports = function(tokens, tt, code) { - // transform tokens to type "Template" - convertTemplateType(tokens, tt); - - var transformedTokens = []; - for (var i = 0; i < tokens.length; i++) { - var token = tokens[i]; - if (token.type !== "CommentLine" && token.type !== "CommentBlock") { - transformedTokens.push(toToken(token, tt, code)); - } - } - - return transformedTokens; + return convertTemplateType(tokens, tt) + .filter(t => t.type !== "CommentLine" && t.type !== "CommentBlock") + .map(t => toToken(t, tt, code)); }; diff --git a/eslint/babel-eslint-parser/test/babel-eslint.js b/eslint/babel-eslint-parser/test/babel-eslint.js index b0a2cd10f2..98b7e93928 100644 --- a/eslint/babel-eslint-parser/test/babel-eslint.js +++ b/eslint/babel-eslint-parser/test/babel-eslint.js @@ -62,7 +62,7 @@ function parseAndAssertSame(code) { `); throw err; } - // assert.equal(esAST, babylonAST); + //assert.equal(esAST, babylonAST); } describe("babylon-to-espree", () => { @@ -158,6 +158,14 @@ describe("babylon-to-espree", () => { }; `); }); + + it("template with arrow returning template #603", () => { + parseAndAssertSame(` + var a = \`\${() => { + \`\${''}\` + }}\`; + `); + }); }); it("simple expression", () => { diff --git a/eslint/babel-eslint-parser/test/non-regression.js b/eslint/babel-eslint-parser/test/non-regression.js index 687af37cc4..af36963e5c 100644 --- a/eslint/babel-eslint-parser/test/non-regression.js +++ b/eslint/babel-eslint-parser/test/non-regression.js @@ -1112,6 +1112,18 @@ describe("verify", () => { ); }); + it("template with arrow returning template #603", () => { + verifyAndAssertMessages( + ` + var a = \`\${() => { + \`\${''}\` + }}\`; + `, + { indent: 1 }, + [] + ); + }); + describe("decorators #72", () => { it("class declaration", () => { verifyAndAssertMessages(