export type MailboxFolderInfo = { name: string; flags?: string[]; message_count?: number | null; unseen_count?: number | null; }; export type MailFolderNode = { id: string; label: string; folderName: string | null; flags: string[]; messageCount: number | null; unseenCount: number | null; children: MailFolderNode[]; }; export function buildMailboxFolderTree(folders: MailboxFolderInfo[]): MailFolderNode[] { const roots: MailFolderNode[] = []; const byId = new Map(); function ensureNode(parts: string[], index: number): MailFolderNode | null { if (index < 0 || index >= parts.length) return null; const id = parts.slice(0, index + 1).join("/"); const existing = byId.get(id); if (existing) return existing; const node: MailFolderNode = { id, label: parts[index], folderName: null, flags: [], messageCount: null, unseenCount: null, children: [] }; byId.set(id, node); if (index === 0) { roots.push(node); } else { ensureNode(parts, index - 1)?.children.push(node); } return node; } for (const folder of folders) { const parts = folderParts(folder.name); const node = ensureNode(parts, parts.length - 1); if (node) { node.folderName = folder.name; node.flags = folder.flags ?? []; node.messageCount = typeof folder.message_count === "number" ? folder.message_count : null; node.unseenCount = typeof folder.unseen_count === "number" ? folder.unseen_count : null; } } sortFolderNodes(roots); return roots; } export function folderParts(folderName: string): string[] { const normalized = folderName.trim(); if (!normalized) return []; if (normalized.includes("/")) return normalized.split("/").filter(Boolean); if (/^INBOX[.]/i.test(normalized)) return ["INBOX", ...normalized.slice(6).split(".").filter(Boolean)]; return [normalized]; } export function findFolderNodeId(nodes: MailFolderNode[], folderName: string): string | null { for (const node of nodes) { if (node.folderName === folderName) return node.id; const child = findFolderNodeId(node.children, folderName); if (child) return child; } return null; } export function folderAncestorIds(nodes: MailFolderNode[], folderName: string, parents: string[] = []): string[] { for (const node of nodes) { const path = [...parents, node.id]; if (node.folderName === folderName) return path; const child = folderAncestorIds(node.children, folderName, path); if (child.length > 0) return child; } return []; } function sortFolderNodes(nodes: MailFolderNode[]) { nodes.sort((left, right) => folderSortKey(left.label).localeCompare(folderSortKey(right.label))); nodes.forEach((node) => sortFolderNodes(node.children)); } function folderSortKey(label: string): string { return label.toUpperCase() === "INBOX" ? "0" : `1:${label.toLocaleLowerCase()}`; }