@oalacea/daemon 0.6.4 → 0.7.0

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 (285) hide show
  1. package/README.md +268 -58
  2. package/bin/Dockerfile +158 -16
  3. package/dist/cli/cli.d.ts.map +1 -1
  4. package/dist/cli/cli.js +22 -2
  5. package/dist/cli/cli.js.map +1 -1
  6. package/dist/cli/commands/command.types.d.ts +216 -0
  7. package/dist/cli/commands/command.types.d.ts.map +1 -0
  8. package/dist/cli/commands/command.types.js +64 -0
  9. package/dist/cli/commands/command.types.js.map +1 -0
  10. package/dist/cli/commands/history.command.d.ts +91 -0
  11. package/dist/cli/commands/history.command.d.ts.map +1 -0
  12. package/dist/cli/commands/history.command.js +336 -0
  13. package/dist/cli/commands/history.command.js.map +1 -0
  14. package/dist/cli/commands/index.d.ts +14 -3
  15. package/dist/cli/commands/index.d.ts.map +1 -1
  16. package/dist/cli/commands/index.js +7 -0
  17. package/dist/cli/commands/index.js.map +1 -1
  18. package/dist/cli/commands/optimize.command.d.ts +110 -0
  19. package/dist/cli/commands/optimize.command.d.ts.map +1 -0
  20. package/dist/cli/commands/optimize.command.js +497 -0
  21. package/dist/cli/commands/optimize.command.js.map +1 -0
  22. package/dist/cli/commands/report.command.d.ts +110 -0
  23. package/dist/cli/commands/report.command.d.ts.map +1 -0
  24. package/dist/cli/commands/report.command.js +532 -0
  25. package/dist/cli/commands/report.command.js.map +1 -0
  26. package/dist/cli/commands/review.command.d.ts +110 -0
  27. package/dist/cli/commands/review.command.d.ts.map +1 -0
  28. package/dist/cli/commands/review.command.js +520 -0
  29. package/dist/cli/commands/review.command.js.map +1 -0
  30. package/dist/cli/commands/score.command.d.ts +47 -0
  31. package/dist/cli/commands/score.command.d.ts.map +1 -0
  32. package/dist/cli/commands/score.command.js +261 -0
  33. package/dist/cli/commands/score.command.js.map +1 -0
  34. package/dist/cli/utils/index.d.ts +10 -0
  35. package/dist/cli/utils/index.d.ts.map +1 -0
  36. package/dist/cli/utils/index.js +10 -0
  37. package/dist/cli/utils/index.js.map +1 -0
  38. package/dist/cli/utils/output.d.ts +192 -0
  39. package/dist/cli/utils/output.d.ts.map +1 -0
  40. package/dist/cli/utils/output.js +411 -0
  41. package/dist/cli/utils/output.js.map +1 -0
  42. package/dist/cli/utils/progress.d.ts +204 -0
  43. package/dist/cli/utils/progress.d.ts.map +1 -0
  44. package/dist/cli/utils/progress.js +396 -0
  45. package/dist/cli/utils/progress.js.map +1 -0
  46. package/dist/core/types/index.d.ts +1 -0
  47. package/dist/core/types/index.d.ts.map +1 -1
  48. package/dist/core/types/project.types.d.ts +3 -3
  49. package/dist/core/types/project.types.d.ts.map +1 -1
  50. package/dist/core/types/scoring.types.d.ts +301 -0
  51. package/dist/core/types/scoring.types.d.ts.map +1 -0
  52. package/dist/core/types/scoring.types.js +8 -0
  53. package/dist/core/types/scoring.types.js.map +1 -0
  54. package/dist/services/detection/framework-detector.d.ts.map +1 -1
  55. package/dist/services/detection/framework-detector.js +74 -5
  56. package/dist/services/detection/framework-detector.js.map +1 -1
  57. package/dist/services/index.d.ts +12 -0
  58. package/dist/services/index.d.ts.map +1 -1
  59. package/dist/services/index.js +14 -0
  60. package/dist/services/index.js.map +1 -1
  61. package/dist/services/optimization/detectors/bug-detector.d.ts +82 -0
  62. package/dist/services/optimization/detectors/bug-detector.d.ts.map +1 -0
  63. package/dist/services/optimization/detectors/bug-detector.js +443 -0
  64. package/dist/services/optimization/detectors/bug-detector.js.map +1 -0
  65. package/dist/services/optimization/detectors/code-smell-detector.d.ts +108 -0
  66. package/dist/services/optimization/detectors/code-smell-detector.d.ts.map +1 -0
  67. package/dist/services/optimization/detectors/code-smell-detector.js +569 -0
  68. package/dist/services/optimization/detectors/code-smell-detector.js.map +1 -0
  69. package/dist/services/optimization/detectors/index.d.ts +7 -0
  70. package/dist/services/optimization/detectors/index.d.ts.map +1 -0
  71. package/dist/services/optimization/detectors/index.js +7 -0
  72. package/dist/services/optimization/detectors/index.js.map +1 -0
  73. package/dist/services/optimization/detectors/perf-detector.d.ts +80 -0
  74. package/dist/services/optimization/detectors/perf-detector.d.ts.map +1 -0
  75. package/dist/services/optimization/detectors/perf-detector.js +451 -0
  76. package/dist/services/optimization/detectors/perf-detector.js.map +1 -0
  77. package/dist/services/optimization/index.d.ts +61 -0
  78. package/dist/services/optimization/index.d.ts.map +1 -0
  79. package/dist/services/optimization/index.js +69 -0
  80. package/dist/services/optimization/index.js.map +1 -0
  81. package/dist/services/optimization/optimization.service.d.ts +65 -0
  82. package/dist/services/optimization/optimization.service.d.ts.map +1 -0
  83. package/dist/services/optimization/optimization.service.js +511 -0
  84. package/dist/services/optimization/optimization.service.js.map +1 -0
  85. package/dist/services/optimization/optimization.types.d.ts +343 -0
  86. package/dist/services/optimization/optimization.types.d.ts.map +1 -0
  87. package/dist/services/optimization/optimization.types.js +8 -0
  88. package/dist/services/optimization/optimization.types.js.map +1 -0
  89. package/dist/services/optimization/optimizers/code-optimizer.d.ts +87 -0
  90. package/dist/services/optimization/optimizers/code-optimizer.d.ts.map +1 -0
  91. package/dist/services/optimization/optimizers/code-optimizer.js +436 -0
  92. package/dist/services/optimization/optimizers/code-optimizer.js.map +1 -0
  93. package/dist/services/optimization/optimizers/index.d.ts +7 -0
  94. package/dist/services/optimization/optimizers/index.d.ts.map +1 -0
  95. package/dist/services/optimization/optimizers/index.js +7 -0
  96. package/dist/services/optimization/optimizers/index.js.map +1 -0
  97. package/dist/services/optimization/optimizers/perf-optimizer.d.ts +64 -0
  98. package/dist/services/optimization/optimizers/perf-optimizer.d.ts.map +1 -0
  99. package/dist/services/optimization/optimizers/perf-optimizer.js +330 -0
  100. package/dist/services/optimization/optimizers/perf-optimizer.js.map +1 -0
  101. package/dist/services/optimization/optimizers/refact-optimizer.d.ts +82 -0
  102. package/dist/services/optimization/optimizers/refact-optimizer.d.ts.map +1 -0
  103. package/dist/services/optimization/optimizers/refact-optimizer.js +354 -0
  104. package/dist/services/optimization/optimizers/refact-optimizer.js.map +1 -0
  105. package/dist/services/optimization/patterns/anti-patterns.d.ts +31 -0
  106. package/dist/services/optimization/patterns/anti-patterns.d.ts.map +1 -0
  107. package/dist/services/optimization/patterns/anti-patterns.js +501 -0
  108. package/dist/services/optimization/patterns/anti-patterns.js.map +1 -0
  109. package/dist/services/optimization/patterns/index.d.ts +5 -0
  110. package/dist/services/optimization/patterns/index.d.ts.map +1 -0
  111. package/dist/services/optimization/patterns/index.js +5 -0
  112. package/dist/services/optimization/patterns/index.js.map +1 -0
  113. package/dist/services/reporting/export/chart.exporter.d.ts +59 -0
  114. package/dist/services/reporting/export/chart.exporter.d.ts.map +1 -0
  115. package/dist/services/reporting/export/chart.exporter.js +350 -0
  116. package/dist/services/reporting/export/chart.exporter.js.map +1 -0
  117. package/dist/services/reporting/export/index.d.ts +9 -0
  118. package/dist/services/reporting/export/index.d.ts.map +1 -0
  119. package/dist/services/reporting/export/index.js +10 -0
  120. package/dist/services/reporting/export/index.js.map +1 -0
  121. package/dist/services/reporting/export/pdf.exporter.d.ts +133 -0
  122. package/dist/services/reporting/export/pdf.exporter.d.ts.map +1 -0
  123. package/dist/services/reporting/export/pdf.exporter.js +270 -0
  124. package/dist/services/reporting/export/pdf.exporter.js.map +1 -0
  125. package/dist/services/reporting/history.service.d.ts +93 -0
  126. package/dist/services/reporting/history.service.d.ts.map +1 -0
  127. package/dist/services/reporting/history.service.js +285 -0
  128. package/dist/services/reporting/history.service.js.map +1 -0
  129. package/dist/services/reporting/index.d.ts +15 -0
  130. package/dist/services/reporting/index.d.ts.map +1 -0
  131. package/dist/services/reporting/index.js +16 -0
  132. package/dist/services/reporting/index.js.map +1 -0
  133. package/dist/services/reporting/report.service.d.ts +102 -0
  134. package/dist/services/reporting/report.service.d.ts.map +1 -0
  135. package/dist/services/reporting/report.service.js +240 -0
  136. package/dist/services/reporting/report.service.js.map +1 -0
  137. package/dist/services/reporting/reporting.types.d.ts +329 -0
  138. package/dist/services/reporting/reporting.types.d.ts.map +1 -0
  139. package/dist/services/reporting/reporting.types.js +8 -0
  140. package/dist/services/reporting/reporting.types.js.map +1 -0
  141. package/dist/services/reporting/templates/html.template.d.ts +81 -0
  142. package/dist/services/reporting/templates/html.template.d.ts.map +1 -0
  143. package/dist/services/reporting/templates/html.template.js +741 -0
  144. package/dist/services/reporting/templates/html.template.js.map +1 -0
  145. package/dist/services/reporting/templates/json.template.d.ts +85 -0
  146. package/dist/services/reporting/templates/json.template.d.ts.map +1 -0
  147. package/dist/services/reporting/templates/json.template.js +308 -0
  148. package/dist/services/reporting/templates/json.template.js.map +1 -0
  149. package/dist/services/reporting/templates/markdown.template.d.ts +69 -0
  150. package/dist/services/reporting/templates/markdown.template.d.ts.map +1 -0
  151. package/dist/services/reporting/templates/markdown.template.js +311 -0
  152. package/dist/services/reporting/templates/markdown.template.js.map +1 -0
  153. package/dist/services/reporting/trend-analyzer.d.ts +73 -0
  154. package/dist/services/reporting/trend-analyzer.d.ts.map +1 -0
  155. package/dist/services/reporting/trend-analyzer.js +291 -0
  156. package/dist/services/reporting/trend-analyzer.js.map +1 -0
  157. package/dist/services/review/analyzers/dependency-analyzer.d.ts +87 -0
  158. package/dist/services/review/analyzers/dependency-analyzer.d.ts.map +1 -0
  159. package/dist/services/review/analyzers/dependency-analyzer.js +458 -0
  160. package/dist/services/review/analyzers/dependency-analyzer.js.map +1 -0
  161. package/dist/services/review/analyzers/index.d.ts +13 -0
  162. package/dist/services/review/analyzers/index.d.ts.map +1 -0
  163. package/dist/services/review/analyzers/index.js +13 -0
  164. package/dist/services/review/analyzers/index.js.map +1 -0
  165. package/dist/services/review/analyzers/nestjs-analyzer.d.ts +210 -0
  166. package/dist/services/review/analyzers/nestjs-analyzer.d.ts.map +1 -0
  167. package/dist/services/review/analyzers/nestjs-analyzer.js +571 -0
  168. package/dist/services/review/analyzers/nestjs-analyzer.js.map +1 -0
  169. package/dist/services/review/analyzers/performance-analyzer.d.ts +91 -0
  170. package/dist/services/review/analyzers/performance-analyzer.d.ts.map +1 -0
  171. package/dist/services/review/analyzers/performance-analyzer.js +589 -0
  172. package/dist/services/review/analyzers/performance-analyzer.js.map +1 -0
  173. package/dist/services/review/analyzers/security-analyzer.d.ts +96 -0
  174. package/dist/services/review/analyzers/security-analyzer.d.ts.map +1 -0
  175. package/dist/services/review/analyzers/security-analyzer.js +512 -0
  176. package/dist/services/review/analyzers/security-analyzer.js.map +1 -0
  177. package/dist/services/review/analyzers/static-analyzer.d.ts +90 -0
  178. package/dist/services/review/analyzers/static-analyzer.d.ts.map +1 -0
  179. package/dist/services/review/analyzers/static-analyzer.js +423 -0
  180. package/dist/services/review/analyzers/static-analyzer.js.map +1 -0
  181. package/dist/services/review/fixers/auto-fixer.d.ts +94 -0
  182. package/dist/services/review/fixers/auto-fixer.d.ts.map +1 -0
  183. package/dist/services/review/fixers/auto-fixer.js +404 -0
  184. package/dist/services/review/fixers/auto-fixer.js.map +1 -0
  185. package/dist/services/review/fixers/index.d.ts +11 -0
  186. package/dist/services/review/fixers/index.d.ts.map +1 -0
  187. package/dist/services/review/fixers/index.js +11 -0
  188. package/dist/services/review/fixers/index.js.map +1 -0
  189. package/dist/services/review/fixers/refactor-suggester.d.ts +100 -0
  190. package/dist/services/review/fixers/refactor-suggester.d.ts.map +1 -0
  191. package/dist/services/review/fixers/refactor-suggester.js +555 -0
  192. package/dist/services/review/fixers/refactor-suggester.js.map +1 -0
  193. package/dist/services/review/fixers/test-generator.d.ts +99 -0
  194. package/dist/services/review/fixers/test-generator.d.ts.map +1 -0
  195. package/dist/services/review/fixers/test-generator.js +458 -0
  196. package/dist/services/review/fixers/test-generator.js.map +1 -0
  197. package/dist/services/review/index.d.ts +14 -0
  198. package/dist/services/review/index.d.ts.map +1 -0
  199. package/dist/services/review/index.js +14 -0
  200. package/dist/services/review/index.js.map +1 -0
  201. package/dist/services/review/reporters/fix-reporter.d.ts +67 -0
  202. package/dist/services/review/reporters/fix-reporter.d.ts.map +1 -0
  203. package/dist/services/review/reporters/fix-reporter.js +437 -0
  204. package/dist/services/review/reporters/fix-reporter.js.map +1 -0
  205. package/dist/services/review/reporters/index.d.ts +10 -0
  206. package/dist/services/review/reporters/index.d.ts.map +1 -0
  207. package/dist/services/review/reporters/index.js +10 -0
  208. package/dist/services/review/reporters/index.js.map +1 -0
  209. package/dist/services/review/reporters/score-reporter.d.ts +84 -0
  210. package/dist/services/review/reporters/score-reporter.d.ts.map +1 -0
  211. package/dist/services/review/reporters/score-reporter.js +560 -0
  212. package/dist/services/review/reporters/score-reporter.js.map +1 -0
  213. package/dist/services/review/review.service.d.ts +129 -0
  214. package/dist/services/review/review.service.d.ts.map +1 -0
  215. package/dist/services/review/review.service.js +396 -0
  216. package/dist/services/review/review.service.js.map +1 -0
  217. package/dist/services/review/review.types.d.ts +443 -0
  218. package/dist/services/review/review.types.d.ts.map +1 -0
  219. package/dist/services/review/review.types.js +11 -0
  220. package/dist/services/review/review.types.js.map +1 -0
  221. package/dist/services/scoring/dimensions/accessibility.analyzer.d.ts +53 -0
  222. package/dist/services/scoring/dimensions/accessibility.analyzer.d.ts.map +1 -0
  223. package/dist/services/scoring/dimensions/accessibility.analyzer.js +260 -0
  224. package/dist/services/scoring/dimensions/accessibility.analyzer.js.map +1 -0
  225. package/dist/services/scoring/dimensions/backend-logic.analyzer.d.ts +138 -0
  226. package/dist/services/scoring/dimensions/backend-logic.analyzer.d.ts.map +1 -0
  227. package/dist/services/scoring/dimensions/backend-logic.analyzer.js +713 -0
  228. package/dist/services/scoring/dimensions/backend-logic.analyzer.js.map +1 -0
  229. package/dist/services/scoring/dimensions/business-logic.analyzer.d.ts +142 -0
  230. package/dist/services/scoring/dimensions/business-logic.analyzer.d.ts.map +1 -0
  231. package/dist/services/scoring/dimensions/business-logic.analyzer.js +747 -0
  232. package/dist/services/scoring/dimensions/business-logic.analyzer.js.map +1 -0
  233. package/dist/services/scoring/dimensions/code-quality.analyzer.d.ts +142 -0
  234. package/dist/services/scoring/dimensions/code-quality.analyzer.d.ts.map +1 -0
  235. package/dist/services/scoring/dimensions/code-quality.analyzer.js +685 -0
  236. package/dist/services/scoring/dimensions/code-quality.analyzer.js.map +1 -0
  237. package/dist/services/scoring/dimensions/index.d.ts +18 -0
  238. package/dist/services/scoring/dimensions/index.d.ts.map +1 -0
  239. package/dist/services/scoring/dimensions/index.js +27 -0
  240. package/dist/services/scoring/dimensions/index.js.map +1 -0
  241. package/dist/services/scoring/dimensions/performance.analyzer.d.ts +125 -0
  242. package/dist/services/scoring/dimensions/performance.analyzer.d.ts.map +1 -0
  243. package/dist/services/scoring/dimensions/performance.analyzer.js +615 -0
  244. package/dist/services/scoring/dimensions/performance.analyzer.js.map +1 -0
  245. package/dist/services/scoring/dimensions/security.analyzer.d.ts +53 -0
  246. package/dist/services/scoring/dimensions/security.analyzer.d.ts.map +1 -0
  247. package/dist/services/scoring/dimensions/security.analyzer.js +327 -0
  248. package/dist/services/scoring/dimensions/security.analyzer.js.map +1 -0
  249. package/dist/services/scoring/dimensions/seo.analyzer.d.ts +77 -0
  250. package/dist/services/scoring/dimensions/seo.analyzer.d.ts.map +1 -0
  251. package/dist/services/scoring/dimensions/seo.analyzer.js +502 -0
  252. package/dist/services/scoring/dimensions/seo.analyzer.js.map +1 -0
  253. package/dist/services/scoring/dimensions/test-coverage.analyzer.d.ts +106 -0
  254. package/dist/services/scoring/dimensions/test-coverage.analyzer.d.ts.map +1 -0
  255. package/dist/services/scoring/dimensions/test-coverage.analyzer.js +496 -0
  256. package/dist/services/scoring/dimensions/test-coverage.analyzer.js.map +1 -0
  257. package/dist/services/scoring/dimensions/ui-ux.analyzer.d.ts +126 -0
  258. package/dist/services/scoring/dimensions/ui-ux.analyzer.d.ts.map +1 -0
  259. package/dist/services/scoring/dimensions/ui-ux.analyzer.js +665 -0
  260. package/dist/services/scoring/dimensions/ui-ux.analyzer.js.map +1 -0
  261. package/dist/services/scoring/index.d.ts +10 -0
  262. package/dist/services/scoring/index.d.ts.map +1 -0
  263. package/dist/services/scoring/index.js +10 -0
  264. package/dist/services/scoring/index.js.map +1 -0
  265. package/dist/services/scoring/scoring-service.d.ts +222 -0
  266. package/dist/services/scoring/scoring-service.d.ts.map +1 -0
  267. package/dist/services/scoring/scoring-service.js +636 -0
  268. package/dist/services/scoring/scoring-service.js.map +1 -0
  269. package/package.json +11 -3
  270. package/templates/README.md +183 -0
  271. package/templates/nestjs/controller.spec.ts +203 -0
  272. package/templates/nestjs/e2e/api.e2e-spec.ts +451 -0
  273. package/templates/nestjs/e2e/auth.e2e-spec.ts +533 -0
  274. package/templates/nestjs/fixtures/test-module.ts +311 -0
  275. package/templates/nestjs/guard.spec.ts +314 -0
  276. package/templates/nestjs/interceptor.spec.ts +458 -0
  277. package/templates/nestjs/module.spec.ts +173 -0
  278. package/templates/nestjs/pipe.spec.ts +474 -0
  279. package/templates/nestjs/service.spec.ts +296 -0
  280. package/templates/rust/Cargo.toml +72 -0
  281. package/templates/rust/actix-controller.test.rs +114 -0
  282. package/templates/rust/axum-handler.test.rs +117 -0
  283. package/templates/rust/integration.test.rs +63 -0
  284. package/templates/rust/rocket-route.test.rs +106 -0
  285. package/templates/rust/unit.test.rs +38 -0
@@ -0,0 +1,713 @@
1
+ /**
2
+ * Backend Logic Analyzer
3
+ *
4
+ * Analyzes backend code quality including API design, error handling consistency,
5
+ * input validation, rate limiting, and caching strategy.
6
+ *
7
+ * @module services/scoring/dimensions/backend-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
+ * Backend Logic Analyzer
16
+ *
17
+ * Evaluates backend code quality across multiple dimensions:
18
+ * - API design (REST conventions, status codes)
19
+ * - Error handling consistency
20
+ * - Input validation
21
+ * - Rate limiting presence
22
+ * - Caching strategy
23
+ */
24
+ export class BackendLogicAnalyzer {
25
+ /** Analyzer configuration */
26
+ config = {
27
+ dimension: 'backend-logic',
28
+ defaultWeight: 0.10,
29
+ estimatedDuration: 25000,
30
+ supportedFrameworks: ['NestJS', 'Express', 'Fastify', 'Hono', 'Koa', 'Next.js'],
31
+ };
32
+ logger;
33
+ executor;
34
+ checkApiRoutesFlag;
35
+ checkErrorHandlingFlag;
36
+ checkInputValidationFlag;
37
+ checkRateLimitingFlag;
38
+ checkCachingFlag;
39
+ constructor(options = {}) {
40
+ this.logger = createLogger('BackendLogicAnalyzer');
41
+ this.executor = new CommandExecutor();
42
+ this.checkApiRoutesFlag = options.checkApiRoutes ?? true;
43
+ this.checkErrorHandlingFlag = options.checkErrorHandling ?? true;
44
+ this.checkInputValidationFlag = options.checkInputValidation ?? true;
45
+ this.checkRateLimitingFlag = options.checkRateLimiting ?? true;
46
+ this.checkCachingFlag = options.checkCaching ?? true;
47
+ }
48
+ /**
49
+ * Get the dimension this analyzer handles
50
+ */
51
+ getDimension() {
52
+ return 'backend-logic';
53
+ }
54
+ /**
55
+ * Get the default weight for this dimension
56
+ */
57
+ getWeight() {
58
+ return 0.15; // 15% weight in overall score
59
+ }
60
+ /**
61
+ * Analyze backend logic for a project
62
+ *
63
+ * @param projectPath - Path to the project root
64
+ * @param _framework - Detected framework (optional, for framework-specific analysis)
65
+ * @param _options - Scoring options (optional)
66
+ * @returns Dimension score with backend metrics
67
+ */
68
+ async analyze(projectPath, _framework, _options) {
69
+ const startTime = performance.now();
70
+ this.logger.info(`Analyzing backend logic for: ${projectPath}`);
71
+ const issues = [];
72
+ const improvements = [];
73
+ try {
74
+ // Detect backend framework
75
+ const framework = await this.detectBackendFramework(projectPath);
76
+ // Skip if no backend detected
77
+ if (framework === 'unknown') {
78
+ return this.createNoBackendResult(issues, improvements);
79
+ }
80
+ // Analyze API routes
81
+ const apiRoutes = this.checkApiRoutesFlag ? await this.analyzeApiRoutes(projectPath, framework) : [];
82
+ // Check error handling
83
+ const errorHandling = this.checkErrorHandlingFlag ? await this.checkErrorHandling(projectPath, framework) : { hasErrorHandling: false, consistent: false };
84
+ // Check input validation
85
+ const inputValidation = this.checkInputValidationFlag ? await this.checkInputValidation(projectPath, framework) : { hasValidation: false, coverage: 0 };
86
+ // Check rate limiting
87
+ const rateLimiting = this.checkRateLimitingFlag ? await this.checkRateLimiting(projectPath, framework) : { hasRateLimiting: false };
88
+ // Check caching
89
+ const caching = this.checkCachingFlag ? await this.checkCaching(projectPath, framework) : { hasCaching: false, strategy: null };
90
+ // Check API versioning
91
+ const apiVersioning = await this.checkApiVersioning(projectPath, framework);
92
+ const metrics = {
93
+ framework,
94
+ restfulAdherence: this.calculateRestfulAdherence(apiRoutes),
95
+ consistentStatusCodes: this.checkConsistentStatusCodes(apiRoutes),
96
+ hasErrorHandling: errorHandling.hasErrorHandling,
97
+ routesWithErrorHandling: apiRoutes.filter((r) => r.hasErrorHandling).length,
98
+ totalRoutes: apiRoutes.length,
99
+ hasInputValidation: inputValidation.hasValidation,
100
+ routesWithValidation: apiRoutes.filter((r) => r.hasValidation).length,
101
+ hasRateLimiting: rateLimiting.hasRateLimiting,
102
+ hasCaching: caching.hasCaching,
103
+ hasApiVersioning: apiVersioning,
104
+ };
105
+ // Build issues list
106
+ issues.push(...this.identifyBackendIssues(metrics));
107
+ // Build improvements list
108
+ improvements.push(...this.generateBackendImprovements(metrics));
109
+ // Calculate final score
110
+ const score = this.calculateBackendScore(metrics);
111
+ const duration = Math.round(performance.now() - startTime);
112
+ return {
113
+ dimension: this.getDimension(),
114
+ score,
115
+ weight: this.getWeight(),
116
+ weightedScore: score * this.getWeight(),
117
+ issues,
118
+ improvements,
119
+ metadata: {
120
+ itemsChecked: metrics.totalRoutes + 5,
121
+ itemsPassed: this.countPassedChecks(metrics),
122
+ metrics: {
123
+ framework: metrics.framework,
124
+ restfulAdherence: metrics.restfulAdherence,
125
+ consistentStatusCodes: metrics.consistentStatusCodes ? 1 : 0,
126
+ routesWithErrorHandling: metrics.routesWithErrorHandling,
127
+ totalRoutes: metrics.totalRoutes,
128
+ routesWithValidation: metrics.routesWithValidation,
129
+ hasRateLimiting: metrics.hasRateLimiting ? 1 : 0,
130
+ hasCaching: metrics.hasCaching ? 1 : 0,
131
+ hasApiVersioning: metrics.hasApiVersioning ? 1 : 0,
132
+ },
133
+ },
134
+ };
135
+ }
136
+ catch (error) {
137
+ this.logger.error('Error analyzing backend logic', error);
138
+ issues.push({
139
+ severity: 'medium',
140
+ category: 'architecture',
141
+ description: `Failed to analyze backend logic: ${error instanceof Error ? error.message : String(error)}`,
142
+ fixable: false,
143
+ });
144
+ const duration = Math.round(performance.now() - startTime);
145
+ return {
146
+ dimension: this.getDimension(),
147
+ score: 50,
148
+ weight: this.getWeight(),
149
+ weightedScore: 50 * this.getWeight(),
150
+ issues,
151
+ improvements,
152
+ metadata: { error: String(error) },
153
+ };
154
+ }
155
+ }
156
+ /**
157
+ * Detect backend framework
158
+ */
159
+ async detectBackendFramework(projectPath) {
160
+ try {
161
+ const pkgPath = join(projectPath, 'package.json');
162
+ const pkgContent = await readFile(pkgPath, 'utf-8');
163
+ const pkg = JSON.parse(pkgContent);
164
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
165
+ if ('@nestjs/core' in deps)
166
+ return 'nest';
167
+ if ('express' in deps)
168
+ return 'express';
169
+ if ('fastify' in deps)
170
+ return 'fastify';
171
+ if ('koa' in deps)
172
+ return 'koa';
173
+ if ('hono' in deps)
174
+ return 'hono';
175
+ // Check for Next.js API routes
176
+ if (existsSync(join(projectPath, 'pages', 'api')) || existsSync(join(projectPath, 'app', 'api'))) {
177
+ return 'next-api';
178
+ }
179
+ return 'unknown';
180
+ }
181
+ catch {
182
+ return 'unknown';
183
+ }
184
+ }
185
+ /**
186
+ * Analyze API routes
187
+ */
188
+ async analyzeApiRoutes(projectPath, framework) {
189
+ const routes = [];
190
+ const apiDirs = [
191
+ join(projectPath, 'pages', 'api'),
192
+ join(projectPath, 'app', 'api'),
193
+ join(projectPath, 'src', 'api'),
194
+ join(projectPath, 'api'),
195
+ join(projectPath, 'src', 'routes'),
196
+ join(projectPath, 'routes'),
197
+ ];
198
+ for (const apiDir of apiDirs) {
199
+ if (!existsSync(apiDir))
200
+ continue;
201
+ await this.scanDirectoryForApiRoutes(apiDir, routes, framework);
202
+ }
203
+ return routes;
204
+ }
205
+ /**
206
+ * Scan directory for API routes
207
+ */
208
+ async scanDirectoryForApiRoutes(dir, routes, framework) {
209
+ try {
210
+ const entries = await readdir(dir, { withFileTypes: true });
211
+ for (const entry of entries) {
212
+ const fullPath = join(dir, entry.name);
213
+ if (entry.isDirectory()) {
214
+ await this.scanDirectoryForApiRoutes(fullPath, routes, framework);
215
+ }
216
+ else if (entry.isFile()) {
217
+ const ext = extname(entry.name);
218
+ if (['.ts', '.tsx', '.js', '.jsx'].includes(ext)) {
219
+ const routeInfo = await this.analyzeApiFile(fullPath, framework);
220
+ if (routeInfo) {
221
+ routes.push(routeInfo);
222
+ }
223
+ }
224
+ }
225
+ }
226
+ }
227
+ catch {
228
+ // Directory not accessible
229
+ }
230
+ }
231
+ /**
232
+ * Analyze a single API file
233
+ */
234
+ async analyzeApiFile(filepath, framework) {
235
+ try {
236
+ const content = await readFile(filepath, 'utf-8');
237
+ const relativePath = relative(process.cwd(), filepath);
238
+ // Detect HTTP methods
239
+ const methods = [];
240
+ if (/export\s+(?:const|function|async\s+function)\s+(GET|get|HEAD|head|POST|post|PUT|put|DELETE|delete|PATCH|patch)/.test(content)) {
241
+ const match = content.match(/(?:export\s+(?:const|function|async\s+function)\s+)(GET|get|HEAD|head|POST|post|PUT|put|DELETE|delete|PATCH|patch)/);
242
+ if (match)
243
+ methods.push(match[1].toUpperCase());
244
+ }
245
+ if (framework === 'next-api') {
246
+ if (/export\s+(?:const|async\s+function)\s+default/.test(content)) {
247
+ methods.push('GET'); // Default export for Next.js API routes
248
+ if (content.includes('export const POST'))
249
+ methods.push('POST');
250
+ }
251
+ }
252
+ // Check for error handling
253
+ const hasErrorHandling = /try\s*{/.test(content) ||
254
+ /catch\s*\(/.test(content) ||
255
+ /\.catch\(/.test(content) ||
256
+ /error/i.test(content);
257
+ // Check for validation
258
+ const hasValidation = /zod/i.test(content) ||
259
+ /joi/i.test(content) ||
260
+ /yup/i.test(content) ||
261
+ /validation/i.test(content) ||
262
+ /schema/i.test(content);
263
+ // Extract status code
264
+ const statusCodeMatch = content.match(/status\((\d+)\)/);
265
+ const statusCode = statusCodeMatch ? parseInt(statusCodeMatch[1], 10) : null;
266
+ return {
267
+ method: methods[0] || 'GET',
268
+ path: relativePath,
269
+ file: relativePath,
270
+ hasErrorHandling,
271
+ hasValidation,
272
+ hasRateLimit: content.includes('rate') || content.includes('throttle'),
273
+ statusCode,
274
+ };
275
+ }
276
+ catch {
277
+ return null;
278
+ }
279
+ }
280
+ /**
281
+ * Check error handling patterns
282
+ */
283
+ async checkErrorHandling(projectPath, framework) {
284
+ // Analyze consistency of error handling across routes
285
+ const apiRoutes = await this.analyzeApiRoutes(projectPath, framework);
286
+ if (apiRoutes.length === 0) {
287
+ return { hasErrorHandling: false, consistent: false };
288
+ }
289
+ const routesWithErrorHandling = apiRoutes.filter((r) => r.hasErrorHandling).length;
290
+ const hasErrorHandling = routesWithErrorHandling > 0;
291
+ const consistent = routesWithErrorHandling === apiRoutes.length;
292
+ return { hasErrorHandling, consistent };
293
+ }
294
+ /**
295
+ * Check input validation
296
+ */
297
+ async checkInputValidation(projectPath, framework) {
298
+ const apiRoutes = await this.analyzeApiRoutes(projectPath, framework);
299
+ if (apiRoutes.length === 0) {
300
+ return { hasValidation: false, coverage: 0 };
301
+ }
302
+ const routesWithValidation = apiRoutes.filter((r) => r.hasValidation).length;
303
+ const hasValidation = routesWithValidation > 0;
304
+ const coverage = routesWithValidation / apiRoutes.length;
305
+ return { hasValidation, coverage };
306
+ }
307
+ /**
308
+ * Check rate limiting
309
+ */
310
+ async checkRateLimiting(projectPath, framework) {
311
+ // Check for rate limiting middleware or configuration
312
+ const rateLimitPatterns = [
313
+ /rate-limit/i,
314
+ /express-rate-limit/i,
315
+ /rateLimit/i,
316
+ /throttle/i,
317
+ /x-ratelimit/i,
318
+ ];
319
+ // Check package.json for rate limiting dependencies
320
+ try {
321
+ const pkgPath = join(projectPath, 'package.json');
322
+ const pkgContent = await readFile(pkgPath, 'utf-8');
323
+ const pkg = JSON.parse(pkgContent);
324
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
325
+ for (const dep of Object.keys(deps)) {
326
+ if (rateLimitPatterns.some((p) => p.test(dep))) {
327
+ return { hasRateLimiting: true };
328
+ }
329
+ }
330
+ }
331
+ catch {
332
+ // Ignore
333
+ }
334
+ // Check API routes for rate limiting usage
335
+ const apiRoutes = await this.analyzeApiRoutes(projectPath, framework);
336
+ const hasRateLimiting = apiRoutes.some((r) => r.hasRateLimit);
337
+ return { hasRateLimiting };
338
+ }
339
+ /**
340
+ * Check caching strategy
341
+ */
342
+ async checkCaching(projectPath, framework) {
343
+ const cachePatterns = [
344
+ /cache/i,
345
+ /redis/i,
346
+ /memcached/i,
347
+ /swr/i,
348
+ /stale-while-revalidate/i,
349
+ ];
350
+ // Check Next.js caching (ISR, revalidate)
351
+ if (framework === 'next-api') {
352
+ try {
353
+ const appDir = join(projectPath, 'app');
354
+ const pagesDir = join(projectPath, 'pages');
355
+ if (existsSync(appDir)) {
356
+ // Check for revalidate in route files
357
+ const hasRevalidate = await this.directoryContainsPattern(appDir, /revalidate/i);
358
+ if (hasRevalidate) {
359
+ return { hasCaching: true, strategy: 'ISR' };
360
+ }
361
+ }
362
+ }
363
+ catch {
364
+ // Ignore
365
+ }
366
+ }
367
+ // Check package.json for caching dependencies
368
+ try {
369
+ const pkgPath = join(projectPath, 'package.json');
370
+ const pkgContent = await readFile(pkgPath, 'utf-8');
371
+ const pkg = JSON.parse(pkgContent);
372
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
373
+ for (const dep of Object.keys(deps)) {
374
+ if (cachePatterns.some((p) => p.test(dep))) {
375
+ return { hasCaching: true, strategy: dep };
376
+ }
377
+ }
378
+ }
379
+ catch {
380
+ // Ignore
381
+ }
382
+ return { hasCaching: false, strategy: null };
383
+ }
384
+ /**
385
+ * Check if directory contains pattern
386
+ */
387
+ async directoryContainsPattern(dir, pattern) {
388
+ try {
389
+ const entries = await readdir(dir, { withFileTypes: true });
390
+ for (const entry of entries) {
391
+ const fullPath = join(dir, entry.name);
392
+ if (entry.isDirectory()) {
393
+ if (!['node_modules', '.git', 'dist', 'build'].includes(entry.name)) {
394
+ if (await this.directoryContainsPattern(fullPath, pattern)) {
395
+ return true;
396
+ }
397
+ }
398
+ }
399
+ else if (entry.isFile()) {
400
+ const ext = extname(entry.name);
401
+ if (['.ts', '.tsx', '.js', '.jsx'].includes(ext)) {
402
+ try {
403
+ const content = await readFile(fullPath, 'utf-8');
404
+ if (pattern.test(content)) {
405
+ return true;
406
+ }
407
+ }
408
+ catch {
409
+ // Skip unreadable files
410
+ }
411
+ }
412
+ }
413
+ }
414
+ }
415
+ catch {
416
+ // Directory not accessible
417
+ }
418
+ return false;
419
+ }
420
+ /**
421
+ * Check API versioning
422
+ */
423
+ async checkApiVersioning(projectPath, framework) {
424
+ const versionPatterns = [
425
+ /\/v\d+\//,
426
+ /\/api\/v\d+/,
427
+ /version.*:?/i,
428
+ ];
429
+ const apiDirs = [
430
+ join(projectPath, 'app', 'api'),
431
+ join(projectPath, 'pages', 'api'),
432
+ join(projectPath, 'src', 'api'),
433
+ join(projectPath, 'api'),
434
+ ];
435
+ for (const apiDir of apiDirs) {
436
+ if (!existsSync(apiDir))
437
+ continue;
438
+ const hasVersioning = await this.directoryContainsPattern(apiDir, /\/v\d+/);
439
+ if (hasVersioning) {
440
+ return true;
441
+ }
442
+ }
443
+ return false;
444
+ }
445
+ /**
446
+ * Calculate RESTful adherence score
447
+ */
448
+ calculateRestfulAdherence(routes) {
449
+ if (routes.length === 0)
450
+ return 0;
451
+ let score = 0;
452
+ let maxScore = 0;
453
+ for (const route of routes) {
454
+ maxScore += 10;
455
+ // Proper HTTP method usage (5 points)
456
+ if (['GET', 'POST', 'PUT', 'DELETE', 'PATCH'].includes(route.method)) {
457
+ score += 5;
458
+ }
459
+ // Proper status codes (3 points)
460
+ if (route.statusCode) {
461
+ if (route.method === 'GET' && route.statusCode === 200)
462
+ score += 3;
463
+ if (route.method === 'POST' && route.statusCode === 201)
464
+ score += 3;
465
+ if (route.method === 'DELETE' && (route.statusCode === 204 || route.statusCode === 200))
466
+ score += 3;
467
+ if (route.method === 'PUT' && route.statusCode === 200)
468
+ score += 3;
469
+ }
470
+ // Error handling (2 points)
471
+ if (route.hasErrorHandling) {
472
+ score += 2;
473
+ }
474
+ }
475
+ return maxScore > 0 ? (score / maxScore) * 100 : 0;
476
+ }
477
+ /**
478
+ * Check consistent status codes
479
+ */
480
+ checkConsistentStatusCodes(routes) {
481
+ const statusCodes = new Set(routes.map((r) => r.statusCode).filter((c) => c !== null));
482
+ // Should have consistent status codes for same methods
483
+ return statusCodes.size <= routes.length;
484
+ }
485
+ /**
486
+ * Identify backend issues
487
+ */
488
+ identifyBackendIssues(metrics) {
489
+ const issues = [];
490
+ if (metrics.totalRoutes === 0) {
491
+ issues.push({
492
+ severity: 'low',
493
+ category: 'architecture',
494
+ description: 'No API routes detected',
495
+ fixable: false,
496
+ });
497
+ return issues;
498
+ }
499
+ if (metrics.restfulAdherence < 60) {
500
+ issues.push({
501
+ severity: 'medium',
502
+ category: 'architecture',
503
+ description: `Low RESTful adherence (${metrics.restfulAdherence.toFixed(0)}%)`,
504
+ fixable: true,
505
+ suggestion: 'Follow REST conventions for HTTP methods and status codes',
506
+ });
507
+ }
508
+ if (!metrics.consistentStatusCodes) {
509
+ issues.push({
510
+ severity: 'medium',
511
+ category: 'architecture',
512
+ description: 'Inconsistent HTTP status codes across routes',
513
+ fixable: true,
514
+ suggestion: 'Use consistent status codes (200 for GET, 201 for POST, 204 for DELETE)',
515
+ });
516
+ }
517
+ if (!metrics.hasErrorHandling || metrics.routesWithErrorHandling < metrics.totalRoutes) {
518
+ issues.push({
519
+ severity: 'high',
520
+ category: 'error-handling',
521
+ description: `${metrics.totalRoutes - metrics.routesWithErrorHandling} route(s) lack error handling`,
522
+ fixable: true,
523
+ suggestion: 'Add try-catch blocks and error middleware to all routes',
524
+ });
525
+ }
526
+ if (!metrics.hasInputValidation || metrics.routesWithValidation < metrics.totalRoutes) {
527
+ issues.push({
528
+ severity: 'high',
529
+ category: 'error-handling',
530
+ description: `${metrics.totalRoutes - metrics.routesWithValidation} route(s) lack input validation`,
531
+ fixable: true,
532
+ suggestion: 'Add input validation using Zod, Joi, or similar',
533
+ });
534
+ }
535
+ if (!metrics.hasRateLimiting) {
536
+ issues.push({
537
+ severity: 'medium',
538
+ category: 'architecture',
539
+ description: 'No rate limiting detected',
540
+ fixable: true,
541
+ suggestion: 'Implement rate limiting to prevent abuse',
542
+ });
543
+ }
544
+ if (!metrics.hasCaching) {
545
+ issues.push({
546
+ severity: 'low',
547
+ category: 'architecture',
548
+ description: 'No caching strategy detected',
549
+ fixable: true,
550
+ suggestion: 'Consider caching for frequently accessed data',
551
+ });
552
+ }
553
+ return issues;
554
+ }
555
+ /**
556
+ * Generate backend improvements
557
+ */
558
+ generateBackendImprovements(metrics) {
559
+ const improvements = [];
560
+ if (metrics.restfulAdherence < 80) {
561
+ improvements.push({
562
+ type: 'refactor',
563
+ description: 'Improve RESTful API design',
564
+ effort: 'moderate',
565
+ impact: 'medium',
566
+ steps: [
567
+ 'Use proper HTTP methods (GET, POST, PUT, DELETE)',
568
+ 'Return appropriate status codes',
569
+ 'Use plural nouns for resource names',
570
+ 'Implement HATEOAS for linked resources',
571
+ ],
572
+ });
573
+ }
574
+ if (!metrics.hasErrorHandling || metrics.routesWithErrorHandling < metrics.totalRoutes) {
575
+ improvements.push({
576
+ type: 'refactor',
577
+ description: 'Add comprehensive error handling to all API routes',
578
+ effort: 'moderate',
579
+ impact: 'high',
580
+ steps: [
581
+ 'Add try-catch blocks to all route handlers',
582
+ 'Implement global error middleware',
583
+ 'Return consistent error response format',
584
+ 'Log errors for debugging',
585
+ ],
586
+ });
587
+ }
588
+ if (!metrics.hasInputValidation || metrics.routesWithValidation < metrics.totalRoutes) {
589
+ improvements.push({
590
+ type: 'type-safe',
591
+ description: 'Add input validation to all API routes',
592
+ effort: 'moderate',
593
+ impact: 'high',
594
+ steps: [
595
+ 'Install validation library (Zod, Joi)',
596
+ 'Create validation schemas for request bodies',
597
+ 'Validate query parameters',
598
+ 'Sanitize user input',
599
+ ],
600
+ });
601
+ }
602
+ if (!metrics.hasRateLimiting) {
603
+ improvements.push({
604
+ type: 'refactor',
605
+ description: 'Implement rate limiting',
606
+ effort: 'quick',
607
+ impact: 'medium',
608
+ steps: [
609
+ 'Install rate limiting middleware',
610
+ 'Configure rate limits per route',
611
+ 'Add rate limit headers to responses',
612
+ ],
613
+ });
614
+ }
615
+ if (!metrics.hasCaching) {
616
+ improvements.push({
617
+ type: 'optimize',
618
+ description: 'Implement caching strategy',
619
+ effort: 'moderate',
620
+ impact: 'medium',
621
+ steps: [
622
+ 'Identify cacheable endpoints',
623
+ 'Set appropriate cache headers',
624
+ 'Consider Redis for distributed caching',
625
+ 'Implement cache invalidation strategy',
626
+ ],
627
+ });
628
+ }
629
+ if (!metrics.hasApiVersioning) {
630
+ improvements.push({
631
+ type: 'refactor',
632
+ description: 'Add API versioning',
633
+ effort: 'moderate',
634
+ impact: 'low',
635
+ steps: [
636
+ 'Add version prefix to routes (e.g., /api/v1)',
637
+ 'Document version changes',
638
+ 'Maintain backward compatibility',
639
+ ],
640
+ });
641
+ }
642
+ return improvements;
643
+ }
644
+ /**
645
+ * Calculate backend score
646
+ */
647
+ calculateBackendScore(metrics) {
648
+ if (metrics.totalRoutes === 0) {
649
+ return 100; // No backend = N/A = perfect for this dimension
650
+ }
651
+ let score = 0;
652
+ // RESTful adherence (25 points)
653
+ score += (metrics.restfulAdherence / 100) * 25;
654
+ // Error handling (25 points)
655
+ const errorHandlingRatio = metrics.routesWithErrorHandling / metrics.totalRoutes;
656
+ score += errorHandlingRatio * 25;
657
+ // Input validation (20 points)
658
+ const validationRatio = metrics.routesWithValidation / metrics.totalRoutes;
659
+ score += validationRatio * 20;
660
+ // Rate limiting (15 points)
661
+ if (metrics.hasRateLimiting)
662
+ score += 15;
663
+ // Caching (10 points)
664
+ if (metrics.hasCaching)
665
+ score += 10;
666
+ // API versioning (5 points)
667
+ if (metrics.hasApiVersioning)
668
+ score += 5;
669
+ return Math.min(100, score);
670
+ }
671
+ /**
672
+ * Count passed checks for metadata
673
+ */
674
+ countPassedChecks(metrics) {
675
+ let count = 0;
676
+ if (metrics.restfulAdherence >= 80)
677
+ count++;
678
+ if (metrics.consistentStatusCodes)
679
+ count++;
680
+ if (metrics.routesWithErrorHandling === metrics.totalRoutes && metrics.totalRoutes > 0)
681
+ count++;
682
+ if (metrics.routesWithValidation === metrics.totalRoutes && metrics.totalRoutes > 0)
683
+ count++;
684
+ if (metrics.hasRateLimiting)
685
+ count++;
686
+ if (metrics.hasCaching)
687
+ count++;
688
+ return count;
689
+ }
690
+ /**
691
+ * Create result when no backend detected
692
+ */
693
+ createNoBackendResult(issues, improvements) {
694
+ return {
695
+ dimension: this.getDimension(),
696
+ score: 100, // No backend to score
697
+ weight: this.getWeight(),
698
+ weightedScore: 100 * this.getWeight(),
699
+ issues: [],
700
+ improvements: [],
701
+ metadata: {
702
+ itemsChecked: 0,
703
+ itemsPassed: 0,
704
+ metrics: { framework: 'unknown' },
705
+ },
706
+ };
707
+ }
708
+ }
709
+ /**
710
+ * Default analyzer instance
711
+ */
712
+ export const backendLogicAnalyzer = new BackendLogicAnalyzer();
713
+ //# sourceMappingURL=backend-logic.analyzer.js.map