Skip to content

Commit

Permalink
fix(eslint-plugin): [require-await] treat yield* asynciterable as an …
Browse files Browse the repository at this point in the history
…await (#4125)
  • Loading branch information
danny-may committed Nov 17, 2021
1 parent f99a9a5 commit 5a4ce6a
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 6 deletions.
25 changes: 19 additions & 6 deletions packages/eslint-plugin/src/rules/require-await.ts
Expand Up @@ -115,16 +115,22 @@ export default util.createRule({
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;
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;
const typesToCheck = expandUnionOrIntersectionType(type);
for (const type of typesToCheck) {
const asyncIterator = tsutils.getWellKnownSymbolPropertyOfType(
type,
'asyncIterator',
checker,
);
if (asyncIterator !== undefined) {
scopeInfo.isAsyncYield = true;
break;
}
}
}

Expand Down Expand Up @@ -230,3 +236,10 @@ function getFunctionHeadLoc(
end,
};
}

function expandUnionOrIntersectionType(type: ts.Type): ts.Type[] {
if (type.isUnionOrIntersection()) {
return type.types.flatMap(expandUnionOrIntersectionType);
}
return [type];
}
86 changes: 86 additions & 0 deletions packages/eslint-plugin/tests/rules/require-await.test.ts
Expand Up @@ -159,6 +159,57 @@ async function* asyncGenerator() {
}
async function* test1() {
yield* asyncGenerator();
}
`,
`
async function* asyncGenerator() {
await Promise.resolve();
yield 1;
}
async function* test1() {
yield* asyncGenerator();
yield* 2;
}
`,
`
async function* test(source: AsyncIterable<any>) {
yield* source;
}
`,
`
async function* test(source: Iterable<any> & AsyncIterable<any>) {
yield* source;
}
`,
`
async function* test(source: Iterable<any> | AsyncIterable<any>) {
yield* source;
}
`,
`
type MyType = {
[Symbol.iterator](): Iterator<any>;
[Symbol.asyncIterator](): AsyncIterator<any>;
};
async function* test(source: MyType) {
yield* source;
}
`,
`
type MyType = {
[Symbol.asyncIterator]: () => AsyncIterator<any>;
};
async function* test(source: MyType) {
yield* source;
}
`,
`
type MyFunctionType = () => AsyncIterator<any>;
type MyType = {
[Symbol.asyncIterator]: MyFunctionType;
};
async function* test(source: MyType) {
yield* source;
}
`,
'const foo: () => void = async function* () {};',
Expand Down Expand Up @@ -294,6 +345,41 @@ async function* asyncGenerator() {
},
{
code: `
async function* asyncGenerator(source: Iterable<any>) {
yield* source;
}
`,
errors: [
{
messageId: 'missingAwait',
data: {
name: "Async generator function 'asyncGenerator'",
},
},
],
},
{
code: `
function isAsyncIterable(value: unknown): value is AsyncIterable<any> {
return true;
}
async function* asyncGenerator(source: Iterable<any> | AsyncIterable<any>) {
if (!isAsyncIterable(source)) {
yield* source;
}
}
`,
errors: [
{
messageId: 'missingAwait',
data: {
name: "Async generator function 'asyncGenerator'",
},
},
],
},
{
code: `
function* syncGenerator() {
yield 1;
}
Expand Down

0 comments on commit 5a4ce6a

Please sign in to comment.