@lakindu_perera/toren 1.0.7 → 1.0.9

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.
Files changed (61) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +120 -31
  3. package/dist/cli/toren.d.ts +24 -0
  4. package/dist/cli/toren.js +254 -0
  5. package/dist/cli/toren.js.map +1 -0
  6. package/dist/detectors/config-detector.d.ts +3 -0
  7. package/dist/detectors/config-detector.js +58 -0
  8. package/dist/detectors/config-detector.js.map +1 -0
  9. package/dist/detectors/health-detector.d.ts +12 -0
  10. package/dist/detectors/health-detector.js +53 -0
  11. package/dist/detectors/health-detector.js.map +1 -0
  12. package/dist/detectors/important-files-detector.d.ts +51 -0
  13. package/dist/detectors/important-files-detector.js +455 -0
  14. package/dist/detectors/important-files-detector.js.map +1 -0
  15. package/dist/detectors/package-manager-detector.d.ts +7 -0
  16. package/dist/detectors/package-manager-detector.js +35 -0
  17. package/dist/detectors/package-manager-detector.js.map +1 -0
  18. package/dist/detectors/project-info-detector.d.ts +13 -0
  19. package/dist/detectors/project-info-detector.js +97 -0
  20. package/dist/detectors/project-info-detector.js.map +1 -0
  21. package/dist/detectors/script-detector.d.ts +42 -0
  22. package/dist/detectors/script-detector.js +199 -0
  23. package/dist/detectors/script-detector.js.map +1 -0
  24. package/dist/focused-output.d.ts +27 -0
  25. package/dist/focused-output.js +201 -0
  26. package/dist/focused-output.js.map +1 -0
  27. package/dist/lifecycle.d.ts +2 -0
  28. package/dist/lifecycle.js +114 -0
  29. package/dist/lifecycle.js.map +1 -0
  30. package/dist/renderers/console-renderer.d.ts +19 -0
  31. package/dist/renderers/console-renderer.js +361 -0
  32. package/dist/renderers/console-renderer.js.map +1 -0
  33. package/dist/renderers/html-renderer.d.ts +14 -0
  34. package/{src → dist}/renderers/html-renderer.js +263 -201
  35. package/dist/renderers/html-renderer.js.map +1 -0
  36. package/dist/renderers/index.d.ts +6 -0
  37. package/dist/renderers/index.js +12 -0
  38. package/dist/renderers/index.js.map +1 -0
  39. package/dist/renderers/json-renderer.d.ts +10 -0
  40. package/dist/renderers/json-renderer.js +127 -0
  41. package/dist/renderers/json-renderer.js.map +1 -0
  42. package/dist/renderers/markdown-renderer.d.ts +13 -0
  43. package/dist/renderers/markdown-renderer.js +360 -0
  44. package/dist/renderers/markdown-renderer.js.map +1 -0
  45. package/dist/scanner/scan.d.ts +2 -0
  46. package/dist/scanner/scan.js +573 -0
  47. package/dist/scanner/scan.js.map +1 -0
  48. package/dist/types/index.d.ts +85 -0
  49. package/dist/types/index.js +2 -0
  50. package/dist/types/index.js.map +1 -0
  51. package/package.json +16 -7
  52. package/bin/toren.js +0 -308
  53. package/src/detectors/config-detector.js +0 -81
  54. package/src/detectors/script-detector.js +0 -32
  55. package/src/focused-output.js +0 -146
  56. package/src/lifecycle.js +0 -124
  57. package/src/renderers/console-renderer.js +0 -350
  58. package/src/renderers/index.js +0 -41
  59. package/src/renderers/json-renderer.js +0 -154
  60. package/src/renderers/markdown-renderer.js +0 -337
  61. package/src/scanner/scan.js +0 -532
@@ -1,337 +0,0 @@
1
- /**
2
- * @fileoverview Toren — Markdown Renderer
3
- *
4
- * Consumes a {@link ScanResult} and writes a polished, GitHub-flavored
5
- * Markdown report to stdout.
6
- *
7
- * Design contract (mirrors all other renderers):
8
- * - Accepts a ScanResult and an optional options object.
9
- * - Never scans files or modifies the data it receives.
10
- * - Produces only plain Markdown — no ANSI codes, no HTML, no emoji.
11
- * - All output goes to stdout so users can redirect freely:
12
- * toren --format markdown > PROJECT_REPORT.md
13
- *
14
- * Sections (in order):
15
- * 1. Title
16
- * 2. Project Summary (table)
17
- * 3. Entry Points (list)
18
- * 4. Folder Structure (fenced code block)
19
- * 5. Statistics (table)
20
- * 6. Scan Information
21
- *
22
- * @module renderers/markdown-renderer
23
- */
24
-
25
- import path from 'node:path';
26
-
27
- // ---------------------------------------------------------------------------
28
- // Plain-text tree builder (Markdown-safe, no ANSI, no emoji)
29
- // ---------------------------------------------------------------------------
30
-
31
-
32
-
33
- /**
34
- * Recursively serialise a tree node into classic tree-connector lines.
35
- * Output is plain ASCII — safe for any Markdown renderer.
36
- *
37
- * @param {object} node - Current tree node
38
- * @param {string} prefix - Accumulated prefix string for indentation
39
- * @param {boolean} isLast - Whether this node is the last sibling
40
- * @param {string[]} lines - Accumulator for output lines
41
- * @param {number} depth - Current recursion depth
42
- * @param {number} maxDepth - Maximum depth to render
43
- */
44
- function serializeNode(node, prefix, isLast, lines, depth = 0, maxDepth = 5) {
45
- if (depth >= maxDepth) return;
46
-
47
- const connector = isLast ? '└── ' : '├── ';
48
- const childPad = isLast ? ' ' : '│ ';
49
- const label = node.type === 'directory' ? `${node.name}/` : node.name;
50
-
51
- lines.push(`${prefix}${connector}${label}`);
52
-
53
- if (node.type === 'directory') {
54
- const children = node.children || [];
55
-
56
- // Truncate deep directories with an ellipsis rather than cutting silently.
57
- if (depth === maxDepth - 1 && children.length > 0) {
58
- lines.push(`${prefix}${childPad}└── ...`);
59
- return;
60
- }
61
-
62
- for (let i = 0; i < children.length; i++) {
63
- serializeNode(
64
- children[i],
65
- prefix + childPad,
66
- i === children.length - 1,
67
- lines,
68
- depth + 1,
69
- maxDepth,
70
- );
71
- }
72
- }
73
- }
74
-
75
- /**
76
- * Convert a ScanResult tree into a Markdown-safe tree string.
77
- *
78
- * @param {import('../scanner/scan.js').DirNode} tree
79
- * @param {string} rootName - Display name for the root node (e.g. "my-app/")
80
- * @param {number} totalFiles
81
- * @returns {string}
82
- */
83
- function buildTreeString(tree, rootName, totalFiles) {
84
- if (totalFiles === 0) return '';
85
-
86
- const lines = [`${rootName}/`];
87
- const children = tree.children || [];
88
-
89
- for (let i = 0; i < children.length; i++) {
90
- serializeNode(children[i], '', i === children.length - 1, lines);
91
- }
92
-
93
- return lines.join('\n');
94
- }
95
-
96
- // ---------------------------------------------------------------------------
97
- // Formatting helpers
98
- // ---------------------------------------------------------------------------
99
-
100
- /**
101
- * Format a scan duration in milliseconds to a human-readable string.
102
- *
103
- * @param {number} ms
104
- * @returns {string}
105
- */
106
- function formatDuration(ms) {
107
- if (ms < 1) return '< 1 ms';
108
- if (ms >= 1000) return `${(ms / 1000).toFixed(2)} s`;
109
- return `${Math.round(ms)} ms`;
110
- }
111
-
112
- /**
113
- * Build a Markdown table from an array of two-element [label, value] pairs.
114
- * Column widths are padded to keep the source Markdown tidy.
115
- *
116
- * @param {[string, string][]} rows
117
- * @returns {string}
118
- */
119
- function markdownTable(rows) {
120
- const colA = Math.max(8, ...rows.map(([k]) => k.length));
121
- const colB = Math.max(5, ...rows.map(([, v]) => String(v).length));
122
-
123
- const pad = (s, n) => String(s).padEnd(n);
124
- const hr = `|${'-'.repeat(colA + 2)}|${'-'.repeat(colB + 2)}|`;
125
- const head = `| ${pad('Property', colA)} | ${pad('Value', colB)} |`;
126
- const body = rows.map(([k, v]) => `| ${pad(k, colA)} | ${pad(v, colB)} |`);
127
-
128
- return [head, hr, ...body].join('\n');
129
- }
130
-
131
- /**
132
- * Derive a frameworks array from the projectType string.
133
- * Returns [] when no specific framework is detected.
134
- * Mirrors the identical derivation in console-renderer.js and json-renderer.js.
135
- *
136
- * @param {string} projectType
137
- * @returns {string[]}
138
- */
139
- function deriveFrameworks(projectType) {
140
- if (!projectType || projectType === 'Unknown') return [];
141
- return [projectType];
142
- }
143
-
144
- /**
145
- * Build a right-aligned Markdown table (used for statistics).
146
- *
147
- * @param {[string, string|number][]} rows
148
- * @returns {string}
149
- */
150
- function statsTable(rows) {
151
- const colA = Math.max(6, ...rows.map(([k]) => k.length));
152
- const colB = Math.max(5, ...rows.map(([, v]) => String(v).length));
153
-
154
- const padL = (s, n) => String(s).padEnd(n);
155
- const padR = (s, n) => String(s).padStart(n);
156
- const hr = `|${'-'.repeat(colA + 2)}|${'-'.repeat(colB + 1)}:|`;
157
- const head = `| ${padL('Metric', colA)} | ${padR('Value', colB)} |`;
158
- const body = rows.map(([k, v]) => `| ${padL(k, colA)} | ${padR(v, colB)} |`);
159
-
160
- return [head, hr, ...body].join('\n');
161
- }
162
-
163
- // ---------------------------------------------------------------------------
164
- // Section builders (private — one function per report section)
165
- // ---------------------------------------------------------------------------
166
-
167
- /** @param {string[]} out */
168
- function sectionTitle(out) {
169
- out.push('# Toren Report');
170
- out.push('');
171
- out.push('Generated by **Toren** — Codebase Onboarding Intelligence');
172
- }
173
-
174
- /**
175
- * @param {string[]} out
176
- * @param {import('../scanner/scan.js').ScanResult} result
177
- * @param {string} relRoot
178
- */
179
- function sectionSummary(out, result, relRoot) {
180
- const { projectType, flatFiles, totalFolders } = result;
181
-
182
- out.push('');
183
- out.push('## Project');
184
- out.push('');
185
- out.push(markdownTable([
186
- ['Project Type', projectType],
187
- ['Scan Path', relRoot],
188
- ['Total Files', String(flatFiles.length)],
189
- ['Total Folders', String(totalFolders)],
190
- ]));
191
- }
192
-
193
- /**
194
- * @param {string[]} out
195
- * @param {string} projectType
196
- */
197
- function sectionFrameworks(out, projectType) {
198
- const frameworks = deriveFrameworks(projectType);
199
-
200
- out.push('');
201
- out.push('## Frameworks');
202
- out.push('');
203
-
204
- if (frameworks.length === 0) {
205
- out.push('No frameworks detected.');
206
- } else {
207
- for (const fw of frameworks) {
208
- out.push(`- ${fw}`);
209
- }
210
- }
211
- }
212
-
213
- /**
214
- * @param {string[]} out
215
- * @param {string[]} configs
216
- */
217
- function sectionConfigurationFiles(out, configs) {
218
- out.push('');
219
- out.push('## Configurations');
220
- out.push('');
221
-
222
- if (configs.length === 0) {
223
- out.push('No configuration files detected.');
224
- } else {
225
- for (const c of configs) {
226
- out.push(`- ${c}`);
227
- }
228
- }
229
- }
230
-
231
- /**
232
- * @param {string[]} out
233
- * @param {Array<{name: string, command: string}>} scripts
234
- */
235
- function sectionPackageScripts(out, scripts) {
236
- out.push('');
237
- out.push('## Scripts');
238
- out.push('');
239
-
240
- if (scripts.length === 0) {
241
- out.push('No package scripts detected.');
242
- } else {
243
- for (const s of scripts) {
244
- out.push(`- ${s.name}: ${s.command}`);
245
- }
246
- }
247
- }
248
-
249
- /**
250
- * @param {string[]} out
251
- * @param {string[]} entryPoints
252
- */
253
- function sectionEntryPoints(out, entryPoints) {
254
- out.push('');
255
- out.push('## Entry Points');
256
- out.push('');
257
-
258
- if (entryPoints.length === 0) {
259
- out.push('No entry points detected.');
260
- } else {
261
- for (const ep of entryPoints) {
262
- out.push(`- ${ep}`);
263
- }
264
- }
265
- }
266
-
267
- /**
268
- * @param {string[]} out
269
- * @param {import('../scanner/scan.js').DirNode} tree
270
- * @param {number} totalFiles
271
- * @param {string} rootName
272
- */
273
- function sectionFolderStructure(out, tree, totalFiles, rootName) {
274
- // Contract: omit section entirely when no files were scanned.
275
- if (totalFiles === 0) return;
276
-
277
- out.push('');
278
- out.push('## Structure');
279
- out.push('');
280
-
281
- const treeStr = buildTreeString(tree, rootName, totalFiles);
282
- out.push('```text');
283
- out.push(treeStr);
284
- out.push('```');
285
- }
286
-
287
- /**
288
- * @param {string[]} out
289
- * @param {import('../scanner/scan.js').ScanResult} result
290
- */
291
- function sectionStatistics(out, result) {
292
- const { flatFiles, totalFolders, scanDurationMs } = result;
293
-
294
- out.push('');
295
- out.push('## Statistics');
296
- out.push('');
297
- out.push(statsTable([
298
- ['Files', flatFiles.length],
299
- ['Folders', totalFolders],
300
- ['Scan Duration', formatDuration(scanDurationMs)],
301
- ]));
302
- }
303
-
304
- // ---------------------------------------------------------------------------
305
- // Public API
306
- // ---------------------------------------------------------------------------
307
-
308
- /**
309
- * Render a ScanResult as a GitHub-flavored Markdown report to stdout.
310
- *
311
- * All sections are built into an in-memory string array and joined once
312
- * at the end — a single `console.log` call keeps stdout writes atomic.
313
- *
314
- * @param {import('../scanner/scan.js').ScanResult} result
315
- * @param {{ cwd?: string }} [options]
316
- */
317
- export function render(result, options = {}) {
318
- const { rootPath, projectType, entryPoints, configs = [], scripts = [], flatFiles, tree } = result;
319
-
320
- const cwd = options.cwd ?? process.cwd();
321
- const relRoot = path.relative(cwd, rootPath) || '.';
322
- const rootName = relRoot === '.' ? path.basename(rootPath) : relRoot;
323
-
324
- /** @type {string[]} */
325
- const out = [];
326
-
327
- sectionTitle(out);
328
- sectionSummary(out, result, relRoot);
329
- sectionFrameworks(out, projectType);
330
- sectionEntryPoints(out, entryPoints);
331
- sectionConfigurationFiles(out, configs);
332
- sectionPackageScripts(out, scripts);
333
- sectionStatistics(out, result);
334
- sectionFolderStructure(out, tree, flatFiles.length, rootName);
335
-
336
- console.log(out.join('\n'));
337
- }