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.
- package/README.md +227 -22
- package/dist/__tests__/aiRefactoring.test.d.ts +2 -0
- package/dist/__tests__/aiRefactoring.test.d.ts.map +1 -0
- package/dist/__tests__/aiRefactoring.test.js +86 -0
- package/dist/__tests__/analyzer-real.test.d.ts +2 -0
- package/dist/__tests__/analyzer-real.test.d.ts.map +1 -0
- package/dist/__tests__/analyzer-real.test.js +149 -0
- package/dist/__tests__/analyzer.test.d.ts +2 -0
- package/dist/__tests__/analyzer.test.d.ts.map +1 -0
- package/dist/__tests__/analyzer.test.js +173 -0
- package/dist/__tests__/baseline.test.d.ts +2 -0
- package/dist/__tests__/baseline.test.d.ts.map +1 -0
- package/dist/__tests__/baseline.test.js +136 -0
- package/dist/__tests__/bundleAnalyzer.test.d.ts +2 -0
- package/dist/__tests__/bundleAnalyzer.test.d.ts.map +1 -0
- package/dist/__tests__/bundleAnalyzer.test.js +182 -0
- package/dist/__tests__/customRules.test.d.ts +2 -0
- package/dist/__tests__/customRules.test.d.ts.map +1 -0
- package/dist/__tests__/customRules.test.js +283 -0
- package/dist/__tests__/detectors/index.test.d.ts +2 -0
- package/dist/__tests__/detectors/index.test.d.ts.map +1 -0
- package/dist/__tests__/detectors/index.test.js +1012 -0
- package/dist/__tests__/detectors/newDetectors.test.d.ts +2 -0
- package/dist/__tests__/detectors/newDetectors.test.d.ts.map +1 -0
- package/dist/__tests__/detectors/newDetectors.test.js +333 -0
- package/dist/__tests__/docGenerator.test.d.ts +2 -0
- package/dist/__tests__/docGenerator.test.d.ts.map +1 -0
- package/dist/__tests__/docGenerator.test.js +157 -0
- package/dist/__tests__/fixer.test.d.ts +2 -0
- package/dist/__tests__/fixer.test.d.ts.map +1 -0
- package/dist/__tests__/fixer.test.js +193 -0
- package/dist/__tests__/git.test.d.ts +2 -0
- package/dist/__tests__/git.test.d.ts.map +1 -0
- package/dist/__tests__/git.test.js +38 -0
- package/dist/__tests__/graphGenerator.test.d.ts +2 -0
- package/dist/__tests__/graphGenerator.test.d.ts.map +1 -0
- package/dist/__tests__/graphGenerator.test.js +190 -0
- package/dist/__tests__/htmlReporter.test.d.ts +2 -0
- package/dist/__tests__/htmlReporter.test.d.ts.map +1 -0
- package/dist/__tests__/htmlReporter.test.js +258 -0
- package/dist/__tests__/interactiveFixer.test.d.ts +2 -0
- package/dist/__tests__/interactiveFixer.test.d.ts.map +1 -0
- package/dist/__tests__/interactiveFixer.test.js +231 -0
- package/dist/__tests__/parser.test.d.ts +2 -0
- package/dist/__tests__/parser.test.d.ts.map +1 -0
- package/dist/__tests__/parser.test.js +56 -0
- package/dist/__tests__/performanceBudget.test.d.ts +2 -0
- package/dist/__tests__/performanceBudget.test.d.ts.map +1 -0
- package/dist/__tests__/performanceBudget.test.js +242 -0
- package/dist/__tests__/prComments.test.d.ts +2 -0
- package/dist/__tests__/prComments.test.d.ts.map +1 -0
- package/dist/__tests__/prComments.test.js +118 -0
- package/dist/__tests__/reporter.test.d.ts +2 -0
- package/dist/__tests__/reporter.test.d.ts.map +1 -0
- package/dist/__tests__/reporter.test.js +136 -0
- package/dist/__tests__/watcher.test.d.ts +2 -0
- package/dist/__tests__/watcher.test.d.ts.map +1 -0
- package/dist/__tests__/watcher.test.js +161 -0
- package/dist/__tests__/webhooks.test.d.ts +2 -0
- package/dist/__tests__/webhooks.test.d.ts.map +1 -0
- package/dist/__tests__/webhooks.test.js +209 -0
- package/dist/aiRefactoring.d.ts +29 -0
- package/dist/aiRefactoring.d.ts.map +1 -0
- package/dist/aiRefactoring.js +290 -0
- package/dist/analyzer.d.ts.map +1 -1
- package/dist/analyzer.js +33 -1
- package/dist/cli.js +123 -1
- package/dist/detectors/contextApi.d.ts +11 -0
- package/dist/detectors/contextApi.d.ts.map +1 -0
- package/dist/detectors/contextApi.js +151 -0
- package/dist/detectors/errorBoundary.d.ts +11 -0
- package/dist/detectors/errorBoundary.d.ts.map +1 -0
- package/dist/detectors/errorBoundary.js +167 -0
- package/dist/detectors/formValidation.d.ts +11 -0
- package/dist/detectors/formValidation.d.ts.map +1 -0
- package/dist/detectors/formValidation.js +193 -0
- package/dist/detectors/index.d.ts +6 -0
- package/dist/detectors/index.d.ts.map +1 -1
- package/dist/detectors/index.js +12 -0
- package/dist/detectors/serverComponents.d.ts +11 -0
- package/dist/detectors/serverComponents.d.ts.map +1 -0
- package/dist/detectors/serverComponents.js +222 -0
- package/dist/detectors/stateManagement.d.ts +11 -0
- package/dist/detectors/stateManagement.d.ts.map +1 -0
- package/dist/detectors/stateManagement.js +193 -0
- package/dist/detectors/testingGaps.d.ts +15 -0
- package/dist/detectors/testingGaps.d.ts.map +1 -0
- package/dist/detectors/testingGaps.js +182 -0
- package/dist/docGenerator.d.ts +37 -0
- package/dist/docGenerator.d.ts.map +1 -0
- package/dist/docGenerator.js +306 -0
- package/dist/guide.d.ts +9 -0
- package/dist/guide.d.ts.map +1 -0
- package/dist/guide.js +922 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/interactiveFixer.d.ts +20 -0
- package/dist/interactiveFixer.d.ts.map +1 -0
- package/dist/interactiveFixer.js +178 -0
- package/dist/performanceBudget.d.ts +54 -0
- package/dist/performanceBudget.d.ts.map +1 -0
- package/dist/performanceBudget.js +218 -0
- package/dist/prComments.d.ts +47 -0
- package/dist/prComments.d.ts.map +1 -0
- package/dist/prComments.js +233 -0
- package/dist/types/index.d.ts +12 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +18 -0
- 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
|
+
}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -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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"}
|
package/dist/types/index.js
CHANGED
|
@@ -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
|
-
"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": "^
|
|
54
|
+
"vitest": "^4.0.18"
|
|
49
55
|
},
|
|
50
56
|
"engines": {
|
|
51
57
|
"node": ">=18.0.0"
|