ai-first-cli 1.3.1 → 1.3.5

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 (532) hide show
  1. package/.ai-dev/index.db +0 -0
  2. package/BETA_EVALUATION_REPORT.md +151 -0
  3. package/CHANGELOG.md +178 -0
  4. package/PHASE1_USER_SIMULATION.md +56 -0
  5. package/PHASE2_USER_SIMULATION.md +81 -0
  6. package/PHASE3_USER_SIMULATION.md +176 -0
  7. package/README.es.md +18 -0
  8. package/README.md +80 -1
  9. package/ai/graph/knowledge-graph.json +10 -0
  10. package/ai-context/ai_context.md +130 -0
  11. package/{test-projects/react-app/.ai-dev → ai-context}/ai_rules.md +10 -5
  12. package/ai-context/architecture.md +136 -0
  13. package/ai-context/context/features/src.json +69 -0
  14. package/ai-context/context/features/test-projects.json +69 -0
  15. package/ai-context/context/flows/App.json +17 -0
  16. package/ai-context/context/flows/DashboardPage.json +14 -0
  17. package/ai-context/context/flows/LoginPage.json +14 -0
  18. package/ai-context/context/flows/admin.json +10 -0
  19. package/ai-context/context/flows/ai-first.json +9 -0
  20. package/ai-context/context/flows/androidresources.json +11 -0
  21. package/ai-context/context/flows/auth.json +13 -0
  22. package/ai-context/context/flows/authController.json +14 -0
  23. package/ai-context/context/flows/doctor.json +9 -0
  24. package/ai-context/context/flows/entrypoints.json +9 -0
  25. package/ai-context/context/flows/explore.json +9 -0
  26. package/ai-context/context/flows/fastapiAdapter.json +14 -0
  27. package/ai-context/context/flows/fastapiadapter.json +11 -0
  28. package/ai-context/context/flows/index.json +19 -0
  29. package/ai-context/context/flows/indexer.json +9 -0
  30. package/ai-context/context/flows/indexstate.json +9 -0
  31. package/ai-context/context/flows/init.json +22 -0
  32. package/ai-context/context/flows/main.json +18 -0
  33. package/ai-context/context/flows/mainactivity.json +9 -0
  34. package/ai-context/context/flows/models.json +15 -0
  35. package/ai-context/context/flows/posts.json +15 -0
  36. package/ai-context/context/flows/repoMapper.json +20 -0
  37. package/ai-context/context/flows/repomapper.json +11 -0
  38. package/ai-context/context/flows/routes.json +15 -0
  39. package/ai-context/context/flows/serializers.json +10 -0
  40. package/ai-context/context/flows/user.json +23 -0
  41. package/ai-context/context/flows/views.json +12 -0
  42. package/{test-projects/react-app/.ai-dev → ai-context}/conventions.md +3 -2
  43. package/ai-context/dependencies.json +3360 -0
  44. package/ai-context/entrypoints.md +45 -0
  45. package/ai-context/index-state.json +196 -0
  46. package/ai-context/modules.json +901 -0
  47. package/ai-context/project.json +33 -0
  48. package/ai-context/repo_map.json +8857 -0
  49. package/ai-context/repo_map.md +2002 -0
  50. package/{test-projects/flask-app/.ai-dev → ai-context}/schema.json +1 -1
  51. package/ai-context/summary.md +46 -0
  52. package/ai-context/symbols.json +82467 -0
  53. package/{test-projects/react-app/.ai-dev → ai-context}/tech_stack.md +15 -7
  54. package/ai-context-evaluation-report-1774223059505.md +206 -0
  55. package/dist/analyzers/architecture.d.ts.map +1 -1
  56. package/dist/analyzers/architecture.js +6 -0
  57. package/dist/analyzers/architecture.js.map +1 -1
  58. package/dist/analyzers/entrypoints.d.ts.map +1 -1
  59. package/dist/analyzers/entrypoints.js +105 -0
  60. package/dist/analyzers/entrypoints.js.map +1 -1
  61. package/dist/analyzers/symbols.d.ts.map +1 -1
  62. package/dist/analyzers/symbols.js +72 -1
  63. package/dist/analyzers/symbols.js.map +1 -1
  64. package/dist/analyzers/techStack.d.ts +8 -0
  65. package/dist/analyzers/techStack.d.ts.map +1 -1
  66. package/dist/analyzers/techStack.js +75 -0
  67. package/dist/analyzers/techStack.js.map +1 -1
  68. package/dist/scripts/ai-context-evaluator.js +367 -0
  69. package/package.json +1 -1
  70. package/quick-evaluation-report-1774396002305.md +64 -0
  71. package/quick-evaluator.ts +200 -0
  72. package/scripts/ai-context-evaluator.ts +440 -0
  73. package/src/analyzers/architecture.ts +8 -0
  74. package/src/analyzers/entrypoints.ts +115 -0
  75. package/src/analyzers/symbols.ts +77 -1
  76. package/src/analyzers/techStack.ts +93 -0
  77. package/tests/apex-parser.test.ts +193 -0
  78. package/tests/cli-commands-batch1.test.ts +808 -0
  79. package/tests/cli-commands-batch2.test.ts +1113 -0
  80. package/tests/cli-commands-batch3.test.ts +1128 -0
  81. package/tests/cli-index.test.ts +1007 -0
  82. package/tests/cli-init.test.ts +761 -0
  83. package/tests/salesforce-apex-classes.test.ts +713 -0
  84. package/tests/salesforce-apex-triggers.test.ts +871 -0
  85. package/tests/salesforce-custom-objects.test.ts +918 -0
  86. package/tests/salesforce-flows.test.ts +710 -0
  87. package/tests/salesforce-lwc.test.ts +963 -0
  88. package/tests/salesforce-sfdx-integration.test.ts +1125 -0
  89. package/ANALISIS_COMPLETO.md +0 -424
  90. package/ANALISIS_MEJORAS.md +0 -327
  91. package/CONTRIBUTING.md +0 -89
  92. package/FLOW.md +0 -129
  93. package/TEST_RESULTS.md +0 -198
  94. package/TEST_RESULTS_COMPARATIVE.md +0 -159
  95. package/TEST_RESULTS_COMPLETE.md +0 -127
  96. package/TEST_RESULTS_COMPREHENSIVE.md +0 -208
  97. package/install.sh +0 -188
  98. package/run-all-tests.sh +0 -184
  99. package/test-ai-context-understanding.sh +0 -21
  100. package/test-projects/django-app/.ai-dev/ai_context.md +0 -92
  101. package/test-projects/django-app/.ai-dev/ai_rules.md +0 -47
  102. package/test-projects/django-app/.ai-dev/architecture.md +0 -57
  103. package/test-projects/django-app/.ai-dev/cache.json +0 -169
  104. package/test-projects/django-app/.ai-dev/context/flows/views.json +0 -10
  105. package/test-projects/django-app/.ai-dev/conventions.md +0 -51
  106. package/test-projects/django-app/.ai-dev/dependencies.json +0 -312
  107. package/test-projects/django-app/.ai-dev/entrypoints.md +0 -4
  108. package/test-projects/django-app/.ai-dev/files.json +0 -209
  109. package/test-projects/django-app/.ai-dev/graph/knowledge-graph.json +0 -36
  110. package/test-projects/django-app/.ai-dev/graph/module-graph.json +0 -145
  111. package/test-projects/django-app/.ai-dev/graph/symbol-graph.json +0 -1488
  112. package/test-projects/django-app/.ai-dev/graph/symbol-references.json +0 -1
  113. package/test-projects/django-app/.ai-dev/index-state.json +0 -294
  114. package/test-projects/django-app/.ai-dev/modules.json +0 -35
  115. package/test-projects/django-app/.ai-dev/project.json +0 -11
  116. package/test-projects/django-app/.ai-dev/repo_map.json +0 -412
  117. package/test-projects/django-app/.ai-dev/repo_map.md +0 -105
  118. package/test-projects/django-app/.ai-dev/schema.json +0 -5
  119. package/test-projects/django-app/.ai-dev/summary.md +0 -15
  120. package/test-projects/django-app/.ai-dev/symbols.json +0 -1
  121. package/test-projects/django-app/.ai-dev/tech_stack.md +0 -32
  122. package/test-projects/django-app/README.md +0 -91
  123. package/test-projects/django-app/blog/__init__.py +0 -0
  124. package/test-projects/django-app/blog/admin.py +0 -31
  125. package/test-projects/django-app/blog/models.py +0 -55
  126. package/test-projects/django-app/blog/serializers.py +0 -69
  127. package/test-projects/django-app/blog/urls.py +0 -14
  128. package/test-projects/django-app/blog/views.py +0 -96
  129. package/test-projects/django-app/django_app/__init__.py +0 -0
  130. package/test-projects/django-app/django_app/settings.py +0 -90
  131. package/test-projects/django-app/django_app/urls.py +0 -11
  132. package/test-projects/django-app/django_app/wsgi.py +0 -9
  133. package/test-projects/django-app/manage.py +0 -23
  134. package/test-projects/django-app/requirements.txt +0 -3
  135. package/test-projects/django-app/users/__init__.py +0 -0
  136. package/test-projects/django-app/users/admin.py +0 -42
  137. package/test-projects/django-app/users/models.py +0 -54
  138. package/test-projects/django-app/users/serializers.py +0 -113
  139. package/test-projects/django-app/users/urls.py +0 -13
  140. package/test-projects/django-app/users/views.py +0 -135
  141. package/test-projects/express-api/.ai-dev/ai_context.md +0 -112
  142. package/test-projects/express-api/.ai-dev/ai_rules.md +0 -50
  143. package/test-projects/express-api/.ai-dev/architecture.md +0 -62
  144. package/test-projects/express-api/.ai-dev/context/features/controllers.json +0 -13
  145. package/test-projects/express-api/.ai-dev/context/features/services.json +0 -13
  146. package/test-projects/express-api/.ai-dev/context/flows/auth.json +0 -12
  147. package/test-projects/express-api/.ai-dev/context/flows/user.json +0 -13
  148. package/test-projects/express-api/.ai-dev/conventions.md +0 -51
  149. package/test-projects/express-api/.ai-dev/dependencies.json +0 -54
  150. package/test-projects/express-api/.ai-dev/entrypoints.md +0 -17
  151. package/test-projects/express-api/.ai-dev/modules.json +0 -30
  152. package/test-projects/express-api/.ai-dev/project.json +0 -15
  153. package/test-projects/express-api/.ai-dev/repo_map.json +0 -100
  154. package/test-projects/express-api/.ai-dev/repo_map.md +0 -36
  155. package/test-projects/express-api/.ai-dev/schema.json +0 -5
  156. package/test-projects/express-api/.ai-dev/summary.md +0 -14
  157. package/test-projects/express-api/.ai-dev/symbols.json +0 -7
  158. package/test-projects/express-api/.ai-dev/tech_stack.md +0 -38
  159. package/test-projects/express-api/.ai-dev/tools.json +0 -10
  160. package/test-projects/express-api/controllers/authController.js +0 -32
  161. package/test-projects/express-api/controllers/userController.js +0 -51
  162. package/test-projects/express-api/index.js +0 -30
  163. package/test-projects/express-api/middleware/authMiddleware.js +0 -30
  164. package/test-projects/express-api/models/userRepository.js +0 -25
  165. package/test-projects/express-api/package.json +0 -18
  166. package/test-projects/express-api/services/authService.js +0 -17
  167. package/test-projects/express-api/services/userService.js +0 -28
  168. package/test-projects/fastapi-app/.ai-dev/ai_context.md +0 -89
  169. package/test-projects/fastapi-app/.ai-dev/ai_rules.md +0 -47
  170. package/test-projects/fastapi-app/.ai-dev/architecture.md +0 -39
  171. package/test-projects/fastapi-app/.ai-dev/cache.json +0 -125
  172. package/test-projects/fastapi-app/.ai-dev/conventions.md +0 -51
  173. package/test-projects/fastapi-app/.ai-dev/dependencies.json +0 -244
  174. package/test-projects/fastapi-app/.ai-dev/entrypoints.md +0 -4
  175. package/test-projects/fastapi-app/.ai-dev/files.json +0 -154
  176. package/test-projects/fastapi-app/.ai-dev/graph/knowledge-graph.json +0 -15
  177. package/test-projects/fastapi-app/.ai-dev/graph/module-graph.json +0 -78
  178. package/test-projects/fastapi-app/.ai-dev/graph/symbol-graph.json +0 -1724
  179. package/test-projects/fastapi-app/.ai-dev/graph/symbol-references.json +0 -51
  180. package/test-projects/fastapi-app/.ai-dev/index-state.json +0 -217
  181. package/test-projects/fastapi-app/.ai-dev/modules.json +0 -16
  182. package/test-projects/fastapi-app/.ai-dev/project.json +0 -9
  183. package/test-projects/fastapi-app/.ai-dev/repo_map.json +0 -298
  184. package/test-projects/fastapi-app/.ai-dev/repo_map.md +0 -74
  185. package/test-projects/fastapi-app/.ai-dev/schema.json +0 -5
  186. package/test-projects/fastapi-app/.ai-dev/summary.md +0 -12
  187. package/test-projects/fastapi-app/.ai-dev/symbols.json +0 -1
  188. package/test-projects/fastapi-app/.ai-dev/tech_stack.md +0 -32
  189. package/test-projects/fastapi-app/.ai-dev/tools.json +0 -10
  190. package/test-projects/fastapi-app/README.md +0 -118
  191. package/test-projects/fastapi-app/app/database.py +0 -21
  192. package/test-projects/fastapi-app/app/dependencies.py +0 -107
  193. package/test-projects/fastapi-app/app/main.py +0 -47
  194. package/test-projects/fastapi-app/app/models.py +0 -149
  195. package/test-projects/fastapi-app/app/routers/auth.py +0 -117
  196. package/test-projects/fastapi-app/app/routers/posts.py +0 -272
  197. package/test-projects/fastapi-app/app/schemas.py +0 -191
  198. package/test-projects/fastapi-app/requirements.txt +0 -10
  199. package/test-projects/flask-app/.ai-dev/ai_context.md +0 -94
  200. package/test-projects/flask-app/.ai-dev/ai_rules.md +0 -47
  201. package/test-projects/flask-app/.ai-dev/architecture.md +0 -49
  202. package/test-projects/flask-app/.ai-dev/cache.json +0 -157
  203. package/test-projects/flask-app/.ai-dev/context/features/app.json +0 -25
  204. package/test-projects/flask-app/.ai-dev/context/flows/routes.json +0 -14
  205. package/test-projects/flask-app/.ai-dev/conventions.md +0 -51
  206. package/test-projects/flask-app/.ai-dev/dependencies.json +0 -298
  207. package/test-projects/flask-app/.ai-dev/entrypoints.md +0 -4
  208. package/test-projects/flask-app/.ai-dev/files.json +0 -194
  209. package/test-projects/flask-app/.ai-dev/graph/knowledge-graph.json +0 -60
  210. package/test-projects/flask-app/.ai-dev/graph/module-graph.json +0 -95
  211. package/test-projects/flask-app/.ai-dev/graph/symbol-graph.json +0 -1448
  212. package/test-projects/flask-app/.ai-dev/graph/symbol-references.json +0 -45
  213. package/test-projects/flask-app/.ai-dev/index-state.json +0 -273
  214. package/test-projects/flask-app/.ai-dev/modules.json +0 -21
  215. package/test-projects/flask-app/.ai-dev/project.json +0 -13
  216. package/test-projects/flask-app/.ai-dev/repo_map.json +0 -400
  217. package/test-projects/flask-app/.ai-dev/repo_map.md +0 -98
  218. package/test-projects/flask-app/.ai-dev/summary.md +0 -13
  219. package/test-projects/flask-app/.ai-dev/symbols.json +0 -1
  220. package/test-projects/flask-app/.ai-dev/tech_stack.md +0 -32
  221. package/test-projects/flask-app/.ai-dev/tools.json +0 -10
  222. package/test-projects/flask-app/README.md +0 -129
  223. package/test-projects/flask-app/app/__init__.py +0 -46
  224. package/test-projects/flask-app/app/api/__init__.py +0 -7
  225. package/test-projects/flask-app/app/api/routes.py +0 -122
  226. package/test-projects/flask-app/app/auth/__init__.py +0 -7
  227. package/test-projects/flask-app/app/auth/forms.py +0 -52
  228. package/test-projects/flask-app/app/auth/routes.py +0 -68
  229. package/test-projects/flask-app/app/blog/__init__.py +0 -7
  230. package/test-projects/flask-app/app/blog/forms.py +0 -35
  231. package/test-projects/flask-app/app/blog/routes.py +0 -140
  232. package/test-projects/flask-app/app/main/__init__.py +0 -7
  233. package/test-projects/flask-app/app/main/routes.py +0 -88
  234. package/test-projects/flask-app/app/models.py +0 -177
  235. package/test-projects/flask-app/config.py +0 -64
  236. package/test-projects/flask-app/requirements.txt +0 -10
  237. package/test-projects/laravel-app/.ai-dev/ai_context.md +0 -97
  238. package/test-projects/laravel-app/.ai-dev/ai_rules.md +0 -47
  239. package/test-projects/laravel-app/.ai-dev/architecture.md +0 -60
  240. package/test-projects/laravel-app/.ai-dev/cache.json +0 -161
  241. package/test-projects/laravel-app/.ai-dev/context/features/app.json +0 -21
  242. package/test-projects/laravel-app/.ai-dev/context/flows/.json +0 -9
  243. package/test-projects/laravel-app/.ai-dev/context/flows/category.json +0 -12
  244. package/test-projects/laravel-app/.ai-dev/context/flows/comment.json +0 -12
  245. package/test-projects/laravel-app/.ai-dev/context/flows/post.json +0 -12
  246. package/test-projects/laravel-app/.ai-dev/context/flows/unnamed.json +0 -9
  247. package/test-projects/laravel-app/.ai-dev/conventions.md +0 -51
  248. package/test-projects/laravel-app/.ai-dev/dependencies.json +0 -6
  249. package/test-projects/laravel-app/.ai-dev/entrypoints.md +0 -4
  250. package/test-projects/laravel-app/.ai-dev/files.json +0 -199
  251. package/test-projects/laravel-app/.ai-dev/graph/knowledge-graph.json +0 -98
  252. package/test-projects/laravel-app/.ai-dev/graph/module-graph.json +0 -30
  253. package/test-projects/laravel-app/.ai-dev/graph/symbol-graph.json +0 -5
  254. package/test-projects/laravel-app/.ai-dev/graph/symbol-references.json +0 -1
  255. package/test-projects/laravel-app/.ai-dev/index-state.json +0 -280
  256. package/test-projects/laravel-app/.ai-dev/modules.json +0 -29
  257. package/test-projects/laravel-app/.ai-dev/project.json +0 -17
  258. package/test-projects/laravel-app/.ai-dev/repo_map.json +0 -419
  259. package/test-projects/laravel-app/.ai-dev/repo_map.md +0 -106
  260. package/test-projects/laravel-app/.ai-dev/schema.json +0 -5
  261. package/test-projects/laravel-app/.ai-dev/summary.md +0 -15
  262. package/test-projects/laravel-app/.ai-dev/symbols.json +0 -1
  263. package/test-projects/laravel-app/.ai-dev/tech_stack.md +0 -34
  264. package/test-projects/laravel-app/.ai-dev/tools.json +0 -10
  265. package/test-projects/laravel-app/README.md +0 -107
  266. package/test-projects/laravel-app/app/Http/Controllers/Api/CategoryController.php +0 -88
  267. package/test-projects/laravel-app/app/Http/Controllers/Api/CommentController.php +0 -56
  268. package/test-projects/laravel-app/app/Http/Controllers/Api/PostController.php +0 -174
  269. package/test-projects/laravel-app/app/Http/Controllers/Controller.php +0 -12
  270. package/test-projects/laravel-app/app/Models/Category.php +0 -34
  271. package/test-projects/laravel-app/app/Models/Comment.php +0 -51
  272. package/test-projects/laravel-app/app/Models/Post.php +0 -108
  273. package/test-projects/laravel-app/app/Models/User.php +0 -85
  274. package/test-projects/laravel-app/bootstrap/app.php +0 -25
  275. package/test-projects/laravel-app/composer.json +0 -35
  276. package/test-projects/laravel-app/routes/api.php +0 -40
  277. package/test-projects/nestjs-backend/.ai-dev/ai_context.md +0 -111
  278. package/test-projects/nestjs-backend/.ai-dev/ai_rules.md +0 -52
  279. package/test-projects/nestjs-backend/.ai-dev/architecture.md +0 -49
  280. package/test-projects/nestjs-backend/.ai-dev/cache.json +0 -169
  281. package/test-projects/nestjs-backend/.ai-dev/context/features/src.json +0 -23
  282. package/test-projects/nestjs-backend/.ai-dev/context/flows/auth.controller.json +0 -14
  283. package/test-projects/nestjs-backend/.ai-dev/context/flows/auth.json +0 -10
  284. package/test-projects/nestjs-backend/.ai-dev/context/flows/users..json +0 -10
  285. package/test-projects/nestjs-backend/.ai-dev/context/flows/users.controller.json +0 -14
  286. package/test-projects/nestjs-backend/.ai-dev/context/flows/users.json +0 -10
  287. package/test-projects/nestjs-backend/.ai-dev/conventions.md +0 -52
  288. package/test-projects/nestjs-backend/.ai-dev/dependencies.json +0 -152
  289. package/test-projects/nestjs-backend/.ai-dev/entrypoints.md +0 -18
  290. package/test-projects/nestjs-backend/.ai-dev/files.json +0 -209
  291. package/test-projects/nestjs-backend/.ai-dev/graph/knowledge-graph.json +0 -132
  292. package/test-projects/nestjs-backend/.ai-dev/graph/module-graph.json +0 -29
  293. package/test-projects/nestjs-backend/.ai-dev/graph/symbol-graph.json +0 -304
  294. package/test-projects/nestjs-backend/.ai-dev/graph/symbol-references.json +0 -5
  295. package/test-projects/nestjs-backend/.ai-dev/index-state.json +0 -294
  296. package/test-projects/nestjs-backend/.ai-dev/modules.json +0 -19
  297. package/test-projects/nestjs-backend/.ai-dev/project.json +0 -18
  298. package/test-projects/nestjs-backend/.ai-dev/repo_map.json +0 -427
  299. package/test-projects/nestjs-backend/.ai-dev/repo_map.md +0 -104
  300. package/test-projects/nestjs-backend/.ai-dev/schema.json +0 -5
  301. package/test-projects/nestjs-backend/.ai-dev/summary.md +0 -13
  302. package/test-projects/nestjs-backend/.ai-dev/symbols.json +0 -1
  303. package/test-projects/nestjs-backend/.ai-dev/tech_stack.md +0 -38
  304. package/test-projects/nestjs-backend/.ai-dev/tools.json +0 -10
  305. package/test-projects/nestjs-backend/package.json +0 -22
  306. package/test-projects/nestjs-backend/src/app.module.ts +0 -8
  307. package/test-projects/nestjs-backend/src/auth/auth.controller.ts +0 -22
  308. package/test-projects/nestjs-backend/src/auth/auth.module.ts +0 -11
  309. package/test-projects/nestjs-backend/src/auth/auth.service.ts +0 -28
  310. package/test-projects/nestjs-backend/src/auth/dto/login.dto.ts +0 -4
  311. package/test-projects/nestjs-backend/src/auth/strategies/jwt.strategy.ts +0 -18
  312. package/test-projects/nestjs-backend/src/main.ts +0 -9
  313. package/test-projects/nestjs-backend/src/users/users.controller.ts +0 -32
  314. package/test-projects/nestjs-backend/src/users/users.module.ts +0 -10
  315. package/test-projects/nestjs-backend/src/users/users.service.ts +0 -42
  316. package/test-projects/nestjs-backend/tsconfig.json +0 -21
  317. package/test-projects/python-cli/.ai-dev/ai_context.md +0 -95
  318. package/test-projects/python-cli/.ai-dev/ai_rules.md +0 -47
  319. package/test-projects/python-cli/.ai-dev/architecture.md +0 -55
  320. package/test-projects/python-cli/.ai-dev/cache.json +0 -149
  321. package/test-projects/python-cli/.ai-dev/context/features/cli.json +0 -16
  322. package/test-projects/python-cli/.ai-dev/context/flows/list_.json +0 -9
  323. package/test-projects/python-cli/.ai-dev/context/flows/remove_.json +0 -9
  324. package/test-projects/python-cli/.ai-dev/conventions.md +0 -51
  325. package/test-projects/python-cli/.ai-dev/dependencies.json +0 -66
  326. package/test-projects/python-cli/.ai-dev/entrypoints.md +0 -4
  327. package/test-projects/python-cli/.ai-dev/files.json +0 -184
  328. package/test-projects/python-cli/.ai-dev/graph/knowledge-graph.json +0 -83
  329. package/test-projects/python-cli/.ai-dev/graph/module-graph.json +0 -31
  330. package/test-projects/python-cli/.ai-dev/graph/symbol-graph.json +0 -358
  331. package/test-projects/python-cli/.ai-dev/graph/symbol-references.json +0 -11
  332. package/test-projects/python-cli/.ai-dev/index-state.json +0 -259
  333. package/test-projects/python-cli/.ai-dev/modules.json +0 -21
  334. package/test-projects/python-cli/.ai-dev/project.json +0 -15
  335. package/test-projects/python-cli/.ai-dev/repo_map.json +0 -367
  336. package/test-projects/python-cli/.ai-dev/repo_map.md +0 -93
  337. package/test-projects/python-cli/.ai-dev/schema.json +0 -5
  338. package/test-projects/python-cli/.ai-dev/summary.md +0 -14
  339. package/test-projects/python-cli/.ai-dev/symbols.json +0 -1
  340. package/test-projects/python-cli/.ai-dev/tech_stack.md +0 -32
  341. package/test-projects/python-cli/.ai-dev/tools.json +0 -10
  342. package/test-projects/python-cli/__init__.py +0 -1
  343. package/test-projects/python-cli/cli/__init__.py +0 -1
  344. package/test-projects/python-cli/cli/add_command.py +0 -6
  345. package/test-projects/python-cli/cli/list_command.py +0 -7
  346. package/test-projects/python-cli/cli/remove_command.py +0 -6
  347. package/test-projects/python-cli/main.py +0 -34
  348. package/test-projects/python-cli/models/__init__.py +0 -2
  349. package/test-projects/python-cli/models/task.py +0 -19
  350. package/test-projects/python-cli/models/task_repository.py +0 -44
  351. package/test-projects/rails-app/.ai-dev/ai_context.md +0 -94
  352. package/test-projects/rails-app/.ai-dev/ai_rules.md +0 -47
  353. package/test-projects/rails-app/.ai-dev/architecture.md +0 -49
  354. package/test-projects/rails-app/.ai-dev/cache.json +0 -193
  355. package/test-projects/rails-app/.ai-dev/context/features/app.json +0 -24
  356. package/test-projects/rails-app/.ai-dev/context/features/config.json +0 -13
  357. package/test-projects/rails-app/.ai-dev/context/flows/application.json +0 -9
  358. package/test-projects/rails-app/.ai-dev/context/flows/application_.json +0 -9
  359. package/test-projects/rails-app/.ai-dev/context/flows/comments.json +0 -11
  360. package/test-projects/rails-app/.ai-dev/context/flows/comments_.json +0 -11
  361. package/test-projects/rails-app/.ai-dev/context/flows/posts.json +0 -11
  362. package/test-projects/rails-app/.ai-dev/context/flows/posts_.json +0 -11
  363. package/test-projects/rails-app/.ai-dev/context/flows/routes.json +0 -9
  364. package/test-projects/rails-app/.ai-dev/context/flows/users.json +0 -11
  365. package/test-projects/rails-app/.ai-dev/context/flows/users_.json +0 -11
  366. package/test-projects/rails-app/.ai-dev/conventions.md +0 -51
  367. package/test-projects/rails-app/.ai-dev/dependencies.json +0 -6
  368. package/test-projects/rails-app/.ai-dev/entrypoints.md +0 -4
  369. package/test-projects/rails-app/.ai-dev/files.json +0 -239
  370. package/test-projects/rails-app/.ai-dev/graph/knowledge-graph.json +0 -130
  371. package/test-projects/rails-app/.ai-dev/graph/module-graph.json +0 -27
  372. package/test-projects/rails-app/.ai-dev/graph/symbol-graph.json +0 -5
  373. package/test-projects/rails-app/.ai-dev/graph/symbol-references.json +0 -1
  374. package/test-projects/rails-app/.ai-dev/index-state.json +0 -336
  375. package/test-projects/rails-app/.ai-dev/modules.json +0 -26
  376. package/test-projects/rails-app/.ai-dev/project.json +0 -22
  377. package/test-projects/rails-app/.ai-dev/repo_map.json +0 -486
  378. package/test-projects/rails-app/.ai-dev/repo_map.md +0 -117
  379. package/test-projects/rails-app/.ai-dev/schema.json +0 -5
  380. package/test-projects/rails-app/.ai-dev/summary.md +0 -13
  381. package/test-projects/rails-app/.ai-dev/symbols.json +0 -1
  382. package/test-projects/rails-app/.ai-dev/tech_stack.md +0 -32
  383. package/test-projects/rails-app/.ai-dev/tools.json +0 -10
  384. package/test-projects/rails-app/Gemfile +0 -38
  385. package/test-projects/rails-app/README.md +0 -140
  386. package/test-projects/rails-app/Rakefile +0 -8
  387. package/test-projects/rails-app/app/controllers/api/comments_controller.rb +0 -75
  388. package/test-projects/rails-app/app/controllers/api/posts_controller.rb +0 -68
  389. package/test-projects/rails-app/app/controllers/api/users_controller.rb +0 -54
  390. package/test-projects/rails-app/app/controllers/application_controller.rb +0 -31
  391. package/test-projects/rails-app/app/models/comment.rb +0 -34
  392. package/test-projects/rails-app/app/models/post.rb +0 -36
  393. package/test-projects/rails-app/app/models/user.rb +0 -28
  394. package/test-projects/rails-app/app/services/post_service.rb +0 -92
  395. package/test-projects/rails-app/app/services/user_service.rb +0 -76
  396. package/test-projects/rails-app/config/application.rb +0 -27
  397. package/test-projects/rails-app/config/environment.rb +0 -7
  398. package/test-projects/rails-app/config/routes.rb +0 -15
  399. package/test-projects/react-app/.ai-dev/ai_context.md +0 -96
  400. package/test-projects/react-app/.ai-dev/architecture.md +0 -39
  401. package/test-projects/react-app/.ai-dev/cache.json +0 -153
  402. package/test-projects/react-app/.ai-dev/context/features/src.json +0 -18
  403. package/test-projects/react-app/.ai-dev/context/flows/UsersPage.json +0 -14
  404. package/test-projects/react-app/.ai-dev/context/flows/dashboard.json +0 -9
  405. package/test-projects/react-app/.ai-dev/context/flows/login.json +0 -9
  406. package/test-projects/react-app/.ai-dev/context/flows/users.json +0 -9
  407. package/test-projects/react-app/.ai-dev/dependencies.json +0 -128
  408. package/test-projects/react-app/.ai-dev/entrypoints.md +0 -4
  409. package/test-projects/react-app/.ai-dev/files.json +0 -189
  410. package/test-projects/react-app/.ai-dev/graph/knowledge-graph.json +0 -112
  411. package/test-projects/react-app/.ai-dev/graph/module-graph.json +0 -31
  412. package/test-projects/react-app/.ai-dev/graph/symbol-graph.json +0 -868
  413. package/test-projects/react-app/.ai-dev/graph/symbol-references.json +0 -31
  414. package/test-projects/react-app/.ai-dev/index-state.json +0 -266
  415. package/test-projects/react-app/.ai-dev/modules.json +0 -17
  416. package/test-projects/react-app/.ai-dev/project.json +0 -16
  417. package/test-projects/react-app/.ai-dev/repo_map.json +0 -391
  418. package/test-projects/react-app/.ai-dev/repo_map.md +0 -94
  419. package/test-projects/react-app/.ai-dev/schema.json +0 -5
  420. package/test-projects/react-app/.ai-dev/summary.md +0 -13
  421. package/test-projects/react-app/.ai-dev/symbols.json +0 -1
  422. package/test-projects/react-app/.ai-dev/tools.json +0 -10
  423. package/test-projects/react-app/package.json +0 -16
  424. package/test-projects/react-app/src/App.tsx +0 -21
  425. package/test-projects/react-app/src/context/AuthContext.tsx +0 -41
  426. package/test-projects/react-app/src/hooks/useAuth.ts +0 -10
  427. package/test-projects/react-app/src/main.tsx +0 -10
  428. package/test-projects/react-app/src/pages/DashboardPage.tsx +0 -17
  429. package/test-projects/react-app/src/pages/LoginPage.tsx +0 -41
  430. package/test-projects/react-app/src/pages/UsersPage.tsx +0 -36
  431. package/test-projects/react-app/src/services/userService.ts +0 -37
  432. package/test-projects/salesforce-cli/.ai-dev/ai_context.md +0 -89
  433. package/test-projects/salesforce-cli/.ai-dev/ai_rules.md +0 -47
  434. package/test-projects/salesforce-cli/.ai-dev/architecture.md +0 -39
  435. package/test-projects/salesforce-cli/.ai-dev/cache.json +0 -125
  436. package/test-projects/salesforce-cli/.ai-dev/context/features/force-app.json +0 -14
  437. package/test-projects/salesforce-cli/.ai-dev/context/flows/account.json +0 -9
  438. package/test-projects/salesforce-cli/.ai-dev/context/flows/opportunity.json +0 -9
  439. package/test-projects/salesforce-cli/.ai-dev/conventions.md +0 -51
  440. package/test-projects/salesforce-cli/.ai-dev/dependencies.json +0 -6
  441. package/test-projects/salesforce-cli/.ai-dev/entrypoints.md +0 -4
  442. package/test-projects/salesforce-cli/.ai-dev/files.json +0 -154
  443. package/test-projects/salesforce-cli/.ai-dev/graph/knowledge-graph.json +0 -64
  444. package/test-projects/salesforce-cli/.ai-dev/graph/module-graph.json +0 -13
  445. package/test-projects/salesforce-cli/.ai-dev/graph/symbol-graph.json +0 -148
  446. package/test-projects/salesforce-cli/.ai-dev/graph/symbol-references.json +0 -1
  447. package/test-projects/salesforce-cli/.ai-dev/index-state.json +0 -217
  448. package/test-projects/salesforce-cli/.ai-dev/modules.json +0 -12
  449. package/test-projects/salesforce-cli/.ai-dev/project.json +0 -14
  450. package/test-projects/salesforce-cli/.ai-dev/repo_map.json +0 -328
  451. package/test-projects/salesforce-cli/.ai-dev/repo_map.md +0 -80
  452. package/test-projects/salesforce-cli/.ai-dev/schema.json +0 -5
  453. package/test-projects/salesforce-cli/.ai-dev/summary.md +0 -13
  454. package/test-projects/salesforce-cli/.ai-dev/symbols.json +0 -1
  455. package/test-projects/salesforce-cli/.ai-dev/tech_stack.md +0 -31
  456. package/test-projects/salesforce-cli/.ai-dev/tools.json +0 -10
  457. package/test-projects/salesforce-cli/.forceignore +0 -27
  458. package/test-projects/salesforce-cli/force-app/main/default/classes/AccountController.cls +0 -24
  459. package/test-projects/salesforce-cli/force-app/main/default/classes/OpportunityController.cls +0 -25
  460. package/test-projects/salesforce-cli/force-app/main/default/objects/Project__c.object.xml +0 -45
  461. package/test-projects/salesforce-cli/force-app/main/default/triggers/AccountTrigger.trigger +0 -33
  462. package/test-projects/salesforce-cli/sfdx-project.json +0 -11
  463. package/test-projects/spring-boot-app/.ai-dev/ai_context.md +0 -91
  464. package/test-projects/spring-boot-app/.ai-dev/ai_rules.md +0 -48
  465. package/test-projects/spring-boot-app/.ai-dev/architecture.md +0 -39
  466. package/test-projects/spring-boot-app/.ai-dev/cache.json +0 -173
  467. package/test-projects/spring-boot-app/.ai-dev/context/features/src.json +0 -26
  468. package/test-projects/spring-boot-app/.ai-dev/context/flows/PostController.json +0 -19
  469. package/test-projects/spring-boot-app/.ai-dev/context/flows/UserController.json +0 -19
  470. package/test-projects/spring-boot-app/.ai-dev/context/flows/comment.json +0 -11
  471. package/test-projects/spring-boot-app/.ai-dev/context/flows/post.json +0 -14
  472. package/test-projects/spring-boot-app/.ai-dev/context/flows/user.json +0 -14
  473. package/test-projects/spring-boot-app/.ai-dev/conventions.md +0 -52
  474. package/test-projects/spring-boot-app/.ai-dev/dependencies.json +0 -326
  475. package/test-projects/spring-boot-app/.ai-dev/entrypoints.md +0 -4
  476. package/test-projects/spring-boot-app/.ai-dev/files.json +0 -214
  477. package/test-projects/spring-boot-app/.ai-dev/graph/knowledge-graph.json +0 -231
  478. package/test-projects/spring-boot-app/.ai-dev/graph/module-graph.json +0 -22
  479. package/test-projects/spring-boot-app/.ai-dev/graph/symbol-graph.json +0 -794
  480. package/test-projects/spring-boot-app/.ai-dev/graph/symbol-references.json +0 -70
  481. package/test-projects/spring-boot-app/.ai-dev/index-state.json +0 -301
  482. package/test-projects/spring-boot-app/.ai-dev/modules.json +0 -21
  483. package/test-projects/spring-boot-app/.ai-dev/project.json +0 -17
  484. package/test-projects/spring-boot-app/.ai-dev/repo_map.json +0 -461
  485. package/test-projects/spring-boot-app/.ai-dev/repo_map.md +0 -109
  486. package/test-projects/spring-boot-app/.ai-dev/schema.json +0 -5
  487. package/test-projects/spring-boot-app/.ai-dev/summary.md +0 -12
  488. package/test-projects/spring-boot-app/.ai-dev/symbols.json +0 -1
  489. package/test-projects/spring-boot-app/.ai-dev/tech_stack.md +0 -32
  490. package/test-projects/spring-boot-app/.ai-dev/tools.json +0 -10
  491. package/test-projects/spring-boot-app/.classpath +0 -57
  492. package/test-projects/spring-boot-app/.factorypath +0 -69
  493. package/test-projects/spring-boot-app/.project +0 -34
  494. package/test-projects/spring-boot-app/.settings/org.eclipse.core.resources.prefs +0 -4
  495. package/test-projects/spring-boot-app/.settings/org.eclipse.jdt.apt.core.prefs +0 -4
  496. package/test-projects/spring-boot-app/.settings/org.eclipse.jdt.core.prefs +0 -10
  497. package/test-projects/spring-boot-app/.settings/org.eclipse.m2e.core.prefs +0 -4
  498. package/test-projects/spring-boot-app/README.md +0 -122
  499. package/test-projects/spring-boot-app/pom.xml +0 -79
  500. package/test-projects/spring-boot-app/src/main/java/com/example/demo/DemoApplication.java +0 -12
  501. package/test-projects/spring-boot-app/src/main/java/com/example/demo/controllers/CommentController.java +0 -89
  502. package/test-projects/spring-boot-app/src/main/java/com/example/demo/controllers/PostController.java +0 -92
  503. package/test-projects/spring-boot-app/src/main/java/com/example/demo/controllers/UserController.java +0 -84
  504. package/test-projects/spring-boot-app/src/main/java/com/example/demo/models/Comment.java +0 -38
  505. package/test-projects/spring-boot-app/src/main/java/com/example/demo/models/Post.java +0 -56
  506. package/test-projects/spring-boot-app/src/main/java/com/example/demo/models/User.java +0 -44
  507. package/test-projects/spring-boot-app/src/main/java/com/example/demo/repositories/CommentRepository.java +0 -21
  508. package/test-projects/spring-boot-app/src/main/java/com/example/demo/repositories/PostRepository.java +0 -18
  509. package/test-projects/spring-boot-app/src/main/java/com/example/demo/repositories/UserRepository.java +0 -15
  510. package/test-projects/spring-boot-app/src/main/java/com/example/demo/services/PostService.java +0 -83
  511. package/test-projects/spring-boot-app/src/main/java/com/example/demo/services/UserService.java +0 -62
  512. package/test-projects/spring-boot-app/src/main/resources/application.properties +0 -22
  513. package/test-projects/spring-boot-app/target/classes/com/example/demo/DemoApplication.class +0 -0
  514. package/test-projects/spring-boot-app/target/classes/com/example/demo/controllers/CommentController$CommentCreateRequest.class +0 -0
  515. package/test-projects/spring-boot-app/target/classes/com/example/demo/controllers/CommentController$CommentUpdateRequest.class +0 -0
  516. package/test-projects/spring-boot-app/target/classes/com/example/demo/controllers/CommentController.class +0 -0
  517. package/test-projects/spring-boot-app/target/classes/com/example/demo/controllers/PostController$PostCreateRequest.class +0 -0
  518. package/test-projects/spring-boot-app/target/classes/com/example/demo/controllers/PostController$PostUpdateRequest.class +0 -0
  519. package/test-projects/spring-boot-app/target/classes/com/example/demo/controllers/PostController.class +0 -0
  520. package/test-projects/spring-boot-app/target/classes/com/example/demo/controllers/UserController$UserCreateRequest.class +0 -0
  521. package/test-projects/spring-boot-app/target/classes/com/example/demo/controllers/UserController$UserUpdateRequest.class +0 -0
  522. package/test-projects/spring-boot-app/target/classes/com/example/demo/controllers/UserController.class +0 -0
  523. package/test-projects/spring-boot-app/target/classes/com/example/demo/models/Comment.class +0 -0
  524. package/test-projects/spring-boot-app/target/classes/com/example/demo/models/Post.class +0 -0
  525. package/test-projects/spring-boot-app/target/classes/com/example/demo/models/User.class +0 -0
  526. package/test-projects/spring-boot-app/target/classes/com/example/demo/repositories/CommentRepository.class +0 -0
  527. package/test-projects/spring-boot-app/target/classes/com/example/demo/repositories/PostRepository.class +0 -0
  528. package/test-projects/spring-boot-app/target/classes/com/example/demo/repositories/UserRepository.class +0 -0
  529. package/test-projects/spring-boot-app/target/classes/com/example/demo/services/PostService.class +0 -0
  530. package/test-projects/spring-boot-app/target/classes/com/example/demo/services/UserService.class +0 -0
  531. package/tests/e2e/run-e2e.sh +0 -88
  532. /package/{test-projects/django-app/.ai-dev → ai-context}/tools.json +0 -0
@@ -0,0 +1,710 @@
1
+ import { describe, it, expect, beforeAll, afterAll } from "vitest";
2
+ import { FileInfo } from "../src/core/repoScanner";
3
+ import fs from "fs";
4
+ import path from "path";
5
+ import os from "os";
6
+ import { extractSymbols } from "../src/analyzers/symbols";
7
+
8
+ const SALESFORCE_ENTERPRISE_PATH = path.join(process.cwd(), "test-projects/salesforce-enterprise");
9
+
10
+ describe("Salesforce Flows Detection", () => {
11
+ let tempDir: string;
12
+
13
+ beforeAll(() => {
14
+ tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "salesforce-flows-test-"));
15
+ });
16
+
17
+ afterAll(() => {
18
+ fs.rmSync(tempDir, { recursive: true, force: true });
19
+ });
20
+
21
+ const createFileInfo = (filePath: string, extension: string, content: string): FileInfo => {
22
+ const fullPath = path.join(tempDir, filePath);
23
+ fs.mkdirSync(path.dirname(fullPath), { recursive: true });
24
+ fs.writeFileSync(fullPath, content);
25
+
26
+ return {
27
+ path: fullPath,
28
+ relativePath: filePath,
29
+ extension,
30
+ name: filePath.split("/").pop()?.replace(`.${extension}`, "") || "",
31
+ };
32
+ };
33
+
34
+ // =========================================================================
35
+ // INTEGRATION TESTS - Using real Salesforce Enterprise test project
36
+ // =========================================================================
37
+
38
+ describe("Integration: Real Salesforce Enterprise Project", () => {
39
+ it("should detect both Flow files in the enterprise project", () => {
40
+ const flowsDir = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/flows");
41
+ const files = fs.readdirSync(flowsDir).filter(f => f.endsWith(".flow-meta.xml"));
42
+
43
+ expect(files).toHaveLength(2);
44
+ expect(files).toContain("Account_Create.flow-meta.xml");
45
+ expect(files).toContain("Opportunity_Update.flow-meta.xml");
46
+ });
47
+
48
+ it("should read both Flow files successfully", () => {
49
+ const accountCreatePath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/flows/Account_Create.flow-meta.xml");
50
+ const opportunityUpdatePath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/flows/Opportunity_Update.flow-meta.xml");
51
+
52
+ const accountCreateContent = fs.readFileSync(accountCreatePath, "utf-8");
53
+ const opportunityUpdateContent = fs.readFileSync(opportunityUpdatePath, "utf-8");
54
+
55
+ expect(accountCreateContent).toContain("<Flow xmlns=");
56
+ expect(opportunityUpdateContent).toContain("<Flow xmlns=");
57
+ });
58
+ });
59
+
60
+ // =========================================================================
61
+ // Account_Create.flow-meta.xml - Screen Flow
62
+ // =========================================================================
63
+
64
+ describe("Account_Create Flow (Screen Flow)", () => {
65
+ let accountCreateContent: string;
66
+
67
+ beforeAll(() => {
68
+ const accountCreatePath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/flows/Account_Create.flow-meta.xml");
69
+ accountCreateContent = fs.readFileSync(accountCreatePath, "utf-8");
70
+ });
71
+
72
+ it("should have correct apiVersion (59.0)", () => {
73
+ expect(accountCreateContent).toContain("<apiVersion>59.0</apiVersion>");
74
+ });
75
+
76
+ it("should have correct label (Account Create)", () => {
77
+ expect(accountCreateContent).toContain("<label>Account Create</label>");
78
+ });
79
+
80
+ it("should have processType as Flow (Screen Flow)", () => {
81
+ expect(accountCreateContent).toContain("<processType>Flow</processType>");
82
+ });
83
+
84
+ it("should have status Active", () => {
85
+ expect(accountCreateContent).toContain("<status>Active</status>");
86
+ });
87
+
88
+ describe("Screen Elements", () => {
89
+ it("should have EnterAccountDetails screen", () => {
90
+ expect(accountCreateContent).toContain("<name>EnterAccountDetails</name>");
91
+ expect(accountCreateContent).toContain("<label>Enter Account Details</label>");
92
+ });
93
+
94
+ it("should have screen location coordinates", () => {
95
+ expect(accountCreateContent).toContain("<locationX>176</locationX>");
96
+ expect(accountCreateContent).toContain("<locationY>158</locationY>");
97
+ });
98
+
99
+ it("should allow back, finish, and pause on screen", () => {
100
+ expect(accountCreateContent).toContain("<allowBack>true</allowBack>");
101
+ expect(accountCreateContent).toContain("<allowFinish>true</allowFinish>");
102
+ expect(accountCreateContent).toContain("<allowPause>true</allowPause>");
103
+ });
104
+
105
+ it("should have connector to ValidateAccountData", () => {
106
+ expect(accountCreateContent).toContain("<targetReference>ValidateAccountData</targetReference>");
107
+ });
108
+ });
109
+
110
+ describe("Input Fields", () => {
111
+ it("should have AccountName field (required)", () => {
112
+ expect(accountCreateContent).toContain("<name>AccountName</name>");
113
+ expect(accountCreateContent).toContain("<fieldType>InputField</fieldType>");
114
+ expect(accountCreateContent).toContain("<label>Account Name</label>");
115
+ expect(accountCreateContent).toContain("<required>true</required>");
116
+ expect(accountCreateContent).toContain("Enter the full legal name of the account");
117
+ });
118
+
119
+ it("should have Industry field", () => {
120
+ expect(accountCreateContent).toContain("<name>Industry</name>");
121
+ expect(accountCreateContent).toContain("<fieldType>InputField</fieldType>");
122
+ expect(accountCreateContent).toContain("<label>Industry</label>");
123
+ expect(accountCreateContent).toContain("<dataType>String</dataType>");
124
+ });
125
+
126
+ it("should have AnnualRevenue field (Currency)", () => {
127
+ expect(accountCreateContent).toContain("<name>AnnualRevenue</name>");
128
+ expect(accountCreateContent).toContain("<fieldType>InputField</fieldType>");
129
+ expect(accountCreateContent).toContain("<label>Annual Revenue</label>");
130
+ expect(accountCreateContent).toContain("<dataType>Currency</dataType>");
131
+ });
132
+
133
+ it("should have Phone field", () => {
134
+ expect(accountCreateContent).toContain("<name>Phone</name>");
135
+ expect(accountCreateContent).toContain("<fieldType>InputField</fieldType>");
136
+ expect(accountCreateContent).toContain("<label>Phone</label>");
137
+ expect(accountCreateContent).toContain("<dataType>Phone</dataType>");
138
+ });
139
+
140
+ it("should have BillingStreet field", () => {
141
+ expect(accountCreateContent).toContain("<name>BillingStreet</name>");
142
+ expect(accountCreateContent).toContain("<fieldType>InputField</fieldType>");
143
+ expect(accountCreateContent).toContain("<label>Billing Street</label>");
144
+ expect(accountCreateContent).toContain("<dataType>String</dataType>");
145
+ });
146
+
147
+ it("should have additional billing address fields", () => {
148
+ expect(accountCreateContent).toContain("<name>BillingCity</name>");
149
+ expect(accountCreateContent).toContain("<name>BillingState</name>");
150
+ expect(accountCreateContent).toContain("<name>BillingPostalCode</name>");
151
+ expect(accountCreateContent).toContain("<name>BillingCountry</name>");
152
+ });
153
+
154
+ it("should have total of 9 input fields in screen", () => {
155
+ // Count <fields> elements within the <screens> section
156
+ const screensMatch = accountCreateContent.match(/<screens>([\s\S]*?)<\/screens>/);
157
+ expect(screensMatch).toBeTruthy();
158
+ const screensContent = screensMatch?.[1] || "";
159
+ const fieldMatches = screensContent.match(/<fields>/g);
160
+ expect(fieldMatches).toHaveLength(9);
161
+ });
162
+ });
163
+
164
+ describe("Decision Elements", () => {
165
+ it("should have ValidateAccountData decision", () => {
166
+ expect(accountCreateContent).toContain("<name>ValidateAccountData</name>");
167
+ expect(accountCreateContent).toContain("<label>Validate Account Data</label>");
168
+ });
169
+
170
+ it("should have decision location coordinates", () => {
171
+ expect(accountCreateContent).toContain("<locationX>176</locationX>");
172
+ expect(accountCreateContent).toContain("<locationY>326</locationY>");
173
+ });
174
+
175
+ it("should have default connector label", () => {
176
+ expect(accountCreateContent).toContain("<defaultConnectorLabel>Default Outcome</defaultConnectorLabel>");
177
+ });
178
+
179
+ it("should have IsValidAccount rule with conditions", () => {
180
+ expect(accountCreateContent).toContain("<name>IsValidAccount</name>");
181
+ expect(accountCreateContent).toContain("<conditionLogic>and</conditionLogic>");
182
+ expect(accountCreateContent).toContain("<leftValueReference>EnterAccountDetails.AccountName</leftValueReference>");
183
+ expect(accountCreateContent).toContain("<operator>IsNull</operator>");
184
+ expect(accountCreateContent).toContain("<label>Is Valid Account</label>");
185
+ });
186
+ });
187
+
188
+ describe("Action Elements", () => {
189
+ it("should have CreateAccountRecord action", () => {
190
+ expect(accountCreateContent).toContain("<name>CreateAccountRecord</name>");
191
+ expect(accountCreateContent).toContain("<label>Create Account Record</label>");
192
+ });
193
+
194
+ it("should have action type CreateRecord", () => {
195
+ expect(accountCreateContent).toContain("<actionType>CreateRecord</actionType>");
196
+ });
197
+
198
+ it("should have input parameters mapping to screen fields", () => {
199
+ expect(accountCreateContent).toContain("<elementReference>EnterAccountDetails.AccountName</elementReference>");
200
+ expect(accountCreateContent).toContain("<elementReference>EnterAccountDetails.Industry</elementReference>");
201
+ expect(accountCreateContent).toContain("<elementReference>EnterAccountDetails.AnnualRevenue</elementReference>");
202
+ expect(accountCreateContent).toContain("<elementReference>EnterAccountDetails.Phone</elementReference>");
203
+ });
204
+
205
+ it("should target Account object", () => {
206
+ expect(accountCreateContent).toContain("<object>Account</object>");
207
+ });
208
+ });
209
+
210
+ describe("Start Element", () => {
211
+ it("should have start element with location", () => {
212
+ expect(accountCreateContent).toContain("<locationX>50</locationX>");
213
+ expect(accountCreateContent).toContain("<locationY>0</locationY>");
214
+ });
215
+
216
+ it("should start with connector to EnterAccountDetails", () => {
217
+ expect(accountCreateContent).toContain("<targetReference>EnterAccountDetails</targetReference>");
218
+ });
219
+ });
220
+ });
221
+
222
+ // =========================================================================
223
+ // Opportunity_Update.flow-meta.xml - Record-triggered Flow
224
+ // =========================================================================
225
+
226
+ describe("Opportunity_Update Flow (Record-triggered Flow)", () => {
227
+ let opportunityUpdateContent: string;
228
+
229
+ beforeAll(() => {
230
+ const opportunityUpdatePath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/flows/Opportunity_Update.flow-meta.xml");
231
+ opportunityUpdateContent = fs.readFileSync(opportunityUpdatePath, "utf-8");
232
+ });
233
+
234
+ it("should have correct apiVersion (59.0)", () => {
235
+ expect(opportunityUpdateContent).toContain("<apiVersion>59.0</apiVersion>");
236
+ });
237
+
238
+ it("should have correct label (Opportunity Update)", () => {
239
+ expect(opportunityUpdateContent).toContain("<label>Opportunity Update</label>");
240
+ });
241
+
242
+ it("should have processType as Flow (Record-triggered)", () => {
243
+ expect(opportunityUpdateContent).toContain("<processType>Flow</processType>");
244
+ });
245
+
246
+ it("should have status Active", () => {
247
+ expect(opportunityUpdateContent).toContain("<status>Active</status>");
248
+ });
249
+
250
+ describe("Trigger Elements", () => {
251
+ it("should have OnOpportunityChange trigger", () => {
252
+ expect(opportunityUpdateContent).toContain("<name>OnOpportunityChange</name>");
253
+ expect(opportunityUpdateContent).toContain("<label>When an Opportunity is updated</label>");
254
+ });
255
+
256
+ it("should have trigger location coordinates", () => {
257
+ expect(opportunityUpdateContent).toContain("<locationX>0</locationX>");
258
+ expect(opportunityUpdateContent).toContain("<locationY>0</locationY>");
259
+ });
260
+
261
+ it("should have trigger condition in Chinese (当一条记录被更新时)", () => {
262
+ expect(opportunityUpdateContent).toContain("<触发条件>When a record is updated</触发条件>");
263
+ });
264
+
265
+ it("should trigger on Opportunity object", () => {
266
+ expect(opportunityUpdateContent).toContain("<object>Opportunity</object>");
267
+ });
268
+
269
+ it("should have trigger type Upon Create or Update", () => {
270
+ expect(opportunityUpdateContent).toContain("<triggerType>Upon Create or Update</triggerType>");
271
+ });
272
+
273
+ it("should have filter on StageName IsChanged", () => {
274
+ expect(opportunityUpdateContent).toContain("<filters>");
275
+ expect(opportunityUpdateContent).toContain("<field>StageName</field>");
276
+ expect(opportunityUpdateContent).toContain("<operator>IsChanged</operator>");
277
+ expect(opportunityUpdateContent).toContain("<booleanValue>true</booleanValue>");
278
+ });
279
+ });
280
+
281
+ describe("Decision Elements", () => {
282
+ it("should have CheckStageChange decision", () => {
283
+ expect(opportunityUpdateContent).toContain("<name>CheckStageChange</name>");
284
+ expect(opportunityUpdateContent).toContain("<label>Check Stage Change</label>");
285
+ });
286
+
287
+ it("should have decision location coordinates", () => {
288
+ expect(opportunityUpdateContent).toContain("<locationX>128</locationX>");
289
+ expect(opportunityUpdateContent).toContain("<locationY>224</locationY>");
290
+ });
291
+
292
+ it("should have default connector label (No Stage Change)", () => {
293
+ expect(opportunityUpdateContent).toContain("<defaultConnectorLabel>No Stage Change</defaultConnectorLabel>");
294
+ });
295
+
296
+ it("should have StageChangedToNegotiation rule", () => {
297
+ expect(opportunityUpdateContent).toContain("<name>StageChangedToNegotiation</name>");
298
+ expect(opportunityUpdateContent).toContain("<conditionLogic>and</conditionLogic>");
299
+ expect(opportunityUpdateContent).toContain("<leftValueReference>$Opportunity.StageName</leftValueReference>");
300
+ expect(opportunityUpdateContent).toContain("<operator>Equal</operator>");
301
+ expect(opportunityUpdateContent).toContain("<stringValue>Negotiation/Review</stringValue>");
302
+ expect(opportunityUpdateContent).toContain("<label>Stage Changed to Negotiation</label>");
303
+ });
304
+
305
+ it("should have StageChangedToClosedWon rule", () => {
306
+ expect(opportunityUpdateContent).toContain("<name>StageChangedToClosedWon</name>");
307
+ expect(opportunityUpdateContent).toContain("<conditionLogic>and</conditionLogic>");
308
+ expect(opportunityUpdateContent).toContain("<leftValueReference>$Opportunity.StageName</leftValueReference>");
309
+ expect(opportunityUpdateContent).toContain("<operator>Equal</operator>");
310
+ expect(opportunityUpdateContent).toContain("<stringValue>Closed Won</stringValue>");
311
+ expect(opportunityUpdateContent).toContain("<label>Stage Changed to Closed Won</label>");
312
+ });
313
+
314
+ it("should have 2 decision rules", () => {
315
+ const ruleMatches = opportunityUpdateContent.match(/<name>StageChangedTo/g);
316
+ expect(ruleMatches).toHaveLength(2);
317
+ });
318
+ });
319
+
320
+ describe("Action Elements", () => {
321
+ it("should have UpdateProbabilityHigh action", () => {
322
+ expect(opportunityUpdateContent).toContain("<name>UpdateProbabilityHigh</name>");
323
+ expect(opportunityUpdateContent).toContain("<label>Set Probability to High</label>");
324
+ });
325
+
326
+ it("should have action type UpdateRecord", () => {
327
+ expect(opportunityUpdateContent).toContain("<actionType>UpdateRecord</actionType>");
328
+ });
329
+
330
+ it("should have OpportunityId input parameter", () => {
331
+ expect(opportunityUpdateContent).toContain("<name>OpportunityId</name>");
332
+ expect(opportunityUpdateContent).toContain("<elementReference>$Opportunity.Id</elementReference>");
333
+ });
334
+
335
+ it("should have Probability input parameter with value 90", () => {
336
+ expect(opportunityUpdateContent).toContain("<name>Probability</name>");
337
+ expect(opportunityUpdateContent).toContain("<numberValue>90</numberValue>");
338
+ });
339
+
340
+ it("should have SendWinNotification action", () => {
341
+ expect(opportunityUpdateContent).toContain("<name>SendWinNotification</name>");
342
+ expect(opportunityUpdateContent).toContain("<label>Send Win Notification</label>");
343
+ });
344
+
345
+ it("should have action type EmailAlert", () => {
346
+ expect(opportunityUpdateContent).toContain("<actionType>EmailAlert</actionType>");
347
+ });
348
+
349
+ it("should have flowTransactionModel", () => {
350
+ expect(opportunityUpdateContent).toContain("<flowTransactionModel>CurrentTransaction</flowTransactionModel>");
351
+ });
352
+ });
353
+
354
+ describe("Start Element", () => {
355
+ it("should have start element with location", () => {
356
+ expect(opportunityUpdateContent).toContain("<locationX>50</locationX>");
357
+ expect(opportunityUpdateContent).toContain("<locationY>0</locationY>");
358
+ });
359
+
360
+ it("should start with connector to CheckStageChange", () => {
361
+ expect(opportunityUpdateContent).toContain("<targetReference>CheckStageChange</targetReference>");
362
+ });
363
+ });
364
+ });
365
+
366
+ // =========================================================================
367
+ // FLOW FILE STRUCTURE VERIFICATION
368
+ // =========================================================================
369
+
370
+ describe("Flow File Structure", () => {
371
+ it("should have valid XML declaration", () => {
372
+ const accountCreatePath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/flows/Account_Create.flow-meta.xml");
373
+ const opportunityUpdatePath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/flows/Opportunity_Update.flow-meta.xml");
374
+
375
+ const accountCreateContent = fs.readFileSync(accountCreatePath, "utf-8");
376
+ const opportunityUpdateContent = fs.readFileSync(opportunityUpdatePath, "utf-8");
377
+
378
+ expect(accountCreateContent).toContain("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
379
+ expect(opportunityUpdateContent).toContain("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
380
+ });
381
+
382
+ it("should have correct Salesforce Flow namespace", () => {
383
+ const accountCreatePath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/flows/Account_Create.flow-meta.xml");
384
+ const opportunityUpdatePath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/flows/Opportunity_Update.flow-meta.xml");
385
+
386
+ const accountCreateContent = fs.readFileSync(accountCreatePath, "utf-8");
387
+ const opportunityUpdateContent = fs.readFileSync(opportunityUpdatePath, "utf-8");
388
+
389
+ expect(accountCreateContent).toContain('xmlns="http://soap.sforce.com/2006/04/metadata"');
390
+ expect(opportunityUpdateContent).toContain('xmlns="http://soap.sforce.com/2006/04/metadata"');
391
+ });
392
+
393
+ it("should have Flow root element in both files", () => {
394
+ const accountCreatePath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/flows/Account_Create.flow-meta.xml");
395
+ const opportunityUpdatePath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/flows/Opportunity_Update.flow-meta.xml");
396
+
397
+ const accountCreateContent = fs.readFileSync(accountCreatePath, "utf-8");
398
+ const opportunityUpdateContent = fs.readFileSync(opportunityUpdatePath, "utf-8");
399
+
400
+ expect(accountCreateContent).toContain("<Flow xmlns=");
401
+ expect(opportunityUpdateContent).toContain("<Flow xmlns=");
402
+ });
403
+
404
+ it("should have interviewLabel in both flows", () => {
405
+ const accountCreatePath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/flows/Account_Create.flow-meta.xml");
406
+ const opportunityUpdatePath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/flows/Opportunity_Update.flow-meta.xml");
407
+
408
+ const accountCreateContent = fs.readFileSync(accountCreatePath, "utf-8");
409
+ const opportunityUpdateContent = fs.readFileSync(opportunityUpdatePath, "utf-8");
410
+
411
+ expect(accountCreateContent).toContain("<interviewLabel>Account Create Flow-1</interviewLabel>");
412
+ expect(opportunityUpdateContent).toContain("<interviewLabel>Opportunity Update Flow-1</interviewLabel>");
413
+ });
414
+ });
415
+
416
+ // =========================================================================
417
+ // FLOW TYPES COMPARISON
418
+ // =========================================================================
419
+
420
+ describe("Flow Types Comparison", () => {
421
+ it("should distinguish Screen Flow (Account_Create) from Record-triggered Flow (Opportunity_Update)", () => {
422
+ const accountCreatePath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/flows/Account_Create.flow-meta.xml");
423
+ const opportunityUpdatePath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/flows/Opportunity_Update.flow-meta.xml");
424
+
425
+ const accountCreateContent = fs.readFileSync(accountCreatePath, "utf-8");
426
+ const opportunityUpdateContent = fs.readFileSync(opportunityUpdatePath, "utf-8");
427
+
428
+ // Account_Create has screens element (Screen Flow indicator)
429
+ expect(accountCreateContent).toContain("<screens>");
430
+ expect(accountCreateContent).not.toContain("<triggers>");
431
+
432
+ // Opportunity_Update has triggers element (Record-triggered Flow indicator)
433
+ expect(opportunityUpdateContent).toContain("<triggers>");
434
+ expect(opportunityUpdateContent).not.toContain("<screens>");
435
+ });
436
+
437
+ it("should have different start element targets based on flow type", () => {
438
+ const accountCreatePath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/flows/Account_Create.flow-meta.xml");
439
+ const opportunityUpdatePath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/flows/Opportunity_Update.flow-meta.xml");
440
+
441
+ const accountCreateContent = fs.readFileSync(accountCreatePath, "utf-8");
442
+ const opportunityUpdateContent = fs.readFileSync(opportunityUpdatePath, "utf-8");
443
+
444
+ // Account_Create starts with screen (EnterAccountDetails)
445
+ expect(accountCreateContent).toContain("<targetReference>EnterAccountDetails</targetReference>");
446
+
447
+ // Opportunity_Update starts with decision (CheckStageChange)
448
+ expect(opportunityUpdateContent).toContain("<targetReference>CheckStageChange</targetReference>");
449
+ });
450
+ });
451
+
452
+ // =========================================================================
453
+ // UNIT TESTS - Flow XML parsing patterns
454
+ // =========================================================================
455
+
456
+ describe("Unit: Flow XML parsing patterns", () => {
457
+ it("should parse Flow metadata elements", () => {
458
+ const flowXml = `<?xml version="1.0" encoding="UTF-8"?>
459
+ <Flow xmlns="http://soap.sforce.com/2006/04/metadata">
460
+ <apiVersion>59.0</apiVersion>
461
+ <interviewLabel>Test Flow-1</interviewLabel>
462
+ <label>Test Flow</label>
463
+ <processType>Flow</processType>
464
+ <status>Active</status>
465
+ </Flow>`;
466
+
467
+ expect(flowXml).toContain("<apiVersion>59.0</apiVersion>");
468
+ expect(flowXml).toContain("<label>Test Flow</label>");
469
+ expect(flowXml).toContain("<processType>Flow</processType>");
470
+ expect(flowXml).toContain("<status>Active</status>");
471
+ });
472
+
473
+ it("should parse Screen Flow elements", () => {
474
+ const screenFlowXml = `<?xml version="1.0" encoding="UTF-8"?>
475
+ <Flow xmlns="http://soap.sforce.com/2006/04/metadata">
476
+ <screens>
477
+ <name>TestScreen</name>
478
+ <label>Test Screen</label>
479
+ <fields>
480
+ <name>TestField</name>
481
+ <fieldType>InputField</fieldType>
482
+ <required>true</required>
483
+ </fields>
484
+ </screens>
485
+ </Flow>`;
486
+
487
+ expect(screenFlowXml).toContain("<screens>");
488
+ expect(screenFlowXml).toContain("<name>TestScreen</name>");
489
+ expect(screenFlowXml).toContain("<fieldType>InputField</fieldType>");
490
+ expect(screenFlowXml).toContain("<required>true</required>");
491
+ });
492
+
493
+ it("should parse Record-triggered Flow elements", () => {
494
+ const recordTriggeredFlowXml = `<?xml version="1.0" encoding="UTF-8"?>
495
+ <Flow xmlns="http://soap.sforce.com/2006/04/metadata">
496
+ <triggers>
497
+ <name>TestTrigger</name>
498
+ <object>TestObject__c</object>
499
+ <triggerType>Upon Create or Update</triggerType>
500
+ <filters>
501
+ <field>Status__c</field>
502
+ <operator>Equal</operator>
503
+ </filters>
504
+ </triggers>
505
+ </Flow>`;
506
+
507
+ expect(recordTriggeredFlowXml).toContain("<triggers>");
508
+ expect(recordTriggeredFlowXml).toContain("<name>TestTrigger</name>");
509
+ expect(recordTriggeredFlowXml).toContain("<object>TestObject__c</object>");
510
+ expect(recordTriggeredFlowXml).toContain("<triggerType>Upon Create or Update</triggerType>");
511
+ expect(recordTriggeredFlowXml).toContain("<filters>");
512
+ });
513
+
514
+ it("should parse Decision elements with rules", () => {
515
+ const decisionFlowXml = `<?xml version="1.0" encoding="UTF-8"?>
516
+ <Flow xmlns="http://soap.sforce.com/2006/04/metadata">
517
+ <decisions>
518
+ <name>CheckCondition</name>
519
+ <rules>
520
+ <name>ConditionMet</name>
521
+ <conditions>
522
+ <leftValueReference>$Record.Status</leftValueReference>
523
+ <operator>Equal</operator>
524
+ <rightValue>
525
+ <stringValue>Active</stringValue>
526
+ </rightValue>
527
+ </conditions>
528
+ </rules>
529
+ </decisions>
530
+ </Flow>`;
531
+
532
+ expect(decisionFlowXml).toContain("<decisions>");
533
+ expect(decisionFlowXml).toContain("<name>CheckCondition</name>");
534
+ expect(decisionFlowXml).toContain("<rules>");
535
+ expect(decisionFlowXml).toContain("<name>ConditionMet</name>");
536
+ expect(decisionFlowXml).toContain("<leftValueReference>$Record.Status</leftValueReference>");
537
+ expect(decisionFlowXml).toContain("<stringValue>Active</stringValue>");
538
+ });
539
+
540
+ it("should parse Action elements", () => {
541
+ const actionFlowXml = `<?xml version="1.0" encoding="UTF-8"?>
542
+ <Flow xmlns="http://soap.sforce.com/2006/04/metadata">
543
+ <actions>
544
+ <name>UpdateRecord</name>
545
+ <label>Update Record</label>
546
+ <actionType>UpdateRecord</actionType>
547
+ <inputParameters>
548
+ <name>RecordId</name>
549
+ <value>
550
+ <elementReference>$Record.Id</elementReference>
551
+ </value>
552
+ </inputParameters>
553
+ </actions>
554
+ </Flow>`;
555
+
556
+ expect(actionFlowXml).toContain("<actions>");
557
+ expect(actionFlowXml).toContain("<name>UpdateRecord</name>");
558
+ expect(actionFlowXml).toContain("<actionType>UpdateRecord</actionType>");
559
+ expect(actionFlowXml).toContain("<elementReference>$Record.Id</elementReference>");
560
+ });
561
+ });
562
+
563
+ // =========================================================================
564
+ // FLOW SYMBOL EXTRACTION
565
+ // =========================================================================
566
+
567
+ describe("Flow Symbol Extraction", () => {
568
+ it("should extract Flow file as symbol (via XML extension)", () => {
569
+ const accountCreatePath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/flows/Account_Create.flow-meta.xml");
570
+ const content = fs.readFileSync(accountCreatePath, "utf-8");
571
+
572
+ // Flow files have .flow-meta.xml extension
573
+ // The symbol extractor handles XML files through the parser registry
574
+ const file = createFileInfo("force-app/main/default/flows/Account_Create.flow-meta.xml", "flow-meta.xml", content);
575
+ const result = extractSymbols([file]);
576
+
577
+ // XML files should be parsed (at minimum, the Flow root element should be recognized)
578
+ // Note: The current symbol extractor doesn't have specific Flow XML parsing
579
+ // but it should still process the file without error
580
+ expect(result).toBeDefined();
581
+ expect(result.symbols).toBeDefined();
582
+ });
583
+
584
+ it("should detect Flow metadata via XML content parsing", () => {
585
+ const accountCreatePath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/flows/Account_Create.flow-meta.xml");
586
+ const opportunityUpdatePath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/flows/Opportunity_Update.flow-meta.xml");
587
+
588
+ const accountCreateContent = fs.readFileSync(accountCreatePath, "utf-8");
589
+ const opportunityUpdateContent = fs.readFileSync(opportunityUpdatePath, "utf-8");
590
+
591
+ // Verify we can parse Flow name from XML
592
+ const accountCreateNameMatch = accountCreateContent.match(/<interviewLabel>([^<]+)-1<\/interviewLabel>/);
593
+ const opportunityUpdateNameMatch = opportunityUpdateContent.match(/<interviewLabel>([^<]+)-1<\/interviewLabel>/);
594
+
595
+ expect(accountCreateNameMatch).toBeTruthy();
596
+ expect(accountCreateNameMatch?.[1]).toBe("Account Create Flow");
597
+ expect(opportunityUpdateNameMatch).toBeTruthy();
598
+ expect(opportunityUpdateNameMatch?.[1]).toBe("Opportunity Update Flow");
599
+ });
600
+
601
+ it("should extract Flow type from processType element", () => {
602
+ const accountCreatePath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/flows/Account_Create.flow-meta.xml");
603
+ const opportunityUpdatePath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/flows/Opportunity_Update.flow-meta.xml");
604
+
605
+ const accountCreateContent = fs.readFileSync(accountCreatePath, "utf-8");
606
+ const opportunityUpdateContent = fs.readFileSync(opportunityUpdatePath, "utf-8");
607
+
608
+ const accountCreateTypeMatch = accountCreateContent.match(/<processType>(\w+)<\/processType>/);
609
+ const opportunityUpdateTypeMatch = opportunityUpdateContent.match(/<processType>(\w+)<\/processType>/);
610
+
611
+ expect(accountCreateTypeMatch?.[1]).toBe("Flow");
612
+ expect(opportunityUpdateTypeMatch?.[1]).toBe("Flow");
613
+ });
614
+
615
+ it("should extract Flow elements (screens, triggers, decisions, actions)", () => {
616
+ const accountCreatePath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/flows/Account_Create.flow-meta.xml");
617
+ const opportunityUpdatePath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/flows/Opportunity_Update.flow-meta.xml");
618
+
619
+ const accountCreateContent = fs.readFileSync(accountCreatePath, "utf-8");
620
+ const opportunityUpdateContent = fs.readFileSync(opportunityUpdatePath, "utf-8");
621
+
622
+ // Account_Create has screens and decisions and actions
623
+ expect(accountCreateContent).toMatch(/<screens>[\s\S]*<\/screens>/);
624
+ expect(accountCreateContent).toMatch(/<decisions>[\s\S]*<\/decisions>/);
625
+ expect(accountCreateContent).toMatch(/<actions>[\s\S]*<\/actions>/);
626
+
627
+ // Opportunity_Update has triggers and decisions and actions
628
+ expect(opportunityUpdateContent).toMatch(/<triggers>[\s\S]*<\/triggers>/);
629
+ expect(opportunityUpdateContent).toMatch(/<decisions>[\s\S]*<\/decisions>/);
630
+ expect(opportunityUpdateContent).toMatch(/<actions>[\s\S]*<\/actions>/);
631
+ });
632
+ });
633
+
634
+ // =========================================================================
635
+ // EDGE CASES
636
+ // =========================================================================
637
+
638
+ describe("Edge Cases", () => {
639
+ it("should handle flows with multiple decision rules", () => {
640
+ const accountCreatePath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/flows/Account_Create.flow-meta.xml");
641
+ const content = fs.readFileSync(accountCreatePath, "utf-8");
642
+
643
+ // ValidateAccountData decision has 1 rule
644
+ const validateAccountDecision = content.match(/<name>ValidateAccountData<\/name>[\s\S]*?<\/decisions>/);
645
+ expect(validateAccountDecision).toBeTruthy();
646
+
647
+ const ruleMatches = content.match(/<name>IsValidAccount<\/name>/g);
648
+ expect(ruleMatches).toHaveLength(1);
649
+ });
650
+
651
+ it("should handle flows with multiple actions", () => {
652
+ const opportunityUpdatePath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/flows/Opportunity_Update.flow-meta.xml");
653
+ const content = fs.readFileSync(opportunityUpdatePath, "utf-8");
654
+
655
+ // Opportunity_Update has 2 action blocks
656
+ const actionMatches = content.match(/<name>UpdateProbabilityHigh<\/name>|<name>SendWinNotification<\/name>/g);
657
+ expect(actionMatches).toHaveLength(2);
658
+ });
659
+
660
+ it("should handle flows with Chinese characters in trigger condition", () => {
661
+ const opportunityUpdatePath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/flows/Opportunity_Update.flow-meta.xml");
662
+ const content = fs.readFileSync(opportunityUpdatePath, "utf-8");
663
+
664
+ // Chinese characters in XML element
665
+ expect(content).toContain("<触发条件>When a record is updated</触发条件>");
666
+ });
667
+
668
+ it("should handle flows with different field data types", () => {
669
+ const accountCreatePath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/flows/Account_Create.flow-meta.xml");
670
+ const content = fs.readFileSync(accountCreatePath, "utf-8");
671
+
672
+ // Different data types in fields
673
+ expect(content).toContain("<dataType>String</dataType>");
674
+ expect(content).toContain("<dataType>Currency</dataType>");
675
+ expect(content).toContain("<dataType>Phone</dataType>");
676
+ });
677
+
678
+ it("should handle flows with conditionLogic variations", () => {
679
+ const opportunityUpdatePath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/flows/Opportunity_Update.flow-meta.xml");
680
+ const accountCreatePath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/flows/Account_Create.flow-meta.xml");
681
+
682
+ const opportunityUpdateContent = fs.readFileSync(opportunityUpdatePath, "utf-8");
683
+ const accountCreateContent = fs.readFileSync(accountCreatePath, "utf-8");
684
+
685
+ // Both use "and" condition logic
686
+ expect(opportunityUpdateContent).toContain("<conditionLogic>and</conditionLogic>");
687
+ expect(accountCreateContent).toContain("<conditionLogic>and</conditionLogic>");
688
+ });
689
+
690
+ it("should handle flows with element references ($Record, $Opportunity)", () => {
691
+ const opportunityUpdatePath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/flows/Opportunity_Update.flow-meta.xml");
692
+ const content = fs.readFileSync(opportunityUpdatePath, "utf-8");
693
+
694
+ // Opportunity_Update uses $Opportunity variable
695
+ expect(content).toContain("$Opportunity.StageName");
696
+ expect(content).toContain("$Opportunity.Id");
697
+ });
698
+
699
+ it("should handle flows with input/output field mappings", () => {
700
+ const accountCreatePath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/flows/Account_Create.flow-meta.xml");
701
+ const content = fs.readFileSync(accountCreatePath, "utf-8");
702
+
703
+ // Element references in input parameters
704
+ expect(content).toContain("<elementReference>EnterAccountDetails.AccountName</elementReference>");
705
+ expect(content).toContain("<elementReference>EnterAccountDetails.Industry</elementReference>");
706
+ expect(content).toContain("<elementReference>EnterAccountDetails.AnnualRevenue</elementReference>");
707
+ expect(content).toContain("<elementReference>EnterAccountDetails.Phone</elementReference>");
708
+ });
709
+ });
710
+ });