-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
fe25e8f
commit 5a00bc4
Showing
4 changed files
with
171 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import { _rangeAsyncIterable } from '../array/range' | ||
import { AsyncIterable2 } from './asyncIterable2' | ||
|
||
test('asyncIterable2', async () => { | ||
expect(await _rangeAsyncIterable(3).toArray()).toEqual([0, 1, 2]) | ||
|
||
expect(await _rangeAsyncIterable(1, 4).find(v => v % 2 === 0)).toBe(2) | ||
expect(await _rangeAsyncIterable(1, 4).some(v => v % 2 === 0)).toBe(true) | ||
expect(await _rangeAsyncIterable(1, 4).some(v => v % 2 === -1)).toBe(false) | ||
expect(await _rangeAsyncIterable(1, 4).every(v => v % 2 === 0)).toBe(false) | ||
expect(await _rangeAsyncIterable(1, 4).every(v => v > 0)).toBe(true) | ||
|
||
expect( | ||
await _rangeAsyncIterable(1, 4) | ||
.filter(v => v % 2 === 1) | ||
.toArray(), | ||
).toEqual([1, 3]) | ||
|
||
expect( | ||
await _rangeAsyncIterable(1, 4) | ||
.map(v => v * 2) | ||
.toArray(), | ||
).toEqual([2, 4, 6]) | ||
|
||
const a: number[] = [] | ||
await _rangeAsyncIterable(1, 4).forEach(v => a.push(v)) | ||
expect(a).toEqual([1, 2, 3]) | ||
|
||
expect(await AsyncIterable2.ofIterable([]).toArray()).toEqual([]) | ||
expect(await AsyncIterable2.empty().toArray()).toEqual([]) | ||
expect(await AsyncIterable2.ofIterable([3, 4]).toArray()).toEqual([3, 4]) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
import { Promisable } from '../typeFest' | ||
import { AbortableAsyncMapper, AbortableAsyncPredicate, END, SKIP } from '../types' | ||
|
||
/** | ||
* Similar to Iterable2, but for AsyncIterable. | ||
* | ||
* AsyncIterable2 is a wrapper around AsyncIterable that implements "Iterator Helpers proposal": | ||
* https://github.com/tc39/proposal-iterator-helpers | ||
* | ||
* AsyncIterable2 can be removed after the proposal is widely implemented in Node & browsers. | ||
* | ||
* @experimental | ||
*/ | ||
export class AsyncIterable2<T> implements AsyncIterable<T> { | ||
private constructor(private it: AsyncIterable<T>) {} | ||
|
||
static of<T>(it: AsyncIterable<T>): AsyncIterable2<T> { | ||
return new AsyncIterable2(it) | ||
} | ||
|
||
static ofIterable<T>(it: Iterable<T>): AsyncIterable2<T> { | ||
return new AsyncIterable2<T>({ | ||
async *[Symbol.asyncIterator]() { | ||
yield* it | ||
}, | ||
}) | ||
} | ||
|
||
static empty<T>(): AsyncIterable2<T> { | ||
return new AsyncIterable2<T>({ | ||
async *[Symbol.asyncIterator]() {}, | ||
}) | ||
} | ||
|
||
[Symbol.asyncIterator](): AsyncIterator<T> { | ||
return this.it[Symbol.asyncIterator]() | ||
} | ||
|
||
async toArray(): Promise<T[]> { | ||
// todo: Array.fromAsync is not yet available, use that when it's ready | ||
// return await Array.fromAsync(this.it) | ||
|
||
const res: T[] = [] | ||
for await (const item of this.it) { | ||
res.push(item) | ||
} | ||
return res | ||
} | ||
|
||
async forEach(cb: (v: T, i: number) => Promisable<any | typeof END>): Promise<void> { | ||
let i = 0 | ||
for await (const v of this.it) { | ||
if ((await cb(v, i++)) === END) return | ||
} | ||
} | ||
|
||
async some(cb: AbortableAsyncPredicate<T>): Promise<boolean> { | ||
return !!(await this.find(cb)) | ||
} | ||
|
||
async every(cb: AbortableAsyncPredicate<T>): Promise<boolean> { | ||
let i = 0 | ||
for await (const v of this.it) { | ||
const r = await cb(v, i++) | ||
if (r === END || !r) return false | ||
} | ||
return true | ||
} | ||
|
||
async find(cb: AbortableAsyncPredicate<T>): Promise<T | undefined> { | ||
let i = 0 | ||
for await (const v of this.it) { | ||
const r = await cb(v, i++) | ||
if (r === END) return | ||
if (r) return v | ||
} | ||
} | ||
|
||
filter(cb: AbortableAsyncPredicate<T>): AsyncIterable2<T> { | ||
const { it } = this | ||
|
||
return new AsyncIterable2<T>({ | ||
async *[Symbol.asyncIterator]() { | ||
let i = 0 | ||
for await (const v of it) { | ||
const r = await cb(v, i++) | ||
if (r === END) return | ||
if (r) yield v | ||
} | ||
}, | ||
}) | ||
} | ||
|
||
map<OUT>(mapper: AbortableAsyncMapper<T, OUT>): AsyncIterable2<OUT> { | ||
const { it } = this | ||
|
||
return new AsyncIterable2<OUT>({ | ||
async *[Symbol.asyncIterator]() { | ||
let i = 0 | ||
for await (const v of it) { | ||
const r = await mapper(v, i++) | ||
if (r === END) return | ||
if (r === SKIP) continue | ||
yield r | ||
} | ||
}, | ||
}) | ||
} | ||
} |