Skip to content

Commit 9642d9d

Browse files
fix(eslint-plugin): [require-await] handle async generators (typescript-eslint#1782)
Co-authored-by: Brad Zacher <brad.zacher@gmail.com>
1 parent 8ec53a3 commit 9642d9d

File tree

2 files changed

+217
-65
lines changed

2 files changed

+217
-65
lines changed

packages/eslint-plugin/src/rules/require-await.ts

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ interface ScopeInfo {
1111
upper: ScopeInfo | null;
1212
hasAwait: boolean;
1313
hasAsync: boolean;
14+
isGen: boolean;
15+
isAsyncYield: boolean;
1416
}
1517
type FunctionNode =
1618
| TSESTree.FunctionDeclaration
@@ -49,6 +51,8 @@ export default util.createRule({
4951
upper: scopeInfo,
5052
hasAwait: false,
5153
hasAsync: node.async,
54+
isGen: node.generator || false,
55+
isAsyncYield: false,
5256
};
5357
}
5458

@@ -62,7 +66,12 @@ export default util.createRule({
6266
return;
6367
}
6468

65-
if (node.async && !scopeInfo.hasAwait && !isEmptyFunction(node)) {
69+
if (
70+
node.async &&
71+
!scopeInfo.hasAwait &&
72+
!isEmptyFunction(node) &&
73+
!(scopeInfo.isGen && scopeInfo.isAsyncYield)
74+
) {
6675
context.report({
6776
node,
6877
loc: getFunctionHeadLoc(node, sourceCode),
@@ -92,10 +101,34 @@ export default util.createRule({
92101
if (!scopeInfo) {
93102
return;
94103
}
95-
96104
scopeInfo.hasAwait = true;
97105
}
98106

107+
/**
108+
* mark `scopeInfo.isAsyncYield` to `true` if its a generator
109+
* function and the delegate is `true`
110+
*/
111+
function markAsHasDelegateGen(node: TSESTree.YieldExpression): void {
112+
if (!scopeInfo || !scopeInfo.isGen || !node.argument) {
113+
return;
114+
}
115+
116+
if (node?.argument?.type === AST_NODE_TYPES.Literal) {
117+
// making this `false` as for literals we don't need to check the definition
118+
// eg : async function* run() { yield* 1 }
119+
scopeInfo.isAsyncYield = false;
120+
}
121+
122+
const tsNode = parserServices.esTreeNodeToTSNodeMap.get(node?.argument);
123+
const type = checker.getTypeAtLocation(tsNode);
124+
const symbol = type.getSymbol();
125+
126+
// async function* test1() {yield* asyncGenerator() }
127+
if (symbol?.getName() === 'AsyncGenerator') {
128+
scopeInfo.isAsyncYield = true;
129+
}
130+
}
131+
99132
return {
100133
FunctionDeclaration: enterFunction,
101134
FunctionExpression: enterFunction,
@@ -106,6 +139,7 @@ export default util.createRule({
106139

107140
AwaitExpression: markAsHasAwait,
108141
'ForOfStatement[await = true]': markAsHasAwait,
142+
'YieldExpression[delegate = true]': markAsHasDelegateGen,
109143

110144
// check body-less async arrow function.
111145
// ignore `async () => await foo` because it's obviously correct

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy