@byloth/core 2.0.2 → 2.1.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/README.md +4 -1
- package/dist/core.cjs +6 -0
- package/dist/core.cjs.map +1 -0
- package/dist/{core.js → core.esm.js} +1083 -774
- package/dist/core.esm.js.map +1 -0
- package/dist/core.global.js +6 -0
- package/dist/core.global.js.map +1 -0
- package/dist/core.umd.cjs +3 -3
- package/dist/core.umd.cjs.map +1 -1
- package/package.json +12 -10
- package/src/core/types.ts +6 -1
- package/src/index.ts +9 -1
- package/src/models/callbacks/publisher.ts +4 -4
- package/src/models/callbacks/types.ts +111 -1
- package/src/models/collections/index.ts +4 -0
- package/src/models/collections/map-view.ts +206 -0
- package/src/models/collections/set-view.ts +204 -0
- package/src/models/collections/types.ts +184 -0
- package/src/models/exceptions/core.ts +1 -1
- package/src/models/index.ts +1 -0
- package/src/models/json/json-storage.ts +1 -1
- package/src/models/types.ts +3 -8
- package/src/utils/iterator.ts +3 -3
- package/dist/core.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@byloth/core",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.1",
|
|
4
4
|
"description": "An unopinionated collection of useful functions and classes that I use widely in all my projects. 🔧",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Core",
|
|
@@ -32,31 +32,33 @@
|
|
|
32
32
|
"src"
|
|
33
33
|
],
|
|
34
34
|
"main": "dist/core.umd.cjs",
|
|
35
|
-
"module": "dist/core.
|
|
35
|
+
"module": "dist/core.cjs",
|
|
36
|
+
"unpkg": "dist/core.global.js",
|
|
37
|
+
"jsdelivr": "dist/core.global.js",
|
|
36
38
|
"exports": {
|
|
37
39
|
".": {
|
|
38
40
|
"import": {
|
|
39
41
|
"types": "./src/index.ts",
|
|
40
|
-
"default": "./dist/core.js"
|
|
42
|
+
"default": "./dist/core.esm.js"
|
|
41
43
|
},
|
|
42
44
|
"require": {
|
|
43
45
|
"types": "./src/index.ts",
|
|
44
|
-
"default": "./dist/core.
|
|
46
|
+
"default": "./dist/core.cjs"
|
|
45
47
|
}
|
|
46
48
|
}
|
|
47
49
|
},
|
|
48
50
|
"types": "src/index.ts",
|
|
49
51
|
"devDependencies": {
|
|
50
52
|
"@byloth/eslint-config-typescript": "^3.1.0",
|
|
51
|
-
"@eslint/compat": "^1.2.
|
|
52
|
-
"@types/node": "^22.
|
|
53
|
-
"@vitest/coverage-v8": "^3.1.
|
|
54
|
-
"eslint": "^9.
|
|
53
|
+
"@eslint/compat": "^1.2.9",
|
|
54
|
+
"@types/node": "^22.15.18",
|
|
55
|
+
"@vitest/coverage-v8": "^3.1.3",
|
|
56
|
+
"eslint": "^9.26.0",
|
|
55
57
|
"husky": "^9.1.7",
|
|
56
58
|
"jsdom": "^26.1.0",
|
|
57
59
|
"typescript": "^5.8.3",
|
|
58
|
-
"vite": "^6.3.
|
|
59
|
-
"vitest": "^3.1.
|
|
60
|
+
"vite": "^6.3.5",
|
|
61
|
+
"vitest": "^3.1.3"
|
|
60
62
|
},
|
|
61
63
|
"scripts": {
|
|
62
64
|
"dev": "vite",
|
package/src/core/types.ts
CHANGED
|
@@ -10,9 +10,14 @@
|
|
|
10
10
|
*
|
|
11
11
|
* const instance: MyObject = factory(MyObject);
|
|
12
12
|
* ```
|
|
13
|
+
*
|
|
14
|
+
* ---
|
|
15
|
+
*
|
|
16
|
+
* @template T The type of the instance to create. Default is `object`.
|
|
17
|
+
* @template P The type of the constructor parameters. Default is `any[]`.
|
|
13
18
|
*/
|
|
14
19
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
15
|
-
export type Constructor<T extends object, P extends unknown[] = any[]> = new (...args: P) => T;
|
|
20
|
+
export type Constructor<T extends object = object, P extends unknown[] = any[]> = new (...args: P) => T;
|
|
16
21
|
|
|
17
22
|
/**
|
|
18
23
|
* A type that represents the return value of {@link setInterval} function,
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const VERSION = "2.
|
|
1
|
+
export const VERSION = "2.1.1";
|
|
2
2
|
|
|
3
3
|
export type { Constructor, Interval, Timeout, ValueOf } from "./core/types.js";
|
|
4
4
|
|
|
@@ -20,6 +20,7 @@ export {
|
|
|
20
20
|
GameLoop,
|
|
21
21
|
JSONStorage,
|
|
22
22
|
KeyException,
|
|
23
|
+
MapView,
|
|
23
24
|
NotImplementedException,
|
|
24
25
|
NetworkException,
|
|
25
26
|
PermissionException,
|
|
@@ -28,6 +29,7 @@ export {
|
|
|
28
29
|
ReducedIterator,
|
|
29
30
|
ReferenceException,
|
|
30
31
|
RuntimeException,
|
|
32
|
+
SetView,
|
|
31
33
|
SmartIterator,
|
|
32
34
|
SmartAsyncIterator,
|
|
33
35
|
SmartPromise,
|
|
@@ -58,6 +60,7 @@ export type {
|
|
|
58
60
|
KeyedIteratee,
|
|
59
61
|
KeyedReducer,
|
|
60
62
|
KeyedTypeGuardPredicate,
|
|
63
|
+
MapViewEventsMap,
|
|
61
64
|
MaybeAsyncKeyedIteratee,
|
|
62
65
|
MaybeAsyncKeyedReducer,
|
|
63
66
|
MaybeAsyncGeneratorFunction,
|
|
@@ -68,8 +71,13 @@ export type {
|
|
|
68
71
|
PromiseExecutor,
|
|
69
72
|
PromiseRejecter,
|
|
70
73
|
PromiseResolver,
|
|
74
|
+
Publishable,
|
|
75
|
+
ReadonlyMapView,
|
|
76
|
+
ReadonlySetView,
|
|
71
77
|
Reducer,
|
|
72
78
|
RejectedHandler,
|
|
79
|
+
SetViewEventsMap,
|
|
80
|
+
Subscribable,
|
|
73
81
|
TypeGuardPredicate
|
|
74
82
|
|
|
75
83
|
} from "./models/types.js";
|
|
@@ -123,7 +123,7 @@ export default class Publisher<T extends CallbackMap<T> = CallbackMap>
|
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
/**
|
|
126
|
-
* Subscribes a
|
|
126
|
+
* Subscribes to an event and adds a subscriber to be executed when the event is published.
|
|
127
127
|
*
|
|
128
128
|
* ---
|
|
129
129
|
*
|
|
@@ -142,9 +142,9 @@ export default class Publisher<T extends CallbackMap<T> = CallbackMap>
|
|
|
142
142
|
* @template K The key of the map containing the callback signature to subscribe.
|
|
143
143
|
*
|
|
144
144
|
* @param event The name of the event to subscribe to.
|
|
145
|
-
* @param subscriber The subscriber to
|
|
145
|
+
* @param subscriber The subscriber to execute when the event is published.
|
|
146
146
|
*
|
|
147
|
-
* @returns A function that can be used to unsubscribe the subscriber.
|
|
147
|
+
* @returns A function that can be used to unsubscribe the subscriber from the event.
|
|
148
148
|
*/
|
|
149
149
|
public subscribe<K extends keyof T>(event: K & string, subscriber: T[K]): () => void
|
|
150
150
|
{
|
|
@@ -167,7 +167,7 @@ export default class Publisher<T extends CallbackMap<T> = CallbackMap>
|
|
|
167
167
|
}
|
|
168
168
|
|
|
169
169
|
/**
|
|
170
|
-
* Unsubscribes a subscriber from
|
|
170
|
+
* Unsubscribes from an event and removes a subscriber from being executed when the event is published.
|
|
171
171
|
*
|
|
172
172
|
* ---
|
|
173
173
|
*
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
2
|
+
import type Publisher from "./publisher.js";
|
|
3
|
+
|
|
1
4
|
/**
|
|
2
5
|
* A type that represents a generic function.
|
|
3
6
|
*
|
|
@@ -24,7 +27,7 @@ export type Callback<A extends unknown[] = [], R = void> = (...args: A) => R;
|
|
|
24
27
|
/**
|
|
25
28
|
* An utility type that is required to represents a map of callbacks.
|
|
26
29
|
*
|
|
27
|
-
* It is used for type inheritance on the
|
|
30
|
+
* It is used for type inheritance on the {@link Publisher} class signature.
|
|
28
31
|
* Whenever you'll need to extend that class, you may need to use this type too.
|
|
29
32
|
*
|
|
30
33
|
* ---
|
|
@@ -47,3 +50,110 @@ export type Callback<A extends unknown[] = [], R = void> = (...args: A) => R;
|
|
|
47
50
|
*/
|
|
48
51
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
49
52
|
export type CallbackMap<T = Record<string, Callback<unknown[], unknown>>> = { [K in keyof T]: Callback<any[], any> };
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* An utility type that represents a {@link Publisher} object that can be published to.
|
|
56
|
+
* See also {@link Subscribable}.
|
|
57
|
+
*
|
|
58
|
+
* It can be used to prevent the user from modifying the publisher while
|
|
59
|
+
* still allowing them to subscribe to events and publish them.
|
|
60
|
+
*
|
|
61
|
+
* ---
|
|
62
|
+
*
|
|
63
|
+
* @template T
|
|
64
|
+
* A map containing the names of the emittable events and the
|
|
65
|
+
* related callback signatures that can be subscribed to them.
|
|
66
|
+
* Default is `Record<string, (...args: unknown[]) => unknown>`.
|
|
67
|
+
*/
|
|
68
|
+
export interface Publishable<T extends CallbackMap<T> = CallbackMap>
|
|
69
|
+
{
|
|
70
|
+
/**
|
|
71
|
+
* Publishes an event to all the subscribers.
|
|
72
|
+
*
|
|
73
|
+
* ---
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```ts
|
|
77
|
+
* publisher.subscribe("player:move", (coords) => { [...] });
|
|
78
|
+
* publisher.subscribe("player:move", ({ x, y }) => { [...] });
|
|
79
|
+
* publisher.subscribe("player:move", (evt) => { [...] });
|
|
80
|
+
*
|
|
81
|
+
* publisher.publish("player:move", { x: 10, y: 20 });
|
|
82
|
+
* ```
|
|
83
|
+
*
|
|
84
|
+
* ---
|
|
85
|
+
*
|
|
86
|
+
* @template K The key of the map containing the callback signature to publish.
|
|
87
|
+
*
|
|
88
|
+
* @param event The name of the event to publish.
|
|
89
|
+
* @param args The arguments to pass to the subscribers.
|
|
90
|
+
*
|
|
91
|
+
* @returns An array containing the return values of all the subscribers.
|
|
92
|
+
*/
|
|
93
|
+
publish<K extends keyof T>(event: K & string, ...args: Parameters<T[K]>): ReturnType<T[K]>[];
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* An utility type that represents a {@link Publisher} object that can be subscribed to.
|
|
98
|
+
* See also {@link Publishable}.
|
|
99
|
+
*
|
|
100
|
+
* It can be used to prevent the user from modifying the publisher while
|
|
101
|
+
* still allowing them to subscribe to events and publish them.
|
|
102
|
+
*
|
|
103
|
+
* ---
|
|
104
|
+
*
|
|
105
|
+
* @template T
|
|
106
|
+
* A map containing the names of the emittable events and the
|
|
107
|
+
* related callback signatures that can be subscribed to them.
|
|
108
|
+
* Default is `Record<string, (...args: unknown[]) => unknown>`.
|
|
109
|
+
*/
|
|
110
|
+
export interface Subscribable<T extends CallbackMap<T> = CallbackMap>
|
|
111
|
+
{
|
|
112
|
+
/**
|
|
113
|
+
* Subscribes to an event and adds a subscriber to be executed when the event is published.
|
|
114
|
+
*
|
|
115
|
+
* ---
|
|
116
|
+
*
|
|
117
|
+
* @example
|
|
118
|
+
* ```ts
|
|
119
|
+
* let unsubscribe: () => void;
|
|
120
|
+
* publisher.subscribe("player:death", unsubscribe);
|
|
121
|
+
* publisher.subscribe("player:spawn", (evt) =>
|
|
122
|
+
* {
|
|
123
|
+
* unsubscribe = publisher.subscribe("player:move", ({ x, y }) => { [...] });
|
|
124
|
+
* });
|
|
125
|
+
* ```
|
|
126
|
+
*
|
|
127
|
+
* ---
|
|
128
|
+
*
|
|
129
|
+
* @template K The key of the map containing the callback signature to subscribe.
|
|
130
|
+
*
|
|
131
|
+
* @param event The name of the event to subscribe to.
|
|
132
|
+
* @param subscriber The subscriber to execute when the event is published.
|
|
133
|
+
*
|
|
134
|
+
* @returns A function that can be used to unsubscribe the subscriber from the event.
|
|
135
|
+
*/
|
|
136
|
+
subscribe<K extends keyof T>(event: K & string, subscriber: T[K]): () => void;
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Unsubscribes from an event and removes a subscriber from being executed when the event is published.
|
|
140
|
+
*
|
|
141
|
+
* ---
|
|
142
|
+
*
|
|
143
|
+
* @example
|
|
144
|
+
* ```ts
|
|
145
|
+
* const onPlayerMove = ({ x, y }: Point) => { [...] };
|
|
146
|
+
*
|
|
147
|
+
* publisher.subscribe("player:spawn", (evt) => publisher.subscribe("player:move", onPlayerMove));
|
|
148
|
+
* publisher.subscribe("player:death", () => publisher.unsubscribe("player:move", onPlayerMove));
|
|
149
|
+
* ```
|
|
150
|
+
*
|
|
151
|
+
* ---
|
|
152
|
+
*
|
|
153
|
+
* @template K The key of the map containing the callback signature to unsubscribe.
|
|
154
|
+
*
|
|
155
|
+
* @param event The name of the event to unsubscribe from.
|
|
156
|
+
* @param subscriber The subscriber to remove from the event.
|
|
157
|
+
*/
|
|
158
|
+
unsubscribe<K extends keyof T>(event: K & string, subscriber: T[K]): void;
|
|
159
|
+
}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import Publisher from "../callbacks/publisher.js";
|
|
2
|
+
|
|
3
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
4
|
+
import type SetView from "./set-view.js";
|
|
5
|
+
import type { MapViewEventsMap } from "./types.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* A wrapper class around the native {@link Map} class that provides additional functionality
|
|
9
|
+
* for publishing events when entries are added, removed or the collection is cleared.
|
|
10
|
+
* There's also a complementary class that works with the native `Set` class.
|
|
11
|
+
* See also {@link SetView}.
|
|
12
|
+
*
|
|
13
|
+
* ---
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* const map = new MapView<string, number>();
|
|
18
|
+
*
|
|
19
|
+
* map.subscribe("entry:add", (key: string, value: number) => console.log(`Added ${key}: ${value}`));
|
|
20
|
+
* map.set("answer", 42); // Added answer: 42
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* ---
|
|
24
|
+
*
|
|
25
|
+
* @template K The type of the keys in the map.
|
|
26
|
+
* @template V The type of the values in the map.
|
|
27
|
+
*/
|
|
28
|
+
export default class MapView<K, V> extends Map<K, V>
|
|
29
|
+
{
|
|
30
|
+
/**
|
|
31
|
+
* The internal {@link Publisher} instance used to publish events.
|
|
32
|
+
*/
|
|
33
|
+
protected readonly _publisher: Publisher<MapViewEventsMap<K, V>>;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Initializes a new instance of the {@link MapView} class.
|
|
37
|
+
*
|
|
38
|
+
* ---
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```ts
|
|
42
|
+
* const map = new MapView<string, number>([["key1", 2], ["key2", 4], ["key3", 8]]);
|
|
43
|
+
* ```
|
|
44
|
+
*
|
|
45
|
+
* ---
|
|
46
|
+
*
|
|
47
|
+
* @param iterable An optional iterable of key-value pairs to initialize the {@link Map} with.
|
|
48
|
+
*/
|
|
49
|
+
public constructor(iterable?: Iterable<[K, V]> | null)
|
|
50
|
+
{
|
|
51
|
+
super();
|
|
52
|
+
|
|
53
|
+
this._publisher = new Publisher();
|
|
54
|
+
|
|
55
|
+
if (iterable)
|
|
56
|
+
{
|
|
57
|
+
for (const [key, value] of iterable) { this.set(key, value); }
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Adds a new entry with a specified key and value to the {@link Map}.
|
|
63
|
+
* If an entry with the same key already exists, the entry will be overwritten with the new value.
|
|
64
|
+
*
|
|
65
|
+
* ---
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```ts
|
|
69
|
+
* const map = new MapView<string, number>();
|
|
70
|
+
* map.set("key1", 2)
|
|
71
|
+
* .set("key2", 4)
|
|
72
|
+
* .set("key3", 8);
|
|
73
|
+
*
|
|
74
|
+
* console.log(map); // MapView { "key1" => 2, "key2" => 4, "key3" => 8 }
|
|
75
|
+
* ```
|
|
76
|
+
*
|
|
77
|
+
* ---
|
|
78
|
+
*
|
|
79
|
+
* @param key The key of the entry to add.
|
|
80
|
+
* @param value The value of the entry to add.
|
|
81
|
+
*
|
|
82
|
+
* @returns The current instance of the {@link MapView} class.
|
|
83
|
+
*/
|
|
84
|
+
public override set(key: K, value: V): this
|
|
85
|
+
{
|
|
86
|
+
super.set(key, value);
|
|
87
|
+
|
|
88
|
+
this._publisher.publish("entry:add", key, value);
|
|
89
|
+
|
|
90
|
+
return this;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Removes an entry with a specified key from the {@link Map}.
|
|
95
|
+
*
|
|
96
|
+
* ---
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* ```ts
|
|
100
|
+
* const map = new MapView<string, number>([["key1", 2], ["key2", 4], ["key3", 8]]);
|
|
101
|
+
* map.delete("key2"); // true
|
|
102
|
+
* map.delete("key4"); // false
|
|
103
|
+
*
|
|
104
|
+
* console.log(map); // MapView { "key1" => 2, "key3" => 8 }
|
|
105
|
+
* ```
|
|
106
|
+
*
|
|
107
|
+
* ---
|
|
108
|
+
*
|
|
109
|
+
* @param key The key of the entry to remove.
|
|
110
|
+
*
|
|
111
|
+
* @returns `true` if the entry existed and has been removed; otherwise `false` if the entry doesn't exist.
|
|
112
|
+
*/
|
|
113
|
+
public override delete(key: K): boolean
|
|
114
|
+
{
|
|
115
|
+
const result = super.delete(key);
|
|
116
|
+
if (result) { this._publisher.publish("entry:remove", key); }
|
|
117
|
+
|
|
118
|
+
return result;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Removes all entries from the {@link Map}.
|
|
123
|
+
*
|
|
124
|
+
* ---
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* ```ts
|
|
128
|
+
* const map = new MapView<string, number>([["key1", 2], ["key2", 4], ["key3", 8]]);
|
|
129
|
+
* map.clear();
|
|
130
|
+
*
|
|
131
|
+
* console.log(map); // MapView { }
|
|
132
|
+
* ```
|
|
133
|
+
*/
|
|
134
|
+
public override clear(): void
|
|
135
|
+
{
|
|
136
|
+
const size = this.size;
|
|
137
|
+
|
|
138
|
+
super.clear();
|
|
139
|
+
if (size > 0) { this._publisher.publish("collection:clear"); }
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Subscribes to an event and adds a callback to be executed when the event is published.
|
|
144
|
+
*
|
|
145
|
+
* ---
|
|
146
|
+
*
|
|
147
|
+
* @example
|
|
148
|
+
* ```ts
|
|
149
|
+
* const map = new MapView<string, number>();
|
|
150
|
+
* const unsubscribe = map.subscribe("entry:add", (key: string, value: number) =>
|
|
151
|
+
* {
|
|
152
|
+
* if (key === "answer") { unsubscribe(); }
|
|
153
|
+
* console.log(`Added ${key}: ${value}`);
|
|
154
|
+
* });
|
|
155
|
+
*
|
|
156
|
+
* map.set("key1", 2); // Added key1: 2
|
|
157
|
+
* map.set("answer", 42); // Added answer: 42
|
|
158
|
+
* map.set("key2", 4);
|
|
159
|
+
* map.set("key3", 8);
|
|
160
|
+
* ```
|
|
161
|
+
*
|
|
162
|
+
* ---
|
|
163
|
+
*
|
|
164
|
+
* @template T The key of the map containing the callback signature to subscribe.
|
|
165
|
+
*
|
|
166
|
+
* @param event The name of the event to subscribe to.
|
|
167
|
+
* @param callback The callback to execute when the event is published.
|
|
168
|
+
*
|
|
169
|
+
* @returns A function that can be used to unsubscribe the callback from the event.
|
|
170
|
+
*/
|
|
171
|
+
public subscribe<T extends keyof MapViewEventsMap<K, V>>(event: T, callback: MapViewEventsMap<K, V>[T]): () => void
|
|
172
|
+
{
|
|
173
|
+
return this._publisher.subscribe(event, callback);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Unsubscribes from an event and removes a callback from being executed when the event is published.
|
|
178
|
+
*
|
|
179
|
+
* ---
|
|
180
|
+
*
|
|
181
|
+
* @example
|
|
182
|
+
* ```ts
|
|
183
|
+
* const callback = (key: string, value: number) => console.log(`Added ${key}: ${value}`);
|
|
184
|
+
* const map = new MapView<string, number>();
|
|
185
|
+
*
|
|
186
|
+
* map.subscribe("entry:add", callback);
|
|
187
|
+
* map.set("key1", 2); // Added key1: 2
|
|
188
|
+
*
|
|
189
|
+
* map.unsubscribe("entry:add", callback);
|
|
190
|
+
* map.set("key2", 4);
|
|
191
|
+
* ```
|
|
192
|
+
*
|
|
193
|
+
* ---
|
|
194
|
+
*
|
|
195
|
+
* @template T The key of the map containing the callback signature to unsubscribe.
|
|
196
|
+
*
|
|
197
|
+
* @param event The name of the event to unsubscribe from.
|
|
198
|
+
* @param callback The callback to remove from the event.
|
|
199
|
+
*/
|
|
200
|
+
public unsubscribe<T extends keyof MapViewEventsMap<K, V>>(event: T, callback: MapViewEventsMap<K, V>[T]): void
|
|
201
|
+
{
|
|
202
|
+
this._publisher.unsubscribe(event, callback);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
public override readonly [Symbol.toStringTag]: string = "MapView";
|
|
206
|
+
}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import Publisher from "../callbacks/publisher.js";
|
|
2
|
+
|
|
3
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
4
|
+
import type MapView from "./map-view.js";
|
|
5
|
+
import type { SetViewEventsMap } from "./types.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* A wrapper class around the native {@link Set} class that provides additional functionality
|
|
9
|
+
* for publishing events when entries are added, removed or the collection is cleared.
|
|
10
|
+
* There's also a complementary class that works with the native `Map` class.
|
|
11
|
+
* See also {@link MapView}.
|
|
12
|
+
*
|
|
13
|
+
* ---
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* const set = new SetView<number>();
|
|
18
|
+
*
|
|
19
|
+
* set.subscribe("entry:add", (value: number) => console.log(`Added ${value}`));
|
|
20
|
+
* set.add(42); // Added 42
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* ---
|
|
24
|
+
*
|
|
25
|
+
* @template T The type of the values in the set.
|
|
26
|
+
*/
|
|
27
|
+
export default class SetView<T> extends Set<T>
|
|
28
|
+
{
|
|
29
|
+
/**
|
|
30
|
+
* The internal {@link Publisher} instance used to publish events.
|
|
31
|
+
*/
|
|
32
|
+
protected readonly _publisher: Publisher<SetViewEventsMap<T>>;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Initializes a new instance of the {@link SetView} class.
|
|
36
|
+
*
|
|
37
|
+
* ---
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```ts
|
|
41
|
+
* const set = new SetView<number>([2, 4, 8]);
|
|
42
|
+
* ```
|
|
43
|
+
*
|
|
44
|
+
* ---
|
|
45
|
+
*
|
|
46
|
+
* @param iterable An optional iterable of values to initialize the {@link Set} with.
|
|
47
|
+
*/
|
|
48
|
+
public constructor(iterable?: Iterable<T> | null)
|
|
49
|
+
{
|
|
50
|
+
super();
|
|
51
|
+
|
|
52
|
+
this._publisher = new Publisher();
|
|
53
|
+
|
|
54
|
+
if (iterable)
|
|
55
|
+
{
|
|
56
|
+
for (const value of iterable) { this.add(value); }
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Appends a new element with a specified value to the end of the {@link Set}.
|
|
62
|
+
* If the value already exists, it will not be added again.
|
|
63
|
+
*
|
|
64
|
+
* ---
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```ts
|
|
68
|
+
* const set = new SetView<number>();
|
|
69
|
+
* set.add(2)
|
|
70
|
+
* .add(4)
|
|
71
|
+
* .add(8);
|
|
72
|
+
*
|
|
73
|
+
* console.log(set); // SetView(4) { 2, 4, 8 }
|
|
74
|
+
* ```
|
|
75
|
+
*
|
|
76
|
+
* ---
|
|
77
|
+
*
|
|
78
|
+
* @param value The value to add.
|
|
79
|
+
*
|
|
80
|
+
* @returns The current instance of the {@link SetView} class.
|
|
81
|
+
*/
|
|
82
|
+
public override add(value: T): this
|
|
83
|
+
{
|
|
84
|
+
super.add(value);
|
|
85
|
+
|
|
86
|
+
this._publisher.publish("entry:add", value);
|
|
87
|
+
|
|
88
|
+
return this;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Removes the specified value from the {@link Set}.
|
|
93
|
+
*
|
|
94
|
+
* ---
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* ```ts
|
|
98
|
+
* const set = new SetView<number>([2, 4, 8]);
|
|
99
|
+
* set.delete(4); // true
|
|
100
|
+
* set.delete(16); // false
|
|
101
|
+
*
|
|
102
|
+
* console.log(set); // SetView(2) { 2, 8 }
|
|
103
|
+
* ```
|
|
104
|
+
*
|
|
105
|
+
* ---
|
|
106
|
+
*
|
|
107
|
+
* @param value The value to remove.
|
|
108
|
+
*
|
|
109
|
+
* @returns `true` if the entry existed and has been removed; otherwise `false` if the entry doesn't exist.
|
|
110
|
+
*/
|
|
111
|
+
public override delete(value: T): boolean
|
|
112
|
+
{
|
|
113
|
+
const result = super.delete(value);
|
|
114
|
+
if (result) { this._publisher.publish("entry:remove", value); }
|
|
115
|
+
|
|
116
|
+
return result;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Removes all entries from the {@link Set}.
|
|
121
|
+
*
|
|
122
|
+
* ---
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* ```ts
|
|
126
|
+
* const set = new SetView<number>([2, 4, 8]);
|
|
127
|
+
* set.clear();
|
|
128
|
+
*
|
|
129
|
+
* console.log(set); // SetView(0) { }
|
|
130
|
+
* ```
|
|
131
|
+
*/
|
|
132
|
+
public override clear(): void
|
|
133
|
+
{
|
|
134
|
+
const size = this.size;
|
|
135
|
+
|
|
136
|
+
super.clear();
|
|
137
|
+
if (size > 0) { this._publisher.publish("collection:clear"); }
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Subscribes to an event and adds a callback to be executed when the event is published.
|
|
142
|
+
*
|
|
143
|
+
* ---
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* ```ts
|
|
147
|
+
* const set = new SetView<number>();
|
|
148
|
+
* const unsubscribe = set.subscribe("entry:add", (value: number) =>
|
|
149
|
+
* {
|
|
150
|
+
* if (value === 42) { unsubscribe(); }
|
|
151
|
+
* console.log(`Added ${value}`);
|
|
152
|
+
* });
|
|
153
|
+
*
|
|
154
|
+
* set.add(2); // Added 2
|
|
155
|
+
* set.add(42); // Added 42
|
|
156
|
+
* set.add(4);
|
|
157
|
+
* set.add(8);
|
|
158
|
+
* ```
|
|
159
|
+
*
|
|
160
|
+
* ---
|
|
161
|
+
*
|
|
162
|
+
* @template K The key of the map containing the callback signature to subscribe.
|
|
163
|
+
*
|
|
164
|
+
* @param event The name of the event to subscribe to.
|
|
165
|
+
* @param callback The callback to execute when the event is published.
|
|
166
|
+
*
|
|
167
|
+
* @returns A function that can be used to unsubscribe the callback from the event.
|
|
168
|
+
*/
|
|
169
|
+
public subscribe<K extends keyof SetViewEventsMap<T>>(event: K, callback: SetViewEventsMap<T>[K]): () => void
|
|
170
|
+
{
|
|
171
|
+
return this._publisher.subscribe(event, callback);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Unsubscribes from an event and removes a callback from being executed when the event is published.
|
|
176
|
+
*
|
|
177
|
+
* ---
|
|
178
|
+
*
|
|
179
|
+
* @example
|
|
180
|
+
* ```ts
|
|
181
|
+
* const callback = (value: number) => console.log(`Added ${value}`);
|
|
182
|
+
* const set = new SetView<number>();
|
|
183
|
+
*
|
|
184
|
+
* set.subscribe("entry:add", callback);
|
|
185
|
+
* set.add(2); // Added 2
|
|
186
|
+
*
|
|
187
|
+
* set.unsubscribe("entry:add", callback);
|
|
188
|
+
* set.add(4);
|
|
189
|
+
* ```
|
|
190
|
+
*
|
|
191
|
+
* ---
|
|
192
|
+
*
|
|
193
|
+
* @template K The key of the map containing the callback signature to unsubscribe.
|
|
194
|
+
*
|
|
195
|
+
* @param event The name of the event to unsubscribe from.
|
|
196
|
+
* @param callback The callback to remove from the event.
|
|
197
|
+
*/
|
|
198
|
+
public unsubscribe<K extends keyof SetViewEventsMap<T>>(event: K, callback: SetViewEventsMap<T>[K]): void
|
|
199
|
+
{
|
|
200
|
+
this._publisher.unsubscribe(event, callback);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
public override readonly [Symbol.toStringTag]: string = "SetView";
|
|
204
|
+
}
|