react-code-smell-detector 1.2.0 ā 1.4.1
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/LICENSE +21 -0
- package/README.md +200 -4
- package/dist/analyzer.d.ts.map +1 -1
- package/dist/analyzer.js +22 -1
- package/dist/baseline.d.ts +37 -0
- package/dist/baseline.d.ts.map +1 -0
- package/dist/baseline.js +112 -0
- package/dist/cli.js +125 -26
- package/dist/detectors/complexity.d.ts +17 -0
- package/dist/detectors/complexity.d.ts.map +1 -0
- package/dist/detectors/complexity.js +69 -0
- package/dist/detectors/imports.d.ts +22 -0
- package/dist/detectors/imports.d.ts.map +1 -0
- package/dist/detectors/imports.js +210 -0
- package/dist/detectors/index.d.ts +4 -0
- package/dist/detectors/index.d.ts.map +1 -1
- package/dist/detectors/index.js +5 -0
- package/dist/detectors/memoryLeak.d.ts +7 -0
- package/dist/detectors/memoryLeak.d.ts.map +1 -0
- package/dist/detectors/memoryLeak.js +111 -0
- package/dist/detectors/unusedCode.d.ts +7 -0
- package/dist/detectors/unusedCode.d.ts.map +1 -0
- package/dist/detectors/unusedCode.js +78 -0
- package/dist/fixer.d.ts +23 -0
- package/dist/fixer.d.ts.map +1 -0
- package/dist/fixer.js +133 -0
- package/dist/git.d.ts +31 -0
- package/dist/git.d.ts.map +1 -0
- package/dist/git.js +137 -0
- package/dist/reporter.js +16 -0
- package/dist/types/index.d.ts +13 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +18 -0
- package/dist/watcher.d.ts +16 -0
- package/dist/watcher.d.ts.map +1 -0
- package/dist/watcher.js +89 -0
- package/dist/webhooks.d.ts +20 -0
- package/dist/webhooks.d.ts.map +1 -0
- package/dist/webhooks.js +199 -0
- package/package.json +10 -2
- package/src/analyzer.ts +0 -324
- package/src/cli.ts +0 -159
- package/src/detectors/accessibility.ts +0 -212
- package/src/detectors/deadCode.ts +0 -163
- package/src/detectors/debug.ts +0 -103
- package/src/detectors/dependencyArray.ts +0 -176
- package/src/detectors/hooksRules.ts +0 -101
- package/src/detectors/index.ts +0 -20
- package/src/detectors/javascript.ts +0 -169
- package/src/detectors/largeComponent.ts +0 -63
- package/src/detectors/magicValues.ts +0 -114
- package/src/detectors/memoization.ts +0 -177
- package/src/detectors/missingKey.ts +0 -105
- package/src/detectors/nestedTernary.ts +0 -75
- package/src/detectors/nextjs.ts +0 -124
- package/src/detectors/nodejs.ts +0 -199
- package/src/detectors/propDrilling.ts +0 -103
- package/src/detectors/reactNative.ts +0 -154
- package/src/detectors/security.ts +0 -179
- package/src/detectors/typescript.ts +0 -151
- package/src/detectors/useEffect.ts +0 -117
- package/src/htmlReporter.ts +0 -464
- package/src/index.ts +0 -4
- package/src/parser/index.ts +0 -195
- package/src/reporter.ts +0 -291
- package/src/types/index.ts +0 -165
- package/tsconfig.json +0 -19
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 vsthakur101
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ A CLI tool that analyzes React projects and detects common code smells, providin
|
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
|
-
- š **Detect Code Smells**: Identifies common React anti-patterns
|
|
7
|
+
- š **Detect Code Smells**: Identifies common React anti-patterns (51+ smell types)
|
|
8
8
|
- š **Technical Debt Score**: Grades your codebase from A to F
|
|
9
9
|
- š” **Refactoring Suggestions**: Actionable recommendations for each issue
|
|
10
10
|
- š **Multiple Output Formats**: Console (colored), JSON, Markdown, and HTML
|
|
@@ -12,6 +12,15 @@ A CLI tool that analyzes React projects and detects common code smells, providin
|
|
|
12
12
|
- āæ **Accessibility Checks**: Missing alt text, labels, ARIA attributes
|
|
13
13
|
- š **Debug Cleanup**: console.log, debugger, TODO/FIXME detection
|
|
14
14
|
- š¤ **CI/CD Ready**: Exit codes and flags for pipeline integration
|
|
15
|
+
- š§ **Auto-Fix**: Automatically fix simple issues (console.log, var, ==, missing alt)
|
|
16
|
+
- š **Watch Mode**: Re-analyze on file changes
|
|
17
|
+
- š **Git Integration**: Analyze only modified files
|
|
18
|
+
- š§® **Complexity Metrics**: Cyclomatic and cognitive complexity scoring
|
|
19
|
+
- š§ **Memory Leak Detection**: Find missing cleanup in useEffect
|
|
20
|
+
- š **Import Analysis**: Detect circular dependencies and barrel file issues
|
|
21
|
+
- šļø **Unused Code Detection**: Find unused exports and dead imports
|
|
22
|
+
- š **Baseline Tracking**: Track code smell trends over time with git commit history
|
|
23
|
+
- š¬ **Chat Notifications**: Send analysis results to Slack, Discord, or custom webhooks
|
|
15
24
|
|
|
16
25
|
### Detected Code Smells
|
|
17
26
|
|
|
@@ -25,6 +34,10 @@ A CLI tool that analyzes React projects and detects common code smells, providin
|
|
|
25
34
|
| **Security Issues** | dangerouslySetInnerHTML, eval(), innerHTML, exposed API keys |
|
|
26
35
|
| **Accessibility** | Missing alt text, form labels, keyboard handlers, semantic HTML |
|
|
27
36
|
| **Debug Statements** | console.log, debugger statements, TODO/FIXME comments |
|
|
37
|
+
| **Memory Leaks** | Missing cleanup for event listeners, timers, subscriptions |
|
|
38
|
+
| **Code Complexity** | Cyclomatic complexity, cognitive complexity, deep nesting |
|
|
39
|
+
| **Import Issues** | Circular dependencies, barrel file imports, excessive imports |
|
|
40
|
+
| **Unused Code** | Unused exports, dead imports |
|
|
28
41
|
| **Framework-Specific** | Next.js, React Native, Node.js, TypeScript issues |
|
|
29
42
|
|
|
30
43
|
## Installation
|
|
@@ -97,12 +110,147 @@ Or create manually:
|
|
|
97
110
|
| `-c, --config <file>` | Path to config file | `.smellrc.json` |
|
|
98
111
|
| `--ci` | CI mode: exit with code 1 if any issues | `false` |
|
|
99
112
|
| `--fail-on <severity>` | Exit code 1 threshold: error, warning, info | `error` |
|
|
113
|
+
| `--fix` | Auto-fix simple issues (console.log, var, ==, alt) | `false` |
|
|
114
|
+
| `--watch` | Watch mode: re-analyze on file changes | `false` |
|
|
115
|
+
| `--changed` | Only analyze git-modified files | `false` |
|
|
100
116
|
| `--max-effects <number>` | Max useEffects per component | `3` |
|
|
101
117
|
| `--max-props <number>` | Max props before warning | `7` |
|
|
102
118
|
| `--max-lines <number>` | Max lines per component | `300` |
|
|
103
119
|
| `--include <patterns>` | Glob patterns to include | `**/*.tsx,**/*.jsx` |
|
|
104
120
|
| `--exclude <patterns>` | Glob patterns to exclude | `node_modules,dist` |
|
|
105
121
|
| `-o, --output <file>` | Write output to file | - |
|
|
122
|
+
| `--baseline` | Enable baseline tracking and trend analysis | `false` |
|
|
123
|
+
| `--slack <url>` | Slack webhook URL for notifications | - |
|
|
124
|
+
| `--discord <url>` | Discord webhook URL for notifications | - |
|
|
125
|
+
| `--webhook <url>` | Generic webhook URL for notifications | - |
|
|
126
|
+
| `--webhook-threshold <number>` | Only notify if smells exceed threshold | `10` |
|
|
127
|
+
|
|
128
|
+
### Auto-Fix
|
|
129
|
+
|
|
130
|
+
Automatically fix simple issues:
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
# Fix and show remaining issues
|
|
134
|
+
react-smell ./src --fix
|
|
135
|
+
|
|
136
|
+
# Fix only (no report)
|
|
137
|
+
react-smell ./src --fix -f json > /dev/null
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Fixable issues:
|
|
141
|
+
- `console.log`, `console.debug`, etc. ā Removed
|
|
142
|
+
- `var x = 1` ā `let x = 1`
|
|
143
|
+
- `a == b` ā `a === b`
|
|
144
|
+
- `<img src="...">` ā `<img src="..." alt="">`
|
|
145
|
+
|
|
146
|
+
### Watch Mode
|
|
147
|
+
|
|
148
|
+
Re-analyze on every file change:
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
react-smell ./src --watch
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Git Integration
|
|
155
|
+
|
|
156
|
+
Only analyze modified files:
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
react-smell ./src --changed
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Baseline Tracking & Trend Analysis
|
|
163
|
+
|
|
164
|
+
Track code smell trends over time with automatic baseline recording:
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
# Enable baseline tracking
|
|
168
|
+
react-smell ./src --baseline
|
|
169
|
+
|
|
170
|
+
# Output includes trend analysis
|
|
171
|
+
š Code Smell Trend Analysis
|
|
172
|
+
āāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
173
|
+
Latest Run: 42 total smells
|
|
174
|
+
Trend: IMPROVING
|
|
175
|
+
Previous Run: 48 smells
|
|
176
|
+
Improved: 6 issues fixed
|
|
177
|
+
Worsened: 0 new issues
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
**Features:**
|
|
181
|
+
- Stores history in `.smellrc-baseline.json`
|
|
182
|
+
- Tracks timestamps, commit hashes, and author names
|
|
183
|
+
- Automatic trend calculation (improving/worsening/stable)
|
|
184
|
+
- Keeps last 50 records with automatic cleanup
|
|
185
|
+
- Perfect for CI/CD pipelines to monitor progress
|
|
186
|
+
|
|
187
|
+
**Configuration:**
|
|
188
|
+
```json
|
|
189
|
+
{
|
|
190
|
+
"baselineEnabled": true,
|
|
191
|
+
"baselineThreshold": 5
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Chat Notifications
|
|
196
|
+
|
|
197
|
+
Send analysis results to Slack, Discord, or custom webhooks:
|
|
198
|
+
|
|
199
|
+
#### Slack Integration
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
react-smell ./src --slack https://hooks.slack.com/services/YOUR/WEBHOOK
|
|
203
|
+
|
|
204
|
+
# With threshold (only notify if issues exceed limit)
|
|
205
|
+
react-smell ./src --slack $SLACK_URL --webhook-threshold 20
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
**Features:**
|
|
209
|
+
- Rich formatted messages with severity levels
|
|
210
|
+
- Includes branch, commit hash, and author info
|
|
211
|
+
- Shows top 5 issue types by frequency
|
|
212
|
+
- Color-coded severity (Critical/High/Medium/Low)
|
|
213
|
+
|
|
214
|
+
#### Discord Integration
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
react-smell ./src --discord https://discord.com/api/webhooks/123/abc
|
|
218
|
+
|
|
219
|
+
# With environment variable
|
|
220
|
+
export REACT_SMELL_DISCORD_WEBHOOK=https://...
|
|
221
|
+
react-smell ./src --discord $REACT_SMELL_DISCORD_WEBHOOK
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
**Features:**
|
|
225
|
+
- Embedded messages with visual design
|
|
226
|
+
- Color-coded smells by severity
|
|
227
|
+
- Full metadata included (branch, author, commit)
|
|
228
|
+
|
|
229
|
+
#### Generic Webhooks
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
react-smell ./src --webhook https://example.com/webhook
|
|
233
|
+
|
|
234
|
+
# Custom platform webhooks
|
|
235
|
+
react-smell ./src --webhook $CUSTOM_URL --webhook-threshold 15
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
**Environment Variables:**
|
|
239
|
+
```bash
|
|
240
|
+
export REACT_SMELL_SLACK_WEBHOOK=https://...
|
|
241
|
+
export REACT_SMELL_DISCORD_WEBHOOK=https://...
|
|
242
|
+
export REACT_SMELL_WEBHOOK=https://...
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
**CI/CD Example with Notifications:**
|
|
246
|
+
```bash
|
|
247
|
+
# Run analysis, track baseline, and notify on failures
|
|
248
|
+
react-smell ./src \
|
|
249
|
+
--baseline \
|
|
250
|
+
--slack $SLACK_WEBHOOK \
|
|
251
|
+
--webhook-threshold 10 \
|
|
252
|
+
--ci
|
|
253
|
+
```
|
|
106
254
|
|
|
107
255
|
## Example Output
|
|
108
256
|
|
|
@@ -134,18 +282,41 @@ Or create manually:
|
|
|
134
282
|
|
|
135
283
|
```typescript
|
|
136
284
|
import { analyzeProject, reportResults } from 'react-code-smell-detector';
|
|
285
|
+
import { initializeBaseline, recordBaseline, getTrendAnalysis, formatTrendReport } from 'react-code-smell-detector';
|
|
286
|
+
import { sendWebhookNotification, getWebhookConfig } from 'react-code-smell-detector';
|
|
137
287
|
|
|
138
288
|
const result = await analyzeProject({
|
|
139
289
|
rootDir: './src',
|
|
140
290
|
config: {
|
|
141
291
|
maxUseEffectsPerComponent: 3,
|
|
142
292
|
maxComponentLines: 300,
|
|
293
|
+
checkUnusedCode: true,
|
|
294
|
+
baselineEnabled: true,
|
|
143
295
|
},
|
|
144
296
|
});
|
|
145
297
|
|
|
146
298
|
console.log(`Grade: ${result.debtScore.grade}`);
|
|
147
299
|
console.log(`Total issues: ${result.summary.totalSmells}`);
|
|
148
300
|
|
|
301
|
+
// Track baseline
|
|
302
|
+
initializeBaseline('./src');
|
|
303
|
+
recordBaseline('./src', result.files.flatMap(f => f.smells));
|
|
304
|
+
const trend = getTrendAnalysis('./src');
|
|
305
|
+
console.log(formatTrendReport('./src'));
|
|
306
|
+
|
|
307
|
+
// Send notification
|
|
308
|
+
const webhookConfig = getWebhookConfig(
|
|
309
|
+
process.env.REACT_SMELL_SLACK_WEBHOOK,
|
|
310
|
+
process.env.REACT_SMELL_DISCORD_WEBHOOK
|
|
311
|
+
);
|
|
312
|
+
if (webhookConfig) {
|
|
313
|
+
await sendWebhookNotification(
|
|
314
|
+
webhookConfig,
|
|
315
|
+
result.files.flatMap(f => f.smells),
|
|
316
|
+
'my-project'
|
|
317
|
+
);
|
|
318
|
+
}
|
|
319
|
+
|
|
149
320
|
// Or use the reporter
|
|
150
321
|
const report = reportResults(result, {
|
|
151
322
|
format: 'markdown',
|
|
@@ -156,7 +327,7 @@ const report = reportResults(result, {
|
|
|
156
327
|
|
|
157
328
|
## CI/CD Integration
|
|
158
329
|
|
|
159
|
-
The tool provides flexible exit codes for CI/CD pipelines:
|
|
330
|
+
The tool provides flexible exit codes and notification capabilities for CI/CD pipelines:
|
|
160
331
|
|
|
161
332
|
```bash
|
|
162
333
|
# Fail on any issues (strict mode)
|
|
@@ -167,6 +338,9 @@ react-smell ./src --fail-on warning
|
|
|
167
338
|
|
|
168
339
|
# Generate HTML report and fail on errors
|
|
169
340
|
react-smell ./src -f html -o report.html --fail-on error
|
|
341
|
+
|
|
342
|
+
# Track trends and notify
|
|
343
|
+
react-smell ./src --baseline --slack $SLACK_WEBHOOK --ci
|
|
170
344
|
```
|
|
171
345
|
|
|
172
346
|
### GitHub Actions Example
|
|
@@ -181,6 +355,9 @@ jobs:
|
|
|
181
355
|
runs-on: ubuntu-latest
|
|
182
356
|
steps:
|
|
183
357
|
- uses: actions/checkout@v4
|
|
358
|
+
with:
|
|
359
|
+
fetch-depth: 0 # For git baseline tracking
|
|
360
|
+
|
|
184
361
|
- uses: actions/setup-node@v4
|
|
185
362
|
with:
|
|
186
363
|
node-version: '20'
|
|
@@ -188,8 +365,12 @@ jobs:
|
|
|
188
365
|
- name: Install dependencies
|
|
189
366
|
run: npm ci
|
|
190
367
|
|
|
191
|
-
- name: Check code smells
|
|
192
|
-
run: npx react-smell ./src -f html -o smell-report.html --fail-on warning
|
|
368
|
+
- name: Check code smells with baseline tracking
|
|
369
|
+
run: npx react-smell ./src -f html -o smell-report.html --baseline --fail-on warning
|
|
370
|
+
|
|
371
|
+
- name: Notify Slack on failure
|
|
372
|
+
if: failure()
|
|
373
|
+
run: npx react-smell ./src --slack ${{ secrets.SLACK_WEBHOOK }} --webhook-threshold 10
|
|
193
374
|
|
|
194
375
|
- name: Upload report
|
|
195
376
|
uses: actions/upload-artifact@v4
|
|
@@ -199,6 +380,21 @@ jobs:
|
|
|
199
380
|
path: smell-report.html
|
|
200
381
|
```
|
|
201
382
|
|
|
383
|
+
### GitLab CI Example
|
|
384
|
+
|
|
385
|
+
```yaml
|
|
386
|
+
code-quality:
|
|
387
|
+
image: node:20
|
|
388
|
+
script:
|
|
389
|
+
- npm ci
|
|
390
|
+
- npx react-smell ./src --baseline --fail-on warning
|
|
391
|
+
artifacts:
|
|
392
|
+
reports:
|
|
393
|
+
codequality: code-smell-report.json
|
|
394
|
+
after_script:
|
|
395
|
+
- npx react-smell ./src --discord $DISCORD_WEBHOOK || true
|
|
396
|
+
```
|
|
397
|
+
|
|
202
398
|
## Ignoring Issues
|
|
203
399
|
|
|
204
400
|
Use `@smell-ignore` comments to suppress specific issues:
|
package/dist/analyzer.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../src/analyzer.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../src/analyzer.ts"],"names":[],"mappings":"AA6BA,OAAO,EACL,cAAc,EAMd,cAAc,EAIf,MAAM,kBAAkB,CAAC;AAE1B,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;CAClC;AAED,wBAAsB,cAAc,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CA0CtF;AAkQD,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/analyzer.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fg from 'fast-glob';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import { parseFile } from './parser/index.js';
|
|
4
|
-
import { detectUseEffectOveruse, detectPropDrilling, analyzePropDrillingDepth, detectLargeComponent, detectUnmemoizedCalculations, detectMissingKeys, detectHooksRulesViolations, detectDependencyArrayIssues, detectNestedTernaries, detectDeadCode, detectMagicValues, detectNextjsIssues, detectReactNativeIssues, detectNodejsIssues, detectJavascriptIssues, detectTypescriptIssues, detectDebugStatements, detectSecurityIssues, detectAccessibilityIssues, } from './detectors/index.js';
|
|
4
|
+
import { detectUseEffectOveruse, detectPropDrilling, analyzePropDrillingDepth, detectLargeComponent, detectUnmemoizedCalculations, detectMissingKeys, detectHooksRulesViolations, detectDependencyArrayIssues, detectNestedTernaries, detectDeadCode, detectMagicValues, detectNextjsIssues, detectReactNativeIssues, detectNodejsIssues, detectJavascriptIssues, detectTypescriptIssues, detectDebugStatements, detectSecurityIssues, detectAccessibilityIssues, detectComplexity, detectMemoryLeaks, detectImportIssues, detectUnusedCode, } from './detectors/index.js';
|
|
5
5
|
import { DEFAULT_CONFIG, } from './types/index.js';
|
|
6
6
|
export async function analyzeProject(options) {
|
|
7
7
|
const { rootDir, include = ['**/*.tsx', '**/*.jsx'], exclude = ['**/node_modules/**', '**/dist/**', '**/build/**', '**/*.test.*', '**/*.spec.*'], config: userConfig = {}, } = options;
|
|
@@ -78,6 +78,11 @@ function analyzeFile(parseResult, filePath, config) {
|
|
|
78
78
|
smells.push(...detectDebugStatements(component, filePath, sourceCode, config));
|
|
79
79
|
smells.push(...detectSecurityIssues(component, filePath, sourceCode, config));
|
|
80
80
|
smells.push(...detectAccessibilityIssues(component, filePath, sourceCode, config));
|
|
81
|
+
// Complexity and Memory Leaks
|
|
82
|
+
smells.push(...detectComplexity(component, filePath, sourceCode, config));
|
|
83
|
+
smells.push(...detectMemoryLeaks(component, filePath, sourceCode, config));
|
|
84
|
+
smells.push(...detectImportIssues(component, filePath, sourceCode, config));
|
|
85
|
+
smells.push(...detectUnusedCode(component, filePath, sourceCode, config));
|
|
81
86
|
});
|
|
82
87
|
// Run cross-component analysis
|
|
83
88
|
smells.push(...analyzePropDrillingDepth(components, filePath, sourceCode, config));
|
|
@@ -170,6 +175,22 @@ function calculateSummary(files) {
|
|
|
170
175
|
'a11y-interactive-role': 0,
|
|
171
176
|
'a11y-keyboard': 0,
|
|
172
177
|
'a11y-semantic': 0,
|
|
178
|
+
// Complexity
|
|
179
|
+
'high-cyclomatic-complexity': 0,
|
|
180
|
+
'high-cognitive-complexity': 0,
|
|
181
|
+
// Memory leaks
|
|
182
|
+
'memory-leak-event-listener': 0,
|
|
183
|
+
'memory-leak-subscription': 0,
|
|
184
|
+
'memory-leak-timer': 0,
|
|
185
|
+
'memory-leak-async': 0,
|
|
186
|
+
// Import issues
|
|
187
|
+
'circular-dependency': 0,
|
|
188
|
+
'barrel-file-import': 0,
|
|
189
|
+
'namespace-import': 0,
|
|
190
|
+
'excessive-imports': 0,
|
|
191
|
+
// Unused code
|
|
192
|
+
'unused-export': 0,
|
|
193
|
+
'dead-import': 0,
|
|
173
194
|
};
|
|
174
195
|
const smellsBySeverity = {
|
|
175
196
|
error: 0,
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { CodeSmell } from './types/index.js';
|
|
2
|
+
export interface BaselineRecord {
|
|
3
|
+
timestamp: string;
|
|
4
|
+
commit?: string;
|
|
5
|
+
totalSmells: number;
|
|
6
|
+
byType: Record<string, number>;
|
|
7
|
+
smells: CodeSmell[];
|
|
8
|
+
}
|
|
9
|
+
export interface BaselineData {
|
|
10
|
+
version: '1.0';
|
|
11
|
+
records: BaselineRecord[];
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Initialize baseline tracking
|
|
15
|
+
*/
|
|
16
|
+
export declare function initializeBaseline(projectRoot: string): void;
|
|
17
|
+
/**
|
|
18
|
+
* Record current analysis result
|
|
19
|
+
*/
|
|
20
|
+
export declare function recordBaseline(projectRoot: string, smells: CodeSmell[], commit?: string): BaselineRecord;
|
|
21
|
+
/**
|
|
22
|
+
* Get trend analysis compared to previous baseline
|
|
23
|
+
*/
|
|
24
|
+
export declare function getTrendAnalysis(projectRoot: string): {
|
|
25
|
+
improved: number;
|
|
26
|
+
worsened: number;
|
|
27
|
+
trend: 'improving' | 'worsening' | 'stable';
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Get baseline history
|
|
31
|
+
*/
|
|
32
|
+
export declare function getBaselineHistory(projectRoot: string): BaselineRecord[];
|
|
33
|
+
/**
|
|
34
|
+
* Format trend report
|
|
35
|
+
*/
|
|
36
|
+
export declare function formatTrendReport(projectRoot: string): string;
|
|
37
|
+
//# sourceMappingURL=baseline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"baseline.d.ts","sourceRoot":"","sources":["../src/baseline.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE7C,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,MAAM,EAAE,SAAS,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,KAAK,CAAC;IACf,OAAO,EAAE,cAAc,EAAE,CAAC;CAC3B;AAID;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAa5D;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,SAAS,EAAE,EACnB,MAAM,CAAC,EAAE,MAAM,GACd,cAAc,CAgChB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,MAAM,GAClB;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,WAAW,GAAG,WAAW,GAAG,QAAQ,CAAA;CAAE,CAuBrF;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,cAAc,EAAE,CAQxE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAsB7D"}
|
package/dist/baseline.js
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
const BASELINE_FILE = '.smellrc-baseline.json';
|
|
4
|
+
/**
|
|
5
|
+
* Initialize baseline tracking
|
|
6
|
+
*/
|
|
7
|
+
export function initializeBaseline(projectRoot) {
|
|
8
|
+
const baselinePath = path.join(projectRoot, BASELINE_FILE);
|
|
9
|
+
try {
|
|
10
|
+
const stats = fs.statSync(baselinePath);
|
|
11
|
+
// File exists
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
// File doesn't exist, create it
|
|
15
|
+
const data = {
|
|
16
|
+
version: '1.0',
|
|
17
|
+
records: [],
|
|
18
|
+
};
|
|
19
|
+
fs.writeFileSync(baselinePath, JSON.stringify(data, null, 2));
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Record current analysis result
|
|
24
|
+
*/
|
|
25
|
+
export function recordBaseline(projectRoot, smells, commit) {
|
|
26
|
+
const baselinePath = path.join(projectRoot, BASELINE_FILE);
|
|
27
|
+
let data;
|
|
28
|
+
try {
|
|
29
|
+
const content = fs.readFileSync(baselinePath, 'utf-8');
|
|
30
|
+
data = JSON.parse(content);
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
data = { version: '1.0', records: [] };
|
|
34
|
+
}
|
|
35
|
+
const byType = {};
|
|
36
|
+
for (const smell of smells) {
|
|
37
|
+
byType[smell.type] = (byType[smell.type] || 0) + 1;
|
|
38
|
+
}
|
|
39
|
+
const record = {
|
|
40
|
+
timestamp: new Date().toISOString(),
|
|
41
|
+
commit,
|
|
42
|
+
totalSmells: smells.length,
|
|
43
|
+
byType,
|
|
44
|
+
smells: smells.slice(0, 100), // Keep first 100 for history
|
|
45
|
+
};
|
|
46
|
+
data.records.push(record);
|
|
47
|
+
// Keep last 50 records
|
|
48
|
+
if (data.records.length > 50) {
|
|
49
|
+
data.records = data.records.slice(-50);
|
|
50
|
+
}
|
|
51
|
+
fs.writeFileSync(baselinePath, JSON.stringify(data, null, 2));
|
|
52
|
+
return record;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Get trend analysis compared to previous baseline
|
|
56
|
+
*/
|
|
57
|
+
export function getTrendAnalysis(projectRoot) {
|
|
58
|
+
const baselinePath = path.join(projectRoot, BASELINE_FILE);
|
|
59
|
+
if (!fs.existsSync(baselinePath)) {
|
|
60
|
+
return { improved: 0, worsened: 0, trend: 'stable' };
|
|
61
|
+
}
|
|
62
|
+
const data = JSON.parse(fs.readFileSync(baselinePath, 'utf-8'));
|
|
63
|
+
if (data.records.length < 2) {
|
|
64
|
+
return { improved: 0, worsened: 0, trend: 'stable' };
|
|
65
|
+
}
|
|
66
|
+
const current = data.records[data.records.length - 1];
|
|
67
|
+
const previous = data.records[data.records.length - 2];
|
|
68
|
+
const diff = previous.totalSmells - current.totalSmells;
|
|
69
|
+
const improved = Math.max(0, diff);
|
|
70
|
+
const worsened = Math.max(0, -diff);
|
|
71
|
+
let trend = 'stable';
|
|
72
|
+
if (improved > worsened)
|
|
73
|
+
trend = 'improving';
|
|
74
|
+
if (worsened > improved)
|
|
75
|
+
trend = 'worsening';
|
|
76
|
+
return { improved, worsened, trend };
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Get baseline history
|
|
80
|
+
*/
|
|
81
|
+
export function getBaselineHistory(projectRoot) {
|
|
82
|
+
const baselinePath = path.join(projectRoot, BASELINE_FILE);
|
|
83
|
+
try {
|
|
84
|
+
const data = JSON.parse(fs.readFileSync(baselinePath, 'utf-8'));
|
|
85
|
+
return data.records;
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
return [];
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Format trend report
|
|
93
|
+
*/
|
|
94
|
+
export function formatTrendReport(projectRoot) {
|
|
95
|
+
const trend = getTrendAnalysis(projectRoot);
|
|
96
|
+
const history = getBaselineHistory(projectRoot);
|
|
97
|
+
if (history.length === 0) {
|
|
98
|
+
return 'No baseline history available yet.';
|
|
99
|
+
}
|
|
100
|
+
const latest = history[history.length - 1];
|
|
101
|
+
let report = `\nš Code Smell Trend Analysis\n`;
|
|
102
|
+
report += `āāāāāāāāāāāāāāāāāāāāāāāāāā\n`;
|
|
103
|
+
report += `Latest Run: ${latest.totalSmells} total smells\n`;
|
|
104
|
+
report += `Trend: ${trend.trend.toUpperCase()}\n`;
|
|
105
|
+
if (history.length >= 2) {
|
|
106
|
+
const previous = history[history.length - 2];
|
|
107
|
+
report += `Previous Run: ${previous.totalSmells} smells\n`;
|
|
108
|
+
report += `Improved: ${trend.improved} issues fixed\n`;
|
|
109
|
+
report += `Worsened: ${trend.worsened} new issues\n`;
|
|
110
|
+
}
|
|
111
|
+
return report;
|
|
112
|
+
}
|