array/asyncArray.ts

import { ReduceArrayCallbackType, EachArrayCallbackType, filterArrayF, eachArrayF, takeArrayF } from "./array";
import { CheckPromiseIterableType, CheckPromiseReturnType, CheckIterableType} from "../types";
import { reduceArrayF, mapArrayF } from "./array";
import { exec, curry } from "../utils";

/**
 * @namespace asyncArray
 */
/**
 * @memberof asyncArray
 * @typedef
 */
export type ReduceAsyncArrayCallbackType<T, U extends any[]> =
  ReduceArrayCallbackType<T, CheckPromiseIterableType<U>, U>;

/**
 * @memberof asyncArray
 * @typedef
 */
export type EachAsyncArrayCallbackType<T extends any[], U> =
  EachArrayCallbackType<CheckPromiseIterableType<T>, U>;

/**
 * @memberof asyncArray
 * @typedef
 */
export type AsyncArrayReturnType<T extends any[], U> =
  CheckPromiseReturnType<CheckIterableType<T>, U>;

/**
 * @memberof asyncArray
 * @typedef
 */
export type PureArrayType<T extends any[]> =
  Array<CheckPromiseIterableType<T>>;

export function syncArray<T extends any[]>(arr: T):
  AsyncArrayReturnType<T, PureArrayType<T>>;
/**
 * @memberof asyncArray
 * @example
// [1, 2, 3, 4]
const arr1: number[] = syncArray([1, 2, 3, 4]);
// Promise => [1, 2, 3, 4]
const arr2: Promise<number[]> = syncArray([1, Promise.resolve(2), 3, 4]);
 */
export function syncArray<T extends any[]>(arr: T) {
  return takeArrayF(Infinity, arr);
}

/**
 * @memberof asyncArray
 */
export function reduceAsyncArrayF<T, U extends any[]>(
  callbackFn: ReduceAsyncArrayCallbackType<T, U>,
  initial: T,
  iterator: U,
): AsyncArrayReturnType<U, T>;
/**
 * @memberof asyncArray
 */
export function reduceAsyncArrayF<T, U extends any[]>(
  callbackFn: ReduceAsyncArrayCallbackType<T, U>,
  initial: T,
  arr: U): T | Promise<T> {
  return exec(arr2 => reduceArrayF(callbackFn, initial, arr2), syncArray(arr));
}

export type Curry2ReduceAsyncArrayType<T, U extends any[]> =
  (<R extends U>(initial: T, arr: R) => AsyncArrayReturnType<R, T>) &
  ((initial: T) => <R extends U>(arr: R) => AsyncArrayReturnType<R, T>);

/**
 * @memberof asyncArray
 * @function
 */
export const reduceAsyncArray:
(<T, U extends any[]>(
  callbackFn: ReduceAsyncArrayCallbackType<T, U>,
  ) => Curry2ReduceAsyncArrayType<T, U>) &
  (<T, U extends any[]>(
    callbackFn: ReduceAsyncArrayCallbackType<T, U>,
    initial: T,
    arr: U) => AsyncArrayReturnType<U, T>) =
  /*#__PURE__*/curry(reduceAsyncArrayF);
export function eachAsyncArrayF<T extends any[]>(
  callbackFn: EachAsyncArrayCallbackType<T, void>, arr: T):
  AsyncArrayReturnType<T, PureArrayType<T>>;

/**
 * @memberof asyncArray
 */
export function eachAsyncArrayF<T extends any[]>(
  callbackFn: EachAsyncArrayCallbackType<T, void>, arr: T) {
  return exec(arr2 => eachArrayF(callbackFn, arr2), syncArray(arr));
}

/**
 * @memberof asyncArray
 * @function
 */
export const eachAsyncArray:
  (<T extends any[]>(callbackFn: EachAsyncArrayCallbackType<T, void>) =>
    <U extends T>(arr: U) => AsyncArrayReturnType<U, PureArrayType<U>>) &
  (<T extends any[]>(callbackFn: EachAsyncArrayCallbackType<T, void>, arr: T) =>
    AsyncArrayReturnType<T, PureArrayType<T>>) =
  /*#__PURE__*/curry(eachAsyncArrayF);

export function mapAsyncArrayF<T extends any[], U>(
  callbackFn: EachAsyncArrayCallbackType<T, U>, arr: T):
  AsyncArrayReturnType<T, U[]>;
/**
 * @memberof asyncArray
 */
export function mapAsyncArrayF<T extends any[], U>(
  callbackFn: EachAsyncArrayCallbackType<T, U>, arr: T) {
  return exec(arr2 => mapArrayF(callbackFn, arr2), syncArray(arr));
}

/**
 * @memberof asyncArray
 * @function
 */
export const mapAsyncArray:
  (<T extends any[], U>(callbackFn: EachAsyncArrayCallbackType<T, U>) =>
    <A extends T, B extends U>(arr: A) => AsyncArrayReturnType<A, B[]>) &
  (<T extends any[], U>(callbackFn: EachAsyncArrayCallbackType<T, U>, arr: T) =>
  AsyncArrayReturnType<T, U[]>) =
  /*#__PURE__*/curry(mapAsyncArrayF);

export function filterAsyncArrayF<T extends any[]>(
  callbackFn: EachAsyncArrayCallbackType<T, boolean>, arr: T):
  AsyncArrayReturnType<T, Array<CheckPromiseIterableType<T>>>;
/**
 * @memberof asyncArray
 */
export function filterAsyncArrayF<T extends any[]>(
  callbackFn: EachAsyncArrayCallbackType<T, boolean>, arr: T) {
  return exec(arr2 => filterArrayF(callbackFn, arr2), syncArray(arr));
}