Skip to content

Commit 9642d9d

Browse files
fix(eslint-plugin): [require-await] handle async generators (#1782)
Co-authored-by: Brad Zacher <[email protected]>
1 parent 8ec53a3 commit 9642d9d

File tree

2 files changed

+217
-65
lines changed

2 files changed

+217
-65
lines changed

Diff for: packages/eslint-plugin/src/rules/require-await.ts

+36-2
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)