/** * Filesystem utilities */ /** * Per-run memo for the two filesystem lookups that validation repeats on values * which are constant for the whole run: `realpath` of roots, and `readdir` of the * directories link targets live in. * * A markdown corpus resolves thousands of links into a few hundred directories, so * the uncached form is an N+1: measured at 9,963 `readdir` calls on a 3,437-document * tree and 7,443 on a 1,132-document monorepo. Concurrent callers share the * in-flight promise rather than each starting their own syscall. * * **Instance-based on purpose — never make this a module-level singleton.** The * cache holds a *snapshot* of directory contents, and a long-lived process (watch * mode, a language server, a daemon) would then answer from a listing taken * arbitrarily long ago. The intended lifetime is one instance per validation run, * constructed as a local and collected with the run. * * @example * ```typescript * const fsCache = new FsLookupCache(); // one per run * for (const link of links) { * await verifyCaseSensitiveFilename(link.target, fsCache); * } * ``` */ export declare class FsLookupCache { #private; /** * Canonical path for `targetPath`, falling back to `safePath.resolve()` when the * path does not exist or cannot be resolved (a non-existent file has no realpath, * and callers comparing paths still need an answer). * * @param targetPath - Path to canonicalize * @returns Canonical path with forward slashes on every platform */ realpath(targetPath: string): Promise; /** * Entry names of `dirPath`, or `null` when it cannot be read (missing directory, * no permission). The unreadable answer is cached too — re-asking is the same * failed syscall. * * @param dirPath - Directory to list * @returns Entry names, or `null` if the directory could not be read */ readdir(dirPath: string): Promise; } /** * Recursively copy a directory * * @param src - Source directory path * @param dest - Destination directory path * * @example * await copyDirectory('/source/dir', '/dest/dir'); */ export declare function copyDirectory(src: string, dest: string): Promise; /** * Verify that a file exists with the exact case-sensitive filename. * * On case-insensitive filesystems (Windows, macOS), a file might be found even if * the case doesn't match. This function checks that the actual filename on disk * matches the requested path exactly (case-sensitive). * * Answering requires listing the target's parent directory. Callers checking many * paths (every link in a corpus) hit the same handful of directories over and over, * so the listing comes from a caller-supplied {@link FsLookupCache}. * * The cache parameter is **required rather than defaulted on purpose**: a default * would let an unmigrated call site silently keep the un-memoized behaviour, which * is a no-op wearing the shape of a fix. `new FsLookupCache()` per call reproduces * the old behaviour exactly, so migrating is mechanical — but it has to be a * decision someone made. * * @param filePath - Absolute path to the file to verify * @param fsCache - Per-run lookup cache (one instance per validation run) * @returns Object with exists flag and actual filename (or null if not found) * * @example * ```typescript * // On case-insensitive filesystem with file "README.md" * const fsCache = new FsLookupCache(); * const result1 = await verifyCaseSensitiveFilename('/project/README.md', fsCache); * // { exists: true, actualName: 'README.md' } * * const result2 = await verifyCaseSensitiveFilename('/project/readme.md', fsCache); * // { exists: false, actualName: 'README.md' } - case mismatch! * ``` */ export declare function verifyCaseSensitiveFilename(filePath: string, fsCache: FsLookupCache): Promise<{ exists: boolean; actualName: string | null; }>; //# sourceMappingURL=fs-utils.d.ts.map