import { display } from './display' let onMonitorErrorCollected: undefined | ((error: unknown) => void) let debugMode = false export function startMonitorErrorCollection(newOnMonitorErrorCollected: (error: unknown) => void) { onMonitorErrorCollected = newOnMonitorErrorCollected } export function setDebugMode(newDebugMode: boolean) { debugMode = newDebugMode } export function resetMonitor() { onMonitorErrorCollected = undefined debugMode = false } export function monitored unknown>( _: any, __: string, descriptor: TypedPropertyDescriptor ) { const originalMethod = descriptor.value! descriptor.value = function (this: ThisParameterType, ...args: Parameters) { const decorated = onMonitorErrorCollected ? monitor(originalMethod) : originalMethod return decorated.apply(this, args) as ReturnType } as T } export function monitor unknown>(fn: T): T { return function (this: ThisParameterType, ...args: Parameters) { return callMonitored(fn, this, args) } as unknown as T // consider output type has input type } export function callMonitored unknown>( fn: T, context: ThisParameterType, args: Parameters ): ReturnType | undefined export function callMonitored unknown>(fn: T): ReturnType | undefined export function callMonitored unknown>( fn: T, context?: any, args?: any ): ReturnType | undefined { try { return fn.apply(context, args) as ReturnType } catch (e) { monitorError(e) } } export function monitorError(e: unknown) { displayIfDebugEnabled(e) if (onMonitorErrorCollected) { try { onMonitorErrorCollected(e) } catch (e) { displayIfDebugEnabled(e) } } } export function displayIfDebugEnabled(...args: unknown[]) { if (debugMode) { display.error('[MONITOR]', ...args) } }