+145
src/lib/wisp-utils.ts
+145
src/lib/wisp-utils.ts
···
80
80
81
81
// Remove any base folder name from the path
82
82
const normalizedPath = file.name.replace(/^[^\/]*\//, '');
83
+
84
+
// Skip files in .git directories
85
+
if (normalizedPath.startsWith('.git/') || normalizedPath === '.git') {
86
+
continue;
87
+
}
88
+
83
89
const parts = normalizedPath.split('/');
84
90
85
91
if (parts.length === 1) {
···
296
302
const subMap = extractBlobMap(entry.node as Directory, fullPath);
297
303
subMap.forEach((value, key) => blobMap.set(key, value));
298
304
}
305
+
// Skip subfs nodes - they don't contain blobs in the main tree
299
306
}
300
307
301
308
return blobMap;
302
309
}
310
+
311
+
/**
312
+
* Extract all subfs URIs from a directory tree with their mount paths
313
+
*/
314
+
export function extractSubfsUris(
315
+
directory: Directory,
316
+
currentPath: string = ''
317
+
): Array<{ uri: string; path: string }> {
318
+
const uris: Array<{ uri: string; path: string }> = [];
319
+
320
+
for (const entry of directory.entries) {
321
+
const fullPath = currentPath ? `${currentPath}/${entry.name}` : entry.name;
322
+
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 });
329
+
}
330
+
} else if (entry.node.type === 'directory') {
331
+
// Recursively search subdirectories
332
+
const subUris = extractSubfsUris(entry.node as Directory, fullPath);
333
+
uris.push(...subUris);
334
+
}
335
+
}
336
+
}
337
+
338
+
return uris;
339
+
}
340
+
341
+
/**
342
+
* Estimate the JSON size of a directory tree
343
+
*/
344
+
export function estimateDirectorySize(directory: Directory): number {
345
+
return JSON.stringify(directory).length;
346
+
}
347
+
348
+
/**
349
+
* Count files in a directory tree
350
+
*/
351
+
export function countFilesInDirectory(directory: Directory): number {
352
+
let count = 0;
353
+
for (const entry of directory.entries) {
354
+
if ('type' in entry.node && entry.node.type === 'file') {
355
+
count++;
356
+
} else if ('type' in entry.node && entry.node.type === 'directory') {
357
+
count += countFilesInDirectory(entry.node as Directory);
358
+
}
359
+
}
360
+
return count;
361
+
}
362
+
363
+
/**
364
+
* Find all directories in a tree with their paths and sizes
365
+
*/
366
+
export function findLargeDirectories(directory: Directory, currentPath: string = ''): Array<{
367
+
path: string;
368
+
directory: Directory;
369
+
size: number;
370
+
fileCount: number;
371
+
}> {
372
+
const result: Array<{ path: string; directory: Directory; size: number; fileCount: number }> = [];
373
+
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);
380
+
381
+
result.push({ path: dirPath, directory: dir, size, fileCount });
382
+
383
+
// Recursively find subdirectories
384
+
const subdirs = findLargeDirectories(dir, dirPath);
385
+
result.push(...subdirs);
386
+
}
387
+
}
388
+
389
+
return result;
390
+
}
391
+
392
+
/**
393
+
* Replace a directory with a subfs node in the tree
394
+
*/
395
+
export function replaceDirectoryWithSubfs(
396
+
directory: Directory,
397
+
targetPath: string,
398
+
subfsUri: string
399
+
): Directory {
400
+
const pathParts = targetPath.split('/');
401
+
const targetName = pathParts[pathParts.length - 1];
402
+
const parentPath = pathParts.slice(0, -1).join('/');
403
+
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') {
408
+
return {
409
+
name: entry.name,
410
+
node: {
411
+
$type: 'place.wisp.fs#subfs' as const,
412
+
type: 'subfs' as const,
413
+
subject: subfsUri
414
+
}
415
+
};
416
+
}
417
+
return entry;
418
+
});
419
+
420
+
return {
421
+
$type: 'place.wisp.fs#directory' as const,
422
+
type: 'directory' as const,
423
+
entries: newEntries
424
+
};
425
+
}
426
+
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('/');
433
+
return {
434
+
name: entry.name,
435
+
node: replaceDirectoryWithSubfs(entry.node as Directory, remainingPath, subfsUri)
436
+
};
437
+
}
438
+
}
439
+
return entry;
440
+
});
441
+
442
+
return {
443
+
$type: 'place.wisp.fs#directory' as const,
444
+
type: 'directory' as const,
445
+
entries: newEntries
446
+
};
447
+
}