@blackglory/structures 0.14.0 → 0.14.2

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/README.md CHANGED
@@ -73,6 +73,78 @@ class Emitter<
73
73
  }
74
74
  ```
75
75
 
76
+ ### GeneratorEmitter
77
+ ```ts
78
+ type Listener<Args extends unknown[], Yield, Next> = (...args: Args) =>
79
+ | void
80
+ | Generator<Yield, void, Next>
81
+
82
+ class GeneratorEmitter<
83
+ EventToArgs extends Record<Event, unknown[]> = Record<
84
+ string | number | symbol
85
+ , unknown[]
86
+ >
87
+ , Event extends string | number | symbol = keyof EventToArgs
88
+ , Yield = unknown
89
+ , Next = unknown
90
+ > {
91
+ get [Symbol.toStringTag](): string
92
+
93
+ on<T extends Event>(
94
+ event: T
95
+ , listener: Listener<EventToArgs[T], Yield, Next>
96
+ ): () => void
97
+
98
+ once<T extends Event>(
99
+ event: T
100
+ , listener: Listener<EventToArgs[T], Yield, Next>
101
+ ): () => void
102
+
103
+ emit<T extends Event>(
104
+ event: T
105
+ , ...args: EventToArgs[T]
106
+ ): Generator<Yield, void, Next>
107
+
108
+ removeAllListeners<T extends Event>(event: T): void
109
+ }
110
+ ```
111
+
112
+ ### AsyncGeneratorEmitter
113
+ ```ts
114
+ type Listener<Args extends unknown[], Yield, Next> = (...args: Args) =>
115
+ | void
116
+ | Generator<Yield, void, Next>
117
+ | AsyncGenerator<Yield, void, Next>
118
+
119
+ class AsyncGeneratorEmitter<
120
+ EventToArgs extends Record<Event, unknown[]> = Record<
121
+ string | number | symbol
122
+ , unknown[]
123
+ >
124
+ , Event extends string | number | symbol = keyof EventToArgs
125
+ , Yield = unknown
126
+ , Next = unknown
127
+ > {
128
+ get [Symbol.toStringTag](): string
129
+
130
+ on<T extends Event>(event: T
131
+ , listener: Listener<EventToArgs[T], Yield, Next>
132
+ ): () => void
133
+
134
+ once<T extends Event>(
135
+ event: T
136
+ , listener: Listener<EventToArgs[T], Yield, Next>
137
+ ): () => void
138
+
139
+ emit<T extends Event>(
140
+ event: T
141
+ , ...args: EventToArgs[T]
142
+ ): AsyncGenerator<Yield, void, Next>
143
+
144
+ removeAllListeners<T extends Event>(event: T): void
145
+ }
146
+ ```
147
+
76
148
  ### BigMap
77
149
  ```ts
78
150
  class BigMap<K, V> implements Iterable<[K, V]> {
@@ -0,0 +1,10 @@
1
+ type Listener<Args extends unknown[], Yield, Next> = (...args: Args) => void | Generator<Yield, void, Next> | AsyncGenerator<Yield, void, Next>;
2
+ export declare class AsyncGeneratorEmitter<EventToArgs extends Record<Event, unknown[]> = Record<string | number | symbol, unknown[]>, Event extends string | number | symbol = keyof EventToArgs, Yield = unknown, Next = unknown> {
3
+ private map;
4
+ get [Symbol.toStringTag](): string;
5
+ on<T extends Event>(event: T, listener: Listener<EventToArgs[T], Yield, Next>): () => void;
6
+ once<T extends Event>(event: T, listener: Listener<EventToArgs[T], Yield, Next>): () => void;
7
+ emit<T extends Event>(event: T, ...args: EventToArgs[T]): AsyncGenerator<Yield, void, Next>;
8
+ removeAllListeners<T extends Event>(event: T): void;
9
+ }
10
+ export {};
@@ -0,0 +1,55 @@
1
+ import { go, goAsyncGenerator } from '@blackglory/go';
2
+ export class AsyncGeneratorEmitter {
3
+ constructor() {
4
+ this.map = new Map();
5
+ }
6
+ get [Symbol.toStringTag]() {
7
+ return this.constructor.name;
8
+ }
9
+ on(event, listener) {
10
+ const set = go(() => {
11
+ const set = this.map.get(event);
12
+ if (set) {
13
+ return set;
14
+ }
15
+ else {
16
+ const set = new Set();
17
+ this.map.set(event, set);
18
+ return set;
19
+ }
20
+ });
21
+ set.add(handler);
22
+ return () => {
23
+ const handlers = this.map.get(event);
24
+ if (handlers) {
25
+ const deleted = handlers.delete(handler);
26
+ if (deleted && handlers.size === 0) {
27
+ this.map.delete(event);
28
+ }
29
+ }
30
+ };
31
+ async function* handler(...args) {
32
+ yield* goAsyncGenerator(() => listener(...args));
33
+ }
34
+ }
35
+ once(event, listener) {
36
+ const removeListener = this.on(event, async function* (...args) {
37
+ yield* goAsyncGenerator(() => listener(...args));
38
+ removeListener();
39
+ });
40
+ return removeListener;
41
+ }
42
+ async *emit(event, ...args) {
43
+ const listeners = this.map.get(event);
44
+ if (listeners) {
45
+ for (const listener of listeners) {
46
+ yield* goAsyncGenerator(() => listener(...args));
47
+ }
48
+ }
49
+ }
50
+ removeAllListeners(event) {
51
+ var _a;
52
+ (_a = this.map.get(event)) === null || _a === void 0 ? void 0 : _a.clear();
53
+ }
54
+ }
55
+ //# sourceMappingURL=async-generator-emitter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"async-generator-emitter.js","sourceRoot":"","sources":["../src/async-generator-emitter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAOrD,MAAM,OAAO,qBAAqB;IAAlC;QASU,QAAG,GAAG,IAAI,GAAG,EAGlB,CAAA;IA0EL,CAAC;IAxEC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC;QACtB,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,CAAA;IAC9B,CAAC;IAED,EAAE,CACA,KAAQ,EACR,QAA+C;QAE/C,MAAM,GAAG,GAAG,EAAE,CAAC,GAAG,EAAE;YAClB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;YAC/B,IAAI,GAAG,EAAE,CAAC;gBACR,OAAO,GAAG,CAAA;YACZ,CAAC;iBAAM,CAAC;gBACN,MAAM,GAAG,GAAG,IAAI,GAAG,EAAyD,CAAA;gBAC5E,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;gBACxB,OAAO,GAAG,CAAA;YACZ,CAAC;QACH,CAAC,CAAC,CAAA;QACF,GAAG,CAAC,GAAG,CAAC,OAAoD,CAAC,CAAA;QAE7D,OAAO,GAAG,EAAE;YACV,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;YACpC,IAAI,QAAQ,EAAE,CAAC;gBACb,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAC7B,OAAoD,CACrD,CAAA;gBACD,IAAI,OAAO,IAAI,QAAQ,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;oBACnC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;gBACxB,CAAC;YACH,CAAC;QACH,CAAC,CAAA;QAED,KAAK,SAAU,CAAC,CAAC,OAAO,CACtB,GAAG,IAAuD;YAE1D,KAAK,CAAC,CAAC,gBAAgB,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC,CAAC,CAAA;QAClD,CAAC;IACH,CAAC;IAED,IAAI,CACF,KAAQ,EACR,QAA+C;QAE/C,MAAM,cAAc,GAAG,IAAI,CAAC,EAAE,CAC5B,KAAK,EACL,KAAK,SAAU,CAAC,EACd,GAAG,IAAuD;YAE1D,KAAK,CAAC,CAAC,gBAAgB,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC,CAAC,CAAA;YAChD,cAAc,EAAE,CAAA;QAClB,CAAC,CACF,CAAA;QAED,OAAO,cAAc,CAAA;IACvB,CAAC;IAED,KAAK,CAAC,CAAE,IAAI,CACV,KAAQ,EACR,GAAG,IAAoB;QAEvB,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;QAErC,IAAI,SAAS,EAAE,CAAC;YACd,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;gBACjC,KAAK,CAAC,CAAC,gBAAgB,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC,CAAC,CAAA;YAClD,CAAC;QACH,CAAC;IACH,CAAC;IAED,kBAAkB,CAAkB,KAAQ;;QAC1C,MAAA,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,0CAAE,KAAK,EAAE,CAAA;IAC9B,CAAC;CACF"}
@@ -0,0 +1,10 @@
1
+ type Listener<Args extends unknown[], Yield, Next> = (...args: Args) => void | Generator<Yield, void, Next>;
2
+ export declare class GeneratorEmitter<EventToArgs extends Record<Event, unknown[]> = Record<string | number | symbol, unknown[]>, Event extends string | number | symbol = keyof EventToArgs, Yield = unknown, Next = unknown> {
3
+ private map;
4
+ get [Symbol.toStringTag](): string;
5
+ on<T extends Event>(event: T, listener: Listener<EventToArgs[T], Yield, Next>): () => void;
6
+ once<T extends Event>(event: T, listener: Listener<EventToArgs[T], Yield, Next>): () => void;
7
+ emit<T extends Event>(event: T, ...args: EventToArgs[T]): Generator<Yield, void, Next>;
8
+ removeAllListeners<T extends Event>(event: T): void;
9
+ }
10
+ export {};
@@ -0,0 +1,55 @@
1
+ import { go, goGenerator } from '@blackglory/go';
2
+ export class GeneratorEmitter {
3
+ constructor() {
4
+ this.map = new Map();
5
+ }
6
+ get [Symbol.toStringTag]() {
7
+ return this.constructor.name;
8
+ }
9
+ on(event, listener) {
10
+ const set = go(() => {
11
+ const set = this.map.get(event);
12
+ if (set) {
13
+ return set;
14
+ }
15
+ else {
16
+ const set = new Set();
17
+ this.map.set(event, set);
18
+ return set;
19
+ }
20
+ });
21
+ set.add(handler);
22
+ return () => {
23
+ const handlers = this.map.get(event);
24
+ if (handlers) {
25
+ const deleted = handlers.delete(handler);
26
+ if (deleted && handlers.size === 0) {
27
+ this.map.delete(event);
28
+ }
29
+ }
30
+ };
31
+ function* handler(...args) {
32
+ yield* goGenerator(() => listener(...args));
33
+ }
34
+ }
35
+ once(event, listener) {
36
+ const removeListener = this.on(event, function* (...args) {
37
+ yield* goGenerator(() => listener(...args));
38
+ removeListener();
39
+ });
40
+ return removeListener;
41
+ }
42
+ *emit(event, ...args) {
43
+ const listeners = this.map.get(event);
44
+ if (listeners) {
45
+ for (const listener of listeners) {
46
+ yield* goGenerator(() => listener(...args));
47
+ }
48
+ }
49
+ }
50
+ removeAllListeners(event) {
51
+ var _a;
52
+ (_a = this.map.get(event)) === null || _a === void 0 ? void 0 : _a.clear();
53
+ }
54
+ }
55
+ //# sourceMappingURL=generator-emitter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generator-emitter.js","sourceRoot":"","sources":["../src/generator-emitter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAMhD,MAAM,OAAO,gBAAgB;IAA7B;QASU,QAAG,GAAG,IAAI,GAAG,EAGlB,CAAA;IA0EL,CAAC;IAxEC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC;QACtB,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,CAAA;IAC9B,CAAC;IAED,EAAE,CACA,KAAQ,EACR,QAA+C;QAE/C,MAAM,GAAG,GAAG,EAAE,CAAC,GAAG,EAAE;YAClB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;YAC/B,IAAI,GAAG,EAAE,CAAC;gBACR,OAAO,GAAG,CAAA;YACZ,CAAC;iBAAM,CAAC;gBACN,MAAM,GAAG,GAAG,IAAI,GAAG,EAAyD,CAAA;gBAC5E,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;gBACxB,OAAO,GAAG,CAAA;YACZ,CAAC;QACH,CAAC,CAAC,CAAA;QACF,GAAG,CAAC,GAAG,CAAC,OAAoD,CAAC,CAAA;QAE7D,OAAO,GAAG,EAAE;YACV,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;YACpC,IAAI,QAAQ,EAAE,CAAC;gBACb,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAC7B,OAAoD,CACrD,CAAA;gBACD,IAAI,OAAO,IAAI,QAAQ,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;oBACnC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;gBACxB,CAAC;YACH,CAAC;QACH,CAAC,CAAA;QAED,QAAS,CAAC,CAAC,OAAO,CAChB,GAAG,IAAuD;YAE1D,KAAK,CAAC,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC,CAAC,CAAA;QAC7C,CAAC;IACH,CAAC;IAED,IAAI,CACF,KAAQ,EACR,QAA+C;QAE/C,MAAM,cAAc,GAAG,IAAI,CAAC,EAAE,CAC5B,KAAK,EACL,QAAS,CAAC,EACR,GAAG,IAAuD;YAE1D,KAAK,CAAC,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC,CAAC,CAAA;YAC3C,cAAc,EAAE,CAAA;QAClB,CAAC,CACF,CAAA;QAED,OAAO,cAAc,CAAA;IACvB,CAAC;IAED,CAAE,IAAI,CACJ,KAAQ,EACR,GAAG,IAAoB;QAEvB,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;QAErC,IAAI,SAAS,EAAE,CAAC;YACd,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;gBACjC,KAAK,CAAC,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC,CAAC,CAAA;YAC7C,CAAC;QACH,CAAC;IACH,CAAC;IAED,kBAAkB,CAAkB,KAAQ;;QAC1C,MAAA,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,0CAAE,KAAK,EAAE,CAAA;IAC9B,CAAC;CACF"}
package/lib/index.d.ts CHANGED
@@ -2,6 +2,8 @@ export * from './box.js';
2
2
  export * from './cons.js';
3
3
  export * from './array.js';
4
4
  export * from './emitter.js';
5
+ export * from './generator-emitter.js';
6
+ export * from './async-generator-emitter.js';
5
7
  export * from './big-map.js';
6
8
  export * from './big-set.js';
7
9
  export * from './hash-map.js';
package/lib/index.js CHANGED
@@ -2,6 +2,8 @@ export * from './box.js';
2
2
  export * from './cons.js';
3
3
  export * from './array.js';
4
4
  export * from './emitter.js';
5
+ export * from './generator-emitter.js';
6
+ export * from './async-generator-emitter.js';
5
7
  export * from './big-map.js';
6
8
  export * from './big-set.js';
7
9
  export * from './hash-map.js';
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAA;AACxB,cAAc,WAAW,CAAA;AACzB,cAAc,YAAY,CAAA;AAC1B,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA;AAC5B,cAAc,eAAe,CAAA;AAC7B,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA;AAC1B,cAAc,cAAc,CAAA;AAC5B,cAAc,oBAAoB,CAAA;AAClC,cAAc,eAAe,CAAA;AAC7B,cAAc,eAAe,CAAA;AAC7B,cAAc,sBAAsB,CAAA;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AACxD,cAAc,iBAAiB,CAAA;AAC/B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,uBAAuB,CAAA;AACrC,cAAc,uBAAuB,CAAA;AACrC,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;AAC5D,cAAc,iBAAiB,CAAA;AAC/B,cAAc,cAAc,CAAA;AAC5B,cAAc,oBAAoB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAA;AACxB,cAAc,WAAW,CAAA;AACzB,cAAc,YAAY,CAAA;AAC1B,cAAc,cAAc,CAAA;AAC5B,cAAc,wBAAwB,CAAA;AACtC,cAAc,8BAA8B,CAAA;AAC5C,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA;AAC5B,cAAc,eAAe,CAAA;AAC7B,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA;AAC1B,cAAc,cAAc,CAAA;AAC5B,cAAc,oBAAoB,CAAA;AAClC,cAAc,eAAe,CAAA;AAC7B,cAAc,eAAe,CAAA;AAC7B,cAAc,sBAAsB,CAAA;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AACxD,cAAc,iBAAiB,CAAA;AAC/B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,uBAAuB,CAAA;AACrC,cAAc,uBAAuB,CAAA;AACrC,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;AAC5D,cAAc,iBAAiB,CAAA;AAC/B,cAAc,cAAc,CAAA;AAC5B,cAAc,oBAAoB,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blackglory/structures",
3
- "version": "0.14.0",
3
+ "version": "0.14.2",
4
4
  "description": "",
5
5
  "files": [
6
6
  "lib",
@@ -65,7 +65,7 @@
65
65
  },
66
66
  "dependencies": {
67
67
  "@blackglory/errors": "^3.0.3",
68
- "@blackglory/go": "^1.1.3",
68
+ "@blackglory/go": "^2.0.0",
69
69
  "extra-timers": "^0.2.6",
70
70
  "extra-utils": "^5.6.0",
71
71
  "iterable-operator": "^5.0.0",
@@ -0,0 +1,94 @@
1
+ import { go, goAsyncGenerator } from '@blackglory/go'
2
+
3
+ type Listener<Args extends unknown[], Yield, Next> = (...args: Args) =>
4
+ | void
5
+ | Generator<Yield, void, Next>
6
+ | AsyncGenerator<Yield, void, Next>
7
+
8
+ export class AsyncGeneratorEmitter<
9
+ EventToArgs extends Record<Event, unknown[]> = Record<
10
+ string | number | symbol
11
+ , unknown[]
12
+ >
13
+ , Event extends string | number | symbol = keyof EventToArgs
14
+ , Yield = unknown
15
+ , Next = unknown
16
+ > {
17
+ private map = new Map<
18
+ Event
19
+ , Set<Listener<EventToArgs[Event], Yield, Next>>
20
+ >()
21
+
22
+ get [Symbol.toStringTag](): string {
23
+ return this.constructor.name
24
+ }
25
+
26
+ on<T extends Event>(
27
+ event: T
28
+ , listener: Listener<EventToArgs[T], Yield, Next>
29
+ ): () => void {
30
+ const set = go(() => {
31
+ const set = this.map.get(event)
32
+ if (set) {
33
+ return set
34
+ } else {
35
+ const set = new Set<Listener<EventToArgs[keyof EventToArgs], Yield, Next>>()
36
+ this.map.set(event, set)
37
+ return set
38
+ }
39
+ })
40
+ set.add(handler as Listener<EventToArgs[Event], Yield, Next>)
41
+
42
+ return () => {
43
+ const handlers = this.map.get(event)
44
+ if (handlers) {
45
+ const deleted = handlers.delete(
46
+ handler as Listener<EventToArgs[Event], Yield, Next>
47
+ )
48
+ if (deleted && handlers.size === 0) {
49
+ this.map.delete(event)
50
+ }
51
+ }
52
+ }
53
+
54
+ async function * handler(
55
+ ...args: Parameters<Listener<EventToArgs[T], Yield, Next>>
56
+ ): AsyncGenerator<Yield, void, Next> {
57
+ yield* goAsyncGenerator(() => listener(...args))
58
+ }
59
+ }
60
+
61
+ once<T extends Event>(
62
+ event: T
63
+ , listener: Listener<EventToArgs[T], Yield, Next>
64
+ ): () => void {
65
+ const removeListener = this.on(
66
+ event
67
+ , async function * (
68
+ ...args: Parameters<Listener<EventToArgs[T], Yield, Next>>
69
+ ): AsyncGenerator<Yield, void, Next> {
70
+ yield* goAsyncGenerator(() => listener(...args))
71
+ removeListener()
72
+ }
73
+ )
74
+
75
+ return removeListener
76
+ }
77
+
78
+ async * emit<T extends Event>(
79
+ event: T
80
+ , ...args: EventToArgs[T]
81
+ ): AsyncGenerator<Yield, void, Next> {
82
+ const listeners = this.map.get(event)
83
+
84
+ if (listeners) {
85
+ for (const listener of listeners) {
86
+ yield* goAsyncGenerator(() => listener(...args))
87
+ }
88
+ }
89
+ }
90
+
91
+ removeAllListeners<T extends Event>(event: T): void {
92
+ this.map.get(event)?.clear()
93
+ }
94
+ }
@@ -0,0 +1,93 @@
1
+ import { go, goGenerator } from '@blackglory/go'
2
+
3
+ type Listener<Args extends unknown[], Yield, Next> = (...args: Args) =>
4
+ | void
5
+ | Generator<Yield, void, Next>
6
+
7
+ export class GeneratorEmitter<
8
+ EventToArgs extends Record<Event, unknown[]> = Record<
9
+ string | number | symbol
10
+ , unknown[]
11
+ >
12
+ , Event extends string | number | symbol = keyof EventToArgs
13
+ , Yield = unknown
14
+ , Next = unknown
15
+ > {
16
+ private map = new Map<
17
+ Event
18
+ , Set<Listener<EventToArgs[Event], Yield, Next>>
19
+ >()
20
+
21
+ get [Symbol.toStringTag](): string {
22
+ return this.constructor.name
23
+ }
24
+
25
+ on<T extends Event>(
26
+ event: T
27
+ , listener: Listener<EventToArgs[T], Yield, Next>
28
+ ): () => void {
29
+ const set = go(() => {
30
+ const set = this.map.get(event)
31
+ if (set) {
32
+ return set
33
+ } else {
34
+ const set = new Set<Listener<EventToArgs[keyof EventToArgs], Yield, Next>>()
35
+ this.map.set(event, set)
36
+ return set
37
+ }
38
+ })
39
+ set.add(handler as Listener<EventToArgs[Event], Yield, Next>)
40
+
41
+ return () => {
42
+ const handlers = this.map.get(event)
43
+ if (handlers) {
44
+ const deleted = handlers.delete(
45
+ handler as Listener<EventToArgs[Event], Yield, Next>
46
+ )
47
+ if (deleted && handlers.size === 0) {
48
+ this.map.delete(event)
49
+ }
50
+ }
51
+ }
52
+
53
+ function * handler(
54
+ ...args: Parameters<Listener<EventToArgs[T], Yield, Next>>
55
+ ): Generator<Yield, void, Next> {
56
+ yield* goGenerator(() => listener(...args))
57
+ }
58
+ }
59
+
60
+ once<T extends Event>(
61
+ event: T
62
+ , listener: Listener<EventToArgs[T], Yield, Next>
63
+ ): () => void {
64
+ const removeListener = this.on(
65
+ event
66
+ , function * (
67
+ ...args: Parameters<Listener<EventToArgs[T], Yield, Next>>
68
+ ): Generator<Yield, void, Next> {
69
+ yield* goGenerator(() => listener(...args))
70
+ removeListener()
71
+ }
72
+ )
73
+
74
+ return removeListener
75
+ }
76
+
77
+ * emit<T extends Event>(
78
+ event: T
79
+ , ...args: EventToArgs[T]
80
+ ): Generator<Yield, void, Next> {
81
+ const listeners = this.map.get(event)
82
+
83
+ if (listeners) {
84
+ for (const listener of listeners) {
85
+ yield* goGenerator(() => listener(...args))
86
+ }
87
+ }
88
+ }
89
+
90
+ removeAllListeners<T extends Event>(event: T): void {
91
+ this.map.get(event)?.clear()
92
+ }
93
+ }
package/src/index.ts CHANGED
@@ -2,6 +2,8 @@ export * from './box.js'
2
2
  export * from './cons.js'
3
3
  export * from './array.js'
4
4
  export * from './emitter.js'
5
+ export * from './generator-emitter.js'
6
+ export * from './async-generator-emitter.js'
5
7
  export * from './big-map.js'
6
8
  export * from './big-set.js'
7
9
  export * from './hash-map.js'