@vpmedia/simplify 1.66.0 → 1.68.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +31 -0
- package/package.json +11 -14
- package/src/index.js +1 -0
- package/src/pagelifecycle/util.js +2 -1
- package/src/util/event_emitter.js +198 -0
- package/src/util/event_emitter.test.js +231 -0
- package/src/util/object.js +2 -2
- package/types/index.d.ts +1 -0
- package/types/pagelifecycle/util.d.ts +1 -1
- package/types/pagelifecycle/util.d.ts.map +1 -1
- package/types/util/event_emitter.d.ts +69 -0
- package/types/util/event_emitter.d.ts.map +1 -0
- package/types/util/object.d.ts.map +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,34 @@
|
|
|
1
|
+
## [1.68.0] - 2026-02-04
|
|
2
|
+
|
|
3
|
+
### 🚜 Refactor
|
|
4
|
+
|
|
5
|
+
- Use event emitter custom internally
|
|
6
|
+
|
|
7
|
+
### ⚙️ Miscellaneous Tasks
|
|
8
|
+
|
|
9
|
+
- Release
|
|
10
|
+
- *(release)* V1.68.0
|
|
11
|
+
## [1.67.0] - 2026-02-04
|
|
12
|
+
|
|
13
|
+
### 🚀 Features
|
|
14
|
+
|
|
15
|
+
- Added es6 event emitter implementation
|
|
16
|
+
|
|
17
|
+
### 💼 Other
|
|
18
|
+
|
|
19
|
+
- *(deps)* Bump dependency versions
|
|
20
|
+
- *(deps)* Bump dependency versions
|
|
21
|
+
- *(deps)* Bump dependency versions
|
|
22
|
+
|
|
23
|
+
### 🚜 Refactor
|
|
24
|
+
|
|
25
|
+
- Simplify purgeObject helper
|
|
26
|
+
|
|
27
|
+
### ⚙️ Miscellaneous Tasks
|
|
28
|
+
|
|
29
|
+
- Release
|
|
30
|
+
- Fixed lint errors
|
|
31
|
+
- *(release)* V1.67.0
|
|
1
32
|
## [1.66.0] - 2026-01-30
|
|
2
33
|
|
|
3
34
|
### ⚙️ Miscellaneous Tasks
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vpmedia/simplify",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.68.0",
|
|
4
4
|
"description": "@vpmedia/simplify",
|
|
5
5
|
"author": "Andras Csizmadia <andras@vpmedia.hu> (www.vpmedia.hu)",
|
|
6
6
|
"license": "MIT",
|
|
@@ -18,27 +18,24 @@
|
|
|
18
18
|
"main": "./src/index.js",
|
|
19
19
|
"types": "./types/index.d.ts",
|
|
20
20
|
"type": "module",
|
|
21
|
-
"dependencies": {
|
|
22
|
-
"eventemitter3": "^5.0.4"
|
|
23
|
-
},
|
|
24
21
|
"optionalDependencies": {
|
|
25
22
|
"@sentry/browser": "^10.38.0"
|
|
26
23
|
},
|
|
27
24
|
"devDependencies": {
|
|
28
|
-
"@commitlint/cli": "^20.
|
|
29
|
-
"@commitlint/config-conventional": "^20.
|
|
25
|
+
"@commitlint/cli": "^20.4.1",
|
|
26
|
+
"@commitlint/config-conventional": "^20.4.1",
|
|
30
27
|
"@eslint/js": "^9.39.2",
|
|
31
|
-
"@types/node": "^25.
|
|
28
|
+
"@types/node": "^25.2.0",
|
|
32
29
|
"@vitest/coverage-v8": "^4.0.18",
|
|
33
30
|
"eslint": "^9.39.2",
|
|
34
|
-
"eslint-plugin-jsdoc": "^62.5.
|
|
35
|
-
"eslint-plugin-oxlint": "^1.
|
|
31
|
+
"eslint-plugin-jsdoc": "^62.5.1",
|
|
32
|
+
"eslint-plugin-oxlint": "^1.43.0",
|
|
36
33
|
"eslint-plugin-unicorn": "^62.0.0",
|
|
37
|
-
"globals": "^17.
|
|
38
|
-
"jsdom": "^
|
|
39
|
-
"msw": "^2.12.
|
|
40
|
-
"oxlint": "^1.
|
|
41
|
-
"oxlint-tsgolint": "^0.11.
|
|
34
|
+
"globals": "^17.3.0",
|
|
35
|
+
"jsdom": "^28.0.0",
|
|
36
|
+
"msw": "^2.12.8",
|
|
37
|
+
"oxlint": "^1.43.0",
|
|
38
|
+
"oxlint-tsgolint": "^0.11.4",
|
|
42
39
|
"prettier": "^3.8.1",
|
|
43
40
|
"typescript": "^5.9.3",
|
|
44
41
|
"typescript-eslint": "^8.54.0",
|
package/src/index.js
CHANGED
|
@@ -21,6 +21,7 @@ export { TypeCheckError } from './typecheck/TypeCheckError.js';
|
|
|
21
21
|
export { typeCheck, typeCheckArray, typeCheckEnum } from './typecheck/util.js';
|
|
22
22
|
export { delayPromise, loadJSON } from './util/async.js';
|
|
23
23
|
export { getErrorDetails, getTypedError } from './util/error.js';
|
|
24
|
+
export { EventEmitter as EventEmitter3 } from './util/event_emitter.js';
|
|
24
25
|
export { FetchError, fetchRetry, HTTP_0_ANY } from './util/fetch.js';
|
|
25
26
|
export {
|
|
26
27
|
deg2rad,
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
/* oxlint-disable prefer-await-to-callbacks */
|
|
2
|
+
/* eslint-disable unicorn/prefer-event-target */
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Page lifecycle helper.
|
|
5
6
|
* @see https://developer.chrome.com/docs/web-platform/page-lifecycle-api
|
|
6
7
|
*/
|
|
7
8
|
|
|
8
|
-
import { EventEmitter } from 'eventemitter3';
|
|
9
9
|
import { Logger } from '../logging/Logger.js';
|
|
10
|
+
import { EventEmitter } from '../util/event_emitter.js';
|
|
10
11
|
import {
|
|
11
12
|
DOCUMENT_STATE_CHANGE_EVENT,
|
|
12
13
|
DOCUMENT_STATE_DOM_LOADED,
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @callback EventListener
|
|
3
|
+
* A function invoked when an event is emitted.
|
|
4
|
+
* @param {...any} args - Arguments passed from the emitter.
|
|
5
|
+
* @returns {void}
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Internal listener wrapper that stores metadata
|
|
10
|
+
* about a registered event listener.
|
|
11
|
+
*/
|
|
12
|
+
// oxlint-disable-next-line no-extraneous-class
|
|
13
|
+
class Listener {
|
|
14
|
+
/**
|
|
15
|
+
* @param {EventListener} fn - The listener callback function.
|
|
16
|
+
* @param {any} context - The `this` value used when invoking the listener.
|
|
17
|
+
* @param {boolean} [once] - Whether the listener should be invoked only once.
|
|
18
|
+
*/
|
|
19
|
+
constructor(fn, context, once = false) {
|
|
20
|
+
/** @type {EventListener} The listener callback */
|
|
21
|
+
this.fn = fn;
|
|
22
|
+
|
|
23
|
+
/** @type {any} Execution context for the callback */
|
|
24
|
+
this.context = context;
|
|
25
|
+
|
|
26
|
+
/** @type {boolean} Whether this listener is one-time */
|
|
27
|
+
this.once = once;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Event emitter implementation inspired by Node.js/EventEmitter3.
|
|
33
|
+
* Allows registering, emitting, and removing event listeners.
|
|
34
|
+
*/
|
|
35
|
+
export class EventEmitter {
|
|
36
|
+
#events;
|
|
37
|
+
|
|
38
|
+
constructor() {
|
|
39
|
+
/**
|
|
40
|
+
* Map of event name - array of listener wrappers.
|
|
41
|
+
* @type {Map<string | symbol, Listener[]>}
|
|
42
|
+
*/
|
|
43
|
+
this.#events = new Map();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Get all registered event names.
|
|
48
|
+
* @returns {(string | symbol)[]} Array of event identifiers.
|
|
49
|
+
*/
|
|
50
|
+
eventNames() {
|
|
51
|
+
return [...this.#events.keys()];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Get all listener functions registered for an event.
|
|
56
|
+
* @param {string | symbol} event - Event name.
|
|
57
|
+
* @returns {EventListener[]} List of listener callbacks.
|
|
58
|
+
*/
|
|
59
|
+
listeners(event) {
|
|
60
|
+
const listeners = this.#events.get(event);
|
|
61
|
+
return listeners ? listeners.map((l) => l.fn) : [];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Get the number of listeners registered for an event.
|
|
66
|
+
* @param {string | symbol} event - Event name.
|
|
67
|
+
* @returns {number} Number of listeners.
|
|
68
|
+
*/
|
|
69
|
+
listenerCount(event) {
|
|
70
|
+
const listeners = this.#events.get(event);
|
|
71
|
+
return listeners ? listeners.length : 0;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Emit an event, invoking all registered listeners
|
|
76
|
+
* with the provided arguments.
|
|
77
|
+
* @param {string | symbol} event - Event name.
|
|
78
|
+
* @param {...any} args - Arguments passed to listeners.
|
|
79
|
+
* @returns {boolean} True if the event had listeners, otherwise false.
|
|
80
|
+
*/
|
|
81
|
+
emit(event, ...args) {
|
|
82
|
+
const listeners = this.#events.get(event);
|
|
83
|
+
if (!listeners || listeners.length === 0) {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Clone to prevent mutation during iteration
|
|
88
|
+
// eslint-disable-next-line unicorn/no-useless-spread
|
|
89
|
+
for (const listener of [...listeners]) {
|
|
90
|
+
listener.fn.apply(listener.context, args);
|
|
91
|
+
if (listener.once) {
|
|
92
|
+
this.off(event, listener.fn, listener.context);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Internal helper for registering a listener.
|
|
101
|
+
* @param {string | symbol} event - Event name.
|
|
102
|
+
* @param {EventListener} fn - Listener callback.
|
|
103
|
+
* @param {any} context - Execution context for the callback.
|
|
104
|
+
* @param {boolean} once - Whether the listener is one-time.
|
|
105
|
+
* @returns {EventEmitter} The emitter instance.
|
|
106
|
+
*/
|
|
107
|
+
#addListener(event, fn, context, once) {
|
|
108
|
+
if (typeof fn !== 'function') {
|
|
109
|
+
throw new TypeError('Listener must be a function');
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const listener = new Listener(fn, context ?? this, once);
|
|
113
|
+
const listeners = this.#events.get(event);
|
|
114
|
+
|
|
115
|
+
if (listeners) {
|
|
116
|
+
listeners.push(listener);
|
|
117
|
+
} else {
|
|
118
|
+
this.#events.set(event, [listener]);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return this;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Register a persistent listener for an event.
|
|
126
|
+
* @param {string | symbol} event - Event name.
|
|
127
|
+
* @param {EventListener} fn - Listener callback.
|
|
128
|
+
* @param {any} [context] - Optional execution context.
|
|
129
|
+
* @returns {EventEmitter} The emitter instance.
|
|
130
|
+
*/
|
|
131
|
+
on(event, fn, context) {
|
|
132
|
+
return this.#addListener(event, fn, context, false);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Register a one-time listener for an event.
|
|
137
|
+
* The listener is removed after its first invocation.
|
|
138
|
+
* @param {string | symbol} event - Event name.
|
|
139
|
+
* @param {EventListener} fn - Listener callback.
|
|
140
|
+
* @param {any} [context] - Optional execution context.
|
|
141
|
+
* @returns {EventEmitter} The emitter instance.
|
|
142
|
+
*/
|
|
143
|
+
once(event, fn, context) {
|
|
144
|
+
return this.#addListener(event, fn, context, true);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Remove a specific listener, or all listeners for an event.
|
|
149
|
+
* @param {string | symbol} event - Event name.
|
|
150
|
+
* @param {EventListener} [fn] - Listener callback to remove.
|
|
151
|
+
* @param {any} [context] - Context to match when removing.
|
|
152
|
+
* @returns {EventEmitter} The emitter instance.
|
|
153
|
+
*/
|
|
154
|
+
off(event, fn, context) {
|
|
155
|
+
if (!this.#events.has(event)) {
|
|
156
|
+
return this;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (!fn) {
|
|
160
|
+
this.#events.delete(event);
|
|
161
|
+
return this;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const filtered = this.#events.get(event).filter((listener) => {
|
|
165
|
+
if (listener.fn !== fn) {
|
|
166
|
+
return true;
|
|
167
|
+
}
|
|
168
|
+
if (context !== undefined && listener.context !== context) {
|
|
169
|
+
return true;
|
|
170
|
+
}
|
|
171
|
+
return false;
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
if (filtered.length > 0) {
|
|
175
|
+
this.#events.set(event, filtered);
|
|
176
|
+
} else {
|
|
177
|
+
this.#events.delete(event);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return this;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Remove all listeners from the emitter,
|
|
185
|
+
* or all listeners for a specific event.
|
|
186
|
+
* @param {string | symbol} [event] - Optional event name.
|
|
187
|
+
* @returns {EventEmitter} The emitter instance.
|
|
188
|
+
*/
|
|
189
|
+
removeAllListeners(event) {
|
|
190
|
+
if (event === undefined) {
|
|
191
|
+
this.#events.clear();
|
|
192
|
+
} else {
|
|
193
|
+
this.#events.delete(event);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return this;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/* eslint-disable unicorn/prefer-event-target, no-empty-function, no-invalid-this, func-names, func-style, unicorn/consistent-function-scoping */
|
|
2
|
+
|
|
3
|
+
import { describe, it, expect } from 'vitest';
|
|
4
|
+
import { EventEmitter } from './event_emitter.js';
|
|
5
|
+
|
|
6
|
+
describe('EventEmitter3 basics', () => {
|
|
7
|
+
it('can be instantiated', () => {
|
|
8
|
+
const e = new EventEmitter();
|
|
9
|
+
expect(e).toBeInstanceOf(EventEmitter);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('supports subclassing', () => {
|
|
13
|
+
class Beast extends EventEmitter {}
|
|
14
|
+
const beast = new Beast();
|
|
15
|
+
|
|
16
|
+
expect(beast).toBeInstanceOf(Beast);
|
|
17
|
+
expect(beast).toBeInstanceOf(EventEmitter);
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
describe('emit()', () => {
|
|
22
|
+
it('returns false when no listeners exist', () => {
|
|
23
|
+
const e = new EventEmitter();
|
|
24
|
+
expect(e.emit('foo')).toBe(false);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('returns true when listeners exist', () => {
|
|
28
|
+
const e = new EventEmitter();
|
|
29
|
+
e.on('foo', () => {});
|
|
30
|
+
expect(e.emit('foo')).toBe(true);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('invokes listeners with provided arguments', async () => {
|
|
34
|
+
const e = new EventEmitter();
|
|
35
|
+
|
|
36
|
+
await new Promise((resolve) => {
|
|
37
|
+
e.on('foo', (a, b) => {
|
|
38
|
+
expect(a).toBe(1);
|
|
39
|
+
expect(b).toBe(2);
|
|
40
|
+
resolve();
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
e.emit('foo', 1, 2);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('binds the correct context', async () => {
|
|
48
|
+
const e = new EventEmitter();
|
|
49
|
+
const ctx = { value: 42 };
|
|
50
|
+
|
|
51
|
+
await new Promise((resolve) => {
|
|
52
|
+
e.on(
|
|
53
|
+
'foo',
|
|
54
|
+
function () {
|
|
55
|
+
// @ts-expect-error
|
|
56
|
+
expect(this).toBe(ctx);
|
|
57
|
+
resolve();
|
|
58
|
+
},
|
|
59
|
+
ctx
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
e.emit('foo');
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('supports many listeners for the same event', () => {
|
|
67
|
+
const e = new EventEmitter();
|
|
68
|
+
const calls = [];
|
|
69
|
+
|
|
70
|
+
e.on('foo', () => calls.push(1));
|
|
71
|
+
e.on('foo', () => calls.push(2));
|
|
72
|
+
|
|
73
|
+
e.emit('foo');
|
|
74
|
+
|
|
75
|
+
expect(calls).toEqual([1, 2]);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
describe('once()', () => {
|
|
80
|
+
it('fires the listener only once', () => {
|
|
81
|
+
const e = new EventEmitter();
|
|
82
|
+
let calls = 0;
|
|
83
|
+
|
|
84
|
+
e.once('foo', () => {
|
|
85
|
+
calls += 1;
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
e.emit('foo');
|
|
89
|
+
e.emit('foo');
|
|
90
|
+
|
|
91
|
+
expect(calls).toBe(1);
|
|
92
|
+
expect(e.listenerCount('foo')).toBe(0);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('passes arguments correctly', async () => {
|
|
96
|
+
const e = new EventEmitter();
|
|
97
|
+
|
|
98
|
+
await new Promise((resolve) => {
|
|
99
|
+
e.once('foo', (...args) => {
|
|
100
|
+
expect(args).toEqual([1, 2, 3]);
|
|
101
|
+
resolve();
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
e.emit('foo', 1, 2, 3);
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
describe('listeners() and listenerCount()', () => {
|
|
110
|
+
it('returns an empty array when no listeners exist', () => {
|
|
111
|
+
const e = new EventEmitter();
|
|
112
|
+
expect(e.listeners('foo')).toEqual([]);
|
|
113
|
+
expect(e.listenerCount('foo')).toBe(0);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it('returns only listener functions (not internals)', () => {
|
|
117
|
+
const e = new EventEmitter();
|
|
118
|
+
function fn() {}
|
|
119
|
+
|
|
120
|
+
e.on('foo', fn);
|
|
121
|
+
|
|
122
|
+
expect(e.listeners('foo')).toEqual([fn]);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('does not expose internal listener storage', () => {
|
|
126
|
+
const e = new EventEmitter();
|
|
127
|
+
function fn() {}
|
|
128
|
+
|
|
129
|
+
e.on('foo', fn);
|
|
130
|
+
const listeners = e.listeners('foo');
|
|
131
|
+
listeners.push(() => {});
|
|
132
|
+
|
|
133
|
+
expect(e.listeners('foo')).toEqual([fn]);
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
describe('off()', () => {
|
|
138
|
+
it('removes all listeners for an event when fn is omitted', () => {
|
|
139
|
+
const e = new EventEmitter();
|
|
140
|
+
|
|
141
|
+
e.on('foo', () => {});
|
|
142
|
+
e.on('foo', () => {});
|
|
143
|
+
|
|
144
|
+
e.off('foo');
|
|
145
|
+
|
|
146
|
+
expect(e.listenerCount('foo')).toBe(0);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it('removes a specific listener', () => {
|
|
150
|
+
const e = new EventEmitter();
|
|
151
|
+
function fn() {}
|
|
152
|
+
|
|
153
|
+
e.on('foo', fn);
|
|
154
|
+
e.off('foo', fn);
|
|
155
|
+
|
|
156
|
+
expect(e.listeners('foo')).toEqual([]);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it('removes listeners matching both function and context', () => {
|
|
160
|
+
const e = new EventEmitter();
|
|
161
|
+
const ctx1 = {};
|
|
162
|
+
const ctx2 = {};
|
|
163
|
+
function fn() {}
|
|
164
|
+
|
|
165
|
+
e.on('foo', fn, ctx1);
|
|
166
|
+
e.on('foo', fn, ctx2);
|
|
167
|
+
|
|
168
|
+
e.off('foo', fn, ctx1);
|
|
169
|
+
|
|
170
|
+
expect(e.listenerCount('foo')).toBe(1);
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
describe('removeAllListeners()', () => {
|
|
175
|
+
it('removes listeners for a single event', () => {
|
|
176
|
+
const e = new EventEmitter();
|
|
177
|
+
|
|
178
|
+
e.on('foo', () => {});
|
|
179
|
+
e.on('bar', () => {});
|
|
180
|
+
|
|
181
|
+
e.removeAllListeners('foo');
|
|
182
|
+
|
|
183
|
+
expect(e.listenerCount('foo')).toBe(0);
|
|
184
|
+
expect(e.listenerCount('bar')).toBe(1);
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it('removes all listeners when no event is specified', () => {
|
|
188
|
+
const e = new EventEmitter();
|
|
189
|
+
|
|
190
|
+
e.on('foo', () => {});
|
|
191
|
+
e.on('bar', () => {});
|
|
192
|
+
|
|
193
|
+
e.removeAllListeners();
|
|
194
|
+
|
|
195
|
+
expect(e.eventNames()).toEqual([]);
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
describe('eventNames()', () => {
|
|
200
|
+
it('returns an empty array when no events exist', () => {
|
|
201
|
+
const e = new EventEmitter();
|
|
202
|
+
expect(e.eventNames()).toEqual([]);
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it('returns all registered event names', () => {
|
|
206
|
+
const e = new EventEmitter();
|
|
207
|
+
|
|
208
|
+
e.on('foo', () => {});
|
|
209
|
+
e.on('bar', () => {});
|
|
210
|
+
|
|
211
|
+
expect(e.eventNames()).toContain('foo');
|
|
212
|
+
expect(e.eventNames()).toContain('bar');
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
it('supports symbol event names', () => {
|
|
216
|
+
const e = new EventEmitter();
|
|
217
|
+
const sym = Symbol('test');
|
|
218
|
+
|
|
219
|
+
e.on(sym, () => {});
|
|
220
|
+
expect(e.eventNames()).toContain(sym);
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
it('events map is instance field', () => {
|
|
224
|
+
const e1 = new EventEmitter();
|
|
225
|
+
const e2 = new EventEmitter();
|
|
226
|
+
e1.on('event', () => {});
|
|
227
|
+
expect(e1.listenerCount('event')).toBe(1);
|
|
228
|
+
expect(e1.listenerCount('no-event')).toBe(0);
|
|
229
|
+
expect(e2.listenerCount('event')).toBe(0);
|
|
230
|
+
});
|
|
231
|
+
});
|
package/src/util/object.js
CHANGED
|
@@ -8,9 +8,8 @@ export const purgeObject = (target) => {
|
|
|
8
8
|
if (!target) {
|
|
9
9
|
return;
|
|
10
10
|
}
|
|
11
|
-
const reference = target;
|
|
12
11
|
for (const entry of Object.keys(target)) {
|
|
13
|
-
|
|
12
|
+
target[entry] = null;
|
|
14
13
|
}
|
|
15
14
|
};
|
|
16
15
|
|
|
@@ -51,6 +50,7 @@ export const deepMerge = (target, source) => {
|
|
|
51
50
|
* @returns {number} The sum value.
|
|
52
51
|
*/
|
|
53
52
|
export const getObjArrayPropSum = (arr, prop) => arr.reduce((accumulator, object) => accumulator + object[prop], 0);
|
|
53
|
+
|
|
54
54
|
/**
|
|
55
55
|
* Get object value by path.
|
|
56
56
|
* @param {object} obj - The source object to get the value from.
|
package/types/index.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ export { OpenTelemetryLogHandler } from "./logging/OpenTelemetryLogHandler.js";
|
|
|
10
10
|
export { SentryLogHandler } from "./logging/SentryLogHandler.js";
|
|
11
11
|
export { typeChecker } from "./typecheck/TypeChecker.js";
|
|
12
12
|
export { TypeCheckError } from "./typecheck/TypeCheckError.js";
|
|
13
|
+
export { EventEmitter as EventEmitter3 } from "./util/event_emitter.js";
|
|
13
14
|
export { serverDataToState } from "./util/state.js";
|
|
14
15
|
export { formatLogMessage, getLogLevelName } from "./logging/util.js";
|
|
15
16
|
export { addPageLifecycleCallback, getDocumentState, getPageLifecycleEventEmitter, getPageLifecycleState, initPageLifecycle, isPageLifecycleInitialized } from "./pagelifecycle/util.js";
|
|
@@ -4,5 +4,5 @@ export function getDocumentState(): import("./typedef.js").DocumentState | null
|
|
|
4
4
|
export function getPageLifecycleEventEmitter(): EventEmitter;
|
|
5
5
|
export function isPageLifecycleInitialized(): boolean;
|
|
6
6
|
export function addPageLifecycleCallback(state: import("./typedef.js").DocumentState | import("./typedef.js").PageLifecycleState, callback: () => void): void;
|
|
7
|
-
import { EventEmitter } from '
|
|
7
|
+
import { EventEmitter } from '../util/event_emitter.js';
|
|
8
8
|
//# sourceMappingURL=util.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../src/pagelifecycle/util.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../src/pagelifecycle/util.js"],"names":[],"mappings":"AAmGO,0CAyBN;AAMM,yCAFM,MAAM,GAAG,IAAI,GAAG,SAAS,CAE8B;AAM7D,oCAFM,OAAO,cAAc,EAAE,aAAa,GAAG,IAAI,GAAG,SAAS,CAEV;AAMnD,gDAFM,YAAY,CAOxB;AAMM,8CAFM,OAAO,CAEyC;AAOtD,gDAHI,OAAO,cAAc,EAAE,aAAa,GAAG,OAAO,cAAc,EAAE,kBAAkB,YAChF,MAAM,IAAI,QAMpB;6BA3J4B,0BAA0B"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Event emitter implementation inspired by Node.js/EventEmitter3.
|
|
3
|
+
* Allows registering, emitting, and removing event listeners.
|
|
4
|
+
*/
|
|
5
|
+
export class EventEmitter {
|
|
6
|
+
/**
|
|
7
|
+
* Get all registered event names.
|
|
8
|
+
* @returns {(string | symbol)[]} Array of event identifiers.
|
|
9
|
+
*/
|
|
10
|
+
eventNames(): (string | symbol)[];
|
|
11
|
+
/**
|
|
12
|
+
* Get all listener functions registered for an event.
|
|
13
|
+
* @param {string | symbol} event - Event name.
|
|
14
|
+
* @returns {EventListener[]} List of listener callbacks.
|
|
15
|
+
*/
|
|
16
|
+
listeners(event: string | symbol): EventListener[];
|
|
17
|
+
/**
|
|
18
|
+
* Get the number of listeners registered for an event.
|
|
19
|
+
* @param {string | symbol} event - Event name.
|
|
20
|
+
* @returns {number} Number of listeners.
|
|
21
|
+
*/
|
|
22
|
+
listenerCount(event: string | symbol): number;
|
|
23
|
+
/**
|
|
24
|
+
* Emit an event, invoking all registered listeners
|
|
25
|
+
* with the provided arguments.
|
|
26
|
+
* @param {string | symbol} event - Event name.
|
|
27
|
+
* @param {...any} args - Arguments passed to listeners.
|
|
28
|
+
* @returns {boolean} True if the event had listeners, otherwise false.
|
|
29
|
+
*/
|
|
30
|
+
emit(event: string | symbol, ...args: any[]): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Register a persistent listener for an event.
|
|
33
|
+
* @param {string | symbol} event - Event name.
|
|
34
|
+
* @param {EventListener} fn - Listener callback.
|
|
35
|
+
* @param {any} [context] - Optional execution context.
|
|
36
|
+
* @returns {EventEmitter} The emitter instance.
|
|
37
|
+
*/
|
|
38
|
+
on(event: string | symbol, fn: EventListener, context?: any): EventEmitter;
|
|
39
|
+
/**
|
|
40
|
+
* Register a one-time listener for an event.
|
|
41
|
+
* The listener is removed after its first invocation.
|
|
42
|
+
* @param {string | symbol} event - Event name.
|
|
43
|
+
* @param {EventListener} fn - Listener callback.
|
|
44
|
+
* @param {any} [context] - Optional execution context.
|
|
45
|
+
* @returns {EventEmitter} The emitter instance.
|
|
46
|
+
*/
|
|
47
|
+
once(event: string | symbol, fn: EventListener, context?: any): EventEmitter;
|
|
48
|
+
/**
|
|
49
|
+
* Remove a specific listener, or all listeners for an event.
|
|
50
|
+
* @param {string | symbol} event - Event name.
|
|
51
|
+
* @param {EventListener} [fn] - Listener callback to remove.
|
|
52
|
+
* @param {any} [context] - Context to match when removing.
|
|
53
|
+
* @returns {EventEmitter} The emitter instance.
|
|
54
|
+
*/
|
|
55
|
+
off(event: string | symbol, fn?: EventListener, context?: any): EventEmitter;
|
|
56
|
+
/**
|
|
57
|
+
* Remove all listeners from the emitter,
|
|
58
|
+
* or all listeners for a specific event.
|
|
59
|
+
* @param {string | symbol} [event] - Optional event name.
|
|
60
|
+
* @returns {EventEmitter} The emitter instance.
|
|
61
|
+
*/
|
|
62
|
+
removeAllListeners(event?: string | symbol): EventEmitter;
|
|
63
|
+
#private;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* A function invoked when an event is emitted.
|
|
67
|
+
*/
|
|
68
|
+
export type EventListener = (...args: any[]) => void;
|
|
69
|
+
//# sourceMappingURL=event_emitter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event_emitter.d.ts","sourceRoot":"","sources":["../../src/util/event_emitter.js"],"names":[],"mappings":"AA8BA;;;GAGG;AACH;IAWE;;;OAGG;IACH,cAFa,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAI/B;IAED;;;;OAIG;IACH,iBAHW,MAAM,GAAG,MAAM,GACb,aAAa,EAAE,CAK3B;IAED;;;;OAIG;IACH,qBAHW,MAAM,GAAG,MAAM,GACb,MAAM,CAKlB;IAED;;;;;;OAMG;IACH,YAJW,MAAM,GAAG,MAAM,WACZ,GAAG,EAAA,GACJ,OAAO,CAkBnB;IA2BD;;;;;;OAMG;IACH,UALW,MAAM,GAAG,MAAM,MACf,aAAa,YACb,GAAG,GACD,YAAY,CAIxB;IAED;;;;;;;OAOG;IACH,YALW,MAAM,GAAG,MAAM,MACf,aAAa,YACb,GAAG,GACD,YAAY,CAIxB;IAED;;;;;;OAMG;IACH,WALW,MAAM,GAAG,MAAM,OACf,aAAa,YACb,GAAG,GACD,YAAY,CA6BxB;IAED;;;;;OAKG;IACH,2BAHW,MAAM,GAAG,MAAM,GACb,YAAY,CAUxB;;CACF;;;;sCAlMa,GAAG,EAAA,KACJ,IAAI"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"object.d.ts","sourceRoot":"","sources":["../../src/util/object.js"],"names":[],"mappings":"AAMO,oCAFI,MAAM,
|
|
1
|
+
{"version":3,"file":"object.d.ts","sourceRoot":"","sources":["../../src/util/object.js"],"names":[],"mappings":"AAMO,oCAFI,MAAM,QAShB;AAQM,kCAJI,MAAM,UACN,MAAM,GACJ,MAAM,CAwBlB;AAQM,wCAJI,MAAM,EAAE,QACR,MAAM,GACJ,MAAM,CAEgG;AAQ5G,uCAJI,MAAM,QACN,MAAM,GACJ,MAAM,GAAG,IAAI,CAezB;AASM,uCALI,MAAM,QACN,MAAM,SACN,MAAM,GAAG,IAAI,GAAG,SAAS,QAqBnC"}
|