import mitt, { Emitter } from 'mitt'; import { Fn, KeyOfMethods, Parameters } from '../utils/type-utils'; import { createFnsWireGuard, FnsWire, isFnsWire } from './fns-wire'; type DisconnectFunction = () => void; type ConnectFunction = () => DisconnectFunction; export interface Action< Fns extends {}, K extends KeyOfMethods = KeyOfMethods, > { type: K; args: Parameters; } export function createFnsWire( ctx: FnsWire, ): [FnsWire, ConnectFunction]; export function createFnsWire( ctx: Partial>, ): [FnsWire, ConnectFunction]; export function createFnsWire( ctx: FnsWire | Partial>, ): [FnsWire, ConnectFunction] { const emitter: Emitter = mitt(); const upLink: FnsWire | null = isFnsWire(ctx) ? ctx : null; const handler: ProxyHandler<{}> = { get: function (target, prop: string) { return (...args: any) => { if (upLink) { (upLink.fns as any)[prop](...args); } else { emitter.emit(prop, { type: prop, args }); } }; }, }; const fns = new Proxy({}, handler) as any; const fn = >( name: K, fn: Fns[K], ): (() => void) => { if (upLink) { return upLink.fn(name, fn); } else { const handle = (action: Action) => { (fn as Fn)(...action.args); }; emitter.on(name as string, handle); return () => { emitter.off(name as string, handle); }; } }; const fnsContext = { fn, fns, }; const connect = () => { return () => {}; }; return [{ ...fnsContext, ...createFnsWireGuard() }, connect]; }