summaryrefslogtreecommitdiff
path: root/node_modules/@11ty/eleventy/src/Util/AsyncEventEmitter.js
blob: 0bc471f9b0c1bd5133df3f160f94b3fd143ce6ac (plain)
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
import { EventEmitter } from "node:events";

/**
 * This class emits events asynchronously.
 *
 * Note that Eleventy has two separate event emitter instances it uses:
 * 1. a userland one (UserConfig.js)
 * 2. a global one for internals (EventBus.js)
 */
class AsyncEventEmitter extends EventEmitter {
	#handlerMode = "parallel";

	// TypeScript slop
	constructor(...args) {
		super(...args);
	}

	reset() {
		// `eleventy#` event type listeners are removed at the start of each build (singletons)
		for (let type of this.eventNames()) {
			if (typeof type === "string" && type.startsWith("eleventy#")) {
				this.removeAllListeners(type);
			}
		}

	}

	/**
	 * @param {string} type - The event name to emit.
	 * @param {...*} args - Additional arguments that get passed to listeners.
	 * @returns {Promise} - Promise resolves once all listeners were invoked
	 */
	/** @ts-expect-error */
	async emit(type, ...args) {
		let listeners = this.listeners(type);
		if (listeners.length === 0) {
			return [];
		}

		if (this.#handlerMode == "sequential") {
			const result = [];
			for (const listener of listeners) {
				const returnValue = await listener.apply(this, args);
				result.push(returnValue);
			}
			return result;
		} else {
			return Promise.all(
				listeners.map((listener) => {
					return listener.apply(this, args);
				}),
			);
		}
	}

	/**
	 * @param {string} type - The event name to emit.
	 * @param {...*} args - Additional lazy-executed function arguments that get passed to listeners.
	 * @returns {Promise} - Promise resolves once all listeners were invoked
	 */
	async emitLazy(type, ...args) {
		let listeners = this.listeners(type);
		if (listeners.length === 0) {
			return [];
		}

		let argsMap = [];
		for (let arg of args) {
			if (typeof arg === "function") {
				let r = arg();
				if (r instanceof Promise) {
					r = await r;
				}
				argsMap.push(r);
			} else {
				argsMap.push(arg);
			}
		}

		return this.emit.call(this, type, ...argsMap);
	}

	setHandlerMode(mode) {
		this.#handlerMode = mode;
	}
}

export default AsyncEventEmitter;