@lakindu_perera/toren 1.0.3 → 1.0.4

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 CHANGED
@@ -62,6 +62,12 @@ toren --format markdown > PROJECT_REPORT.md
62
62
  toren --format html > report.html
63
63
  toren --format json > scan.json
64
64
 
65
+ # Focused Output Modes (Mutually Exclusive)
66
+ toren --project-type
67
+ toren --frameworks
68
+ toren --entry-points
69
+ toren --structure
70
+
65
71
  # Lifecycle & Help Commands
66
72
  toren --help
67
73
  toren --version
@@ -74,6 +80,10 @@ toren --uninstall
74
80
  | Flag | Description |
75
81
  |------|-------------|
76
82
  | `[path]` | Directory to scan. Defaults to the current directory (`.`). |
83
+ | `--project-type` | Show detected project type only. |
84
+ | `--frameworks` | Show detected frameworks only. |
85
+ | `--entry-points` | Show detected entry points only. |
86
+ | `--structure` | Show repository structure only. |
77
87
  | `--format <type>` | Output format: `console` (default), `json`, `markdown`, `html`. |
78
88
  | `--include-hidden` | Include hidden files and dot-directories in the scan. |
79
89
  | `--max-files <N>` | Override the default 50,000-file scan limit. |
@@ -83,16 +93,33 @@ toren --uninstall
83
93
  | `--uninstall` | Safely remove Toren from the global npm environment. |
84
94
 
85
95
  > **Note:** `--format md` is not a valid alias. Use `--format markdown` in full.
96
+ > **Note:** Focused output flags (`--project-type`, `--frameworks`, `--entry-points`, `--structure`) are mutually exclusive.
86
97
 
87
98
  ---
88
99
 
89
100
  ## Output Examples
90
101
 
102
+ ### Focused Output Example
103
+ Sometimes you only need a specific piece of intelligence for use in a script or a quick lookup. Use the focused output flags to bypass the full report:
104
+
105
+ ```bash
106
+ $ toren --project-type
107
+ Project Type: Node.js / JavaScript
108
+
109
+ $ toren --frameworks
110
+ Frameworks:
111
+ - React
112
+
113
+ $ toren --entry-points
114
+ Entry Points:
115
+ - src/main.tsx
116
+ ```
117
+
91
118
  ### Console Output Example
92
119
  The default `console` format renders a beautiful summary directly in your terminal:
93
120
 
94
121
  ```text
95
- Toren v1.0.3 — Codebase Onboarding Intelligence
122
+ Toren v1.0.4 — Codebase Onboarding Intelligence
96
123
 
97
124
  🔍 Project Summary
98
125
  ────────────────────────────────────────────────────────────────────────────────
package/bin/toren.js CHANGED
@@ -25,6 +25,7 @@
25
25
  import { createRequire } from 'node:module';
26
26
  import { scan } from '../src/scanner/scan.js';
27
27
  import renderers from '../src/renderers/index.js';
28
+ import { getFocusedModeInfo, renderFocusedMode, FOCUSED_FLAGS } from '../src/focused-output.js';
28
29
  import { runDoctor, runUninstall } from '../src/lifecycle.js';
29
30
 
30
31
  const require = createRequire(import.meta.url);
@@ -44,14 +45,20 @@ function printHelp() {
44
45
  const formatList = SUPPORTED_FORMATS.map(f => ` ${f}`).join('\n');
45
46
  console.log(`
46
47
  \x1b[1mUsage:\x1b[0m
47
- toren [path] Scan a directory (defaults to current directory)
48
- toren --format <type> Select output format (default: console)
49
- toren --include-hidden Include hidden dot-files in the scan
50
- toren --max-files <N> Set max file scan limit (default: 50000)
51
- toren --help Show this help message
52
- toren --version Show version number
53
- toren --doctor Check global installation health
54
- toren --uninstall Safely remove global installation
48
+ toren [path] [options]
49
+
50
+ \x1b[1mOptions:\x1b[0m
51
+ --project-type Show detected project type only
52
+ --frameworks Show detected frameworks only
53
+ --entry-points Show detected entry points only
54
+ --structure Show repository structure only
55
+ --format <type> Output as console, json, markdown, or html
56
+ --include-hidden Include hidden files and folders
57
+ --max-files <n> Set scan file limit
58
+ --help Show this help message
59
+ --version Show version number
60
+ --doctor Run CLI diagnostics
61
+ --uninstall Remove Toren global installation
55
62
 
56
63
  \x1b[1mOutput Formats:\x1b[0m
57
64
  ${formatList}
@@ -140,6 +147,16 @@ function parseArgs() {
140
147
  format = 'json';
141
148
  }
142
149
 
150
+ // ── Focused Output Flags ────────────────────────────────────────────────
151
+ const focusedInfo = getFocusedModeInfo(args);
152
+
153
+ if (focusedInfo.error) {
154
+ console.error(focusedInfo.message);
155
+ return { action: 'exit', code: 1 };
156
+ }
157
+
158
+ const focusedMode = focusedInfo.mode;
159
+
143
160
  // ── Hidden files ────────────────────────────────────────────────────────
144
161
  const includeHidden = args.includes('--include-hidden');
145
162
 
@@ -184,6 +201,7 @@ function parseArgs() {
184
201
  '--uninstall',
185
202
  '--format',
186
203
  '--json',
204
+ ...FOCUSED_FLAGS,
187
205
  '--include-hidden',
188
206
  '--max-files',
189
207
  ]);
@@ -198,7 +216,7 @@ function parseArgs() {
198
216
  return { action: 'exit', code: 1 };
199
217
  }
200
218
 
201
- return { action: 'scan', target, format, includeHidden, maxFiles };
219
+ return { action: 'scan', target, format, includeHidden, maxFiles, focusedMode };
202
220
  }
203
221
 
204
222
  // ---------------------------------------------------------------------------
@@ -249,7 +267,12 @@ function assertValidFormat(format) {
249
267
  includeHidden: parsed.includeHidden,
250
268
  maxFiles: parsed.maxFiles,
251
269
  });
252
- render(result, { cwd: process.cwd() });
270
+
271
+ if (parsed.focusedMode) {
272
+ renderFocusedMode(parsed.focusedMode, result);
273
+ } else {
274
+ render(result, { cwd: process.cwd() });
275
+ }
253
276
  } catch (err) {
254
277
  // Render errors in the requested format where possible.
255
278
  if (parsed.format === 'json') {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lakindu_perera/toren",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "A powerful codebase scanner CLI tool for project analysis, framework detection, and understanding repository structure instantly.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -0,0 +1,71 @@
1
+ /**
2
+ * @fileoverview Focused output modes handling for Toren CLI.
3
+ */
4
+
5
+ import { renderStructure } from './renderers/console-renderer.js';
6
+
7
+ export const FOCUSED_FLAGS = [
8
+ '--project-type',
9
+ '--frameworks',
10
+ '--entry-points',
11
+ '--structure'
12
+ ];
13
+
14
+ /**
15
+ * Validates focused flags in the provided arguments.
16
+ *
17
+ * @param {string[]} args Process arguments
18
+ * @returns {{ error: boolean, message?: string, mode?: string|null }}
19
+ */
20
+ export function getFocusedModeInfo(args) {
21
+ const activeFlags = FOCUSED_FLAGS.filter(flag => args.includes(flag));
22
+
23
+ if (activeFlags.length > 1) {
24
+ return {
25
+ error: true,
26
+ message: '\x1b[31mError: focused output flags are mutually exclusive. Please use only one of:\x1b[0m\n' +
27
+ FOCUSED_FLAGS.map(f => ` ${f}`).join('\n') + '\n'
28
+ };
29
+ }
30
+
31
+ return {
32
+ error: false,
33
+ mode: activeFlags[0] || null
34
+ };
35
+ }
36
+
37
+ /**
38
+ * Renders the scan result based on the active focused mode.
39
+ *
40
+ * @param {string} mode Active focused mode flag
41
+ * @param {import('./scanner/scan.js').ScanResult} result
42
+ */
43
+ export function renderFocusedMode(mode, result) {
44
+ switch (mode) {
45
+ case '--project-type':
46
+ console.log(`Project Type: ${result.projectType}`);
47
+ break;
48
+
49
+ case '--frameworks':
50
+ if (!result.projectType || result.projectType === 'Unknown') {
51
+ console.log('Frameworks: None detected');
52
+ } else {
53
+ console.log('Frameworks:');
54
+ console.log(`- ${result.projectType}`);
55
+ }
56
+ break;
57
+
58
+ case '--entry-points':
59
+ if (!result.entryPoints || result.entryPoints.length === 0) {
60
+ console.log('Entry Points: None detected');
61
+ } else {
62
+ console.log('Entry Points:');
63
+ result.entryPoints.forEach(ep => console.log(`- ${ep}`));
64
+ }
65
+ break;
66
+
67
+ case '--structure':
68
+ renderStructure(result);
69
+ break;
70
+ }
71
+ }
@@ -99,8 +99,11 @@ function row(label, value, ...valueCodes) {
99
99
  * @param {string} prefix - Accumulated indentation
100
100
  * @param {boolean} isLast - Whether this is the last sibling
101
101
  * @param {{ count: number, maxReached: boolean }} counter - Shared mutable file counter
102
+ * @param {number} limit - Max files to render
103
+ * @param {number} depth - Current depth
104
+ * @param {number} maxDepth - Max recursion depth
102
105
  */
103
- function renderTree(node, prefix, isLast, counter, depth = 0, maxDepth = 4) {
106
+ function renderTree(node, prefix, isLast, counter, limit = PREVIEW_LIMIT, depth = 0, maxDepth = 4) {
104
107
  if (counter.maxReached) return;
105
108
  if (depth >= maxDepth) return;
106
109
 
@@ -117,7 +120,7 @@ function renderTree(node, prefix, isLast, counter, depth = 0, maxDepth = 4) {
117
120
  }
118
121
 
119
122
  for (let i = 0; i < children.length; i++) {
120
- if (counter.count >= PREVIEW_LIMIT) {
123
+ if (counter.count >= limit) {
121
124
  console.log(`${prefix}${extension}└── ${paint('...', C.dim)}`);
122
125
  counter.maxReached = true;
123
126
  break;
@@ -125,7 +128,7 @@ function renderTree(node, prefix, isLast, counter, depth = 0, maxDepth = 4) {
125
128
  // Check if this child will be the last one we render due to limits
126
129
  let willBeLast = i === children.length - 1;
127
130
 
128
- renderTree(children[i], prefix + extension, willBeLast, counter, depth + 1, maxDepth);
131
+ renderTree(children[i], prefix + extension, willBeLast, counter, limit, depth + 1, maxDepth);
129
132
  if (counter.maxReached) break;
130
133
  }
131
134
  } else {
@@ -228,3 +231,28 @@ export function render(result, options = {}) {
228
231
  console.log(paint(' ✅ Scan complete.', C.green));
229
232
  console.log('');
230
233
  }
234
+
235
+ /**
236
+ * Render only the project structure for the --structure flag.
237
+ *
238
+ * @param {import('../scanner/scan.js').ScanResult} result
239
+ */
240
+ export function renderStructure(result) {
241
+ const { tree, flatFiles } = result;
242
+
243
+ console.log(paint('Project Structure:', C.bold, C.white));
244
+ console.log(paint(`${tree.name || '.'}/`, C.bold, C.blue));
245
+
246
+ const counter = { count: 0, maxReached: false };
247
+ const children = tree.children ?? [];
248
+ const limit = flatFiles.length; // No preview limit for focused --structure
249
+
250
+ for (let i = 0; i < children.length; i++) {
251
+ if (counter.count >= limit) {
252
+ console.log(`└── ${paint('...', C.dim)}`);
253
+ break;
254
+ }
255
+ renderTree(children[i], '', i === children.length - 1, counter, limit, 0, Infinity);
256
+ if (counter.maxReached) break;
257
+ }
258
+ }