Directory traversal library that walks file system trees with multiple interface options including callback, event emitter, synchronous, and promise-based patterns.
—
Modern async/await compatible interface that returns promises for directory traversal operations.
Walk directory tree and return a promise that resolves with all discovered paths.
/**
* Walk directory tree and return promise of results
* @param {string} path - Directory path to walk
* @param {WalkOptions} [options] - Walk configuration options
* @param {WalkEventListener} [eventListener] - Optional callback for each path found
* @returns {Promise<string[]|Object<string,fs.Stats>>} - Promise resolving to paths array or stats object
*/
function walkdir.async(path, options, eventListener);Promise Resolution:
string[] - Array of all discovered pathsreturn_object: true: Resolves to {[path]: fs.Stats} - Object with paths as keys and stat objects as valuesno_return: true: Resolves to undefined after completionUsage Examples:
const walkdir = require('walkdir');
// Basic async/await usage
async function listFiles() {
try {
const paths = await walkdir.async('./my-directory');
console.log('Found', paths.length, 'items');
return paths;
} catch (error) {
console.error('Failed to walk directory:', error);
}
}
// Promise chain syntax
walkdir.async('./src')
.then(paths => {
const jsFiles = paths.filter(p => p.endsWith('.js'));
console.log('JavaScript files:', jsFiles);
})
.catch(error => {
console.error('Walk failed:', error);
});
// With event listener callback
const paths = await walkdir.async('./project', (path, stat) => {
if (stat.isFile() && stat.size > 1024 * 1024) {
console.log('Large file found:', path);
}
});
// Return object format
const stats = await walkdir.async('./project', { return_object: true });
for (const [path, stat] of Object.entries(stats)) {
console.log(path, 'modified:', stat.mtime);
}Configure async behavior with comprehensive options.
/**
* Walk directory tree with specific options and return promise
* @param {string} path - Directory path to walk
* @param {WalkOptions} options - Configuration options
* @param {WalkEventListener} [eventListener] - Optional callback for each path
* @returns {Promise<string[]|Object<string,fs.Stats>|undefined>} - Promise resolving based on options
*/
function walkdir.async(path, options, eventListener);Advanced Usage Examples:
// Depth-limited traversal
const shallowPaths = await walkdir.async('./deep-directory', {
max_depth: 3
});
// Custom filtering with promise-based filter
const filteredPaths = await walkdir.async('./src', {
filter: async (dir, files) => {
// Async filter - could involve file system checks, database lookups, etc.
const results = [];
for (const file of files) {
if (file.endsWith('.js') || file.endsWith('.ts')) {
results.push(file);
}
}
return results;
}
});
// Memory-optimized async traversal
await walkdir.async('/var/log', { no_return: true }, (path, stat) => {
// Process each path immediately without building result array
if (stat.isFile() && path.endsWith('.log')) {
console.log('Log file:', path, 'Size:', stat.size);
}
});
// Follow symlinks
const allPaths = await walkdir.async('./project', {
follow_symlinks: true,
max_depth: 10 // Prevent infinite loops
});
// Custom fs implementation
const gracefulFs = require('graceful-fs');
const paths = await walkdir.async('./directory', {
fs: gracefulFs // Use graceful-fs for better error handling
});The async function provides detailed error handling through promise rejection.
/**
* Promise rejection scenarios:
* - Target directory doesn't exist or can't be accessed
* - Permissions error on initial path
* - Filter function throws an error
* - Custom fs implementation throws an error
*/Error Handling Examples:
try {
const paths = await walkdir.async('./nonexistent');
} catch (error) {
console.error('Directory access failed:', error.message);
// Error includes details about the failing path
}
// Handle nested path failures gracefully
const paths = await walkdir.async('./mixed-permissions', (path, stat) => {
console.log('Accessible path:', path);
});
// Note: nested permission errors don't cause promise rejection
// They're handled by emitting 'fail' events internally
// Monitor for nested failures with event listener
const emitter = walkdir('./mixed-permissions');
emitter.on('fail', (path, error) => {
console.warn('Could not access:', path, error.message);
});
const paths = await walkdir.async('./mixed-permissions');The async function can be combined with event listeners for real-time processing.
async function processLargeDirectory() {
let processedCount = 0;
const paths = await walkdir.async('./huge-directory', (path, stat) => {
processedCount++;
if (processedCount % 1000 === 0) {
console.log(`Processed ${processedCount} items so far...`);
}
// Real-time processing
if (stat.isFile() && path.endsWith('.txt')) {
// Process text files immediately
processFile(path);
}
});
console.log(`Completed! Total items: ${paths.length}`);
return paths;
}async function analyzeProject(projectPath) {
const [allPaths, stats] = await Promise.all([
walkdir.async(projectPath),
walkdir.async(projectPath, { return_object: true })
]);
return {
totalFiles: allPaths.length,
totalSize: Object.values(stats)
.filter(stat => stat.isFile())
.reduce((sum, stat) => sum + stat.size, 0),
directories: Object.values(stats)
.filter(stat => stat.isDirectory()).length
};
}async function robustWalk(path, options = {}) {
const maxRetries = 3;
let attempt = 0;
while (attempt < maxRetries) {
try {
return await walkdir.async(path, options);
} catch (error) {
attempt++;
if (attempt >= maxRetries) throw error;
console.warn(`Walk attempt ${attempt} failed, retrying...`);
await new Promise(resolve => setTimeout(resolve, 1000));
}
}
}Install with Tessl CLI
npx tessl i tessl/npm-walkdir