import { isObservableProp , toJS , runInAction } from 'mobx' ; import { testOnly , isTestEnv } from '../__internal' ; export type classType < T = any > = { new ( ... args ) : T ; } ; function recordState ( instances , blackList ? ) { const data = new Map ( ) ; instances . forEach ( ( value , key ) => { const observableData = { } as any ; Object . keys ( value ) . forEach ( ( k ) => { if ( isObservableProp ( value , k ) && blackList ?. indexOf ( k ) === - 1 ) { observableData [ k ] = toJS ( value [ k ] ) ; } } ) ; data . set ( key , observableData ) ; } ) ; return data ; } class DI { constructor ( ) { this . clear = this . clear . bind ( this ) ; this . register = this . register . bind ( this ) ; this . getInstance = this . getInstance . bind ( this ) ; this . goto = this . goto . bind ( this ) ; this . record = this . record . bind ( this ) ; } private _instancesMap = new Map ( ) ; /**
     * offset of _historyObservableData
     * 0 mean last _historyObservableData
     * -1 mean pre
     */ private _currentHistory = 0 ; /**
     * history of record observable data
     */ private _historyObservableData : Map < any , any > [ ] = [ ] ; /**
     * record current _instancesMap
     * return length of records
     */ record ( opts ? ) { this . _historyObservableData = this . _historyObservableData . slice ( 0 , this . _historyObservableData . length + this . _currentHistory ) ; this . _currentHistory = 0 ; this . _historyObservableData . push ( recordState ( this . _instancesMap , opts ?. blackList ) ) ; return { index : this . _currentHistory , length : this . _historyObservableData . length , } ; } /**
     * goto history of _historyObservableData
     * return {
     *   success: boolean // really change the state
     *   index: number // current index of record [-x, 0]
     * }
     */ goto ( fn ) { const index = fn ( this . _currentHistory ) ; const ret = { success : false , index : this . _currentHistory , } ; if ( index > 0 ) { return ret ; } if ( index <= - this . _historyObservableData . length ) { return ret ; } const gotoInstances = this . _historyObservableData . slice ( ) . reverse ( ) [ - index ] ; this . _currentHistory = index ; runInAction ( ( ) => { gotoInstances . forEach ( ( value , uid ) => { const ins = this . _instancesMap . get ( uid ) ; for ( const key in value ) { ins [ key ] = value [ key ] ; } } ) ; } ) ; ret . index = this . _currentHistory ; ret . success = true ; return ret ; } /**
     * test only
     *
     * clear all instances for each test case
     */ @ testOnly clear ( ) { this . _instancesMap . clear ( ) ; } param target param store @ testOnly register < S = any , T = any > ( uid , store ) { this . _instancesMap . set ( uid , store ) ; } param uid param fn getInstance < T > ( uid , fn ) { const self = this ; if ( isTestEnv ( ) ) { const ins = new Proxy ( { } as object & T , { get : function ( obj , prop ) { if ( prop === '$uid' ) { return uid ; } const ins = self . _resolve ( uid , fn ) ; return ins [ prop ] ; } , set : function ( obj , prop , value ) { const ins = self . _resolve ( uid , fn ) ; ins [ prop ] = value ; return true ; } , } ) ; return ins ; } return this . _resolve < T > ( uid , fn ) ; } private _resolve < T > ( uid , fn ) { if ( this . _instancesMap . has ( uid ) ) { return this . _instancesMap . get ( uid ) ; } const instance = fn ( ) ; this . _instancesMap . set ( uid , instance ) ; return instance ; } } const { clear , register , getInstance , goto , record } = new DI ( ) ; export { clear , register , getInstance , goto , record } ;