@byloth/core 2.1.7 → 2.2.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@byloth/core",
3
- "version": "2.1.7",
3
+ "version": "2.2.0",
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",
@@ -49,15 +49,15 @@
49
49
  },
50
50
  "types": "src/index.ts",
51
51
  "devDependencies": {
52
- "@byloth/eslint-config-typescript": "^3.1.0",
53
- "@eslint/compat": "^1.3.0",
54
- "@types/node": "^22.15.32",
52
+ "@byloth/eslint-config-typescript": "^3.2.2",
53
+ "@eslint/compat": "^1.4.1",
54
+ "@types/node": "^22.19.0",
55
55
  "@vitest/coverage-v8": "^3.2.4",
56
- "eslint": "^9.29.0",
56
+ "eslint": "^9.39.1",
57
57
  "husky": "^9.1.7",
58
- "jsdom": "^26.1.0",
59
- "typescript": "^5.8.3",
60
- "vite": "^6.3.5",
58
+ "jsdom": "^27.1.0",
59
+ "typescript": "^5.9.3",
60
+ "vite": "^7.2.1",
61
61
  "vitest": "^3.2.4"
62
62
  },
63
63
  "scripts": {
package/src/index.ts CHANGED
@@ -1,9 +1,8 @@
1
- export const VERSION = "2.1.7";
1
+ export const VERSION = "2.2.0";
2
2
 
3
3
  export type { Constructor, Interval, Timeout, ValueOf } from "./core/types.js";
4
4
 
5
5
  export { isBrowser, isNode, isWorker } from "./helpers.js";
6
-
7
6
  export {
8
7
  AggregatedIterator,
9
8
  AggregatedAsyncIterator,
@@ -62,7 +61,6 @@ export type {
62
61
  KeyedIteratee,
63
62
  KeyedReducer,
64
63
  KeyedTypeGuardPredicate,
65
- MapViewEventsMap,
66
64
  MaybeAsyncKeyedIteratee,
67
65
  MaybeAsyncKeyedReducer,
68
66
  MaybeAsyncGeneratorFunction,
@@ -78,7 +76,6 @@ export type {
78
76
  ReadonlySetView,
79
77
  Reducer,
80
78
  RejectedHandler,
81
- SetViewEventsMap,
82
79
  Subscribable,
83
80
  TypeGuardPredicate,
84
81
  WildcardEventsMap
@@ -507,8 +507,9 @@ export default class AggregatedAsyncIterator<K extends PropertyKey, T>
507
507
  * @returns
508
508
  * A {@link Promise} resolving to a new {@link ReducedIterator} containing the reduced results for each group.
509
509
  */
510
- public async reduce<A extends PropertyKey>(reducer: MaybeAsyncKeyedReducer<K, T, A>, initialValue: MaybePromise<A>)
511
- : Promise<ReducedIterator<K, A>>;
510
+ public async reduce<A extends PropertyKey>(
511
+ reducer: MaybeAsyncKeyedReducer<K, T, A>, initialValue: MaybePromise<A>
512
+ ): Promise<ReducedIterator<K, A>>;
512
513
 
513
514
  /**
514
515
  * Reduces the elements of the iterator using a given reducer function.
@@ -545,8 +546,9 @@ export default class AggregatedAsyncIterator<K extends PropertyKey, T>
545
546
  * @returns
546
547
  * A {@link Promise} resolving to a new {@link ReducedIterator} containing the reduced results for each group.
547
548
  */
548
- public async reduce<A>(reducer: MaybeAsyncKeyedReducer<K, T, A>, initialValue: (key: K) => MaybePromise<A>)
549
- : Promise<ReducedIterator<K, A>>;
549
+ public async reduce<A>(
550
+ reducer: MaybeAsyncKeyedReducer<K, T, A>, initialValue: (key: K) => MaybePromise<A>
551
+ ): Promise<ReducedIterator<K, A>>;
550
552
  public async reduce<A>(
551
553
  reducer: MaybeAsyncKeyedReducer<K, T, A>, initialValue?: MaybePromise<A> | ((key: K) => MaybePromise<A>)
552
554
  ): Promise<ReducedIterator<K, A>>
@@ -810,9 +812,9 @@ export default class AggregatedAsyncIterator<K extends PropertyKey, T>
810
812
  * A {@link Promise} resolving to a new {@link ReducedIterator} containing
811
813
  * the first element that satisfies the condition for each group.
812
814
  */
813
- public async find<S extends T>(predicate: MaybeAsyncKeyedIteratee<K, T, boolean>)
814
- : Promise<ReducedIterator<K, S | undefined>>;
815
-
815
+ public async find<S extends T>(
816
+ predicate: MaybeAsyncKeyedIteratee<K, T, boolean>
817
+ ): Promise<ReducedIterator<K, S | undefined>>;
816
818
  public async find(predicate: MaybeAsyncKeyedIteratee<K, T, boolean>): Promise<ReducedIterator<K, T | undefined>>
817
819
  {
818
820
  const values = new Map<K, [number, T | undefined]>();
@@ -1020,8 +1022,9 @@ export default class AggregatedAsyncIterator<K extends PropertyKey, T>
1020
1022
  *
1021
1023
  * @returns A new {@link AggregatedAsyncIterator} containing the elements reorganized by the new keys.
1022
1024
  */
1023
- public reorganizeBy<J extends PropertyKey>(iteratee: MaybeAsyncKeyedIteratee<K, T, J>)
1024
- : AggregatedAsyncIterator<J, T>
1025
+ public reorganizeBy<J extends PropertyKey>(
1026
+ iteratee: MaybeAsyncKeyedIteratee<K, T, J>
1027
+ ): AggregatedAsyncIterator<J, T>
1025
1028
  {
1026
1029
  const elements = this._elements;
1027
1030
 
@@ -1,7 +1,7 @@
1
1
  import type { Callback } from "./types.js";
2
2
 
3
3
  const SmartFunction = (Function as unknown) as new<A extends unknown[] = [], R = void>(...args: string[])
4
- => Callback<A, R>;
4
+ => Callback<A, R>;
5
5
 
6
6
  /**
7
7
  * An abstract class that can be used to implement callable objects.
@@ -41,7 +41,7 @@ export default abstract class CallableObject<T extends Callback<any[], any> = Ca
41
41
  */
42
42
  public constructor()
43
43
  {
44
- super(`return this._invoke(...arguments);`);
44
+ super("return this._invoke(...arguments);");
45
45
 
46
46
  const self = this.bind(this);
47
47
  Object.setPrototypeOf(this, self);
@@ -68,33 +68,6 @@ export default class Publisher<T extends CallbackMap<T> = CallbackMap>
68
68
  this._subscribers = new Map();
69
69
  }
70
70
 
71
- /**
72
- * Unsubscribes all the subscribers from all the events.
73
- *
74
- * ---
75
- *
76
- * @example
77
- * ```ts
78
- * publisher.subscribe("player:spawn", (evt) => { [...] });
79
- * publisher.subscribe("player:move", (coords) => { [...] });
80
- * publisher.subscribe("player:move", () => { [...] });
81
- * publisher.subscribe("player:move", ({ x, y }) => { [...] });
82
- * publisher.subscribe("player:death", () => { [...] });
83
- *
84
- * // All these subscribers are working fine...
85
- *
86
- * publisher.clear();
87
- *
88
- * // ... but now they're all gone!
89
- * ```
90
- */
91
- public clear(): void
92
- {
93
- this.publish("__internals__:clear");
94
-
95
- this._subscribers.clear();
96
- }
97
-
98
71
  /**
99
72
  * Creates a new scoped instance of the {@link Publisher} class,
100
73
  * which can be used to publish and subscribe events within a specific context.
@@ -110,8 +83,8 @@ export default class Publisher<T extends CallbackMap<T> = CallbackMap>
110
83
  * const publisher = new Publisher();
111
84
  * const context = publisher.createScope();
112
85
  *
113
- * publisher.subscribe("player:death", () => console.log(`Player has died.`));
114
- * context.subscribe("player:spawn", () => console.log(`Player has spawned.`));
86
+ * publisher.subscribe("player:death", () => console.log("Player has died."));
87
+ * context.subscribe("player:spawn", () => console.log("Player has spawned."));
115
88
  *
116
89
  * publisher.publish("player:spawn"); // "Player has spawned."
117
90
  * context.publish("player:death"); // * no output *
@@ -239,7 +212,7 @@ export default class Publisher<T extends CallbackMap<T> = CallbackMap>
239
212
  *
240
213
  * @returns A function that can be used to unsubscribe the subscriber from the event.
241
214
  */
242
- public subscribe<K extends keyof T>(event: K & string, subscriber: T[K]): () => void;
215
+ public subscribe<K extends keyof T>(event: K & string, subscriber: T[K]): Callback;
243
216
 
244
217
  /**
245
218
  * Subscribes to the wildcard event to listen to all published events.
@@ -253,21 +226,21 @@ export default class Publisher<T extends CallbackMap<T> = CallbackMap>
253
226
  * ```ts
254
227
  * publisher.subscribe("*", (type, ...args) =>
255
228
  * {
256
- * console.log(`Event \`${type}\` was fired with args:`, args);
229
+ * console.log(`Event "${type}" was fired with args:`, args);
257
230
  * });
258
231
  * ```
259
232
  *
260
233
  * ---
261
234
  *
262
- * @template K The key of the wildcard events map (always "*").
235
+ * @template K The key of the wildcard events map (always `*`).
263
236
  *
264
- * @param event The wildcard event name ("*").
237
+ * @param event The wildcard event name (`*`).
265
238
  * @param subscriber The subscriber to execute for all published events.
266
239
  *
267
240
  * @returns A function that can be used to unsubscribe the subscriber from the wildcard event.
268
241
  */
269
- public subscribe<K extends keyof S>(event: K & string, subscriber: S[K]): () => void;
270
- public subscribe(event: string, subscriber: Callback<unknown[], unknown>): () => void
242
+ public subscribe<K extends keyof S>(event: K & string, subscriber: S[K]): Callback;
243
+ public subscribe(event: string, subscriber: Callback<unknown[], unknown>): Callback
271
244
  {
272
245
  const subscribers = this._subscribers.get(event) ?? [];
273
246
  subscribers.push(subscriber);
@@ -326,9 +299,9 @@ export default class Publisher<T extends CallbackMap<T> = CallbackMap>
326
299
  *
327
300
  * ---
328
301
  *
329
- * @template K The key of the wildcard events map (always "*").
302
+ * @template K The key of the wildcard events map (always `*`).
330
303
  *
331
- * @param event The wildcard event name ("*").
304
+ * @param event The wildcard event name (`*`).
332
305
  * @param subscriber The wildcard subscriber to remove.
333
306
  */
334
307
  public unsubscribe<K extends keyof S>(event: K & string, subscriber: S[K]): void;
@@ -352,5 +325,94 @@ export default class Publisher<T extends CallbackMap<T> = CallbackMap>
352
325
  if (subscribers.length === 0) { this._subscribers.delete(event); }
353
326
  }
354
327
 
328
+ /**
329
+ * Unsubscribes all subscribers from a specific event and removes
330
+ * them from being executed when the event is published.
331
+ *
332
+ * ---
333
+ *
334
+ * @example
335
+ * ```ts
336
+ * publisher.subscribe("player:spawn", (evt) => { [...] });
337
+ * publisher.subscribe("player:move", (coords) => { [...] });
338
+ * publisher.subscribe("player:move", () => { [...] });
339
+ * publisher.subscribe("player:move", ({ x, y }) => { [...] });
340
+ * publisher.subscribe("player:death", () => { [...] });
341
+ *
342
+ * // All these subscribers are working fine...
343
+ *
344
+ * publisher.unsubscribeAll("player:move");
345
+ *
346
+ * // ... but now "player:move" subscribers are gone!
347
+ * ```
348
+ *
349
+ * ---
350
+ *
351
+ * @template K The key of the map containing the event to clear.
352
+ *
353
+ * @param event The name of the event to unsubscribe all subscribers from.
354
+ */
355
+ public unsubscribeAll<K extends keyof T>(event: K & string): void;
356
+
357
+ /**
358
+ * Unsubscribes all subscribers from the wildcard event and removes
359
+ * them from being executed for all published events.
360
+ *
361
+ * ---
362
+ *
363
+ * @example
364
+ * ```ts
365
+ * publisher.subscribe("player:spawn", (evt) => { [...] });
366
+ * publisher.subscribe("*", (type, ...args) => { [...] });
367
+ * publisher.subscribe("*", (type, arg1, arg2, arg3) => { [...] });
368
+ * publisher.subscribe("*", (_, arg, ...rest) => { [...] });
369
+ * publisher.subscribe("player:death", () => { [...] });
370
+ *
371
+ * // All these subscribers are working fine...
372
+ *
373
+ * publisher.unsubscribeAll("*");
374
+ *
375
+ * // ... but now wildcard subscribers are gone!
376
+ * ```
377
+ *
378
+ * ---
379
+ *
380
+ * @template K The key of the wildcard events map (`*`).
381
+ *
382
+ * @param event The wildcard event name (`*`).
383
+ */
384
+ public unsubscribeAll<K extends keyof S>(event: K & string): void;
385
+ public unsubscribeAll(event: string): void
386
+ {
387
+ this._subscribers.delete(event);
388
+ }
389
+
390
+ /**
391
+ * Unsubscribes all the subscribers from all the events.
392
+ *
393
+ * ---
394
+ *
395
+ * @example
396
+ * ```ts
397
+ * publisher.subscribe("player:spawn", (evt) => { [...] });
398
+ * publisher.subscribe("player:move", (coords) => { [...] });
399
+ * publisher.subscribe("*", () => { [...] });
400
+ * publisher.subscribe("player:move", ({ x, y }) => { [...] });
401
+ * publisher.subscribe("player:death", () => { [...] });
402
+ *
403
+ * // All these subscribers are working fine...
404
+ *
405
+ * publisher.clear();
406
+ *
407
+ * // ... but now they're all gone!
408
+ * ```
409
+ */
410
+ public clear(): void
411
+ {
412
+ this.publish("__internals__:clear");
413
+
414
+ this._subscribers.clear();
415
+ }
416
+
355
417
  public readonly [Symbol.toStringTag]: string = "Publisher";
356
418
  }
@@ -130,7 +130,6 @@ export default class SwitchableCallback<T extends Callback<any[], any> = Callbac
130
130
  "The `SwitchableCallback` has no callback defined yet. " +
131
131
  "Did you forget to call the `register` method?"
132
132
  );
133
-
134
133
  }) as unknown) as T;
135
134
  }
136
135
 
@@ -87,14 +87,14 @@ export type InternalsEventsMap = Record<`__${string}__:${string}`, Callback<unkn
87
87
  *
88
88
  * publisher.subscribe("*", (type: string, ...args: unknown[]) =>
89
89
  * {
90
- * console.log(`Event \`${type}\` was fired with args:`, args));
90
+ * console.log(`Event "${type}" was fired with args:`, args));
91
91
  * });
92
92
  *
93
93
  * publisher.publish("player:move", { x: 10, y: 20 }); // "Event `player:move` was fired with args: [{ x: 10, y: 20 }]"
94
94
  * publisher.publish("player:death"); // "Event `player:death` was fired with args: []"
95
95
  * ```
96
96
  */
97
- export interface WildcardEventsMap { "*": (type: string, ...args: unknown[]) => void; }
97
+ export interface WildcardEventsMap { "*": (type: string, ...args: unknown[]) => void }
98
98
 
99
99
  /**
100
100
  * An utility type that represents a {@link Publisher} object that can be published to.
@@ -178,7 +178,7 @@ export interface Subscribable<T extends CallbackMap<T> = CallbackMap>
178
178
  *
179
179
  * @returns A function that can be used to unsubscribe the subscriber from the event.
180
180
  */
181
- subscribe<K extends keyof T>(event: K & string, subscriber: T[K]): () => void;
181
+ subscribe<K extends keyof T>(event: K & string, subscriber: T[K]): Callback;
182
182
 
183
183
  /**
184
184
  * Unsubscribes from an event and removes a subscriber from being executed when the event is published.
@@ -1,9 +1,16 @@
1
1
  import Publisher from "../callbacks/publisher.js";
2
- import type { Subscribable } from "../types.js";
2
+ import type { Callback } from "../types.js";
3
3
 
4
4
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
5
5
  import type SetView from "./set-view.js";
6
- import type { MapViewEventsMap } from "./types.js";
6
+
7
+ interface MapViewEventsMap<K, V>
8
+ {
9
+ "add": (key: K, value: V) => void;
10
+ "remove": (key: K, value: V) => void;
11
+
12
+ "clear": () => void;
13
+ }
7
14
 
8
15
  /**
9
16
  * A wrapper class around the native {@link Map} class that provides additional functionality
@@ -17,7 +24,7 @@ import type { MapViewEventsMap } from "./types.js";
17
24
  * ```ts
18
25
  * const map = new MapView<string, number>();
19
26
  *
20
- * map.subscribe("entry:add", (key: string, value: number) => console.log(`Added ${key}: ${value}`));
27
+ * map.onAdd((key: string, value: number) => console.log(`Added ${key}: ${value}`));
21
28
  * map.set("answer", 42); // "Added answer: 42"
22
29
  * ```
23
30
  *
@@ -26,7 +33,7 @@ import type { MapViewEventsMap } from "./types.js";
26
33
  * @template K The type of the keys in the map.
27
34
  * @template V The type of the values in the map.
28
35
  */
29
- export default class MapView<K, V> extends Map<K, V> implements Subscribable<MapViewEventsMap<K, V>>
36
+ export default class MapView<K, V> extends Map<K, V>
30
37
  {
31
38
  /**
32
39
  * The internal {@link Publisher} instance used to publish events.
@@ -86,7 +93,7 @@ export default class MapView<K, V> extends Map<K, V> implements Subscribable<Map
86
93
  {
87
94
  super.set(key, value);
88
95
 
89
- this._publisher.publish("entry:add", key, value);
96
+ this._publisher.publish("add", key, value);
90
97
 
91
98
  return this;
92
99
  }
@@ -118,7 +125,7 @@ export default class MapView<K, V> extends Map<K, V> implements Subscribable<Map
118
125
 
119
126
  super.delete(key);
120
127
 
121
- this._publisher.publish("entry:remove", key, value);
128
+ this._publisher.publish("remove", key, value);
122
129
 
123
130
  return true;
124
131
  }
@@ -141,72 +148,77 @@ export default class MapView<K, V> extends Map<K, V> implements Subscribable<Map
141
148
  const size = this.size;
142
149
 
143
150
  super.clear();
144
- if (size > 0) { this._publisher.publish("collection:clear"); }
151
+ if (size > 0) { this._publisher.publish("clear"); }
145
152
  }
146
153
 
147
154
  /**
148
- * Subscribes to an event and adds a callback to be executed when the event is published.
155
+ * Subscribes to the `add` event of the map with a callback that will be executed when an entry is added.
149
156
  *
150
157
  * ---
151
158
  *
152
159
  * @example
153
160
  * ```ts
154
- * const map = new MapView<string, number>();
155
- * const unsubscribe = map.subscribe("entry:add", (key: string, value: number) =>
156
- * {
157
- * if (key === "answer") { unsubscribe(); }
158
- * console.log(`Added ${key}: ${value}`);
159
- * });
161
+ * map.onAdd((key, value) => console.log(`Added ${key}: ${value}`));
160
162
  *
161
163
  * map.set("key1", 2); // "Added key1: 2"
162
164
  * map.set("answer", 42); // "Added answer: 42"
163
- * map.set("key2", 4);
164
- * map.set("key3", 8);
165
165
  * ```
166
166
  *
167
167
  * ---
168
168
  *
169
- * @template T The key of the map containing the callback signature to subscribe.
170
- *
171
- * @param event The name of the event to subscribe to.
172
- * @param subscriber The callback to execute when the event is published.
169
+ * @param callback The callback that will be executed when an entry is added to the map.
173
170
  *
174
- * @returns A function that can be used to unsubscribe the callback from the event.
171
+ * @returns A function that can be used to unsubscribe from the event.
175
172
  */
176
- public subscribe<T extends keyof MapViewEventsMap<K, V>>(event: T, subscriber: MapViewEventsMap<K, V>[T])
177
- : () => void
173
+ public onAdd(callback: (key: K, value: V) => void): Callback
178
174
  {
179
- return this._publisher.subscribe(event, subscriber);
175
+ return this._publisher.subscribe("add", callback);
180
176
  }
181
177
 
182
178
  /**
183
- * Unsubscribes from an event and removes a callback from being executed when the event is published.
179
+ * Subscribes to the `remove` event of the map with a callback that will be executed when an entry is removed.
184
180
  *
185
181
  * ---
186
182
  *
187
183
  * @example
188
184
  * ```ts
189
- * const callback = (key: string, value: number) => console.log(`Added ${key}: ${value}`);
190
- * const map = new MapView<string, number>();
185
+ * map.onRemove((key, value) => console.log(`Removed ${key}: ${value}`));
191
186
  *
192
- * map.subscribe("entry:add", callback);
193
- * map.set("key1", 2); // "Added key1: 2"
187
+ * map.delete("key1"); // "Removed key1: 2"
188
+ * map.delete("answer"); // "Removed answer: 42"
189
+ * ```
190
+ *
191
+ * ---
194
192
  *
195
- * map.unsubscribe("entry:add", callback);
196
- * map.set("key2", 4);
193
+ * @param callback The callback that will be executed when an entry is removed from the map.
194
+ *
195
+ * @returns A function that can be used to unsubscribe from the event.
196
+ */
197
+ public onRemove(callback: (key: K, value: V) => void): Callback
198
+ {
199
+ return this._publisher.subscribe("remove", callback);
200
+ }
201
+
202
+ /**
203
+ * Subscribes to the `clear` event of the map with a callback that will be executed when the map is cleared.
204
+ *
205
+ * ---
206
+ *
207
+ * @example
208
+ * ```ts
209
+ * map.onClear(() => console.log("The map has all been cleared."));
210
+ * map.clear(); // "The map has all been cleared."
197
211
  * ```
198
212
  *
199
213
  * ---
200
214
  *
201
- * @template T The key of the map containing the callback signature to unsubscribe.
215
+ * @param callback The callback that will be executed when the map is cleared.
202
216
  *
203
- * @param event The name of the event to unsubscribe from.
204
- * @param subscriber The callback to remove from the event.
217
+ * @returns A function that can be used to unsubscribe from the event.
205
218
  */
206
- public unsubscribe<T extends keyof MapViewEventsMap<K, V>>(event: T & string, subscriber: MapViewEventsMap<K, V>[T])
207
- : void
219
+ public onClear(callback: () => void): Callback
208
220
  {
209
- this._publisher.unsubscribe(event, subscriber);
221
+ return this._publisher.subscribe("clear", callback);
210
222
  }
211
223
 
212
224
  public override readonly [Symbol.toStringTag]: string = "MapView";