@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,91 @@
1
+ /**
2
+ * Performance Analyzer
3
+ *
4
+ * Analyse les problèmes de performance:
5
+ * - Taille du bundle
6
+ * - Opportunités de lazy loading
7
+ * - Re-renders inutiles (React)
8
+ * - Requêtes N+1
9
+ * - Index manquants
10
+ *
11
+ * @module services/review/analyzers/performance-analyzer
12
+ */
13
+ import type { Issue, PerformanceMetrics, PerformanceAnalyzerConfig } from '../review.types.js';
14
+ import { DockerManager } from '../../docker/docker-manager.js';
15
+ /**
16
+ * Analyseur de performance
17
+ */
18
+ export declare class PerformanceAnalyzer {
19
+ private readonly docker;
20
+ private readonly logger;
21
+ private config;
22
+ private issueCounter;
23
+ constructor(config?: PerformanceAnalyzerConfig, docker?: DockerManager);
24
+ /**
25
+ * Configure l'analyseur
26
+ */
27
+ configure(config: Partial<PerformanceAnalyzerConfig>): void;
28
+ /**
29
+ * Analyse les performances d'un projet
30
+ *
31
+ * @param projectPath - Chemin du projet à analyser
32
+ * @returns Métriques de performance et issues
33
+ */
34
+ analyze(projectPath: string): Promise<{
35
+ metrics: PerformanceMetrics;
36
+ issues: Issue[];
37
+ }>;
38
+ /**
39
+ * Analyse la taille du bundle
40
+ */
41
+ private analyzeBundleSize;
42
+ /**
43
+ * Calcule la taille d'un dossier
44
+ */
45
+ private calculateDirSize;
46
+ /**
47
+ * Estime la taille du bundle à partir des dépendances
48
+ */
49
+ private estimateBundleSizeFromDeps;
50
+ /**
51
+ * Détecte les opportunités de lazy loading
52
+ */
53
+ private detectLazyLoading;
54
+ /**
55
+ * Détecte les re-renders inutiles React
56
+ */
57
+ private detectRerenders;
58
+ /**
59
+ * Détecte les requêtes N+1
60
+ */
61
+ private detectNPlusOneQueries;
62
+ /**
63
+ * Détecte les index manquants (pour Prisma/TypeORM)
64
+ */
65
+ private detectMissingIndexes;
66
+ /**
67
+ * Trouve les composants déjà lazy-loadés
68
+ */
69
+ private findLazyComponents;
70
+ /**
71
+ * Trouve tous les fichiers source
72
+ */
73
+ private findSourceFiles;
74
+ /**
75
+ * Trouve la position ligne/colonne à partir d'un index
76
+ */
77
+ private findPosition;
78
+ /**
79
+ * Extrait un extrait de code
80
+ */
81
+ private extractCodeSnippet;
82
+ /**
83
+ * Formate une taille en octets pour l'affichage
84
+ */
85
+ private formatBytes;
86
+ /**
87
+ * Génère un ID unique
88
+ */
89
+ private generateIssueId;
90
+ }
91
+ //# sourceMappingURL=performance-analyzer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"performance-analyzer.d.ts","sourceRoot":"","sources":["../../../../src/services/review/analyzers/performance-analyzer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAMH,OAAO,KAAK,EACV,KAAK,EACL,kBAAkB,EAElB,yBAAyB,EAC1B,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAkF/D;;GAEG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;IACvC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,YAAY,CAAK;gBAEb,MAAM,GAAE,yBAA8B,EAAE,MAAM,CAAC,EAAE,aAAa;IAM1E;;OAEG;IACH,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,yBAAyB,CAAC,GAAG,IAAI;IAI3D;;;;;OAKG;IACG,OAAO,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,kBAAkB,CAAC;QAAC,MAAM,EAAE,KAAK,EAAE,CAAA;KAAE,CAAC;IA0F7F;;OAEG;YACW,iBAAiB;IA6B/B;;OAEG;YACW,gBAAgB;IA2C9B;;OAEG;YACW,0BAA0B;IAgDxC;;OAEG;YACW,iBAAiB;IAiD/B;;OAEG;YACW,eAAe;IA8C7B;;OAEG;YACW,qBAAqB;IA0DnC;;OAEG;YACW,oBAAoB;IAqDlC;;OAEG;YACW,kBAAkB;IAmBhC;;OAEG;YACW,eAAe;IAgC7B;;OAEG;IACH,OAAO,CAAC,YAAY;IASpB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAM1B;;OAEG;IACH,OAAO,CAAC,WAAW;IAQnB;;OAEG;IACH,OAAO,CAAC,eAAe;CAGxB"}
@@ -0,0 +1,589 @@
1
+ /**
2
+ * Performance Analyzer
3
+ *
4
+ * Analyse les problèmes de performance:
5
+ * - Taille du bundle
6
+ * - Opportunités de lazy loading
7
+ * - Re-renders inutiles (React)
8
+ * - Requêtes N+1
9
+ * - Index manquants
10
+ *
11
+ * @module services/review/analyzers/performance-analyzer
12
+ */
13
+ import { readFile, readdir } from 'node:fs/promises';
14
+ import { join, relative } from 'node:path';
15
+ import { access, constants } from 'node:fs/promises';
16
+ import { DockerManager } from '../../docker/docker-manager.js';
17
+ import { createLogger } from '../../../shared/utils/logger.js';
18
+ /**
19
+ * Extensions de fichiers source
20
+ */
21
+ const SOURCE_EXTENSIONS = ['.ts', '.tsx', '.js', '.jsx', '.vue', '.svelte'];
22
+ /**
23
+ * Dossiers à exclure
24
+ */
25
+ const EXCLUDE_DIRS = ['node_modules', '.git', 'dist', 'build', 'coverage', '.next', '.nuxt', 'out'];
26
+ /**
27
+ * Patterns de code indiquant un manque de lazy loading
28
+ */
29
+ const LAZY_LOAD_PATTERNS = [
30
+ {
31
+ pattern: /import\s+.*?\s+from\s+['"`](?![@\.]).*?['"`]/g,
32
+ description: 'Eager import of library component',
33
+ suggestion: 'Use dynamic import() for code splitting',
34
+ },
35
+ {
36
+ pattern: /lazy\s*=\s*false|Suspense.*?fallback\s*=\s*null/g,
37
+ description: 'Explicit lazy loading disabled',
38
+ suggestion: 'Enable lazy loading for better initial load time',
39
+ },
40
+ ];
41
+ /**
42
+ * Patterns React pour détecter les re-renders inutiles
43
+ */
44
+ const RE_RENDER_PATTERNS = [
45
+ {
46
+ pattern: /useState\s*\(\[\]\)/g,
47
+ description: 'Array state without memo',
48
+ suggestion: 'Use useMemo if array is used in dependencies',
49
+ },
50
+ {
51
+ pattern: /new\s+(?:Array|Object|Date)\s*\([^)]*\)\s*[,\)]/g,
52
+ description: 'Creating new object/array in render',
53
+ suggestion: 'Move to useMemo or outside component',
54
+ },
55
+ {
56
+ pattern: /function\s+\w+\s*\([^)]*\)\s*\{[^}]*\{[^}]*\.map\s*\(/g,
57
+ description: 'Inline function with map in render',
58
+ suggestion: 'Extract component or use useCallback',
59
+ },
60
+ ];
61
+ /**
62
+ * Patterns de requêtes N+1
63
+ */
64
+ const N_PLUS_ONE_PATTERNS = [
65
+ {
66
+ pattern: /forEach.*?(?:find|query|fetch|select)/gi,
67
+ description: 'Query inside forEach loop - potential N+1',
68
+ suggestion: 'Use batch loading or include relations',
69
+ },
70
+ {
71
+ pattern: /for\s*\([^)]*\)\s*\{[^}]*?(?:find|query|fetch|select)/gi,
72
+ description: 'Query inside for loop - potential N+1',
73
+ suggestion: 'Use batch loading or include relations',
74
+ },
75
+ {
76
+ pattern: /\.map\s*\([^)]*\)\s*=>\s*\{[^}]*?(?:find|query|fetch|select)/gi,
77
+ description: 'Query inside map - potential N+1',
78
+ suggestion: 'Use batch loading or include relations',
79
+ },
80
+ ];
81
+ /**
82
+ * Configuration par défaut
83
+ */
84
+ const DEFAULT_CONFIG = {
85
+ analyzeBundleSize: true,
86
+ detectLazyOpportunities: true,
87
+ detectRerenders: true,
88
+ detectNPlusOne: true,
89
+ detectMissingIndexes: true,
90
+ };
91
+ /**
92
+ * Analyseur de performance
93
+ */
94
+ export class PerformanceAnalyzer {
95
+ docker;
96
+ logger;
97
+ config;
98
+ issueCounter = 0;
99
+ constructor(config = {}, docker) {
100
+ this.config = { ...DEFAULT_CONFIG, ...config };
101
+ this.docker = docker ?? new DockerManager();
102
+ this.logger = createLogger('PerformanceAnalyzer');
103
+ }
104
+ /**
105
+ * Configure l'analyseur
106
+ */
107
+ configure(config) {
108
+ this.config = { ...this.config, ...config };
109
+ }
110
+ /**
111
+ * Analyse les performances d'un projet
112
+ *
113
+ * @param projectPath - Chemin du projet à analyser
114
+ * @returns Métriques de performance et issues
115
+ */
116
+ async analyze(projectPath) {
117
+ this.issueCounter = 0;
118
+ const startTime = performance.now();
119
+ this.logger.info(`Starting performance analysis for: ${projectPath}`);
120
+ const metrics = {
121
+ lazyLoadingOpportunities: 0,
122
+ unnecessaryRerenders: 0,
123
+ nPlusOneQueries: [],
124
+ missingIndexes: [],
125
+ lazyComponents: [],
126
+ };
127
+ const issues = [];
128
+ // Analyser la taille du bundle
129
+ if (this.config.analyzeBundleSize) {
130
+ const bundleSize = await this.analyzeBundleSize(projectPath);
131
+ metrics.bundleSize = bundleSize;
132
+ if (bundleSize.total > 500_000) {
133
+ // 500 KB warning threshold
134
+ issues.push({
135
+ id: this.generateIssueId('bundle-size'),
136
+ category: 'performance',
137
+ severity: bundleSize.total > 1_000_000 ? 'high' : 'medium',
138
+ description: 'Large bundle size detected',
139
+ message: `Total bundle size is ${this.formatBytes(bundleSize.total)}. Consider code splitting and tree shaking.`,
140
+ location: {
141
+ file: join(projectPath, 'package.json'),
142
+ line: 1,
143
+ },
144
+ fixable: false,
145
+ effort: 6,
146
+ suggestions: [
147
+ 'Implement code splitting with dynamic imports',
148
+ 'Use bundle analyzer to identify large modules',
149
+ 'Remove unused dependencies',
150
+ 'Enable tree shaking in bundler config',
151
+ ],
152
+ });
153
+ }
154
+ }
155
+ // Détecter les opportunités de lazy loading
156
+ if (this.config.detectLazyOpportunities) {
157
+ const lazyIssues = await this.detectLazyLoading(projectPath);
158
+ metrics.lazyLoadingOpportunities = lazyIssues.length;
159
+ issues.push(...lazyIssues);
160
+ }
161
+ // Détecter les re-renders React
162
+ if (this.config.detectRerenders) {
163
+ const rerenderIssues = await this.detectRerenders(projectPath);
164
+ metrics.unnecessaryRerenders = rerenderIssues.length;
165
+ issues.push(...rerenderIssues);
166
+ }
167
+ // Détecter les requêtes N+1
168
+ if (this.config.detectNPlusOne) {
169
+ const nPlusOneIssues = await this.detectNPlusOneQueries(projectPath);
170
+ metrics.nPlusOneQueries = nPlusOneIssues.map((i) => ({
171
+ file: i.location.file,
172
+ line: i.location.line,
173
+ description: i.description,
174
+ }));
175
+ issues.push(...nPlusOneIssues);
176
+ }
177
+ // Détecter les index manquants
178
+ if (this.config.detectMissingIndexes) {
179
+ const missingIndexIssues = await this.detectMissingIndexes(projectPath);
180
+ metrics.missingIndexes = missingIndexIssues.map((i) => ({
181
+ table: i.description.split(' on ')[1]?.split(' ')[0] || 'unknown',
182
+ column: i.description.split(' on ')[1]?.split(' ')[1]?.replace(/[()]/g, '') || 'unknown',
183
+ query: i.message || i.description,
184
+ }));
185
+ issues.push(...missingIndexIssues);
186
+ }
187
+ // Détecter les composants déjà lazy-loadés
188
+ metrics.lazyComponents = await this.findLazyComponents(projectPath);
189
+ const duration = Math.round(performance.now() - startTime);
190
+ this.logger.info(`Performance analysis completed in ${duration}ms (${issues.length} issues found)`);
191
+ return { metrics, issues };
192
+ }
193
+ /**
194
+ * Analyse la taille du bundle
195
+ */
196
+ async analyzeBundleSize(projectPath) {
197
+ let js = 0;
198
+ let css = 0;
199
+ // Chercher les dossiers de build courants
200
+ const buildDirs = ['dist', 'build', '.next', 'out', '.output'];
201
+ for (const buildDir of buildDirs) {
202
+ const dirPath = join(projectPath, buildDir);
203
+ try {
204
+ await access(dirPath, constants.F_OK);
205
+ const sizes = await this.calculateDirSize(dirPath);
206
+ js += sizes.js;
207
+ css += sizes.css;
208
+ }
209
+ catch {
210
+ // Dossier n'existe pas
211
+ }
212
+ }
213
+ // Fallback: utiliser next build ou webpack-bundle-analyzer si disponible
214
+ if (js === 0 && css === 0) {
215
+ const estimated = await this.estimateBundleSizeFromDeps(projectPath);
216
+ return { js: estimated, css: 0, total: estimated };
217
+ }
218
+ return { js, css, total: js + css };
219
+ }
220
+ /**
221
+ * Calcule la taille d'un dossier
222
+ */
223
+ async calculateDirSize(dirPath) {
224
+ let js = 0;
225
+ let css = 0;
226
+ const traverse = async (path) => {
227
+ try {
228
+ const entries = await readdir(path, { withFileTypes: true });
229
+ for (const entry of entries) {
230
+ const fullPath = join(path, entry.name);
231
+ if (entry.isDirectory()) {
232
+ await traverse(fullPath);
233
+ }
234
+ else if (entry.isFile()) {
235
+ const ext = entry.name.split('.').pop()?.toLowerCase();
236
+ if (ext === 'js' || ext === 'mjs') {
237
+ try {
238
+ const { stat } = await import('node:fs/promises');
239
+ const stats = await stat(fullPath);
240
+ js += stats.size;
241
+ }
242
+ catch {
243
+ // Ignore stat errors
244
+ }
245
+ }
246
+ else if (ext === 'css') {
247
+ try {
248
+ const { stat } = await import('node:fs/promises');
249
+ const stats = await stat(fullPath);
250
+ css += stats.size;
251
+ }
252
+ catch {
253
+ // Ignore stat errors
254
+ }
255
+ }
256
+ }
257
+ }
258
+ }
259
+ catch {
260
+ // Ignore errors
261
+ }
262
+ };
263
+ await traverse(dirPath);
264
+ return { js, css };
265
+ }
266
+ /**
267
+ * Estime la taille du bundle à partir des dépendances
268
+ */
269
+ async estimateBundleSizeFromDeps(projectPath) {
270
+ try {
271
+ const pkgPath = join(projectPath, 'package.json');
272
+ const content = await readFile(pkgPath, 'utf-8');
273
+ const pkg = JSON.parse(content);
274
+ // Estimations approximatives de tailles de packages populaires
275
+ const packageSizes = {
276
+ react: 45000,
277
+ 'react-dom': 130000,
278
+ 'react-router-dom': 70000,
279
+ '@tanstack/react-query': 55000,
280
+ axios: 35000,
281
+ lodash: 70000,
282
+ 'lodash-es': 60000,
283
+ moment: 70000,
284
+ 'dayjs': 2000,
285
+ datefns: 28000,
286
+ '@mui/material': 400000,
287
+ '@mui/system': 180000,
288
+ '@chakra-ui/react': 250000,
289
+ framerMotion: 90000,
290
+ };
291
+ let total = 0;
292
+ const deps = { ...(pkg.dependencies ?? {}), ...(pkg.devDependencies ?? {}) };
293
+ for (const [name, version] of Object.entries(deps)) {
294
+ // Ignorer les @types
295
+ if (name.startsWith('@types/')) {
296
+ continue;
297
+ }
298
+ const baseName = name.split('/').pop() ?? name;
299
+ if (baseName in packageSizes) {
300
+ total += packageSizes[baseName];
301
+ }
302
+ else {
303
+ // Estimation par défaut
304
+ total += 10000;
305
+ }
306
+ }
307
+ return total;
308
+ }
309
+ catch {
310
+ return 0;
311
+ }
312
+ }
313
+ /**
314
+ * Détecte les opportunités de lazy loading
315
+ */
316
+ async detectLazyLoading(projectPath) {
317
+ const issues = [];
318
+ const files = await this.findSourceFiles(projectPath);
319
+ for (const filePath of files) {
320
+ try {
321
+ const content = await readFile(filePath, 'utf-8');
322
+ const lines = content.split('\n');
323
+ const relativePath = relative(projectPath, filePath);
324
+ for (const patternConfig of LAZY_LOAD_PATTERNS) {
325
+ let match;
326
+ const regex = new RegExp(patternConfig.pattern.source, patternConfig.pattern.flags);
327
+ while ((match = regex.exec(content)) !== null) {
328
+ const position = this.findPosition(content, match.index);
329
+ // Ignorer si déjà dans un lazy context
330
+ const lineContent = lines[position.line - 1] ?? '';
331
+ if (lineContent.includes('dynamic(') || lineContent.includes('React.lazy(')) {
332
+ continue;
333
+ }
334
+ issues.push({
335
+ id: this.generateIssueId(`lazy-${position.line}`),
336
+ category: 'performance',
337
+ severity: 'medium',
338
+ description: patternConfig.description,
339
+ message: patternConfig.suggestion,
340
+ location: {
341
+ file: filePath,
342
+ line: position.line,
343
+ column: position.column,
344
+ },
345
+ code: this.extractCodeSnippet(lines, position.line, 1),
346
+ fixable: true,
347
+ effort: 3,
348
+ suggestions: [patternConfig.suggestion],
349
+ });
350
+ }
351
+ }
352
+ }
353
+ catch {
354
+ // Erreur de lecture, ignorer
355
+ }
356
+ }
357
+ return issues;
358
+ }
359
+ /**
360
+ * Détecte les re-renders inutiles React
361
+ */
362
+ async detectRerenders(projectPath) {
363
+ const issues = [];
364
+ const files = await this.findSourceFiles(projectPath);
365
+ // Ne traiter que les fichiers React
366
+ const reactFiles = files.filter((f) => /\.(tsx|jsx|vue)$/.test(f));
367
+ for (const filePath of reactFiles) {
368
+ try {
369
+ const content = await readFile(filePath, 'utf-8');
370
+ const lines = content.split('\n');
371
+ const relativePath = relative(projectPath, filePath);
372
+ for (const patternConfig of RE_RENDER_PATTERNS) {
373
+ let match;
374
+ const regex = new RegExp(patternConfig.pattern.source, patternConfig.pattern.flags);
375
+ while ((match = regex.exec(content)) !== null) {
376
+ const position = this.findPosition(content, match.index);
377
+ issues.push({
378
+ id: this.generateIssueId(`rerender-${relativePath}-${position.line}`),
379
+ category: 'performance',
380
+ severity: 'low',
381
+ description: patternConfig.description,
382
+ message: patternConfig.suggestion,
383
+ location: {
384
+ file: filePath,
385
+ line: position.line,
386
+ column: position.column,
387
+ },
388
+ code: this.extractCodeSnippet(lines, position.line, 2),
389
+ fixable: true,
390
+ effort: 4,
391
+ suggestions: [patternConfig.suggestion],
392
+ });
393
+ }
394
+ }
395
+ }
396
+ catch {
397
+ // Erreur de lecture, ignorer
398
+ }
399
+ }
400
+ return issues;
401
+ }
402
+ /**
403
+ * Détecte les requêtes N+1
404
+ */
405
+ async detectNPlusOneQueries(projectPath) {
406
+ const issues = [];
407
+ const files = await this.findSourceFiles(projectPath);
408
+ // Filtrer les fichiers backend/API
409
+ const apiFiles = files.filter((f) => f.includes('/api/') ||
410
+ f.includes('/server/') ||
411
+ f.includes('/controllers/') ||
412
+ f.includes('/services/') ||
413
+ f.includes('/lib/db') ||
414
+ f.endsWith('.query.ts') ||
415
+ f.endsWith('.queries.ts'));
416
+ for (const filePath of apiFiles) {
417
+ try {
418
+ const content = await readFile(filePath, 'utf-8');
419
+ const lines = content.split('\n');
420
+ for (const patternConfig of N_PLUS_ONE_PATTERNS) {
421
+ let match;
422
+ const regex = new RegExp(patternConfig.pattern.source, patternConfig.pattern.flags);
423
+ while ((match = regex.exec(content)) !== null) {
424
+ const position = this.findPosition(content, match.index);
425
+ issues.push({
426
+ id: this.generateIssueId(`nplusone-${filePath.replace(/[^a-zA-Z0-9]/g, '-')}-${position.line}`),
427
+ category: 'performance',
428
+ severity: 'high',
429
+ description: patternConfig.description,
430
+ message: patternConfig.suggestion,
431
+ location: {
432
+ file: filePath,
433
+ line: position.line,
434
+ column: position.column,
435
+ },
436
+ code: this.extractCodeSnippet(lines, position.line, 3),
437
+ fixable: false,
438
+ effort: 6,
439
+ suggestions: [
440
+ patternConfig.suggestion,
441
+ 'Use DataLoader pattern',
442
+ 'Use JOIN or IN clause for batch queries',
443
+ ],
444
+ });
445
+ }
446
+ }
447
+ }
448
+ catch {
449
+ // Erreur de lecture, ignorer
450
+ }
451
+ }
452
+ return issues;
453
+ }
454
+ /**
455
+ * Détecte les index manquants (pour Prisma/TypeORM)
456
+ */
457
+ async detectMissingIndexes(projectPath) {
458
+ const issues = [];
459
+ // Chercher les fichiers Prisma schema
460
+ const schemaFiles = ['schema.prisma', 'prisma/schema.prisma'];
461
+ for (const schemaFile of schemaFiles) {
462
+ const schemaPath = join(projectPath, schemaFile);
463
+ try {
464
+ await access(schemaPath, constants.F_OK);
465
+ const content = await readFile(schemaPath, 'utf-8');
466
+ // Détecter les relations sans index
467
+ const relationPattern = /(\w+)\s+(\w+)\s+@relation\([^)]*\)/g;
468
+ let match;
469
+ while ((match = relationPattern.exec(content)) !== null) {
470
+ const fieldName = match[2];
471
+ const lines = content.split('\n');
472
+ const lineNum = content.substring(0, match.index).split('\n').length;
473
+ // Vérifier s'il y a un index sur ce champ
474
+ const hasIndex = /@@index.*?\[.*?['"`]/.test(content) && content.includes(fieldName);
475
+ const hasUnique = content.includes(`@@unique([${fieldName}]`);
476
+ const hasIdIndex = fieldName === 'id' || fieldName.endsWith('Id');
477
+ if (!hasIndex && !hasUnique && !hasIdIndex) {
478
+ issues.push({
479
+ id: this.generateIssueId(`index-${schemaFile}-${fieldName}`),
480
+ category: 'performance',
481
+ severity: 'medium',
482
+ description: `Missing index on foreign key: ${fieldName}`,
483
+ message: `Foreign key field ${fieldName} should be indexed for better query performance.`,
484
+ location: {
485
+ file: schemaPath,
486
+ line: lineNum,
487
+ },
488
+ code: lines[lineNum - 1],
489
+ fixable: true,
490
+ effort: 2,
491
+ suggestions: [`Add @@index([${fieldName}]) to the model`],
492
+ });
493
+ }
494
+ }
495
+ }
496
+ catch {
497
+ // Schéma non trouvé
498
+ }
499
+ }
500
+ return issues;
501
+ }
502
+ /**
503
+ * Trouve les composants déjà lazy-loadés
504
+ */
505
+ async findLazyComponents(projectPath) {
506
+ const lazy = [];
507
+ const files = await this.findSourceFiles(projectPath);
508
+ for (const filePath of files) {
509
+ try {
510
+ const content = await readFile(filePath, 'utf-8');
511
+ if (/dynamic\s*\(|React\.lazy\s*\(|lazy\s*\(\s*\(|import\s*\(/.test(content)) {
512
+ lazy.push(relative(projectPath, filePath));
513
+ }
514
+ }
515
+ catch {
516
+ // Erreur de lecture
517
+ }
518
+ }
519
+ return lazy;
520
+ }
521
+ /**
522
+ * Trouve tous les fichiers source
523
+ */
524
+ async findSourceFiles(projectPath) {
525
+ const files = [];
526
+ const traverse = async (dir) => {
527
+ try {
528
+ const entries = await readdir(dir, { withFileTypes: true });
529
+ for (const entry of entries) {
530
+ const fullPath = join(dir, entry.name);
531
+ if (EXCLUDE_DIRS.includes(entry.name)) {
532
+ continue;
533
+ }
534
+ if (entry.isDirectory()) {
535
+ await traverse(fullPath);
536
+ }
537
+ else if (entry.isFile()) {
538
+ const ext = `.${entry.name.split('.').pop()}`;
539
+ if (SOURCE_EXTENSIONS.includes(ext)) {
540
+ files.push(fullPath);
541
+ }
542
+ }
543
+ }
544
+ }
545
+ catch {
546
+ // Ignorer les erreurs
547
+ }
548
+ };
549
+ await traverse(projectPath);
550
+ return files;
551
+ }
552
+ /**
553
+ * Trouve la position ligne/colonne à partir d'un index
554
+ */
555
+ findPosition(content, index) {
556
+ const before = content.substring(0, index);
557
+ const lines = before.split('\n');
558
+ return {
559
+ line: lines.length,
560
+ column: (lines[lines.length - 1] ?? '').length + 1,
561
+ };
562
+ }
563
+ /**
564
+ * Extrait un extrait de code
565
+ */
566
+ extractCodeSnippet(lines, targetLine, context) {
567
+ const start = Math.max(0, targetLine - context - 1);
568
+ const end = Math.min(lines.length, targetLine + context);
569
+ return lines.slice(start, end).join('\n');
570
+ }
571
+ /**
572
+ * Formate une taille en octets pour l'affichage
573
+ */
574
+ formatBytes(bytes) {
575
+ if (bytes === 0)
576
+ return '0 B';
577
+ const k = 1024;
578
+ const sizes = ['B', 'KB', 'MB', 'GB'];
579
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
580
+ return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`;
581
+ }
582
+ /**
583
+ * Génère un ID unique
584
+ */
585
+ generateIssueId(suffix) {
586
+ return `perf-${suffix}-${++this.issueCounter}`.replace(/[^a-zA-Z0-9-]/g, '-');
587
+ }
588
+ }
589
+ //# sourceMappingURL=performance-analyzer.js.map