ts-analyzer 1.0.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/README.md +356 -0
- package/bin/cli.js +4 -0
- package/bin/cli.ts +241 -0
- package/dist/bin/cli.d.ts +2 -0
- package/dist/bin/cli.js +215 -0
- package/dist/bin/cli.js.map +1 -0
- package/dist/src/code-complexity.d.ts +24 -0
- package/dist/src/code-complexity.js +338 -0
- package/dist/src/code-complexity.js.map +1 -0
- package/dist/src/index.d.ts +47 -0
- package/dist/src/index.js +115 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/table-formatter.d.ts +6 -0
- package/dist/src/table-formatter.js +82 -0
- package/dist/src/table-formatter.js.map +1 -0
- package/dist/src/typescript-safety.d.ts +27 -0
- package/dist/src/typescript-safety.js +287 -0
- package/dist/src/typescript-safety.js.map +1 -0
- package/package.json +51 -0
- package/src/code-complexity.ts +431 -0
- package/src/index.ts +180 -0
- package/src/table-formatter.ts +94 -0
- package/src/typescript-safety.ts +346 -0
- package/tsconfig.json +18 -0
package/README.md
ADDED
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
# ts-analyzer
|
|
2
|
+
|
|
3
|
+
A comprehensive TypeScript codebase analyzer that provides detailed metrics on type safety, code complexity, and quality. Get actionable insights to improve your TypeScript projects.
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+

|
|
7
|
+
|
|
8
|
+
> **Note**: This is the new and improved version of the previous `react-loc-analyzer` package, with enhanced TypeScript safety analysis, code complexity metrics, and better reports.
|
|
9
|
+
|
|
10
|
+
## Features
|
|
11
|
+
|
|
12
|
+
- 🧪 **TypeScript Safety Analysis** with detailed type coverage metrics
|
|
13
|
+
- 📊 **Code Complexity Evaluation** for better maintainability
|
|
14
|
+
- 📏 **Detailed Code Statistics** with file type breakdown
|
|
15
|
+
- 📝 **Actionable Quality Recommendations** based on analysis
|
|
16
|
+
- 🎯 **Framework-Agnostic** works with any TypeScript project (React, Vue, Angular, Node.js)
|
|
17
|
+
- 🎨 **Beautiful Formatted Output** with colored terminal support
|
|
18
|
+
- ⚡ **Fast Performance** with asynchronous file processing
|
|
19
|
+
- ⚙️ **Highly Configurable** with customizable options
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
You can use it directly with npx (no installation required):
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npx ts-analyzer
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Or install it globally:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npm install -g ts-analyzer
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Usage
|
|
36
|
+
|
|
37
|
+
### Basic Usage
|
|
38
|
+
|
|
39
|
+
Analyze the current directory:
|
|
40
|
+
```bash
|
|
41
|
+
npx ts-analyzer
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Analyze a specific directory:
|
|
45
|
+
```bash
|
|
46
|
+
npx ts-analyzer /path/to/your/typescript/project
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Options
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
npx ts-analyzer [directory] [options]
|
|
53
|
+
|
|
54
|
+
Options:
|
|
55
|
+
-V, --version output version number
|
|
56
|
+
-e, --exclude <patterns> additional patterns to exclude (comma-separated)
|
|
57
|
+
-i, --include <extensions> additional file extensions to include (comma-separated)
|
|
58
|
+
--no-color disable colored output
|
|
59
|
+
--no-safety disable TypeScript safety analysis
|
|
60
|
+
--no-complexity disable code complexity analysis
|
|
61
|
+
-h, --help display help for command
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Examples
|
|
65
|
+
|
|
66
|
+
Analyze with additional exclude patterns:
|
|
67
|
+
```bash
|
|
68
|
+
npx ts-analyzer --exclude .cache,public,static
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Include additional file extensions:
|
|
72
|
+
```bash
|
|
73
|
+
npx ts-analyzer --include .vue,.svelte
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Disable TypeScript safety analysis:
|
|
77
|
+
```bash
|
|
78
|
+
npx ts-analyzer --no-safety
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Output
|
|
82
|
+
|
|
83
|
+
The analyzer provides four main sections of output:
|
|
84
|
+
|
|
85
|
+
### 1. Project Summary
|
|
86
|
+
Shows overall statistics including:
|
|
87
|
+
- Total Files
|
|
88
|
+
- Total Lines
|
|
89
|
+
- Code Lines
|
|
90
|
+
- Comment Lines
|
|
91
|
+
- Empty Lines
|
|
92
|
+
|
|
93
|
+
### 2. Files by Type
|
|
94
|
+
Detailed breakdown for each file extension:
|
|
95
|
+
- Number of files
|
|
96
|
+
- Total lines
|
|
97
|
+
- Code lines
|
|
98
|
+
- Comment lines
|
|
99
|
+
- Empty lines
|
|
100
|
+
- Percentage of codebase
|
|
101
|
+
|
|
102
|
+
### 3. TypeScript Safety Analysis
|
|
103
|
+
Comprehensive TypeScript safety metrics:
|
|
104
|
+
- TypeScript Files Count
|
|
105
|
+
- Type Coverage Percentage
|
|
106
|
+
- Any Type Usage Count
|
|
107
|
+
- Type Assertions Count
|
|
108
|
+
- Type Safety Score
|
|
109
|
+
- Type Safety Rating
|
|
110
|
+
|
|
111
|
+
### 4. Code Complexity Analysis
|
|
112
|
+
Detailed complexity metrics:
|
|
113
|
+
- Function Count
|
|
114
|
+
- Cyclomatic Complexity
|
|
115
|
+
- Nesting Depth
|
|
116
|
+
- Function Size
|
|
117
|
+
- Overall Complexity Rating
|
|
118
|
+
|
|
119
|
+
### 5. Code Quality Recommendations
|
|
120
|
+
Actionable suggestions to improve your code quality.
|
|
121
|
+
|
|
122
|
+
## Example Output
|
|
123
|
+
|
|
124
|
+
```
|
|
125
|
+
Project Summary:
|
|
126
|
+
┌───────────────┬────────────┐
|
|
127
|
+
│ Metric │ Value │
|
|
128
|
+
├───────────────┼────────────┤
|
|
129
|
+
│ Total Files │ 156 │
|
|
130
|
+
│ Total Lines │ 15,234 │
|
|
131
|
+
│ Code Lines │ 12,845 │
|
|
132
|
+
│ Comment Lines │ 1,523 │
|
|
133
|
+
│ Empty Lines │ 866 │
|
|
134
|
+
└───────────────┴────────────┘
|
|
135
|
+
|
|
136
|
+
Files by Type:
|
|
137
|
+
┌────────────┬───────┬─────────────┬────────────┬───────────────┐
|
|
138
|
+
│ Extension │ Files │ Total Lines │ Code Lines │ % of Codebase │
|
|
139
|
+
├────────────┼───────┼─────────────┼────────────┼───────────────┤
|
|
140
|
+
│ .ts │ 87 │ 8,456 │ 7,234 │ 56.3% │
|
|
141
|
+
│ .tsx │ 45 │ 4,234 │ 3,845 │ 29.9% │
|
|
142
|
+
│ .js │ 23 │ 2,456 │ 1,923 │ 15.0% │
|
|
143
|
+
└────────────┴───────┴─────────────┴────────────┴───────────────┘
|
|
144
|
+
|
|
145
|
+
TypeScript Safety:
|
|
146
|
+
┌─────────────────────┬───────────────────────┐
|
|
147
|
+
│ metric │ value │
|
|
148
|
+
├─────────────────────┼───────────────────────┤
|
|
149
|
+
│ TypeScript Files │ 132 (84.6% of codebase)│
|
|
150
|
+
│ Type Coverage │ 92.3% (Good) │
|
|
151
|
+
│ Any Type Usage │ 12 │
|
|
152
|
+
│ Type Assertions │ 5 │
|
|
153
|
+
│ Non-Null Assertions │ 0 │
|
|
154
|
+
│ Type Safety Score │ 85/100 (Good ✓) │
|
|
155
|
+
│ Type Safety Rating │ Low │
|
|
156
|
+
└─────────────────────┴───────────────────────┘
|
|
157
|
+
|
|
158
|
+
Code Complexity:
|
|
159
|
+
┌───────────────────────────┬────────────┐
|
|
160
|
+
│ metric │ value │
|
|
161
|
+
├───────────────────────────┼────────────┤
|
|
162
|
+
│ Analyzed Files │ 110 │
|
|
163
|
+
│ Total Functions │ 345 │
|
|
164
|
+
│ Avg Cyclomatic Complexity │ 3.2 │
|
|
165
|
+
│ Max Cyclomatic Complexity │ 12 │
|
|
166
|
+
│ Avg Nesting Depth │ 2.1 │
|
|
167
|
+
│ Max Nesting Depth │ 6 │
|
|
168
|
+
│ Avg Function Size │ 12.5 lines │
|
|
169
|
+
│ Complex Files │ 3 │
|
|
170
|
+
│ Overall Complexity │ Simple ✓ │
|
|
171
|
+
└───────────────────────────┴────────────┘
|
|
172
|
+
|
|
173
|
+
📝 Code Quality Recommendations:
|
|
174
|
+
• Reduce usage of 'any' type (found 12 instances) by using more specific types
|
|
175
|
+
• Consider refactoring functions with high complexity (max: 12) to improve maintainability
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## TypeScript Safety Analysis
|
|
179
|
+
|
|
180
|
+
### How TypeScript Safety Analysis Works
|
|
181
|
+
|
|
182
|
+
The TypeScript safety analyzer evaluates your TypeScript code quality by calculating several metrics. Here's how it works:
|
|
183
|
+
|
|
184
|
+
```
|
|
185
|
+
┌─────────────────────┐
|
|
186
|
+
│ TypeScript Files │
|
|
187
|
+
└─────────┬───────────┘
|
|
188
|
+
│
|
|
189
|
+
▼
|
|
190
|
+
┌─────────────────────┐ ┌─────────────────────┐
|
|
191
|
+
│ AST Analysis │───>│ Node Classification │
|
|
192
|
+
└─────────┬───────────┘ └─────────┬───────────┘
|
|
193
|
+
│ │
|
|
194
|
+
▼ ▼
|
|
195
|
+
┌─────────────────────┐ ┌─────────────────────┐
|
|
196
|
+
│ Explicitly Typed │ │ Implicitly Typed │
|
|
197
|
+
│ Nodes │ │ Nodes │
|
|
198
|
+
└─────────┬───────────┘ └─────────┬───────────┘
|
|
199
|
+
│ │
|
|
200
|
+
└──────────┬──────────────┘
|
|
201
|
+
│
|
|
202
|
+
▼
|
|
203
|
+
┌─────────────────────┐ ┌─────────────────────┐
|
|
204
|
+
│ Type Coverage │<───│ tsconfig.json │
|
|
205
|
+
│ Calculation │ │ Analysis │
|
|
206
|
+
└─────────┬───────────┘ └─────────────────────┘
|
|
207
|
+
│
|
|
208
|
+
▼
|
|
209
|
+
┌─────────────────────┐
|
|
210
|
+
│ "any" & Assertion │
|
|
211
|
+
│ Penalty Calculation │
|
|
212
|
+
└─────────┬───────────┘
|
|
213
|
+
│
|
|
214
|
+
▼
|
|
215
|
+
┌─────────────────────┐
|
|
216
|
+
│ Final Type Safety │
|
|
217
|
+
│ Score & Rating │
|
|
218
|
+
└─────────────────────┘
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### Type Coverage Calculation
|
|
222
|
+
|
|
223
|
+
Type coverage measures what percentage of your code has proper type information, either through explicit type annotations or TypeScript's type inference.
|
|
224
|
+
|
|
225
|
+
```typescript
|
|
226
|
+
// Example TypeScript code with various levels of typing
|
|
227
|
+
|
|
228
|
+
// Explicitly typed (counts as typed)
|
|
229
|
+
const userName: string = "John";
|
|
230
|
+
|
|
231
|
+
// Implicitly typed through inference (counts as typed)
|
|
232
|
+
const userAge = 30; // TypeScript infers 'number'
|
|
233
|
+
|
|
234
|
+
// Object with explicit interface (counts as typed)
|
|
235
|
+
interface User {
|
|
236
|
+
id: number;
|
|
237
|
+
name: string;
|
|
238
|
+
active: boolean;
|
|
239
|
+
}
|
|
240
|
+
const user: User = { id: 1, name: "Alice", active: true };
|
|
241
|
+
|
|
242
|
+
// Function with explicit type annotations (counts as typed)
|
|
243
|
+
function calculateTotal(prices: number[]): number {
|
|
244
|
+
return prices.reduce((sum, price) => sum + price, 0);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Any type usage (counts as typed, but with penalty)
|
|
248
|
+
const userData: any = fetchUserData();
|
|
249
|
+
|
|
250
|
+
// No type annotation or clear inference (counts as untyped)
|
|
251
|
+
let someData;
|
|
252
|
+
|
|
253
|
+
// Type assertion (counts as typed, but with penalty)
|
|
254
|
+
const userInput = document.getElementById("user-input") as HTMLInputElement;
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### Type Safety Score Formula
|
|
258
|
+
|
|
259
|
+
The type safety score (0-100) is calculated using the following formula:
|
|
260
|
+
|
|
261
|
+
```
|
|
262
|
+
Type Safety Score = Coverage Score - Any Type Penalty - Type Assertion Penalty
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
Where:
|
|
266
|
+
- **Coverage Score** = Type Coverage Percentage × 0.6 (60% weight)
|
|
267
|
+
- **Any Type Penalty** = (Any Type Count / Total Nodes) × 100 × 0.2 (20% weight)
|
|
268
|
+
- **Type Assertion Penalty** = (Type Assertions / Total Nodes) × 100 × 0.2 (20% weight)
|
|
269
|
+
|
|
270
|
+
### TypeScript Configuration Impact
|
|
271
|
+
|
|
272
|
+
The analyzer checks your `tsconfig.json` for strict type checking options and awards bonus points:
|
|
273
|
+
|
|
274
|
+
| Configuration Option | Points |
|
|
275
|
+
|----------------------|--------|
|
|
276
|
+
| `strict: true` | 5 |
|
|
277
|
+
| `noImplicitAny: true`| 3 |
|
|
278
|
+
| `strictNullChecks: true` | 3 |
|
|
279
|
+
| `noImplicitReturns: true` | 2 |
|
|
280
|
+
|
|
281
|
+
### Rating Scale
|
|
282
|
+
|
|
283
|
+
| Type Safety Score | Rating | Description |
|
|
284
|
+
|-------------------|--------|-------------|
|
|
285
|
+
| ≥ 80 | Good | Your TypeScript code is well-typed and maintains high type safety |
|
|
286
|
+
| 50-79 | Moderate | Your code has reasonable type safety but could be improved |
|
|
287
|
+
| < 50 | Poor | Your code has significant type safety issues that should be addressed |
|
|
288
|
+
|
|
289
|
+
### Type Coverage Benchmarks
|
|
290
|
+
|
|
291
|
+
| Type Coverage | Rating | Description |
|
|
292
|
+
|---------------|--------|-------------|
|
|
293
|
+
| ≥ 95% | Excellent | Top-tier type safety, comparable to well-maintained libraries |
|
|
294
|
+
| 85-94% | Good | Strong type safety, suitable for production applications |
|
|
295
|
+
| 70-84% | Moderate | Acceptable type safety, but has room for improvement |
|
|
296
|
+
| < 70% | Needs Improvement | Type coverage is too low for reliable code |
|
|
297
|
+
|
|
298
|
+
## Code Complexity Analysis
|
|
299
|
+
|
|
300
|
+
### How Code Complexity Analysis Works
|
|
301
|
+
|
|
302
|
+
The complexity analyzer evaluates several aspects of your code structure to determine maintainability:
|
|
303
|
+
|
|
304
|
+
1. **Cyclomatic Complexity**: Measures the number of independent paths through code
|
|
305
|
+
2. **Nesting Depth**: Measures how deeply code blocks are nested
|
|
306
|
+
3. **Function Size**: Measures average lines of code per function
|
|
307
|
+
4. **Parameter Count**: Analyzes how many parameters functions receive
|
|
308
|
+
|
|
309
|
+
### Complexity Rating Scale
|
|
310
|
+
|
|
311
|
+
| Complexity Score | Rating | Description |
|
|
312
|
+
|------------------|--------|-------------|
|
|
313
|
+
| < 30 | Simple | Your code is clean and easily maintainable |
|
|
314
|
+
| 30-60 | Moderate | Your code has reasonable complexity but watch for complex areas |
|
|
315
|
+
| > 60 | Complex | Your code may be difficult to maintain and test |
|
|
316
|
+
|
|
317
|
+
## Why This Is Better Than react-loc-analyzer
|
|
318
|
+
|
|
319
|
+
The `ts-analyzer` is a significant improvement over the previous `react-loc-analyzer`:
|
|
320
|
+
|
|
321
|
+
1. **TypeScript Specialization**: Built specifically for analyzing TypeScript codebases with deep type safety insights
|
|
322
|
+
2. **Framework Agnostic**: Works with any TypeScript project, not just React
|
|
323
|
+
3. **Advanced Metrics**: Provides sophisticated type coverage and code complexity metrics
|
|
324
|
+
4. **Actionable Insights**: Generates specific recommendations to improve your code quality
|
|
325
|
+
5. **Modern Implementation**: Fully written in TypeScript with strong typing throughout
|
|
326
|
+
6. **Better Performance**: Optimized for faster analysis of large TypeScript projects
|
|
327
|
+
|
|
328
|
+
## Default Configuration
|
|
329
|
+
|
|
330
|
+
### Included File Extensions
|
|
331
|
+
- `.js`, `.jsx`, `.ts`, `.tsx`
|
|
332
|
+
- `.css`, `.scss`, `.sass`
|
|
333
|
+
- `.html`, `.json`
|
|
334
|
+
|
|
335
|
+
### Default Ignore Patterns
|
|
336
|
+
- `node_modules`
|
|
337
|
+
- `build`
|
|
338
|
+
- `dist`
|
|
339
|
+
- `.git`
|
|
340
|
+
- `coverage`
|
|
341
|
+
- `.next`
|
|
342
|
+
- `out`
|
|
343
|
+
|
|
344
|
+
## Contributing
|
|
345
|
+
|
|
346
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
347
|
+
|
|
348
|
+
1. Fork the repository
|
|
349
|
+
2. Create your feature branch (`git checkout -b feature/AmazingFeature`)
|
|
350
|
+
3. Commit your changes (`git commit -m 'Add some AmazingFeature'`)
|
|
351
|
+
4. Push to the branch (`git push origin feature/AmazingFeature`)
|
|
352
|
+
5. Open a Pull Request
|
|
353
|
+
|
|
354
|
+
## License
|
|
355
|
+
|
|
356
|
+
MIT License - see the [LICENSE](LICENSE) file for details
|
package/bin/cli.js
ADDED
package/bin/cli.ts
ADDED
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// bin/cli.ts
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
import ora from 'ora';
|
|
6
|
+
import { analyzeProject } from '../src/index.js';
|
|
7
|
+
import { formatTable } from '../src/table-formatter.js';
|
|
8
|
+
|
|
9
|
+
const program = new Command();
|
|
10
|
+
|
|
11
|
+
interface ProgramOptions {
|
|
12
|
+
exclude?: string;
|
|
13
|
+
include?: string;
|
|
14
|
+
color?: boolean;
|
|
15
|
+
safety?: boolean;
|
|
16
|
+
complexity?: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
program
|
|
20
|
+
.name('ts-analyzer')
|
|
21
|
+
.description('Comprehensive TypeScript code analyzer with type safety and complexity metrics')
|
|
22
|
+
.version('1.1.2')
|
|
23
|
+
.argument('[dir]', 'project directory to analyze', '.')
|
|
24
|
+
.option('-e, --exclude <patterns>', 'additional patterns to exclude (comma-separated)')
|
|
25
|
+
.option('-i, --include <extensions>', 'additional file extensions to include (comma-separated)')
|
|
26
|
+
.option('--no-color', 'disable colored output')
|
|
27
|
+
.option('--no-safety', 'disable TypeScript safety analysis')
|
|
28
|
+
.option('--no-complexity', 'disable code complexity analysis')
|
|
29
|
+
.action(async (dir: string, options: ProgramOptions) => {
|
|
30
|
+
const spinner = ora('Analyzing React project...').start();
|
|
31
|
+
const useColors = options.color !== false;
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
const extraExcludes = options.exclude ? options.exclude.split(',') : [];
|
|
35
|
+
const extraExtensions = options.include ? options.include.split(',').map(ext =>
|
|
36
|
+
ext.startsWith('.') ? ext : `.${ext}`
|
|
37
|
+
) : [];
|
|
38
|
+
|
|
39
|
+
const stats = await analyzeProject(dir, {
|
|
40
|
+
excludePatterns: extraExcludes,
|
|
41
|
+
additionalExtensions: extraExtensions,
|
|
42
|
+
analyzeSafety: options.safety !== false,
|
|
43
|
+
analyzeComplexity: options.complexity !== false
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
spinner.succeed('Analysis complete!');
|
|
47
|
+
|
|
48
|
+
// Print summary table
|
|
49
|
+
console.log('\n' + (useColors ? chalk.bold.green('Project Summary:') : 'Project Summary:'));
|
|
50
|
+
formatTable([
|
|
51
|
+
{ metric: 'Total Files', value: stats.formatNumber(stats.files) },
|
|
52
|
+
{ metric: 'Total Lines', value: stats.formatNumber(stats.totalLines) },
|
|
53
|
+
{ metric: 'Code Lines', value: stats.formatNumber(stats.codeLines) },
|
|
54
|
+
{ metric: 'Comment Lines', value: stats.formatNumber(stats.commentLines) },
|
|
55
|
+
{ metric: 'Empty Lines', value: stats.formatNumber(stats.emptyLines) }
|
|
56
|
+
]);
|
|
57
|
+
|
|
58
|
+
// Print file types table
|
|
59
|
+
console.log('\n' + (useColors ? chalk.bold.green('Files by Type:') : 'Files by Type:'));
|
|
60
|
+
formatTable(stats.formattedFileTypes as any[]);
|
|
61
|
+
|
|
62
|
+
// Print TypeScript safety metrics if available
|
|
63
|
+
if (stats.typescriptSafety) {
|
|
64
|
+
console.log('\n' + (useColors ? chalk.bold.green('TypeScript Safety:') : 'TypeScript Safety:'));
|
|
65
|
+
|
|
66
|
+
// Prepare safety indicators
|
|
67
|
+
let safetyIndicator;
|
|
68
|
+
if (stats.typescriptSafety.avgTypeSafetyScore >= 80) {
|
|
69
|
+
safetyIndicator = useColors ? chalk.green('Good ✓') : 'Good ✓';
|
|
70
|
+
} else if (stats.typescriptSafety.avgTypeSafetyScore >= 50) {
|
|
71
|
+
safetyIndicator = useColors ? chalk.yellow('Moderate ⚠') : 'Moderate ⚠';
|
|
72
|
+
} else {
|
|
73
|
+
safetyIndicator = useColors ? chalk.red('Poor ✗') : 'Poor ✗';
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
let safetyRating;
|
|
77
|
+
if (stats.typescriptSafety.overallComplexity === 'Low') {
|
|
78
|
+
safetyRating = useColors ? chalk.green('Low') : 'Low';
|
|
79
|
+
} else if (stats.typescriptSafety.overallComplexity === 'Medium') {
|
|
80
|
+
safetyRating = useColors ? chalk.yellow('Medium') : 'Medium';
|
|
81
|
+
} else {
|
|
82
|
+
safetyRating = useColors ? chalk.red('High') : 'High';
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Create coverage evaluation
|
|
86
|
+
let coverageEvaluation;
|
|
87
|
+
const typeCoverage = parseFloat(stats.typescriptSafety.avgTypeCoverage);
|
|
88
|
+
if (typeCoverage >= 95) {
|
|
89
|
+
coverageEvaluation = useColors ? chalk.green('(Excellent)') : '(Excellent)';
|
|
90
|
+
} else if (typeCoverage >= 85) {
|
|
91
|
+
coverageEvaluation = useColors ? chalk.green('(Good)') : '(Good)';
|
|
92
|
+
} else if (typeCoverage >= 70) {
|
|
93
|
+
coverageEvaluation = useColors ? chalk.yellow('(Moderate)') : '(Moderate)';
|
|
94
|
+
} else {
|
|
95
|
+
coverageEvaluation = useColors ? chalk.red('(Needs Improvement)') : '(Needs Improvement)';
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
formatTable([
|
|
99
|
+
{ metric: 'TypeScript Files', value: `${stats.formatNumber(stats.typescriptSafety.tsFileCount)} (${stats.typescriptSafety.tsPercentage}% of codebase)` },
|
|
100
|
+
{ metric: 'Type Coverage', value: `${stats.typescriptSafety.avgTypeCoverage}% ${coverageEvaluation}` },
|
|
101
|
+
{ metric: 'Any Type Usage', value: stats.formatNumber(stats.typescriptSafety.totalAnyCount) },
|
|
102
|
+
{ metric: 'Type Assertions', value: stats.formatNumber(stats.typescriptSafety.totalAssertions) },
|
|
103
|
+
{ metric: 'Non-Null Assertions', value: stats.formatNumber(stats.typescriptSafety.totalNonNullAssertions) },
|
|
104
|
+
{ metric: 'Type Safety Score', value: `${stats.typescriptSafety.avgTypeSafetyScore}/100 (${safetyIndicator})` },
|
|
105
|
+
{ metric: 'Type Safety Rating', value: safetyRating }
|
|
106
|
+
]);
|
|
107
|
+
|
|
108
|
+
// Add explanation about TypeScript metrics
|
|
109
|
+
console.log('\n' + (useColors ? chalk.italic('Type Coverage:') : 'Type Coverage:'));
|
|
110
|
+
console.log(useColors
|
|
111
|
+
? chalk.italic('• Measures the percentage of code elements that have proper type information')
|
|
112
|
+
: '• Measures the percentage of code elements that have proper type information');
|
|
113
|
+
console.log(useColors
|
|
114
|
+
? chalk.italic('• Includes both explicit type annotations and TypeScript\'s type inference')
|
|
115
|
+
: '• Includes both explicit type annotations and TypeScript\'s type inference');
|
|
116
|
+
console.log(useColors
|
|
117
|
+
? chalk.italic('• Industry standard for production TypeScript is 85-95% coverage')
|
|
118
|
+
: '• Industry standard for production TypeScript is 85-95% coverage');
|
|
119
|
+
|
|
120
|
+
console.log('\n' + (useColors ? chalk.italic('Type Safety Score:') : 'Type Safety Score:'));
|
|
121
|
+
console.log(useColors
|
|
122
|
+
? chalk.italic('• Comprehensive evaluation that considers type coverage, "any" usage, and type assertions')
|
|
123
|
+
: '• Comprehensive evaluation that considers type coverage, "any" usage, and type assertions');
|
|
124
|
+
console.log(useColors
|
|
125
|
+
? chalk.italic('• Also accounts for TypeScript configuration in tsconfig.json')
|
|
126
|
+
: '• Also accounts for TypeScript configuration in tsconfig.json');
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Print code complexity metrics if available
|
|
130
|
+
if (stats.codeComplexity) {
|
|
131
|
+
console.log('\n' + (useColors ? chalk.bold.green('Code Complexity:') : 'Code Complexity:'));
|
|
132
|
+
|
|
133
|
+
// Prepare complexity indicator
|
|
134
|
+
let complexityIndicator;
|
|
135
|
+
if (stats.codeComplexity.overallComplexity === 'Low') {
|
|
136
|
+
complexityIndicator = useColors ? chalk.green('Simple ✓') : 'Simple ✓';
|
|
137
|
+
} else if (stats.codeComplexity.overallComplexity === 'Medium') {
|
|
138
|
+
complexityIndicator = useColors ? chalk.yellow('Moderate ⚠') : 'Moderate ⚠';
|
|
139
|
+
} else {
|
|
140
|
+
complexityIndicator = useColors ? chalk.red('Complex ✗') : 'Complex ✗';
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
formatTable([
|
|
144
|
+
{ metric: 'Analyzed Files', value: stats.formatNumber(stats.codeComplexity.analyzedFiles) },
|
|
145
|
+
{ metric: 'Total Functions', value: stats.formatNumber(stats.codeComplexity.totalFunctions) },
|
|
146
|
+
{ metric: 'Avg Cyclomatic Complexity', value: stats.codeComplexity.avgComplexity },
|
|
147
|
+
{ metric: 'Max Cyclomatic Complexity', value: stats.formatNumber(stats.codeComplexity.maxComplexity) },
|
|
148
|
+
{ metric: 'Avg Nesting Depth', value: stats.codeComplexity.avgNestingDepth },
|
|
149
|
+
{ metric: 'Max Nesting Depth', value: stats.formatNumber(stats.codeComplexity.maxNestingDepth) },
|
|
150
|
+
{ metric: 'Avg Function Size', value: `${stats.codeComplexity.avgFunctionSize} lines` },
|
|
151
|
+
{ metric: 'Complex Files', value: stats.formatNumber(stats.codeComplexity.complexFiles) },
|
|
152
|
+
{ metric: 'Overall Complexity', value: complexityIndicator }
|
|
153
|
+
]);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Add code quality recommendations
|
|
157
|
+
if (stats.typescriptSafety || stats.codeComplexity) {
|
|
158
|
+
console.log('\n' + (useColors ? chalk.bold.blue('📝 Code Quality Recommendations:') : '📝 Code Quality Recommendations:'));
|
|
159
|
+
const recommendations: string[] = [];
|
|
160
|
+
|
|
161
|
+
if (stats.typescriptSafety) {
|
|
162
|
+
const typeCoverage = parseFloat(stats.typescriptSafety.avgTypeCoverage);
|
|
163
|
+
|
|
164
|
+
// Type safety recommendations - with more specific thresholds
|
|
165
|
+
if (typeCoverage < 85) {
|
|
166
|
+
recommendations.push(useColors
|
|
167
|
+
? chalk.yellow('• Improve type coverage by adding more explicit type annotations')
|
|
168
|
+
: '• Improve type coverage by adding more explicit type annotations');
|
|
169
|
+
} else if (typeCoverage < 95) {
|
|
170
|
+
recommendations.push(useColors
|
|
171
|
+
? chalk.yellow('• Consider adding explicit type annotations to remaining untyped areas')
|
|
172
|
+
: '• Consider adding explicit type annotations to remaining untyped areas');
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (stats.typescriptSafety.totalAnyCount > 10) {
|
|
176
|
+
recommendations.push(useColors
|
|
177
|
+
? chalk.yellow(`• Reduce usage of 'any' type (found ${stats.typescriptSafety.totalAnyCount} instances) by using more specific types`)
|
|
178
|
+
: `• Reduce usage of 'any' type (found ${stats.typescriptSafety.totalAnyCount} instances) by using more specific types`);
|
|
179
|
+
} else if (stats.typescriptSafety.totalAnyCount > 0) {
|
|
180
|
+
recommendations.push(useColors
|
|
181
|
+
? chalk.yellow(`• Consider replacing the ${stats.typescriptSafety.totalAnyCount} 'any' type usage(s) with more specific types`)
|
|
182
|
+
: `• Consider replacing the ${stats.typescriptSafety.totalAnyCount} 'any' type usage(s) with more specific types`);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (stats.typescriptSafety.totalAssertions > 5) {
|
|
186
|
+
recommendations.push(useColors
|
|
187
|
+
? chalk.yellow(`• Reduce type assertions (${stats.typescriptSafety.totalAssertions} instances) by improving type declarations`)
|
|
188
|
+
: `• Reduce type assertions (${stats.typescriptSafety.totalAssertions} instances) by improving type declarations`);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (stats.typescriptSafety.totalNonNullAssertions > 5) {
|
|
192
|
+
recommendations.push(useColors
|
|
193
|
+
? chalk.yellow(`• Replace non-null assertions (${stats.typescriptSafety.totalNonNullAssertions} instances) with proper null checks`)
|
|
194
|
+
: `• Replace non-null assertions (${stats.typescriptSafety.totalNonNullAssertions} instances) with proper null checks`);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (stats.codeComplexity) {
|
|
199
|
+
// Code complexity recommendations
|
|
200
|
+
if (parseFloat(stats.codeComplexity.avgComplexity) > 6) {
|
|
201
|
+
recommendations.push(useColors
|
|
202
|
+
? chalk.yellow('• Reduce function complexity by breaking down complex functions into smaller, more focused ones')
|
|
203
|
+
: '• Reduce function complexity by breaking down complex functions into smaller, more focused ones');
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (parseFloat(stats.codeComplexity.avgNestingDepth) > 3) {
|
|
207
|
+
recommendations.push(useColors
|
|
208
|
+
? chalk.yellow('• Reduce nesting depth by extracting deeply nested code into separate functions')
|
|
209
|
+
: '• Reduce nesting depth by extracting deeply nested code into separate functions');
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (parseFloat(stats.codeComplexity.avgFunctionSize) > 15) {
|
|
213
|
+
recommendations.push(useColors
|
|
214
|
+
? chalk.yellow('• Consider refactoring large functions to improve readability and maintainability')
|
|
215
|
+
: '• Consider refactoring large functions to improve readability and maintainability');
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if (stats.codeComplexity.complexFiles > 0) {
|
|
219
|
+
recommendations.push(useColors
|
|
220
|
+
? chalk.yellow(`• Address high complexity in ${stats.codeComplexity.complexFiles} files with potential technical debt`)
|
|
221
|
+
: `• Address high complexity in ${stats.codeComplexity.complexFiles} files with potential technical debt`);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (recommendations.length > 0) {
|
|
226
|
+
console.log(recommendations.join('\n'));
|
|
227
|
+
} else {
|
|
228
|
+
console.log(useColors
|
|
229
|
+
? chalk.green('✓ Your code looks well structured! Keep up the good work.')
|
|
230
|
+
: '✓ Your code looks well structured! Keep up the good work.');
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
} catch (error) {
|
|
235
|
+
spinner.fail('Analysis failed');
|
|
236
|
+
console.error(useColors ? chalk.red('Error:') : 'Error:', (error as Error).message);
|
|
237
|
+
process.exit(1);
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
program.parse();
|