@lucas-bur/effect-memfs
v1.2.1
Published
In-memory file system for Effect v4. Great for mocking, tests, simulating files and keeping files in memory. Duh.
Maintainers
Readme
@lucas-bur/effect-memfs
Platform-agnostic in-memory file system for Effect v4. Everything is kept in RAM – no disk, no native bindings. Works in Node, browsers, edge runtimes, anywhere.
Ideal for testing, mocking, and scenarios where you need a filesystem but don't want to touch the real one. Exposes the standard FileSystem service so your Effect code doesn't know the difference.
Install
npm install @lucas-bur/effect-memfs effectUsage
import { Effect, FileSystem } from "effect"
import * as MemoryFileSystem from "@lucas-bur/effect-memfs"
const program = Effect.gen(function* () {
const fs = yield* FileSystem.FileSystem
yield* fs.writeFileString("hello.txt", "world")
return yield* fs.readFileString("hello.txt")
})
Effect.runPromise(program.pipe(Effect.provide(MemoryFileSystem.layer())))
// => "world"Pre-populate files:
import { Effect, FileSystem } from "effect"
import { layer } from "@lucas-bur/effect-memfs"
const program = Effect.gen(function* () {
const fs = yield* FileSystem.FileSystem
return yield* fs.readFileString("/src/index.ts")
})
Effect.runPromise(
program.pipe(
Effect.provide(
layer({
src: {
"index.ts": "export const x = 1",
utils: { "math.ts": "export const add = (a, b) => a + b" },
},
test: {
"foo.test.ts": "import { x } from '../src'",
},
assets: null, // empty directory
}),
),
),
)Relative paths use / as their working directory by default, so src/index.ts
and /src/index.ts address the same file. Pass a custom cwd to mirror a
specific Node working directory instead; the initial file tree is mounted at
that same location:
const testLayer = layer(
{
src: { "index.ts": "export const x = 1" },
},
{ cwd: process.cwd() },
)Snapshot a real directory tree into a fresh in-memory layer. Files, empty
directories, symlinks, file mode, owner, and access/modification times are
all replicated. The caller provides the FileSystem.FileSystem service used
for the walk, so the source can live on Node, Bun, Deno, or any other
Effect-TS FileSystem backend.
import { NodeFileSystem } from "@effect/platform-node-shared"
import { Effect, FileSystem } from "effect"
import { layerFromPath } from "@lucas-bur/effect-memfs"
const program = Effect.gen(function* () {
const fs = yield* FileSystem.FileSystem
return yield* fs.readFileString("/data/fixtures/test.json")
}).pipe(Effect.provide(layerFromPath("/data/fixtures")), Effect.provide(NodeFileSystem.layer))The source path is mounted at the same location in the in-memory
filesystem by default; pass { mountAt: "/some/other/path" } to remap.
Roadmap
- [ ] 1:1 parity with Node's filesystem —
@lucas-bur/effect-memfsmust be a drop-in replacement forNodeFileSystem: identical behavior, error tags, and edge cases. Enforced bytest/file-system-suite.test.ts, which runs the same suite against both backends. Any divergence is a bug to fix, not a quirk to document. Pinned via theTODO(1:1-parity)marker insrc/index.ts.
License
MIT
