export function formatBytes( bytes: number, { decimals = 2, short = false }: { decimals?: number; short?: boolean } = { decimals: 2, short: false }, ) { if (bytes === 0) return "0 Bytes"; const k = 1024; const dm = decimals < 0 ? 0 : decimals; const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]; const i = Math.floor(Math.log(bytes) / Math.log(k)); const value = parseFloat((bytes / Math.pow(k, i)).toFixed(dm)); if (short) { return value + sizes[i].charAt(0); } else { return value + " " + sizes[i]; } } export function getDeep(obj: Record, path: string[]) { return path.reduce((acc, key) => acc?.[key], obj); } export function isObject(value: any): value is Record { return typeof value === "object" && value !== null && !Array.isArray(value); } export function flattenJSON(obj: Record, path: string[] = []) { const map = flattenJSONToMap(obj); const result = {} as Record; for (const [key, value] of map) { result[key.join(".")] = value; } return result; } export function flattenJSONToMap(obj: Record, path: string[] = []): Map { const result = new Map(); for (const key of Object.keys(obj)) { const value = obj[key]; const newPath = path.concat(key); if (isObject(value)) { for (const [k, v] of flattenJSONToMap(value, newPath)) { result.set(k, v); } } else { result.set(newPath, value); } } return result; } export function arrayEquals(a: string[], b: string[]): boolean { return Array.isArray(a) && Array.isArray(b) && a.length === b.length && a.every((val, index) => val === b[index]); } export function stripVersion(label: string) { const [name, _] = label.split(":"); return name; } export function useExponentialMovingAverage>(source: Ref, alpha: number = 0.2) { const ema = ref(source.value) as Ref; watch(source, (value) => { const newValue = {} as Record; for (const key in value) { newValue[key] = alpha * value[key] + (1 - alpha) * ema.value[key]; } ema.value = newValue as T; }); return ema; } interface UseSimpleRefHistoryOptions { capacity: number; deep?: boolean; initial?: T[]; } export function useSimpleRefHistory(source: Ref, options: UseSimpleRefHistoryOptions) { const { capacity, deep = true, initial = [] as T[] } = options; const history = ref(initial) as Ref; watch( source, (value) => { history.value.push(value); if (history.value.length > capacity) { history.value.shift(); } }, { deep }, ); const reset = ({ initial = [] }: Pick, "initial">) => { history.value = initial; }; return { history, reset }; } export function hashCode(str: string) { let hash = 0; for (let i = 0; i < str.length; i++) { hash = (hash << 5) - hash + str.charCodeAt(i); hash |= 0; } return hash; } const units: [Intl.RelativeTimeFormatUnit, number][] = [ ["year", 31536000], ["month", 2592000], ["week", 604800], ["day", 86400], ["hour", 3600], ["minute", 60], ["second", 1], ]; export function toRelativeTime(date: Date, locale: string | undefined): string { const diffInSeconds = (date.getTime() - new Date().getTime()) / 1000; const rtf = new Intl.RelativeTimeFormat(locale, { numeric: "auto" }); for (const [unit, seconds] of units) { const value = Math.round(diffInSeconds / seconds); if (Math.abs(value) >= 1) { return rtf.format(value, unit); } } return rtf.format(0, "second"); }