@defai.digital/ax-cli 3.4.5 → 3.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (211) hide show
  1. package/LICENSE +2 -6
  2. package/README.md +91 -3
  3. package/dist/analyzers/ast/parser.d.ts +59 -0
  4. package/dist/analyzers/ast/parser.js +293 -0
  5. package/dist/analyzers/ast/parser.js.map +1 -0
  6. package/dist/analyzers/ast/types.d.ts +107 -0
  7. package/dist/analyzers/ast/types.js +7 -0
  8. package/dist/analyzers/ast/types.js.map +1 -0
  9. package/dist/analyzers/code-smells/base-smell-detector.d.ts +30 -0
  10. package/dist/analyzers/code-smells/base-smell-detector.js +44 -0
  11. package/dist/analyzers/code-smells/base-smell-detector.js.map +1 -0
  12. package/dist/analyzers/code-smells/code-smell-analyzer.d.ts +30 -0
  13. package/dist/analyzers/code-smells/code-smell-analyzer.js +167 -0
  14. package/dist/analyzers/code-smells/code-smell-analyzer.js.map +1 -0
  15. package/dist/analyzers/code-smells/detectors/data-clumps-detector.d.ts +11 -0
  16. package/dist/analyzers/code-smells/detectors/data-clumps-detector.js +66 -0
  17. package/dist/analyzers/code-smells/detectors/data-clumps-detector.js.map +1 -0
  18. package/dist/analyzers/code-smells/detectors/dead-code-detector.d.ts +11 -0
  19. package/dist/analyzers/code-smells/detectors/dead-code-detector.js +53 -0
  20. package/dist/analyzers/code-smells/detectors/dead-code-detector.js.map +1 -0
  21. package/dist/analyzers/code-smells/detectors/duplicate-code-detector.d.ts +11 -0
  22. package/dist/analyzers/code-smells/detectors/duplicate-code-detector.js +51 -0
  23. package/dist/analyzers/code-smells/detectors/duplicate-code-detector.js.map +1 -0
  24. package/dist/analyzers/code-smells/detectors/feature-envy-detector.d.ts +11 -0
  25. package/dist/analyzers/code-smells/detectors/feature-envy-detector.js +64 -0
  26. package/dist/analyzers/code-smells/detectors/feature-envy-detector.js.map +1 -0
  27. package/dist/analyzers/code-smells/detectors/inappropriate-intimacy-detector.d.ts +11 -0
  28. package/dist/analyzers/code-smells/detectors/inappropriate-intimacy-detector.js +56 -0
  29. package/dist/analyzers/code-smells/detectors/inappropriate-intimacy-detector.js.map +1 -0
  30. package/dist/analyzers/code-smells/detectors/large-class-detector.d.ts +13 -0
  31. package/dist/analyzers/code-smells/detectors/large-class-detector.js +58 -0
  32. package/dist/analyzers/code-smells/detectors/large-class-detector.js.map +1 -0
  33. package/dist/analyzers/code-smells/detectors/long-method-detector.d.ts +12 -0
  34. package/dist/analyzers/code-smells/detectors/long-method-detector.js +52 -0
  35. package/dist/analyzers/code-smells/detectors/long-method-detector.js.map +1 -0
  36. package/dist/analyzers/code-smells/detectors/long-parameter-list-detector.d.ts +12 -0
  37. package/dist/analyzers/code-smells/detectors/long-parameter-list-detector.js +50 -0
  38. package/dist/analyzers/code-smells/detectors/long-parameter-list-detector.js.map +1 -0
  39. package/dist/analyzers/code-smells/detectors/magic-numbers-detector.d.ts +12 -0
  40. package/dist/analyzers/code-smells/detectors/magic-numbers-detector.js +54 -0
  41. package/dist/analyzers/code-smells/detectors/magic-numbers-detector.js.map +1 -0
  42. package/dist/analyzers/code-smells/detectors/nested-conditionals-detector.d.ts +13 -0
  43. package/dist/analyzers/code-smells/detectors/nested-conditionals-detector.js +71 -0
  44. package/dist/analyzers/code-smells/detectors/nested-conditionals-detector.js.map +1 -0
  45. package/dist/analyzers/code-smells/index.d.ts +16 -0
  46. package/dist/analyzers/code-smells/index.js +19 -0
  47. package/dist/analyzers/code-smells/index.js.map +1 -0
  48. package/dist/analyzers/code-smells/types.d.ts +82 -0
  49. package/dist/analyzers/code-smells/types.js +30 -0
  50. package/dist/analyzers/code-smells/types.js.map +1 -0
  51. package/dist/analyzers/dependency/circular-detector.d.ts +17 -0
  52. package/dist/analyzers/dependency/circular-detector.js +71 -0
  53. package/dist/analyzers/dependency/circular-detector.js.map +1 -0
  54. package/dist/analyzers/dependency/coupling-calculator.d.ts +24 -0
  55. package/dist/analyzers/dependency/coupling-calculator.js +86 -0
  56. package/dist/analyzers/dependency/coupling-calculator.js.map +1 -0
  57. package/dist/analyzers/dependency/dependency-analyzer.d.ts +40 -0
  58. package/dist/analyzers/dependency/dependency-analyzer.js +214 -0
  59. package/dist/analyzers/dependency/dependency-analyzer.js.map +1 -0
  60. package/dist/analyzers/dependency/dependency-graph.d.ts +57 -0
  61. package/dist/analyzers/dependency/dependency-graph.js +186 -0
  62. package/dist/analyzers/dependency/dependency-graph.js.map +1 -0
  63. package/dist/analyzers/dependency/index.d.ts +8 -0
  64. package/dist/analyzers/dependency/index.js +8 -0
  65. package/dist/analyzers/dependency/index.js.map +1 -0
  66. package/dist/analyzers/dependency/types.d.ts +105 -0
  67. package/dist/analyzers/dependency/types.js +5 -0
  68. package/dist/analyzers/dependency/types.js.map +1 -0
  69. package/dist/analyzers/git/churn-calculator.d.ts +34 -0
  70. package/dist/analyzers/git/churn-calculator.js +214 -0
  71. package/dist/analyzers/git/churn-calculator.js.map +1 -0
  72. package/dist/analyzers/git/git-analyzer.d.ts +19 -0
  73. package/dist/analyzers/git/git-analyzer.js +71 -0
  74. package/dist/analyzers/git/git-analyzer.js.map +1 -0
  75. package/dist/analyzers/git/hotspot-detector.d.ts +34 -0
  76. package/dist/analyzers/git/hotspot-detector.js +170 -0
  77. package/dist/analyzers/git/hotspot-detector.js.map +1 -0
  78. package/dist/analyzers/git/index.d.ts +7 -0
  79. package/dist/analyzers/git/index.js +7 -0
  80. package/dist/analyzers/git/index.js.map +1 -0
  81. package/dist/analyzers/git/types.d.ts +88 -0
  82. package/dist/analyzers/git/types.js +5 -0
  83. package/dist/analyzers/git/types.js.map +1 -0
  84. package/dist/analyzers/metrics/halstead-calculator.d.ts +30 -0
  85. package/dist/analyzers/metrics/halstead-calculator.js +150 -0
  86. package/dist/analyzers/metrics/halstead-calculator.js.map +1 -0
  87. package/dist/analyzers/metrics/index.d.ts +9 -0
  88. package/dist/analyzers/metrics/index.js +9 -0
  89. package/dist/analyzers/metrics/index.js.map +1 -0
  90. package/dist/analyzers/metrics/maintainability-calculator.d.ts +17 -0
  91. package/dist/analyzers/metrics/maintainability-calculator.js +46 -0
  92. package/dist/analyzers/metrics/maintainability-calculator.js.map +1 -0
  93. package/dist/analyzers/metrics/metrics-analyzer.d.ts +32 -0
  94. package/dist/analyzers/metrics/metrics-analyzer.js +140 -0
  95. package/dist/analyzers/metrics/metrics-analyzer.js.map +1 -0
  96. package/dist/analyzers/metrics/types.d.ts +67 -0
  97. package/dist/analyzers/metrics/types.js +5 -0
  98. package/dist/analyzers/metrics/types.js.map +1 -0
  99. package/dist/analyzers/security/base-detector.d.ts +58 -0
  100. package/dist/analyzers/security/base-detector.js +104 -0
  101. package/dist/analyzers/security/base-detector.js.map +1 -0
  102. package/dist/analyzers/security/detectors/command-injection-detector.d.ts +12 -0
  103. package/dist/analyzers/security/detectors/command-injection-detector.js +84 -0
  104. package/dist/analyzers/security/detectors/command-injection-detector.js.map +1 -0
  105. package/dist/analyzers/security/detectors/hardcoded-secrets-detector.d.ts +16 -0
  106. package/dist/analyzers/security/detectors/hardcoded-secrets-detector.js +140 -0
  107. package/dist/analyzers/security/detectors/hardcoded-secrets-detector.js.map +1 -0
  108. package/dist/analyzers/security/detectors/insecure-deserialization-detector.d.ts +12 -0
  109. package/dist/analyzers/security/detectors/insecure-deserialization-detector.js +109 -0
  110. package/dist/analyzers/security/detectors/insecure-deserialization-detector.js.map +1 -0
  111. package/dist/analyzers/security/detectors/insecure-random-detector.d.ts +12 -0
  112. package/dist/analyzers/security/detectors/insecure-random-detector.js +61 -0
  113. package/dist/analyzers/security/detectors/insecure-random-detector.js.map +1 -0
  114. package/dist/analyzers/security/detectors/path-traversal-detector.d.ts +12 -0
  115. package/dist/analyzers/security/detectors/path-traversal-detector.js +82 -0
  116. package/dist/analyzers/security/detectors/path-traversal-detector.js.map +1 -0
  117. package/dist/analyzers/security/detectors/sql-injection-detector.d.ts +12 -0
  118. package/dist/analyzers/security/detectors/sql-injection-detector.js +88 -0
  119. package/dist/analyzers/security/detectors/sql-injection-detector.js.map +1 -0
  120. package/dist/analyzers/security/detectors/weak-crypto-detector.d.ts +12 -0
  121. package/dist/analyzers/security/detectors/weak-crypto-detector.js +104 -0
  122. package/dist/analyzers/security/detectors/weak-crypto-detector.js.map +1 -0
  123. package/dist/analyzers/security/detectors/xss-detector.d.ts +12 -0
  124. package/dist/analyzers/security/detectors/xss-detector.js +90 -0
  125. package/dist/analyzers/security/detectors/xss-detector.js.map +1 -0
  126. package/dist/analyzers/security/index.d.ts +16 -0
  127. package/dist/analyzers/security/index.js +18 -0
  128. package/dist/analyzers/security/index.js.map +1 -0
  129. package/dist/analyzers/security/security-analyzer.d.ts +38 -0
  130. package/dist/analyzers/security/security-analyzer.js +215 -0
  131. package/dist/analyzers/security/security-analyzer.js.map +1 -0
  132. package/dist/analyzers/security/types.d.ts +95 -0
  133. package/dist/analyzers/security/types.js +7 -0
  134. package/dist/analyzers/security/types.js.map +1 -0
  135. package/dist/commands/memory.js +1 -1
  136. package/dist/commands/memory.js.map +1 -1
  137. package/dist/commands/setup.js +6 -1
  138. package/dist/commands/setup.js.map +1 -1
  139. package/dist/hooks/use-enhanced-input.d.ts +0 -1
  140. package/dist/hooks/use-enhanced-input.js.map +1 -1
  141. package/dist/mcp/health.js +4 -2
  142. package/dist/mcp/health.js.map +1 -1
  143. package/dist/mcp/validation.js +12 -6
  144. package/dist/mcp/validation.js.map +1 -1
  145. package/dist/tools/analysis-tools.d.ts +73 -0
  146. package/dist/tools/analysis-tools.js +422 -0
  147. package/dist/tools/analysis-tools.js.map +1 -0
  148. package/dist/tools/bash.js +2 -1
  149. package/dist/tools/bash.js.map +1 -1
  150. package/dist/ui/components/chat-history.js +1 -1
  151. package/dist/ui/components/chat-history.js.map +1 -1
  152. package/dist/ui/components/chat-interface.js +3 -2
  153. package/dist/ui/components/chat-interface.js.map +1 -1
  154. package/dist/ui/components/confirmation-dialog.js +1 -1
  155. package/dist/ui/components/confirmation-dialog.js.map +1 -1
  156. package/dist/ui/components/welcome-panel.js +1 -1
  157. package/dist/ui/components/welcome-panel.js.map +1 -1
  158. package/dist/ui/hooks/use-chat-reducer.d.ts +61 -0
  159. package/dist/ui/hooks/use-chat-reducer.js +118 -0
  160. package/dist/ui/hooks/use-chat-reducer.js.map +1 -0
  161. package/dist/ui/hooks/use-enhanced-input.d.ts +40 -0
  162. package/dist/ui/hooks/use-enhanced-input.js +254 -0
  163. package/dist/ui/hooks/use-enhanced-input.js.map +1 -0
  164. package/dist/ui/hooks/use-input-handler.d.ts +46 -0
  165. package/dist/ui/hooks/use-input-handler.js +1434 -0
  166. package/dist/ui/hooks/use-input-handler.js.map +1 -0
  167. package/dist/ui/hooks/use-input-history.d.ts +9 -0
  168. package/dist/ui/hooks/use-input-history.js +117 -0
  169. package/dist/ui/hooks/use-input-history.js.map +1 -0
  170. package/dist/utils/config-loader.js +3 -3
  171. package/dist/utils/config-loader.js.map +1 -1
  172. package/dist/utils/parallel-analyzer.js +7 -11
  173. package/dist/utils/parallel-analyzer.js.map +1 -1
  174. package/dist/utils/paste-collapse.d.ts +46 -0
  175. package/dist/utils/paste-collapse.js +77 -0
  176. package/dist/utils/paste-collapse.js.map +1 -0
  177. package/dist/utils/settings-manager.js +16 -2
  178. package/dist/utils/settings-manager.js.map +1 -1
  179. package/dist/utils/streaming-analyzer.js +9 -21
  180. package/dist/utils/streaming-analyzer.js.map +1 -1
  181. package/package.json +5 -5
  182. package/vitest.config.ts +1 -0
  183. package/dist/commands/weather.d.ts +0 -8
  184. package/dist/commands/weather.js +0 -160
  185. package/dist/commands/weather.js.map +0 -1
  186. package/dist/grok/client.d.ts +0 -144
  187. package/dist/grok/client.js +0 -237
  188. package/dist/grok/client.js.map +0 -1
  189. package/dist/grok/tools.d.ts +0 -8
  190. package/dist/grok/tools.js +0 -318
  191. package/dist/grok/tools.js.map +0 -1
  192. package/dist/grok/types.d.ts +0 -291
  193. package/dist/grok/types.js +0 -127
  194. package/dist/grok/types.js.map +0 -1
  195. package/dist/tools/morph-editor.d.ts +0 -36
  196. package/dist/tools/morph-editor.js +0 -308
  197. package/dist/tools/morph-editor.js.map +0 -1
  198. package/dist/ui/components/session-recovery.d.ts +0 -12
  199. package/dist/ui/components/session-recovery.js +0 -93
  200. package/dist/ui/components/session-recovery.js.map +0 -1
  201. package/dist/utils/model-config.d.ts +0 -28
  202. package/dist/utils/model-config.js +0 -43
  203. package/dist/utils/model-config.js.map +0 -1
  204. package/dist/utils/tool-helpers.d.ts +0 -25
  205. package/dist/utils/tool-helpers.js +0 -79
  206. package/dist/utils/tool-helpers.js.map +0 -1
  207. /package/{automatosx.config.json → ax.config.json} +0 -0
  208. /package/{config → config-defaults}/messages.yaml +0 -0
  209. /package/{config → config-defaults}/models.yaml +0 -0
  210. /package/{config → config-defaults}/prompts.yaml +0 -0
  211. /package/{config → config-defaults}/settings.yaml +0 -0
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Base Smell Detector
3
+ *
4
+ * Abstract base class for all smell detectors
5
+ */
6
+ import { ASTParser } from '../ast/parser.js';
7
+ export class BaseSmellDetector {
8
+ type;
9
+ config;
10
+ astParser;
11
+ constructor(type, config) {
12
+ this.type = type;
13
+ this.config = config;
14
+ this.astParser = new ASTParser();
15
+ }
16
+ /**
17
+ * Check if detector is enabled
18
+ */
19
+ isEnabled() {
20
+ return this.config.enabled;
21
+ }
22
+ /**
23
+ * Get threshold value
24
+ */
25
+ getThreshold(key, defaultValue) {
26
+ return this.config.thresholds?.[key] ?? defaultValue;
27
+ }
28
+ /**
29
+ * Create a code smell object
30
+ */
31
+ createSmell(filePath, startLine, endLine, message, suggestion, severity, metadata = {}) {
32
+ return Object.freeze({
33
+ type: this.type,
34
+ severity,
35
+ filePath,
36
+ startLine,
37
+ endLine,
38
+ message,
39
+ suggestion,
40
+ metadata: Object.freeze(metadata),
41
+ });
42
+ }
43
+ }
44
+ //# sourceMappingURL=base-smell-detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base-smell-detector.js","sourceRoot":"","sources":["../../../src/analyzers/code-smells/base-smell-detector.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAI7C,MAAM,OAAgB,iBAAiB;IAInB;IACA;IAJR,SAAS,CAAY;IAE/B,YACkB,IAAe,EACf,MAAsB;QADtB,SAAI,GAAJ,IAAI,CAAW;QACf,WAAM,GAAN,MAAM,CAAgB;QAEtC,IAAI,CAAC,SAAS,GAAG,IAAI,SAAS,EAAE,CAAC;IACnC,CAAC;IAOD;;OAEG;IACO,SAAS;QACjB,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC;IAC7B,CAAC;IAED;;OAEG;IACO,YAAY,CAAC,GAAW,EAAE,YAAoB;QACtD,OAAO,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,GAAG,CAAC,IAAI,YAAY,CAAC;IACvD,CAAC;IAED;;OAEG;IACO,WAAW,CACnB,QAAgB,EAChB,SAAiB,EACjB,OAAe,EACf,OAAe,EACf,UAAkB,EAClB,QAAuB,EACvB,WAAoC,EAAE;QAEtC,OAAO,MAAM,CAAC,MAAM,CAAC;YACnB,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,QAAQ;YACR,QAAQ;YACR,SAAS;YACT,OAAO;YACP,OAAO;YACP,UAAU;YACV,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC;SAClC,CAAC,CAAC;IACL,CAAC;CACF"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Code Smell Analyzer
3
+ *
4
+ * Main orchestrator for code smell detection
5
+ */
6
+ import { type CodeSmell, type CodeSmellAnalysisResult, type CodeSmellAnalysisOptions } from './types.js';
7
+ export declare class CodeSmellAnalyzer {
8
+ private detectors;
9
+ constructor(options?: CodeSmellAnalysisOptions);
10
+ /**
11
+ * Initialize all detectors with configuration
12
+ */
13
+ private initializeDetectors;
14
+ /**
15
+ * Analyze directory for code smells
16
+ */
17
+ analyzeDirectory(directory: string, pattern?: string, options?: CodeSmellAnalysisOptions): Promise<CodeSmellAnalysisResult>;
18
+ /**
19
+ * Analyze single file
20
+ */
21
+ analyzeFile(filePath: string): Promise<CodeSmell[]>;
22
+ /**
23
+ * Calculate summary statistics
24
+ */
25
+ private calculateSummary;
26
+ /**
27
+ * Calculate code health score (0-100)
28
+ */
29
+ private calculateHealthScore;
30
+ }
@@ -0,0 +1,167 @@
1
+ /**
2
+ * Code Smell Analyzer
3
+ *
4
+ * Main orchestrator for code smell detection
5
+ */
6
+ import { glob } from 'glob';
7
+ import { SmellType, SmellSeverity } from './types.js';
8
+ import { LongMethodDetector } from './detectors/long-method-detector.js';
9
+ import { LargeClassDetector } from './detectors/large-class-detector.js';
10
+ import { LongParameterListDetector } from './detectors/long-parameter-list-detector.js';
11
+ import { MagicNumbersDetector } from './detectors/magic-numbers-detector.js';
12
+ import { NestedConditionalsDetector } from './detectors/nested-conditionals-detector.js';
13
+ import { DeadCodeDetector } from './detectors/dead-code-detector.js';
14
+ import { DuplicateCodeDetector } from './detectors/duplicate-code-detector.js';
15
+ import { FeatureEnvyDetector } from './detectors/feature-envy-detector.js';
16
+ import { DataClumpsDetector } from './detectors/data-clumps-detector.js';
17
+ import { InappropriateIntimacyDetector } from './detectors/inappropriate-intimacy-detector.js';
18
+ export class CodeSmellAnalyzer {
19
+ detectors;
20
+ constructor(options = {}) {
21
+ this.detectors = new Map();
22
+ this.initializeDetectors(options);
23
+ }
24
+ /**
25
+ * Initialize all detectors with configuration
26
+ */
27
+ initializeDetectors(options) {
28
+ const defaultConfig = { enabled: true };
29
+ const detectorClasses = [
30
+ LongMethodDetector,
31
+ LargeClassDetector,
32
+ LongParameterListDetector,
33
+ MagicNumbersDetector,
34
+ NestedConditionalsDetector,
35
+ DeadCodeDetector,
36
+ DuplicateCodeDetector,
37
+ FeatureEnvyDetector,
38
+ DataClumpsDetector,
39
+ InappropriateIntimacyDetector,
40
+ ];
41
+ for (const DetectorClass of detectorClasses) {
42
+ const detector = new DetectorClass(defaultConfig);
43
+ const config = options.detectorConfigs?.[detector.type] ?? defaultConfig;
44
+ const configuredDetector = new DetectorClass(config);
45
+ this.detectors.set(configuredDetector.type, configuredDetector);
46
+ }
47
+ }
48
+ /**
49
+ * Analyze directory for code smells
50
+ */
51
+ async analyzeDirectory(directory, pattern = '**/*.{ts,tsx,js,jsx}', options = {}) {
52
+ const timestamp = new Date();
53
+ // Find all files
54
+ const ignorePatterns = [
55
+ '**/node_modules/**',
56
+ '**/dist/**',
57
+ '**/build/**',
58
+ '**/.git/**',
59
+ '**/*.test.{ts,tsx,js,jsx}',
60
+ '**/*.spec.{ts,tsx,js,jsx}',
61
+ ...(options.ignorePatterns || []),
62
+ ];
63
+ const files = await glob(pattern, {
64
+ cwd: directory,
65
+ absolute: true,
66
+ nodir: true,
67
+ ignore: ignorePatterns,
68
+ });
69
+ // Analyze all files
70
+ const allSmells = [];
71
+ const filesWithSmells = new Set();
72
+ for (const file of files) {
73
+ for (const detector of this.detectors.values()) {
74
+ try {
75
+ const smells = await detector.detect(file);
76
+ if (smells.length > 0) {
77
+ allSmells.push(...smells);
78
+ filesWithSmells.add(file);
79
+ }
80
+ }
81
+ catch (error) {
82
+ // Skip detector errors
83
+ console.error(`Error running ${detector.type} on ${file}:`, error);
84
+ }
85
+ }
86
+ }
87
+ // Calculate summary
88
+ const summary = this.calculateSummary(allSmells, files.length, filesWithSmells.size);
89
+ return Object.freeze({
90
+ smells: Object.freeze(allSmells),
91
+ summary: Object.freeze(summary),
92
+ timestamp,
93
+ });
94
+ }
95
+ /**
96
+ * Analyze single file
97
+ */
98
+ async analyzeFile(filePath) {
99
+ const smells = [];
100
+ for (const detector of this.detectors.values()) {
101
+ try {
102
+ const detectedSmells = await detector.detect(filePath);
103
+ smells.push(...detectedSmells);
104
+ }
105
+ catch (error) {
106
+ console.error(`Error running ${detector.type} on ${filePath}:`, error);
107
+ }
108
+ }
109
+ return smells;
110
+ }
111
+ /**
112
+ * Calculate summary statistics
113
+ */
114
+ calculateSummary(smells, totalFiles, filesWithSmells) {
115
+ // Count by type
116
+ const smellsByType = {};
117
+ for (const type of Object.values(SmellType)) {
118
+ smellsByType[type] = 0;
119
+ }
120
+ for (const smell of smells) {
121
+ smellsByType[smell.type]++;
122
+ }
123
+ // Count by severity
124
+ const smellsBySeverity = {};
125
+ for (const severity of Object.values(SmellSeverity)) {
126
+ smellsBySeverity[severity] = 0;
127
+ }
128
+ for (const smell of smells) {
129
+ smellsBySeverity[smell.severity]++;
130
+ }
131
+ // Calculate health score
132
+ const codeHealthScore = this.calculateHealthScore(smells, totalFiles);
133
+ return {
134
+ totalSmells: smells.length,
135
+ smellsByType: Object.freeze(smellsByType),
136
+ smellsBySeverity: Object.freeze(smellsBySeverity),
137
+ filesAnalyzed: totalFiles,
138
+ filesWithSmells,
139
+ averageSmellsPerFile: totalFiles > 0 ? smells.length / totalFiles : 0,
140
+ codeHealthScore,
141
+ };
142
+ }
143
+ /**
144
+ * Calculate code health score (0-100)
145
+ */
146
+ calculateHealthScore(smells, totalFiles) {
147
+ if (totalFiles === 0)
148
+ return 100;
149
+ // Weighted penalties by severity
150
+ const severityWeights = {
151
+ [SmellSeverity.LOW]: 1,
152
+ [SmellSeverity.MEDIUM]: 3,
153
+ [SmellSeverity.HIGH]: 7,
154
+ [SmellSeverity.CRITICAL]: 15,
155
+ };
156
+ let totalPenalty = 0;
157
+ for (const smell of smells) {
158
+ totalPenalty += severityWeights[smell.severity];
159
+ }
160
+ // Normalize penalty per file (penalty per file should reduce score)
161
+ const penaltyPerFile = totalPenalty / totalFiles;
162
+ // Score calculation: 100 - (penalty per file, capped at 100)
163
+ const score = Math.max(0, 100 - Math.min(100, penaltyPerFile * 2));
164
+ return Math.round(score);
165
+ }
166
+ }
167
+ //# sourceMappingURL=code-smell-analyzer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code-smell-analyzer.js","sourceRoot":"","sources":["../../../src/analyzers/code-smells/code-smell-analyzer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Data Clumps Detector
3
+ *
4
+ * Detects groups of parameters that frequently appear together
5
+ */
6
+ import { BaseSmellDetector } from '../base-smell-detector.js';
7
+ import { type CodeSmell, type DetectorConfig } from '../types.js';
8
+ export declare class DataClumpsDetector extends BaseSmellDetector {
9
+ constructor(config?: DetectorConfig);
10
+ detect(filePath: string): Promise<CodeSmell[]>;
11
+ }
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Data Clumps Detector
3
+ *
4
+ * Detects groups of parameters that frequently appear together
5
+ */
6
+ import { BaseSmellDetector } from '../base-smell-detector.js';
7
+ import { SmellType, SmellSeverity } from '../types.js';
8
+ export class DataClumpsDetector extends BaseSmellDetector {
9
+ constructor(config = { enabled: true, thresholds: { minOccurrences: 3, minParams: 3 } }) {
10
+ super(SmellType.DATA_CLUMPS, config);
11
+ }
12
+ async detect(filePath) {
13
+ if (!this.isEnabled())
14
+ return [];
15
+ const smells = [];
16
+ const minOccurrences = this.getThreshold('minOccurrences', 3);
17
+ const minParams = this.getThreshold('minParams', 3);
18
+ try {
19
+ const ast = this.astParser.parseFile(filePath);
20
+ // Collect parameter combinations
21
+ const paramCombinations = new Map();
22
+ // Check functions
23
+ for (const func of ast.functions) {
24
+ if (func.parameters.length >= minParams) {
25
+ const paramNames = func.parameters.map(p => p.name).sort().join(',');
26
+ if (!paramCombinations.has(paramNames)) {
27
+ paramCombinations.set(paramNames, []);
28
+ }
29
+ paramCombinations.get(paramNames).push({
30
+ location: `function ${func.name}`,
31
+ line: func.startLine,
32
+ params: func.parameters.map(p => p.name),
33
+ });
34
+ }
35
+ }
36
+ // Check methods
37
+ for (const cls of ast.classes) {
38
+ for (const method of cls.methods) {
39
+ if (method.parameters.length >= minParams) {
40
+ const paramNames = method.parameters.map(p => p.name).sort().join(',');
41
+ if (!paramCombinations.has(paramNames)) {
42
+ paramCombinations.set(paramNames, []);
43
+ }
44
+ paramCombinations.get(paramNames).push({
45
+ location: `${cls.name}.${method.name}`,
46
+ line: method.startLine,
47
+ params: method.parameters.map(p => p.name),
48
+ });
49
+ }
50
+ }
51
+ }
52
+ // Report data clumps
53
+ for (const [, occurrences] of paramCombinations.entries()) {
54
+ if (occurrences.length >= minOccurrences) {
55
+ const firstOccurrence = occurrences[0];
56
+ smells.push(this.createSmell(filePath, firstOccurrence.line, firstOccurrence.line, `Data clump detected: Parameters (${firstOccurrence.params.join(', ')}) appear together in ${occurrences.length} locations`, `Consider creating a data class or configuration object to group these related parameters.`, occurrences.length >= 5 ? SmellSeverity.HIGH : SmellSeverity.MEDIUM, { parameters: firstOccurrence.params, occurrences: occurrences.length, locations: occurrences.map(o => o.location) }));
57
+ }
58
+ }
59
+ }
60
+ catch (error) {
61
+ // Skip files that can't be parsed
62
+ }
63
+ return smells;
64
+ }
65
+ }
66
+ //# sourceMappingURL=data-clumps-detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data-clumps-detector.js","sourceRoot":"","sources":["../../../../src/analyzers/code-smells/detectors/data-clumps-detector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Dead Code Detector
3
+ *
4
+ * Detects unused exports and variables
5
+ */
6
+ import { BaseSmellDetector } from '../base-smell-detector.js';
7
+ import { type CodeSmell, type DetectorConfig } from '../types.js';
8
+ export declare class DeadCodeDetector extends BaseSmellDetector {
9
+ constructor(config?: DetectorConfig);
10
+ detect(filePath: string): Promise<CodeSmell[]>;
11
+ }
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Dead Code Detector
3
+ *
4
+ * Detects unused exports and variables
5
+ */
6
+ import { BaseSmellDetector } from '../base-smell-detector.js';
7
+ import { SmellType, SmellSeverity } from '../types.js';
8
+ export class DeadCodeDetector extends BaseSmellDetector {
9
+ constructor(config = { enabled: true }) {
10
+ super(SmellType.DEAD_CODE, config);
11
+ }
12
+ async detect(filePath) {
13
+ if (!this.isEnabled())
14
+ return [];
15
+ const smells = [];
16
+ try {
17
+ const ast = this.astParser.parseFile(filePath);
18
+ const sourceFile = this.astParser.getSourceFile(filePath);
19
+ // Find all exported symbols
20
+ const exportedSymbols = new Set(ast.exports.map(e => e.name));
21
+ // Find all variable declarations
22
+ const variables = sourceFile.getVariableDeclarations();
23
+ for (const variable of variables) {
24
+ const name = variable.getName();
25
+ // Skip exported variables
26
+ if (exportedSymbols.has(name))
27
+ continue;
28
+ // Check if variable is referenced
29
+ const references = variable.findReferencesAsNodes();
30
+ // If only 1 reference (the declaration itself), it's unused
31
+ if (references.length <= 1) {
32
+ smells.push(this.createSmell(filePath, variable.getStartLineNumber(), variable.getEndLineNumber(), `Unused variable '${name}'`, `Remove this unused variable or export it if needed elsewhere.`, SmellSeverity.LOW, { variableName: name, references: references.length }));
33
+ }
34
+ }
35
+ // Check for unused functions (not exported and not called)
36
+ const functions = sourceFile.getFunctions();
37
+ for (const func of functions) {
38
+ const name = func.getName();
39
+ if (!name || exportedSymbols.has(name))
40
+ continue;
41
+ const references = func.findReferencesAsNodes();
42
+ if (references.length <= 1) {
43
+ smells.push(this.createSmell(filePath, func.getStartLineNumber(), func.getEndLineNumber(), `Unused function '${name}'`, `Remove this unused function or export it if needed.`, SmellSeverity.MEDIUM, { functionName: name, references: references.length }));
44
+ }
45
+ }
46
+ }
47
+ catch (error) {
48
+ // Skip files that can't be parsed
49
+ }
50
+ return smells;
51
+ }
52
+ }
53
+ //# sourceMappingURL=dead-code-detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dead-code-detector.js","sourceRoot":"","sources":["../../../../src/analyzers/code-smells/detectors/dead-code-detector.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,SAAS,EAAE,aAAa,EAAuC,MAAM,aAAa,CAAC;AAE5F,MAAM,OAAO,gBAAiB,SAAQ,iBAAiB;IACrD,YAAY,SAAyB,EAAE,OAAO,EAAE,IAAI,EAAE;QACpD,KAAK,CAAC,SAAS,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IACrC,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,QAAgB;QAC3B,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE;YAAE,OAAO,EAAE,CAAC;QAEjC,MAAM,MAAM,GAAgB,EAAE,CAAC;QAE/B,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;YAC/C,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;YAE1D,4BAA4B;YAC5B,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;YAE9D,iCAAiC;YACjC,MAAM,SAAS,GAAG,UAAU,CAAC,uBAAuB,EAAE,CAAC;YAEvD,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;gBACjC,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,EAAE,CAAC;gBAEhC,0BAA0B;gBAC1B,IAAI,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC;oBAAE,SAAS;gBAExC,kCAAkC;gBAClC,MAAM,UAAU,GAAG,QAAQ,CAAC,qBAAqB,EAAE,CAAC;gBAEpD,4DAA4D;gBAC5D,IAAI,UAAU,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;oBAC3B,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,WAAW,CACd,QAAQ,EACR,QAAQ,CAAC,kBAAkB,EAAE,EAC7B,QAAQ,CAAC,gBAAgB,EAAE,EAC3B,oBAAoB,IAAI,GAAG,EAC3B,+DAA+D,EAC/D,aAAa,CAAC,GAAG,EACjB,EAAE,YAAY,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,CAAC,MAAM,EAAE,CACtD,CACF,CAAC;gBACJ,CAAC;YACH,CAAC;YAED,2DAA2D;YAC3D,MAAM,SAAS,GAAG,UAAU,CAAC,YAAY,EAAE,CAAC;YAC5C,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;gBAC7B,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;gBAC5B,IAAI,CAAC,IAAI,IAAI,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC;oBAAE,SAAS;gBAEjD,MAAM,UAAU,GAAG,IAAI,CAAC,qBAAqB,EAAE,CAAC;gBAChD,IAAI,UAAU,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;oBAC3B,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,WAAW,CACd,QAAQ,EACR,IAAI,CAAC,kBAAkB,EAAE,EACzB,IAAI,CAAC,gBAAgB,EAAE,EACvB,oBAAoB,IAAI,GAAG,EAC3B,qDAAqD,EACrD,aAAa,CAAC,MAAM,EACpB,EAAE,YAAY,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,CAAC,MAAM,EAAE,CACtD,CACF,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,kCAAkC;QACpC,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;CACF"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Duplicate Code Detector
3
+ *
4
+ * Detects similar code blocks (simplified heuristic-based detection)
5
+ */
6
+ import { BaseSmellDetector } from '../base-smell-detector.js';
7
+ import { type CodeSmell, type DetectorConfig } from '../types.js';
8
+ export declare class DuplicateCodeDetector extends BaseSmellDetector {
9
+ constructor(config?: DetectorConfig);
10
+ detect(filePath: string): Promise<CodeSmell[]>;
11
+ }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Duplicate Code Detector
3
+ *
4
+ * Detects similar code blocks (simplified heuristic-based detection)
5
+ */
6
+ import { BaseSmellDetector } from '../base-smell-detector.js';
7
+ import { SmellType, SmellSeverity } from '../types.js';
8
+ export class DuplicateCodeDetector extends BaseSmellDetector {
9
+ constructor(config = { enabled: true, thresholds: { minLines: 5 } }) {
10
+ super(SmellType.DUPLICATE_CODE, config);
11
+ }
12
+ async detect(filePath) {
13
+ if (!this.isEnabled())
14
+ return [];
15
+ const smells = [];
16
+ try {
17
+ const ast = this.astParser.parseFile(filePath);
18
+ // Simplified detection: Check for functions/methods with identical names (potential copy-paste)
19
+ const functionSignatures = new Map();
20
+ // Collect function signatures
21
+ for (const func of ast.functions) {
22
+ const signature = `${func.name}_${func.parameters.length}`;
23
+ if (!functionSignatures.has(signature)) {
24
+ functionSignatures.set(signature, []);
25
+ }
26
+ functionSignatures.get(signature).push({
27
+ name: func.name,
28
+ line: func.startLine,
29
+ params: func.parameters.length,
30
+ });
31
+ }
32
+ // Check for methods with very similar signatures across classes
33
+ const methodMap = new Map();
34
+ for (const cls of ast.classes) {
35
+ for (const method of cls.methods) {
36
+ const key = `${method.name}_${method.parameters.length}`;
37
+ methodMap.set(key, (methodMap.get(key) || 0) + 1);
38
+ // If same method appears in multiple classes, might be code duplication
39
+ if (methodMap.get(key) > 1) {
40
+ smells.push(this.createSmell(filePath, method.startLine, method.endLine, `Potential code duplication: Method '${method.name}' with ${method.parameters.length} parameters appears in multiple classes`, `Consider extracting common logic into a shared utility function or base class.`, SmellSeverity.MEDIUM, { methodName: method.name, occurrences: methodMap.get(key) }));
41
+ }
42
+ }
43
+ }
44
+ }
45
+ catch (error) {
46
+ // Skip files that can't be parsed
47
+ }
48
+ return smells;
49
+ }
50
+ }
51
+ //# sourceMappingURL=duplicate-code-detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"duplicate-code-detector.js","sourceRoot":"","sources":["../../../../src/analyzers/code-smells/detectors/duplicate-code-detector.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,SAAS,EAAE,aAAa,EAAuC,MAAM,aAAa,CAAC;AAE5F,MAAM,OAAO,qBAAsB,SAAQ,iBAAiB;IAC1D,YAAY,SAAyB,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE;QACjF,KAAK,CAAC,SAAS,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC;IAC1C,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,QAAgB;QAC3B,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE;YAAE,OAAO,EAAE,CAAC;QAEjC,MAAM,MAAM,GAAgB,EAAE,CAAC;QAE/B,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;YAE/C,gGAAgG;YAChG,MAAM,kBAAkB,GAAG,IAAI,GAAG,EAAiE,CAAC;YAEpG,8BAA8B;YAC9B,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,SAAS,EAAE,CAAC;gBACjC,MAAM,SAAS,GAAG,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC;gBAC3D,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;oBACvC,kBAAkB,CAAC,GAAG,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;gBACxC,CAAC;gBACD,kBAAkB,CAAC,GAAG,CAAC,SAAS,CAAE,CAAC,IAAI,CAAC;oBACtC,IAAI,EAAE,IAAI,CAAC,IAAI;oBACf,IAAI,EAAE,IAAI,CAAC,SAAS;oBACpB,MAAM,EAAE,IAAI,CAAC,UAAU,CAAC,MAAM;iBAC/B,CAAC,CAAC;YACL,CAAC;YAED,gEAAgE;YAChE,MAAM,SAAS,GAAG,IAAI,GAAG,EAAkB,CAAC;YAC5C,KAAK,MAAM,GAAG,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;gBAC9B,KAAK,MAAM,MAAM,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;oBACjC,MAAM,GAAG,GAAG,GAAG,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC;oBACzD,SAAS,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;oBAElD,wEAAwE;oBACxE,IAAI,SAAS,CAAC,GAAG,CAAC,GAAG,CAAE,GAAG,CAAC,EAAE,CAAC;wBAC5B,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,WAAW,CACd,QAAQ,EACR,MAAM,CAAC,SAAS,EAChB,MAAM,CAAC,OAAO,EACd,uCAAuC,MAAM,CAAC,IAAI,UAAU,MAAM,CAAC,UAAU,CAAC,MAAM,yCAAyC,EAC7H,gFAAgF,EAChF,aAAa,CAAC,MAAM,EACpB,EAAE,UAAU,EAAE,MAAM,CAAC,IAAI,EAAE,WAAW,EAAE,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAC7D,CACF,CAAC;oBACJ,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,kCAAkC;QACpC,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;CACF"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Feature Envy Detector
3
+ *
4
+ * Detects methods that use more features from other classes than their own
5
+ */
6
+ import { BaseSmellDetector } from '../base-smell-detector.js';
7
+ import { type CodeSmell, type DetectorConfig } from '../types.js';
8
+ export declare class FeatureEnvyDetector extends BaseSmellDetector {
9
+ constructor(config?: DetectorConfig);
10
+ detect(filePath: string): Promise<CodeSmell[]>;
11
+ }
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Feature Envy Detector
3
+ *
4
+ * Detects methods that use more features from other classes than their own
5
+ */
6
+ import { BaseSmellDetector } from '../base-smell-detector.js';
7
+ import { SmellType, SmellSeverity } from '../types.js';
8
+ import { SyntaxKind } from 'ts-morph';
9
+ export class FeatureEnvyDetector extends BaseSmellDetector {
10
+ constructor(config = { enabled: true, thresholds: { ratio: 0.7 } }) {
11
+ super(SmellType.FEATURE_ENVY, config);
12
+ }
13
+ async detect(filePath) {
14
+ if (!this.isEnabled())
15
+ return [];
16
+ const smells = [];
17
+ const envyRatio = this.getThreshold('ratio', 0.7);
18
+ try {
19
+ const sourceFile = this.astParser.getSourceFile(filePath);
20
+ const classes = sourceFile.getClasses();
21
+ for (const cls of classes) {
22
+ const className = cls.getName() || 'anonymous';
23
+ const classProperties = new Set(cls.getProperties().map(p => p.getName()));
24
+ for (const method of cls.getMethods()) {
25
+ const methodName = method.getName();
26
+ let ownPropertyAccess = 0;
27
+ let externalPropertyAccess = 0;
28
+ // Count property accesses
29
+ method.forEachDescendant((node) => {
30
+ if (node.getKind() === SyntaxKind.PropertyAccessExpression) {
31
+ const text = node.getText();
32
+ // Check if accessing own property
33
+ if (text.startsWith('this.')) {
34
+ const propName = text.slice(5).split('.')[0];
35
+ if (classProperties.has(propName)) {
36
+ ownPropertyAccess++;
37
+ }
38
+ else {
39
+ externalPropertyAccess++;
40
+ }
41
+ }
42
+ else {
43
+ externalPropertyAccess++;
44
+ }
45
+ }
46
+ });
47
+ const totalAccess = ownPropertyAccess + externalPropertyAccess;
48
+ if (totalAccess > 5) {
49
+ // Only check if significant number of accesses
50
+ const externalRatio = externalPropertyAccess / totalAccess;
51
+ if (externalRatio >= envyRatio) {
52
+ smells.push(this.createSmell(filePath, method.getStartLineNumber(), method.getEndLineNumber(), `Method '${className}.${methodName}' exhibits feature envy (${Math.round(externalRatio * 100)}% external access)`, `This method accesses more external properties than its own. Consider moving this logic to the class it's most interested in.`, externalRatio >= 0.9 ? SmellSeverity.HIGH : SmellSeverity.MEDIUM, { className, methodName, ownAccess: ownPropertyAccess, externalAccess: externalPropertyAccess }));
53
+ }
54
+ }
55
+ }
56
+ }
57
+ }
58
+ catch (error) {
59
+ // Skip files that can't be parsed
60
+ }
61
+ return smells;
62
+ }
63
+ }
64
+ //# sourceMappingURL=feature-envy-detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feature-envy-detector.js","sourceRoot":"","sources":["../../../../src/analyzers/code-smells/detectors/feature-envy-detector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Inappropriate Intimacy Detector
3
+ *
4
+ * Detects classes that are too tightly coupled
5
+ */
6
+ import { BaseSmellDetector } from '../base-smell-detector.js';
7
+ import { type CodeSmell, type DetectorConfig } from '../types.js';
8
+ export declare class InappropriateIntimacyDetector extends BaseSmellDetector {
9
+ constructor(config?: DetectorConfig);
10
+ detect(filePath: string): Promise<CodeSmell[]>;
11
+ }
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Inappropriate Intimacy Detector
3
+ *
4
+ * Detects classes that are too tightly coupled
5
+ */
6
+ import { BaseSmellDetector } from '../base-smell-detector.js';
7
+ import { SmellType, SmellSeverity } from '../types.js';
8
+ import { SyntaxKind } from 'ts-morph';
9
+ export class InappropriateIntimacyDetector extends BaseSmellDetector {
10
+ constructor(config = { enabled: true, thresholds: { maxAccess: 10 } }) {
11
+ super(SmellType.INAPPROPRIATE_INTIMACY, config);
12
+ }
13
+ async detect(filePath) {
14
+ if (!this.isEnabled())
15
+ return [];
16
+ const smells = [];
17
+ const maxAccess = this.getThreshold('maxAccess', 10);
18
+ try {
19
+ const sourceFile = this.astParser.getSourceFile(filePath);
20
+ const classes = sourceFile.getClasses();
21
+ for (const cls of classes) {
22
+ const className = cls.getName() || 'anonymous';
23
+ const externalClassAccess = new Map();
24
+ // Count accesses to other classes
25
+ cls.forEachDescendant((node) => {
26
+ if (node.getKind() === SyntaxKind.PropertyAccessExpression) {
27
+ const text = node.getText();
28
+ // Skip 'this.' accesses
29
+ if (text.startsWith('this.'))
30
+ return;
31
+ // Extract potential class name from property access (e.g., 'otherClass.property')
32
+ const parts = text.split('.');
33
+ if (parts.length >= 2) {
34
+ const potentialClass = parts[0];
35
+ // Simple heuristic: capitalized names or common object names
36
+ if (potentialClass.length > 0 && /^[a-z][a-zA-Z]*$/.test(potentialClass)) {
37
+ externalClassAccess.set(potentialClass, (externalClassAccess.get(potentialClass) || 0) + 1);
38
+ }
39
+ }
40
+ }
41
+ });
42
+ // Report excessive coupling
43
+ for (const [externalClass, accessCount] of externalClassAccess.entries()) {
44
+ if (accessCount > maxAccess) {
45
+ smells.push(this.createSmell(filePath, cls.getStartLineNumber(), cls.getEndLineNumber(), `Class '${className}' is too intimate with '${externalClass}' (${accessCount} accesses)`, `Consider refactoring to reduce coupling. Move shared functionality to a common base class or use composition.`, accessCount >= 20 ? SmellSeverity.HIGH : SmellSeverity.MEDIUM, { className, targetClass: externalClass, accessCount, threshold: maxAccess }));
46
+ }
47
+ }
48
+ }
49
+ }
50
+ catch (error) {
51
+ // Skip files that can't be parsed
52
+ }
53
+ return smells;
54
+ }
55
+ }
56
+ //# sourceMappingURL=inappropriate-intimacy-detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inappropriate-intimacy-detector.js","sourceRoot":"","sources":["../../../../src/analyzers/code-smells/detectors/inappropriate-intimacy-detector.ts"],"names":[],"mappings":"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"}