Convert a directory tree to a JS object with flexible filtering and callback support.
npx @tessl/cli install tessl/npm-directory-tree@3.5.0Directory Tree is a Node.js library that converts directory structures into JavaScript objects. It provides flexible scanning of file system hierarchies with support for filtering by file extensions, excluding specific paths, and customizing output attributes including file size, modification time, and type information.
npm install directory-treeconst directoryTree = require("directory-tree");For TypeScript:
import directoryTree = require("directory-tree");
import { DirectoryTree, DirectoryTreeOptions, DirectoryTreeCallback } from "directory-tree";const directoryTree = require("directory-tree");
// Basic directory scan
const tree = directoryTree("/path/to/directory");
// Scan with file extension filtering
const filteredTree = directoryTree("/path/to/directory", {
extensions: /\.(js|ts|md)$/
});
// Scan with additional attributes
const detailedTree = directoryTree("/path/to/directory", {
attributes: ["size", "type", "extension", "mtime"]
});
console.log(JSON.stringify(tree, null, 2));Directory Tree is built around several key components:
Core directory scanning functionality that converts filesystem hierarchies into JavaScript objects with configurable filtering and attribute collection.
/**
* Scans a directory and returns a JavaScript object representation
* @param path - The directory path to scan
* @param options - Configuration options for scanning behavior
* @param onEachFile - Optional callback executed for each file
* @param onEachDirectory - Optional callback executed for each directory
* @returns DirectoryTree object or null if path is inaccessible
*/
declare function directoryTree<
TCustomFile extends Record<string, any> = Record<string, any>,
TCustomDir extends Record<string, any> = Record<string, any>,
TCustomResult extends Record<string, any> = TCustomFile & TCustomDir
>(
path: string,
options?: DirectoryTreeOptions,
onEachFile?: DirectoryTreeCallback<TCustomFile>,
onEachDirectory?: DirectoryTreeCallback<TCustomDir>
): DirectoryTree<TCustomResult> | null;Usage Examples:
const directoryTree = require("directory-tree");
// Basic usage
const tree = directoryTree("./src");
// With options
const tree = directoryTree("./src", {
extensions: /\.(js|ts)$/,
attributes: ["size", "type", "extension"],
depth: 3,
exclude: /node_modules/
});
// With callbacks
const tree = directoryTree("./src", { extensions: /\.js$/ },
(item, path, stats) => {
console.log(`File: ${item.name} (${stats.size} bytes)`);
},
(item, path, stats) => {
console.log(`Directory: ${item.name}`);
}
);Comprehensive options for controlling directory scanning behavior.
interface DirectoryTreeOptions {
/** Normalize Windows paths to Unix-style paths (/ instead of \\) */
normalizePath?: boolean;
/** RegExp or array of RegExp patterns to exclude directories/files */
exclude?: RegExp | RegExp[];
/** Array of fs.Stats attributes to include in output plus 'type' and 'extension' */
attributes?: (keyof Stats | "type" | "extension")[];
/** RegExp pattern to filter files by extension */
extensions?: RegExp;
/** Whether to follow symbolic links (default: true) */
followSymlinks?: boolean;
/** Maximum directory depth to scan (undefined = unlimited) */
depth?: number;
}Supported Attributes:
"type", "extension""size", "mode", "mtime", "atime", "ctime", "birthtime", "dev", "ino", "nlink", "uid", "gid", "rdev", "blksize", "blocks"Usage Examples:
// Filter by multiple extensions
const tree = directoryTree("./docs", {
extensions: /\.(md|txt|html)$/
});
// Exclude multiple patterns
const tree = directoryTree("./project", {
exclude: [/node_modules/, /\.git/, /dist/]
});
// Include file attributes
const tree = directoryTree("./assets", {
attributes: ["size", "mtime", "type", "extension"]
});
// Limit scanning depth
const tree = directoryTree("./deep-structure", {
depth: 2,
attributes: ["type"] // Note: 'size' cannot be used with 'depth'
});
// Normalize paths for cross-platform compatibility
const tree = directoryTree("./src", {
normalizePath: true,
followSymlinks: false
});The structure of objects returned by directory scanning.
interface DirectoryTree<C extends Record<string, any> = Record<string, any>> {
/** Full path to the file or directory */
path: string;
/** Name of the file or directory (basename) */
name: string;
/** Size in bytes (only if 'size' attribute is requested) */
size: number;
/** Type of item: 'file' or 'directory' (only if 'type' attribute is requested) */
type: "directory" | "file";
/** Array of child items (directories only, when children exist) */
children?: DirectoryTree<C>[];
/** File extension including the dot (files only, if 'extension' attribute is requested) */
extension?: string;
/** Whether the item is a symbolic link */
isSymbolicLink?: boolean;
/** Custom properties added via callbacks */
custom: C;
}Example Result:
{
"path": "photos",
"name": "photos",
"size": 600,
"type": "directory",
"children": [
{
"path": "photos/vacation.jpg",
"name": "vacation.jpg",
"size": 400,
"type": "file",
"extension": ".jpg"
},
{
"path": "photos/family",
"name": "family",
"size": 200,
"type": "directory",
"children": [
{
"path": "photos/family/portrait.png",
"name": "portrait.png",
"size": 200,
"type": "file",
"extension": ".png"
}
]
}
]
}Optional callback functions for processing files and directories during traversal.
// Import from Node.js fs module
import { Stats } from "fs";
/**
* Callback function executed for each file or directory
* @param item - The DirectoryTree item being processed
* @param path - Full path to the item
* @param stats - Node.js fs.Stats object for the item
*/
type DirectoryTreeCallback<TCustom extends Record<string, any> = Record<string, any>> = (
item: DirectoryTree<TCustom>,
path: string,
stats: Stats
) => void;Usage Examples:
const crypto = require('crypto');
const directoryTree = require("directory-tree");
// Add custom IDs to all items
const tree = directoryTree("./src", {},
(item, path, stats) => {
// File callback
item.custom = {
id: crypto.createHash('sha1').update(path).digest('base64'),
lastModified: stats.mtime.toISOString()
};
},
(item, path, stats) => {
// Directory callback
item.custom = {
id: crypto.createHash('sha1').update(path).digest('base64'),
itemCount: item.children ? item.children.length : 0
};
}
);
// Log processing progress
const tree = directoryTree("./large-directory", {},
(item, path) => console.log(`Processing file: ${path}`),
(item, path) => console.log(`Entering directory: ${path}`)
);CLI tool for generating JSON representations of directory structures from the command line.
# Basic usage
npx directory-tree /path/to/directory
# With options
npx directory-tree --path /home/user/docs --attributes type,extension,size --pretty --output result.json
# Available options:
# -p, --path <string> Input folder path (required)
# -e, --exclude <string> Exclude pattern (regex string)
# -o, --output <string> Output file path
# -d, --depth <number> Maximum directory depth
# --attributes <string> Comma-separated attributes list
# --pretty Pretty-print JSON output
# -h, --help Show helpCLI Examples:
# Scan current directory with file types and extensions
npx directory-tree . --attributes type,extension --pretty
# Exclude certain directories and save to file
npx directory-tree /project --exclude "node_modules|\.git|dist" --output tree.json
# Limit depth and include file sizes
npx directory-tree /deep/structure --depth 2 --attributes type,extension
# Scan and format for readability
npx directory-tree ~/Documents --pretty --attributes type,size,mtimesize attribute when depth option is specified (throws an Error)// This will throw an error
try {
const tree = directoryTree("./src", {
depth: 2,
attributes: ["size"] // Error: size cannot be used with depth
});
} catch (error) {
console.error(error.message); // "usage of size attribute with depth option is prohibited"
}
// Permission errors are handled gracefully
const tree = directoryTree("/root"); // Returns null if no permissionFull TypeScript support with generic types for custom callback data.
import { createHash } from 'crypto';
import { Stats } from 'fs';
import directoryTree = require('directory-tree');
import { DirectoryTree, DirectoryTreeOptions, DirectoryTreeCallback } from 'directory-tree';
// Generic usage with custom types
interface CustomData {
id: string;
processed: boolean;
}
const callback: DirectoryTreeCallback<CustomData> = (
item: DirectoryTree<CustomData>,
path: string,
stats: Stats
) => {
item.custom = {
id: createHash('sha1').update(path).digest('base64'),
processed: true
};
};
const tree: DirectoryTree<CustomData> = directoryTree(
"./src",
{ attributes: ["type", "size"] },
callback,
callback
);
// Access custom properties with type safety
if (tree?.custom?.processed) {
console.log(`Processed with ID: ${tree.custom.id}`);
}