import { RawNode , TreeNode , TreeNodeMap , LevelTreeNodeMap , TreeMate , TreeMateOptions , Key , InputMergedKeys , GetPathOptions , CheckOptions , GetPrevNextOptions , GetNonLeafKeysOptions , GetChildren } from './interface' ; import { getCheckedKeys } from './check' ; import { toArray , isDisabled , isLeaf , isGroup , isNodeInvalid , unwrapCheckedKeys , isShallowLoaded , unwrapIndeterminateKeys , getNonLeafKeys , isIgnored , defaultGetChildren , defaultGetKey } from './utils' ; import { getPath } from './path' ; import { moveMethods , getFirstAvailableNode } from './move' ; import { flatten } from './flatten' ; import { contains } from './contains' ; function createTreeNodes < R , G , I > ( rawNodes , treeNodeMap , levelTreeNodeMap , nodeProto , getChildren , parent = null , level = 0 ) { const treeNodes = [ ] ; rawNodes . forEach ( ( rawNode , index ) => { if ( process . env . NODE_ENV !== 'production' && isNodeInvalid ( rawNode , getChildren ) ) { console . error ( '[treemate]: node' , rawNode , 'is invalid' ) ; } const treeNode = Object . create ( nodeProto ) ; treeNode . rawNode = rawNode ; treeNode . siblings = treeNodes ; treeNode . level = level ; treeNode . index = index ; treeNode . isFirstChild = index === 0 ; treeNode . isLastChild = index + 1 === rawNodes . length ; treeNode . parent = parent ; if ( ! treeNode . ignored ) { const rawChildren = getChildren ( rawNode as R | G ) ; if ( Array . isArray ( rawChildren ) ) { treeNode . children = createTreeNodes < R , G , I > ( rawChildren , treeNodeMap , levelTreeNodeMap , nodeProto , getChildren , treeNode as unknown as TreeNode < R , G > , level + 1 ) ; } } treeNodes . push ( treeNode ) ; treeNodeMap . set ( treeNode . key , treeNode ) ; if ( ! levelTreeNodeMap . has ( level ) ) levelTreeNodeMap . set ( level , [ ] ) ; levelTreeNodeMap . get ( level ) ?. push ( treeNode ) ; } ) ; return treeNodes as any ; } export function createTreeMate < R = RawNode , G = R , I = R > ( rawNodes , options = { } ) { const treeNodeMap = new Map ( ) ; const levelTreeNodeMap = new Map ( ) ; const { getDisabled = isDisabled , getIgnored = isIgnored , getIsGroup = isGroup , getKey = defaultGetKey } = options ; const _getChildren = options . getChildren ?? defaultGetChildren ; const getChildren = options . ignoreEmptyChildren ? ( node ) => { const children = _getChildren ( node ) ; if ( Array . isArray ( children ) ) { if ( ! children . length ) return null ; return children ; } return children ; } : _getChildren ; const nodeProto = Object . assign ( { get key ( ) : Key { return getKey ( ( this as any ) . rawNode ) ; } , get disabled ( ) : boolean { return getDisabled ( ( this as any ) . rawNode ) ; } , get isGroup ( ) : boolean { return getIsGroup ( ( this as any ) . rawNode ) ; } , get isLeaf ( ) : boolean { return isLeaf ( ( this as any ) . rawNode , getChildren ) ; } , get shallowLoaded ( ) : boolean { return isShallowLoaded ( ( this as any ) . rawNode , getChildren ) ; } , get ignored ( ) : boolean { return getIgnored ( ( this as any ) . rawNode ) ; } , contains < R , G , I > ( this , node ) { return contains ( this , node ) ; } } , moveMethods ) ; const treeNodes = createTreeNodes < R , G , I > ( rawNodes , treeNodeMap , levelTreeNodeMap , nodeProto , getChildren ) ; function getNode < T > ( key ) ; function getNode ( key ) { if ( key === null || key === undefined ) return null ; const tmNode = treeNodeMap . get ( key ) ; if ( tmNode && ! tmNode . isGroup && ! tmNode . ignored ) { return tmNode as unknown as TreeNode < R > ; } return null ; } function _getNode < T > ( key ) ; function _getNode ( key ) { if ( key === null || key === undefined ) return null ; const tmNode = treeNodeMap . get ( key ) ; if ( tmNode && ! tmNode . ignored ) { return tmNode as unknown as TreeNode < R , G > ; } return null ; } function getPrev < T > ( key ) ; function getPrev ( key , options ? ) { const node = _getNode ( key ) ; if ( ! node ) return null ; return node . getPrev ( options ) ; } function getNext < T > ( key ) ; function getNext ( key , options ? ) { const node = _getNode ( key ) ; if ( ! node ) return null ; return node . getNext ( options ) ; } function getParent < T > ( key ) ; function getParent ( key ) { const node = _getNode ( key ) ; if ( ! node ) return null ; return node . getParent ( ) ; } function getChild < T > ( key ) ; function getChild ( key ) { const node = _getNode ( key ) ; if ( ! node ) return null ; return node . getChild ( ) ; } const treemate = { treeNodes , treeNodeMap , levelTreeNodeMap , maxLevel : Math . max ( ... levelTreeNodeMap . keys ( ) ) , getChildren , getFlattenedNodes ( expandedKeys ? ) { return flatten ( treeNodes , expandedKeys ) ; } , getNode , getPrev , getNext , getParent , getChild , getFirstAvailableNode ( ) { return getFirstAvailableNode ( treeNodes ) ; } , getPath < T extends boolean > ( key , options = { } ) { return getPath < R , G , I , T > ( key , options , treemate ) ; } , getCheckedKeys ( checkedKeys , options = { } ) { const { cascade = true , leafOnly = false , checkStrategy = 'all' } = options ; return getCheckedKeys ( { checkedKeys : unwrapCheckedKeys ( checkedKeys ) , indeterminateKeys : unwrapIndeterminateKeys ( checkedKeys ) , cascade , leafOnly , checkStrategy } , treemate ) ; } , check ( keysToCheck , checkedKeys , options = { } ) { const { cascade = true , leafOnly = false , checkStrategy = 'all' } = options ; return getCheckedKeys ( { checkedKeys : unwrapCheckedKeys ( checkedKeys ) , indeterminateKeys : unwrapIndeterminateKeys ( checkedKeys ) , keysToCheck : keysToCheck === undefined || keysToCheck === null ? [ ] : toArray ( keysToCheck ) , cascade , leafOnly , checkStrategy } , treemate ) ; } , uncheck ( keysToUncheck , checkedKeys , options = { } ) { const { cascade = true , leafOnly = false , checkStrategy = 'all' } = options ; return getCheckedKeys ( { checkedKeys : unwrapCheckedKeys ( checkedKeys ) , indeterminateKeys : unwrapIndeterminateKeys ( checkedKeys ) , keysToUncheck : keysToUncheck === null || keysToUncheck === undefined ? [ ] : toArray ( keysToUncheck ) , cascade , leafOnly , checkStrategy } , treemate ) ; } , getNonLeafKeys ( options = { } ) { return getNonLeafKeys ( treeNodes , options ) ; } } ; return treemate ; }