@xlink-network/xlink-sdk
Version:
191 lines (173 loc) • 5.21 kB
text/typescript
import { OneOrMore } from "./typeHelpers"
export function hasAny<T>(ary: T[]): ary is [T, ...T[]]
export function hasAny<T>(ary: readonly T[]): ary is readonly [T, ...T[]]
export function hasAny<T>(ary: readonly T[]): ary is readonly [T, ...T[]] {
return ary.length > 0
}
export function hasLength<T>(input: readonly T[], length: 0): input is []
export function hasLength<T>(input: readonly T[], length: 1): input is [T]
export function hasLength<T>(input: readonly T[], length: 2): input is [T, T]
export function hasLength<T>(input: readonly T[], length: 3): input is [T, T, T]
export function hasLength<T>(
input: readonly T[],
length: 4,
): input is [T, T, T, T]
export function hasLength<T>(
input: readonly T[],
length: 5,
): input is [T, T, T, T, T]
export function hasLength<T>(
input: readonly T[],
length: number,
): input is OneOrMore<T> {
return input.length === length
}
export function first<T>(ary: readonly [T, ...T[]]): T
export function first<T>(ary: readonly [...T[], T]): T
export function first<T>(ary: readonly T[]): undefined | T
export function first<T>(ary: readonly T[]): undefined | T {
return ary[0]
}
export function last<T>(ary: readonly [T, ...T[]]): T
export function last<T>(ary: readonly [...T[], T]): T
export function last<T>(ary: readonly T[]): undefined | T
export function last<T>(ary: readonly T[]): undefined | T {
return ary[ary.length - 1]
}
const _concat = [].concat
export function concat<Ts extends any[]>(
...inputArrays: Ts[]
): Ts[number] extends (infer U)[] ? U[] : never {
return _concat.apply([], inputArrays as any) as any
}
const _reduce = [].reduce
export function reduce<Ts extends readonly any[], U>(
fn: (acc: U, item: Ts[number], index: number, items: Ts) => U,
initialValue: U,
inputArray: Ts,
): U {
return _reduce.call(inputArray, fn as any, initialValue) as any
}
export function range(start: number, end: number): number[] {
return Array.from({ length: end - start }, (_, i) => i + start)
}
export function reverse<T>(ary: T[]): T[] {
const newAry = [...ary]
newAry.reverse()
return newAry
}
export function uniq<T>(
ary: T[],
iteratee: (item: T) => any = item => item,
): T[] {
const seen = new Set<any>()
return ary.filter(item => {
const key = iteratee(item)
if (seen.has(key)) {
return false
}
seen.add(key)
return true
})
}
export function oneOf<T extends string[]>(
...coll: T
): (input: unknown) => input is T[number]
export function oneOf<T extends any[]>(
...coll: T
): (input: unknown) => input is T[number]
export function oneOf<T extends any[]>(
...coll: T
): (input: unknown) => input is T[number] {
return ((input: unknown) => coll.includes(input)) as any
}
export type SortByIteratee<T> = (
item: T,
index: number,
ary: T[],
) => number | bigint
/**
* https://github.com/jashkenas/underscore/blob/1abc36c169947c54c97e266513b1d763d0198f46/modules/sortBy.js
*/
export function sortBy<T>(
iteratee: SortByIteratee<T> | SortByIteratee<T>[],
ary: T[],
): T[] {
const _iteratee = Array.isArray(iteratee) ? iteratee : [iteratee]
return ary
.map((value, index, ary) => ({
value: value,
index: index,
criteria: _iteratee.map(f => f(value, index, ary)),
}))
.sort((left, right) => compareMultiple(left, right))
.map(v => v.value)
}
interface CompareMultipleItem<T> {
value: T
index: number
criteria: (number | bigint)[]
}
/**
* https://github.com/lodash/lodash/blob/4.17.15/lodash.js#L4632-L4657
*/
function compareMultiple<T>(
obj: CompareMultipleItem<T>,
oth: CompareMultipleItem<T>,
): number {
const objCriteria = obj.criteria
const othCriteria = oth.criteria
const length = objCriteria.length
let index = -1
while (++index < length) {
const objCri = objCriteria[index]
const othCri = othCriteria[index]
let result = 0
if (typeof objCri === typeof othCri) {
result = Number((objCri as bigint) - (othCri as bigint))
} else {
result = Number(objCri) - Number(othCri)
}
if (result) return result
}
return obj.index - oth.index
}
export interface CurriedMapFindFn {
<T, U>(fn: (input: T) => U | undefined, input: readonly T[]): U | undefined
<T, U>(
fn: (input: T) => U | undefined,
): (input: readonly T[]) => U | undefined
}
export const mapFind: CurriedMapFindFn = (<T, U>(
fn: (input: T) => U | undefined,
input: readonly T[],
): U | undefined => {
for (const item of input) {
const result = fn(item)
if (result != null) {
return result
}
}
return undefined
}) as any
export interface CurriedMapFindPFn {
<T, U>(
fn: (input: T) => Promise<U | undefined> | U | undefined,
input: readonly T[],
): Promise<U | undefined>
<T, U>(
fn: (input: T) => Promise<U | undefined> | U | undefined,
): (input: readonly T[]) => Promise<U | undefined>
}
export const mapFindP: CurriedMapFindPFn = (async <T, U>(
fn: (input: T) => Promise<U | undefined> | U | undefined,
input: readonly T[],
): Promise<U | undefined> => {
for (const item of input) {
const result = await fn(item)
if (result != null) {
return result
}
}
return undefined
}) as any