react-code-smell-detector 1.4.2 → 1.5.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 (110) hide show
  1. package/README.md +227 -22
  2. package/dist/__tests__/aiRefactoring.test.d.ts +2 -0
  3. package/dist/__tests__/aiRefactoring.test.d.ts.map +1 -0
  4. package/dist/__tests__/aiRefactoring.test.js +86 -0
  5. package/dist/__tests__/analyzer-real.test.d.ts +2 -0
  6. package/dist/__tests__/analyzer-real.test.d.ts.map +1 -0
  7. package/dist/__tests__/analyzer-real.test.js +149 -0
  8. package/dist/__tests__/analyzer.test.d.ts +2 -0
  9. package/dist/__tests__/analyzer.test.d.ts.map +1 -0
  10. package/dist/__tests__/analyzer.test.js +173 -0
  11. package/dist/__tests__/baseline.test.d.ts +2 -0
  12. package/dist/__tests__/baseline.test.d.ts.map +1 -0
  13. package/dist/__tests__/baseline.test.js +136 -0
  14. package/dist/__tests__/bundleAnalyzer.test.d.ts +2 -0
  15. package/dist/__tests__/bundleAnalyzer.test.d.ts.map +1 -0
  16. package/dist/__tests__/bundleAnalyzer.test.js +182 -0
  17. package/dist/__tests__/customRules.test.d.ts +2 -0
  18. package/dist/__tests__/customRules.test.d.ts.map +1 -0
  19. package/dist/__tests__/customRules.test.js +283 -0
  20. package/dist/__tests__/detectors/index.test.d.ts +2 -0
  21. package/dist/__tests__/detectors/index.test.d.ts.map +1 -0
  22. package/dist/__tests__/detectors/index.test.js +1012 -0
  23. package/dist/__tests__/detectors/newDetectors.test.d.ts +2 -0
  24. package/dist/__tests__/detectors/newDetectors.test.d.ts.map +1 -0
  25. package/dist/__tests__/detectors/newDetectors.test.js +333 -0
  26. package/dist/__tests__/docGenerator.test.d.ts +2 -0
  27. package/dist/__tests__/docGenerator.test.d.ts.map +1 -0
  28. package/dist/__tests__/docGenerator.test.js +157 -0
  29. package/dist/__tests__/fixer.test.d.ts +2 -0
  30. package/dist/__tests__/fixer.test.d.ts.map +1 -0
  31. package/dist/__tests__/fixer.test.js +193 -0
  32. package/dist/__tests__/git.test.d.ts +2 -0
  33. package/dist/__tests__/git.test.d.ts.map +1 -0
  34. package/dist/__tests__/git.test.js +38 -0
  35. package/dist/__tests__/graphGenerator.test.d.ts +2 -0
  36. package/dist/__tests__/graphGenerator.test.d.ts.map +1 -0
  37. package/dist/__tests__/graphGenerator.test.js +190 -0
  38. package/dist/__tests__/htmlReporter.test.d.ts +2 -0
  39. package/dist/__tests__/htmlReporter.test.d.ts.map +1 -0
  40. package/dist/__tests__/htmlReporter.test.js +258 -0
  41. package/dist/__tests__/interactiveFixer.test.d.ts +2 -0
  42. package/dist/__tests__/interactiveFixer.test.d.ts.map +1 -0
  43. package/dist/__tests__/interactiveFixer.test.js +231 -0
  44. package/dist/__tests__/parser.test.d.ts +2 -0
  45. package/dist/__tests__/parser.test.d.ts.map +1 -0
  46. package/dist/__tests__/parser.test.js +56 -0
  47. package/dist/__tests__/performanceBudget.test.d.ts +2 -0
  48. package/dist/__tests__/performanceBudget.test.d.ts.map +1 -0
  49. package/dist/__tests__/performanceBudget.test.js +242 -0
  50. package/dist/__tests__/prComments.test.d.ts +2 -0
  51. package/dist/__tests__/prComments.test.d.ts.map +1 -0
  52. package/dist/__tests__/prComments.test.js +118 -0
  53. package/dist/__tests__/reporter.test.d.ts +2 -0
  54. package/dist/__tests__/reporter.test.d.ts.map +1 -0
  55. package/dist/__tests__/reporter.test.js +136 -0
  56. package/dist/__tests__/watcher.test.d.ts +2 -0
  57. package/dist/__tests__/watcher.test.d.ts.map +1 -0
  58. package/dist/__tests__/watcher.test.js +161 -0
  59. package/dist/__tests__/webhooks.test.d.ts +2 -0
  60. package/dist/__tests__/webhooks.test.d.ts.map +1 -0
  61. package/dist/__tests__/webhooks.test.js +209 -0
  62. package/dist/aiRefactoring.d.ts +29 -0
  63. package/dist/aiRefactoring.d.ts.map +1 -0
  64. package/dist/aiRefactoring.js +290 -0
  65. package/dist/analyzer.d.ts.map +1 -1
  66. package/dist/analyzer.js +33 -1
  67. package/dist/cli.js +123 -1
  68. package/dist/detectors/contextApi.d.ts +11 -0
  69. package/dist/detectors/contextApi.d.ts.map +1 -0
  70. package/dist/detectors/contextApi.js +151 -0
  71. package/dist/detectors/errorBoundary.d.ts +11 -0
  72. package/dist/detectors/errorBoundary.d.ts.map +1 -0
  73. package/dist/detectors/errorBoundary.js +167 -0
  74. package/dist/detectors/formValidation.d.ts +11 -0
  75. package/dist/detectors/formValidation.d.ts.map +1 -0
  76. package/dist/detectors/formValidation.js +193 -0
  77. package/dist/detectors/index.d.ts +6 -0
  78. package/dist/detectors/index.d.ts.map +1 -1
  79. package/dist/detectors/index.js +12 -0
  80. package/dist/detectors/serverComponents.d.ts +11 -0
  81. package/dist/detectors/serverComponents.d.ts.map +1 -0
  82. package/dist/detectors/serverComponents.js +222 -0
  83. package/dist/detectors/stateManagement.d.ts +11 -0
  84. package/dist/detectors/stateManagement.d.ts.map +1 -0
  85. package/dist/detectors/stateManagement.js +193 -0
  86. package/dist/detectors/testingGaps.d.ts +15 -0
  87. package/dist/detectors/testingGaps.d.ts.map +1 -0
  88. package/dist/detectors/testingGaps.js +182 -0
  89. package/dist/docGenerator.d.ts +37 -0
  90. package/dist/docGenerator.d.ts.map +1 -0
  91. package/dist/docGenerator.js +306 -0
  92. package/dist/guide.d.ts +9 -0
  93. package/dist/guide.d.ts.map +1 -0
  94. package/dist/guide.js +922 -0
  95. package/dist/index.d.ts +5 -0
  96. package/dist/index.d.ts.map +1 -1
  97. package/dist/index.js +5 -0
  98. package/dist/interactiveFixer.d.ts +20 -0
  99. package/dist/interactiveFixer.d.ts.map +1 -0
  100. package/dist/interactiveFixer.js +178 -0
  101. package/dist/performanceBudget.d.ts +54 -0
  102. package/dist/performanceBudget.d.ts.map +1 -0
  103. package/dist/performanceBudget.js +218 -0
  104. package/dist/prComments.d.ts +47 -0
  105. package/dist/prComments.d.ts.map +1 -0
  106. package/dist/prComments.js +233 -0
  107. package/dist/types/index.d.ts +12 -1
  108. package/dist/types/index.d.ts.map +1 -1
  109. package/dist/types/index.js +18 -0
  110. package/package.json +10 -4
@@ -0,0 +1,233 @@
1
+ /**
2
+ * Generate a PR comment summary from analysis results
3
+ */
4
+ export function generatePRComment(result, rootDir) {
5
+ const { summary, debtScore, files } = result;
6
+ let comment = '## 🔍 Code Smell Analysis Report\n\n';
7
+ // Grade badge
8
+ const gradeEmoji = getGradeEmoji(debtScore.grade);
9
+ comment += `### ${gradeEmoji} Technical Debt Grade: **${debtScore.grade}** (Score: ${debtScore.score}/100)\n\n`;
10
+ // Summary table
11
+ comment += '| Metric | Count |\n';
12
+ comment += '|--------|-------|\n';
13
+ comment += `| Files Analyzed | ${summary.totalFiles} |\n`;
14
+ comment += `| Components | ${summary.totalComponents} |\n`;
15
+ comment += `| Total Issues | ${summary.totalSmells} |\n`;
16
+ comment += `| 🔴 Errors | ${summary.smellsBySeverity.error} |\n`;
17
+ comment += `| 🟡 Warnings | ${summary.smellsBySeverity.warning} |\n`;
18
+ comment += `| 🔵 Info | ${summary.smellsBySeverity.info} |\n\n`;
19
+ // Estimated refactor time
20
+ comment += `**Estimated Refactor Time:** ${debtScore.estimatedRefactorTime}\n\n`;
21
+ // Top issues by type
22
+ const topIssues = Object.entries(summary.smellsByType)
23
+ .filter(([_, count]) => count > 0)
24
+ .sort((a, b) => b[1] - a[1])
25
+ .slice(0, 5);
26
+ if (topIssues.length > 0) {
27
+ comment += '### Top Issues\n\n';
28
+ for (const [type, count] of topIssues) {
29
+ comment += `- **${type}**: ${count} occurrence(s)\n`;
30
+ }
31
+ comment += '\n';
32
+ }
33
+ // Breakdown by file (collapsible if many)
34
+ const filesWithIssues = files.filter(f => f.smells.length > 0);
35
+ if (filesWithIssues.length > 0) {
36
+ comment += '<details>\n<summary>📁 Issues by File</summary>\n\n';
37
+ for (const file of filesWithIssues.slice(0, 10)) {
38
+ const relativePath = file.file.replace(rootDir, '').replace(/^\//, '');
39
+ const errors = file.smells.filter(s => s.severity === 'error').length;
40
+ const warnings = file.smells.filter(s => s.severity === 'warning').length;
41
+ comment += `#### \`${relativePath}\`\n`;
42
+ comment += `🔴 ${errors} errors, 🟡 ${warnings} warnings\n\n`;
43
+ for (const smell of file.smells.slice(0, 5)) {
44
+ const emoji = smell.severity === 'error' ? '🔴' : smell.severity === 'warning' ? '🟡' : '🔵';
45
+ comment += `- ${emoji} Line ${smell.line}: ${smell.message}\n`;
46
+ }
47
+ if (file.smells.length > 5) {
48
+ comment += `- ... and ${file.smells.length - 5} more\n`;
49
+ }
50
+ comment += '\n';
51
+ }
52
+ if (filesWithIssues.length > 10) {
53
+ comment += `\n*... and ${filesWithIssues.length - 10} more files with issues*\n`;
54
+ }
55
+ comment += '</details>\n\n';
56
+ }
57
+ // Score breakdown
58
+ comment += '<details>\n<summary>📊 Score Breakdown</summary>\n\n';
59
+ comment += '| Category | Score |\n';
60
+ comment += '|----------|-------|\n';
61
+ comment += `| useEffect Usage | ${debtScore.breakdown.useEffectScore}/100 |\n`;
62
+ comment += `| Prop Drilling | ${debtScore.breakdown.propDrillingScore}/100 |\n`;
63
+ comment += `| Component Size | ${debtScore.breakdown.componentSizeScore}/100 |\n`;
64
+ comment += `| Memoization | ${debtScore.breakdown.memoizationScore}/100 |\n\n`;
65
+ comment += '</details>\n\n';
66
+ // Footer
67
+ comment += '---\n';
68
+ comment += '*Generated by [react-code-smell-detector](https://github.com/vsthakur101/react-code-smell-detector)*';
69
+ return comment;
70
+ }
71
+ /**
72
+ * Generate inline review comments for specific lines
73
+ */
74
+ export function generateInlineComments(smells, rootDir) {
75
+ const comments = [];
76
+ // Group by file and line to avoid duplicate comments
77
+ const grouped = new Map();
78
+ for (const smell of smells) {
79
+ const key = `${smell.file}:${smell.line}`;
80
+ const existing = grouped.get(key) || [];
81
+ existing.push(smell);
82
+ grouped.set(key, existing);
83
+ }
84
+ for (const [key, lineSmells] of grouped) {
85
+ const [file, lineStr] = key.split(':');
86
+ const line = parseInt(lineStr, 10);
87
+ const relativePath = file.replace(rootDir, '').replace(/^\//, '');
88
+ let body = '';
89
+ for (const smell of lineSmells) {
90
+ const emoji = smell.severity === 'error' ? '🔴' : smell.severity === 'warning' ? '🟡' : '🔵';
91
+ body += `${emoji} **${smell.type}**: ${smell.message}\n\n`;
92
+ body += `> 💡 ${smell.suggestion}\n\n`;
93
+ }
94
+ comments.push({
95
+ body: body.trim(),
96
+ path: relativePath,
97
+ line,
98
+ side: 'RIGHT',
99
+ });
100
+ }
101
+ return comments;
102
+ }
103
+ /**
104
+ * Post a comment to a GitHub PR using the GitHub API
105
+ */
106
+ export async function postPRComment(config, comment) {
107
+ const { token, owner, repo, prNumber } = config;
108
+ const url = `https://api.github.com/repos/${owner}/${repo}/issues/${prNumber}/comments`;
109
+ try {
110
+ const response = await fetch(url, {
111
+ method: 'POST',
112
+ headers: {
113
+ 'Authorization': `Bearer ${token}`,
114
+ 'Accept': 'application/vnd.github.v3+json',
115
+ 'Content-Type': 'application/json',
116
+ 'X-GitHub-Api-Version': '2022-11-28',
117
+ },
118
+ body: JSON.stringify({ body: comment }),
119
+ });
120
+ if (!response.ok) {
121
+ const error = await response.text();
122
+ console.error(`Failed to post PR comment: ${response.status} ${error}`);
123
+ return false;
124
+ }
125
+ return true;
126
+ }
127
+ catch (error) {
128
+ console.error(`Error posting PR comment: ${error.message}`);
129
+ return false;
130
+ }
131
+ }
132
+ /**
133
+ * Post inline review comments to a GitHub PR
134
+ */
135
+ export async function postInlineComments(config, comments) {
136
+ const { token, owner, repo, prNumber, commitSha } = config;
137
+ if (!commitSha) {
138
+ console.error('Commit SHA is required for inline comments');
139
+ return { success: 0, failed: comments.length };
140
+ }
141
+ let success = 0;
142
+ let failed = 0;
143
+ // Create a review with all comments
144
+ const url = `https://api.github.com/repos/${owner}/${repo}/pulls/${prNumber}/reviews`;
145
+ const reviewComments = comments.map(c => ({
146
+ path: c.path,
147
+ line: c.line,
148
+ side: c.side || 'RIGHT',
149
+ body: c.body,
150
+ }));
151
+ try {
152
+ const response = await fetch(url, {
153
+ method: 'POST',
154
+ headers: {
155
+ 'Authorization': `Bearer ${token}`,
156
+ 'Accept': 'application/vnd.github.v3+json',
157
+ 'Content-Type': 'application/json',
158
+ 'X-GitHub-Api-Version': '2022-11-28',
159
+ },
160
+ body: JSON.stringify({
161
+ commit_id: commitSha,
162
+ event: 'COMMENT',
163
+ comments: reviewComments,
164
+ }),
165
+ });
166
+ if (!response.ok) {
167
+ const error = await response.text();
168
+ console.error(`Failed to post inline comments: ${response.status} ${error}`);
169
+ failed = comments.length;
170
+ }
171
+ else {
172
+ success = comments.length;
173
+ }
174
+ }
175
+ catch (error) {
176
+ console.error(`Error posting inline comments: ${error.message}`);
177
+ failed = comments.length;
178
+ }
179
+ return { success, failed };
180
+ }
181
+ /**
182
+ * Get emoji for grade
183
+ */
184
+ function getGradeEmoji(grade) {
185
+ switch (grade) {
186
+ case 'A': return '🏆';
187
+ case 'B': return '✅';
188
+ case 'C': return '⚠️';
189
+ case 'D': return '🔶';
190
+ case 'F': return '🔴';
191
+ default: return '📊';
192
+ }
193
+ }
194
+ /**
195
+ * Parse GitHub repository info from environment or git remote
196
+ */
197
+ export function parseGitHubInfo() {
198
+ // Try GITHUB_REPOSITORY environment variable (set in GitHub Actions)
199
+ const ghRepo = process.env.GITHUB_REPOSITORY;
200
+ if (ghRepo) {
201
+ const [owner, repo] = ghRepo.split('/');
202
+ return { owner, repo };
203
+ }
204
+ return null;
205
+ }
206
+ /**
207
+ * Get PR number from environment (GitHub Actions)
208
+ */
209
+ export function getPRNumber() {
210
+ // GITHUB_REF format: refs/pull/{number}/merge
211
+ const ref = process.env.GITHUB_REF;
212
+ if (ref && ref.includes('/pull/')) {
213
+ const match = ref.match(/\/pull\/(\d+)\//);
214
+ if (match) {
215
+ return parseInt(match[1], 10);
216
+ }
217
+ }
218
+ // Try GITHUB_EVENT_PATH for pull_request events
219
+ const eventPath = process.env.GITHUB_EVENT_PATH;
220
+ if (eventPath) {
221
+ try {
222
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
223
+ const event = require(eventPath);
224
+ if (event.pull_request?.number) {
225
+ return event.pull_request.number;
226
+ }
227
+ }
228
+ catch {
229
+ // Ignore
230
+ }
231
+ }
232
+ return null;
233
+ }
@@ -1,5 +1,5 @@
1
1
  export type SmellSeverity = 'error' | 'warning' | 'info';
2
- export type SmellType = 'useEffect-overuse' | 'prop-drilling' | 'large-component' | 'unmemoized-calculation' | 'missing-dependency' | 'state-in-loop' | 'inline-function-prop' | 'deep-nesting' | 'missing-key' | 'hooks-rules-violation' | 'dependency-array-issue' | 'nested-ternary' | 'dead-code' | 'magic-value' | 'debug-statement' | 'todo-comment' | 'security-xss' | 'security-eval' | 'security-secrets' | 'a11y-missing-alt' | 'a11y-missing-label' | 'a11y-interactive-role' | 'a11y-keyboard' | 'a11y-semantic' | 'nextjs-client-server-boundary' | 'nextjs-missing-metadata' | 'nextjs-image-unoptimized' | 'nextjs-router-misuse' | 'rn-inline-style' | 'rn-missing-accessibility' | 'rn-performance-issue' | 'nodejs-callback-hell' | 'nodejs-unhandled-promise' | 'nodejs-sync-io' | 'nodejs-missing-error-handling' | 'js-var-usage' | 'js-loose-equality' | 'js-implicit-coercion' | 'js-global-pollution' | 'ts-any-usage' | 'ts-missing-return-type' | 'ts-non-null-assertion' | 'ts-type-assertion' | 'high-cyclomatic-complexity' | 'high-cognitive-complexity' | 'memory-leak-event-listener' | 'memory-leak-subscription' | 'memory-leak-timer' | 'memory-leak-async' | 'circular-dependency' | 'barrel-file-import' | 'namespace-import' | 'excessive-imports' | 'unused-export' | 'dead-import' | 'custom-rule';
2
+ export type SmellType = 'useEffect-overuse' | 'prop-drilling' | 'large-component' | 'unmemoized-calculation' | 'missing-dependency' | 'state-in-loop' | 'inline-function-prop' | 'deep-nesting' | 'missing-key' | 'hooks-rules-violation' | 'dependency-array-issue' | 'nested-ternary' | 'dead-code' | 'magic-value' | 'debug-statement' | 'todo-comment' | 'security-xss' | 'security-eval' | 'security-secrets' | 'a11y-missing-alt' | 'a11y-missing-label' | 'a11y-interactive-role' | 'a11y-keyboard' | 'a11y-semantic' | 'nextjs-client-server-boundary' | 'nextjs-missing-metadata' | 'nextjs-image-unoptimized' | 'nextjs-router-misuse' | 'rn-inline-style' | 'rn-missing-accessibility' | 'rn-performance-issue' | 'nodejs-callback-hell' | 'nodejs-unhandled-promise' | 'nodejs-sync-io' | 'nodejs-missing-error-handling' | 'js-var-usage' | 'js-loose-equality' | 'js-implicit-coercion' | 'js-global-pollution' | 'ts-any-usage' | 'ts-missing-return-type' | 'ts-non-null-assertion' | 'ts-type-assertion' | 'high-cyclomatic-complexity' | 'high-cognitive-complexity' | 'memory-leak-event-listener' | 'memory-leak-subscription' | 'memory-leak-timer' | 'memory-leak-async' | 'circular-dependency' | 'barrel-file-import' | 'namespace-import' | 'excessive-imports' | 'unused-export' | 'dead-import' | 'server-component-hooks' | 'server-component-events' | 'server-component-browser-api' | 'async-client-component' | 'mixed-directives' | 'context-overuse' | 'context-in-loop' | 'missing-context-memo' | 'large-context-value' | 'missing-error-boundary' | 'error-boundary-missing-fallback' | 'suspense-missing-fallback' | 'uncontrolled-form' | 'missing-form-validation' | 'form-without-onsubmit' | 'input-without-label' | 'redux-in-render' | 'excessive-redux-selectors' | 'state-sync-anti-pattern' | 'derived-state-in-state' | 'complex-untestable' | 'side-effect-heavy' | 'tightly-coupled' | 'custom-rule';
3
3
  export interface CodeSmell {
4
4
  type: SmellType;
5
5
  severity: SmellSeverity;
@@ -92,6 +92,17 @@ export interface DetectorConfig {
92
92
  analyzeBundleSize?: boolean;
93
93
  maxComponentSize?: number;
94
94
  customRules?: any[];
95
+ checkServerComponents: boolean;
96
+ checkContextApi: boolean;
97
+ maxContextConsumers: number;
98
+ checkErrorBoundaries: boolean;
99
+ checkForms: boolean;
100
+ checkStateManagement: boolean;
101
+ checkTestingGaps: boolean;
102
+ testComplexityThreshold: number;
103
+ aiRefactoringEnabled: boolean;
104
+ aiApiKey?: string;
105
+ aiModel?: string;
95
106
  }
96
107
  export declare const DEFAULT_CONFIG: DetectorConfig;
97
108
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"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"}
@@ -48,4 +48,22 @@ export const DEFAULT_CONFIG = {
48
48
  maxComponentSize: 10000,
49
49
  // Custom rules
50
50
  customRules: undefined,
51
+ // Server Components (React 19)
52
+ checkServerComponents: true,
53
+ // Context API analysis
54
+ checkContextApi: true,
55
+ maxContextConsumers: 5,
56
+ // Error boundary detection
57
+ checkErrorBoundaries: true,
58
+ // Form validation
59
+ checkForms: true,
60
+ // State management
61
+ checkStateManagement: true,
62
+ // Testing gaps
63
+ checkTestingGaps: true,
64
+ testComplexityThreshold: 10,
65
+ // AI refactoring
66
+ aiRefactoringEnabled: false,
67
+ aiApiKey: undefined,
68
+ aiModel: 'gpt-4',
51
69
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "react-code-smell-detector",
3
- "version": "1.4.2",
4
- "description": "Detect code smells in React projects - useEffect overuse, prop drilling, large components, security issues, accessibility, memory leaks, and more",
3
+ "version": "1.5.1",
4
+ "description": "Detect code smells in React projects - useEffect overuse, prop drilling, large components, security issues, accessibility, memory leaks, React 19 Server Components, and more",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
7
7
  "react-smell": "dist/cli.js"
@@ -16,7 +16,11 @@
16
16
  "build": "tsc",
17
17
  "dev": "tsc --watch",
18
18
  "start": "node dist/cli.js",
19
- "test": "vitest"
19
+ "test": "vitest",
20
+ "test:ui": "vitest --ui",
21
+ "test:coverage": "vitest run --coverage",
22
+ "test:report": "vitest run --reporter=html --outputFile.html=./test-report/index.html && open ./test-report/index.html",
23
+ "test:all": "vitest run --coverage --reporter=html --outputFile.html=./test-report/index.html"
20
24
  },
21
25
  "keywords": [
22
26
  "react",
@@ -44,8 +48,10 @@
44
48
  "devDependencies": {
45
49
  "@types/babel__traverse": "^7.20.4",
46
50
  "@types/node": "^20.10.0",
51
+ "@vitest/coverage-v8": "^4.0.18",
52
+ "@vitest/ui": "^4.0.18",
47
53
  "typescript": "^5.3.0",
48
- "vitest": "^1.0.0"
54
+ "vitest": "^4.0.18"
49
55
  },
50
56
  "engines": {
51
57
  "node": ">=18.0.0"