1export interface FileTreeExpansionModel {
2 getItem(path: string): unknown;
3}
4
5type DirectoryHandle = {
6 isDirectory(): boolean;
7 isExpanded(): boolean;
8 expand(): void;
9 collapse(): void;
10};
11
12function asDirectoryHandle(item: unknown): DirectoryHandle | null {
13 if (
14 typeof item !== "object" ||
15 item === null ||
16 !("isDirectory" in item) ||
17 typeof item.isDirectory !== "function" ||
18 !item.isDirectory() ||
19 !("isExpanded" in item) ||
20 typeof item.isExpanded !== "function" ||
21 !("expand" in item) ||
22 typeof item.expand !== "function" ||
23 !("collapse" in item) ||
24 typeof item.collapse !== "function"
25 ) {
26 return null;
27 }
28 return item as DirectoryHandle;
29}
30
31export function areAllDirectoriesExpanded(
32 model: FileTreeExpansionModel,
33 directoryPaths: readonly string[],
34): boolean {
35 return (
36 directoryPaths.length > 0 &&
37 directoryPaths.every((path) => {
38 const item = asDirectoryHandle(model.getItem(path));
39 return item !== null && item.isExpanded();
40 })
41 );
42}
43
44export function setAllDirectoriesExpanded(
45 model: FileTreeExpansionModel,
46 directoryPaths: readonly string[],
47 expanded: boolean,
48): void {
49 for (const path of directoryPaths) {
50 const item = asDirectoryHandle(model.getItem(path));
51 if (item === null || item.isExpanded() === expanded) continue;
52 if (expanded) item.expand();
53 else item.collapse();
54 }
55}