import { ProxyHandler , Content } from '../types' ; import isObjectFn from './is-object' ; import setDeep from './set-deep' ; import Change , { getChangeValue , isChange } from '../-private/change' ; import normalizeObject from './normalize-object' ; import { objectToArray , arrayToObject } from './array-object' ; import mergeDeep from './merge-deep' ; const objectProxyHandler = { property get ( node , key ) { if ( typeof key === 'symbol' ) { return ; } let childValue = node . safeGet ( node . changes , key ) ; if ( isChange ( childValue ) ) { return getChangeValue ( childValue ) ; } if ( isObjectFn ( childValue ) ) { let childNode = node . children [ key ] ; if ( childNode === undefined && node . content ) { let childContent = node . safeGet ( node . content , key ) ; childNode = node . children [ key ] = new ObjectTreeNode ( childValue , childContent , node . safeGet ) ; } if ( childNode ) { return childNode . proxy ; } } if ( typeof childValue !== 'undefined' ) { return childValue ; } else if ( node . content ) { const nodeContent = node . content ; if ( node . safeGet ( nodeContent , key ) ) { return node . safeGet ( nodeContent , key ) ; } } if ( typeof node [ key ] === 'function' || node . hasOwnProperty ( key ) ) { return node [ key ] ; } } , ownKeys ( node ) { return Reflect . ownKeys ( node . changes ) ; } , getOwnPropertyDescriptor ( node , prop ) { return Reflect . getOwnPropertyDescriptor ( node . changes , prop ) ; } , has ( node , prop ) { return Reflect . has ( node . changes , prop ) ; } , set ( node , key , value ) { if ( key . startsWith ( '_' ) ) { return Reflect . set ( node , key , value ) ; } return Reflect . set ( node . changes , key , new Change ( value ) ) ; } } ; function defaultSafeGet ( obj , key ) { return obj [ key ] ; } class ObjectTreeNode implements ProxyHandler { changes : Record < string , any > ; content : Content ; proxy : any ; children : Record < string , any > ; constructor ( changes = { } , content = { } , public safeGet = defaultSafeGet , public isObject = isObjectFn ) { this . changes = changes ; this . content = content ; this . proxy = new Proxy ( this , objectProxyHandler ) ; this . children = Object . create ( null ) ; } get ( key ) { return this . safeGet ( this . changes , key ) ; } set ( key , value ) { return setDeep ( this . changes , key , value ) ; } unwrap ( ) { let changes = this . changes ; if ( isObjectFn ( changes ) ) { changes = normalizeObject ( changes , this . isObject ) ; const content = this . content ; if ( isObjectFn ( content ) ) { changes = normalizeObject ( changes , this . isObject ) ; return { ... content , ... changes } ; } else if ( Array . isArray ( content ) ) { changes = normalizeObject ( changes , this . isObject ) ; return objectToArray ( mergeDeep ( arrayToObject ( content ) , changes ) ) ; } } return changes ; } } export { ObjectTreeNode } ;