From a1b3f7b4d97154ac4b0d7934d12f1d5970cffe15 Mon Sep 17 00:00:00 2001 From: YeonJuan Date: Mon, 13 Feb 2023 03:07:23 +0900 Subject: [PATCH] feat(eslint-plugin): [explicit-function-return-type] add allowIIFEs option (#6237) * feat(eslint-plugin): [explicit-function-return-type] add allowIIFEs option * remove useless code * fix tests * apply reviews * remove useless lint * add tc * fix * add test cases * fix * fix * add test cases * add test case * Update packages/eslint-plugin/tests/rules/explicit-function-return-type.test.ts --------- Co-authored-by: Josh Goldberg --- .../rules/explicit-function-return-type.md | 20 ++ .../rules/explicit-function-return-type.ts | 21 ++ .../explicit-function-return-type.test.ts | 214 ++++++++++++++++++ 3 files changed, 255 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 9c91aa6d83d..254c48a0965 100644 --- a/packages/eslint-plugin/src/rules/explicit-function-return-type.ts +++ b/packages/eslint-plugin/src/rules/explicit-function-return-type.ts @@ -17,6 +17,7 @@ type Options = [ allowConciseArrowFunctionExpressionsStartingWithVoid?: boolean; allowFunctionsWithoutTypeParameters?: boolean; allowedNames?: string[]; + allowIIFEs?: boolean; }, ]; type MessageIds = 'missingReturnType'; @@ -75,6 +76,11 @@ export default util.createRule({ }, type: 'array', }, + allowIIFEs: { + description: + 'Whether to ignore immediately invoked function expressions (IIFEs).', + type: 'boolean', + }, }, additionalProperties: false, }, @@ -88,6 +94,7 @@ export default util.createRule({ allowDirectConstAssertionInArrowFunctions: true, allowConciseArrowFunctionExpressionsStartingWithVoid: false, allowedNames: [], + allowIIFEs: false, }, ], create(context, [options]) { @@ -102,6 +109,10 @@ export default util.createRule({ return true; } + if (options.allowIIFEs && isIIFE(node)) { + return true; + } + if (!options.allowedNames?.length) { return false; } @@ -149,6 +160,16 @@ export default util.createRule({ } return false; } + + function isIIFE( + node: + | TSESTree.ArrowFunctionExpression + | TSESTree.FunctionExpression + | TSESTree.FunctionDeclaration, + ): boolean { + return node.parent!.type === AST_NODE_TYPES.CallExpression; + } + return { 'ArrowFunctionExpression, FunctionExpression'( node: TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression, 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 912242247af..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 @@ -595,6 +595,132 @@ 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; +})(); + `, + options: [ + { + allowIIFEs: true, + }, + ], + }, + { + filename: 'test.ts', + code: ` +const foo = (() => { + return 1; +})(); + `, + options: [ + { + allowIIFEs: true, + }, + ], + }, + { + filename: 'test.ts', + code: ` +const foo = ((arg: number): number => { + return arg; +})(0); + `, + options: [ + { + allowIIFEs: true, + }, + ], + }, + { + filename: 'test.ts', + code: ` +const foo = (() => (() => 'foo')())(); + `, + options: [ + { + allowIIFEs: true, + }, + ], + }, + { + 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, + }, + ], + }, + { + filename: 'test.ts', + code: ` +let foo = (() => (): void => {})()(); + `, + options: [ + { + allowIIFEs: true, + }, + ], + }, + { + filename: 'test.ts', + code: ` +let foo = (() => (() => {})())(); + `, + options: [ + { + allowIIFEs: true, + }, + ], + }, ], invalid: [ { @@ -1477,5 +1603,93 @@ 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, + }, + ], + }, + { + filename: 'test.ts', + code: ` +let foo = function () { + return 'foo'; +}; + `, + options: [ + { + allowIIFEs: true, + }, + ], + errors: [ + { + messageId: 'missingReturnType', + line: 2, + endLine: 2, + column: 11, + endColumn: 22, + }, + ], + }, + { + filename: 'test.ts', + code: ` +let foo = (() => () => {})()(); + `, + options: [ + { + allowIIFEs: true, + }, + ], + errors: [ + { + messageId: 'missingReturnType', + line: 2, + endLine: 2, + column: 18, + endColumn: 23, + }, + ], + }, ], });