@prefecthq/prefect-ui-library
Version:
This library is the Vue and Typescript component library for [Prefect 2](https://github.com/PrefectHQ/prefect) and [Prefect Cloud 2](https://www.prefect.io/cloud/). _The components and utilities in this project are not meant to be used independently_.
175 lines (131 loc) • 4.74 kB
text/typescript
import { floor, random, uniform } from '@/utilities/math'
export function isArray(value: unknown): value is unknown[] {
return Array.isArray(value)
}
// we really do want any here
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function toMap<T extends any[], K extends keyof T[number]>(source: T, key: K): Map<T[number][K], T[number]> {
return source.reduce<Map<K, T>>((result, item) => {
result.set(item[key], item)
return result
}, new Map())
}
// Random element selector equivalent to python's choice method
export const choice = <T>(list: T[] | Readonly<T[]>): T => list[floor(random() * list.length)]
export const range = (min: number, max: number): number[] => Array.from({ length: max - min }, (x, i) => min + i)
export function unique<T>(array: T[]): T[] {
return [...new Set(array)]
}
// we really do want any here
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function isNonEmptyArray<T extends any[]>(
array: T | undefined,
): array is T {
return array !== undefined && array.length > 0
}
export function asArray<T>(input: T | T[] | null): T[] {
if (input === null || input === undefined) {
return []
}
if (!Array.isArray(input)) {
return [input]
}
return input
}
// we really do want any here
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function isSame(arrayA: any[], arrayB: any[]): boolean {
if (arrayA.length !== arrayB.length) {
return false
}
const arrayBCopy = [...arrayB]
return arrayA.every(itemA => arrayBCopy.some((itemB, index) => {
const match = itemA.toString() === itemB.toString()
if (match) {
arrayBCopy.splice(index, 1)
}
return match
}))
}
// we really do want any here
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function lastItemInArray<T extends any[]>(array: T): T[number] {
return array[array.length - 1]
}
// we really do want any here
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function allButLastArrayItems<T extends any[]>(array: T): T[number][] {
return array.slice(0, array.length - 1)
}
// shamelessly copied from https://stackoverflow.com/a/2450976/2687861
export function shuffle<T>(array: T[]): T[] {
let currentIndex = array.length
let randomIndex = undefined
while (currentIndex != 0) {
randomIndex = Math.floor(Math.random() * currentIndex)
currentIndex--;
[array[currentIndex], array[randomIndex]] = [array[randomIndex], array[currentIndex]]
}
return array
}
export function isEmptyArray(value: unknown): value is unknown[] {
return Array.isArray(value) && value.length === 0
}
export function isStringArray(value: unknown): value is string[] {
return Array.isArray(value) && value.length > 0 && value.every(item => typeof item === 'string')
}
export function isNumberArray(value: unknown): value is number[] {
return Array.isArray(value) && value.length > 0 && value.every(item => typeof item === 'number')
}
export function asSingle<T>(value: T | T[]): T {
if (Array.isArray(value)) {
const [first] = value
return first
}
return value
}
export function repeat<T>(count: number, method: (index: number) => T): T[] {
return new Array(count).fill(null).map((value, index) => method(index))
}
export function some<T>(source: T[], min?: number, max?: number): T[] {
const minArg = min ?? 1
const maxArg = max ?? source.length
const count = uniform(minArg, maxArg)
const copy = [...source]
const value = repeat(count, () => {
const index = uniform(0, copy.length - 1)
const value = copy.splice(index, 1)
return value[0]
})
return value
}
export function intersects(first: unknown[], ...rest: unknown[][]): boolean {
return first.some(firstValue => rest.every(restArray => restArray.includes(firstValue)))
}
export function groupBy<T, K extends keyof T>(source: T[], key: K): Map<T[K], T[]> {
return source.reduce((result, value) => {
const mapKey = value[key]
const initial = result.get(mapKey) ?? []
initial.push(value)
result.set(mapKey, initial)
return result
}, new Map<T[K], T[]>())
}
export function separate<T>(source: T[], filter: (value: T) => boolean): [found: T[], notFound: T[]] {
return source.reduce<[T[], T[]]>(([found, notFound], value) => {
if (filter(value)) {
found.push(value)
} else {
notFound.push(value)
}
return [found, notFound]
}, [[], []])
}
export function toggle<T>(source: T[], value: T, force?: boolean): T[] {
const index = source.indexOf(value)
const add = force === true || index === -1
if (add) {
return [...source, value]
}
return source.filter(item => item !== value)
}