Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | 1067x 1067x 1067x 2x 3511x 1x 1x 3510x 3510x 3507x 3506x 3506x 3506x 3510x 3510x 1067x 1064x 1064x 1064x 3501x 3501x 3x 1064x 1064x 1063x | import type { Unsubscribe } from './types';
/** Owns cleanup functions and releases them once in reverse registration order. @internal */
export interface DisposableScope {
/** Adds a cleanup function, or executes it immediately when the scope is already disposed. */
add(dispose: Unsubscribe): Unsubscribe;
/** Removes and executes every owned resource. Repeated calls are no-ops. */
dispose(): void;
/** Reports whether the scope has released its resources. */
readonly disposed: boolean;
}
/** Creates an idempotent cleanup scope for listeners, timers, and observers. @internal */
export function createDisposableScope(): DisposableScope {
const disposers = new Set<Unsubscribe>();
let disposed = false;
return {
get disposed() {
return disposed;
},
add(dispose) {
if (disposed) {
dispose();
return () => undefined;
}
let active = true;
const owned = () => {
if (!active) return;
active = false;
disposers.delete(owned);
dispose();
};
disposers.add(owned);
return owned;
},
dispose() {
if (disposed) return;
disposed = true;
const errors: unknown[] = [];
for (const dispose of [...disposers].reverse()) {
try {
dispose();
} catch (error) {
errors.push(error);
}
}
disposers.clear();
if (errors.length === 1) throw errors[0];
if (errors.length > 1) throw new AggregateError(errors, 'Multiple resource cleanups failed.');
},
};
}
|