From dd7e799d521142bbb1bc95fd8388ff17f76a0751 Mon Sep 17 00:00:00 2001 From: yeonjuan Date: Sun, 18 Dec 2022 01:50:28 +0900 Subject: [PATCH 01/13] feat(eslint-plugin): [explicit-function-return-type] add allowIIFEs option --- .../rules/explicit-function-return-type.md | 20 ++++++ .../rules/explicit-function-return-type.ts | 25 +++++++ .../explicit-function-return-type.test.ts | 72 +++++++++++++++++++ 3 files changed, 117 insertions(+) diff --git a/packages/eslint-plugin/docs/rules/explicit-function-return-type.md b/packages/eslint-plugin/docs/rules/explicit-function-return-type.md index 3a67a7e2372..a5df82f958a 100644 --- a/packages/eslint-plugin/docs/rules/explicit-function-return-type.md +++ b/packages/eslint-plugin/docs/rules/explicit-function-return-type.md @@ -257,6 +257,26 @@ You may pass function/method names you would like this rule to ignore, like so: } ``` +### `allowIIFE` + +Examples of code for this rule with `{ allowIIFE: true }`: + +#### ❌ Incorrect + +```ts +var func = () => 'foo'; +``` + +#### ✅ Correct + +```ts +var foo = (() => 'foo')(); + +var bar = (function () { + return 'bar'; +})(); +``` + ## When Not To Use It If you don't wish to prevent calling code from using function return values in unexpected ways, then diff --git a/packages/eslint-plugin/src/rules/explicit-function-return-type.ts b/packages/eslint-plugin/src/rules/explicit-function-return-type.ts index 1d216ebff1d..887ff7b20bd 100644 --- a/packages/eslint-plugin/src/rules/explicit-function-return-type.ts +++ b/packages/eslint-plugin/src/rules/explicit-function-return-type.ts @@ -16,6 +16,7 @@ type Options = [ allowDirectConstAssertionInArrowFunctions?: boolean; allowConciseArrowFunctionExpressionsStartingWithVoid?: boolean; allowedNames?: string[]; + allowIIFEs?: boolean; }, ]; type MessageIds = 'missingReturnType'; @@ -69,6 +70,11 @@ export default util.createRule({ }, type: 'array', }, + allowIIFEs: { + description: + 'Whether to ignore functions immediately invoked (IIFEs).', + type: 'boolean', + }, }, additionalProperties: false, }, @@ -82,6 +88,7 @@ export default util.createRule({ allowDirectConstAssertionInArrowFunctions: true, allowConciseArrowFunctionExpressionsStartingWithVoid: false, allowedNames: [], + allowIIFEs: false, }, ], create(context, [options]) { @@ -139,6 +146,16 @@ export default util.createRule({ } return false; } + + function isIIFE( + node: TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression, + ): boolean { + return ( + node.parent?.type === AST_NODE_TYPES.CallExpression && + node.parent?.callee === node + ); + } + return { 'ArrowFunctionExpression, FunctionExpression'( node: TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression, @@ -153,6 +170,14 @@ export default util.createRule({ return; } + if ( + options.allowIIFEs && + node.parent?.type === AST_NODE_TYPES.CallExpression && + isIIFE(node) + ) { + return; + } + if (isAllowedName(node)) { return; } diff --git a/packages/eslint-plugin/tests/rules/explicit-function-return-type.test.ts b/packages/eslint-plugin/tests/rules/explicit-function-return-type.test.ts index 40c15a89a2f..126d6f71b6b 100644 --- a/packages/eslint-plugin/tests/rules/explicit-function-return-type.test.ts +++ b/packages/eslint-plugin/tests/rules/explicit-function-return-type.test.ts @@ -555,6 +555,32 @@ const x: Bar = arg1 => arg2 => arg1 + arg2; }, ], }, + { + filename: 'test.ts', + code: ` +const foo = (function () { + return 1; +})(); + `, + options: [ + { + allowIIFEs: true, + }, + ], + }, + { + filename: 'test.ts', + code: ` +const foo = (() => { + return 1; +})(); + `, + options: [ + { + allowIIFEs: true, + }, + ], + }, ], invalid: [ { @@ -1414,5 +1440,51 @@ class Foo { }, ], }, + { + filename: 'test.ts', + code: ` +const foo = (function () { + return 'foo'; +})(); + `, + options: [ + { + allowIIFEs: false, + }, + ], + errors: [ + { + messageId: 'missingReturnType', + line: 2, + endLine: 2, + column: 14, + endColumn: 25, + }, + ], + }, + { + filename: 'test.ts', + code: ` +const foo = (function () { + return () => { + return 1; + }; +})(); + `, + options: [ + { + allowIIFEs: true, + }, + ], + errors: [ + { + messageId: 'missingReturnType', + line: 3, + endLine: 3, + column: 10, + endColumn: 15, + }, + ], + }, ], }); From 3f8a981bab5ec925fb83bb55a080246664621f51 Mon Sep 17 00:00:00 2001 From: yeonjuan Date: Sun, 18 Dec 2022 02:53:47 +0900 Subject: [PATCH 02/13] remove useless code --- .../rules/explicit-function-return-type.ts | 6 +---- .../explicit-function-return-type.test.ts | 22 +++++++++++++++++++ 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/packages/eslint-plugin/src/rules/explicit-function-return-type.ts b/packages/eslint-plugin/src/rules/explicit-function-return-type.ts index 887ff7b20bd..1958d139fe1 100644 --- a/packages/eslint-plugin/src/rules/explicit-function-return-type.ts +++ b/packages/eslint-plugin/src/rules/explicit-function-return-type.ts @@ -170,11 +170,7 @@ export default util.createRule({ return; } - if ( - options.allowIIFEs && - node.parent?.type === AST_NODE_TYPES.CallExpression && - isIIFE(node) - ) { + if (options.allowIIFEs && isIIFE(node)) { return; } diff --git a/packages/eslint-plugin/tests/rules/explicit-function-return-type.test.ts b/packages/eslint-plugin/tests/rules/explicit-function-return-type.test.ts index 126d6f71b6b..ea06a9c050a 100644 --- a/packages/eslint-plugin/tests/rules/explicit-function-return-type.test.ts +++ b/packages/eslint-plugin/tests/rules/explicit-function-return-type.test.ts @@ -1486,5 +1486,27 @@ const foo = (function () { }, ], }, + { + filename: 'test.ts', + code: ` +function foo() { + return 'foo'; +} + `, + options: [ + { + allowIIFEs: true, + }, + ], + errors: [ + { + messageId: 'missingReturnType', + line: 2, + endLine: 2, + column: 1, + endColumn: 15, + }, + ], + }, ], }); From a242fb71203fa304d70cf6e8840e50c2bf9d1e6e Mon Sep 17 00:00:00 2001 From: yeonjuan Date: Sun, 18 Dec 2022 03:14:03 +0900 Subject: [PATCH 03/13] fix tests --- .../tests/rules/explicit-function-return-type.test.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/eslint-plugin/tests/rules/explicit-function-return-type.test.ts b/packages/eslint-plugin/tests/rules/explicit-function-return-type.test.ts index ea06a9c050a..a1e705c21c8 100644 --- a/packages/eslint-plugin/tests/rules/explicit-function-return-type.test.ts +++ b/packages/eslint-plugin/tests/rules/explicit-function-return-type.test.ts @@ -1489,9 +1489,9 @@ const foo = (function () { { filename: 'test.ts', code: ` -function foo() { +let foo = function () { return 'foo'; -} +}; `, options: [ { @@ -1503,8 +1503,8 @@ function foo() { messageId: 'missingReturnType', line: 2, endLine: 2, - column: 1, - endColumn: 15, + column: 11, + endColumn: 22, }, ], }, From 75a520d815458bbb6a9890c6768e7635c9841b7b Mon Sep 17 00:00:00 2001 From: yeonjuan Date: Sun, 18 Dec 2022 15:00:01 +0900 Subject: [PATCH 04/13] apply reviews --- .../rules/explicit-function-return-type.ts | 4 ++-- .../explicit-function-return-type.test.ts | 24 +++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/packages/eslint-plugin/src/rules/explicit-function-return-type.ts b/packages/eslint-plugin/src/rules/explicit-function-return-type.ts index 1958d139fe1..03a7aa0b934 100644 --- a/packages/eslint-plugin/src/rules/explicit-function-return-type.ts +++ b/packages/eslint-plugin/src/rules/explicit-function-return-type.ts @@ -72,7 +72,7 @@ export default util.createRule({ }, allowIIFEs: { description: - 'Whether to ignore functions immediately invoked (IIFEs).', + 'Whether to ignore immediately invoked function expressions (IIFEs).', type: 'boolean', }, }, @@ -152,7 +152,7 @@ export default util.createRule({ ): boolean { return ( node.parent?.type === AST_NODE_TYPES.CallExpression && - node.parent?.callee === node + node.parent.callee === node ); } diff --git a/packages/eslint-plugin/tests/rules/explicit-function-return-type.test.ts b/packages/eslint-plugin/tests/rules/explicit-function-return-type.test.ts index a1e705c21c8..ba203d57e98 100644 --- a/packages/eslint-plugin/tests/rules/explicit-function-return-type.test.ts +++ b/packages/eslint-plugin/tests/rules/explicit-function-return-type.test.ts @@ -581,6 +581,30 @@ const foo = (() => { }, ], }, + { + filename: 'test.ts', + code: ` +const foo = ((arg: number): number => { + return arg; +})(); + `, + options: [ + { + allowIIFEs: true, + }, + ], + }, + { + filename: 'test.ts', + code: ` +const foo = (() => (() => 'foo')())(); + `, + options: [ + { + allowIIFEs: true, + }, + ], + }, ], invalid: [ { From 28f2a6a1b99e1b2309ebb505687eb1475aa4cc0b Mon Sep 17 00:00:00 2001 From: yeonjuan Date: Sun, 18 Dec 2022 23:47:38 +0900 Subject: [PATCH 05/13] remove useless lint --- .../eslint-plugin/src/rules/explicit-function-return-type.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/eslint-plugin/src/rules/explicit-function-return-type.ts b/packages/eslint-plugin/src/rules/explicit-function-return-type.ts index 03a7aa0b934..1fbc589b77c 100644 --- a/packages/eslint-plugin/src/rules/explicit-function-return-type.ts +++ b/packages/eslint-plugin/src/rules/explicit-function-return-type.ts @@ -150,10 +150,7 @@ export default util.createRule({ function isIIFE( node: TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression, ): boolean { - return ( - node.parent?.type === AST_NODE_TYPES.CallExpression && - node.parent.callee === node - ); + return node.parent?.type === AST_NODE_TYPES.CallExpression; } return { From 0739ae5156220305238242743b29d9444046c49a Mon Sep 17 00:00:00 2001 From: yeonjuan Date: Mon, 19 Dec 2022 00:04:11 +0900 Subject: [PATCH 06/13] add tc --- .../rules/explicit-function-return-type.test.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/eslint-plugin/tests/rules/explicit-function-return-type.test.ts b/packages/eslint-plugin/tests/rules/explicit-function-return-type.test.ts index ba203d57e98..ccd7ce5f196 100644 --- a/packages/eslint-plugin/tests/rules/explicit-function-return-type.test.ts +++ b/packages/eslint-plugin/tests/rules/explicit-function-return-type.test.ts @@ -558,6 +558,19 @@ const x: Bar = arg1 => arg2 => arg1 + arg2; { filename: 'test.ts', code: ` +let foo = function (): number { + return 1; +}; + `, + options: [ + { + allowIIFEs: true, + }, + ], + }, + { + filename: 'test.ts', + code: ` const foo = (function () { return 1; })(); From d3e168cff551959df34714cf77a25862cbb2248b Mon Sep 17 00:00:00 2001 From: yeonjuan Date: Mon, 19 Dec 2022 00:27:34 +0900 Subject: [PATCH 07/13] fix --- .../eslint-plugin/src/rules/explicit-function-return-type.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/eslint-plugin/src/rules/explicit-function-return-type.ts b/packages/eslint-plugin/src/rules/explicit-function-return-type.ts index 1fbc589b77c..eedf418dd42 100644 --- a/packages/eslint-plugin/src/rules/explicit-function-return-type.ts +++ b/packages/eslint-plugin/src/rules/explicit-function-return-type.ts @@ -150,7 +150,7 @@ export default util.createRule({ function isIIFE( node: TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression, ): boolean { - return node.parent?.type === AST_NODE_TYPES.CallExpression; + return node.parent!.type === AST_NODE_TYPES.CallExpression; } return { From a6fba09cba23f49aefe664b6b4d91a1ebbc5bd70 Mon Sep 17 00:00:00 2001 From: yeonjuan Date: Tue, 27 Dec 2022 02:16:16 +0900 Subject: [PATCH 08/13] add test cases --- .../explicit-function-return-type.test.ts | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/packages/eslint-plugin/tests/rules/explicit-function-return-type.test.ts b/packages/eslint-plugin/tests/rules/explicit-function-return-type.test.ts index ccd7ce5f196..b219a2fcb84 100644 --- a/packages/eslint-plugin/tests/rules/explicit-function-return-type.test.ts +++ b/packages/eslint-plugin/tests/rules/explicit-function-return-type.test.ts @@ -618,6 +618,47 @@ const foo = (() => (() => 'foo')())(); }, ], }, + { + filename: 'test.ts', + code: ` +let foo = (() => (): string => { + return 'foo'; +})()(); + `, + options: [ + { + allowIIFEs: true, + }, + ], + }, + { + filename: 'test.ts', + code: ` +let foo = (() => (): string => { + return 'foo'; +})(); + `, + options: [ + { + allowIIFEs: true, + allowHigherOrderFunctions: false, + }, + ], + }, + { + filename: 'test.ts', + code: ` +let foo = (() => (): string => { + return 'foo'; +})()(); + `, + options: [ + { + allowIIFEs: true, + allowHigherOrderFunctions: true, + }, + ], + }, ], invalid: [ { @@ -1545,5 +1586,25 @@ let foo = function () { }, ], }, + { + filename: 'test.ts', + code: ` +let foo = (() => () => {})()(); + `, + options: [ + { + allowIIFEs: true, + }, + ], + errors: [ + { + messageId: 'missingReturnType', + line: 2, + endLine: 2, + column: 18, + endColumn: 23, + }, + ], + }, ], }); From 7affa5b3ac436189f2b0b0b25141bd8d45376516 Mon Sep 17 00:00:00 2001 From: yeonjuan Date: Sun, 12 Feb 2023 23:21:45 +0900 Subject: [PATCH 09/13] fix --- .../src/rules/explicit-function-return-type.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/eslint-plugin/src/rules/explicit-function-return-type.ts b/packages/eslint-plugin/src/rules/explicit-function-return-type.ts index 6fe63292665..c2449d24da4 100644 --- a/packages/eslint-plugin/src/rules/explicit-function-return-type.ts +++ b/packages/eslint-plugin/src/rules/explicit-function-return-type.ts @@ -113,6 +113,10 @@ export default util.createRule({ return false; } + if (options.allowIIFEs && isIIFE(node)) { + return true; + } + if ( node.type === AST_NODE_TYPES.ArrowFunctionExpression || node.type === AST_NODE_TYPES.FunctionExpression @@ -158,7 +162,10 @@ export default util.createRule({ } function isIIFE( - node: TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression, + node: + | TSESTree.ArrowFunctionExpression + | TSESTree.FunctionExpression + | TSESTree.FunctionDeclaration, ): boolean { return node.parent!.type === AST_NODE_TYPES.CallExpression; } From 2657eb61ace821d597c0c75b50b4ab4907c8174e Mon Sep 17 00:00:00 2001 From: yeonjuan Date: Sun, 12 Feb 2023 23:51:27 +0900 Subject: [PATCH 10/13] fix --- .../src/rules/explicit-function-return-type.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/eslint-plugin/src/rules/explicit-function-return-type.ts b/packages/eslint-plugin/src/rules/explicit-function-return-type.ts index c2449d24da4..254c48a0965 100644 --- a/packages/eslint-plugin/src/rules/explicit-function-return-type.ts +++ b/packages/eslint-plugin/src/rules/explicit-function-return-type.ts @@ -109,14 +109,14 @@ export default util.createRule({ return true; } - if (!options.allowedNames?.length) { - return false; - } - if (options.allowIIFEs && isIIFE(node)) { return true; } + if (!options.allowedNames?.length) { + return false; + } + if ( node.type === AST_NODE_TYPES.ArrowFunctionExpression || node.type === AST_NODE_TYPES.FunctionExpression From 0af3c215962808e89b5ee72a7890801792c4c1d1 Mon Sep 17 00:00:00 2001 From: yeonjuan Date: Mon, 13 Feb 2023 00:07:48 +0900 Subject: [PATCH 11/13] add test cases --- .../tests/rules/explicit-function-return-type.test.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/eslint-plugin/tests/rules/explicit-function-return-type.test.ts b/packages/eslint-plugin/tests/rules/explicit-function-return-type.test.ts index c3b75e00276..96cfd61191e 100644 --- a/packages/eslint-plugin/tests/rules/explicit-function-return-type.test.ts +++ b/packages/eslint-plugin/tests/rules/explicit-function-return-type.test.ts @@ -699,6 +699,17 @@ let foo = (() => (): string => { }, ], }, + { + filename: 'test.ts', + code: ` +let foo = (() => (): void => {})()(); + `, + options: [ + { + allowIIFEs: true, + }, + ], + }, ], invalid: [ { From 1c702dc2ceb9bd8f4561458730422e8e6e2386f7 Mon Sep 17 00:00:00 2001 From: yeonjuan Date: Mon, 13 Feb 2023 00:09:23 +0900 Subject: [PATCH 12/13] add test case --- .../tests/rules/explicit-function-return-type.test.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/eslint-plugin/tests/rules/explicit-function-return-type.test.ts b/packages/eslint-plugin/tests/rules/explicit-function-return-type.test.ts index 96cfd61191e..a8049a5c0b9 100644 --- a/packages/eslint-plugin/tests/rules/explicit-function-return-type.test.ts +++ b/packages/eslint-plugin/tests/rules/explicit-function-return-type.test.ts @@ -710,6 +710,17 @@ let foo = (() => (): void => {})()(); }, ], }, + { + filename: 'test.ts', + code: ` +let foo = (() => (() => {})())(); + `, + options: [ + { + allowIIFEs: true, + }, + ], + }, ], invalid: [ { From f18a367d80de15c401f19d28a8cf2df73604e414 Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Sun, 12 Feb 2023 12:41:28 -0500 Subject: [PATCH 13/13] Update packages/eslint-plugin/tests/rules/explicit-function-return-type.test.ts --- .../tests/rules/explicit-function-return-type.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/eslint-plugin/tests/rules/explicit-function-return-type.test.ts b/packages/eslint-plugin/tests/rules/explicit-function-return-type.test.ts index a8049a5c0b9..d3c1a540192 100644 --- a/packages/eslint-plugin/tests/rules/explicit-function-return-type.test.ts +++ b/packages/eslint-plugin/tests/rules/explicit-function-return-type.test.ts @@ -639,7 +639,7 @@ const foo = (() => { code: ` const foo = ((arg: number): number => { return arg; -})(); +})(0); `, options: [ {