@boshu2/vibe-check 2.0.0 → 2.2.0
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/.agents/plans/2025-12-27-vibe-check-evolution-plan.md +383 -0
- package/.agents/research/2025-12-27-vibe-check-evolution.md +352 -0
- package/.claude/settings.local.json +8 -2
- package/CHANGELOG.md +33 -0
- package/CLAUDE.md +201 -26
- package/README.md +95 -0
- package/dist/analyzers/eldritch.d.ts +40 -0
- package/dist/analyzers/eldritch.d.ts.map +1 -0
- package/dist/analyzers/eldritch.js +202 -0
- package/dist/analyzers/eldritch.js.map +1 -0
- package/dist/analyzers/modularity.d.ts +67 -0
- package/dist/analyzers/modularity.d.ts.map +1 -0
- package/dist/analyzers/modularity.js +254 -0
- package/dist/analyzers/modularity.js.map +1 -0
- package/dist/cli.js +2 -1
- package/dist/cli.js.map +1 -1
- package/dist/commands/analyze.d.ts.map +1 -1
- package/dist/commands/analyze.js +11 -1
- package/dist/commands/analyze.js.map +1 -1
- package/dist/commands/audit.d.ts.map +1 -1
- package/dist/commands/audit.js +25 -0
- package/dist/commands/audit.js.map +1 -1
- package/dist/commands/forensics.d.ts +8 -0
- package/dist/commands/forensics.d.ts.map +1 -1
- package/dist/commands/forensics.js +51 -4
- package/dist/commands/forensics.js.map +1 -1
- package/dist/commands/index.d.ts +1 -0
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +1 -0
- package/dist/commands/index.js.map +1 -1
- package/dist/commands/modularity.d.ts +27 -0
- package/dist/commands/modularity.d.ts.map +1 -0
- package/dist/commands/modularity.js +182 -0
- package/dist/commands/modularity.js.map +1 -0
- package/dist/git.d.ts.map +1 -1
- package/dist/git.js +8 -2
- package/dist/git.js.map +1 -1
- package/dist/metrics/cohesion.d.ts +27 -0
- package/dist/metrics/cohesion.d.ts.map +1 -0
- package/dist/metrics/cohesion.js +134 -0
- package/dist/metrics/cohesion.js.map +1 -0
- package/dist/metrics/index.d.ts +8 -0
- package/dist/metrics/index.d.ts.map +1 -1
- package/dist/metrics/index.js +36 -0
- package/dist/metrics/index.js.map +1 -1
- package/dist/metrics/investigation.d.ts +25 -0
- package/dist/metrics/investigation.d.ts.map +1 -0
- package/dist/metrics/investigation.js +115 -0
- package/dist/metrics/investigation.js.map +1 -0
- package/dist/metrics/tracers.d.ts +28 -0
- package/dist/metrics/tracers.d.ts.map +1 -0
- package/dist/metrics/tracers.js +117 -0
- package/dist/metrics/tracers.js.map +1 -0
- package/dist/output/terminal.d.ts.map +1 -1
- package/dist/output/terminal.js +34 -1
- package/dist/output/terminal.js.map +1 -1
- package/dist/types.d.ts +36 -1
- package/dist/types.d.ts.map +1 -1
- package/docs/ENHANCEMENT-PLAN.md +32 -14
- package/package.json +1 -1
- package/.claude/skills/typescript-review.md +0 -152
package/README.md
CHANGED
|
@@ -187,6 +187,15 @@ vibe-check profile # XP and achievements
|
|
|
187
187
|
vibe-check insights # Your spiral patterns
|
|
188
188
|
```
|
|
189
189
|
|
|
190
|
+
### Code Quality
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
vibe-check audit # Scan for monoliths, test gaps, TODOs
|
|
194
|
+
vibe-check modularity # Pattern-aware modularity analysis
|
|
195
|
+
vibe-check modularity --verbose # Detailed breakdown with metrics
|
|
196
|
+
vibe-check modularity -f json # JSON output for CI integration
|
|
197
|
+
```
|
|
198
|
+
|
|
190
199
|
### Tools
|
|
191
200
|
|
|
192
201
|
```bash
|
|
@@ -241,6 +250,92 @@ When inner loop issues are detected:
|
|
|
241
250
|
|
|
242
251
|
---
|
|
243
252
|
|
|
253
|
+
## Modularity Analysis
|
|
254
|
+
|
|
255
|
+
Goes beyond simple LOC counting to assess whether large files are well-organized or problematic.
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
vibe-check modularity
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
```
|
|
262
|
+
📐 Modularity Analysis
|
|
263
|
+
────────────────────────────────────────────────────────────
|
|
264
|
+
|
|
265
|
+
Analyzed 584 files (195,345 lines)
|
|
266
|
+
Average modularity score: 9.5/10
|
|
267
|
+
|
|
268
|
+
Score Distribution:
|
|
269
|
+
Elite (9-10): ████████████████░░░░ 82%
|
|
270
|
+
Good (7-8): ███░░░░░░░░░░░░░░░░░ 15%
|
|
271
|
+
Acceptable (5-6): ░░░░░░░░░░░░░░░░░░░░ 2%
|
|
272
|
+
Needs Work (3-4): ░░░░░░░░░░░░░░░░░░░░ 1%
|
|
273
|
+
Poor (0-2): ░░░░░░░░░░░░░░░░░░░░ 0%
|
|
274
|
+
|
|
275
|
+
⚠️ Files Needing Attention (8):
|
|
276
|
+
|
|
277
|
+
6/10 stores/network.js 1023 lines [state-machine]
|
|
278
|
+
⚠ no sections/organization
|
|
279
|
+
5/10 server/WebSocketGateway.ts 702 lines
|
|
280
|
+
⚠ no sections/organization
|
|
281
|
+
4/10 client/App.tsx 568 lines [component]
|
|
282
|
+
⚠ no sections/organization, ⚠ high coupling
|
|
283
|
+
|
|
284
|
+
👍 Good modularity. Minor improvements possible.
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### Pattern-Aware Scoring
|
|
288
|
+
|
|
289
|
+
A 2,500-line file can score **10/10** if well-organized. A 300-line file can score **4/10** if it's a mess.
|
|
290
|
+
|
|
291
|
+
| Factor | Impact | What It Checks |
|
|
292
|
+
|--------|--------|----------------|
|
|
293
|
+
| **Pattern Match** | +1 | Is it a controller/store/routes/state-machine? |
|
|
294
|
+
| **Internal Sections** | +1/-2 | Does it use `// ====` dividers or nested classes? |
|
|
295
|
+
| **Single Responsibility** | +2/-2 | Can purpose be described in one sentence? |
|
|
296
|
+
| **Coupling** | -1/-2 | >15 imports = high coupling warning |
|
|
297
|
+
| **Export Surface** | -1 | >20 exports = bloated API |
|
|
298
|
+
|
|
299
|
+
### Pattern-Specific Thresholds
|
|
300
|
+
|
|
301
|
+
Different file types have different acceptable sizes:
|
|
302
|
+
|
|
303
|
+
| Pattern | Yellow | Red | Why |
|
|
304
|
+
|---------|--------|-----|-----|
|
|
305
|
+
| `store` | 1,500 | 2,500 | Data layer naturally groups many methods |
|
|
306
|
+
| `controller` | 800 | 1,200 | K8s-style with reconciliation loops |
|
|
307
|
+
| `routes` | 1,000 | 1,500 | Vertical slice entry points |
|
|
308
|
+
| `component` | 250 | 400 | React components should stay focused |
|
|
309
|
+
| `utility` | 150 | 250 | Utilities should be smallest |
|
|
310
|
+
|
|
311
|
+
### Automatic Exemptions
|
|
312
|
+
|
|
313
|
+
These patterns skip modularity checks:
|
|
314
|
+
- `*.test.ts` — Tests can be comprehensive
|
|
315
|
+
- `*.generated.ts` — Generated files
|
|
316
|
+
- Type definition files — Central types are OK to be large
|
|
317
|
+
|
|
318
|
+
### Forensics Integration
|
|
319
|
+
|
|
320
|
+
Modularity is also included in `vibe-check forensics` for complete code health analysis:
|
|
321
|
+
|
|
322
|
+
```bash
|
|
323
|
+
vibe-check forensics
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
```
|
|
327
|
+
Modularity Health:
|
|
328
|
+
Average Score: 9.5/10 (303 files analyzed)
|
|
329
|
+
⚠️ 8 files need attention:
|
|
330
|
+
6/10 stores/network.js 1023 lines (no-internal-structure)
|
|
331
|
+
5/10 server/WebSocketGateway.ts 702 lines
|
|
332
|
+
...
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
Poor modularity (score <5) triggers the **SWEEP** recommendation alongside commit pattern issues.
|
|
336
|
+
|
|
337
|
+
---
|
|
338
|
+
|
|
244
339
|
## For Autonomous Agents
|
|
245
340
|
|
|
246
341
|
vibe-check measures **human-AI collaboration sessions**—the inner loop where you're working with an AI assistant.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Eldritch Horror Detector
|
|
3
|
+
*
|
|
4
|
+
* Detects oversized functions that are symptomatic of the "Eldritch Horror"
|
|
5
|
+
* middle loop failure pattern from vibe coding. This pattern occurs when
|
|
6
|
+
* AI generates monolithic functions that are impossible to understand.
|
|
7
|
+
*
|
|
8
|
+
* Thresholds:
|
|
9
|
+
* - Warning: Functions > 200 lines
|
|
10
|
+
* - Critical: Functions > 500 lines
|
|
11
|
+
*
|
|
12
|
+
* Detection is heuristic-based (not full AST parsing) to keep it fast
|
|
13
|
+
* and work across multiple languages.
|
|
14
|
+
*/
|
|
15
|
+
export interface EldritchHorror {
|
|
16
|
+
file: string;
|
|
17
|
+
functionName: string;
|
|
18
|
+
lineStart: number;
|
|
19
|
+
lineCount: number;
|
|
20
|
+
severity: 'warning' | 'critical';
|
|
21
|
+
}
|
|
22
|
+
export interface EldritchHorrorResult {
|
|
23
|
+
detected: boolean;
|
|
24
|
+
horrors: EldritchHorror[];
|
|
25
|
+
totalCount: number;
|
|
26
|
+
criticalCount: number;
|
|
27
|
+
warningCount: number;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Detect oversized functions in source files.
|
|
31
|
+
*
|
|
32
|
+
* @param files - List of file paths to analyze
|
|
33
|
+
* @returns Detection result with list of horrors
|
|
34
|
+
*/
|
|
35
|
+
export declare function detectEldritchHorrors(files: string[]): EldritchHorrorResult;
|
|
36
|
+
/**
|
|
37
|
+
* Run eldritch horror detection on a directory.
|
|
38
|
+
*/
|
|
39
|
+
export declare function scanForHorrors(dir: string): EldritchHorrorResult;
|
|
40
|
+
//# sourceMappingURL=eldritch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eldritch.d.ts","sourceRoot":"","sources":["../../src/analyzers/eldritch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAKH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,SAAS,GAAG,UAAU,CAAC;CAClC;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;CACtB;AAqBD;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,oBAAoB,CAuB3E;AA8HD;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,oBAAoB,CAGhE"}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Eldritch Horror Detector
|
|
3
|
+
*
|
|
4
|
+
* Detects oversized functions that are symptomatic of the "Eldritch Horror"
|
|
5
|
+
* middle loop failure pattern from vibe coding. This pattern occurs when
|
|
6
|
+
* AI generates monolithic functions that are impossible to understand.
|
|
7
|
+
*
|
|
8
|
+
* Thresholds:
|
|
9
|
+
* - Warning: Functions > 200 lines
|
|
10
|
+
* - Critical: Functions > 500 lines
|
|
11
|
+
*
|
|
12
|
+
* Detection is heuristic-based (not full AST parsing) to keep it fast
|
|
13
|
+
* and work across multiple languages.
|
|
14
|
+
*/
|
|
15
|
+
import * as fs from 'fs';
|
|
16
|
+
import * as path from 'path';
|
|
17
|
+
const WARNING_THRESHOLD = 200;
|
|
18
|
+
const CRITICAL_THRESHOLD = 500;
|
|
19
|
+
// Pattern matchers for function declarations across languages
|
|
20
|
+
const FUNCTION_PATTERNS = {
|
|
21
|
+
// JavaScript/TypeScript
|
|
22
|
+
jsFunction: /^\s*(?:export\s+)?(?:async\s+)?function\s+(\w+)\s*\(/,
|
|
23
|
+
jsArrow: /^\s*(?:export\s+)?(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s+)?\(/,
|
|
24
|
+
jsMethod: /^\s*(?:async\s+)?(\w+)\s*\([^)]*\)\s*{/,
|
|
25
|
+
jsClass: /^\s*(?:export\s+)?class\s+(\w+)/,
|
|
26
|
+
// Python
|
|
27
|
+
pyFunction: /^\s*(?:async\s+)?def\s+(\w+)\s*\(/,
|
|
28
|
+
pyClass: /^\s*class\s+(\w+)/,
|
|
29
|
+
// Go
|
|
30
|
+
goFunction: /^\s*func\s+(?:\([^)]+\)\s+)?(\w+)\s*\(/,
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Detect oversized functions in source files.
|
|
34
|
+
*
|
|
35
|
+
* @param files - List of file paths to analyze
|
|
36
|
+
* @returns Detection result with list of horrors
|
|
37
|
+
*/
|
|
38
|
+
export function detectEldritchHorrors(files) {
|
|
39
|
+
const horrors = [];
|
|
40
|
+
for (const file of files) {
|
|
41
|
+
try {
|
|
42
|
+
const content = fs.readFileSync(file, 'utf-8');
|
|
43
|
+
const fileHorrors = analyzeFile(file, content);
|
|
44
|
+
horrors.push(...fileHorrors);
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
// Skip files that can't be read
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const criticalCount = horrors.filter((h) => h.severity === 'critical').length;
|
|
51
|
+
const warningCount = horrors.filter((h) => h.severity === 'warning').length;
|
|
52
|
+
return {
|
|
53
|
+
detected: horrors.length > 0,
|
|
54
|
+
horrors: horrors.sort((a, b) => b.lineCount - a.lineCount),
|
|
55
|
+
totalCount: horrors.length,
|
|
56
|
+
criticalCount,
|
|
57
|
+
warningCount,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Analyze a single file for oversized functions.
|
|
62
|
+
*/
|
|
63
|
+
function analyzeFile(filePath, content) {
|
|
64
|
+
const horrors = [];
|
|
65
|
+
const lines = content.split('\n');
|
|
66
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
67
|
+
// Determine which patterns to use based on file extension
|
|
68
|
+
const patterns = getPatterns(ext);
|
|
69
|
+
let currentFunction = null;
|
|
70
|
+
for (let i = 0; i < lines.length; i++) {
|
|
71
|
+
const line = lines[i];
|
|
72
|
+
const lineNum = i + 1;
|
|
73
|
+
// Check if this line starts a new function
|
|
74
|
+
for (const pattern of patterns) {
|
|
75
|
+
const match = line.match(pattern);
|
|
76
|
+
if (match) {
|
|
77
|
+
// If we were tracking a function, close it out
|
|
78
|
+
if (currentFunction) {
|
|
79
|
+
const lineCount = lineNum - currentFunction.startLine;
|
|
80
|
+
if (lineCount >= WARNING_THRESHOLD) {
|
|
81
|
+
horrors.push(createHorror(filePath, currentFunction.name, currentFunction.startLine, lineCount));
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
currentFunction = {
|
|
85
|
+
name: match[1] || 'anonymous',
|
|
86
|
+
startLine: lineNum,
|
|
87
|
+
braceDepth: countBraces(line),
|
|
88
|
+
};
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
// Track brace depth
|
|
93
|
+
if (currentFunction && !line.match(/^\s*\/\//)) {
|
|
94
|
+
currentFunction.braceDepth += countBraces(line);
|
|
95
|
+
// Check for function end (Python uses indentation, others use braces)
|
|
96
|
+
if (ext === '.py') {
|
|
97
|
+
// For Python, check if we hit a line with less indentation
|
|
98
|
+
// This is a simplified heuristic
|
|
99
|
+
if (i + 1 < lines.length) {
|
|
100
|
+
const nextLine = lines[i + 1];
|
|
101
|
+
if (nextLine.match(/^(?:def|class|@|\S)/) && !nextLine.match(/^\s*#/)) {
|
|
102
|
+
const lineCount = lineNum - currentFunction.startLine + 1;
|
|
103
|
+
if (lineCount >= WARNING_THRESHOLD) {
|
|
104
|
+
horrors.push(createHorror(filePath, currentFunction.name, currentFunction.startLine, lineCount));
|
|
105
|
+
}
|
|
106
|
+
currentFunction = null;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
else if (currentFunction.braceDepth <= 0) {
|
|
111
|
+
// For brace-based languages, function ends when braces balance
|
|
112
|
+
const lineCount = lineNum - currentFunction.startLine + 1;
|
|
113
|
+
if (lineCount >= WARNING_THRESHOLD) {
|
|
114
|
+
horrors.push(createHorror(filePath, currentFunction.name, currentFunction.startLine, lineCount));
|
|
115
|
+
}
|
|
116
|
+
currentFunction = null;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
// Handle function that extends to end of file
|
|
121
|
+
if (currentFunction) {
|
|
122
|
+
const lineCount = lines.length - currentFunction.startLine + 1;
|
|
123
|
+
if (lineCount >= WARNING_THRESHOLD) {
|
|
124
|
+
horrors.push(createHorror(filePath, currentFunction.name, currentFunction.startLine, lineCount));
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return horrors;
|
|
128
|
+
}
|
|
129
|
+
function getPatterns(ext) {
|
|
130
|
+
switch (ext) {
|
|
131
|
+
case '.ts':
|
|
132
|
+
case '.tsx':
|
|
133
|
+
case '.js':
|
|
134
|
+
case '.jsx':
|
|
135
|
+
return [
|
|
136
|
+
FUNCTION_PATTERNS.jsFunction,
|
|
137
|
+
FUNCTION_PATTERNS.jsArrow,
|
|
138
|
+
FUNCTION_PATTERNS.jsMethod,
|
|
139
|
+
];
|
|
140
|
+
case '.py':
|
|
141
|
+
return [FUNCTION_PATTERNS.pyFunction];
|
|
142
|
+
case '.go':
|
|
143
|
+
return [FUNCTION_PATTERNS.goFunction];
|
|
144
|
+
default:
|
|
145
|
+
// Default to JS-like patterns
|
|
146
|
+
return [FUNCTION_PATTERNS.jsFunction, FUNCTION_PATTERNS.jsMethod];
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
function countBraces(line) {
|
|
150
|
+
// Simple brace counting (doesn't handle strings/comments perfectly)
|
|
151
|
+
let count = 0;
|
|
152
|
+
for (const char of line) {
|
|
153
|
+
if (char === '{')
|
|
154
|
+
count++;
|
|
155
|
+
if (char === '}')
|
|
156
|
+
count--;
|
|
157
|
+
}
|
|
158
|
+
return count;
|
|
159
|
+
}
|
|
160
|
+
function createHorror(file, functionName, lineStart, lineCount) {
|
|
161
|
+
return {
|
|
162
|
+
file,
|
|
163
|
+
functionName,
|
|
164
|
+
lineStart,
|
|
165
|
+
lineCount,
|
|
166
|
+
severity: lineCount >= CRITICAL_THRESHOLD ? 'critical' : 'warning',
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Run eldritch horror detection on a directory.
|
|
171
|
+
*/
|
|
172
|
+
export function scanForHorrors(dir) {
|
|
173
|
+
const files = scanDirectory(dir);
|
|
174
|
+
return detectEldritchHorrors(files);
|
|
175
|
+
}
|
|
176
|
+
// Utility to scan directory (matching audit.ts pattern)
|
|
177
|
+
const IGNORE_DIRS = ['node_modules', 'dist', 'coverage', '.git', '.vibe-check', '__pycache__'];
|
|
178
|
+
function scanDirectory(dir) {
|
|
179
|
+
const results = [];
|
|
180
|
+
try {
|
|
181
|
+
const list = fs.readdirSync(dir);
|
|
182
|
+
for (const file of list) {
|
|
183
|
+
const filePath = path.join(dir, file);
|
|
184
|
+
const stat = fs.statSync(filePath);
|
|
185
|
+
if (stat && stat.isDirectory()) {
|
|
186
|
+
if (!IGNORE_DIRS.includes(file) && !file.startsWith('.')) {
|
|
187
|
+
results.push(...scanDirectory(filePath));
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
if (file.match(/\.(ts|js|jsx|tsx|py|go)$/)) {
|
|
192
|
+
results.push(filePath);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
catch {
|
|
198
|
+
// Silently skip unreadable directories
|
|
199
|
+
}
|
|
200
|
+
return results;
|
|
201
|
+
}
|
|
202
|
+
//# sourceMappingURL=eldritch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eldritch.js","sourceRoot":"","sources":["../../src/analyzers/eldritch.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Modularity Analyzer
|
|
3
|
+
*
|
|
4
|
+
* Pattern-aware modularity assessment that goes beyond simple LOC counting.
|
|
5
|
+
* Recognizes that a well-organized 2,500-line file can be more maintainable
|
|
6
|
+
* than a poorly-structured 300-line file.
|
|
7
|
+
*
|
|
8
|
+
* Based on research into:
|
|
9
|
+
* - K8s-style controller patterns
|
|
10
|
+
* - Cohesion metrics (LCOM)
|
|
11
|
+
* - Coupling analysis (CBO, fan-in/fan-out)
|
|
12
|
+
* - Single Responsibility Principle indicators
|
|
13
|
+
*/
|
|
14
|
+
export interface ModularityResult {
|
|
15
|
+
files: FileModularity[];
|
|
16
|
+
summary: ModularitySummary;
|
|
17
|
+
exempted: ExemptedFile[];
|
|
18
|
+
}
|
|
19
|
+
export interface FileModularity {
|
|
20
|
+
file: string;
|
|
21
|
+
lines: number;
|
|
22
|
+
pattern: FilePattern | null;
|
|
23
|
+
score: number;
|
|
24
|
+
rating: ModularityRating;
|
|
25
|
+
flags: ModularityFlag[];
|
|
26
|
+
details: ModularityDetails;
|
|
27
|
+
}
|
|
28
|
+
export interface ModularityDetails {
|
|
29
|
+
hasSections: boolean;
|
|
30
|
+
sectionCount: number;
|
|
31
|
+
exportCount: number;
|
|
32
|
+
importCount: number;
|
|
33
|
+
hasNestedClasses: boolean;
|
|
34
|
+
methodCount: number;
|
|
35
|
+
}
|
|
36
|
+
export interface ModularitySummary {
|
|
37
|
+
totalFiles: number;
|
|
38
|
+
totalLines: number;
|
|
39
|
+
avgScore: number;
|
|
40
|
+
distribution: {
|
|
41
|
+
elite: number;
|
|
42
|
+
good: number;
|
|
43
|
+
acceptable: number;
|
|
44
|
+
needsWork: number;
|
|
45
|
+
poor: number;
|
|
46
|
+
};
|
|
47
|
+
largestFiles: {
|
|
48
|
+
file: string;
|
|
49
|
+
lines: number;
|
|
50
|
+
score: number;
|
|
51
|
+
}[];
|
|
52
|
+
}
|
|
53
|
+
export interface ExemptedFile {
|
|
54
|
+
file: string;
|
|
55
|
+
lines: number;
|
|
56
|
+
reason: string;
|
|
57
|
+
}
|
|
58
|
+
export type ModularityRating = 'elite' | 'good' | 'acceptable' | 'needs-work' | 'poor';
|
|
59
|
+
export type ModularityFlag = 'no-single-responsibility' | 'no-internal-structure' | 'high-coupling' | 'low-cohesion' | 'missing-tests' | 'god-class' | 'utility-grab-bag';
|
|
60
|
+
export type FilePattern = 'controller' | 'store' | 'routes' | 'types' | 'state-machine' | 'test' | 'generated' | 'component' | 'middleware' | 'utility';
|
|
61
|
+
export interface ModularityOptions {
|
|
62
|
+
minLines?: number;
|
|
63
|
+
includeAll?: boolean;
|
|
64
|
+
patterns?: FilePattern[];
|
|
65
|
+
}
|
|
66
|
+
export declare function analyzeModularity(rootDir: string, options?: ModularityOptions): ModularityResult;
|
|
67
|
+
//# sourceMappingURL=modularity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"modularity.d.ts","sourceRoot":"","sources":["../../src/analyzers/modularity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAUH,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,OAAO,EAAE,iBAAiB,CAAC;IAC3B,QAAQ,EAAE,YAAY,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,WAAW,GAAG,IAAI,CAAC;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,gBAAgB,CAAC;IACzB,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,OAAO,EAAE,iBAAiB,CAAC;CAC5B;AAED,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,OAAO,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE;QACZ,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,UAAU,EAAE,MAAM,CAAC;QACnB,SAAS,EAAE,MAAM,CAAC;QAClB,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IACF,YAAY,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAChE;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,MAAM,GAAG,YAAY,GAAG,YAAY,GAAG,MAAM,CAAC;AAEvF,MAAM,MAAM,cAAc,GACtB,0BAA0B,GAC1B,uBAAuB,GACvB,eAAe,GACf,cAAc,GACd,eAAe,GACf,WAAW,GACX,kBAAkB,CAAC;AAEvB,MAAM,MAAM,WAAW,GACnB,YAAY,GACZ,OAAO,GACP,QAAQ,GACR,OAAO,GACP,eAAe,GACf,MAAM,GACN,WAAW,GACX,WAAW,GACX,YAAY,GACZ,SAAS,CAAC;AAyMd,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,WAAW,EAAE,CAAC;CAC1B;AAED,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,iBAAsB,GAC9B,gBAAgB,CAoClB"}
|