@oalacea/daemon 0.6.4 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (286) hide show
  1. package/README.md +268 -58
  2. package/bin/Dockerfile +158 -16
  3. package/bin/docker-entrypoint.sh +293 -0
  4. package/dist/cli/cli.d.ts.map +1 -1
  5. package/dist/cli/cli.js +22 -2
  6. package/dist/cli/cli.js.map +1 -1
  7. package/dist/cli/commands/command.types.d.ts +216 -0
  8. package/dist/cli/commands/command.types.d.ts.map +1 -0
  9. package/dist/cli/commands/command.types.js +64 -0
  10. package/dist/cli/commands/command.types.js.map +1 -0
  11. package/dist/cli/commands/history.command.d.ts +91 -0
  12. package/dist/cli/commands/history.command.d.ts.map +1 -0
  13. package/dist/cli/commands/history.command.js +336 -0
  14. package/dist/cli/commands/history.command.js.map +1 -0
  15. package/dist/cli/commands/index.d.ts +14 -3
  16. package/dist/cli/commands/index.d.ts.map +1 -1
  17. package/dist/cli/commands/index.js +7 -0
  18. package/dist/cli/commands/index.js.map +1 -1
  19. package/dist/cli/commands/optimize.command.d.ts +110 -0
  20. package/dist/cli/commands/optimize.command.d.ts.map +1 -0
  21. package/dist/cli/commands/optimize.command.js +497 -0
  22. package/dist/cli/commands/optimize.command.js.map +1 -0
  23. package/dist/cli/commands/report.command.d.ts +110 -0
  24. package/dist/cli/commands/report.command.d.ts.map +1 -0
  25. package/dist/cli/commands/report.command.js +532 -0
  26. package/dist/cli/commands/report.command.js.map +1 -0
  27. package/dist/cli/commands/review.command.d.ts +110 -0
  28. package/dist/cli/commands/review.command.d.ts.map +1 -0
  29. package/dist/cli/commands/review.command.js +520 -0
  30. package/dist/cli/commands/review.command.js.map +1 -0
  31. package/dist/cli/commands/score.command.d.ts +47 -0
  32. package/dist/cli/commands/score.command.d.ts.map +1 -0
  33. package/dist/cli/commands/score.command.js +261 -0
  34. package/dist/cli/commands/score.command.js.map +1 -0
  35. package/dist/cli/utils/index.d.ts +10 -0
  36. package/dist/cli/utils/index.d.ts.map +1 -0
  37. package/dist/cli/utils/index.js +10 -0
  38. package/dist/cli/utils/index.js.map +1 -0
  39. package/dist/cli/utils/output.d.ts +192 -0
  40. package/dist/cli/utils/output.d.ts.map +1 -0
  41. package/dist/cli/utils/output.js +411 -0
  42. package/dist/cli/utils/output.js.map +1 -0
  43. package/dist/cli/utils/progress.d.ts +204 -0
  44. package/dist/cli/utils/progress.d.ts.map +1 -0
  45. package/dist/cli/utils/progress.js +396 -0
  46. package/dist/cli/utils/progress.js.map +1 -0
  47. package/dist/core/types/index.d.ts +1 -0
  48. package/dist/core/types/index.d.ts.map +1 -1
  49. package/dist/core/types/project.types.d.ts +3 -3
  50. package/dist/core/types/project.types.d.ts.map +1 -1
  51. package/dist/core/types/scoring.types.d.ts +301 -0
  52. package/dist/core/types/scoring.types.d.ts.map +1 -0
  53. package/dist/core/types/scoring.types.js +8 -0
  54. package/dist/core/types/scoring.types.js.map +1 -0
  55. package/dist/services/detection/framework-detector.d.ts.map +1 -1
  56. package/dist/services/detection/framework-detector.js +74 -5
  57. package/dist/services/detection/framework-detector.js.map +1 -1
  58. package/dist/services/index.d.ts +12 -0
  59. package/dist/services/index.d.ts.map +1 -1
  60. package/dist/services/index.js +14 -0
  61. package/dist/services/index.js.map +1 -1
  62. package/dist/services/optimization/detectors/bug-detector.d.ts +82 -0
  63. package/dist/services/optimization/detectors/bug-detector.d.ts.map +1 -0
  64. package/dist/services/optimization/detectors/bug-detector.js +443 -0
  65. package/dist/services/optimization/detectors/bug-detector.js.map +1 -0
  66. package/dist/services/optimization/detectors/code-smell-detector.d.ts +108 -0
  67. package/dist/services/optimization/detectors/code-smell-detector.d.ts.map +1 -0
  68. package/dist/services/optimization/detectors/code-smell-detector.js +569 -0
  69. package/dist/services/optimization/detectors/code-smell-detector.js.map +1 -0
  70. package/dist/services/optimization/detectors/index.d.ts +7 -0
  71. package/dist/services/optimization/detectors/index.d.ts.map +1 -0
  72. package/dist/services/optimization/detectors/index.js +7 -0
  73. package/dist/services/optimization/detectors/index.js.map +1 -0
  74. package/dist/services/optimization/detectors/perf-detector.d.ts +80 -0
  75. package/dist/services/optimization/detectors/perf-detector.d.ts.map +1 -0
  76. package/dist/services/optimization/detectors/perf-detector.js +451 -0
  77. package/dist/services/optimization/detectors/perf-detector.js.map +1 -0
  78. package/dist/services/optimization/index.d.ts +61 -0
  79. package/dist/services/optimization/index.d.ts.map +1 -0
  80. package/dist/services/optimization/index.js +69 -0
  81. package/dist/services/optimization/index.js.map +1 -0
  82. package/dist/services/optimization/optimization.service.d.ts +65 -0
  83. package/dist/services/optimization/optimization.service.d.ts.map +1 -0
  84. package/dist/services/optimization/optimization.service.js +511 -0
  85. package/dist/services/optimization/optimization.service.js.map +1 -0
  86. package/dist/services/optimization/optimization.types.d.ts +343 -0
  87. package/dist/services/optimization/optimization.types.d.ts.map +1 -0
  88. package/dist/services/optimization/optimization.types.js +8 -0
  89. package/dist/services/optimization/optimization.types.js.map +1 -0
  90. package/dist/services/optimization/optimizers/code-optimizer.d.ts +87 -0
  91. package/dist/services/optimization/optimizers/code-optimizer.d.ts.map +1 -0
  92. package/dist/services/optimization/optimizers/code-optimizer.js +436 -0
  93. package/dist/services/optimization/optimizers/code-optimizer.js.map +1 -0
  94. package/dist/services/optimization/optimizers/index.d.ts +7 -0
  95. package/dist/services/optimization/optimizers/index.d.ts.map +1 -0
  96. package/dist/services/optimization/optimizers/index.js +7 -0
  97. package/dist/services/optimization/optimizers/index.js.map +1 -0
  98. package/dist/services/optimization/optimizers/perf-optimizer.d.ts +64 -0
  99. package/dist/services/optimization/optimizers/perf-optimizer.d.ts.map +1 -0
  100. package/dist/services/optimization/optimizers/perf-optimizer.js +330 -0
  101. package/dist/services/optimization/optimizers/perf-optimizer.js.map +1 -0
  102. package/dist/services/optimization/optimizers/refact-optimizer.d.ts +82 -0
  103. package/dist/services/optimization/optimizers/refact-optimizer.d.ts.map +1 -0
  104. package/dist/services/optimization/optimizers/refact-optimizer.js +354 -0
  105. package/dist/services/optimization/optimizers/refact-optimizer.js.map +1 -0
  106. package/dist/services/optimization/patterns/anti-patterns.d.ts +31 -0
  107. package/dist/services/optimization/patterns/anti-patterns.d.ts.map +1 -0
  108. package/dist/services/optimization/patterns/anti-patterns.js +501 -0
  109. package/dist/services/optimization/patterns/anti-patterns.js.map +1 -0
  110. package/dist/services/optimization/patterns/index.d.ts +5 -0
  111. package/dist/services/optimization/patterns/index.d.ts.map +1 -0
  112. package/dist/services/optimization/patterns/index.js +5 -0
  113. package/dist/services/optimization/patterns/index.js.map +1 -0
  114. package/dist/services/reporting/export/chart.exporter.d.ts +59 -0
  115. package/dist/services/reporting/export/chart.exporter.d.ts.map +1 -0
  116. package/dist/services/reporting/export/chart.exporter.js +350 -0
  117. package/dist/services/reporting/export/chart.exporter.js.map +1 -0
  118. package/dist/services/reporting/export/index.d.ts +9 -0
  119. package/dist/services/reporting/export/index.d.ts.map +1 -0
  120. package/dist/services/reporting/export/index.js +10 -0
  121. package/dist/services/reporting/export/index.js.map +1 -0
  122. package/dist/services/reporting/export/pdf.exporter.d.ts +133 -0
  123. package/dist/services/reporting/export/pdf.exporter.d.ts.map +1 -0
  124. package/dist/services/reporting/export/pdf.exporter.js +270 -0
  125. package/dist/services/reporting/export/pdf.exporter.js.map +1 -0
  126. package/dist/services/reporting/history.service.d.ts +93 -0
  127. package/dist/services/reporting/history.service.d.ts.map +1 -0
  128. package/dist/services/reporting/history.service.js +285 -0
  129. package/dist/services/reporting/history.service.js.map +1 -0
  130. package/dist/services/reporting/index.d.ts +15 -0
  131. package/dist/services/reporting/index.d.ts.map +1 -0
  132. package/dist/services/reporting/index.js +16 -0
  133. package/dist/services/reporting/index.js.map +1 -0
  134. package/dist/services/reporting/report.service.d.ts +102 -0
  135. package/dist/services/reporting/report.service.d.ts.map +1 -0
  136. package/dist/services/reporting/report.service.js +240 -0
  137. package/dist/services/reporting/report.service.js.map +1 -0
  138. package/dist/services/reporting/reporting.types.d.ts +329 -0
  139. package/dist/services/reporting/reporting.types.d.ts.map +1 -0
  140. package/dist/services/reporting/reporting.types.js +8 -0
  141. package/dist/services/reporting/reporting.types.js.map +1 -0
  142. package/dist/services/reporting/templates/html.template.d.ts +81 -0
  143. package/dist/services/reporting/templates/html.template.d.ts.map +1 -0
  144. package/dist/services/reporting/templates/html.template.js +741 -0
  145. package/dist/services/reporting/templates/html.template.js.map +1 -0
  146. package/dist/services/reporting/templates/json.template.d.ts +85 -0
  147. package/dist/services/reporting/templates/json.template.d.ts.map +1 -0
  148. package/dist/services/reporting/templates/json.template.js +308 -0
  149. package/dist/services/reporting/templates/json.template.js.map +1 -0
  150. package/dist/services/reporting/templates/markdown.template.d.ts +69 -0
  151. package/dist/services/reporting/templates/markdown.template.d.ts.map +1 -0
  152. package/dist/services/reporting/templates/markdown.template.js +311 -0
  153. package/dist/services/reporting/templates/markdown.template.js.map +1 -0
  154. package/dist/services/reporting/trend-analyzer.d.ts +73 -0
  155. package/dist/services/reporting/trend-analyzer.d.ts.map +1 -0
  156. package/dist/services/reporting/trend-analyzer.js +291 -0
  157. package/dist/services/reporting/trend-analyzer.js.map +1 -0
  158. package/dist/services/review/analyzers/dependency-analyzer.d.ts +87 -0
  159. package/dist/services/review/analyzers/dependency-analyzer.d.ts.map +1 -0
  160. package/dist/services/review/analyzers/dependency-analyzer.js +458 -0
  161. package/dist/services/review/analyzers/dependency-analyzer.js.map +1 -0
  162. package/dist/services/review/analyzers/index.d.ts +13 -0
  163. package/dist/services/review/analyzers/index.d.ts.map +1 -0
  164. package/dist/services/review/analyzers/index.js +13 -0
  165. package/dist/services/review/analyzers/index.js.map +1 -0
  166. package/dist/services/review/analyzers/nestjs-analyzer.d.ts +210 -0
  167. package/dist/services/review/analyzers/nestjs-analyzer.d.ts.map +1 -0
  168. package/dist/services/review/analyzers/nestjs-analyzer.js +571 -0
  169. package/dist/services/review/analyzers/nestjs-analyzer.js.map +1 -0
  170. package/dist/services/review/analyzers/performance-analyzer.d.ts +91 -0
  171. package/dist/services/review/analyzers/performance-analyzer.d.ts.map +1 -0
  172. package/dist/services/review/analyzers/performance-analyzer.js +589 -0
  173. package/dist/services/review/analyzers/performance-analyzer.js.map +1 -0
  174. package/dist/services/review/analyzers/security-analyzer.d.ts +96 -0
  175. package/dist/services/review/analyzers/security-analyzer.d.ts.map +1 -0
  176. package/dist/services/review/analyzers/security-analyzer.js +512 -0
  177. package/dist/services/review/analyzers/security-analyzer.js.map +1 -0
  178. package/dist/services/review/analyzers/static-analyzer.d.ts +90 -0
  179. package/dist/services/review/analyzers/static-analyzer.d.ts.map +1 -0
  180. package/dist/services/review/analyzers/static-analyzer.js +423 -0
  181. package/dist/services/review/analyzers/static-analyzer.js.map +1 -0
  182. package/dist/services/review/fixers/auto-fixer.d.ts +94 -0
  183. package/dist/services/review/fixers/auto-fixer.d.ts.map +1 -0
  184. package/dist/services/review/fixers/auto-fixer.js +404 -0
  185. package/dist/services/review/fixers/auto-fixer.js.map +1 -0
  186. package/dist/services/review/fixers/index.d.ts +11 -0
  187. package/dist/services/review/fixers/index.d.ts.map +1 -0
  188. package/dist/services/review/fixers/index.js +11 -0
  189. package/dist/services/review/fixers/index.js.map +1 -0
  190. package/dist/services/review/fixers/refactor-suggester.d.ts +100 -0
  191. package/dist/services/review/fixers/refactor-suggester.d.ts.map +1 -0
  192. package/dist/services/review/fixers/refactor-suggester.js +555 -0
  193. package/dist/services/review/fixers/refactor-suggester.js.map +1 -0
  194. package/dist/services/review/fixers/test-generator.d.ts +99 -0
  195. package/dist/services/review/fixers/test-generator.d.ts.map +1 -0
  196. package/dist/services/review/fixers/test-generator.js +458 -0
  197. package/dist/services/review/fixers/test-generator.js.map +1 -0
  198. package/dist/services/review/index.d.ts +14 -0
  199. package/dist/services/review/index.d.ts.map +1 -0
  200. package/dist/services/review/index.js +14 -0
  201. package/dist/services/review/index.js.map +1 -0
  202. package/dist/services/review/reporters/fix-reporter.d.ts +67 -0
  203. package/dist/services/review/reporters/fix-reporter.d.ts.map +1 -0
  204. package/dist/services/review/reporters/fix-reporter.js +437 -0
  205. package/dist/services/review/reporters/fix-reporter.js.map +1 -0
  206. package/dist/services/review/reporters/index.d.ts +10 -0
  207. package/dist/services/review/reporters/index.d.ts.map +1 -0
  208. package/dist/services/review/reporters/index.js +10 -0
  209. package/dist/services/review/reporters/index.js.map +1 -0
  210. package/dist/services/review/reporters/score-reporter.d.ts +84 -0
  211. package/dist/services/review/reporters/score-reporter.d.ts.map +1 -0
  212. package/dist/services/review/reporters/score-reporter.js +560 -0
  213. package/dist/services/review/reporters/score-reporter.js.map +1 -0
  214. package/dist/services/review/review.service.d.ts +129 -0
  215. package/dist/services/review/review.service.d.ts.map +1 -0
  216. package/dist/services/review/review.service.js +396 -0
  217. package/dist/services/review/review.service.js.map +1 -0
  218. package/dist/services/review/review.types.d.ts +443 -0
  219. package/dist/services/review/review.types.d.ts.map +1 -0
  220. package/dist/services/review/review.types.js +11 -0
  221. package/dist/services/review/review.types.js.map +1 -0
  222. package/dist/services/scoring/dimensions/accessibility.analyzer.d.ts +53 -0
  223. package/dist/services/scoring/dimensions/accessibility.analyzer.d.ts.map +1 -0
  224. package/dist/services/scoring/dimensions/accessibility.analyzer.js +260 -0
  225. package/dist/services/scoring/dimensions/accessibility.analyzer.js.map +1 -0
  226. package/dist/services/scoring/dimensions/backend-logic.analyzer.d.ts +138 -0
  227. package/dist/services/scoring/dimensions/backend-logic.analyzer.d.ts.map +1 -0
  228. package/dist/services/scoring/dimensions/backend-logic.analyzer.js +713 -0
  229. package/dist/services/scoring/dimensions/backend-logic.analyzer.js.map +1 -0
  230. package/dist/services/scoring/dimensions/business-logic.analyzer.d.ts +142 -0
  231. package/dist/services/scoring/dimensions/business-logic.analyzer.d.ts.map +1 -0
  232. package/dist/services/scoring/dimensions/business-logic.analyzer.js +747 -0
  233. package/dist/services/scoring/dimensions/business-logic.analyzer.js.map +1 -0
  234. package/dist/services/scoring/dimensions/code-quality.analyzer.d.ts +142 -0
  235. package/dist/services/scoring/dimensions/code-quality.analyzer.d.ts.map +1 -0
  236. package/dist/services/scoring/dimensions/code-quality.analyzer.js +685 -0
  237. package/dist/services/scoring/dimensions/code-quality.analyzer.js.map +1 -0
  238. package/dist/services/scoring/dimensions/index.d.ts +18 -0
  239. package/dist/services/scoring/dimensions/index.d.ts.map +1 -0
  240. package/dist/services/scoring/dimensions/index.js +27 -0
  241. package/dist/services/scoring/dimensions/index.js.map +1 -0
  242. package/dist/services/scoring/dimensions/performance.analyzer.d.ts +125 -0
  243. package/dist/services/scoring/dimensions/performance.analyzer.d.ts.map +1 -0
  244. package/dist/services/scoring/dimensions/performance.analyzer.js +615 -0
  245. package/dist/services/scoring/dimensions/performance.analyzer.js.map +1 -0
  246. package/dist/services/scoring/dimensions/security.analyzer.d.ts +53 -0
  247. package/dist/services/scoring/dimensions/security.analyzer.d.ts.map +1 -0
  248. package/dist/services/scoring/dimensions/security.analyzer.js +327 -0
  249. package/dist/services/scoring/dimensions/security.analyzer.js.map +1 -0
  250. package/dist/services/scoring/dimensions/seo.analyzer.d.ts +77 -0
  251. package/dist/services/scoring/dimensions/seo.analyzer.d.ts.map +1 -0
  252. package/dist/services/scoring/dimensions/seo.analyzer.js +502 -0
  253. package/dist/services/scoring/dimensions/seo.analyzer.js.map +1 -0
  254. package/dist/services/scoring/dimensions/test-coverage.analyzer.d.ts +106 -0
  255. package/dist/services/scoring/dimensions/test-coverage.analyzer.d.ts.map +1 -0
  256. package/dist/services/scoring/dimensions/test-coverage.analyzer.js +496 -0
  257. package/dist/services/scoring/dimensions/test-coverage.analyzer.js.map +1 -0
  258. package/dist/services/scoring/dimensions/ui-ux.analyzer.d.ts +126 -0
  259. package/dist/services/scoring/dimensions/ui-ux.analyzer.d.ts.map +1 -0
  260. package/dist/services/scoring/dimensions/ui-ux.analyzer.js +665 -0
  261. package/dist/services/scoring/dimensions/ui-ux.analyzer.js.map +1 -0
  262. package/dist/services/scoring/index.d.ts +10 -0
  263. package/dist/services/scoring/index.d.ts.map +1 -0
  264. package/dist/services/scoring/index.js +10 -0
  265. package/dist/services/scoring/index.js.map +1 -0
  266. package/dist/services/scoring/scoring-service.d.ts +222 -0
  267. package/dist/services/scoring/scoring-service.d.ts.map +1 -0
  268. package/dist/services/scoring/scoring-service.js +636 -0
  269. package/dist/services/scoring/scoring-service.js.map +1 -0
  270. package/package.json +13 -4
  271. package/templates/README.md +183 -0
  272. package/templates/nestjs/controller.spec.ts +203 -0
  273. package/templates/nestjs/e2e/api.e2e-spec.ts +451 -0
  274. package/templates/nestjs/e2e/auth.e2e-spec.ts +533 -0
  275. package/templates/nestjs/fixtures/test-module.ts +311 -0
  276. package/templates/nestjs/guard.spec.ts +314 -0
  277. package/templates/nestjs/interceptor.spec.ts +458 -0
  278. package/templates/nestjs/module.spec.ts +173 -0
  279. package/templates/nestjs/pipe.spec.ts +474 -0
  280. package/templates/nestjs/service.spec.ts +296 -0
  281. package/templates/rust/Cargo.toml +72 -0
  282. package/templates/rust/actix-controller.test.rs +114 -0
  283. package/templates/rust/axum-handler.test.rs +117 -0
  284. package/templates/rust/integration.test.rs +63 -0
  285. package/templates/rust/rocket-route.test.rs +106 -0
  286. package/templates/rust/unit.test.rs +38 -0
@@ -0,0 +1,747 @@
1
+ /**
2
+ * Business Logic Analyzer
3
+ *
4
+ * Analyzes business logic quality including domain separation, business rule consistency,
5
+ * edge case handling, and state management appropriateness.
6
+ *
7
+ * @module services/scoring/dimensions/business-logic
8
+ */
9
+ import { readFile, readdir } from 'node:fs/promises';
10
+ import { join, extname, relative } from 'node:path';
11
+ import { existsSync } from 'node:fs';
12
+ import { CommandExecutor } from '../../../shared/utils/command-executor.js';
13
+ import { createLogger } from '../../../shared/utils/logger.js';
14
+ /**
15
+ * Business Logic Analyzer
16
+ *
17
+ * Evaluates business logic quality across multiple dimensions:
18
+ * - Domain separation (features/ pattern)
19
+ * - Business rule consistency
20
+ * - Edge case handling
21
+ * - State management appropriateness
22
+ */
23
+ export class BusinessLogicAnalyzer {
24
+ /** Analyzer configuration */
25
+ config = {
26
+ dimension: 'business-logic',
27
+ defaultWeight: 0.05,
28
+ estimatedDuration: 20000,
29
+ supportedFrameworks: ['Next.js', 'React', 'Vue', 'Nuxt', 'Svelte', 'Angular', 'Remix', 'SvelteKit', 'Astro', 'Gatsby'],
30
+ };
31
+ logger;
32
+ executor;
33
+ _checkDomainSeparation;
34
+ _checkBusinessRules;
35
+ _checkEdgeCaseHandling;
36
+ _checkStateManagement;
37
+ constructor(options = {}) {
38
+ this.logger = createLogger('BusinessLogicAnalyzer');
39
+ this.executor = new CommandExecutor();
40
+ this._checkDomainSeparation = options.checkDomainSeparation ?? true;
41
+ this._checkBusinessRules = options.checkBusinessRules ?? true;
42
+ this._checkEdgeCaseHandling = options.checkEdgeCaseHandling ?? true;
43
+ this._checkStateManagement = options.checkStateManagement ?? true;
44
+ }
45
+ /**
46
+ * Get the dimension this analyzer handles
47
+ */
48
+ getDimension() {
49
+ return 'business-logic';
50
+ }
51
+ /**
52
+ * Get the default weight for this dimension
53
+ */
54
+ getWeight() {
55
+ return 0.10; // 10% weight in overall score
56
+ }
57
+ /**
58
+ * Analyze business logic for a project
59
+ *
60
+ * @param projectPath - Path to the project root
61
+ * @param _framework - Detected framework (optional, for framework-specific analysis)
62
+ * @param _options - Scoring options (optional)
63
+ * @returns Dimension score with business logic metrics
64
+ */
65
+ async analyze(projectPath, _framework, _options) {
66
+ const startTime = performance.now();
67
+ this.logger.info(`Analyzing business logic for: ${projectPath}`);
68
+ const issues = [];
69
+ const improvements = [];
70
+ try {
71
+ // Analyze project structure
72
+ const structureType = this._checkDomainSeparation ? await this.analyzeProjectStructure(projectPath) : 'flat';
73
+ // Analyze feature modules
74
+ const featureModules = this._checkDomainSeparation ? await this.analyzeFeatureModules(projectPath) : [];
75
+ // Check state management
76
+ const stateManagement = this._checkStateManagement ? await this.analyzeStateManagement(projectPath) : 'unknown';
77
+ // Check business rules consistency
78
+ const ruleConsistency = this._checkBusinessRules ? await this.checkBusinessRuleConsistency(projectPath) : 0;
79
+ // Check edge case handling
80
+ const edgeCaseHandling = this._checkEdgeCaseHandling ? await this.checkEdgeCaseHandlingPatterns(projectPath) : 0;
81
+ // Check DDD patterns
82
+ const dddAdherence = await this.checkDddPatterns(projectPath);
83
+ const metrics = {
84
+ domainSeparation: this.calculateDomainSeparationScore(structureType, featureModules),
85
+ structureType,
86
+ ruleConsistency,
87
+ edgeCaseHandling,
88
+ stateManagementScore: this.calculateStateManagementScore(stateManagement),
89
+ stateManagement,
90
+ featureIsolation: this.calculateFeatureIsolation(featureModules),
91
+ dddAdherence,
92
+ };
93
+ // Build issues list
94
+ issues.push(...this.identifyBusinessLogicIssues(metrics));
95
+ // Build improvements list
96
+ improvements.push(...this.generateBusinessLogicImprovements(metrics));
97
+ // Calculate final score
98
+ const score = this.calculateBusinessLogicScore(metrics);
99
+ const duration = Math.round(performance.now() - startTime);
100
+ return {
101
+ dimension: this.getDimension(),
102
+ score,
103
+ weight: this.getWeight(),
104
+ weightedScore: score * this.getWeight(),
105
+ issues,
106
+ improvements,
107
+ metadata: {
108
+ itemsChecked: 5 + featureModules.length,
109
+ itemsPassed: this.countPassedChecks(metrics),
110
+ metrics: {
111
+ structureType: metrics.structureType,
112
+ domainSeparation: metrics.domainSeparation,
113
+ ruleConsistency: metrics.ruleConsistency,
114
+ edgeCaseHandling: metrics.edgeCaseHandling,
115
+ stateManagement: metrics.stateManagement,
116
+ stateManagementScore: metrics.stateManagementScore,
117
+ featureIsolation: metrics.featureIsolation,
118
+ dddAdherence: metrics.dddAdherence,
119
+ featureModuleCount: featureModules.length,
120
+ },
121
+ },
122
+ };
123
+ }
124
+ catch (error) {
125
+ this.logger.error('Error analyzing business logic', error);
126
+ issues.push({
127
+ severity: 'medium',
128
+ category: 'architecture',
129
+ description: `Failed to analyze business logic: ${error instanceof Error ? error.message : String(error)}`,
130
+ fixable: false,
131
+ });
132
+ const duration = Math.round(performance.now() - startTime);
133
+ return {
134
+ dimension: this.getDimension(),
135
+ score: 50,
136
+ weight: this.getWeight(),
137
+ weightedScore: 50 * this.getWeight(),
138
+ issues,
139
+ improvements,
140
+ metadata: { error: String(error) },
141
+ };
142
+ }
143
+ }
144
+ /**
145
+ * Analyze project structure
146
+ */
147
+ async analyzeProjectStructure(projectPath) {
148
+ const srcDir = join(projectPath, 'src');
149
+ const appDir = join(projectPath, 'app');
150
+ // Check for features directory pattern
151
+ const featuresDir = join(srcDir, 'features');
152
+ if (existsSync(featuresDir)) {
153
+ return 'features';
154
+ }
155
+ // Check for layered architecture
156
+ if (existsSync(join(srcDir, 'services')) && existsSync(join(srcDir, 'controllers'))) {
157
+ return 'layered';
158
+ }
159
+ // Check for modular structure
160
+ const modulesDir = join(srcDir, 'modules');
161
+ if (existsSync(modulesDir)) {
162
+ return 'modular';
163
+ }
164
+ // Check if flat (everything in one directory)
165
+ if (existsSync(srcDir)) {
166
+ try {
167
+ const entries = await readdir(srcDir, { withFileTypes: true });
168
+ const dirs = entries.filter((e) => e.isDirectory());
169
+ if (dirs.length <= 3) {
170
+ return 'flat';
171
+ }
172
+ }
173
+ catch {
174
+ // Ignore
175
+ }
176
+ }
177
+ return 'unknown';
178
+ }
179
+ /**
180
+ * Analyze feature modules
181
+ */
182
+ async analyzeFeatureModules(projectPath) {
183
+ const modules = [];
184
+ const featuresDir = join(projectPath, 'src', 'features');
185
+ const modulesDir = join(projectPath, 'src', 'modules');
186
+ const appDir = join(projectPath, 'app');
187
+ if (existsSync(featuresDir)) {
188
+ await this.scanFeaturesDirectory(featuresDir, modules);
189
+ }
190
+ else if (existsSync(modulesDir)) {
191
+ await this.scanFeaturesDirectory(modulesDir, modules);
192
+ }
193
+ else if (existsSync(appDir)) {
194
+ // Analyze app directory structure
195
+ await this.scanAppDirectory(appDir, modules);
196
+ }
197
+ return modules;
198
+ }
199
+ /**
200
+ * Scan features directory for feature modules
201
+ */
202
+ async scanFeaturesDirectory(dir, modules) {
203
+ try {
204
+ const entries = await readdir(dir, { withFileTypes: true });
205
+ for (const entry of entries) {
206
+ const fullPath = join(dir, entry.name);
207
+ if (entry.isDirectory()) {
208
+ // Skip common non-feature directories
209
+ if (['shared', 'common', 'lib', 'utils', 'components'].includes(entry.name)) {
210
+ continue;
211
+ }
212
+ const feature = await this.analyzeFeatureModule(fullPath, entry.name);
213
+ if (feature) {
214
+ modules.push(feature);
215
+ }
216
+ }
217
+ }
218
+ }
219
+ catch {
220
+ // Directory not accessible
221
+ }
222
+ }
223
+ /**
224
+ * Scan app directory for feature modules
225
+ */
226
+ async scanAppDirectory(dir, modules) {
227
+ try {
228
+ const entries = await readdir(dir, { withFileTypes: true });
229
+ for (const entry of entries) {
230
+ const fullPath = join(dir, entry.name);
231
+ if (entry.isDirectory()) {
232
+ if (entry.name.startsWith('(') && entry.name.endsWith(')')) {
233
+ // Next.js route group - treat as potential feature
234
+ const feature = await this.analyzeFeatureModule(fullPath, entry.name);
235
+ if (feature) {
236
+ modules.push(feature);
237
+ }
238
+ }
239
+ else {
240
+ await this.scanAppDirectory(fullPath, modules);
241
+ }
242
+ }
243
+ }
244
+ }
245
+ catch {
246
+ // Directory not accessible
247
+ }
248
+ }
249
+ /**
250
+ * Analyze a single feature module
251
+ */
252
+ async analyzeFeatureModule(modulePath, name) {
253
+ try {
254
+ const entries = await readdir(modulePath, { withFileTypes: true });
255
+ const feature = {
256
+ name,
257
+ path: relative(process.cwd(), modulePath),
258
+ hasComponents: false,
259
+ hasHooks: false,
260
+ hasServices: false,
261
+ hasTypes: false,
262
+ hasActions: false,
263
+ isolationScore: 0,
264
+ };
265
+ let hasFeatureFiles = 0;
266
+ let totalFeatureFiles = 0;
267
+ for (const entry of entries) {
268
+ const ext = extname(entry.name);
269
+ if (entry.isFile()) {
270
+ totalFeatureFiles++;
271
+ if (entry.name.includes('.test.') || entry.name.includes('.spec.')) {
272
+ // Test files are good
273
+ hasFeatureFiles++;
274
+ continue;
275
+ }
276
+ if (['.ts', '.tsx', '.js', '.jsx'].includes(ext)) {
277
+ try {
278
+ const content = await readFile(join(modulePath, entry.name), 'utf-8');
279
+ // Check for feature-specific patterns
280
+ if (/component|Component/.test(content) || entry.name.includes('component')) {
281
+ feature.hasComponents = true;
282
+ hasFeatureFiles++;
283
+ }
284
+ if (/use[A-Z]/.test(content) || entry.name.includes('hook') || entry.name.includes('use')) {
285
+ feature.hasHooks = true;
286
+ hasFeatureFiles++;
287
+ }
288
+ if (/service|Service/.test(content) || entry.name.includes('service')) {
289
+ feature.hasServices = true;
290
+ hasFeatureFiles++;
291
+ }
292
+ if (/interface|type/.test(content) || entry.name.endsWith('.types.ts') || entry.name.endsWith('.types.js')) {
293
+ feature.hasTypes = true;
294
+ hasFeatureFiles++;
295
+ }
296
+ if (/action|Action|server/.test(content)) {
297
+ feature.hasActions = true;
298
+ hasFeatureFiles++;
299
+ }
300
+ }
301
+ catch {
302
+ // Skip unreadable files
303
+ }
304
+ }
305
+ }
306
+ }
307
+ // Calculate isolation score based on self-contained files
308
+ feature.isolationScore = totalFeatureFiles > 0 ? hasFeatureFiles / totalFeatureFiles : 0;
309
+ return feature;
310
+ }
311
+ catch {
312
+ return null;
313
+ }
314
+ }
315
+ /**
316
+ * Analyze state management
317
+ */
318
+ async analyzeStateManagement(projectPath) {
319
+ try {
320
+ const pkgPath = join(projectPath, 'package.json');
321
+ const pkgContent = await readFile(pkgPath, 'utf-8');
322
+ const pkg = JSON.parse(pkgContent);
323
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
324
+ if ('@tanstack/react-query' in deps || '@tanstack/react-query' in deps) {
325
+ return 'tanstack-query';
326
+ }
327
+ if ('zustand' in deps) {
328
+ return 'zustand';
329
+ }
330
+ if ('@reduxjs/toolkit' in deps || 'redux' in deps) {
331
+ return 'redux';
332
+ }
333
+ // Check if using only React Context
334
+ const srcDir = join(projectPath, 'src');
335
+ if (existsSync(srcDir)) {
336
+ const hasContext = await this.directoryContainsPattern(srcDir, /createContext|useContext|Context\.Provider/);
337
+ if (hasContext) {
338
+ return 'context';
339
+ }
340
+ }
341
+ return 'local';
342
+ }
343
+ catch {
344
+ return 'unknown';
345
+ }
346
+ }
347
+ /**
348
+ * Check business rule consistency
349
+ */
350
+ async checkBusinessRuleConsistency(projectPath) {
351
+ // Check for consistent validation patterns
352
+ const srcDir = join(projectPath, 'src');
353
+ if (!existsSync(srcDir)) {
354
+ return 50; // Neutral score
355
+ }
356
+ let hasValidation = false;
357
+ let hasSchema = false;
358
+ let hasConstants = false;
359
+ await this.scanDirectoryForPatterns(srcDir, [
360
+ { pattern: /zod\.|Joi|yup\./, found: () => { hasValidation = true; } },
361
+ { pattern: /schema|Schema/i, found: () => { hasSchema = true; } },
362
+ { pattern: /const\s+[A-Z_]+\s*=/, found: () => { hasConstants = true; } },
363
+ ]);
364
+ let score = 0;
365
+ if (hasValidation)
366
+ score += 40;
367
+ if (hasSchema)
368
+ score += 30;
369
+ if (hasConstants)
370
+ score += 30;
371
+ return score;
372
+ }
373
+ /**
374
+ * Check edge case handling
375
+ */
376
+ async checkEdgeCaseHandlingPatterns(projectPath) {
377
+ const srcDir = join(projectPath, 'src');
378
+ const appDir = join(projectPath, 'app');
379
+ const dirsToCheck = [];
380
+ if (existsSync(srcDir))
381
+ dirsToCheck.push(srcDir);
382
+ if (existsSync(appDir))
383
+ dirsToCheck.push(appDir);
384
+ let edgeCasePatterns = 0;
385
+ let totalPatterns = 0;
386
+ const edgeCaseRegexes = [
387
+ /if\s*\(\s*!/,
388
+ /\|\|/,
389
+ /\?\?/,
390
+ /else\s*if/,
391
+ /try\s*{/,
392
+ /catch\s*\(/,
393
+ /throw\s+new/,
394
+ /\.default/,
395
+ /undefined/i,
396
+ /null/i,
397
+ ];
398
+ for (const dir of dirsToCheck) {
399
+ await this.scanDirectoryForEdgeCases(dir, (count) => {
400
+ edgeCasePatterns += count;
401
+ totalPatterns += edgeCaseRegexes.length;
402
+ });
403
+ }
404
+ if (totalPatterns === 0)
405
+ return 50;
406
+ return Math.min(100, (edgeCasePatterns / totalPatterns) * 100);
407
+ }
408
+ /**
409
+ * Scan directory for edge case patterns
410
+ */
411
+ async scanDirectoryForEdgeCases(dir, callback) {
412
+ try {
413
+ const entries = await readdir(dir, { withFileTypes: true });
414
+ for (const entry of entries) {
415
+ const fullPath = join(dir, entry.name);
416
+ if (entry.isDirectory()) {
417
+ if (!['node_modules', '.git', 'dist', 'build', 'coverage'].includes(entry.name)) {
418
+ await this.scanDirectoryForEdgeCases(fullPath, callback);
419
+ }
420
+ }
421
+ else if (entry.isFile()) {
422
+ const ext = extname(entry.name);
423
+ if (['.ts', '.tsx', '.js', '.jsx'].includes(ext)) {
424
+ try {
425
+ const content = await readFile(fullPath, 'utf-8');
426
+ let count = 0;
427
+ const edgeCaseRegexes = [
428
+ /if\s*\(\s*!/,
429
+ /\|\|/,
430
+ /\?\?/,
431
+ /else\s*if/,
432
+ /try\s*{/,
433
+ /catch\s*\(/,
434
+ ];
435
+ for (const regex of edgeCaseRegexes) {
436
+ if (regex.test(content)) {
437
+ count++;
438
+ }
439
+ }
440
+ callback(count);
441
+ }
442
+ catch {
443
+ // Skip unreadable files
444
+ }
445
+ }
446
+ }
447
+ }
448
+ }
449
+ catch {
450
+ // Directory not accessible
451
+ }
452
+ }
453
+ /**
454
+ * Check DDD patterns
455
+ */
456
+ async checkDddPatterns(projectPath) {
457
+ let score = 0;
458
+ const srcDir = join(projectPath, 'src');
459
+ if (!existsSync(srcDir)) {
460
+ return 0;
461
+ }
462
+ // Check for DDD directory structure
463
+ const dddDirs = ['domain', 'application', 'infrastructure', 'interfaces'];
464
+ for (const dddDir of dddDirs) {
465
+ if (existsSync(join(srcDir, dddDir))) {
466
+ score += 25;
467
+ }
468
+ }
469
+ return Math.min(100, score);
470
+ }
471
+ /**
472
+ * Scan directory for patterns
473
+ */
474
+ async scanDirectoryForPatterns(dir, patterns) {
475
+ try {
476
+ const entries = await readdir(dir, { withFileTypes: true });
477
+ for (const entry of entries) {
478
+ const fullPath = join(dir, entry.name);
479
+ if (entry.isDirectory()) {
480
+ if (!['node_modules', '.git', 'dist', 'build', 'coverage'].includes(entry.name)) {
481
+ await this.scanDirectoryForPatterns(fullPath, patterns);
482
+ }
483
+ }
484
+ else if (entry.isFile()) {
485
+ const ext = extname(entry.name);
486
+ if (['.ts', '.tsx', '.js', '.jsx'].includes(ext)) {
487
+ try {
488
+ const content = await readFile(fullPath, 'utf-8');
489
+ for (const { pattern, found } of patterns) {
490
+ if (pattern.test(content)) {
491
+ found();
492
+ break;
493
+ }
494
+ }
495
+ }
496
+ catch {
497
+ // Skip unreadable files
498
+ }
499
+ }
500
+ }
501
+ }
502
+ }
503
+ catch {
504
+ // Directory not accessible
505
+ }
506
+ }
507
+ /**
508
+ * Check if directory contains pattern
509
+ */
510
+ async directoryContainsPattern(dir, pattern) {
511
+ let found = false;
512
+ await this.scanDirectoryForPatterns(dir, [
513
+ { pattern, found: () => { found = true; } },
514
+ ]);
515
+ return found;
516
+ }
517
+ /**
518
+ * Calculate domain separation score
519
+ */
520
+ calculateDomainSeparationScore(structureType, featureModules) {
521
+ let score = 0;
522
+ // Base score from structure type
523
+ switch (structureType) {
524
+ case 'features':
525
+ score += 50;
526
+ break;
527
+ case 'layered':
528
+ score += 30;
529
+ break;
530
+ case 'modular':
531
+ score += 40;
532
+ break;
533
+ case 'flat':
534
+ score += 10;
535
+ break;
536
+ default:
537
+ score += 20;
538
+ }
539
+ // Bonus for well-structured feature modules
540
+ if (featureModules.length > 0) {
541
+ const avgIsolation = featureModules.reduce((sum, m) => sum + m.isolationScore, 0) / featureModules.length;
542
+ score += avgIsolation * 50;
543
+ }
544
+ return Math.min(100, score);
545
+ }
546
+ /**
547
+ * Calculate feature isolation score
548
+ */
549
+ calculateFeatureIsolation(featureModules) {
550
+ if (featureModules.length === 0)
551
+ return 0;
552
+ let totalIsolation = 0;
553
+ for (const module of featureModules) {
554
+ let hasAll = 0;
555
+ if (module.hasComponents)
556
+ hasAll++;
557
+ if (module.hasHooks)
558
+ hasAll++;
559
+ if (module.hasTypes)
560
+ hasAll++;
561
+ if (module.hasActions)
562
+ hasAll++;
563
+ totalIsolation += hasAll / 4;
564
+ }
565
+ return (totalIsolation / featureModules.length) * 100;
566
+ }
567
+ /**
568
+ * Calculate state management score
569
+ */
570
+ calculateStateManagementScore(stateManagement) {
571
+ const scores = {
572
+ 'tanstack-query': 100,
573
+ 'zustand': 90,
574
+ 'redux': 80,
575
+ 'context': 60,
576
+ 'local': 40,
577
+ 'unknown': 50,
578
+ };
579
+ return scores[stateManagement];
580
+ }
581
+ /**
582
+ * Identify business logic issues
583
+ */
584
+ identifyBusinessLogicIssues(metrics) {
585
+ const issues = [];
586
+ if (metrics.structureType === 'flat') {
587
+ issues.push({
588
+ severity: 'medium',
589
+ category: 'architecture',
590
+ description: 'Flat project structure detected - consider feature-based organization',
591
+ fixable: true,
592
+ suggestion: 'Organize code by features using the features/ pattern for better maintainability',
593
+ });
594
+ }
595
+ if (metrics.domainSeparation < 50) {
596
+ issues.push({
597
+ severity: 'medium',
598
+ category: 'architecture',
599
+ description: 'Poor domain separation - business logic mixed with UI',
600
+ fixable: true,
601
+ suggestion: 'Separate business logic into services and use feature-based organization',
602
+ });
603
+ }
604
+ if (metrics.ruleConsistency < 60) {
605
+ issues.push({
606
+ severity: 'low',
607
+ category: 'architecture',
608
+ description: 'Inconsistent business rule patterns detected',
609
+ fixable: true,
610
+ suggestion: 'Centralize validation rules and use schemas for consistent validation',
611
+ });
612
+ }
613
+ if (metrics.edgeCaseHandling < 50) {
614
+ issues.push({
615
+ severity: 'low',
616
+ category: 'error-handling',
617
+ description: 'Insufficient edge case handling detected',
618
+ fixable: true,
619
+ suggestion: 'Add proper null checks, error handling, and default values throughout the codebase',
620
+ });
621
+ }
622
+ if (metrics.stateManagement === 'local' && metrics.stateManagementScore < 50) {
623
+ issues.push({
624
+ severity: 'low',
625
+ category: 'architecture',
626
+ description: 'Only local state management detected - consider state management library for server data',
627
+ fixable: true,
628
+ suggestion: 'Use TanStack Query for server state and Zustand for client state',
629
+ });
630
+ }
631
+ return issues;
632
+ }
633
+ /**
634
+ * Generate business logic improvements
635
+ */
636
+ generateBusinessLogicImprovements(metrics) {
637
+ const improvements = [];
638
+ if (metrics.structureType === 'flat' || metrics.domainSeparation < 60) {
639
+ improvements.push({
640
+ type: 'refactor',
641
+ description: 'Reorganize code into feature-based modules',
642
+ effort: 'significant',
643
+ impact: 'high',
644
+ steps: [
645
+ 'Create features/ directory',
646
+ 'Group related components, hooks, and services by feature',
647
+ 'Create barrel exports for each feature',
648
+ 'Update imports to use feature paths',
649
+ ],
650
+ });
651
+ }
652
+ if (metrics.ruleConsistency < 70) {
653
+ improvements.push({
654
+ type: 'refactor',
655
+ description: 'Centralize business rules and validation',
656
+ effort: 'moderate',
657
+ impact: 'medium',
658
+ steps: [
659
+ 'Create schemas using Zod or similar',
660
+ 'Extract business rules into service functions',
661
+ 'Define constants for business values',
662
+ 'Create shared validation utilities',
663
+ ],
664
+ });
665
+ }
666
+ if (metrics.edgeCaseHandling < 60) {
667
+ improvements.push({
668
+ type: 'refactor',
669
+ description: 'Improve edge case handling',
670
+ effort: 'moderate',
671
+ impact: 'medium',
672
+ steps: [
673
+ 'Add null checks for all external data',
674
+ 'Implement proper error boundaries',
675
+ 'Use default values for optional props',
676
+ 'Handle loading and error states consistently',
677
+ ],
678
+ });
679
+ }
680
+ if (metrics.stateManagement === 'local') {
681
+ improvements.push({
682
+ type: 'refactor',
683
+ description: 'Implement appropriate state management strategy',
684
+ effort: 'moderate',
685
+ impact: 'medium',
686
+ steps: [
687
+ 'Use TanStack Query for server state',
688
+ 'Use Zustand for global client state',
689
+ 'Keep component-local state for UI-only state',
690
+ 'Avoid prop drilling with context or state library',
691
+ ],
692
+ });
693
+ }
694
+ improvements.push({
695
+ type: 'refactor',
696
+ description: 'Consider Domain-Driven Design patterns for complex business logic',
697
+ effort: 'major',
698
+ impact: 'medium',
699
+ steps: [
700
+ 'Identify bounded contexts in the application',
701
+ 'Create domain models with business logic',
702
+ 'Separate domain logic from application logic',
703
+ 'Implement repository patterns for data access',
704
+ ],
705
+ });
706
+ return improvements;
707
+ }
708
+ /**
709
+ * Calculate business logic score
710
+ */
711
+ calculateBusinessLogicScore(metrics) {
712
+ let score = 0;
713
+ // Domain separation (30 points)
714
+ score += (metrics.domainSeparation / 100) * 30;
715
+ // Business rule consistency (25 points)
716
+ score += (metrics.ruleConsistency / 100) * 25;
717
+ // Edge case handling (20 points)
718
+ score += (metrics.edgeCaseHandling / 100) * 20;
719
+ // State management (15 points)
720
+ score += (metrics.stateManagementScore / 100) * 15;
721
+ // Feature isolation (10 points)
722
+ score += (metrics.featureIsolation / 100) * 10;
723
+ return Math.min(100, score);
724
+ }
725
+ /**
726
+ * Count passed checks for metadata
727
+ */
728
+ countPassedChecks(metrics) {
729
+ let count = 0;
730
+ if (metrics.domainSeparation >= 70)
731
+ count++;
732
+ if (metrics.ruleConsistency >= 70)
733
+ count++;
734
+ if (metrics.edgeCaseHandling >= 60)
735
+ count++;
736
+ if (metrics.stateManagementScore >= 70)
737
+ count++;
738
+ if (metrics.featureIsolation >= 60)
739
+ count++;
740
+ return count;
741
+ }
742
+ }
743
+ /**
744
+ * Default analyzer instance
745
+ */
746
+ export const businessLogicAnalyzer = new BusinessLogicAnalyzer();
747
+ //# sourceMappingURL=business-logic.analyzer.js.map