export interface TreeNode { name: string; fullPath: string; type: "file" | "directory"; children?: TreeNode[]; } type BuildNode = { children: { [key: string]: BuildNode }; }; export function buildTree(paths: string[]): TreeNode { // sorry i used claude for this const root: { [key: string]: BuildNode } = {}; for (const path of paths) { const parts = path.split("/"); let current = root; for (let i = 0; i < parts.length; i++) { const part = parts[i]; current[part] ??= { children: {} }; if (i < parts.length - 1) { current = current[part].children; } } } const entries = (obj: BuildNode["children"], path: string) => Object.entries(obj) .map(([k, v]) => convert(path, v, k)) .sort((a, b) => { if (a.type !== b.type) return a.type === "directory" ? -1 : 1; const aDot = a.name.startsWith("."); const bDot = b.name.startsWith("."); if (aDot !== bDot) return aDot ? -1 : 1; return a.name.localeCompare(b.name, undefined, { numeric: true }); }); const convert = (path: string, node: BuildNode, name: string): TreeNode => { const hasChildren = Object.keys(node.children).length > 0; const fullPath = `${path}${name}`; return { name, type: hasChildren ? "directory" : "file", fullPath, children: hasChildren ? entries(node.children, `${fullPath}/`) : undefined, }; }; return { name: "", fullPath: "", type: "directory", children: entries(root, ""), }; }