UNPKG

micro-spark

Version:

Micro-Spark is a modern, lightweight, and environment-agnostic event emitter library built in TypeScript. It is designed for complex event-driven systems across various environments such as Node.js, Deno, Bun, and browsers. With features like wildcard eve

179 lines (177 loc) 5.63 kB
class MicroSpark { events; weakListeners; errorListeners = []; /** * Creates a new instance of the Spark event emitter. */ constructor() { this.events = /* @__PURE__ */ new Map(); this.weakListeners = /* @__PURE__ */ new WeakMap(); } /** * Registers a listener for a specific event. * * @param {keyof Events} event - The name of the event or a wildcard pattern (e.g., `user.*`). * @param {Listener<Events[Event]>} listener - The function to be called when the event is emitted. * * @example * emitter.on('message', (msg) => { * console.log(`Message: ${msg}`); * }); */ on(event, listener) { const pattern = this.getWildcardPattern(event) || event; if (!this.events.has(pattern)) { this.events.set(pattern, []); } this.events.get(pattern)?.push(listener); if (typeof listener === "object") { const listenersSet = this.weakListeners.get(listener) || /* @__PURE__ */ new Set(); listenersSet.add(listener); this.weakListeners.set(listener, listenersSet); } } /** * Registers a one-time listener for a specific event. * * @param event - The name of the event or a wildcard pattern. * @param listener - The function to be called when the event is emitted. * @param maxEmits - The maximum number of times the listener should be invoked. Defaults to 1 if not provided. * * @example * emitter.once('message', (msg) => { * console.log(`One-time message: ${msg}`); * }); */ once(event, listener, maxEmits = 1) { let emitCount = 0; const onceWrapper = (...args) => { if (emitCount < maxEmits) { listener(...args); emitCount++; } if (emitCount >= maxEmits) { this.off(event, onceWrapper); } }; this.on(event, onceWrapper); } /** * Removes a listener from a specific event. * * @param {keyof Events} event - The name of the event or a wildcard pattern. * @param {Listener<Events[Event]>} [listener] - The listener function to be removed. If not provided, all listeners for the event will be removed. * * @example * emitter.off('message', listener); */ off(event, listener) { const pattern = this.getWildcardPattern(event) || event; if (this.events.has(pattern)) { if (!listener) { this.events.delete(pattern); } else { const listeners = this.events.get(pattern); if (!listeners) return; const filtered = listeners.filter((l) => l !== listener); this.events.set(pattern, filtered); } } } /** * Emits an event, invoking all matching listeners. * * @param {keyof Events} event - The name of the event. * @param {...Events[Event]} args - Arguments to be passed to the listeners. * * @returns {EmitResult | Promise<EmitResult>} The result of the emit operation, including any errors. * * @example * emitter.emit('message', 'Hello, World!'); */ emit(event, ...args) { const errors = []; const promises = []; const processedArgs = args.map( (arg) => typeof arg === "function" ? arg() : arg ); for (const [key, listeners] of this.events.entries()) { if (typeof key === "string" && this.eventMatches(key, event)) { for (const listener of listeners) { try { if (key.includes("*")) { const result = listener(event, ...processedArgs); if (result instanceof Promise) promises.push(result); } else { const result = listener(...processedArgs); if (result instanceof Promise) promises.push(result); } } catch (err) { this.emitError(event, err); errors.push(err); } } } } if (promises.length > 0) { return Promise.all(promises).then( () => errors.length > 0 ? { success: false, errors } : { success: true } ).catch((err) => { this.emitError(event, err); errors.push(err); return { success: false, errors }; }); } return errors.length > 0 ? { success: false, errors } : { success: true }; } /** * Registers an error handler for the event emitter. * * @param {ErrorListener} handler - A function to handle errors emitted during listener execution. * * @example * emitter.onError((event, error) => { * console.error(`Error in event "${event}": ${error.message}`); * }); */ onError(handler) { this.errorListeners.push(handler); } /** * Clears the listeners for a specific event, or all listeners if no event is provided. * * @param {keyof Events} [event] - The name of the event to clear listeners for. If not provided, clears all listeners. * * @example * emitter.clear('message'); // Clears listeners for the "message" event * emitter.clear(); // Clears all listeners */ clear(event) { if (event) { const pattern = this.getWildcardPattern(event) || event; if (this.events.has(pattern)) { this.events.delete(pattern); } } else { this.events.clear(); } } emitError(event, err) { for (const listener of this.errorListeners) { listener(event, err); } } getWildcardPattern(event) { return event.includes("*") ? event.replace(/\*/g, ".*") : void 0; } eventMatches(pattern, event) { if (pattern.includes(".*")) { const regex = new RegExp(`^${pattern}$`); return regex.test(event); } return pattern === event; } } export { MicroSpark }; //# sourceMappingURL=micro-spark.es.js.map