8000 feat(eslint-plugin): [no-floating-promise] add option to ignore IIFEs… · DudaGod/typescript-eslint@cea51bf · GitHub
[go: up one dir, main page]

Skip to content

Commit cea51bf

Browse files
authored
feat(eslint-plugin): [no-floating-promise] add option to ignore IIFEs (typescript-eslint#1799)
1 parent c5106dd commit cea51bf

File tree

4 files changed

+217
-5
lines changed

4 files changed

+217
-5
lines changed

packages/eslint-plugin/docs/rules/no-floating-promises.md

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ The rule accepts an options object with the following properties:
5151
type Options = {
5252
// if true, checking void expressions will be skipped
5353
ignoreVoid?: boolean;
54+
// if true, checking for async iife will be skipped
55+
ignoreIIFE?: boolean;
5456
};
5557

5658
const defaults = {
@@ -60,7 +62,8 @@ const defaults = {
6062

6163
### `ignoreVoid`
6264

63-
This allows to easily suppress false-positives with void operator.
65+
This allows you to stop the rule reporting promises consumed with void operator.
66+
This can be a good way to explicitly mark a promise as intentionally not awaited.
6467

6568
Examples of **correct** code for this rule with `{ ignoreVoid: true }`:
6669

@@ -73,10 +76,25 @@ void returnsPromise();
7376
void Promise.reject('value');
7477
```
7578

79+
### `ignoreIIFE`
80+
81+
This allows you to skip checking of async iife
82+
83+
Examples of **correct** code for this rule with `{ ignoreIIFE: true }`:
84+
85+
```ts
86+
await(async function() {
87+
await res(1);
88+
})();
89+
90+
(async function() {
91+
await res(1);
92+
})();
93+
```
94+
7695
## When Not To Use It
7796

78-
If you do not use Promise-like values in your codebase or want to allow them to
79-
remain unhandled.
97+
If you do not use Promise-like values in your codebase, or want to allow them to remain unhandled.
8098

8199
## Related to
82100

packages/eslint-plugin/src/rules/no-floating-promises.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
import * as tsutils from 'tsutils';
22
import * as ts from 'typescript';
3-
import { TSESLint } from '@typescript-eslint/experimental-utils';
3+
import {
4+
TSESLint,
5+
AST_NODE_TYPES,
6+
TSESTree,
7+
} from '@typescript-eslint/experimental-utils';
48

59
import * as util from '../util';
610

711
type Options = [
812
{
913
ignoreVoid?: boolean;
14+
ignoreIIFE?: boolean;
1015
},
1116
];
1217

@@ -33,6 +38,7 @@ export default util.createRule<Options, MessageId>({
3338
type: 'object',
3439
properties: {
3540
ignoreVoid: { type: 'boolean' },
41+
ignoreIIFE: { type: 'boolean' },
3642
},
3743
additionalProperties: false,
3844
},
@@ -42,6 +48,7 @@ export default util.createRule<Options, MessageId>({
4248
defaultOptions: [
4349
{
4450
ignoreVoid: false,
51+
ignoreIIFE: false,
4552
},
4653
],
4754

@@ -54,6 +61,10 @@ export default util.createRule<Options, MessageId>({
5461
ExpressionStatement(node): void {
5562
const { expression } = parserServices.esTreeNodeToTSNodeMap.get(node);
5663

64+
if (options.ignoreIIFE && isAsyncIife(node)) {
65+
return;
66+
}
67+
5768
if (isUnhandledPromise(checker, expression)) {
5869
if (options.ignoreVoid) {
5970
context.report({
@@ -80,6 +91,19 @@ export default util.createRule<Options, MessageId>({
8091
},
8192
};
8293

94+
function isAsyncIife(node: TSESTree.ExpressionStatement): boolean {
95+
if (node.expression.type !== AST_NODE_TYPES.CallExpression) {
96+
return false;
97+
}
98+
99+
return (
100+
node.expression.type === AST_NODE_TYPES.CallExpression &&
101+
(node.expression.callee.type ===
102+
AST_NODE_TYPES.ArrowFunctionExpression ||
103+
node.expression.callee.type === AST_NODE_TYPES.FunctionExpression)
104+
);
105+
}
106+
83107
function isUnhandledPromise(
84108
checker: ts.TypeChecker,
85109
node: ts.Node,

packages/eslint-plugin/tests/rules/no-floating-promises.test.ts

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,54 @@ async function test() {
335335
return returnsPromise();
336336
}
337337
`,
338+
// ignoreIIFE
339+
{
340+
code: `
341+
(async () => {
342+
await something();
343+
})();
344+
`,
345+
options: [{ ignoreIIFE: true }],
346+
},
347+
{
348+
code: `
349+
(async () => {
350+
something();
351+
})();
352+
`,
353+
options: [{ ignoreIIFE: true }],
354+
},
355+
{
356+
code: '(async function foo() {})();',
357+
options: [{ ignoreIIFE: true }],
358+
},
359+
{
360+
code: `
361+
function foo() {
362+
(async function bar() {})();
363+
}
364+
`,
365+
options: [{ ignoreIIFE: true }],
366+
},
367+
{
368+
code: `
369+
const foo = () =>
370+
new Promise(res => {
371+
(async function() {
372+
await res(1);
373+
})();
374+
});
375+
`,
376+
options: [{ ignoreIIFE: true }],
377+
},
378+
{
379+
code: `
380+
(async function() {
381+
await res(1);
382+
})();
383+
`,
384+
options: [{ ignoreIIFE: true }],
385+
},
338386
],
339387

340388
invalid: [
@@ -726,5 +774,126 @@ async function test() {
726774
},
727775
],
728776
},
777+
{
778+
code: `
779+
(async () => {
780+
await something();
781+
})();
782+
`,
783+
errors: [
784+
{
785+
line: 2,
786+
messageId: 'floating',
787+
},
788+
],
789+
},
790+
{
791+
code: `
792+
(async () => {
793+
something();
794+
})();
795+
`,
796+
errors: [
797+
{
798+
line: 2,
799+
messageId: 'floating',
800+
},
801+
],
802+
},
803+
{
804+
code: '(async function foo() {})();',
805+
errors: [
806+
{
807+
line: 1,
808+
messageId: 'floating',
809+
},
810+
],
811+
},
812+
{
813+
code: `
814+
function foo() {
815+
(async function bar() {})();
816+
}
817+
`,
818+
errors: [
819+
{
820+
line: 3,
821+
messageId: 'floating',
822+
},
823+
],
824+
},
825+
{
826+
code: `
827+
const foo = () =>
828+
new Promise(res => {
829+
(async function() {
830+
await res(1);
831+
})();
832+
});
833+
`,
834+
errors: [
835+
{
836+
line: 4,
837+
messageId: 'floating',
838+
},
839+
],
840+
},
841+
{
842+
code: `
843+
(async function() {
844+
await res(1);
845+
})();
846+
`,
847+
errors: [
848+
{
849+
line: 2,
850+
messageId: 'floating',
851+
},
852+
],
853+
},
854+
{
855+
code: `
856+
(async function() {
857+
Promise.resolve();
858+
})();
859+
`,
860+
options: [{ ignoreIIFE: true }],
861+
errors: [
862+
{
863+
line: 3,
864+
messageId: 'floating',
865+
},
866+
],
867+
},
868+
{
869+
code: `
870+
(async function() {
871+
const promiseIntersection: Promise<number> & number;
872+
promiseIntersection;
873+
promiseIntersection.then(() => {});
874+
promiseIntersection.catch();
875+
promiseIntersection.finally();
876+
})();
877+
`,
878+
options: [{ ignoreIIFE: true }],
879+
errors: [
880+
{
881+
line: 4,
882+
messageId: 'floating',
883+
},
884+
{
885+
line: 5,
886+
messageId: 'floating',
887+
},
888+
{
889+
line: 6,
890+
messageId: 'floating',
891+
},
892+
{
893+
line: 7,
894+
messageId: 'floating',
895+
},
896+
],
897+
},
729898
],
730899
});

packages/typescript-estree/src/ts-estree/ts-estree.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,8 @@ export type LeftHandSideExpression =
392392
| PrimaryExpression
393393
| TaggedTemplateExpression
394394
| TSNonNullExpression
395-
| TSAsExpression;
395+
| TSAsExpression
396+
| ArrowFunctionExpression;
396397
export type Literal =
397398
| BooleanLiteral
398399
| NumberLiteral

0 commit comments

Comments
 (0)
0