From 5ff91de0ef195348a806bbf0051acb5a8c921166 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 1 Aug 2025 21:27:12 +0000
Subject: [PATCH 1/2] Initial plan
From 5dce66895e5b33a85acd25fbc3660371f67f58d2 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 1 Aug 2025 21:40:45 +0000
Subject: [PATCH 2/2] docs: implement comprehensive documentation website
Co-authored-by: streamich <9773803+streamich@users.noreply.github.com>
---
README.md | 4 +
docs/browser-usage.md | 425 ++++++++++++++++++++++++++++++++++++++++
docs/getting-started.md | 140 +++++++++++++
docs/index.md | 149 ++++++++++++++
docs/testing-usage.md | 265 +++++++++++++++++++++++++
tsconfig.json | 18 +-
6 files changed, 1000 insertions(+), 1 deletion(-)
create mode 100644 docs/browser-usage.md
create mode 100644 docs/getting-started.md
create mode 100644 docs/index.md
create mode 100644 docs/testing-usage.md
diff --git a/README.md b/README.md
index d245c5f53..30d7ea579 100644
--- a/README.md
+++ b/README.md
@@ -16,6 +16,10 @@ npm i memfs
## Resources
- Documentation
+ - **[Complete Documentation](./docs/index.md)** - Comprehensive guides and examples
+ - **[Getting Started](./docs/getting-started.md)** - Quick start guide with examples
+ - **[Testing Usage](./docs/testing-usage.md)** - Using memfs in your tests
+ - **[Browser Usage](./docs/browser-usage.md)** - Running memfs in browsers
- [In-memory Node.js `fs` API](./docs/node/index.md)
- [In-memory browser File System (Access) API](./docs/fsa/fsa.md)
- [`fs` to File System (Access) API adapter](./docs/fsa/fs-to-fsa.md)
diff --git a/docs/browser-usage.md b/docs/browser-usage.md
new file mode 100644
index 000000000..677a617f3
--- /dev/null
+++ b/docs/browser-usage.md
@@ -0,0 +1,425 @@
+# Browser Usage Guide
+
+memfs provides excellent browser support, offering both Node.js-style `fs` API and modern File System Access (FSA) API implementations that work entirely in memory.
+
+## Installation for Browser
+
+### Using a Bundler (Recommended)
+
+With webpack, Vite, Rollup, or similar:
+
+```bash
+npm install memfs
+```
+
+```js
+import { fs, vol } from 'memfs';
+// or
+import { fsa } from 'memfs/lib/fsa';
+```
+
+### Using CDN
+
+```html
+
+
+
+
+
+
+```
+
+## Node.js fs API in Browser
+
+### Basic File Operations
+
+```js
+import { fs, vol } from 'memfs';
+
+// Create files and directories
+fs.mkdirSync('/app');
+fs.writeFileSync(
+ '/app/config.json',
+ JSON.stringify({
+ name: 'My Browser App',
+ version: '1.0.0',
+ }),
+);
+
+// Read files
+const config = JSON.parse(fs.readFileSync('/app/config.json', 'utf8'));
+console.log(config.name); // "My Browser App"
+
+// List directory contents
+const files = fs.readdirSync('/app');
+console.log(files); // ['config.json']
+```
+
+### Working with Binary Data
+
+```js
+import { fs } from 'memfs';
+
+// Write binary data
+const imageData = new Uint8Array([137, 80, 78, 71]); // PNG header
+fs.writeFileSync('/images/logo.png', imageData);
+
+// Read binary data
+const buffer = fs.readFileSync('/images/logo.png');
+console.log(buffer); // Uint8Array([137, 80, 78, 71])
+```
+
+### Async Operations
+
+```js
+import { fs } from 'memfs';
+
+// Using callbacks
+fs.writeFile('/data.txt', 'Hello, browser!', err => {
+ if (err) throw err;
+
+ fs.readFile('/data.txt', 'utf8', (err, data) => {
+ if (err) throw err;
+ console.log(data); // "Hello, browser!"
+ });
+});
+
+// Using promises
+async function browserFileOps() {
+ await fs.promises.writeFile('/async-data.txt', 'Async content');
+ const content = await fs.promises.readFile('/async-data.txt', 'utf8');
+ console.log(content); // "Async content"
+}
+```
+
+## File System Access (FSA) API
+
+The FSA API provides a modern, Promise-based interface that's compatible with the browser's File System Access API.
+
+### Basic FSA Usage
+
+```js
+import { fsa } from 'memfs/lib/fsa';
+
+// Create a new filesystem
+const { dir, core } = fsa({ mode: 'readwrite' });
+
+async function fsaExample() {
+ // Create a directory
+ const documentsDir = await dir.getDirectoryHandle('documents', { create: true });
+
+ // Create a file
+ const file = await documentsDir.getFileHandle('readme.txt', { create: true });
+
+ // Write to the file
+ const writable = await file.createWritable();
+ await writable.write('Welcome to my browser app!');
+ await writable.close();
+
+ // Read the file
+ const fileObject = await file.getFile();
+ const content = await fileObject.text();
+ console.log(content); // "Welcome to my browser app!"
+
+ // Export to JSON for inspection
+ console.log(core.toJSON()); // { '/documents/readme.txt': 'Welcome to my browser app!' }
+}
+
+fsaExample();
+```
+
+### Advanced FSA Operations
+
+```js
+import { fsa } from 'memfs/lib/fsa';
+
+const { dir, core } = fsa({ mode: 'readwrite' });
+
+async function advancedFSA() {
+ // Create nested directory structure
+ const projectDir = await dir.getDirectoryHandle('my-project', { create: true });
+ const srcDir = await projectDir.getDirectoryHandle('src', { create: true });
+
+ // Create multiple files
+ const files = [
+ { name: 'index.js', content: 'console.log("main");' },
+ { name: 'utils.js', content: 'export const helper = () => {};' },
+ { name: 'config.json', content: JSON.stringify({ env: 'production' }) },
+ ];
+
+ for (const { name, content } of files) {
+ const file = await srcDir.getFileHandle(name, { create: true });
+ const writable = await file.createWritable();
+ await writable.write(content);
+ await writable.close();
+ }
+
+ // List directory contents
+ for await (const [name, handle] of srcDir.entries()) {
+ console.log(name, handle.kind); // "index.js file", "utils.js file", etc.
+ }
+
+ // Remove a file
+ await srcDir.removeEntry('config.json');
+
+ // Export final structure
+ console.log(core.toJSON());
+}
+```
+
+## Browser-Specific Use Cases
+
+### Single Page Applications (SPA)
+
+```js
+import { vol } from 'memfs';
+
+class BrowserAppStorage {
+ constructor() {
+ this.vol = vol;
+ this.initializeStorage();
+ }
+
+ initializeStorage() {
+ // Create application directory structure
+ this.vol.fromJSON({
+ '/app/data/users.json': '[]',
+ '/app/data/settings.json': JSON.stringify({ theme: 'light' }),
+ '/app/cache/': null, // empty directory
+ '/app/temp/': null,
+ });
+ }
+
+ saveUserData(users) {
+ this.vol.writeFileSync('/app/data/users.json', JSON.stringify(users));
+ }
+
+ getUserData() {
+ return JSON.parse(this.vol.readFileSync('/app/data/users.json', 'utf8'));
+ }
+
+ updateSettings(settings) {
+ const current = JSON.parse(this.vol.readFileSync('/app/data/settings.json', 'utf8'));
+ const updated = { ...current, ...settings };
+ this.vol.writeFileSync('/app/data/settings.json', JSON.stringify(updated));
+ }
+
+ clearCache() {
+ // Remove all files in cache directory
+ const cacheFiles = this.vol.readdirSync('/app/cache');
+ cacheFiles.forEach(file => {
+ this.vol.unlinkSync(`/app/cache/${file}`);
+ });
+ }
+
+ exportData() {
+ return this.vol.toJSON();
+ }
+}
+
+const storage = new BrowserAppStorage();
+```
+
+### File Upload Simulation
+
+```js
+import { fs } from 'memfs';
+
+class FileUploadSimulator {
+ constructor() {
+ fs.mkdirSync('/uploads', { recursive: true });
+ }
+
+ async simulateUpload(file) {
+ // Convert File/Blob to buffer
+ const arrayBuffer = await file.arrayBuffer();
+ const buffer = new Uint8Array(arrayBuffer);
+
+ // Save to memfs
+ const uploadPath = `/uploads/${file.name}`;
+ fs.writeFileSync(uploadPath, buffer);
+
+ return {
+ path: uploadPath,
+ size: buffer.length,
+ type: file.type,
+ lastModified: file.lastModified,
+ };
+ }
+
+ getUploadedFiles() {
+ const files = fs.readdirSync('/uploads');
+ return files.map(filename => {
+ const path = `/uploads/${filename}`;
+ const stats = fs.statSync(path);
+ return {
+ name: filename,
+ path,
+ size: stats.size,
+ uploaded: stats.mtime,
+ };
+ });
+ }
+
+ downloadFile(filename) {
+ const buffer = fs.readFileSync(`/uploads/${filename}`);
+ const blob = new Blob([buffer]);
+
+ // Create download link
+ const url = URL.createObjectURL(blob);
+ const a = document.createElement('a');
+ a.href = url;
+ a.download = filename;
+ a.click();
+ URL.revokeObjectURL(url);
+ }
+}
+
+// Usage
+const uploader = new FileUploadSimulator();
+
+// Handle file input
+document.getElementById('fileInput').addEventListener('change', async e => {
+ for (const file of e.target.files) {
+ const result = await uploader.simulateUpload(file);
+ console.log('Uploaded:', result);
+ }
+});
+```
+
+### Progressive Web App (PWA) Storage
+
+```js
+import { vol } from 'memfs';
+
+class PWAStorage {
+ constructor() {
+ this.loadFromLocalStorage();
+ }
+
+ loadFromLocalStorage() {
+ const stored = localStorage.getItem('pwa-memfs');
+ if (stored) {
+ vol.fromJSON(JSON.parse(stored));
+ } else {
+ this.initializeDefaults();
+ }
+ }
+
+ initializeDefaults() {
+ vol.fromJSON({
+ '/pwa/manifest.json': JSON.stringify({
+ name: 'My PWA',
+ version: '1.0.0',
+ offline: true,
+ }),
+ '/pwa/data/': null,
+ '/pwa/cache/': null,
+ });
+ this.saveToLocalStorage();
+ }
+
+ saveToLocalStorage() {
+ const data = vol.toJSON();
+ localStorage.setItem('pwa-memfs', JSON.stringify(data));
+ }
+
+ cacheResource(url, content) {
+ const filename = url.replace(/[^a-zA-Z0-9]/g, '_');
+ vol.writeFileSync(`/pwa/cache/${filename}`, content);
+ this.saveToLocalStorage();
+ }
+
+ getCachedResource(url) {
+ const filename = url.replace(/[^a-zA-Z0-9]/g, '_');
+ try {
+ return vol.readFileSync(`/pwa/cache/${filename}`, 'utf8');
+ } catch {
+ return null;
+ }
+ }
+}
+```
+
+## Integration with Bundlers
+
+### Webpack Configuration
+
+```js
+// webpack.config.js
+module.exports = {
+ resolve: {
+ fallback: {
+ fs: false,
+ path: require.resolve('path-browserify'),
+ stream: require.resolve('stream-browserify'),
+ util: require.resolve('util/'),
+ buffer: require.resolve('buffer/'),
+ },
+ },
+ plugins: [
+ new webpack.ProvidePlugin({
+ Buffer: ['buffer', 'Buffer'],
+ process: 'process/browser',
+ }),
+ ],
+};
+```
+
+### Vite Configuration
+
+```js
+// vite.config.js
+import { defineConfig } from 'vite';
+
+export default defineConfig({
+ define: {
+ global: 'globalThis',
+ },
+ resolve: {
+ alias: {
+ stream: 'stream-browserify',
+ util: 'util',
+ },
+ },
+});
+```
+
+## Browser Compatibility
+
+- **Modern browsers**: Full support for both fs API and FSA API
+- **IE11+**: Basic fs API support with polyfills
+- **Mobile browsers**: Full support
+- **Node.js compatibility**: Code written for memfs works in both browser and Node.js
+
+## Performance Considerations
+
+- **Memory usage**: Files are stored in memory, so consider total size
+- **Persistence**: Data is lost on page refresh unless saved to localStorage/IndexedDB
+- **Streaming**: Use createReadStream/createWriteStream for large files
+- **Chunking**: Break large operations into smaller chunks to avoid blocking
+
+## Security Considerations
+
+- **Same-origin policy**: memfs data is isolated to your application
+- **No file system access**: Cannot access real file system (that's the point!)
+- **Memory limits**: Browser memory limits apply to stored data
+
+## Examples and Demos
+
+Check out the [demo folder](../demo) for complete browser examples:
+
+- [Git in browser with FSA](../demo/git-fsa/)
+- [File system sync tests](../demo/fsa-to-node-sync-tests/)
+- [CRUD and CAS operations](../demo/crud-and-cas/)
+
+## See Also
+
+- [Getting Started Guide](./getting-started.md)
+- [Testing Usage Guide](./testing-usage.md)
+- [File System Access API Reference](./fsa/fsa.md)
+- [API Documentation](https://streamich.github.io/memfs/)
diff --git a/docs/getting-started.md b/docs/getting-started.md
new file mode 100644
index 000000000..64b597022
--- /dev/null
+++ b/docs/getting-started.md
@@ -0,0 +1,140 @@
+# Getting Started with memfs
+
+memfs is a complete in-memory file system implementation that provides Node.js `fs` API compatibility and browser File System Access (FSA) API support.
+
+## Installation
+
+```bash
+npm install memfs
+```
+
+## Quick Start
+
+### Basic Usage
+
+```js
+import { fs } from 'memfs';
+
+// Write a file
+fs.writeFileSync('/hello.txt', 'World!');
+
+// Read a file
+const content = fs.readFileSync('/hello.txt', 'utf8');
+console.log(content); // World!
+```
+
+### Creating a File System from JSON
+
+You can initialize a file system from a JSON object:
+
+```js
+import { fs, vol } from 'memfs';
+
+const files = {
+ './README.md': '# My Project',
+ './src/index.js': 'console.log("Hello, world!");',
+ './package.json': JSON.stringify({ name: 'my-project', version: '1.0.0' }),
+};
+
+vol.fromJSON(files, '/app');
+
+// Now you can access the files
+console.log(fs.readFileSync('/app/README.md', 'utf8')); // # My Project
+console.log(fs.readFileSync('/app/src/index.js', 'utf8')); // console.log("Hello, world!");
+```
+
+### Creating Multiple Volumes
+
+Create separate, isolated file systems:
+
+```js
+import { Volume } from 'memfs';
+
+// Create first volume
+const vol1 = Volume.fromJSON({ '/config.json': '{"env": "dev"}' });
+
+// Create second volume
+const vol2 = Volume.fromJSON({ '/config.json': '{"env": "prod"}' });
+
+// They are completely separate
+console.log(vol1.readFileSync('/config.json', 'utf8')); // {"env": "dev"}
+console.log(vol2.readFileSync('/config.json', 'utf8')); // {"env": "prod"}
+```
+
+## Common Use Cases
+
+### Testing
+
+Perfect for unit tests where you need a predictable file system:
+
+```js
+import { vol } from 'memfs';
+
+beforeEach(() => {
+ vol.reset(); // Clear the file system
+ vol.fromJSON({
+ '/project/package.json': JSON.stringify({ name: 'test-project' }),
+ '/project/src/index.js': 'module.exports = "hello";',
+ });
+});
+
+test('should read package.json', () => {
+ const pkg = JSON.parse(vol.readFileSync('/project/package.json', 'utf8'));
+ expect(pkg.name).toBe('test-project');
+});
+```
+
+### Browser Environment
+
+Use with bundlers like webpack or Vite:
+
+```js
+import { fs } from 'memfs';
+
+// Create some files in memory
+fs.writeFileSync('/data.txt', 'Browser data');
+fs.mkdirSync('/uploads');
+
+// Read directory contents
+const files = fs.readdirSync('/');
+console.log(files); // ['data.txt', 'uploads']
+```
+
+### File System Access API (Browser)
+
+For modern browsers with File System Access API support:
+
+```js
+import { fsa } from 'memfs/lib/fsa';
+
+// Create a new FSA-compatible filesystem
+const { dir, core } = fsa({ mode: 'readwrite' });
+
+// Create folders and files using FSA API
+const folder = await dir.getDirectoryHandle('documents', { create: true });
+const file = await folder.getFileHandle('note.txt', { create: true });
+
+// Write to file
+const writable = await file.createWritable();
+await writable.write('My note content');
+await writable.close();
+
+// Export to JSON
+console.log(core.toJSON()); // { '/documents/note.txt': 'My note content' }
+```
+
+## Next Steps
+
+- [Testing Usage Guide](./testing-usage.md) - Learn how to use memfs in your tests
+- [Browser Usage Guide](./browser-usage.md) - Use memfs in browser environments
+- [Node.js fs API Reference](./node/index.md) - Complete Node.js fs API implementation
+- [File System Access API Reference](./fsa/fsa.md) - Browser FSA API implementation
+- [API Documentation](https://streamich.github.io/memfs/) - Complete TypeDoc reference
+
+## Examples
+
+Explore the [demo folder](../demo) for comprehensive examples including:
+
+- Git integration in the browser
+- File system synchronization
+- Advanced usage patterns
diff --git a/docs/index.md b/docs/index.md
new file mode 100644
index 000000000..22e00e91b
--- /dev/null
+++ b/docs/index.md
@@ -0,0 +1,149 @@
+# memfs Documentation
+
+> In-memory file system for Node.js and browsers
+
+memfs is a complete in-memory file system implementation that provides Node.js `fs` API compatibility and browser File System Access (FSA) API support. Perfect for testing, browser applications, and any scenario where you need a fast, predictable file system that doesn't touch the disk.
+
+## Quick Start
+
+```bash
+npm install memfs
+```
+
+```js
+import { fs } from 'memfs';
+
+fs.writeFileSync('/hello.txt', 'World!');
+fs.readFileSync('/hello.txt', 'utf8'); // World!
+```
+
+## Documentation
+
+### ๐ [Getting Started](./getting-started.md)
+
+Learn the basics of memfs with practical examples covering file operations, JSON initialization, and common patterns.
+
+### ๐งช [Testing Usage](./testing-usage.md)
+
+Comprehensive guide for using memfs in unit tests, integration tests, and mocking file system operations.
+
+### ๐ [Browser Usage](./browser-usage.md)
+
+Everything you need to know about using memfs in browsers, including FSA API, bundler configuration, and PWA integration.
+
+### ๐ API References
+
+#### Node.js fs API
+
+- **[Node.js fs API Implementation](./node/index.md)** - Complete guide to the Node.js-compatible fs API
+- **[Usage Examples](./node/usage.md)** - Practical examples and patterns
+- **[API Reference](./node/reference.md)** - Detailed API documentation
+
+#### File System Access API
+
+- **[FSA API Guide](./fsa/fsa.md)** - Browser File System Access API implementation
+- **[fs to FSA Adapter](./fsa/fs-to-fsa.md)** - Bridge Node.js fs API to browser FSA API
+- **[FSA to fs Adapter](./fsa/fsa-to-fs.md)** - Use FSA API with Node.js fs interface
+
+#### Experimental APIs
+
+- **[CRUD File System](./crudfs/index.md)** - High-level CRUD operations `experimental`
+- **[CAS File System](./casfs/index.md)** - Content Addressable Storage `experimental`
+
+### ๐ ๏ธ Utilities
+
+- **[Directory Snapshots](./snapshot/index.md)** - Serialize and restore file system state
+- **[Directory Tree Printing](./print/index.md)** - Pretty-print directory structures
+
+### ๐ [Complete API Documentation](https://streamich.github.io/memfs/)
+
+TypeDoc-generated API reference with complete type information and examples.
+
+## Features
+
+- โ
**Complete Node.js fs API** - All major fs methods implemented
+- โ
**Browser compatible** - Works in all modern browsers
+- โ
**File System Access API** - Modern browser file system interface
+- โ
**TypeScript support** - Full type definitions included
+- โ
**Zero dependencies** - Lightweight and self-contained
+- โ
**Testing friendly** - Perfect for unit tests and mocking
+- โ
**JSON serialization** - Export/import entire file systems
+- โ
**Stream support** - ReadStream and WriteStream implementations
+- โ
**Symlinks & hardlinks** - Full link support like real file systems
+- โ
**Async/sync APIs** - Both callback and promise-based operations
+
+## Use Cases
+
+### Testing
+
+```js
+import { vol } from 'memfs';
+
+beforeEach(() => {
+ vol.reset();
+ vol.fromJSON({
+ '/project/package.json': JSON.stringify({ name: 'test' }),
+ '/project/src/index.js': 'console.log("test");',
+ });
+});
+```
+
+### Browser Applications
+
+```js
+import { fsa } from 'memfs/lib/fsa';
+
+const { dir } = fsa({ mode: 'readwrite' });
+const file = await dir.getFileHandle('data.txt', { create: true });
+```
+
+### Mocking File Systems
+
+```js
+import { patchFs } from 'fs-monkey';
+import { vol } from 'memfs';
+
+// Replace Node.js fs with memfs
+patchFs(vol);
+```
+
+## Examples
+
+Explore comprehensive examples in the [demo directory](../demo/):
+
+- **[Git in Browser (FSA)](../demo/git-fsa/README.md)** - Git operations with File System Access API
+- **[Git in Browser (OPFS)](../demo/git-opfs/README.md)** - Git with Origin Private File System
+- **[fs to FSA Bridge](../demo/fsa-to-node-zipfile/README.md)** - Create real files from memory
+- **[Sync File Operations](../demo/fsa-to-node-sync-tests/README.md)** - Synchronous browser file operations
+- **[CRUD & CAS Demo](../demo/crud-and-cas/README.md)** - Advanced file system patterns
+
+## Performance
+
+memfs is designed for speed and efficiency:
+
+- Files stored directly in memory for instant access
+- No I/O blocking or disk latency
+- Optimized for both small files and large binary data
+- Streaming support for memory-efficient large file operations
+
+## Ecosystem
+
+memfs works great with other streamich file system libraries:
+
+- **[unionfs](https://github.com/streamich/unionfs)** - Union multiple file systems
+- **[fs-monkey](https://github.com/streamich/fs-monkey)** - Monkey-patch Node.js fs
+- **[linkfs](https://github.com/streamich/linkfs)** - Redirect file system paths
+- **[spyfs](https://github.com/streamich/spyfs)** - Spy on file system operations
+
+## Contributing
+
+memfs is open source! Check out the [GitHub repository](https://github.com/streamich/memfs) to:
+
+- Report bugs or request features
+- Submit pull requests
+- Read the source code
+- See test coverage at [streamich.github.io/memfs/coverage/](https://streamich.github.io/memfs/coverage/)
+
+## License
+
+Apache 2.0
diff --git a/docs/testing-usage.md b/docs/testing-usage.md
new file mode 100644
index 000000000..270cadd02
--- /dev/null
+++ b/docs/testing-usage.md
@@ -0,0 +1,265 @@
+# Testing with memfs
+
+memfs is particularly useful for testing because it provides a completely isolated, predictable file system that doesn't interact with your actual disk.
+
+## Basic Testing Setup
+
+### Jest Example
+
+```js
+import { vol } from 'memfs';
+
+describe('File operations', () => {
+ beforeEach(() => {
+ // Reset the file system before each test
+ vol.reset();
+ });
+
+ test('should create and read files', () => {
+ vol.writeFileSync('/test.txt', 'test content');
+ const content = vol.readFileSync('/test.txt', 'utf8');
+ expect(content).toBe('test content');
+ });
+
+ test('should handle JSON files', () => {
+ const data = { name: 'test', version: '1.0.0' };
+ vol.writeFileSync('/package.json', JSON.stringify(data));
+
+ const content = JSON.parse(vol.readFileSync('/package.json', 'utf8'));
+ expect(content.name).toBe('test');
+ expect(content.version).toBe('1.0.0');
+ });
+});
+```
+
+### Mocha Example
+
+```js
+import { vol } from 'memfs';
+import { expect } from 'chai';
+
+describe('File system tests', () => {
+ beforeEach(() => {
+ vol.reset();
+ });
+
+ it('should support directory operations', () => {
+ vol.mkdirSync('/projects');
+ vol.mkdirSync('/projects/myapp');
+ vol.writeFileSync('/projects/myapp/index.js', 'console.log("Hello");');
+
+ const dirs = vol.readdirSync('/projects');
+ expect(dirs).to.include('myapp');
+
+ const files = vol.readdirSync('/projects/myapp');
+ expect(files).to.include('index.js');
+ });
+});
+```
+
+## Testing File System Interactions
+
+### Mocking Node.js fs Module
+
+Use with libraries like `fs-monkey` to completely replace Node.js fs:
+
+```js
+import { vol } from 'memfs';
+import { patchFs } from 'fs-monkey';
+
+describe('Code that uses fs', () => {
+ let restoreFs;
+
+ beforeEach(() => {
+ vol.reset();
+ vol.fromJSON({
+ '/app/config.json': JSON.stringify({ database: 'sqlite' }),
+ '/app/data/users.json': JSON.stringify([{ id: 1, name: 'John' }]),
+ });
+
+ // Replace Node.js fs with memfs
+ restoreFs = patchFs(vol);
+ });
+
+ afterEach(() => {
+ // Restore original fs
+ restoreFs();
+ });
+
+ test('application reads config correctly', () => {
+ // Your application code that uses fs will now use memfs
+ const config = require('./my-app').loadConfig('/app/config.json');
+ expect(config.database).toBe('sqlite');
+ });
+});
+```
+
+### Testing Async Operations
+
+```js
+import { vol } from 'memfs';
+import { promisify } from 'util';
+
+describe('Async file operations', () => {
+ beforeEach(() => {
+ vol.reset();
+ });
+
+ test('should handle promises', async () => {
+ const writeFile = promisify(vol.writeFile.bind(vol));
+ const readFile = promisify(vol.readFile.bind(vol));
+
+ await writeFile('/async-test.txt', 'async content');
+ const content = await readFile('/async-test.txt', 'utf8');
+ expect(content).toBe('async content');
+ });
+
+ test('should handle fs promises API', async () => {
+ await vol.promises.writeFile('/promise-test.txt', 'promise content');
+ const content = await vol.promises.readFile('/promise-test.txt', 'utf8');
+ expect(content).toBe('promise content');
+ });
+});
+```
+
+## Advanced Testing Patterns
+
+### Setup Complex File Structures
+
+```js
+import { vol } from 'memfs';
+
+function setupProjectStructure() {
+ vol.fromJSON({
+ '/project/package.json': JSON.stringify({
+ name: 'test-project',
+ version: '1.0.0',
+ scripts: {
+ test: 'jest',
+ build: 'webpack',
+ },
+ }),
+ '/project/src/index.js': `
+ const config = require('./config');
+ module.exports = { config };
+ `,
+ '/project/src/config.js': 'module.exports = { env: "test" };',
+ '/project/tests/index.test.js': 'test("placeholder", () => {});',
+ '/project/node_modules/some-module/index.js': 'module.exports = "mock module";',
+ });
+}
+
+describe('Project structure tests', () => {
+ beforeEach(() => {
+ vol.reset();
+ setupProjectStructure();
+ });
+
+ test('should have correct project structure', () => {
+ expect(vol.existsSync('/project/package.json')).toBe(true);
+ expect(vol.existsSync('/project/src/index.js')).toBe(true);
+ expect(vol.existsSync('/project/tests/index.test.js')).toBe(true);
+ });
+});
+```
+
+### Testing Error Conditions
+
+```js
+import { vol } from 'memfs';
+
+describe('Error handling', () => {
+ beforeEach(() => {
+ vol.reset();
+ });
+
+ test('should throw ENOENT for missing files', () => {
+ expect(() => {
+ vol.readFileSync('/nonexistent.txt');
+ }).toThrow(/ENOENT/);
+ });
+
+ test('should throw EEXIST when creating existing files', () => {
+ vol.writeFileSync('/existing.txt', 'content');
+
+ expect(() => {
+ vol.writeFileSync('/existing.txt', 'new content', { flag: 'wx' });
+ }).toThrow(/EEXIST/);
+ });
+
+ test('should handle permission-like errors', () => {
+ vol.mkdirSync('/readonly');
+
+ // Simulate readonly behavior by catching and re-throwing
+ expect(() => {
+ vol.writeFileSync('/readonly/test.txt', 'content');
+ }).not.toThrow(); // memfs doesn't enforce permissions, but your app might
+ });
+});
+```
+
+### Integration with Testing Frameworks
+
+#### Testing with Snapshots
+
+```js
+import { vol } from 'memfs';
+
+describe('File system snapshots', () => {
+ test('should match file system structure', () => {
+ vol.fromJSON({
+ '/app/index.js': 'console.log("app");',
+ '/app/lib/utils.js': 'module.exports = {};',
+ '/app/test/index.test.js': 'test("", () => {});',
+ });
+
+ const snapshot = vol.toJSON();
+ expect(snapshot).toMatchSnapshot();
+ });
+});
+```
+
+#### Parameterized Tests
+
+```js
+import { vol } from 'memfs';
+
+describe.each([
+ ['text file', '/test.txt', 'text content'],
+ ['json file', '/test.json', JSON.stringify({ test: true })],
+ ['empty file', '/empty.txt', ''],
+])('File operations with %s', (fileType, path, content) => {
+ beforeEach(() => {
+ vol.reset();
+ });
+
+ test(`should handle ${fileType}`, () => {
+ vol.writeFileSync(path, content);
+ const result = vol.readFileSync(path, 'utf8');
+ expect(result).toBe(content);
+ });
+});
+```
+
+## Testing Best Practices
+
+1. **Always reset between tests**: Use `vol.reset()` in `beforeEach` to ensure test isolation
+2. **Use descriptive file paths**: Makes debugging easier when tests fail
+3. **Test both sync and async operations**: Ensure your code works with both patterns
+4. **Mock external dependencies**: Use memfs with fs-monkey to isolate file system interactions
+5. **Test error conditions**: Verify your code handles missing files, permission errors, etc.
+6. **Use JSON setup for complex structures**: `vol.fromJSON()` is great for setting up complex file trees
+
+## Common Gotchas
+
+- **Path separators**: memfs uses `/` even on Windows in the in-memory representation
+- **Encoding**: Always specify encoding when reading text files: `vol.readFileSync(path, 'utf8')`
+- **Cleanup**: Remember to call `vol.reset()` between tests to avoid interference
+- **Absolute paths**: memfs works with absolute paths; relative paths are resolved from the current working directory
+
+## See Also
+
+- [Getting Started Guide](./getting-started.md)
+- [Browser Usage Guide](./browser-usage.md)
+- [Node.js fs API Reference](./node/index.md)
+- [API Documentation](https://streamich.github.io/memfs/)
diff --git a/tsconfig.json b/tsconfig.json
index 00dda587a..ba1816d46 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -27,6 +27,22 @@
"src/node-to-crud/index.ts",
"src/node-to-fsa/index.ts"
],
- "out": "typedocs"
+ "out": "typedocs",
+ "name": "memfs",
+ "includeVersion": true,
+ "readme": "docs/index.md",
+ "categorizeByGroup": true,
+ "sort": ["source-order"],
+ "excludePrivate": true,
+ "excludeProtected": true,
+ "excludeExternals": true,
+ "hideGenerator": true,
+ "searchInComments": true,
+ "navigationLinks": {
+ "Getting Started": "https://github.com/streamich/memfs/blob/master/docs/getting-started.md",
+ "Testing Guide": "https://github.com/streamich/memfs/blob/master/docs/testing-usage.md",
+ "Browser Guide": "https://github.com/streamich/memfs/blob/master/docs/browser-usage.md",
+ "GitHub": "https://github.com/streamich/memfs"
+ }
}
}