interface Dep { deps : any [ ] ; add ( watcher ) : void ; } interface Watcher { node : any ; attr : string ; data : any ; key : string ; update ( ) : void ; } import { trigger , track } from '../effect/effect' ; const isObject = ( val ) : val is Record < any , any > => val !== null && typeof val === 'object' ; const rawToReactive = new WeakMap ( ) ; const reactiveToRaw = new WeakMap ( ) ; export const enum OperationTypes { SET = 'set' , ADD = 'add' , DELETE = 'delete' , CLEAR = 'clear' , GET = 'get' , HAS = 'has' , ITERATE = 'iterate' } export const targetMap = new WeakMap ( ) ; export default { createApp ( ) { return { mount ( app , el ) { let data = app . setup ( ) ; const nodes = document . querySelector ( el ) . children ; const $data = data ; _compile ( nodes , $data ) ; } } ; } , reactive } ; const Dep = { deps : [ ] , add ( watcher ) { this . deps . push ( watcher ) ; } } ; function notify ( ) { Dep . deps . forEach ( ( e ) => { e . update ( ) ; } ) ; } function _watcher ( node , attr , data , key ) { return { node , attr , data , key , update ( ) { const mutationKeys = this . key . split ( '.' ) ; if ( mutationKeys . length > 1 ) { let d = null ; mutationKeys . forEach ( key => ( d = this . data [ key ] || ( d && d [ key ] ) ) ) ; this . node [ this . attr ] = d ; return ; } this . node [ this . attr ] = this . data [ this . key ] ; } } ; } function reactive ( data ) { let observed = rawToReactive . get ( data ) ; if ( observed !== void 0 ) { return observed ; } if ( reactiveToRaw . has ( data ) ) { return data ; } const handler = { get : function ( target , key , receiver ) { const res = Reflect . get ( target , key , receiver ) ; if ( isObject ( res ) ) { data [ key ] = data [ key ] = reactive ( res ) ; } track ( target , key ) ; return target [ key ] ; } , set : function ( target , key , value ) { target [ key ] = value ; notify ( ) ; trigger ( target , key ) ; return value ; } } ; observed = new Proxy ( data , handler as any ) ; rawToReactive . set ( data , observed ) ; reactiveToRaw . set ( observed , data ) ; if ( ! targetMap . has ( data ) ) { targetMap . set ( data , new Map ( ) ) ; } return observed ; } function _compile ( nodes , $data ) { [ ... nodes ] . forEach ( ( e , index ) => { const theNode = nodes [ index ] ; if ( theNode . tagName === 'INPUT' && theNode . hasAttribute ( 'c-model' ) ) { const key = theNode . getAttribute ( 'c-model' ) ; Dep . add ( _watcher ( theNode , 'value' , $data , key ) ) ; theNode . addEventListener ( 'input' , ( ) => { const mutationKeys = key . split ( '.' ) ; if ( mutationKeys . length > 1 ) { eval ( `$data.${ key }='${ theNode . value }'` ) ; return ; } $data [ key ] = theNode . value ; } ) ; } if ( theNode . hasAttribute ( 'c-bind' ) ) { const key = theNode . getAttribute ( 'c-bind' ) ; Dep . add ( _watcher ( theNode , 'innerHTML' , $data , key ) ) ; } } ) ; notify ( ) ; }