jest-metadata
Version:
🦸♂️ Superhero power for your Jest reporters! 🦸♀️
106 lines • 3.54 kB
JavaScript
;
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