export class TreeNode { name: string; value: T | null; path: string = ''; parent: TreeNode | null = null; private _children: TreeNode[] = []; constructor(name: string, path: string, value: T | null = null, children: TreeNode[] = []) { this.name = name; this.path = path; this.value = value; this.addChild(...children) } addChild(...children: TreeNode[]) { children.forEach(child => child.parent = this) this._children.push(...children) } get children(): TreeNode[] { return this._children } get isRoot(): boolean { return !this.parent; } get isLeaf(): boolean { return this._children.length === 0; } first(fn: (node: TreeNode) => boolean): TreeNode | null { if (fn(this)) { return this; } for (const child of this._children) { const result = child.first(fn); if (result !== null) { return result; } } return null; } forEach(fn: (node: TreeNode) => void) { fn(this) for (const child of this._children) { child.forEach(fn) } } values(): T[] { let result: T[] = []; const collect = (node: TreeNode) => { if (node.value !== null) { result.push(node.value); } for (const child of node.children) { collect(child); } } collect(this) return result; } toJSON(): object { return { name: this.name, path: this.path, value: this.value, isLeaf: this.isLeaf, children: this._children }; } static fromJSON(data: TreeNode): TreeNode { const { name, path, value, children } = data; const node = new TreeNode(name, path, value); if (children && children.length > 0) { const parsedChildren = children.map((childData) => TreeNode.fromJSON(childData)); node.addChild(...parsedChildren); } return node; } } // getPaths(): string[] { // let paths: string[] = []; // const traverse = (node: TreeNode) => { // if (node.isLeaf) { // paths.push(node.path); // } else { // for (let child of node.children) { // traverse(child); // } // } // }; // traverse(this); // return paths; // } // getPartialPaths(keyProperty?: keyof TreeNode): string[] { // let key = String(keyProperty ?? "name"); // let paths: string[] = []; // const traverse = (node: TreeNode, path: string) => { // path += "/" + node[key]; // if (node.isLeaf) { // paths.push(path); // } else { // for (let child of node.children) { // traverse(child, path); // } // } // }; // traverse(this, ''); // return paths; // } // find(path: string): TreeNode | null { // // Start with this node // let stack: TreeNode[] = [this]; // // While there are nodes left to check // while (stack.length > 0) { // let node = stack.pop(); // // If this node's path matches the path, return it // if (node.path === path) { // return node; // } // // Add this node's children to the stack to be checked // stack.push(...node.children); // } // // If no node was found with a matching path, return null // return null; // }