react-code-smell-detector 1.4.1 โ†’ 1.5.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.
Files changed (56) hide show
  1. package/README.md +347 -22
  2. package/dist/__tests__/parser.test.d.ts +2 -0
  3. package/dist/__tests__/parser.test.d.ts.map +1 -0
  4. package/dist/__tests__/parser.test.js +56 -0
  5. package/dist/__tests__/performanceBudget.test.d.ts +2 -0
  6. package/dist/__tests__/performanceBudget.test.d.ts.map +1 -0
  7. package/dist/__tests__/performanceBudget.test.js +91 -0
  8. package/dist/__tests__/prComments.test.d.ts +2 -0
  9. package/dist/__tests__/prComments.test.d.ts.map +1 -0
  10. package/dist/__tests__/prComments.test.js +118 -0
  11. package/dist/analyzer.d.ts.map +1 -1
  12. package/dist/analyzer.js +34 -1
  13. package/dist/bundleAnalyzer.d.ts +25 -0
  14. package/dist/bundleAnalyzer.d.ts.map +1 -0
  15. package/dist/bundleAnalyzer.js +375 -0
  16. package/dist/cli.js +148 -1
  17. package/dist/customRules.d.ts +31 -0
  18. package/dist/customRules.d.ts.map +1 -0
  19. package/dist/customRules.js +289 -0
  20. package/dist/detectors/complexity.d.ts +0 -4
  21. package/dist/detectors/complexity.d.ts.map +1 -1
  22. package/dist/detectors/complexity.js +1 -1
  23. package/dist/detectors/deadCode.d.ts +0 -7
  24. package/dist/detectors/deadCode.d.ts.map +1 -1
  25. package/dist/detectors/deadCode.js +0 -24
  26. package/dist/detectors/index.d.ts +3 -2
  27. package/dist/detectors/index.d.ts.map +1 -1
  28. package/dist/detectors/index.js +4 -2
  29. package/dist/detectors/serverComponents.d.ts +11 -0
  30. package/dist/detectors/serverComponents.d.ts.map +1 -0
  31. package/dist/detectors/serverComponents.js +222 -0
  32. package/dist/docGenerator.d.ts +37 -0
  33. package/dist/docGenerator.d.ts.map +1 -0
  34. package/dist/docGenerator.js +306 -0
  35. package/dist/git.d.ts.map +1 -1
  36. package/dist/git.js +0 -7
  37. package/dist/graphGenerator.d.ts +34 -0
  38. package/dist/graphGenerator.d.ts.map +1 -0
  39. package/dist/graphGenerator.js +320 -0
  40. package/dist/index.d.ts +4 -0
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.js +4 -0
  43. package/dist/interactiveFixer.d.ts +20 -0
  44. package/dist/interactiveFixer.d.ts.map +1 -0
  45. package/dist/interactiveFixer.js +178 -0
  46. package/dist/performanceBudget.d.ts +54 -0
  47. package/dist/performanceBudget.d.ts.map +1 -0
  48. package/dist/performanceBudget.js +218 -0
  49. package/dist/prComments.d.ts +47 -0
  50. package/dist/prComments.d.ts.map +1 -0
  51. package/dist/prComments.js +233 -0
  52. package/dist/reporter.js +2 -0
  53. package/dist/types/index.d.ts +7 -1
  54. package/dist/types/index.d.ts.map +1 -1
  55. package/dist/types/index.js +10 -0
  56. package/package.json +10 -4
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 (51+ smell types)
7
+ - ๐Ÿ” **Detect Code Smells**: Identifies common React anti-patterns (70+ 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
@@ -21,6 +21,20 @@ A CLI tool that analyzes React projects and detects common code smells, providin
21
21
  - ๐Ÿ—‘๏ธ **Unused Code Detection**: Find unused exports and dead imports
22
22
  - ๐Ÿ“ˆ **Baseline Tracking**: Track code smell trends over time with git commit history
23
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
27
+ - ๐Ÿ”ง **Interactive Fix Mode**: Review and apply fixes one by one with diff preview
28
+ - ๐Ÿ’ฌ **GitHub PR Comments**: Auto-comment analysis results on pull requests
29
+ - ๐Ÿ“Š **Performance Budget**: Set thresholds and enforce limits in CI/CD
30
+ - ๐Ÿ“š **Component Documentation**: Auto-generate docs from component analysis
31
+ - โš›๏ธ **React 19 Server Components**: Detect Server/Client boundary issues
32
+ - ๐Ÿ”ฎ **Context API Analysis**: Detect context overuse, missing memoization, re-render issues
33
+ - ๐Ÿ›ก๏ธ **Error Boundary Detection**: Find missing ErrorBoundary and Suspense wrappers
34
+ - ๐Ÿ“‹ **Form Validation Smells**: Detect uncontrolled inputs, missing validation
35
+ - ๐Ÿ—ƒ๏ธ **State Management Analysis**: Redux/Zustand anti-patterns, selector issues
36
+ - ๐Ÿงช **Testing Gap Detection**: Identify complex components likely needing tests
37
+ - ๐Ÿค– **AI Refactoring Suggestions**: LLM-powered smart refactoring recommendations
24
38
 
25
39
  ### Detected Code Smells
26
40
 
@@ -38,7 +52,14 @@ A CLI tool that analyzes React projects and detects common code smells, providin
38
52
  | **Code Complexity** | Cyclomatic complexity, cognitive complexity, deep nesting |
39
53
  | **Import Issues** | Circular dependencies, barrel file imports, excessive imports |
40
54
  | **Unused Code** | Unused exports, dead imports |
55
+ | **Custom Rules** | User-defined code quality rules |
56
+ | **Server Components** | React 19 client/server boundary issues, async components |
41
57
  | **Framework-Specific** | Next.js, React Native, Node.js, TypeScript issues |
58
+ | **Context API** | Context overuse, missing memoization, large context values |
59
+ | **Error Boundaries** | Missing ErrorBoundary, Suspense without fallback |
60
+ | **Form Validation** | Uncontrolled forms, missing validation, controlled inputs without onChange |
61
+ | **State Management** | Redux selector anti-patterns, derived state issues, state sync problems |
62
+ | **Testing Gaps** | Complex untestable components, side-effect heavy code, tight coupling |
42
63
 
43
64
  ## Installation
44
65
 
@@ -124,6 +145,20 @@ Or create manually:
124
145
  | `--discord <url>` | Discord webhook URL for notifications | - |
125
146
  | `--webhook <url>` | Generic webhook URL for notifications | - |
126
147
  | `--webhook-threshold <number>` | Only notify if smells exceed threshold | `10` |
148
+ | `--graph` | Generate dependency graph visualization | `false` |
149
+ | `--graph-format <format>` | Graph output format: svg, html | `html` |
150
+ | `--bundle` | Analyze bundle size impact per component | `false` |
151
+ | `--rules <file>` | Custom rules configuration file | - |
152
+ | `--fix-interactive` | Interactive fix mode: review fixes one by one | `false` |
153
+ | `--fix-preview` | Preview fixable issues without applying | `false` |
154
+ | `--pr-comment` | Generate PR comment (for GitHub Actions) | `false` |
155
+ | `--budget` | Check against performance budget | `false` |
156
+ | `--budget-config <file>` | Path to budget config file | `.smellbudget.json` |
157
+ | `--docs` | Generate component documentation | `false` |
158
+ | `--docs-format <format>` | Documentation format: markdown, html, json | `markdown` |
159
+ | `--ai` | Enable AI-powered refactoring suggestions | `false` |
160
+ | `--ai-key <key>` | API key for AI provider | - |
161
+ | `--ai-model <model>` | AI model to use (gpt-4, claude-3-sonnet, etc.) | `gpt-4` |
127
162
 
128
163
  ### Auto-Fix
129
164
 
@@ -252,6 +287,285 @@ react-smell ./src \
252
287
  --ci
253
288
  ```
254
289
 
290
+ ### Dependency Graph Visualization
291
+
292
+ Generate interactive dependency graphs showing component and file relationships:
293
+
294
+ ```bash
295
+ # Generate dependency graph
296
+ react-smell ./src --graph
297
+
298
+ # Auto-generates: dependency-graph.html
299
+ ```
300
+
301
+ **Features:**
302
+ - Visual representation of file imports and dependencies
303
+ - Circular dependency detection and highlighting
304
+ - Force-directed layout for clarity
305
+ - Exportable SVG or HTML format
306
+ - Legend showing node types and relationships
307
+
308
+ **Example Usage:**
309
+ ```bash
310
+ # Generate and analyze all at once
311
+ react-smell ./src --graph --bundle --baseline --ci
312
+ ```
313
+
314
+ ### Bundle Size Impact Analysis
315
+
316
+ Estimate per-component bundle size impact:
317
+
318
+ ```bash
319
+ # Analyze bundle impact
320
+ react-smell ./src --bundle
321
+
322
+ # Auto-generates: bundle-analysis.html
323
+ ```
324
+
325
+ **Features:**
326
+ - Estimated size per component (in bytes)
327
+ - Line of code (LOC) analysis
328
+ - Dependency complexity scoring
329
+ - Impact level classification (low/medium/high/critical)
330
+ - Recommendations for optimization
331
+ - Breakdown of largest components
332
+
333
+ **Impact Levels:**
334
+ - ๐ŸŸข **Low**: <2KB, <150 LOC, low complexity
335
+ - ๐ŸŸก **Medium**: 2-5KB, 150-300 LOC, medium complexity
336
+ - ๐ŸŸ  **High**: 5-10KB, 300-500 LOC, high complexity
337
+ - ๐Ÿ”ด **Critical**: >10KB, >500 LOC, very complex
338
+
339
+ ### Custom Rules Engine
340
+
341
+ Define project-specific code quality rules:
342
+
343
+ **Configuration File (.smellrc-rules.json):**
344
+ ```json
345
+ {
346
+ "rules": [
347
+ {
348
+ "name": "no-hardcoded-strings",
349
+ "description": "Prevent hardcoded strings (use i18n)",
350
+ "severity": "warning",
351
+ "pattern": "\"(hello|world|test)\"",
352
+ "patternType": "regex",
353
+ "enabled": true
354
+ },
355
+ {
356
+ "name": "require-display-name",
357
+ "description": "All components must have displayName",
358
+ "severity": "info",
359
+ "pattern": "displayName",
360
+ "patternType": "text",
361
+ "enabled": true
362
+ }
363
+ ]
364
+ }
365
+ ```
366
+
367
+ **CLI Usage:**
368
+ ```bash
369
+ # Use custom rules
370
+ react-smell ./src --rules .smellrc-rules.json
371
+
372
+ # Combined with other features
373
+ react-smell ./src --rules .smellrc-rules.json --format json --ci
374
+ ```
375
+
376
+ **Rule Properties:**
377
+
378
+ | Property | Type | Description |
379
+ |----------|------|-------------|
380
+ | `name` | string | Unique rule identifier |
381
+ | `description` | string | Human-readable explanation |
382
+ | `severity` | string | error, warning, or info |
383
+ | `pattern` | string | Regex or text pattern |
384
+ | `patternType` | string | regex, text, or ast |
385
+ | `enabled` | boolean | Enable/disable rule |
386
+
387
+ **Pattern Types:**
388
+
389
+ - **regex**: Regular expression matching (e.g., `"hardcoded.*string"`)
390
+ - **text**: Simple string matching
391
+ - **ast**: Babel AST node type matching (e.g., `FunctionExpression`)
392
+
393
+ **Real-World Examples:**
394
+
395
+ ```json
396
+ {
397
+ "rules": [
398
+ {
399
+ "name": "no-console-in-production",
400
+ "pattern": "console\\.(log|warn|info)",
401
+ "patternType": "regex",
402
+ "severity": "error"
403
+ },
404
+ {
405
+ "name": "enforce-prop-types",
406
+ "pattern": "PropTypes",
407
+ "patternType": "text",
408
+ "severity": "warning",
409
+ "message": "Consider using TypeScript instead of PropTypes"
410
+ },
411
+ {
412
+ "name": "limit-nesting",
413
+ "description": "Flag deeply nested JSX",
414
+ "pattern": "<.*>.*<.*>.*<.*>.*<.*>.*<",
415
+ "patternType": "regex",
416
+ "severity": "info"
417
+ }
418
+ ]
419
+ }
420
+ ```
421
+
422
+ ### Interactive Fix Mode
423
+
424
+ Review and apply fixes one by one with diff preview:
425
+
426
+ ```bash
427
+ # Interactive mode - review each fix
428
+ react-smell ./src --fix-interactive
429
+
430
+ # Preview fixable issues without applying
431
+ react-smell ./src --fix-preview
432
+ ```
433
+
434
+ **Output:**
435
+ ```
436
+ ๐Ÿ”ง Interactive Fix Mode
437
+ Found 5 fixable issue(s). Review each one:
438
+
439
+ Commands: [y]es, [n]o, [a]ll, [q]uit
440
+
441
+ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
442
+ src/utils/helper.ts:15
443
+ debug-statement: console.log found
444
+ Fix: Remove console.log/debugger statements
445
+
446
+ - console.log('debug:', value);
447
+ + (line removed)
448
+
449
+ Apply this fix? [y/n/a/q]: y
450
+ โœ“ Applied
451
+ ```
452
+
453
+ ### GitHub PR Comments
454
+
455
+ Auto-comment code smell analysis on pull requests:
456
+
457
+ ```bash
458
+ # Generate PR comment (outputs markdown)
459
+ react-smell ./src --pr-comment
460
+
461
+ # In GitHub Actions (auto-posts to PR)
462
+ react-smell ./src --pr-comment --ci
463
+ ```
464
+
465
+ **GitHub Actions workflow:**
466
+ ```yaml
467
+ - name: Analyze Code
468
+ run: npx react-smell ./src --pr-comment --ci
469
+ env:
470
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
471
+ ```
472
+
473
+ ### Performance Budget
474
+
475
+ Set thresholds for code quality and enforce in CI/CD:
476
+
477
+ ```bash
478
+ # Create budget config
479
+ react-smell init-budget
480
+
481
+ # Check against budget
482
+ react-smell ./src --budget
483
+
484
+ # With custom config
485
+ react-smell ./src --budget --budget-config my-budget.json
486
+ ```
487
+
488
+ **Budget config (`.smellbudget.json`):**
489
+ ```json
490
+ {
491
+ "maxErrors": 0,
492
+ "maxWarnings": 10,
493
+ "minScore": 70,
494
+ "minGrade": "C",
495
+ "maxSmellsPerFile": 5,
496
+ "maxByType": {
497
+ "useEffect-overuse": 3,
498
+ "prop-drilling": 5
499
+ }
500
+ }
501
+ ```
502
+
503
+ **Output:**
504
+ ```
505
+ โœ— Performance budget check failed
506
+
507
+ Violations:
508
+ โœ— Errors (2) exceeds budget (0)
509
+ โš  Warnings (15) exceeds budget (10)
510
+
511
+ Checks: 3 passed, 2 failed
512
+ ```
513
+
514
+ ### Component Documentation
515
+
516
+ Auto-generate documentation from component analysis:
517
+
518
+ ```bash
519
+ # Generate markdown docs
520
+ react-smell docs ./src
521
+
522
+ # Generate HTML docs
523
+ react-smell docs ./src -f html
524
+
525
+ # Output to specific directory
526
+ react-smell docs ./src -f html -o ./docs
527
+ ```
528
+
529
+ **Output (COMPONENTS.md):**
530
+ ```markdown
531
+ # Component Documentation
532
+
533
+ ## Summary
534
+ | Metric | Value |
535
+ |--------|-------|
536
+ | Total Components | 25 |
537
+ | Technical Debt Grade | B |
538
+
539
+ ## Components
540
+
541
+ #### Button
542
+ ๐Ÿ“„ `components/Button.tsx`
543
+
544
+ | Metric | Value |
545
+ |--------|-------|
546
+ | Lines | 45 |
547
+ | Complexity | ๐ŸŸข Low |
548
+ | Maintainability | ๐ŸŸข Good |
549
+
550
+ **Hooks:** useState (2), useCallback (1)
551
+ ```
552
+
553
+ ### React 19 Server Components
554
+
555
+ Detect Server/Client component boundary issues:
556
+
557
+ ```bash
558
+ # Enabled by default for app/ directory components
559
+ react-smell ./src
560
+ ```
561
+
562
+ **Detected issues:**
563
+ - `server-component-hooks`: Using useState/useEffect in Server Components
564
+ - `server-component-events`: Using onClick/onChange in Server Components
565
+ - `server-component-browser-api`: Using window/document in Server Components
566
+ - `async-client-component`: Async function in 'use client' component
567
+ - `mixed-directives`: Both 'use client' and 'use server' in same file
568
+
255
569
  ## Example Output
256
570
 
257
571
  ```
@@ -281,9 +595,23 @@ react-smell ./src \
281
595
  ## Programmatic API
282
596
 
283
597
  ```typescript
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';
598
+ import {
599
+ analyzeProject,
600
+ reportResults,
601
+ // Interactive fixing
602
+ runInteractiveFix,
603
+ previewFixes,
604
+ // PR Comments
605
+ generatePRComment,
606
+ postPRComment,
607
+ // Performance Budget
608
+ loadBudget,
609
+ checkBudget,
610
+ formatBudgetReport,
611
+ // Documentation
612
+ generateComponentDocs,
613
+ writeComponentDocs,
614
+ } from 'react-code-smell-detector';
287
615
 
288
616
  const result = await analyzeProject({
289
617
  rootDir: './src',
@@ -291,32 +619,29 @@ const result = await analyzeProject({
291
619
  maxUseEffectsPerComponent: 3,
292
620
  maxComponentLines: 300,
293
621
  checkUnusedCode: true,
294
- baselineEnabled: true,
622
+ checkServerComponents: true, // React 19
295
623
  },
296
624
  });
297
625
 
298
626
  console.log(`Grade: ${result.debtScore.grade}`);
299
627
  console.log(`Total issues: ${result.summary.totalSmells}`);
300
628
 
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
- );
629
+ // Check against performance budget
630
+ const budget = await loadBudget();
631
+ const budgetResult = checkBudget(result, budget);
632
+ if (!budgetResult.passed) {
633
+ console.log(formatBudgetReport(budgetResult));
318
634
  }
319
635
 
636
+ // Generate documentation
637
+ const docsPath = await writeComponentDocs(result, './src', {
638
+ format: 'markdown',
639
+ includeSmells: true,
640
+ });
641
+
642
+ // Generate PR comment
643
+ const prComment = generatePRComment(result, './src');
644
+
320
645
  // Or use the reporter
321
646
  const report = reportResults(result, {
322
647
  format: 'markdown',
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=parser.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/parser.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,56 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { parseCode } from '../parser/index.js';
3
+ describe('Parser', () => {
4
+ it('should parse a simple React component', () => {
5
+ const code = `
6
+ function Hello({ name }) {
7
+ return <div>Hello {name}</div>;
8
+ }
9
+ `;
10
+ const result = parseCode(code);
11
+ expect(result.components).toHaveLength(1);
12
+ expect(result.components[0].name).toBe('Hello');
13
+ });
14
+ it('should detect useState hook', () => {
15
+ const code = `
16
+ function Counter() {
17
+ const [count, setCount] = useState(0);
18
+ return <button onClick={() => setCount(count + 1)}>{count}</button>;
19
+ }
20
+ `;
21
+ const result = parseCode(code);
22
+ expect(result.components).toHaveLength(1);
23
+ expect(result.components[0].hooks.useState).toHaveLength(1);
24
+ });
25
+ it('should detect useEffect hook', () => {
26
+ const code = `
27
+ function Timer() {
28
+ const [time, setTime] = useState(0);
29
+ useEffect(() => {
30
+ const id = setInterval(() => setTime(t => t + 1), 1000);
31
+ return () => clearInterval(id);
32
+ }, []);
33
+ return <span>{time}</span>;
34
+ }
35
+ `;
36
+ const result = parseCode(code);
37
+ expect(result.components).toHaveLength(1);
38
+ expect(result.components[0].hooks.useEffect).toHaveLength(1);
39
+ });
40
+ it('should extract component props', () => {
41
+ const code = `
42
+ function Card({ title, description, onClick }) {
43
+ return (
44
+ <div onClick={onClick}>
45
+ <h1>{title}</h1>
46
+ <p>{description}</p>
47
+ </div>
48
+ );
49
+ }
50
+ `;
51
+ const result = parseCode(code);
52
+ expect(result.components[0].props).toContain('title');
53
+ expect(result.components[0].props).toContain('description');
54
+ expect(result.components[0].props).toContain('onClick');
55
+ });
56
+ });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=performanceBudget.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"performanceBudget.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/performanceBudget.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,91 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { checkBudget } from '../performanceBudget.js';
3
+ describe('Performance Budget', () => {
4
+ const createMockResult = (overrides = {}) => ({
5
+ files: [],
6
+ summary: {
7
+ totalFiles: 5,
8
+ totalComponents: 10,
9
+ totalSmells: 3,
10
+ smellsByType: Object.fromEntries([
11
+ 'useEffect-overuse', 'prop-drilling', 'large-component', 'unmemoized-calculation',
12
+ 'missing-dependency', 'state-in-loop', 'inline-function-prop', 'deep-nesting',
13
+ 'missing-key', 'hooks-rules-violation', 'dependency-array-issue', 'nested-ternary',
14
+ 'dead-code', 'magic-value', 'debug-statement', 'todo-comment', 'security-xss',
15
+ 'security-eval', 'security-secrets', 'a11y-missing-alt', 'a11y-missing-label',
16
+ 'a11y-interactive-role', 'a11y-keyboard', 'a11y-semantic',
17
+ 'nextjs-client-server-boundary', 'nextjs-missing-metadata', 'nextjs-image-unoptimized',
18
+ 'nextjs-router-misuse', 'rn-inline-style', 'rn-missing-accessibility', 'rn-performance-issue',
19
+ 'nodejs-callback-hell', 'nodejs-unhandled-promise', 'nodejs-sync-io', 'nodejs-missing-error-handling',
20
+ 'js-var-usage', 'js-loose-equality', 'js-implicit-coercion', 'js-global-pollution',
21
+ 'ts-any-usage', 'ts-missing-return-type', 'ts-non-null-assertion', 'ts-type-assertion',
22
+ 'high-cyclomatic-complexity', 'high-cognitive-complexity',
23
+ 'memory-leak-event-listener', 'memory-leak-subscription', 'memory-leak-timer', 'memory-leak-async',
24
+ 'circular-dependency', 'barrel-file-import', 'namespace-import', 'excessive-imports',
25
+ 'unused-export', 'dead-import',
26
+ 'server-component-hooks', 'server-component-events', 'server-component-browser-api',
27
+ 'async-client-component', 'mixed-directives', 'custom-rule'
28
+ ].map(key => [key, 0])),
29
+ smellsBySeverity: { error: 0, warning: 2, info: 1 },
30
+ },
31
+ debtScore: {
32
+ score: 85,
33
+ grade: 'B',
34
+ breakdown: {
35
+ useEffectScore: 90,
36
+ propDrillingScore: 80,
37
+ componentSizeScore: 85,
38
+ memoizationScore: 85,
39
+ },
40
+ estimatedRefactorTime: '< 30 minutes',
41
+ },
42
+ ...overrides,
43
+ });
44
+ it('should pass when all budgets are met', () => {
45
+ const budget = {
46
+ maxTotalSmells: 10,
47
+ maxErrors: 5,
48
+ minGrade: 'C',
49
+ };
50
+ const result = checkBudget(createMockResult(), budget);
51
+ expect(result.passed).toBe(true);
52
+ expect(result.violations).toHaveLength(0);
53
+ });
54
+ it('should fail when total smells exceed budget', () => {
55
+ const budget = {
56
+ maxTotalSmells: 2,
57
+ };
58
+ const result = checkBudget(createMockResult(), budget);
59
+ expect(result.passed).toBe(false);
60
+ expect(result.violations).toHaveLength(1);
61
+ expect(result.violations[0].rule).toBe('maxTotalSmells');
62
+ });
63
+ it('should fail when errors exceed budget', () => {
64
+ const budget = {
65
+ maxErrors: 0,
66
+ };
67
+ const mockResult = createMockResult();
68
+ mockResult.summary.smellsBySeverity.error = 2;
69
+ const result = checkBudget(mockResult, budget);
70
+ expect(result.passed).toBe(false);
71
+ expect(result.violations[0].rule).toBe('maxErrors');
72
+ });
73
+ it('should fail when grade is below minimum', () => {
74
+ const budget = {
75
+ minGrade: 'A',
76
+ };
77
+ const result = checkBudget(createMockResult(), budget);
78
+ expect(result.passed).toBe(false);
79
+ expect(result.violations[0].rule).toBe('minGrade');
80
+ });
81
+ it('should allow warnings as non-blocking violations', () => {
82
+ const budget = {
83
+ maxWarnings: 1,
84
+ };
85
+ const result = checkBudget(createMockResult(), budget);
86
+ // Should have violation but still pass (warnings are non-blocking)
87
+ expect(result.violations).toHaveLength(1);
88
+ expect(result.violations[0].severity).toBe('warning');
89
+ expect(result.passed).toBe(true);
90
+ });
91
+ });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=prComments.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prComments.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/prComments.test.ts"],"names":[],"mappings":""}