All files / src/event event.ts

100% Statements 44/44
100% Branches 14/14
100% Functions 11/11
100% Lines 42/42

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 10821x 21x 21x 21x           21x             143x 143x 9x 9x 4x   2x 2x   2x 4x   4x     2x     7x       143x       11x 3x 3x     8x 1x 1x       7x       6x 6x 2x   4x 4x                   4x 3x 3x   1x 1x                                     3x 3x 3x 2x 2x 2x 1x          
import { Accessor } from '../accessor';
import { MethodNotFoundError } from '../error';
import { InvalidAccessorDefinitionError } from '../error/invalid-accessor-definition';
import { Loader } from '../loader';
import { IEvent, IEvents, IEventsDefinition } from './interfaces';
 
/**
 * Event
 */
export class Event {
	/**
	 * factory function that creates an event object from an event definition
	 * @param events
	 * @returns
	 */
	public static factory<T>(events: IEventsDefinition<T>): IEvents<T> {
		const factoredEvents: IEvents<T> = {};
		for (const name in events) {
			const event = events[name];
			if (Array.isArray(event)) {
				const eventArr = event.map((eventItem) => Event.getFactoredEvent(eventItem));
 
				factoredEvents[name] = (args: any) => {
					let prevent = false;
 
					eventArr.forEach((eventItem) => {
						const result = !!eventItem(args);
 
						if (result) prevent = true;
					});
 
					return prevent;
				};
			} else {
				factoredEvents[name] = Event.getFactoredEvent<T>(event);
			}
		}
 
		return factoredEvents;
	}
 
	private static getFactoredEvent<T>(event: undefined | string | IEvent<T>) {
		if (Accessor.isAccessorDefinition(event)) {
			const [controllerName, method] = Accessor.getAccessor(event as string);
			return Event.getEventMethod<T>(controllerName, method);
		}
 
		if (typeof event !== 'function') {
			return () => {
				throw new InvalidAccessorDefinitionError(event);
			};
		}
 
		return event;
	}
 
	private static getEventMethod<T>(controllerName: string, method: string): IEvent<T> {
		const instance = Loader.getInstance(controllerName);
		if (instance?.[method]) {
			return instance[method].bind(instance);
		}
		return () => {
			throw new MethodNotFoundError(method, controllerName);
		};
	}
 
	/**
	 * Return a event function
	 * @param event
	 * @returns
	 */
	public static get<T = any>(event: string): IEvent<T> {
		if (Accessor.isAccessorDefinition(event)) {
			const [controllerName, method] = Accessor.getAccessor(event as string);
			return Event.getEventMethod(controllerName, method);
		}
		return () => {
			throw new InvalidAccessorDefinitionError(event);
		};
	}
 
	/**
	 * An asynchronous function that performs a loop of events on a system
	 * @param before
	 * @param after
	 * @param events
	 * @param eventArgs
	 * @param callback
	 */
	public static async callEventCycle<T>(
		before: string,
		after: string,
		events: IEvents<T>,
		eventArgs: T,
		callback: () => void | Promise<void>,
	): Promise<void> {
		const beforeEvent = events[before];
		const prevent = beforeEvent && typeof beforeEvent === 'function' && beforeEvent(eventArgs) === true;
		if (!prevent) {
			await callback();
			const afterEvent = events[after];
			if (afterEvent && typeof afterEvent === 'function') {
				afterEvent(eventArgs);
			}
		}
	}
}