import isEqual from 'fast-deep-equal' ; import { IRxParams , TRxLangHandler } from '../types' ; import { getPathVal } from '../util' ; import { ELang } from './el' ; import { QueryLang } from './ql' ; /**
 * design a simple reactive class
 * from bigQuery, we can computed QL
 * from computeEL, we can effect our side-effect
 */ export default class Rx { constructor ( params ) { const { dev = false , data = { } , getter = { } , effect = { } } = params ; this . dev = dev ; this . getter = getter ; this . initData ( data ) ; this . effect = this . processEL ( effect ) ; } data = { } ; dev = false ; effect : Array < TRxLangHandler > = [ ] ; getter : { [ key ] : QueryLang ; } = Object . create ( { } ) ; _cacheQL = { } as { [ key ] : Array < any > ; } ; /**
     * compute ql's value and merge to this.data
     */ initData = ( data ) => { const rxData = this . computeQL ( data ) ; this . data = { ... data , rx : { ... rxData } } ; if ( this . dev ) { console . log ( '初始化data:' , this . data ) ; } } ; computeQL = ( data ) => { let rx = { } ; for ( let qlName in this . getter ) { if ( this . getter . hasOwnProperty ( qlName ) ) { const ql = this . getter [ qlName ] ; const value = this . bigQuery ( data , ql ) ; if ( ! isEqual ( value , ( data as any ) . rx [ qlName ] ) ) { rx [ qlName ] = value ; } } } return rx ; } ; processEL = ( effect = { } ) => { const effects = [ ] ; Object . keys ( effect ) . forEach ( key => { effects . push ( this . parseEL ( this . data , effect [ key ] ) ) ; } ) ; return effects ; } ; bigQuery ( data , ql ) { const { id , name , handler , deps } = ql . parse ( ) ; const len = deps . length ; if ( this . dev ) { console . groupCollapsed ( `=================ql#${ name }=====================` ) ; } ! this . _cacheQL [ id ] && ( this . _cacheQL [ id ] = [ ] ) ; let isChanged = false ; deps . forEach ( ( dep , i ) => { let val = null ; if ( dep instanceof QueryLang ) { val = this . bigQuery ( data , dep ) ; } else { val = getPathVal ( data , dep ) ; } if ( ! isEqual ( val , this . _cacheQL [ id ] [ i ] ) ) { isChanged = true ; this . _cacheQL [ id ] [ i ] = val ; } } ) ; if ( isChanged ) { const pathVals = this . _cacheQL [ id ] . slice ( 0 , len ) ; const result = handler ( ... pathVals ) ; this . _cacheQL [ id ] [ len ] = result ; if ( this . dev ) { console . log ( 'update:🔥' , result ) ; console . groupEnd ( ) ; } return result ; } else { const result = this . _cacheQL [ id ] [ len ] ; if ( this . dev ) { console . log ( 'cache:😆' , result ) ; console . groupEnd ( ) ; } return result ; } } parseEL = ( data , el ) => { const cache = [ ] ; const { name , deps , handler } = el . parse ( ) ; for ( let dep of deps ) { cache . push ( dep instanceof QueryLang ? this . bigQuery ( data , dep ) : getPathVal ( data , dep ) ) ; } return ( newData , ctx ) => { if ( this . dev ) { console . groupCollapsed ( `=================el#${ name }=====================` ) ; } let isChanged = false ; deps . forEach ( ( dep , i ) => { let pathVal = dep instanceof QueryLang ? this . bigQuery ( newData , dep ) : getPathVal ( newData , dep ) ; if ( ! isEqual ( pathVal , cache [ i ] ) ) { cache [ i ] = pathVal ; isChanged = true ; } } ) ; if ( isChanged ) { if ( this . dev ) { console . log ( `${ name }#changed:🔥` ) ; console . groupEnd ( ) ; } handler . apply ( ctx , [ ... cache , ctx ] ) ; } else { if ( this . dev ) { console . groupEnd ( ) ; } } } ; } ; }