treeviz-cli 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/README.md +47 -0
- package/dist/index.js +182 -0
- package/package.json +35 -0
package/README.md
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# @treeviz/cli
|
|
2
|
+
|
|
3
|
+
Generate ASCII directory trees from the terminal. Zero dependencies, powered by Bun.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
bun add -g @treeviz/cli
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# Current directory
|
|
15
|
+
treeviz
|
|
16
|
+
|
|
17
|
+
# Specific path
|
|
18
|
+
treeviz ./src
|
|
19
|
+
|
|
20
|
+
# Add custom ignores
|
|
21
|
+
treeviz --ignore .env,coverage
|
|
22
|
+
|
|
23
|
+
# Disable default ignores
|
|
24
|
+
treeviz --no-default-ignores
|
|
25
|
+
|
|
26
|
+
# Copy output to clipboard
|
|
27
|
+
treeviz --copy
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Options
|
|
31
|
+
|
|
32
|
+
| Option | Alias | Description |
|
|
33
|
+
|--------|-------|-------------|
|
|
34
|
+
| `[path]` | | Directory to visualize (default: `.`) |
|
|
35
|
+
| `--ignore <folders>` | `-i` | Comma-separated folders to add to ignore list |
|
|
36
|
+
| `--no-default-ignores` | | Disable the default ignore list |
|
|
37
|
+
| `--copy` | `-c` | Copy output to clipboard |
|
|
38
|
+
| `--help` | `-h` | Show help |
|
|
39
|
+
| `--version` | `-v` | Show version |
|
|
40
|
+
|
|
41
|
+
## Default Ignores
|
|
42
|
+
|
|
43
|
+
`node_modules`, `.git`, `.next`, `.husky`, `.turbo`, `dist`, `build`, `.DS_Store`
|
|
44
|
+
|
|
45
|
+
## Web Version
|
|
46
|
+
|
|
47
|
+
Try the browser-based version at [treeviz.dev](https://treeviz.dev) — select a folder and get the same output with zero uploads.
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
// @bun
|
|
3
|
+
|
|
4
|
+
// src/index.ts
|
|
5
|
+
import { existsSync, statSync } from "fs";
|
|
6
|
+
import { resolve } from "path";
|
|
7
|
+
|
|
8
|
+
// src/tree-generator.ts
|
|
9
|
+
import { readdirSync } from "fs";
|
|
10
|
+
import { join, basename } from "path";
|
|
11
|
+
var DEFAULT_IGNORES = [
|
|
12
|
+
"node_modules",
|
|
13
|
+
".git",
|
|
14
|
+
".next",
|
|
15
|
+
".husky",
|
|
16
|
+
".turbo",
|
|
17
|
+
"dist",
|
|
18
|
+
"build",
|
|
19
|
+
".DS_Store"
|
|
20
|
+
];
|
|
21
|
+
function traverseDirectory(dirPath, ignoreList = DEFAULT_IGNORES) {
|
|
22
|
+
const entries = readdirSync(dirPath, { withFileTypes: true });
|
|
23
|
+
const children = [];
|
|
24
|
+
for (const entry of entries) {
|
|
25
|
+
if (ignoreList.includes(entry.name))
|
|
26
|
+
continue;
|
|
27
|
+
if (entry.isDirectory()) {
|
|
28
|
+
const childNode = traverseDirectory(join(dirPath, entry.name), ignoreList);
|
|
29
|
+
children.push(childNode);
|
|
30
|
+
} else {
|
|
31
|
+
children.push({ name: entry.name, type: "file" });
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
children.sort((a, b) => {
|
|
35
|
+
if (a.type !== b.type)
|
|
36
|
+
return a.type === "directory" ? -1 : 1;
|
|
37
|
+
return a.name.localeCompare(b.name);
|
|
38
|
+
});
|
|
39
|
+
return {
|
|
40
|
+
name: basename(dirPath),
|
|
41
|
+
type: "directory",
|
|
42
|
+
children
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function generateAsciiTree(node, prefix = "", isRoot = true) {
|
|
46
|
+
let result = "";
|
|
47
|
+
if (isRoot) {
|
|
48
|
+
result += node.name + `/
|
|
49
|
+
`;
|
|
50
|
+
}
|
|
51
|
+
const children = node.children ?? [];
|
|
52
|
+
children.forEach((child, index) => {
|
|
53
|
+
const isLast = index === children.length - 1;
|
|
54
|
+
const connector = isLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
|
|
55
|
+
const childPrefix = isLast ? " " : "\u2502 ";
|
|
56
|
+
const suffix = child.type === "directory" ? "/" : "";
|
|
57
|
+
result += prefix + connector + child.name + suffix + `
|
|
58
|
+
`;
|
|
59
|
+
if (child.type === "directory" && child.children?.length) {
|
|
60
|
+
result += generateAsciiTree(child, prefix + childPrefix, false);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// src/index.ts
|
|
67
|
+
var VERSION = "1.0.0";
|
|
68
|
+
var HELP = `
|
|
69
|
+
treeviz - Generate ASCII directory trees
|
|
70
|
+
|
|
71
|
+
Usage:
|
|
72
|
+
treeviz [path] [options]
|
|
73
|
+
|
|
74
|
+
Arguments:
|
|
75
|
+
path Directory to visualize (default: current directory)
|
|
76
|
+
|
|
77
|
+
Options:
|
|
78
|
+
-i, --ignore <folders> Comma-separated folders to ignore (added to defaults)
|
|
79
|
+
--no-default-ignores Disable the default ignore list
|
|
80
|
+
-c, --copy Copy output to clipboard
|
|
81
|
+
-h, --help Show this help message
|
|
82
|
+
-v, --version Show version
|
|
83
|
+
|
|
84
|
+
Default ignores:
|
|
85
|
+
${DEFAULT_IGNORES.join(", ")}
|
|
86
|
+
|
|
87
|
+
Examples:
|
|
88
|
+
treeviz
|
|
89
|
+
treeviz ./src
|
|
90
|
+
treeviz --ignore .env,coverage
|
|
91
|
+
treeviz --no-default-ignores
|
|
92
|
+
treeviz --copy
|
|
93
|
+
`.trim();
|
|
94
|
+
function parseArgs(argv) {
|
|
95
|
+
const args = argv.slice(2);
|
|
96
|
+
let targetPath = ".";
|
|
97
|
+
let extraIgnores = [];
|
|
98
|
+
let useDefaultIgnores = true;
|
|
99
|
+
let copyToClipboard = false;
|
|
100
|
+
for (let i = 0;i < args.length; i++) {
|
|
101
|
+
const arg = args[i];
|
|
102
|
+
if (arg === "-h" || arg === "--help") {
|
|
103
|
+
console.log(HELP);
|
|
104
|
+
process.exit(0);
|
|
105
|
+
}
|
|
106
|
+
if (arg === "-v" || arg === "--version") {
|
|
107
|
+
console.log(`treeviz v${VERSION}`);
|
|
108
|
+
process.exit(0);
|
|
109
|
+
}
|
|
110
|
+
if (arg === "--no-default-ignores") {
|
|
111
|
+
useDefaultIgnores = false;
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
if (arg === "-c" || arg === "--copy") {
|
|
115
|
+
copyToClipboard = true;
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
if (arg === "-i" || arg === "--ignore") {
|
|
119
|
+
const next = args[++i];
|
|
120
|
+
if (!next) {
|
|
121
|
+
console.error("Error: --ignore requires a value");
|
|
122
|
+
process.exit(1);
|
|
123
|
+
}
|
|
124
|
+
extraIgnores = next.split(",").map((s) => s.trim());
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
if (!arg.startsWith("-")) {
|
|
128
|
+
targetPath = arg;
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
console.error(`Unknown option: ${arg}`);
|
|
132
|
+
console.error('Run "treeviz --help" for usage');
|
|
133
|
+
process.exit(1);
|
|
134
|
+
}
|
|
135
|
+
return { targetPath, extraIgnores, useDefaultIgnores, copyToClipboard };
|
|
136
|
+
}
|
|
137
|
+
async function main() {
|
|
138
|
+
const { targetPath, extraIgnores, useDefaultIgnores, copyToClipboard } = parseArgs(process.argv);
|
|
139
|
+
const fullPath = resolve(targetPath);
|
|
140
|
+
if (!existsSync(fullPath)) {
|
|
141
|
+
console.error(`Error: Path does not exist: ${fullPath}`);
|
|
142
|
+
process.exit(1);
|
|
143
|
+
}
|
|
144
|
+
if (!statSync(fullPath).isDirectory()) {
|
|
145
|
+
console.error(`Error: Not a directory: ${fullPath}`);
|
|
146
|
+
process.exit(1);
|
|
147
|
+
}
|
|
148
|
+
const ignoreList = [
|
|
149
|
+
...useDefaultIgnores ? DEFAULT_IGNORES : [],
|
|
150
|
+
...extraIgnores
|
|
151
|
+
];
|
|
152
|
+
const tree = traverseDirectory(fullPath, ignoreList);
|
|
153
|
+
const output = generateAsciiTree(tree);
|
|
154
|
+
console.log(output);
|
|
155
|
+
if (copyToClipboard) {
|
|
156
|
+
try {
|
|
157
|
+
const proc = Bun.spawn(["pbcopy"], {
|
|
158
|
+
stdin: "pipe"
|
|
159
|
+
});
|
|
160
|
+
proc.stdin.write(output);
|
|
161
|
+
proc.stdin.end();
|
|
162
|
+
await proc.exited;
|
|
163
|
+
console.log(`
|
|
164
|
+
\u2713 Copied to clipboard`);
|
|
165
|
+
} catch {
|
|
166
|
+
try {
|
|
167
|
+
const proc = Bun.spawn(["xclip", "-selection", "clipboard"], {
|
|
168
|
+
stdin: "pipe"
|
|
169
|
+
});
|
|
170
|
+
proc.stdin.write(output);
|
|
171
|
+
proc.stdin.end();
|
|
172
|
+
await proc.exited;
|
|
173
|
+
console.log(`
|
|
174
|
+
\u2713 Copied to clipboard`);
|
|
175
|
+
} catch {
|
|
176
|
+
console.error(`
|
|
177
|
+
\u2717 Could not copy to clipboard (pbcopy/xclip not found)`);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
main();
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "treeviz-cli",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Generate ASCII directory trees from the terminal",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"treeviz": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"dev": "bun run src/index.ts",
|
|
11
|
+
"build": "bun build ./src/index.ts --outdir ./dist --target bun"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist"
|
|
15
|
+
],
|
|
16
|
+
"keywords": [
|
|
17
|
+
"tree",
|
|
18
|
+
"directory",
|
|
19
|
+
"ascii",
|
|
20
|
+
"cli",
|
|
21
|
+
"file-tree"
|
|
22
|
+
],
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "https://github.com/bireycikan/treeviz-cli"
|
|
27
|
+
},
|
|
28
|
+
"homepage": "https://github.com/bireycikan/treeviz-cli#readme",
|
|
29
|
+
"bugs": {
|
|
30
|
+
"url": "https://github.com/bireycikan/treeviz-cli/issues"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"bun-types": "^1.3.8"
|
|
34
|
+
}
|
|
35
|
+
}
|