@oscarpalmer/atoms 0.192.0 → 0.193.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/index.d.mts +25 -23
- package/dist/index.mjs +30 -31
- package/dist/queue.d.mts +25 -23
- package/dist/queue.mjs +27 -28
- package/package.json +3 -4
- package/src/array/difference.ts +0 -73
- package/src/array/exists.ts +0 -93
- package/src/array/filter.ts +0 -182
- package/src/array/find.ts +0 -183
- package/src/array/first.ts +0 -196
- package/src/array/flatten.ts +0 -20
- package/src/array/from.ts +0 -129
- package/src/array/get.ts +0 -131
- package/src/array/group-by.ts +0 -369
- package/src/array/index.ts +0 -26
- package/src/array/insert.ts +0 -52
- package/src/array/intersection.ts +0 -72
- package/src/array/last.ts +0 -194
- package/src/array/match.ts +0 -436
- package/src/array/move.ts +0 -315
- package/src/array/partition.ts +0 -91
- package/src/array/push.ts +0 -23
- package/src/array/reverse.ts +0 -33
- package/src/array/select.ts +0 -260
- package/src/array/single.ts +0 -93
- package/src/array/slice.ts +0 -335
- package/src/array/sort.ts +0 -607
- package/src/array/splice.ts +0 -106
- package/src/array/swap.ts +0 -322
- package/src/array/to-map.ts +0 -371
- package/src/array/to-record.ts +0 -351
- package/src/array/to-set.ts +0 -80
- package/src/array/toggle.ts +0 -79
- package/src/array/union.ts +0 -72
- package/src/array/unique.ts +0 -67
- package/src/array/update.ts +0 -75
- package/src/beacon.ts +0 -378
- package/src/color/constants.ts +0 -137
- package/src/color/index.ts +0 -83
- package/src/color/instance.ts +0 -162
- package/src/color/misc/alpha.ts +0 -56
- package/src/color/misc/format.ts +0 -29
- package/src/color/misc/get.ts +0 -210
- package/src/color/misc/is.ts +0 -221
- package/src/color/misc/state.ts +0 -243
- package/src/color/models.ts +0 -389
- package/src/color/space/hex.ts +0 -184
- package/src/color/space/hsl.ts +0 -174
- package/src/color/space/hwb.ts +0 -153
- package/src/color/space/rgb.ts +0 -240
- package/src/function/assert.ts +0 -174
- package/src/function/index.ts +0 -2
- package/src/function/limit.ts +0 -83
- package/src/function/memoize.ts +0 -202
- package/src/function/once.ts +0 -200
- package/src/function/retry.ts +0 -175
- package/src/function/work.ts +0 -1007
- package/src/herald.ts +0 -216
- package/src/index.ts +0 -68
- package/src/internal/array/callbacks.ts +0 -46
- package/src/internal/array/chunk.ts +0 -51
- package/src/internal/array/compact.ts +0 -56
- package/src/internal/array/find.ts +0 -200
- package/src/internal/array/group.ts +0 -42
- package/src/internal/array/index-of.ts +0 -182
- package/src/internal/array/insert.ts +0 -80
- package/src/internal/array/overlap.ts +0 -35
- package/src/internal/array/sets.ts +0 -74
- package/src/internal/array/shuffle.ts +0 -33
- package/src/internal/array/update.ts +0 -52
- package/src/internal/function/misc.ts +0 -8
- package/src/internal/function/timer.ts +0 -168
- package/src/internal/is.ts +0 -244
- package/src/internal/math/aggregate.ts +0 -164
- package/src/internal/math/misc.ts +0 -28
- package/src/internal/number.ts +0 -129
- package/src/internal/random.ts +0 -49
- package/src/internal/result.ts +0 -92
- package/src/internal/sized.ts +0 -25
- package/src/internal/string.ts +0 -128
- package/src/internal/subscription.ts +0 -264
- package/src/internal/value/compare.ts +0 -170
- package/src/internal/value/equal.ts +0 -465
- package/src/internal/value/get.ts +0 -57
- package/src/internal/value/handlers.ts +0 -95
- package/src/internal/value/has.ts +0 -118
- package/src/internal/value/misc.ts +0 -125
- package/src/internal/value/partial.ts +0 -46
- package/src/internal/value/set.ts +0 -132
- package/src/is.ts +0 -182
- package/src/logger.ts +0 -230
- package/src/math.ts +0 -281
- package/src/models.ts +0 -286
- package/src/number.ts +0 -1
- package/src/promise/delay.ts +0 -62
- package/src/promise/helpers.ts +0 -96
- package/src/promise/index.ts +0 -300
- package/src/promise/misc.ts +0 -96
- package/src/promise/models.ts +0 -195
- package/src/promise/timed.ts +0 -91
- package/src/query.ts +0 -147
- package/src/queue.ts +0 -814
- package/src/random.ts +0 -125
- package/src/result/index.ts +0 -105
- package/src/result/match.ts +0 -124
- package/src/result/misc.ts +0 -129
- package/src/result/models.ts +0 -83
- package/src/result/work/flow.ts +0 -488
- package/src/result/work/pipe.ts +0 -496
- package/src/sized/map.ts +0 -110
- package/src/sized/set.ts +0 -107
- package/src/string/case.ts +0 -236
- package/src/string/fuzzy.ts +0 -444
- package/src/string/index.ts +0 -199
- package/src/string/match.ts +0 -80
- package/src/string/normalize.ts +0 -205
- package/src/string/template.ts +0 -161
- package/src/value/clone.ts +0 -319
- package/src/value/collection.ts +0 -63
- package/src/value/diff.ts +0 -232
- package/src/value/freeze.ts +0 -322
- package/src/value/handle.ts +0 -3
- package/src/value/index.ts +0 -5
- package/src/value/merge.ts +0 -278
- package/src/value/omit.ts +0 -20
- package/src/value/pick.ts +0 -20
- package/src/value/shake.ts +0 -45
- package/src/value/smush.ts +0 -89
- package/src/value/transform.ts +0 -153
- package/src/value/unsmush.ts +0 -84
package/src/queue.ts
DELETED
|
@@ -1,814 +0,0 @@
|
|
|
1
|
-
import {getNumberOrDefault} from './internal/number';
|
|
2
|
-
import type {GenericAsyncCallback, GenericCallback} from './models';
|
|
3
|
-
|
|
4
|
-
// #region Types
|
|
5
|
-
|
|
6
|
-
type HandleType = 'clear' | 'pause' | 'resume';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* A queue that can be used to manage (a)synchronous tasks with a specific key
|
|
10
|
-
*/
|
|
11
|
-
export type KeyedQueue<
|
|
12
|
-
CallbackParameters extends Parameters<GenericAsyncCallback>,
|
|
13
|
-
CallbackResult,
|
|
14
|
-
> = {
|
|
15
|
-
/**
|
|
16
|
-
* Get keys of all active queues
|
|
17
|
-
*/
|
|
18
|
-
get active(): string[];
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Does the queue automatically start when the first item is added?
|
|
22
|
-
*/
|
|
23
|
-
get autostart(): boolean;
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Maximum number of runners to process the queue concurrently
|
|
27
|
-
*/
|
|
28
|
-
get concurrency(): number;
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Get keys of all empty queues
|
|
32
|
-
*/
|
|
33
|
-
get empty(): string[];
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Get keys of all full queues
|
|
37
|
-
*/
|
|
38
|
-
get full(): string[];
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Number of items in all queues
|
|
42
|
-
*/
|
|
43
|
-
get items(): Record<string, number>;
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Keys of all queues
|
|
47
|
-
*/
|
|
48
|
-
get keys(): string[];
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Maximum number of items allowed in the queue
|
|
52
|
-
*/
|
|
53
|
-
get maximum(): number;
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Are all queues paused?
|
|
57
|
-
*/
|
|
58
|
-
get paused(): string[];
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Number of queues
|
|
62
|
-
*/
|
|
63
|
-
get queues(): number;
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Queue an item for a specific key
|
|
67
|
-
*
|
|
68
|
-
* @param key Key to queue the item for
|
|
69
|
-
* @param parameters Parameters to use when item runs
|
|
70
|
-
* @param signal Optional signal to abort the item
|
|
71
|
-
* @returns Queued item
|
|
72
|
-
*/
|
|
73
|
-
add(
|
|
74
|
-
key: string,
|
|
75
|
-
parameters: Tail<CallbackParameters>,
|
|
76
|
-
signal?: AbortSignal,
|
|
77
|
-
): Queued<CallbackResult>;
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Clear all items for a specific key _(or all items for all keys, if no key is provided)_
|
|
81
|
-
*
|
|
82
|
-
* @param key Optional key to clear the queue for
|
|
83
|
-
*/
|
|
84
|
-
clear(key?: string): void;
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Get the queue for a specific key
|
|
88
|
-
*
|
|
89
|
-
* @param key Key to get the queue for
|
|
90
|
-
* @returns Queue for the key, or `undefined` if it doesn't exist
|
|
91
|
-
*/
|
|
92
|
-
get(key: string): Queue<Tail<CallbackParameters>, CallbackResult> | undefined;
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Pause the queue for a specific key _(or all queues, if no key is provided)_
|
|
96
|
-
*
|
|
97
|
-
* @param key Optional key to pause the queue for
|
|
98
|
-
*/
|
|
99
|
-
pause(key?: string): void;
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Remove a specific item for a specific key
|
|
103
|
-
*
|
|
104
|
-
* @param key Key to remove the item for
|
|
105
|
-
* @param id ID of the item to remove
|
|
106
|
-
*/
|
|
107
|
-
remove(key: string, id: number): void;
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Remove a queue and its items for a specific key
|
|
111
|
-
*
|
|
112
|
-
* _(To remove all items for a specific key, use `clear()` instead)_
|
|
113
|
-
*
|
|
114
|
-
* @param key Key to remove the queue for
|
|
115
|
-
*/
|
|
116
|
-
remove(key: string): void;
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Remove all queues and their items
|
|
120
|
-
*/
|
|
121
|
-
remove(): void;
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Resume the queue for a specific key _(or all queues, if no key is provided)_
|
|
125
|
-
*
|
|
126
|
-
* @param key Optional key to resume the queue for
|
|
127
|
-
*/
|
|
128
|
-
resume(key?: string): void;
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
type KeyedQueueState = {
|
|
132
|
-
callback: GenericAsyncCallback;
|
|
133
|
-
options: Required<QueueOptions>;
|
|
134
|
-
queues: Map<string, Queue<Tail<unknown[]>, unknown>>;
|
|
135
|
-
};
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* A queue that can be used to manage (a)synchronous tasks
|
|
139
|
-
*/
|
|
140
|
-
export type Queue<CallbackParameters extends Parameters<GenericAsyncCallback>, CallbackResult> = {
|
|
141
|
-
/**
|
|
142
|
-
* Is the queue active?
|
|
143
|
-
*/
|
|
144
|
-
get active(): boolean;
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Does the queue automatically start when the first item is added?
|
|
148
|
-
*/
|
|
149
|
-
get autostart(): boolean;
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* Maximum number of runners to process the queue concurrently
|
|
153
|
-
*/
|
|
154
|
-
get concurrency(): number;
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* Is the queue empty?
|
|
158
|
-
*/
|
|
159
|
-
get empty(): boolean;
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* Is the queue full?
|
|
163
|
-
*/
|
|
164
|
-
get full(): boolean;
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Maximum number of items allowed in the queue
|
|
168
|
-
*/
|
|
169
|
-
get maximum(): number;
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* Is the queue paused?
|
|
173
|
-
*/
|
|
174
|
-
get paused(): boolean;
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* Number of items in the queue
|
|
178
|
-
*/
|
|
179
|
-
get size(): number;
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* Add an item to the queue
|
|
183
|
-
*
|
|
184
|
-
* @param parameters Parameters to use when item runs
|
|
185
|
-
* @param signal Optional signal to abort the item
|
|
186
|
-
* @returns Queued item
|
|
187
|
-
*/
|
|
188
|
-
add(parameters: CallbackParameters, signal?: AbortSignal): Queued<CallbackResult>;
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
* Remove and reject all items in the queue
|
|
192
|
-
*/
|
|
193
|
-
clear(): void;
|
|
194
|
-
|
|
195
|
-
/**
|
|
196
|
-
* Pause the queue
|
|
197
|
-
*
|
|
198
|
-
* - Currently running items will not be stopped
|
|
199
|
-
* - New added items will not run until the queue is resumed
|
|
200
|
-
*/
|
|
201
|
-
pause(): void;
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* Remove and reject a specific item in the queue
|
|
205
|
-
*
|
|
206
|
-
* @param id ID of queued item
|
|
207
|
-
*/
|
|
208
|
-
remove(id: number): void;
|
|
209
|
-
|
|
210
|
-
/**
|
|
211
|
-
* Resume the queue
|
|
212
|
-
*/
|
|
213
|
-
resume(): void;
|
|
214
|
-
};
|
|
215
|
-
|
|
216
|
-
type QueueState = {
|
|
217
|
-
callback: GenericCallback | GenericAsyncCallback;
|
|
218
|
-
handled: GenericCallback[];
|
|
219
|
-
id: number;
|
|
220
|
-
items: Array<QueuedItem>;
|
|
221
|
-
key: string | undefined;
|
|
222
|
-
options: Required<QueueOptions>;
|
|
223
|
-
paused: boolean;
|
|
224
|
-
runners: number;
|
|
225
|
-
};
|
|
226
|
-
|
|
227
|
-
/**
|
|
228
|
-
* An error thrown by the Queue when an operation fails
|
|
229
|
-
*/
|
|
230
|
-
export class QueueError extends Error {
|
|
231
|
-
constructor(message: string) {
|
|
232
|
-
super(message);
|
|
233
|
-
|
|
234
|
-
this.name = ERROR_NAME;
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
export type QueueOptions = {
|
|
239
|
-
/**
|
|
240
|
-
* Automatically start processing the queue when the first item is added _(defaults to `true`)_
|
|
241
|
-
*/
|
|
242
|
-
autostart?: boolean;
|
|
243
|
-
/**
|
|
244
|
-
* Number of runners to process the queue concurrently _(defaults to `1`)_
|
|
245
|
-
*/
|
|
246
|
-
concurrency?: number;
|
|
247
|
-
/**
|
|
248
|
-
* Maximum number of items allowed in the queue _(defaults to `0`, which means no limit)_
|
|
249
|
-
*/
|
|
250
|
-
maximum?: number;
|
|
251
|
-
};
|
|
252
|
-
|
|
253
|
-
/**
|
|
254
|
-
* A queued item
|
|
255
|
-
*/
|
|
256
|
-
export type Queued<Value> = {
|
|
257
|
-
/**
|
|
258
|
-
* ID of the queued item _(can be used to remove it from the queue)_
|
|
259
|
-
*/
|
|
260
|
-
readonly id: number;
|
|
261
|
-
/**
|
|
262
|
-
* Queued promise
|
|
263
|
-
*/
|
|
264
|
-
readonly promise: Promise<QueuedResult<Value>>;
|
|
265
|
-
};
|
|
266
|
-
|
|
267
|
-
type QueuedItem = {
|
|
268
|
-
abort?: () => void;
|
|
269
|
-
id: number;
|
|
270
|
-
key?: string;
|
|
271
|
-
parameters: unknown[];
|
|
272
|
-
promise: Promise<QueuedResult<unknown>>;
|
|
273
|
-
reject: (reason?: unknown) => void;
|
|
274
|
-
resolve: (value: QueuedResult<unknown>) => void;
|
|
275
|
-
signal?: AbortSignal;
|
|
276
|
-
};
|
|
277
|
-
|
|
278
|
-
export type QueuedResult<Value> = {
|
|
279
|
-
/**
|
|
280
|
-
* Has the queue finished processing all items?
|
|
281
|
-
*/
|
|
282
|
-
finished: boolean;
|
|
283
|
-
/**
|
|
284
|
-
* Result for the queued promise
|
|
285
|
-
*/
|
|
286
|
-
value: Value extends Promise<infer Result> ? Result : Value;
|
|
287
|
-
};
|
|
288
|
-
|
|
289
|
-
type StatusKey = 'active' | 'empty' | 'full' | 'paused';
|
|
290
|
-
|
|
291
|
-
type Tail<Values extends any[]> = Values extends [infer _, ...infer Rest] ? Rest : never;
|
|
292
|
-
|
|
293
|
-
// #endregion
|
|
294
|
-
|
|
295
|
-
// #region Functions
|
|
296
|
-
|
|
297
|
-
function createQueue(
|
|
298
|
-
callback: GenericCallback | GenericAsyncCallback,
|
|
299
|
-
options?: QueueOptions,
|
|
300
|
-
key?: string,
|
|
301
|
-
): Queue<unknown[], unknown> {
|
|
302
|
-
if (typeof callback !== 'function') {
|
|
303
|
-
throw new TypeError(MESSAGE_CALLBACK);
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
const state: QueueState = {
|
|
307
|
-
callback,
|
|
308
|
-
key,
|
|
309
|
-
handled: [],
|
|
310
|
-
id: 0,
|
|
311
|
-
items: [],
|
|
312
|
-
options: getOptions(options),
|
|
313
|
-
paused: !getBooleanOrDefault(options?.autostart, true),
|
|
314
|
-
runners: 0,
|
|
315
|
-
};
|
|
316
|
-
|
|
317
|
-
const instance = {
|
|
318
|
-
add: (parameters: unknown[], signal?: AbortSignal) => {
|
|
319
|
-
if ((instance as Queue<unknown[], unknown>).full) {
|
|
320
|
-
throw new QueueError(MESSAGE_MAXIMUM);
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
const abortSignal = signal instanceof AbortSignal ? signal : undefined;
|
|
324
|
-
|
|
325
|
-
if (abortSignal?.aborted ?? false) {
|
|
326
|
-
throw new Error(abortSignal!.reason);
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
const id = identify(state);
|
|
330
|
-
|
|
331
|
-
let rejector: (reason?: unknown) => void;
|
|
332
|
-
let resolver: (value: QueuedResult<unknown>) => void;
|
|
333
|
-
|
|
334
|
-
const promise = new Promise<QueuedResult<unknown>>((resolve, reject) => {
|
|
335
|
-
rejector = reject;
|
|
336
|
-
resolver = resolve;
|
|
337
|
-
});
|
|
338
|
-
|
|
339
|
-
const aborter = abortSignal == null ? undefined : () => rejector(abortSignal.reason);
|
|
340
|
-
|
|
341
|
-
signal?.addEventListener(EVENT_NAME, aborter!, EVENT_OPTIONS);
|
|
342
|
-
|
|
343
|
-
state.items.push({
|
|
344
|
-
id,
|
|
345
|
-
parameters,
|
|
346
|
-
promise,
|
|
347
|
-
abort: aborter,
|
|
348
|
-
key: state.key,
|
|
349
|
-
reject: rejector!,
|
|
350
|
-
resolve: resolver!,
|
|
351
|
-
signal: abortSignal,
|
|
352
|
-
});
|
|
353
|
-
|
|
354
|
-
if (state.options.autostart) {
|
|
355
|
-
void run(state);
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
return {id, promise};
|
|
359
|
-
},
|
|
360
|
-
clear: () => {
|
|
361
|
-
const items = state.items.splice(0);
|
|
362
|
-
const {length} = items;
|
|
363
|
-
|
|
364
|
-
for (let index = 0; index < length; index += 1) {
|
|
365
|
-
const {abort, reject, signal} = items[index];
|
|
366
|
-
|
|
367
|
-
reject(new QueueError(MESSAGE_CLEAR));
|
|
368
|
-
|
|
369
|
-
signal?.removeEventListener(EVENT_NAME, abort!);
|
|
370
|
-
}
|
|
371
|
-
},
|
|
372
|
-
pause: () => {
|
|
373
|
-
state.paused = true;
|
|
374
|
-
},
|
|
375
|
-
remove: (id: number) => {
|
|
376
|
-
const index = state.items.findIndex(item => item.id === id);
|
|
377
|
-
|
|
378
|
-
if (index > -1) {
|
|
379
|
-
const {abort, reject, signal} = state.items.splice(index, 1)[0];
|
|
380
|
-
|
|
381
|
-
reject(new QueueError(MESSAGE_REMOVE));
|
|
382
|
-
|
|
383
|
-
signal?.removeEventListener(EVENT_NAME, abort!);
|
|
384
|
-
}
|
|
385
|
-
},
|
|
386
|
-
resume: () => {
|
|
387
|
-
if (state.paused) {
|
|
388
|
-
const handled = state.handled.splice(0);
|
|
389
|
-
const {length} = handled;
|
|
390
|
-
|
|
391
|
-
for (let index = 0; index < length; index += 1) {
|
|
392
|
-
handled[index]();
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
state.paused = false;
|
|
397
|
-
|
|
398
|
-
const length = Math.min(state.options.concurrency, state.items.length);
|
|
399
|
-
|
|
400
|
-
for (let index = 0; index < length; index += 1) {
|
|
401
|
-
void run(state);
|
|
402
|
-
}
|
|
403
|
-
},
|
|
404
|
-
};
|
|
405
|
-
|
|
406
|
-
Object.defineProperties(instance, {
|
|
407
|
-
[KEY_QUEUE]: {
|
|
408
|
-
enumerable: false,
|
|
409
|
-
value: NAME_QUEUE,
|
|
410
|
-
},
|
|
411
|
-
active: {
|
|
412
|
-
enumerable: true,
|
|
413
|
-
get: () => state.runners > 0,
|
|
414
|
-
},
|
|
415
|
-
autostart: {
|
|
416
|
-
enumerable: true,
|
|
417
|
-
get: () => state.options.autostart,
|
|
418
|
-
},
|
|
419
|
-
concurrency: {
|
|
420
|
-
enumerable: true,
|
|
421
|
-
get: () => state.options.concurrency,
|
|
422
|
-
},
|
|
423
|
-
empty: {
|
|
424
|
-
enumerable: true,
|
|
425
|
-
get: () => state.items.length === 0,
|
|
426
|
-
},
|
|
427
|
-
full: {
|
|
428
|
-
enumerable: true,
|
|
429
|
-
get: () => state.options.maximum > 0 && state.items.length >= state.options.maximum,
|
|
430
|
-
},
|
|
431
|
-
maximum: {
|
|
432
|
-
enumerable: true,
|
|
433
|
-
get: () => state.options.maximum,
|
|
434
|
-
},
|
|
435
|
-
paused: {
|
|
436
|
-
enumerable: true,
|
|
437
|
-
get: () => state.paused,
|
|
438
|
-
},
|
|
439
|
-
size: {
|
|
440
|
-
enumerable: true,
|
|
441
|
-
get: () => state.items.length,
|
|
442
|
-
},
|
|
443
|
-
});
|
|
444
|
-
|
|
445
|
-
return Object.freeze(instance) as Queue<unknown[], unknown>;
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
function getBooleanOrDefault(value: unknown, defaultValue: boolean): boolean {
|
|
449
|
-
return typeof value === 'boolean' ? value : defaultValue;
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
function getOptions(input?: QueueOptions): Required<QueueOptions> {
|
|
453
|
-
const options = typeof input === 'object' && input != null ? input : {};
|
|
454
|
-
|
|
455
|
-
return {
|
|
456
|
-
autostart: getBooleanOrDefault(options.autostart, true),
|
|
457
|
-
concurrency: getNumberOrDefault(options.concurrency, 1, 1),
|
|
458
|
-
maximum: getNumberOrDefault(options.maximum, 0),
|
|
459
|
-
};
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
function getQueue(state: KeyedQueueState, key: string, add: true): Queue<Tail<unknown[]>, unknown>;
|
|
463
|
-
|
|
464
|
-
function getQueue(state: KeyedQueueState, key: string): Queue<Tail<unknown[]>, unknown> | undefined;
|
|
465
|
-
|
|
466
|
-
function getQueue(
|
|
467
|
-
state: KeyedQueueState,
|
|
468
|
-
key: string,
|
|
469
|
-
add?: boolean,
|
|
470
|
-
): Queue<Tail<unknown[]>, unknown> | undefined {
|
|
471
|
-
if (typeof key !== 'string' || key.trim().length === 0) {
|
|
472
|
-
throw new TypeError(MESSAGE_KEY);
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
let queue = state.queues.get(key);
|
|
476
|
-
|
|
477
|
-
if (queue == null && add === true) {
|
|
478
|
-
queue = createQueue(state.callback, state.options, key);
|
|
479
|
-
|
|
480
|
-
state.queues.set(key, queue);
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
return queue;
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
function getStatus(state: KeyedQueueState, status: StatusKey): string[] {
|
|
487
|
-
const queues = state.queues.entries();
|
|
488
|
-
|
|
489
|
-
const result: string[] = [];
|
|
490
|
-
|
|
491
|
-
for (const [key, queue] of queues) {
|
|
492
|
-
if (queue[status]) {
|
|
493
|
-
result.push(key);
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
return result;
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
function handleQueuedResult(
|
|
501
|
-
item: QueuedItem,
|
|
502
|
-
error: boolean,
|
|
503
|
-
result: unknown,
|
|
504
|
-
finished: boolean,
|
|
505
|
-
): void {
|
|
506
|
-
item.signal?.removeEventListener(EVENT_NAME, item.abort!);
|
|
507
|
-
|
|
508
|
-
if (item.signal?.aborted ?? false) {
|
|
509
|
-
item.reject();
|
|
510
|
-
|
|
511
|
-
return;
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
if (error) {
|
|
515
|
-
item.reject(result);
|
|
516
|
-
|
|
517
|
-
return;
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
item.resolve({
|
|
521
|
-
finished,
|
|
522
|
-
value: result as never,
|
|
523
|
-
});
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
function handleQueues(state: KeyedQueueState, type: HandleType, key?: string): void {
|
|
527
|
-
if (typeof key === 'string') {
|
|
528
|
-
getQueue(state, key)?.[type]();
|
|
529
|
-
|
|
530
|
-
return;
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
const queues = state.queues.values();
|
|
534
|
-
|
|
535
|
-
for (const queue of queues) {
|
|
536
|
-
queue[type]();
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
function identify(state: QueueState): number {
|
|
541
|
-
state.id += 1;
|
|
542
|
-
|
|
543
|
-
return state.id;
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
/**
|
|
547
|
-
* Is the value keyed queue?
|
|
548
|
-
*
|
|
549
|
-
* @param value Value to check
|
|
550
|
-
* @returns `true` if the value is a keyed queue, otherwise `false`
|
|
551
|
-
*/
|
|
552
|
-
export function isKeyedQueue(value: unknown): value is KeyedQueue<unknown[], unknown> {
|
|
553
|
-
return isQueueInstance(NAME_KEYED, value);
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
/**
|
|
557
|
-
* Is the value a queue?
|
|
558
|
-
*
|
|
559
|
-
* @param value Value to check
|
|
560
|
-
* @returns `true` if the value is a queue, otherwise `false`
|
|
561
|
-
*/
|
|
562
|
-
export function isQueue(value: unknown): value is Queue<unknown[], unknown> {
|
|
563
|
-
return isQueueInstance(NAME_QUEUE, value);
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
export function isQueueInstance<Instance>(name: string, value: unknown): value is Instance {
|
|
567
|
-
return (
|
|
568
|
-
typeof value === 'object' &&
|
|
569
|
-
value != null &&
|
|
570
|
-
(value as Record<string, unknown>)[KEY_QUEUE] === name
|
|
571
|
-
);
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
export function keyedQueue<Callback extends (key: string, ...parameters: any[]) => Promise<void>>(
|
|
575
|
-
callback: Callback,
|
|
576
|
-
options?: QueueOptions,
|
|
577
|
-
): KeyedQueue<Parameters<Callback>, Awaited<ReturnType<Callback>>>;
|
|
578
|
-
|
|
579
|
-
export function keyedQueue<Callback extends (key: string, ...parameters: any[]) => void>(
|
|
580
|
-
callback: Callback,
|
|
581
|
-
options?: QueueOptions,
|
|
582
|
-
): KeyedQueue<Parameters<Callback>, ReturnType<Callback>>;
|
|
583
|
-
|
|
584
|
-
export function keyedQueue(
|
|
585
|
-
callback: GenericCallback | GenericAsyncCallback,
|
|
586
|
-
options?: QueueOptions,
|
|
587
|
-
): KeyedQueue<unknown[], unknown> {
|
|
588
|
-
if (typeof callback !== 'function') {
|
|
589
|
-
throw new TypeError(MESSAGE_CALLBACK);
|
|
590
|
-
}
|
|
591
|
-
|
|
592
|
-
const state: KeyedQueueState = {
|
|
593
|
-
callback,
|
|
594
|
-
options: getOptions(options),
|
|
595
|
-
queues: new Map(),
|
|
596
|
-
};
|
|
597
|
-
|
|
598
|
-
const instance = {
|
|
599
|
-
add: (key: string, parameters: Tail<unknown[]>, signal?: AbortSignal) =>
|
|
600
|
-
getQueue(state, key, true).add(parameters, signal),
|
|
601
|
-
clear: (key?: string) => {
|
|
602
|
-
handleQueues(state, HANDLE_CLEAR, key);
|
|
603
|
-
},
|
|
604
|
-
get: (key: string) => getQueue(state, key),
|
|
605
|
-
pause: (key?: string): void => {
|
|
606
|
-
handleQueues(state, HANDLE_PAUSE, key);
|
|
607
|
-
},
|
|
608
|
-
remove: (key?: string, id?: number): void => {
|
|
609
|
-
if (key == null) {
|
|
610
|
-
handleQueues(state, HANDLE_CLEAR);
|
|
611
|
-
|
|
612
|
-
state.queues.clear();
|
|
613
|
-
|
|
614
|
-
return;
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
const queue = getQueue(state, key);
|
|
618
|
-
|
|
619
|
-
if (queue == null) {
|
|
620
|
-
return;
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
if (typeof id === 'number') {
|
|
624
|
-
queue.remove(id);
|
|
625
|
-
|
|
626
|
-
return;
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
queue.clear();
|
|
630
|
-
|
|
631
|
-
state.queues.delete(key);
|
|
632
|
-
},
|
|
633
|
-
resume: (key?: string): void => {
|
|
634
|
-
handleQueues(state, HANDLE_RESUME, key);
|
|
635
|
-
},
|
|
636
|
-
};
|
|
637
|
-
|
|
638
|
-
Object.defineProperties(instance, {
|
|
639
|
-
[KEY_QUEUE]: {
|
|
640
|
-
enumerable: false,
|
|
641
|
-
value: NAME_KEYED,
|
|
642
|
-
},
|
|
643
|
-
active: {
|
|
644
|
-
enumerable: true,
|
|
645
|
-
get: () => getStatus(state, STATUS_ACTIVE),
|
|
646
|
-
},
|
|
647
|
-
autostart: {
|
|
648
|
-
enumerable: true,
|
|
649
|
-
get: () => state.options.autostart,
|
|
650
|
-
},
|
|
651
|
-
concurrency: {
|
|
652
|
-
enumerable: true,
|
|
653
|
-
get: () => state.options.concurrency,
|
|
654
|
-
},
|
|
655
|
-
empty: {
|
|
656
|
-
enumerable: true,
|
|
657
|
-
get: () => getStatus(state, STATUS_EMPTY),
|
|
658
|
-
},
|
|
659
|
-
full: {
|
|
660
|
-
enumerable: true,
|
|
661
|
-
get: () => getStatus(state, STATUS_FULL),
|
|
662
|
-
},
|
|
663
|
-
items: {
|
|
664
|
-
enumerable: true,
|
|
665
|
-
get: () => {
|
|
666
|
-
const size: Record<string, number> = {};
|
|
667
|
-
|
|
668
|
-
const queues = state.queues.entries();
|
|
669
|
-
|
|
670
|
-
for (const [key, queue] of queues) {
|
|
671
|
-
size[key] = queue.size;
|
|
672
|
-
}
|
|
673
|
-
|
|
674
|
-
return size;
|
|
675
|
-
},
|
|
676
|
-
},
|
|
677
|
-
keys: {
|
|
678
|
-
enumerable: true,
|
|
679
|
-
get: () => [...state.queues.keys()],
|
|
680
|
-
},
|
|
681
|
-
maximum: {
|
|
682
|
-
enumerable: true,
|
|
683
|
-
get: () => state.options.maximum,
|
|
684
|
-
},
|
|
685
|
-
paused: {
|
|
686
|
-
enumerable: true,
|
|
687
|
-
get: () => getStatus(state, STATUS_PAUSED),
|
|
688
|
-
},
|
|
689
|
-
queues: {
|
|
690
|
-
enumerable: true,
|
|
691
|
-
get: () => state.queues.size,
|
|
692
|
-
},
|
|
693
|
-
});
|
|
694
|
-
|
|
695
|
-
return Object.freeze(instance) as KeyedQueue<unknown[], unknown>;
|
|
696
|
-
}
|
|
697
|
-
|
|
698
|
-
/**
|
|
699
|
-
* Create a queue for an asynchronous callback function
|
|
700
|
-
*
|
|
701
|
-
* @param callback Callback function for queued items
|
|
702
|
-
* @param options Queue options
|
|
703
|
-
* @returns Queue instance
|
|
704
|
-
*/
|
|
705
|
-
export function queue<Callback extends GenericAsyncCallback>(
|
|
706
|
-
callback: Callback,
|
|
707
|
-
options?: QueueOptions,
|
|
708
|
-
): Queue<Parameters<Callback>, Awaited<ReturnType<Callback>>>;
|
|
709
|
-
|
|
710
|
-
/**
|
|
711
|
-
* Create a queue for a synchronous callback function
|
|
712
|
-
*
|
|
713
|
-
* @param callback Callback function for queued items
|
|
714
|
-
* @param options Queue options
|
|
715
|
-
* @returns Queue instance
|
|
716
|
-
*/
|
|
717
|
-
export function queue<Callback extends GenericCallback>(
|
|
718
|
-
callback: Callback,
|
|
719
|
-
options?: QueueOptions,
|
|
720
|
-
): Queue<Parameters<Callback>, ReturnType<Callback>>;
|
|
721
|
-
|
|
722
|
-
export function queue(
|
|
723
|
-
callback: GenericCallback | GenericAsyncCallback,
|
|
724
|
-
options?: QueueOptions,
|
|
725
|
-
): Queue<unknown[], unknown> {
|
|
726
|
-
return createQueue(callback, options);
|
|
727
|
-
}
|
|
728
|
-
|
|
729
|
-
queue.keyed = keyedQueue;
|
|
730
|
-
|
|
731
|
-
async function run(state: QueueState): Promise<void> {
|
|
732
|
-
if (state.paused || state.runners >= state.options.concurrency) {
|
|
733
|
-
return;
|
|
734
|
-
}
|
|
735
|
-
|
|
736
|
-
state.runners += 1;
|
|
737
|
-
|
|
738
|
-
let item = state.items.shift();
|
|
739
|
-
|
|
740
|
-
while (item != null) {
|
|
741
|
-
let error = false;
|
|
742
|
-
|
|
743
|
-
let result: unknown;
|
|
744
|
-
|
|
745
|
-
try {
|
|
746
|
-
if (!(item.signal?.aborted ?? false)) {
|
|
747
|
-
const parameters = item.key == null ? item.parameters : [item.key, ...item.parameters];
|
|
748
|
-
|
|
749
|
-
result = await state.callback(...parameters);
|
|
750
|
-
}
|
|
751
|
-
} catch (thrown) {
|
|
752
|
-
error = true;
|
|
753
|
-
result = thrown;
|
|
754
|
-
}
|
|
755
|
-
|
|
756
|
-
if (state.paused) {
|
|
757
|
-
const paused = item;
|
|
758
|
-
|
|
759
|
-
state.handled.push(() => {
|
|
760
|
-
handleQueuedResult(paused, error, result, state.items.length === 0);
|
|
761
|
-
});
|
|
762
|
-
|
|
763
|
-
break;
|
|
764
|
-
}
|
|
765
|
-
|
|
766
|
-
handleQueuedResult(item, error, result, state.items.length === 0);
|
|
767
|
-
|
|
768
|
-
item = state.items.shift();
|
|
769
|
-
}
|
|
770
|
-
|
|
771
|
-
state.runners -= 1;
|
|
772
|
-
}
|
|
773
|
-
|
|
774
|
-
// #endregion
|
|
775
|
-
|
|
776
|
-
// #region Variables
|
|
777
|
-
|
|
778
|
-
const ERROR_NAME = 'QueueError';
|
|
779
|
-
|
|
780
|
-
const EVENT_NAME = 'abort';
|
|
781
|
-
|
|
782
|
-
const EVENT_OPTIONS = {once: true};
|
|
783
|
-
|
|
784
|
-
const KEY_QUEUE = '$queue';
|
|
785
|
-
|
|
786
|
-
const HANDLE_CLEAR: HandleType = 'clear';
|
|
787
|
-
|
|
788
|
-
const HANDLE_PAUSE: HandleType = 'pause';
|
|
789
|
-
|
|
790
|
-
const HANDLE_RESUME: HandleType = 'resume';
|
|
791
|
-
|
|
792
|
-
const MESSAGE_CALLBACK = 'A Queue requires a callback function';
|
|
793
|
-
|
|
794
|
-
const MESSAGE_CLEAR = 'Queue was cleared';
|
|
795
|
-
|
|
796
|
-
const MESSAGE_KEY = 'Key must be a non-empty string';
|
|
797
|
-
|
|
798
|
-
const MESSAGE_MAXIMUM = 'Queue has reached its maximum size';
|
|
799
|
-
|
|
800
|
-
const MESSAGE_REMOVE = 'Item removed from queue';
|
|
801
|
-
|
|
802
|
-
const NAME_KEYED = 'keyedQueue';
|
|
803
|
-
|
|
804
|
-
const NAME_QUEUE = 'queue';
|
|
805
|
-
|
|
806
|
-
const STATUS_ACTIVE: StatusKey = 'active';
|
|
807
|
-
|
|
808
|
-
const STATUS_EMPTY: StatusKey = 'empty';
|
|
809
|
-
|
|
810
|
-
const STATUS_FULL: StatusKey = 'full';
|
|
811
|
-
|
|
812
|
-
const STATUS_PAUSED: StatusKey = 'paused';
|
|
813
|
-
|
|
814
|
-
// #endregion
|