UNPKG

@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_.

178 lines (129 loc) 5.64 kB
import { isDate } from 'date-fns' import { unique } from '@/utilities/arrays' export function flip<K extends string, V extends string>(obj: Record<K, V>): Record<V, K> { const result = {} as Record<V, K> for (const key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { result[obj[key]] = key } } return result } export function omit<T extends Record<string, unknown>, K extends(keyof T)[]>(source: T, keys: K): Omit<T, K[number]> { const copy = { ...source } keys.forEach(key => delete copy[key]) return copy } export function clone<T>(source: T): T { if (source === null || typeof source !== 'object') { return source } if (isDate(source)) { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-expect-error return new Date(source) } // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-expect-error const copy = new source() for (const key in source) { copy[key] = clone(source[key]) } return copy } export function hasProperty<T extends Record<string | symbol, unknown>>(needle: T, property: unknown): property is keyof T { return (typeof property === 'string' || typeof property === 'symbol') && property in needle } export type MapKeysCallback<PreviousKey extends PropertyKey, Value, NewKey extends PropertyKey> = (key: PreviousKey, value: Value) => NewKey export function mapKeys<K extends PropertyKey, V, Key extends PropertyKey>(object: Record<K, V>, callback: MapKeysCallback<K, V, Key>): Record<Key, V> { const entries = Object.entries(object) as [K, V][] const result = {} as Record<Key, V> return entries.reduce((result, [key, value]) => { const newKey = callback(key, value) result[newKey] = object[key] return result }, result) } export type MapValuesCallback<Key extends PropertyKey, PreviousValue, NewValue> = (key: Key, value: PreviousValue) => NewValue export function mapValues<Key extends PropertyKey, PreviousValue, NewValue>(object: Record<Key, PreviousValue>, callback: MapValuesCallback<Key, PreviousValue, NewValue>): Record<Key, NewValue> { const entries = Object.entries(object) as [Key, PreviousValue][] const result = {} as Record<Key, NewValue> return entries.reduce((result, [key, value]) => { result[key] = callback(key, value) return result }, result) } export type MapEntriesCallback<PreviousKey extends PropertyKey, PreviousValue, NewKey extends PropertyKey, NewValue> = (key: PreviousKey, value: PreviousValue) => [NewKey, NewValue] export function mapEntries<PreviousKey extends PropertyKey, PreviousValue, NewKey extends PropertyKey, NewValue>(object: Partial<Record<PreviousKey, PreviousValue>>, callback: MapEntriesCallback<PreviousKey, PreviousValue, NewKey, NewValue>): Partial<Record<NewKey, NewValue>> { const entries = Object.entries(object) as [PreviousKey, PreviousValue][] const result = {} as Record<NewKey, NewValue> return entries.reduce((result, [key, value]) => { const [newKey, newValue] = callback(key, value) result[newKey] = newValue return result }, result) } export function isEmptyObject(value: unknown): value is Record<string, never> { return typeof value === 'object' && !Array.isArray(value) && value !== null && Object.keys(value).length === 0 } export function isTypeRequired<T extends Record<PropertyKey, unknown>>(value: Partial<T>): value is Required<T> { return Object.values(value).every(value => value !== undefined) } export function hasString<T extends Record<PropertyKey, unknown>>(obj: T, str: string): boolean { const values = Object.values(obj).map(val => val?.toString().toLowerCase() ?? '').join('') return values.includes(str.toLowerCase()) } export function isRecord(item: unknown): item is Record<PropertyKey, unknown> { return item !== null && typeof item === 'object' && !Array.isArray(item) && !isDate(item) } /** * @deprecated Please use lodash.merge instead. */ export function merge<T extends Record<PropertyKey, unknown>>(target: T, ...sources: T[]): T { if (sources.length === 0) { return target } const [source, ...rest] = sources const keys = unique([...Object.keys(target), ...Object.keys(source)]) for (const key of keys) { const targetValue: unknown = target[key] const sourceValue: unknown = source[key] if (targetValue === sourceValue) { continue } if (isRecord(targetValue) && isRecord(sourceValue)) { merge(targetValue, sourceValue) continue } if (isRecord(targetValue) && isRecord(source) && !(key in source)) { merge(targetValue, { [key]: {} }) continue } // this is really sloppy typescript... // eslint-disable-next-line @typescript-eslint/no-explicit-any target[key as keyof T] = source[key] as any } return merge(target, ...rest) } type EmptyObjectsRemoved<T extends Record<PropertyKey, unknown>> = { [P in keyof T]: T[P] extends Record<PropertyKey, unknown> ? EmptyObjectsRemoved<T[P]> | undefined : T[P]; } export function removeEmptyObjects<T extends Record<PropertyKey, unknown>>(input: T): EmptyObjectsRemoved<T> { const response: Record<PropertyKey, unknown> = {} const keys = Object.keys(input) for (const key of keys) { const value = input[key] if (value === undefined) { continue } if (isRecord(value)) { const possiblyEmptyObject = removeEmptyObjects(value) if (Object.keys(possiblyEmptyObject).length) { response[key] = possiblyEmptyObject } continue } response[key] = value } return response as EmptyObjectsRemoved<T> }