UNPKG

@lithiumjs/angular

Version:

Reactive components made easy. Lithium provides utilities that enable seamless reactive state and event interactions for Angular components.

1 lines 151 kB
{"version":3,"file":"lithiumjs-angular.mjs","sources":["../../src/metadata/metadata.ts","../../src/metadata/component-state-metadata.ts","../../src/metadata/common-metadata.ts","../../src/metadata/emitter-metadata.ts","../../src/metadata/event-metadata.ts","../../src/async-state.ts","../../src/autopush.ts","../../src/component.ts","../../src/managed-observable.ts","../../src/lifecycle-event.ts","../../src/event-source.ts","../../src/component-state.ts","../../src/declare-state.ts","../../src/directive-state.ts","../../src/lang-utils.ts","../../src/lifecycle.ts","../../src/observable-util.ts","../../src/state-emitter.ts","../../src/lithiumjs-angular.ts"],"sourcesContent":["export namespace Metadata {\n\n type MetadataKey = string | symbol | number;\n\n const LI_METADATA_ROOT = Symbol('$LI_');\n\n export function requireMetadata<T>(symbol: MetadataKey, target: any, defaultValue?: T): T {\n if (!hasMetadata(symbol, target)) {\n setMetadata(symbol, target, defaultValue);\n }\n\n return getOwnMetadata(symbol, target) || getMetadata(symbol, target);\n }\n\n export function requireOwnMetadata<T>(symbol: MetadataKey, target: any, defaultValue?: T): T {\n if (!hasOwnMetadata(symbol, target)) {\n setMetadata(symbol, target, defaultValue);\n }\n\n return getOwnMetadata(symbol, target);\n }\n\n export function getMetadataMap(target: any): Map<MetadataKey, any> {\n return (getMetadataKeys(target) || [])\n .reduce((map, key) => map.set(key, getMetadata(key, target)), new Map());\n }\n\n export function setMetadata(symbol: MetadataKey, target: any, value: any) {\n Object.defineProperty(rootMetadata(target), symbol, {\n writable: true,\n enumerable: true,\n value\n });\n }\n\n export function hasMetadata(symbol: MetadataKey, target: any): boolean {\n return !!getMetadata(symbol, target); // TODO\n }\n\n export function hasOwnMetadata(symbol: MetadataKey, target: any): boolean {\n return !!getOwnMetadata(symbol, target);\n }\n\n export function getMetadata(symbol: MetadataKey, target: any): any {\n const metadata = getOwnMetadata(symbol, target);\n\n if (!metadata && target.prototype) {\n return getMetadata(symbol, target.prototype);\n }\n \n return metadata;\n }\n\n export function getOwnMetadata(symbol: MetadataKey | number, target: any): any {\n const descriptor = Object.getOwnPropertyDescriptor(rootMetadata(target), symbol);\n return descriptor ? descriptor.value : undefined;\n }\n\n export function getMetadataKeys(target: any): MetadataKey[] {\n return Object.keys(rootMetadata(target));\n }\n\n function ensureRootMetadataExists(target: any) {\n if (!Object.getOwnPropertyDescriptor(target, LI_METADATA_ROOT)) {\n Object.defineProperty(target, LI_METADATA_ROOT, {\n enumerable: false,\n writable: true,\n value: Object.create({})\n })\n }\n }\n\n function rootMetadata(target: any): any {\n ensureRootMetadataExists(target);\n\n return Object.getOwnPropertyDescriptor(target, LI_METADATA_ROOT)!.value;\n }\n}\n\n// Workaround for angular-cli 5.0.0 metadata gen bug\nexport interface Metadata {}","import type { StringKey } from \"../lang-utils\";\nimport { Metadata } from \"./metadata\";\n\nexport type AsyncSourceKey<T, K extends StringKey<T> = StringKey<T>> = `${K}$`;\n\nexport type ValidAsyncSourceKey<T, K extends StringKey<T> = StringKey<T>> = AsyncSourceKey<T, K> & StringKey<T>;\nexport namespace ComponentStateMetadata {\n export interface ManagedProperty<T, K extends StringKey<T> = StringKey<T>> {\n key: K;\n publicKey?: StringKey<T>;\n asyncSource?: ValidAsyncSourceKey<T>;\n }\n\n export type ManagedPropertyList<T> = ManagedProperty<T>[];\n\n export const MANAGED_PROPERTY_LIST_KEY = \"MANAGED_PROPERTY_LIST_KEY\";\n\n const ManagedPropertyListSymbol = Symbol(\"ManagedPropertyList\");\n\n export function GetOwnManagedPropertyList<T>(target: Object): ManagedPropertyList<T> {\n return Metadata.requireOwnMetadata<ManagedPropertyList<T>>(ManagedPropertyListSymbol, target, []);\n }\n\n export function GetInheritedManagedPropertyList<T>(target: Object): ManagedPropertyList<T> {\n const targetMetadata = GetOwnManagedPropertyList<T>(target).slice(0);\n const targetPrototype = Object.getPrototypeOf(target);\n\n if (targetPrototype) {\n targetMetadata.push(...GetInheritedManagedPropertyList(targetPrototype));\n }\n\n return targetMetadata;\n }\n\n export function SetManagedPropertyList<T>(target: Object, list: ManagedPropertyList<T>) {\n Metadata.setMetadata(ManagedPropertyListSymbol, target, list);\n }\n\n export function AddManagedProperty<T>(target: Object, property: ManagedProperty<T>) {\n SetManagedPropertyList<T>(target, GetOwnManagedPropertyList<T>(target).concat([property]));\n }\n}\n\nexport function asyncStateKey<ComponentT, K extends StringKey<ComponentT> = StringKey<ComponentT>>(\n key: K\n): AsyncSourceKey<ComponentT, K> {\n return `${key}$` as any;\n}\n","import { Metadata } from \"./metadata\";\n\nexport namespace CommonMetadata {\n\n export const MANAGED_ONDESTROY_KEY = \"__LI__MANAGED__ONDESTROY__\";\n export const MANAGED_INSTANCE_DESTROYED_KEY = \"__LI__MANAGED__INSTANCE__DESTROYED__\";\n\n export function instanceIsDestroyed(componentInstance: any): boolean {\n return !!Metadata.getOwnMetadata(CommonMetadata.MANAGED_INSTANCE_DESTROYED_KEY, componentInstance);\n }\n}","import { Subject, Observable } from \"rxjs\";\nimport { Metadata } from \"./metadata\";\n\n/** @deprecated */\nexport type EmitterType = string;\n\n/** @deprecated */\nexport namespace EmitterMetadata {\n\n export const BOOTSTRAPPED_KEY = \"$$STATEEMITTER_BOOTSTRAPPED\";\n\n export type ProxyMode = keyof {\n None: any,\n From: any,\n Alias: any,\n Merge: any\n };\n\n export namespace ProxyMode {\n\n export const None: ProxyMode = \"None\";\n export const From: ProxyMode = \"From\";\n export const Alias: ProxyMode = \"Alias\";\n export const Merge: ProxyMode = \"Merge\";\n }\n\n export interface SubjectInfo extends SubjectInfo.CoreDetails {\n propertyKey: string | symbol;\n observable: Subject<any> | Observable<any>;\n }\n\n export namespace SubjectInfo {\n\n export interface CoreDetails {\n initial?: () => any;\n initialValue?: any;\n readOnly?: boolean;\n writeOnly?: boolean;\n proxyMode?: ProxyMode;\n proxyPath?: string;\n proxyMergeUpdates?: boolean;\n unmanaged?: boolean;\n }\n\n export interface WithDynamicAlias extends SubjectInfo {\n observable: Observable<any>;\n }\n\n export interface WithStaticAlias extends SubjectInfo {\n observable: Subject<any>;\n }\n\n export function IsDynamicAlias(subjectInfo: SubjectInfo): subjectInfo is SubjectInfo.WithDynamicAlias {\n return !IsStaticAlias(subjectInfo);\n }\n\n export function IsStaticAlias(subjectInfo: SubjectInfo): subjectInfo is SubjectInfo.WithStaticAlias {\n return (subjectInfo.observable instanceof Subject);\n }\n\n export function IsSelfProxy(subjectInfo: SubjectInfo): boolean {\n return subjectInfo.proxyPath === subjectInfo.propertyKey;\n }\n }\n\n export type MetadataMap = Map<EmitterType, SubjectInfo>;\n\n export const EmitterMapSymbol = Symbol(\"EmitterMapSymbol\");\n\n /** @description Gets the metadata map object for the given target class (or its inheritted classes). */\n export function GetMetadataMap(target: Object): MetadataMap {\n return Metadata.requireMetadata<MetadataMap>(EmitterMapSymbol, target, new Map());\n }\n\n /** @description Gets the metadata map object for the given target class. */\n export function GetOwnMetadataMap(target: Object): MetadataMap {\n return Metadata.requireOwnMetadata<MetadataMap>(EmitterMapSymbol, target, new Map());\n }\n\n export function HasOwnMetadataMap(target: Object): boolean {\n return Metadata.hasOwnMetadata(EmitterMapSymbol, target);\n }\n\n export function SetMetadataMap(target: Object, map: MetadataMap) {\n Metadata.setMetadata(EmitterMapSymbol, target, map);\n }\n\n /** @description Copy all metadata from the source map to the target map.\n * \n * Note: This mutates the target map.\n **/\n export function CopyMetadata(target: MetadataMap, source: MetadataMap, overwrite?: boolean): MetadataMap {\n // Iterate over all source metadata properties...\n source.forEach((subjectInfo, eventType) => {\n // And add them to this class' metadata map if not already defined\n if (overwrite || !target.has(eventType)) {\n target.set(eventType, Object.assign({}, subjectInfo));\n }\n });\n\n return target;\n }\n\n /** @description Merge own and inheritted metadata into a single map.\n * \n * Note: This mutates the object's metadata.\n **/\n export function CopyInherittedMetadata(object: any): MetadataMap {\n if (object) {\n let metadataMap: MetadataMap = GetMetadataMap(object);\n let inherittedMap: MetadataMap = CopyInherittedMetadata(Object.getPrototypeOf(object));\n\n return CopyMetadata(metadataMap, inherittedMap);\n }\n\n return new Map();\n }\n}","import { Subject } from \"rxjs\";\nimport type { ImmutableMap } from \"../lang-utils\";\nimport { Metadata } from \"./metadata\";\n\nexport type EventType = string;\n\nexport namespace EventMetadata {\n\n export const SUBJECT_TABLE_MERGED_KEY = \"$$EVENTSOURCE_SUBJECT_TABLE_MERGED\";\n export const BOOTSTRAPPED_KEY = \"$$EVENTSOURCE_BOOTSTRAPPED\";\n export const LIFECYCLE_REGISTRATION_KEY = \"$$EVENTSOURCE_LIFECYCLE_REGISTRATION\";\n\n export interface ConfigOptions {\n eventType: EventType;\n skipMethodCheck?: boolean;\n unmanaged?: boolean;\n }\n\n export interface SubjectInfo extends ConfigOptions {\n subject: Subject<any>;\n }\n\n export type PropertySubjectMap = Map<string | symbol, SubjectInfo>;\n export type EventSubjectTable = Map<EventType, PropertySubjectMap>;\n export type InstanceBootstrapMap = Map<EventType, boolean>;\n export type LifecycleRegistrationMap = Map<EventType, boolean>;\n export type LifecycleCallbackMap = Map<EventType, Array<(...args: any[]) => void>>;\n\n const EventSubjectTableSymbol = Symbol(\"EventSubjectTableSymbol\");\n const InstanceBootstrapMapSymbol = Symbol(\"InstanceBootstrapMapSymbol\");\n const LifecycleRegistrationMapSymbol = Symbol(\"LifecycleRegistrationMapSymbol\");\n const LifecycleCallbackMapSymbol = Symbol(\"LifecycleCallbackMapSymbol\");\n\n /** @description Gets the metadata map object for the given target class (or its inheritted classes). */\n export function GetEventSubjectTable(target: Object): EventSubjectTable {\n return Metadata.requireMetadata<EventSubjectTable>(EventSubjectTableSymbol, target, new Map());\n }\n\n /** @description Gets the metadata map object for the given target class. */\n export function GetOwnEventSubjectTable(target: Object): EventSubjectTable {\n return Metadata.requireOwnMetadata<EventSubjectTable>(EventSubjectTableSymbol, target, new Map());\n }\n\n export function GetInstanceBootstrapMap(target: Object): InstanceBootstrapMap {\n return Metadata.requireMetadata<InstanceBootstrapMap>(InstanceBootstrapMapSymbol, target, new Map());\n }\n\n export function GetOwnLifecycleRegistrationMap(target: Object): LifecycleRegistrationMap {\n return Metadata.requireOwnMetadata<LifecycleRegistrationMap>(LifecycleRegistrationMapSymbol, target, new Map());\n }\n\n /** @description Gets own and inherited lifecycle registration data merged into a single Map. */\n export function GetLifecycleRegistrationMap(target: Object): ImmutableMap<LifecycleRegistrationMap> {\n const metadata: LifecycleRegistrationMap = new Map();\n const ownMetadata = GetOwnLifecycleRegistrationMap(target);\n\n ownMetadata.forEach((v, k) => metadata.set(k, v));\n\n const targetPrototype = Object.getPrototypeOf(target);\n\n if (targetPrototype) {\n const inherittedMetadata = GetLifecycleRegistrationMap(targetPrototype);\n\n inherittedMetadata.forEach((v, k) => metadata.set(k, v ?? metadata.get(k)));\n }\n\n return metadata;\n }\n\n export function GetOwnLifecycleCallbackMap(target: Object): LifecycleCallbackMap {\n return Metadata.requireOwnMetadata<LifecycleCallbackMap>(LifecycleCallbackMapSymbol, target, new Map());\n }\n\n /** @description Gets own and inherited lifecycle callback data merged into a single Map. */\n export function GetLifecycleCallbackMap(target: Object): ImmutableMap<LifecycleCallbackMap> {\n const metadata: LifecycleCallbackMap = new Map();\n const ownMetadata = GetOwnLifecycleCallbackMap(target);\n\n ownMetadata.forEach((v, k) => {\n if (!metadata.has(k)) {\n metadata.set(k, []);\n }\n\n metadata.get(k)!.push(...v);\n });\n\n const targetPrototype = Object.getPrototypeOf(target);\n\n if (targetPrototype) {\n const inherittedMetadata = GetLifecycleCallbackMap(targetPrototype);\n\n inherittedMetadata.forEach((v, k) => {\n if (!metadata.has(k)) {\n metadata.set(k, []);\n }\n\n metadata.get(k)!.push(...v);\n });\n }\n\n return metadata;\n }\n\n /** \n * @description\n * Gets the property subject map for the given event type from the metadata map for the given target class (or its inheritted classes).\n */\n export function GetPropertySubjectMap(type: EventType, target: Object): PropertySubjectMap {\n let table = GetEventSubjectTable(target);\n let subjectMap = table.get(type);\n\n if (!subjectMap) {\n subjectMap = new Map();\n table.set(type, subjectMap);\n }\n\n return subjectMap;\n }\n\n /** \n * @description\n * Gets the property subject map for the given event type from the metadata map for the given target class.\n */\n export function GetOwnPropertySubjectMap(type: EventType, target: Object): PropertySubjectMap {\n let table = GetOwnEventSubjectTable(target);\n let subjectMap = table.get(type);\n\n if (!subjectMap) {\n subjectMap = new Map();\n table.set(type, subjectMap);\n }\n\n return subjectMap;\n }\n\n export function GetLifecycleCallbackList(target: Object, type: EventType): ReadonlyArray<(...args: any[]) => void> {\n const map = GetLifecycleCallbackMap(target);\n\n return map.get(type) ?? [];\n }\n\n export function HasOwnEventSubjectTable(target: Object): boolean {\n return Metadata.hasOwnMetadata(EventSubjectTableSymbol, target);\n }\n\n export function SetEventSubjectTable(target: Object, map: EventSubjectTable) {\n Metadata.setMetadata(EventSubjectTableSymbol, target, map);\n }\n\n export function AddLifecycleCallback(target: Object, type: EventType, callback: (...args: any[]) => void) {\n const map = GetOwnLifecycleCallbackMap(target);\n\n if (!map.has(type)) {\n map.set(type, []);\n }\n\n const callbacks = map.get(type)!;\n callbacks.push(callback);\n Metadata.setMetadata(LifecycleCallbackMapSymbol, target, map);\n }\n\n export function RemoveLifecycleCallback(target: Object, type: EventType, callback: (...args: any[]) => void) {\n const map = GetOwnLifecycleCallbackMap(target);\n\n if (!map.has(type)) {\n return;\n }\n\n const callbacks = map.get(type)!;\n map.set(type, callbacks.filter(curCallback => curCallback !== callback));\n Metadata.setMetadata(LifecycleCallbackMapSymbol, target, map);\n }\n\n /** \n * @description Copy all metadata from the source map to the target map.\n * \n * Note: This mutates the target map.\n **/\n export function CopySubjectTable(target: EventSubjectTable, source: EventSubjectTable, overwrite?: boolean): EventSubjectTable {\n // Iterate over all source metadata properties...\n source.forEach((propertySubjectMap, eventType) => propertySubjectMap.forEach((value, propertyKey) => {\n let targetPropertySubjectMap: PropertySubjectMap;\n\n // Get the property subject map (or create it if it doesn't exist for this eventType)\n if (target.has(eventType)) {\n targetPropertySubjectMap = target.get(eventType)!;\n }\n else {\n targetPropertySubjectMap = new Map();\n target.set(eventType, targetPropertySubjectMap);\n }\n\n // And add them to this class' metadata map if not already defined\n if (overwrite || !targetPropertySubjectMap.has(propertyKey)) {\n targetPropertySubjectMap.set(propertyKey, Object.assign({}, value));\n }\n }));\n\n return target;\n }\n\n /** \n * @description Merge own and inheritted metadata into a single map.\n * \n * Note: This mutates the object's metadata.\n **/\n export function CopyInherittedSubjectTable(object: any): EventSubjectTable {\n if (object) {\n let subjectTable = GetEventSubjectTable(object);\n let inherittedTable = CopyInherittedSubjectTable(Object.getPrototypeOf(object));\n\n // Merge own and inheritted metadata into a single map (note: this mutates object's metadata)\n return CopySubjectTable(subjectTable, inherittedTable);\n }\n\n return new Map();\n }\n}","import type { Observable } from \"rxjs\";\nimport type { Constructable, StringKey } from \"./lang-utils\";\nimport type { AsyncSourceKey, ValidAsyncSourceKey } from \"./metadata\";\nimport { ComponentStateMetadata, asyncStateKey } from \"./metadata\"\n\ntype ValidateAsyncSource<\n T,\n K extends StringKey<T>,\n Source extends string | undefined = AsyncSourceKey<T, K>\n> = Source extends StringKey<T>\n ? (T[Source] extends Observable<T[K]> ? T[Source] : never)\n : never;\n\n/** @PropertyDecoratorFactory */\nexport function AsyncState<Source extends string | undefined = undefined>(asyncSource?: Source) {\n\n /** @PropertyDecorator */\n return function<ComponentT extends Constructable<any, any>, K extends StringKey<ComponentT>>(\n target: Source extends undefined ? ComponentT : (ValidateAsyncSource<ComponentT, K, Source> extends never ? never : ComponentT),\n key: Source extends undefined ? (ValidateAsyncSource<ComponentT, K> extends never ? never : K) : K\n ) {\n const asyncKey = (asyncSource ?? asyncStateKey<ComponentT, K>(key)) as ValidAsyncSourceKey<ComponentT>;\n\n ComponentStateMetadata.AddManagedProperty<ComponentT>(target.constructor, { key, asyncSource: asyncKey });\n }\n}\n","import { ChangeDetectorRef } from \"@angular/core\";\nimport { Metadata } from \"./metadata\";\n\nexport namespace AutoPush {\n\n const CHANGE_DETECTOR_DATA = Symbol(\"cdRefData\");\n\n type ChangeDetectorLike = Pick<ChangeDetectorRef, \"detectChanges\" | \"markForCheck\">;\n\n interface Metadata {\n changeDetector: ChangeDetectorProxy;\n options: Options;\n }\n\n export interface ChangeDetectorProxy {\n doCheck(): void;\n }\n\n export namespace ChangeDetectorProxy {\n\n export function fromRef(ref: ChangeDetectorLike, options: CdRefOptions): ChangeDetectorProxy {\n return {\n doCheck() {\n if (options.forceDetectChanges) {\n ref.detectChanges();\n } else {\n ref.markForCheck();\n }\n }\n };\n }\n }\n\n export interface Options {}\n\n export interface CdRefOptions extends Options {\n forceDetectChanges?: boolean;\n }\n\n export function changeDetector(component: any): ChangeDetectorProxy | undefined {\n const metadata = changeDetectorMetadata(component);\n return metadata ? metadata.changeDetector : undefined;\n }\n\n export function enable(component: any, changeDetector: ChangeDetectorLike, options?: CdRefOptions): void;\n export function enable(component: any, changeDetector: ChangeDetectorProxy, options?: Options): void;\n\n export function enable(component: any, changeDetector: ChangeDetectorLike | ChangeDetectorProxy, options: Options = {}) {\n Metadata.setMetadata(CHANGE_DETECTOR_DATA, component, {\n options,\n changeDetector: isProxy(changeDetector) ? changeDetector : ChangeDetectorProxy.fromRef(changeDetector, options)\n });\n }\n\n export function notifyChanges(component: any) {\n // Check to see if AutoPush is enabled on this component\n const cdData = changeDetectorMetadata(component);\n\n if (cdData) {\n // Notify change detector that there were changes to a component value\n cdData.changeDetector.doCheck();\n }\n }\n\n export function isChangeDetectorLike(object: any): object is ChangeDetectorLike {\n return object && typeof object.detectChanges === \"function\";\n }\n\n function changeDetectorMetadata(component: any): Metadata {\n return Metadata.getMetadata(CHANGE_DETECTOR_DATA, component);\n }\n\n function isProxy(input: any): input is ChangeDetectorProxy {\n return input && typeof input.doCheck === \"function\";\n }\n}","// Enable dynamic templating for Ivy-compiled components:\n/** @deprecated */\nexport function TemplateDynamic(): new(...args: any[]) => { [K in keyof any]: any[K]; } {\n return class TemplateDynamic{};\n}\n\n/** @deprecated */\nexport abstract class LiComponent extends TemplateDynamic() {}\n","import { Subscription, Observable, Subject, BehaviorSubject, Subscriber, TeardownLogic, EMPTY, ReplaySubject, SchedulerLike } from \"rxjs\";\nimport { CommonMetadata, Metadata } from \"./metadata\";\n\nexport type Constructor<T> = new (...args: any[]) => T;\nexport type GenericConstructor<BaseT> = new<T extends BaseT> (...args: any[]) => T;\nexport type BaseObservable = Observable<unknown>;\n\n// TODO fix generics when TypeScript mixin issue is fixed: https://github.com/Microsoft/TypeScript/issues/24122\nexport function ManagedObservableWrapper/*<T, BaseObservable extends Observable<T>>*/($class: Constructor<BaseObservable>): GenericConstructor<BaseObservable> {\n\n class _Managed extends $class {\n\n protected subscriptions?: Subscription = new Subscription();\n\n constructor(private componentInstance: any, ...args: any[]) {\n super(...args);\n\n // Automatically handle unsubscribing on component's ngOnDestroy event\n this.subscriptions!.add(componentInstance[CommonMetadata.MANAGED_ONDESTROY_KEY].subscribe(() => {\n // Mark the component instance as destroyed\n Metadata.setMetadata(CommonMetadata.MANAGED_INSTANCE_DESTROYED_KEY, this.componentInstance, true);\n\n this.subscriptions?.unsubscribe();\n this.subscriptions = undefined;\n this.componentInstance = undefined;\n\n if (this instanceof Subject) {\n this.complete();\n }\n }));\n }\n\n public subscribe(...args: any[]): Subscription {\n if (this.componentInstance && !CommonMetadata.instanceIsDestroyed(this.componentInstance)) {\n const subscription = super.subscribe(...args);\n\n // Manage new subscription\n this.subscriptions!.add(subscription);\n return subscription;\n } else {\n return EMPTY.subscribe();\n }\n }\n };\n\n return _Managed as GenericConstructor<BaseObservable>;\n}\n\nexport class ManagedObservable<T> extends ManagedObservableWrapper(Observable)<Observable<T>> {\n\n constructor(componentInstance: any, subscribe?: (this: Observable<T>, subscriber: Subscriber<T>) => TeardownLogic) {\n super(componentInstance, subscribe);\n }\n}\n\nexport class ManagedSubject<T> extends ManagedObservableWrapper(Subject)<Subject<T>> {\n\n constructor(componentInstance: any) {\n super(componentInstance);\n }\n}\n\nexport class ManagedBehaviorSubject<T> extends ManagedObservableWrapper(BehaviorSubject)<BehaviorSubject<T>> {\n\n constructor(componentInstance: any, initialValue: T) {\n super(componentInstance, initialValue);\n }\n}\n\nexport class ManagedReplaySubject<T> extends ManagedObservableWrapper(ReplaySubject)<ReplaySubject<T>> {\n\n constructor(componentInstance: any, bufferSize?: number, windowTime?: number, scheduler?: SchedulerLike) {\n super(componentInstance, bufferSize, windowTime, scheduler);\n }\n}\n","export enum AngularLifecycleType {\n OnChanges = \"ngOnChanges\",\n OnInit = \"ngOnInit\",\n OnDestroy = \"ngOnDestroy\",\n DoCheck = \"ngDoCheck\",\n AfterContentInit = \"ngAfterContentInit\",\n AfterContentChecked = \"ngAfterContentChecked\",\n AfterViewInit = \"ngAfterViewInit\",\n AfterViewChecked = \"ngAfterViewChecked\"\n};\n\nexport namespace AngularLifecycleType {\n\n export const values: AngularLifecycleType[] = [\n AngularLifecycleType.OnChanges,\n AngularLifecycleType.OnInit,\n AngularLifecycleType.OnDestroy,\n AngularLifecycleType.DoCheck,\n AngularLifecycleType.AfterContentInit,\n AngularLifecycleType.AfterContentChecked,\n AngularLifecycleType.AfterViewInit,\n AngularLifecycleType.AfterViewChecked\n ];\n}","\nimport { Type } from \"@angular/core\";\nimport { Observable, Subject } from \"rxjs\";\nimport { EventMetadata, EventType, Metadata, CommonMetadata } from \"./metadata\";\nimport { ManagedSubject } from \"./managed-observable\";\nimport { AngularLifecycleType } from \"./lifecycle-event\";\n\nexport function EventSource(): PropertyDecorator;\nexport function EventSource(...methodDecorators: MethodDecorator[]): PropertyDecorator;\nexport function EventSource(options: EventSource.DecoratorOptions, ...methodDecorators: MethodDecorator[]): PropertyDecorator;\n\n/** @PropertyDecoratorFactory */\nexport function EventSource(...args: any[]): PropertyDecorator {\n let paramsArg: EventSource.DecoratorOptions | MethodDecorator | undefined;\n\n if (args.length > 0) {\n paramsArg = args[0];\n }\n\n if (!paramsArg || paramsArg instanceof Function) {\n return EventSource.WithParams(undefined, ...args);\n }\n else {\n return EventSource.WithParams(paramsArg, ...args.slice(1));\n }\n}\n\nexport namespace EventSource {\n\n export type DecoratorOptions = Partial<EventMetadata.ConfigOptions>;\n\n /** @PropertyDecoratorFactory */\n export function WithParams(options?: DecoratorOptions, ...methodDecorators: MethodDecorator[]): PropertyDecorator {\n options ??= {};\n\n /** @PropertyDecorator */\n return function(target: any, propertyKey: string | symbol) {\n if (propertyKey !== CommonMetadata.MANAGED_ONDESTROY_KEY && !options!.unmanaged) {\n // Ensure that we create a ngOnDestroy EventSource on the target for managing subscriptions\n WithParams({ eventType: AngularLifecycleType.OnDestroy })(target, CommonMetadata.MANAGED_ONDESTROY_KEY);\n }\n \n // If an eventType wasn't specified...\n if (!options!.eventType) {\n // Try to deduce the eventType from the propertyKey\n if (typeof propertyKey === \"string\" && propertyKey.endsWith(\"$\")) {\n options!.eventType = propertyKey.substring(0, propertyKey.length - 1);\n }\n else {\n throw new Error(`@EventSource error: eventType could not be deduced from propertyKey \"${propertyKey as any}\" (only keys ending with '$' can be auto-deduced).`);\n }\n }\n\n // Create the event source metadata for the decorated property\n createMetadata(options as EventMetadata.SubjectInfo, target, propertyKey);\n\n // Apply any method decorators to the facade function\n methodDecorators.forEach(methodDecorator => methodDecorator(target, options!.eventType!, Object.getOwnPropertyDescriptor(target, options!.eventType!)!));\n };\n }\n\n function bootstrapInstance(this: any, eventType: EventType, isLifecycleEvent?: boolean) {\n const targetInstance: any = this;\n \n if (!isLifecycleEvent) {\n // Assign the facade function for the given event type to the target instance\n Facade.CreateAndAssign(eventType, targetInstance);\n }\n\n function classSubjectTableMerged(merged?: boolean): boolean | undefined {\n if (merged === undefined) {\n return !!Metadata.getMetadata(EventMetadata.SUBJECT_TABLE_MERGED_KEY, targetInstance);\n } else {\n Metadata.setMetadata(EventMetadata.SUBJECT_TABLE_MERGED_KEY, targetInstance, merged);\n }\n return undefined;\n }\n\n const subjectTable = EventMetadata.GetOwnEventSubjectTable(targetInstance);\n\n if (!classSubjectTableMerged()) {\n // Copy all event metadata from the class constructor to the target instance\n EventMetadata.CopySubjectTable(subjectTable, EventMetadata.CopyInherittedSubjectTable(targetInstance.constructor), true);\n classSubjectTableMerged(true);\n }\n\n const propertySubjectMap = subjectTable.get(eventType);\n\n // Iterate over each of the target properties for each proxied event type used in this class\n propertySubjectMap?.forEach((subjectInfo, propertyKey) => {\n // If the event proxy subject hasn't been created for this property yet...\n if (!subjectInfo.subject) {\n // Create a new Subject\n if (subjectInfo.unmanaged || propertyKey === CommonMetadata.MANAGED_ONDESTROY_KEY) {\n subjectInfo.subject = new Subject<any>();\n } else {\n subjectInfo.subject = new ManagedSubject<any>(targetInstance);\n }\n }\n\n // Set the property key to a function that will invoke the facade method when called\n // (This is needed to allow EventSources to work with Angular event decorators like @HostListener)\n // Compose the function with the observable\n // TODO - Figure out a better way to do this with Ivy\n let propertyValue: Observable<any> & Function = Object.setPrototypeOf(Facade.Create(eventType), subjectInfo.subject);\n\n Object.defineProperty(targetInstance, propertyKey, {\n get: () => propertyValue\n });\n });\n\n EventMetadata.GetInstanceBootstrapMap(targetInstance).set(eventType, true);\n }\n\n namespace Facade {\n\n /** @description\n * Creates an event facade function (the function that is invoked during an event) for the given event type.\n */\n export function Create(eventType: EventType): ((...value: any[]) => void) & { eventType: EventType } {\n return Object.assign(function (this: any, ...values: any[]) {\n // Get the list of subjects to notify for this `eventType`\n const subjectInfoList = Array.from(EventMetadata.GetPropertySubjectMap(eventType, this).values());\n // Use the first value from this event if only a single value was given, otherwise emit all given values as an array to the Subject\n const valueToEmit = (values.length > 1) ? values : (values.length > 0) ? values[0] : undefined;\n\n // Iterate in reverse order for ngOnDestroy eventTypes.\n // This ensures that all user-defined OnDestroy EventSources are fired before final cleanup of subscriptions.\n if (eventType === \"ngOnDestroy\") {\n subjectInfoList.reverse();\n }\n \n // Emit the given event value to each interested subject\n subjectInfoList\n .filter(subjectInfo => !!subjectInfo.subject)\n .forEach(subjectInfo => subjectInfo.subject.next(valueToEmit));\n }, { eventType });\n }\n\n export function CreateAndAssign(eventType: EventType, instance: any): void {\n // Assign the facade function for the given event type to the appropriate target class method\n // This function gets called from the view template and triggers the associated Subject\n Object.defineProperty(instance, eventType, {\n enumerable: true,\n value: Create(eventType)\n });\n }\n }\n\n function createMetadata(options: EventMetadata.SubjectInfo, target: any, propertyKey: string | symbol) {\n const ContainsCustomMethod = ($class = target): boolean => {\n const methodDescriptor = Object.getOwnPropertyDescriptor($class, options.eventType);\n const method = methodDescriptor ? (methodDescriptor.value || methodDescriptor.get) : undefined; \n const isCustomMethod = method && method.eventType !== options.eventType;\n return isCustomMethod || (!method && target.prototype && ContainsCustomMethod(target.prototype));\n };\n\n // Determine if this EventSource is handling an Angular lifecycle event\n const isLifecycleEvent = AngularLifecycleType.values.includes(options.eventType as AngularLifecycleType);\n\n if (!options.skipMethodCheck && ContainsCustomMethod()) {\n // Make sure the target class doesn't have a custom method already defined for this event type\n throw new Error(`@EventSource metadata creation failed. Class already has a custom ${options.eventType} method.`);\n }\n\n // Add ths EventSource definition to the class' metadata\n EventMetadata.GetOwnPropertySubjectMap(options.eventType, target.constructor).set(propertyKey, options);\n\n if (isLifecycleEvent) {\n registerLifecycleEventFacade(target.constructor, options.eventType);\n }\n\n // Initialize the propertyKey on the target to a self-bootstrapper that will initialize an instance's EventSource when called\n Object.defineProperty(target, propertyKey, {\n configurable: true,\n get: function () {\n // Ensure we only bootstrap once for this `eventType` if the intializer is re-invoked (Ivy)\n if (!isBootstrapped.call(this, options.eventType)) {\n // Boostrap the event source for this instance\n bootstrapInstance.bind(this)(options.eventType, isLifecycleEvent);\n }\n \n // Return the Observable for the event\n return this[propertyKey];\n }\n });\n\n // Only initialize a bootstrapper function for the eventType if this isn't a lifecycle event (otherwise Ivy will handle it)\n if (!isLifecycleEvent) {\n // Set the eventType on the target to a self-bootstrapper function that will initialize an instance's EventSource when called\n Object.defineProperty(target, options.eventType, {\n configurable: true,\n writable: true,\n value: Object.assign(function (this: any, ...args: any[]) {\n // Ensure we only bootstrap once for this `eventType` if the intializer is re-invoked (Ivy)\n if (!isBootstrapped.call(this, options.eventType)) {\n // Boostrap the event source for this instance\n bootstrapInstance.bind(this)(options.eventType);\n }\n\n // Invoke the facade function for the event\n return this[options.eventType].call(this, ...args);\n }, { eventType: options.eventType })\n });\n }\n }\n\n function registerLifecycleEventFacade(targetClass: Type<any>, eventType: EventType) {\n const registrationMap = EventMetadata.GetLifecycleRegistrationMap(targetClass);\n \n // Register the facade function for this component lifecycle target if we haven't already\n if (!registrationMap.get(eventType)) {\n const ownRegistrationMap = EventMetadata.GetOwnLifecycleRegistrationMap(targetClass);\n\n registerLifecycleEvent(targetClass, eventType, Facade.Create(eventType));\n ownRegistrationMap.set(eventType, true);\n }\n }\n\n /**\n * @description Registers a lifecycle event handler for use with `registerPreOrderHooks`/`registerPostOrderHooks`\n */\n export function registerLifecycleEvent(targetClass: Type<any>, eventType: EventType, hookFn: (...args: any[]) => void) {\n EventMetadata.AddLifecycleCallback(targetClass, eventType, hookFn);\n\n // Ensure a valid prototype exists for this component\n if (!targetClass.prototype) {\n targetClass.prototype = Object.create({});\n }\n\n // Get the name of the hook for this lifecycle event\n const hookName = eventType as AngularLifecycleType;\n // Store a reference to the original hook function\n const prevLifecycleHook = targetClass.prototype[hookName];\n\n // Replace the default lifecycle hook with a modified one that ensures the given hook fns are invoked\n if (!prevLifecycleHook?.eventType) {\n targetClass.prototype[hookName] = Object.assign(function (this: any, ...args: any[]) {\n // Call the previous hook function on the component instance if there is one\n if (prevLifecycleHook) {\n prevLifecycleHook.call(this, ...args);\n }\n\n // Invoke all of the hook functions associated with this lifeycle event for the current component instance\n const hookFns = EventMetadata.GetLifecycleCallbackList(this.constructor, eventType);\n hookFns.forEach(hookFn => hookFn.call(this, ...args));\n }, { eventType });\n }\n }\n\n export function unregisterLifecycleEvent(targetClass: Type<any>, eventType: EventType, hookFn: (...args: any[]) => void) {\n EventMetadata.RemoveLifecycleCallback(targetClass, eventType, hookFn);\n }\n\n function isBootstrapped(this: any, eventType: EventType): boolean {\n const map = EventMetadata.GetInstanceBootstrapMap(this);\n return map.has(eventType) ? map.get(eventType)! : false;\n }\n}","import type { Constructable, IfEquals, IfReadonly, StringKey } from \"./lang-utils\";\nimport { AsyncSourceKey, EmitterMetadata } from \"./metadata\";\nimport { EventEmitter, FactoryProvider, Injector, resolveForwardRef, Type } from \"@angular/core\";\nimport { combineLatest, forkJoin, from, merge, Observable, of, ReplaySubject, Subject, Subscription, throwError } from \"rxjs\";\nimport { distinctUntilChanged, filter, map, mergeMap, skip, switchMap, takeUntil, tap } from \"rxjs/operators\";\nimport { AutoPush } from \"./autopush\";\nimport { ManagedBehaviorSubject, ManagedObservable } from \"./managed-observable\";\nimport { EventSource } from \"./event-source\";\nimport { AngularLifecycleType } from \"./lifecycle-event\";\nimport { ComponentStateMetadata, CommonMetadata, asyncStateKey } from \"./metadata\";\n\nconst COMPONENT_STATE_IDENTITY = Symbol(\"COMPONENT_STATE_IDENTITY\");\n\nexport type ComponentState<ComponentT> = ComponentState.Of<ComponentT>;\n\ntype ComponentClassProvider<ComponentT> = Type<ComponentT> | Type<unknown>;\n\nexport type ManagedComponent = Constructable<any, any> & { [CommonMetadata.MANAGED_ONDESTROY_KEY]: Observable<void> };\n\nexport class ComponentStateRef<ComponentT> extends Promise<ComponentState<ComponentT>> {\n\n public componentInstance!: ComponentT & ManagedComponent;\n\n /**\n * @description Resolves the `ComponentState` instance for this reference.\n * @returns An `Observable` that emits the `ComponentState` instance for this reference.\n */\n public state(): Observable<ComponentState<ComponentT>> {\n return from(this);\n }\n\n /**\n * @description Returns an `Observable` that represents the current value of the given state property and emits whenever the value of the given state\n * property is changed.\n * @param stateProp - The state property to observe.\n * @returns An `Observable` that emits the value of the given state property and re-emits when the value is changed.\n */\n public get<K extends StringKey<ComponentT>>(\n stateProp: ComponentState.ReadableKey<ComponentT, K>\n ): Observable<ComponentT[K]> {\n const stateKey = ComponentState.stateKey<ComponentT, K>(stateProp);\n const resolvedSource$ = this.resolvedState?.[stateKey];\n\n if (resolvedSource$) {\n return resolvedSource$ as unknown as Observable<ComponentT[K]>;\n } else {\n return this.state().pipe(\n mergeMap((state: ComponentState<ComponentT>) => {\n if (!state[stateKey]) {\n return throwError(\n`[ComponentStateRef] Failed to get state for component property \"${stateProp}\". Ensure that this property is explicitly initialized (or declare it with @DeclareState()).`\n );\n }\n \n return state[stateKey] as unknown as Observable<ComponentT[K]>;\n })\n );\n }\n }\n\n /**\n * @description Returns an array of `Observable`s that represents the current value for each given state property. Each `Observable` emits whenever a\n * value of the corresponding given state property is changed.\n * @param stateProps - The state properties to observe.\n * @returns An array of `Observable`s that represents the current value for each given state property and re-emits when the corresponding value is\n * changed.\n */\n public getAll<\n K extends Array<ComponentState.ReadableKey<ComponentT, StringKey<ComponentT>>>\n >(...stateProps: K): ComponentState.StateSelector<ComponentT, K> {\n return stateProps.map(stateProp => this.get(stateProp)) as ComponentState.StateSelector<ComponentT, K>;\n }\n\n /**\n * @description Returns an `EventEmitter` that emits whenever the value of the given state property is changed.\n * @param stateProp - The state property to observe.\n * @returns An `EventEmitter` instance that emits whenever the value of the given state property is changed.\n */\n public emitter<K extends StringKey<ComponentT>>(\n stateProp: ComponentState.ReadableKey<ComponentT, K>\n ): EventEmitter<ComponentT[K]> {\n const emitter$ = new EventEmitter<ComponentT[K]>();\n\n this.get<K>(stateProp)\n .pipe(skip(1))\n .subscribe({\n next: value => emitter$.emit(value),\n error: err => emitter$.error(err)\n });\n return emitter$;\n }\n\n /**\n * @description Updates the value of the given state property with the given value. Equivalent to assigning to the component state property directly.\n * @param stateProp - The state property to update. This property must not be readonly.\n * @param value - The new value to update to.\n * @returns An `Observable` that emits and completes when the value has been updated.\n */\n public set<K extends StringKey<ComponentT>, V extends ComponentT[K]>(\n stateProp: ComponentState.WritableKey<ComponentT, K>,\n value: V\n ): Observable<void> {\n const stateKey = ComponentState.stateKey<ComponentT, K>(stateProp);\n const result$ = new ReplaySubject<void>(1);\n const resolvedSource$ = this.resolvedState?.[stateKey] as unknown as Subject<V>;\n\n if (resolvedSource$) {\n resolvedSource$.next(value);\n result$.next();\n result$.complete();\n } else {\n this.state().pipe(\n map((state) => {\n const stateSubject$ = state[ComponentState.stateKey<ComponentT, K>(stateProp)] as any as Subject<V>;\n \n if (!stateSubject$) {\n throw new Error(\n`[ComponentStateRef] Failed to set state for component property \"${stateProp}\". Ensure that this property is explicitly initialized (or declare it with @DeclareState()).`\n );\n }\n\n return stateSubject$;\n })\n ).subscribe((stateSubject$) => {\n stateSubject$.next(value);\n result$.next();\n result$.complete();\n }, (e) => {\n result$.error(e);\n result$.complete();\n }, () => result$.complete());\n }\n\n return result$;\n }\n\n /**\n * @description Subscribes the given state property to the given source `Observable`. If `managed` is set to true, the lifetime of the subscription will\n * be managed and cleaned up when the component is destroyed.\n * @param stateProp - The state property to receive source updates. This property must not be readonly.\n * @param source$ - The source `Observable` to subscribe to.\n * @param managed - Whether or not the subscription lifetime should be managed. Defaults to `true`.\n * @returns A `Subscription` representing the subscription to the source.\n */\n public subscribeTo<K extends StringKey<ComponentT>, V extends ComponentT[K]>(\n stateProp: ComponentState.WritableKey<ComponentT, K>,\n source$: Observable<V>,\n managed: boolean = true\n ): Subscription {\n let managedSource$: Observable<V>;\n if (managed) {\n managedSource$ = this.state().pipe(\n mergeMap(() => _createManagedSource<ManagedComponent, V, Observable<V>>(source$, this.componentInstance))\n );\n } else {\n managedSource$ = source$;\n }\n\n return managedSource$.pipe(\n tap(sourceValue => this.set<K, V>(stateProp, sourceValue))\n ).subscribe();\n }\n\n /**\n * @description Synchronizes the values of the given state properties such that any changes from one state property will be propagated to the\n * other state property. The initial value of the first given state property is used.\n * @param statePropA - The first state property to synchronize. This property must not be readonly.\n * @param statePropB - The second state property to synchronize. This property must not be readonly.\n */\n public sync<\n K1 extends StringKey<ComponentT>,\n K2 extends StringKey<ComponentT>,\n V extends IfEquals<ComponentT[K1], ComponentT[K2]> extends true ? ComponentT[K1] & ComponentT[K2] : never\n >(\n statePropA: V extends never ? never : ComponentState.WritableKey<ComponentT, K1>,\n statePropB: V extends never ? never : ComponentState.WritableKey<ComponentT, K2>\n ): void {\n let syncing = false;\n \n merge(this.get(statePropB), this.get(statePropA)).pipe(\n skip(1),\n distinctUntilChanged(),\n filter(() => !syncing),\n tap(() => syncing = true),\n mergeMap((value) => combineLatest([\n this.set<K1, V>(statePropA, value as V),\n this.set<K2, V>(statePropB, value as V)\n ])),\n tap(() => syncing = false)\n ).subscribe();\n }\n\n /**\n * @description Synchronizes the values of the given state property and source `Subject` such that any changes from the state property will be\n * propagated to the source `Subject` and vice versa. The initial value of the source `Subject` is used.\n * @param stateProp - The state property to synchronize. This property must not be readonly.\n * @param source$ - The source `Subject` to synchronize with.\n */\n public syncWith<K extends StringKey<ComponentT>>(\n stateProp: ComponentState.WritableKey<ComponentT, K>,\n source$: Subject<ComponentT[K]>\n ): void;\n\n /**\n * @description Synchronizes the state of `stateProp` and `sourceProp`, a property from another `ComponentStateRef`, such that any changes from \n * `stateProp` will be propagated to `sourceProp` and vice versa. The initial state value of `sourceProp` is used.\n * @param stateProp - The state property to synchronize. This property must not be readonly.\n * @param sourceState - The source `ComponentStateRef` instance