@matter/general 0.16.0-alpha.0-20251030-e9ca79f93 → 0.16.0-alpha.0-20251031-0f308af69
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/cjs/MatterError.d.ts +17 -0
- package/dist/cjs/MatterError.d.ts.map +1 -1
- package/dist/cjs/MatterError.js +24 -0
- package/dist/cjs/MatterError.js.map +1 -1
- package/dist/cjs/util/Abort.d.ts +83 -7
- package/dist/cjs/util/Abort.d.ts.map +1 -1
- package/dist/cjs/util/Abort.js +138 -24
- package/dist/cjs/util/Abort.js.map +2 -2
- package/dist/cjs/util/Error.d.ts.map +1 -1
- package/dist/cjs/util/Error.js +7 -0
- package/dist/cjs/util/Error.js.map +1 -1
- package/dist/cjs/util/Function.d.ts +18 -0
- package/dist/cjs/util/Function.d.ts.map +1 -0
- package/dist/cjs/util/Function.js +38 -0
- package/dist/cjs/util/Function.js.map +6 -0
- package/dist/cjs/util/Observable.d.ts +16 -4
- package/dist/cjs/util/Observable.d.ts.map +1 -1
- package/dist/cjs/util/Observable.js +8 -3
- package/dist/cjs/util/Observable.js.map +1 -1
- package/dist/cjs/util/Set.d.ts +1 -1
- package/dist/cjs/util/Set.d.ts.map +1 -1
- package/dist/cjs/util/Set.js +4 -1
- package/dist/cjs/util/Set.js.map +1 -1
- package/dist/cjs/util/index.d.ts +1 -0
- package/dist/cjs/util/index.d.ts.map +1 -1
- package/dist/cjs/util/index.js +1 -0
- package/dist/cjs/util/index.js.map +1 -1
- package/dist/esm/MatterError.d.ts +17 -0
- package/dist/esm/MatterError.d.ts.map +1 -1
- package/dist/esm/MatterError.js +24 -0
- package/dist/esm/MatterError.js.map +1 -1
- package/dist/esm/util/Abort.d.ts +83 -7
- package/dist/esm/util/Abort.d.ts.map +1 -1
- package/dist/esm/util/Abort.js +139 -25
- package/dist/esm/util/Abort.js.map +2 -2
- package/dist/esm/util/Error.d.ts.map +1 -1
- package/dist/esm/util/Error.js +7 -0
- package/dist/esm/util/Error.js.map +1 -1
- package/dist/esm/util/Function.d.ts +18 -0
- package/dist/esm/util/Function.d.ts.map +1 -0
- package/dist/esm/util/Function.js +18 -0
- package/dist/esm/util/Function.js.map +6 -0
- package/dist/esm/util/Observable.d.ts +16 -4
- package/dist/esm/util/Observable.d.ts.map +1 -1
- package/dist/esm/util/Observable.js +8 -3
- package/dist/esm/util/Observable.js.map +1 -1
- package/dist/esm/util/Set.d.ts +1 -1
- package/dist/esm/util/Set.d.ts.map +1 -1
- package/dist/esm/util/Set.js +4 -1
- package/dist/esm/util/Set.js.map +1 -1
- package/dist/esm/util/index.d.ts +1 -0
- package/dist/esm/util/index.d.ts.map +1 -1
- package/dist/esm/util/index.js +1 -0
- package/dist/esm/util/index.js.map +1 -1
- package/package.json +2 -2
- package/src/MatterError.ts +30 -0
- package/src/util/Abort.ts +235 -34
- package/src/util/Error.ts +9 -0
- package/src/util/Function.ts +23 -0
- package/src/util/Observable.ts +31 -12
- package/src/util/Set.ts +5 -1
- package/src/util/index.ts +1 -0
package/src/util/Abort.ts
CHANGED
|
@@ -4,26 +4,216 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { TimeoutError } from "#MatterError.js";
|
|
7
|
+
import { AbortedError, TimeoutError } from "#MatterError.js";
|
|
8
8
|
import { Duration } from "#time/Duration.js";
|
|
9
9
|
import { Time, Timer } from "#time/Time.js";
|
|
10
|
+
import { asError } from "./Error.js";
|
|
11
|
+
import { Callable } from "./Function.js";
|
|
10
12
|
import { SafePromise } from "./Promises.js";
|
|
11
13
|
|
|
14
|
+
/**
|
|
15
|
+
* Convenience abort implementation.
|
|
16
|
+
*
|
|
17
|
+
* Acts as both an {@link AbortController} and {@link AbortSignal}.
|
|
18
|
+
*
|
|
19
|
+
* May be awaited like a promise, although it returns the {@link reason} rather than throwing.
|
|
20
|
+
*
|
|
21
|
+
* May be invoked as a function to perform abort.
|
|
22
|
+
*
|
|
23
|
+
* Optionally will register for abort with an outer {@link AbortController} and/or add a timeout. You must abort or
|
|
24
|
+
* invoke {@link close} if you use either of these options.
|
|
25
|
+
*/
|
|
26
|
+
export class Abort extends Callable<[reason?: Error]> implements AbortController, AbortSignal, PromiseLike<Error> {
|
|
27
|
+
// The native controller implementation
|
|
28
|
+
#controller: AbortController;
|
|
29
|
+
|
|
30
|
+
// Optional abort chaining
|
|
31
|
+
#dependents?: AbortSignal[];
|
|
32
|
+
#listener?: (reason: any) => void;
|
|
33
|
+
|
|
34
|
+
// Optional PromiseLike behavior
|
|
35
|
+
#aborted?: Promise<Error>;
|
|
36
|
+
#resolve?: (reason: Error) => void;
|
|
37
|
+
|
|
38
|
+
// Optional timeout
|
|
39
|
+
#timeout?: Timer;
|
|
40
|
+
|
|
41
|
+
constructor({ abort, timeout, handler }: Abort.Options = {}) {
|
|
42
|
+
super(() => this.abort());
|
|
43
|
+
|
|
44
|
+
this.#controller = new AbortController();
|
|
45
|
+
|
|
46
|
+
const self = (reason?: any) => {
|
|
47
|
+
this.abort(reason);
|
|
48
|
+
};
|
|
49
|
+
Object.setPrototypeOf(self, Object.getPrototypeOf(this));
|
|
50
|
+
|
|
51
|
+
if (abort && !Array.isArray(abort)) {
|
|
52
|
+
abort = [abort];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (abort?.length) {
|
|
56
|
+
const dependents = abort.map(abort => ("signal" in abort ? abort.signal : abort));
|
|
57
|
+
this.#dependents = dependents;
|
|
58
|
+
|
|
59
|
+
this.#listener = (reason: any) => this.abort(reason);
|
|
60
|
+
for (const dependent of dependents) {
|
|
61
|
+
dependent.addEventListener("abort", this.#listener);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (timeout) {
|
|
66
|
+
this.#timeout = Time.getPeriodicTimer("subtask timeout", timeout, () => {
|
|
67
|
+
if (this.aborted) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
this.abort(new TimeoutError());
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
this.#timeout.start();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (handler) {
|
|
78
|
+
this.addEventListener("abort", () => handler(this.reason));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
abort(reason?: any) {
|
|
83
|
+
this.#controller.abort(reason ?? new AbortedError());
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
get signal() {
|
|
87
|
+
return this.#controller.signal;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Race one or more promises with my abort signal.
|
|
92
|
+
*
|
|
93
|
+
* If aborted returns undefined.
|
|
94
|
+
*/
|
|
95
|
+
async race<T>(...promises: Array<T | PromiseLike<T>>): Promise<Awaited<T> | void> {
|
|
96
|
+
return Abort.race(this, ...promises);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Free resources.
|
|
101
|
+
*
|
|
102
|
+
* You must abort or invoke {@link close} when finished if you construct with {@link Abort.Options#abort} or
|
|
103
|
+
* {@link Abort.Options#timeout}.
|
|
104
|
+
*/
|
|
105
|
+
close() {
|
|
106
|
+
this.#timeout?.stop();
|
|
107
|
+
if (this.#listener && this.#dependents) {
|
|
108
|
+
for (const dependent of this.#dependents) {
|
|
109
|
+
dependent.removeEventListener("abort", this.#listener);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
[Symbol.dispose]() {
|
|
115
|
+
this.close();
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
get aborted() {
|
|
119
|
+
return this.signal.aborted;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
set onabort(onabort: ((this: AbortSignal, ev: Event) => any) | null) {
|
|
123
|
+
this.signal.onabort = onabort;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
get onabort() {
|
|
127
|
+
return this.signal.onabort;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
get reason() {
|
|
131
|
+
return asError(this.signal.reason);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
throwIfAborted() {
|
|
135
|
+
this.signal.throwIfAborted();
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
then<TResult1 = void, TResult2 = never>(
|
|
139
|
+
onfulfilled?: ((value: Error) => TResult1 | PromiseLike<TResult1>) | null,
|
|
140
|
+
onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null,
|
|
141
|
+
): PromiseLike<TResult1 | TResult2> {
|
|
142
|
+
if (!this.#aborted) {
|
|
143
|
+
this.#aborted = new Promise(resolve => (this.#resolve = resolve));
|
|
144
|
+
this.addEventListener("abort", () => this.#resolve!(asError(this.reason)));
|
|
145
|
+
}
|
|
146
|
+
return this.#aborted.then(onfulfilled, onrejected);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
addEventListener<K extends keyof AbortSignalEventMap>(
|
|
150
|
+
type: K,
|
|
151
|
+
listener: (this: AbortSignal, ev: AbortSignalEventMap[K]) => any,
|
|
152
|
+
options?: boolean | AddEventListenerOptions,
|
|
153
|
+
): void;
|
|
154
|
+
addEventListener(
|
|
155
|
+
type: string,
|
|
156
|
+
listener: EventListenerOrEventListenerObject,
|
|
157
|
+
options?: boolean | AddEventListenerOptions,
|
|
158
|
+
): void;
|
|
159
|
+
addEventListener(type: any, listener: any, options?: any) {
|
|
160
|
+
this.signal.addEventListener(type, listener, options);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
removeEventListener<K extends keyof AbortSignalEventMap>(
|
|
164
|
+
type: K,
|
|
165
|
+
listener: (this: AbortSignal, ev: AbortSignalEventMap[K]) => any,
|
|
166
|
+
options?: boolean | EventListenerOptions,
|
|
167
|
+
): void;
|
|
168
|
+
removeEventListener(
|
|
169
|
+
type: string,
|
|
170
|
+
listener: EventListenerOrEventListenerObject,
|
|
171
|
+
options?: boolean | EventListenerOptions,
|
|
172
|
+
): void;
|
|
173
|
+
removeEventListener(type: any, listener: any, options?: any) {
|
|
174
|
+
this.signal.addEventListener(type, listener, options);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
dispatchEvent(event: Event) {
|
|
178
|
+
return this.signal.dispatchEvent(event);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
12
182
|
/**
|
|
13
183
|
* Utilities for implementing abort logic.
|
|
14
184
|
*/
|
|
15
185
|
export namespace Abort {
|
|
16
186
|
/**
|
|
17
|
-
*
|
|
187
|
+
* Optional configuration for {@link Abort}.
|
|
18
188
|
*/
|
|
19
|
-
export
|
|
189
|
+
export interface Options {
|
|
190
|
+
/**
|
|
191
|
+
* One or more parent abort signals.
|
|
192
|
+
*
|
|
193
|
+
* If a parent aborts, this {@link Abort} will abort as well. However the inverse is not true, so this task is
|
|
194
|
+
* independently abortable.
|
|
195
|
+
*
|
|
196
|
+
* This functions similarly to {@link AbortSignal.any} but has additional protection against memory leaks.
|
|
197
|
+
*/
|
|
198
|
+
abort?: Signal | Signal[];
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* An abort timeout.
|
|
202
|
+
*
|
|
203
|
+
* If you specify a timeout, you must either abort or close the {@link Abort}.
|
|
204
|
+
*/
|
|
205
|
+
timeout?: Duration;
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Adds a default abort handler.
|
|
209
|
+
*/
|
|
210
|
+
handler?: (reason?: Error) => void;
|
|
211
|
+
}
|
|
20
212
|
|
|
21
213
|
/**
|
|
22
|
-
* An
|
|
214
|
+
* An entity that may be used to signal abort of an operation.
|
|
23
215
|
*/
|
|
24
|
-
export
|
|
25
|
-
[Symbol.dispose](): void;
|
|
26
|
-
}
|
|
216
|
+
export type Signal = AbortController | AbortSignal;
|
|
27
217
|
|
|
28
218
|
/**
|
|
29
219
|
* Determine whether a {@link Signal} is aborted.
|
|
@@ -72,6 +262,17 @@ export namespace Abort {
|
|
|
72
262
|
return SafePromise.race(promises);
|
|
73
263
|
}
|
|
74
264
|
|
|
265
|
+
/**
|
|
266
|
+
* Perform abortable sleep.
|
|
267
|
+
*/
|
|
268
|
+
export function sleep(description: string, abort: Signal | undefined, duration: Duration) {
|
|
269
|
+
let timer!: Timer;
|
|
270
|
+
const rested = new Promise<void>(resolve => {
|
|
271
|
+
timer = Time.getTimer(description, duration, resolve);
|
|
272
|
+
});
|
|
273
|
+
return race(abort, rested).finally(timer.stop.bind(timer));
|
|
274
|
+
}
|
|
275
|
+
|
|
75
276
|
/**
|
|
76
277
|
* Create independently abortable subtask with a new {@link AbortController} that is aborted if another controller
|
|
77
278
|
* aborts.
|
|
@@ -80,39 +281,39 @@ export namespace Abort {
|
|
|
80
281
|
*
|
|
81
282
|
* {@link timeout} is a convenience for adding a timeout.
|
|
82
283
|
*/
|
|
83
|
-
export function subtask(signal: Signal | undefined, timeout?: Duration):
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
if (signal && "signal" in signal) {
|
|
87
|
-
signal = signal.signal;
|
|
88
|
-
}
|
|
284
|
+
export function subtask(signal: Signal | undefined, timeout?: Duration): Abort {
|
|
285
|
+
return new Abort({ abort: signal, timeout });
|
|
286
|
+
}
|
|
89
287
|
|
|
90
|
-
|
|
288
|
+
/**
|
|
289
|
+
* Like {@link AbortSignal.any} but does not leak memory so long as the returned {@link Abort} is aborted or closed.
|
|
290
|
+
*/
|
|
291
|
+
export function any(...signals: (Signal | undefined)[]) {
|
|
292
|
+
return new Abort({ abort: [...(signals.filter(signal => signal) as Signal[])] });
|
|
293
|
+
}
|
|
91
294
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
295
|
+
/**
|
|
296
|
+
* Generate a function that will throw if aborted.
|
|
297
|
+
*/
|
|
298
|
+
export function checkerFor(signal?: Signal | { abort?: Signal }) {
|
|
299
|
+
if (!signal) {
|
|
300
|
+
return () => {};
|
|
301
|
+
}
|
|
97
302
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
303
|
+
if ("abort" in signal && typeof signal.abort === "object") {
|
|
304
|
+
signal = signal.abort;
|
|
305
|
+
}
|
|
306
|
+
if (!signal) {
|
|
307
|
+
return () => {};
|
|
101
308
|
}
|
|
102
309
|
|
|
103
|
-
if (signal) {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
timer?.stop();
|
|
109
|
-
};
|
|
110
|
-
} else {
|
|
111
|
-
controller[Symbol.dispose] = () => {
|
|
112
|
-
timer?.stop();
|
|
113
|
-
};
|
|
310
|
+
if ("signal" in signal) {
|
|
311
|
+
signal = signal.signal;
|
|
312
|
+
}
|
|
313
|
+
if (!signal) {
|
|
314
|
+
return () => {};
|
|
114
315
|
}
|
|
115
316
|
|
|
116
|
-
return
|
|
317
|
+
return (signal as AbortSignal).throwIfAborted.bind(signal);
|
|
117
318
|
}
|
|
118
319
|
}
|
package/src/util/Error.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import { AbortedError } from "#MatterError.js";
|
|
7
8
|
import type { Constructable } from "./Construction.js";
|
|
8
9
|
import { ClassExtends } from "./Type.js";
|
|
9
10
|
|
|
@@ -14,6 +15,14 @@ function considerAsError(error: unknown): error is Error {
|
|
|
14
15
|
|
|
15
16
|
export function asError(e: any): Error {
|
|
16
17
|
if (considerAsError(e)) {
|
|
18
|
+
// AbortController defaults to a DOMException which isn't ideal; translate here
|
|
19
|
+
if (e instanceof DOMException && e.name === "AbortError") {
|
|
20
|
+
const aborted = new AbortedError(e.message);
|
|
21
|
+
aborted.stack = e.stack;
|
|
22
|
+
aborted.cause = e.cause;
|
|
23
|
+
return aborted;
|
|
24
|
+
}
|
|
25
|
+
|
|
17
26
|
return e;
|
|
18
27
|
}
|
|
19
28
|
return new Error(e?.toString() ?? "Unknown error");
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2022-2025 Matter.js Authors
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* A base for classes that are also functions.
|
|
9
|
+
*/
|
|
10
|
+
export interface Callable<A extends unknown[], R = void> {
|
|
11
|
+
(...args: A): R;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging
|
|
15
|
+
export class Callable<A extends unknown[], R> {
|
|
16
|
+
/**
|
|
17
|
+
* Create a new invocable
|
|
18
|
+
*/
|
|
19
|
+
constructor(invoke: Callable<A, R>) {
|
|
20
|
+
Object.setPrototypeOf(invoke, new.target.prototype);
|
|
21
|
+
return invoke;
|
|
22
|
+
}
|
|
23
|
+
}
|
package/src/util/Observable.ts
CHANGED
|
@@ -138,7 +138,9 @@ export interface Observable<T extends any[] = any[], R = void> extends AsyncIter
|
|
|
138
138
|
* Also unlike a normal {@link Observable}, an {@link ObservableValue} may be placed into an error state which will
|
|
139
139
|
* result in rejection if awaited.
|
|
140
140
|
*/
|
|
141
|
-
export interface ObservableValue<T extends [any, ...any[]] = [boolean]
|
|
141
|
+
export interface ObservableValue<T extends [any, ...any[]] = [boolean], R extends MaybePromise<void> = void>
|
|
142
|
+
extends Observable<T, R>,
|
|
143
|
+
Promise<T[0]> {
|
|
142
144
|
value: T[0] | undefined;
|
|
143
145
|
error?: Error;
|
|
144
146
|
|
|
@@ -170,6 +172,11 @@ export const observant = Symbol("consider-observed");
|
|
|
170
172
|
*/
|
|
171
173
|
export interface AsyncObservable<T extends any[] = any[], R = void> extends Observable<T, MaybePromise<R>> {}
|
|
172
174
|
|
|
175
|
+
/**
|
|
176
|
+
* An {@link ObservableValue} that explicitly supports asynchronous observers.
|
|
177
|
+
*/
|
|
178
|
+
export interface AsyncObservableValue<T extends [any, ...any[]] = [boolean]> extends ObservableValue<T, MaybePromise> {}
|
|
179
|
+
|
|
173
180
|
function defaultErrorHandler(error: Error) {
|
|
174
181
|
throw error;
|
|
175
182
|
}
|
|
@@ -425,10 +432,6 @@ export class BasicObservable<T extends any[] = any[], R = void> implements Obser
|
|
|
425
432
|
|
|
426
433
|
type Next<T> = undefined | { value: T; promise: Promise<Next<T>> };
|
|
427
434
|
|
|
428
|
-
function constructObservable(handleError?: ObserverErrorHandler) {
|
|
429
|
-
return new BasicObservable(handleError);
|
|
430
|
-
}
|
|
431
|
-
|
|
432
435
|
/**
|
|
433
436
|
* Create an {@link Observable}.
|
|
434
437
|
*/
|
|
@@ -437,8 +440,8 @@ export const Observable = constructObservable as unknown as {
|
|
|
437
440
|
<T extends any[], R = void>(errorHandler?: ObserverErrorHandler): Observable<T, R>;
|
|
438
441
|
};
|
|
439
442
|
|
|
440
|
-
function
|
|
441
|
-
return new BasicObservable(handleError
|
|
443
|
+
function constructObservable(handleError?: ObserverErrorHandler) {
|
|
444
|
+
return new BasicObservable(handleError);
|
|
442
445
|
}
|
|
443
446
|
|
|
444
447
|
/**
|
|
@@ -449,6 +452,10 @@ export const AsyncObservable = constructAsyncObservable as unknown as {
|
|
|
449
452
|
<T extends any[], R = void>(handleError?: ObserverErrorHandler): AsyncObservable<T, R>;
|
|
450
453
|
};
|
|
451
454
|
|
|
455
|
+
function constructAsyncObservable(handleError?: ObserverErrorHandler) {
|
|
456
|
+
return new BasicObservable(handleError, true);
|
|
457
|
+
}
|
|
458
|
+
|
|
452
459
|
function event<E, N extends string>(emitter: E, name: N) {
|
|
453
460
|
const observer = (emitter as any)[name];
|
|
454
461
|
if (typeof !observer?.on !== "function") {
|
|
@@ -471,7 +478,7 @@ export class BasicObservableValue<T extends [any, ...any[]] = [boolean]>
|
|
|
471
478
|
reject?: ((reason: any) => void) | null;
|
|
472
479
|
}[];
|
|
473
480
|
|
|
474
|
-
constructor(value?: T, handleError?: ObserverErrorHandler, asyncConfig?: ObserverPromiseHandler | boolean) {
|
|
481
|
+
constructor(value?: T[0], handleError?: ObserverErrorHandler, asyncConfig?: ObserverPromiseHandler | boolean) {
|
|
475
482
|
super(handleError, asyncConfig);
|
|
476
483
|
this.#value = value;
|
|
477
484
|
this.on(this.#maybeResolve.bind(this) as unknown as Observer<T, void>);
|
|
@@ -558,12 +565,24 @@ export class BasicObservableValue<T extends [any, ...any[]] = [boolean]>
|
|
|
558
565
|
* Create an {@link ObservableValue}.
|
|
559
566
|
*/
|
|
560
567
|
export const ObservableValue = constructObservableValue as unknown as {
|
|
561
|
-
new <T extends [any, ...any[]]>(value?: T, errorHandler?: ObserverErrorHandler): ObservableValue<T>;
|
|
562
|
-
<T extends [any, ...any[]]>(value?: T, errorHandler?: ObserverErrorHandler): ObservableValue<T>;
|
|
568
|
+
new <T extends [any, ...any[]]>(value?: T[0], errorHandler?: ObserverErrorHandler): ObservableValue<T>;
|
|
569
|
+
<T extends [any, ...any[]]>(value?: T[0], errorHandler?: ObserverErrorHandler): ObservableValue<T>;
|
|
570
|
+
};
|
|
571
|
+
|
|
572
|
+
function constructObservableValue(value?: unknown, handleError?: ObserverErrorHandler) {
|
|
573
|
+
return new BasicObservableValue<any>(value, handleError);
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
/**
|
|
577
|
+
* Create an {@link AsyncObservableValue}.
|
|
578
|
+
*/
|
|
579
|
+
export const AsyncObservableValue = constructAsyncObservableValue as unknown as {
|
|
580
|
+
new <T extends [any, ...any[]]>(value?: T[0], errorHandler?: ObserverErrorHandler): AsyncObservableValue<T>;
|
|
581
|
+
<T extends [any, ...any[]]>(value?: T[0], errorHandler?: ObserverErrorHandler): AsyncObservableValue<T>;
|
|
563
582
|
};
|
|
564
583
|
|
|
565
|
-
function
|
|
566
|
-
return new
|
|
584
|
+
function constructAsyncObservableValue(value?: unknown, handleError?: ObserverErrorHandler) {
|
|
585
|
+
return new BasicObservableValue<any>(value, handleError, true);
|
|
567
586
|
}
|
|
568
587
|
|
|
569
588
|
/**
|
package/src/util/Set.ts
CHANGED
|
@@ -138,6 +138,10 @@ export class BasicSet<T, AddT = T> implements ImmutableSet<T>, MutableSet<T, Add
|
|
|
138
138
|
}
|
|
139
139
|
|
|
140
140
|
this.#added?.emit(created);
|
|
141
|
+
|
|
142
|
+
if (this.#empty && this.#empty.value) {
|
|
143
|
+
this.#empty.emit(false);
|
|
144
|
+
}
|
|
141
145
|
}
|
|
142
146
|
|
|
143
147
|
get<F extends keyof T>(field: F, value: T[F]) {
|
|
@@ -242,7 +246,7 @@ export class BasicSet<T, AddT = T> implements ImmutableSet<T>, MutableSet<T, Add
|
|
|
242
246
|
|
|
243
247
|
get empty() {
|
|
244
248
|
if (this.#empty === undefined) {
|
|
245
|
-
this.#empty = ObservableValue();
|
|
249
|
+
this.#empty = ObservableValue(!this.#entries.size);
|
|
246
250
|
}
|
|
247
251
|
return this.#empty;
|
|
248
252
|
}
|
package/src/util/index.ts
CHANGED
|
@@ -20,6 +20,7 @@ export * from "./DeepEqual.js";
|
|
|
20
20
|
export * from "./Entropy.js";
|
|
21
21
|
export * from "./Error.js";
|
|
22
22
|
export * from "./FormattedText.js";
|
|
23
|
+
export * from "./Function.js";
|
|
23
24
|
export * from "./GeneratedClass.js";
|
|
24
25
|
export * from "./Ip.js";
|
|
25
26
|
export * from "./Lifecycle.js";
|