react-code-smell-detector 1.3.1 → 1.4.2

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 (39) hide show
  1. package/README.md +294 -4
  2. package/dist/analyzer.d.ts.map +1 -1
  3. package/dist/analyzer.js +29 -1
  4. package/dist/baseline.d.ts +37 -0
  5. package/dist/baseline.d.ts.map +1 -0
  6. package/dist/baseline.js +112 -0
  7. package/dist/bundleAnalyzer.d.ts +25 -0
  8. package/dist/bundleAnalyzer.d.ts.map +1 -0
  9. package/dist/bundleAnalyzer.js +375 -0
  10. package/dist/cli.js +74 -0
  11. package/dist/customRules.d.ts +31 -0
  12. package/dist/customRules.d.ts.map +1 -0
  13. package/dist/customRules.js +289 -0
  14. package/dist/detectors/complexity.d.ts +0 -4
  15. package/dist/detectors/complexity.d.ts.map +1 -1
  16. package/dist/detectors/complexity.js +1 -1
  17. package/dist/detectors/deadCode.d.ts +0 -7
  18. package/dist/detectors/deadCode.d.ts.map +1 -1
  19. package/dist/detectors/deadCode.js +0 -24
  20. package/dist/detectors/index.d.ts +3 -2
  21. package/dist/detectors/index.d.ts.map +1 -1
  22. package/dist/detectors/index.js +3 -2
  23. package/dist/detectors/unusedCode.d.ts +7 -0
  24. package/dist/detectors/unusedCode.d.ts.map +1 -0
  25. package/dist/detectors/unusedCode.js +78 -0
  26. package/dist/git.d.ts +3 -0
  27. package/dist/git.d.ts.map +1 -1
  28. package/dist/git.js +13 -0
  29. package/dist/graphGenerator.d.ts +34 -0
  30. package/dist/graphGenerator.d.ts.map +1 -0
  31. package/dist/graphGenerator.js +320 -0
  32. package/dist/reporter.js +5 -0
  33. package/dist/types/index.d.ts +12 -1
  34. package/dist/types/index.d.ts.map +1 -1
  35. package/dist/types/index.js +17 -0
  36. package/dist/webhooks.d.ts +20 -0
  37. package/dist/webhooks.d.ts.map +1 -0
  38. package/dist/webhooks.js +199 -0
  39. package/package.json +3 -1
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
@@ -18,6 +18,12 @@ A CLI tool that analyzes React projects and detects common code smells, providin
18
18
  - 🧮 **Complexity Metrics**: Cyclomatic and cognitive complexity scoring
19
19
  - šŸ’§ **Memory Leak Detection**: Find missing cleanup in useEffect
20
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
24
+ - šŸ”— **Dependency Graph Visualization**: Visual SVG/HTML of component and import relationships
25
+ - šŸ“¦ **Bundle Size Impact**: Per-component bundle size estimates and optimization suggestions
26
+ - āš™ļø **Custom Rules Engine**: Define project-specific code quality rules in configuration
21
27
 
22
28
  ### Detected Code Smells
23
29
 
@@ -34,6 +40,8 @@ A CLI tool that analyzes React projects and detects common code smells, providin
34
40
  | **Memory Leaks** | Missing cleanup for event listeners, timers, subscriptions |
35
41
  | **Code Complexity** | Cyclomatic complexity, cognitive complexity, deep nesting |
36
42
  | **Import Issues** | Circular dependencies, barrel file imports, excessive imports |
43
+ | **Unused Code** | Unused exports, dead imports |
44
+ | **Custom Rules** | User-defined code quality rules |
37
45
  | **Framework-Specific** | Next.js, React Native, Node.js, TypeScript issues |
38
46
 
39
47
  ## Installation
@@ -115,6 +123,15 @@ Or create manually:
115
123
  | `--include <patterns>` | Glob patterns to include | `**/*.tsx,**/*.jsx` |
116
124
  | `--exclude <patterns>` | Glob patterns to exclude | `node_modules,dist` |
117
125
  | `-o, --output <file>` | Write output to file | - |
126
+ | `--baseline` | Enable baseline tracking and trend analysis | `false` |
127
+ | `--slack <url>` | Slack webhook URL for notifications | - |
128
+ | `--discord <url>` | Discord webhook URL for notifications | - |
129
+ | `--webhook <url>` | Generic webhook URL for notifications | - |
130
+ | `--webhook-threshold <number>` | Only notify if smells exceed threshold | `10` |
131
+ | `--graph` | Generate dependency graph visualization | `false` |
132
+ | `--graph-format <format>` | Graph output format: svg, html | `html` |
133
+ | `--bundle` | Analyze bundle size impact per component | `false` |
134
+ | `--rules <file>` | Custom rules configuration file | - |
118
135
 
119
136
  ### Auto-Fix
120
137
 
@@ -150,6 +167,231 @@ Only analyze modified files:
150
167
  react-smell ./src --changed
151
168
  ```
152
169
 
170
+ ### Baseline Tracking & Trend Analysis
171
+
172
+ Track code smell trends over time with automatic baseline recording:
173
+
174
+ ```bash
175
+ # Enable baseline tracking
176
+ react-smell ./src --baseline
177
+
178
+ # Output includes trend analysis
179
+ šŸ“Š Code Smell Trend Analysis
180
+ ──────────────────────────
181
+ Latest Run: 42 total smells
182
+ Trend: IMPROVING
183
+ Previous Run: 48 smells
184
+ Improved: 6 issues fixed
185
+ Worsened: 0 new issues
186
+ ```
187
+
188
+ **Features:**
189
+ - Stores history in `.smellrc-baseline.json`
190
+ - Tracks timestamps, commit hashes, and author names
191
+ - Automatic trend calculation (improving/worsening/stable)
192
+ - Keeps last 50 records with automatic cleanup
193
+ - Perfect for CI/CD pipelines to monitor progress
194
+
195
+ **Configuration:**
196
+ ```json
197
+ {
198
+ "baselineEnabled": true,
199
+ "baselineThreshold": 5
200
+ }
201
+ ```
202
+
203
+ ### Chat Notifications
204
+
205
+ Send analysis results to Slack, Discord, or custom webhooks:
206
+
207
+ #### Slack Integration
208
+
209
+ ```bash
210
+ react-smell ./src --slack https://hooks.slack.com/services/YOUR/WEBHOOK
211
+
212
+ # With threshold (only notify if issues exceed limit)
213
+ react-smell ./src --slack $SLACK_URL --webhook-threshold 20
214
+ ```
215
+
216
+ **Features:**
217
+ - Rich formatted messages with severity levels
218
+ - Includes branch, commit hash, and author info
219
+ - Shows top 5 issue types by frequency
220
+ - Color-coded severity (Critical/High/Medium/Low)
221
+
222
+ #### Discord Integration
223
+
224
+ ```bash
225
+ react-smell ./src --discord https://discord.com/api/webhooks/123/abc
226
+
227
+ # With environment variable
228
+ export REACT_SMELL_DISCORD_WEBHOOK=https://...
229
+ react-smell ./src --discord $REACT_SMELL_DISCORD_WEBHOOK
230
+ ```
231
+
232
+ **Features:**
233
+ - Embedded messages with visual design
234
+ - Color-coded smells by severity
235
+ - Full metadata included (branch, author, commit)
236
+
237
+ #### Generic Webhooks
238
+
239
+ ```bash
240
+ react-smell ./src --webhook https://example.com/webhook
241
+
242
+ # Custom platform webhooks
243
+ react-smell ./src --webhook $CUSTOM_URL --webhook-threshold 15
244
+ ```
245
+
246
+ **Environment Variables:**
247
+ ```bash
248
+ export REACT_SMELL_SLACK_WEBHOOK=https://...
249
+ export REACT_SMELL_DISCORD_WEBHOOK=https://...
250
+ export REACT_SMELL_WEBHOOK=https://...
251
+ ```
252
+
253
+ **CI/CD Example with Notifications:**
254
+ ```bash
255
+ # Run analysis, track baseline, and notify on failures
256
+ react-smell ./src \
257
+ --baseline \
258
+ --slack $SLACK_WEBHOOK \
259
+ --webhook-threshold 10 \
260
+ --ci
261
+ ```
262
+
263
+ ### Dependency Graph Visualization
264
+
265
+ Generate interactive dependency graphs showing component and file relationships:
266
+
267
+ ```bash
268
+ # Generate dependency graph
269
+ react-smell ./src --graph
270
+
271
+ # Auto-generates: dependency-graph.html
272
+ ```
273
+
274
+ **Features:**
275
+ - Visual representation of file imports and dependencies
276
+ - Circular dependency detection and highlighting
277
+ - Force-directed layout for clarity
278
+ - Exportable SVG or HTML format
279
+ - Legend showing node types and relationships
280
+
281
+ **Example Usage:**
282
+ ```bash
283
+ # Generate and analyze all at once
284
+ react-smell ./src --graph --bundle --baseline --ci
285
+ ```
286
+
287
+ ### Bundle Size Impact Analysis
288
+
289
+ Estimate per-component bundle size impact:
290
+
291
+ ```bash
292
+ # Analyze bundle impact
293
+ react-smell ./src --bundle
294
+
295
+ # Auto-generates: bundle-analysis.html
296
+ ```
297
+
298
+ **Features:**
299
+ - Estimated size per component (in bytes)
300
+ - Line of code (LOC) analysis
301
+ - Dependency complexity scoring
302
+ - Impact level classification (low/medium/high/critical)
303
+ - Recommendations for optimization
304
+ - Breakdown of largest components
305
+
306
+ **Impact Levels:**
307
+ - 🟢 **Low**: <2KB, <150 LOC, low complexity
308
+ - 🟔 **Medium**: 2-5KB, 150-300 LOC, medium complexity
309
+ - 🟠 **High**: 5-10KB, 300-500 LOC, high complexity
310
+ - šŸ”“ **Critical**: >10KB, >500 LOC, very complex
311
+
312
+ ### Custom Rules Engine
313
+
314
+ Define project-specific code quality rules:
315
+
316
+ **Configuration File (.smellrc-rules.json):**
317
+ ```json
318
+ {
319
+ "rules": [
320
+ {
321
+ "name": "no-hardcoded-strings",
322
+ "description": "Prevent hardcoded strings (use i18n)",
323
+ "severity": "warning",
324
+ "pattern": "\"(hello|world|test)\"",
325
+ "patternType": "regex",
326
+ "enabled": true
327
+ },
328
+ {
329
+ "name": "require-display-name",
330
+ "description": "All components must have displayName",
331
+ "severity": "info",
332
+ "pattern": "displayName",
333
+ "patternType": "text",
334
+ "enabled": true
335
+ }
336
+ ]
337
+ }
338
+ ```
339
+
340
+ **CLI Usage:**
341
+ ```bash
342
+ # Use custom rules
343
+ react-smell ./src --rules .smellrc-rules.json
344
+
345
+ # Combined with other features
346
+ react-smell ./src --rules .smellrc-rules.json --format json --ci
347
+ ```
348
+
349
+ **Rule Properties:**
350
+
351
+ | Property | Type | Description |
352
+ |----------|------|-------------|
353
+ | `name` | string | Unique rule identifier |
354
+ | `description` | string | Human-readable explanation |
355
+ | `severity` | string | error, warning, or info |
356
+ | `pattern` | string | Regex or text pattern |
357
+ | `patternType` | string | regex, text, or ast |
358
+ | `enabled` | boolean | Enable/disable rule |
359
+
360
+ **Pattern Types:**
361
+
362
+ - **regex**: Regular expression matching (e.g., `"hardcoded.*string"`)
363
+ - **text**: Simple string matching
364
+ - **ast**: Babel AST node type matching (e.g., `FunctionExpression`)
365
+
366
+ **Real-World Examples:**
367
+
368
+ ```json
369
+ {
370
+ "rules": [
371
+ {
372
+ "name": "no-console-in-production",
373
+ "pattern": "console\\.(log|warn|info)",
374
+ "patternType": "regex",
375
+ "severity": "error"
376
+ },
377
+ {
378
+ "name": "enforce-prop-types",
379
+ "pattern": "PropTypes",
380
+ "patternType": "text",
381
+ "severity": "warning",
382
+ "message": "Consider using TypeScript instead of PropTypes"
383
+ },
384
+ {
385
+ "name": "limit-nesting",
386
+ "description": "Flag deeply nested JSX",
387
+ "pattern": "<.*>.*<.*>.*<.*>.*<.*>.*<",
388
+ "patternType": "regex",
389
+ "severity": "info"
390
+ }
391
+ ]
392
+ }
393
+ ```
394
+
153
395
  ## Example Output
154
396
 
155
397
  ```
@@ -180,18 +422,41 @@ react-smell ./src --changed
180
422
 
181
423
  ```typescript
182
424
  import { analyzeProject, reportResults } from 'react-code-smell-detector';
425
+ import { initializeBaseline, recordBaseline, getTrendAnalysis, formatTrendReport } from 'react-code-smell-detector';
426
+ import { sendWebhookNotification, getWebhookConfig } from 'react-code-smell-detector';
183
427
 
184
428
  const result = await analyzeProject({
185
429
  rootDir: './src',
186
430
  config: {
187
431
  maxUseEffectsPerComponent: 3,
188
432
  maxComponentLines: 300,
433
+ checkUnusedCode: true,
434
+ baselineEnabled: true,
189
435
  },
190
436
  });
191
437
 
192
438
  console.log(`Grade: ${result.debtScore.grade}`);
193
439
  console.log(`Total issues: ${result.summary.totalSmells}`);
194
440
 
441
+ // Track baseline
442
+ initializeBaseline('./src');
443
+ recordBaseline('./src', result.files.flatMap(f => f.smells));
444
+ const trend = getTrendAnalysis('./src');
445
+ console.log(formatTrendReport('./src'));
446
+
447
+ // Send notification
448
+ const webhookConfig = getWebhookConfig(
449
+ process.env.REACT_SMELL_SLACK_WEBHOOK,
450
+ process.env.REACT_SMELL_DISCORD_WEBHOOK
451
+ );
452
+ if (webhookConfig) {
453
+ await sendWebhookNotification(
454
+ webhookConfig,
455
+ result.files.flatMap(f => f.smells),
456
+ 'my-project'
457
+ );
458
+ }
459
+
195
460
  // Or use the reporter
196
461
  const report = reportResults(result, {
197
462
  format: 'markdown',
@@ -202,7 +467,7 @@ const report = reportResults(result, {
202
467
 
203
468
  ## CI/CD Integration
204
469
 
205
- The tool provides flexible exit codes for CI/CD pipelines:
470
+ The tool provides flexible exit codes and notification capabilities for CI/CD pipelines:
206
471
 
207
472
  ```bash
208
473
  # Fail on any issues (strict mode)
@@ -213,6 +478,9 @@ react-smell ./src --fail-on warning
213
478
 
214
479
  # Generate HTML report and fail on errors
215
480
  react-smell ./src -f html -o report.html --fail-on error
481
+
482
+ # Track trends and notify
483
+ react-smell ./src --baseline --slack $SLACK_WEBHOOK --ci
216
484
  ```
217
485
 
218
486
  ### GitHub Actions Example
@@ -227,6 +495,9 @@ jobs:
227
495
  runs-on: ubuntu-latest
228
496
  steps:
229
497
  - uses: actions/checkout@v4
498
+ with:
499
+ fetch-depth: 0 # For git baseline tracking
500
+
230
501
  - uses: actions/setup-node@v4
231
502
  with:
232
503
  node-version: '20'
@@ -234,8 +505,12 @@ jobs:
234
505
  - name: Install dependencies
235
506
  run: npm ci
236
507
 
237
- - name: Check code smells
238
- run: npx react-smell ./src -f html -o smell-report.html --fail-on warning
508
+ - name: Check code smells with baseline tracking
509
+ run: npx react-smell ./src -f html -o smell-report.html --baseline --fail-on warning
510
+
511
+ - name: Notify Slack on failure
512
+ if: failure()
513
+ run: npx react-smell ./src --slack ${{ secrets.SLACK_WEBHOOK }} --webhook-threshold 10
239
514
 
240
515
  - name: Upload report
241
516
  uses: actions/upload-artifact@v4
@@ -245,6 +520,21 @@ jobs:
245
520
  path: smell-report.html
246
521
  ```
247
522
 
523
+ ### GitLab CI Example
524
+
525
+ ```yaml
526
+ code-quality:
527
+ image: node:20
528
+ script:
529
+ - npm ci
530
+ - npx react-smell ./src --baseline --fail-on warning
531
+ artifacts:
532
+ reports:
533
+ codequality: code-smell-report.json
534
+ after_script:
535
+ - npx react-smell ./src --discord $DISCORD_WEBHOOK || true
536
+ ```
537
+
248
538
  ## Ignoring Issues
249
539
 
250
540
  Use `@smell-ignore` comments to suppress specific issues:
@@ -1 +1 @@
1
- {"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../src/analyzer.ts"],"names":[],"mappings":"AA4BA,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;AA8PD,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../src/analyzer.ts"],"names":[],"mappings":"AA+BA,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,CA8DtF;AA0QD,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC"}
package/dist/analyzer.js CHANGED
@@ -1,7 +1,10 @@
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, detectComplexity, detectMemoryLeaks, detectImportIssues, } 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
+ import { parseCustomRules, detectCustomRuleViolations } from './customRules.js';
6
+ import { buildDependencyGraph } from './graphGenerator.js';
7
+ import { analyzeBundleImpact } from './bundleAnalyzer.js';
5
8
  import { DEFAULT_CONFIG, } from './types/index.js';
6
9
  export async function analyzeProject(options) {
7
10
  const { rootDir, include = ['**/*.tsx', '**/*.jsx'], exclude = ['**/node_modules/**', '**/dist/**', '**/build/**', '**/*.test.*', '**/*.spec.*'], config: userConfig = {}, } = options;
@@ -30,6 +33,20 @@ export async function analyzeProject(options) {
30
33
  // Calculate summary and score
31
34
  const summary = calculateSummary(fileAnalyses);
32
35
  const debtScore = calculateTechnicalDebtScore(fileAnalyses, summary);
36
+ // Generate dependency graph if requested
37
+ if (config.generateDependencyGraph) {
38
+ const importsData = fileAnalyses.map(f => ({ file: f.file, imports: f.imports }));
39
+ const graph = buildDependencyGraph(importsData, rootDir);
40
+ // Graph is available via extension (not in standard result yet)
41
+ global._dependencyGraph = graph;
42
+ }
43
+ // Analyze bundle size if requested
44
+ if (config.analyzeBundleSize) {
45
+ const allComponents = fileAnalyses.flatMap(f => f.components);
46
+ const bundleAnalysis = analyzeBundleImpact(fileAnalyses.map(f => ({ components: f.components, file: f.file })), fileAnalyses, '');
47
+ // Bundle analysis is available via extension
48
+ global._bundleAnalysis = bundleAnalysis;
49
+ }
33
50
  return {
34
51
  files: fileAnalyses,
35
52
  summary,
@@ -82,6 +99,12 @@ function analyzeFile(parseResult, filePath, config) {
82
99
  smells.push(...detectComplexity(component, filePath, sourceCode, config));
83
100
  smells.push(...detectMemoryLeaks(component, filePath, sourceCode, config));
84
101
  smells.push(...detectImportIssues(component, filePath, sourceCode, config));
102
+ smells.push(...detectUnusedCode(component, filePath, sourceCode, config));
103
+ // Custom rules
104
+ const customRules = parseCustomRules(config);
105
+ if (customRules.length > 0) {
106
+ smells.push(...detectCustomRuleViolations(component, filePath, sourceCode, customRules));
107
+ }
85
108
  });
86
109
  // Run cross-component analysis
87
110
  smells.push(...analyzePropDrillingDepth(components, filePath, sourceCode, config));
@@ -187,6 +210,11 @@ function calculateSummary(files) {
187
210
  'barrel-file-import': 0,
188
211
  'namespace-import': 0,
189
212
  'excessive-imports': 0,
213
+ // Unused code
214
+ 'unused-export': 0,
215
+ 'dead-import': 0,
216
+ // Custom rules
217
+ 'custom-rule': 0,
190
218
  };
191
219
  const smellsBySeverity = {
192
220
  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
+ }
@@ -0,0 +1,25 @@
1
+ export interface ComponentBundleInfo {
2
+ name: string;
3
+ file: string;
4
+ estimatedSize: number;
5
+ dependencies: number;
6
+ exports: number;
7
+ complexity: number;
8
+ impact: 'low' | 'medium' | 'high' | 'critical';
9
+ }
10
+ export interface BundleAnalysisResult {
11
+ components: ComponentBundleInfo[];
12
+ totalEstimatedSize: number;
13
+ averageComponentSize: number;
14
+ largestComponents: ComponentBundleInfo[];
15
+ recommendations: string[];
16
+ }
17
+ /**
18
+ * Estimate bundle size impact per component
19
+ */
20
+ export declare function analyzeBundleImpact(components: any[], files: any[], sourceCode: string): BundleAnalysisResult;
21
+ /**
22
+ * Generate HTML bundle analysis report
23
+ */
24
+ export declare function generateBundleReport(analysis: BundleAnalysisResult, projectName: string): string;
25
+ //# sourceMappingURL=bundleAnalyzer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bundleAnalyzer.d.ts","sourceRoot":"","sources":["../src/bundleAnalyzer.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,UAAU,CAAC;CAChD;AAED,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,mBAAmB,EAAE,CAAC;IAClC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,iBAAiB,EAAE,mBAAmB,EAAE,CAAC;IACzC,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,GAAG,EAAE,EACjB,KAAK,EAAE,GAAG,EAAE,EACZ,UAAU,EAAE,MAAM,GACjB,oBAAoB,CAuBtB;AAuJD;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,oBAAoB,EAC9B,WAAW,EAAE,MAAM,GAClB,MAAM,CAmOR"}