···
// Remove any base folder name from the path
const normalizedPath = file.name.replace(/^[^\/]*\//, '');
84
+
// Skip files in .git directories
85
+
if (normalizedPath.startsWith('.git/') || normalizedPath === '.git') {
const parts = normalizedPath.split('/');
if (parts.length === 1) {
···
const subMap = extractBlobMap(entry.node as Directory, fullPath);
subMap.forEach((value, key) => blobMap.set(key, value));
305
+
// Skip subfs nodes - they don't contain blobs in the main tree
312
+
* Extract all subfs URIs from a directory tree with their mount paths
314
+
export function extractSubfsUris(
315
+
directory: Directory,
316
+
currentPath: string = ''
317
+
): Array<{ uri: string; path: string }> {
318
+
const uris: Array<{ uri: string; path: string }> = [];
320
+
for (const entry of directory.entries) {
321
+
const fullPath = currentPath ? `${currentPath}/${entry.name}` : entry.name;
323
+
if ('type' in entry.node) {
324
+
if (entry.node.type === 'subfs') {
325
+
// Subfs node with subject URI
326
+
const subfsNode = entry.node as any;
327
+
if (subfsNode.subject) {
328
+
uris.push({ uri: subfsNode.subject, path: fullPath });
330
+
} else if (entry.node.type === 'directory') {
331
+
// Recursively search subdirectories
332
+
const subUris = extractSubfsUris(entry.node as Directory, fullPath);
333
+
uris.push(...subUris);
342
+
* Estimate the JSON size of a directory tree
344
+
export function estimateDirectorySize(directory: Directory): number {
345
+
return JSON.stringify(directory).length;
349
+
* Count files in a directory tree
351
+
export function countFilesInDirectory(directory: Directory): number {
353
+
for (const entry of directory.entries) {
354
+
if ('type' in entry.node && entry.node.type === 'file') {
356
+
} else if ('type' in entry.node && entry.node.type === 'directory') {
357
+
count += countFilesInDirectory(entry.node as Directory);
364
+
* Find all directories in a tree with their paths and sizes
366
+
export function findLargeDirectories(directory: Directory, currentPath: string = ''): Array<{
368
+
directory: Directory;
372
+
const result: Array<{ path: string; directory: Directory; size: number; fileCount: number }> = [];
374
+
for (const entry of directory.entries) {
375
+
if ('type' in entry.node && entry.node.type === 'directory') {
376
+
const dirPath = currentPath ? `${currentPath}/${entry.name}` : entry.name;
377
+
const dir = entry.node as Directory;
378
+
const size = estimateDirectorySize(dir);
379
+
const fileCount = countFilesInDirectory(dir);
381
+
result.push({ path: dirPath, directory: dir, size, fileCount });
383
+
// Recursively find subdirectories
384
+
const subdirs = findLargeDirectories(dir, dirPath);
385
+
result.push(...subdirs);
393
+
* Replace a directory with a subfs node in the tree
395
+
export function replaceDirectoryWithSubfs(
396
+
directory: Directory,
397
+
targetPath: string,
400
+
const pathParts = targetPath.split('/');
401
+
const targetName = pathParts[pathParts.length - 1];
402
+
const parentPath = pathParts.slice(0, -1).join('/');
404
+
// If this is a root-level directory
405
+
if (pathParts.length === 1) {
406
+
const newEntries = directory.entries.map(entry => {
407
+
if (entry.name === targetName && 'type' in entry.node && entry.node.type === 'directory') {
411
+
$type: 'place.wisp.fs#subfs' as const,
412
+
type: 'subfs' as const,
421
+
$type: 'place.wisp.fs#directory' as const,
422
+
type: 'directory' as const,
423
+
entries: newEntries
427
+
// Recursively navigate to parent directory
428
+
const newEntries = directory.entries.map(entry => {
429
+
if ('type' in entry.node && entry.node.type === 'directory') {
430
+
const entryPath = entry.name;
431
+
if (parentPath.startsWith(entryPath) || parentPath === entry.name) {
432
+
const remainingPath = pathParts.slice(1).join('/');
435
+
node: replaceDirectoryWithSubfs(entry.node as Directory, remainingPath, subfsUri)
443
+
$type: 'place.wisp.fs#directory' as const,
444
+
type: 'directory' as const,
445
+
entries: newEntries