or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

core-filesystem.mdhelpers.mdindex.md

helpers.mddocs/

0

# Helper Classes and Utilities

1

2

File statistics, directory entries, and utility classes available through the fs object for working with file system metadata and operations.

3

4

## Core Imports

5

6

```typescript

7

import { fs } from "memfs";

8

```

9

10

## Capabilities

11

12

### File Statistics

13

14

Comprehensive file and directory statistics matching Node.js Stats interface. Accessible via the fs.Stats constructor or returned by stat operations.

15

16

```typescript { .api }

17

/**

18

* File statistics class providing metadata about files and directories

19

* Accessible through fs.Stats constructor or returned by fs.statSync(), etc.

20

*/

21

interface Stats<T = number | bigint> {

22

// File size and identification

23

size: T;

24

ino: T;

25

mode: T;

26

nlink: T;

27

28

// Ownership and permissions

29

uid: T;

30

gid: T;

31

rdev: T;

32

33

// Timestamps

34

atime: Date;

35

mtime: Date;

36

ctime: Date;

37

birthtime: Date;

38

39

// Timestamp numbers (for compatibility)

40

atimeMs: T;

41

mtimeMs: T;

42

ctimeMs: T;

43

birthtimeMs: T;

44

45

// File type detection methods

46

isFile(): boolean;

47

isDirectory(): boolean;

48

isSymbolicLink(): boolean;

49

isSocket(): boolean;

50

isFIFO(): boolean;

51

isCharacterDevice(): boolean;

52

isBlockDevice(): boolean;

53

54

// BigInt support

55

isBigIntStats(): this is Stats<bigint>;

56

}

57

58

/**

59

* File system statistics - returned by fs.statfsSync()

60

*/

61

interface StatFs<T = number | bigint> {

62

type: T;

63

bsize: T;

64

blocks: T;

65

bfree: T;

66

bavail: T;

67

files: T;

68

ffree: T;

69

}

70

```

71

72

**Usage Examples:**

73

74

```typescript

75

import { fs } from "memfs";

76

77

// Create test files

78

fs.writeFileSync('/data.txt', 'Hello World!');

79

fs.mkdirSync('/folder');

80

fs.symlinkSync('./data.txt', '/link.txt');

81

82

// Get file statistics

83

const fileStats = fs.statSync('/data.txt');

84

console.log('File size:', fileStats.size);

85

console.log('Is file:', fileStats.isFile()); // true

86

console.log('Is directory:', fileStats.isDirectory()); // false

87

console.log('Mode:', fileStats.mode.toString(8)); // octal permissions

88

console.log('Modified:', fileStats.mtime);

89

90

// Directory statistics

91

const dirStats = fs.statSync('/folder');

92

console.log('Directory size:', dirStats.size);

93

console.log('Is directory:', dirStats.isDirectory()); // true

94

95

// Symlink statistics (lstat vs stat)

96

const linkStats = fs.lstatSync('/link.txt'); // stats of the link itself

97

const targetStats = fs.statSync('/link.txt'); // stats of the target file

98

console.log('Link is symlink:', linkStats.isSymbolicLink()); // true

99

console.log('Target is file:', targetStats.isFile()); // true

100

101

// BigInt statistics

102

const bigintStats = fs.statSync('/data.txt', { bigint: true });

103

console.log('BigInt size:', typeof bigintStats.size); // 'bigint'

104

console.log('Is BigInt stats:', bigintStats.isBigIntStats()); // true

105

106

// File system statistics

107

const fsStats = fs.statfsSync('/');

108

console.log('Block size:', fsStats.bsize);

109

console.log('Total blocks:', fsStats.blocks);

110

console.log('Free blocks:', fsStats.bfree);

111

```

112

113

### Directory Entries

114

115

Directory entry objects providing file type and name information.

116

117

```typescript { .api }

118

/**

119

* Directory entry interface representing items found in directory listings

120

* Returned by fs.readdirSync() with withFileTypes: true option

121

*/

122

interface Dirent {

123

// Entry name and path

124

name: string;

125

path?: string;

126

127

// File type detection methods (same as Stats)

128

isFile(): boolean;

129

isDirectory(): boolean;

130

isSymbolicLink(): boolean;

131

isSocket(): boolean;

132

isFIFO(): boolean;

133

isCharacterDevice(): boolean;

134

isBlockDevice(): boolean;

135

}

136

```

137

138

**Usage Examples:**

139

140

```typescript

141

import { fs } from "memfs";

142

143

// Set up directory structure

144

fs.mkdirSync('/app');

145

fs.writeFileSync('/app/index.js', 'console.log("Hello");');

146

fs.writeFileSync('/app/package.json', '{"name": "app"}');

147

fs.mkdirSync('/app/src');

148

fs.symlinkSync('./index.js', '/app/main.js');

149

150

// Get directory entries with file types

151

const entries = fs.readdirSync('/app', { withFileTypes: true });

152

153

entries.forEach(entry => {

154

console.log(`${entry.name}:`);

155

156

if (entry.isFile()) {

157

console.log(' Type: File');

158

} else if (entry.isDirectory()) {

159

console.log(' Type: Directory');

160

} else if (entry.isSymbolicLink()) {

161

console.log(' Type: Symbolic Link');

162

}

163

164

// Optional: check path property if available

165

if (entry.path) {

166

console.log(' Path:', entry.path);

167

}

168

});

169

170

// Filter entries by type

171

const files = entries.filter(entry => entry.isFile());

172

const directories = entries.filter(entry => entry.isDirectory());

173

const symlinks = entries.filter(entry => entry.isSymbolicLink());

174

175

console.log('Files:', files.map(f => f.name));

176

console.log('Directories:', directories.map(d => d.name));

177

console.log('Symlinks:', symlinks.map(s => s.name));

178

179

// Recursive directory traversal

180

function listAllFiles(dirPath: string, prefix = '') {

181

const entries = fs.readdirSync(dirPath, { withFileTypes: true });

182

183

entries.forEach(entry => {

184

const fullPath = `${dirPath}/${entry.name}`;

185

console.log(`${prefix}${entry.name}`);

186

187

if (entry.isDirectory()) {

188

listAllFiles(fullPath, prefix + ' ');

189

}

190

});

191

}

192

193

listAllFiles('/app');

194

```

195

196

### File Handles

197

198

Promise-based file handle interface for advanced file operations.

199

200

```typescript { .api }

201

/**

202

* File handle class for promise-based file operations

203

*/

204

export class FileHandle extends EventEmitter {

205

// File descriptor

206

readonly fd: number;

207

208

// File operations

209

appendFile(data: string | Buffer, options?: { encoding?: BufferEncoding; mode?: number; flag?: string }): Promise<void>;

210

chmod(mode: string | number): Promise<void>;

211

chown(uid: number, gid: number): Promise<void>;

212

close(): Promise<void>;

213

datasync(): Promise<void>;

214

sync(): Promise<void>;

215

216

// Reading operations

217

read<T extends ArrayBufferView>(

218

buffer: T,

219

offset?: number,

220

length?: number,

221

position?: number

222

): Promise<{ bytesRead: number; buffer: T }>;

223

224

readFile(options?: { encoding?: BufferEncoding | null; flag?: string }): Promise<string | Buffer>;

225

226

readv(buffers: readonly ArrayBufferView[], position?: number): Promise<ReadVResult>;

227

228

// File metadata

229

stat(options?: { bigint?: boolean }): Promise<Stats>;

230

truncate(len?: number): Promise<void>;

231

utimes(atime: string | number | Date, mtime: string | number | Date): Promise<void>;

232

233

// Writing operations

234

write<T extends ArrayBufferView>(

235

buffer: T,

236

offset?: number,

237

length?: number,

238

position?: number

239

): Promise<{ bytesWritten: number; buffer: T }>;

240

241

write(data: string, position?: number, encoding?: BufferEncoding): Promise<{ bytesWritten: number; buffer: string }>;

242

243

writeFile(data: string | Buffer, options?: { encoding?: BufferEncoding; mode?: number; flag?: string }): Promise<void>;

244

245

writev(buffers: readonly ArrayBufferView[], position?: number): Promise<WriteVResult>;

246

}

247

248

// Result types for vectored I/O

249

export interface ReadVResult {

250

bytesRead: number;

251

buffers: ArrayBufferView[];

252

}

253

254

export interface WriteVResult {

255

bytesWritten: number;

256

buffers: ArrayBufferView[];

257

}

258

```

259

260

**Usage Examples:**

261

262

```typescript

263

import { fs } from "memfs";

264

265

async function fileHandleOperations() {

266

// Open file handle

267

const fileHandle = await fs.promises.open('/data.txt', 'w+');

268

269

try {

270

// Write data

271

await fileHandle.writeFile('Hello World!\nSecond line\n');

272

273

// Read data

274

const content = await fileHandle.readFile('utf8');

275

console.log('Content:', content);

276

277

// Buffer-based operations

278

const buffer = Buffer.alloc(5);

279

const readResult = await fileHandle.read(buffer, 0, 5, 0);

280

console.log('Read:', readResult.bytesRead, 'bytes:', buffer.toString());

281

282

// Write buffer

283

const writeBuffer = Buffer.from('New content');

284

const writeResult = await fileHandle.write(writeBuffer, 0, writeBuffer.length, 0);

285

console.log('Wrote:', writeResult.bytesWritten, 'bytes');

286

287

// File metadata operations

288

await fileHandle.chmod(0o644);

289

await fileHandle.utimes(new Date(), new Date());

290

291

const stats = await fileHandle.stat();

292

console.log('File size:', stats.size);

293

294

// Vectored I/O

295

const buffers = [Buffer.from('Hello '), Buffer.from('World!')];

296

const writevResult = await fileHandle.writev(buffers);

297

console.log('Vectored write:', writevResult.bytesWritten, 'bytes');

298

299

// Sync operations

300

await fileHandle.datasync(); // Sync data only

301

await fileHandle.sync(); // Sync data and metadata

302

303

} finally {

304

// Always close file handle

305

await fileHandle.close();

306

}

307

}

308

309

// File handle with error handling

310

async function safeFileOperations() {

311

let fileHandle;

312

try {

313

fileHandle = await fs.promises.open('/safe-file.txt', 'w');

314

await fileHandle.writeFile('Safe content');

315

} catch (error) {

316

console.error('File operation failed:', error);

317

} finally {

318

if (fileHandle) {

319

await fileHandle.close();

320

}

321

}

322

}

323

```

324

325

### Directory Iterator

326

327

Directory class for iterating over directory contents.

328

329

```typescript { .api }

330

/**

331

* Directory iterator class for asynchronous directory traversal

332

*/

333

export class Dir {

334

readonly path: string;

335

336

/**

337

* Read next directory entry asynchronously

338

* @returns Promise resolving to next Dirent or null if end reached

339

*/

340

read(): Promise<Dirent | null>;

341

342

/**

343

* Read next directory entry synchronously

344

* @returns Next Dirent or null if end reached

345

*/

346

readSync(): Dirent | null;

347

348

/**

349

* Close directory iterator asynchronously

350

* @returns Promise that resolves when closed

351

*/

352

close(): Promise<void>;

353

354

/**

355

* Close directory iterator synchronously

356

*/

357

closeSync(): void;

358

359

/**

360

* Async iterator interface

361

*/

362

[Symbol.asyncIterator](): AsyncIterableIterator<Dirent>;

363

}

364

```

365

366

**Usage Examples:**

367

368

```typescript

369

import { fs } from "memfs";

370

371

async function directoryIteration() {

372

// Set up directory

373

fs.mkdirSync('/items');

374

fs.writeFileSync('/items/file1.txt', 'content1');

375

fs.writeFileSync('/items/file2.txt', 'content2');

376

fs.mkdirSync('/items/subdir');

377

378

// Open directory

379

const dir = await fs.promises.opendir('/items');

380

381

try {

382

// Manual iteration

383

let entry;

384

while ((entry = await dir.read()) !== null) {

385

console.log(`${entry.name}: ${entry.isFile() ? 'file' : 'directory'}`);

386

}

387

} finally {

388

await dir.close();

389

}

390

391

// Async iterator (recommended)

392

const dir2 = await fs.promises.opendir('/items');

393

try {

394

for await (const entry of dir2) {

395

console.log(`Async: ${entry.name}`);

396

397

if (entry.isFile()) {

398

const content = fs.readFileSync(`/items/${entry.name}`, 'utf8');

399

console.log(` Content: ${content}`);

400

}

401

}

402

} finally {

403

await dir2.close();

404

}

405

406

// Synchronous directory iteration

407

const dirSync = fs.opendirSync('/items');

408

try {

409

let entry;

410

while ((entry = dirSync.readSync()) !== null) {

411

console.log(`Sync: ${entry.name}`);

412

}

413

} finally {

414

dirSync.closeSync();

415

}

416

}

417

418

// Directory traversal with filtering

419

async function findFiles(dirPath: string, extension: string): Promise<string[]> {

420

const results: string[] = [];

421

const dir = await fs.promises.opendir(dirPath);

422

423

try {

424

for await (const entry of dir) {

425

const fullPath = `${dirPath}/${entry.name}`;

426

427

if (entry.isFile() && entry.name.endsWith(extension)) {

428

results.push(fullPath);

429

} else if (entry.isDirectory()) {

430

// Recursive search

431

const subdirResults = await findFiles(fullPath, extension);

432

results.push(...subdirResults);

433

}

434

}

435

} finally {

436

await dir.close();

437

}

438

439

return results;

440

}

441

```

442

443

### Tree Visualization

444

445

Utility functions for generating human-readable tree representations of file systems.

446

447

```typescript { .api }

448

/**

449

* Generate a tree representation of the file system

450

* @param fs File system API to use

451

* @param opts Tree generation options

452

* @returns String representation of the file system tree

453

*/

454

export function toTreeSync(fs: FsSynchronousApi, opts?: ToTreeOptions): string;

455

456

/**

457

* Options for tree generation

458

*/

459

export interface ToTreeOptions {

460

/** Root directory to start from (default: '/') */

461

dir?: string;

462

/** Tab character or string for indentation (default: '') */

463

tab?: string;

464

/** Maximum depth to traverse (default: 10) */

465

depth?: number;

466

/** Path separator character (default: '/') */

467

separator?: '/' | '\\';

468

}

469

```

470

471

**Usage Examples:**

472

473

```typescript

474

import { fs, toTreeSync } from "memfs";

475

476

// Create sample file system

477

fs.mkdirSync('/project', { recursive: true });

478

fs.writeFileSync('/project/README.md', '# My Project');

479

fs.writeFileSync('/project/package.json', '{"name": "my-project"}');

480

fs.mkdirSync('/project/src');

481

fs.writeFileSync('/project/src/index.js', 'console.log("Hello");');

482

fs.writeFileSync('/project/src/utils.js', 'module.exports = {};');

483

fs.mkdirSync('/project/tests');

484

fs.writeFileSync('/project/tests/index.test.js', 'test("works", () => {});');

485

fs.symlinkSync('../README.md', '/project/src/README.md');

486

487

// Generate tree with default options

488

const tree = toTreeSync(fs);

489

console.log('Full file system tree:');

490

console.log(tree);

491

492

// Generate tree for specific directory

493

const projectTree = toTreeSync(fs, { dir: '/project' });

494

console.log('Project tree:');

495

console.log(projectTree);

496

497

// Customize tree appearance

498

const customTree = toTreeSync(fs, {

499

dir: '/project',

500

tab: ' ', // Use 2 spaces for indentation

501

depth: 2, // Limit depth to 2 levels

502

separator: '/' // Use forward slash

503

});

504

console.log('Custom tree:');

505

console.log(customTree);

506

507

// Tree with different indentation

508

const fancyTree = toTreeSync(fs, {

509

dir: '/project',

510

tab: '│ ', // Use box drawing characters

511

depth: 3

512

});

513

console.log('Fancy tree:');

514

console.log(fancyTree);

515

516

// Utility function to print directory structure

517

function printDirectoryStructure(path: string, maxDepth = 5) {

518

console.log(`Directory structure for ${path}:`);

519

console.log(toTreeSync(fs, {

520

dir: path,

521

tab: '├─ ',

522

depth: maxDepth

523

}));

524

}

525

526

printDirectoryStructure('/project');

527

528

// Compare two directory structures

529

function compareDirectories(path1: string, path2: string) {

530

const tree1 = toTreeSync(fs, { dir: path1, tab: ' ' });

531

const tree2 = toTreeSync(fs, { dir: path2, tab: ' ' });

532

533

console.log(`${path1}:`);

534

console.log(tree1);

535

console.log(`\n${path2}:`);

536

console.log(tree2);

537

}

538

```

539

540

### Stream Classes

541

542

Stream implementations for reading and writing files.

543

544

```typescript { .api }

545

/**

546

* Readable stream for file reading

547

*/

548

export class ReadStream extends Readable {

549

readonly path: string;

550

readonly fd: number;

551

readonly flags: string;

552

readonly mode: number;

553

readonly start?: number;

554

readonly end?: number;

555

readonly autoClose: boolean;

556

557

bytesRead: number;

558

pending: boolean;

559

560

// Readable stream interface

561

_read(size: number): void;

562

_destroy(error: Error | null, callback: (error?: Error | null) => void): void;

563

}

564

565

/**

566

* Writable stream for file writing

567

*/

568

export class WriteStream extends Writable {

569

readonly path: string;

570

readonly fd: number;

571

readonly flags: string;

572

readonly mode: number;

573

readonly start?: number;

574

readonly autoClose: boolean;

575

576

bytesWritten: number;

577

pending: boolean;

578

579

// Writable stream interface

580

_write(chunk: any, encoding: BufferEncoding, callback: (error?: Error | null) => void): void;

581

_destroy(error: Error | null, callback: (error?: Error | null) => void): void;

582

}

583

```

584

585

**Usage Examples:**

586

587

```typescript

588

import { fs } from "memfs";

589

590

function streamOperations() {

591

// Create readable stream

592

fs.writeFileSync('/source.txt', 'Hello\nWorld\nFrom\nStream!');

593

const readStream = fs.createReadStream('/source.txt', { encoding: 'utf8' });

594

595

// Create writable stream

596

const writeStream = fs.createWriteStream('/destination.txt');

597

598

// Stream events

599

readStream.on('data', (chunk) => {

600

console.log('Read chunk:', chunk);

601

});

602

603

readStream.on('end', () => {

604

console.log('Reading finished');

605

});

606

607

writeStream.on('finish', () => {

608

console.log('Writing finished');

609

console.log('Bytes written:', writeStream.bytesWritten);

610

});

611

612

// Pipe streams

613

readStream.pipe(writeStream);

614

615

// Manual stream writing

616

const manualWriteStream = fs.createWriteStream('/manual.txt');

617

manualWriteStream.write('Line 1\n');

618

manualWriteStream.write('Line 2\n');

619

manualWriteStream.end('Final line\n');

620

621

// Stream with options

622

const rangeReadStream = fs.createReadStream('/source.txt', {

623

start: 5, // Start at byte 5

624

end: 10, // End at byte 10

625

encoding: 'utf8'

626

});

627

628

rangeReadStream.on('data', (chunk) => {

629

console.log('Range chunk:', chunk);

630

});

631

}

632

```

633

634

## Type Definitions

635

636

```typescript { .api }

637

// File system API interface for utilities

638

export interface FsSynchronousApi {

639

readdirSync(path: string, options?: any): string[] | Dirent[];

640

statSync(path: string, options?: any): Stats;

641

lstatSync(path: string, options?: any): Stats;

642

readFileSync(path: string, options?: any): string | Buffer;

643

readlinkSync(path: string, options?: any): string;

644

// ... other synchronous methods

645

}

646

647

// Event types for file handles and streams

648

export interface FileHandleEventMap {

649

'close': () => void;

650

'error': (error: Error) => void;

651

}

652

653

export interface StreamEventMap {

654

'data': (chunk: any) => void;

655

'end': () => void;

656

'error': (error: Error) => void;

657

'close': () => void;

658

'finish': () => void;

659

}

660

661

// Generic buffer types

662

export type BufferLike = ArrayBufferView | ArrayBuffer;

663

export type StringOrBuffer = string | Buffer;

664

```