{"version":3,"file":"index.cjs","names":[],"sources":["../src/mini-signals.ts","../src/mini-signals-emitter.ts","../src/mini-signals-utils.ts"],"sourcesContent":["import type { EventHandler, MiniSignalBinding } from './mini-signals-types.js';\n\nconst MINI_SIGNAL_KEY: unique symbol = Symbol('SIGNAL');\n\nexport interface MiniSignalNode<T extends any[]> {\n  fn: EventHandler<T>;\n  next?: MiniSignalNode<T>;\n  prev?: MiniSignalNode<T>;\n}\n\nfunction isBinding(obj: any): obj is MiniSignalBinding<any, any> {\n  return typeof obj === 'object' && MINI_SIGNAL_KEY in obj;\n}\n\n/**\n * @document __docs__/mini-signal.md\n */\nexport class MiniSignal<T extends any[] = any[], S = never> {\n  /**\n   * A Symbol that is used to guarantee the uniqueness of the MiniSignal instance.\n   */\n  private readonly _symbol = Symbol('MiniSignal');\n  private _refMap = new WeakMap<MiniSignalBinding<T, S>, MiniSignalNode<T>>();\n\n  private _head?: MiniSignalNode<T> = undefined;\n  private _tail?: MiniSignalNode<T> = undefined;\n  private _dispatching = false;\n\n  /**\n   * Check if there are any listeners attached.\n   */\n  hasListeners(): boolean {\n    return this._head != null;\n  }\n\n  /**\n   * Register a new listener.\n   */\n  add(fn: EventHandler<T>): MiniSignalBinding<T, S> {\n    if (typeof fn !== 'function') {\n      throw new Error('MiniSignal#add(): First arg must be a Function.');\n    }\n    return this._createBinding(this._addNode({ fn }));\n  }\n\n  /**\n   * Dispatches a signal to all registered listeners.\n   */\n  dispatch(...args: T): boolean {\n    if (this._dispatching)\n      throw new Error('MiniSignal#dispatch(): Signal already dispatching.');\n\n    let node = this._head;\n    if (node == null) return false;\n    this._dispatching = true;\n\n    // We know we have at least one node here\n    void node.fn(...args);\n    node = node.next;\n\n    while (node != null) {\n      void node.fn(...args);\n      node = node.next;\n    }\n\n    this._dispatching = false;\n    return true;\n  }\n\n  /**\n   * Dispatches listeners serially, waiting for each to complete if they return a Promise.\n   * Returns a Promise that resolves to true if listeners were called, false otherwise.\n   */\n  async dispatchSerial(...args: T): Promise<boolean> {\n    if (this._dispatching)\n      throw new Error(\n        'MiniSignal#dispatchSerial(): Signal already dispatching.'\n      );\n\n    let node = this._head;\n\n    if (node == null) return false;\n    this._dispatching = true;\n\n    // We know we have at least one node here\n    await node.fn(...args);\n    node = node.next;\n\n    while (node != null) {\n      await node.fn(...args);\n      node = node.next;\n    }\n\n    this._dispatching = false;\n    return true;\n  }\n\n  /**\n   * Dispatches listeners in parallel, waiting for all to complete if they return Promises.\n   * Returns a Promise that resolves to true if listeners were called, false otherwise.\n   */\n  async dispatchParallel(...args: T): Promise<boolean> {\n    if (this._dispatching) {\n      throw new Error(\n        'MiniSignal#dispatchParallel(): Signal already dispatching.'\n      );\n    }\n\n    let node = this._head;\n\n    if (node == null) return await Promise.resolve(false);\n    this._dispatching = true;\n\n    // Fast Promise.all implementation to avoid creating an array of promises\n    return await new Promise((resolve, reject) => {\n      let promisesRunning = 0;\n\n      while (node != null) {\n        promisesRunning++;\n\n        Promise.resolve(node.fn(...args)) // ensures non-promise values are handled as promises\n          .then(() => {\n            promisesRunning--;\n            if (node == null && promisesRunning === 0) {\n              this._dispatching = false;\n              resolve(true);\n            }\n          })\n          .catch((err) => {\n            this._dispatching = false;\n            reject(err);\n          });\n\n        node = node.next;\n      }\n    });\n  }\n\n  /**\n   * Remove binding object.\n   */\n  detach(sym: MiniSignalBinding<T, S>): this {\n    if (!isBinding(sym)) {\n      throw new Error(\n        'MiniSignal#detach(): First arg must be a MiniSignal listener reference.'\n      );\n    }\n\n    if (sym[MINI_SIGNAL_KEY] !== this._symbol) {\n      throw new Error(\n        'MiniSignal#detach(): MiniSignal listener does not belong to this MiniSignal.'\n      );\n    }\n\n    const node = this._refMap.get(sym);\n\n    if (node == null) return this; // already detached\n\n    this._refMap.delete(sym);\n    this._disconnectNode(node);\n    this._destroyNode(node);\n\n    return this;\n  }\n\n  /**\n   * Detach all listeners.\n   */\n  detachAll(): this {\n    let n = this._head;\n    if (n == null) return this;\n\n    this._head = this._tail = undefined;\n    this._refMap = new WeakMap();\n\n    while (n != null) {\n      this._destroyNode(n);\n      n = n.next;\n    }\n\n    return this;\n  }\n\n  private _destroyNode(node: MiniSignalNode<T>): void {\n    node.fn = undefined as any;\n    node.prev = undefined;\n  }\n\n  private _disconnectNode(node: MiniSignalNode<T>): void {\n    if (node === this._head) {\n      // first node\n      this._head = node.next;\n      if (node.next == null) {\n        this._tail = undefined;\n      }\n    } else if (node === this._tail) {\n      // last node\n      this._tail = node.prev;\n      if (this._tail != null) {\n        this._tail.next = undefined;\n      }\n    }\n\n    if (node.prev != null) {\n      node.prev.next = node.next;\n    }\n    if (node.next != null) {\n      node.next.prev = node.prev;\n    }\n  }\n\n  private _addNode(node: MiniSignalNode<T>): MiniSignalNode<T> {\n    if (this._head == null) {\n      this._head = node;\n      this._tail = node;\n    } else {\n      // eslint-disable-next-line  @typescript-eslint/no-non-null-assertion\n      this._tail!.next = node;\n      node.prev = this._tail;\n      this._tail = node;\n    }\n\n    return node;\n  }\n\n  private _createBinding(node: MiniSignalNode<T>): MiniSignalBinding<T, S> {\n    const sym = {\n      [MINI_SIGNAL_KEY]: this._symbol,\n    } as unknown as MiniSignalBinding<T, S>;\n    this._refMap.set(sym, node);\n    return sym;\n  }\n}\n","import type {\n  MiniSignalBinding,\n  EventHandler,\n  EventMap,\n  MiniSignalMap,\n  EventKey,\n} from './mini-signals-types.d.ts';\nimport type { MiniSignal } from './mini-signals.ts';\n\ntype SignalMap<T> = T extends EventMap<any>\n  ? MiniSignalMap<T>\n  : T extends MiniSignalMap<any>\n  ? T\n  : never;\n\ntype Listener<T> = T extends any[]\n  ? EventHandler<T>\n  : T extends MiniSignal<infer U, any>\n  ? EventHandler<U>\n  : never;\ntype Args<T> = T extends any[]\n  ? T\n  : T extends MiniSignal<infer U, any>\n  ? U\n  : never;\n\ntype _B<S, K> = [S] extends [never] ? K : S;\ntype Brand<T, K> = T extends any[]\n  ? K\n  : T extends MiniSignal<any, infer S>\n  ? _B<S, K>\n  : never;\n\ntype Signal<T, K> = MiniSignal<Args<T>, Brand<T, K>>;\n// eslint-disable-next-line @typescript-eslint/ban-types\ntype Binding<T, K> = MiniSignalBinding<Args<T>, Brand<T, K>>;\n\n/**\n * @document __docs__/mini-signal-emitter.md\n */\nexport class MiniSignalEmitter<\n  T extends EventMap<any> | MiniSignalMap<EventMap<any>> = any\n> {\n  protected readonly signals: SignalMap<T>;\n\n  // Note: signals must be provided from outside\n  // but are not required to be branded\n  constructor(signals: SignalMap<T>) {\n    this.signals = { ...signals };\n    // Copy symbol keys\n    for (const key of Object.getOwnPropertySymbols(signals)) {\n      this.signals[key as keyof T] = signals[key as keyof T];\n    }\n  }\n\n  // TODO: Can we extact the branding from the original signal here?\n  protected getSignal<K extends EventKey<T>>(event: K): Signal<T[K], K> {\n    const signal = this.signals[event];\n    // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions\n    if (!signal) {\n      throw new Error(`Signal for event '${String(event)}' not found`);\n    }\n    // Returns the signal with implied branding\n    return signal as unknown as Signal<T[K], K>;\n  }\n\n  /**\n   * Register a listener for a specific event\n   */\n  on<K extends EventKey<T>>(\n    event: K,\n    handler: Listener<T[K]>\n  ): Binding<T[K], K> {\n    const signal = this.getSignal(event);\n    return signal.add(handler);\n  }\n\n  /**\n   * Register a one-time listener for a specific event\n   */\n  once<K extends EventKey<T>>(\n    event: K,\n    handler: Listener<T[K]>\n  ): Binding<T[K], K> {\n    const signal = this.getSignal(event);\n    const binding = signal.add((...args: Args<T[K]>): void => {\n      handler(...args);\n      signal.detach(binding);\n    });\n    return binding;\n  }\n\n  /**\n   * Emit an event with data\n   */\n  emit<K extends EventKey<T>>(event: K, ...args: Args<T[K]>): boolean {\n    const signal = this.getSignal(event);\n    return signal.dispatch(...args);\n  }\n\n  async emitParallel<K extends EventKey<T>>(\n    event: K,\n    ...args: Args<T[K]>\n  ): Promise<boolean> {\n    const signal = this.getSignal(event);\n    return await signal.dispatchParallel(...args);\n  }\n\n  async emitSerial<K extends EventKey<T>>(\n    event: K,\n    ...args: Args<T[K]>\n  ): Promise<boolean> {\n    const signal = this.getSignal(event);\n    return await signal.dispatchSerial(...args);\n  }\n\n  off<K extends EventKey<T>, B extends Binding<T[K], K>>(\n    event: K,\n    binding: B\n  ): void {\n    const signal = this.getSignal(event);\n    signal.detach(binding);\n  }\n\n  clear<K extends EventKey<T>>(event?: K): void {\n    if (event !== undefined) {\n      this.getSignal(event).detachAll();\n    } else {\n      for (const key of Object.keys(this.signals)) {\n        this.getSignal(key as K)?.detachAll();\n      }\n      for (const key of Object.getOwnPropertySymbols(this.signals)) {\n        this.getSignal(key as K)?.detachAll();\n      }\n    }\n  }\n}\n","import { MiniSignal } from './mini-signals.ts';\nimport type { EventMap, MiniSignalMap } from './mini-signals-types.js';\n\n/**\n * Helper to create a signal map for SignalEmitter\n */\nexport function createSignalMap<T extends EventMap<any>>(\n  events: Array<keyof T>\n): MiniSignalMap<T> {\n  const map: Partial<MiniSignalMap<T>> = {};\n  for (const event of events) {\n    map[event] = new MiniSignal<T[typeof event]>();\n  }\n  return map as MiniSignalMap<T>;\n}\n"],"mappings":"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"}