Skip to content

Commit 2ad174d

Browse files
committed
imp: Implemented new unsubscribeAll method on Publisher object class.
1 parent 2b46244 commit 2ad174d

13 files changed

Lines changed: 595 additions & 519 deletions

File tree

package.json

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@byloth/core",
3-
"version": "2.1.7",
3+
"version": "2.1.8",
44
"description": "An unopinionated collection of useful functions and classes that I use widely in all my projects. 🔧",
55
"keywords": [
66
"Core",
@@ -61,14 +61,14 @@
6161
},
6262
"devDependencies": {
6363
"@byloth/eslint-config-typescript": "^3.2.2",
64-
"@eslint/compat": "^1.4.0",
65-
"@types/node": "^22.18.6",
64+
"@eslint/compat": "^1.4.1",
65+
"@types/node": "^22.19.0",
6666
"@vitest/coverage-v8": "^3.2.4",
67-
"eslint": "^9.36.0",
67+
"eslint": "^9.39.1",
6868
"husky": "^9.1.7",
69-
"jsdom": "^27.0.0",
70-
"typescript": "^5.9.2",
71-
"vite": "^7.1.7",
69+
"jsdom": "^27.1.0",
70+
"typescript": "^5.9.3",
71+
"vite": "^7.2.1",
7272
"vitest": "^3.2.4"
7373
}
7474
}

pnpm-lock.yaml

Lines changed: 441 additions & 454 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/index.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
export const VERSION = "2.1.7";
1+
export const VERSION = "2.1.8";
22

33
export type { Constructor, Interval, Timeout, ValueOf } from "./core/types.js";
44

55
export { isBrowser, isNode, isWorker } from "./helpers.js";
6-
76
export {
87
AggregatedIterator,
98
AggregatedAsyncIterator,

src/models/callbacks/publisher.ts

Lines changed: 99 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -68,33 +68,6 @@ export default class Publisher<T extends CallbackMap<T> = CallbackMap>
6868
this._subscribers = new Map();
6969
}
7070

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-
9871
/**
9972
* Creates a new scoped instance of the {@link Publisher} class,
10073
* 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>
11083
* const publisher = new Publisher();
11184
* const context = publisher.createScope();
11285
*
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."));
11588
*
11689
* publisher.publish("player:spawn"); // "Player has spawned."
11790
* context.publish("player:death"); // * no output *
@@ -239,7 +212,7 @@ export default class Publisher<T extends CallbackMap<T> = CallbackMap>
239212
*
240213
* @returns A function that can be used to unsubscribe the subscriber from the event.
241214
*/
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;
243216

244217
/**
245218
* Subscribes to the wildcard event to listen to all published events.
@@ -253,21 +226,21 @@ export default class Publisher<T extends CallbackMap<T> = CallbackMap>
253226
* ```ts
254227
* publisher.subscribe("*", (type, ...args) =>
255228
* {
256-
* console.log(`Event \`${type}\` was fired with args:`, args);
229+
* console.log(`Event "${type}" was fired with args:`, args);
257230
* });
258231
* ```
259232
*
260233
* ---
261234
*
262-
* @template K The key of the wildcard events map (always "*").
235+
* @template K The key of the wildcard events map (always `*`).
263236
*
264-
* @param event The wildcard event name ("*").
237+
* @param event The wildcard event name (`*`).
265238
* @param subscriber The subscriber to execute for all published events.
266239
*
267240
* @returns A function that can be used to unsubscribe the subscriber from the wildcard event.
268241
*/
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
271244
{
272245
const subscribers = this._subscribers.get(event) ?? [];
273246
subscribers.push(subscriber);
@@ -326,9 +299,9 @@ export default class Publisher<T extends CallbackMap<T> = CallbackMap>
326299
*
327300
* ---
328301
*
329-
* @template K The key of the wildcard events map (always "*").
302+
* @template K The key of the wildcard events map (always `*`).
330303
*
331-
* @param event The wildcard event name ("*").
304+
* @param event The wildcard event name (`*`).
332305
* @param subscriber The wildcard subscriber to remove.
333306
*/
334307
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>
352325
if (subscribers.length === 0) { this._subscribers.delete(event); }
353326
}
354327

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+
355417
public readonly [Symbol.toStringTag]: string = "Publisher";
356418
}

src/models/callbacks/types.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ export type InternalsEventsMap = Record<`__${string}__:${string}`, Callback<unkn
8787
*
8888
* publisher.subscribe("*", (type: string, ...args: unknown[]) =>
8989
* {
90-
* console.log(`Event \`${type}\` was fired with args:`, args));
90+
* console.log(`Event "${type}" was fired with args:`, args));
9191
* });
9292
*
9393
* publisher.publish("player:move", { x: 10, y: 20 }); // "Event `player:move` was fired with args: [{ x: 10, y: 20 }]"
@@ -178,7 +178,7 @@ export interface Subscribable<T extends CallbackMap<T> = CallbackMap>
178178
*
179179
* @returns A function that can be used to unsubscribe the subscriber from the event.
180180
*/
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;
182182

183183
/**
184184
* Unsubscribes from an event and removes a subscriber from being executed when the event is published.

src/models/collections/map-view.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import Publisher from "../callbacks/publisher.js";
2-
import type { Subscribable } from "../types.js";
2+
import type { Callback, Subscribable } from "../types.js";
33

44
// eslint-disable-next-line @typescript-eslint/no-unused-vars
55
import type SetView from "./set-view.js";
@@ -174,8 +174,8 @@ export default class MapView<K, V> extends Map<K, V> implements Subscribable<Map
174174
* @returns A function that can be used to unsubscribe the callback from the event.
175175
*/
176176
public subscribe<T extends keyof MapViewEventsMap<K, V>>(
177-
event: T, subscriber: MapViewEventsMap<K, V>[T]
178-
): () => void
177+
event: T & string, subscriber: MapViewEventsMap<K, V>[T]
178+
): Callback
179179
{
180180
return this._publisher.subscribe(event, subscriber);
181181
}

src/models/collections/set-view.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import Publisher from "../callbacks/publisher.js";
2-
import type { Subscribable } from "../types.js";
2+
import type { Callback, Subscribable } from "../types.js";
33

44
// eslint-disable-next-line @typescript-eslint/no-unused-vars
55
import type MapView from "./map-view.js";
@@ -169,7 +169,7 @@ export default class SetView<T> extends Set<T> implements Subscribable<SetViewEv
169169
*/
170170
public subscribe<K extends keyof SetViewEventsMap<T>>(
171171
event: K & string, subscriber: SetViewEventsMap<T>[K]
172-
): () => void
172+
): Callback
173173
{
174174
return this._publisher.subscribe(event, subscriber);
175175
}

src/models/collections/types.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import type { Callback } from "../types.js";
2+
13
// eslint-disable-next-line @typescript-eslint/no-unused-vars
24
import type MapView from "./map-view.js";
35

@@ -66,7 +68,7 @@ export interface ReadonlyMapView<K, V> extends ReadonlyMap<K, V>
6668
*
6769
* @returns A function that can be used to unsubscribe the callback from the event.
6870
*/
69-
subscribe<T extends keyof MapViewEventsMap<K, V>>(event: T, callback: MapViewEventsMap<K, V>[T]): () => void;
71+
subscribe<T extends keyof MapViewEventsMap<K, V>>(event: T & string, callback: MapViewEventsMap<K, V>[T]): Callback;
7072

7173
/**
7274
* Unsubscribes from an event and removes a callback from being executed when the event is published.
@@ -92,7 +94,7 @@ export interface ReadonlyMapView<K, V> extends ReadonlyMap<K, V>
9294
* @param event The name of the event to unsubscribe from.
9395
* @param callback The callback to remove from the event.
9496
*/
95-
unsubscribe<T extends keyof MapViewEventsMap<K, V>>(event: T, callback: MapViewEventsMap<K, V>[T]): void;
97+
unsubscribe<T extends keyof MapViewEventsMap<K, V>>(event: T & string, callback: MapViewEventsMap<K, V>[T]): void;
9698
}
9799

98100
/**
@@ -155,7 +157,7 @@ export interface ReadonlySetView<T> extends ReadonlySet<T>
155157
*
156158
* @returns A function that can be used to unsubscribe the callback from the event.
157159
*/
158-
subscribe<K extends keyof SetViewEventsMap<T>>(event: K, callback: SetViewEventsMap<T>[K]): () => void;
160+
subscribe<K extends keyof SetViewEventsMap<T>>(event: K & string, callback: SetViewEventsMap<T>[K]): Callback;
159161

160162
/**
161163
* Unsubscribes from an event and removes a callback from being executed when the event is published.
@@ -181,5 +183,5 @@ export interface ReadonlySetView<T> extends ReadonlySet<T>
181183
* @param event The name of the event to unsubscribe from.
182184
* @param callback The callback to remove from the event.
183185
*/
184-
unsubscribe<K extends keyof SetViewEventsMap<T>>(event: K, callback: SetViewEventsMap<T>[K]): void;
186+
unsubscribe<K extends keyof SetViewEventsMap<T>>(event: K & string, callback: SetViewEventsMap<T>[K]): void;
185187
}

src/models/promises/smart-promise.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type { Callback } from "../types.js";
12
import type { FulfilledHandler, PromiseExecutor, RejectedHandler } from "./types.js";
23

34
/**
@@ -333,7 +334,7 @@ export default class SmartPromise<T = void> implements Promise<T>
333334
*
334335
* @returns A new {@link Promise} that executes the callback once the promise is settled.
335336
*/
336-
public finally(onFinally?: (() => void) | null): Promise<T>
337+
public finally(onFinally?: Callback | null): Promise<T>
337338
{
338339
return this._promise.finally(onFinally);
339340
}

src/models/timers/clock.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { TimeUnit } from "../../utils/date.js";
22

33
import type Publisher from "../callbacks/publisher.js";
44
import { FatalErrorException, RangeException, RuntimeException } from "../exceptions/index.js";
5+
import type { Callback } from "../types.js";
56

67
import GameLoop from "./game-loop.js";
78

@@ -136,7 +137,7 @@ export default class Clock extends GameLoop
136137
*
137138
* @returns A function that can be used to unsubscribe from the event.
138139
*/
139-
public onTick(callback: (elapsedTime: number) => void, tickStep = 0): () => void
140+
public onTick(callback: (elapsedTime: number) => void, tickStep = 0): Callback
140141
{
141142
if (tickStep < 0) { throw new RangeException("The tick step must be a non-negative number."); }
142143
if (tickStep === 0) { return this._publisher.subscribe("tick", callback); }

0 commit comments

Comments
 (0)