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

constants-and-utilities.mddocs/

0

# Constants and Utilities

1

2

File mode constants, error factories, and statistics utilities that provide essential building blocks for filesystem operations.

3

4

## Overview

5

6

The @yarnpkg/fslib package provides three key utility modules:

7

- **constants**: File mode and path constants for filesystem operations

8

- **errors**: Factory functions for creating filesystem-specific errors

9

- **statUtils**: Utilities for working with file statistics and metadata

10

11

## Constants

12

13

### File Mode Constants

14

15

Standard POSIX file mode constants for working with file types and permissions.

16

17

```typescript { .api }

18

import { constants } from '@yarnpkg/fslib';

19

20

// File type mask and specific types

21

const S_IFMT = constants.S_IFMT; // 0o170000 - File type mask

22

const S_IFDIR = constants.S_IFDIR; // 0o040000 - Directory

23

const S_IFREG = constants.S_IFREG; // 0o100000 - Regular file

24

const S_IFLNK = constants.S_IFLNK; // 0o120000 - Symbolic link

25

26

// Safe timestamp constant

27

const SAFE_TIME = constants.SAFE_TIME; // 456789000 (1984-06-22T21:50:00.000Z)

28

```

29

30

#### Working with File Mode Constants

31

32

```typescript { .api }

33

import { constants, type Stats } from '@yarnpkg/fslib';

34

35

// Check file type from stats

36

function getFileType(stats: Stats): string {

37

const mode = stats.mode;

38

39

if ((mode & constants.S_IFMT) === constants.S_IFDIR) {

40

return 'directory';

41

} else if ((mode & constants.S_IFMT) === constants.S_IFREG) {

42

return 'file';

43

} else if ((mode & constants.S_IFMT) === constants.S_IFLNK) {

44

return 'symlink';

45

} else {

46

return 'other';

47

}

48

}

49

50

// Usage with filesystem operations

51

import { xfs } from '@yarnpkg/fslib';

52

53

const stats = await xfs.statPromise('/path/to/item' as PortablePath);

54

const type = getFileType(stats);

55

console.log(`Item type: ${type}`);

56

57

// Check if item is a directory

58

const isDirectory = (stats.mode & constants.S_IFMT) === constants.S_IFDIR;

59

```

60

61

### Path Constants

62

63

Predefined portable path and filename constants for common filesystem items.

64

65

```typescript { .api }

66

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

67

68

// Portable path constants

69

const root = PortablePath.root; // '/' as PortablePath

70

const dot = PortablePath.dot; // '.' as PortablePath

71

const parent = PortablePath.parent; // '..' as PortablePath

72

73

// Common filename constants

74

const home = Filename.home; // '~' as Filename

75

const nodeModules = Filename.nodeModules; // 'node_modules' as Filename

76

const packageJson = Filename.manifest; // 'package.json' as Filename

77

const yarnLock = Filename.lockfile; // 'yarn.lock' as Filename

78

const env = Filename.env; // '.env' as Filename

79

80

// Yarn-specific constants

81

const virtual = Filename.virtual; // '__virtual__' as Filename

82

const pnpCjs = Filename.pnpCjs; // '.pnp.cjs' as Filename

83

const pnpData = Filename.pnpData; // '.pnp.data.json' as Filename

84

const pnpLoader = Filename.pnpEsmLoader; // '.pnp.loader.mjs' as Filename

85

const yarnrc = Filename.rc; // '.yarnrc.yml' as Filename

86

```

87

88

#### Using Path Constants

89

90

```typescript { .api }

91

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

92

93

// Build common paths

94

const projectRoot = '/my/project' as PortablePath;

95

const nodeModulesPath = ppath.join(projectRoot, Filename.nodeModules);

96

const packageJsonPath = ppath.join(projectRoot, Filename.manifest);

97

const yarnLockPath = ppath.join(projectRoot, Filename.lockfile);

98

99

// Work with Yarn-specific paths

100

const virtualPath = ppath.join(nodeModulesPath, Filename.virtual);

101

const pnpPath = ppath.join(projectRoot, Filename.pnpCjs);

102

103

// Navigate using path constants

104

const parentDir = ppath.join(projectRoot, PortablePath.parent);

105

const currentDir = ppath.join(projectRoot, PortablePath.dot);

106

```

107

108

## Error Utilities

109

110

Factory functions for creating filesystem-specific errors with appropriate error codes and messages.

111

112

### Basic Error Factories

113

114

```typescript { .api }

115

import { errors } from '@yarnpkg/fslib';

116

117

// File and directory errors

118

const busyError = errors.EBUSY('Resource is busy');

119

const notFoundError = errors.ENOENT('File not found: /missing/file.txt');

120

const notDirError = errors.ENOTDIR('Not a directory: /file.txt');

121

const isDirError = errors.EISDIR('Is a directory: /some/directory');

122

const existsError = errors.EEXIST('File already exists: /existing/file.txt');

123

124

// Permission and access errors

125

const accessError = errors.EBADF('Bad file descriptor');

126

const invalidError = errors.EINVAL('Invalid argument provided');

127

const readOnlyError = errors.EROFS('Read-only filesystem');

128

const notEmptyError = errors.ENOTEMPTY('Directory not empty: /directory');

129

130

// Operation errors

131

const notSupportedError = errors.EOPNOTSUPP('Operation not supported');

132

const notImplementedError = errors.ENOSYS('Function not implemented', 'custom reason');

133

const dirClosedError = errors.ERR_DIR_CLOSED();

134

```

135

136

### Using Error Factories

137

138

```typescript { .api }

139

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

140

141

// Custom filesystem implementation with proper error handling

142

class CustomFS extends BasePortableFakeFS {

143

private files = new Map<string, Buffer>();

144

145

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

146

if (!this.files.has(p)) {

147

throw errors.ENOENT(`No such file: ${p}`);

148

}

149

150

const content = this.files.get(p)!;

151

return encoding && encoding !== 'buffer' ? content.toString(encoding) : content;

152

}

153

154

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

155

if (this.isReadOnly) {

156

throw errors.EROFS(`Cannot write to read-only filesystem: ${p}`);

157

}

158

159

const buffer = Buffer.isBuffer(content) ? content : Buffer.from(content);

160

this.files.set(p, buffer);

161

}

162

163

async mkdirPromise(p: PortablePath, options?: MkdirOptions): Promise<void> {

164

if (this.files.has(p)) {

165

throw errors.EEXIST(`Directory already exists: ${p}`);

166

}

167

168

if (!options?.recursive) {

169

const parent = ppath.dirname(p);

170

if (parent !== p && !this.files.has(parent)) {

171

throw errors.ENOENT(`Parent directory does not exist: ${parent}`);

172

}

173

}

174

175

this.files.set(p, Buffer.alloc(0)); // Mark as directory

176

}

177

}

178

```

179

180

### Error Code Handling

181

182

```typescript { .api }

183

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

184

185

// Robust error handling in filesystem operations

186

async function safeFileRead(path: PortablePath): Promise<string | null> {

187

try {

188

return await xfs.readFilePromise(path, 'utf8');

189

} catch (error) {

190

switch (error.code) {

191

case 'ENOENT':

192

console.log(`File not found: ${path}`);

193

return null;

194

195

case 'EACCES':

196

console.error(`Access denied: ${path}`);

197

throw errors.EACCES(`Cannot read file: ${path}`);

198

199

case 'EISDIR':

200

console.error(`Expected file but found directory: ${path}`);

201

throw errors.EISDIR(`Cannot read directory as file: ${path}`);

202

203

default:

204

console.error(`Unexpected error reading ${path}:`, error.message);

205

throw error;

206

}

207

}

208

}

209

210

// Conditional file operations based on error types

211

async function ensureFileExists(path: PortablePath, defaultContent: string): Promise<void> {

212

try {

213

await xfs.statPromise(path);

214

// File exists, nothing to do

215

} catch (error) {

216

if (error.code === 'ENOENT') {

217

// File doesn't exist, create it

218

await xfs.writeFilePromise(path, defaultContent);

219

} else {

220

// Other error, re-throw

221

throw error;

222

}

223

}

224

}

225

```

226

227

## Statistics Utilities

228

229

Utilities for working with file statistics, creating default stat objects, and comparing file metadata.

230

231

### Statistics Classes

232

233

```typescript { .api }

234

import { statUtils, type Stats, type BigIntStats, type Dirent } from '@yarnpkg/fslib';

235

236

// Directory entry with filesystem type information

237

class DirEntry<T extends Path> implements Dirent<T> {

238

constructor(

239

public name: Filename,

240

public path: T,

241

private stats: Stats

242

) {}

243

244

isFile(): boolean { return this.stats.isFile(); }

245

isDirectory(): boolean { return this.stats.isDirectory(); }

246

isBlockDevice(): boolean { return this.stats.isBlockDevice(); }

247

isCharacterDevice(): boolean { return this.stats.isCharacterDevice(); }

248

isSymbolicLink(): boolean { return this.stats.isSymbolicLink(); }

249

isFIFO(): boolean { return this.stats.isFIFO(); }

250

isSocket(): boolean { return this.stats.isSocket(); }

251

}

252

253

// File statistics entry (extends Node.js Stats)

254

class StatEntry implements Stats {

255

dev: number;

256

ino: number;

257

mode: number;

258

nlink: number;

259

uid: number;

260

gid: number;

261

rdev: number;

262

size: number;

263

blksize: number;

264

blocks: number;

265

atimeMs: number;

266

mtimeMs: number;

267

ctimeMs: number;

268

birthtimeMs: number;

269

atime: Date;

270

mtime: Date;

271

ctime: Date;

272

birthtime: Date;

273

crc?: number; // Optional CRC checksum

274

275

// Standard Stats methods...

276

}

277

```

278

279

### Statistics Constants and Utilities

280

281

```typescript { .api }

282

import { statUtils, constants } from '@yarnpkg/fslib';

283

284

// Default file mode

285

const DEFAULT_MODE = statUtils.DEFAULT_MODE; // S_IFREG | 0o644

286

287

// Create default statistics objects

288

const defaultStats = statUtils.makeDefaultStats();

289

const emptyStats = statUtils.makeEmptyStats();

290

291

// Working with stats objects

292

const stats1 = statUtils.makeDefaultStats();

293

stats1.size = 1024;

294

stats1.mode = constants.S_IFREG | 0o755;

295

296

const stats2 = statUtils.makeDefaultStats();

297

stats2.size = 1024;

298

stats2.mode = constants.S_IFREG | 0o755;

299

300

// Compare statistics objects

301

const areEqual = statUtils.areStatsEqual(stats1, stats2);

302

console.log('Stats are equal:', areEqual);

303

304

// Clear statistics (mutates object)

305

statUtils.clearStats(stats1);

306

console.log('Cleared size:', stats1.size); // 0

307

```

308

309

### Statistics Conversion

310

311

```typescript { .api }

312

import { statUtils, type Stats, type BigIntStats } from '@yarnpkg/fslib';

313

314

// Convert regular Stats to BigIntStats

315

const regularStats = statUtils.makeDefaultStats();

316

regularStats.size = 1024;

317

regularStats.mtimeMs = Date.now();

318

319

const bigIntStats: BigIntStats = statUtils.convertToBigIntStats(regularStats);

320

console.log('BigInt size:', bigIntStats.size); // 1024n

321

console.log('BigInt mtime:', bigIntStats.mtimeMs); // BigInt version

322

```

323

324

### Creating Custom Statistics

325

326

```typescript { .api }

327

import { statUtils, constants, type Stats } from '@yarnpkg/fslib';

328

329

// Create file statistics

330

function createFileStats(size: number, mtime: Date): Stats {

331

const stats = statUtils.makeDefaultStats();

332

333

stats.size = size;

334

stats.mode = constants.S_IFREG | 0o644; // Regular file, rw-r--r--

335

stats.mtime = mtime;

336

stats.mtimeMs = mtime.getTime();

337

stats.atime = mtime;

338

stats.atimeMs = mtime.getTime();

339

stats.ctime = mtime;

340

stats.ctimeMs = mtime.getTime();

341

342

return stats;

343

}

344

345

// Create directory statistics

346

function createDirectoryStats(mtime: Date): Stats {

347

const stats = statUtils.makeDefaultStats();

348

349

stats.size = 0;

350

stats.mode = constants.S_IFDIR | 0o755; // Directory, rwxr-xr-x

351

stats.mtime = mtime;

352

stats.mtimeMs = mtime.getTime();

353

stats.atime = mtime;

354

stats.atimeMs = mtime.getTime();

355

stats.ctime = mtime;

356

stats.ctimeMs = mtime.getTime();

357

358

return stats;

359

}

360

361

// Usage

362

const fileStats = createFileStats(2048, new Date());

363

const dirStats = createDirectoryStats(new Date());

364

365

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

366

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

367

```

368

369

## Integration Examples

370

371

### Comprehensive File Operations

372

373

```typescript { .api }

374

import {

375

constants, errors, statUtils, xfs, ppath,

376

type PortablePath, type Stats

377

} from '@yarnpkg/fslib';

378

379

// Enhanced file information utility

380

async function getFileInfo(path: PortablePath): Promise<{

381

path: PortablePath;

382

type: string;

383

size: number;

384

mode: string;

385

exists: boolean;

386

readable: boolean;

387

writable: boolean;

388

}> {

389

try {

390

const stats = await xfs.statPromise(path);

391

392

// Determine file type using constants

393

let type: string;

394

if ((stats.mode & constants.S_IFMT) === constants.S_IFDIR) {

395

type = 'directory';

396

} else if ((stats.mode & constants.S_IFMT) === constants.S_IFREG) {

397

type = 'file';

398

} else if ((stats.mode & constants.S_IFMT) === constants.S_IFLNK) {

399

type = 'symlink';

400

} else {

401

type = 'other';

402

}

403

404

// Format mode as octal string

405

const mode = (stats.mode & 0o777).toString(8).padStart(3, '0');

406

407

// Test access permissions

408

let readable = false;

409

let writable = false;

410

411

try {

412

await xfs.accessPromise(path, constants.R_OK);

413

readable = true;

414

} catch {}

415

416

try {

417

await xfs.accessPromise(path, constants.W_OK);

418

writable = true;

419

} catch {}

420

421

return {

422

path,

423

type,

424

size: stats.size,

425

mode,

426

exists: true,

427

readable,

428

writable

429

};

430

431

} catch (error) {

432

if (error.code === 'ENOENT') {

433

return {

434

path,

435

type: 'none',

436

size: 0,

437

mode: '000',

438

exists: false,

439

readable: false,

440

writable: false

441

};

442

}

443

throw error;

444

}

445

}

446

447

// Usage

448

const info = await getFileInfo('/path/to/file.txt' as PortablePath);

449

console.log(`${info.path}: ${info.type} (${info.mode}) ${info.size} bytes`);

450

```

451

452

### Safe Timestamp Operations

453

454

```typescript { .api }

455

import { constants, statUtils, type Stats } from '@yarnpkg/fslib';

456

457

// Use safe timestamp for reproducible builds

458

function createReproducibleStats(size: number): Stats {

459

const stats = statUtils.makeDefaultStats();

460

461

stats.size = size;

462

stats.mode = constants.S_IFREG | 0o644;

463

464

// Use safe timestamp for reproducibility

465

const safeTime = new Date(constants.SAFE_TIME * 1000);

466

stats.mtime = safeTime;

467

stats.mtimeMs = constants.SAFE_TIME * 1000;

468

stats.atime = safeTime;

469

stats.atimeMs = constants.SAFE_TIME * 1000;

470

stats.ctime = safeTime;

471

stats.ctimeMs = constants.SAFE_TIME * 1000;

472

473

return stats;

474

}

475

476

// Compare file timestamps safely

477

function compareFileTimestamps(stats1: Stats, stats2: Stats): number {

478

const time1 = Math.floor(stats1.mtimeMs / 1000);

479

const time2 = Math.floor(stats2.mtimeMs / 1000);

480

481

if (time1 < time2) return -1;

482

if (time1 > time2) return 1;

483

return 0;

484

}

485

```

486

487

### Error Context Enhancement

488

489

```typescript { .api }

490

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

491

492

// Enhanced error factory with context

493

class FileSystemError extends Error {

494

constructor(

495

public code: string,

496

message: string,

497

public path?: PortablePath,

498

public operation?: string

499

) {

500

super(message);

501

this.name = 'FileSystemError';

502

}

503

}

504

505

// Create contextual errors

506

function createContextualError(

507

operation: string,

508

path: PortablePath,

509

originalError: Error

510

): FileSystemError {

511

const message = `${operation} failed for ${path}: ${originalError.message}`;

512

return new FileSystemError(originalError.code || 'UNKNOWN', message, path, operation);

513

}

514

515

// Usage in filesystem operations

516

async function safeOperation<T>(

517

operation: string,

518

path: PortablePath,

519

fn: () => Promise<T>

520

): Promise<T> {

521

try {

522

return await fn();

523

} catch (error) {

524

throw createContextualError(operation, path, error);

525

}

526

}

527

528

// Example usage

529

try {

530

await safeOperation('read', '/missing/file.txt' as PortablePath, async () => {

531

return await xfs.readFilePromise('/missing/file.txt' as PortablePath, 'utf8');

532

});

533

} catch (error) {

534

console.error(`Operation failed: ${error.operation} on ${error.path}`);

535

console.error(`Error: ${error.message}`);

536

}

537

```

538

539

## Related Documentation

540

541

- [Filesystem Abstractions](./filesystem-abstractions.md) - Base classes that use these constants and utilities

542

- [Filesystem Implementations](./filesystem-implementations.md) - Concrete implementations using error handling

543

- [Path Handling](./path-handling.md) - Path constants and utilities

544

- [Advanced Features](./advanced-features.md) - Advanced operations building on these foundations