import { For } from 'solid-js'; import { createMutable } from 'solid-js/store'; import { assert } from '~/lib/utils/invariant'; interface LogEntry { typ: 'log' | 'info' | 'warn' | 'error'; at: number; msg: string; } interface PendingLogEntry { msg: string; } export const createLogger = () => { const pending = createMutable([]); let backlog: LogEntry[] | undefined = []; let push = (entry: LogEntry) => { backlog!.push(entry); }; return { internal: { get pending() { return pending; }, attach(fn: (entry: LogEntry) => void) { if (backlog !== undefined) { for (let idx = 0, len = backlog.length; idx < len; idx++) { fn(backlog[idx]); } backlog = undefined; } push = fn; }, }, log(msg: string) { push({ typ: 'log', at: Date.now(), msg }); }, info(msg: string) { push({ typ: 'info', at: Date.now(), msg }); }, warn(msg: string) { push({ typ: 'warn', at: Date.now(), msg }); }, error(msg: string) { push({ typ: 'error', at: Date.now(), msg }); }, progress(initialMsg: string, throttleMs = 500) { pending.unshift({ msg: initialMsg }); let entry: PendingLogEntry | undefined = pending[0]; return { update: throttle((msg: string) => { if (entry !== undefined) { entry.msg = msg; } }, throttleMs), destroy() { if (entry !== undefined) { const index = pending.indexOf(entry); pending.splice(index, 1); entry = undefined; } }, [Symbol.dispose]() { this.destroy(); }, }; }, }; }; export interface LoggerProps { logger: ReturnType; } const Logger = ({ logger }: LoggerProps) => { const formatter = new Intl.DateTimeFormat('en-US', { timeStyle: 'short', hour12: false }); return ( ); }; export default Logger; const throttle = void>(func: T, wait: number) => { let timeout: ReturnType | null = null; let lastArgs: Parameters | null = null; let lastCallTime = 0; const invoke = () => { func(...lastArgs!); lastCallTime = Date.now(); timeout = null; }; return (...args: Parameters) => { const now = Date.now(); const timeSinceLastCall = now - lastCallTime; lastArgs = args; if (timeSinceLastCall >= wait) { if (timeout !== null) { clearTimeout(timeout); } invoke(); } else if (timeout === null) { timeout = setTimeout(invoke, wait - timeSinceLastCall); } }; };