import type { AppEvent } from '../events/types'; import { safeJsonStringify } from '../utils/safe-json'; type Constructor = new (...args: any[]) => T; type EventConstructor = TBase & { new (...args: ConstructorParameters): InstanceType & AppEvent; deserialize(data: string): InstanceType & AppEvent; readonly eventName: string; prototype: InstanceType & AppEvent; }; /** * @Event decorator * * Marks a class as an event type that can be emitted and handled. * * @example * ```typescript * @Event * export class ItemAdded { * constructor( * public key: string, * public value: string * ) {} * } * ``` */ export function Event(target: TBase): EventConstructor { const enhanced = class extends target implements AppEvent { serialize(): string { const plain: Record = {}; for (const key in this) { if (Object.prototype.hasOwnProperty.call(this, key)) { plain[key] = (this as Record)[key]; } } return safeJsonStringify({ eventType: (this.constructor as typeof enhanced).eventName, ...plain, }); } static deserialize(data: string): InstanceType & AppEvent { const parsed = JSON.parse(data); if (parsed && typeof parsed === 'object' && 'eventType' in parsed) { delete parsed.eventType; } return Object.assign(new target(), parsed) as InstanceType & AppEvent; } static get eventName(): string { return target.name; } }; (enhanced as any)._calimeroEvent = true; return enhanced as unknown as EventConstructor; }