@lowentry/utils 1.21.1 → 1.22.1
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/build/classes/EventEmitter.d.ts +46 -0
- package/build/index.d.ts +1 -0
- package/index.d.ts +47 -0
- package/index.js +150 -12
- package/index.js.map +1 -1
- package/package.json +1 -1
- package/src/classes/EventEmitter.js +124 -0
- package/src/index.js +1 -0
- package/tests/event-emitter.test.js +179 -0
package/package.json
CHANGED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A simple event emitter class that allows you to register listeners for events, emit events, and remove listeners.
|
|
3
|
+
*/
|
|
4
|
+
export class EventEmitter
|
|
5
|
+
{
|
|
6
|
+
/** @type {Map<string, Set<Function>>} */
|
|
7
|
+
#events;
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Creates a new EventEmitter instance.
|
|
12
|
+
*/
|
|
13
|
+
constructor()
|
|
14
|
+
{
|
|
15
|
+
this.#events = new Map();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Registers a listener for a specific event.
|
|
21
|
+
*
|
|
22
|
+
* @param {string} event - The name of the event to listen for.
|
|
23
|
+
* @param {Function} listener - The function to call when the event is emitted.
|
|
24
|
+
* @returns {{remove:(()=>void)}}
|
|
25
|
+
*/
|
|
26
|
+
on(event, listener)
|
|
27
|
+
{
|
|
28
|
+
if(!this.#events.has(event))
|
|
29
|
+
{
|
|
30
|
+
this.#events.set(event, new Set());
|
|
31
|
+
}
|
|
32
|
+
this.#events.get(event)?.add(listener);
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
remove:
|
|
36
|
+
() => this.off(event, listener),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Registers a listener for a specific event, this listener will be called only once.
|
|
42
|
+
*
|
|
43
|
+
* @param {string} event - The name of the event to listen for.
|
|
44
|
+
* @param {Function} listener - The function to call when the event is emitted.
|
|
45
|
+
* @returns {{remove:()=>void}}
|
|
46
|
+
*/
|
|
47
|
+
once(event, listener)
|
|
48
|
+
{
|
|
49
|
+
const wrapper = (/** @type {*[]} */ ...args) =>
|
|
50
|
+
{
|
|
51
|
+
this.off(event, wrapper);
|
|
52
|
+
listener(...args);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
this.on(event, wrapper);
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
remove:
|
|
59
|
+
() => this.off(event, wrapper),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Removes a listener for a specific event.
|
|
65
|
+
*
|
|
66
|
+
* @param {string} event - The name of the event to stop listening for.
|
|
67
|
+
* @param {Function} listener - The function to remove from the event listeners.
|
|
68
|
+
*/
|
|
69
|
+
off(event, listener)
|
|
70
|
+
{
|
|
71
|
+
const listeners = this.#events.get(event);
|
|
72
|
+
if(listeners)
|
|
73
|
+
{
|
|
74
|
+
listeners.delete(listener);
|
|
75
|
+
if(listeners.size === 0)
|
|
76
|
+
{
|
|
77
|
+
this.#events.delete(event);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Emits an event, calling all registered listeners with the provided arguments.
|
|
84
|
+
*
|
|
85
|
+
* @param {string} event - The name of the event to emit.
|
|
86
|
+
* @param {...*} args - The arguments to pass to the listeners.
|
|
87
|
+
*/
|
|
88
|
+
emit(event, ...args)
|
|
89
|
+
{
|
|
90
|
+
const listeners = this.#events.get(event);
|
|
91
|
+
if(listeners)
|
|
92
|
+
{
|
|
93
|
+
const snapshot = [...listeners];
|
|
94
|
+
for(const listener of snapshot)
|
|
95
|
+
{
|
|
96
|
+
try
|
|
97
|
+
{
|
|
98
|
+
listener(...args);
|
|
99
|
+
}
|
|
100
|
+
catch(err)
|
|
101
|
+
{
|
|
102
|
+
console.error(`Error in listener for "${event}":`, err);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Clears all listeners for a specific event or all events if no event is specified.
|
|
110
|
+
*
|
|
111
|
+
* @param {string} [event] - The name of the event to clear listeners for. If not provided, all events will be cleared.
|
|
112
|
+
*/
|
|
113
|
+
clear(event)
|
|
114
|
+
{
|
|
115
|
+
if(event !== undefined)
|
|
116
|
+
{
|
|
117
|
+
this.#events.delete(event);
|
|
118
|
+
}
|
|
119
|
+
else
|
|
120
|
+
{
|
|
121
|
+
this.#events.clear();
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
package/src/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export {LeUtils} from './LeUtils.js';
|
|
2
2
|
export {ISSET, IS_ARRAY, ARRAY, IS_OBJECT, OBJECT, STRING, STRING_ANY, INT, INT_ANY, FLOAT, FLOAT_ANY, INT_LAX, INT_LAX_ANY, FLOAT_LAX, FLOAT_LAX_ANY} from './LeTypes.js';
|
|
3
|
+
export {EventEmitter} from './classes/EventEmitter.js';
|
|
3
4
|
export {LinkedList} from './classes/LinkedList.js';
|
|
4
5
|
export {SerializableMap} from './classes/SerializableMap.js';
|
|
5
6
|
export {TreeSet} from './classes/TreeSet.js';
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import {describe, test, expect} from 'vitest';
|
|
2
|
+
import {EventEmitter} from '../src/index.js';
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
describe('EventEmitter', () =>
|
|
6
|
+
{
|
|
7
|
+
test('should create an instance of EventEmitter', () =>
|
|
8
|
+
{
|
|
9
|
+
const emitter = new EventEmitter();
|
|
10
|
+
expect(emitter).toBeInstanceOf(EventEmitter);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
test('should emit and listen to events', () =>
|
|
14
|
+
{
|
|
15
|
+
const emitter = new EventEmitter();
|
|
16
|
+
let called = 0;
|
|
17
|
+
|
|
18
|
+
emitter.on('testEvent', () =>
|
|
19
|
+
{
|
|
20
|
+
called++;
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
emitter.emit('testEvent');
|
|
24
|
+
expect(called).toBe(1);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test('should remove event listeners', () =>
|
|
28
|
+
{
|
|
29
|
+
const emitter = new EventEmitter();
|
|
30
|
+
let called = 0;
|
|
31
|
+
|
|
32
|
+
const listener = () =>
|
|
33
|
+
{
|
|
34
|
+
called++;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
emitter.on('testEvent', listener);
|
|
38
|
+
emitter.off('testEvent', listener);
|
|
39
|
+
|
|
40
|
+
emitter.emit('testEvent');
|
|
41
|
+
expect(called).toBe(0);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test('should handle multiple listeners for the same event', () =>
|
|
45
|
+
{
|
|
46
|
+
const emitter = new EventEmitter();
|
|
47
|
+
let called1 = 0;
|
|
48
|
+
let called2 = 0;
|
|
49
|
+
|
|
50
|
+
const listener1 = () =>
|
|
51
|
+
{
|
|
52
|
+
called1++;
|
|
53
|
+
};
|
|
54
|
+
const listener2 = () =>
|
|
55
|
+
{
|
|
56
|
+
called2++;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
emitter.on('testEvent', listener1);
|
|
60
|
+
emitter.on('testEvent', listener2);
|
|
61
|
+
|
|
62
|
+
emitter.emit('testEvent');
|
|
63
|
+
expect(called1).toBe(1);
|
|
64
|
+
expect(called2).toBe(1);
|
|
65
|
+
|
|
66
|
+
emitter.off('testEvent', listener1);
|
|
67
|
+
emitter.emit('testEvent');
|
|
68
|
+
expect(called1).toBe(1);
|
|
69
|
+
expect(called2).toBe(2);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
test('should handle event names with special characters', () =>
|
|
73
|
+
{
|
|
74
|
+
const emitter = new EventEmitter();
|
|
75
|
+
let called = 0;
|
|
76
|
+
|
|
77
|
+
emitter.on('test-event!@#$', () =>
|
|
78
|
+
{
|
|
79
|
+
called++;
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
emitter.emit('test-event!@#$');
|
|
83
|
+
expect(called).toBe(1);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
test('should handle event names with spaces', () =>
|
|
87
|
+
{
|
|
88
|
+
const emitter = new EventEmitter();
|
|
89
|
+
let called = 0;
|
|
90
|
+
|
|
91
|
+
emitter.on('test event with spaces', () =>
|
|
92
|
+
{
|
|
93
|
+
called++;
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
emitter.emit('test event with spaces');
|
|
97
|
+
expect(called).toBe(1);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
test('should be able to remove a listener using the returned listener object', () =>
|
|
101
|
+
{
|
|
102
|
+
const emitter = new EventEmitter();
|
|
103
|
+
let called = 0;
|
|
104
|
+
|
|
105
|
+
const listener = emitter.on('test123', () =>
|
|
106
|
+
{
|
|
107
|
+
called++;
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
emitter.emit('test123');
|
|
111
|
+
expect(called).toBe(1);
|
|
112
|
+
|
|
113
|
+
listener.remove();
|
|
114
|
+
emitter.emit('test123');
|
|
115
|
+
expect(called).toBe(1);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test('should handle multiple events with the same name', () =>
|
|
119
|
+
{
|
|
120
|
+
const emitter = new EventEmitter();
|
|
121
|
+
let called1 = 0;
|
|
122
|
+
let called2 = 0;
|
|
123
|
+
|
|
124
|
+
emitter.on('testEvent', () =>
|
|
125
|
+
{
|
|
126
|
+
called1++;
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
emitter.on('testEvent', () =>
|
|
130
|
+
{
|
|
131
|
+
called2++;
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
emitter.emit('testEvent');
|
|
135
|
+
expect(called1).toBe(1);
|
|
136
|
+
expect(called2).toBe(1);
|
|
137
|
+
|
|
138
|
+
emitter.clear('testEvent');
|
|
139
|
+
emitter.emit('testEvent');
|
|
140
|
+
expect(called1).toBe(1);
|
|
141
|
+
expect(called2).toBe(1);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
test('should handle once() method', () =>
|
|
145
|
+
{
|
|
146
|
+
const emitter = new EventEmitter();
|
|
147
|
+
let called = 0;
|
|
148
|
+
|
|
149
|
+
emitter.once('testOnce', () =>
|
|
150
|
+
{
|
|
151
|
+
called++;
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
emitter.emit('testOnce');
|
|
155
|
+
expect(called).toBe(1);
|
|
156
|
+
|
|
157
|
+
emitter.emit('testOnce');
|
|
158
|
+
expect(called).toBe(1);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
test('should allow canceling a once listener using .remove()', () =>
|
|
162
|
+
{
|
|
163
|
+
const emitter = new EventEmitter();
|
|
164
|
+
let called = 0;
|
|
165
|
+
|
|
166
|
+
const listener = emitter.once('testOnceCancel', () =>
|
|
167
|
+
{
|
|
168
|
+
called++;
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
listener.remove();
|
|
172
|
+
|
|
173
|
+
emitter.emit('testOnceCancel');
|
|
174
|
+
expect(called).toBe(0);
|
|
175
|
+
|
|
176
|
+
emitter.emit('testOnceCancel');
|
|
177
|
+
expect(called).toBe(0);
|
|
178
|
+
});
|
|
179
|
+
});
|