import { _Callback , NodePathSegmentFormatter , NodeType } from "./types" ; const getNormalizedType = ( val ) : NodeType => { return Array . isArray ( val ) ? 'array' : typeof val === 'object' ? 'object' : 'value' ; } ; function defaultPathFormatter ( node ) { return node . isArrayMember ? `[${ node . key }]` : `["${ node . key }"]` ; } export class WalkNode { private _children ? : WalkNode [ ] = undefined ; private static _idx : number = 0 ; public readonly id : number ; constructor ( public val , public isRoot = false , public isArrayMember = false , public nodeType = 'value' , public rawType = 'undefined' , public executedCallbacks = [ ] , public key ? , public parent ? ) { this . id = WalkNode . _idx ++ ; } public static fromRoot ( obj ) { return new WalkNode ( obj , true , false , getNormalizedType ( obj ) , typeof obj , [ ] , undefined , undefined ) ; } public static fromObjectKey ( parent , key ) { return new WalkNode ( parent . val [ key ] , false , false , getNormalizedType ( parent . val [ key ] ) , typeof parent . val [ key ] , [ ] , key , parent ) ; } public static fromArrayIndex ( parent , index ) { return new WalkNode ( parent . val [ index ] , false , true , getNormalizedType ( parent . val [ index ] ) , typeof parent . val [ index ] , [ ] , index , parent ) ; } public canBeCompared ( ) { return this . nodeType !== 'value' && this . val !== null && ! Object . is ( NaN , this . val ) ; } public sameAs ( other ) { if ( ! this . canBeCompared ( ) || this . nodeType !== other . nodeType ) return false ; if ( this . val === null || Object . is ( NaN , this . val ) ) return false ; return Object . is ( this . val , other . val ) ; } public getPath ( pathFormat ? ) { if ( this . isRoot ) return "" ; pathFormat = pathFormat || defaultPathFormatter ; return this . parent ! . getPath ( pathFormat ) + pathFormat ( this ) ; } public get children ( ) : WalkNode [ ] { if ( typeof this . _children === 'undefined' ) this . _children = [ ... this . getChildren ( ) ] ; return this . _children ; } public * getChildren ( ) { if ( this . nodeType === 'array' ) { for ( let i = 0 ; i < this . val . length ; i ++ ) yield WalkNode . fromArrayIndex ( this , i ) ; } else if ( this . nodeType === 'object' ) { if ( this . val === null ) return ; for ( let key of Object . keys ( this . val ) ) yield WalkNode . fromObjectKey ( this , key ) ; } } public get siblings ( ) : WalkNode [ ] { return [ ... this . getSiblings ( ) ] ; } public * getSiblings ( ) { if ( ! this . parent ) return ; for ( let child of this . parent . children ) if ( this . key !== child . key ) yield child ; } public get ancestors ( ) : WalkNode [ ] { return [ ... this . getAncestors ( ) ] ; } public * getAncestors ( ) { let next = this . parent ; while ( next ) { yield next ; next = next . parent ; } } public get descendants ( ) : WalkNode [ ] { return [ ... this . getDescendants ( ) ] ; } public * getDescendants ( ) { for ( const child of this . getChildren ( ) ) { yield child ; yield * child . getDescendants ( ) ; } } }