Initial Commit
This commit is contained in:
82
packages/devtools/tooling/installer/src/fs/memory-fs.md
Normal file
82
packages/devtools/tooling/installer/src/fs/memory-fs.md
Normal file
@@ -0,0 +1,82 @@
|
||||
# `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 `listDir` returns
|
||||
deterministic, sorted results without sniffing files for shared
|
||||
prefixes.
|
||||
- `writeFile`/`mkdir` create intermediate directories implicitly.
|
||||
- `deleteFile` refuses 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 an `AbortError` once the signal aborts.
|
||||
|
||||
## Basic Example
|
||||
|
||||
```ts
|
||||
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
|
||||
|
||||
```ts
|
||||
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): string`
|
||||
- `exists(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.
|
||||
Reference in New Issue
Block a user