Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: pass index to callback functions #124

Merged
merged 2 commits into from
Apr 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 13 additions & 11 deletions packages/it-filter/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
* // This can also be an iterator, generator, etc
* const values = [0, 1, 2, 3, 4]
*
* const fn = val => val > 2 // Return boolean to keep item
* const fn = (val, index) => val > 2 // Return boolean to keep item
*
* const arr = all(filter(values, fn))
*
Expand All @@ -29,7 +29,7 @@
* yield * [0, 1, 2, 3, 4]
* }
*
* const fn = async val => val > 2 // Return boolean or promise of boolean to keep item
* const fn = async val => (val, index) > 2 // Return boolean or promise of boolean to keep item
*
* const arr = await all(filter(values, fn))
*
Expand All @@ -46,14 +46,16 @@ function isAsyncIterable <T> (thing: any): thing is AsyncIterable<T> {
/**
* Filters the passed (async) iterable by using the filter function
*/
function filter <T> (source: Iterable<T>, fn: (val: T) => Promise<boolean>): AsyncGenerator<T, void, undefined>
function filter <T> (source: Iterable<T>, fn: (val: T) => boolean): Generator<T, void, undefined>
function filter <T> (source: Iterable<T> | AsyncIterable<T>, fn: (val: T) => boolean | Promise<boolean>): AsyncGenerator<T, void, undefined>
function filter <T> (source: Iterable<T> | AsyncIterable<T>, fn: (val: T) => boolean | Promise<boolean>): Generator<T, void, undefined> | AsyncGenerator<T, void, undefined> {
function filter <T> (source: Iterable<T>, fn: (val: T, index: number) => Promise<boolean>): AsyncGenerator<T, void, undefined>
function filter <T> (source: Iterable<T>, fn: (val: T, index: number) => boolean): Generator<T, void, undefined>
function filter <T> (source: Iterable<T> | AsyncIterable<T>, fn: (val: T, index: number) => boolean | Promise<boolean>): AsyncGenerator<T, void, undefined>
function filter <T> (source: Iterable<T> | AsyncIterable<T>, fn: (val: T, index: number) => boolean | Promise<boolean>): Generator<T, void, undefined> | AsyncGenerator<T, void, undefined> {
let index = 0

if (isAsyncIterable(source)) {
return (async function * () {
for await (const entry of source) {
if (await fn(entry)) {
if (await fn(entry, index++)) {
yield entry
}
}
Expand All @@ -68,7 +70,7 @@ function filter <T> (source: Iterable<T> | AsyncIterable<T>, fn: (val: T) => boo
return (function * () {}())
}

const res = fn(value)
const res = fn(value, index++)

// @ts-expect-error .then is not present on O
if (typeof res.then === 'function') {
Expand All @@ -78,22 +80,22 @@ function filter <T> (source: Iterable<T> | AsyncIterable<T>, fn: (val: T) => boo
}

for await (const entry of peekable) {
if (await fn(entry)) {
if (await fn(entry, index++)) {
yield entry
}
}
})()
}

const func = fn as (val: T) => boolean
const func = fn as (val: T, index: number) => boolean

return (function * () {
if (res === true) {
yield value
}

for (const entry of peekable) {
if (func(entry)) {
if (func(entry, index++)) {
yield entry
}
}
Expand Down
46 changes: 42 additions & 4 deletions packages/it-filter/test/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import { expect } from 'aegir/chai'
import all from 'it-all'
import filter from '../src/index.js'

function * values (): Generator<number, void, undefined> {
yield * [0, 1, 2, 3, 4]
function * values (vals: number[] = [0, 1, 2, 3, 4]): Generator<number, void, undefined> {
yield * vals
}

async function * asyncValues (): AsyncGenerator<number, void, undefined> {
yield * values()
async function * asyncValues (vals: number[] = [0, 1, 2, 3, 4]): AsyncGenerator<number, void, undefined> {
yield * values(vals)
}

describe('it-filter', () => {
Expand Down Expand Up @@ -52,4 +52,42 @@ describe('it-filter', () => {
expect(res[Symbol.asyncIterator]).to.be.ok()
await expect(all(res)).to.eventually.deep.equal([3, 4])
})

it('should filter values with indexes', async () => {
const vals = [4, 3, 2, 1, 0]
const callbackArgs: any[] = []
const gen = filter(values(vals), (...args: any[]) => {
callbackArgs.push(args)
return true
})
expect(gen[Symbol.iterator]).to.be.ok()

const results = all(gen)
expect(results).to.have.lengthOf(vals.length)
expect(callbackArgs).to.have.lengthOf(vals.length)

vals.forEach((value, index) => {
expect(callbackArgs).to.have.nested.property(`[${index}][0]`, value)
expect(callbackArgs).to.have.nested.property(`[${index}][1]`, index)
})
})

it('should filter async values with indexes', async () => {
const vals = [4, 3, 2, 1, 0]
const callbackArgs: any[] = []
const gen = filter(asyncValues(vals), (...args: any[]) => {
callbackArgs.push(args)
return true
})
expect(gen[Symbol.asyncIterator]).to.be.ok()

const results = await all(gen)
expect(results).to.have.lengthOf(vals.length)
expect(callbackArgs).to.have.lengthOf(vals.length)

vals.forEach((value, index) => {
expect(callbackArgs).to.have.nested.property(`[${index}][0]`, value)
expect(callbackArgs).to.have.nested.property(`[${index}][1]`, index)
})
})
})
24 changes: 13 additions & 11 deletions packages/it-foreach/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
* // This can also be an iterator, generator, etc
* const values = [0, 1, 2, 3, 4]
*
* // prints 0, 1, 2, 3, 4
* // prints [0, 0], [1, 1], [2, 2], [3, 3], [4, 4]
* const arr = drain(
* each(values, console.info)
* )
Expand All @@ -32,7 +32,7 @@
* yield * [0, 1, 2, 3, 4]
* }
*
* // prints 0, 1, 2, 3, 4
* // prints [0, 0], [1, 1], [2, 2], [3, 3], [4, 4]
* const arr = await drain(
* each(values(), console.info)
* )
Expand All @@ -52,14 +52,16 @@ function isPromise <T = unknown> (thing: any): thing is Promise<T> {
/**
* Invokes the passed function for each item in an iterable
*/
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: 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> {
function forEach <T> (source: Iterable<T>, fn: (thing: T, index: number) => Promise<void>): AsyncGenerator<T, void, undefined>
function forEach <T> (source: Iterable<T>, fn: (thing: T, index: number) => void): Generator<T, void, undefined>
function forEach <T> (source: Iterable<T> | AsyncIterable<T>, fn: (thing: T, index: number) => void | Promise<void>): AsyncGenerator<T, void, undefined>
function forEach <T> (source: Iterable<T> | AsyncIterable<T>, fn: (thing: T, index: number) => void | Promise<void>): AsyncGenerator<T, void, undefined> | Generator<T, void, undefined> {
let index = 0

if (isAsyncIterable(source)) {
return (async function * () {
for await (const val of source) {
const res = fn(val)
const res = fn(val, index++)

if (isPromise(res)) {
await res
Expand All @@ -78,14 +80,14 @@ function forEach <T> (source: Iterable<T> | AsyncIterable<T>, fn: (thing: T) =>
return (function * () {}())
}

const res = fn(value)
const res = fn(value, index++)

if (typeof res?.then === 'function') {
return (async function * () {
yield value

for await (const val of peekable) {
const res = fn(val)
const res = fn(val, index++)

if (isPromise(res)) {
await res
Expand All @@ -96,13 +98,13 @@ function forEach <T> (source: Iterable<T> | AsyncIterable<T>, fn: (thing: T) =>
})()
}

const func = fn as (val: T) => void
const func = fn as (val: T, index: number) => void

return (function * () {
yield value

for (const val of peekable) {
func(val)
func(val, index++)
yield val
}
})()
Expand Down
93 changes: 75 additions & 18 deletions packages/it-foreach/test/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,82 +2,85 @@ import { expect } from 'aegir/chai'
import all from 'it-all'
import forEach from '../src/index.js'

function * values (vals: number[] = [0, 1, 2, 3, 4]): Generator<number, void, undefined> {
yield * vals
}

async function * asyncValues (vals: number[] = [0, 1, 2, 3, 4]): AsyncGenerator<number, void, undefined> {
yield * values(vals)
}

describe('it-for-each', () => {
it('should iterate over every value', () => {
const values = [0, 1, 2, 3, 4]
const vals = [0, 1, 2, 3, 4]
let sum = 0

const gen = forEach(values, (val) => {
const gen = forEach(values(vals), (val) => {
sum += val
})

expect(gen[Symbol.iterator]).to.be.ok()

const res = all(gen)

expect(res).to.deep.equal(values)
expect(res).to.deep.equal(vals)
expect(10).to.equal(sum)
})

it('should iterate over every async value', async () => {
const values = async function * (): AsyncGenerator<number, void, undefined> {
yield * [0, 1, 2, 3, 4]
}
const vals = [0, 1, 2, 3, 4]
let sum = 0

const gen = forEach(values(), (val) => {
const gen = forEach(asyncValues(vals), (val) => {
sum += val
})

expect(gen[Symbol.asyncIterator]).to.be.ok()

const res = await all(gen)

expect(res).to.deep.equal(await all(values()))
expect(res).to.deep.equal(vals)
expect(10).to.equal(sum)
})

it('should iterate over every value asyncly', async () => {
const values = [0, 1, 2, 3, 4]
const vals = [0, 1, 2, 3, 4]
let sum = 0

const gen = forEach(values, async (val) => {
const gen = forEach(values(), async (val) => {
sum += val
})

expect(gen[Symbol.asyncIterator]).to.be.ok()

const res = await all(gen)

expect(res).to.deep.equal(values)
expect(res).to.deep.equal(vals)
expect(10).to.equal(sum)
})

it('should iterate over every async value asyncly', async () => {
const values = async function * (): AsyncGenerator<number, void, undefined> {
yield * [0, 1, 2, 3, 4]
}
const vals = [0, 1, 2, 3, 4]
let sum = 0

const gen = forEach(values(), async (val) => {
const gen = forEach(asyncValues(), async (val) => {
sum += val
})

expect(gen[Symbol.asyncIterator]).to.be.ok()

const res = await all(gen)

expect(res).to.deep.equal(await all(values()))
expect(res).to.deep.equal(vals)
expect(10).to.equal(sum)
})

it('should abort source', () => {
const values = [0, 1, 2, 3, 4]
let sum = 0
const err = new Error('wat')

try {
all(forEach(values, (val) => {
all(forEach(values(), (val) => {
sum += val

if (val === 3) {
Expand All @@ -91,4 +94,58 @@ describe('it-for-each', () => {
expect(sum).to.equal(6)
}
})

it('should iterate over values with indexes', async () => {
const vals = [4, 3, 2, 1, 0]
const callbackArgs: any[] = []
const gen = forEach(values(vals), (...args: [number]) => {
callbackArgs.push(args)
})
expect(gen[Symbol.iterator]).to.be.ok()

const results = all(gen)
expect(results).to.have.lengthOf(vals.length)
expect(callbackArgs).to.have.lengthOf(vals.length)

vals.forEach((value, index) => {
expect(callbackArgs).to.have.nested.property(`[${index}][0]`, value)
expect(callbackArgs).to.have.nested.property(`[${index}][1]`, index)
})
})

it('should iterate over async values with indexes', async () => {
const vals = [4, 3, 2, 1, 0]
const callbackArgs: any[] = []
const gen = forEach(asyncValues(vals), (...args: any[]) => {
callbackArgs.push(args)
})
expect(gen[Symbol.asyncIterator]).to.be.ok()

const results = await all(gen)
expect(results).to.have.lengthOf(vals.length)
expect(callbackArgs).to.have.lengthOf(vals.length)

vals.forEach((value, index) => {
expect(callbackArgs).to.have.nested.property(`[${index}][0]`, value)
expect(callbackArgs).to.have.nested.property(`[${index}][1]`, index)
})
})

it('should iterate over async values with indexes asyncly', async () => {
const vals = [4, 3, 2, 1, 0]
const callbackArgs: any[] = []
const gen = forEach(asyncValues(vals), async (...args: any[]) => {
callbackArgs.push(args)
})
expect(gen[Symbol.asyncIterator]).to.be.ok()

const results = await all(gen)
expect(results).to.have.lengthOf(vals.length)
expect(callbackArgs).to.have.lengthOf(vals.length)

vals.forEach((value, index) => {
expect(callbackArgs).to.have.nested.property(`[${index}][0]`, value)
expect(callbackArgs).to.have.nested.property(`[${index}][1]`, index)
})
})
})
Loading
Loading