react-code-smell-detector 1.4.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.
package/dist/cli.js CHANGED
@@ -11,6 +11,8 @@ import { startWatch } from './watcher.js';
11
11
  import { getAllModifiedFiles, filterReactFiles, getGitInfo } from './git.js';
12
12
  import { initializeBaseline, recordBaseline, formatTrendReport } from './baseline.js';
13
13
  import { sendWebhookNotification, getWebhookConfig } from './webhooks.js';
14
+ import { generateDependencyGraphHTML } from './graphGenerator.js';
15
+ import { generateBundleReport } from './bundleAnalyzer.js';
14
16
  import fs from 'fs/promises';
15
17
  const program = new Command();
16
18
  program
@@ -37,6 +39,10 @@ program
37
39
  .option('--discord <url>', 'Discord webhook URL for notifications')
38
40
  .option('--webhook <url>', 'Generic webhook URL for notifications')
39
41
  .option('--webhook-threshold <number>', 'Only notify if smells exceed this threshold', parseInt)
42
+ .option('--graph', 'Generate dependency graph visualization', false)
43
+ .option('--graph-format <format>', 'Graph output format: svg, html', 'html')
44
+ .option('--bundle', 'Analyze bundle size impact per component', false)
45
+ .option('--rules <file>', 'Custom rules configuration file')
40
46
  .action(async (directory, options) => {
41
47
  const rootDir = path.resolve(process.cwd(), directory);
42
48
  // Check if directory exists
@@ -60,6 +66,18 @@ program
60
66
  process.exit(1);
61
67
  }
62
68
  }
69
+ // Load custom rules if specified
70
+ let customRules;
71
+ if (options.rules) {
72
+ try {
73
+ const rulesPath = path.resolve(process.cwd(), options.rules);
74
+ const rulesContent = await fs.readFile(rulesPath, 'utf-8');
75
+ customRules = JSON.parse(rulesContent);
76
+ }
77
+ catch (error) {
78
+ console.warn(chalk.yellow(`Warning: Could not load custom rules: ${error.message}`));
79
+ }
80
+ }
63
81
  // Build config from options
64
82
  const config = {
65
83
  ...DEFAULT_CONFIG,
@@ -67,6 +85,10 @@ program
67
85
  ...(options.maxEffects && { maxUseEffectsPerComponent: options.maxEffects }),
68
86
  ...(options.maxProps && { maxPropsCount: options.maxProps }),
69
87
  ...(options.maxLines && { maxComponentLines: options.maxLines }),
88
+ ...(options.graph && { generateDependencyGraph: true }),
89
+ ...(options.graphFormat && { graphOutputFormat: options.graphFormat }),
90
+ ...(options.bundle && { analyzeBundleSize: true }),
91
+ ...(customRules && { customRules }),
70
92
  };
71
93
  const include = options.include?.split(',').map((p) => p.trim()) || ['**/*.tsx', '**/*.jsx'];
72
94
  const exclude = options.exclude?.split(',').map((p) => p.trim()) || ['**/node_modules/**', '**/dist/**'];
@@ -188,6 +210,26 @@ program
188
210
  console.log(chalk.green('✓ Notification sent to webhook'));
189
211
  }
190
212
  }
213
+ // Generate dependency graph if requested
214
+ if (options.graph) {
215
+ const graph = global._dependencyGraph;
216
+ if (graph) {
217
+ const graphHTML = generateDependencyGraphHTML(graph, path.basename(rootDir), graph.circularDependencies.length);
218
+ const graphPath = path.resolve(process.cwd(), 'dependency-graph.html');
219
+ await fs.writeFile(graphPath, graphHTML, 'utf-8');
220
+ console.log(chalk.green(`✓ Dependency graph written to ${graphPath}`));
221
+ }
222
+ }
223
+ // Generate bundle analysis if requested
224
+ if (options.bundle) {
225
+ const bundleAnalysis = global._bundleAnalysis;
226
+ if (bundleAnalysis) {
227
+ const bundleHTML = generateBundleReport(bundleAnalysis, path.basename(rootDir));
228
+ const bundlePath = path.resolve(process.cwd(), 'bundle-analysis.html');
229
+ await fs.writeFile(bundlePath, bundleHTML, 'utf-8');
230
+ console.log(chalk.green(`✓ Bundle analysis written to ${bundlePath}`));
231
+ }
232
+ }
191
233
  // CI/CD exit code handling
192
234
  const { smellsBySeverity } = result.summary;
193
235
  let shouldFail = false;
@@ -0,0 +1,31 @@
1
+ import { CodeSmell } from './types/index.js';
2
+ export interface CustomRule {
3
+ name: string;
4
+ description?: string;
5
+ severity: 'error' | 'warning' | 'info';
6
+ pattern: string | RegExp;
7
+ patternType: 'regex' | 'ast' | 'text';
8
+ message?: string;
9
+ enabled?: boolean;
10
+ }
11
+ export interface CustomRulesConfig {
12
+ rules: CustomRule[];
13
+ enabled?: boolean;
14
+ }
15
+ /**
16
+ * Parse custom rules from configuration
17
+ */
18
+ export declare function parseCustomRules(config: any): CustomRule[];
19
+ /**
20
+ * Detect violations of custom rules
21
+ */
22
+ export declare function detectCustomRuleViolations(component: any, filePath: string, sourceCode: string, customRules: CustomRule[]): CodeSmell[];
23
+ /**
24
+ * Example custom rules configuration
25
+ */
26
+ export declare const EXAMPLE_CUSTOM_RULES: CustomRulesConfig;
27
+ /**
28
+ * Generate custom rules documentation
29
+ */
30
+ export declare function generateRulesDocumentation(): string;
31
+ //# sourceMappingURL=customRules.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"customRules.d.ts","sourceRoot":"","sources":["../src/customRules.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAK7C,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;IACvC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,WAAW,EAAE,OAAO,GAAG,KAAK,GAAG,MAAM,CAAC;IACtC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,GAAG,GAAG,UAAU,EAAE,CAY1D;AAsBD;;GAEG;AACH,wBAAgB,0BAA0B,CACxC,SAAS,EAAE,GAAG,EACd,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,UAAU,EAAE,GACxB,SAAS,EAAE,CA2Bb;AAuDD;;GAEG;AACH,eAAO,MAAM,oBAAoB,EAAE,iBAoClC,CAAC;AAEF;;GAEG;AACH,wBAAgB,0BAA0B,IAAI,MAAM,CA8InD"}
@@ -0,0 +1,289 @@
1
+ import _traverse from '@babel/traverse';
2
+ const traverse = typeof _traverse === 'function' ? _traverse : _traverse.default;
3
+ /**
4
+ * Parse custom rules from configuration
5
+ */
6
+ export function parseCustomRules(config) {
7
+ if (!config.customRules || typeof config.customRules !== 'object') {
8
+ return [];
9
+ }
10
+ const rulesArray = Array.isArray(config.customRules)
11
+ ? config.customRules
12
+ : [config.customRules];
13
+ return rulesArray
14
+ .map((rule) => normalizeRule(rule))
15
+ .filter((rule) => rule !== null);
16
+ }
17
+ /**
18
+ * Normalize and validate a custom rule
19
+ */
20
+ function normalizeRule(rule) {
21
+ if (!rule.name || !rule.pattern) {
22
+ console.warn('Invalid custom rule: missing name or pattern');
23
+ return null;
24
+ }
25
+ return {
26
+ name: rule.name,
27
+ description: rule.description || '',
28
+ severity: rule.severity || 'warning',
29
+ pattern: rule.pattern,
30
+ patternType: rule.patternType || 'text',
31
+ message: rule.message || `Custom rule violation: ${rule.name}`,
32
+ enabled: rule.enabled !== false,
33
+ };
34
+ }
35
+ /**
36
+ * Detect violations of custom rules
37
+ */
38
+ export function detectCustomRuleViolations(component, filePath, sourceCode, customRules) {
39
+ const smells = [];
40
+ for (const rule of customRules) {
41
+ if (!rule.enabled)
42
+ continue;
43
+ const violations = detectRuleViolation(component, sourceCode, rule);
44
+ violations.forEach(violation => {
45
+ smells.push({
46
+ type: 'custom-rule',
47
+ severity: rule.severity,
48
+ message: violation.message,
49
+ file: filePath,
50
+ line: violation.line,
51
+ column: violation.column,
52
+ suggestion: `Follow custom rule: ${rule.name}. ${rule.description || ''}`,
53
+ codeSnippet: violation.snippet,
54
+ });
55
+ });
56
+ }
57
+ return smells;
58
+ }
59
+ /**
60
+ * Detect a single rule violation
61
+ */
62
+ function detectRuleViolation(component, sourceCode, rule) {
63
+ const violations = [];
64
+ if (rule.patternType === 'regex' || rule.patternType === 'text') {
65
+ // Text/regex matching
66
+ const pattern = new RegExp(rule.pattern, 'gm');
67
+ const lines = sourceCode.split('\n');
68
+ for (let i = 0; i < lines.length; i++) {
69
+ const line = lines[i];
70
+ let match;
71
+ if (typeof rule.pattern === 'string') {
72
+ pattern.lastIndex = 0;
73
+ match = pattern.exec(line);
74
+ }
75
+ else {
76
+ match = rule.pattern.exec(line);
77
+ }
78
+ if (match) {
79
+ violations.push({
80
+ line: i + 1,
81
+ column: match.index,
82
+ message: rule.message || `Matches custom pattern: ${rule.pattern}`,
83
+ snippet: line,
84
+ });
85
+ }
86
+ }
87
+ }
88
+ else if (rule.patternType === 'ast') {
89
+ // AST-based matching
90
+ const patternStr = typeof rule.pattern === 'string' ? rule.pattern : String(rule.pattern);
91
+ const handlers = {};
92
+ handlers[patternStr] = (path) => {
93
+ violations.push({
94
+ line: path.node.loc?.start.line || 1,
95
+ column: path.node.loc?.start.column || 0,
96
+ message: rule.message || `Violates AST rule: ${patternStr}`,
97
+ snippet: sourceCode.split('\n')[path.node.loc?.start.line - 1] || '',
98
+ });
99
+ };
100
+ component.path.traverse(handlers);
101
+ }
102
+ return violations;
103
+ }
104
+ /**
105
+ * Example custom rules configuration
106
+ */
107
+ export const EXAMPLE_CUSTOM_RULES = {
108
+ enabled: true,
109
+ rules: [
110
+ {
111
+ name: 'no-hardcoded-strings',
112
+ description: 'Flags hardcoded strings in components (should use i18n)',
113
+ severity: 'warning',
114
+ pattern: '"(hello|world|test|demo|todo)"',
115
+ patternType: 'regex',
116
+ enabled: false,
117
+ },
118
+ {
119
+ name: 'no-px-margins',
120
+ description: 'Disallow px units for margins (use rem or em)',
121
+ severity: 'info',
122
+ pattern: 'margin[^:]*:\\s*\\d+px',
123
+ patternType: 'regex',
124
+ enabled: false,
125
+ },
126
+ {
127
+ name: 'max-inline-styles',
128
+ description: 'Disallow multiple inline style props in JSX',
129
+ severity: 'warning',
130
+ pattern: 'style={{[^}]*[,;][^}]*}}.*style={{',
131
+ patternType: 'regex',
132
+ enabled: false,
133
+ },
134
+ {
135
+ name: 'require-display-name',
136
+ description: 'All components must have a display name',
137
+ severity: 'info',
138
+ pattern: 'displayName',
139
+ patternType: 'text',
140
+ enabled: false,
141
+ },
142
+ ],
143
+ };
144
+ /**
145
+ * Generate custom rules documentation
146
+ */
147
+ export function generateRulesDocumentation() {
148
+ return `# Custom Rules Configuration
149
+
150
+ ## Overview
151
+ Custom rules allow you to define project-specific code quality standards. Add custom rules to your \`.smellrc.json\` configuration.
152
+
153
+ ## Configuration
154
+
155
+ ### Basic Example
156
+
157
+ \`\`\`json
158
+ {
159
+ "customRules": [
160
+ {
161
+ "name": "no-console-logs",
162
+ "description": "Disallow console.log in production code",
163
+ "severity": "warning",
164
+ "pattern": "console\\\\.(log|debug|info)",
165
+ "patternType": "regex",
166
+ "enabled": true
167
+ }
168
+ ]
169
+ }
170
+ \`\`\`
171
+
172
+ ## Rule Properties
173
+
174
+ | Property | Type | Required | Default | Description |
175
+ |----------|------|----------|---------|-------------|
176
+ | name | string | ✓ | - | Unique rule identifier |
177
+ | description | string | | "" | Human-readable description |
178
+ | severity | string | | "warning" | One of: error, warning, info |
179
+ | pattern | string | ✓ | - | Regex pattern or AST node type |
180
+ | patternType | string | | "text" | One of: regex, text, ast |
181
+ | message | string | | Rule pattern | Custom error message |
182
+ | enabled | boolean | | true | Enable/disable rule |
183
+
184
+ ## Pattern Types
185
+
186
+ ### 1. Regex Pattern
187
+ Match against source code using regular expressions.
188
+
189
+ \`\`\`json
190
+ {
191
+ "name": "no-hardcoded-urls",
192
+ "pattern": "https?://[^\\\"']+",
193
+ "patternType": "regex",
194
+ "severity": "warning"
195
+ }
196
+ \`\`\`
197
+
198
+ ### 2. Text Pattern
199
+ Simple string matching (case-sensitive).
200
+
201
+ \`\`\`json
202
+ {
203
+ "name": "no-debugger",
204
+ "pattern": "debugger",
205
+ "patternType": "text",
206
+ "severity": "error"
207
+ }
208
+ \`\`\`
209
+
210
+ ### 3. AST Pattern
211
+ Match against Babel AST node types.
212
+
213
+ \`\`\`json
214
+ {
215
+ "name": "no-nested-functions",
216
+ "pattern": "FunctionExpression",
217
+ "patternType": "ast",
218
+ "severity": "info"
219
+ }
220
+ \`\`\`
221
+
222
+ ## Real-World Examples
223
+
224
+ ### Prevent hardcoded strings for i18n
225
+ \`\`\`json
226
+ {
227
+ "name": "require-i18n",
228
+ "description": "All strings must be internationalized",
229
+ "pattern": "['\\\"]([A-Z][a-z]+\\\\s*){2,}['\\\"]",
230
+ "patternType": "regex",
231
+ "severity": "warning",
232
+ "message": "Hardcoded text found. Use i18n instead."
233
+ }
234
+ \`\`\`
235
+
236
+ ### Enforce accessibility attributes
237
+ \`\`\`json
238
+ {
239
+ "name": "missing-aria-label",
240
+ "description": "Interactive elements need aria-label",
241
+ "pattern": "<(button|input|select)(?!.*aria-label)",
242
+ "patternType": "regex",
243
+ "severity": "error"
244
+ }
245
+ \`\`\`
246
+
247
+ ### No logger calls without context
248
+ \`\`\`json
249
+ {
250
+ "name": "logger-needs-context",
251
+ "description": "Logger calls must include context",
252
+ "pattern": "logger\\\\.(log|warn)\\\\(['\\\"](?!\\\\[)",
253
+ "patternType": "regex",
254
+ "severity": "warning",
255
+ "message": "Logger call missing context. Use: logger.log('[Component]', ...)"
256
+ }
257
+ \`\`\`
258
+
259
+ ### Maximum nesting depth for JSX
260
+ \`\`\`json
261
+ {
262
+ "name": "jsx-nesting-limit",
263
+ "description": "Limit JSX nesting to improve readability",
264
+ "pattern": "<.*>.*<.*>.*<.*>.*<.*>.*<",
265
+ "patternType": "regex",
266
+ "severity": "info"
267
+ }
268
+ \`\`\`
269
+
270
+ ## Using Custom Rules in CLI
271
+
272
+ \`\`\`bash
273
+ # Custom rules are automatically applied with config file
274
+ react-smell ./src -c .smellrc.json
275
+
276
+ # Or create default config with examples
277
+ react-smell init
278
+ \`\`\`
279
+
280
+ ## Tips
281
+
282
+ 1. **Start simple** - Begin with basic regex patterns
283
+ 2. **Test patterns** - Use online regex testers before adding to config
284
+ 3. **Use specific patterns** - Avoid overly broad patterns that match unintended code
285
+ 4. **Document rules** - Always include clear descriptions
286
+ 5. **Set appropriate severity** - Use 'error' for critical rules, 'info' for suggestions
287
+ 6. **Enable progressively** - Start with disabled rules, enable after team agreement
288
+ `;
289
+ }
@@ -10,8 +10,4 @@ export interface ComplexityMetrics {
10
10
  * Detect code complexity issues in a component
11
11
  */
12
12
  export declare function detectComplexity(component: ParsedComponent, filePath: string, sourceCode: string, config: DetectorConfig): CodeSmell[];
13
- /**
14
- * Calculate complexity metrics for a component
15
- */
16
- export declare function calculateComplexityMetrics(component: ParsedComponent): ComplexityMetrics;
17
13
  //# sourceMappingURL=complexity.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"complexity.d.ts","sourceRoot":"","sources":["../../src/detectors/complexity.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAE9D,MAAM,WAAW,iBAAiB;IAChC,oBAAoB,EAAE,MAAM,CAAC;IAC7B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,eAAe,EAC1B,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,cAAc,GACrB,SAAS,EAAE,CAqCb;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CAAC,SAAS,EAAE,eAAe,GAAG,iBAAiB,CA6BxF"}
1
+ {"version":3,"file":"complexity.d.ts","sourceRoot":"","sources":["../../src/detectors/complexity.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAE9D,MAAM,WAAW,iBAAiB;IAChC,oBAAoB,EAAE,MAAM,CAAC;IAC7B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,eAAe,EAC1B,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,cAAc,GACrB,SAAS,EAAE,CAqCb"}
@@ -38,7 +38,7 @@ export function detectComplexity(component, filePath, sourceCode, config) {
38
38
  /**
39
39
  * Calculate complexity metrics for a component
40
40
  */
41
- export function calculateComplexityMetrics(component) {
41
+ function calculateComplexityMetrics(component) {
42
42
  let cyclomaticComplexity = 1;
43
43
  let cognitiveComplexity = 0;
44
44
  component.path.traverse({
@@ -4,11 +4,4 @@ import { CodeSmell, DetectorConfig } from '../types/index.js';
4
4
  * Detects potentially dead code: unused variables, imports, and functions
5
5
  */
6
6
  export declare function detectDeadCode(component: ParsedComponent, filePath: string, sourceCode: string, config?: DetectorConfig): CodeSmell[];
7
- /**
8
- * Detects unused imports at the file level
9
- */
10
- export declare function detectUnusedImports(imports: Map<string, {
11
- source: string;
12
- line: number;
13
- }>, usedInFile: Set<string>, filePath: string, sourceCode: string): CodeSmell[];
14
7
  //# sourceMappingURL=deadCode.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"deadCode.d.ts","sourceRoot":"","sources":["../../src/detectors/deadCode.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAkB,MAAM,oBAAoB,CAAC;AACrE,OAAO,EAAE,SAAS,EAAE,cAAc,EAAkB,MAAM,mBAAmB,CAAC;AAE9E;;GAEG;AACH,wBAAgB,cAAc,CAC5B,SAAS,EAAE,eAAe,EAC1B,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,MAAM,GAAE,cAA+B,GACtC,SAAS,EAAE,CAsHb;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,EACtD,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,EACvB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,SAAS,EAAE,CAsBb"}
1
+ {"version":3,"file":"deadCode.d.ts","sourceRoot":"","sources":["../../src/detectors/deadCode.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAkB,MAAM,oBAAoB,CAAC;AACrE,OAAO,EAAE,SAAS,EAAE,cAAc,EAAkB,MAAM,mBAAmB,CAAC;AAE9E;;GAEG;AACH,wBAAgB,cAAc,CAC5B,SAAS,EAAE,eAAe,EAC1B,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,MAAM,GAAE,cAA+B,GACtC,SAAS,EAAE,CAsHb"}
@@ -115,27 +115,3 @@ export function detectDeadCode(component, filePath, sourceCode, config = DEFAULT
115
115
  });
116
116
  return smells;
117
117
  }
118
- /**
119
- * Detects unused imports at the file level
120
- */
121
- export function detectUnusedImports(imports, usedInFile, filePath, sourceCode) {
122
- const smells = [];
123
- imports.forEach((info, name) => {
124
- // Skip React imports as they might be used implicitly
125
- if (name === 'React' || info.source === 'react')
126
- return;
127
- if (!usedInFile.has(name)) {
128
- smells.push({
129
- type: 'dead-code',
130
- severity: 'info',
131
- message: `Unused import "${name}" from "${info.source}"`,
132
- file: filePath,
133
- line: info.line,
134
- column: 0,
135
- suggestion: `Remove the unused import: import { ${name} } from '${info.source}'`,
136
- codeSnippet: getCodeSnippet(sourceCode, info.line),
137
- });
138
- }
139
- });
140
- return smells;
141
- }
@@ -6,7 +6,7 @@ export { detectMissingKeys } from './missingKey.js';
6
6
  export { detectHooksRulesViolations } from './hooksRules.js';
7
7
  export { detectDependencyArrayIssues } from './dependencyArray.js';
8
8
  export { detectNestedTernaries } from './nestedTernary.js';
9
- export { detectDeadCode, detectUnusedImports } from './deadCode.js';
9
+ export { detectDeadCode } from './deadCode.js';
10
10
  export { detectMagicValues } from './magicValues.js';
11
11
  export { detectNextjsIssues } from './nextjs.js';
12
12
  export { detectReactNativeIssues } from './reactNative.js';
@@ -16,7 +16,7 @@ export { detectTypescriptIssues } from './typescript.js';
16
16
  export { detectDebugStatements } from './debug.js';
17
17
  export { detectSecurityIssues } from './security.js';
18
18
  export { detectAccessibilityIssues } from './accessibility.js';
19
- export { detectComplexity, calculateComplexityMetrics } from './complexity.js';
19
+ export { detectComplexity } from './complexity.js';
20
20
  export { detectMemoryLeaks } from './memoryLeak.js';
21
21
  export { detectImportIssues, analyzeImports } from './imports.js';
22
22
  export { detectUnusedCode } from './unusedCode.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/detectors/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AACjF,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,4BAA4B,EAAE,MAAM,kBAAkB,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,0BAA0B,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EAAE,2BAA2B,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpE,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAErD,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAEzD,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAE/D,OAAO,EAAE,gBAAgB,EAAE,0BAA0B,EAAE,MAAM,iBAAiB,CAAC;AAC/E,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/detectors/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AACjF,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,4BAA4B,EAAE,MAAM,kBAAkB,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,0BAA0B,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EAAE,2BAA2B,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAErD,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAEzD,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAE/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC"}
@@ -6,7 +6,7 @@ export { detectMissingKeys } from './missingKey.js';
6
6
  export { detectHooksRulesViolations } from './hooksRules.js';
7
7
  export { detectDependencyArrayIssues } from './dependencyArray.js';
8
8
  export { detectNestedTernaries } from './nestedTernary.js';
9
- export { detectDeadCode, detectUnusedImports } from './deadCode.js';
9
+ export { detectDeadCode } from './deadCode.js';
10
10
  export { detectMagicValues } from './magicValues.js';
11
11
  // Framework-specific detectors
12
12
  export { detectNextjsIssues } from './nextjs.js';
@@ -19,7 +19,7 @@ export { detectDebugStatements } from './debug.js';
19
19
  export { detectSecurityIssues } from './security.js';
20
20
  export { detectAccessibilityIssues } from './accessibility.js';
21
21
  // Complexity, Memory Leaks, Imports
22
- export { detectComplexity, calculateComplexityMetrics } from './complexity.js';
22
+ export { detectComplexity } from './complexity.js';
23
23
  export { detectMemoryLeaks } from './memoryLeak.js';
24
24
  export { detectImportIssues, analyzeImports } from './imports.js';
25
25
  export { detectUnusedCode } from './unusedCode.js';
package/dist/git.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../src/git.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,OAAO;IACtB,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAiFnD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAcpE;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,GAAE,MAAU,GAAG,MAAM,EAAE,CAcpF;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAW7D;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAG1D"}
1
+ {"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../src/git.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,OAAO;IACtB,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAyEnD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAcpE;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,GAAE,MAAU,GAAG,MAAM,EAAE,CAcpF;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAW7D;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAG1D"}
package/dist/git.js CHANGED
@@ -61,13 +61,6 @@ export function getGitInfo(rootDir) {
61
61
  stagedFiles,
62
62
  untrackedFiles,
63
63
  };
64
- return {
65
- isGitRepo: true,
66
- currentBranch,
67
- changedFiles,
68
- stagedFiles,
69
- untrackedFiles,
70
- };
71
64
  }
72
65
  catch {
73
66
  return {
@@ -0,0 +1,34 @@
1
+ export interface DependencyNode {
2
+ id: string;
3
+ file: string;
4
+ type: 'component' | 'file';
5
+ imports: string[];
6
+ importedBy: string[];
7
+ size?: number;
8
+ isCircular?: boolean;
9
+ }
10
+ export interface DependencyGraph {
11
+ nodes: Map<string, DependencyNode>;
12
+ edges: Array<{
13
+ from: string;
14
+ to: string;
15
+ circular: boolean;
16
+ }>;
17
+ circularDependencies: string[][];
18
+ }
19
+ /**
20
+ * Build dependency graph from parsed components
21
+ */
22
+ export declare function buildDependencyGraph(files: Array<{
23
+ file: string;
24
+ imports: string[];
25
+ }>, rootDir: string): DependencyGraph;
26
+ /**
27
+ * Generate SVG representation of dependency graph
28
+ */
29
+ export declare function generateDependencyGraph(graph: DependencyGraph, width?: number, height?: number): string;
30
+ /**
31
+ * Generate HTML report with dependency graph
32
+ */
33
+ export declare function generateDependencyGraphHTML(graph: DependencyGraph, projectName: string, circularCount?: number): string;
34
+ //# sourceMappingURL=graphGenerator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graphGenerator.d.ts","sourceRoot":"","sources":["../src/graphGenerator.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,WAAW,GAAG,MAAM,CAAC;IAC3B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IACnC,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAC9D,oBAAoB,EAAE,MAAM,EAAE,EAAE,CAAC;CAClC;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,EACjD,OAAO,EAAE,MAAM,GACd,eAAe,CA2CjB;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,eAAe,EAAE,KAAK,SAAO,EAAE,MAAM,SAAM,GAAG,MAAM,CA4DlG;AAED;;GAEG;AACH,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,eAAe,EACtB,WAAW,EAAE,MAAM,EACnB,aAAa,SAAI,GAChB,MAAM,CA6HR"}