UNPKG

jest-metadata

Version:

🦸‍♂️ Superhero power for your Jest reporters! 🦸‍♀️

106 lines 3.54 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SerialEmitter = void 0; const logger_1 = require("../logger"); //#region Optimized event helpers const CATEGORIES = { ENQUEUE: ['enqueue'], EMIT: ['emit'], INVOKE: ['invoke'], LISTENERS: ['listeners'], }; const __EMIT = (0, logger_1.optimizeTracing)((event) => ({ cat: CATEGORIES.EMIT, event })); const __ENQUEUE = (0, logger_1.optimizeTracing)((event) => ({ cat: CATEGORIES.ENQUEUE, event, })); const __INVOKE = (0, logger_1.optimizeTracing)((listener, type) => ({ cat: CATEGORIES.INVOKE, fn: `${listener}`, type, })); const __LISTENERS = (0, logger_1.optimizeTracing)((listener) => ({ cat: CATEGORIES.LISTENERS, fn: `${listener}`, })); //#endregion const ONCE = Symbol('ONCE'); /** * An event emitter that emits events in the order they are received. * If an event is emitted while another event is being emitted, the new event * will be queued and emitted after the current event is finished. */ class SerialEmitter { _log; _listeners = new Map(); #queue = []; constructor(name, shouldLog = true) { this._log = (shouldLog ? logger_1.diagnostics : logger_1.nologger).child({ cat: [`emitter`, `emitter-${name}`], tid: `jest-metadata-emitter-${name}`, }); this._listeners.set('*', []); } on(type, listener) { if (!listener[ONCE]) { this._log.trace(__LISTENERS(listener), `on(${type})`); } if (!this._listeners.has(type)) { this._listeners.set(type, []); } const listeners = this._listeners.get(type); listeners.push(listener); return this; } once(type, listener) { this._log.trace(__LISTENERS(listener), `once(${type})`); return this.on(type, this.#createOnceListener(type, listener)); } off(type, listener) { if (!listener[ONCE]) { this._log.trace(__LISTENERS(listener), `off(${type})`); } const listeners = this._listeners.get(type) || []; const index = listeners.indexOf(listener); if (index !== -1) { listeners.splice(index, 1); } return this; } emit(nextEvent) { this.#queue.push(Object.freeze(nextEvent)); if (this.#queue.length > 1) { this._log.trace(__ENQUEUE(nextEvent), `enqueue(${nextEvent.type})`); return; } while (this.#queue.length > 0) { const event = this.#queue[0]; const eventType = event.type; const listeners = this._getListeners(eventType); this._log.trace.complete(__EMIT(event), event.type, () => { if (listeners) { for (const listener of listeners) { this._log.trace(__INVOKE(listener), 'invoke'); listener(event); } } }); this.#queue.shift(); } } _getListeners(type) { const wildcard = this._listeners.get('*') ?? []; const named = this._listeners.get(type) ?? []; return [...wildcard, ...named]; } #createOnceListener(type, listener) { const onceListener = ((event) => { this.off(type, onceListener); listener(event); }); onceListener[ONCE] = true; return onceListener; } } exports.SerialEmitter = SerialEmitter; //# sourceMappingURL=SerialEmitter.js.map