From 2dc38aa653f1d5137a9abf82024c67a11620bb7c Mon Sep 17 00:00:00 2001 From: Milos Djermanovic Date: Tue, 8 Feb 2022 12:26:24 +0100 Subject: [PATCH] feat: fix bug with arrow function return types in function-paren-newline (#15541) Fixes #15091 --- lib/rules/function-paren-newline.js | 6 +- .../arrow-function-return-type.js | 660 ++++++++++++++++++ tests/lib/rules/function-paren-newline.js | 44 ++ 3 files changed, 709 insertions(+), 1 deletion(-) create mode 100644 tests/fixtures/parsers/function-paren-newline/arrow-function-return-type.js diff --git a/lib/rules/function-paren-newline.js b/lib/rules/function-paren-newline.js index ed94fad460c..898e113ee8e 100644 --- a/lib/rules/function-paren-newline.js +++ b/lib/rules/function-paren-newline.js @@ -227,9 +227,13 @@ module.exports = { return null; } + const rightParen = node.params.length + ? sourceCode.getTokenAfter(node.params[node.params.length - 1], astUtils.isClosingParenToken) + : sourceCode.getTokenAfter(firstToken); + return { leftParen: firstToken, - rightParen: sourceCode.getTokenBefore(node.body, astUtils.isClosingParenToken) + rightParen }; } diff --git a/tests/fixtures/parsers/function-paren-newline/arrow-function-return-type.js b/tests/fixtures/parsers/function-paren-newline/arrow-function-return-type.js new file mode 100644 index 00000000000..dbd9d48ede7 --- /dev/null +++ b/tests/fixtures/parsers/function-paren-newline/arrow-function-return-type.js @@ -0,0 +1,660 @@ +"use strict"; + +/** + * Parser: @typescript-eslint/parser@5.10.1 + * Source code: + * const method6 = ( + * abc: number, + * def: () => void, + * ): [ + * string, + * () => void + * ] => [`a${abc}`, def]; + * method6(3, () => {}); + */ + + exports.parse = () => ({ + type: "Program", + body: [ + { + type: "VariableDeclaration", + declarations: [ + { + type: "VariableDeclarator", + id: { + type: "Identifier", + name: "method6", + range: [6, 13], + loc: { + start: { line: 1, column: 6 }, + end: { line: 1, column: 13 }, + }, + }, + init: { + type: "ArrowFunctionExpression", + generator: false, + id: null, + params: [ + { + type: "Identifier", + name: "abc", + range: [20, 31], + loc: { + start: { line: 2, column: 2 }, + end: { line: 2, column: 13 }, + }, + typeAnnotation: { + type: "TSTypeAnnotation", + loc: { + start: { line: 2, column: 5 }, + end: { line: 2, column: 13 }, + }, + range: [23, 31], + typeAnnotation: { + type: "TSNumberKeyword", + range: [25, 31], + loc: { + start: { line: 2, column: 7 }, + end: { line: 2, column: 13 }, + }, + }, + }, + }, + { + type: "Identifier", + name: "def", + range: [35, 50], + loc: { + start: { line: 3, column: 2 }, + end: { line: 3, column: 17 }, + }, + typeAnnotation: { + type: "TSTypeAnnotation", + loc: { + start: { line: 3, column: 5 }, + end: { line: 3, column: 17 }, + }, + range: [38, 50], + typeAnnotation: { + type: "TSFunctionType", + params: [], + range: [40, 50], + loc: { + start: { line: 3, column: 7 }, + end: { line: 3, column: 17 }, + }, + returnType: { + type: "TSTypeAnnotation", + loc: { + start: { line: 3, column: 10 }, + end: { line: 3, column: 17 }, + }, + range: [43, 50], + typeAnnotation: { + type: "TSVoidKeyword", + range: [46, 50], + loc: { + start: { + line: 3, + column: 13, + }, + end: { + line: 3, + column: 17, + }, + }, + }, + }, + }, + }, + }, + ], + body: { + type: "ArrayExpression", + elements: [ + { + type: "TemplateLiteral", + quasis: [ + { + type: "TemplateElement", + value: { raw: "a", cooked: "a" }, + tail: false, + range: [86, 90], + loc: { + start: { line: 7, column: 6 }, + end: { line: 7, column: 10 }, + }, + }, + { + type: "TemplateElement", + value: { raw: "", cooked: "" }, + tail: true, + range: [93, 95], + loc: { + start: { line: 7, column: 13 }, + end: { line: 7, column: 15 }, + }, + }, + ], + expressions: [ + { + type: "Identifier", + name: "abc", + range: [90, 93], + loc: { + start: { line: 7, column: 10 }, + end: { line: 7, column: 13 }, + }, + }, + ], + range: [86, 95], + loc: { + start: { line: 7, column: 6 }, + end: { line: 7, column: 15 }, + }, + }, + { + type: "Identifier", + name: "def", + range: [97, 100], + loc: { + start: { line: 7, column: 17 }, + end: { line: 7, column: 20 }, + }, + }, + ], + range: [85, 101], + loc: { + start: { line: 7, column: 5 }, + end: { line: 7, column: 21 }, + }, + }, + async: false, + expression: true, + range: [16, 101], + loc: { + start: { line: 1, column: 16 }, + end: { line: 7, column: 21 }, + }, + returnType: { + type: "TSTypeAnnotation", + loc: { + start: { line: 4, column: 1 }, + end: { line: 7, column: 1 }, + }, + range: [53, 81], + typeAnnotation: { + type: "TSTupleType", + elementTypes: [ + { + type: "TSStringKeyword", + range: [59, 65], + loc: { + start: { line: 5, column: 2 }, + end: { line: 5, column: 8 }, + }, + }, + { + type: "TSFunctionType", + params: [], + range: [69, 79], + loc: { + start: { line: 6, column: 2 }, + end: { line: 6, column: 12 }, + }, + returnType: { + type: "TSTypeAnnotation", + loc: { + start: { line: 6, column: 5 }, + end: { line: 6, column: 12 }, + }, + range: [72, 79], + typeAnnotation: { + type: "TSVoidKeyword", + range: [75, 79], + loc: { + start: { + line: 6, + column: 8, + }, + end: { + line: 6, + column: 12, + }, + }, + }, + }, + }, + ], + range: [55, 81], + loc: { + start: { line: 4, column: 3 }, + end: { line: 7, column: 1 }, + }, + }, + }, + }, + range: [6, 101], + loc: { + start: { line: 1, column: 6 }, + end: { line: 7, column: 21 }, + }, + }, + ], + kind: "const", + range: [0, 102], + loc: { + start: { line: 1, column: 0 }, + end: { line: 7, column: 22 }, + }, + }, + { + type: "ExpressionStatement", + expression: { + type: "CallExpression", + callee: { + type: "Identifier", + name: "method6", + range: [103, 110], + loc: { + start: { line: 8, column: 0 }, + end: { line: 8, column: 7 }, + }, + }, + arguments: [ + { + type: "Literal", + value: 3, + raw: "3", + range: [111, 112], + loc: { + start: { line: 8, column: 8 }, + end: { line: 8, column: 9 }, + }, + }, + { + type: "ArrowFunctionExpression", + generator: false, + id: null, + params: [], + body: { + type: "BlockStatement", + body: [], + range: [120, 122], + loc: { + start: { line: 8, column: 17 }, + end: { line: 8, column: 19 }, + }, + }, + async: false, + expression: false, + range: [114, 122], + loc: { + start: { line: 8, column: 11 }, + end: { line: 8, column: 19 }, + }, + }, + ], + optional: false, + range: [103, 123], + loc: { + start: { line: 8, column: 0 }, + end: { line: 8, column: 20 }, + }, + }, + range: [103, 124], + loc: { + start: { line: 8, column: 0 }, + end: { line: 8, column: 21 }, + }, + }, + ], + sourceType: "script", + range: [0, 125], + loc: { start: { line: 1, column: 0 }, end: { line: 9, column: 0 } }, + tokens: [ + { + type: "Keyword", + value: "const", + range: [0, 5], + loc: { start: { line: 1, column: 0 }, end: { line: 1, column: 5 } }, + }, + { + type: "Identifier", + value: "method6", + range: [6, 13], + loc: { + start: { line: 1, column: 6 }, + end: { line: 1, column: 13 }, + }, + }, + { + type: "Punctuator", + value: "=", + range: [14, 15], + loc: { + start: { line: 1, column: 14 }, + end: { line: 1, column: 15 }, + }, + }, + { + type: "Punctuator", + value: "(", + range: [16, 17], + loc: { + start: { line: 1, column: 16 }, + end: { line: 1, column: 17 }, + }, + }, + { + type: "Identifier", + value: "abc", + range: [20, 23], + loc: { start: { line: 2, column: 2 }, end: { line: 2, column: 5 } }, + }, + { + type: "Punctuator", + value: ":", + range: [23, 24], + loc: { start: { line: 2, column: 5 }, end: { line: 2, column: 6 } }, + }, + { + type: "Identifier", + value: "number", + range: [25, 31], + loc: { + start: { line: 2, column: 7 }, + end: { line: 2, column: 13 }, + }, + }, + { + type: "Punctuator", + value: ",", + range: [31, 32], + loc: { + start: { line: 2, column: 13 }, + end: { line: 2, column: 14 }, + }, + }, + { + type: "Identifier", + value: "def", + range: [35, 38], + loc: { start: { line: 3, column: 2 }, end: { line: 3, column: 5 } }, + }, + { + type: "Punctuator", + value: ":", + range: [38, 39], + loc: { start: { line: 3, column: 5 }, end: { line: 3, column: 6 } }, + }, + { + type: "Punctuator", + value: "(", + range: [40, 41], + loc: { start: { line: 3, column: 7 }, end: { line: 3, column: 8 } }, + }, + { + type: "Punctuator", + value: ")", + range: [41, 42], + loc: { start: { line: 3, column: 8 }, end: { line: 3, column: 9 } }, + }, + { + type: "Punctuator", + value: "=>", + range: [43, 45], + loc: { + start: { line: 3, column: 10 }, + end: { line: 3, column: 12 }, + }, + }, + { + type: "Keyword", + value: "void", + range: [46, 50], + loc: { + start: { line: 3, column: 13 }, + end: { line: 3, column: 17 }, + }, + }, + { + type: "Punctuator", + value: ",", + range: [50, 51], + loc: { + start: { line: 3, column: 17 }, + end: { line: 3, column: 18 }, + }, + }, + { + type: "Punctuator", + value: ")", + range: [52, 53], + loc: { start: { line: 4, column: 0 }, end: { line: 4, column: 1 } }, + }, + { + type: "Punctuator", + value: ":", + range: [53, 54], + loc: { start: { line: 4, column: 1 }, end: { line: 4, column: 2 } }, + }, + { + type: "Punctuator", + value: "[", + range: [55, 56], + loc: { start: { line: 4, column: 3 }, end: { line: 4, column: 4 } }, + }, + { + type: "Identifier", + value: "string", + range: [59, 65], + loc: { start: { line: 5, column: 2 }, end: { line: 5, column: 8 } }, + }, + { + type: "Punctuator", + value: ",", + range: [65, 66], + loc: { start: { line: 5, column: 8 }, end: { line: 5, column: 9 } }, + }, + { + type: "Punctuator", + value: "(", + range: [69, 70], + loc: { start: { line: 6, column: 2 }, end: { line: 6, column: 3 } }, + }, + { + type: "Punctuator", + value: ")", + range: [70, 71], + loc: { start: { line: 6, column: 3 }, end: { line: 6, column: 4 } }, + }, + { + type: "Punctuator", + value: "=>", + range: [72, 74], + loc: { start: { line: 6, column: 5 }, end: { line: 6, column: 7 } }, + }, + { + type: "Keyword", + value: "void", + range: [75, 79], + loc: { + start: { line: 6, column: 8 }, + end: { line: 6, column: 12 }, + }, + }, + { + type: "Punctuator", + value: "]", + range: [80, 81], + loc: { start: { line: 7, column: 0 }, end: { line: 7, column: 1 } }, + }, + { + type: "Punctuator", + value: "=>", + range: [82, 84], + loc: { start: { line: 7, column: 2 }, end: { line: 7, column: 4 } }, + }, + { + type: "Punctuator", + value: "[", + range: [85, 86], + loc: { start: { line: 7, column: 5 }, end: { line: 7, column: 6 } }, + }, + { + type: "Template", + value: "`a${", + range: [86, 90], + loc: { + start: { line: 7, column: 6 }, + end: { line: 7, column: 10 }, + }, + }, + { + type: "Identifier", + value: "abc", + range: [90, 93], + loc: { + start: { line: 7, column: 10 }, + end: { line: 7, column: 13 }, + }, + }, + { + type: "Template", + value: "}`", + range: [93, 95], + loc: { + start: { line: 7, column: 13 }, + end: { line: 7, column: 15 }, + }, + }, + { + type: "Punctuator", + value: ",", + range: [95, 96], + loc: { + start: { line: 7, column: 15 }, + end: { line: 7, column: 16 }, + }, + }, + { + type: "Identifier", + value: "def", + range: [97, 100], + loc: { + start: { line: 7, column: 17 }, + end: { line: 7, column: 20 }, + }, + }, + { + type: "Punctuator", + value: "]", + range: [100, 101], + loc: { + start: { line: 7, column: 20 }, + end: { line: 7, column: 21 }, + }, + }, + { + type: "Punctuator", + value: ";", + range: [101, 102], + loc: { + start: { line: 7, column: 21 }, + end: { line: 7, column: 22 }, + }, + }, + { + type: "Identifier", + value: "method6", + range: [103, 110], + loc: { start: { line: 8, column: 0 }, end: { line: 8, column: 7 } }, + }, + { + type: "Punctuator", + value: "(", + range: [110, 111], + loc: { start: { line: 8, column: 7 }, end: { line: 8, column: 8 } }, + }, + { + type: "Numeric", + value: "3", + range: [111, 112], + loc: { start: { line: 8, column: 8 }, end: { line: 8, column: 9 } }, + }, + { + type: "Punctuator", + value: ",", + range: [112, 113], + loc: { + start: { line: 8, column: 9 }, + end: { line: 8, column: 10 }, + }, + }, + { + type: "Punctuator", + value: "(", + range: [114, 115], + loc: { + start: { line: 8, column: 11 }, + end: { line: 8, column: 12 }, + }, + }, + { + type: "Punctuator", + value: ")", + range: [115, 116], + loc: { + start: { line: 8, column: 12 }, + end: { line: 8, column: 13 }, + }, + }, + { + type: "Punctuator", + value: "=>", + range: [117, 119], + loc: { + start: { line: 8, column: 14 }, + end: { line: 8, column: 16 }, + }, + }, + { + type: "Punctuator", + value: "{", + range: [120, 121], + loc: { + start: { line: 8, column: 17 }, + end: { line: 8, column: 18 }, + }, + }, + { + type: "Punctuator", + value: "}", + range: [121, 122], + loc: { + start: { line: 8, column: 18 }, + end: { line: 8, column: 19 }, + }, + }, + { + type: "Punctuator", + value: ")", + range: [122, 123], + loc: { + start: { line: 8, column: 19 }, + end: { line: 8, column: 20 }, + }, + }, + { + type: "Punctuator", + value: ";", + range: [123, 124], + loc: { + start: { line: 8, column: 20 }, + end: { line: 8, column: 21 }, + }, + }, + ], + comments: [], +}); diff --git a/tests/lib/rules/function-paren-newline.js b/tests/lib/rules/function-paren-newline.js index 0c9feb7a789..048370f356a 100644 --- a/tests/lib/rules/function-paren-newline.js +++ b/tests/lib/rules/function-paren-newline.js @@ -11,6 +11,9 @@ const rule = require("../../../lib/rules/function-paren-newline"); const { RuleTester } = require("../../../lib/rule-tester"); +const { unIndent } = require("../../_utils"); +const fixtureParser = require("../../fixtures/fixture-parser"); + //------------------------------------------------------------------------------ // Tests @@ -583,6 +586,22 @@ ruleTester.run("function-paren-newline", rule, { code: "import(\n source\n)", options: ["consistent"], parserOptions: { ecmaVersion: 2020 } + }, + + // https://github.com/eslint/eslint/issues/15091#issuecomment-975605821 + { + code: unIndent` + const method6 = ( + abc: number, + def: () => void, + ): [ + string, + () => void + ] => [\`a\${abc}\`, def]; + method6(3, () => {}); + `, + options: ["multiline"], + parser: fixtureParser("function-paren-newline", "arrow-function-return-type") } ], @@ -1437,6 +1456,31 @@ ruleTester.run("function-paren-newline", rule, { options: ["consistent"], parserOptions: { ecmaVersion: 2020 }, errors: [RIGHT_MISSING_ERROR] + }, + + // https://github.com/eslint/eslint/issues/15091#issuecomment-975605821 + { + code: unIndent` + const method6 = ( + abc: number, + def: () => void, + ): [ + string, + () => void + ] => [\`a\${abc}\`, def]; + method6(3, () => {}); + `, + output: unIndent` + const method6 = (abc: number, + def: () => void,): [ + string, + () => void + ] => [\`a\${abc}\`, def]; + method6(3, () => {}); + `, + options: ["never"], + parser: fixtureParser("function-paren-newline", "arrow-function-return-type"), + errors: [LEFT_UNEXPECTED_ERROR, RIGHT_UNEXPECTED_ERROR] } ] });