(paths: string[])
| 67 | } |
| 68 | |
| 69 | export function buildFileTree(paths: string[]): FileTreeNode { |
| 70 | const root: FileTreeNode = { |
| 71 | name: "", |
| 72 | path: "", |
| 73 | isDirectory: true, |
| 74 | children: [], |
| 75 | }; |
| 76 | |
| 77 | // Side-table mapping a parent node to its child lookup map. Keeping the |
| 78 | // accelerator out of the FileTreeNode shape itself means consumers never |
| 79 | // see it — no post-build cleanup pass, and the public type stays clean. |
| 80 | const childMap = new Map<FileTreeNode, Map<string, FileTreeNode>>(); |
| 81 | |
| 82 | for (const path of paths) { |
| 83 | const segments = path.split("/").filter(Boolean); |
| 84 | if (segments.length > 0) { |
| 85 | let cursor: FileTreeNode = root; |
| 86 | let prefix = ""; |
| 87 | for (let i = 0; i < segments.length; i += 1) { |
| 88 | const segment = segments[i]; |
| 89 | prefix = prefix ? `${prefix}/${segment}` : segment; |
| 90 | const isLast = i === segments.length - 1; |
| 91 | cursor = getOrCreateChild(cursor, childMap, segment, prefix, isLast); |
| 92 | } |
| 93 | } |
| 94 | } |
| 95 | |
| 96 | sortTreeInPlace(root); |
| 97 | return root; |
| 98 | } |
no test coverage detected