|
|
- import {
- logger
- } from './logger.js'
-
- const NAME = 'Events';
-
- let watches = {};
- let triggers = {};
- let id = 0;
-
- Array.prototype.removeIf = function (callback) {
- let i = this.length;
- while (i--) {
- if (callback(this[i], i)) {
- this.splice(i, 1);
- return true;
- }
- }
-
- return false;
- };
-
- export class Events {
-
- /**
- * Similar in operation to `Hooks.on`, with two exceptions. First, the provided function
- * can be asynchronous and will be awaited. Second, an optional `conditionFn` parameter
- * is added to help compartmentalize logic between detecting the desired event and responding to said event.
- *
- * @param {String} name Event name to watch for; It is recommended to use the enums found in {@link warpgate.EVENT}
- * @param {function(object):Promise|void} fn Function to execute when this event has passed the condition function. Will be awaited
- * @param {function(object):boolean} [condition = ()=>true] Optional. Function to determine if the event function should
- * be executed. While not strictly required, as the `fn` function could simply return as a NOOP, providing this
- * parameter may help compartmentalize "detection" vs "action" processing.
- *
- * @returns {number} Function id assigned to this event, for use with {@link warpgate.event.remove}
- */
- static watch(name, fn, condition = () => {
- return true;
- }) {
- if (!watches[name]) watches[name] = [];
- id++;
- watches[name].push({
- fn,
- condition,
- id
- });
- return id;
- }
-
- /**
- * Identical to {@link warpgate.event.watch}, except that this function will only be called once, after the condition is met.
- *
- * @see {@link warpgate.event.watch}
- */
- static trigger(name, fn, condition = () => {
- return true;
- }) {
- if (!triggers[name]) triggers[name] = [];
- id++;
- triggers[name].push({
- fn,
- condition,
- id
- });
- return id;
- }
-
-
- static async run(name, data) {
- for (const {
- fn,
- condition,
- id
- } of watches[name] ?? []) {
- try {
- if (condition(data)) {
- logger.debug(`${name} | ${id} passes watch condition`);
- await fn(data);
- } else {
- logger.debug(`${name} | ${id} fails watch condition`);
- }
- } catch (e) {
- logger.error(`${NAME} | error`, e, `\n \nIn watch function (${name})\n`, fn);
- }
- }
-
- let {
- run,
- keep
- } = (triggers[name] ?? []).reduce((acum, elem) => {
- try {
- const passed = elem.condition(data);
- if (passed) {
- logger.debug(`${name} | ${elem.id} passes trigger condition`);
- acum.run.push(elem);
- } else {
- logger.debug(`${name} | ${elem.id} fails trigger condition`);
- acum.keep.push(elem);
- }
- } catch (e) {
- logger.error(`${NAME} | error`, e, `\n \nIn trigger condition function (${name})\n`, elem.condition);
- return acum;
- } finally {
- return acum;
- }
- }, {
- run: [],
- keep: []
- });
-
- for (const {
- fn,
- id
- } of run) {
- logger.debug(`${name} | calling trigger ${id}`);
- try {
- await fn(data);
- } catch (e) {
- logger.error(`${NAME} | error`, e, `\n \nIn trigger function (${name})\n`, fn);
- }
- }
-
- triggers[name] = keep;
- }
-
- /**
- * Removes a `watch` or `trigger` by its provided id -- obtained by the return value of `watch` and `trigger`.
- *
- * @param {number} id Numerical ID of the event function to remove.
- *
- * @see warpgate.event.watch
- * @see warpgate.event.trigger
- */
- static remove(id) {
- const searchFn = (elem) => {
- return elem.id === id
- };
-
- const tryRemove = (page) => page.removeIf(searchFn);
-
- const hookRemove = Object.values(watches).map(tryRemove).reduce((sum, current) => {
- return sum || current
- }, false);
-
- const triggerRemove = Object.values(triggers).map(tryRemove).reduce((sum, current) => {
- return sum || current
- }, false);
-
- return hookRemove || triggerRemove;
- }
- }
|