@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
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":""}
package/package.json CHANGED
@@ -1,14 +1,13 @@
1
1
  {
2
2
  "name": "@lakindu_perera/toren",
3
- "version": "1.0.8",
3
+ "version": "1.0.9",
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": {
7
- "toren": "bin/toren.js"
7
+ "toren": "dist/cli/toren.js"
8
8
  },
9
9
  "files": [
10
- "bin",
11
- "src",
10
+ "dist",
12
11
  "LICENSE",
13
12
  "README.md",
14
13
  "CHANGELOG.md"
@@ -17,9 +16,11 @@
17
16
  "access": "public"
18
17
  },
19
18
  "scripts": {
20
- "start": "node bin/toren.js",
19
+ "start": "node dist/cli/toren.js",
20
+ "typecheck": "tsc --noEmit",
21
+ "build": "tsc",
21
22
  "test": "node --test",
22
- "lint": "node --check bin/toren.js src/scanner/scan.js src/lifecycle.js src/renderers/index.js src/renderers/console-renderer.js src/renderers/json-renderer.js src/renderers/markdown-renderer.js src/renderers/html-renderer.js src/detectors/config-detector.js src/detectors/script-detector.js src/detectors/package-manager-detector.js"
23
+ "lint": "node --check dist/cli/toren.js dist/scanner/scan.js dist/lifecycle.js dist/renderers/index.js dist/renderers/console-renderer.js dist/renderers/json-renderer.js dist/renderers/markdown-renderer.js dist/renderers/html-renderer.js dist/detectors/config-detector.js dist/detectors/script-detector.js dist/detectors/package-manager-detector.js"
23
24
  },
24
25
  "keywords": [
25
26
  "cli tool",
@@ -44,5 +45,9 @@
44
45
  "license": "MIT",
45
46
  "engines": {
46
47
  "node": ">=18.0.0"
48
+ },
49
+ "devDependencies": {
50
+ "@types/node": "^26.4.0",
51
+ "typescript": "^7.0.2"
47
52
  }
48
53
  }
package/bin/toren.js DELETED
@@ -1,311 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * @fileoverview Toren CLI — Entry Point
4
- *
5
- * Usage:
6
- * toren [path] Scan <path> (defaults to current directory)
7
- * toren --format <type> Select output format (default: console)
8
- * toren --json Legacy alias for --format json
9
- * toren --version Print version
10
- * toren --help Print usage
11
- * toren --doctor Check global installation health
12
- * toren --uninstall Safely remove global installation
13
- * toren --include-hidden Include hidden files (dot-files) in scan
14
- * toren --max-files <N> Override the max file scan limit
15
- *
16
- * Adding a new output format
17
- * ──────────────────────────
18
- * 1. Create src/renderers/<format>-renderer.js
19
- * and export: render(result, options?) => void
20
- * 2. Register it in src/renderers/index.js
21
- *
22
- * No changes to this file are required.
23
- */
24
-
25
- import { createRequire } from 'node:module';
26
- import { scan } from '../src/scanner/scan.js';
27
- import renderers from '../src/renderers/index.js';
28
- import { getFocusedModeInfo, renderFocusedMode, FOCUSED_FLAGS } from '../src/focused-output.js';
29
- import { runDoctor, runUninstall } from '../src/lifecycle.js';
30
-
31
- const require = createRequire(import.meta.url);
32
- const pkg = require('../package.json');
33
-
34
- /** Format used when no --format flag is supplied. */
35
- const DEFAULT_FORMAT = 'console';
36
-
37
- /** Derived from the registry — always in sync with available renderers. */
38
- const SUPPORTED_FORMATS = Object.keys(renderers);
39
-
40
- // ---------------------------------------------------------------------------
41
- // Helpers
42
- // ---------------------------------------------------------------------------
43
-
44
- function printError(title, message, detailLabel, detailValue) {
45
- console.error(`\x1b[31m✖ ${title}\x1b[0m\n`);
46
- console.error(`${message}\n`);
47
- if (detailLabel && detailValue) {
48
- console.error(`${detailLabel}:\n`);
49
- console.error(`${detailValue}\n`);
50
- }
51
- }
52
-
53
- function printHelp() {
54
- const formatList = SUPPORTED_FORMATS.map(f => {
55
- const suffix = f === DEFAULT_FORMAT ? ' (default)' : '';
56
- return ` --format ${f.padEnd(10)}${suffix}`;
57
- }).join('\n');
58
-
59
- console.log(`
60
- \x1b[1mToren\x1b[0m v${pkg.version}
61
- Fast Repository Discovery CLI
62
-
63
- \x1b[1mUSAGE\x1b[0m
64
- toren [path] [options]
65
-
66
- \x1b[1mCOMMANDS\x1b[0m
67
- --project-type Show detected project type only
68
- --frameworks Show detected frameworks only
69
- --entry-points Show detected entry points only
70
- --structure Show repository structure only
71
- --configs Show detected project configuration files
72
- --scripts Show available package scripts only
73
- --summary Show project summary only
74
- --important-files Show important files only
75
- --health Show project health observations only
76
- --include-hidden Include hidden files and folders
77
- --max-files <n> Set scan file limit
78
- --doctor Run CLI diagnostics
79
- --uninstall Remove Toren global installation
80
- --help Show this help message
81
- --version Show version number
82
-
83
- \x1b[1mOUTPUT FORMATS\x1b[0m
84
- ${formatList}
85
-
86
- \x1b[1mEXAMPLES\x1b[0m
87
- toren . Scan the current directory
88
- toren ./my-project Scan a specific project folder
89
- toren --format json . Output results as JSON
90
- toren --format markdown . > out.md Save a Markdown report to a file
91
- toren --format html . > out.html Save an HTML report to a file
92
- toren . --configs Show project configuration files
93
- toren . --frameworks Show detected frameworks
94
- `);
95
- }
96
-
97
- // ---------------------------------------------------------------------------
98
- // Argument parsing
99
- // ---------------------------------------------------------------------------
100
-
101
- /**
102
- * @typedef {Object} ParsedArgs
103
- * @property {'exit'|'wait'|'scan'} action
104
- * @property {string} [target] - Resolved path to scan
105
- * @property {string} [format] - Renderer format name
106
- * @property {boolean} [includeHidden] - Whether to include hidden files
107
- * @property {number} [maxFiles] - Max files to scan
108
- */
109
-
110
- /**
111
- * Parse process.argv into a structured options object.
112
- *
113
- * Returns { action: 'exit' } when the process should exit immediately.
114
- * Returns { action: 'wait' } when an async interactive command is running.
115
- * Returns { action: 'scan', target, format } for normal scan operations.
116
- *
117
- * @returns {ParsedArgs}
118
- */
119
- function parseArgs() {
120
- const args = process.argv.slice(2);
121
-
122
- // ── Informational flags ─────────────────────────────────────────────────
123
- if (args.includes('--help') || args.includes('-h')) {
124
- printHelp();
125
- return { action: 'exit', code: 0 };
126
- }
127
-
128
- if (args.includes('--version') || args.includes('-V') || args.includes('-v')) {
129
- console.log(`Toren ${pkg.version}`);
130
- return { action: 'exit', code: 0 };
131
- }
132
-
133
- // ── Lifecycle commands ──────────────────────────────────────────────────
134
- if (args.includes('--doctor')) {
135
- runDoctor(pkg.version);
136
- return { action: 'exit', code: 0 };
137
- }
138
-
139
- if (args.includes('--uninstall')) {
140
- runUninstall();
141
- return { action: 'wait' };
142
- }
143
-
144
- // ── Output format ───────────────────────────────────────────────────────
145
- // --json is a legacy alias for --format json, kept for backwards
146
- // compatibility. It will be removed in a future major version.
147
- let format = DEFAULT_FORMAT;
148
-
149
- const formatIdx = args.indexOf('--format');
150
- if (formatIdx !== -1) {
151
- const nextToken = args[formatIdx + 1];
152
- // If the next token is missing or starts with '-', the user omitted the value.
153
- if (nextToken === undefined || nextToken.startsWith('-')) {
154
- printError(
155
- 'Missing value',
156
- 'The --format flag requires a valid output format.',
157
- 'Supported formats',
158
- SUPPORTED_FORMATS.join(', ')
159
- );
160
- return { action: 'exit', code: 1 };
161
- }
162
- format = nextToken;
163
- } else if (args.includes('--json')) {
164
- format = 'json';
165
- }
166
-
167
- // ── Focused Output Flags ────────────────────────────────────────────────
168
- const focusedInfo = getFocusedModeInfo(args);
169
-
170
- if (focusedInfo.error) {
171
- printError(focusedInfo.title, focusedInfo.message, focusedInfo.detailLabel, focusedInfo.detailValue);
172
- return { action: 'exit', code: 1 };
173
- }
174
-
175
- const focusedMode = focusedInfo.mode;
176
-
177
- // ── Hidden files ────────────────────────────────────────────────────────
178
- const includeHidden = args.includes('--include-hidden');
179
-
180
- // ── Target path ─────────────────────────────────────────────────────────
181
- // Build the set of tokens that are consumed as values by named flags so
182
- // we don't accidentally treat them as the positional path argument.
183
- const consumedValues = new Set();
184
- if (formatIdx !== -1 && args[formatIdx + 1] !== undefined && !args[formatIdx + 1].startsWith('-')) {
185
- consumedValues.add(args[formatIdx + 1]);
186
- }
187
-
188
- // ── Max files ───────────────────────────────────────────────────────────
189
- let maxFiles = undefined;
190
- const maxFilesIdx = args.indexOf('--max-files');
191
- if (maxFilesIdx !== -1) {
192
- const rawVal = args[maxFilesIdx + 1];
193
- if (rawVal === undefined || rawVal.startsWith('-')) {
194
- printError(
195
- 'Missing value',
196
- 'The --max-files flag requires a numeric value.',
197
- 'Example',
198
- 'toren --max-files 100000'
199
- );
200
- return { action: 'exit', code: 1 };
201
- }
202
- maxFiles = parseInt(rawVal, 10);
203
- if (isNaN(maxFiles) || maxFiles < 1) {
204
- printError(
205
- 'Invalid value',
206
- 'The --max-files flag must be a positive integer.',
207
- 'Provided value',
208
- rawVal
209
- );
210
- return { action: 'exit', code: 1 };
211
- }
212
- consumedValues.add(rawVal);
213
- }
214
-
215
- // First non-flag, non-consumed token is the target path; default to cwd.
216
- const target = args.find(a => !a.startsWith('-') && !consumedValues.has(a)) ?? '.';
217
-
218
- // ── Unknown flag check ──────────────────────────────────────────────────
219
- const knownFlags = new Set([
220
- '--help', '-h',
221
- '--version', '-V', '-v',
222
- '--doctor',
223
- '--uninstall',
224
- '--format',
225
- '--json',
226
- ...FOCUSED_FLAGS,
227
- '--include-hidden',
228
- '--max-files',
229
- ]);
230
-
231
- const unknownFlag = args.find(
232
- a => a.startsWith('-') && !knownFlags.has(a) && !consumedValues.has(a),
233
- );
234
-
235
- if (unknownFlag) {
236
- printError(
237
- 'Unknown option',
238
- 'An unrecognized flag was provided.',
239
- 'Flag',
240
- unknownFlag
241
- );
242
- return { action: 'exit', code: 1 };
243
- }
244
-
245
- return { action: 'scan', target, format, includeHidden, maxFiles, focusedMode };
246
- }
247
-
248
- // ---------------------------------------------------------------------------
249
- // Format validation
250
- // ---------------------------------------------------------------------------
251
-
252
- /**
253
- * Assert that `format` has a registered renderer.
254
- * Prints a descriptive error message and exits with code 1 if not found.
255
- *
256
- * @param {string} format
257
- */
258
- function assertValidFormat(format) {
259
- if (renderers[format]) return;
260
-
261
- printError(
262
- 'Unsupported output format',
263
- 'The requested output format is not supported.',
264
- 'Format',
265
- format
266
- );
267
- process.exit(1);
268
- }
269
-
270
- // ---------------------------------------------------------------------------
271
- // Main
272
- // ---------------------------------------------------------------------------
273
-
274
- (function main() {
275
- const parsed = parseArgs();
276
-
277
- if (parsed.action === 'exit') {
278
- process.exit(parsed.code ?? 0);
279
- }
280
- if (parsed.action === 'wait') return;
281
-
282
- // Validate before scanning — fail fast on bad format names.
283
- assertValidFormat(parsed.format);
284
-
285
- const render = renderers[parsed.format];
286
-
287
- try {
288
- const result = scan(parsed.target, {
289
- includeHidden: parsed.includeHidden,
290
- maxFiles: parsed.maxFiles,
291
- });
292
-
293
- if (parsed.focusedMode) {
294
- renderFocusedMode(parsed.focusedMode, result);
295
- } else {
296
- render(result, { cwd: process.cwd() });
297
- }
298
- } catch (err) {
299
- // Render errors in the requested format where possible.
300
- if (parsed.format === 'json') {
301
- console.error(JSON.stringify({ error: err.message }, null, 2));
302
- } else {
303
- if (err.title) {
304
- printError(err.title, err.message, err.detailLabel, err.detailValue);
305
- } else {
306
- printError('Scan failed', err.message);
307
- }
308
- }
309
- process.exit(1);
310
- }
311
- })();
@@ -1,81 +0,0 @@
1
- /**
2
- * @fileoverview Configuration file detector
3
- */
4
-
5
- /**
6
- * Detects common configuration files in the root of the repository.
7
- *
8
- * @param {string[]} flatFiles - Array of relative file paths from the scanner
9
- * @returns {{ configs: string[] }}
10
- */
11
- export function detectConfigs(flatFiles) {
12
- const configPatterns = [
13
- // Package
14
- /^package\.json$/,
15
- /^package-lock\.json$/,
16
- /^pnpm-lock\.yaml$/,
17
- /^yarn\.lock$/,
18
- /^bun\.lockb$/,
19
-
20
- // TypeScript
21
- /^tsconfig\.json$/,
22
- /^jsconfig\.json$/,
23
-
24
- // Frontend
25
- /^vite\.config\.[a-zA-Z0-9]+$/,
26
- /^next\.config\.[a-zA-Z0-9]+$/,
27
- /^nuxt\.config\.[a-zA-Z0-9]+$/,
28
- /^astro\.config\.[a-zA-Z0-9]+$/,
29
- /^angular\.json$/,
30
-
31
- // Build
32
- /^webpack\.config\.[a-zA-Z0-9]+$/,
33
- /^rollup\.config\.[a-zA-Z0-9]+$/,
34
- /^turbo\.json$/,
35
- /^nx\.json$/,
36
-
37
- // Styling
38
- /^tailwind\.config\.[a-zA-Z0-9]+$/,
39
- /^postcss\.config\.[a-zA-Z0-9]+$/,
40
-
41
- // Lint
42
- /^eslint\.config\.[a-zA-Z0-9]+$/,
43
- /^\.eslintrc.*$/,
44
- /^prettier\.config\.[a-zA-Z0-9]+$/,
45
- /^\.prettierrc.*$/,
46
-
47
- // Backend
48
- /^pom\.xml$/,
49
- /^build\.gradle$/,
50
- /^build\.gradle\.kts$/,
51
-
52
- // Languages
53
- /^requirements\.txt$/,
54
- /^pyproject\.toml$/,
55
- /^Cargo\.toml$/,
56
- /^go\.mod$/,
57
-
58
- // Deployment
59
- /^Dockerfile$/,
60
- /^docker-compose\.ya?ml$/
61
- ];
62
-
63
- const matchedSet = new Set();
64
-
65
- for (const file of flatFiles) {
66
- // Ensure we only match files at the root of the repository
67
- if (file.includes('/')) continue;
68
-
69
- for (const pattern of configPatterns) {
70
- if (pattern.test(file)) {
71
- matchedSet.add(file);
72
- break; // Stop checking patterns once a match is found
73
- }
74
- }
75
- }
76
-
77
- // Convert Set to Array and sort alphabetically
78
- const configs = Array.from(matchedSet).sort();
79
-
80
- return { configs };
81
- }
@@ -1,72 +0,0 @@
1
- /**
2
- * Detect project health observations.
3
- */
4
- export function detectHealth({
5
- flatFiles,
6
- configs,
7
- importantFiles,
8
- scripts,
9
- projectType
10
- }) {
11
- const health = [];
12
- const fileSet = new Set(flatFiles);
13
-
14
- // README
15
- if (fileSet.has('README.md') || fileSet.has('README') || fileSet.has('readme.md')) {
16
- health.push({ id: 'readme', status: 'pass', message: 'README found' });
17
- } else {
18
- health.push({ id: 'readme', status: 'warning', message: 'README not found' });
19
- }
20
-
21
- // LICENSE
22
- if (fileSet.has('LICENSE') || fileSet.has('LICENSE.md') || fileSet.has('LICENSE.txt')) {
23
- health.push({ id: 'license', status: 'pass', message: 'LICENSE found' });
24
- } else {
25
- health.push({ id: 'license', status: 'warning', message: 'LICENSE not found' });
26
- }
27
-
28
- // ENVIRONMENT EXAMPLE
29
- if (fileSet.has('.env.example') || fileSet.has('.env.sample')) {
30
- health.push({ id: 'env-example', status: 'pass', message: 'Environment example found' });
31
- }
32
-
33
- // TESTS
34
- const hasTestFiles = flatFiles.some(f =>
35
- f.startsWith('test/') ||
36
- f.startsWith('tests/') ||
37
- f.startsWith('__tests__/') ||
38
- f.includes('.test.') ||
39
- f.includes('.spec.')
40
- );
41
- const hasTestScripts = (scripts || []).some(s => s.category === 'testing' || s.name === 'test');
42
- if (hasTestFiles || hasTestScripts) {
43
- health.push({ id: 'tests', status: 'pass', message: 'Tests detected' });
44
- }
45
-
46
- // LINTER
47
- const hasLinter = (configs || []).some(c =>
48
- c.includes('eslint') ||
49
- c.includes('biome') ||
50
- c.includes('stylelint')
51
- ) || (scripts || []).some(s => s.category === 'quality' || s.name === 'lint');
52
- if (hasLinter) {
53
- health.push({ id: 'lint', status: 'pass', message: 'Linter detected' });
54
- }
55
-
56
- // TYPESCRIPT
57
- if (fileSet.has('tsconfig.json')) {
58
- health.push({ id: 'typescript', status: 'pass', message: 'TypeScript configuration found' });
59
- }
60
-
61
- // GIT
62
- if (fileSet.has('.gitignore')) {
63
- health.push({ id: 'git', status: 'info', message: '.gitignore found' });
64
- }
65
-
66
- // DOCKER
67
- if (fileSet.has('Dockerfile') || fileSet.has('docker-compose.yml') || fileSet.has('compose.yml')) {
68
- health.push({ id: 'docker', status: 'info', message: 'Docker configuration found' });
69
- }
70
-
71
- return { health };
72
- }