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: add async iterator utilities #844

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
6 changes: 1 addition & 5 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
{
"files.eol": "\n",
"sonarlint.connectedMode.project": {
"connectionId": "sapphiredev",
"projectKey": "sapphiredev_utilities"
}
"files.eol": "\n"
}
254 changes: 169 additions & 85 deletions packages/iterator-utilities/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,88 +1,172 @@
export * from './lib/all';
export * from './lib/any';
export * from './lib/append';
export * from './lib/at';
export * from './lib/average';
export * from './lib/chain';
export * from './lib/chunk';
export * from './lib/collect';
export * from './lib/collectInto';
export * from './lib/compact';
export * from './lib/compare';
export * from './lib/compareBy';
export * from './lib/compress';
export * from './lib/contains';
export * from './lib/count';
export * from './lib/cycle';
export * from './lib/difference';
export * from './lib/drop';
export * from './lib/dropLast';
export * from './lib/dropWhile';
export * from './lib/empty';
export * from './lib/enumerate';
export * from './lib/equal';
export * from './lib/equalBy';
export * from './lib/every';
export * from './lib/filter';
export * from './lib/find';
export * from './lib/findIndex';
export * from './lib/first';
export * from './lib/flat';
export * from './lib/flatMap';
export * from './lib/forEach';
export * from './lib/from';
export * from './lib/fuse';
export * from './lib/greaterOrEqualThan';
export * from './lib/greaterThan';
export * from './lib/indexOf';
export * from './lib/inspect';
export * from './lib/intersect';
export * from './lib/intersperse';
export * from './lib/isEmpty';
export * from './lib/isSorted';
export * from './lib/isSortedBy';
export * from './lib/isSortedByKey';
export * from './lib/last';
export * from './lib/lessOrEqualThan';
export * from './lib/lessThan';
export * from './lib/map';
export * from './lib/max';
export * from './lib/maxBy';
export * from './lib/maxByKey';
export * from './lib/min';
export * from './lib/minBy';
export * from './lib/minByKey';
export * from './lib/notEqual';
export * from './lib/nth';
export * from './lib/partition';
export * from './lib/peekable';
export * from './lib/position';
export * from './lib/prepend';
export * from './lib/product';
export * from './lib/range';
export * from './lib/reduce';
export * from './lib/repeat';
export * from './lib/reverse';
export * from './lib/async/all';
export * from './lib/async/any';
export * from './lib/async/append';
export * from './lib/async/at';
export * from './lib/async/average';
export * from './lib/async/chain';
export * from './lib/async/chunk';
export * from './lib/async/collect';
export * from './lib/async/collectInto';
export * from './lib/async/compact';
export * from './lib/async/compare';
export * from './lib/async/compareBy';
export * from './lib/async/compress';
export * from './lib/async/contains';
export * from './lib/async/count';
export * from './lib/async/cycle';
export * from './lib/async/difference';
export * from './lib/async/drop';
export * from './lib/async/dropLast';
export * from './lib/async/dropWhile';
export * from './lib/async/empty';
export * from './lib/async/enumerate';
export * from './lib/async/equal';
export * from './lib/async/equalBy';
export * from './lib/async/every';
export * from './lib/async/filter';
export * from './lib/async/find';
export * from './lib/async/findIndex';
export * from './lib/async/first';
export * from './lib/async/flat';
export * from './lib/async/flatMap';
export * from './lib/async/forEach';
export * from './lib/async/from';
export * from './lib/async/fuse';
export * from './lib/async/greaterOrEqualThan';
export * from './lib/async/greaterThan';
export * from './lib/async/indexOf';
export * from './lib/async/inspect';
export * from './lib/async/intersect';
export * from './lib/async/intersperse';
export * from './lib/async/isEmpty';
export * from './lib/async/isSorted';
export * from './lib/async/isSortedBy';
export * from './lib/async/isSortedByKey';
export * from './lib/async/last';
export * from './lib/async/lessOrEqualThan';
export * from './lib/async/lessThan';
export * from './lib/async/map';
export * from './lib/async/max';
export * from './lib/async/maxBy';
export * from './lib/async/maxByKey';
export * from './lib/async/min';
export * from './lib/async/minBy';
export * from './lib/async/minByKey';
export * from './lib/async/notEqual';
export * from './lib/async/nth';
export * from './lib/async/partition';
export * from './lib/async/peekable';
export * from './lib/async/position';
export * from './lib/async/prepend';
export * from './lib/async/product';
export * from './lib/async/reduce';
export * from './lib/async/reverse';
export * from './lib/async/skip';
export * from './lib/async/skipLast';
export * from './lib/async/skipWhile';
export * from './lib/async/slice';
export * from './lib/async/some';
export * from './lib/async/sorted';
export * from './lib/async/starMap';
export * from './lib/async/stepBy';
export * from './lib/async/sum';
export * from './lib/async/take';
export * from './lib/async/takeLast';
export * from './lib/async/takeWhile';
export * from './lib/async/tee';
export * from './lib/async/toArray';
export * from './lib/async/toIterableIterator';
export * from './lib/async/union';
export * from './lib/async/unique';
export * from './lib/async/unzip';
export * from './lib/async/windows';
export * from './lib/async/zip';
export type { LexicographicComparison, CompareByComparator } from './lib/shared/_compare';
export type { NumberResolvable } from './lib/shared/_toNumberOrThrow';
export type { Awaitable } from './lib/shared/_types';
export * from './lib/shared/comparators';
export * from './lib/skip';
export * from './lib/skipLast';
export * from './lib/skipWhile';
export * from './lib/slice';
export * from './lib/some';
export * from './lib/sorted';
export * from './lib/starMap';
export * from './lib/stepBy';
export * from './lib/sum';
export * from './lib/take';
export * from './lib/takeLast';
export * from './lib/takeWhile';
export * from './lib/tee';
export * from './lib/toArray';
export * from './lib/toIterableIterator';
export * from './lib/union';
export * from './lib/unique';
export * from './lib/unzip';
export * from './lib/windows';
export * from './lib/zip';
export * from './lib/sync/all';
export * from './lib/sync/any';
export * from './lib/sync/append';
export * from './lib/sync/at';
export * from './lib/sync/average';
export * from './lib/sync/chain';
export * from './lib/sync/chunk';
export * from './lib/sync/collect';
export * from './lib/sync/collectInto';
export * from './lib/sync/compact';
export * from './lib/sync/compare';
export * from './lib/sync/compareBy';
export * from './lib/sync/compress';
export * from './lib/sync/contains';
export * from './lib/sync/count';
export * from './lib/sync/cycle';
export * from './lib/sync/difference';
export * from './lib/sync/drop';
export * from './lib/sync/dropLast';
export * from './lib/sync/dropWhile';
export * from './lib/sync/empty';
export * from './lib/sync/enumerate';
export * from './lib/sync/equal';
export * from './lib/sync/equalBy';
export * from './lib/sync/every';
export * from './lib/sync/filter';
export * from './lib/sync/find';
export * from './lib/sync/findIndex';
export * from './lib/sync/first';
export * from './lib/sync/flat';
export * from './lib/sync/flatMap';
export * from './lib/sync/forEach';
export * from './lib/sync/from';
export * from './lib/sync/fuse';
export * from './lib/sync/greaterOrEqualThan';
export * from './lib/sync/greaterThan';
export * from './lib/sync/indexOf';
export * from './lib/sync/inspect';
export * from './lib/sync/intersect';
export * from './lib/sync/intersperse';
export * from './lib/sync/isEmpty';
export * from './lib/sync/isSorted';
export * from './lib/sync/isSortedBy';
export * from './lib/sync/isSortedByKey';
export * from './lib/sync/last';
export * from './lib/sync/lessOrEqualThan';
export * from './lib/sync/lessThan';
export * from './lib/sync/map';
export * from './lib/sync/max';
export * from './lib/sync/maxBy';
export * from './lib/sync/maxByKey';
export * from './lib/sync/min';
export * from './lib/sync/minBy';
export * from './lib/sync/minByKey';
export * from './lib/sync/notEqual';
export * from './lib/sync/nth';
export * from './lib/sync/partition';
export * from './lib/sync/peekable';
export * from './lib/sync/position';
export * from './lib/sync/prepend';
export * from './lib/sync/product';
export * from './lib/sync/range';
export * from './lib/sync/reduce';
export * from './lib/sync/repeat';
export * from './lib/sync/reverse';
export * from './lib/sync/skip';
export * from './lib/sync/skipLast';
export * from './lib/sync/skipWhile';
export * from './lib/sync/slice';
export * from './lib/sync/some';
export * from './lib/sync/sorted';
export * from './lib/sync/starMap';
export * from './lib/sync/stepBy';
export * from './lib/sync/sum';
export * from './lib/sync/take';
export * from './lib/sync/takeLast';
export * from './lib/sync/takeWhile';
export * from './lib/sync/tee';
export * from './lib/sync/toArray';
export * from './lib/sync/toIterableIterator';
export * from './lib/sync/union';
export * from './lib/sync/unique';
export * from './lib/sync/unzip';
export * from './lib/sync/windows';
export * from './lib/sync/zip';
1 change: 1 addition & 0 deletions packages/iterator-utilities/src/lib/async/all.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { everyAsync as allAsync } from './every';
1 change: 1 addition & 0 deletions packages/iterator-utilities/src/lib/async/any.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { someAsync as anyAsync } from './some';
30 changes: 30 additions & 0 deletions packages/iterator-utilities/src/lib/async/append.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { chainAsync } from './chain';
import type { AsyncIterableResolvable } from './from';
import type { prependAsync } from './prepend';

/**
* Appends iterables to the end of the first iterable, returning a new iterable combining all of them. It's similar to concatenating arrays or doing `[...a, ...b, ...c]`.
*
* @param iterable The iterator to append values to.
* @param iterables The iterables to append to the iterator.
* @returns An iterator that yields the values of the provided iterator followed by the values of the provided iterables.
*
* @example
* ```typescript
* import { appendAsync, collectAsync } from '@sapphire/iterator-utilities';
*
* const iterable = appendAsync([1, 2, 3], [4, 5, 6], [7, 8, 9]);
* console.log(await collectAsync(iterable));
* // Output: [1, 2, 3, 4, 5, 6, 7, 8, 9]
* ```
*
* @seealso {@link prependAsync} to append values to the end of an iterator.
*/
export function appendAsync<const ElementType>(
iterable: AsyncIterableResolvable<ElementType>,
...iterables: AsyncIterableResolvable<ElementType>[]
): AsyncIterableIterator<ElementType> {
return chainAsync(iterable, ...iterables);
}

export { appendAsync as concatAsync };
30 changes: 30 additions & 0 deletions packages/iterator-utilities/src/lib/async/at.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { assertNotNegative } from '../shared/_assertNotNegative';
import { toIntegerOrInfinityOrThrow } from '../shared/_toIntegerOrInfinityOrThrow';
import { dropAsync } from './drop';
import { firstAsync } from './first';
import type { AsyncIterableResolvable } from './from';

/**
* Advances the iterable to the `n`th element and returns it. If the iterable is exhausted before reaching the `n`th element, it returns `undefined`.
*
* @param iterable An iterator to return an element from.
* @param index The index of the element to retrieve.
* @returns The element at the specified index, or `undefined` if the index is out of range.
*
* @example
* ```typescript
* import { atAsync } from '@sapphire/iterator-utilities';
*
* const iterable = [1, 2, 3, 4, 5];
* console.log(await atAsync(iterable, 2));
* // Output: 3
* ```
*
* @remarks
*
* This function consumes the input iterator up to the specified index.
*/
export function atAsync<const ElementType>(iterable: AsyncIterableResolvable<ElementType>, index: number): Promise<ElementType | undefined> {
index = assertNotNegative(toIntegerOrInfinityOrThrow(index), index);
return firstAsync(index === 0 ? iterable : dropAsync(iterable, index));
}
33 changes: 33 additions & 0 deletions packages/iterator-utilities/src/lib/async/average.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { toNumberOrThrow, type NumberResolvable } from '../shared/_toNumberOrThrow';
import type { AsyncIterableResolvable } from './from';
import { mapAsync } from './map';

/**
* Consumes the iterable and returns the average value of all the elements. If the iterable is empty, it returns `null`.
*
* @param iterable The iterator to calculate the average of.
* @returns The average of the sequence of numbers, or `null` if the sequence is empty or contains only non-number values.
*
* @example
* ```typescript
* import { averageAsync } from '@sapphire/iterator-utilities';
*
* const iterable = [1, 2, 3, 4, 5];
* console.log(await averageAsync(iterable));
* // Output: 3
* ```
*
* @remarks
*
* This function consumes the entire iterator.
*/
export async function averageAsync(iterable: AsyncIterableResolvable<NumberResolvable>): Promise<number | null> {
let sum = 0;
let total = 0;
for await (const value of mapAsync(iterable, toNumberOrThrow)) {
sum += value;
total++;
}

return total === 0 ? null : sum / total;
}
25 changes: 25 additions & 0 deletions packages/iterator-utilities/src/lib/async/chain.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import type { AsyncIterableResolvable } from './from';
import { toAsyncIterableIterator } from './toIterableIterator';

/**
* Similar to `append`, but takes an iterable of iterables and chains them together.
*
* @param iterables The iterators to chain together.
* @returns An iterator that yields the values of the provided iterators in order.
*
* @example
* ```typescript
* import { chainAsync, collectAsync } from '@sapphire/iterator-utilities';
*
* const iterable = chainAsync([1, 2, 3], [4, 5, 6], [7, 8, 9]);
* console.log(await collectAsync(iterable));
* // Output: [1, 2, 3, 4, 5, 6, 7, 8, 9]
* ```
*/
export async function* chainAsync<const ElementType>(...iterables: AsyncIterableResolvable<ElementType>[]): AsyncIterableIterator<ElementType> {
for (const iterable of iterables) {
for await (const value of toAsyncIterableIterator(iterable)) {
yield value;
}
}
}
Loading
Loading