import type { MaybePromise } from "https://esm.town/v/postpostscript/typeUtils";
export type AsyncReducer<U, T> =
| ((acc: T, next: T, index: number, values: T[]) => MaybePromise<T>)
| ((acc: T, next: T, index: number, values: T[]) => MaybePromise<T>)
| ((acc: U, next: T, index: number, values: T[]) => MaybePromise<U>);
export async function reduceAsync<U, T>(
values: T[],
reducer: (acc: T, next: T, index: number, values: T[]) => MaybePromise<T>,
): Promise<T>;
export async function reduceAsync<U, T>(
values: T[],
reducer: (acc: T, next: T, index: number, values: T[]) => MaybePromise<T>,
initialValue: T,
): Promise<T>;
export async function reduceAsync<U, T>(
values: T[],
reducer: (acc: U, next: T, index: number, values: T[]) => MaybePromise<U>,
initialValue: U,
): Promise<U>;
export async function reduceAsync<U, T>(
values: T[],
reducer: AsyncReducer<U, T>,
initial?: T | U,
) {
const hasInitial = arguments.length > 2 ? 1 : 0;
if (!hasInitial && !values.length) {
throw new Error("reduceAsync needs at least one values element or an initial value");
}
const acc = hasInitial ? initial : values[0];
let accPromise = acc instanceof Promise
? acc
: (async () => acc)();
let i = hasInitial ? 0 : 1;
for (i = 0; i < values.length; i++) {
const index = i;
accPromise = accPromise.then(acc => reducer(acc, values[index], index, values));
}
return accPromise;
}