@girardelli/architect 2.2.0 → 4.0.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 (296) hide show
  1. package/README.md +105 -116
  2. package/__test_agent_output__/INDEX.md +1 -0
  3. package/__test_agent_output__/agents/AGENT-ORCHESTRATOR.md +1 -0
  4. package/__test_agent_output__/agents/DATABASE-ENGINEER.md +174 -0
  5. package/__test_agent_output__/agents/QA-TEST-ENGINEER.md +138 -0
  6. package/__test_agent_output__/agents/SECURITY-AUDITOR.md +106 -0
  7. package/__test_agent_output__/agents/TECH-DEBT-CONTROLLER.md +104 -0
  8. package/__test_agent_output__/agents/TYPESCRIPT-BACKEND-DEVELOPER.md +135 -0
  9. package/__test_agent_output__/guards/CODE-REVIEW-CHECKLIST.md +95 -0
  10. package/__test_agent_output__/guards/PREFLIGHT.md +200 -0
  11. package/__test_agent_output__/guards/QUALITY-GATES.md +1 -0
  12. package/__test_agent_output__/rules/00-general.md +229 -0
  13. package/__test_agent_output__/rules/01-architecture.md +191 -0
  14. package/__test_agent_output__/rules/02-security.md +402 -0
  15. package/__test_agent_output__/rules/03-nestjs.md +124 -0
  16. package/__test_agent_output__/templates/ADR.md +95 -0
  17. package/__test_agent_output__/templates/BDD.md +58 -0
  18. package/__test_agent_output__/templates/C4.md +68 -0
  19. package/__test_agent_output__/templates/TDD.md +86 -0
  20. package/__test_agent_output__/templates/THREAT-MODEL.md +82 -0
  21. package/__test_agent_output__/workflows/fix-bug.md +228 -0
  22. package/__test_agent_output__/workflows/new-feature.md +311 -0
  23. package/__test_agent_output__/workflows/review.md +95 -0
  24. package/__test_context_7RvUrO/src/modules/empty/empty.ts +0 -0
  25. package/__test_context_Rf5fNJ/src/modules/mixed/mixed.ts +5 -0
  26. package/__test_context_WRCnYH/src/modules/test/test.ts +10 -0
  27. package/__test_context_YsnVS3/src/modules/test/test.ts +10 -0
  28. package/__test_context_w7XZeH/src/modules/mixed/mixed.ts +5 -0
  29. package/__test_context_y5noh6/src/modules/empty/empty.ts +0 -0
  30. package/__test_framework__24OjAu/package.json +1 -0
  31. package/__test_framework__3ZDZsx/pyproject.toml +8 -0
  32. package/__test_framework__4T54Jn/package.json +1 -0
  33. package/__test_framework__4tlXu9/pyproject.toml +8 -0
  34. package/__test_framework__6boWqQ/Pipfile +6 -0
  35. package/__test_framework__6gygMU/pom.xml +10 -0
  36. package/__test_framework__6kxj0N/go.mod +8 -0
  37. package/__test_framework__7CEoXw/pom.xml +10 -0
  38. package/__test_framework__85DDz0/Pipfile +6 -0
  39. package/__test_framework__9WrRIr/pom.xml +7 -0
  40. package/__test_framework__ANqGKl/Gemfile +5 -0
  41. package/__test_framework__BCXTEM/go.mod +3 -0
  42. package/__test_framework__BHiPNq/setup.py +2 -0
  43. package/__test_framework__BqkiKv/package.json +1 -0
  44. package/__test_framework__C5yd8X/Pipfile.lock +1 -0
  45. package/__test_framework__C5yd8X/requirements.txt +1 -0
  46. package/__test_framework__C87d3a/manage.py +1 -0
  47. package/__test_framework__C87d3a/requirements.txt +2 -0
  48. package/__test_framework__DXNwc5/build.gradle +7 -0
  49. package/__test_framework__GhHSt3/build.gradle.kts +4 -0
  50. package/__test_framework__GzklJP/Cargo.toml +7 -0
  51. package/__test_framework__H4hd13/go.mod +8 -0
  52. package/__test_framework__HKjOXO/composer.json +1 -0
  53. package/__test_framework__HaDN45/Gemfile +3 -0
  54. package/__test_framework__IBO7YG/pyproject.toml +9 -0
  55. package/__test_framework__JwSOyF/pyproject.toml +6 -0
  56. package/__test_framework__K6HrCr/build.gradle +2 -0
  57. package/__test_framework__KzRPlh/pubspec.yaml +9 -0
  58. package/__test_framework__L6uIym/pyproject.toml +6 -0
  59. package/__test_framework__LOdoGK/requirements.txt +4 -0
  60. package/__test_framework__LgHzss/package.json +1 -0
  61. package/__test_framework__M76M6q/Gemfile +5 -0
  62. package/__test_framework__Mr9vWW/composer.json +1 -0
  63. package/__test_framework__N03Gnv/package.json +1 -0
  64. package/__test_framework__Num4UE/requirements +1 -0
  65. package/__test_framework__OAGw3Y/build.gradle +7 -0
  66. package/__test_framework__OQc8yG/pubspec.yaml +9 -0
  67. package/__test_framework__OwKZcd/requirements.txt +3 -0
  68. package/__test_framework__P0gFv7/requirements +1 -0
  69. package/__test_framework__PN55Rq/package.json +1 -0
  70. package/__test_framework__PQiqX8/pubspec.yaml +3 -0
  71. package/__test_framework__RBHsg7/composer.json +1 -0
  72. package/__test_framework__RHxif4/Cargo.toml +7 -0
  73. package/__test_framework__T0v0p1/Cargo.toml +4 -0
  74. package/__test_framework__Tu0clt/Pipfile.lock +1 -0
  75. package/__test_framework__Tu0clt/requirements.txt +1 -0
  76. package/__test_framework__TwDj9P/Cargo.toml +4 -0
  77. package/__test_framework__VQJNC4/pom.xml +7 -0
  78. package/__test_framework__W6sm05/package.json +1 -0
  79. package/__test_framework__W7vBLy/pyproject.toml +4 -0
  80. package/__test_framework__WNJOWT/setup.py +2 -0
  81. package/__test_framework__WSJs7U/package.json +1 -0
  82. package/__test_framework__YQ5VpA/build.gradle.kts +4 -0
  83. package/__test_framework__ZNEUEs/package.json +1 -0
  84. package/__test_framework__Znt922/pom.xml +7 -0
  85. package/__test_framework__azyg0h/pom.xml +7 -0
  86. package/__test_framework__c6otLr/package.json +1 -0
  87. package/__test_framework__cl9S9G/build.gradle +2 -0
  88. package/__test_framework__eilvV4/composer.json +1 -0
  89. package/__test_framework__gQZxXO/manage.py +1 -0
  90. package/__test_framework__gQZxXO/requirements.txt +2 -0
  91. package/__test_framework__ghvl26/poetry.lock +1 -0
  92. package/__test_framework__ghvl26/pyproject.toml +2 -0
  93. package/__test_framework__hR7b9U/Makefile +11 -0
  94. package/__test_framework__iESVsi/composer.json +1 -0
  95. package/__test_framework__jm6TJy/package.json +1 -0
  96. package/__test_framework__kBUpjs/pyproject.toml +9 -0
  97. package/__test_framework__kqoZrw/requirements.txt +4 -0
  98. package/__test_framework__lWkoyO/pyproject.toml +4 -0
  99. package/__test_framework__mTKnUO/package.json +1 -0
  100. package/__test_framework__nCeZwe/Makefile +11 -0
  101. package/__test_framework__oljsU0/package.json +1 -0
  102. package/__test_framework__osRG4q/go.mod +3 -0
  103. package/__test_framework__pCHH4F/package.json +1 -0
  104. package/__test_framework__pExx6E/Gemfile +3 -0
  105. package/__test_framework__pyBoGd/pyproject.toml +5 -0
  106. package/__test_framework__qw16VQ/package.json +1 -0
  107. package/__test_framework__rRayrG/package.json +1 -0
  108. package/__test_framework__s82zO5/package.json +1 -0
  109. package/__test_framework__tp8MFK/pyproject.toml +5 -0
  110. package/__test_framework__w44k4w/composer.json +1 -0
  111. package/__test_framework__yefPZY/poetry.lock +1 -0
  112. package/__test_framework__yefPZY/pyproject.toml +2 -0
  113. package/__test_framework__zCiyDT/requirements.txt +3 -0
  114. package/__test_framework__zGZN3j/pubspec.yaml +3 -0
  115. package/__test_framework__zXpnxL/package.json +1 -0
  116. package/architect-run.sh +431 -0
  117. package/assets/banner-v3.html +561 -0
  118. package/dist/agent-generator/context-enricher.d.ts +58 -0
  119. package/dist/agent-generator/context-enricher.d.ts.map +1 -0
  120. package/dist/agent-generator/context-enricher.js +581 -0
  121. package/dist/agent-generator/context-enricher.js.map +1 -0
  122. package/dist/agent-generator/domain-inferrer.d.ts +52 -0
  123. package/dist/agent-generator/domain-inferrer.d.ts.map +1 -0
  124. package/dist/agent-generator/domain-inferrer.js +575 -0
  125. package/dist/agent-generator/domain-inferrer.js.map +1 -0
  126. package/dist/agent-generator/framework-detector.d.ts +40 -0
  127. package/dist/agent-generator/framework-detector.d.ts.map +1 -0
  128. package/dist/agent-generator/framework-detector.js +611 -0
  129. package/dist/agent-generator/framework-detector.js.map +1 -0
  130. package/dist/agent-generator/index.d.ts +33 -0
  131. package/dist/agent-generator/index.d.ts.map +1 -0
  132. package/dist/agent-generator/index.js +477 -0
  133. package/dist/agent-generator/index.js.map +1 -0
  134. package/dist/agent-generator/stack-detector.d.ts +12 -0
  135. package/dist/agent-generator/stack-detector.d.ts.map +1 -0
  136. package/dist/agent-generator/stack-detector.js +128 -0
  137. package/dist/agent-generator/stack-detector.js.map +1 -0
  138. package/dist/agent-generator/templates/core/agents.d.ts +17 -0
  139. package/dist/agent-generator/templates/core/agents.d.ts.map +1 -0
  140. package/dist/agent-generator/templates/core/agents.js +1252 -0
  141. package/dist/agent-generator/templates/core/agents.js.map +1 -0
  142. package/dist/agent-generator/templates/core/architecture-rules.d.ts +7 -0
  143. package/dist/agent-generator/templates/core/architecture-rules.d.ts.map +1 -0
  144. package/dist/agent-generator/templates/core/architecture-rules.js +274 -0
  145. package/dist/agent-generator/templates/core/architecture-rules.js.map +1 -0
  146. package/dist/agent-generator/templates/core/general-rules.d.ts +8 -0
  147. package/dist/agent-generator/templates/core/general-rules.d.ts.map +1 -0
  148. package/dist/agent-generator/templates/core/general-rules.js +301 -0
  149. package/dist/agent-generator/templates/core/general-rules.js.map +1 -0
  150. package/dist/agent-generator/templates/core/index-md.d.ts +7 -0
  151. package/dist/agent-generator/templates/core/index-md.d.ts.map +1 -0
  152. package/dist/agent-generator/templates/core/index-md.js +246 -0
  153. package/dist/agent-generator/templates/core/index-md.js.map +1 -0
  154. package/dist/agent-generator/templates/core/orchestrator.d.ts +8 -0
  155. package/dist/agent-generator/templates/core/orchestrator.d.ts.map +1 -0
  156. package/dist/agent-generator/templates/core/orchestrator.js +422 -0
  157. package/dist/agent-generator/templates/core/orchestrator.js.map +1 -0
  158. package/dist/agent-generator/templates/core/preflight.d.ts +8 -0
  159. package/dist/agent-generator/templates/core/preflight.d.ts.map +1 -0
  160. package/dist/agent-generator/templates/core/preflight.js +213 -0
  161. package/dist/agent-generator/templates/core/preflight.js.map +1 -0
  162. package/dist/agent-generator/templates/core/quality-gates.d.ts +11 -0
  163. package/dist/agent-generator/templates/core/quality-gates.d.ts.map +1 -0
  164. package/dist/agent-generator/templates/core/quality-gates.js +254 -0
  165. package/dist/agent-generator/templates/core/quality-gates.js.map +1 -0
  166. package/dist/agent-generator/templates/core/security-rules.d.ts +7 -0
  167. package/dist/agent-generator/templates/core/security-rules.d.ts.map +1 -0
  168. package/dist/agent-generator/templates/core/security-rules.js +528 -0
  169. package/dist/agent-generator/templates/core/security-rules.js.map +1 -0
  170. package/dist/agent-generator/templates/core/skills-generator.d.ts +6 -0
  171. package/dist/agent-generator/templates/core/skills-generator.d.ts.map +1 -0
  172. package/dist/agent-generator/templates/core/skills-generator.js +207 -0
  173. package/dist/agent-generator/templates/core/skills-generator.js.map +1 -0
  174. package/dist/agent-generator/templates/core/workflow-fix-bug.d.ts +7 -0
  175. package/dist/agent-generator/templates/core/workflow-fix-bug.d.ts.map +1 -0
  176. package/dist/agent-generator/templates/core/workflow-fix-bug.js +237 -0
  177. package/dist/agent-generator/templates/core/workflow-fix-bug.js.map +1 -0
  178. package/dist/agent-generator/templates/core/workflow-new-feature.d.ts +8 -0
  179. package/dist/agent-generator/templates/core/workflow-new-feature.d.ts.map +1 -0
  180. package/dist/agent-generator/templates/core/workflow-new-feature.js +321 -0
  181. package/dist/agent-generator/templates/core/workflow-new-feature.js.map +1 -0
  182. package/dist/agent-generator/templates/core/workflow-review.d.ts +7 -0
  183. package/dist/agent-generator/templates/core/workflow-review.d.ts.map +1 -0
  184. package/dist/agent-generator/templates/core/workflow-review.js +104 -0
  185. package/dist/agent-generator/templates/core/workflow-review.js.map +1 -0
  186. package/dist/agent-generator/templates/domain/index.d.ts +22 -0
  187. package/dist/agent-generator/templates/domain/index.d.ts.map +1 -0
  188. package/dist/agent-generator/templates/domain/index.js +1176 -0
  189. package/dist/agent-generator/templates/domain/index.js.map +1 -0
  190. package/dist/agent-generator/templates/stack/index.d.ts +8 -0
  191. package/dist/agent-generator/templates/stack/index.d.ts.map +1 -0
  192. package/dist/agent-generator/templates/stack/index.js +695 -0
  193. package/dist/agent-generator/templates/stack/index.js.map +1 -0
  194. package/dist/agent-generator/templates/template-helpers.d.ts +75 -0
  195. package/dist/agent-generator/templates/template-helpers.d.ts.map +1 -0
  196. package/dist/agent-generator/templates/template-helpers.js +726 -0
  197. package/dist/agent-generator/templates/template-helpers.js.map +1 -0
  198. package/dist/agent-generator/types.d.ts +196 -0
  199. package/dist/agent-generator/types.d.ts.map +1 -0
  200. package/dist/agent-generator/types.js +27 -0
  201. package/dist/agent-generator/types.js.map +1 -0
  202. package/dist/analyzer.d.ts +5 -0
  203. package/dist/analyzer.d.ts.map +1 -1
  204. package/dist/analyzer.js +35 -4
  205. package/dist/analyzer.js.map +1 -1
  206. package/dist/analyzers/forecast.d.ts +85 -0
  207. package/dist/analyzers/forecast.d.ts.map +1 -0
  208. package/dist/analyzers/forecast.js +337 -0
  209. package/dist/analyzers/forecast.js.map +1 -0
  210. package/dist/analyzers/git-cache.d.ts +7 -0
  211. package/dist/analyzers/git-cache.d.ts.map +1 -0
  212. package/dist/analyzers/git-cache.js +41 -0
  213. package/dist/analyzers/git-cache.js.map +1 -0
  214. package/dist/analyzers/git-history.d.ts +113 -0
  215. package/dist/analyzers/git-history.d.ts.map +1 -0
  216. package/dist/analyzers/git-history.js +333 -0
  217. package/dist/analyzers/git-history.js.map +1 -0
  218. package/dist/analyzers/index.d.ts +10 -0
  219. package/dist/analyzers/index.d.ts.map +1 -0
  220. package/dist/analyzers/index.js +7 -0
  221. package/dist/analyzers/index.js.map +1 -0
  222. package/dist/analyzers/temporal-scorer.d.ts +72 -0
  223. package/dist/analyzers/temporal-scorer.d.ts.map +1 -0
  224. package/dist/analyzers/temporal-scorer.js +140 -0
  225. package/dist/analyzers/temporal-scorer.js.map +1 -0
  226. package/dist/cli.d.ts +2 -3
  227. package/dist/cli.d.ts.map +1 -1
  228. package/dist/cli.js +275 -113
  229. package/dist/cli.js.map +1 -1
  230. package/dist/html-reporter.d.ts +3 -1
  231. package/dist/html-reporter.d.ts.map +1 -1
  232. package/dist/html-reporter.js +248 -12
  233. package/dist/html-reporter.js.map +1 -1
  234. package/dist/index.d.ts +16 -3
  235. package/dist/index.d.ts.map +1 -1
  236. package/dist/index.js +63 -4
  237. package/dist/index.js.map +1 -1
  238. package/dist/project-summarizer.d.ts +18 -0
  239. package/dist/project-summarizer.d.ts.map +1 -0
  240. package/dist/project-summarizer.js +306 -0
  241. package/dist/project-summarizer.js.map +1 -0
  242. package/dist/refactor-reporter.js +1 -1
  243. package/dist/types.d.ts +13 -0
  244. package/dist/types.d.ts.map +1 -1
  245. package/package.json +12 -3
  246. package/src/agent-generator/context-enricher.ts +643 -0
  247. package/src/agent-generator/domain-inferrer.ts +625 -0
  248. package/src/agent-generator/framework-detector.ts +669 -0
  249. package/src/agent-generator/index.ts +555 -0
  250. package/src/agent-generator/stack-detector.ts +103 -0
  251. package/src/agent-generator/templates/core/agents.ts +1293 -0
  252. package/src/agent-generator/templates/core/architecture-rules.ts +287 -0
  253. package/src/agent-generator/templates/core/general-rules.ts +306 -0
  254. package/src/agent-generator/templates/core/index-md.ts +260 -0
  255. package/src/agent-generator/templates/core/orchestrator.ts +459 -0
  256. package/src/agent-generator/templates/core/preflight.ts +215 -0
  257. package/src/agent-generator/templates/core/quality-gates.ts +256 -0
  258. package/src/agent-generator/templates/core/security-rules.ts +543 -0
  259. package/src/agent-generator/templates/core/skills-generator.ts +236 -0
  260. package/src/agent-generator/templates/core/workflow-fix-bug.ts +239 -0
  261. package/src/agent-generator/templates/core/workflow-new-feature.ts +323 -0
  262. package/src/agent-generator/templates/core/workflow-review.ts +106 -0
  263. package/src/agent-generator/templates/domain/index.ts +1201 -0
  264. package/src/agent-generator/templates/stack/index.ts +705 -0
  265. package/src/agent-generator/templates/template-helpers.ts +776 -0
  266. package/src/agent-generator/types.ts +232 -0
  267. package/src/analyzer.ts +38 -4
  268. package/src/analyzers/forecast.ts +496 -0
  269. package/src/analyzers/git-cache.ts +52 -0
  270. package/src/analyzers/git-history.ts +488 -0
  271. package/src/analyzers/index.ts +33 -0
  272. package/src/analyzers/temporal-scorer.ts +227 -0
  273. package/src/cli.ts +316 -117
  274. package/src/html-reporter.ts +263 -13
  275. package/src/index.ts +92 -9
  276. package/src/project-summarizer.ts +347 -0
  277. package/src/refactor-reporter.ts +1 -1
  278. package/src/types.ts +10 -0
  279. package/tests/agent-generator.test.ts +411 -0
  280. package/tests/analyzers-integration.test.ts +174 -0
  281. package/tests/architect-adapter-enrichment.test.ts +9 -0
  282. package/tests/context-enricher.test.ts +971 -0
  283. package/tests/forecast.test.ts +509 -0
  284. package/tests/framework-detector.test.ts +1172 -0
  285. package/tests/git-history.test.ts +254 -0
  286. package/tests/scanner.test.ts +7 -8
  287. package/tests/scorer.test.ts +588 -0
  288. package/tests/stack-detector.test.ts +241 -0
  289. package/tests/template-generation.test.ts +706 -0
  290. package/tests/template-helpers.test.ts +1152 -0
  291. package/tests/temporal-scorer.test.ts +307 -0
  292. package/dist/agent-generator.d.ts +0 -106
  293. package/dist/agent-generator.d.ts.map +0 -1
  294. package/dist/agent-generator.js +0 -1398
  295. package/dist/agent-generator.js.map +0 -1
  296. package/src/agent-generator.ts +0 -1526
@@ -0,0 +1,971 @@
1
+ import { ContextEnricher } from '../src/agent-generator/context-enricher.js';
2
+ import { AnalysisReport, RefactoringPlan } from '../src/types.js';
3
+ import { mkdtempSync, rmSync, writeFileSync, mkdirSync } from 'fs';
4
+ import { join } from 'path';
5
+
6
+ // ── Test Data Factories ──
7
+
8
+ function makeReport(overrides: Partial<AnalysisReport> = {}): AnalysisReport {
9
+ return {
10
+ timestamp: new Date().toISOString(),
11
+ projectInfo: {
12
+ path: '/test',
13
+ name: 'test-project',
14
+ frameworks: ['NestJS'],
15
+ totalFiles: 50,
16
+ totalLines: 5000,
17
+ primaryLanguages: ['TypeScript'],
18
+ },
19
+ score: {
20
+ overall: 72,
21
+ components: [],
22
+ breakdown: { modularity: 80, coupling: 65, cohesion: 70, layering: 75 },
23
+ },
24
+ antiPatterns: [
25
+ {
26
+ name: 'God Class',
27
+ severity: 'CRITICAL',
28
+ location: 'src/AppService.ts',
29
+ description: 'Class with 800 lines',
30
+ suggestion: 'Split into smaller services',
31
+ affectedFiles: ['src/AppService.ts'],
32
+ },
33
+ ],
34
+ layers: [
35
+ { name: 'API', files: ['src/controller.ts'], description: 'API layer' },
36
+ { name: 'Service', files: ['src/service.ts'], description: 'Service layer' },
37
+ ],
38
+ dependencyGraph: {
39
+ nodes: ['src/app.module.ts', 'src/app.controller.ts', 'src/app.service.ts', 'src/entity/user.entity.ts'],
40
+ edges: [
41
+ { from: 'src/app.controller.ts', to: 'src/app.service.ts', type: 'import', weight: 1 },
42
+ { from: 'src/app.service.ts', to: 'src/entity/user.entity.ts', type: 'import', weight: 1 },
43
+ ],
44
+ },
45
+ suggestions: [],
46
+ diagram: { mermaid: '', type: 'layer' },
47
+ ...overrides,
48
+ };
49
+ }
50
+
51
+ function makePlan(overrides: Partial<RefactoringPlan> = {}): RefactoringPlan {
52
+ return {
53
+ timestamp: new Date().toISOString(),
54
+ projectPath: '/test',
55
+ currentScore: {
56
+ overall: 72,
57
+ components: [],
58
+ breakdown: { modularity: 80, coupling: 65, cohesion: 70, layering: 75 },
59
+ },
60
+ estimatedScoreAfter: { overall: 82, breakdown: { modularity: 85, coupling: 75, cohesion: 80, layering: 80 } },
61
+ steps: [
62
+ {
63
+ id: 1,
64
+ tier: 1,
65
+ rule: 'hub-splitter',
66
+ priority: 'HIGH',
67
+ title: 'Split AppService',
68
+ description: 'Split monolith service',
69
+ rationale: 'Reduce coupling',
70
+ operations: [],
71
+ scoreImpact: [{ metric: 'modularity', before: 80, after: 85 }],
72
+ },
73
+ ],
74
+ totalOperations: 1,
75
+ tier1Steps: 1,
76
+ tier2Steps: 0,
77
+ ...overrides,
78
+ };
79
+ }
80
+
81
+ // ── Test Suite ──
82
+
83
+ describe('ContextEnricher', () => {
84
+ const enricher = new ContextEnricher();
85
+ let tempDir: string;
86
+
87
+ beforeEach(() => {
88
+ tempDir = mkdtempSync(join(process.cwd(), '__test_context_'));
89
+ });
90
+
91
+ afterEach(() => {
92
+ if (tempDir) {
93
+ rmSync(tempDir, { recursive: true, force: true });
94
+ }
95
+ });
96
+
97
+ describe('enrich()', () => {
98
+ it('should return a valid EnrichedTemplateContext', () => {
99
+ const report = makeReport();
100
+ const plan = makePlan();
101
+
102
+ const result = enricher.enrich(report, plan, {
103
+ primary: 'TypeScript',
104
+ languages: ['TypeScript'],
105
+ frameworks: ['NestJS'],
106
+ hasBackend: true,
107
+ hasFrontend: false,
108
+ hasMobile: false,
109
+ hasDatabase: true,
110
+ testFramework: 'Jest',
111
+ packageManager: 'npm',
112
+ }, tempDir);
113
+
114
+ expect(result).toBeDefined();
115
+ expect(result.report).toBe(report);
116
+ expect(result.plan).toBe(plan);
117
+ expect(result.projectName).toBe('test-project');
118
+ expect(result.modules).toBeDefined();
119
+ expect(result.endpoints).toBeDefined();
120
+ expect(result.untestedModules).toBeDefined();
121
+ expect(result.criticalPaths).toBeDefined();
122
+ expect(result.projectDepth).toBeDefined();
123
+ });
124
+
125
+ it('should detect modules from dependency graph nodes', () => {
126
+ const report = makeReport({
127
+ dependencyGraph: {
128
+ nodes: [
129
+ 'src/modules/users/users.controller.ts',
130
+ 'src/modules/users/users.service.ts',
131
+ 'src/modules/users/user.entity.ts',
132
+ 'src/modules/auth/auth.controller.ts',
133
+ 'src/modules/auth/auth.service.ts',
134
+ ],
135
+ edges: [],
136
+ },
137
+ });
138
+ const plan = makePlan();
139
+
140
+ const result = enricher.enrich(report, plan, {
141
+ primary: 'TypeScript',
142
+ languages: ['TypeScript'],
143
+ frameworks: ['NestJS'],
144
+ hasBackend: true,
145
+ hasFrontend: false,
146
+ hasMobile: false,
147
+ hasDatabase: true,
148
+ testFramework: 'Jest',
149
+ packageManager: 'npm',
150
+ }, tempDir);
151
+
152
+ expect(result.modules.length).toBeGreaterThan(0);
153
+ const moduleNames = result.modules.map(m => m.name);
154
+ expect(moduleNames).toContain('users');
155
+ expect(moduleNames).toContain('auth');
156
+ });
157
+
158
+ it('should extract modules sorted by file count descending', () => {
159
+ const report = makeReport({
160
+ dependencyGraph: {
161
+ nodes: [
162
+ 'src/modules/users/users.controller.ts',
163
+ 'src/modules/users/users.service.ts',
164
+ 'src/modules/users/user.entity.ts',
165
+ 'src/modules/auth/auth.controller.ts',
166
+ ],
167
+ edges: [],
168
+ },
169
+ });
170
+ const plan = makePlan();
171
+
172
+ const result = enricher.enrich(report, plan, {
173
+ primary: 'TypeScript',
174
+ languages: ['TypeScript'],
175
+ frameworks: ['NestJS'],
176
+ hasBackend: true,
177
+ hasFrontend: false,
178
+ hasMobile: false,
179
+ hasDatabase: true,
180
+ testFramework: 'Jest',
181
+ packageManager: 'npm',
182
+ }, tempDir);
183
+
184
+ // Users has 3 files, auth has 1 file → users should come first
185
+ expect(result.modules[0].name).toBe('users');
186
+ expect(result.modules[0].fileCount).toBe(3);
187
+ });
188
+
189
+ it('should generate smart descriptions for known patterns', () => {
190
+ const report = makeReport({
191
+ dependencyGraph: {
192
+ nodes: [
193
+ 'src/modules/extractors/pdf.extractor.ts',
194
+ 'src/modules/extractors/image.extractor.ts',
195
+ 'src/modules/ocr/ocr.service.ts',
196
+ 'src/modules/guards/auth.guard.ts',
197
+ ],
198
+ edges: [],
199
+ },
200
+ });
201
+ const plan = makePlan();
202
+
203
+ const result = enricher.enrich(report, plan, {
204
+ primary: 'TypeScript',
205
+ languages: ['TypeScript'],
206
+ frameworks: ['NestJS'],
207
+ hasBackend: true,
208
+ hasFrontend: false,
209
+ hasMobile: false,
210
+ hasDatabase: true,
211
+ testFramework: 'Jest',
212
+ packageManager: 'npm',
213
+ }, tempDir);
214
+
215
+ const extractorsModule = result.modules.find(m => m.name === 'extractors');
216
+ expect(extractorsModule).toBeDefined();
217
+ expect(extractorsModule!.description).toContain('Extração');
218
+
219
+ const ocrModule = result.modules.find(m => m.name === 'ocr');
220
+ expect(ocrModule).toBeDefined();
221
+ expect(ocrModule!.description).toContain('OCR');
222
+
223
+ const guardsModule = result.modules.find(m => m.name === 'guards');
224
+ expect(guardsModule).toBeDefined();
225
+ expect(guardsModule!.description).toContain('Validação');
226
+ });
227
+
228
+ it('should count lines for real files', () => {
229
+ // Create a temp file with 10 lines
230
+ const subdir = join(tempDir, 'src', 'modules', 'test');
231
+ mkdirSync(subdir, { recursive: true });
232
+ const filePath = join(subdir, 'test.ts');
233
+ const content = Array(10).fill('console.log("test");').join('\n');
234
+ writeFileSync(filePath, content);
235
+
236
+ const report = makeReport({
237
+ dependencyGraph: {
238
+ nodes: ['src/modules/test/test.ts'],
239
+ edges: [],
240
+ },
241
+ });
242
+ const plan = makePlan();
243
+
244
+ const result = enricher.enrich(report, plan, {
245
+ primary: 'TypeScript',
246
+ languages: ['TypeScript'],
247
+ frameworks: ['NestJS'],
248
+ hasBackend: true,
249
+ hasFrontend: false,
250
+ hasMobile: false,
251
+ hasDatabase: true,
252
+ testFramework: 'Jest',
253
+ packageManager: 'npm',
254
+ }, tempDir);
255
+
256
+ const testModule = result.modules.find(m => m.name === 'test');
257
+ expect(testModule).toBeDefined();
258
+ expect(testModule!.lineCount).toBeGreaterThan(0);
259
+ });
260
+
261
+ it('should detect test files in modules', () => {
262
+ const report = makeReport({
263
+ dependencyGraph: {
264
+ nodes: [
265
+ 'src/modules/users/users.service.ts',
266
+ 'src/modules/users/users.service.test.ts',
267
+ 'src/modules/users/__tests__/users.spec.ts',
268
+ ],
269
+ edges: [],
270
+ },
271
+ });
272
+ const plan = makePlan();
273
+
274
+ const result = enricher.enrich(report, plan, {
275
+ primary: 'TypeScript',
276
+ languages: ['TypeScript'],
277
+ frameworks: ['NestJS'],
278
+ hasBackend: true,
279
+ hasFrontend: false,
280
+ hasMobile: false,
281
+ hasDatabase: true,
282
+ testFramework: 'Jest',
283
+ packageManager: 'npm',
284
+ }, tempDir);
285
+
286
+ const usersModule = result.modules.find(m => m.name === 'users');
287
+ expect(usersModule).toBeDefined();
288
+ expect(usersModule!.hasTests).toBe(true);
289
+ expect(usersModule!.testFiles.length).toBe(2);
290
+ });
291
+
292
+ it('should extract endpoints from route/controller files', () => {
293
+ const report = makeReport({
294
+ dependencyGraph: {
295
+ nodes: [
296
+ 'src/modules/users/users.controller.ts',
297
+ 'src/modules/users/users.service.ts',
298
+ 'src/auth/auth.controller.ts',
299
+ 'src/health/health.controller.ts',
300
+ ],
301
+ edges: [
302
+ { from: 'src/modules/users/users.controller.ts', to: 'src/modules/users/users.service.ts', type: 'import', weight: 1 },
303
+ { from: 'src/auth/auth.controller.ts', to: 'src/dependencies/auth.guard.ts', type: 'import', weight: 1 },
304
+ ],
305
+ },
306
+ });
307
+ const plan = makePlan();
308
+
309
+ const result = enricher.enrich(report, plan, {
310
+ primary: 'TypeScript',
311
+ languages: ['TypeScript'],
312
+ frameworks: ['NestJS'],
313
+ hasBackend: true,
314
+ hasFrontend: false,
315
+ hasMobile: false,
316
+ hasDatabase: true,
317
+ testFramework: 'Jest',
318
+ packageManager: 'npm',
319
+ }, tempDir);
320
+
321
+ expect(result.endpoints.length).toBeGreaterThan(0);
322
+ // Should detect users endpoints
323
+ const userEndpoints = result.endpoints.filter(e => e.path.includes('users'));
324
+ expect(userEndpoints.length).toBeGreaterThan(0);
325
+ });
326
+
327
+ it('should detect endpoints with authentication', () => {
328
+ const report = makeReport({
329
+ dependencyGraph: {
330
+ nodes: [
331
+ 'src/auth/auth.controller.ts',
332
+ 'src/dependencies/auth.guard.ts',
333
+ ],
334
+ edges: [
335
+ { from: 'src/auth/auth.controller.ts', to: 'src/dependencies/auth.guard.ts', type: 'import', weight: 1 },
336
+ ],
337
+ },
338
+ });
339
+ const plan = makePlan();
340
+
341
+ const result = enricher.enrich(report, plan, {
342
+ primary: 'TypeScript',
343
+ languages: ['TypeScript'],
344
+ frameworks: ['NestJS'],
345
+ hasBackend: true,
346
+ hasFrontend: false,
347
+ hasMobile: false,
348
+ hasDatabase: true,
349
+ testFramework: 'Jest',
350
+ packageManager: 'npm',
351
+ }, tempDir);
352
+
353
+ const authEndpoints = result.endpoints.filter(e => e.path.includes('auth'));
354
+ expect(authEndpoints.length).toBeGreaterThan(0);
355
+ // Auth endpoints should be marked as no auth (login/register are public)
356
+ const loginEndpoint = authEndpoints.find(e => e.path === '/auth/login');
357
+ expect(loginEndpoint).toBeDefined();
358
+ expect(loginEndpoint!.hasAuth).toBe(false);
359
+ });
360
+
361
+ it('should detect untested modules', () => {
362
+ const report = makeReport({
363
+ dependencyGraph: {
364
+ nodes: [
365
+ 'src/modules/users/users.service.ts',
366
+ 'src/modules/users/users.controller.ts',
367
+ 'src/modules/notested/service.ts',
368
+ 'src/modules/notested/handler.ts',
369
+ ],
370
+ edges: [],
371
+ },
372
+ });
373
+ const plan = makePlan();
374
+
375
+ const result = enricher.enrich(report, plan, {
376
+ primary: 'TypeScript',
377
+ languages: ['TypeScript'],
378
+ frameworks: ['NestJS'],
379
+ hasBackend: true,
380
+ hasFrontend: false,
381
+ hasMobile: false,
382
+ hasDatabase: true,
383
+ testFramework: 'Jest',
384
+ packageManager: 'npm',
385
+ }, tempDir);
386
+
387
+ expect(result.untestedModules).toContain('notested');
388
+ });
389
+
390
+ it('should identify critical paths (files with high coupling)', () => {
391
+ const report = makeReport({
392
+ dependencyGraph: {
393
+ nodes: [
394
+ 'src/app.module.ts',
395
+ 'src/app.controller.ts',
396
+ 'src/app.service.ts',
397
+ 'src/users/user.service.ts',
398
+ 'src/auth/auth.service.ts',
399
+ ],
400
+ edges: [
401
+ { from: 'src/app.module.ts', to: 'src/app.controller.ts', type: 'import', weight: 1 },
402
+ { from: 'src/app.module.ts', to: 'src/app.service.ts', type: 'import', weight: 1 },
403
+ { from: 'src/app.module.ts', to: 'src/users/user.service.ts', type: 'import', weight: 1 },
404
+ { from: 'src/app.module.ts', to: 'src/auth/auth.service.ts', type: 'import', weight: 1 },
405
+ { from: 'src/app.controller.ts', to: 'src/app.service.ts', type: 'import', weight: 1 },
406
+ ],
407
+ },
408
+ });
409
+ const plan = makePlan();
410
+
411
+ const result = enricher.enrich(report, plan, {
412
+ primary: 'TypeScript',
413
+ languages: ['TypeScript'],
414
+ frameworks: ['NestJS'],
415
+ hasBackend: true,
416
+ hasFrontend: false,
417
+ hasMobile: false,
418
+ hasDatabase: true,
419
+ testFramework: 'Jest',
420
+ packageManager: 'npm',
421
+ }, tempDir);
422
+
423
+ expect(result.criticalPaths.length).toBeGreaterThan(0);
424
+ // app.module.ts should be in critical paths (4 edges)
425
+ expect(result.criticalPaths).toContain('src/app.module.ts');
426
+ });
427
+
428
+ it('should classify project depth as small', () => {
429
+ const report = makeReport({
430
+ projectInfo: {
431
+ path: '/test',
432
+ name: 'small-project',
433
+ frameworks: ['NestJS'],
434
+ totalFiles: 10,
435
+ totalLines: 1000,
436
+ primaryLanguages: ['TypeScript'],
437
+ },
438
+ dependencyGraph: {
439
+ nodes: [],
440
+ edges: [],
441
+ },
442
+ });
443
+ const plan = makePlan();
444
+
445
+ const result = enricher.enrich(report, plan, {
446
+ primary: 'TypeScript',
447
+ languages: ['TypeScript'],
448
+ frameworks: ['NestJS'],
449
+ hasBackend: true,
450
+ hasFrontend: false,
451
+ hasMobile: false,
452
+ hasDatabase: true,
453
+ testFramework: 'Jest',
454
+ packageManager: 'npm',
455
+ }, tempDir);
456
+
457
+ expect(result.projectDepth).toBe('small');
458
+ });
459
+
460
+ it('should classify project depth as medium', () => {
461
+ const report = makeReport({
462
+ projectInfo: {
463
+ path: '/test',
464
+ name: 'medium-project',
465
+ frameworks: ['NestJS'],
466
+ totalFiles: 150,
467
+ totalLines: 30000,
468
+ primaryLanguages: ['TypeScript'],
469
+ },
470
+ dependencyGraph: {
471
+ nodes: [],
472
+ edges: [],
473
+ },
474
+ });
475
+ const plan = makePlan();
476
+
477
+ const result = enricher.enrich(report, plan, {
478
+ primary: 'TypeScript',
479
+ languages: ['TypeScript'],
480
+ frameworks: ['NestJS'],
481
+ hasBackend: true,
482
+ hasFrontend: false,
483
+ hasMobile: false,
484
+ hasDatabase: true,
485
+ testFramework: 'Jest',
486
+ packageManager: 'npm',
487
+ }, tempDir);
488
+
489
+ expect(result.projectDepth).toBe('medium');
490
+ });
491
+
492
+ it('should classify project depth as large', () => {
493
+ const report = makeReport({
494
+ projectInfo: {
495
+ path: '/test',
496
+ name: 'large-project',
497
+ frameworks: ['NestJS'],
498
+ totalFiles: 300,
499
+ totalLines: 70000,
500
+ primaryLanguages: ['TypeScript'],
501
+ },
502
+ dependencyGraph: {
503
+ nodes: [],
504
+ edges: [],
505
+ },
506
+ });
507
+ const plan = makePlan();
508
+
509
+ const result = enricher.enrich(report, plan, {
510
+ primary: 'TypeScript',
511
+ languages: ['TypeScript'],
512
+ frameworks: ['NestJS'],
513
+ hasBackend: true,
514
+ hasFrontend: false,
515
+ hasMobile: false,
516
+ hasDatabase: true,
517
+ testFramework: 'Jest',
518
+ packageManager: 'npm',
519
+ }, tempDir);
520
+
521
+ expect(result.projectDepth).toBe('large');
522
+ });
523
+
524
+ it('should classify project depth as enterprise', () => {
525
+ const report = makeReport({
526
+ projectInfo: {
527
+ path: '/test',
528
+ name: 'enterprise-project',
529
+ frameworks: ['NestJS'],
530
+ totalFiles: 1000,
531
+ totalLines: 150000,
532
+ primaryLanguages: ['TypeScript'],
533
+ },
534
+ dependencyGraph: {
535
+ nodes: [],
536
+ edges: [],
537
+ },
538
+ });
539
+ const plan = makePlan();
540
+
541
+ const result = enricher.enrich(report, plan, {
542
+ primary: 'TypeScript',
543
+ languages: ['TypeScript'],
544
+ frameworks: ['NestJS'],
545
+ hasBackend: true,
546
+ hasFrontend: false,
547
+ hasMobile: false,
548
+ hasDatabase: true,
549
+ testFramework: 'Jest',
550
+ packageManager: 'npm',
551
+ }, tempDir);
552
+
553
+ expect(result.projectDepth).toBe('enterprise');
554
+ });
555
+ });
556
+
557
+ describe('Module inference strategies', () => {
558
+ it('should infer module name from explicit module markers', () => {
559
+ const report = makeReport({
560
+ dependencyGraph: {
561
+ nodes: [
562
+ 'src/modules/users/users.service.ts',
563
+ 'src/modules/auth/auth.service.ts',
564
+ 'src/features/notifications/notifier.ts',
565
+ ],
566
+ edges: [],
567
+ },
568
+ });
569
+ const plan = makePlan();
570
+
571
+ const result = enricher.enrich(report, plan, {
572
+ primary: 'TypeScript',
573
+ languages: ['TypeScript'],
574
+ frameworks: ['NestJS'],
575
+ hasBackend: true,
576
+ hasFrontend: false,
577
+ hasMobile: false,
578
+ hasDatabase: true,
579
+ testFramework: 'Jest',
580
+ packageManager: 'npm',
581
+ }, tempDir);
582
+
583
+ const moduleNames = result.modules.map(m => m.name);
584
+ expect(moduleNames).toContain('users');
585
+ expect(moduleNames).toContain('auth');
586
+ expect(moduleNames).toContain('notifications');
587
+ });
588
+
589
+ it('should infer module name from Django app pattern', () => {
590
+ const report = makeReport({
591
+ dependencyGraph: {
592
+ nodes: [
593
+ 'apps/users/views.py',
594
+ 'apps/users/models.py',
595
+ 'apps/posts/views.py',
596
+ ],
597
+ edges: [],
598
+ },
599
+ });
600
+ const plan = makePlan();
601
+
602
+ const result = enricher.enrich(report, plan, {
603
+ primary: 'Python',
604
+ languages: ['Python'],
605
+ frameworks: ['Django'],
606
+ hasBackend: true,
607
+ hasFrontend: false,
608
+ hasMobile: false,
609
+ hasDatabase: true,
610
+ testFramework: 'pytest',
611
+ packageManager: 'pip',
612
+ }, tempDir);
613
+
614
+ const moduleNames = result.modules.map(m => m.name);
615
+ expect(moduleNames).toContain('users');
616
+ expect(moduleNames).toContain('posts');
617
+ });
618
+
619
+ it('should infer module name from clean architecture layers', () => {
620
+ const report = makeReport({
621
+ dependencyGraph: {
622
+ nodes: [
623
+ 'src/domain/entities/user.entity.ts',
624
+ 'src/application/services/user.service.ts',
625
+ 'src/infrastructure/persistence/user.repository.ts',
626
+ ],
627
+ edges: [],
628
+ },
629
+ });
630
+ const plan = makePlan();
631
+
632
+ const result = enricher.enrich(report, plan, {
633
+ primary: 'TypeScript',
634
+ languages: ['TypeScript'],
635
+ frameworks: ['NestJS'],
636
+ hasBackend: true,
637
+ hasFrontend: false,
638
+ hasMobile: false,
639
+ hasDatabase: true,
640
+ testFramework: 'Jest',
641
+ packageManager: 'npm',
642
+ }, tempDir);
643
+
644
+ // Should infer modules related to user entity
645
+ expect(result.modules.length).toBeGreaterThan(0);
646
+ });
647
+
648
+ it('should handle Java package structure', () => {
649
+ const report = makeReport({
650
+ dependencyGraph: {
651
+ nodes: [
652
+ 'src/main/java/com/example/users/User.java',
653
+ 'src/main/java/com/example/users/UserService.java',
654
+ 'src/main/java/com/example/auth/AuthService.java',
655
+ ],
656
+ edges: [],
657
+ },
658
+ });
659
+ const plan = makePlan();
660
+
661
+ const result = enricher.enrich(report, plan, {
662
+ primary: 'Java',
663
+ languages: ['Java'],
664
+ frameworks: ['Spring Boot'],
665
+ hasBackend: true,
666
+ hasFrontend: false,
667
+ hasMobile: false,
668
+ hasDatabase: true,
669
+ testFramework: 'JUnit',
670
+ packageManager: 'maven',
671
+ }, tempDir);
672
+
673
+ const moduleNames = result.modules.map(m => m.name);
674
+ expect(moduleNames.length).toBeGreaterThan(0);
675
+ });
676
+ });
677
+
678
+ describe('Entity and controller detection', () => {
679
+ it('should detect entity files', () => {
680
+ const report = makeReport({
681
+ dependencyGraph: {
682
+ nodes: [
683
+ 'src/modules/users/entities/user.entity.ts',
684
+ 'src/modules/users/models/user.model.ts',
685
+ 'src/modules/users/user.service.ts',
686
+ ],
687
+ edges: [],
688
+ },
689
+ });
690
+ const plan = makePlan();
691
+
692
+ const result = enricher.enrich(report, plan, {
693
+ primary: 'TypeScript',
694
+ languages: ['TypeScript'],
695
+ frameworks: ['NestJS'],
696
+ hasBackend: true,
697
+ hasFrontend: false,
698
+ hasMobile: false,
699
+ hasDatabase: true,
700
+ testFramework: 'Jest',
701
+ packageManager: 'npm',
702
+ }, tempDir);
703
+
704
+ const usersModule = result.modules.find(m => m.name === 'users');
705
+ expect(usersModule).toBeDefined();
706
+ expect(usersModule!.entities.length).toBeGreaterThan(0);
707
+ expect(usersModule!.entities.some(e => e.includes('User'))).toBe(true);
708
+ });
709
+
710
+ it('should detect controller files', () => {
711
+ const report = makeReport({
712
+ dependencyGraph: {
713
+ nodes: [
714
+ 'src/modules/users/users.controller.ts',
715
+ 'src/modules/auth/auth.controller.ts',
716
+ 'src/modules/users/users.service.ts',
717
+ ],
718
+ edges: [],
719
+ },
720
+ });
721
+ const plan = makePlan();
722
+
723
+ const result = enricher.enrich(report, plan, {
724
+ primary: 'TypeScript',
725
+ languages: ['TypeScript'],
726
+ frameworks: ['NestJS'],
727
+ hasBackend: true,
728
+ hasFrontend: false,
729
+ hasMobile: false,
730
+ hasDatabase: true,
731
+ testFramework: 'Jest',
732
+ packageManager: 'npm',
733
+ }, tempDir);
734
+
735
+ const usersModule = result.modules.find(m => m.name === 'users');
736
+ expect(usersModule).toBeDefined();
737
+ expect(usersModule!.controllers.length).toBeGreaterThan(0);
738
+ });
739
+
740
+ it('should detect service files', () => {
741
+ const report = makeReport({
742
+ dependencyGraph: {
743
+ nodes: [
744
+ 'src/modules/users/users.service.ts',
745
+ 'src/modules/auth/auth.service.ts',
746
+ 'src/modules/users/users.controller.ts',
747
+ ],
748
+ edges: [],
749
+ },
750
+ });
751
+ const plan = makePlan();
752
+
753
+ const result = enricher.enrich(report, plan, {
754
+ primary: 'TypeScript',
755
+ languages: ['TypeScript'],
756
+ frameworks: ['NestJS'],
757
+ hasBackend: true,
758
+ hasFrontend: false,
759
+ hasMobile: false,
760
+ hasDatabase: true,
761
+ testFramework: 'Jest',
762
+ packageManager: 'npm',
763
+ }, tempDir);
764
+
765
+ const usersModule = result.modules.find(m => m.name === 'users');
766
+ expect(usersModule).toBeDefined();
767
+ expect(usersModule!.services.length).toBeGreaterThan(0);
768
+ });
769
+ });
770
+
771
+ describe('Smart descriptions for patterns', () => {
772
+ it('should generate description for routes/controllers', () => {
773
+ const report = makeReport({
774
+ dependencyGraph: {
775
+ nodes: ['src/modules/routes/app.routes.ts'],
776
+ edges: [],
777
+ },
778
+ });
779
+ const plan = makePlan();
780
+
781
+ const result = enricher.enrich(report, plan, {
782
+ primary: 'TypeScript',
783
+ languages: ['TypeScript'],
784
+ frameworks: ['NestJS'],
785
+ hasBackend: true,
786
+ hasFrontend: false,
787
+ hasMobile: false,
788
+ hasDatabase: true,
789
+ testFramework: 'Jest',
790
+ packageManager: 'npm',
791
+ }, tempDir);
792
+
793
+ const routesModule = result.modules.find(m => m.name === 'routes');
794
+ expect(routesModule).toBeDefined();
795
+ expect(routesModule!.description).toContain('rotas');
796
+ });
797
+
798
+ it('should generate description for services', () => {
799
+ const report = makeReport({
800
+ dependencyGraph: {
801
+ nodes: ['src/modules/services/payment.service.ts'],
802
+ edges: [],
803
+ },
804
+ });
805
+ const plan = makePlan();
806
+
807
+ const result = enricher.enrich(report, plan, {
808
+ primary: 'TypeScript',
809
+ languages: ['TypeScript'],
810
+ frameworks: ['NestJS'],
811
+ hasBackend: true,
812
+ hasFrontend: false,
813
+ hasMobile: false,
814
+ hasDatabase: true,
815
+ testFramework: 'Jest',
816
+ packageManager: 'npm',
817
+ }, tempDir);
818
+
819
+ const servicesModule = result.modules.find(m => m.name === 'services');
820
+ expect(servicesModule).toBeDefined();
821
+ expect(servicesModule!.description).toContain('Serviços');
822
+ });
823
+
824
+ it('should generate description for auth modules', () => {
825
+ const report = makeReport({
826
+ dependencyGraph: {
827
+ nodes: ['src/modules/auth/auth.service.ts'],
828
+ edges: [],
829
+ },
830
+ });
831
+ const plan = makePlan();
832
+
833
+ const result = enricher.enrich(report, plan, {
834
+ primary: 'TypeScript',
835
+ languages: ['TypeScript'],
836
+ frameworks: ['NestJS'],
837
+ hasBackend: true,
838
+ hasFrontend: false,
839
+ hasMobile: false,
840
+ hasDatabase: true,
841
+ testFramework: 'Jest',
842
+ packageManager: 'npm',
843
+ }, tempDir);
844
+
845
+ const authModule = result.modules.find(m => m.name === 'auth');
846
+ expect(authModule).toBeDefined();
847
+ expect(authModule!.description.toLowerCase()).toContain('autenticação');
848
+ });
849
+
850
+ it('should include composition info in descriptions', () => {
851
+ const report = makeReport({
852
+ dependencyGraph: {
853
+ nodes: [
854
+ 'src/modules/users/users.controller.ts',
855
+ 'src/modules/users/users.service.ts',
856
+ 'src/modules/users/entities/user.entity.ts',
857
+ ],
858
+ edges: [],
859
+ },
860
+ });
861
+ const plan = makePlan();
862
+
863
+ const result = enricher.enrich(report, plan, {
864
+ primary: 'TypeScript',
865
+ languages: ['TypeScript'],
866
+ frameworks: ['NestJS'],
867
+ hasBackend: true,
868
+ hasFrontend: false,
869
+ hasMobile: false,
870
+ hasDatabase: true,
871
+ testFramework: 'Jest',
872
+ packageManager: 'npm',
873
+ }, tempDir);
874
+
875
+ const usersModule = result.modules.find(m => m.name === 'users');
876
+ expect(usersModule).toBeDefined();
877
+ // Should include composition info (endpoints, services, entities)
878
+ expect(usersModule!.description).toMatch(/endpoint|service|entit/i);
879
+ });
880
+ });
881
+
882
+ describe('Line counting edge cases', () => {
883
+ it('should handle missing files gracefully', () => {
884
+ const report = makeReport({
885
+ dependencyGraph: {
886
+ nodes: ['src/nonexistent/file.ts'],
887
+ edges: [],
888
+ },
889
+ });
890
+ const plan = makePlan();
891
+
892
+ const result = enricher.enrich(report, plan, {
893
+ primary: 'TypeScript',
894
+ languages: ['TypeScript'],
895
+ frameworks: ['NestJS'],
896
+ hasBackend: true,
897
+ hasFrontend: false,
898
+ hasMobile: false,
899
+ hasDatabase: true,
900
+ testFramework: 'Jest',
901
+ packageManager: 'npm',
902
+ }, tempDir);
903
+
904
+ // Should not crash, modules should exist
905
+ expect(result.modules).toBeDefined();
906
+ });
907
+
908
+ it('should handle empty files', () => {
909
+ const subdir = join(tempDir, 'src', 'modules', 'empty');
910
+ mkdirSync(subdir, { recursive: true });
911
+ const filePath = join(subdir, 'empty.ts');
912
+ writeFileSync(filePath, '');
913
+
914
+ const report = makeReport({
915
+ dependencyGraph: {
916
+ nodes: ['src/modules/empty/empty.ts'],
917
+ edges: [],
918
+ },
919
+ });
920
+ const plan = makePlan();
921
+
922
+ const result = enricher.enrich(report, plan, {
923
+ primary: 'TypeScript',
924
+ languages: ['TypeScript'],
925
+ frameworks: ['NestJS'],
926
+ hasBackend: true,
927
+ hasFrontend: false,
928
+ hasMobile: false,
929
+ hasDatabase: true,
930
+ testFramework: 'Jest',
931
+ packageManager: 'npm',
932
+ }, tempDir);
933
+
934
+ const emptyModule = result.modules.find(m => m.name === 'empty');
935
+ expect(emptyModule).toBeDefined();
936
+ expect(emptyModule!.lineCount).toBe(0);
937
+ });
938
+
939
+ it('should count lines in files with various line endings', () => {
940
+ const subdir = join(tempDir, 'src', 'modules', 'mixed');
941
+ mkdirSync(subdir, { recursive: true });
942
+ const filePath = join(subdir, 'mixed.ts');
943
+ // 5 lines
944
+ writeFileSync(filePath, 'line1\nline2\nline3\nline4\nline5');
945
+
946
+ const report = makeReport({
947
+ dependencyGraph: {
948
+ nodes: ['src/modules/mixed/mixed.ts'],
949
+ edges: [],
950
+ },
951
+ });
952
+ const plan = makePlan();
953
+
954
+ const result = enricher.enrich(report, plan, {
955
+ primary: 'TypeScript',
956
+ languages: ['TypeScript'],
957
+ frameworks: ['NestJS'],
958
+ hasBackend: true,
959
+ hasFrontend: false,
960
+ hasMobile: false,
961
+ hasDatabase: true,
962
+ testFramework: 'Jest',
963
+ packageManager: 'npm',
964
+ }, tempDir);
965
+
966
+ const mixedModule = result.modules.find(m => m.name === 'mixed');
967
+ expect(mixedModule).toBeDefined();
968
+ expect(mixedModule!.lineCount).toBeGreaterThan(0);
969
+ });
970
+ });
971
+ });