Directory traversal library that walks file system trees with multiple interface options including callback, event emitter, synchronous, and promise-based patterns.
—
Event emitter interface providing comprehensive file system events and flow control methods for directory traversal operations.
The emitter returned by walkdir provides fine-grained control over the traversal process.
/**
* Extended EventEmitter with walkdir-specific control methods
*/
interface WalkEmitter extends EventEmitter {
/** Stop the walk immediately and prevent further events */
end(): void;
/** Alias for end() - stop the walk immediately */
stop(): void;
/** Pause event emission while keeping traversal active */
pause(): void;
/** Resume event emission after pause */
resume(): void;
/** Ignore specific paths during traversal */
ignore(paths: string | string[]): void;
}Usage Examples:
const walkdir = require('walkdir');
const emitter = walkdir('./my-directory');
// Stop after finding 100 files
let fileCount = 0;
emitter.on('file', (path, stat) => {
fileCount++;
if (fileCount >= 100) {
emitter.end(); // Stop immediately
}
});
// Pause and resume based on system load
emitter.on('directory', (path, stat) => {
if (isSystemBusy()) {
emitter.pause();
setTimeout(() => emitter.resume(), 1000);
}
});
// Ignore specific directories dynamically
emitter.on('directory', (path, stat) => {
if (path.includes('node_modules') || path.includes('.git')) {
emitter.ignore(path); // Skip this directory and all children
}
});Events emitted for different types of file system objects found during traversal.
/**
* All events follow the pattern: (path: string, stat: fs.Stats, depth: number)
*/
/** Emitted for every file system object found */
emitter.on('path', (path, stat, depth) => {});
/** Emitted only for regular files */
emitter.on('file', (path, stat, depth) => {});
/** Emitted only for directories */
emitter.on('directory', (path, stat, depth) => {});
/** Emitted only for symbolic links */
emitter.on('link', (path, stat, depth) => {});
/** Emitted for the initial target directory (if it's a directory) */
emitter.on('targetdirectory', (path, stat, depth) => {});
/** Emitted when a directory is empty */
emitter.on('empty', (path, stat, depth) => {});
/** Emitted when traversal completes successfully */
emitter.on('end', () => {});Usage Examples:
const emitter = walkdir('./project');
// Process different file types
emitter.on('file', (path, stat, depth) => {
if (path.endsWith('.js')) {
console.log('JavaScript file:', path, 'at depth', depth);
}
});
emitter.on('directory', (path, stat, depth) => {
console.log('Directory:', path, 'contains', stat.size, 'entries');
});
emitter.on('link', (path, stat, depth) => {
console.log('Symbolic link found:', path);
});
// Handle completion
emitter.on('end', () => {
console.log('Directory traversal completed');
});
// Track progress
let totalItems = 0;
emitter.on('path', () => {
totalItems++;
if (totalItems % 100 === 0) {
console.log(`Processed ${totalItems} items...`);
}
});Events for special file system objects like sockets, fifos, and devices.
/** Emitted for socket descriptors */
emitter.on('socket', (path, stat, depth) => {});
/** Emitted for FIFO/named pipes */
emitter.on('fifo', (path, stat, depth) => {});
/** Emitted for block devices */
emitter.on('blockdevice', (path, stat, depth) => {});
/** Emitted for character devices */
emitter.on('characterdevice', (path, stat, depth) => {});Usage Example:
const emitter = walkdir('/dev');
emitter.on('blockdevice', (path, stat) => {
console.log('Block device (disk):', path);
});
emitter.on('characterdevice', (path, stat) => {
console.log('Character device (terminal/tty):', path);
});
emitter.on('socket', (path, stat) => {
console.log('Socket found:', path);
});Error handling events for various failure scenarios during traversal.
/** Emitted for fatal errors reading the target directory */
emitter.on('error', (error) => {});
/** Emitted for non-fatal errors reading nested paths */
emitter.on('fail', (path, error) => {});
/** Emitted when maximum depth is reached */
emitter.on('maxdepth', (path, stat, depth) => {});Error Handling Examples:
const emitter = walkdir('./some-directory');
// Handle fatal errors (target directory issues)
emitter.on('error', (error) => {
console.error('Fatal error - cannot read target directory:', error.message);
process.exit(1);
});
// Handle non-fatal errors (permission issues, corrupt files, etc.)
emitter.on('fail', (path, error) => {
console.warn('Could not access path:', path, '-', error.message);
// Continue processing other paths
});
// Handle depth limits
emitter.on('maxdepth', (path, stat, depth) => {
console.log('Reached maximum depth at:', path, 'depth:', depth);
// Note: traversal continues but won't go deeper into this path
});
// Graceful error handling
let errorCount = 0;
emitter.on('fail', (path, error) => {
errorCount++;
if (errorCount > 10) {
console.warn('Too many errors, stopping traversal');
emitter.end();
}
});Methods for controlling the traversal process dynamically.
/**
* Stop the walk immediately
* No more events will be emitted after calling end()
*/
emitter.end();
/**
* Alias for end() - stop the walk immediately
* Same functionality as end()
*/
emitter.stop();
/**
* Pause event emission
* Traversal continues but events are queued until resume()
*/
emitter.pause();
/**
* Resume event emission after pause
* Queued events will be emitted in order
*/
emitter.resume();
/**
* Ignore specific paths during traversal
* Ignored directories will not be entered or have children processed
* @param {string|string[]} paths - Path or array of paths to ignore
*/
emitter.ignore(paths);Flow Control Examples:
const emitter = walkdir('./large-project');
// Conditional stopping
emitter.on('file', (path, stat) => {
if (path.endsWith('.exe') && stat.size > 100 * 1024 * 1024) {
console.log('Found large executable, stopping scan');
emitter.end();
}
});
// Throttling with pause/resume
let processedCount = 0;
emitter.on('path', (path, stat) => {
processedCount++;
// Pause every 1000 items to prevent overwhelming
if (processedCount % 1000 === 0) {
emitter.pause();
setTimeout(() => {
console.log(`Processed ${processedCount} items, resuming...`);
emitter.resume();
}, 100);
}
});
// Dynamic path ignoring
const ignoredPaths = [];
emitter.on('directory', (path, stat) => {
if (path.includes('cache') || path.includes('temp')) {
ignoredPaths.push(path);
emitter.ignore(path);
console.log('Ignoring cache/temp directory:', path);
}
});
// Bulk ignore patterns
emitter.on('targetdirectory', () => {
// Ignore common build/cache directories upfront
emitter.ignore([
'./node_modules',
'./.git',
'./build',
'./dist',
'./.cache'
]);
});Common patterns for combining events and control methods.
// Progress reporting with early termination
const emitter = walkdir('./project');
let startTime = Date.now();
let itemCount = 0;
emitter.on('path', (path, stat) => {
itemCount++;
// Progress every 500 items
if (itemCount % 500 === 0) {
const elapsed = (Date.now() - startTime) / 1000;
console.log(`${itemCount} items processed in ${elapsed}s`);
}
// Stop after 10 seconds
if (Date.now() - startTime > 10000) {
console.log('Time limit reached, stopping');
emitter.end();
}
});
emitter.on('end', () => {
const elapsed = (Date.now() - startTime) / 1000;
console.log(`Completed: ${itemCount} items in ${elapsed}s`);
});Install with Tessl CLI
npx tessl i tessl/npm-walkdir