Skip to content

Commit

Permalink
Add documentation and change object to map.
Browse files Browse the repository at this point in the history
  • Loading branch information
ramhr committed Feb 4, 2024
1 parent a4f7aa3 commit 342427a
Showing 1 changed file with 63 additions and 15 deletions.
78 changes: 63 additions & 15 deletions src/modules/hooks/base_hooks.js
Original file line number Diff line number Diff line change
@@ -1,55 +1,103 @@
module.exports = class BaseHooks {
constructor() {
this._events = {};
/**
* @type {Map.<string, Set.<Function>>} 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;
}
};

0 comments on commit 342427a

Please sign in to comment.