-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add documentation and change object to map.
- Loading branch information
Showing
1 changed file
with
63 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
}; |