@byloth/core 2.0.0-rc.9 → 2.0.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/dist/core.js +4087 -621
- package/dist/core.js.map +1 -1
- package/dist/core.umd.cjs +2 -2
- package/dist/core.umd.cjs.map +1 -1
- package/package.json +17 -13
- package/src/core/types.ts +41 -0
- package/src/helpers.ts +11 -2
- package/src/index.ts +12 -9
- package/src/models/aggregators/aggregated-async-iterator.ts +920 -21
- package/src/models/aggregators/aggregated-iterator.ts +838 -22
- package/src/models/aggregators/reduced-iterator.ts +827 -11
- package/src/models/aggregators/types.ts +153 -10
- package/src/models/callbacks/callable-object.ts +42 -6
- package/src/models/callbacks/index.ts +2 -2
- package/src/models/callbacks/publisher.ts +160 -4
- package/src/models/callbacks/switchable-callback.ts +230 -23
- package/src/models/callbacks/types.ts +16 -0
- package/src/models/exceptions/core.ts +132 -3
- package/src/models/exceptions/index.ts +405 -13
- package/src/models/index.ts +4 -8
- package/src/models/iterators/smart-async-iterator.ts +827 -22
- package/src/models/iterators/smart-iterator.ts +755 -20
- package/src/models/iterators/types.ts +268 -9
- package/src/models/json/json-storage.ts +508 -110
- package/src/models/json/types.ts +10 -1
- package/src/models/promises/deferred-promise.ts +85 -5
- package/src/models/promises/index.ts +1 -3
- package/src/models/promises/smart-promise.ts +272 -4
- package/src/models/promises/timed-promise.ts +43 -1
- package/src/models/promises/types.ts +84 -2
- package/src/models/timers/clock.ts +109 -19
- package/src/models/timers/countdown.ts +176 -21
- package/src/models/timers/game-loop.ts +266 -0
- package/src/models/timers/index.ts +2 -1
- package/src/models/types.ts +6 -5
- package/src/utils/async.ts +43 -0
- package/src/utils/curve.ts +85 -0
- package/src/utils/date.ts +204 -10
- package/src/utils/dom.ts +16 -2
- package/src/utils/index.ts +3 -2
- package/src/utils/iterator.ts +200 -17
- package/src/utils/math.ts +55 -3
- package/src/utils/random.ts +139 -2
- package/src/utils/string.ts +11 -0
- package/src/models/game-loop.ts +0 -83
- package/src/models/promises/long-running-task.ts +0 -294
- package/src/models/promises/thenable.ts +0 -97
|
@@ -1,19 +1,162 @@
|
|
|
1
|
-
/* eslint-disable max-len */
|
|
2
|
-
|
|
3
1
|
import type { MaybePromise } from "../promises/types.js";
|
|
4
2
|
|
|
3
|
+
/**
|
|
4
|
+
* An utility type that represents an {@link https://en.wikipedia.org/wiki/Iteratee|iteratee}-like function
|
|
5
|
+
* with the addition of a `key` parameter, compared to the JavaScript's standard ones.
|
|
6
|
+
* It can be used to transform the elements of an aggregated iterable.
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* const iteratee: KeyedIteratee<string, number, string> = (key: string, value: number) => `${value}`;
|
|
10
|
+
* const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
|
|
11
|
+
* .groupBy((value) => value % 2 === 0 ? "even" : "odd")
|
|
12
|
+
* .map(iteratee);
|
|
13
|
+
*
|
|
14
|
+
* console.log(results.toObject()); // { odd: ["-3", "-1", "3", "5"], even: ["0", "2", "6", "8"] }
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* @template K The type of the key used to aggregate elements in the iterable.
|
|
18
|
+
* @template T The type of the elements in the iterable.
|
|
19
|
+
* @template R The type of the return value of the iteratee. Default is `void`.
|
|
20
|
+
*/
|
|
5
21
|
export type KeyedIteratee<K extends PropertyKey, T, R = void> = (key: K, value: T, index: number) => R;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* An utility type that represents an asynchronous {@link https://en.wikipedia.org/wiki/Iteratee|iteratee}-like
|
|
25
|
+
* function with the addition of a `key` parameter.
|
|
26
|
+
* It can be used to transform the elements of an aggregated iterable asynchronously.
|
|
27
|
+
*
|
|
28
|
+
* ```ts
|
|
29
|
+
* const iteratee: AsyncKeyedIteratee<string, number, string> = async (key: string, value: number) => `${value}`;
|
|
30
|
+
* const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
|
|
31
|
+
* .groupBy((value) => value % 2 === 0 ? "even" : "odd")
|
|
32
|
+
* .map(iteratee);
|
|
33
|
+
*
|
|
34
|
+
* console.log(await results.toObject()); // { odd: ["-3", "-1", "3", "5"], even: ["0", "2", "6", "8"] }
|
|
35
|
+
* ```
|
|
36
|
+
*
|
|
37
|
+
* @template K The type of the key used to aggregate elements in the iterable.
|
|
38
|
+
* @template T The type of the elements in the iterable.
|
|
39
|
+
* @template R The type of the return value of the iteratee. Default is `void`.
|
|
40
|
+
*/
|
|
6
41
|
export type AsyncKeyedIteratee<K extends PropertyKey, T, R = void> = (key: K, value: T, index: number) => Promise<R>;
|
|
7
|
-
export type MaybeAsyncKeyedIteratee<K extends PropertyKey, T, R = void> = (key: K, value: T, index: number) => MaybePromise<R>;
|
|
8
42
|
|
|
9
|
-
|
|
43
|
+
/**
|
|
44
|
+
* An utility type that represents an {@link https://en.wikipedia.org/wiki/Iteratee|iteratee}-like function
|
|
45
|
+
* with the addition of a `key` parameter that can be either synchronous or asynchronous.
|
|
46
|
+
* It can be used to transform the elements of an aggregated iterable.
|
|
47
|
+
*
|
|
48
|
+
* ```ts
|
|
49
|
+
* const iteratee: AsyncKeyedIteratee<string, number, string> = [async] (key: string, value: number) => `${value}`;
|
|
50
|
+
* const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
|
|
51
|
+
* .groupBy((value) => value % 2 === 0 ? "even" : "odd")
|
|
52
|
+
* .map(iteratee);
|
|
53
|
+
*
|
|
54
|
+
* console.log(await results.toObject()); // { odd: ["-3", "-1", "3", "5"], even: ["0", "2", "6", "8"] }
|
|
55
|
+
* ```
|
|
56
|
+
*
|
|
57
|
+
* @template K The type of the key used to aggregate elements in the iterable.
|
|
58
|
+
* @template T The type of the elements in the iterable.
|
|
59
|
+
* @template R The type of the return value of the iteratee. Default is `void`.
|
|
60
|
+
*/
|
|
61
|
+
export type MaybeAsyncKeyedIteratee<K extends PropertyKey, T, R = void> =
|
|
62
|
+
(key: K, value: T, index: number) => MaybePromise<R>;
|
|
10
63
|
|
|
11
|
-
|
|
12
|
-
|
|
64
|
+
/**
|
|
65
|
+
* An utility type that represents a {@link https://en.wikipedia.org/wiki/Predicate_(mathematical_logic)|predicate}-like
|
|
66
|
+
* function with the addition of a `key` parameter, compared to the JavaScript's standard ones,
|
|
67
|
+
* which act as a
|
|
68
|
+
* {@link https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates|type guard}.
|
|
69
|
+
* It can be used to filter the elements of an aggregated iterable
|
|
70
|
+
* while allowing the type-system to infer them correctly.
|
|
71
|
+
*
|
|
72
|
+
* ```ts
|
|
73
|
+
* const predicate: KeyedTypeGuardPredicate<string, number | string, string> =
|
|
74
|
+
* (key: string, value: number | string): value is string => typeof value === "string";
|
|
75
|
+
*
|
|
76
|
+
* const results = new SmartIterator<number | string>([-3, -1, "0", 2, 3, "5", 6, "8"])
|
|
77
|
+
* .groupBy((value) => Number(value) % 2 === 0 ? "even" : "odd")
|
|
78
|
+
* .filter(predicate);
|
|
79
|
+
*
|
|
80
|
+
* console.log(results.toObject()); // { odd: ["0", "5", "8"], even: [] }
|
|
81
|
+
* ```
|
|
82
|
+
*
|
|
83
|
+
* @template K The type of the key used to aggregate elements in the iterable.
|
|
84
|
+
* @template T The type of the elements in the iterable.
|
|
85
|
+
* @template R
|
|
86
|
+
* The type of the return value of the predicate.
|
|
87
|
+
* It must be a subtype of `T`. Default is `T`.
|
|
88
|
+
*/
|
|
89
|
+
export type KeyedTypeGuardPredicate<K extends PropertyKey, T, R extends T> =
|
|
90
|
+
(key: K, value: T, index: number) => value is R;
|
|
13
91
|
|
|
14
|
-
//
|
|
15
|
-
|
|
92
|
+
// These types need this Issue to be solved: https://github.com/microsoft/TypeScript/issues/37681
|
|
93
|
+
//
|
|
94
|
+
// export type AsyncKeyedTypeGuardPredicate<K extends PropertyKey, T, R extends T> =
|
|
95
|
+
// (key: K, value: T, index: number) => value is Promise<R>;
|
|
96
|
+
// export type MaybeAsyncKeyedTypeGuardPredicate<K extends PropertyKey, T, R extends T> =
|
|
97
|
+
// (key: K, value: T, index: number) => value is MaybePromise<R>;
|
|
16
98
|
|
|
99
|
+
/**
|
|
100
|
+
* An utility type that represents a reducer-like function.
|
|
101
|
+
* It can be used to reduce the elements of an aggregated iterable into a single value.
|
|
102
|
+
*
|
|
103
|
+
* ```ts
|
|
104
|
+
* const sum: KeyedReducer<string, number, number> =
|
|
105
|
+
* (key: string, accumulator: number, value: number) => accumulator + value;
|
|
106
|
+
*
|
|
107
|
+
* const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
|
|
108
|
+
* .groupBy((value) => value % 2 === 0 ? "even" : "odd")
|
|
109
|
+
* .reduce(sum);
|
|
110
|
+
*
|
|
111
|
+
* console.log(results.toObject()); // { odd: 4, even: 16 }
|
|
112
|
+
* ```
|
|
113
|
+
*
|
|
114
|
+
* @template K The type of the key used to aggregate elements in the iterable.
|
|
115
|
+
* @template T The type of the elements in the iterable.
|
|
116
|
+
* @template A The type of the accumulator.
|
|
117
|
+
*/
|
|
17
118
|
export type KeyedReducer<K extends PropertyKey, T, A> = (key: K, accumulator: A, value: T, index: number) => A;
|
|
18
|
-
|
|
19
|
-
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* An utility type that represents an asynchronous reducer-like function.
|
|
122
|
+
* It can be used to reduce the elements of an aggregated iterable into a single value.
|
|
123
|
+
*
|
|
124
|
+
* ```ts
|
|
125
|
+
* const sum: AsyncKeyedReducer<string, number, number> =
|
|
126
|
+
* async (key: string, accumulator: number, value: number) => accumulator + value;
|
|
127
|
+
*
|
|
128
|
+
* const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
|
|
129
|
+
* .groupBy((value) => value % 2 === 0 ? "even" : "odd")
|
|
130
|
+
* .reduce(sum);
|
|
131
|
+
*
|
|
132
|
+
* console.log(await results.toObject()); // { odd: 4, even: 16 }
|
|
133
|
+
* ```
|
|
134
|
+
*
|
|
135
|
+
* @template K The type of the key used to aggregate elements in the iterable.
|
|
136
|
+
* @template T The type of the elements in the iterable.
|
|
137
|
+
* @template A The type of the accumulator.
|
|
138
|
+
*/
|
|
139
|
+
export type AsyncKeyedReducer<K extends PropertyKey, T, A> =
|
|
140
|
+
(key: K, accumulator: A, value: T, index: number) => Promise<A>;
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* An utility type that represents a reducer-like function that can be either synchronous or asynchronous.
|
|
144
|
+
* It can be used to reduce the elements of an aggregated iterable into a single value.
|
|
145
|
+
*
|
|
146
|
+
* ```ts
|
|
147
|
+
* const sum: MaybeAsyncKeyedReducer<string, number, number> =
|
|
148
|
+
* [async] (key: string, accumulator: number, value: number) => accumulator + value;
|
|
149
|
+
*
|
|
150
|
+
* const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
|
|
151
|
+
* .groupBy((value) => value % 2 === 0 ? "even" : "odd")
|
|
152
|
+
* .reduce(sum);
|
|
153
|
+
*
|
|
154
|
+
* console.log(await results.toObject()); // { odd: 4, even: 16 }
|
|
155
|
+
* ```
|
|
156
|
+
*
|
|
157
|
+
* @template K The type of the key used to aggregate elements in the iterable.
|
|
158
|
+
* @template T The type of the elements in the iterable.
|
|
159
|
+
* @template A The type of the accumulator.
|
|
160
|
+
*/
|
|
161
|
+
export type MaybeAsyncKeyedReducer<K extends PropertyKey, T, A> =
|
|
162
|
+
(key: K, accumulator: A, value: T, index: number) => MaybePromise<A>;
|
|
@@ -2,16 +2,42 @@
|
|
|
2
2
|
|
|
3
3
|
import type { Callback } from "./types.js";
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
(...args: Parameters<T>) => ReturnType<T>;
|
|
5
|
+
const SmartFunction = (Function as unknown) as new<A extends unknown[] = [], R = void>(...args: string[])
|
|
6
|
+
=> (...args: A) => R;
|
|
8
7
|
|
|
8
|
+
/**
|
|
9
|
+
* An abstract class that can be used to implement callable objects.
|
|
10
|
+
*
|
|
11
|
+
* ```ts
|
|
12
|
+
* class ActivableCallback extends CallableObject<(evt: PointerEvent) => void>
|
|
13
|
+
* {
|
|
14
|
+
* public enabled = false;
|
|
15
|
+
* protected _invoke(): void
|
|
16
|
+
* {
|
|
17
|
+
* if (this.enabled) { [...] }
|
|
18
|
+
* }
|
|
19
|
+
* }
|
|
20
|
+
*
|
|
21
|
+
* const callback = new ActivableCallback();
|
|
22
|
+
*
|
|
23
|
+
* window.addEventListener("pointerdown", () => { callback.enabled = true; });
|
|
24
|
+
* window.addEventListener("pointermove", callback);
|
|
25
|
+
* window.addEventListener("pointerup", () => { callback.enabled = false; });
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* @template T
|
|
29
|
+
* The type signature of the callback function.
|
|
30
|
+
* It must be a function. Default is `(...args: any[]) => any`.
|
|
31
|
+
*/
|
|
9
32
|
export default abstract class CallableObject<T extends Callback<any[], any> = () => void>
|
|
10
|
-
extends SmartFunction<T
|
|
33
|
+
extends SmartFunction<Parameters<T>, ReturnType<T>>
|
|
11
34
|
{
|
|
35
|
+
/**
|
|
36
|
+
* Initializes a new instance of the {@link CallableObject} class.
|
|
37
|
+
*/
|
|
12
38
|
public constructor()
|
|
13
39
|
{
|
|
14
|
-
super(`return this.
|
|
40
|
+
super(`return this._invoke(...arguments);`);
|
|
15
41
|
|
|
16
42
|
const self = this.bind(this);
|
|
17
43
|
Object.setPrototypeOf(this, self);
|
|
@@ -19,5 +45,15 @@ export default abstract class CallableObject<T extends Callback<any[], any> = ()
|
|
|
19
45
|
return self as this;
|
|
20
46
|
}
|
|
21
47
|
|
|
22
|
-
|
|
48
|
+
/**
|
|
49
|
+
* The method that will be called when the object is invoked.
|
|
50
|
+
* It must be implemented by the derived classes.
|
|
51
|
+
*
|
|
52
|
+
* @param args The arguments that have been passed to the object.
|
|
53
|
+
*
|
|
54
|
+
* @returns The return value of the method.
|
|
55
|
+
*/
|
|
56
|
+
protected abstract _invoke(...args: Parameters<T>): ReturnType<T>;
|
|
57
|
+
|
|
58
|
+
public readonly [Symbol.toStringTag]: string = "CallableObject";
|
|
23
59
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import CallableObject
|
|
1
|
+
import CallableObject from "./callable-object.js";
|
|
2
2
|
import Publisher from "./publisher.js";
|
|
3
3
|
import SwitchableCallback from "./switchable-callback.js";
|
|
4
4
|
|
|
5
|
-
export { CallableObject, Publisher,
|
|
5
|
+
export { CallableObject, Publisher, SwitchableCallback };
|
|
@@ -2,16 +2,146 @@ import { ReferenceException } from "../exceptions/index.js";
|
|
|
2
2
|
|
|
3
3
|
import type { Callback } from "./types.js";
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* A class implementing the
|
|
7
|
+
* {@link https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern|Publish-subscribe} pattern.
|
|
8
|
+
*
|
|
9
|
+
* It can be used to create a simple event system where objects can subscribe
|
|
10
|
+
* to events and receive notifications when the events are published.
|
|
11
|
+
* It's a simple and efficient way to decouple the objects and make them communicate with each other.
|
|
12
|
+
*
|
|
13
|
+
* Using generics, it's also possible to define the type of the events and the callbacks that can be subscribed to them.
|
|
14
|
+
*
|
|
15
|
+
* ```ts
|
|
16
|
+
* interface EventsMap
|
|
17
|
+
* {
|
|
18
|
+
* "player:spawn": (evt: SpawnEvent) => void;
|
|
19
|
+
* "player:move": ({ x, y }: Point) => void;
|
|
20
|
+
* "player:death": () => void;
|
|
21
|
+
* }
|
|
22
|
+
*
|
|
23
|
+
* const publisher = new Publisher<EventsMap>();
|
|
24
|
+
*
|
|
25
|
+
* let unsubscribe: () => void;
|
|
26
|
+
* publisher.subscribe("player:death", unsubscribe);
|
|
27
|
+
* publisher.subscribe("player:spawn", (evt) =>
|
|
28
|
+
* {
|
|
29
|
+
* unsubscribe = publisher.subscribe("player:move", ({ x, y }) => { [...] });
|
|
30
|
+
* });
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* @template T
|
|
34
|
+
* A map containing the names of the emittable events and the
|
|
35
|
+
* related callback signatures that can be subscribed to them.
|
|
36
|
+
* Default is `Record<string, () => void>`.
|
|
37
|
+
*/
|
|
5
38
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
6
39
|
export default class Publisher<T extends { [K in keyof T]: Callback<any[], any> } = Record<string, Callback>>
|
|
7
40
|
{
|
|
41
|
+
/**
|
|
42
|
+
* A map containing all the subscribers for each event.
|
|
43
|
+
*
|
|
44
|
+
* The keys are the names of the events they are subscribed to.
|
|
45
|
+
* The values are the arrays of the subscribers themselves.
|
|
46
|
+
*/
|
|
8
47
|
protected _subscribers: Map<keyof T, Callback<unknown[], unknown>[]>;
|
|
9
48
|
|
|
49
|
+
/**
|
|
50
|
+
* Initializes a new instance of the {@link Publisher} class.
|
|
51
|
+
*
|
|
52
|
+
* ---
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```ts
|
|
56
|
+
* const publisher = new Publisher();
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
10
59
|
public constructor()
|
|
11
60
|
{
|
|
12
61
|
this._subscribers = new Map();
|
|
13
62
|
}
|
|
14
63
|
|
|
64
|
+
/**
|
|
65
|
+
* Unsubscribes all the subscribers from all the events.
|
|
66
|
+
*
|
|
67
|
+
* ---
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```ts
|
|
71
|
+
* publisher.subscribe("player:spawn", (evt) => { [...] });
|
|
72
|
+
* publisher.subscribe("player:move", (coords) => { [...] });
|
|
73
|
+
* publisher.subscribe("player:move", () => { [...] });
|
|
74
|
+
* publisher.subscribe("player:move", ({ x, y }) => { [...] });
|
|
75
|
+
* publisher.subscribe("player:death", () => { [...] });
|
|
76
|
+
*
|
|
77
|
+
* // All these subscribers are working fine...
|
|
78
|
+
*
|
|
79
|
+
* publisher.clear();
|
|
80
|
+
*
|
|
81
|
+
* // ... but now they're all gone!
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
public clear(): void
|
|
85
|
+
{
|
|
86
|
+
this._subscribers.clear();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Publishes an event to all the subscribers.
|
|
91
|
+
*
|
|
92
|
+
* ---
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```ts
|
|
96
|
+
* publisher.subscribe("player:move", (coords) => { [...] });
|
|
97
|
+
* publisher.subscribe("player:move", ({ x, y }) => { [...] });
|
|
98
|
+
* publisher.subscribe("player:move", (evt) => { [...] });
|
|
99
|
+
*
|
|
100
|
+
* publisher.publish("player:move", { x: 10, y: 20 });
|
|
101
|
+
* ```
|
|
102
|
+
*
|
|
103
|
+
* ---
|
|
104
|
+
*
|
|
105
|
+
* @template K The key of the map containing the callback signature to publish.
|
|
106
|
+
*
|
|
107
|
+
* @param event The name of the event to publish.
|
|
108
|
+
* @param args The arguments to pass to the subscribers.
|
|
109
|
+
*
|
|
110
|
+
* @returns An array containing the return values of all the subscribers.
|
|
111
|
+
*/
|
|
112
|
+
public publish<K extends keyof T>(event: K, ...args: Parameters<T[K]>): ReturnType<T[K]>[]
|
|
113
|
+
{
|
|
114
|
+
const subscribers = this._subscribers.get(event);
|
|
115
|
+
if (!(subscribers)) { return []; }
|
|
116
|
+
|
|
117
|
+
return subscribers.slice()
|
|
118
|
+
.map((subscriber) => subscriber(...args)) as ReturnType<T[K]>[];
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Subscribes a new subscriber to an event.
|
|
123
|
+
*
|
|
124
|
+
* ---
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* ```ts
|
|
128
|
+
* let unsubscribe: () => void;
|
|
129
|
+
* publisher.subscribe("player:death", unsubscribe);
|
|
130
|
+
* publisher.subscribe("player:spawn", (evt) =>
|
|
131
|
+
* {
|
|
132
|
+
* unsubscribe = publisher.subscribe("player:move", ({ x, y }) => { [...] });
|
|
133
|
+
* });
|
|
134
|
+
* ```
|
|
135
|
+
*
|
|
136
|
+
* ---
|
|
137
|
+
*
|
|
138
|
+
* @template K The key of the map containing the callback signature to subscribe.
|
|
139
|
+
*
|
|
140
|
+
* @param event The name of the event to subscribe to.
|
|
141
|
+
* @param subscriber The subscriber to add to the event.
|
|
142
|
+
*
|
|
143
|
+
* @returns A function that can be used to unsubscribe the subscriber.
|
|
144
|
+
*/
|
|
15
145
|
public subscribe<K extends keyof T>(event: K, subscriber: T[K]): () => void
|
|
16
146
|
{
|
|
17
147
|
if (!(this._subscribers.has(event))) { this._subscribers.set(event, []); }
|
|
@@ -32,13 +162,39 @@ export default class Publisher<T extends { [K in keyof T]: Callback<any[], any>
|
|
|
32
162
|
};
|
|
33
163
|
}
|
|
34
164
|
|
|
35
|
-
|
|
165
|
+
/**
|
|
166
|
+
* Unsubscribes a subscriber from an event.
|
|
167
|
+
*
|
|
168
|
+
* ---
|
|
169
|
+
*
|
|
170
|
+
* @example
|
|
171
|
+
* ```ts
|
|
172
|
+
* const onPlayerMove = ({ x, y }: Point) => { [...] };
|
|
173
|
+
*
|
|
174
|
+
* publisher.subscribe("player:spawn", (evt) => publisher.subscribe("player:move", onPlayerMove));
|
|
175
|
+
* publisher.subscribe("player:death", () => publisher.unsubscribe("player:move", onPlayerMove));
|
|
176
|
+
* ```
|
|
177
|
+
*
|
|
178
|
+
* ---
|
|
179
|
+
*
|
|
180
|
+
* @template K The key of the map containing the callback signature to unsubscribe.
|
|
181
|
+
*
|
|
182
|
+
* @param event The name of the event to unsubscribe from.
|
|
183
|
+
* @param subscriber The subscriber to remove from the event.
|
|
184
|
+
*/
|
|
185
|
+
public unsubscribe<K extends keyof T>(event: K, subscriber: T[K]): void
|
|
36
186
|
{
|
|
37
187
|
const subscribers = this._subscribers.get(event);
|
|
38
|
-
if (!(subscribers)) { return
|
|
188
|
+
if (!(subscribers)) { return; }
|
|
39
189
|
|
|
40
|
-
|
|
41
|
-
|
|
190
|
+
const index = subscribers.indexOf(subscriber);
|
|
191
|
+
if (index < 0)
|
|
192
|
+
{
|
|
193
|
+
throw new ReferenceException("Unable to unsubscribe the required subscriber. " +
|
|
194
|
+
"The subscription was already unsubscribed or was never subscribed.");
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
subscribers.splice(index, 1);
|
|
42
198
|
}
|
|
43
199
|
|
|
44
200
|
public readonly [Symbol.toStringTag]: string = "Publisher";
|