diff --git a/lib/rules/arrow-parens.js b/lib/rules/arrow-parens.js index dc3c3825791..f5134f9b4bf 100644 --- a/lib/rules/arrow-parens.js +++ b/lib/rules/arrow-parens.js @@ -74,35 +74,65 @@ 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 isAsync = node.async; - const firstTokenOfParam = sourceCode.getFirstToken(node, isAsync ? 1 : 0); + const arrowToken = sourceCode.getTokenBefore(node.body, astUtils.isArrowToken); + + 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 * @param {Fixer} fixer Fixer * @returns {string} fixed parameter */ - function fixParamsWithParenthesis(fixer) { - const paramToken = sourceCode.getTokenAfter(firstTokenOfParam); + 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(paramToken, astUtils.isClosingParenToken); - const asyncToken = isAsync ? sourceCode.getTokenBefore(firstTokenOfParam) : null; - const shouldAddSpaceForAsync = asyncToken && (asyncToken.range[1] === firstTokenOfParam.range[0]); + // /* + // * 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 adjacentToken = sourceCode.getTokenBefore(openingParenToken); + + const shouldAddSpace = + adjacentToken && + !astUtils.canTokensBeAdjacent(adjacentToken, firstParamToken) && + adjacentToken.range[1] === openingParenToken.range[0]; return fixer.replaceTextRange([ - firstTokenOfParam.range[0], + openingParenToken.range[0], closingParenToken.range[1] - ], `${shouldAddSpaceForAsync ? " " : ""}${paramToken.value}`); + ], `${shouldAddSpace ? " " : ""}${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 @@ -111,15 +141,17 @@ module.exports = { node.params.length === 1 && node.params[0].type === "Identifier" && !node.params[0].typeAnnotation && + !node.typeParameters && 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 +161,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; @@ -147,33 +177,28 @@ module.exports = { node.params.length === 1 && node.params[0].type === "Identifier" && !node.params[0].typeAnnotation && + !node.typeParameters && !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/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-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/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 3e796c1ec3c..1d7a8f5359e 100644 --- a/tests/lib/rules/arrow-parens.js +++ b/tests/lib/rules/arrow-parens.js @@ -53,6 +53,11 @@ 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") }, + { 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 }] }, @@ -67,8 +72,12 @@ 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: "(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"; @@ -194,6 +203,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",