/* eslint-disable @typescript-eslint/no-explicit-any */ import { KeyboardShortcut } from '../interfaces/keyboard.interface'; import { PromiseWithResolver } from '../interfaces/utils.interface'; import { SHORTCUT_KEY_DISPLAY_MAP } from './constant/shortcut.const'; export function debounce( fn: (...args: T) => void, delay: number, ) { let timeoutId: ReturnType; return (...args: T) => { clearTimeout(timeoutId); timeoutId = setTimeout(() => { fn(...args); }, delay); }; } export function createDebounce() { let timeout: null | ReturnType = null; return (callback: () => void, timeoutMs: number) => { if (timeout !== null) { clearTimeout(timeout); timeout = setTimeout(callback, timeoutMs); return; } timeout = setTimeout(callback, timeoutMs); }; } export type ThrottledFunction = (...args: T) => void; export function throttle( func: (...args: T) => void, limit = 1000, ): ThrottledFunction { let lastExecutionTime = 0; let timeout: number | ReturnType = -1; return function throttledFunc(...args: T): void { const now = Date.now(); if (now - lastExecutionTime < limit) { if (timeout) { return; } timeout = setTimeout( () => { func(...args); lastExecutionTime = now; timeout = -1; }, limit - (now - lastExecutionTime), ); } else { func(...args); lastExecutionTime = now; } }; } export function parseJSON( input: string, def?: K, ): T | K { try { return JSON.parse(input) as T; } catch (_error) { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore return def; } } export function isObject( input: unknown, ): input is Record { return typeof input === 'object' && !Array.isArray(input) && input !== null; } export function sleep(ms = 1000) { return new Promise((r) => setTimeout(r, ms)); } export function getRandomArbitrary(min = 0, max = 10, remainder?: number) { let randomInteger = Math.floor(Math.random() * (max - min + 1) + min); if (typeof remainder === 'number') { const adjustment = (remainder - ((randomInteger - min) % remainder)) % remainder; randomInteger += adjustment; } return randomInteger; } export function getRandomItemFromArr(array: T[]): T { const randomIndex = Math.floor(Math.random() * array.length); return array[randomIndex]; } export function shuffleArray(array: T[]): T[] { let currentIndex: number = array.length; let randomIndex: number; while (currentIndex > 0) { randomIndex = Math.floor(Math.random() * currentIndex); currentIndex--; [array[currentIndex], array[randomIndex]] = [ array[randomIndex], array[currentIndex], ]; } return array; } export function isValidURL(url: string) { try { new URL(url); return true; } catch (_error) { return false; } } export function getShortcutStr(shortcut?: KeyboardShortcut, wrap = true) { if (!shortcut) return ''; let str = SHORTCUT_KEY_DISPLAY_MAP[shortcut.mod1] ?? shortcut.mod1; if (shortcut.mod2) str += `+${SHORTCUT_KEY_DISPLAY_MAP[shortcut.mod2] ?? shortcut.mod2}`; str += `+${SHORTCUT_KEY_DISPLAY_MAP[shortcut.key] ?? shortcut.key.toUpperCase()}`; if (!wrap) return str; return `(${str})`; } export function generateRandomString(length = 12) { const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; let result = ''; for (let i = 0; i < length; i++) { const randomIndex = Math.floor(Math.random() * characters.length); result += characters.charAt(randomIndex); } return result; } export function promiseWithResolver(): PromiseWithResolver { let reject: (reason?: any) => void = () => {}; let resolve: (value: T | PromiseLike) => void = () => {}; const promise = new Promise((res, rej) => { reject = rej; resolve = res; }); return { promise, resolve, reject }; } export function sleepWithRetry( callback: () => boolean | Promise, ms = 1000, ) { const resolver = promiseWithResolver(); const resolvePromise = async () => { try { const result = await callback(); if (result) { resolver.resolve(); return; } setTimeout(resolvePromise, ms); } catch (error) { resolver.reject(error); } }; resolvePromise(); return resolver.promise; } export function searhParamsBuilder( queries: Record, ) { const searhParams = new URLSearchParams(); for (const key in queries) { const value = queries[key]; if (typeof value !== 'undefined') searhParams.set(key, value); } return searhParams; }