| 1 | import type { FileTreeBatchOperation } from "@pierre/trees"; |
| 2 | |
| 3 | function pathDepth(path: string): number { |
| 4 | return path.split("/").filter(Boolean).length; |
| 5 | } |
| 6 | |
| 7 | export function buildFileTreePathUpdates( |
| 8 | previousPaths: readonly string[], |
| 9 | nextPaths: readonly string[], |
| 10 | ): FileTreeBatchOperation[] { |
| 11 | const previous = new Set(previousPaths); |
| 12 | const next = new Set(nextPaths); |
| 13 | const removedDirectoryRoots: string[] = []; |
| 14 | const updates: FileTreeBatchOperation[] = []; |
| 15 | |
| 16 | const removedPaths = previousPaths |
| 17 | .filter((path) => !next.has(path)) |
| 18 | .toSorted((left, right) => pathDepth(left) - pathDepth(right)); |
| 19 | for (const path of removedPaths) { |
| 20 | if (removedDirectoryRoots.some((directory) => path.startsWith(directory))) continue; |
| 21 | const recursive = path.endsWith("/"); |
| 22 | updates.push({ type: "remove", path, ...(recursive ? { recursive: true } : {}) }); |
| 23 | if (recursive) removedDirectoryRoots.push(path); |
| 24 | } |
| 25 | |
| 26 | const addedPaths = nextPaths |
| 27 | .filter((path) => !previous.has(path)) |
| 28 | .toSorted((left, right) => pathDepth(left) - pathDepth(right)); |
| 29 | for (const path of addedPaths) updates.push({ type: "add", path }); |
| 30 | |
| 31 | return updates; |
| 32 | } |