or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced-features.mdconstants-and-utilities.mdfilesystem-abstractions.mdfilesystem-implementations.mdindex.mdpath-handling.md

filesystem-implementations.mddocs/

0

# Filesystem Implementations

1

2

Concrete filesystem implementations that provide different behaviors and capabilities built on the @yarnpkg/fslib abstractions.

3

4

## Overview

5

6

The package provides several filesystem implementations for different use cases:

7

- **NodeFS**: Direct access to the real filesystem

8

- **VirtualFS**: In-memory filesystem for testing and isolation

9

- **JailFS**: Security-restricted filesystem

10

- **CwdFS**: Working directory-relative filesystem

11

- **MountFS**: Multi-filesystem composition

12

- **ProxiedFS**: Base for filesystem decorators

13

- **Specialized implementations**: AliasFS, LazyFS, PosixFS, NoFS

14

15

## Real Filesystem Access

16

17

### NodeFS

18

19

Direct interface to the Node.js filesystem with portable path support.

20

21

```typescript { .api }

22

import { NodeFS, type PortablePath } from '@yarnpkg/fslib';

23

24

// Create a NodeFS instance

25

const nodeFs = new NodeFS();

26

27

// Standard filesystem operations

28

const content = await nodeFs.readFilePromise('/path/to/file.txt' as PortablePath, 'utf8');

29

await nodeFs.writeFilePromise('/path/to/output.txt' as PortablePath, content);

30

31

// Directory operations

32

await nodeFs.mkdirPromise('/new/directory' as PortablePath, { recursive: true });

33

const files = await nodeFs.readdirPromise('/directory' as PortablePath);

34

35

// Metadata operations

36

const stats = await nodeFs.statPromise('/file.txt' as PortablePath);

37

console.log(`File size: ${stats.size}, Modified: ${stats.mtime}`);

38

```

39

40

### NodePathFS

41

42

Compatibility wrapper that adds support for file URLs and Buffers to any filesystem. Primarily used internally for Node.js compatibility.

43

44

```typescript { .api }

45

import { NodePathFS, NodeFS, type NativePath } from '@yarnpkg/fslib';

46

47

/**

48

* Adds support for file URLs and Buffers to the wrapped baseFs

49

* Only exists for compatibility with Node's behavior - avoid direct use

50

*/

51

class NodePathFS extends ProxiedFS<NativePath, NativePath> {

52

constructor(baseFs: FakeFS<NativePath>);

53

}

54

55

// Usage (typically internal)

56

const nodeFs = new NodeFS();

57

const pathFs = new NodePathFS(nodeFs);

58

59

// Now supports file URLs and Buffers (compatibility only)

60

const fileUrl = new URL('file:///path/to/file.txt');

61

const content = await pathFs.readFilePromise(fileUrl, 'utf8');

62

63

// Also supports Buffer paths (compatibility only)

64

const bufferPath = Buffer.from('/path/to/file.txt');

65

const data = await pathFs.readFilePromise(bufferPath, 'utf8');

66

```

67

68

## Virtual and Memory-Based Filesystems

69

70

### VirtualFS

71

72

In-memory filesystem implementation for testing and isolated operations.

73

74

```typescript { .api }

75

import { VirtualFS, ppath, type PortablePath } from '@yarnpkg/fslib';

76

77

// Create a virtual filesystem

78

const vfs = new VirtualFS();

79

80

// Create directory structure

81

await vfs.mkdirPromise('/project' as PortablePath, { recursive: true });

82

await vfs.mkdirPromise('/project/src' as PortablePath);

83

84

// Write virtual files

85

await vfs.writeFilePromise('/project/package.json' as PortablePath, JSON.stringify({

86

name: 'my-project',

87

version: '1.0.0'

88

}, null, 2));

89

90

await vfs.writeFilePromise('/project/src/index.ts' as PortablePath, 'console.log("Hello World");');

91

92

// Read from virtual filesystem

93

const packageContent = await vfs.readFilePromise('/project/package.json' as PortablePath, 'utf8');

94

const packageData = JSON.parse(packageContent);

95

console.log(`Project: ${packageData.name} v${packageData.version}`);

96

97

// List virtual directory contents

98

const sourceFiles = await vfs.readdirPromise('/project/src' as PortablePath);

99

console.log('Source files:', sourceFiles);

100

```

101

102

## Security and Isolation Filesystems

103

104

### JailFS

105

106

Filesystem that restricts access to within a specific directory tree.

107

108

```typescript { .api }

109

import { JailFS, NodeFS, type PortablePath } from '@yarnpkg/fslib';

110

111

// Create a jailed filesystem

112

const baseFs = new NodeFS();

113

const jailPath = '/safe/sandbox' as PortablePath;

114

const jailedFs = new JailFS(jailPath, { baseFs });

115

116

// All operations are restricted to the jail directory

117

await jailedFs.writeFilePromise('/file.txt' as PortablePath, 'content');

118

// Actually writes to /safe/sandbox/file.txt

119

120

await jailedFs.mkdirPromise('/subdir' as PortablePath);

121

// Actually creates /safe/sandbox/subdir

122

123

// Attempts to access outside the jail will fail

124

try {

125

await jailedFs.readFilePromise('/../../../etc/passwd' as PortablePath);

126

// This will throw an error or be blocked

127

} catch (error) {

128

console.log('Access denied outside jail');

129

}

130

131

// Safe operations within the jail

132

const files = await jailedFs.readdirPromise('/' as PortablePath);

133

console.log('Files in jail:', files);

134

```

135

136

### JailFS Options

137

138

```typescript { .api }

139

import { JailFS, type PortablePath } from '@yarnpkg/fslib';

140

141

interface JailFSOptions {

142

baseFs?: FakeFS<PortablePath>;

143

}

144

145

// Custom configuration

146

const jailedFs = new JailFS('/restricted/area' as PortablePath, {

147

baseFs: customFileSystem

148

});

149

```

150

151

## Working Directory Filesystems

152

153

### CwdFS

154

155

Filesystem that operates relative to a specific working directory.

156

157

```typescript { .api }

158

import { CwdFS, NodeFS, type PortablePath } from '@yarnpkg/fslib';

159

160

// Create a filesystem rooted at a specific directory

161

const baseFs = new NodeFS();

162

const projectRoot = '/path/to/project' as PortablePath;

163

const cwdFs = new CwdFS(projectRoot, { baseFs });

164

165

// All relative paths are resolved relative to the project root

166

await cwdFs.writeFilePromise('config.json' as PortablePath, '{}');

167

// Actually writes to /path/to/project/config.json

168

169

await cwdFs.mkdirPromise('src/components' as PortablePath, { recursive: true });

170

// Creates /path/to/project/src/components

171

172

// Read files relative to the working directory

173

const configContent = await cwdFs.readFilePromise('config.json' as PortablePath, 'utf8');

174

175

// Absolute paths still work but are resolved from the working directory

176

const absoluteInCwd = await cwdFs.readFilePromise('/README.md' as PortablePath, 'utf8');

177

// Reads /path/to/project/README.md

178

```

179

180

### CwdFS Options

181

182

```typescript { .api }

183

import { CwdFS, type PortablePath } from '@yarnpkg/fslib';

184

185

interface CwdFSOptions {

186

baseFs?: FakeFS<PortablePath>;

187

}

188

189

// Custom configuration

190

const cwdFs = new CwdFS('/working/directory' as PortablePath, {

191

baseFs: virtualFileSystem

192

});

193

```

194

195

## Composite and Mounting Filesystems

196

197

### MountFS

198

199

Filesystem that can mount other filesystems at specific paths.

200

201

```typescript { .api }

202

import { MountFS, NodeFS, VirtualFS, type PortablePath } from '@yarnpkg/fslib';

203

204

// Create mount filesystem

205

const mountFs = new MountFS({ baseFs: new NodeFS() });

206

207

// Mount virtual filesystem at /virtual

208

const virtualFs = new VirtualFS();

209

await virtualFs.writeFilePromise('/data.txt' as PortablePath, 'virtual content');

210

mountFs.mount('/virtual' as PortablePath, virtualFs);

211

212

// Mount real directory at /real

213

const realFs = new NodeFS();

214

mountFs.mount('/real' as PortablePath, realFs);

215

216

// Access mounted filesystems

217

const virtualData = await mountFs.readFilePromise('/virtual/data.txt' as PortablePath, 'utf8');

218

console.log('Virtual content:', virtualData);

219

220

const realFiles = await mountFs.readdirPromise('/real' as PortablePath);

221

console.log('Real files:', realFiles);

222

223

// Unmount when done

224

mountFs.unmount('/virtual' as PortablePath);

225

```

226

227

### MountFS Types and Options

228

229

```typescript { .api }

230

import { type MountableFS, type GetMountPointFn, type MountFSOptions } from '@yarnpkg/fslib';

231

232

// Mountable filesystem interface

233

interface MountableFS extends FakeFS<PortablePath> {

234

// Additional requirements for mountable filesystems

235

}

236

237

// Function to determine mount points

238

type GetMountPointFn<T extends MountableFS> = (

239

fs: T,

240

path: PortablePath

241

) => PortablePath | null;

242

243

// Mount filesystem options

244

interface MountFSOptions<T extends MountableFS> {

245

baseFs?: FakeFS<PortablePath>;

246

getMountPoint?: GetMountPointFn<T>;

247

}

248

```

249

250

## Specialized Filesystem Implementations

251

252

### AliasFS

253

254

Filesystem that redirects specific paths to other locations.

255

256

```typescript { .api }

257

import { AliasFS, NodeFS, type PortablePath } from '@yarnpkg/fslib';

258

259

// Create filesystem with path aliasing

260

const baseFs = new NodeFS();

261

const aliasMap = new Map<PortablePath, PortablePath>();

262

aliasMap.set('/alias/target' as PortablePath, '/real/location' as PortablePath);

263

264

const aliasFs = new AliasFS('/base/path' as PortablePath, aliasMap, { baseFs });

265

266

// Access through alias

267

const content = await aliasFs.readFilePromise('/alias/target/file.txt' as PortablePath, 'utf8');

268

// Actually reads from /real/location/file.txt

269

```

270

271

### LazyFS

272

273

Filesystem with deferred initialization.

274

275

```typescript { .api }

276

import { LazyFS, NodeFS, type PortablePath } from '@yarnpkg/fslib';

277

278

// Create lazy filesystem that initializes on first use

279

const lazyFs = new LazyFS<PortablePath>(() => {

280

console.log('Initializing filesystem...');

281

return new NodeFS();

282

}, { baseFs: undefined });

283

284

// Filesystem is not initialized until first operation

285

const content = await lazyFs.readFilePromise('/file.txt' as PortablePath, 'utf8');

286

// Now the underlying NodeFS is created and used

287

```

288

289

### PosixFS

290

291

Filesystem that handles conversion between native and portable paths.

292

293

```typescript { .api }

294

import { PosixFS, type NativePath, type PortablePath } from '@yarnpkg/fslib';

295

296

// Create POSIX filesystem for cross-platform compatibility

297

const posixFs = new PosixFS();

298

299

// Works with native paths, converts internally

300

const nativePath = process.platform === 'win32' ? 'C:\\Windows\\System32' : '/usr/bin';

301

const files = await posixFs.readdirPromise(nativePath as NativePath);

302

console.log('System files:', files);

303

```

304

305

### NoFS

306

307

Filesystem that denies all operations.

308

309

```typescript { .api }

310

import { NoFS, type PortablePath } from '@yarnpkg/fslib';

311

312

// Create filesystem that throws errors for all operations

313

const noFs = new NoFS();

314

315

try {

316

await noFs.readFilePromise('/any/file.txt' as PortablePath, 'utf8');

317

} catch (error) {

318

console.log('Operation denied:', error.message);

319

}

320

321

// Useful as a placeholder or for security

322

```

323

324

## Base Classes for Custom Implementations

325

326

### ProxiedFS

327

328

Abstract base class for filesystems that proxy to another filesystem.

329

330

```typescript { .api }

331

import { ProxiedFS, type PortablePath, type NativePath } from '@yarnpkg/fslib';

332

333

// Create a custom proxied filesystem

334

class LoggingFS extends ProxiedFS<PortablePath, PortablePath> {

335

constructor(baseFs: FakeFS<PortablePath>) {

336

super(baseFs);

337

}

338

339

async readFilePromise(p: PortablePath, encoding?: BufferEncoding): Promise<Buffer | string> {

340

console.log(`Reading file: ${p}`);

341

const result = await this.baseFs.readFilePromise(p, encoding);

342

console.log(`Read ${Buffer.isBuffer(result) ? result.length : result.length} bytes/characters`);

343

return result;

344

}

345

346

async writeFilePromise(p: PortablePath, content: string | Buffer): Promise<void> {

347

console.log(`Writing file: ${p}`);

348

await this.baseFs.writeFilePromise(p, content);

349

console.log(`Write completed`);

350

}

351

352

// Other methods automatically proxy to baseFs

353

}

354

355

// Usage

356

const baseFs = new NodeFS();

357

const loggingFs = new LoggingFS(baseFs);

358

359

await loggingFs.writeFilePromise('/log/file.txt' as PortablePath, 'content');

360

// Logs: Writing file: /log/file.txt

361

// Logs: Write completed

362

```

363

364

## Advanced Usage Patterns

365

366

### Filesystem Composition

367

368

```typescript { .api }

369

import {

370

MountFS, JailFS, VirtualFS, NodeFS,

371

type PortablePath

372

} from '@yarnpkg/fslib';

373

374

// Create a complex filesystem setup

375

async function createDevelopmentEnvironment(): Promise<MountFS> {

376

const mountFs = new MountFS({ baseFs: new NodeFS() });

377

378

// Mount real project directory at /project (jailed for security)

379

const projectFs = new JailFS('/real/project/path' as PortablePath, {

380

baseFs: new NodeFS()

381

});

382

mountFs.mount('/project' as PortablePath, projectFs);

383

384

// Mount virtual filesystem for temporary files at /tmp

385

const tmpFs = new VirtualFS();

386

mountFs.mount('/tmp' as PortablePath, tmpFs);

387

388

// Mount system tools (read-only jail) at /tools

389

const toolsFs = new JailFS('/usr/local/bin' as PortablePath, {

390

baseFs: new NodeFS()

391

});

392

mountFs.mount('/tools' as PortablePath, toolsFs);

393

394

return mountFs;

395

}

396

397

// Usage

398

const devEnv = await createDevelopmentEnvironment();

399

await devEnv.writeFilePromise('/project/src/main.ts' as PortablePath, 'code');

400

await devEnv.writeFilePromise('/tmp/cache.json' as PortablePath, '{}');

401

const tools = await devEnv.readdirPromise('/tools' as PortablePath);

402

```

403

404

### Testing with Virtual Filesystems

405

406

```typescript { .api }

407

import { VirtualFS, type PortablePath } from '@yarnpkg/fslib';

408

409

// Set up test filesystem

410

async function setupTestEnvironment(): Promise<VirtualFS> {

411

const testFs = new VirtualFS();

412

413

// Create test project structure

414

await testFs.mkdirPromise('/test-project' as PortablePath, { recursive: true });

415

await testFs.mkdirPromise('/test-project/src' as PortablePath);

416

await testFs.mkdirPromise('/test-project/tests' as PortablePath);

417

418

// Add test files

419

await testFs.writeFilePromise(

420

'/test-project/package.json' as PortablePath,

421

JSON.stringify({ name: 'test-pkg', version: '1.0.0' }, null, 2)

422

);

423

424

await testFs.writeFilePromise(

425

'/test-project/src/index.ts' as PortablePath,

426

'export function hello() { return "world"; }'

427

);

428

429

await testFs.writeFilePromise(

430

'/test-project/tests/index.test.ts' as PortablePath,

431

'import { hello } from "../src"; console.assert(hello() === "world");'

432

);

433

434

return testFs;

435

}

436

437

// Use in tests

438

describe('File operations', () => {

439

let testFs: VirtualFS;

440

441

beforeEach(async () => {

442

testFs = await setupTestEnvironment();

443

});

444

445

it('should read package.json', async () => {

446

const content = await testFs.readFilePromise('/test-project/package.json' as PortablePath, 'utf8');

447

const pkg = JSON.parse(content);

448

expect(pkg.name).toBe('test-pkg');

449

});

450

});

451

```

452

453

### Migration Between Filesystems

454

455

```typescript { .api }

456

import {

457

VirtualFS, NodeFS,

458

type FakeFS, type PortablePath

459

} from '@yarnpkg/fslib';

460

461

// Copy directory tree between filesystems

462

async function copyDirectoryTree(

463

sourceFs: FakeFS<PortablePath>,

464

targetFs: FakeFS<PortablePath>,

465

sourcePath: PortablePath,

466

targetPath: PortablePath

467

): Promise<void> {

468

const entries = await sourceFs.readdirPromise(sourcePath, { withFileTypes: true });

469

470

await targetFs.mkdirPromise(targetPath, { recursive: true });

471

472

for (const entry of entries) {

473

const srcPath = ppath.join(sourcePath, entry.name);

474

const dstPath = ppath.join(targetPath, entry.name);

475

476

if (entry.isDirectory()) {

477

await copyDirectoryTree(sourceFs, targetFs, srcPath, dstPath);

478

} else if (entry.isFile()) {

479

const content = await sourceFs.readFilePromise(srcPath);

480

await targetFs.writeFilePromise(dstPath, content);

481

}

482

}

483

}

484

485

// Usage: migrate from virtual to real filesystem

486

const virtualFs = new VirtualFS();

487

const nodeFs = new NodeFS();

488

489

// ... populate virtualFs ...

490

491

await copyDirectoryTree(

492

virtualFs,

493

nodeFs,

494

'/virtual/project' as PortablePath,

495

'/real/backup' as PortablePath

496

);

497

```

498

499

## Related Documentation

500

501

- [Filesystem Abstractions](./filesystem-abstractions.md) - Base classes and interfaces these implementations extend

502

- [Path Handling](./path-handling.md) - Path utilities used by filesystem operations

503

- [Constants and Utilities](./constants-and-utilities.md) - Error handling and statistics utilities

504

- [Advanced Features](./advanced-features.md) - Advanced operations and filesystem patching