2.8 KiB
memory-fs
Purpose
In-memory implementation of MutableInstallerFs. Used by the testing
harness (runPlugin constructs one if the caller doesn't supply one) and
by anything that needs deterministic, side-effect-free filesystem
behaviour: integration tests, dry-run inspection of large plugins,
fixture seeding for replays. POSIX-style paths only; Windows-style
backslashes are normalised to forward slashes on entry.
Features
- Seedable from a
Record<string, string | Uint8Array>map at construction time — strings are UTF-8 encoded automatically. - Tracks directories as first-class entries, so
listDirreturns deterministic, sorted results without sniffing files for shared prefixes. writeFile/mkdircreate intermediate directories implicitly.deleteFilerefuses to remove a non-empty directory (ENOTEMPTY); empty dirs delete cleanly.snapshot()returns a{ path: Uint8Array }map of every file — handy for end-of-test assertions.- Honours an optional
AbortSignal— every async call short-circuits with anAbortErroronce the signal aborts.
Basic Example
import { MemoryFs } from "@suaveplan/installer";
const fs = new MemoryFs({ seed: { "/README.md": "# hi\n" } });
const bytes = await fs.readFile("/README.md");
console.log(new TextDecoder().decode(bytes));
Advanced Example
import { MemoryFs } from "@suaveplan/installer";
const ac = new AbortController();
const fs = new MemoryFs({ signal: ac.signal });
await fs.mkdir("/.suaveplan/skills");
await fs.writeJson("/.suaveplan/skills/index.json", { skills: [] });
await fs.writeFile(
"/.suaveplan/skills/echo/SKILL.md",
new TextEncoder().encode("# echo\n")
);
const list = await fs.listDir("/.suaveplan/skills");
console.log(list); // ["echo", "index.json"]
ac.abort();
await fs.writeFile("/late.txt", new Uint8Array()); // throws AbortError
API Reference
new MemoryFs(options?: { seed?, signal? })pathOf(...segments): stringexists(path): Promise<boolean>stat(path): Promise<{ size, isFile, isDir }>readFile(path): Promise<Uint8Array>readJson<T>(path): Promise<T>listDir(path): Promise<string[]>writeFile(path, contents, mode?): Promise<void>deleteFile(path): Promise<void>mkdir(path): Promise<void>rename(from, to): Promise<void>writeJson(path, value): Promise<void>snapshot(): Record<string, Uint8Array>
Implementation Notes
Path normalisation collapses repeated slashes, strips trailing slashes
(except at the root), and canonicalises backslashes. Seeding paths whose
parents collide with an already-seeded file throws ENOTDIR — this is
intentional and mirrors POSIX behaviour. The internal entries map is
ordered by insertion; listDir re-sorts on every call so results are
stable regardless of write order.