UNPKG

@akala/core

Version:
193 lines 5.7 kB
/** * Checks if an object is a Promise-like instance * @template T - The expected resolved value type * @param {T | PromiseLike<T>} o - The object to check * @returns {boolean} True if the object has a 'then' method, indicating it's Promise-like */ export function isPromiseLike(o) { return o && o['then'] && typeof (o['then']) == 'function'; } export function combineSubscriptions(...subs) { return () => { let unsubscribed = false; for (const sub of subs) { const result = sub && sub(); unsubscribed ||= result; } return unsubscribed = true; }; } export function teardown(subscription, abort) { abort.addEventListener('abort', () => subscription()); } export function combineAsyncSubscriptions(...subs) { return async () => { let unsubscribed = false; for (const sub of subs) { const result = sub && await sub(); unsubscribed ||= result; } return unsubscribed; }; } /** * Manages cleanup of subscriptions and disposable resources */ export class TeardownManager { /** * @param subscriptions - Optional initial array of teardown subscriptions */ constructor(subscriptions) { if (subscriptions) this.subscriptions = subscriptions; } subscriptions = []; /** * Cleans up all registered subscriptions (implements Disposable pattern) */ [Symbol.dispose]() { this.subscriptions.forEach(s => s()); this.subscriptions.length = 0; } /** * Registers a teardown subscription or Disposable * @typeParam T - Subscription function or Disposable object * @param sub - Subscription callback or Disposable object to register * @returns The original subscription for chaining */ teardown(sub) { if (!sub) return sub; if (Symbol.dispose in sub) { this.subscriptions.push(() => { sub[Symbol.dispose](); return true; }); } else this.subscriptions.push(sub); return sub; } } /** * Manages cleanup of subscriptions and disposable resources */ export class AsyncTeardownManager { /** * @param subscriptions - Optional initial array of teardown subscriptions */ constructor(subscriptions) { if (subscriptions) this.subscriptions = subscriptions; } subscriptions = []; /** * Cleans up all registered subscriptions (implements Disposable pattern) */ async [Symbol.asyncDispose]() { await Promise.all(this.subscriptions.map(s => s())); this.subscriptions.length = 0; } /** * Cleans up all registered subscriptions (implements Disposable pattern) */ [Symbol.dispose]() { const subs = this.subscriptions.slice(0); this.subscriptions.length = 0; subs.map(s => s()); } /** * Registers a teardown subscription or Disposable * @typeParam T - Subscription function or Disposable object * @param sub - Subscription callback or Disposable object to register * @returns The original subscription for chaining */ teardown(sub) { if (!sub) return sub; if (isPromiseLike(sub)) return sub.then(s => { this.teardown(s); return s; }); if (Symbol.dispose in sub) this.subscriptions.push(() => { sub[Symbol.dispose](); return Promise.resolve(true); }); else if (Symbol.asyncDispose in sub) this.subscriptions.push(async () => { await sub[Symbol.asyncDispose](); return true; }); else this.subscriptions.push(sub); return sub; } } export class StatefulSubscription { _unsubscribe; _unsubscribed = false; constructor(_unsubscribe) { this._unsubscribe = _unsubscribe; } unsubscribe = () => { if (this._unsubscribed) return false; this._unsubscribe(); return this._unsubscribed = true; }; get unsubscribed() { return this._unsubscribed; } [Symbol.dispose]() { this._unsubscribe(); } } export class StatefulAsyncSubscription { _unsubscribe; _unsubscribed = false; constructor(_unsubscribe) { this._unsubscribe = _unsubscribe; } unsubscribe = async () => { if (this._unsubscribed) return false; await this._unsubscribe(); return this._unsubscribed = true; }; get unsubscribed() { return this._unsubscribed; } async [Symbol.asyncDispose]() { await this._unsubscribe(); } } export class ReplaceableSubscription extends StatefulSubscription { subscription; constructor(subscription) { super(() => { this.subscription?.(); this.subscription = null; }); this.subscription = subscription; } update(subscription, unsubscribePrevious) { if (unsubscribePrevious) this.subscription?.(); this.subscription = subscription; } } export class ReplaceableAsyncSubscription extends StatefulSubscription { subscription; constructor(subscription) { super(() => { this.subscription?.(); this.subscription = null; }); this.subscription = subscription; } update(subscription, unsubscribePrevious) { if (unsubscribePrevious) this.subscription?.(); this.subscription = subscription; } } //# sourceMappingURL=teardown-manager.js.map