import type { UnwrapRef } from 'vue' import type { Obj } from '@/types/commons' /** * Allow to set a timeout on a `Promise` expected response. * The returned Promise will be rejected if the original Promise is not resolved or * rejected before the delay. * * @param promise - A promise (like a fetch call). * @param delay - delay after which the promise is rejected */ export function timeout( promise: Promise, delay: number, ): Promise { return new Promise((resolve, reject) => { // FIXME reject(new Error('api_not_responding')) for post-install setTimeout(() => reject, delay) promise.then(resolve, reject) }) } /** * Check if passed value is an object literal. * * @param value - Anything. */ export function isObjectLiteral(value: any): value is object { return ( value !== null && value !== undefined && Object.is(value.constructor, Object) ) } export function objectGet< T extends Obj, K extends keyof T | string, F extends any = undefined, >(obj: T, key: K, fallback?: F) { return (key in obj ? obj[key] : fallback) as K extends keyof T ? T[K] : F } /** * Check if value is "empty" (`null`, `undefined`, `''`, `[]`, '{}'). * Note: `0` is not considered "empty" in that helper. * * @param value - Anything. */ export function isEmptyValue( value: any, ): value is null | undefined | '' | [] | {} { if (typeof value === 'number' || typeof value === 'boolean') return false return ( !value || (Array.isArray(value) && value.length === 0) || Object.keys(value).length === 0 ) } type Flatten = object extends T ? object : { [K in keyof T]-?: ( x: NonNullable extends infer V ? V extends object ? V extends readonly any[] ? Pick : Flatten extends infer FV ? { [P in keyof FV as `${Extract}`]: FV[P] } : never : Pick : never, ) => void } extends Record void> ? O extends infer U ? { [K in keyof O]: O[K] } : never : never /** * Returns an flattened object literal, with all keys at first level and removing nested ones. * * @param obj - An object literal to flatten. * @param flattened - An object literal to add passed obj keys/values. */ export function flattenObjectLiteral( obj: T, flattened: Partial> = {}, ) { function flatten(objLit: Partial>) { for (const key in objLit) { const value = objLit[key] if (isObjectLiteral(value)) { flatten(value) } else { flattened[key] = value } } } flatten(obj) return flattened as Flatten } /** * Returns an new Object filtered with passed filter function. * Each entry `[key, value]` will be forwarded to the `filter` function. * * @param obj - object to filter. * @param filter - the filter function to call for each entry. */ export function filterObject( obj: T, filter: ( entries: [string, any], index: number, array: [string, any][], ) => boolean, ) { return Object.fromEntries( Object.entries(obj).filter((...args) => filter(...args)), ) } /** * Returns an new array containing items that are in first array but not in the other. */ export function arrayDiff( arr1: T[] = [], arr2: T[] = [], ): T[] { return arr1.filter((item) => !arr2.includes(item)) } /** * Returns a new string with escaped HTML (`&<>"'` replaced by entities). * * @param unsafe - string to escape */ export function escapeHtml(unsafe: string) { return unsafe .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, ''') } /** * Returns a random integer between `min` and `max`. * * @param min - min possible value * @param max - max possible value */ export function randint(min: number, max: number) { return Math.floor(Math.random() * (max - min + 1)) + min } /** * Returns a File content. * * @param file - * @param base64 - returns a base64 representation of the file. */ export function getFileContent( file: File, { base64 = false } = {}, ): Promise { return new Promise((resolve, reject) => { const reader = new FileReader() reader.onerror = reject reader.onload = () => resolve(reader.result as string) if (base64) { reader.readAsDataURL(file) } else { reader.readAsText(file) } }) } export function toEntries>( obj: T, ): { [K in keyof T]: [K, T[K]] }[keyof T][] { return Object.entries(obj) as { [K in keyof T]: [K, T[K]] }[keyof T][] } } export function omit( obj: T, keys: K, ): Omit { return Object.fromEntries( Object.keys(obj) .filter((key) => !keys.includes(key)) .map((key) => [key, obj[key]]), ) as Omit } export function asUnreffed(value: T): UnwrapRef { return value as UnwrapRef }