@byloth/core 2.1.4 → 2.1.5

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.4",
3
+ "version": "2.1.5",
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",
@@ -51,9 +51,9 @@
51
51
  "devDependencies": {
52
52
  "@byloth/eslint-config-typescript": "^3.1.0",
53
53
  "@eslint/compat": "^1.3.0",
54
- "@types/node": "^22.15.31",
54
+ "@types/node": "^22.15.32",
55
55
  "@vitest/coverage-v8": "^3.2.3",
56
- "eslint": "^9.28.0",
56
+ "eslint": "^9.29.0",
57
57
  "husky": "^9.1.7",
58
58
  "jsdom": "^26.1.0",
59
59
  "typescript": "^5.8.3",
package/src/core/types.ts CHANGED
@@ -74,7 +74,7 @@ export type Timeout = ReturnType<typeof setTimeout>;
74
74
  * public greet() { console.log("Hello, world!"); }
75
75
  * }
76
76
  *
77
- * type MyObjectProperties = ValueOf<MyObject>; // number | (() => void)
77
+ * type MyObjectProperties = ValueOf<MyObject>; // number | (() => void)
78
78
  * ```
79
79
  *
80
80
  * ---
package/src/index.ts CHANGED
@@ -1,4 +1,4 @@
1
- export const VERSION = "2.1.4";
1
+ export const VERSION = "2.1.5";
2
2
 
3
3
  export type { Constructor, Interval, Timeout, ValueOf } from "./core/types.js";
4
4
 
@@ -24,6 +24,7 @@ export {
24
24
  NotImplementedException,
25
25
  NetworkException,
26
26
  PermissionException,
27
+ PromiseQueue,
27
28
  Publisher,
28
29
  RangeException,
29
30
  ReducedIterator,
@@ -125,6 +125,10 @@ export default class Publisher<T extends CallbackMap<T> = CallbackMap, W extends
125
125
  * Default is `T`.
126
126
  *
127
127
  * @template X An utility type that extends the `U` map with a wildcard event.
128
+ *
129
+ * @return
130
+ * A new instance of the {@link Publisher} class that can be
131
+ * used to publish and subscribe events within a specific context.
128
132
  */
129
133
  public createScope<U extends T = T, X extends WithWildcard<U> = WithWildcard<U>>(): Publisher<U, X>
130
134
  {
@@ -29,5 +29,5 @@ export {
29
29
 
30
30
  export { SmartIterator, SmartAsyncIterator } from "./iterators/index.js";
31
31
  export { JSONStorage } from "./json/index.js";
32
- export { DeferredPromise, SmartPromise, TimedPromise } from "./promises/index.js";
32
+ export { DeferredPromise, PromiseQueue, SmartPromise, TimedPromise } from "./promises/index.js";
33
33
  export { Clock, Countdown, GameLoop } from "./timers/index.js";
@@ -1,5 +1,6 @@
1
1
  import DeferredPromise from "./deferred-promise.js";
2
+ import PromiseQueue from "./promise-queue.js";
2
3
  import SmartPromise from "./smart-promise.js";
3
4
  import TimedPromise from "./timed-promise.js";
4
5
 
5
- export { DeferredPromise, SmartPromise, TimedPromise };
6
+ export { DeferredPromise, PromiseQueue, SmartPromise, TimedPromise };
@@ -0,0 +1,222 @@
1
+ import type { Callback } from "../callbacks/types.js";
2
+
3
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
4
+ import { TimeoutException, ValueException } from "../exceptions/index.js";
5
+
6
+ import DeferredPromise from "./deferred-promise.js";
7
+ import SmartPromise from "./smart-promise.js";
8
+ import TimedPromise from "./timed-promise.js";
9
+ import type { MaybePromise, PromiseRejecter, PromiseResolver } from "./types.js";
10
+
11
+ /**
12
+ * A class that represents a queue of asynchronous operations, allowing them to be executed sequentially.
13
+ *
14
+ * It extends the {@link SmartPromise} class, providing a way to manage multiple promises in a controlled manner.
15
+ * This class is useful for scenarios where you need to ensure
16
+ * that only one asynchronous operation is executed at a time,
17
+ * such as when dealing with API requests, file operations or any other
18
+ * asynchronous tasks that need to be handled in a specific order.
19
+ *
20
+ * ---
21
+ *
22
+ * @example
23
+ * ```ts
24
+ * const queue = new PromiseQueue();
25
+ *
26
+ * queue.enqueue(() => new Promise((resolve) => setTimeout(() => resolve("First"), 2000)))
27
+ * queue.enqueue(() => new Promise((resolve) => setTimeout(() => resolve("Second"), 500)))
28
+ * queue.enqueue(() => new Promise((resolve) => setTimeout(() => resolve("Third"), 1000)))
29
+ *
30
+ * await queue; // "First", "Second", "Third"
31
+ * ```
32
+ */
33
+ export default class PromiseQueue extends SmartPromise<void>
34
+ {
35
+ /**
36
+ * The number of promises currently in the queue.
37
+ */
38
+ protected _count: number;
39
+
40
+ /**
41
+ * A flag indicating whether the promise is still pending or not.
42
+ */
43
+ public override get isPending(): boolean
44
+ {
45
+ return this._count > 0;
46
+ }
47
+ /**
48
+ * A flag indicating whether the promise has been fulfilled or not.
49
+ */
50
+ public override get isFulfilled(): boolean
51
+ {
52
+ return this._count === 0;
53
+ }
54
+
55
+ /**
56
+ * A flag indicating whether the promise has been rejected or not.
57
+ *
58
+ * Please note the {@link PromiseQueue} doesn't support rejection states.
59
+ * Accessing this property will always result in a {@link ValueException}.
60
+ */
61
+ public override get isRejected(): never
62
+ {
63
+ throw new ValueException("`PromiseQueue` doesn't support rejection states.");
64
+ }
65
+
66
+ /**
67
+ * The native {@link Promise} object wrapped by this instance.
68
+ */
69
+ declare protected _promise: Promise<void>;
70
+
71
+ /**
72
+ * Initializes a new instance of the {@link PromiseQueue} class.
73
+ */
74
+ public constructor()
75
+ {
76
+ super((resolve) => resolve());
77
+
78
+ this._count = 0;
79
+
80
+ this._isPending = false;
81
+ this._isFulfilled = false;
82
+ this._isRejected = false;
83
+ }
84
+
85
+ /**
86
+ * Enqueues a {@link DeferredPromise} into the queue.
87
+ *
88
+ * The promise will be executed in sequence after previously enqueued promises.
89
+ *
90
+ * ---
91
+ *
92
+ * @example
93
+ * ```ts
94
+ * const queue = new PromiseQueue();
95
+ * const deferred = new DeferredPromise(() => console.log("Hello, world!"));
96
+ *
97
+ * queue.enqueue(deferred); // "Hello, world!"
98
+ * ```
99
+ *
100
+ * ---
101
+ *
102
+ * @template T The type of value the promise will eventually resolve to.
103
+ *
104
+ * @param promise A `DeferredPromise<void, T>` instance to enqueue.
105
+ *
106
+ * @returns A {@link Promise} that resolves to the value of the enqueued promise.
107
+ */
108
+ public enqueue<T>(promise: DeferredPromise<void, T>): Promise<T>;
109
+
110
+ /**
111
+ * Enqueues a {@link DeferredPromise} into the queue with an optional timeout.
112
+ *
113
+ * The promise will be executed in sequence after previously enqueued promises.
114
+ * If the promise takes longer than the specified timeout, it will be rejected with a {@link TimeoutException}.
115
+ *
116
+ * ---
117
+ *
118
+ * @example
119
+ * ```ts
120
+ * const queue = new PromiseQueue();
121
+ * const deferred = new DeferredPromise(() => console.log("Hello, world!"));
122
+ *
123
+ * queue.enqueue(deferred, 5000); // "Hello, world!"
124
+ * ```
125
+ *
126
+ * ---
127
+ *
128
+ * @template T The type of value the promise will eventually resolve to.
129
+ *
130
+ * @param promise A `DeferredPromise<void, T>` instance to enqueue.
131
+ * @param timeout The maximum time in milliseconds that the operation can take before timing out.
132
+ *
133
+ * @returns
134
+ * A {@link TimedPromise} that resolves to the value of the enqueued promise or rejects
135
+ * with a `TimeoutException` if the operation takes longer than the specified timeout.
136
+ */
137
+ public enqueue<T>(promise: DeferredPromise<void, T>, timeout: number): TimedPromise<T>;
138
+
139
+ /**
140
+ * Enqueues a callback that returns a {@link MaybePromise} value of type `T` into the queue.
141
+ *
142
+ * The executor will be executed in sequence after previously enqueued promises.
143
+ *
144
+ * ---
145
+ *
146
+ * @example
147
+ * ```ts
148
+ * const queue = new PromiseQueue();
149
+ *
150
+ * queue.enqueue(() => console.log("Hello, world!")); // "Hello, world!"
151
+ * ```
152
+ *
153
+ * ---
154
+ *
155
+ * @template T The type of value the promise will eventually resolve to.
156
+ *
157
+ * @param executor A callback that returns a `MaybePromise<T>` value to enqueue.
158
+ *
159
+ * @returns A {@link Promise} that resolves to the value of the enqueued executor.
160
+ */
161
+ public enqueue<T>(executor: Callback<[], MaybePromise<T>>): Promise<T>;
162
+
163
+ /**
164
+ * Enqueues a callback that returns a {@link MaybePromise}
165
+ * value of type `T` into the queue with an optional timeout.
166
+ *
167
+ * The executor will be executed in sequence after previously enqueued promises.
168
+ * If the executor takes longer than the specified timeout, it will be rejected with a {@link TimeoutException}.
169
+ *
170
+ * ---
171
+ *
172
+ * @example
173
+ * ```ts
174
+ * const queue = new PromiseQueue();
175
+ *
176
+ * queue.enqueue(() => console.log("Hello, world!"), 5000); // "Hello, world!"
177
+ * ```
178
+ *
179
+ * ---
180
+ *
181
+ * @template T The type of value the promise will eventually resolve to.
182
+ *
183
+ * @param executor A callback that returns a `MaybePromise<T>` value to enqueue.
184
+ * @param timeout The maximum time in milliseconds that the operation can take before timing out.
185
+ *
186
+ * @returns
187
+ * A {@link TimedPromise} that resolves to the value of the enqueued executor or rejects
188
+ * with a `TimeoutException` if the operation takes longer than the specified timeout.
189
+ */
190
+ public enqueue<T>(executor: Callback<[], MaybePromise<T>>, timeout?: number): TimedPromise<T>;
191
+ public enqueue<T>(executor: DeferredPromise<void, T> | Callback<[], MaybePromise<T>>, timeout?: number)
192
+ : Promise<T> | TimedPromise<T>
193
+ {
194
+ this._count += 1;
195
+
196
+ if (executor instanceof DeferredPromise)
197
+ {
198
+ const _executor = executor as DeferredPromise<void, T>;
199
+
200
+ executor = () =>
201
+ {
202
+ _executor.resolve();
203
+
204
+ return _executor;
205
+ };
206
+ }
207
+
208
+ const _executor = (resolve: PromiseResolver<T>, reject: PromiseRejecter) =>
209
+ {
210
+ this._promise = this._promise
211
+ .then(executor)
212
+ .then((value) => { this._count -= 1; resolve(value); })
213
+ .catch((value) => { this._count -= 1; reject(value); });
214
+ };
215
+
216
+ if (timeout) { return new TimedPromise<T>(_executor, timeout); }
217
+
218
+ return new Promise<T>(_executor);
219
+ }
220
+
221
+ public override readonly [Symbol.toStringTag]: string = "PromiseQueue";
222
+ }