@jvens/neverthrow-fs
v1.1.0
Published
Node.js fs and fs/promises wrapped in neverthrow Result types for type-safe error handling
Downloads
163
Maintainers
Readme
@jvens/neverthrow-fs
A type-safe wrapper around Node.js fs and fs/promises APIs using neverthrow's Result and ResultAsync types for explicit error handling.
🚀 Features
- Type-safe error handling: All file system operations return
Result<T, FsError>orResultAsync<T, FsError> - Comprehensive coverage: Wraps all major
fsandfs/promisesfunctions - Detailed error types: Specific error classes for different failure scenarios (FileNotFound, PermissionDenied, etc.)
- Tree-shakeable: Import only what you need
- Dual module support: CommonJS and ESM compatible
- Full TypeScript support: Accurate type definitions included
📦 Installation
npm install @jvens/neverthrow-fs neverthrowNote: neverthrow is a peer dependency and must be installed separately.
🔧 Usage
Synchronous Operations
import { readFileSync, writeFileSync, existsSync } from '@jvens/neverthrow-fs';
// Reading a file
const result = readFileSync('/path/to/file.txt', 'utf8');
if (result.isOk()) {
console.log('File contents:', result.value);
} else {
console.error('Error reading file:', result.error.message);
console.error('Error type:', result.error.kind);
}
// Writing a file with error handling
const writeResult = writeFileSync('/path/to/output.txt', 'Hello, World!');
writeResult
.map(() => console.log('File written successfully'))
.mapErr((error) => console.error(`Failed to write file: ${error.message}`));
// Checking file existence
const exists = existsSync('/path/to/file.txt');
if (exists.isOk() && exists.value) {
console.log('File exists');
}Asynchronous Operations
import { readFile, writeFile, mkdir, stat } from '@jvens/neverthrow-fs';
// Reading a file asynchronously
const result = await readFile('/path/to/file.txt', 'utf8');
result
.map((contents) => console.log('File contents:', contents))
.mapErr((error) => console.error('Error:', error.message));
// Chaining operations
const processFile = await readFile('/input.txt', 'utf8')
.andThen(async (content) => {
const processed = content.toUpperCase();
return writeFile('/output.txt', processed);
});
if (processFile.isErr()) {
console.error('Operation failed:', processFile.error.message);
}
// Creating directories with proper error handling
const dirResult = await mkdir('/path/to/new/directory', { recursive: true });
if (dirResult.isErr()) {
if (dirResult.error.kind === 'FileAlreadyExistsError') {
console.log('Directory already exists');
} else {
console.error('Failed to create directory:', dirResult.error.message);
}
}Mixed Import Style
import * as fs from '@jvens/neverthrow-fs';
const syncResult = fs.readFileSync('/file.txt', 'utf8');
const asyncResult = await fs.readFile('/file.txt', 'utf8');🎯 Error Types
The library provides specific error types for better error handling:
import type { FsError, FsErrorKind } from '@jvens/neverthrow-fs';
// Available error types (strongly typed):
// - FileNotFoundError (ENOENT)
// - PermissionDeniedError (EACCES, EPERM)
// - DirectoryNotEmptyError (ENOTEMPTY)
// - FileAlreadyExistsError (EEXIST)
// - NotADirectoryError (ENOTDIR)
// - IsADirectoryError (EISDIR)
// - InvalidArgumentError (EINVAL)
// - IOError (other filesystem errors)
// - UnknownError (unexpected errors)
function handleError(error: FsError) {
// TypeScript will provide exhaustive checking and autocomplete
switch (error.kind) {
case 'FileNotFoundError':
console.log('File not found:', error.path);
break;
case 'PermissionDeniedError':
console.log('Permission denied for:', error.path);
break;
case 'FileAlreadyExistsError':
console.log('File already exists:', error.path);
break;
case 'DirectoryNotEmptyError':
console.log('Directory not empty:', error.path);
break;
case 'NotADirectoryError':
console.log('Not a directory:', error.path);
break;
case 'IsADirectoryError':
console.log('Is a directory:', error.path);
break;
case 'InvalidArgumentError':
console.log('Invalid argument:', error.message);
break;
case 'IOError':
console.log('I/O error:', error.message, error.code);
break;
case 'UnknownError':
console.log('Unknown error:', error.message);
break;
// TypeScript will ensure all cases are handled
}
}
// You can also use the FsErrorKind type directly
function isFileNotFound(errorKind: FsErrorKind): boolean {
return errorKind === 'FileNotFoundError';
}📚 API Reference
Synchronous Functions (from /sync)
All functions return Result<T, FsError>:
accessSync(path, mode?)- Test file permissionsappendFileSync(file, data, options?)- Append to filechmodSync(path, mode)- Change permissionschownSync(path, uid, gid)- Change ownershipcopyFileSync(src, dest, mode?)- Copy fileexistsSync(path)- Check if file existslinkSync(existingPath, newPath)- Create hard linkmkdirSync(path, options?)- Create directorymkdtempSync(prefix, options?)- Create temp directoryreaddirSync(path, options?)- Read dir contentsreadFileSync(path, options?)- Read filereadlinkSync(path, options?)- Read symlinkrealpathSync(path, options?)- Resolve pathrenameSync(oldPath, newPath)- Rename file/dirrmdirSync(path, options?)- Remove directoryrmSync(path, options?)- Remove files/dirsstatSync(path, options?)- Get file statslstatSync(path, options?)- Get file stats (no symlink follow)symlinkSync(target, path, type?)- Create symlinktruncateSync(path, len?)- Truncate fileunlinkSync(path)- Remove fileutimesSync(path, atime, mtime)- Update timestampswriteFileSync(file, data, options?)- Write file
Asynchronous Functions (from /async)
All functions return ResultAsync<T, FsError>:
access(path, mode?)- Test file permissionsappendFile(file, data, options?)- Append to filechmod(path, mode)- Change permissionschown(path, uid, gid)- Change ownershipcopyFile(src, dest, mode?)- Copy filecp(src, dest, options?)- Copy recursivelylink(existingPath, newPath)- Create hard linklchown(path, uid, gid)- Change symlink ownershiplchmod(path, mode)- Change symlink permissionslutimes(path, atime, mtime)- Update symlink timestampsmkdir(path, options?)- Create directorymkdtemp(prefix, options?)- Create temp directoryopen(path, flags?, mode?)- Open file handleopendir(path, options?)- Open directoryreaddir(path, options?)- Read dir contentsreadFile(path, options?)- Read filereadlink(path, options?)- Read symlinkrealpath(path, options?)- Resolve pathrename(oldPath, newPath)- Rename file/dirrmdir(path, options?)- Remove directoryrm(path, options?)- Remove files/dirsstat(path, options?)- Get file statslstat(path, options?)- Get file stats (no symlink follow)symlink(target, path, type?)- Create symlinktruncate(path, len?)- Truncate fileunlink(path)- Remove fileutimes(path, atime, mtime)- Update timestampswatch(filename, options?)- Watch for changeswriteFile(file, data, options?)- Write file
🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
Development Setup
# Clone the repository
git clone https://github.com/jvens/neverthrow-fs.git
cd neverthrow-fs
# Install dependencies
npm install
# Run tests
npm test
# Run tests with coverage
npm run test:coverage
# Build the package
npm run build
# Run linter
npm run lint
# Run type checking
npm run typecheck📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
🙏 Acknowledgments
- neverthrow - The excellent Result type library this package builds upon
- Node.js fs module - The underlying filesystem API
