import { combine , PureEffect } from '@typed/effects' ; export function createTreeManager < A extends object > ( ) { const parentToChildren = new WeakMap < A , Set < A > > ( ) ; const childToParent = new WeakMap < A , A > ( ) ; function getChildren ( node ) { return parentToChildren . get ( node ) ; } function getParent ( node ) { return childToParent . get ( node ) ; } function removeNodeFromParent ( parent , node ) { const children = parentToChildren . get ( parent ) ; if ( children ) { children . delete ( node ) ; } } function removeFromParent ( node ) { const parent = childToParent . get ( node ) ; if ( parent ) { removeNodeFromParent ( parent , node ) ; } childToParent . delete ( node ) ; } function * setParent ( child , parent ) { removeFromParent ( child ) ; childToParent . set ( child , parent ) ; if ( ! parentToChildren . has ( parent ) ) { parentToChildren . set ( parent , new Set ( ) ) ; } const children = parentToChildren . get ( parent ) ! ; children . add ( child ) ; return ; } function * removeNode ( node ) { removeFromParent ( node ) ; const children = getChildren ( node ) ; if ( children ) { yield * combine ( ... Array . from ( children ) . map ( removeNode ) ) ; } parentToChildren . delete ( node ) ; } function * getAllDescendants ( providers , consumers , node ) { const children = getChildren ( node ) ; if ( ! children ) { return ; } for ( const child of children ) { if ( ! providers . has ( child ) ) { if ( consumers . has ( child ) ) { yield child ; } yield * getAllDescendants ( providers , consumers , child ) ; } } } function * getAllAncestors ( node ) { let parent = childToParent . get ( node ) ; while ( parent ) { yield parent ; parent = childToParent . get ( parent ) ; } } return { setParent , removeNode , getParent , getChildren , getAllDescendants , getAllAncestors , } as const ; } type TreeManager < A extends object > = { readonly setParent : ( child : A , parent : A ) => PureEffect < void > ; readonly removeNode : ( node : A ) => PureEffect < void > ; readonly getParent : ( node : A ) => A | undefined ; readonly getChildren : ( node : A ) => Set < A > | undefined ; readonly getAllDescendants : ( providers : WeakSet < A > , consumers : WeakMap < A , any > , node : A ) => Generator < A , void , any > ; readonly getAllAncestors : ( node : A ) => Generator < A , void , any > ; } ;