/
mapAsyncIterator.ts
55 lines (51 loc) · 1.56 KB
/
mapAsyncIterator.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import type { PromiseOrValue } from '../jsutils/PromiseOrValue';
/**
* Given an AsyncIterable and a callback function, return an AsyncIterator
* which produces values mapped via calling the callback function.
*/
export function mapAsyncIterator<T, U, R = undefined>(
iterable: AsyncGenerator<T, R, void> | AsyncIterable<T>,
callback: (value: T) => PromiseOrValue<U>,
): AsyncGenerator<U, R, void> {
// $FlowIssue[incompatible-use]
const iterator = iterable[Symbol.asyncIterator]();
async function mapResult(
result: IteratorResult<T, R>,
): Promise<IteratorResult<U, R>> {
if (result.done) {
return result;
}
try {
return { value: await callback(result.value), done: false };
} catch (error) {
// istanbul ignore else (FIXME: add test case)
if (typeof iterator.return === 'function') {
try {
await iterator.return();
} catch (_e) {
/* ignore error */
}
}
throw error;
}
}
return {
async next() {
return mapResult(await iterator.next());
},
async return(): Promise<IteratorResult<U, R>> {
// If iterator.return() does not exist, then type R must be undefined.
return typeof iterator.return === 'function'
? mapResult(await iterator.return())
: { value: undefined as any, done: true };
},
async throw(error?: unknown) {
return typeof iterator.throw === 'function'
? mapResult(await iterator.throw(error))
: Promise.reject(error);
},
[Symbol.asyncIterator]() {
return this;
},
};
}