@crashbytes/dendro 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,32 @@
1
+ # Changelog
2
+
3
+ All notable changes to dendro will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [1.0.0] - 2025-10-13
9
+
10
+ ### Added
11
+ - Initial release of dendro ๐ŸŒณ
12
+ - Beautiful directory tree visualization with Unicode box-drawing characters
13
+ - Smart file type icons for 30+ file types
14
+ - CLI with flexible options (depth control, filtering, etc.)
15
+ - Programmatic API for Node.js integration
16
+ - Statistics display (file and directory counts)
17
+ - Smart default exclusions (node_modules, .git, etc.)
18
+ - Regex-based pattern exclusion
19
+ - Hidden file support with `-a` flag
20
+ - Full path display option
21
+ - Plain text mode (no icons)
22
+ - Comprehensive documentation and examples
23
+
24
+ ### Features
25
+ - ๐Ÿ“ Directory visualization
26
+ - ๐ŸŽจ File type icons
27
+ - โšก Fast directory traversal
28
+ - ๐ŸŽฏ Pattern-based filtering
29
+ - ๐Ÿ“Š Built-in statistics
30
+ - ๐Ÿ”ง Both CLI and API
31
+
32
+ [1.0.0]: https://github.com/CrashBytes/dendron/releases/tag/v1.0.0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 CrashBytes
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/QUICKSTART.md ADDED
@@ -0,0 +1,109 @@
1
+ # Quick Start Guide - dendro ๐ŸŒณ
2
+
3
+ ## What is dendro?
4
+
5
+ **dendro** (ฮดฮญฮฝฮดฯฮฟ) is Greek for "tree" - a beautiful CLI tool to visualize directory structures with file type icons.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ cd ~/github/crashbytes-tree
11
+ npm install
12
+ ```
13
+
14
+ ## Testing Methods
15
+
16
+ ### Method 1: Run the test suite
17
+ ```bash
18
+ npm test
19
+ ```
20
+
21
+ ### Method 2: Run CLI directly (no installation)
22
+ ```bash
23
+ # Test on current directory
24
+ node bin/cli.js
25
+
26
+ # Test on crashbytes blog
27
+ node bin/cli.js ~/github/crashbytes
28
+
29
+ # Test with depth limit
30
+ node bin/cli.js ~/github/crashbytes -d 2
31
+
32
+ # Show all options
33
+ node bin/cli.js --help
34
+ ```
35
+
36
+ ### Method 3: Install globally (recommended)
37
+ ```bash
38
+ npm link
39
+ ```
40
+
41
+ Then use anywhere:
42
+ ```bash
43
+ dendro
44
+ dendro ~/github/crashbytes -d 3
45
+ dendro . -a
46
+ ```
47
+
48
+ ### Method 4: Use with npx (after publishing)
49
+ ```bash
50
+ npx @crashbytes/dendro
51
+ ```
52
+
53
+ ## Common Test Commands
54
+
55
+ ```bash
56
+ # Show 2 levels of current directory
57
+ node bin/cli.js -d 2
58
+
59
+ # Show all files including hidden
60
+ node bin/cli.js -a
61
+
62
+ # Exclude patterns
63
+ node bin/cli.js -e "test" "*.log"
64
+
65
+ # Show without icons
66
+ node bin/cli.js --no-icons
67
+
68
+ # Show with full paths
69
+ node bin/cli.js -p
70
+
71
+ # Visualize the dendro project itself
72
+ node bin/cli.js . -d 2
73
+ ```
74
+
75
+ ## Programmatic Usage
76
+
77
+ Create a test file:
78
+
79
+ ```javascript
80
+ // my-test.js
81
+ const { buildTree, renderTree, getTreeStats } = require('@crashbytes/dendro');
82
+
83
+ const tree = buildTree('.', { maxDepth: 2 });
84
+ const output = renderTree(tree, { showIcons: true });
85
+ console.log(output);
86
+
87
+ const stats = getTreeStats(tree);
88
+ console.log(`\n${stats.directories} dirs, ${stats.files} files`);
89
+ ```
90
+
91
+ Run it:
92
+ ```bash
93
+ node my-test.js
94
+ ```
95
+
96
+ ## Publishing to NPM
97
+
98
+ When ready:
99
+ ```bash
100
+ npm login
101
+ npm publish
102
+ ```
103
+
104
+ ## Why "dendro"?
105
+
106
+ - **ฮดฮญฮฝฮดฯฮฟ** (dendro) = Greek for "tree"
107
+ - Short, memorable, professional
108
+ - Used in science (dendrology, dendrochronology)
109
+ - Perfect for visualizing tree structures!
package/README.md ADDED
@@ -0,0 +1,385 @@
1
+ # dendro ๐ŸŒณ
2
+
3
+ [![npm version](https://badge.fury.io/js/%40crashbytes%2Fdendro.svg)](https://www.npmjs.com/package/@crashbytes/dendro)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+ [![GitHub issues](https://img.shields.io/github/issues/CrashBytes/dendron)](https://github.com/CrashBytes/dendron/issues)
6
+ [![GitHub stars](https://img.shields.io/github/stars/CrashBytes/dendron)](https://github.com/CrashBytes/dendron/stargazers)
7
+
8
+ **dendro** (ฮดฮญฮฝฮดฯฮฟ) - from the Greek word for "tree"
9
+
10
+ A beautiful, fast directory tree visualization CLI with intuitive file type icons.
11
+
12
+ ๐Ÿ”— **[GitHub Repository](https://github.com/CrashBytes/dendron)** | ๐Ÿ“ฆ **[npm Package](https://www.npmjs.com/package/@crashbytes/dendro)**
13
+
14
+ ---
15
+
16
+ ## Why "dendro"?
17
+
18
+ The name **dendro** comes from the Greek word **ฮดฮญฮฝฮดฯฮฟ** (pronounced "DEN-droh"), meaning "tree". It's:
19
+
20
+ - **Memorable** - Short, unique, and easy to remember
21
+ - **Meaningful** - Directly relates to tree structures and hierarchies
22
+ - **Professional** - Used in scientific contexts (dendrology, dendrochronology)
23
+ - **Global** - Recognizable across languages due to its Greek root
24
+ - **Concise** - Just 6 letters, quick to type
25
+
26
+ When you visualize directory structures, you're essentially mapping a treeโ€”and that's exactly what dendro does, with style.
27
+
28
+ ---
29
+
30
+ ## Features
31
+
32
+ - ๐ŸŒณ Beautiful tree visualization with Unicode box-drawing characters
33
+ - ๐ŸŽจ **Smart file type icons** for instant visual recognition
34
+ - โšก Lightning fast - optimized directory traversal
35
+ - ๐ŸŽฏ Flexible filtering with regex pattern support
36
+ - ๐Ÿ“Š Built-in statistics (file counts, directory counts)
37
+ - ๐Ÿ”ง Both CLI and programmatic API
38
+ - ๐ŸŽญ Smart defaults (auto-excludes node_modules, .git, etc.)
39
+
40
+ ## Installation
41
+
42
+ ### Via npm (Recommended)
43
+
44
+ ```bash
45
+ npm install -g @crashbytes/dendro
46
+ ```
47
+
48
+ ### Via npx (No Installation)
49
+
50
+ ```bash
51
+ npx @crashbytes/dendro
52
+ ```
53
+
54
+ ### From Source (GitHub)
55
+
56
+ ```bash
57
+ git clone https://github.com/CrashBytes/dendron.git
58
+ cd dendron
59
+ npm install
60
+ npm link
61
+ ```
62
+
63
+ ## Quick Start
64
+
65
+ ```bash
66
+ # Visualize current directory
67
+ dendro
68
+
69
+ # Visualize specific directory
70
+ dendro /path/to/project
71
+
72
+ # Limit depth to 3 levels
73
+ dendro ~/projects -d 3
74
+
75
+ # Show all files including hidden
76
+ dendro -a
77
+
78
+ # Show help
79
+ dendro --help
80
+ ```
81
+
82
+ ## Usage
83
+
84
+ ### Command Line Options
85
+
86
+ ```
87
+ Usage: dendro [path] [options]
88
+
89
+ Arguments:
90
+ path Directory path to display (default: ".")
91
+
92
+ Options:
93
+ -V, --version Output version number
94
+ -d, --max-depth <number> Maximum depth to traverse
95
+ -a, --all Show hidden files and directories
96
+ --no-icons Disable file type icons
97
+ -p, --show-paths Show full paths
98
+ -e, --exclude <patterns> Patterns to exclude (regex)
99
+ --no-stats Hide statistics summary
100
+ -h, --help Display help
101
+ ```
102
+
103
+ ### Examples
104
+
105
+ ```bash
106
+ # Show only 2 levels deep
107
+ dendro -d 2
108
+
109
+ # Show all files including hidden ones
110
+ dendro -a
111
+
112
+ # Exclude specific patterns (node_modules, test directories)
113
+ dendro -e "node_modules" "test" "__pycache__"
114
+
115
+ # Show full file paths
116
+ dendro -p
117
+
118
+ # Plain text output (no icons)
119
+ dendro --no-icons
120
+
121
+ # Combine options
122
+ dendro ~/my-project -d 3 -a -e "*.log" "dist"
123
+ ```
124
+
125
+ ## File Type Icons
126
+
127
+ dendro automatically detects and displays appropriate icons for common file types:
128
+
129
+ | Icon | File Types |
130
+ |------|-----------|
131
+ | ๐Ÿ“ | Directories |
132
+ | ๐Ÿ“œ | JavaScript (.js, .jsx, .mjs, .cjs) |
133
+ | ๐Ÿ“˜ | TypeScript (.ts, .tsx) |
134
+ | ๐Ÿ“‹ | JSON (.json) |
135
+ | ๐Ÿ“ | Markdown (.md, .mdx) |
136
+ | ๐ŸŽจ | Stylesheets (.css, .scss, .sass, .less) |
137
+ | ๐ŸŒ | HTML (.html, .htm) |
138
+ | ๐Ÿ–ผ๏ธ | Images (.png, .jpg, .gif, .svg, .webp) |
139
+ | ๐ŸŽฌ | Videos (.mp4, .avi, .mov, .mkv) |
140
+ | ๐ŸŽต | Audio (.mp3, .wav, .ogg, .m4a) |
141
+ | ๐Ÿ“• | PDFs (.pdf) |
142
+ | ๐Ÿ—œ๏ธ | Archives (.zip, .tar, .gz, .rar, .7z) |
143
+ | ๐Ÿ—„๏ธ | Databases (.db, .sqlite, .sql) |
144
+ | โš™๏ธ | Config files (.yaml, .yml, .toml, .ini) |
145
+ | ๐Ÿ”’ | Lock files (package-lock.json, yarn.lock) |
146
+ | ๐Ÿ“ฆ | Git files (.gitignore, .gitattributes) |
147
+ | ๐Ÿ“„ | Other text files |
148
+
149
+ ## Programmatic API
150
+
151
+ Use dendro in your Node.js projects:
152
+
153
+ ```javascript
154
+ const { buildTree, renderTree, getTreeStats } = require('@crashbytes/dendro');
155
+
156
+ // Build a tree structure
157
+ const tree = buildTree('/path/to/directory', {
158
+ maxDepth: 3,
159
+ showHidden: false,
160
+ excludePatterns: [/node_modules/, /\.git/]
161
+ });
162
+
163
+ // Render as text
164
+ const output = renderTree(tree, {
165
+ showIcons: true,
166
+ showPaths: false
167
+ });
168
+
169
+ console.log(output);
170
+
171
+ // Get statistics
172
+ const stats = getTreeStats(tree);
173
+ console.log(`${stats.directories} directories, ${stats.files} files`);
174
+ ```
175
+
176
+ ### API Reference
177
+
178
+ #### `buildTree(dirPath, options)`
179
+
180
+ Builds a tree data structure from a directory.
181
+
182
+ **Parameters:**
183
+ - `dirPath` (string) - Path to directory
184
+ - `options` (object)
185
+ - `maxDepth` (number) - Maximum depth to traverse (default: Infinity)
186
+ - `showHidden` (boolean) - Include hidden files (default: false)
187
+ - `excludePatterns` (RegExp[]) - Patterns to exclude (default: [])
188
+
189
+ **Returns:** Tree object with structure:
190
+ ```javascript
191
+ {
192
+ name: string,
193
+ type: 'file' | 'directory',
194
+ icon: string,
195
+ path: string,
196
+ children?: TreeNode[]
197
+ }
198
+ ```
199
+
200
+ #### `renderTree(tree, options)`
201
+
202
+ Renders a tree structure as formatted text.
203
+
204
+ **Parameters:**
205
+ - `tree` (object) - Tree structure from buildTree
206
+ - `options` (object)
207
+ - `showIcons` (boolean) - Display file type icons (default: true)
208
+ - `showPaths` (boolean) - Display full paths (default: false)
209
+ - `prefix` (string) - Internal use for recursion
210
+ - `isLast` (boolean) - Internal use for recursion
211
+
212
+ **Returns:** Formatted string representation
213
+
214
+ #### `getTreeStats(tree)`
215
+
216
+ Calculates statistics for a tree.
217
+
218
+ **Returns:** Object with `{ files: number, directories: number }`
219
+
220
+ ## Default Exclusions
221
+
222
+ By default (without `-a` flag), dendro excludes:
223
+ - Hidden files/directories (starting with `.`)
224
+ - `node_modules`
225
+ - `.git`
226
+ - `.DS_Store`
227
+ - `dist`
228
+ - `build`
229
+ - `coverage`
230
+
231
+ Override with `-a` or use `-e` to add custom exclusions.
232
+
233
+ ## Advanced Usage
234
+
235
+ ### Custom Filtering
236
+
237
+ ```javascript
238
+ const { buildTree, renderTree } = require('@crashbytes/dendro');
239
+
240
+ // Build tree
241
+ const tree = buildTree('.', { maxDepth: 3 });
242
+
243
+ // Filter to show only JavaScript files
244
+ function filterJS(node) {
245
+ if (node.type === 'file') {
246
+ return /\.(js|jsx|ts|tsx)$/.test(node.name) ? node : null;
247
+ }
248
+
249
+ if (node.children) {
250
+ const filtered = node.children.map(filterJS).filter(Boolean);
251
+ return filtered.length > 0 ? { ...node, children: filtered } : null;
252
+ }
253
+
254
+ return null;
255
+ }
256
+
257
+ const jsOnly = filterJS(tree);
258
+ console.log(renderTree(jsOnly));
259
+ ```
260
+
261
+ ### Integration with Build Tools
262
+
263
+ ```javascript
264
+ // In your build script
265
+ const { buildTree, getTreeStats } = require('@crashbytes/dendro');
266
+
267
+ const tree = buildTree('./dist');
268
+ const stats = getTreeStats(tree);
269
+
270
+ console.log(`Build output: ${stats.files} files in ${stats.directories} directories`);
271
+ ```
272
+
273
+ ## Examples
274
+
275
+ See the [`/examples`](https://github.com/CrashBytes/dendron/tree/main/examples) directory for more usage examples:
276
+ - `basic-usage.js` - Simple tree visualization
277
+ - `advanced-usage.js` - Custom filtering and statistics
278
+
279
+ ## Contributing
280
+
281
+ We welcome contributions! Here's how you can help:
282
+
283
+ 1. **Fork the repository** on [GitHub](https://github.com/CrashBytes/dendron)
284
+ 2. **Clone your fork**
285
+ ```bash
286
+ git clone https://github.com/YOUR-USERNAME/dendron.git
287
+ cd dendron
288
+ npm install
289
+ ```
290
+ 3. **Create a feature branch**
291
+ ```bash
292
+ git checkout -b feature/amazing-feature
293
+ ```
294
+ 4. **Make your changes** and test them
295
+ ```bash
296
+ npm test
297
+ node bin/cli.js
298
+ ```
299
+ 5. **Commit your changes**
300
+ ```bash
301
+ git commit -m "Add amazing feature"
302
+ ```
303
+ 6. **Push to your fork**
304
+ ```bash
305
+ git push origin feature/amazing-feature
306
+ ```
307
+ 7. **Open a Pull Request** on GitHub
308
+
309
+ ### Areas for Contribution
310
+
311
+ - ๐ŸŽจ Add more file type icons
312
+ - โšก Performance optimizations
313
+ - ๐Ÿ“ Documentation improvements
314
+ - ๐Ÿ› Bug fixes
315
+ - โœจ New features
316
+
317
+ ## Bug Reports & Feature Requests
318
+
319
+ Found a bug or have a feature request? Please open an issue on [GitHub Issues](https://github.com/CrashBytes/dendron/issues).
320
+
321
+ When reporting bugs, please include:
322
+ - Your OS and Node.js version
323
+ - Steps to reproduce
324
+ - Expected vs actual behavior
325
+ - Screenshots if applicable
326
+
327
+ ## Development
328
+
329
+ ### Running Tests
330
+
331
+ ```bash
332
+ npm test
333
+ ```
334
+
335
+ ### Local Development
336
+
337
+ ```bash
338
+ # Clone the repository
339
+ git clone https://github.com/CrashBytes/dendron.git
340
+ cd dendron
341
+
342
+ # Install dependencies
343
+ npm install
344
+
345
+ # Link for local testing
346
+ npm link
347
+
348
+ # Make changes and test
349
+ dendro ~/test-directory
350
+ ```
351
+
352
+ ## Changelog
353
+
354
+ See [CHANGELOG.md](https://github.com/CrashBytes/dendron/blob/main/CHANGELOG.md) for version history.
355
+
356
+ ## License
357
+
358
+ MIT License - see [LICENSE](https://github.com/CrashBytes/dendron/blob/main/LICENSE) file for details.
359
+
360
+ ## Author
361
+
362
+ **CrashBytes**
363
+ - Website: [crashbytes.com](https://crashbytes.com)
364
+ - GitHub: [@CrashBytes](https://github.com/CrashBytes)
365
+ - Twitter: [@crashbytes](https://twitter.com/crashbytes)
366
+
367
+ ## Acknowledgments
368
+
369
+ Built with โค๏ธ for developers who love beautiful CLIs.
370
+
371
+ Special thanks to all [contributors](https://github.com/CrashBytes/dendron/graphs/contributors) who help make dendro better!
372
+
373
+ ---
374
+
375
+ ## Support
376
+
377
+ If you find dendro useful, please:
378
+ - โญ Star the project on [GitHub](https://github.com/CrashBytes/dendron)
379
+ - ๐Ÿฆ Share it on social media
380
+ - ๐Ÿ“ Write a blog post about it
381
+ - ๐Ÿ’ฌ Tell your developer friends
382
+
383
+ ---
384
+
385
+ *dendro - Because every great project starts with understanding its structure* ๐ŸŒณ
package/bin/cb-tree.js ADDED
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env node
2
+
3
+ const path = require('path');
4
+ const dirTree = require('../index');
5
+
6
+ const args = process.argv.slice(2);
7
+ const options = {
8
+ all: false,
9
+ depth: Infinity,
10
+ dirsOnly: false,
11
+ exclude: []
12
+ };
13
+
14
+ let targetPath = process.cwd();
15
+
16
+ // Parse arguments
17
+ for (let i = 0; i < args.length; i++) {
18
+ const arg = args[i];
19
+
20
+ if (arg === '-a' || arg === '--all') {
21
+ options.all = true;
22
+ } else if (arg === '-d' || arg === '--dirs-only') {
23
+ options.dirsOnly = true;
24
+ } else if (arg === '-L' || arg === '--level') {
25
+ options.depth = parseInt(args[++i]);
26
+ } else if (arg === '-I' || arg === '--exclude') {
27
+ options.exclude.push(args[++i]);
28
+ } else if (arg === '-h' || arg === '--help') {
29
+ showHelp();
30
+ process.exit(0);
31
+ } else if (!arg.startsWith('-')) {
32
+ targetPath = path.resolve(arg);
33
+ }
34
+ }
35
+
36
+ function showHelp() {
37
+ console.log(`
38
+ crashbytes-tree - A beautiful directory tree with file type icons
39
+
40
+ Usage: cb-tree [options] [path]
41
+
42
+ Options:
43
+ -a, --all Show hidden files (starting with .)
44
+ -d, --dirs-only List directories only
45
+ -L, --level <n> Maximum depth of directory tree
46
+ -I, --exclude <pattern> Exclude files/directories matching pattern
47
+ -h, --help Show this help message
48
+
49
+ Examples:
50
+ cb-tree # Show tree of current directory
51
+ cb-tree /path/to/dir # Show tree of specific directory
52
+ cb-tree -L 2 # Show tree with max depth of 2
53
+ cb-tree -a -L 3 # Show tree including hidden files, max depth 3
54
+ cb-tree -d # Show directories only
55
+ `);
56
+ }
57
+
58
+ try {
59
+ console.log(dirTree(targetPath, options));
60
+ } catch (error) {
61
+ console.error(`Error: ${error.message}`);
62
+ process.exit(1);
63
+ }
package/bin/cli.js ADDED
@@ -0,0 +1,78 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { Command } = require('commander');
4
+ const chalk = require('chalk');
5
+ const path = require('path');
6
+ const { buildTree, renderTree, getTreeStats } = require('../index');
7
+
8
+ const program = new Command();
9
+
10
+ program
11
+ .name('dendro')
12
+ .description('Display directory tree structure with beautiful icons')
13
+ .version('1.0.0')
14
+ .argument('[path]', 'Directory path to display', '.')
15
+ .option('-d, --max-depth <number>', 'Maximum depth to traverse', parseInt)
16
+ .option('-a, --all', 'Show hidden files and directories', false)
17
+ .option('--no-icons', 'Disable file type icons')
18
+ .option('-p, --show-paths', 'Show full paths', false)
19
+ .option('-e, --exclude <patterns...>', 'Patterns to exclude (regex)')
20
+ .option('--no-stats', 'Hide statistics summary')
21
+ .action((dirPath, options) => {
22
+ try {
23
+ const fullPath = path.resolve(dirPath);
24
+
25
+ console.log(chalk.bold.cyan(`\n๐ŸŒณ Directory Tree: ${fullPath}\n`));
26
+
27
+ // Build exclude patterns
28
+ const excludePatterns = options.exclude
29
+ ? options.exclude.map(p => new RegExp(p))
30
+ : [];
31
+
32
+ // Common excludes by default
33
+ if (!options.all) {
34
+ excludePatterns.push(
35
+ /^node_modules$/,
36
+ /^\.git$/,
37
+ /^\.DS_Store$/,
38
+ /^dist$/,
39
+ /^build$/,
40
+ /^coverage$/
41
+ );
42
+ }
43
+
44
+ // Build the tree
45
+ const tree = buildTree(fullPath, {
46
+ maxDepth: options.maxDepth || Infinity,
47
+ showHidden: options.all,
48
+ excludePatterns
49
+ });
50
+
51
+ if (!tree) {
52
+ console.log(chalk.red('Error: Could not read directory'));
53
+ process.exit(1);
54
+ }
55
+
56
+ // Render the tree
57
+ const output = renderTree(tree, {
58
+ showIcons: options.icons,
59
+ showPaths: options.showPaths
60
+ });
61
+
62
+ console.log(output);
63
+
64
+ // Show statistics
65
+ if (options.stats) {
66
+ const stats = getTreeStats(tree);
67
+ console.log(chalk.dim(`\n${stats.directories} directories, ${stats.files} files`));
68
+ }
69
+
70
+ console.log(); // Empty line at the end
71
+
72
+ } catch (error) {
73
+ console.error(chalk.red(`Error: ${error.message}`));
74
+ process.exit(1);
75
+ }
76
+ });
77
+
78
+ program.parse();
@@ -0,0 +1,59 @@
1
+ const { buildTree, renderTree, getTreeStats } = require('../index');
2
+ const chalk = require('chalk');
3
+
4
+ // Advanced usage with custom options
5
+ console.log(chalk.bold.cyan('Advanced Directory Tree Example\n'));
6
+
7
+ const tree = buildTree('.', {
8
+ maxDepth: 3,
9
+ showHidden: true,
10
+ excludePatterns: [
11
+ /node_modules/,
12
+ /\.git/,
13
+ /dist/,
14
+ /coverage/,
15
+ /\.log$/
16
+ ]
17
+ });
18
+
19
+ // Render with custom options
20
+ const output = renderTree(tree, {
21
+ showIcons: true,
22
+ showPaths: false
23
+ });
24
+
25
+ console.log(output);
26
+
27
+ // Get and display statistics
28
+ const stats = getTreeStats(tree);
29
+ console.log(chalk.dim(`\n๐Ÿ“Š Statistics:`));
30
+ console.log(chalk.dim(` Directories: ${stats.directories}`));
31
+ console.log(chalk.dim(` Files: ${stats.files}`));
32
+ console.log(chalk.dim(` Total items: ${stats.directories + stats.files}`));
33
+
34
+ // Custom filtering example
35
+ console.log(chalk.bold.yellow('\n\n๐Ÿ” JavaScript files only:\n'));
36
+
37
+ function filterJavaScriptFiles(node) {
38
+ if (node.type === 'file') {
39
+ const ext = node.name.split('.').pop();
40
+ return ['js', 'jsx', 'ts', 'tsx'].includes(ext) ? node : null;
41
+ }
42
+
43
+ if (node.children) {
44
+ const filteredChildren = node.children
45
+ .map(filterJavaScriptFiles)
46
+ .filter(Boolean);
47
+
48
+ if (filteredChildren.length > 0) {
49
+ return { ...node, children: filteredChildren };
50
+ }
51
+ }
52
+
53
+ return null;
54
+ }
55
+
56
+ const jsTree = filterJavaScriptFiles(tree);
57
+ if (jsTree) {
58
+ console.log(renderTree(jsTree, { showIcons: true }));
59
+ }
@@ -0,0 +1,14 @@
1
+ const { buildTree, renderTree } = require('../index');
2
+
3
+ // Basic usage example
4
+ const tree = buildTree('.', {
5
+ maxDepth: 2,
6
+ showHidden: false
7
+ });
8
+
9
+ const output = renderTree(tree, {
10
+ showIcons: true,
11
+ showPaths: false
12
+ });
13
+
14
+ console.log(output);
package/index.js ADDED
@@ -0,0 +1,296 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ // Icon mappings for different file types and directories
5
+ const icons = {
6
+ // Directory
7
+ directory: '๐Ÿ“',
8
+ directoryOpen: '๐Ÿ“‚',
9
+
10
+ // Common file types
11
+ javascript: '๐Ÿ“œ',
12
+ typescript: '๐Ÿ“˜',
13
+ json: '๐Ÿ“‹',
14
+ markdown: '๐Ÿ“',
15
+ text: '๐Ÿ“„',
16
+ image: '๐Ÿ–ผ๏ธ',
17
+ video: '๐ŸŽฌ',
18
+ audio: '๐ŸŽต',
19
+ pdf: '๐Ÿ“•',
20
+ zip: '๐Ÿ—œ๏ธ',
21
+ executable: 'โš™๏ธ',
22
+ config: 'โš™๏ธ',
23
+ css: '๐ŸŽจ',
24
+ html: '๐ŸŒ',
25
+ database: '๐Ÿ—„๏ธ',
26
+ lock: '๐Ÿ”’',
27
+ git: '๐Ÿ“ฆ',
28
+
29
+ // Default
30
+ default: '๐Ÿ“„'
31
+ };
32
+
33
+ // File extension to icon mapping
34
+ const extensionMap = {
35
+ // JavaScript/TypeScript
36
+ '.js': icons.javascript,
37
+ '.jsx': icons.javascript,
38
+ '.ts': icons.typescript,
39
+ '.tsx': icons.typescript,
40
+ '.mjs': icons.javascript,
41
+ '.cjs': icons.javascript,
42
+
43
+ // Data formats
44
+ '.json': icons.json,
45
+ '.yaml': icons.config,
46
+ '.yml': icons.config,
47
+ '.xml': icons.config,
48
+ '.toml': icons.config,
49
+ '.ini': icons.config,
50
+
51
+ // Markdown/Documentation
52
+ '.md': icons.markdown,
53
+ '.mdx': icons.markdown,
54
+ '.txt': icons.text,
55
+ '.pdf': icons.pdf,
56
+
57
+ // Web
58
+ '.html': icons.html,
59
+ '.htm': icons.html,
60
+ '.css': icons.css,
61
+ '.scss': icons.css,
62
+ '.sass': icons.css,
63
+ '.less': icons.css,
64
+
65
+ // Images
66
+ '.png': icons.image,
67
+ '.jpg': icons.image,
68
+ '.jpeg': icons.image,
69
+ '.gif': icons.image,
70
+ '.svg': icons.image,
71
+ '.webp': icons.image,
72
+ '.ico': icons.image,
73
+ '.bmp': icons.image,
74
+
75
+ // Video
76
+ '.mp4': icons.video,
77
+ '.avi': icons.video,
78
+ '.mov': icons.video,
79
+ '.mkv': icons.video,
80
+ '.webm': icons.video,
81
+
82
+ // Audio
83
+ '.mp3': icons.audio,
84
+ '.wav': icons.audio,
85
+ '.ogg': icons.audio,
86
+ '.m4a': icons.audio,
87
+ '.flac': icons.audio,
88
+
89
+ // Archives
90
+ '.zip': icons.zip,
91
+ '.tar': icons.zip,
92
+ '.gz': icons.zip,
93
+ '.rar': icons.zip,
94
+ '.7z': icons.zip,
95
+
96
+ // Databases
97
+ '.db': icons.database,
98
+ '.sqlite': icons.database,
99
+ '.sql': icons.database,
100
+
101
+ // Executables
102
+ '.exe': icons.executable,
103
+ '.sh': icons.executable,
104
+ '.bat': icons.executable,
105
+ '.cmd': icons.executable,
106
+
107
+ // Lock files
108
+ '.lock': icons.lock,
109
+ };
110
+
111
+ // Special filename mappings
112
+ const filenameMap = {
113
+ '.gitignore': icons.git,
114
+ '.gitattributes': icons.git,
115
+ '.gitmodules': icons.git,
116
+ 'package.json': icons.json,
117
+ 'package-lock.json': icons.lock,
118
+ 'yarn.lock': icons.lock,
119
+ 'pnpm-lock.yaml': icons.lock,
120
+ '.env': icons.config,
121
+ '.env.local': icons.config,
122
+ '.env.development': icons.config,
123
+ '.env.production': icons.config,
124
+ 'Dockerfile': icons.config,
125
+ 'docker-compose.yml': icons.config,
126
+ 'README.md': icons.markdown,
127
+ };
128
+
129
+ /**
130
+ * Get the appropriate icon for a file or directory
131
+ */
132
+ function getIcon(filename, isDirectory) {
133
+ if (isDirectory) {
134
+ return icons.directory;
135
+ }
136
+
137
+ // Check special filenames first
138
+ if (filenameMap[filename]) {
139
+ return filenameMap[filename];
140
+ }
141
+
142
+ // Check by extension
143
+ const ext = path.extname(filename).toLowerCase();
144
+ if (extensionMap[ext]) {
145
+ return extensionMap[ext];
146
+ }
147
+
148
+ return icons.default;
149
+ }
150
+
151
+ /**
152
+ * Build directory tree structure
153
+ */
154
+ function buildTree(dirPath, options = {}) {
155
+ const {
156
+ maxDepth = Infinity,
157
+ currentDepth = 0,
158
+ showHidden = false,
159
+ excludePatterns = []
160
+ } = options;
161
+
162
+ if (currentDepth >= maxDepth) {
163
+ return null;
164
+ }
165
+
166
+ try {
167
+ const stats = fs.statSync(dirPath);
168
+ const name = path.basename(dirPath);
169
+
170
+ // Check if should exclude
171
+ if (!showHidden && name.startsWith('.')) {
172
+ return null;
173
+ }
174
+
175
+ for (const pattern of excludePatterns) {
176
+ if (name.match(pattern)) {
177
+ return null;
178
+ }
179
+ }
180
+
181
+ if (!stats.isDirectory()) {
182
+ return {
183
+ name,
184
+ type: 'file',
185
+ icon: getIcon(name, false),
186
+ path: dirPath
187
+ };
188
+ }
189
+
190
+ // It's a directory
191
+ const children = [];
192
+ const entries = fs.readdirSync(dirPath);
193
+
194
+ for (const entry of entries) {
195
+ const childPath = path.join(dirPath, entry);
196
+ const childTree = buildTree(childPath, {
197
+ ...options,
198
+ currentDepth: currentDepth + 1
199
+ });
200
+
201
+ if (childTree) {
202
+ children.push(childTree);
203
+ }
204
+ }
205
+
206
+ // Sort: directories first, then files, alphabetically
207
+ children.sort((a, b) => {
208
+ if (a.type !== b.type) {
209
+ return a.type === 'directory' ? -1 : 1;
210
+ }
211
+ return a.name.localeCompare(b.name);
212
+ });
213
+
214
+ return {
215
+ name,
216
+ type: 'directory',
217
+ icon: getIcon(name, true),
218
+ path: dirPath,
219
+ children
220
+ };
221
+ } catch (error) {
222
+ console.error(`Error reading ${dirPath}:`, error.message);
223
+ return null;
224
+ }
225
+ }
226
+
227
+ /**
228
+ * Render the tree structure as text
229
+ */
230
+ function renderTree(tree, options = {}) {
231
+ const {
232
+ prefix = '',
233
+ isLast = true,
234
+ showIcons = true,
235
+ showPaths = false
236
+ } = options;
237
+
238
+ if (!tree) return '';
239
+
240
+ const lines = [];
241
+ const connector = isLast ? 'โ””โ”€โ”€ ' : 'โ”œโ”€โ”€ ';
242
+ const icon = showIcons ? `${tree.icon} ` : '';
243
+ const pathInfo = showPaths ? ` (${tree.path})` : '';
244
+
245
+ lines.push(`${prefix}${connector}${icon}${tree.name}${pathInfo}`);
246
+
247
+ if (tree.children && tree.children.length > 0) {
248
+ const newPrefix = prefix + (isLast ? ' ' : 'โ”‚ ');
249
+
250
+ tree.children.forEach((child, index) => {
251
+ const childIsLast = index === tree.children.length - 1;
252
+ lines.push(renderTree(child, {
253
+ ...options,
254
+ prefix: newPrefix,
255
+ isLast: childIsLast
256
+ }));
257
+ });
258
+ }
259
+
260
+ return lines.join('\n');
261
+ }
262
+
263
+ /**
264
+ * Get statistics about the tree
265
+ */
266
+ function getTreeStats(tree) {
267
+ if (!tree) {
268
+ return { files: 0, directories: 0 };
269
+ }
270
+
271
+ let files = 0;
272
+ let directories = 0;
273
+
274
+ if (tree.type === 'file') {
275
+ files = 1;
276
+ } else if (tree.type === 'directory') {
277
+ directories = 1;
278
+ if (tree.children) {
279
+ tree.children.forEach(child => {
280
+ const childStats = getTreeStats(child);
281
+ files += childStats.files;
282
+ directories += childStats.directories;
283
+ });
284
+ }
285
+ }
286
+
287
+ return { files, directories };
288
+ }
289
+
290
+ module.exports = {
291
+ buildTree,
292
+ renderTree,
293
+ getTreeStats,
294
+ getIcon,
295
+ icons
296
+ };
package/package.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "@crashbytes/dendro",
3
+ "version": "1.0.0",
4
+ "description": "A beautiful directory tree visualization CLI with file type icons - dendro (ฮดฮญฮฝฮดฯฮฟ) means 'tree' in Greek",
5
+ "main": "index.js",
6
+ "bin": {
7
+ "dendro": "./bin/cli.js"
8
+ },
9
+ "scripts": {
10
+ "test": "node test.js"
11
+ },
12
+ "keywords": [
13
+ "directory",
14
+ "tree",
15
+ "cli",
16
+ "file-tree",
17
+ "icons",
18
+ "visualization"
19
+ ],
20
+ "author": "CrashBytes",
21
+ "license": "MIT",
22
+ "dependencies": {
23
+ "commander": "^11.1.0",
24
+ "chalk": "^4.1.2"
25
+ },
26
+ "engines": {
27
+ "node": ">=14.0.0"
28
+ }
29
+ }
@@ -0,0 +1,37 @@
1
+ #!/bin/bash
2
+
3
+ echo "๐ŸŒณ Setting up dendro package..."
4
+ echo ""
5
+
6
+ # Navigate to the package directory
7
+ cd "$(dirname "$0")"
8
+
9
+ echo "๐Ÿ“ฆ Installing dependencies..."
10
+ npm install
11
+
12
+ echo ""
13
+ echo "โœ… Installation complete!"
14
+ echo ""
15
+ echo "๐Ÿงช Running tests..."
16
+ echo ""
17
+ node test.js
18
+
19
+ echo ""
20
+ echo "๐Ÿ“‹ Available commands:"
21
+ echo ""
22
+ echo " 1. Test locally:"
23
+ echo " node bin/cli.js"
24
+ echo ""
25
+ echo " 2. Test on a specific directory:"
26
+ echo " node bin/cli.js ~/github/crashbytes -d 2"
27
+ echo ""
28
+ echo " 3. Install globally (link):"
29
+ echo " npm link"
30
+ echo " Then run: dendro"
31
+ echo ""
32
+ echo " 4. Show help:"
33
+ echo " node bin/cli.js --help"
34
+ echo ""
35
+ echo " 5. Visualize the dendro project itself:"
36
+ echo " node bin/cli.js . -d 2"
37
+ echo ""
package/test/test.js ADDED
@@ -0,0 +1,52 @@
1
+ const { buildTree, treeToString, getIcon } = require('../index');
2
+ const path = require('path');
3
+
4
+ console.log('๐Ÿงช Running crashbytes-tree tests...\n');
5
+
6
+ // Test 1: Icon recognition
7
+ console.log('Test 1: Icon Recognition');
8
+ console.log('------------------------');
9
+ console.log('Folder icon:', getIcon('my-folder', true));
10
+ console.log('JavaScript icon:', getIcon('app.js', false));
11
+ console.log('JSON icon:', getIcon('package.json', false));
12
+ console.log('Markdown icon:', getIcon('README.md', false));
13
+ console.log('node_modules icon:', getIcon('node_modules', true));
14
+ console.log('โœ… Icon recognition test passed\n');
15
+
16
+ // Test 2: Build tree structure
17
+ console.log('Test 2: Build Tree Structure');
18
+ console.log('------------------------');
19
+ try {
20
+ const tree = buildTree(path.join(__dirname, '..'), {
21
+ maxDepth: 1,
22
+ showHidden: false,
23
+ ignorePatterns: ['node_modules', '.git']
24
+ });
25
+
26
+ console.log('Root name:', tree.name);
27
+ console.log('Root type:', tree.type);
28
+ console.log('Root icon:', tree.icon);
29
+ console.log('Children count:', tree.children ? tree.children.length : 0);
30
+ console.log('โœ… Build tree test passed\n');
31
+ } catch (error) {
32
+ console.error('โŒ Build tree test failed:', error.message);
33
+ }
34
+
35
+ // Test 3: Tree to string conversion
36
+ console.log('Test 3: Tree to String');
37
+ console.log('------------------------');
38
+ try {
39
+ const tree = buildTree(path.join(__dirname, '..'), {
40
+ maxDepth: 2,
41
+ showHidden: false,
42
+ ignorePatterns: ['node_modules', '.git', 'test']
43
+ });
44
+
45
+ const treeString = treeToString(tree);
46
+ console.log(treeString);
47
+ console.log('โœ… Tree to string test passed\n');
48
+ } catch (error) {
49
+ console.error('โŒ Tree to string test failed:', error.message);
50
+ }
51
+
52
+ console.log('โœ… All tests completed!');
package/test.js ADDED
@@ -0,0 +1,57 @@
1
+ const { buildTree, renderTree, getTreeStats, getIcon } = require('./index');
2
+ const path = require('path');
3
+
4
+ console.log('Running tests for dendro...\n');
5
+
6
+ // Test 1: Icon selection
7
+ console.log('Test 1: Icon Selection');
8
+ console.log('JavaScript file:', getIcon('app.js', false));
9
+ console.log('TypeScript file:', getIcon('component.tsx', false));
10
+ console.log('JSON file:', getIcon('package.json', false));
11
+ console.log('Markdown file:', getIcon('README.md', false));
12
+ console.log('Directory:', getIcon('src', true));
13
+ console.log('โœ“ Icon selection test passed\n');
14
+
15
+ // Test 2: Build tree for current directory (limited depth)
16
+ console.log('Test 2: Build Tree');
17
+ const testPath = path.resolve('.');
18
+ const tree = buildTree(testPath, {
19
+ maxDepth: 2,
20
+ showHidden: false,
21
+ excludePatterns: [/node_modules/, /\.git/]
22
+ });
23
+
24
+ if (tree && tree.type === 'directory') {
25
+ console.log('โœ“ Tree built successfully');
26
+ console.log(` Root: ${tree.name}`);
27
+ console.log(` Children: ${tree.children ? tree.children.length : 0}`);
28
+ } else {
29
+ console.log('โœ— Tree build failed');
30
+ }
31
+ console.log();
32
+
33
+ // Test 3: Render tree
34
+ console.log('Test 3: Render Tree (first 2 levels)');
35
+ const rendered = renderTree(tree, {
36
+ showIcons: true,
37
+ showPaths: false
38
+ });
39
+
40
+ if (rendered && rendered.length > 0) {
41
+ console.log('โœ“ Tree rendered successfully');
42
+ console.log('\nPreview:');
43
+ console.log(rendered.split('\n').slice(0, 15).join('\n'));
44
+ console.log('...');
45
+ } else {
46
+ console.log('โœ— Tree render failed');
47
+ }
48
+ console.log();
49
+
50
+ // Test 4: Statistics
51
+ console.log('Test 4: Statistics');
52
+ const stats = getTreeStats(tree);
53
+ console.log(`Files: ${stats.files}`);
54
+ console.log(`Directories: ${stats.directories}`);
55
+ console.log('โœ“ Statistics test passed\n');
56
+
57
+ console.log('All tests completed!');