Skip to content

feat(vfs): add @scratchyjs/vfs private in-memory filesystem package#30

Merged
Asjas merged 9 commits intomainfrom
copilot/create-private-vfs-package
Mar 23, 2026
Merged

feat(vfs): add @scratchyjs/vfs private in-memory filesystem package#30
Asjas merged 9 commits intomainfrom
copilot/create-private-vfs-package

Conversation

Copy link
Contributor

Copilot AI commented Mar 23, 2026

Ports the Node.js virtual filesystem API from nodejs/node#61478 as a private, local TypeScript package so tests can use a real in-memory FS instead of vi.mock('node:fs').

Package structure

  • src/errors.ts – POSIX error factory helpers (createENOENT, createEEXIST, createENOTDIR, createEISDIR, createENOTEMPTY)
  • src/stats.tsmakeStats() factory that returns a plain object satisfying fs.Stats (replaces the internal getStatsFromBinding from the upstream PR)
  • src/router.tsisUnderMountPoint / getRelativePath path helpers; uses path.posix.join per reviewer feedback on the upstream PR
  • src/memory-provider.tsMemoryProvider class: full in-memory tree backed by a Map<string, MemoryNode>; supports file/directory CRUD, readdir, stat, lstat, recursive mkdir/rm, rename
  • src/file-system.tsVirtualFileSystem class: wraps a provider and monkey-patches node:fs sync/async/promises surface on mount(), restores originals on unmount(); exposes addFile() / addDirectory() convenience helpers
  • src/index.ts – Public API: create(mountPoint) factory + VirtualFileSystem type export

Usage in tests

import { create } from "@scratchyjs/vfs";

const vfs = create("/tmp/my-test");
vfs.addFile("/tmp/my-test/config.json", '{"key":"value"}');
vfs.addDirectory("/tmp/my-test/logs");

vfs.mount(); // patches node:fs for the duration of the test

const content = fs.readFileSync("/tmp/my-test/config.json", "utf8");
// → '{"key":"value"}'

vfs.unmount(); // restores original node:fs

Calling mount() replaces readFileSync, writeFileSync, existsSync, statSync, mkdirSync, readdirSync, rmSync, unlinkSync, and their fs.promises equivalents. All other paths fall through to the real filesystem unchanged.

Notable deviations from the upstream PR

  • No C++ binding dependency — the Stats object is a plain TypeScript value object
  • path.posix.join used throughout (upstream reviewer requested path.join over manual string concatenation)
  • makeDirHelper factory eliminates the empty stub pattern; each VFS instance gets its own scoped addDirectory
  • process.cwd() / process.chdir() are also virtualised while mounted so relative-path tests stay hermetic

🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. Learn more about Advanced Security.

@github-actions
Copy link
Contributor

github-actions bot commented Mar 23, 2026

Coverage Report

Status Category Percentage Covered / Total
🔵 Lines 80.28%
⬇️ -9.09%
4064 / 5062
🔵 Statements 80.28%
⬇️ -9.09%
4064 / 5062
🔵 Functions 76.14%
⬇️ -22.82%
300 / 394
🔵 Branches 79.66%
⬇️ -6.65%
858 / 1077
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
packages/vfs/src/errors.ts 62.16% 75% 50% 62.16% 1, 35-39, 56-57, 67-71, 74-78, 81-85, 88-92
packages/vfs/src/file-system.ts 52.25% 65.97% 43.61% 52.25% 1, 90-91, 198-199, 202-203, 222-223, 235-236, 259, 267-276, 283-290, 342-343, 351-352, 362-367, 370-375, 378-379, 382-391, 394-395, 398-402, 405-406, 409-413, 416-420, 423-424, 427-428, 431-433, 436-437, 440-441, 444-445, 448-449, 452-454, 457-458, 461-465, 517-566, 576-583, 594-595, 601-605, 685, 697, 709, 716, 720-724, 733, 744, 748-752, 761, 768, 778, 788, 798, 802-809, 812-820, 823-831, 834-840, 846, 850-857, 860-866, 869-876, 879-886, 897, 908, 912-920, 926, 930-934, 943, 954, 958-962, 971, 978, 982-989, 992-999, 1002-1009, 1012-1019, 1022-1030, 1033-1042, 1045-1051, 1054-1058, 1061-1069, 1072-1078, 1081-1088, 1091-1098, 1160-1185, 1188-1195
packages/vfs/src/index.ts 85.71% 100% 50% 85.71% 1
packages/vfs/src/memory-provider.ts 72.83% 62.79% 65.33% 72.83% 1, 95-96, 105-106, 142-143, 145-146, 148-149, 151-152, 154-155, 194-195, 199-200, 217-218, 235-236, 245-246, 252-253, 259-260, 275-276, 308-314, 323-330, 335-340, 349-376, 406-407, 427-428, 435-438, 479-480, 486, 506-551, 583, 591, 598-602, 633, 639, 641, 664-669, 705-706, 744-745, 783-784, 796-799, 806, 812-813, 830-831, 834-839, 842-843, 846-850, 853-854, 857-862, 879-880, 892-893, 896-898, 927-931, 938-939, 961-962
packages/vfs/src/router.ts 68.96% 28.57% 66.66% 68.96% 1, 25-26, 29-30, 50-51, 53-54
packages/vfs/src/stats.ts 90.62% 60% 64.28% 90.62% 1, 110-111, 114-115, 118-119, 122-123
Generated in workflow #246 for commit 61173a9 by the Vitest Coverage Report Action

Copilot AI changed the title [WIP] Add private package for Node.js virtual file system feat(vfs): add @scratchyjs/vfs private in-memory filesystem package Mar 23, 2026
Copilot AI requested a review from Asjas March 23, 2026 00:42
@Asjas Asjas marked this pull request as ready for review March 23, 2026 07:18
Copilot AI review requested due to automatic review settings March 23, 2026 07:18
@github-actions
Copy link
Contributor

github-actions bot commented Mar 23, 2026

📚 Docs preview deployed

https://scratchyjs-docs-pr-30.asjas.workers.dev

Updates automatically on every push to this PR.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new private workspace package, @scratchyjs/vfs, providing an in-memory filesystem plus a node:fs monkey-patching layer so tests can use realistic FS behavior without vi.mock("node:fs").

Changes:

  • Introduces MemoryProvider (in-memory tree), routing helpers, POSIX-style error helpers, and Stats/Dirent-like objects.
  • Implements VirtualFileSystem that mounts/unmounts by patching node:fs sync + promises APIs (and optionally process.cwd/chdir).
  • Adds a comprehensive Vitest suite for provider behavior and node:fs interception.

Reviewed changes

Copilot reviewed 9 out of 10 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
pnpm-lock.yaml Adds the new packages/vfs importer entry.
packages/vfs/package.json Defines new private package metadata, exports, and typecheck script.
packages/vfs/tsconfig.json Adds package TS config extending repo defaults.
packages/vfs/src/errors.ts POSIX-style ErrnoException factories used across provider/VFS.
packages/vfs/src/stats.ts Defines VfsStats plus helpers to create file/dir/symlink stats.
packages/vfs/src/router.ts Mount-point routing helpers (isUnderMountPoint, getRelativePath).
packages/vfs/src/memory-provider.ts Implements the in-memory filesystem operations.
packages/vfs/src/file-system.ts Implements VirtualFileSystem plus node:fs + process.cwd/chdir hooks.
packages/vfs/src/index.ts Exposes public API (create, exports).
packages/vfs/src/index.test.ts Adds unit/integration tests for provider + mount interception.
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

Asjas and others added 6 commits March 23, 2026 09:22
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: A-J Roos <asjasroos@pm.me>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: A-J Roos <asjasroos@pm.me>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: A-J Roos <asjasroos@pm.me>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: A-J Roos <asjasroos@pm.me>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: A-J Roos <asjasroos@pm.me>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: A-J Roos <asjasroos@pm.me>
@Asjas Asjas merged commit 55150be into main Mar 23, 2026
9 of 12 checks passed
@Asjas Asjas deleted the copilot/create-private-vfs-package branch March 23, 2026 07:24
Copilot stopped work on behalf of Asjas due to an error March 23, 2026 07:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants