0
# Metro Memory FS
1
2
Metro Memory FS provides a complete in-memory filesystem implementation that mimics the Node.js `fs` module API for testing purposes. It offers a comprehensive drop-in replacement for the native filesystem API, supporting all standard file operations including reading, writing, creating, deleting files and directories, symbolic links, file descriptors, and file watchers.
3
4
## Package Information
5
6
- **Package Name**: metro-memory-fs
7
- **Package Type**: npm
8
- **Language**: JavaScript
9
- **Installation**: `npm install metro-memory-fs`
10
11
## Core Imports
12
13
```javascript
14
const MemoryFs = require("metro-memory-fs");
15
```
16
17
ES Modules:
18
19
```javascript
20
import MemoryFs from "metro-memory-fs";
21
```
22
23
## Basic Usage
24
25
```javascript
26
const MemoryFs = require("metro-memory-fs");
27
28
// Create a new memory filesystem instance
29
const fs = new MemoryFs({
30
cwd: () => "/current/working/dir",
31
platform: "posix" // or "win32"
32
});
33
34
// Write and read files
35
fs.writeFileSync("/hello.txt", "Hello, World!");
36
const content = fs.readFileSync("/hello.txt", "utf8");
37
console.log(content); // "Hello, World!"
38
39
// Create directories
40
fs.mkdirSync("/mydir", { recursive: true });
41
42
// List directory contents
43
const files = fs.readdirSync("/");
44
console.log(files); // ["hello.txt", "mydir"]
45
46
// Check if file exists
47
const exists = fs.existsSync("/hello.txt");
48
console.log(exists); // true
49
50
// Use async operations
51
fs.readFile("/hello.txt", "utf8", (err, data) => {
52
if (!err) {
53
console.log(data); // "Hello, World!"
54
}
55
});
56
57
// Use promises
58
const data = await fs.promises.readFile("/hello.txt", "utf8");
59
console.log(data); // "Hello, World!"
60
```
61
62
## Architecture
63
64
Metro Memory FS is built around several key components:
65
66
- **Memory Filesystem**: Complete in-memory representation of files and directories using Map-based storage
67
- **Path Resolution**: Cross-platform path handling supporting both POSIX and Windows path conventions
68
- **Node Compatibility**: Full API compatibility with Node.js fs module including sync, async, and promise variants
69
- **File Descriptors**: Low-level file descriptor support for fine-grained file operations
70
- **Streams**: Readable and writable stream implementations for large file handling
71
- **File Watching**: Event-based file system monitoring with recursive watching support
72
73
## Capabilities
74
75
### File Operations
76
77
Core file reading, writing, and manipulation operations supporting both synchronous and asynchronous patterns with full Node.js fs API compatibility.
78
79
```javascript { .api }
80
// Synchronous operations
81
writeFileSync(path: string | Buffer, data: string | Buffer, options?: WriteFileOptions): void;
82
readFileSync(path: string | Buffer, options?: ReadFileOptions): string | Buffer;
83
existsSync(path: string | Buffer): boolean;
84
unlinkSync(path: string | Buffer): void;
85
copyFileSync(src: string | Buffer, dest: string | Buffer, flags?: number): void;
86
accessSync(path: string | Buffer, mode?: number): void;
87
truncateSync(path: string | Buffer | number, len?: number): void;
88
89
// Asynchronous operations
90
writeFile(path: string | Buffer, data: string | Buffer, options?: WriteFileOptions, callback?: (err?: Error) => void): void;
91
readFile(path: string | Buffer, options?: ReadFileOptions, callback?: (err?: Error, data?: string | Buffer) => void): void;
92
unlink(path: string | Buffer, callback: (err?: Error) => void): void;
93
copyFile(src: string | Buffer, dest: string | Buffer, flags?: number, callback?: (err?: Error) => void): void;
94
access(path: string | Buffer, mode?: number, callback?: (err?: Error) => void): void;
95
truncate(path: string | Buffer, len?: number, callback?: (err?: Error) => void): void;
96
97
interface WriteFileOptions {
98
encoding?: string;
99
mode?: number;
100
flag?: string;
101
}
102
103
interface ReadFileOptions {
104
encoding?: string;
105
flag?: string;
106
}
107
```
108
109
[File Operations](./file-operations.md)
110
111
### Directory Operations
112
113
Directory creation, listing, and removal operations with support for recursive operations and various output formats.
114
115
```javascript { .api }
116
mkdirSync(path: string | Buffer, options?: MkdirOptions): void;
117
readdirSync(path: string | Buffer, options?: ReaddirOptions): string[] | Buffer[] | Dirent[];
118
rmdirSync(path: string | Buffer): void;
119
rmSync(path: string | Buffer, options?: RmOptions): void;
120
mkdtempSync(prefix: string, options?: MktempOptions): string;
121
122
mkdir(path: string | Buffer, options?: MkdirOptions, callback?: (err?: Error) => void): void;
123
readdir(path: string | Buffer, options?: ReaddirOptions, callback?: (err?: Error, files?: string[] | Buffer[] | Dirent[]) => void): void;
124
125
interface MkdirOptions {
126
recursive?: boolean;
127
mode?: number;
128
}
129
130
interface ReaddirOptions {
131
encoding?: string;
132
withFileTypes?: boolean;
133
}
134
135
interface RmOptions {
136
recursive?: boolean;
137
force?: boolean;
138
}
139
```
140
141
[Directory Operations](./directory-operations.md)
142
143
### File Descriptors
144
145
Low-level file descriptor operations for fine-grained control over file access, positioning, and data manipulation.
146
147
```javascript { .api }
148
openSync(path: string | Buffer, flags: string | number, mode?: number): number;
149
closeSync(fd: number): void;
150
readSync(fd: number, buffer: Buffer, offset: number, length: number, position?: number): number;
151
writeSync(fd: number, buffer: Buffer | string, offset?: number, length?: number | string, position?: number): number;
152
fstatSync(fd: number): Stats;
153
fchmodSync(fd: number, mode: number | string): void;
154
fsyncSync(fd: number): void;
155
fdatasyncSync(fd: number): void;
156
157
open(path: string | Buffer, flags: string | number, mode?: number, callback?: (err?: Error, fd?: number) => void): void;
158
close(fd: number, callback: (err?: Error) => void): void;
159
read(fd: number, buffer: Buffer, offset: number, length: number, position?: number, callback?: (err?: Error, bytesRead?: number) => void): void;
160
write(fd: number, buffer: Buffer | string, offset?: number, length?: number, position?: number, callback?: (err?: Error, bytesWritten?: number) => void): void;
161
```
162
163
[File Descriptors](./file-descriptors.md)
164
165
### Symbolic Links
166
167
Symbolic link and hard link creation, reading, and path resolution with cross-platform support.
168
169
```javascript { .api }
170
symlinkSync(target: string | Buffer, path: string | Buffer, type?: string): void;
171
readlinkSync(path: string | Buffer, options?: ReadlinkOptions): string | Buffer;
172
linkSync(existingPath: string | Buffer, newPath: string | Buffer): void;
173
realpathSync(path: string | Buffer): string;
174
175
symlink(target: string | Buffer, path: string | Buffer, type?: string, callback?: (err?: Error) => void): void;
176
readlink(path: string | Buffer, options?: ReadlinkOptions, callback?: (err?: Error, linkString?: string | Buffer) => void): void;
177
realpath(path: string | Buffer, callback: (err?: Error, resolvedPath?: string) => void): void;
178
179
interface ReadlinkOptions {
180
encoding?: string;
181
}
182
```
183
184
[Symbolic Links](./symbolic-links.md)
185
186
### Streams
187
188
Readable and writable stream implementations for efficient handling of large files with position control and event handling.
189
190
```javascript { .api }
191
createReadStream(path: string | Buffer, options?: ReadStreamOptions): ReadStream;
192
createWriteStream(path: string | Buffer, options?: WriteStreamOptions): WriteStream;
193
194
interface ReadStreamOptions {
195
flags?: string;
196
encoding?: string;
197
fd?: number;
198
mode?: number;
199
autoClose?: boolean;
200
start?: number;
201
end?: number;
202
highWaterMark?: number;
203
}
204
205
interface WriteStreamOptions {
206
flags?: string;
207
encoding?: string;
208
fd?: number;
209
mode?: number;
210
autoClose?: boolean;
211
start?: number;
212
emitClose?: boolean;
213
}
214
```
215
216
[Streams](./streams.md)
217
218
### File Watching
219
220
File system monitoring capabilities with event-driven notifications for file and directory changes, supporting recursive watching.
221
222
```javascript { .api }
223
watch(filename: string | Buffer, options?: WatchOptions, listener?: WatchListener): FSWatcher;
224
225
interface WatchOptions {
226
encoding?: string;
227
persistent?: boolean;
228
recursive?: boolean;
229
}
230
231
type WatchListener = (eventType: 'rename' | 'change', filename?: string | Buffer) => void;
232
233
interface FSWatcher {
234
close(): void;
235
on(event: 'change', listener: WatchListener): this;
236
on(event: 'error', listener: (error: Error) => void): this;
237
on(event: 'close', listener: () => void): this;
238
}
239
```
240
241
[File Watching](./file-watching.md)
242
243
### Stats and Permissions
244
245
File statistics, permission checking, and metadata operations with full compatibility for Node.js Stats objects.
246
247
```javascript { .api }
248
statSync(path: string | Buffer): Stats;
249
lstatSync(path: string | Buffer): Stats;
250
chmodSync(path: string | Buffer, mode: number | string): void;
251
lchmodSync(path: string | Buffer, mode: number | string): void;
252
renameSync(oldPath: string | Buffer, newPath: string | Buffer): void;
253
254
stat(path: string | Buffer, callback: (err?: Error, stats?: Stats) => void): void;
255
lstat(path: string | Buffer, callback: (err?: Error, stats?: Stats) => void): void;
256
chmod(path: string | Buffer, mode: number | string, callback?: (err?: Error) => void): void;
257
rename(oldPath: string | Buffer, newPath: string | Buffer, callback?: (err?: Error) => void): void;
258
259
interface Stats {
260
isFile(): boolean;
261
isDirectory(): boolean;
262
isSymbolicLink(): boolean;
263
isBlockDevice(): boolean;
264
isCharacterDevice(): boolean;
265
isFIFO(): boolean;
266
isSocket(): boolean;
267
size: number;
268
mode: number;
269
uid: number;
270
gid: number;
271
// ... other stat properties
272
}
273
```
274
275
[Stats and Permissions](./stats-permissions.md)
276
277
## Promise API
278
279
```javascript { .api }
280
interface MemoryFs {
281
promises: {
282
writeFile(path: string | Buffer, data: string | Buffer, options?: WriteFileOptions): Promise<void>;
283
readFile(path: string | Buffer, options?: ReadFileOptions): Promise<string | Buffer>;
284
mkdir(path: string | Buffer, options?: MkdirOptions): Promise<void>;
285
readdir(path: string | Buffer, options?: ReaddirOptions): Promise<string[] | Buffer[] | Dirent[]>;
286
stat(path: string | Buffer): Promise<Stats>;
287
lstat(path: string | Buffer): Promise<Stats>;
288
access(path: string | Buffer, mode?: number): Promise<void>;
289
unlink(path: string | Buffer): Promise<void>;
290
copyFile(src: string | Buffer, dest: string | Buffer, flags?: number): Promise<void>;
291
symlink(target: string | Buffer, path: string | Buffer, type?: string): Promise<void>;
292
readlink(path: string | Buffer, options?: ReadlinkOptions): Promise<string | Buffer>;
293
realpath(path: string | Buffer): Promise<string>;
294
truncate(path: string | Buffer, len?: number): Promise<void>;
295
chmod(path: string | Buffer, mode: number | string): Promise<void>;
296
lchmod(path: string | Buffer, mode: number | string): Promise<void>;
297
rename(oldPath: string | Buffer, newPath: string | Buffer): Promise<void>;
298
open(path: string | Buffer, flags: string | number, mode?: number): Promise<number>;
299
rmdir(path: string | Buffer): Promise<void>;
300
utimes(path: string | Buffer, atime: number | Date, mtime: number | Date): Promise<void>;
301
// ... other promise methods
302
};
303
}
304
```
305
306
## Constructor Options
307
308
```javascript { .api }
309
interface MemoryFsOptions {
310
/** Platform type for path handling */
311
platform?: 'posix' | 'win32';
312
/** Function to get current working directory for relative path resolution */
313
cwd?: () => string;
314
}
315
316
class MemoryFs {
317
constructor(options?: MemoryFsOptions);
318
319
/** Reset filesystem to initial empty state */
320
reset(): void;
321
322
/** Node.js filesystem constants */
323
constants: typeof constants;
324
325
/** Dirent class for directory entries */
326
Dirent: typeof Dirent;
327
}
328
```
329
330
## Constants
331
332
```javascript { .api }
333
interface FsConstants {
334
// File access constants
335
F_OK: number; // File existence
336
R_OK: number; // Read permission
337
W_OK: number; // Write permission
338
X_OK: number; // Execute permission
339
340
// Copy file constants
341
COPYFILE_EXCL: number; // Exclusive copy (fail if destination exists)
342
COPYFILE_FICLONE: number; // Clone file
343
344
// File mode constants
345
S_IRUSR: number; // User read permission
346
S_IWUSR: number; // User write permission
347
S_IXUSR: number; // User execute permission
348
S_IRGRP: number; // Group read permission
349
S_IWGRP: number; // Group write permission
350
S_IXGRP: number; // Group execute permission
351
S_IROTH: number; // Other read permission
352
S_IWOTH: number; // Other write permission
353
S_IXOTH: number; // Other execute permission
354
355
// File type constants
356
S_IFMT: number; // File type mask
357
S_IFREG: number; // Regular file
358
S_IFDIR: number; // Directory
359
S_IFLNK: number; // Symbolic link
360
// ... other constants
361
}
362
```
363
364
## Error Handling
365
366
Metro Memory FS throws standard Node.js filesystem errors with appropriate error codes:
367
368
- `ENOENT` - File or directory not found
369
- `EEXIST` - File or directory already exists
370
- `EISDIR` - Is a directory (when file expected)
371
- `ENOTDIR` - Not a directory (when directory expected)
372
- `EPERM` - Operation not permitted
373
- `EBADF` - Bad file descriptor
374
- `EMFILE` - Too many open files
375
- `ELOOP` - Too many symbolic links
376
- `EINVAL` - Invalid argument
377
- `ENOTEMPTY` - Directory not empty
378
- `ENAMETOOLONG` - Filename too long