@juulsgaard/signal-tools 18.0.0 → 18.0.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.
@@ -0,0 +1,115 @@
1
+ import { signal, computed, untracked } from '@angular/core';
2
+ import { pairwiseSignal } from '../operators.js';
3
+
4
+ class SignalQueue {
5
+ constructor(options) {
6
+ this._items = signal([]);
7
+ /** A signal emitting the items of the queue */
8
+ this.items = this._items.asReadonly();
9
+ /** A signal emitting the number of items in the queue */
10
+ this.length = computed(() => this.items().length);
11
+ /** A signal emitting true if there are no items in the queue */
12
+ this.empty = computed(() => this.length() <= 0);
13
+ this._maxSize = options?.size;
14
+ this.front = computed(() => this.items().at(0));
15
+ this.back = computed(() => this.items().at(-1));
16
+ const delta = pairwiseSignal(this.items, []);
17
+ this.frontDelta = computed(() => {
18
+ const [prev, next] = delta();
19
+ const item = next.at(0);
20
+ return { item, added: !item ? false : !prev.includes(item) };
21
+ }, { equal: (a, b) => a.item === b.item });
22
+ this.backDelta = computed(() => {
23
+ const [prev, next] = delta();
24
+ const item = next.at(-1);
25
+ return { item, added: !item ? false : !prev.includes(item) };
26
+ }, { equal: (a, b) => a.item === b.item });
27
+ }
28
+ /** The max size of the queue */
29
+ get maxSize() {
30
+ return this._maxSize;
31
+ }
32
+ //</editor-fold>
33
+ //<editor-fold desc="Actions">
34
+ /**
35
+ * Removes an item from the scheduler
36
+ * @param item
37
+ */
38
+ removeItem(item) {
39
+ const index = untracked(this.items).indexOf(item);
40
+ if (index < 0) return false;
41
+ const arr = [...untracked(this.items)];
42
+ arr.splice(index, 1);
43
+ this._items.set(arr);
44
+ return true;
45
+ }
46
+ dequeue(count) {
47
+ if (count !== void 0) {
48
+ if (count < 1) return [];
49
+ if (!untracked(this.length)) return [];
50
+ const items = untracked(this.items).slice(0, count);
51
+ this._items.set(untracked(this.items).slice(count));
52
+ return items;
53
+ }
54
+ if (!untracked(this.length)) return void 0;
55
+ const item = untracked(this.items).at(0);
56
+ this._items.set(untracked(this.items).slice(1));
57
+ return item;
58
+ }
59
+ removeFromBack(count) {
60
+ if (count !== void 0) {
61
+ if (count < 1) return [];
62
+ if (!untracked(this.length)) return [];
63
+ const start = count * -1;
64
+ const items = untracked(this.items).slice(start);
65
+ this._items.set(untracked(this.items).slice(0, start));
66
+ return items;
67
+ }
68
+ if (!untracked(this.length)) return void 0;
69
+ const item = untracked(this.items).at(-1);
70
+ this._items.set(untracked(this.items).slice(0, -1));
71
+ return item;
72
+ }
73
+ enqueue(...items) {
74
+ let list = [...untracked(this.items), ...items];
75
+ if (this.maxSize !== void 0 && list.length > this.maxSize) {
76
+ const delta = list.length - this.maxSize;
77
+ list = list.slice(delta);
78
+ }
79
+ this._items.set(list);
80
+ }
81
+ addToFront(...items) {
82
+ let list = [...items, ...untracked(this.items)];
83
+ if (this.maxSize !== void 0 && list.length > this.maxSize) {
84
+ const delta = list.length - this.maxSize;
85
+ list = list.slice(0, -delta);
86
+ }
87
+ this._items.set(list);
88
+ }
89
+ /**
90
+ * Checks if the item exists in the queue
91
+ * @param item
92
+ */
93
+ contains(item) {
94
+ return untracked(this.items).includes(item);
95
+ }
96
+ /**
97
+ * Remove all elements from the set
98
+ */
99
+ clear() {
100
+ this._items.set([]);
101
+ }
102
+ //</editor-fold>
103
+ /**
104
+ * Change the max size of the queue
105
+ * @param size - The new max size
106
+ */
107
+ setMaxSize(size) {
108
+ this._maxSize = size;
109
+ if (size === void 0 || untracked(this.length) <= size) return;
110
+ const delta = untracked(this.length) - size;
111
+ this._items.set(untracked(this.items).slice(delta));
112
+ }
113
+ }
114
+
115
+ export { SignalQueue };
@@ -0,0 +1,90 @@
1
+ import { signal, computed, untracked } from '@angular/core';
2
+ import { pairwiseSignal } from '../operators.js';
3
+
4
+ class SignalStack {
5
+ constructor() {
6
+ this._items = signal([]);
7
+ /** A signal containing the items of the stack from bottom to top */
8
+ this.items = this._items.asReadonly();
9
+ /** A signal emitting the number of items in the stack */
10
+ this.length = computed(() => this.items().length);
11
+ /** A signal emitting true if there are no items in the stack */
12
+ this.empty = computed(() => this.length() <= 0);
13
+ this.top = computed(() => this.items().at(-1));
14
+ this.bottom = computed(() => this.items().at(0));
15
+ const delta = pairwiseSignal(this.items, []);
16
+ this.topDelta = computed(() => {
17
+ const [prev, next] = delta();
18
+ const item = next.at(-1);
19
+ return { item, added: !item ? false : !prev.includes(item) };
20
+ }, { equal: (a, b) => a.item === b.item });
21
+ this.bottomDelta = computed(() => {
22
+ const [prev, next] = delta();
23
+ const item = next.at(0);
24
+ return { item, added: !item ? false : !prev.includes(item) };
25
+ }, { equal: (a, b) => a.item === b.item });
26
+ }
27
+ //</editor-fold>
28
+ //<editor-fold desc="Actions">
29
+ /**
30
+ * Removes an item from the scheduler
31
+ * @param item
32
+ */
33
+ removeItem(item) {
34
+ const index = untracked(this.items).indexOf(item);
35
+ if (index < 0) return false;
36
+ const arr = [...untracked(this.items)];
37
+ arr.splice(index, 1);
38
+ this._items.set(arr);
39
+ return true;
40
+ }
41
+ removeFromBottom(count) {
42
+ if (count !== void 0) {
43
+ if (count < 1) return [];
44
+ if (!untracked(this.length)) return [];
45
+ const items = untracked(this.items).slice(0, count);
46
+ this._items.set(untracked(this.items).slice(count));
47
+ return items;
48
+ }
49
+ if (!untracked(this.length)) return void 0;
50
+ const item = untracked(this.items).at(0);
51
+ this._items.set(untracked(this.items).slice(1));
52
+ return item;
53
+ }
54
+ pop(count) {
55
+ if (count !== void 0) {
56
+ if (count < 1) return [];
57
+ if (!untracked(this.length)) return [];
58
+ const start = count * -1;
59
+ const items = untracked(this.items).slice(start);
60
+ this._items.set(untracked(this.items).slice(0, start));
61
+ return items;
62
+ }
63
+ if (!untracked(this.length)) return void 0;
64
+ const item = untracked(this.items).at(-1);
65
+ this._items.set(untracked(this.items).slice(0, -1));
66
+ return item;
67
+ }
68
+ push(...items) {
69
+ this._items.set([...untracked(this.items), ...items]);
70
+ }
71
+ addToBottom(...items) {
72
+ this._items.set([...items, ...untracked(this.items)]);
73
+ }
74
+ /**
75
+ * Checks if the item exists in the queue
76
+ * @param item
77
+ */
78
+ contains(item) {
79
+ return untracked(this.items).includes(item);
80
+ }
81
+ /**
82
+ * Remove all elements from the set
83
+ */
84
+ clear() {
85
+ this._items.set([]);
86
+ }
87
+ //</editor-fold>
88
+ }
89
+
90
+ export { SignalStack };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,7 @@
1
+ import * as _angular_core from '@angular/core';
1
2
  import { Signal, Injector } from '@angular/core';
2
- import { BehaviorSubject, Subject, Subscribable } from 'rxjs';
3
+ import * as rxjs from 'rxjs';
4
+ import { BehaviorSubject, Subject, Subscribable, Observable, Observer, Unsubscribable } from 'rxjs';
3
5
  import { IValueLoadingState } from '@juulsgaard/rxjs-tools';
4
6
 
5
7
  /**
@@ -120,6 +122,86 @@ declare function toLoadingSignal<T>(observable: Subscribable<T>, options?: Loadi
120
122
  */
121
123
  declare function toLoadingSignal<T>(promise: Promise<T>, options?: LoadingSignalOptions): LoadingSignal<T>;
122
124
 
125
+ /**
126
+ * A Map where the state and values are accessible as signals
127
+ * @category Signal Collections
128
+ */
129
+ declare class SignalMap<TKey, TVal> implements ReadonlySignalMap<TKey, TVal> {
130
+ private readonly _map;
131
+ /** @inheritDoc */
132
+ readonly value: Signal<ReadonlyMap<TKey, TVal>>;
133
+ /** @inheritDoc */
134
+ readonly size: Signal<number>;
135
+ /** @inheritDoc */
136
+ readonly empty: Signal<boolean>;
137
+ constructor(values?: ReadonlyMap<TKey, TVal>);
138
+ [Symbol.iterator](): IterableIterator<[TKey, TVal]>;
139
+ private getCopy;
140
+ /**
141
+ * Remove all keys not in the whitelist
142
+ * @param whitelist - The keys to keep
143
+ */
144
+ filter(whitelist: ReadonlyArray<TKey> | ReadonlySet<TKey> | undefined): boolean;
145
+ /** Clear the collection */
146
+ clear(): boolean;
147
+ /**
148
+ * Add a value to the collection if the key is not in use
149
+ * @param key - The key to use
150
+ * @param value - The value to add
151
+ * @return added - Returns true if the value was added
152
+ */
153
+ add(key: TKey, value: TVal): boolean;
154
+ /**
155
+ * Add a value to the collection
156
+ * @param key - The key to use
157
+ * @param value - The value to add
158
+ * @return added - Returns true if the value was added or changed
159
+ */
160
+ set(key: TKey, value: TVal): boolean;
161
+ /**
162
+ * Remove a key from the collection
163
+ * @param key - The key to remove
164
+ * @return removed - True if an item was removed
165
+ */
166
+ delete(key: TKey): boolean;
167
+ /**
168
+ * Remove keys from the collection
169
+ * @param values - The keys to remove
170
+ * @return removed - True if items were removed
171
+ */
172
+ deleteRange(values: TKey[]): boolean;
173
+ /**
174
+ * Toggle a value in the map
175
+ * @param key - The key to toggle
176
+ * @param value - The value to insert if applicable
177
+ * @param state - A forced state (`true` = always add, `false` = always delete)
178
+ * @returns The applied change (`true` = item added, `false` = item removed, `undefined` = nothing changed)
179
+ */
180
+ toggle(key: TKey, value: TVal, state?: boolean): boolean | undefined;
181
+ /** Manually modify the inner collection */
182
+ modify(modify: (map: Map<TKey, TVal>) => void): void;
183
+ /** @inheritDoc */
184
+ has(key: TKey): Signal<boolean>;
185
+ /** @inheritDoc */
186
+ get(key: TKey): Signal<TVal | undefined>;
187
+ }
188
+ /**
189
+ * An immutable Map where the state and values are accessible as signals
190
+ * @category Signal Collections
191
+ */
192
+ interface ReadonlySignalMap<TKey, TVal> extends Iterable<[TKey, TVal]> {
193
+ /** A signal emitting the number of items in the collection */
194
+ readonly size: Signal<number>;
195
+ /** A signal emitting true if the collection is empty */
196
+ readonly empty: Signal<boolean>;
197
+ /** A signal emitting the inner non-signal map */
198
+ readonly value: Signal<ReadonlyMap<TKey, TVal>>;
199
+ /** Create a signal emitting true if a key exists in the collection */
200
+ has(key: TKey): Signal<boolean>;
201
+ /** Create a signal emitting the value under a given key */
202
+ get(key: TKey): Signal<TVal | undefined>;
203
+ }
204
+
123
205
  /**
124
206
  * A Set where the state and values are accessible as signals
125
207
  * @category Signal Collections
@@ -205,83 +287,502 @@ interface ReadonlySignalSet<T> extends Iterable<T> {
205
287
  }
206
288
 
207
289
  /**
208
- * A Map where the state and values are accessible as signals
290
+ * A signal FIFO queue
209
291
  * @category Signal Collections
210
292
  */
211
- declare class SignalMap<TKey, TVal> implements ReadonlySignalMap<TKey, TVal> {
212
- private readonly _map;
213
- /** @inheritDoc */
214
- readonly value: Signal<ReadonlyMap<TKey, TVal>>;
215
- /** @inheritDoc */
216
- readonly size: Signal<number>;
217
- /** @inheritDoc */
293
+ declare class SignalQueue<T> {
294
+ private readonly _items;
295
+ /** A signal emitting the items of the queue */
296
+ readonly items: Signal<T[]>;
297
+ /** A signal emitting the number of items in the queue */
298
+ readonly length: Signal<number>;
299
+ /** A signal emitting true if there are no items in the queue */
218
300
  readonly empty: Signal<boolean>;
219
- constructor(values?: ReadonlyMap<TKey, TVal>);
220
- [Symbol.iterator](): IterableIterator<[TKey, TVal]>;
221
- private getCopy;
301
+ private _maxSize;
302
+ /** The max size of the queue */
303
+ get maxSize(): number | undefined;
304
+ constructor(options?: SignalQueueOptions);
222
305
  /**
223
- * Remove all keys not in the whitelist
224
- * @param whitelist - The keys to keep
306
+ * Signal returning the element at the front of the queue
225
307
  */
226
- filter(whitelist: ReadonlyArray<TKey> | ReadonlySet<TKey> | undefined): boolean;
227
- /** Clear the collection */
228
- clear(): boolean;
308
+ readonly front: Signal<T | undefined>;
309
+ /** Signal returning the current front element and whether it was just added */
310
+ readonly frontDelta: Signal<SignalQueueDelta<T>>;
229
311
  /**
230
- * Add a value to the collection if the key is not in use
231
- * @param key - The key to use
232
- * @param value - The value to add
233
- * @return added - Returns true if the value was added
312
+ * Signal returning the element at the back of the queue
234
313
  */
235
- add(key: TKey, value: TVal): boolean;
314
+ readonly back: Signal<T | undefined>;
315
+ /** Signal returning the current back element and whether it was just added */
316
+ readonly backDelta: Signal<SignalQueueDelta<T>>;
236
317
  /**
237
- * Add a value to the collection
238
- * @param key - The key to use
239
- * @param value - The value to add
240
- * @return added - Returns true if the value was added or changed
318
+ * Removes an item from the scheduler
319
+ * @param item
241
320
  */
242
- set(key: TKey, value: TVal): boolean;
321
+ removeItem(item: T): boolean;
243
322
  /**
244
- * Remove a key from the collection
245
- * @param key - The key to remove
246
- * @return removed - True if an item was removed
323
+ * Remove the front element from the queue and return it
247
324
  */
248
- delete(key: TKey): boolean;
325
+ dequeue(): T | undefined;
249
326
  /**
250
- * Remove keys from the collection
251
- * @param values - The keys to remove
252
- * @return removed - True if items were removed
327
+ * Remove the front x elements from the queue and return them
328
+ * @param count - The amount of elements to remove
253
329
  */
254
- deleteRange(values: TKey[]): boolean;
330
+ dequeue(count: number): T[];
255
331
  /**
256
- * Toggle a value in the map
257
- * @param key - The key to toggle
258
- * @param value - The value to insert if applicable
259
- * @param state - A forced state (`true` = always add, `false` = always delete)
260
- * @returns The applied change (`true` = item added, `false` = item removed, `undefined` = nothing changed)
332
+ * Remove the back element from the queue and return it
261
333
  */
262
- toggle(key: TKey, value: TVal, state?: boolean): boolean | undefined;
263
- /** Manually modify the inner collection */
264
- modify(modify: (map: Map<TKey, TVal>) => void): void;
265
- /** @inheritDoc */
266
- has(key: TKey): Signal<boolean>;
267
- /** @inheritDoc */
268
- get(key: TKey): Signal<TVal | undefined>;
334
+ removeFromBack(): T | undefined;
335
+ /**
336
+ * Remove the back x elements from the queue and return it
337
+ * @param count - The amount of elements to remove
338
+ */
339
+ removeFromBack(count: number): T[];
340
+ /**
341
+ * Add item to the back of the queue
342
+ * @param item - Item to add
343
+ */
344
+ enqueue(item: T): void;
345
+ /**
346
+ * Add items to the back of the queue
347
+ * @param items - Items to add
348
+ */
349
+ enqueue(...items: T[]): void;
350
+ /**
351
+ * Add item to the front of the queue
352
+ * @param item - Item to add
353
+ */
354
+ addToFront(item: T): void;
355
+ /**
356
+ * Add items to the front of the queue
357
+ * @param items - Items to add
358
+ */
359
+ addToFront(...items: T[]): void;
360
+ /**
361
+ * Checks if the item exists in the queue
362
+ * @param item
363
+ */
364
+ contains(item: T): boolean;
365
+ /**
366
+ * Remove all elements from the set
367
+ */
368
+ clear(): void;
369
+ /**
370
+ * Change the max size of the queue
371
+ * @param size - The new max size
372
+ */
373
+ setMaxSize(size: number | undefined): void;
269
374
  }
270
375
  /**
271
- * An immutable Map where the state and values are accessible as signals
376
+ * Options for creating a Queue
272
377
  * @category Signal Collections
273
378
  */
274
- interface ReadonlySignalMap<TKey, TVal> extends Iterable<[TKey, TVal]> {
275
- /** A signal emitting the number of items in the collection */
276
- readonly size: Signal<number>;
277
- /** A signal emitting true if the collection is empty */
379
+ interface SignalQueueOptions {
380
+ size?: number | undefined;
381
+ }
382
+ /**
383
+ * Data indicating the change in state for a location in the Queue
384
+ * @category Signal Collections
385
+ */
386
+ interface SignalQueueDelta<T> {
387
+ added: boolean;
388
+ item?: T;
389
+ }
390
+
391
+ /**
392
+ * A signal based FILO stack
393
+ * @category Signal Collections
394
+ */
395
+ declare class SignalStack<T> {
396
+ private readonly _items;
397
+ /** A signal containing the items of the stack from bottom to top */
398
+ readonly items: Signal<T[]>;
399
+ /** A signal emitting the number of items in the stack */
400
+ readonly length: Signal<number>;
401
+ /** A signal emitting true if there are no items in the stack */
278
402
  readonly empty: Signal<boolean>;
279
- /** A signal emitting the inner non-signal map */
280
- readonly value: Signal<ReadonlyMap<TKey, TVal>>;
281
- /** Create a signal emitting true if a key exists in the collection */
282
- has(key: TKey): Signal<boolean>;
283
- /** Create a signal emitting the value under a given key */
284
- get(key: TKey): Signal<TVal | undefined>;
403
+ constructor();
404
+ /** Signal returning the element at the top of the stack */
405
+ readonly top: Signal<T | undefined>;
406
+ /** Signal returning the current top element and whether it was just added */
407
+ readonly topDelta: Signal<SignalStackDelta<T>>;
408
+ /** Signal returning the element at the bottom of the stack */
409
+ readonly bottom: Signal<T | undefined>;
410
+ /** Signal returning the current bottom element and whether it was just added */
411
+ readonly bottomDelta: Signal<SignalStackDelta<T>>;
412
+ /**
413
+ * Removes an item from the scheduler
414
+ * @param item
415
+ */
416
+ removeItem(item: T): boolean;
417
+ /**
418
+ * Remove the bottom element from the stack and return it
419
+ */
420
+ removeFromBottom(): T | undefined;
421
+ /**
422
+ * Remove the bottom x elements from the stack and return them
423
+ * @param count - The amount of elements to remove
424
+ */
425
+ removeFromBottom(count: number): T[];
426
+ /**
427
+ * Remove the top element from the stack and return it
428
+ */
429
+ pop(): T | undefined;
430
+ /**
431
+ * Remove the top x elements from the stack and return it
432
+ * @param count - The amount of elements to remove
433
+ */
434
+ pop(count: number): T[];
435
+ /**
436
+ * Add item to the top of the stack
437
+ * @param item - Item to add
438
+ */
439
+ push(item: T): void;
440
+ /**
441
+ * Add items to the top of the stack
442
+ * @param items - Items to add
443
+ */
444
+ push(...items: T[]): void;
445
+ /**
446
+ * Add item to the bottom of the stack
447
+ * @param item - Item to add
448
+ */
449
+ addToBottom(item: T): void;
450
+ /**
451
+ * Add items to the bottom of the stack
452
+ * @param items - Items to add
453
+ */
454
+ addToBottom(...items: T[]): void;
455
+ /**
456
+ * Checks if the item exists in the queue
457
+ * @param item
458
+ */
459
+ contains(item: T): boolean;
460
+ /**
461
+ * Remove all elements from the set
462
+ */
463
+ clear(): void;
464
+ }
465
+ /**
466
+ * Data indicating the change in state for a location in the Stack
467
+ * @category Signal Collections
468
+ */
469
+ interface SignalStackDelta<T> {
470
+ item?: T;
471
+ added: boolean;
472
+ }
473
+
474
+ /**
475
+ * A class representing the state of a request
476
+ * @category RequestState
477
+ */
478
+ declare abstract class IRequestState implements Subscribable<unknown> {
479
+ /** The underlying request */
480
+ abstract readonly request$: Observable<unknown>;
481
+ /** The result of the request */
482
+ abstract readonly result$: Observable<unknown>;
483
+ /** The result of the request, or undefined when unresolved */
484
+ abstract readonly result: Signal<unknown | undefined>;
485
+ /** Emits true when the request is running */
486
+ abstract readonly loading: Signal<boolean>;
487
+ /** Emits the error if one is thrown by the request. Otherwise undefined */
488
+ abstract readonly error: Signal<Error | undefined>;
489
+ /** Emits true if the request failed */
490
+ abstract readonly failed: Signal<boolean>;
491
+ /** Cancel a running request */
492
+ abstract cancel(): boolean;
493
+ /**
494
+ * Perform actions when the request finishes
495
+ * @param onValue - Action to perform on successful resolution
496
+ * @param onError - Action to perform on error
497
+ */
498
+ abstract then(onValue: (value: unknown) => void, onError?: (error: Error) => void): this;
499
+ /**
500
+ * Perform an action if the request fails
501
+ * @param onError
502
+ */
503
+ abstract catch(onError: (error: Error) => void): this;
504
+ /**
505
+ * Perform an action when the request finishes (Error or Success)
506
+ * @param onComplete
507
+ */
508
+ abstract finally(onComplete: (error?: Error) => void): this;
509
+ /**
510
+ * Subscribe to the underlying request Observable
511
+ * @param observer
512
+ */
513
+ subscribe(observer: Partial<Observer<unknown>>): Unsubscribable;
514
+ }
515
+ /**
516
+ * A class representing the state of a request with a known return type
517
+ * @category RequestState
518
+ */
519
+ declare abstract class IValueRequestState<T> extends IRequestState implements Subscribable<T> {
520
+ abstract readonly request$: Observable<T>;
521
+ abstract readonly result$: Observable<T>;
522
+ abstract readonly result: Signal<T | undefined>;
523
+ subscribe(observer: Partial<Observer<T>>): Unsubscribable;
524
+ then(onValue: (value: T) => void, onError?: (error: Error) => void): this;
525
+ catch(onError: (error: Error) => void): this;
526
+ finally(onComplete: (error?: Error) => void): this;
527
+ /**
528
+ * Cancel a running request
529
+ * @param error - Optionally provide a custom error to throw when cancelling the request
530
+ */
531
+ abstract cancel(error?: string | Error | (() => Error)): boolean;
532
+ }
533
+
534
+ /**
535
+ * A manually populated RequestState
536
+ * @category RequestState
537
+ */
538
+ declare class WritableRequestState<T> extends IValueRequestState<T> {
539
+ private readonly onCancel?;
540
+ private _completed;
541
+ get completed(): boolean;
542
+ private readonly _request$;
543
+ readonly request$: rxjs.Observable<T>;
544
+ private readonly _result$;
545
+ readonly result$: rxjs.Observable<T>;
546
+ private readonly _result;
547
+ readonly result: _angular_core.Signal<T | undefined>;
548
+ private readonly _loading;
549
+ readonly loading: _angular_core.Signal<boolean>;
550
+ private readonly _error;
551
+ readonly error: _angular_core.Signal<Error | undefined>;
552
+ readonly failed: _angular_core.Signal<boolean>;
553
+ private readonly _cancelled;
554
+ /** Emits true when the RequestState has been cancelled by a consumer, otherwise emits false */
555
+ readonly cancelled: _angular_core.Signal<boolean>;
556
+ private readonly _cancelled$;
557
+ /** Emits true when the RequestState has been cancelled by a consumer */
558
+ readonly cancelled$: rxjs.Observable<true>;
559
+ constructor(onCancel?: (() => void) | undefined);
560
+ /**
561
+ * Create a Readonly version of the RequestState
562
+ */
563
+ asReadonly(): IValueRequestState<T>;
564
+ /**
565
+ * Set the RequestState to an Error state
566
+ * @param error - The error for the RequestState
567
+ */
568
+ setError(error: unknown | Error): void;
569
+ /**
570
+ * Set the RequestState to a completed state with a given value
571
+ * @param value - The value to emit
572
+ */
573
+ setValue(value: T): void;
574
+ cancel(error?: string | Error | (() => Error)): boolean;
575
+ }
576
+
577
+ /**
578
+ * Create a RequestState from a request or Value
579
+ * @param data - The request or value
580
+ * @category RequestState
581
+ */
582
+ declare function valueRequestState<T>(data: T | Promise<T> | Observable<T>): IValueRequestState<T>;
583
+ /** @category RequestState */
584
+ interface AltConstructors {
585
+ /**
586
+ * Create a writable RequestState
587
+ * @param onCancel - Optional cancellation handler
588
+ * @category RequestState
589
+ */
590
+ writable<T>(onCancel?: () => void): WritableRequestState<T>;
591
+ /**
592
+ * Create a RequestState emitting an error
593
+ * @param error - The error to emit
594
+ * @category RequestState
595
+ */
596
+ error(error: Error | (() => Error)): IRequestState;
597
+ /**
598
+ * Create a typed RequestState emitting an error
599
+ * @param error - The error to emit
600
+ * @category RequestState
601
+ */
602
+ error<T>(error: Error | (() => Error)): IValueRequestState<T>;
603
+ /**
604
+ * Create a RequestState which is always loading
605
+ * @category RequestState
606
+ */
607
+ loading(): IRequestState;
608
+ /**
609
+ * Create a typed RequestState which is always loading
610
+ * @category RequestState
611
+ */
612
+ loading<T>(): IValueRequestState<T>;
613
+ /**
614
+ * Create a RequestState that resolves after an amount of time
615
+ * @param duration - The loading duration in milliseconds
616
+ * @category RequestState
617
+ */
618
+ loading(duration: number): IRequestState;
619
+ /**
620
+ * Create a RequestState that resolves with a value after an amount of time
621
+ * @param duration - The loading duration in milliseconds
622
+ * @param value - The value to resolve with after the delay
623
+ * @category RequestState
624
+ */
625
+ loading<T>(duration: number, value: T): IValueRequestState<T>;
626
+ /**
627
+ * Create an empty RequestState
628
+ * @category RequestState
629
+ */
630
+ empty(): IRequestState;
631
+ /**
632
+ * Create a typed empty RequestState
633
+ * @category RequestState
634
+ */
635
+ empty<T>(): IValueRequestState<T>;
636
+ }
637
+ declare const requestState: typeof valueRequestState & AltConstructors;
638
+
639
+ /**
640
+ * A RequestState representing a pending async action
641
+ * @category RequestState
642
+ */
643
+ declare class AsyncRequestState<T> extends IValueRequestState<T> {
644
+ private readonly _request$;
645
+ readonly request$: Observable<T>;
646
+ private readonly _result$;
647
+ readonly result$: Observable<T>;
648
+ private readonly _result;
649
+ readonly result: _angular_core.Signal<T | undefined>;
650
+ private readonly _loading;
651
+ readonly loading: _angular_core.Signal<boolean>;
652
+ private readonly _error;
653
+ readonly error: _angular_core.Signal<Error | undefined>;
654
+ readonly failed: _angular_core.Signal<boolean>;
655
+ private readonly sub;
656
+ constructor(request: Promise<T> | Observable<T>);
657
+ cancel(error?: string | Error | (() => Error)): boolean;
658
+ }
659
+
660
+ /**
661
+ * An Empty RequestState
662
+ * @category RequestState
663
+ */
664
+ declare class EmptyRequestState<T> extends IValueRequestState<T> {
665
+ readonly request$: rxjs.Observable<never>;
666
+ readonly result$: rxjs.Observable<never>;
667
+ readonly result: Signal<undefined>;
668
+ readonly loading: Signal<false>;
669
+ readonly error: Signal<undefined>;
670
+ readonly failed: Signal<false>;
671
+ cancel(): boolean;
672
+ }
673
+
674
+ /**
675
+ * A RequestState which always emits an error
676
+ * @category RequestState
677
+ */
678
+ declare class ErrorRequestState<T> extends IValueRequestState<T> {
679
+ readonly request$: Observable<never>;
680
+ readonly result$: Observable<never>;
681
+ readonly result: Signal<undefined>;
682
+ readonly loading: Signal<boolean>;
683
+ readonly error: Signal<Error | undefined>;
684
+ readonly failed: Signal<boolean>;
685
+ constructor(getError: () => Error);
686
+ cancel(): boolean;
687
+ }
688
+
689
+ /**
690
+ * A RequestState which is perpetually loading
691
+ * @category RequestState
692
+ */
693
+ declare class LoadingRequestState<T> extends IValueRequestState<T> {
694
+ private readonly _request$;
695
+ readonly request$: rxjs.Observable<T>;
696
+ readonly result$: rxjs.Observable<T>;
697
+ readonly result: Signal<undefined>;
698
+ private readonly _loading;
699
+ readonly loading: Signal<boolean>;
700
+ readonly error: Signal<undefined>;
701
+ readonly failed: Signal<false>;
702
+ cancel(): boolean;
703
+ }
704
+
705
+ /**
706
+ * A RequestState which always returns the same value immediately
707
+ * @category RequestState
708
+ */
709
+ declare class StaticRequestState<T> extends IValueRequestState<T> {
710
+ private readonly value;
711
+ readonly request$: Observable<T>;
712
+ readonly result$: Observable<T>;
713
+ readonly result: Signal<T>;
714
+ readonly loading: Signal<false>;
715
+ readonly error: Signal<undefined>;
716
+ readonly failed: Signal<false>;
717
+ constructor(value: T);
718
+ cancel(): boolean;
719
+ then(next: (value: T) => void, _error?: (error: Error) => void): this;
720
+ catch(_onError: (error: Error) => void): this;
721
+ finally(onComplete: () => void): this;
285
722
  }
286
723
 
287
- export { type CreateLoadingSignalOptions, type LoadingSignal, type LoadingSignalOptions, type ReadonlySignalMap, type ReadonlySignalSet, SignalMap, SignalSet, debouncedSignal, debouncedThrottledSignal, loadingSignal, searchSignal, subjectToSignal, throttledSignal, toLoadingSignal };
724
+ /**
725
+ * A container which keeps track of a replaceable RequestState
726
+ * @category RequestState
727
+ */
728
+ declare class RequestTracker {
729
+ private readonly _request;
730
+ /** The currently active RequestState */
731
+ readonly request: Signal<IRequestState>;
732
+ /** The currently active RequestState */
733
+ set current(req: IRequestState);
734
+ get current(): IRequestState;
735
+ /** Emits true if the current RequestState is loading */
736
+ readonly loading: Signal<boolean>;
737
+ /** Emits an error if the current RequestState is in an error state */
738
+ readonly error: Signal<Error | undefined>;
739
+ /** Emits true if the current RequestState has failed */
740
+ readonly failed: Signal<boolean>;
741
+ constructor(request?: IRequestState);
742
+ /**
743
+ * Set a new current RequestState
744
+ * @param state - The new RequestState
745
+ */
746
+ set(state: IRequestState): void;
747
+ /**
748
+ * Resets the Tracker to an Empty state
749
+ */
750
+ reset(): void;
751
+ }
752
+ /**
753
+ * A container which keeps track of a replaceable RequestState of a known return type
754
+ * @category RequestState
755
+ */
756
+ declare class ValueRequestTracker<T> extends RequestTracker {
757
+ private readonly _valueRequest;
758
+ request: Signal<IValueRequestState<T>>;
759
+ set current(req: IValueRequestState<T>);
760
+ get current(): IValueRequestState<T>;
761
+ constructor(request?: IValueRequestState<T>);
762
+ set(req: IValueRequestState<T>): void;
763
+ reset(): void;
764
+ }
765
+ /**
766
+ * Create an empty and untyped RequestTracker
767
+ * @category RequestState
768
+ */
769
+ declare function requestTracker(): RequestTracker;
770
+ /**
771
+ * Create an empty RequestTracker with a known RequestState return type
772
+ * @category RequestState
773
+ */
774
+ declare function requestTracker<T>(): ValueRequestTracker<T>;
775
+ /**
776
+ * Create a typed RequestTracker from a types RequestState
777
+ * @param request - The initial RequestState
778
+ * @category RequestState
779
+ */
780
+ declare function requestTracker<T>(request: IValueRequestState<T>): ValueRequestTracker<T>;
781
+ /**
782
+ * Create an untyped RequestTracker from an untyped RequestState
783
+ * @param request - The initial RequestState
784
+ * @category RequestState
785
+ */
786
+ declare function requestTracker(request: IRequestState): RequestTracker;
787
+
788
+ export { AsyncRequestState, type CreateLoadingSignalOptions, EmptyRequestState, ErrorRequestState, IRequestState, IValueRequestState, LoadingRequestState, type LoadingSignal, type LoadingSignalOptions, type ReadonlySignalMap, type ReadonlySignalSet, RequestTracker, SignalMap, SignalQueue, type SignalQueueDelta, type SignalQueueOptions, SignalSet, SignalStack, type SignalStackDelta, StaticRequestState, ValueRequestTracker, WritableRequestState, debouncedSignal, debouncedThrottledSignal, loadingSignal, requestState, requestTracker, searchSignal, subjectToSignal, throttledSignal, toLoadingSignal };
package/dist/index.js CHANGED
@@ -1,5 +1,16 @@
1
1
  export { debouncedSignal, debouncedThrottledSignal, searchSignal, throttledSignal } from './async.js';
2
2
  export { subjectToSignal } from './interop.js';
3
3
  export { loadingSignal, toLoadingSignal } from './loading-signal.js';
4
- export { SignalSet } from './data-structures/signal-set.js';
5
4
  export { SignalMap } from './data-structures/signal-map.js';
5
+ export { SignalSet } from './data-structures/signal-set.js';
6
+ export { SignalQueue } from './data-structures/signal-queue.js';
7
+ export { SignalStack } from './data-structures/signal-stack.js';
8
+ export { requestState } from './request-state/constructors.js';
9
+ export { IRequestState, IValueRequestState } from './request-state/request-state.js';
10
+ export { AsyncRequestState } from './request-state/async-request-state.js';
11
+ export { EmptyRequestState } from './request-state/empty-request-state.js';
12
+ export { ErrorRequestState } from './request-state/error-request-state.js';
13
+ export { LoadingRequestState } from './request-state/loading-request-state.js';
14
+ export { StaticRequestState } from './request-state/static-request-state.js';
15
+ export { WritableRequestState } from './request-state/writable-request-state.js';
16
+ export { RequestTracker, ValueRequestTracker, requestTracker } from './request-state/request-tracker.js';
@@ -0,0 +1,13 @@
1
+ import { computed } from '@angular/core';
2
+
3
+ function pairwiseSignal(inputSignal, firstValue) {
4
+ let prevValue = firstValue;
5
+ return computed(() => {
6
+ const nextValue = inputSignal();
7
+ const tuple = [prevValue, nextValue];
8
+ prevValue = nextValue;
9
+ return tuple;
10
+ });
11
+ }
12
+
13
+ export { pairwiseSignal };
@@ -0,0 +1,48 @@
1
+ import { ReplaySubject, isObservable, take, from } from 'rxjs';
2
+ import { signal, computed } from '@angular/core';
3
+ import { parseError, isString, isFunction } from '@juulsgaard/ts-tools';
4
+ import { CancelledError } from '@juulsgaard/rxjs-tools';
5
+ import { IValueRequestState } from './request-state.js';
6
+
7
+ class AsyncRequestState extends IValueRequestState {
8
+ constructor(request) {
9
+ super();
10
+ this._request$ = new ReplaySubject();
11
+ this.request$ = this._request$.asObservable();
12
+ this._result$ = new ReplaySubject();
13
+ this.result$ = this._result$.asObservable();
14
+ this._result = signal(void 0);
15
+ this.result = this._result.asReadonly();
16
+ this._loading = signal(true);
17
+ this.loading = this._loading.asReadonly();
18
+ this._error = signal(void 0);
19
+ this.error = this._error.asReadonly();
20
+ this.failed = computed(() => this._error() !== void 0);
21
+ const request$ = isObservable(request) ? request.pipe(take(1)) : from(request);
22
+ this.sub = request$.subscribe(this._request$);
23
+ this.request$.subscribe({
24
+ next: (value) => {
25
+ this._result$.next(value);
26
+ this._result.set(value);
27
+ },
28
+ error: (error) => {
29
+ this._error.set(parseError(error));
30
+ this._result$.complete();
31
+ this._loading.set(false);
32
+ },
33
+ complete: () => {
34
+ this._result$.complete();
35
+ this._loading.set(false);
36
+ }
37
+ });
38
+ }
39
+ cancel(error) {
40
+ if (this.sub.closed) return false;
41
+ this.sub.unsubscribe();
42
+ const fullError = isString(error) ? new CancelledError(error) : isFunction(error) ? error() : error;
43
+ this._request$.error(fullError);
44
+ return true;
45
+ }
46
+ }
47
+
48
+ export { AsyncRequestState };
@@ -0,0 +1,25 @@
1
+ import { isObservable } from 'rxjs';
2
+ import { WritableRequestState } from './writable-request-state.js';
3
+ import { AsyncRequestState } from './async-request-state.js';
4
+ import { StaticRequestState } from './static-request-state.js';
5
+ import { ErrorRequestState } from './error-request-state.js';
6
+ import '@angular/core';
7
+ import '@juulsgaard/ts-tools';
8
+
9
+ function valueRequestState(data) {
10
+ if (isObservable(data)) return new AsyncRequestState(data);
11
+ if (data instanceof Promise) return new AsyncRequestState(data);
12
+ return new StaticRequestState(data);
13
+ }
14
+ function errorRequestState(error) {
15
+ return new ErrorRequestState(error instanceof Error ? () => error : error);
16
+ }
17
+ function writableRequestState(onCancel) {
18
+ return new WritableRequestState(onCancel);
19
+ }
20
+ const compiled = valueRequestState;
21
+ compiled.writable = writableRequestState;
22
+ compiled.error = errorRequestState;
23
+ const requestState = compiled;
24
+
25
+ export { requestState };
@@ -0,0 +1,20 @@
1
+ import { EMPTY } from 'rxjs';
2
+ import { signal } from '@angular/core';
3
+ import { IValueRequestState } from './request-state.js';
4
+
5
+ class EmptyRequestState extends IValueRequestState {
6
+ constructor() {
7
+ super(...arguments);
8
+ this.request$ = EMPTY;
9
+ this.result$ = this.request$;
10
+ this.result = signal(void 0).asReadonly();
11
+ this.loading = signal(false);
12
+ this.error = signal(void 0);
13
+ this.failed = signal(false);
14
+ }
15
+ cancel() {
16
+ return false;
17
+ }
18
+ }
19
+
20
+ export { EmptyRequestState };
@@ -0,0 +1,20 @@
1
+ import { EMPTY, throwError } from 'rxjs';
2
+ import { signal } from '@angular/core';
3
+ import { IValueRequestState } from './request-state.js';
4
+
5
+ class ErrorRequestState extends IValueRequestState {
6
+ constructor(getError) {
7
+ super();
8
+ this.result$ = EMPTY;
9
+ this.result = signal(void 0).asReadonly();
10
+ this.loading = signal(false);
11
+ this.failed = signal(true);
12
+ this.error = signal(getError());
13
+ this.request$ = throwError(getError);
14
+ }
15
+ cancel() {
16
+ return false;
17
+ }
18
+ }
19
+
20
+ export { ErrorRequestState };
@@ -0,0 +1,25 @@
1
+ import { Subject } from 'rxjs';
2
+ import { signal } from '@angular/core';
3
+ import { IValueRequestState } from './request-state.js';
4
+
5
+ class LoadingRequestState extends IValueRequestState {
6
+ constructor() {
7
+ super(...arguments);
8
+ this._request$ = new Subject();
9
+ this.request$ = this._request$.asObservable();
10
+ this.result$ = this.request$;
11
+ this.result = signal(void 0).asReadonly();
12
+ this._loading = signal(true);
13
+ this.loading = this._loading.asReadonly();
14
+ this.error = signal(void 0);
15
+ this.failed = signal(false);
16
+ }
17
+ cancel() {
18
+ if (this._request$.closed) return false;
19
+ this._request$.complete();
20
+ this._loading.set(false);
21
+ return false;
22
+ }
23
+ }
24
+
25
+ export { LoadingRequestState };
@@ -0,0 +1,39 @@
1
+ import { first } from 'rxjs';
2
+ import { parseError } from '@juulsgaard/ts-tools';
3
+
4
+ class IRequestState {
5
+ /**
6
+ * Subscribe to the underlying request Observable
7
+ * @param observer
8
+ */
9
+ subscribe(observer) {
10
+ return this.request$.subscribe(observer);
11
+ }
12
+ }
13
+ class IValueRequestState extends IRequestState {
14
+ subscribe(observer) {
15
+ return this.request$.subscribe(observer);
16
+ }
17
+ then(onValue, onError) {
18
+ this.request$.pipe(first()).subscribe({
19
+ next: (v) => onValue(v),
20
+ error: (e) => onError?.(parseError(e))
21
+ });
22
+ return this;
23
+ }
24
+ catch(onError) {
25
+ this.request$.subscribe({
26
+ error: (e) => onError(parseError(e))
27
+ });
28
+ return this;
29
+ }
30
+ finally(onComplete) {
31
+ this.request$.subscribe({
32
+ error: (e) => onComplete(parseError(e)),
33
+ complete: () => onComplete()
34
+ });
35
+ return this;
36
+ }
37
+ }
38
+
39
+ export { IRequestState, IValueRequestState };
@@ -0,0 +1,64 @@
1
+ import { computed, signal, untracked } from '@angular/core';
2
+ import { IValueRequestState } from './request-state.js';
3
+ import { requestState } from './constructors.js';
4
+
5
+ class RequestTracker {
6
+ constructor(request) {
7
+ /** Emits true if the current RequestState is loading */
8
+ this.loading = computed(() => this._request().loading());
9
+ /** Emits an error if the current RequestState is in an error state */
10
+ this.error = computed(() => this._request().error());
11
+ /** Emits true if the current RequestState has failed */
12
+ this.failed = computed(() => this._request().failed());
13
+ this._request = signal(request ?? requestState.empty());
14
+ this.request = this._request.asReadonly();
15
+ }
16
+ /** The currently active RequestState */
17
+ set current(req) {
18
+ this.set(req);
19
+ }
20
+ get current() {
21
+ return untracked(this.request);
22
+ }
23
+ /**
24
+ * Set a new current RequestState
25
+ * @param state - The new RequestState
26
+ */
27
+ set(state) {
28
+ this._request.set(state);
29
+ }
30
+ /**
31
+ * Resets the Tracker to an Empty state
32
+ */
33
+ reset() {
34
+ this._request.set(requestState.empty());
35
+ }
36
+ }
37
+ class ValueRequestTracker extends RequestTracker {
38
+ set current(req) {
39
+ this.set(req);
40
+ }
41
+ get current() {
42
+ return untracked(this.request);
43
+ }
44
+ constructor(request) {
45
+ super();
46
+ this._valueRequest = signal(request ?? requestState.empty());
47
+ this.request = this._valueRequest.asReadonly();
48
+ }
49
+ set(req) {
50
+ super.set(req);
51
+ this._valueRequest.set(req);
52
+ }
53
+ reset() {
54
+ super.reset();
55
+ this.set(requestState.empty());
56
+ }
57
+ }
58
+ function requestTracker(request) {
59
+ if (!request) return new ValueRequestTracker();
60
+ if (request instanceof IValueRequestState) return new ValueRequestTracker(request);
61
+ return new RequestTracker(request);
62
+ }
63
+
64
+ export { RequestTracker, ValueRequestTracker, requestTracker };
@@ -0,0 +1,32 @@
1
+ import { of } from 'rxjs';
2
+ import { signal } from '@angular/core';
3
+ import { IValueRequestState } from './request-state.js';
4
+
5
+ class StaticRequestState extends IValueRequestState {
6
+ constructor(value) {
7
+ super();
8
+ this.value = value;
9
+ this.loading = signal(false);
10
+ this.error = signal(void 0);
11
+ this.failed = signal(false);
12
+ this.request$ = of(value);
13
+ this.result$ = this.request$;
14
+ this.result = signal(value);
15
+ }
16
+ cancel() {
17
+ return false;
18
+ }
19
+ then(next, _error) {
20
+ next(this.value);
21
+ return this;
22
+ }
23
+ catch(_onError) {
24
+ return this;
25
+ }
26
+ finally(onComplete) {
27
+ onComplete();
28
+ return this;
29
+ }
30
+ }
31
+
32
+ export { StaticRequestState };
@@ -0,0 +1,75 @@
1
+ import { ReplaySubject } from 'rxjs';
2
+ import { signal, computed } from '@angular/core';
3
+ import { parseError, isString, isFunction } from '@juulsgaard/ts-tools';
4
+ import { CancelledError } from '@juulsgaard/rxjs-tools';
5
+ import { IValueRequestState } from './request-state.js';
6
+
7
+ class WritableRequestState extends IValueRequestState {
8
+ constructor(onCancel) {
9
+ super();
10
+ this.onCancel = onCancel;
11
+ this._completed = false;
12
+ this._request$ = new ReplaySubject();
13
+ this.request$ = this._request$.asObservable();
14
+ this._result$ = new ReplaySubject();
15
+ this.result$ = this._result$.asObservable();
16
+ this._result = signal(void 0);
17
+ this.result = this._result.asReadonly();
18
+ this._loading = signal(true);
19
+ this.loading = this._loading.asReadonly();
20
+ this._error = signal(void 0);
21
+ this.error = this._error.asReadonly();
22
+ this.failed = computed(() => this._error() !== void 0);
23
+ this._cancelled = signal(false);
24
+ /** Emits true when the RequestState has been cancelled by a consumer, otherwise emits false */
25
+ this.cancelled = this._cancelled.asReadonly();
26
+ this._cancelled$ = new ReplaySubject();
27
+ /** Emits true when the RequestState has been cancelled by a consumer */
28
+ this.cancelled$ = this._cancelled$.asObservable();
29
+ }
30
+ get completed() {
31
+ return this._completed;
32
+ }
33
+ /**
34
+ * Create a Readonly version of the RequestState
35
+ */
36
+ asReadonly() {
37
+ return this;
38
+ }
39
+ /**
40
+ * Set the RequestState to an Error state
41
+ * @param error - The error for the RequestState
42
+ */
43
+ setError(error) {
44
+ if (this.completed) return;
45
+ this._completed = true;
46
+ this._request$.error(error);
47
+ this._result$.complete();
48
+ this._loading.set(false);
49
+ this._error.set(parseError(error));
50
+ }
51
+ /**
52
+ * Set the RequestState to a completed state with a given value
53
+ * @param value - The value to emit
54
+ */
55
+ setValue(value) {
56
+ if (this.completed) return;
57
+ this._completed = true;
58
+ this._request$.next(value);
59
+ this._request$.complete();
60
+ this._loading.set(false);
61
+ this._result.set(value);
62
+ }
63
+ cancel(error) {
64
+ if (this.completed) return false;
65
+ const fullError = isString(error) ? new CancelledError(error) : isFunction(error) ? error() : error;
66
+ this.setError(fullError);
67
+ this._cancelled.set(true);
68
+ this._cancelled$.next(true);
69
+ this._cancelled$.complete();
70
+ this.onCancel?.();
71
+ return true;
72
+ }
73
+ }
74
+
75
+ export { WritableRequestState };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@juulsgaard/signal-tools",
3
- "version": "18.0.0",
3
+ "version": "18.0.1",
4
4
  "description": "Tools for working with Angular signals",
5
5
  "repository": "git@github.com:Juulsgaard/signal-tools.git",
6
6
  "homepage": "https://juulsgaard.github.io/signal-tools/",
@@ -14,24 +14,24 @@
14
14
  "dist/**"
15
15
  ],
16
16
  "peerDependencies": {
17
- "@angular/core": "^18.2.5",
17
+ "@angular/core": "^18.2.8",
18
18
  "@juulsgaard/ts-tools": "^1.6.4",
19
- "@juulsgaard/rxjs-tools": "^1.7.4",
19
+ "@juulsgaard/rxjs-tools": "^1.7.6",
20
20
  "rxjs": "^7.8.1",
21
21
  "tslib": "^2.7.0",
22
22
  "typescript": "~5.5.4"
23
23
  },
24
24
  "devDependencies": {
25
- "@angular/core": "18.2.5",
26
- "@juulsgaard/rxjs-tools": "1.7.4",
27
- "@types/jest": "^29.5.12",
25
+ "@angular/core": "18.2.8",
26
+ "@juulsgaard/rxjs-tools": "1.7.6",
27
+ "@types/jest": "^29.5.13",
28
28
  "jest": "^29.7.0",
29
- "rollup": "^4.19.1",
29
+ "rollup": "^4.24.0",
30
30
  "rollup-plugin-dts": "^6.1.1",
31
31
  "rollup-plugin-esbuild": "^6.1.1",
32
32
  "rxjs": "7.8.1",
33
- "ts-jest": "^29.2.3",
34
- "typedoc": "^0.26.7",
33
+ "ts-jest": "^29.2.5",
34
+ "typedoc": "^0.26.8",
35
35
  "typescript": "~5.5.4",
36
36
  "tslib": "2.7.0"
37
37
  },