Skip to content

Commit

Permalink
feat(eslint-plugin): [explicit-function-return-type] add allowIIFEs o…
Browse files Browse the repository at this point in the history
…ption (#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 <git@joshuakgoldberg.com>
  • Loading branch information
yeonjuan and JoshuaKGoldberg committed Feb 12, 2023
1 parent 766ab1d commit a1b3f7b
Show file tree
Hide file tree
Showing 3 changed files with 255 additions and 0 deletions.
20 changes: 20 additions & 0 deletions packages/eslint-plugin/docs/rules/explicit-function-return-type.md
Expand Up @@ -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
Expand Down
21 changes: 21 additions & 0 deletions packages/eslint-plugin/src/rules/explicit-function-return-type.ts
Expand Up @@ -17,6 +17,7 @@ type Options = [
allowConciseArrowFunctionExpressionsStartingWithVoid?: boolean;
allowFunctionsWithoutTypeParameters?: boolean;
allowedNames?: string[];
allowIIFEs?: boolean;
},
];
type MessageIds = 'missingReturnType';
Expand Down Expand Up @@ -75,6 +76,11 @@ export default util.createRule<Options, MessageIds>({
},
type: 'array',
},
allowIIFEs: {
description:
'Whether to ignore immediately invoked function expressions (IIFEs).',
type: 'boolean',
},
},
additionalProperties: false,
},
Expand All @@ -88,6 +94,7 @@ export default util.createRule<Options, MessageIds>({
allowDirectConstAssertionInArrowFunctions: true,
allowConciseArrowFunctionExpressionsStartingWithVoid: false,
allowedNames: [],
allowIIFEs: false,
},
],
create(context, [options]) {
Expand All @@ -102,6 +109,10 @@ export default util.createRule<Options, MessageIds>({
return true;
}

if (options.allowIIFEs && isIIFE(node)) {
return true;
}

if (!options.allowedNames?.length) {
return false;
}
Expand Down Expand Up @@ -149,6 +160,16 @@ export default util.createRule<Options, MessageIds>({
}
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,
Expand Down
Expand Up @@ -595,6 +595,132 @@ const x: Bar<Foo> = 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: [
{
Expand Down Expand Up @@ -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,
},
],
},
],
});

0 comments on commit a1b3f7b

Please sign in to comment.