All files / src walk.ts

100% Statements 24/24
95.83% Branches 23/24
100% Functions 2/2
100% Lines 24/24

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 521x                                               2768x 2768x 2768x 2768x   2768x 15068x 23580x 23580x 23580x 12300x 12292x 12292x 12300x 12300x 12300x     23566x 23580x 23580x 15068x   2768x 2768x 2768x 2768x  
import { CONTROL_DIR } from './store.js';
import type { VFSAdapter, VFSStat } from './types.js';
 
export interface WalkedFile {
  path: string;
  stat: VFSStat;
}
 
export interface WalkOptions {
  /** Extra paths/prefixes to skip. `.vfs` is always skipped. */
  ignore?: (path: string) => boolean;
  controlDir?: string;
  /**
   * Include directories in the result. v2 records them as entries of their own
   * — an empty folder did not sync in v1, which is a real hole once `vfs.json`
   * claims to be the mirror of the tree.
   */
  directories?: boolean;
}
 
/**
 * Recursive listing under the adapter root, with the control folder excluded —
 * otherwise the engine would try to sync its own metadata.
 */
export async function walk(adapter: VFSAdapter, options: WalkOptions = {}): Promise<WalkedFile[]> {
  const controlDir = options.controlDir ?? CONTROL_DIR;
  const ignore = options.ignore;
  const files: WalkedFile[] = [];
 
  const visit = async (dir: string): Promise<void> => {
    for (const entry of await adapter.list(dir)) {
      if (entry.path === controlDir || entry.path.startsWith(`${controlDir}/`)) continue;
      if (ignore?.(entry.path)) continue;
      if (entry.kind === 'directory') {
        if (options.directories) {
          files.push({ path: entry.path, stat: entry.stat ?? { kind: 'directory', size: 0, mtime: 0 } });
        }
        await visit(entry.path);
        continue;
      }
      // A listing that already carried the stat saves a call per file — on Drive
      // that is a round trip per file, which is most of what walking one costs.
      const stat = entry.stat ?? (await adapter.stat(entry.path));
      if (stat && stat.kind === 'file') files.push({ path: entry.path, stat });
    }
  };
 
  await visit('');
  files.sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0));
  return files;
}