Skip to content

Commit

Permalink
fix: allow Iterable | AsyncIterable union input (#59)
Browse files Browse the repository at this point in the history
Compatiblity fix - where the input cannot be separated between
Iterable and AsyncIterable sources, update the types to return
async generators.

For best performance users should pass either Iterable or
AsyncIterable, not a union of both.
  • Loading branch information
achingbrain committed Mar 31, 2023
1 parent 0033bfd commit 80ec2ac
Show file tree
Hide file tree
Showing 17 changed files with 53 additions and 48 deletions.
4 changes: 2 additions & 2 deletions packages/it-all/src/index.ts
Expand Up @@ -6,8 +6,8 @@ function isAsyncIterable <T> (thing: any): thing is AsyncIterable<T> {
* Collects all values from an (async) iterable and returns them as an array
*/
function all <T> (source: Iterable<T>): T[]
function all <T> (source: AsyncIterable<T>): Promise<T[]>
function all <T> (source: AsyncIterable<T> | Iterable<T>): Promise<T[]> | T[] {
function all <T> (source: Iterable<T> | AsyncIterable<T>): Promise<T[]>
function all <T> (source: Iterable<T> | AsyncIterable<T>): Promise<T[]> | T[] {
if (isAsyncIterable(source)) {
return (async () => {
const arr = []
Expand Down
4 changes: 2 additions & 2 deletions packages/it-batch/src/index.ts
Expand Up @@ -7,8 +7,8 @@ function isAsyncIterable <T> (thing: any): thing is AsyncIterable<T> {
* emits those things in fixed-sized batches
*/
function batch <T> (source: Iterable<T>, size?: number): Generator<T[], void, undefined>
function batch <T> (source: AsyncIterable<T> | Iterable<T>, size?: number): AsyncGenerator<T[], void, undefined>
function batch <T> (source: AsyncIterable<T> | Iterable<T>, size: number = 1): Generator<T[], void, undefined> | AsyncGenerator<T[], void, undefined> {
function batch <T> (source: Iterable<T> | AsyncIterable<T>, size?: number): AsyncGenerator<T[], void, undefined>
function batch <T> (source: Iterable<T> | AsyncIterable<T>, size: number = 1): Generator<T[], void, undefined> | AsyncGenerator<T[], void, undefined> {
size = Number(size)

if (isAsyncIterable(source)) {
Expand Down
2 changes: 1 addition & 1 deletion packages/it-batched-bytes/src/index.ts
Expand Up @@ -35,7 +35,7 @@ export interface AsyncBatchedBytesOptions extends BatchedBytesOptions {
* or the next event loop tick occurs, yield any bytes from the buffer.
*/
function batchedBytes (source: Iterable<Uint8Array | Uint8ArrayList>, options?: BatchedBytesOptions): Iterable<Uint8Array>
function batchedBytes (source: AsyncIterable<Uint8Array | Uint8ArrayList>, options?: AsyncBatchedBytesOptions): AsyncIterable<Uint8Array>
function batchedBytes (source: Iterable<Uint8Array | Uint8ArrayList> | AsyncIterable<Uint8Array | Uint8ArrayList>, options?: AsyncBatchedBytesOptions): AsyncIterable<Uint8Array>
function batchedBytes (source: Iterable<Uint8Array | Uint8ArrayList> | AsyncIterable<Uint8Array | Uint8ArrayList>, options: AsyncBatchedBytesOptions = {}): AsyncIterable<Uint8Array> | Iterable<Uint8Array> {
if (isAsyncIterable(source)) {
return (async function * () {
Expand Down
4 changes: 2 additions & 2 deletions packages/it-drain/src/index.ts
Expand Up @@ -7,8 +7,8 @@ function isAsyncIterable <T> (thing: any): thing is AsyncIterable<T> {
* anything
*/
function drain (source: Iterable<unknown>): void
function drain (source: AsyncIterable<unknown>): Promise<void>
function drain (source: AsyncIterable<unknown> | Iterable<unknown>): Promise<void> | void {
function drain (source: Iterable<unknown> | AsyncIterable<unknown>): Promise<void>
function drain (source: Iterable<unknown> | AsyncIterable<unknown>): Promise<void> | void {
if (isAsyncIterable(source)) {
return (async () => {
for await (const _ of source) { } // eslint-disable-line no-unused-vars,no-empty,@typescript-eslint/no-unused-vars
Expand Down
4 changes: 2 additions & 2 deletions packages/it-first/src/index.ts
Expand Up @@ -7,8 +7,8 @@ function isAsyncIterable <T> (thing: any): thing is AsyncIterable<T> {
* case returns `undefined`
*/
function first <T> (source: Iterable<T>): T | undefined
function first <T> (source: AsyncIterable<T>): Promise<T | undefined>
function first <T> (source: AsyncIterable<T> | Iterable<T>): Promise<T | undefined> | T | undefined {
function first <T> (source: Iterable<T> | AsyncIterable<T>): Promise<T | undefined>
function first <T> (source: Iterable<T> | AsyncIterable<T>): Promise<T | undefined> | T | undefined {
if (isAsyncIterable(source)) {
return (async () => {
for await (const entry of source) { // eslint-disable-line no-unreachable-loop
Expand Down
4 changes: 2 additions & 2 deletions packages/it-flat-batch/src/index.ts
Expand Up @@ -7,8 +7,8 @@ function isAsyncIterable <T> (thing: any): thing is AsyncIterable<T> {
* returns an async iterable that emits those things in fixed-size batches
*/
function batch <T> (source: Iterable<T[]>, batchSize?: number): Generator<T[], void, undefined>
function batch <T> (source: AsyncIterable<T[]>, batchSize?: number): AsyncGenerator<T[], void, undefined>
function batch <T> (source: AsyncIterable<T[]> | Iterable<T[]>, batchSize: number = 1): AsyncGenerator<T[], void, undefined> | Generator<T[], void, undefined> {
function batch <T> (source: Iterable<T[]> | AsyncIterable<T[]>, batchSize?: number): AsyncGenerator<T[], void, undefined>
function batch <T> (source: Iterable<T[]> | AsyncIterable<T[]>, batchSize: number = 1): AsyncGenerator<T[], void, undefined> | Generator<T[], void, undefined> {
let size = parseInt(`${batchSize}`)

if (isNaN(size) || size < 1) {
Expand Down
4 changes: 2 additions & 2 deletions packages/it-foreach/src/index.ts
Expand Up @@ -9,8 +9,8 @@ function isAsyncIterable <T> (thing: any): thing is AsyncIterable<T> {
*/
function forEach <T> (source: Iterable<T>, fn: (thing: T) => Promise<void>): AsyncGenerator<T, void, undefined>
function forEach <T> (source: Iterable<T>, fn: (thing: T) => void): Generator<T, void, undefined>
function forEach <T> (source: AsyncIterable<T>, fn: (thing: T) => void | Promise<void>): AsyncGenerator<T, void, undefined>
function forEach <T> (source: AsyncIterable<T> | Iterable<T>, fn: (thing: T) => void | Promise<void>): AsyncGenerator<T, void, undefined> | Generator<T, void, undefined> {
function forEach <T> (source: Iterable<T> | AsyncIterable<T>, fn: (thing: T) => void | Promise<void>): AsyncGenerator<T, void, undefined>
function forEach <T> (source: Iterable<T> | AsyncIterable<T>, fn: (thing: T) => void | Promise<void>): AsyncGenerator<T, void, undefined> | Generator<T, void, undefined> {
if (isAsyncIterable(source)) {
return (async function * () {
for await (const thing of source) {
Expand Down
4 changes: 2 additions & 2 deletions packages/it-last/src/index.ts
Expand Up @@ -7,8 +7,8 @@ function isAsyncIterable <T> (thing: any): thing is AsyncIterable<T> {
* return `undefined`
*/
function last <T> (source: Iterable<T>): T | undefined
function last <T> (source: AsyncIterable<T>): Promise<T | undefined>
function last <T> (source: AsyncIterable<T> | Iterable<T>): Promise<T | undefined> | T | undefined {
function last <T> (source: Iterable<T> | AsyncIterable<T>): Promise<T | undefined>
function last <T> (source: Iterable<T> | AsyncIterable<T>): Promise<T | undefined> | T | undefined {
if (isAsyncIterable(source)) {
return (async () => {
let res
Expand Down
4 changes: 2 additions & 2 deletions packages/it-length/src/index.ts
Expand Up @@ -6,8 +6,8 @@ function isAsyncIterable <T> (thing: any): thing is AsyncIterable<T> {
* Consumes the passed iterator and returns the number of items it contained
*/
function length (source: Iterable<unknown>): number
function length (source: AsyncIterable<unknown>): Promise<number>
function length (source: AsyncIterable<unknown> | Iterable<unknown>): Promise<number> | number {
function length (source: Iterable<unknown> | AsyncIterable<unknown>): Promise<number>
function length (source: Iterable<unknown> | AsyncIterable<unknown>): Promise<number> | number {
if (isAsyncIterable(source)) {
return (async () => {
let count = 0
Expand Down
2 changes: 1 addition & 1 deletion packages/it-map/src/index.ts
Expand Up @@ -10,7 +10,7 @@ function isAsyncIterable <T> (thing: any): thing is AsyncIterable<T> {
*/
function map <I, O> (source: Iterable<I>, func: (val: I) => Promise<O>): AsyncGenerator<O, void, undefined>
function map <I, O> (source: Iterable<I>, func: (val: I) => O): Generator<O, void, undefined>
function map <I, O> (source: AsyncIterable<I>, func: (val: I) => O | Promise<O>): AsyncGenerator<O, void, undefined>
function map <I, O> (source: AsyncIterable<I> | Iterable<I>, func: (val: I) => O | Promise<O>): AsyncGenerator<O, void, undefined>
function map <I, O> (source: AsyncIterable<I> | Iterable<I>, func: (val: I) => O | Promise<O>): AsyncGenerator<O, void, undefined> | Generator<O, void, undefined> {
if (isAsyncIterable(source)) {
return (async function * () {
Expand Down
41 changes: 23 additions & 18 deletions packages/it-map/test/index.spec.ts
@@ -1,13 +1,21 @@
import { expect } from 'aegir/chai'
import map from '../src/index.js'

async function * asyncGenerator (): AsyncGenerator<number> {
yield 1
}

function * generator (): Generator<number> {
yield 1
}

async function * source (): Generator<number> | AsyncGenerator<number> {
yield 1
}

describe('it-map', () => {
it('should map an async iterator', async () => {
const iter = async function * (): AsyncGenerator<number> {
yield 1
}

const gen = map(iter(), (val) => val + 1)
const gen = map(asyncGenerator(), (val) => val + 1)
expect(gen[Symbol.asyncIterator]).to.be.ok()

for await (const result of gen) {
Expand All @@ -16,11 +24,7 @@ describe('it-map', () => {
})

it('should map an async iterator to a promise', async () => {
const iter = async function * (): AsyncGenerator<number, void, unknown> {
yield 1
}

const gen = map(iter(), async (val) => val + 1)
const gen = map(asyncGenerator(), async (val) => val + 1)
expect(gen[Symbol.asyncIterator]).to.be.ok()

for await (const result of gen) {
Expand All @@ -29,11 +33,7 @@ describe('it-map', () => {
})

it('should map an iterator', () => {
const iter = function * (): Generator<number> {
yield 1
}

const gen = map(iter(), (val) => val + 1)
const gen = map(generator(), (val) => val + 1)
expect(gen[Symbol.iterator]).to.be.ok()

for (const result of gen) {
Expand All @@ -42,11 +42,16 @@ describe('it-map', () => {
})

it('should map an iterator to a promise', async () => {
const iter = function * (): Generator<number> {
yield 1
const gen = map(generator(), async (val) => val + 1)
expect(gen[Symbol.asyncIterator]).to.be.ok()

for await (const result of gen) {
expect(result).to.equal(2)
}
})

const gen = map(iter(), async (val) => val + 1)
it('should map a source', async () => {
const gen = map(source(), (val) => val + 1)
expect(gen[Symbol.asyncIterator]).to.be.ok()

for await (const result of gen) {
Expand Down
4 changes: 2 additions & 2 deletions packages/it-reduce/src/index.ts
Expand Up @@ -6,8 +6,8 @@ function isAsyncIterable <T> (thing: any): thing is AsyncIterable<T> {
* Reduces the values yielded by an (async) iterable
*/
function reduce <T, V> (source: Iterable<T>, func: (acc: V, curr: T) => V, init: V): V
function reduce <T, V> (source: AsyncIterable<T>, func: (acc: V, curr: T) => V, init: V): Promise<V>
function reduce <T, V> (source: AsyncIterable<T> | Iterable<T>, func: (acc: V, curr: T) => V, init: V): Promise<V> | V {
function reduce <T, V> (source: Iterable<T> | AsyncIterable<T>, func: (acc: V, curr: T) => V, init: V): Promise<V>
function reduce <T, V> (source: Iterable<T> | AsyncIterable<T>, func: (acc: V, curr: T) => V, init: V): Promise<V> | V {
if (isAsyncIterable(source)) {
return (async function () {
for await (const val of source) {
Expand Down
4 changes: 2 additions & 2 deletions packages/it-skip/src/index.ts
Expand Up @@ -6,8 +6,8 @@ function isAsyncIterable <T> (thing: any): thing is AsyncIterable<T> {
* Skip items from an iterable
*/
function skip <T> (source: Iterable<T>, offset: number): Generator<T, void, undefined>
function skip <T> (source: AsyncIterable<T>, offset: number): AsyncGenerator<T, void, undefined>
function skip <T> (source: AsyncIterable<T> | Iterable<T>, offset: number): AsyncGenerator<T, void, undefined> | Generator<T, void, undefined> {
function skip <T> (source: Iterable<T> | AsyncIterable<T>, offset: number): AsyncGenerator<T, void, undefined>
function skip <T> (source: Iterable<T> | AsyncIterable<T>, offset: number): AsyncGenerator<T, void, undefined> | Generator<T, void, undefined> {
if (isAsyncIterable(source)) {
return (async function * () {
for await (const entry of source) {
Expand Down
4 changes: 2 additions & 2 deletions packages/it-sort/src/index.ts
Expand Up @@ -13,8 +13,8 @@ export interface CompareFunction<T> {
* using the passed function and yields them
*/
function sort <T> (source: Iterable<T>, sorter: CompareFunction<T>): Generator<T, void, undefined>
function sort <T> (source: AsyncIterable<T>, sorter: CompareFunction<T>): AsyncGenerator<T, void, undefined>
function sort <T> (source: AsyncIterable<T> | Iterable<T>, sorter: CompareFunction<T>): AsyncGenerator<T, void, undefined> | Generator<T, void, undefined> {
function sort <T> (source: Iterable<T> | AsyncIterable<T>, sorter: CompareFunction<T>): AsyncGenerator<T, void, undefined>
function sort <T> (source: Iterable<T> | AsyncIterable<T>, sorter: CompareFunction<T>): AsyncGenerator<T, void, undefined> | Generator<T, void, undefined> {
if (isAsyncIterable(source)) {
return (async function * () {
const arr = await all(source)
Expand Down
4 changes: 2 additions & 2 deletions packages/it-split/src/index.ts
Expand Up @@ -12,8 +12,8 @@ function isAsyncIterable <T> (thing: any): thing is AsyncIterable<T> {
* Splits Uint8Arrays emitted by an (async) iterable by a delimiter
*/
function split (source: Iterable<Uint8Array>, options?: SplitOptions): Generator<Uint8Array, void, undefined>
function split (source: AsyncIterable<Uint8Array>, options?: SplitOptions): AsyncGenerator<Uint8Array, void, undefined>
function split (source: AsyncIterable<Uint8Array> | Iterable<Uint8Array>, options: SplitOptions = {}): AsyncGenerator<Uint8Array, void, undefined> | Generator<Uint8Array, void, undefined> {
function split (source: Iterable<Uint8Array> | AsyncIterable<Uint8Array>, options?: SplitOptions): AsyncGenerator<Uint8Array, void, undefined>
function split (source: Iterable<Uint8Array> | AsyncIterable<Uint8Array>, options: SplitOptions = {}): AsyncGenerator<Uint8Array, void, undefined> | Generator<Uint8Array, void, undefined> {
const bl = new Uint8ArrayList()
const delimiter = options.delimiter ?? new TextEncoder().encode('\n')

Expand Down
4 changes: 2 additions & 2 deletions packages/it-take/src/index.ts
Expand Up @@ -6,8 +6,8 @@ function isAsyncIterable <T> (thing: any): thing is AsyncIterable<T> {
* Stop iteration after n items have been received
*/
function take <T> (source: Iterable<T>, limit: number): Generator<T, void, undefined>
function take <T> (source: AsyncIterable<T>, limit: number): AsyncGenerator<T, void, undefined>
function take <T> (source: AsyncIterable<T> | Iterable<T>, limit: number): AsyncGenerator<T, void, undefined> | Generator<T, void, undefined> {
function take <T> (source: Iterable<T> | AsyncIterable<T>, limit: number): AsyncGenerator<T, void, undefined>
function take <T> (source: Iterable<T> | AsyncIterable<T>, limit: number): AsyncGenerator<T, void, undefined> | Generator<T, void, undefined> {
if (isAsyncIterable(source)) {
return (async function * () {
let items = 0
Expand Down
4 changes: 2 additions & 2 deletions packages/it-to-buffer/src/index.ts
Expand Up @@ -9,8 +9,8 @@ function isAsyncIterable <T> (thing: any): thing is AsyncIterable<T> {
* into one buffer
*/
function toBuffer (source: Iterable<Uint8Array>): Uint8Array
function toBuffer (source: AsyncIterable<Uint8Array>): Promise<Uint8Array>
function toBuffer (source: AsyncIterable<Uint8Array> | Iterable<Uint8Array>): Promise<Uint8Array> | Uint8Array {
function toBuffer (source: Iterable<Uint8Array> | AsyncIterable<Uint8Array>): Promise<Uint8Array>
function toBuffer (source: Iterable<Uint8Array> | AsyncIterable<Uint8Array>): Promise<Uint8Array> | Uint8Array {
if (isAsyncIterable(source)) {
return (async () => {
let buffer = new Uint8Array(0)
Expand Down

0 comments on commit 80ec2ac

Please sign in to comment.