@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.
- package/CHANGELOG.md +7 -0
- package/dist/cli/toren.d.ts +24 -0
- package/dist/cli/toren.js +254 -0
- package/dist/cli/toren.js.map +1 -0
- package/dist/detectors/config-detector.d.ts +3 -0
- package/dist/detectors/config-detector.js +58 -0
- package/dist/detectors/config-detector.js.map +1 -0
- package/dist/detectors/health-detector.d.ts +12 -0
- package/dist/detectors/health-detector.js +53 -0
- package/dist/detectors/health-detector.js.map +1 -0
- package/dist/detectors/important-files-detector.d.ts +51 -0
- package/dist/detectors/important-files-detector.js +455 -0
- package/dist/detectors/important-files-detector.js.map +1 -0
- package/dist/detectors/package-manager-detector.d.ts +7 -0
- package/dist/detectors/package-manager-detector.js +35 -0
- package/dist/detectors/package-manager-detector.js.map +1 -0
- package/dist/detectors/project-info-detector.d.ts +13 -0
- package/dist/detectors/project-info-detector.js +97 -0
- package/dist/detectors/project-info-detector.js.map +1 -0
- package/dist/detectors/script-detector.d.ts +42 -0
- package/dist/detectors/script-detector.js +199 -0
- package/dist/detectors/script-detector.js.map +1 -0
- package/dist/focused-output.d.ts +27 -0
- package/dist/focused-output.js +201 -0
- package/dist/focused-output.js.map +1 -0
- package/dist/lifecycle.d.ts +2 -0
- package/dist/lifecycle.js +114 -0
- package/dist/lifecycle.js.map +1 -0
- package/dist/renderers/console-renderer.d.ts +19 -0
- package/dist/renderers/console-renderer.js +361 -0
- package/dist/renderers/console-renderer.js.map +1 -0
- package/dist/renderers/html-renderer.d.ts +14 -0
- package/{src → dist}/renderers/html-renderer.js +181 -241
- package/dist/renderers/html-renderer.js.map +1 -0
- package/dist/renderers/index.d.ts +6 -0
- package/dist/renderers/index.js +12 -0
- package/dist/renderers/index.js.map +1 -0
- package/dist/renderers/json-renderer.d.ts +10 -0
- package/dist/renderers/json-renderer.js +127 -0
- package/dist/renderers/json-renderer.js.map +1 -0
- package/dist/renderers/markdown-renderer.d.ts +13 -0
- package/dist/renderers/markdown-renderer.js +360 -0
- package/dist/renderers/markdown-renderer.js.map +1 -0
- package/dist/scanner/scan.d.ts +2 -0
- package/dist/scanner/scan.js +573 -0
- package/dist/scanner/scan.js.map +1 -0
- package/dist/types/index.d.ts +85 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +11 -6
- package/bin/toren.js +0 -311
- package/src/detectors/config-detector.js +0 -81
- package/src/detectors/health-detector.js +0 -72
- package/src/detectors/important-files-detector.js +0 -515
- package/src/detectors/package-manager-detector.js +0 -112
- package/src/detectors/project-info-detector.js +0 -89
- package/src/detectors/script-detector.js +0 -248
- package/src/focused-output.js +0 -216
- package/src/lifecycle.js +0 -124
- package/src/renderers/console-renderer.js +0 -399
- package/src/renderers/index.js +0 -41
- package/src/renderers/json-renderer.js +0 -168
- package/src/renderers/markdown-renderer.js +0 -397
- package/src/scanner/scan.js +0 -554
|
@@ -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.
|
|
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": "
|
|
7
|
+
"toren": "dist/cli/toren.js"
|
|
8
8
|
},
|
|
9
9
|
"files": [
|
|
10
|
-
"
|
|
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
|
|
19
|
+
"start": "node dist/cli/toren.js",
|
|
20
|
+
"typecheck": "tsc --noEmit",
|
|
21
|
+
"build": "tsc",
|
|
21
22
|
"test": "node --test",
|
|
22
|
-
"lint": "node --check
|
|
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
|
-
}
|