Skip to content

Commit

Permalink
fix(eslint-plugin): [require-await] handle async generators (#1782)
Browse files Browse the repository at this point in the history
Co-authored-by: Brad Zacher <[email protected]>
  • Loading branch information
anikethsaha and bradzacher authored Mar 31, 2020
1 parent 8ec53a3 commit 9642d9d
Show file tree
Hide file tree
Showing 2 changed files with 217 additions and 65 deletions.
38 changes: 36 additions & 2 deletions packages/eslint-plugin/src/rules/require-await.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ interface ScopeInfo {
upper: ScopeInfo | null;
hasAwait: boolean;
hasAsync: boolean;
isGen: boolean;
isAsyncYield: boolean;
}
type FunctionNode =
| TSESTree.FunctionDeclaration
Expand Down Expand Up @@ -49,6 +51,8 @@ export default util.createRule({
upper: scopeInfo,
hasAwait: false,
hasAsync: node.async,
isGen: node.generator || false,
isAsyncYield: false,
};
}

Expand All @@ -62,7 +66,12 @@ export default util.createRule({
return;
}

if (node.async && !scopeInfo.hasAwait && !isEmptyFunction(node)) {
if (
node.async &&
!scopeInfo.hasAwait &&
!isEmptyFunction(node) &&
!(scopeInfo.isGen && scopeInfo.isAsyncYield)
) {
context.report({
node,
loc: getFunctionHeadLoc(node, sourceCode),
Expand Down Expand Up @@ -92,10 +101,34 @@ export default util.createRule({
if (!scopeInfo) {
return;
}

scopeInfo.hasAwait = true;
}

/**
* mark `scopeInfo.isAsyncYield` to `true` if its a generator
* function and the delegate is `true`
*/
function markAsHasDelegateGen(node: TSESTree.YieldExpression): void {
if (!scopeInfo || !scopeInfo.isGen || !node.argument) {
return;
}

if (node?.argument?.type === AST_NODE_TYPES.Literal) {
// making this `false` as for literals we don't need to check the definition
// eg : async function* run() { yield* 1 }
scopeInfo.isAsyncYield = false;
}

const tsNode = parserServices.esTreeNodeToTSNodeMap.get(node?.argument);
const type = checker.getTypeAtLocation(tsNode);
const symbol = type.getSymbol();

// async function* test1() {yield* asyncGenerator() }
if (symbol?.getName() === 'AsyncGenerator') {
scopeInfo.isAsyncYield = true;
}
}

return {
FunctionDeclaration: enterFunction,
FunctionExpression: enterFunction,
Expand All @@ -106,6 +139,7 @@ export default util.createRule({

AwaitExpression: markAsHasAwait,
'ForOfStatement[await = true]': markAsHasAwait,
'YieldExpression[delegate = true]': markAsHasDelegateGen,

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

0 comments on commit 9642d9d

Please sign in to comment.