Monorepo for wisp.place. A static site hosting service built on top of the AT Protocol.
wisp.place
1import type { Directory } from "@wisp/lexicons/types/place/wisp/fs";
2
3/**
4 * Estimate the JSON size of a directory tree
5 */
6export function estimateDirectorySize(directory: Directory): number {
7 return JSON.stringify(directory).length;
8}
9
10/**
11 * Count files in a directory tree
12 */
13export function countFilesInDirectory(directory: Directory): number {
14 let count = 0;
15 for (const entry of directory.entries) {
16 if ('type' in entry.node && entry.node.type === 'file') {
17 count++;
18 } else if ('type' in entry.node && entry.node.type === 'directory') {
19 count += countFilesInDirectory(entry.node as Directory);
20 }
21 }
22 return count;
23}
24
25/**
26 * Find all directories in a tree with their paths and sizes
27 */
28export function findLargeDirectories(directory: Directory, currentPath: string = ''): Array<{
29 path: string;
30 directory: Directory;
31 size: number;
32 fileCount: number;
33}> {
34 const result: Array<{ path: string; directory: Directory; size: number; fileCount: number }> = [];
35
36 for (const entry of directory.entries) {
37 if ('type' in entry.node && entry.node.type === 'directory') {
38 const dirPath = currentPath ? `${currentPath}/${entry.name}` : entry.name;
39 const dir = entry.node as Directory;
40 const size = estimateDirectorySize(dir);
41 const fileCount = countFilesInDirectory(dir);
42
43 result.push({ path: dirPath, directory: dir, size, fileCount });
44
45 // Recursively find subdirectories
46 const subdirs = findLargeDirectories(dir, dirPath);
47 result.push(...subdirs);
48 }
49 }
50
51 return result;
52}
53
54/**
55 * Replace a directory with a subfs node in the tree
56 */
57export function replaceDirectoryWithSubfs(
58 directory: Directory,
59 targetPath: string,
60 subfsUri: string
61): Directory {
62 const pathParts = targetPath.split('/');
63 const targetName = pathParts[pathParts.length - 1];
64 const parentPath = pathParts.slice(0, -1).join('/');
65
66 // If this is a root-level directory
67 if (pathParts.length === 1) {
68 const newEntries = directory.entries.map(entry => {
69 if (entry.name === targetName && 'type' in entry.node && entry.node.type === 'directory') {
70 return {
71 name: entry.name,
72 node: {
73 $type: 'place.wisp.fs#subfs' as const,
74 type: 'subfs' as const,
75 subject: subfsUri,
76 flat: false // Preserve directory structure
77 }
78 };
79 }
80 return entry;
81 });
82
83 return {
84 $type: 'place.wisp.fs#directory' as const,
85 type: 'directory' as const,
86 entries: newEntries
87 };
88 }
89
90 // Recursively navigate to parent directory
91 const newEntries = directory.entries.map(entry => {
92 if ('type' in entry.node && entry.node.type === 'directory') {
93 const entryPath = entry.name;
94 if (parentPath.startsWith(entryPath) || parentPath === entry.name) {
95 const remainingPath = pathParts.slice(1).join('/');
96 return {
97 name: entry.name,
98 node: {
99 ...replaceDirectoryWithSubfs(entry.node as Directory, remainingPath, subfsUri),
100 $type: 'place.wisp.fs#directory' as const
101 }
102 };
103 }
104 }
105 return entry;
106 });
107
108 return {
109 $type: 'place.wisp.fs#directory' as const,
110 type: 'directory' as const,
111 entries: newEntries
112 };
113}