import { Change } from './change' ; import { Node } from './node' ; import { Path , deserializePath } from './path' ; import { apply , compare } from '../utils/patch' ; export class MutableTree { public roots : Array < Node > ; diff ( nextTree ) { const changes = < Change [ ] > compare ( this , nextTree ) ; const exclude = /nativeElement$/ ; return changes . filter ( c => exclude . test ( c . path ) === false ) ; } patch ( changes ) { apply ( this , changes ) ; } lookup ( id ) { return this . traverse ( deserializePath ( id ) ) ; } traverse ( path ) { path = path . slice ( 0 ) ; const root = this . roots [ path . shift ( ) ] ; if ( root == null ) { return null ; } if ( path . length === 0 ) { return root ; } let iterator = root ; for ( const index of path ) { if ( iterator == null ) { return null ; } switch ( typeof index ) { case 'number' : if ( iterator . children . length <= index ) { return null ; } iterator = iterator . children [ index ] ; break ; case 'string' : iterator = iterator [ index ] ; break ; } } return iterator ; } recurse ( rootIndex , fn ) { const applyfn = ( node ) => { fn ( node ) ; for ( const child of node . children || [ ] ) { if ( applyfn ( child ) === false ) { return false ; } } } ; return applyfn ( this . roots [ rootIndex ] ) ; } recurseAll ( fn ) { for ( let index = 0 ; index < this . roots . length ; ++ index ) { if ( this . recurse ( index , fn ) === false ) { return false ; } } } filter ( fn ) { const results = new Array < Node > ( ) ; this . recurseAll ( node => { if ( fn ( node ) ) { results . push ( node ) ; } } ) ; return results ; } }