From 342427a319ebcacf7e300d75e536cd7057e17570 Mon Sep 17 00:00:00 2001 From: Ram Hershberg Date: Sun, 4 Feb 2024 18:52:49 +0200 Subject: [PATCH] Add documentation and change object to map. --- src/modules/hooks/base_hooks.js | 78 ++++++++++++++++++++++++++------- 1 file changed, 63 insertions(+), 15 deletions(-) diff --git a/src/modules/hooks/base_hooks.js b/src/modules/hooks/base_hooks.js index fe1e8db..2bf817d 100644 --- a/src/modules/hooks/base_hooks.js +++ b/src/modules/hooks/base_hooks.js @@ -1,55 +1,103 @@ module.exports = class BaseHooks { constructor() { - this._events = {}; + /** + * @type {Map.>} A map between an event name to a set of callbacks registered for it. + * Function shape varies between different events. + * @private + */ + this._events = new Map(); } + /** + * Registers a callback or array of callbacks to an event. + * Callback function shape may vary according to the event type. + * Upon a hook trigger, the callbacks for it will be invoked one by one, but without a particular order. + * The user who registers the callback has the responsibility to handle any error inside of it. Throwing an error inside a callback will propagate it outside to the top level, aborting the process that triggered it. + * @param {string} event The event name to register. + * @param {(Function|Function[])} callback A callback or array of callbacks to register for the event. + * @protected + */ _on(event, callback) { if (Array.isArray(callback)) { this._manyOn(event, callback); return; } - if (!this._events[event]) { - this._events[event] = new Set(); - } - this._events[event].add(callback); + this._getCallbacks(event).add(callback); } + /** + * Registers a number of callbacks for an event. + * @param {string} event The event name to register. + * @param {Function|Function[]} callbacks A callback array register for the event. + * @private + */ _manyOn(event, callbacks) { - if (!this._events[event]) { - this._events[event] = new Set(); - } - callbacks.forEach((callback) => this._events[event].add(callback)); + const registered = this._getCallbacks(event); + callbacks.forEach((callback) => registered.add(callback)); } + /** + * Unregister a callback or array of callbacks from an event. + * Callbacks must be a reference to the same callbacks that registered. + * @param {string} event The event to unregister. + * @param {(Function|Function[])} callback A callback or array of callbacks to unregistered from the event. + * @protected + */ _off(event, callback) { if (Array.isArray(callback)) { this._manyOff(event, callback); return; } - if (!this._events[event]) { + const callbacks = this._getCallbacks(); + if (callbacks) { return; } - this._events[event].delete(callback); + callbacks.delete(callback); } + /** + * Unregister a number of callbacks from an event. + * @param {string} event The event to unregister. + * @param {Function[]} callbacks A callback array to unregistered from the event. + * @private + */ _manyOff(event, callbacks) { - if (!this._events[event]) { + const registered = this._getCallbacks(); + if (registered) { return; } - callbacks.forEach((callback) => this._events[event].delete(callback)); + callbacks.forEach((callback) => registered.delete(callback)); } + /** + * Trigger an event, calling all callbacks registered to it with the given payload. + * @param {*} source The class/object that triggered the event. Will be bound as the 'this' argument of the callbacks. + * @param {string} eventName The name of the event to trigger. + * @param {*} payload The event to pass to the registered callbacks as an argument. + * @public + */ async trigger(source, eventName, payload) { - if (!this._events[eventName]) { + const callbacks = this._getCallbacks(eventName); + if (!callbacks) { return; } // This rule intends to restrict it for arrays, but this is a Set which doesn't have a '.map' function to use instead. // eslint-disable-next-line no-restricted-syntax - for (const callback of this._events[eventName]) { + for (const callback of callbacks) { await callback.call(source, payload); } } + + /** @private */ + _getCallbacks(event) { + let callbacks = this._events.get(event); + if (!callbacks) { + callbacks = new Set(); + this._events.set(event, callbacks); + } + return callbacks; + } };