@applicaster/zapp-react-native-utils
Version:
Applicaster Zapp React Native utilities package
114 lines (96 loc) • 3.5 kB
text/typescript
/* eslint-disable unused-imports/no-unused-vars */
import * as R from "ramda";
import { invariant } from "@applicaster/zapp-react-native-utils/errorUtils";
/**
* shifts an array by the given offset. a negative offset will take items
* from the end of the array and add them at the beginning, while a positive offset
* will take an item at the beginning and shift it to the end
* shiftArray(-1, [1,2,3,4]) => [4, 1, 2, 3]
* shiftArray(1, [1,2,3,4]) => [2, 3, 4, 1]
* an offset of 0 leaves the array unchanged
* this function returns a new array and doesn't mutate the original one
* curried function which can be invoked like offset => array => result
* @param {Number} offset offset to shift the array
* @param {Array<T>} array array to shift
* @returns {Array<T>}
*/
export const shiftArray = R.curry(
<T extends unknown>(offset: number, array: T[]): T[] => {
return R.concat(
R.slice(offset, R.length(array), array),
R.slice(0, offset, array)
);
}
);
/**
* Tries to remove an item from an array, and returns the array if the item is not found
* @param {any} item to remove
* @param {Array<any>} list to remove the item from
* @returns {Array<any>}
*/
export function removeItemFromList<T extends unknown>(item: T, list: T[]): T[] {
return R.compose(
R.ifElse(R.equals(-1), R.always(list), R.remove(R.__, 1, list)),
R.indexOf(item)
)(list);
}
export const mapPromises = R.curry(
<T extends unknown, S extends unknown>(
fn: (value: T, index?: number) => Promise<S>,
values: T[]
): Promise<S[]> => Promise.all(R.addIndex(R.map)(R.nAry(2, fn), values))
);
const waitForPromiseAndRun = R.curryN(
3,
async <T extends unknown, S extends unknown>(
fn: (currentValue: T, previousValue: S, index?: number) => Promise<S>,
previousPromise: Promise<S>,
currentValue: T,
index: number
) => {
const previousValue = await previousPromise;
return fn(currentValue, previousValue, index);
}
);
export const reducePromises = R.curry(
<T extends unknown, S extends unknown>(
fn: (current: T, previous: S, index?: number) => Promise<S>,
initialValue: S,
values: T[]
): Promise<S> =>
R.addIndex(R.reduce)(
waitForPromiseAndRun<T, S>(fn),
Promise.resolve(initialValue),
values
)
);
export const mapAndSplit = R.curry(
<T extends unknown, S extends unknown>(
mapperFn: (T) => S,
chunks: number
): S[][] => R.compose(R.splitEvery(chunks), R.map(mapperFn))
);
export const isLast = (index: number, length: number): boolean =>
index >= length - 1;
export const isFirst = (index: number): boolean => index <= 0;
export const isIndexInRange = (index: number, length: number): boolean => {
if (length <= 0) return false;
if (index < 0) return false;
return index + 1 <= length;
};
export const makeListOfIndexes = (size: number): number[] =>
Array.from({ length: size }, (_, index) => index);
export const makeListOf = (value: unknown, size: number): number[] => {
return Array(size).fill(value);
};
/** Checks if a value is a non-empty array */
export function isFilledArray(value: unknown): boolean {
return R.is(Array, value) && R.length(value) > 0;
}
// get random item from the list
export const sample = (xs: unknown[]): unknown => {
invariant(R.is(Array, xs), `input value is not a array: ${xs}`);
invariant(isFilledArray(xs), `input array is empty: ${xs}`);
const index = Math.floor(Math.random() * xs.length);
return xs[index];
};