From 81761d53fe2ae2a10c4c281581498163cbb60f4c Mon Sep 17 00:00:00 2001 From: Toru Nagashima Date: Thu, 8 Nov 2018 22:05:00 +0900 Subject: [PATCH] Breaking: throw syntax error on solo `const` keyword (fixes #531) --- package.json | 9 ++++++ parser.js | 43 ++++++++++++++++++++++--- tests/fixtures/basics/solo-const.src.js | 1 + tests/lib/__snapshots__/basics.js.snap | 2 ++ 4 files changed, 51 insertions(+), 4 deletions(-) create mode 100644 tests/fixtures/basics/solo-const.src.js diff --git a/package.json b/package.json index efa7b8b..8799fec 100644 --- a/package.json +++ b/package.json @@ -63,6 +63,15 @@ "collectCoverage": true, "coverageReporters": [ "text-summary" + ], + "collectCoverageFrom": [ + "**/*.js", + "!**/coverage/**", + "!**/node_modules/**", + "!**/tests/**", + "!**/tools/**", + "!**/Makefile.js", + "!**/test.js" ] } } diff --git a/parser.js b/parser.js index 32b4e7c..28bc3cb 100644 --- a/parser.js +++ b/parser.js @@ -13,6 +13,21 @@ const astNodeTypes = require("typescript-estree").AST_NODE_TYPES; const traverser = require("eslint/lib/util/traverser"); const visitorKeys = require("./visitor-keys"); +/** + * Create a syntax error object. + * @param {ASTNode} node The node that caused the error. + * @param {string} message The error message. + * @returns {SyntaxError} The created error. + */ +function newSyntaxError(node, message) { + const error = new SyntaxError(message); + error.index = node.range[0]; + error.lineNumber = node.loc.start.line; + error.column = node.loc.start.column + 1; + + return error; +} + //------------------------------------------------------------------------------ // Public //------------------------------------------------------------------------------ @@ -23,10 +38,30 @@ exports.parseForESLint = function parseForESLint(code, options) { const ast = parse(code, options); traverser.traverse(ast, { enter: node => { - if (node.type === "DeclareFunction" || node.type === "FunctionExpression" || node.type === "FunctionDeclaration") { - if (!node.body) { - node.type = `TSEmptyBody${node.type}`; - } + switch (node.type) { + // Just for backword compatibility. + case "DeclareFunction": + if (!node.body) { + node.type = `TSEmptyBody${node.type}`; + } + break; + + // Function#body cannot be null in ESTree spec. + case "FunctionExpression": + case "FunctionDeclaration": + if (!node.body) { + node.type = `TSEmptyBody${node.type}`; + } + break; + + // VariableDeclaration that doesn't have any declarations is syntax error. + case "VariableDeclaration": + if (node.declarations.length === 0) { + throw newSyntaxError(node, `'${node.kind}' declarations require one or more declarator(s).`); + } + break; + + // no default } } }); diff --git a/tests/fixtures/basics/solo-const.src.js b/tests/fixtures/basics/solo-const.src.js new file mode 100644 index 0000000..aaae4e1 --- /dev/null +++ b/tests/fixtures/basics/solo-const.src.js @@ -0,0 +1 @@ +const diff --git a/tests/lib/__snapshots__/basics.js.snap b/tests/lib/__snapshots__/basics.js.snap index d952c5a..d9fc279 100644 --- a/tests/lib/__snapshots__/basics.js.snap +++ b/tests/lib/__snapshots__/basics.js.snap @@ -2162,6 +2162,8 @@ Object { } `; +exports[`basics fixtures/solo-const.src 1`] = `"'const' declarations require one or more declarator(s)."`; + exports[`basics fixtures/typeof-expression.src 1`] = ` Object { "body": Array [