A Node.js port of Python's os.walk for asynchronous and synchronous filesystem traversal with EventEmitter patterns
npx @tessl/cli install tessl/npm-walk@2.3.0Walk is a Node.js port of Python's os.walk that provides both asynchronous and synchronous filesystem traversal capabilities. It uses EventEmitter patterns with built-in flow control to minimize file descriptor usage, making it well-suited for traditional hard disk operations.
npm install walkconst walk = require('walk');const walk = require('walk');
// Create an asynchronous walker
const walker = walk.walk('/tmp');
walker.on('file', function (root, fileStats, next) {
console.log(root + '/' + fileStats.name);
next(); // Must call next() to continue walking
});
walker.on('end', function () {
console.log('Walk completed');
});Walk is built around several key components:
next() callback that must be called to continue processingCreates an asynchronous directory walker that traverses the filesystem using EventEmitter patterns.
/**
* Creates an asynchronous directory walker
* @param {string} path - Starting directory path to walk
* @param {WalkOptions} [options] - Configuration options
* @returns {Walker} EventEmitter instance for handling walk events
*/
function walk(path, options);Usage Example:
const walk = require('walk');
const walker = walk.walk('./my-directory', {
followLinks: false,
filters: ['node_modules', '.git']
});
walker.on('file', function (root, fileStats, next) {
console.log('Found file:', root + '/' + fileStats.name);
next();
});
walker.on('directory', function (root, dirStats, next) {
console.log('Found directory:', root + '/' + dirStats.name);
next();
});
walker.on('end', function () {
console.log('Walk completed');
});Creates a synchronous directory walker with the same API as the asynchronous version.
/**
* Creates a synchronous directory walker
* @param {string} path - Starting directory path to walk
* @param {WalkOptions} [options] - Configuration options
* @returns {Walker} EventEmitter instance for handling walk events
*/
function walkSync(path, options);Usage Example:
const walk = require('walk');
// For truly synchronous operation, use options.listeners
const walker = walk.walkSync('./my-directory', {
listeners: {
file: function (root, fileStats, next) {
console.log('Found file:', root + '/' + fileStats.name);
next();
},
directories: function (root, dirStatsArray, next) {
console.log('Found directories:', dirStatsArray.map(s => s.name));
next();
},
end: function () {
console.log('Walk completed');
}
}
});Control methods available on walker instances for pausing and resuming operations.
/**
* Pauses the walker, preventing further filesystem operations
*/
walker.pause();
/**
* Resumes a paused walker, continuing filesystem operations
*/
walker.resume();All individual node event callbacks have the signature: function (root, stat, next) {}
/**
* Emitted for any filesystem node
* @param {string} root - Current directory path
* @param {WalkStat} stat - File statistics with additional properties
* @param {function} next - Callback to continue processing
*/
walker.on('node', function (root, stat, next) {});
/**
* Emitted for each file (includes symbolic links when followLinks is true)
* @param {string} root - Current directory path
* @param {WalkStat} stat - File statistics with additional properties
* @param {function} next - Callback to continue processing
*/
walker.on('file', function (root, stat, next) {});
/**
* Emitted for each directory
* @param {string} root - Current directory path
* @param {WalkStat} stat - Directory statistics with additional properties
* @param {function} next - Callback to continue processing
*/
walker.on('directory', function (root, stat, next) {});
/**
* Emitted for symbolic links (empty when followLinks is true)
* @param {string} root - Current directory path
* @param {WalkStat} stat - Symbolic link statistics with additional properties
* @param {function} next - Callback to continue processing
*/
walker.on('symbolicLink', function (root, stat, next) {});
/**
* Emitted for block devices
* @param {string} root - Current directory path
* @param {WalkStat} stat - Block device statistics with additional properties
* @param {function} next - Callback to continue processing
*/
walker.on('blockDevice', function (root, stat, next) {});
/**
* Emitted for character devices
* @param {string} root - Current directory path
* @param {WalkStat} stat - Character device statistics with additional properties
* @param {function} next - Callback to continue processing
*/
walker.on('characterDevice', function (root, stat, next) {});
/**
* Emitted for FIFO files
* @param {string} root - Current directory path
* @param {WalkStat} stat - FIFO statistics with additional properties
* @param {function} next - Callback to continue processing
*/
walker.on('FIFO', function (root, stat, next) {});
/**
* Emitted for socket files
* @param {string} root - Current directory path
* @param {WalkStat} stat - Socket statistics with additional properties
* @param {function} next - Callback to continue processing
*/
walker.on('socket', function (root, stat, next) {});All grouped event callbacks have the signature: function (root, statsArray, next) {}
/**
* Emitted before stat operations, contains array of filenames
* @param {string} root - Current directory path
* @param {string[]} nodeNamesArray - Array of filenames in the directory
* @param {function} next - Callback to continue processing (noop for names event)
*/
walker.on('names', function (root, nodeNamesArray, next) {});
/**
* Emitted for each individual filename before stat operations
* @param {string} root - Current directory path
* @param {string} filename - Individual filename
* @param {function} next - Callback to continue processing (noop for name event)
*/
walker.on('name', function (root, filename, next) {});
/**
* Emitted for all nodes in a directory
* @param {string} root - Current directory path
* @param {WalkStat[]} statsArray - Array of all node statistics
* @param {function} next - Callback to continue processing
*/
walker.on('nodes', function (root, statsArray, next) {});
/**
* Emitted for all files in a directory
* @param {string} root - Current directory path
* @param {WalkStat[]} statsArray - Array of file statistics
* @param {function} next - Callback to continue processing
*/
walker.on('files', function (root, statsArray, next) {});
/**
* Emitted for all directories in a directory
* @param {string} root - Current directory path
* @param {WalkStat[]} statsArray - Array of directory statistics
* @param {function} next - Callback to continue processing
*/
walker.on('directories', function (root, statsArray, next) {});
/**
* Emitted for all symbolic links in a directory
* @param {string} root - Current directory path
* @param {WalkStat[]} statsArray - Array of symbolic link statistics
* @param {function} next - Callback to continue processing
*/
walker.on('symbolicLinks', function (root, statsArray, next) {});
/**
* Emitted for all block devices in a directory
* @param {string} root - Current directory path
* @param {WalkStat[]} statsArray - Array of block device statistics
* @param {function} next - Callback to continue processing
*/
walker.on('blockDevices', function (root, statsArray, next) {});
/**
* Emitted for all character devices in a directory
* @param {string} root - Current directory path
* @param {WalkStat[]} statsArray - Array of character device statistics
* @param {function} next - Callback to continue processing
*/
walker.on('characterDevices', function (root, statsArray, next) {});
/**
* Emitted for all FIFO files in a directory
* @param {string} root - Current directory path
* @param {WalkStat[]} statsArray - Array of FIFO statistics
* @param {function} next - Callback to continue processing
*/
walker.on('FIFOs', function (root, statsArray, next) {});
/**
* Emitted for all socket files in a directory
* @param {string} root - Current directory path
* @param {WalkStat[]} statsArray - Array of socket statistics
* @param {function} next - Callback to continue processing
*/
walker.on('sockets', function (root, statsArray, next) {});/**
* Collection of all errors encountered in a directory
* @param {string} root - Current directory path
* @param {WalkStat[]} errorStatsArray - Array of error statistics
* @param {function} next - Callback to continue processing
*/
walker.on('errors', function (root, errorStatsArray, next) {});
/**
* Error when fs.stat/lstat fails
* @param {string} root - Current directory path
* @param {WalkStat} stat - Statistics object with error property
* @param {function} next - Callback to continue processing
*/
walker.on('nodeError', function (root, stat, next) {});
/**
* Error when fs.readdir fails but stat succeeded
* @param {string} root - Current directory path
* @param {WalkStat} stat - Statistics object with error property
* @param {function} next - Callback to continue processing
*/
walker.on('directoryError', function (root, stat, next) {});/**
* Emitted when walking is complete
*/
walker.on('end', function () {});/**
* Configuration options for walk operations
*/
interface WalkOptions {
/** Whether to follow symbolic links (default: false) */
followLinks?: boolean;
/** Array of directory names or regex patterns to filter out */
filters?: (string | RegExp)[];
/** Event listeners for synchronous walker operations */
listeners?: WalkListeners;
}
/**
* Event listeners for synchronous walker operations
*/
interface WalkListeners {
names?: (root: string, nodeNamesArray: string[], next: () => void) => void;
name?: (root: string, filename: string, next: () => void) => void;
node?: (root: string, stat: WalkStat, next: () => void) => void;
file?: (root: string, stat: WalkStat, next: () => void) => void;
directory?: (root: string, stat: WalkStat, next: () => void) => void;
symbolicLink?: (root: string, stat: WalkStat, next: () => void) => void;
blockDevice?: (root: string, stat: WalkStat, next: () => void) => void;
characterDevice?: (root: string, stat: WalkStat, next: () => void) => void;
FIFO?: (root: string, stat: WalkStat, next: () => void) => void;
socket?: (root: string, stat: WalkStat, next: () => void) => void;
nodes?: (root: string, statsArray: WalkStat[], next: () => void) => void;
files?: (root: string, statsArray: WalkStat[], next: () => void) => void;
directories?: (root: string, statsArray: WalkStat[], next: () => void) => void;
symbolicLinks?: (root: string, statsArray: WalkStat[], next: () => void) => void;
blockDevices?: (root: string, statsArray: WalkStat[], next: () => void) => void;
characterDevices?: (root: string, statsArray: WalkStat[], next: () => void) => void;
FIFOs?: (root: string, statsArray: WalkStat[], next: () => void) => void;
sockets?: (root: string, statsArray: WalkStat[], next: () => void) => void;
errors?: (root: string, errorStatsArray: WalkStat[], next: () => void) => void;
nodeError?: (root: string, stat: WalkStat, next: () => void) => void;
directoryError?: (root: string, stat: WalkStat, next: () => void) => void;
end?: () => void;
}
/**
* Enhanced file statistics object extending Node.js fs.Stats
*/
interface WalkStat {
/** The filename */
name: string;
/** File type ('file', 'directory', 'symbolicLink', etc.) */
type: string;
/** Error object if stat operation failed */
error?: Error;
// Standard fs.Stats properties
/** Device ID */
dev: number;
/** File mode (permissions and file type) */
mode: number;
/** Number of hard links */
nlink: number;
/** User ID */
uid: number;
/** Group ID */
gid: number;
/** Device ID (if special file) */
rdev: number;
/** Block size for filesystem I/O */
blksize: number;
/** Inode number */
ino: number;
/** Total size in bytes */
size: number;
/** Number of 512-byte blocks allocated */
blocks: number;
/** Access time */
atime: Date;
/** Modification time */
mtime: Date;
/** Change time */
ctime: Date;
/** Birth time (creation time) */
birthtime: Date;
}
/**
* Walker instance extending EventEmitter
*/
interface Walker extends EventEmitter {
/** Pauses the walker */
pause(): void;
/** Resumes a paused walker */
resume(): void;
}