import { Observable, Observer, Subscription, TeardownLogic } from 'rxjs'; import { Action } from './action'; import { Controller } from './controller'; import { createEffect, Effect, EffectHandler, EffectOptions } from './effect'; import { Query } from './query'; import { createStore, Store, StoreOptions } from './store'; import { AnyObject } from './utils'; /** * A controller-like boundary for effects and business logic. * * `Scope` collects all subscriptions which are made by child entities and provides * `destroy()` method to unsubscribe from them. */ export type Scope = Controller<{ /** * Register subscription-like or teardown function to be called with * `destroy()` method. */ add: (teardown: TeardownLogic) => void; /** * Creates a store which will be destroyed with the scope. * * @param initialState Initial state * @param options Parameters for the store */ createStore( initialState: State, options?: StoreOptions, ): Store; /** * Creates a controller which will be destroyed with the scope. */ createController: ( factory: () => Controller, ) => Controller; /** * Creates an effect which will be destroyed with the scope. */ createEffect: ( handler: EffectHandler, options?: EffectOptions, ) => Effect; /** * Creates an effect which handles `source` by `handler`, and it will be * destroyed with the scope. */ handle: ( source: Observable | Action | Query, handler: EffectHandler, options?: EffectOptions, ) => Effect; /** * Subscribes to the `source` observable until the scope will be destroyed. */ subscribe: { (source: Observable): Subscription; (source: Observable, next: (value: T) => void): Subscription; (source: Observable, observer: Partial>): Subscription; }; }>; /** * `ExternalScope` and `Scope` types allow to distinct which third-party code can invoke `destroy()` method. */ export type ExternalScope = Omit; /** * Creates `Scope` instance. */ export function createScope(): Scope { const subscriptions = new Subscription(); function registerTeardown(teardown: TeardownLogic): void { subscriptions.add(teardown); } function destroy(): void { subscriptions.unsubscribe(); } function createController( factory: () => Controller, ) { const controller = factory(); registerTeardown(controller.destroy); return controller; } return { add: registerTeardown, destroy, createController, createStore( initialState: State, options?: StoreOptions, ): Store { return createController(() => createStore(initialState, options)); }, createEffect( handler: EffectHandler, options?: EffectOptions, ) { return createController(() => createEffect(handler, options), ); }, handle( source: Observable | Action | Query, handler: EffectHandler, options?: EffectOptions, ) { const effect = createController(() => createEffect(handler, options), ); effect.handle(source); return effect; }, subscribe( source: Observable, nextOrObserver?: Partial> | ((value: T) => unknown), ): Subscription { const subscription = source.subscribe(nextOrObserver); registerTeardown(subscription); return subscription; }, }; }