42 lines
1.4 KiB
TypeScript
42 lines
1.4 KiB
TypeScript
/**
|
|
* Typed subtree builder. Given a root `Group` and a flat list of its
|
|
* descendants (in arbitrary order), produces a nested `GroupTreeNode`
|
|
* forest rooted at the supplied group. Replaces the upstream port's
|
|
* `function buildTree(root: any, descendants: any[]): any`.
|
|
*/
|
|
|
|
import type { Group, GroupTreeNode } from "@suaveplan/contacts";
|
|
|
|
/**
|
|
* Build a typed tree rooted at `root` from a flat `descendants` list.
|
|
* Children are derived by `parentId === root.id`; the result is
|
|
* deterministic insofar as the input order is deterministic — the
|
|
* caller is responsible for sorting descendants if a deterministic
|
|
* traversal order is required.
|
|
*/
|
|
export function buildTree(
|
|
root: Group,
|
|
descendants: readonly Group[]
|
|
): GroupTreeNode {
|
|
const childrenByParent = new Map<string, Group[]>();
|
|
for (const d of descendants) {
|
|
const key =
|
|
d.parentId !== null && d.parentId !== undefined ? d.parentId : "";
|
|
const bucket = childrenByParent.get(key);
|
|
if (bucket === undefined) {
|
|
childrenByParent.set(key, [d]);
|
|
} else {
|
|
bucket.push(d);
|
|
}
|
|
}
|
|
return walk(root, childrenByParent);
|
|
}
|
|
|
|
function walk(node: Group, byParent: Map<string, Group[]>): GroupTreeNode {
|
|
const children = byParent.get(node.id) ?? [];
|
|
return {
|
|
group: node,
|
|
children: children.map((child) => walk(child, byParent)),
|
|
};
|
|
}
|