import { observable , makeObservable } from 'mobx' ; import { uuid } from '@cloudbeaver/core-utils' ; import { DIContainer } from '../DIContainer' ; import type { IServiceInjector } from '../IApp' ; import type { InjectionToken } from '../InjectionToken' ; import type { ITypedConstructor } from '../ITypedConstructor' ; import { ServiceInjectorToken } from './ServiceInjectorToken' ; export class Entity { readonly id : string ; protected container = new DIContainer ( ) ; protected children = new Map < string , Entity > ( ) ; private mixins : Array < InjectionToken < any > > = [ ] ; constructor ( providers = [ ] , id ? ) { makeObservable < Entity , 'children' > ( this , { children : observable . shallow , } ) ; this . id = id || uuid ( ) ; this . addMixin ( Entity , this ) ; this . addMixin ( ServiceInjectorToken , this . getServiceInjector ( ) ) ; this . addProviders ( providers ) ; } addChild ( entity ) { if ( this . children . has ( entity . id ) ) { this . removeChild ( entity . id ) ; } this . children . set ( entity . id , entity ) ; entity . bindWithParent ( this ) ; } removeChild ( id ) { if ( ! this . children . has ( id ) ) { return ; } const entity = this . children . get ( id ) ; if ( entity ) { entity . destroyEntity ( ) ; this . children . delete ( id ) ; } } removeAll ( ) { const ids = [ ] ; for ( const [ key , value ] of this . children ) { ids . push ( key ) ; value . destroyEntity ( ) ; } for ( const id of ids ) { this . children . delete ( id ) ; } } getChild ( id ) { return this . children . get ( id ) ; } /**
     * to use for creation of nested React context
     */ getServiceInjector ( ) { return this . container ; } protected bindWithParent ( entity ) { this . container . bindWithParent ( entity . container ) ; } /**
     * Destroy mixins in the reverse order of addition
     */ destroyEntity ( ) { this . mixins . reverse ( ) . forEach ( token => { const mixin = this . getMixin ( token ) as IDestroyableMixin ; if ( mixin . destruct ) { mixin . destruct ( ) ; } } ) ; } protected addProviders ( providers ) { providers . forEach ( provider => { if ( typeof provider === 'function' ) { this . addMixin ( provider ) ; } else { this . addMixin ( provider . token , provider . value ) ; } } ) ; } protected addMixin ( ctor ) ; protected addMixin < T extends Record < string , any > > ( token , value ) ; protected addMixin < T extends Record < string , any > > ( ctorOrToken , value ? ) { this . mixins . push ( ctorOrToken as InjectionToken < any > ) ; if ( value !== undefined ) { this . container . addServiceByToken ( ctorOrToken , value ) ; return ; } this . container . addServiceByClass ( ctorOrToken as ITypedConstructor < any > ) ; } getMixin < T > ( token ) { return this . container . getServiceByToken < T > ( token ) ; } } export type MixinProvider < T extends Record < string , any > > = ITypedConstructor < T > | { token : InjectionToken < T > ; value : T ; } ; export interface IDestroyableMixin { destruct : ( ) => void ; }