| 109 | let uniqueId = 0; |
| 110 | |
| 111 | export class CollapsibleTree<T> { |
| 112 | public readonly nodes: TreeNode<T>[]; |
| 113 | public readonly id: CellColumnId; |
| 114 | |
| 115 | private constructor(nodes: TreeNode<T>[], id: CellColumnId) { |
| 116 | this.nodes = nodes; |
| 117 | this.id = id; |
| 118 | } |
| 119 | |
| 120 | static from<T>(ids: T[]): CollapsibleTree<T> { |
| 121 | const id = `tree_${uniqueId++}` as CellColumnId; |
| 122 | return new CollapsibleTree( |
| 123 | ids.map((id) => new TreeNode(id, false, [])), |
| 124 | id, |
| 125 | ); |
| 126 | } |
| 127 | |
| 128 | /** |
| 129 | * Create a new tree from ids, preserving structure from previous tree if possible |
| 130 | */ |
| 131 | static fromWithPreviousShape<T>( |
| 132 | ids: T[], |
| 133 | previousTree?: CollapsibleTree<T>, |
| 134 | ): CollapsibleTree<T> { |
| 135 | if (!previousTree) { |
| 136 | return CollapsibleTree.from(ids); |
| 137 | } |
| 138 | |
| 139 | // Reuse the previous tree's id if possible |
| 140 | const id = previousTree.id; |
| 141 | |
| 142 | // Create new tree with nothing collapsed |
| 143 | let newTree = new CollapsibleTree( |
| 144 | ids.map((id) => new TreeNode(id, false, [])), |
| 145 | id, |
| 146 | ); |
| 147 | |
| 148 | // Collapse nodes that were collapsed in the previous tree |
| 149 | for (const id of ids) { |
| 150 | if (previousTree.isCollapsed(id)) { |
| 151 | const children = previousTree._nodeMap.get(id)?.children ?? []; |
| 152 | // Find the first child that is also in the new tree, going backwards |
| 153 | for (let i = children.length - 1; i >= 0; i--) { |
| 154 | const child = children[i]; |
| 155 | if (newTree._nodeMap.has(child.value)) { |
| 156 | newTree = newTree.collapse(id, child.value); |
| 157 | break; |
| 158 | } |
| 159 | } |
| 160 | } |
| 161 | } |
| 162 | |
| 163 | return newTree; |
| 164 | } |
| 165 | |
| 166 | withNodes(nodes: TreeNode<T>[]): CollapsibleTree<T> { |
| 167 | return new CollapsibleTree(nodes, this.id); |
| 168 | } |
nothing calls this directly
no outgoing calls
no test coverage detected
searching dependent graphs…