From 7945e7a1d7ed3d9bb64f131d1b384ce37f8716dd Mon Sep 17 00:00:00 2001 From: matmalkowski Date: Thu, 21 Nov 2019 23:09:43 +0700 Subject: [PATCH 1/6] Chore: Adds typescript generics tests for arrow-parens (refs #12570) --- .../parsers/arrow-parens/generic-no-params.js | 521 ++++++++++++++++ .../parsers/arrow-parens/generic-param.js | 557 ++++++++++++++++++ tests/lib/rules/arrow-parens.js | 2 + 3 files changed, 1080 insertions(+) create mode 100644 tests/fixtures/parsers/arrow-parens/generic-no-params.js create mode 100644 tests/fixtures/parsers/arrow-parens/generic-param.js diff --git a/tests/fixtures/parsers/arrow-parens/generic-no-params.js b/tests/fixtures/parsers/arrow-parens/generic-no-params.js new file mode 100644 index 00000000000..7c45d6bde4b --- /dev/null +++ b/tests/fixtures/parsers/arrow-parens/generic-no-params.js @@ -0,0 +1,521 @@ +"use strict"; + +/* + * Parsed on astexplorer.net using @typescript-eslint/parser-2.6.1 + * + * Source: + * (): T => { return 1 } + */ + +exports.parse = () => ( + { + "type": "Program", + "body": [ + { + "type": "ExpressionStatement", + "expression": { + "type": "ArrowFunctionExpression", + "generator": false, + "id": null, + "params": [], + "body": { + "type": "BlockStatement", + "body": [ + { + "type": "ReturnStatement", + "argument": { + "type": "Literal", + "value": 1, + "raw": "1", + "range": [ + 36, + 37 + ], + "loc": { + "start": { + "line": 1, + "column": 36 + }, + "end": { + "line": 1, + "column": 37 + } + } + }, + "range": [ + 29, + 37 + ], + "loc": { + "start": { + "line": 1, + "column": 29 + }, + "end": { + "line": 1, + "column": 37 + } + } + } + ], + "range": [ + 27, + 39 + ], + "loc": { + "start": { + "line": 1, + "column": 27 + }, + "end": { + "line": 1, + "column": 39 + } + } + }, + "async": false, + "expression": false, + "range": [ + 0, + 39 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 39 + } + }, + "returnType": { + "type": "TSTypeAnnotation", + "loc": { + "start": { + "line": 1, + "column": 20 + }, + "end": { + "line": 1, + "column": 23 + } + }, + "range": [ + 20, + 23 + ], + "typeAnnotation": { + "type": "TSTypeReference", + "typeName": { + "type": "Identifier", + "name": "T", + "range": [ + 22, + 23 + ], + "loc": { + "start": { + "line": 1, + "column": 22 + }, + "end": { + "line": 1, + "column": 23 + } + } + }, + "range": [ + 22, + 23 + ], + "loc": { + "start": { + "line": 1, + "column": 22 + }, + "end": { + "line": 1, + "column": 23 + } + } + } + }, + "typeParameters": { + "type": "TSTypeParameterDeclaration", + "range": [ + 0, + 18 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 18 + } + }, + "params": [ + { + "type": "TSTypeParameter", + "name": { + "type": "Identifier", + "name": "T", + "range": [ + 1, + 2 + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 2 + } + } + }, + "constraint": { + "type": "TSTypeReference", + "typeName": { + "type": "Identifier", + "name": "Object", + "range": [ + 11, + 17 + ], + "loc": { + "start": { + "line": 1, + "column": 11 + }, + "end": { + "line": 1, + "column": 17 + } + } + }, + "range": [ + 11, + 17 + ], + "loc": { + "start": { + "line": 1, + "column": 11 + }, + "end": { + "line": 1, + "column": 17 + } + } + }, + "range": [ + 1, + 17 + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 17 + } + } + } + ] + } + }, + "range": [ + 0, + 39 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 39 + } + } + } + ], + "sourceType": "module", + "range": [ + 0, + 39 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 39 + } + }, + "tokens": [ + { + "type": "Punctuator", + "value": "<", + "range": [ + 0, + 1 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + { + "type": "Identifier", + "value": "T", + "range": [ + 1, + 2 + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 2 + } + } + }, + { + "type": "Keyword", + "value": "extends", + "range": [ + 3, + 10 + ], + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 10 + } + } + }, + { + "type": "Identifier", + "value": "Object", + "range": [ + 11, + 17 + ], + "loc": { + "start": { + "line": 1, + "column": 11 + }, + "end": { + "line": 1, + "column": 17 + } + } + }, + { + "type": "Punctuator", + "value": ">", + "range": [ + 17, + 18 + ], + "loc": { + "start": { + "line": 1, + "column": 17 + }, + "end": { + "line": 1, + "column": 18 + } + } + }, + { + "type": "Punctuator", + "value": "(", + "range": [ + 18, + 19 + ], + "loc": { + "start": { + "line": 1, + "column": 18 + }, + "end": { + "line": 1, + "column": 19 + } + } + }, + { + "type": "Punctuator", + "value": ")", + "range": [ + 19, + 20 + ], + "loc": { + "start": { + "line": 1, + "column": 19 + }, + "end": { + "line": 1, + "column": 20 + } + } + }, + { + "type": "Punctuator", + "value": ":", + "range": [ + 20, + 21 + ], + "loc": { + "start": { + "line": 1, + "column": 20 + }, + "end": { + "line": 1, + "column": 21 + } + } + }, + { + "type": "Identifier", + "value": "T", + "range": [ + 22, + 23 + ], + "loc": { + "start": { + "line": 1, + "column": 22 + }, + "end": { + "line": 1, + "column": 23 + } + } + }, + { + "type": "Punctuator", + "value": "=>", + "range": [ + 24, + 26 + ], + "loc": { + "start": { + "line": 1, + "column": 24 + }, + "end": { + "line": 1, + "column": 26 + } + } + }, + { + "type": "Punctuator", + "value": "{", + "range": [ + 27, + 28 + ], + "loc": { + "start": { + "line": 1, + "column": 27 + }, + "end": { + "line": 1, + "column": 28 + } + } + }, + { + "type": "Keyword", + "value": "return", + "range": [ + 29, + 35 + ], + "loc": { + "start": { + "line": 1, + "column": 29 + }, + "end": { + "line": 1, + "column": 35 + } + } + }, + { + "type": "Numeric", + "value": "1", + "range": [ + 36, + 37 + ], + "loc": { + "start": { + "line": 1, + "column": 36 + }, + "end": { + "line": 1, + "column": 37 + } + } + }, + { + "type": "Punctuator", + "value": "}", + "range": [ + 38, + 39 + ], + "loc": { + "start": { + "line": 1, + "column": 38 + }, + "end": { + "line": 1, + "column": 39 + } + } + } + ], + "comments": [] + } +) \ No newline at end of file diff --git a/tests/fixtures/parsers/arrow-parens/generic-param.js b/tests/fixtures/parsers/arrow-parens/generic-param.js new file mode 100644 index 00000000000..9b52f1468db --- /dev/null +++ b/tests/fixtures/parsers/arrow-parens/generic-param.js @@ -0,0 +1,557 @@ +"use strict"; + +/* + * Parsed on astexplorer.net using @typescript-eslint/parser-2.6.1 + * + * Source: + * (param: T) => { return param } + */ + +exports.parse = () => ( + { + "type": "Program", + "body": [ + { + "type": "ExpressionStatement", + "expression": { + "type": "ArrowFunctionExpression", + "generator": false, + "id": null, + "params": [ + { + "type": "Identifier", + "name": "param", + "range": [ + 18, + 26 + ], + "loc": { + "start": { + "line": 1, + "column": 18 + }, + "end": { + "line": 1, + "column": 26 + } + }, + "typeAnnotation": { + "type": "TSTypeAnnotation", + "loc": { + "start": { + "line": 1, + "column": 23 + }, + "end": { + "line": 1, + "column": 26 + } + }, + "range": [ + 23, + 26 + ], + "typeAnnotation": { + "type": "TSTypeReference", + "typeName": { + "type": "Identifier", + "name": "T", + "range": [ + 25, + 26 + ], + "loc": { + "start": { + "line": 1, + "column": 25 + }, + "end": { + "line": 1, + "column": 26 + } + } + }, + "range": [ + 25, + 26 + ], + "loc": { + "start": { + "line": 1, + "column": 25 + }, + "end": { + "line": 1, + "column": 26 + } + } + } + } + } + ], + "body": { + "type": "BlockStatement", + "body": [ + { + "type": "ReturnStatement", + "argument": { + "type": "Identifier", + "name": "param", + "range": [ + 40, + 45 + ], + "loc": { + "start": { + "line": 1, + "column": 40 + }, + "end": { + "line": 1, + "column": 45 + } + } + }, + "range": [ + 33, + 45 + ], + "loc": { + "start": { + "line": 1, + "column": 33 + }, + "end": { + "line": 1, + "column": 45 + } + } + } + ], + "range": [ + 31, + 47 + ], + "loc": { + "start": { + "line": 1, + "column": 31 + }, + "end": { + "line": 1, + "column": 47 + } + } + }, + "async": false, + "expression": false, + "range": [ + 0, + 47 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 47 + } + }, + "typeParameters": { + "type": "TSTypeParameterDeclaration", + "range": [ + 0, + 17 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 17 + } + }, + "params": [ + { + "type": "TSTypeParameter", + "name": { + "type": "Identifier", + "name": "T", + "range": [ + 1, + 2 + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 2 + } + } + }, + "constraint": { + "type": "TSTypeReference", + "typeName": { + "type": "Identifier", + "name": "Array", + "range": [ + 11, + 16 + ], + "loc": { + "start": { + "line": 1, + "column": 11 + }, + "end": { + "line": 1, + "column": 16 + } + } + }, + "range": [ + 11, + 16 + ], + "loc": { + "start": { + "line": 1, + "column": 11 + }, + "end": { + "line": 1, + "column": 16 + } + } + }, + "range": [ + 1, + 16 + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 16 + } + } + } + ] + } + }, + "range": [ + 0, + 47 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 47 + } + } + } + ], + "sourceType": "module", + "range": [ + 0, + 47 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 47 + } + }, + "tokens": [ + { + "type": "Punctuator", + "value": "<", + "range": [ + 0, + 1 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + { + "type": "Identifier", + "value": "T", + "range": [ + 1, + 2 + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 2 + } + } + }, + { + "type": "Keyword", + "value": "extends", + "range": [ + 3, + 10 + ], + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 10 + } + } + }, + { + "type": "Identifier", + "value": "Array", + "range": [ + 11, + 16 + ], + "loc": { + "start": { + "line": 1, + "column": 11 + }, + "end": { + "line": 1, + "column": 16 + } + } + }, + { + "type": "Punctuator", + "value": ">", + "range": [ + 16, + 17 + ], + "loc": { + "start": { + "line": 1, + "column": 16 + }, + "end": { + "line": 1, + "column": 17 + } + } + }, + { + "type": "Punctuator", + "value": "(", + "range": [ + 17, + 18 + ], + "loc": { + "start": { + "line": 1, + "column": 17 + }, + "end": { + "line": 1, + "column": 18 + } + } + }, + { + "type": "Identifier", + "value": "param", + "range": [ + 18, + 23 + ], + "loc": { + "start": { + "line": 1, + "column": 18 + }, + "end": { + "line": 1, + "column": 23 + } + } + }, + { + "type": "Punctuator", + "value": ":", + "range": [ + 23, + 24 + ], + "loc": { + "start": { + "line": 1, + "column": 23 + }, + "end": { + "line": 1, + "column": 24 + } + } + }, + { + "type": "Identifier", + "value": "T", + "range": [ + 25, + 26 + ], + "loc": { + "start": { + "line": 1, + "column": 25 + }, + "end": { + "line": 1, + "column": 26 + } + } + }, + { + "type": "Punctuator", + "value": ")", + "range": [ + 26, + 27 + ], + "loc": { + "start": { + "line": 1, + "column": 26 + }, + "end": { + "line": 1, + "column": 27 + } + } + }, + { + "type": "Punctuator", + "value": "=>", + "range": [ + 28, + 30 + ], + "loc": { + "start": { + "line": 1, + "column": 28 + }, + "end": { + "line": 1, + "column": 30 + } + } + }, + { + "type": "Punctuator", + "value": "{", + "range": [ + 31, + 32 + ], + "loc": { + "start": { + "line": 1, + "column": 31 + }, + "end": { + "line": 1, + "column": 32 + } + } + }, + { + "type": "Keyword", + "value": "return", + "range": [ + 33, + 39 + ], + "loc": { + "start": { + "line": 1, + "column": 33 + }, + "end": { + "line": 1, + "column": 39 + } + } + }, + { + "type": "Identifier", + "value": "param", + "range": [ + 40, + 45 + ], + "loc": { + "start": { + "line": 1, + "column": 40 + }, + "end": { + "line": 1, + "column": 45 + } + } + }, + { + "type": "Punctuator", + "value": "}", + "range": [ + 46, + 47 + ], + "loc": { + "start": { + "line": 1, + "column": 46 + }, + "end": { + "line": 1, + "column": 47 + } + } + } + ], + "comments": [] + } +) \ No newline at end of file diff --git a/tests/lib/rules/arrow-parens.js b/tests/lib/rules/arrow-parens.js index 3e796c1ec3c..066072d014d 100644 --- a/tests/lib/rules/arrow-parens.js +++ b/tests/lib/rules/arrow-parens.js @@ -53,6 +53,8 @@ const valid = [ { code: "async (a, b) => {}", options: ["as-needed"], parserOptions: { ecmaVersion: 8 } }, { code: "(a: T) => a", options: ["as-needed"], parser: parser("identifer-type") }, { code: "(a): T => a", options: ["as-needed"], parser: parser("return-type") }, + { code: "(param: T) => { return param }", options: ["as-needed"], parser: parser("generic-param") }, + { code: "(): T => { return 1 }", options: ["as-needed"], parser: parser("generic-no-params") }, // "as-needed", { "requireForBlockBody": true } { code: "() => {}", options: ["as-needed", { requireForBlockBody: true }] }, From d33c7f03ebb93bc70db0eae3b39d273682a3cadc Mon Sep 17 00:00:00 2001 From: matmalkowski Date: Sat, 23 Nov 2019 17:33:16 +0700 Subject: [PATCH 2/6] Fix: add better TS generic support for arrow-parens (fixes #12570) --- lib/rules/arrow-parens.js | 82 ++++++++++++++++++--------------- lib/rules/utils/ast-utils.js | 10 ++++ tests/lib/rules/arrow-parens.js | 5 +- 3 files changed, 60 insertions(+), 37 deletions(-) diff --git a/lib/rules/arrow-parens.js b/lib/rules/arrow-parens.js index dc3c3825791..f3f9bba2a22 100644 --- a/lib/rules/arrow-parens.js +++ b/lib/rules/arrow-parens.js @@ -80,29 +80,46 @@ module.exports = { * @returns {void} */ function parens(node) { - const isAsync = node.async; - const firstTokenOfParam = sourceCode.getFirstToken(node, isAsync ? 1 : 0); + const firstToken = sourceCode.getFirstToken(node); + const arrowToken = sourceCode.getTokens(node).find(astUtils.isArrowToken); + const openingParenToken = astUtils.isOpeningParenToken(firstToken) + ? firstToken + : sourceCode.getTokensBetween(firstToken, arrowToken).find(astUtils.isOpeningParenToken); /** * Remove the parenthesis around a parameter * @param {Fixer} fixer Fixer * @returns {string} fixed parameter */ - function fixParamsWithParenthesis(fixer) { - const paramToken = sourceCode.getTokenAfter(firstTokenOfParam); - - /* - * ES8 allows Trailing commas in function parameter lists and calls - * https://github.com/eslint/eslint/issues/8834 - */ - const closingParenToken = sourceCode.getTokenAfter(paramToken, astUtils.isClosingParenToken); - const asyncToken = isAsync ? sourceCode.getTokenBefore(firstTokenOfParam) : null; - const shouldAddSpaceForAsync = asyncToken && (asyncToken.range[1] === firstTokenOfParam.range[0]); + function fixUnwrap(fixer) { + const firstParamToken = sourceCode.getTokenAfter(openingParenToken); + + // /* + // * ES8 allows Trailing commas in function parameter lists and calls + // * https://github.com/eslint/eslint/issues/8834 + // */ + const closingParenToken = sourceCode.getTokenAfter(firstParamToken, astUtils.isClosingParenToken); + const asyncToken = astUtils.isAsyncToken(firstToken) + ? firstToken + : sourceCode.getTokensBetween(firstToken, openingParenToken).find(astUtils.isAsyncToken); + const shouldAddSpaceForAsync = asyncToken && (asyncToken.range[1] === openingParenToken.range[0]); return fixer.replaceTextRange([ - firstTokenOfParam.range[0], + openingParenToken.range[0], closingParenToken.range[1] - ], `${shouldAddSpaceForAsync ? " " : ""}${paramToken.value}`); + ], `${shouldAddSpaceForAsync ? " " : ""}${firstParamToken.value}`); + } + + + /** + * Adds the parenthesis around a parameter + * @param {Fixer} fixer Fixer + * @returns {string} fixed parameter + */ + function fixWrap(fixer) { + const firstParamToken = sourceCode.getFirstToken(node, node.async ? 1 : 0); + + return fixer.replaceText(firstParamToken, `(${firstParamToken.value})`); } // "as-needed", { "requireForBlockBody": true }: x => x @@ -114,12 +131,13 @@ module.exports = { node.body.type !== "BlockStatement" && !node.returnType ) { - if (astUtils.isOpeningParenToken(firstTokenOfParam)) { + if (openingParenToken) { context.report({ node, messageId: "unexpectedParensInline", loc: getLocation(node), - fix: fixParamsWithParenthesis + fix: fixUnwrap + }); } return; @@ -129,14 +147,12 @@ module.exports = { requireForBlockBody && node.body.type === "BlockStatement" ) { - if (!astUtils.isOpeningParenToken(firstTokenOfParam)) { + if (!openingParenToken) { context.report({ node, messageId: "expectedParensBlock", loc: getLocation(node), - fix(fixer) { - return fixer.replaceText(firstTokenOfParam, `(${firstTokenOfParam.value})`); - } + fix: fixWrap }); } return; @@ -149,31 +165,25 @@ module.exports = { !node.params[0].typeAnnotation && !node.returnType ) { - if (astUtils.isOpeningParenToken(firstTokenOfParam)) { + if (openingParenToken) { context.report({ node, messageId: "unexpectedParens", loc: getLocation(node), - fix: fixParamsWithParenthesis + fix: fixUnwrap }); } return; } - if (firstTokenOfParam.type === "Identifier") { - const after = sourceCode.getTokenAfter(firstTokenOfParam); - - // (x) => x - if (after.value !== ")") { - context.report({ - node, - messageId: "expectedParens", - loc: getLocation(node), - fix(fixer) { - return fixer.replaceText(firstTokenOfParam, `(${firstTokenOfParam.value})`); - } - }); - } + // "always" + if (!openingParenToken) { + context.report({ + node, + messageId: "expectedParens", + loc: getLocation(node), + fix: fixWrap + }); } } diff --git a/lib/rules/utils/ast-utils.js b/lib/rules/utils/ast-utils.js index 01c6b47b82e..3bc3b29390f 100644 --- a/lib/rules/utils/ast-utils.js +++ b/lib/rules/utils/ast-utils.js @@ -271,6 +271,15 @@ function isArrowToken(token) { return token.value === "=>" && token.type === "Punctuator"; } +/** + * Checks if the given token is an async token or not. + * @param {Token} token The token to check. + * @returns {boolean} `true` if the token is an async token. + */ +function isAsyncToken(token) { + return token.value === "async" && token.type === "Identifier"; +} + /** * Checks if the given token is a comma token or not. * @param {Token} token The token to check. @@ -451,6 +460,7 @@ module.exports = { equalTokens, isArrowToken, + isAsyncToken, isClosingBraceToken, isClosingBracketToken, isClosingParenToken, diff --git a/tests/lib/rules/arrow-parens.js b/tests/lib/rules/arrow-parens.js index 066072d014d..7603ceb7927 100644 --- a/tests/lib/rules/arrow-parens.js +++ b/tests/lib/rules/arrow-parens.js @@ -70,7 +70,10 @@ const valid = [ { code: "async a => ({})", options: ["as-needed", { requireForBlockBody: true }], parserOptions: { ecmaVersion: 8 } }, { code: "async a => a", options: ["as-needed", { requireForBlockBody: true }], parserOptions: { ecmaVersion: 8 } }, { code: "(a: T) => a", options: ["as-needed", { requireForBlockBody: true }], parser: parser("identifer-type") }, - { code: "(a): T => a", options: ["as-needed", { requireForBlockBody: true }], parser: parser("return-type") } + { code: "(a): T => a", options: ["as-needed", { requireForBlockBody: true }], parser: parser("return-type") }, + { code: "(param: T) => { return param }", options: ["as-needed", { requireForBlockBody: true }], parser: parser("generic-param") }, + { code: "(): T => { return 1 }", options: ["as-needed", { requireForBlockBody: true }], parser: parser("generic-no-params") } + ]; const type = "ArrowFunctionExpression"; From d2084cd8bef6a36cab5f143cd3bf4acf27d3c6c6 Mon Sep 17 00:00:00 2001 From: matmalkowski Date: Thu, 26 Dec 2019 23:36:25 +0700 Subject: [PATCH 3/6] Fix: code review comments --- lib/rules/arrow-parens.js | 17 ++++++++++------- tests/lib/rules/arrow-parens.js | 14 ++++++++++++++ 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/lib/rules/arrow-parens.js b/lib/rules/arrow-parens.js index f3f9bba2a22..75d781bebe2 100644 --- a/lib/rules/arrow-parens.js +++ b/lib/rules/arrow-parens.js @@ -81,10 +81,10 @@ module.exports = { */ function parens(node) { const firstToken = sourceCode.getFirstToken(node); - const arrowToken = sourceCode.getTokens(node).find(astUtils.isArrowToken); + const arrowToken = sourceCode.getTokenBefore(node.body, astUtils.isArrowToken); const openingParenToken = astUtils.isOpeningParenToken(firstToken) ? firstToken - : sourceCode.getTokensBetween(firstToken, arrowToken).find(astUtils.isOpeningParenToken); + : sourceCode.getFirstTokenBetween(firstToken, arrowToken, { filter: astUtils.isOpeningParenToken }); /** * Remove the parenthesis around a parameter @@ -99,15 +99,18 @@ module.exports = { // * https://github.com/eslint/eslint/issues/8834 // */ const closingParenToken = sourceCode.getTokenAfter(firstParamToken, astUtils.isClosingParenToken); - const asyncToken = astUtils.isAsyncToken(firstToken) - ? firstToken - : sourceCode.getTokensBetween(firstToken, openingParenToken).find(astUtils.isAsyncToken); - const shouldAddSpaceForAsync = asyncToken && (asyncToken.range[1] === openingParenToken.range[0]); + + const adjacentToken = sourceCode.getTokenBefore(openingParenToken); + + const shouldAddSpace = + adjacentToken && + !astUtils.canTokensBeAdjacent(adjacentToken, firstParamToken) && + adjacentToken.range[1] === openingParenToken.range[0]; return fixer.replaceTextRange([ openingParenToken.range[0], closingParenToken.range[1] - ], `${shouldAddSpaceForAsync ? " " : ""}${firstParamToken.value}`); + ], `${shouldAddSpace ? " " : ""}${firstParamToken.value}`); } diff --git a/tests/lib/rules/arrow-parens.js b/tests/lib/rules/arrow-parens.js index 7603ceb7927..3f6b037679c 100644 --- a/tests/lib/rules/arrow-parens.js +++ b/tests/lib/rules/arrow-parens.js @@ -69,6 +69,7 @@ const valid = [ { code: "a => ({})", options: ["as-needed", { requireForBlockBody: true }] }, { code: "async a => ({})", options: ["as-needed", { requireForBlockBody: true }], parserOptions: { ecmaVersion: 8 } }, { code: "async a => a", options: ["as-needed", { requireForBlockBody: true }], parserOptions: { ecmaVersion: 8 } }, + { code: "function *f() { yield a => a; }", options: ["as-needed", { requireForBlockBody: true }], parserOptions: { ecmaVersion: 8 } }, { code: "(a: T) => a", options: ["as-needed", { requireForBlockBody: true }], parser: parser("identifer-type") }, { code: "(a): T => a", options: ["as-needed", { requireForBlockBody: true }], parser: parser("return-type") }, { code: "(param: T) => { return param }", options: ["as-needed", { requireForBlockBody: true }], parser: parser("generic-param") }, @@ -199,6 +200,19 @@ const invalid = [ type }] }, + { + code: "function *f() { yield(a) => a; }", + output: "function *f() { yield a => a; }", + options: ["as-needed"], + parserOptions: { ecmaVersion: 8 }, + errors: [{ + line: 1, + column: 23, + endColumn: 24, + messageId: "unexpectedParens", + type + }] + }, { code: "async(a) => a", output: "async a => a", From 1bf3ff00e11414c4005f81322afa1a873a9d0920 Mon Sep 17 00:00:00 2001 From: matmalkowski Date: Sat, 28 Dec 2019 15:06:14 +0700 Subject: [PATCH 4/6] Fix: add additional test case for TS generic --- tests/lib/rules/arrow-parens.js | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/lib/rules/arrow-parens.js b/tests/lib/rules/arrow-parens.js index 3f6b037679c..923dbf9b44c 100644 --- a/tests/lib/rules/arrow-parens.js +++ b/tests/lib/rules/arrow-parens.js @@ -55,6 +55,7 @@ const valid = [ { code: "(a): T => a", options: ["as-needed"], parser: parser("return-type") }, { code: "(param: T) => { return param }", options: ["as-needed"], parser: parser("generic-param") }, { code: "(): T => { return 1 }", options: ["as-needed"], parser: parser("generic-no-params") }, + { code: "() => { }", options: ["as-needed"], parser: parser("generic-no-params") }, // "as-needed", { "requireForBlockBody": true } { code: "() => {}", options: ["as-needed", { requireForBlockBody: true }] }, From 444dc142818753376fffb35c7262ec33b90c5e87 Mon Sep 17 00:00:00 2001 From: matmalkowski Date: Wed, 1 Jan 2020 14:06:57 +0700 Subject: [PATCH 5/6] Revert "Fix: add additional test case for TS generic" This reverts commit 1bf3ff00e11414c4005f81322afa1a873a9d0920. --- tests/lib/rules/arrow-parens.js | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/lib/rules/arrow-parens.js b/tests/lib/rules/arrow-parens.js index 923dbf9b44c..3f6b037679c 100644 --- a/tests/lib/rules/arrow-parens.js +++ b/tests/lib/rules/arrow-parens.js @@ -55,7 +55,6 @@ const valid = [ { code: "(a): T => a", options: ["as-needed"], parser: parser("return-type") }, { code: "(param: T) => { return param }", options: ["as-needed"], parser: parser("generic-param") }, { code: "(): T => { return 1 }", options: ["as-needed"], parser: parser("generic-no-params") }, - { code: "() => { }", options: ["as-needed"], parser: parser("generic-no-params") }, // "as-needed", { "requireForBlockBody": true } { code: "() => {}", options: ["as-needed", { requireForBlockBody: true }] }, From eb3003812c20d03e1c99593d3bf08d5ff275fd3e Mon Sep 17 00:00:00 2001 From: matmalkowski Date: Wed, 1 Jan 2020 15:16:52 +0700 Subject: [PATCH 6/6] Fix: code review comments --- lib/rules/arrow-parens.js | 20 +- .../arrow-parens/generic-no-params-simple.js | 344 +++++++ .../generic-union-type-complex.js | 931 ++++++++++++++++++ .../arrow-parens/generic-union-type.js | 699 +++++++++++++ tests/lib/rules/arrow-parens.js | 3 + 5 files changed, 1993 insertions(+), 4 deletions(-) create mode 100644 tests/fixtures/parsers/arrow-parens/generic-no-params-simple.js create mode 100644 tests/fixtures/parsers/arrow-parens/generic-union-type-complex.js create mode 100644 tests/fixtures/parsers/arrow-parens/generic-union-type.js diff --git a/lib/rules/arrow-parens.js b/lib/rules/arrow-parens.js index 75d781bebe2..f5134f9b4bf 100644 --- a/lib/rules/arrow-parens.js +++ b/lib/rules/arrow-parens.js @@ -74,17 +74,27 @@ module.exports = { const sourceCode = context.getSourceCode(); + /** + * Checks if token is part of the given node. + * @param {ASTNode} token A node to check. + * @param {ASTNode} node The arrow function node. + * @returns {boolean} Whether or not the token is part of node. + */ + function isTokenPartOfNode(token, node) { + return token.range[0] >= node.range[0] && token.range[1] <= node.range[1]; + } + /** * Determines whether a arrow function argument end with `)` * @param {ASTNode} node The arrow function node. * @returns {void} */ function parens(node) { - const firstToken = sourceCode.getFirstToken(node); const arrowToken = sourceCode.getTokenBefore(node.body, astUtils.isArrowToken); - const openingParenToken = astUtils.isOpeningParenToken(firstToken) - ? firstToken - : sourceCode.getFirstTokenBetween(firstToken, arrowToken, { filter: astUtils.isOpeningParenToken }); + + const openingParenToken = node.params.length >= 1 && node.params[0].type === "Identifier" + ? sourceCode.getTokenBefore(node.params[0], t => isTokenPartOfNode(t, node) && astUtils.isOpeningParenToken(t)) + : sourceCode.getTokenBefore(arrowToken, t => isTokenPartOfNode(t, node) && astUtils.isOpeningParenToken(t)); /** * Remove the parenthesis around a parameter @@ -131,6 +141,7 @@ module.exports = { node.params.length === 1 && node.params[0].type === "Identifier" && !node.params[0].typeAnnotation && + !node.typeParameters && node.body.type !== "BlockStatement" && !node.returnType ) { @@ -166,6 +177,7 @@ module.exports = { node.params.length === 1 && node.params[0].type === "Identifier" && !node.params[0].typeAnnotation && + !node.typeParameters && !node.returnType ) { if (openingParenToken) { diff --git a/tests/fixtures/parsers/arrow-parens/generic-no-params-simple.js b/tests/fixtures/parsers/arrow-parens/generic-no-params-simple.js new file mode 100644 index 00000000000..732fcf0a036 --- /dev/null +++ b/tests/fixtures/parsers/arrow-parens/generic-no-params-simple.js @@ -0,0 +1,344 @@ +"use strict"; + +/* + * Parsed on astexplorer.net using @typescript-eslint/parser-2.6.1 + * + * Source: + * (x) => {}; + */ + +exports.parse = () => ( + { + "type": "Program", + "body": [ + { + "type": "ExpressionStatement", + "expression": { + "type": "ArrowFunctionExpression", + "generator": false, + "id": null, + "params": [ + { + "type": "Identifier", + "name": "x", + "range": [ + 4, + 5 + ], + "loc": { + "start": { + "line": 1, + "column": 4 + }, + "end": { + "line": 1, + "column": 5 + } + } + } + ], + "body": { + "type": "BlockStatement", + "body": [], + "range": [ + 10, + 12 + ], + "loc": { + "start": { + "line": 1, + "column": 10 + }, + "end": { + "line": 1, + "column": 12 + } + } + }, + "async": false, + "expression": false, + "range": [ + 0, + 12 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 12 + } + }, + "typeParameters": { + "type": "TSTypeParameterDeclaration", + "range": [ + 0, + 3 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 3 + } + }, + "params": [ + { + "type": "TSTypeParameter", + "name": { + "type": "Identifier", + "name": "T", + "range": [ + 1, + 2 + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 2 + } + } + }, + "range": [ + 1, + 2 + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 2 + } + } + } + ] + } + }, + "range": [ + 0, + 13 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 13 + } + } + } + ], + "sourceType": "module", + "range": [ + 0, + 13 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 13 + } + }, + "tokens": [ + { + "type": "Punctuator", + "value": "<", + "range": [ + 0, + 1 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + { + "type": "Identifier", + "value": "T", + "range": [ + 1, + 2 + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 2 + } + } + }, + { + "type": "Punctuator", + "value": ">", + "range": [ + 2, + 3 + ], + "loc": { + "start": { + "line": 1, + "column": 2 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + { + "type": "Punctuator", + "value": "(", + "range": [ + 3, + 4 + ], + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 4 + } + } + }, + { + "type": "Identifier", + "value": "x", + "range": [ + 4, + 5 + ], + "loc": { + "start": { + "line": 1, + "column": 4 + }, + "end": { + "line": 1, + "column": 5 + } + } + }, + { + "type": "Punctuator", + "value": ")", + "range": [ + 5, + 6 + ], + "loc": { + "start": { + "line": 1, + "column": 5 + }, + "end": { + "line": 1, + "column": 6 + } + } + }, + { + "type": "Punctuator", + "value": "=>", + "range": [ + 7, + 9 + ], + "loc": { + "start": { + "line": 1, + "column": 7 + }, + "end": { + "line": 1, + "column": 9 + } + } + }, + { + "type": "Punctuator", + "value": "{", + "range": [ + 10, + 11 + ], + "loc": { + "start": { + "line": 1, + "column": 10 + }, + "end": { + "line": 1, + "column": 11 + } + } + }, + { + "type": "Punctuator", + "value": "}", + "range": [ + 11, + 12 + ], + "loc": { + "start": { + "line": 1, + "column": 11 + }, + "end": { + "line": 1, + "column": 12 + } + } + }, + { + "type": "Punctuator", + "value": ";", + "range": [ + 12, + 13 + ], + "loc": { + "start": { + "line": 1, + "column": 12 + }, + "end": { + "line": 1, + "column": 13 + } + } + } + ], + "comments": [] + } +) \ No newline at end of file diff --git a/tests/fixtures/parsers/arrow-parens/generic-union-type-complex.js b/tests/fixtures/parsers/arrow-parens/generic-union-type-complex.js new file mode 100644 index 00000000000..e6f56354eb3 --- /dev/null +++ b/tests/fixtures/parsers/arrow-parens/generic-union-type-complex.js @@ -0,0 +1,931 @@ +"use strict"; + +/* + * Parsed on astexplorer.net using @typescript-eslint/parser-2.6.1 + * + * Source: + * (a: (string | number)): T => {}; + */ + +exports.parse = () => ( + { + "type": "Program", + "body": [ + { + "type": "ExpressionStatement", + "expression": { + "type": "ArrowFunctionExpression", + "generator": false, + "id": null, + "params": [ + { + "type": "Identifier", + "name": "a", + "range": [ + 24, + 44 + ], + "loc": { + "start": { + "line": 1, + "column": 24 + }, + "end": { + "line": 1, + "column": 44 + } + }, + "typeAnnotation": { + "type": "TSTypeAnnotation", + "loc": { + "start": { + "line": 1, + "column": 25 + }, + "end": { + "line": 1, + "column": 44 + } + }, + "range": [ + 25, + 44 + ], + "typeAnnotation": { + "type": "TSParenthesizedType", + "typeAnnotation": { + "type": "TSUnionType", + "types": [ + { + "type": "TSStringKeyword", + "range": [ + 28, + 34 + ], + "loc": { + "start": { + "line": 1, + "column": 28 + }, + "end": { + "line": 1, + "column": 34 + } + } + }, + { + "type": "TSNumberKeyword", + "range": [ + 37, + 43 + ], + "loc": { + "start": { + "line": 1, + "column": 37 + }, + "end": { + "line": 1, + "column": 43 + } + } + } + ], + "range": [ + 28, + 43 + ], + "loc": { + "start": { + "line": 1, + "column": 28 + }, + "end": { + "line": 1, + "column": 43 + } + } + }, + "range": [ + 27, + 44 + ], + "loc": { + "start": { + "line": 1, + "column": 27 + }, + "end": { + "line": 1, + "column": 44 + } + } + } + } + } + ], + "body": { + "type": "BlockStatement", + "body": [], + "range": [ + 52, + 54 + ], + "loc": { + "start": { + "line": 1, + "column": 52 + }, + "end": { + "line": 1, + "column": 54 + } + } + }, + "async": false, + "expression": false, + "range": [ + 0, + 54 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 54 + } + }, + "returnType": { + "type": "TSTypeAnnotation", + "loc": { + "start": { + "line": 1, + "column": 45 + }, + "end": { + "line": 1, + "column": 48 + } + }, + "range": [ + 45, + 48 + ], + "typeAnnotation": { + "type": "TSTypeReference", + "typeName": { + "type": "Identifier", + "name": "T", + "range": [ + 47, + 48 + ], + "loc": { + "start": { + "line": 1, + "column": 47 + }, + "end": { + "line": 1, + "column": 48 + } + } + }, + "range": [ + 47, + 48 + ], + "loc": { + "start": { + "line": 1, + "column": 47 + }, + "end": { + "line": 1, + "column": 48 + } + } + } + }, + "typeParameters": { + "type": "TSTypeParameterDeclaration", + "range": [ + 0, + 23 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 23 + } + }, + "params": [ + { + "type": "TSTypeParameter", + "name": { + "type": "Identifier", + "name": "T", + "range": [ + 1, + 2 + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 2 + } + } + }, + "constraint": { + "type": "TSIntersectionType", + "types": [ + { + "type": "TSParenthesizedType", + "typeAnnotation": { + "type": "TSUnionType", + "types": [ + { + "type": "TSTypeReference", + "typeName": { + "type": "Identifier", + "name": "A", + "range": [ + 12, + 13 + ], + "loc": { + "start": { + "line": 1, + "column": 12 + }, + "end": { + "line": 1, + "column": 13 + } + } + }, + "range": [ + 12, + 13 + ], + "loc": { + "start": { + "line": 1, + "column": 12 + }, + "end": { + "line": 1, + "column": 13 + } + } + }, + { + "type": "TSTypeReference", + "typeName": { + "type": "Identifier", + "name": "B", + "range": [ + 16, + 17 + ], + "loc": { + "start": { + "line": 1, + "column": 16 + }, + "end": { + "line": 1, + "column": 17 + } + } + }, + "range": [ + 16, + 17 + ], + "loc": { + "start": { + "line": 1, + "column": 16 + }, + "end": { + "line": 1, + "column": 17 + } + } + } + ], + "range": [ + 12, + 17 + ], + "loc": { + "start": { + "line": 1, + "column": 12 + }, + "end": { + "line": 1, + "column": 17 + } + } + }, + "range": [ + 11, + 18 + ], + "loc": { + "start": { + "line": 1, + "column": 11 + }, + "end": { + "line": 1, + "column": 18 + } + } + }, + { + "type": "TSTypeReference", + "typeName": { + "type": "Identifier", + "name": "C", + "range": [ + 21, + 22 + ], + "loc": { + "start": { + "line": 1, + "column": 21 + }, + "end": { + "line": 1, + "column": 22 + } + } + }, + "range": [ + 21, + 22 + ], + "loc": { + "start": { + "line": 1, + "column": 21 + }, + "end": { + "line": 1, + "column": 22 + } + } + } + ], + "range": [ + 11, + 22 + ], + "loc": { + "start": { + "line": 1, + "column": 11 + }, + "end": { + "line": 1, + "column": 22 + } + } + }, + "range": [ + 1, + 22 + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 22 + } + } + } + ] + } + }, + "range": [ + 0, + 55 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 55 + } + } + } + ], + "sourceType": "module", + "range": [ + 0, + 55 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 55 + } + }, + "tokens": [ + { + "type": "Punctuator", + "value": "<", + "range": [ + 0, + 1 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + { + "type": "Identifier", + "value": "T", + "range": [ + 1, + 2 + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 2 + } + } + }, + { + "type": "Keyword", + "value": "extends", + "range": [ + 3, + 10 + ], + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 10 + } + } + }, + { + "type": "Punctuator", + "value": "(", + "range": [ + 11, + 12 + ], + "loc": { + "start": { + "line": 1, + "column": 11 + }, + "end": { + "line": 1, + "column": 12 + } + } + }, + { + "type": "Identifier", + "value": "A", + "range": [ + 12, + 13 + ], + "loc": { + "start": { + "line": 1, + "column": 12 + }, + "end": { + "line": 1, + "column": 13 + } + } + }, + { + "type": "Punctuator", + "value": "|", + "range": [ + 14, + 15 + ], + "loc": { + "start": { + "line": 1, + "column": 14 + }, + "end": { + "line": 1, + "column": 15 + } + } + }, + { + "type": "Identifier", + "value": "B", + "range": [ + 16, + 17 + ], + "loc": { + "start": { + "line": 1, + "column": 16 + }, + "end": { + "line": 1, + "column": 17 + } + } + }, + { + "type": "Punctuator", + "value": ")", + "range": [ + 17, + 18 + ], + "loc": { + "start": { + "line": 1, + "column": 17 + }, + "end": { + "line": 1, + "column": 18 + } + } + }, + { + "type": "Punctuator", + "value": "&", + "range": [ + 19, + 20 + ], + "loc": { + "start": { + "line": 1, + "column": 19 + }, + "end": { + "line": 1, + "column": 20 + } + } + }, + { + "type": "Identifier", + "value": "C", + "range": [ + 21, + 22 + ], + "loc": { + "start": { + "line": 1, + "column": 21 + }, + "end": { + "line": 1, + "column": 22 + } + } + }, + { + "type": "Punctuator", + "value": ">", + "range": [ + 22, + 23 + ], + "loc": { + "start": { + "line": 1, + "column": 22 + }, + "end": { + "line": 1, + "column": 23 + } + } + }, + { + "type": "Punctuator", + "value": "(", + "range": [ + 23, + 24 + ], + "loc": { + "start": { + "line": 1, + "column": 23 + }, + "end": { + "line": 1, + "column": 24 + } + } + }, + { + "type": "Identifier", + "value": "a", + "range": [ + 24, + 25 + ], + "loc": { + "start": { + "line": 1, + "column": 24 + }, + "end": { + "line": 1, + "column": 25 + } + } + }, + { + "type": "Punctuator", + "value": ":", + "range": [ + 25, + 26 + ], + "loc": { + "start": { + "line": 1, + "column": 25 + }, + "end": { + "line": 1, + "column": 26 + } + } + }, + { + "type": "Punctuator", + "value": "(", + "range": [ + 27, + 28 + ], + "loc": { + "start": { + "line": 1, + "column": 27 + }, + "end": { + "line": 1, + "column": 28 + } + } + }, + { + "type": "Identifier", + "value": "string", + "range": [ + 28, + 34 + ], + "loc": { + "start": { + "line": 1, + "column": 28 + }, + "end": { + "line": 1, + "column": 34 + } + } + }, + { + "type": "Punctuator", + "value": "|", + "range": [ + 35, + 36 + ], + "loc": { + "start": { + "line": 1, + "column": 35 + }, + "end": { + "line": 1, + "column": 36 + } + } + }, + { + "type": "Identifier", + "value": "number", + "range": [ + 37, + 43 + ], + "loc": { + "start": { + "line": 1, + "column": 37 + }, + "end": { + "line": 1, + "column": 43 + } + } + }, + { + "type": "Punctuator", + "value": ")", + "range": [ + 43, + 44 + ], + "loc": { + "start": { + "line": 1, + "column": 43 + }, + "end": { + "line": 1, + "column": 44 + } + } + }, + { + "type": "Punctuator", + "value": ")", + "range": [ + 44, + 45 + ], + "loc": { + "start": { + "line": 1, + "column": 44 + }, + "end": { + "line": 1, + "column": 45 + } + } + }, + { + "type": "Punctuator", + "value": ":", + "range": [ + 45, + 46 + ], + "loc": { + "start": { + "line": 1, + "column": 45 + }, + "end": { + "line": 1, + "column": 46 + } + } + }, + { + "type": "Identifier", + "value": "T", + "range": [ + 47, + 48 + ], + "loc": { + "start": { + "line": 1, + "column": 47 + }, + "end": { + "line": 1, + "column": 48 + } + } + }, + { + "type": "Punctuator", + "value": "=>", + "range": [ + 49, + 51 + ], + "loc": { + "start": { + "line": 1, + "column": 49 + }, + "end": { + "line": 1, + "column": 51 + } + } + }, + { + "type": "Punctuator", + "value": "{", + "range": [ + 52, + 53 + ], + "loc": { + "start": { + "line": 1, + "column": 52 + }, + "end": { + "line": 1, + "column": 53 + } + } + }, + { + "type": "Punctuator", + "value": "}", + "range": [ + 53, + 54 + ], + "loc": { + "start": { + "line": 1, + "column": 53 + }, + "end": { + "line": 1, + "column": 54 + } + } + }, + { + "type": "Punctuator", + "value": ";", + "range": [ + 54, + 55 + ], + "loc": { + "start": { + "line": 1, + "column": 54 + }, + "end": { + "line": 1, + "column": 55 + } + } + } + ], + "comments": [] + } +) \ No newline at end of file diff --git a/tests/fixtures/parsers/arrow-parens/generic-union-type.js b/tests/fixtures/parsers/arrow-parens/generic-union-type.js new file mode 100644 index 00000000000..269c3952858 --- /dev/null +++ b/tests/fixtures/parsers/arrow-parens/generic-union-type.js @@ -0,0 +1,699 @@ +"use strict"; + +/* + * Parsed on astexplorer.net using @typescript-eslint/parser-2.6.1 + * + * Source: + * (): T => {}; + */ + +exports.parse = () => ( + { + "type": "Program", + "body": [ + { + "type": "ExpressionStatement", + "expression": { + "type": "ArrowFunctionExpression", + "generator": false, + "id": null, + "params": [], + "body": { + "type": "BlockStatement", + "body": [], + "range": [ + 32, + 34 + ], + "loc": { + "start": { + "line": 1, + "column": 32 + }, + "end": { + "line": 1, + "column": 34 + } + } + }, + "async": false, + "expression": false, + "range": [ + 0, + 34 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 34 + } + }, + "returnType": { + "type": "TSTypeAnnotation", + "loc": { + "start": { + "line": 1, + "column": 25 + }, + "end": { + "line": 1, + "column": 28 + } + }, + "range": [ + 25, + 28 + ], + "typeAnnotation": { + "type": "TSTypeReference", + "typeName": { + "type": "Identifier", + "name": "T", + "range": [ + 27, + 28 + ], + "loc": { + "start": { + "line": 1, + "column": 27 + }, + "end": { + "line": 1, + "column": 28 + } + } + }, + "range": [ + 27, + 28 + ], + "loc": { + "start": { + "line": 1, + "column": 27 + }, + "end": { + "line": 1, + "column": 28 + } + } + } + }, + "typeParameters": { + "type": "TSTypeParameterDeclaration", + "range": [ + 0, + 23 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 23 + } + }, + "params": [ + { + "type": "TSTypeParameter", + "name": { + "type": "Identifier", + "name": "T", + "range": [ + 1, + 2 + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 2 + } + } + }, + "constraint": { + "type": "TSIntersectionType", + "types": [ + { + "type": "TSParenthesizedType", + "typeAnnotation": { + "type": "TSUnionType", + "types": [ + { + "type": "TSTypeReference", + "typeName": { + "type": "Identifier", + "name": "A", + "range": [ + 12, + 13 + ], + "loc": { + "start": { + "line": 1, + "column": 12 + }, + "end": { + "line": 1, + "column": 13 + } + } + }, + "range": [ + 12, + 13 + ], + "loc": { + "start": { + "line": 1, + "column": 12 + }, + "end": { + "line": 1, + "column": 13 + } + } + }, + { + "type": "TSTypeReference", + "typeName": { + "type": "Identifier", + "name": "B", + "range": [ + 16, + 17 + ], + "loc": { + "start": { + "line": 1, + "column": 16 + }, + "end": { + "line": 1, + "column": 17 + } + } + }, + "range": [ + 16, + 17 + ], + "loc": { + "start": { + "line": 1, + "column": 16 + }, + "end": { + "line": 1, + "column": 17 + } + } + } + ], + "range": [ + 12, + 17 + ], + "loc": { + "start": { + "line": 1, + "column": 12 + }, + "end": { + "line": 1, + "column": 17 + } + } + }, + "range": [ + 11, + 18 + ], + "loc": { + "start": { + "line": 1, + "column": 11 + }, + "end": { + "line": 1, + "column": 18 + } + } + }, + { + "type": "TSTypeReference", + "typeName": { + "type": "Identifier", + "name": "C", + "range": [ + 21, + 22 + ], + "loc": { + "start": { + "line": 1, + "column": 21 + }, + "end": { + "line": 1, + "column": 22 + } + } + }, + "range": [ + 21, + 22 + ], + "loc": { + "start": { + "line": 1, + "column": 21 + }, + "end": { + "line": 1, + "column": 22 + } + } + } + ], + "range": [ + 11, + 22 + ], + "loc": { + "start": { + "line": 1, + "column": 11 + }, + "end": { + "line": 1, + "column": 22 + } + } + }, + "range": [ + 1, + 22 + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 22 + } + } + } + ] + } + }, + "range": [ + 0, + 35 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 35 + } + } + } + ], + "sourceType": "module", + "range": [ + 0, + 35 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 35 + } + }, + "tokens": [ + { + "type": "Punctuator", + "value": "<", + "range": [ + 0, + 1 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + { + "type": "Identifier", + "value": "T", + "range": [ + 1, + 2 + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 2 + } + } + }, + { + "type": "Keyword", + "value": "extends", + "range": [ + 3, + 10 + ], + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 10 + } + } + }, + { + "type": "Punctuator", + "value": "(", + "range": [ + 11, + 12 + ], + "loc": { + "start": { + "line": 1, + "column": 11 + }, + "end": { + "line": 1, + "column": 12 + } + } + }, + { + "type": "Identifier", + "value": "A", + "range": [ + 12, + 13 + ], + "loc": { + "start": { + "line": 1, + "column": 12 + }, + "end": { + "line": 1, + "column": 13 + } + } + }, + { + "type": "Punctuator", + "value": "|", + "range": [ + 14, + 15 + ], + "loc": { + "start": { + "line": 1, + "column": 14 + }, + "end": { + "line": 1, + "column": 15 + } + } + }, + { + "type": "Identifier", + "value": "B", + "range": [ + 16, + 17 + ], + "loc": { + "start": { + "line": 1, + "column": 16 + }, + "end": { + "line": 1, + "column": 17 + } + } + }, + { + "type": "Punctuator", + "value": ")", + "range": [ + 17, + 18 + ], + "loc": { + "start": { + "line": 1, + "column": 17 + }, + "end": { + "line": 1, + "column": 18 + } + } + }, + { + "type": "Punctuator", + "value": "&", + "range": [ + 19, + 20 + ], + "loc": { + "start": { + "line": 1, + "column": 19 + }, + "end": { + "line": 1, + "column": 20 + } + } + }, + { + "type": "Identifier", + "value": "C", + "range": [ + 21, + 22 + ], + "loc": { + "start": { + "line": 1, + "column": 21 + }, + "end": { + "line": 1, + "column": 22 + } + } + }, + { + "type": "Punctuator", + "value": ">", + "range": [ + 22, + 23 + ], + "loc": { + "start": { + "line": 1, + "column": 22 + }, + "end": { + "line": 1, + "column": 23 + } + } + }, + { + "type": "Punctuator", + "value": "(", + "range": [ + 23, + 24 + ], + "loc": { + "start": { + "line": 1, + "column": 23 + }, + "end": { + "line": 1, + "column": 24 + } + } + }, + { + "type": "Punctuator", + "value": ")", + "range": [ + 24, + 25 + ], + "loc": { + "start": { + "line": 1, + "column": 24 + }, + "end": { + "line": 1, + "column": 25 + } + } + }, + { + "type": "Punctuator", + "value": ":", + "range": [ + 25, + 26 + ], + "loc": { + "start": { + "line": 1, + "column": 25 + }, + "end": { + "line": 1, + "column": 26 + } + } + }, + { + "type": "Identifier", + "value": "T", + "range": [ + 27, + 28 + ], + "loc": { + "start": { + "line": 1, + "column": 27 + }, + "end": { + "line": 1, + "column": 28 + } + } + }, + { + "type": "Punctuator", + "value": "=>", + "range": [ + 29, + 31 + ], + "loc": { + "start": { + "line": 1, + "column": 29 + }, + "end": { + "line": 1, + "column": 31 + } + } + }, + { + "type": "Punctuator", + "value": "{", + "range": [ + 32, + 33 + ], + "loc": { + "start": { + "line": 1, + "column": 32 + }, + "end": { + "line": 1, + "column": 33 + } + } + }, + { + "type": "Punctuator", + "value": "}", + "range": [ + 33, + 34 + ], + "loc": { + "start": { + "line": 1, + "column": 33 + }, + "end": { + "line": 1, + "column": 34 + } + } + }, + { + "type": "Punctuator", + "value": ";", + "range": [ + 34, + 35 + ], + "loc": { + "start": { + "line": 1, + "column": 34 + }, + "end": { + "line": 1, + "column": 35 + } + } + } + ], + "comments": [] + } +) \ No newline at end of file diff --git a/tests/lib/rules/arrow-parens.js b/tests/lib/rules/arrow-parens.js index 3f6b037679c..1d7a8f5359e 100644 --- a/tests/lib/rules/arrow-parens.js +++ b/tests/lib/rules/arrow-parens.js @@ -55,6 +55,9 @@ const valid = [ { code: "(a): T => a", options: ["as-needed"], parser: parser("return-type") }, { code: "(param: T) => { return param }", options: ["as-needed"], parser: parser("generic-param") }, { code: "(): T => { return 1 }", options: ["as-needed"], parser: parser("generic-no-params") }, + { code: "(x) => {};", options: ["as-needed"], parser: parser("generic-no-params-simple") }, + { code: "(): T => {};", options: ["as-needed"], parser: parser("generic-union-type") }, + { code: "(a: (string | number)): T => {};", options: ["as-needed"], parser: parser("generic-union-type-complex") }, // "as-needed", { "requireForBlockBody": true } { code: "() => {}", options: ["as-needed", { requireForBlockBody: true }] },