docs
evals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5
scenario-6
scenario-7
scenario-8
scenario-9
scenario-10
A memory-based implementation of Node.js fs module for testing purposes
Agent Success
Agent success rate when using this tile
96%
Improvement
Agent success rate improvement when using this tile compared to baseline
1.26x
Baseline
Agent success rate without this tile
76%
tessl install tessl/npm-metro-memory-fs@0.82.0Metro 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.
npm install metro-memory-fsconst MemoryFs = require("metro-memory-fs");ES Modules:
import MemoryFs from "metro-memory-fs";const MemoryFs = require("metro-memory-fs");
// Create a new memory filesystem instance
const fs = new MemoryFs({
cwd: () => "/current/working/dir",
platform: "posix" // or "win32"
});
// Write and read files
fs.writeFileSync("/hello.txt", "Hello, World!");
const content = fs.readFileSync("/hello.txt", "utf8");
console.log(content); // "Hello, World!"
// Create directories
fs.mkdirSync("/mydir", { recursive: true });
// List directory contents
const files = fs.readdirSync("/");
console.log(files); // ["hello.txt", "mydir"]
// Check if file exists
const exists = fs.existsSync("/hello.txt");
console.log(exists); // true
// Use async operations
fs.readFile("/hello.txt", "utf8", (err, data) => {
if (!err) {
console.log(data); // "Hello, World!"
}
});
// Use promises
const data = await fs.promises.readFile("/hello.txt", "utf8");
console.log(data); // "Hello, World!"Metro Memory FS is built around several key components:
Core file reading, writing, and manipulation operations supporting both synchronous and asynchronous patterns with full Node.js fs API compatibility.
// Synchronous operations
writeFileSync(path: string | Buffer, data: string | Buffer, options?: WriteFileOptions): void;
readFileSync(path: string | Buffer, options?: ReadFileOptions): string | Buffer;
existsSync(path: string | Buffer): boolean;
unlinkSync(path: string | Buffer): void;
copyFileSync(src: string | Buffer, dest: string | Buffer, flags?: number): void;
accessSync(path: string | Buffer, mode?: number): void;
truncateSync(path: string | Buffer | number, len?: number): void;
// Asynchronous operations
writeFile(path: string | Buffer, data: string | Buffer, options?: WriteFileOptions, callback?: (err?: Error) => void): void;
readFile(path: string | Buffer, options?: ReadFileOptions, callback?: (err?: Error, data?: string | Buffer) => void): void;
unlink(path: string | Buffer, callback: (err?: Error) => void): void;
copyFile(src: string | Buffer, dest: string | Buffer, flags?: number, callback?: (err?: Error) => void): void;
access(path: string | Buffer, mode?: number, callback?: (err?: Error) => void): void;
truncate(path: string | Buffer, len?: number, callback?: (err?: Error) => void): void;
interface WriteFileOptions {
encoding?: string;
mode?: number;
flag?: string;
}
interface ReadFileOptions {
encoding?: string;
flag?: string;
}Directory creation, listing, and removal operations with support for recursive operations and various output formats.
mkdirSync(path: string | Buffer, options?: MkdirOptions): void;
readdirSync(path: string | Buffer, options?: ReaddirOptions): string[] | Buffer[] | Dirent[];
rmdirSync(path: string | Buffer): void;
rmSync(path: string | Buffer, options?: RmOptions): void;
mkdtempSync(prefix: string, options?: MktempOptions): string;
mkdir(path: string | Buffer, options?: MkdirOptions, callback?: (err?: Error) => void): void;
readdir(path: string | Buffer, options?: ReaddirOptions, callback?: (err?: Error, files?: string[] | Buffer[] | Dirent[]) => void): void;
interface MkdirOptions {
recursive?: boolean;
mode?: number;
}
interface ReaddirOptions {
encoding?: string;
withFileTypes?: boolean;
}
interface RmOptions {
recursive?: boolean;
force?: boolean;
}Low-level file descriptor operations for fine-grained control over file access, positioning, and data manipulation.
openSync(path: string | Buffer, flags: string | number, mode?: number): number;
closeSync(fd: number): void;
readSync(fd: number, buffer: Buffer, offset: number, length: number, position?: number): number;
writeSync(fd: number, buffer: Buffer | string, offset?: number, length?: number | string, position?: number): number;
fstatSync(fd: number): Stats;
fchmodSync(fd: number, mode: number | string): void;
fsyncSync(fd: number): void;
fdatasyncSync(fd: number): void;
open(path: string | Buffer, flags: string | number, mode?: number, callback?: (err?: Error, fd?: number) => void): void;
close(fd: number, callback: (err?: Error) => void): void;
read(fd: number, buffer: Buffer, offset: number, length: number, position?: number, callback?: (err?: Error, bytesRead?: number) => void): void;
write(fd: number, buffer: Buffer | string, offset?: number, length?: number, position?: number, callback?: (err?: Error, bytesWritten?: number) => void): void;Symbolic link and hard link creation, reading, and path resolution with cross-platform support.
symlinkSync(target: string | Buffer, path: string | Buffer, type?: string): void;
readlinkSync(path: string | Buffer, options?: ReadlinkOptions): string | Buffer;
linkSync(existingPath: string | Buffer, newPath: string | Buffer): void;
realpathSync(path: string | Buffer): string;
symlink(target: string | Buffer, path: string | Buffer, type?: string, callback?: (err?: Error) => void): void;
readlink(path: string | Buffer, options?: ReadlinkOptions, callback?: (err?: Error, linkString?: string | Buffer) => void): void;
realpath(path: string | Buffer, callback: (err?: Error, resolvedPath?: string) => void): void;
interface ReadlinkOptions {
encoding?: string;
}Readable and writable stream implementations for efficient handling of large files with position control and event handling.
createReadStream(path: string | Buffer, options?: ReadStreamOptions): ReadStream;
createWriteStream(path: string | Buffer, options?: WriteStreamOptions): WriteStream;
interface ReadStreamOptions {
flags?: string;
encoding?: string;
fd?: number;
mode?: number;
autoClose?: boolean;
start?: number;
end?: number;
highWaterMark?: number;
}
interface WriteStreamOptions {
flags?: string;
encoding?: string;
fd?: number;
mode?: number;
autoClose?: boolean;
start?: number;
emitClose?: boolean;
}File system monitoring capabilities with event-driven notifications for file and directory changes, supporting recursive watching.
watch(filename: string | Buffer, options?: WatchOptions, listener?: WatchListener): FSWatcher;
interface WatchOptions {
encoding?: string;
persistent?: boolean;
recursive?: boolean;
}
type WatchListener = (eventType: 'rename' | 'change', filename?: string | Buffer) => void;
interface FSWatcher {
close(): void;
on(event: 'change', listener: WatchListener): this;
on(event: 'error', listener: (error: Error) => void): this;
on(event: 'close', listener: () => void): this;
}File statistics, permission checking, and metadata operations with full compatibility for Node.js Stats objects.
statSync(path: string | Buffer): Stats;
lstatSync(path: string | Buffer): Stats;
chmodSync(path: string | Buffer, mode: number | string): void;
lchmodSync(path: string | Buffer, mode: number | string): void;
renameSync(oldPath: string | Buffer, newPath: string | Buffer): void;
stat(path: string | Buffer, callback: (err?: Error, stats?: Stats) => void): void;
lstat(path: string | Buffer, callback: (err?: Error, stats?: Stats) => void): void;
chmod(path: string | Buffer, mode: number | string, callback?: (err?: Error) => void): void;
rename(oldPath: string | Buffer, newPath: string | Buffer, callback?: (err?: Error) => void): void;
interface Stats {
isFile(): boolean;
isDirectory(): boolean;
isSymbolicLink(): boolean;
isBlockDevice(): boolean;
isCharacterDevice(): boolean;
isFIFO(): boolean;
isSocket(): boolean;
size: number;
mode: number;
uid: number;
gid: number;
// ... other stat properties
}interface MemoryFs {
promises: {
writeFile(path: string | Buffer, data: string | Buffer, options?: WriteFileOptions): Promise<void>;
readFile(path: string | Buffer, options?: ReadFileOptions): Promise<string | Buffer>;
mkdir(path: string | Buffer, options?: MkdirOptions): Promise<void>;
readdir(path: string | Buffer, options?: ReaddirOptions): Promise<string[] | Buffer[] | Dirent[]>;
stat(path: string | Buffer): Promise<Stats>;
lstat(path: string | Buffer): Promise<Stats>;
access(path: string | Buffer, mode?: number): Promise<void>;
unlink(path: string | Buffer): Promise<void>;
copyFile(src: string | Buffer, dest: string | Buffer, flags?: number): Promise<void>;
symlink(target: string | Buffer, path: string | Buffer, type?: string): Promise<void>;
readlink(path: string | Buffer, options?: ReadlinkOptions): Promise<string | Buffer>;
realpath(path: string | Buffer): Promise<string>;
truncate(path: string | Buffer, len?: number): Promise<void>;
chmod(path: string | Buffer, mode: number | string): Promise<void>;
lchmod(path: string | Buffer, mode: number | string): Promise<void>;
rename(oldPath: string | Buffer, newPath: string | Buffer): Promise<void>;
open(path: string | Buffer, flags: string | number, mode?: number): Promise<number>;
rmdir(path: string | Buffer): Promise<void>;
utimes(path: string | Buffer, atime: number | Date, mtime: number | Date): Promise<void>;
// ... other promise methods
};
}interface MemoryFsOptions {
/** Platform type for path handling */
platform?: 'posix' | 'win32';
/** Function to get current working directory for relative path resolution */
cwd?: () => string;
}
class MemoryFs {
constructor(options?: MemoryFsOptions);
/** Reset filesystem to initial empty state */
reset(): void;
/** Node.js filesystem constants */
constants: typeof constants;
/** Dirent class for directory entries */
Dirent: typeof Dirent;
}interface FsConstants {
// File access constants
F_OK: number; // File existence
R_OK: number; // Read permission
W_OK: number; // Write permission
X_OK: number; // Execute permission
// Copy file constants
COPYFILE_EXCL: number; // Exclusive copy (fail if destination exists)
COPYFILE_FICLONE: number; // Clone file
// File mode constants
S_IRUSR: number; // User read permission
S_IWUSR: number; // User write permission
S_IXUSR: number; // User execute permission
S_IRGRP: number; // Group read permission
S_IWGRP: number; // Group write permission
S_IXGRP: number; // Group execute permission
S_IROTH: number; // Other read permission
S_IWOTH: number; // Other write permission
S_IXOTH: number; // Other execute permission
// File type constants
S_IFMT: number; // File type mask
S_IFREG: number; // Regular file
S_IFDIR: number; // Directory
S_IFLNK: number; // Symbolic link
// ... other constants
}Metro Memory FS throws standard Node.js filesystem errors with appropriate error codes:
ENOENT - File or directory not foundEEXIST - File or directory already existsEISDIR - Is a directory (when file expected)ENOTDIR - Not a directory (when directory expected)EPERM - Operation not permittedEBADF - Bad file descriptorEMFILE - Too many open filesELOOP - Too many symbolic linksEINVAL - Invalid argumentENOTEMPTY - Directory not emptyENAMETOOLONG - Filename too long