@lakindu_perera/toren 1.0.8 → 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 (64) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/cli/toren.d.ts +24 -0
  3. package/dist/cli/toren.js +254 -0
  4. package/dist/cli/toren.js.map +1 -0
  5. package/dist/detectors/config-detector.d.ts +3 -0
  6. package/dist/detectors/config-detector.js +58 -0
  7. package/dist/detectors/config-detector.js.map +1 -0
  8. package/dist/detectors/health-detector.d.ts +12 -0
  9. package/dist/detectors/health-detector.js +53 -0
  10. package/dist/detectors/health-detector.js.map +1 -0
  11. package/dist/detectors/important-files-detector.d.ts +51 -0
  12. package/dist/detectors/important-files-detector.js +455 -0
  13. package/dist/detectors/important-files-detector.js.map +1 -0
  14. package/dist/detectors/package-manager-detector.d.ts +7 -0
  15. package/dist/detectors/package-manager-detector.js +35 -0
  16. package/dist/detectors/package-manager-detector.js.map +1 -0
  17. package/dist/detectors/project-info-detector.d.ts +13 -0
  18. package/dist/detectors/project-info-detector.js +97 -0
  19. package/dist/detectors/project-info-detector.js.map +1 -0
  20. package/dist/detectors/script-detector.d.ts +42 -0
  21. package/dist/detectors/script-detector.js +199 -0
  22. package/dist/detectors/script-detector.js.map +1 -0
  23. package/dist/focused-output.d.ts +27 -0
  24. package/dist/focused-output.js +201 -0
  25. package/dist/focused-output.js.map +1 -0
  26. package/dist/lifecycle.d.ts +2 -0
  27. package/dist/lifecycle.js +114 -0
  28. package/dist/lifecycle.js.map +1 -0
  29. package/dist/renderers/console-renderer.d.ts +19 -0
  30. package/dist/renderers/console-renderer.js +361 -0
  31. package/dist/renderers/console-renderer.js.map +1 -0
  32. package/dist/renderers/html-renderer.d.ts +14 -0
  33. package/{src → dist}/renderers/html-renderer.js +181 -241
  34. package/dist/renderers/html-renderer.js.map +1 -0
  35. package/dist/renderers/index.d.ts +6 -0
  36. package/dist/renderers/index.js +12 -0
  37. package/dist/renderers/index.js.map +1 -0
  38. package/dist/renderers/json-renderer.d.ts +10 -0
  39. package/dist/renderers/json-renderer.js +127 -0
  40. package/dist/renderers/json-renderer.js.map +1 -0
  41. package/dist/renderers/markdown-renderer.d.ts +13 -0
  42. package/dist/renderers/markdown-renderer.js +360 -0
  43. package/dist/renderers/markdown-renderer.js.map +1 -0
  44. package/dist/scanner/scan.d.ts +2 -0
  45. package/dist/scanner/scan.js +573 -0
  46. package/dist/scanner/scan.js.map +1 -0
  47. package/dist/types/index.d.ts +85 -0
  48. package/dist/types/index.js +2 -0
  49. package/dist/types/index.js.map +1 -0
  50. package/package.json +11 -6
  51. package/bin/toren.js +0 -311
  52. package/src/detectors/config-detector.js +0 -81
  53. package/src/detectors/health-detector.js +0 -72
  54. package/src/detectors/important-files-detector.js +0 -515
  55. package/src/detectors/package-manager-detector.js +0 -112
  56. package/src/detectors/project-info-detector.js +0 -89
  57. package/src/detectors/script-detector.js +0 -248
  58. package/src/focused-output.js +0 -216
  59. package/src/lifecycle.js +0 -124
  60. package/src/renderers/console-renderer.js +0 -399
  61. package/src/renderers/index.js +0 -41
  62. package/src/renderers/json-renderer.js +0 -168
  63. package/src/renderers/markdown-renderer.js +0 -397
  64. package/src/scanner/scan.js +0 -554
@@ -1,397 +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, packageManager, projectInfo } = result;
181
-
182
- out.push('');
183
- out.push('## Project');
184
- out.push('');
185
-
186
- const rows = [];
187
- if (projectInfo && projectInfo.name) rows.push(['Name', projectInfo.name]);
188
- rows.push(['Project Type', projectType]);
189
- if (packageManager) rows.push(['Package Manager', packageManager]);
190
- if (projectInfo && projectInfo.runtime) rows.push(['Runtime', projectInfo.runtime]);
191
- if (projectInfo && projectInfo.language) rows.push(['Language', projectInfo.language]);
192
- if (projectInfo && projectInfo.architecture) rows.push(['Architecture', projectInfo.architecture]);
193
- if (projectInfo && projectInfo.framework) rows.push(['Framework', projectInfo.framework]);
194
- if (projectInfo && projectInfo.entryPoint) rows.push(['Entry Point', projectInfo.entryPoint]);
195
- if (projectInfo && projectInfo.sourceDirectory) rows.push(['Source Directory', projectInfo.sourceDirectory]);
196
-
197
- rows.push(['Scan Path', relRoot]);
198
- rows.push(['Total Files', String(flatFiles.length)]);
199
- rows.push(['Total Folders', String(totalFolders)]);
200
-
201
- out.push(markdownTable(rows));
202
- }
203
-
204
- /**
205
- * @param {string[]} out
206
- * @param {string} projectType
207
- */
208
- function sectionFrameworks(out, projectType) {
209
- const frameworks = deriveFrameworks(projectType);
210
-
211
- out.push('');
212
- out.push('## Frameworks');
213
- out.push('');
214
-
215
- if (frameworks.length === 0) {
216
- out.push('No frameworks detected.');
217
- } else {
218
- for (const fw of frameworks) {
219
- out.push(`- ${fw}`);
220
- }
221
- }
222
- }
223
-
224
- /**
225
- * @param {string[]} out
226
- * @param {string[]} configs
227
- */
228
- function sectionConfigurationFiles(out, configs) {
229
- out.push('');
230
- out.push('## Configurations');
231
- out.push('');
232
-
233
- if (configs.length === 0) {
234
- out.push('No configuration files detected.');
235
- } else {
236
- for (const c of configs) {
237
- out.push(`- ${c}`);
238
- }
239
- }
240
- }
241
-
242
- /**
243
- * @param {string[]} out
244
- * @param {Array<{name: string, command: string, description: string, usage: string}>} scripts
245
- */
246
- function sectionPackageScripts(out, scripts) {
247
- out.push('');
248
- out.push('## Scripts');
249
- out.push('');
250
-
251
- if (scripts.length === 0) {
252
- out.push('No package scripts detected.');
253
- } else {
254
- for (const s of scripts) {
255
- const usage = s.usage || `npm run ${s.name}`;
256
- out.push(`- **${usage}**`);
257
- if (s.description) {
258
- out.push(` ${s.description} `);
259
- out.push(` \`${s.command}\``);
260
- } else {
261
- out.push(` \`${s.command}\``);
262
- }
263
- }
264
- }
265
- }
266
-
267
- /**
268
- * @param {string[]} out
269
- * @param {Array<{path: string, reason: string}>} importantFiles
270
- */
271
- function sectionImportantFiles(out, importantFiles) {
272
- out.push('');
273
- out.push('## Important Files');
274
- out.push('');
275
-
276
- if (importantFiles.length === 0) {
277
- out.push('No important files detected.');
278
- } else {
279
- for (const f of importantFiles) {
280
- out.push(`- **${f.path}** `);
281
- out.push(` ${f.reason}`);
282
- }
283
- }
284
- }
285
-
286
- /**
287
- * @param {string[]} out
288
- * @param {Array<{id: string, status: string, message: string}>} health
289
- */
290
- function sectionProjectHealth(out, health) {
291
- out.push('');
292
- out.push('## Project Health');
293
- out.push('');
294
-
295
- if (health.length === 0) {
296
- out.push('No project health observations available.');
297
- } else {
298
- for (const h of health) {
299
- let icon = 'ℹ';
300
- if (h.status === 'pass') icon = '✓';
301
- else if (h.status === 'warning') icon = '⚠';
302
- out.push(`- ${icon} ${h.message}`);
303
- }
304
- }
305
- }
306
-
307
- /**
308
- * @param {string[]} out
309
- * @param {string[]} entryPoints
310
- */
311
- function sectionEntryPoints(out, entryPoints) {
312
- out.push('');
313
- out.push('## Entry Points');
314
- out.push('');
315
-
316
- if (entryPoints.length === 0) {
317
- out.push('No entry points detected.');
318
- } else {
319
- for (const ep of entryPoints) {
320
- out.push(`- ${ep}`);
321
- }
322
- }
323
- }
324
-
325
- /**
326
- * @param {string[]} out
327
- * @param {import('../scanner/scan.js').DirNode} tree
328
- * @param {number} totalFiles
329
- * @param {string} rootName
330
- */
331
- function sectionFolderStructure(out, tree, totalFiles, rootName) {
332
- // Contract: omit section entirely when no files were scanned.
333
- if (totalFiles === 0) return;
334
-
335
- out.push('');
336
- out.push('## Structure');
337
- out.push('');
338
-
339
- const treeStr = buildTreeString(tree, rootName, totalFiles);
340
- out.push('```text');
341
- out.push(treeStr);
342
- out.push('```');
343
- }
344
-
345
- /**
346
- * @param {string[]} out
347
- * @param {import('../scanner/scan.js').ScanResult} result
348
- */
349
- function sectionStatistics(out, result) {
350
- const { flatFiles, totalFolders, scanDurationMs } = result;
351
-
352
- out.push('');
353
- out.push('## Statistics');
354
- out.push('');
355
- out.push(statsTable([
356
- ['Files', flatFiles.length],
357
- ['Folders', totalFolders],
358
- ['Scan Duration', formatDuration(scanDurationMs)],
359
- ]));
360
- }
361
-
362
- // ---------------------------------------------------------------------------
363
- // Public API
364
- // ---------------------------------------------------------------------------
365
-
366
- /**
367
- * Render a ScanResult as a GitHub-flavored Markdown report to stdout.
368
- *
369
- * All sections are built into an in-memory string array and joined once
370
- * at the end — a single `console.log` call keeps stdout writes atomic.
371
- *
372
- * @param {import('../scanner/scan.js').ScanResult} result
373
- * @param {{ cwd?: string }} [options]
374
- */
375
- export function render(result, options = {}) {
376
- const { rootPath, projectType, entryPoints, configs = [], scripts = [], flatFiles, tree, importantFiles = [], health = [] } = result;
377
-
378
- const cwd = options.cwd ?? process.cwd();
379
- const relRoot = path.relative(cwd, rootPath) || '.';
380
- const rootName = relRoot === '.' ? path.basename(rootPath) : relRoot;
381
-
382
- /** @type {string[]} */
383
- const out = [];
384
-
385
- sectionTitle(out);
386
- sectionSummary(out, result, relRoot);
387
- sectionProjectHealth(out, health);
388
- sectionImportantFiles(out, importantFiles);
389
- sectionFrameworks(out, projectType);
390
- sectionEntryPoints(out, entryPoints);
391
- sectionConfigurationFiles(out, configs);
392
- sectionPackageScripts(out, scripts);
393
- sectionStatistics(out, result);
394
- sectionFolderStructure(out, tree, flatFiles.length, rootName);
395
-
396
- console.log(out.join('\n'));
397
- }