diff --git a/eslint/babel-eslint-parser/acorn-to-esprima.js b/eslint/babel-eslint-parser/acorn-to-esprima.js index 995ca2ae5d..8a26e10db5 100644 --- a/eslint/babel-eslint-parser/acorn-to-esprima.js +++ b/eslint/babel-eslint-parser/acorn-to-esprima.js @@ -80,8 +80,10 @@ function isCompatTag(tagName) { function convertTemplateType(tokens) { var startingToken = 0; var currentToken = 0; + // track use of {} var numBraces = 0; - var hasTemplateEnded = true; + // track number of nested templates + var numBackQuotes = 0; function isBackQuote(token) { return tokens[token].type === tt.backQuote; @@ -89,7 +91,8 @@ function convertTemplateType(tokens) { function isTemplateStarter(token) { return isBackQuote(token) || - tokens[token].type === tt.braceR; + // only can be a template starter when in a template already + tokens[token].type === tt.braceR && numBackQuotes > 0; } function isTemplateEnder(token) { @@ -138,6 +141,10 @@ function convertTemplateType(tokens) { 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" @@ -153,10 +160,12 @@ function convertTemplateType(tokens) { currentToken++; } - hasTemplateEnded = isBackQuote(currentToken); + if (isBackQuote(currentToken)) { + numBackQuotes--; + } // template start and end found: create new token replaceWithTemplateType(startingToken, currentToken); - } else if (!hasTemplateEnded) { + } else if (numBackQuotes > 0) { trackNumBraces(startingToken); } startingToken++; diff --git a/eslint/babel-eslint-parser/test/babel-eslint.js b/eslint/babel-eslint-parser/test/babel-eslint.js index 40a9fc84e0..64260de815 100644 --- a/eslint/babel-eslint-parser/test/babel-eslint.js +++ b/eslint/babel-eslint-parser/test/babel-eslint.js @@ -33,16 +33,29 @@ function assertImplementsAST(target, source, path) { function parseAndAssertSame(code) { var esAST = espree.parse(code, { - env: { - "es6": true, - "node": true - }, ecmaFeatures: { + arrowFunctions: true, blockBindings: true, + destructuring: true, + regexYFlag: true, + regexUFlag: true, templateStrings: true, - modules: true, + binaryLiterals: true, + octalLiterals: true, + unicodeCodePointEscapes: true, + defaultParams: true, + restParams: true, + forOf: true, + objectLiteralComputedProperties: true, + objectLiteralShorthandMethods: true, + objectLiteralShorthandProperties: true, + objectLiteralDuplicateProperties: true, + generators: true, + spread: true, classes: true, - jsx: true + modules: true, + jsx: true, + globalReturn: true }, tokens: true, loc: true, @@ -124,6 +137,17 @@ describe("acorn-to-esprima", function () { "}" ); }); + + it("template with destructuring #31", function () { + parseAndAssertSame([ + "module.exports = {", + "render() {", + "var {name} = this.props;", + "return Math.max(null, `Name: ${name}, Name: ${name}`);", + "}", + "};" + ].join("\n")); + }); }); it("simple expression", function () { diff --git a/eslint/babel-eslint-parser/test/non-regression.js b/eslint/babel-eslint-parser/test/non-regression.js index 3cb0222a5b..1b2a2a8a30 100644 --- a/eslint/babel-eslint-parser/test/non-regression.js +++ b/eslint/babel-eslint-parser/test/non-regression.js @@ -164,6 +164,19 @@ describe("verify", function () { ); }); + it("template with destructuring #31", function () { + verifyAndAssertMessages([ + "module.exports = {", + "render() {", + "var {name} = this.props;", + "return Math.max(null, `Name: ${name}, Name: ${name}`);", + "}", + "};"].join("\n"), + { "comma-spacing": 1 }, + [] + ); + }); + describe("decorators #72", function () { it("class declaration", function () { verifyAndAssertMessages(