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.
Files changed (67) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +200 -4
  3. package/dist/analyzer.d.ts.map +1 -1
  4. package/dist/analyzer.js +22 -1
  5. package/dist/baseline.d.ts +37 -0
  6. package/dist/baseline.d.ts.map +1 -0
  7. package/dist/baseline.js +112 -0
  8. package/dist/cli.js +125 -26
  9. package/dist/detectors/complexity.d.ts +17 -0
  10. package/dist/detectors/complexity.d.ts.map +1 -0
  11. package/dist/detectors/complexity.js +69 -0
  12. package/dist/detectors/imports.d.ts +22 -0
  13. package/dist/detectors/imports.d.ts.map +1 -0
  14. package/dist/detectors/imports.js +210 -0
  15. package/dist/detectors/index.d.ts +4 -0
  16. package/dist/detectors/index.d.ts.map +1 -1
  17. package/dist/detectors/index.js +5 -0
  18. package/dist/detectors/memoryLeak.d.ts +7 -0
  19. package/dist/detectors/memoryLeak.d.ts.map +1 -0
  20. package/dist/detectors/memoryLeak.js +111 -0
  21. package/dist/detectors/unusedCode.d.ts +7 -0
  22. package/dist/detectors/unusedCode.d.ts.map +1 -0
  23. package/dist/detectors/unusedCode.js +78 -0
  24. package/dist/fixer.d.ts +23 -0
  25. package/dist/fixer.d.ts.map +1 -0
  26. package/dist/fixer.js +133 -0
  27. package/dist/git.d.ts +31 -0
  28. package/dist/git.d.ts.map +1 -0
  29. package/dist/git.js +137 -0
  30. package/dist/reporter.js +16 -0
  31. package/dist/types/index.d.ts +13 -1
  32. package/dist/types/index.d.ts.map +1 -1
  33. package/dist/types/index.js +18 -0
  34. package/dist/watcher.d.ts +16 -0
  35. package/dist/watcher.d.ts.map +1 -0
  36. package/dist/watcher.js +89 -0
  37. package/dist/webhooks.d.ts +20 -0
  38. package/dist/webhooks.d.ts.map +1 -0
  39. package/dist/webhooks.js +199 -0
  40. package/package.json +10 -2
  41. package/src/analyzer.ts +0 -324
  42. package/src/cli.ts +0 -159
  43. package/src/detectors/accessibility.ts +0 -212
  44. package/src/detectors/deadCode.ts +0 -163
  45. package/src/detectors/debug.ts +0 -103
  46. package/src/detectors/dependencyArray.ts +0 -176
  47. package/src/detectors/hooksRules.ts +0 -101
  48. package/src/detectors/index.ts +0 -20
  49. package/src/detectors/javascript.ts +0 -169
  50. package/src/detectors/largeComponent.ts +0 -63
  51. package/src/detectors/magicValues.ts +0 -114
  52. package/src/detectors/memoization.ts +0 -177
  53. package/src/detectors/missingKey.ts +0 -105
  54. package/src/detectors/nestedTernary.ts +0 -75
  55. package/src/detectors/nextjs.ts +0 -124
  56. package/src/detectors/nodejs.ts +0 -199
  57. package/src/detectors/propDrilling.ts +0 -103
  58. package/src/detectors/reactNative.ts +0 -154
  59. package/src/detectors/security.ts +0 -179
  60. package/src/detectors/typescript.ts +0 -151
  61. package/src/detectors/useEffect.ts +0 -117
  62. package/src/htmlReporter.ts +0 -464
  63. package/src/index.ts +0 -4
  64. package/src/parser/index.ts +0 -195
  65. package/src/reporter.ts +0 -291
  66. package/src/types/index.ts +0 -165
  67. 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:
@@ -1 +1 @@
1
- {"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../src/analyzer.ts"],"names":[],"mappings":"AAwBA,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;AA6OD,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC"}
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"}
@@ -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
+ }