ai-first-cli 1.3.1 → 1.3.6

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 (514) hide show
  1. package/.ai-dev/index.db +0 -0
  2. package/CHANGELOG.md +241 -0
  3. package/PHASE1_USER_SIMULATION.md +56 -0
  4. package/PHASE2_USER_SIMULATION.md +81 -0
  5. package/PHASE3_USER_SIMULATION.md +176 -0
  6. package/README.es.md +73 -0
  7. package/README.md +119 -15
  8. package/ai/graph/knowledge-graph.json +10 -0
  9. package/ai-context/ai_context.md +130 -0
  10. package/{test-projects/react-app/.ai-dev → ai-context}/ai_rules.md +10 -5
  11. package/ai-context/architecture.md +136 -0
  12. package/ai-context/context/features/src.json +69 -0
  13. package/ai-context/context/features/test-projects.json +69 -0
  14. package/ai-context/context/flows/ai-first.json +9 -0
  15. package/ai-context/context/flows/auth.json +13 -0
  16. package/ai-context/context/flows/doctor.json +9 -0
  17. package/ai-context/context/flows/explore.json +9 -0
  18. package/ai-context/context/flows/routes.json +15 -0
  19. package/ai-context/context/flows/user.json +23 -0
  20. package/ai-context/context/flows/views.json +12 -0
  21. package/{test-projects/react-app/.ai-dev → ai-context}/conventions.md +3 -2
  22. package/ai-context/dependencies.json +3360 -0
  23. package/ai-context/entrypoints.md +45 -0
  24. package/ai-context/index-state.json +196 -0
  25. package/ai-context/modules.json +901 -0
  26. package/ai-context/project.json +33 -0
  27. package/ai-context/repo_map.json +8857 -0
  28. package/ai-context/repo_map.md +2002 -0
  29. package/{test-projects/flask-app/.ai-dev → ai-context}/schema.json +1 -1
  30. package/ai-context/summary.md +46 -0
  31. package/ai-context/symbols.json +82467 -0
  32. package/{test-projects/react-app/.ai-dev → ai-context}/tech_stack.md +15 -7
  33. package/ai-context-evaluation-report-1774223059505.md +206 -0
  34. package/dist/analyzers/architecture.d.ts.map +1 -1
  35. package/dist/analyzers/architecture.js +78 -5
  36. package/dist/analyzers/architecture.js.map +1 -1
  37. package/dist/analyzers/entrypoints.d.ts.map +1 -1
  38. package/dist/analyzers/entrypoints.js +358 -0
  39. package/dist/analyzers/entrypoints.js.map +1 -1
  40. package/dist/analyzers/symbols.d.ts.map +1 -1
  41. package/dist/analyzers/symbols.js +119 -3
  42. package/dist/analyzers/symbols.js.map +1 -1
  43. package/dist/analyzers/techStack.d.ts +8 -0
  44. package/dist/analyzers/techStack.d.ts.map +1 -1
  45. package/dist/analyzers/techStack.js +118 -0
  46. package/dist/analyzers/techStack.js.map +1 -1
  47. package/dist/utils/fileUtils.d.ts.map +1 -1
  48. package/dist/utils/fileUtils.js +5 -0
  49. package/dist/utils/fileUtils.js.map +1 -1
  50. package/package.json +1 -1
  51. package/scripts/ai-context-evaluator.ts +440 -0
  52. package/src/analyzers/architecture.ts +83 -6
  53. package/src/analyzers/entrypoints.ts +400 -0
  54. package/src/analyzers/symbols.ts +129 -3
  55. package/src/analyzers/techStack.ts +137 -0
  56. package/src/utils/fileUtils.ts +5 -0
  57. package/tests/apex-parser.test.ts +193 -0
  58. package/tests/cli-commands-batch1.test.ts +808 -0
  59. package/tests/cli-commands-batch2.test.ts +1113 -0
  60. package/tests/cli-commands-batch3.test.ts +1128 -0
  61. package/tests/cli-index.test.ts +1007 -0
  62. package/tests/cli-init.test.ts +761 -0
  63. package/tests/entrypoints-languages.test.ts +373 -0
  64. package/tests/framework-detection.test.ts +296 -0
  65. package/tests/salesforce-apex-classes.test.ts +713 -0
  66. package/tests/salesforce-apex-triggers.test.ts +871 -0
  67. package/tests/salesforce-custom-objects.test.ts +918 -0
  68. package/tests/salesforce-flows.test.ts +710 -0
  69. package/tests/salesforce-lwc.test.ts +963 -0
  70. package/tests/salesforce-sfdx-integration.test.ts +1125 -0
  71. package/ANALISIS_COMPLETO.md +0 -424
  72. package/ANALISIS_MEJORAS.md +0 -327
  73. package/CONTRIBUTING.md +0 -89
  74. package/FLOW.md +0 -129
  75. package/TEST_RESULTS.md +0 -198
  76. package/TEST_RESULTS_COMPARATIVE.md +0 -159
  77. package/TEST_RESULTS_COMPLETE.md +0 -127
  78. package/TEST_RESULTS_COMPREHENSIVE.md +0 -208
  79. package/install.sh +0 -188
  80. package/run-all-tests.sh +0 -184
  81. package/test-ai-context-understanding.sh +0 -21
  82. package/test-projects/django-app/.ai-dev/ai_context.md +0 -92
  83. package/test-projects/django-app/.ai-dev/ai_rules.md +0 -47
  84. package/test-projects/django-app/.ai-dev/architecture.md +0 -57
  85. package/test-projects/django-app/.ai-dev/cache.json +0 -169
  86. package/test-projects/django-app/.ai-dev/context/flows/views.json +0 -10
  87. package/test-projects/django-app/.ai-dev/conventions.md +0 -51
  88. package/test-projects/django-app/.ai-dev/dependencies.json +0 -312
  89. package/test-projects/django-app/.ai-dev/entrypoints.md +0 -4
  90. package/test-projects/django-app/.ai-dev/files.json +0 -209
  91. package/test-projects/django-app/.ai-dev/graph/knowledge-graph.json +0 -36
  92. package/test-projects/django-app/.ai-dev/graph/module-graph.json +0 -145
  93. package/test-projects/django-app/.ai-dev/graph/symbol-graph.json +0 -1488
  94. package/test-projects/django-app/.ai-dev/graph/symbol-references.json +0 -1
  95. package/test-projects/django-app/.ai-dev/index-state.json +0 -294
  96. package/test-projects/django-app/.ai-dev/modules.json +0 -35
  97. package/test-projects/django-app/.ai-dev/project.json +0 -11
  98. package/test-projects/django-app/.ai-dev/repo_map.json +0 -412
  99. package/test-projects/django-app/.ai-dev/repo_map.md +0 -105
  100. package/test-projects/django-app/.ai-dev/schema.json +0 -5
  101. package/test-projects/django-app/.ai-dev/summary.md +0 -15
  102. package/test-projects/django-app/.ai-dev/symbols.json +0 -1
  103. package/test-projects/django-app/.ai-dev/tech_stack.md +0 -32
  104. package/test-projects/django-app/README.md +0 -91
  105. package/test-projects/django-app/blog/__init__.py +0 -0
  106. package/test-projects/django-app/blog/admin.py +0 -31
  107. package/test-projects/django-app/blog/models.py +0 -55
  108. package/test-projects/django-app/blog/serializers.py +0 -69
  109. package/test-projects/django-app/blog/urls.py +0 -14
  110. package/test-projects/django-app/blog/views.py +0 -96
  111. package/test-projects/django-app/django_app/__init__.py +0 -0
  112. package/test-projects/django-app/django_app/settings.py +0 -90
  113. package/test-projects/django-app/django_app/urls.py +0 -11
  114. package/test-projects/django-app/django_app/wsgi.py +0 -9
  115. package/test-projects/django-app/manage.py +0 -23
  116. package/test-projects/django-app/requirements.txt +0 -3
  117. package/test-projects/django-app/users/__init__.py +0 -0
  118. package/test-projects/django-app/users/admin.py +0 -42
  119. package/test-projects/django-app/users/models.py +0 -54
  120. package/test-projects/django-app/users/serializers.py +0 -113
  121. package/test-projects/django-app/users/urls.py +0 -13
  122. package/test-projects/django-app/users/views.py +0 -135
  123. package/test-projects/express-api/.ai-dev/ai_context.md +0 -112
  124. package/test-projects/express-api/.ai-dev/ai_rules.md +0 -50
  125. package/test-projects/express-api/.ai-dev/architecture.md +0 -62
  126. package/test-projects/express-api/.ai-dev/context/features/controllers.json +0 -13
  127. package/test-projects/express-api/.ai-dev/context/features/services.json +0 -13
  128. package/test-projects/express-api/.ai-dev/context/flows/auth.json +0 -12
  129. package/test-projects/express-api/.ai-dev/context/flows/user.json +0 -13
  130. package/test-projects/express-api/.ai-dev/conventions.md +0 -51
  131. package/test-projects/express-api/.ai-dev/dependencies.json +0 -54
  132. package/test-projects/express-api/.ai-dev/entrypoints.md +0 -17
  133. package/test-projects/express-api/.ai-dev/modules.json +0 -30
  134. package/test-projects/express-api/.ai-dev/project.json +0 -15
  135. package/test-projects/express-api/.ai-dev/repo_map.json +0 -100
  136. package/test-projects/express-api/.ai-dev/repo_map.md +0 -36
  137. package/test-projects/express-api/.ai-dev/schema.json +0 -5
  138. package/test-projects/express-api/.ai-dev/summary.md +0 -14
  139. package/test-projects/express-api/.ai-dev/symbols.json +0 -7
  140. package/test-projects/express-api/.ai-dev/tech_stack.md +0 -38
  141. package/test-projects/express-api/.ai-dev/tools.json +0 -10
  142. package/test-projects/express-api/controllers/authController.js +0 -32
  143. package/test-projects/express-api/controllers/userController.js +0 -51
  144. package/test-projects/express-api/index.js +0 -30
  145. package/test-projects/express-api/middleware/authMiddleware.js +0 -30
  146. package/test-projects/express-api/models/userRepository.js +0 -25
  147. package/test-projects/express-api/package.json +0 -18
  148. package/test-projects/express-api/services/authService.js +0 -17
  149. package/test-projects/express-api/services/userService.js +0 -28
  150. package/test-projects/fastapi-app/.ai-dev/ai_context.md +0 -89
  151. package/test-projects/fastapi-app/.ai-dev/ai_rules.md +0 -47
  152. package/test-projects/fastapi-app/.ai-dev/architecture.md +0 -39
  153. package/test-projects/fastapi-app/.ai-dev/cache.json +0 -125
  154. package/test-projects/fastapi-app/.ai-dev/conventions.md +0 -51
  155. package/test-projects/fastapi-app/.ai-dev/dependencies.json +0 -244
  156. package/test-projects/fastapi-app/.ai-dev/entrypoints.md +0 -4
  157. package/test-projects/fastapi-app/.ai-dev/files.json +0 -154
  158. package/test-projects/fastapi-app/.ai-dev/graph/knowledge-graph.json +0 -15
  159. package/test-projects/fastapi-app/.ai-dev/graph/module-graph.json +0 -78
  160. package/test-projects/fastapi-app/.ai-dev/graph/symbol-graph.json +0 -1724
  161. package/test-projects/fastapi-app/.ai-dev/graph/symbol-references.json +0 -51
  162. package/test-projects/fastapi-app/.ai-dev/index-state.json +0 -217
  163. package/test-projects/fastapi-app/.ai-dev/modules.json +0 -16
  164. package/test-projects/fastapi-app/.ai-dev/project.json +0 -9
  165. package/test-projects/fastapi-app/.ai-dev/repo_map.json +0 -298
  166. package/test-projects/fastapi-app/.ai-dev/repo_map.md +0 -74
  167. package/test-projects/fastapi-app/.ai-dev/schema.json +0 -5
  168. package/test-projects/fastapi-app/.ai-dev/summary.md +0 -12
  169. package/test-projects/fastapi-app/.ai-dev/symbols.json +0 -1
  170. package/test-projects/fastapi-app/.ai-dev/tech_stack.md +0 -32
  171. package/test-projects/fastapi-app/.ai-dev/tools.json +0 -10
  172. package/test-projects/fastapi-app/README.md +0 -118
  173. package/test-projects/fastapi-app/app/database.py +0 -21
  174. package/test-projects/fastapi-app/app/dependencies.py +0 -107
  175. package/test-projects/fastapi-app/app/main.py +0 -47
  176. package/test-projects/fastapi-app/app/models.py +0 -149
  177. package/test-projects/fastapi-app/app/routers/auth.py +0 -117
  178. package/test-projects/fastapi-app/app/routers/posts.py +0 -272
  179. package/test-projects/fastapi-app/app/schemas.py +0 -191
  180. package/test-projects/fastapi-app/requirements.txt +0 -10
  181. package/test-projects/flask-app/.ai-dev/ai_context.md +0 -94
  182. package/test-projects/flask-app/.ai-dev/ai_rules.md +0 -47
  183. package/test-projects/flask-app/.ai-dev/architecture.md +0 -49
  184. package/test-projects/flask-app/.ai-dev/cache.json +0 -157
  185. package/test-projects/flask-app/.ai-dev/context/features/app.json +0 -25
  186. package/test-projects/flask-app/.ai-dev/context/flows/routes.json +0 -14
  187. package/test-projects/flask-app/.ai-dev/conventions.md +0 -51
  188. package/test-projects/flask-app/.ai-dev/dependencies.json +0 -298
  189. package/test-projects/flask-app/.ai-dev/entrypoints.md +0 -4
  190. package/test-projects/flask-app/.ai-dev/files.json +0 -194
  191. package/test-projects/flask-app/.ai-dev/graph/knowledge-graph.json +0 -60
  192. package/test-projects/flask-app/.ai-dev/graph/module-graph.json +0 -95
  193. package/test-projects/flask-app/.ai-dev/graph/symbol-graph.json +0 -1448
  194. package/test-projects/flask-app/.ai-dev/graph/symbol-references.json +0 -45
  195. package/test-projects/flask-app/.ai-dev/index-state.json +0 -273
  196. package/test-projects/flask-app/.ai-dev/modules.json +0 -21
  197. package/test-projects/flask-app/.ai-dev/project.json +0 -13
  198. package/test-projects/flask-app/.ai-dev/repo_map.json +0 -400
  199. package/test-projects/flask-app/.ai-dev/repo_map.md +0 -98
  200. package/test-projects/flask-app/.ai-dev/summary.md +0 -13
  201. package/test-projects/flask-app/.ai-dev/symbols.json +0 -1
  202. package/test-projects/flask-app/.ai-dev/tech_stack.md +0 -32
  203. package/test-projects/flask-app/.ai-dev/tools.json +0 -10
  204. package/test-projects/flask-app/README.md +0 -129
  205. package/test-projects/flask-app/app/__init__.py +0 -46
  206. package/test-projects/flask-app/app/api/__init__.py +0 -7
  207. package/test-projects/flask-app/app/api/routes.py +0 -122
  208. package/test-projects/flask-app/app/auth/__init__.py +0 -7
  209. package/test-projects/flask-app/app/auth/forms.py +0 -52
  210. package/test-projects/flask-app/app/auth/routes.py +0 -68
  211. package/test-projects/flask-app/app/blog/__init__.py +0 -7
  212. package/test-projects/flask-app/app/blog/forms.py +0 -35
  213. package/test-projects/flask-app/app/blog/routes.py +0 -140
  214. package/test-projects/flask-app/app/main/__init__.py +0 -7
  215. package/test-projects/flask-app/app/main/routes.py +0 -88
  216. package/test-projects/flask-app/app/models.py +0 -177
  217. package/test-projects/flask-app/config.py +0 -64
  218. package/test-projects/flask-app/requirements.txt +0 -10
  219. package/test-projects/laravel-app/.ai-dev/ai_context.md +0 -97
  220. package/test-projects/laravel-app/.ai-dev/ai_rules.md +0 -47
  221. package/test-projects/laravel-app/.ai-dev/architecture.md +0 -60
  222. package/test-projects/laravel-app/.ai-dev/cache.json +0 -161
  223. package/test-projects/laravel-app/.ai-dev/context/features/app.json +0 -21
  224. package/test-projects/laravel-app/.ai-dev/context/flows/.json +0 -9
  225. package/test-projects/laravel-app/.ai-dev/context/flows/category.json +0 -12
  226. package/test-projects/laravel-app/.ai-dev/context/flows/comment.json +0 -12
  227. package/test-projects/laravel-app/.ai-dev/context/flows/post.json +0 -12
  228. package/test-projects/laravel-app/.ai-dev/context/flows/unnamed.json +0 -9
  229. package/test-projects/laravel-app/.ai-dev/conventions.md +0 -51
  230. package/test-projects/laravel-app/.ai-dev/dependencies.json +0 -6
  231. package/test-projects/laravel-app/.ai-dev/entrypoints.md +0 -4
  232. package/test-projects/laravel-app/.ai-dev/files.json +0 -199
  233. package/test-projects/laravel-app/.ai-dev/graph/knowledge-graph.json +0 -98
  234. package/test-projects/laravel-app/.ai-dev/graph/module-graph.json +0 -30
  235. package/test-projects/laravel-app/.ai-dev/graph/symbol-graph.json +0 -5
  236. package/test-projects/laravel-app/.ai-dev/graph/symbol-references.json +0 -1
  237. package/test-projects/laravel-app/.ai-dev/index-state.json +0 -280
  238. package/test-projects/laravel-app/.ai-dev/modules.json +0 -29
  239. package/test-projects/laravel-app/.ai-dev/project.json +0 -17
  240. package/test-projects/laravel-app/.ai-dev/repo_map.json +0 -419
  241. package/test-projects/laravel-app/.ai-dev/repo_map.md +0 -106
  242. package/test-projects/laravel-app/.ai-dev/schema.json +0 -5
  243. package/test-projects/laravel-app/.ai-dev/summary.md +0 -15
  244. package/test-projects/laravel-app/.ai-dev/symbols.json +0 -1
  245. package/test-projects/laravel-app/.ai-dev/tech_stack.md +0 -34
  246. package/test-projects/laravel-app/.ai-dev/tools.json +0 -10
  247. package/test-projects/laravel-app/README.md +0 -107
  248. package/test-projects/laravel-app/app/Http/Controllers/Api/CategoryController.php +0 -88
  249. package/test-projects/laravel-app/app/Http/Controllers/Api/CommentController.php +0 -56
  250. package/test-projects/laravel-app/app/Http/Controllers/Api/PostController.php +0 -174
  251. package/test-projects/laravel-app/app/Http/Controllers/Controller.php +0 -12
  252. package/test-projects/laravel-app/app/Models/Category.php +0 -34
  253. package/test-projects/laravel-app/app/Models/Comment.php +0 -51
  254. package/test-projects/laravel-app/app/Models/Post.php +0 -108
  255. package/test-projects/laravel-app/app/Models/User.php +0 -85
  256. package/test-projects/laravel-app/bootstrap/app.php +0 -25
  257. package/test-projects/laravel-app/composer.json +0 -35
  258. package/test-projects/laravel-app/routes/api.php +0 -40
  259. package/test-projects/nestjs-backend/.ai-dev/ai_context.md +0 -111
  260. package/test-projects/nestjs-backend/.ai-dev/ai_rules.md +0 -52
  261. package/test-projects/nestjs-backend/.ai-dev/architecture.md +0 -49
  262. package/test-projects/nestjs-backend/.ai-dev/cache.json +0 -169
  263. package/test-projects/nestjs-backend/.ai-dev/context/features/src.json +0 -23
  264. package/test-projects/nestjs-backend/.ai-dev/context/flows/auth.controller.json +0 -14
  265. package/test-projects/nestjs-backend/.ai-dev/context/flows/auth.json +0 -10
  266. package/test-projects/nestjs-backend/.ai-dev/context/flows/users..json +0 -10
  267. package/test-projects/nestjs-backend/.ai-dev/context/flows/users.controller.json +0 -14
  268. package/test-projects/nestjs-backend/.ai-dev/context/flows/users.json +0 -10
  269. package/test-projects/nestjs-backend/.ai-dev/conventions.md +0 -52
  270. package/test-projects/nestjs-backend/.ai-dev/dependencies.json +0 -152
  271. package/test-projects/nestjs-backend/.ai-dev/entrypoints.md +0 -18
  272. package/test-projects/nestjs-backend/.ai-dev/files.json +0 -209
  273. package/test-projects/nestjs-backend/.ai-dev/graph/knowledge-graph.json +0 -132
  274. package/test-projects/nestjs-backend/.ai-dev/graph/module-graph.json +0 -29
  275. package/test-projects/nestjs-backend/.ai-dev/graph/symbol-graph.json +0 -304
  276. package/test-projects/nestjs-backend/.ai-dev/graph/symbol-references.json +0 -5
  277. package/test-projects/nestjs-backend/.ai-dev/index-state.json +0 -294
  278. package/test-projects/nestjs-backend/.ai-dev/modules.json +0 -19
  279. package/test-projects/nestjs-backend/.ai-dev/project.json +0 -18
  280. package/test-projects/nestjs-backend/.ai-dev/repo_map.json +0 -427
  281. package/test-projects/nestjs-backend/.ai-dev/repo_map.md +0 -104
  282. package/test-projects/nestjs-backend/.ai-dev/schema.json +0 -5
  283. package/test-projects/nestjs-backend/.ai-dev/summary.md +0 -13
  284. package/test-projects/nestjs-backend/.ai-dev/symbols.json +0 -1
  285. package/test-projects/nestjs-backend/.ai-dev/tech_stack.md +0 -38
  286. package/test-projects/nestjs-backend/.ai-dev/tools.json +0 -10
  287. package/test-projects/nestjs-backend/package.json +0 -22
  288. package/test-projects/nestjs-backend/src/app.module.ts +0 -8
  289. package/test-projects/nestjs-backend/src/auth/auth.controller.ts +0 -22
  290. package/test-projects/nestjs-backend/src/auth/auth.module.ts +0 -11
  291. package/test-projects/nestjs-backend/src/auth/auth.service.ts +0 -28
  292. package/test-projects/nestjs-backend/src/auth/dto/login.dto.ts +0 -4
  293. package/test-projects/nestjs-backend/src/auth/strategies/jwt.strategy.ts +0 -18
  294. package/test-projects/nestjs-backend/src/main.ts +0 -9
  295. package/test-projects/nestjs-backend/src/users/users.controller.ts +0 -32
  296. package/test-projects/nestjs-backend/src/users/users.module.ts +0 -10
  297. package/test-projects/nestjs-backend/src/users/users.service.ts +0 -42
  298. package/test-projects/nestjs-backend/tsconfig.json +0 -21
  299. package/test-projects/python-cli/.ai-dev/ai_context.md +0 -95
  300. package/test-projects/python-cli/.ai-dev/ai_rules.md +0 -47
  301. package/test-projects/python-cli/.ai-dev/architecture.md +0 -55
  302. package/test-projects/python-cli/.ai-dev/cache.json +0 -149
  303. package/test-projects/python-cli/.ai-dev/context/features/cli.json +0 -16
  304. package/test-projects/python-cli/.ai-dev/context/flows/list_.json +0 -9
  305. package/test-projects/python-cli/.ai-dev/context/flows/remove_.json +0 -9
  306. package/test-projects/python-cli/.ai-dev/conventions.md +0 -51
  307. package/test-projects/python-cli/.ai-dev/dependencies.json +0 -66
  308. package/test-projects/python-cli/.ai-dev/entrypoints.md +0 -4
  309. package/test-projects/python-cli/.ai-dev/files.json +0 -184
  310. package/test-projects/python-cli/.ai-dev/graph/knowledge-graph.json +0 -83
  311. package/test-projects/python-cli/.ai-dev/graph/module-graph.json +0 -31
  312. package/test-projects/python-cli/.ai-dev/graph/symbol-graph.json +0 -358
  313. package/test-projects/python-cli/.ai-dev/graph/symbol-references.json +0 -11
  314. package/test-projects/python-cli/.ai-dev/index-state.json +0 -259
  315. package/test-projects/python-cli/.ai-dev/modules.json +0 -21
  316. package/test-projects/python-cli/.ai-dev/project.json +0 -15
  317. package/test-projects/python-cli/.ai-dev/repo_map.json +0 -367
  318. package/test-projects/python-cli/.ai-dev/repo_map.md +0 -93
  319. package/test-projects/python-cli/.ai-dev/schema.json +0 -5
  320. package/test-projects/python-cli/.ai-dev/summary.md +0 -14
  321. package/test-projects/python-cli/.ai-dev/symbols.json +0 -1
  322. package/test-projects/python-cli/.ai-dev/tech_stack.md +0 -32
  323. package/test-projects/python-cli/.ai-dev/tools.json +0 -10
  324. package/test-projects/python-cli/__init__.py +0 -1
  325. package/test-projects/python-cli/cli/__init__.py +0 -1
  326. package/test-projects/python-cli/cli/add_command.py +0 -6
  327. package/test-projects/python-cli/cli/list_command.py +0 -7
  328. package/test-projects/python-cli/cli/remove_command.py +0 -6
  329. package/test-projects/python-cli/main.py +0 -34
  330. package/test-projects/python-cli/models/__init__.py +0 -2
  331. package/test-projects/python-cli/models/task.py +0 -19
  332. package/test-projects/python-cli/models/task_repository.py +0 -44
  333. package/test-projects/rails-app/.ai-dev/ai_context.md +0 -94
  334. package/test-projects/rails-app/.ai-dev/ai_rules.md +0 -47
  335. package/test-projects/rails-app/.ai-dev/architecture.md +0 -49
  336. package/test-projects/rails-app/.ai-dev/cache.json +0 -193
  337. package/test-projects/rails-app/.ai-dev/context/features/app.json +0 -24
  338. package/test-projects/rails-app/.ai-dev/context/features/config.json +0 -13
  339. package/test-projects/rails-app/.ai-dev/context/flows/application.json +0 -9
  340. package/test-projects/rails-app/.ai-dev/context/flows/application_.json +0 -9
  341. package/test-projects/rails-app/.ai-dev/context/flows/comments.json +0 -11
  342. package/test-projects/rails-app/.ai-dev/context/flows/comments_.json +0 -11
  343. package/test-projects/rails-app/.ai-dev/context/flows/posts.json +0 -11
  344. package/test-projects/rails-app/.ai-dev/context/flows/posts_.json +0 -11
  345. package/test-projects/rails-app/.ai-dev/context/flows/routes.json +0 -9
  346. package/test-projects/rails-app/.ai-dev/context/flows/users.json +0 -11
  347. package/test-projects/rails-app/.ai-dev/context/flows/users_.json +0 -11
  348. package/test-projects/rails-app/.ai-dev/conventions.md +0 -51
  349. package/test-projects/rails-app/.ai-dev/dependencies.json +0 -6
  350. package/test-projects/rails-app/.ai-dev/entrypoints.md +0 -4
  351. package/test-projects/rails-app/.ai-dev/files.json +0 -239
  352. package/test-projects/rails-app/.ai-dev/graph/knowledge-graph.json +0 -130
  353. package/test-projects/rails-app/.ai-dev/graph/module-graph.json +0 -27
  354. package/test-projects/rails-app/.ai-dev/graph/symbol-graph.json +0 -5
  355. package/test-projects/rails-app/.ai-dev/graph/symbol-references.json +0 -1
  356. package/test-projects/rails-app/.ai-dev/index-state.json +0 -336
  357. package/test-projects/rails-app/.ai-dev/modules.json +0 -26
  358. package/test-projects/rails-app/.ai-dev/project.json +0 -22
  359. package/test-projects/rails-app/.ai-dev/repo_map.json +0 -486
  360. package/test-projects/rails-app/.ai-dev/repo_map.md +0 -117
  361. package/test-projects/rails-app/.ai-dev/schema.json +0 -5
  362. package/test-projects/rails-app/.ai-dev/summary.md +0 -13
  363. package/test-projects/rails-app/.ai-dev/symbols.json +0 -1
  364. package/test-projects/rails-app/.ai-dev/tech_stack.md +0 -32
  365. package/test-projects/rails-app/.ai-dev/tools.json +0 -10
  366. package/test-projects/rails-app/Gemfile +0 -38
  367. package/test-projects/rails-app/README.md +0 -140
  368. package/test-projects/rails-app/Rakefile +0 -8
  369. package/test-projects/rails-app/app/controllers/api/comments_controller.rb +0 -75
  370. package/test-projects/rails-app/app/controllers/api/posts_controller.rb +0 -68
  371. package/test-projects/rails-app/app/controllers/api/users_controller.rb +0 -54
  372. package/test-projects/rails-app/app/controllers/application_controller.rb +0 -31
  373. package/test-projects/rails-app/app/models/comment.rb +0 -34
  374. package/test-projects/rails-app/app/models/post.rb +0 -36
  375. package/test-projects/rails-app/app/models/user.rb +0 -28
  376. package/test-projects/rails-app/app/services/post_service.rb +0 -92
  377. package/test-projects/rails-app/app/services/user_service.rb +0 -76
  378. package/test-projects/rails-app/config/application.rb +0 -27
  379. package/test-projects/rails-app/config/environment.rb +0 -7
  380. package/test-projects/rails-app/config/routes.rb +0 -15
  381. package/test-projects/react-app/.ai-dev/ai_context.md +0 -96
  382. package/test-projects/react-app/.ai-dev/architecture.md +0 -39
  383. package/test-projects/react-app/.ai-dev/cache.json +0 -153
  384. package/test-projects/react-app/.ai-dev/context/features/src.json +0 -18
  385. package/test-projects/react-app/.ai-dev/context/flows/UsersPage.json +0 -14
  386. package/test-projects/react-app/.ai-dev/context/flows/dashboard.json +0 -9
  387. package/test-projects/react-app/.ai-dev/context/flows/login.json +0 -9
  388. package/test-projects/react-app/.ai-dev/context/flows/users.json +0 -9
  389. package/test-projects/react-app/.ai-dev/dependencies.json +0 -128
  390. package/test-projects/react-app/.ai-dev/entrypoints.md +0 -4
  391. package/test-projects/react-app/.ai-dev/files.json +0 -189
  392. package/test-projects/react-app/.ai-dev/graph/knowledge-graph.json +0 -112
  393. package/test-projects/react-app/.ai-dev/graph/module-graph.json +0 -31
  394. package/test-projects/react-app/.ai-dev/graph/symbol-graph.json +0 -868
  395. package/test-projects/react-app/.ai-dev/graph/symbol-references.json +0 -31
  396. package/test-projects/react-app/.ai-dev/index-state.json +0 -266
  397. package/test-projects/react-app/.ai-dev/modules.json +0 -17
  398. package/test-projects/react-app/.ai-dev/project.json +0 -16
  399. package/test-projects/react-app/.ai-dev/repo_map.json +0 -391
  400. package/test-projects/react-app/.ai-dev/repo_map.md +0 -94
  401. package/test-projects/react-app/.ai-dev/schema.json +0 -5
  402. package/test-projects/react-app/.ai-dev/summary.md +0 -13
  403. package/test-projects/react-app/.ai-dev/symbols.json +0 -1
  404. package/test-projects/react-app/.ai-dev/tools.json +0 -10
  405. package/test-projects/react-app/package.json +0 -16
  406. package/test-projects/react-app/src/App.tsx +0 -21
  407. package/test-projects/react-app/src/context/AuthContext.tsx +0 -41
  408. package/test-projects/react-app/src/hooks/useAuth.ts +0 -10
  409. package/test-projects/react-app/src/main.tsx +0 -10
  410. package/test-projects/react-app/src/pages/DashboardPage.tsx +0 -17
  411. package/test-projects/react-app/src/pages/LoginPage.tsx +0 -41
  412. package/test-projects/react-app/src/pages/UsersPage.tsx +0 -36
  413. package/test-projects/react-app/src/services/userService.ts +0 -37
  414. package/test-projects/salesforce-cli/.ai-dev/ai_context.md +0 -89
  415. package/test-projects/salesforce-cli/.ai-dev/ai_rules.md +0 -47
  416. package/test-projects/salesforce-cli/.ai-dev/architecture.md +0 -39
  417. package/test-projects/salesforce-cli/.ai-dev/cache.json +0 -125
  418. package/test-projects/salesforce-cli/.ai-dev/context/features/force-app.json +0 -14
  419. package/test-projects/salesforce-cli/.ai-dev/context/flows/account.json +0 -9
  420. package/test-projects/salesforce-cli/.ai-dev/context/flows/opportunity.json +0 -9
  421. package/test-projects/salesforce-cli/.ai-dev/conventions.md +0 -51
  422. package/test-projects/salesforce-cli/.ai-dev/dependencies.json +0 -6
  423. package/test-projects/salesforce-cli/.ai-dev/entrypoints.md +0 -4
  424. package/test-projects/salesforce-cli/.ai-dev/files.json +0 -154
  425. package/test-projects/salesforce-cli/.ai-dev/graph/knowledge-graph.json +0 -64
  426. package/test-projects/salesforce-cli/.ai-dev/graph/module-graph.json +0 -13
  427. package/test-projects/salesforce-cli/.ai-dev/graph/symbol-graph.json +0 -148
  428. package/test-projects/salesforce-cli/.ai-dev/graph/symbol-references.json +0 -1
  429. package/test-projects/salesforce-cli/.ai-dev/index-state.json +0 -217
  430. package/test-projects/salesforce-cli/.ai-dev/modules.json +0 -12
  431. package/test-projects/salesforce-cli/.ai-dev/project.json +0 -14
  432. package/test-projects/salesforce-cli/.ai-dev/repo_map.json +0 -328
  433. package/test-projects/salesforce-cli/.ai-dev/repo_map.md +0 -80
  434. package/test-projects/salesforce-cli/.ai-dev/schema.json +0 -5
  435. package/test-projects/salesforce-cli/.ai-dev/summary.md +0 -13
  436. package/test-projects/salesforce-cli/.ai-dev/symbols.json +0 -1
  437. package/test-projects/salesforce-cli/.ai-dev/tech_stack.md +0 -31
  438. package/test-projects/salesforce-cli/.ai-dev/tools.json +0 -10
  439. package/test-projects/salesforce-cli/.forceignore +0 -27
  440. package/test-projects/salesforce-cli/force-app/main/default/classes/AccountController.cls +0 -24
  441. package/test-projects/salesforce-cli/force-app/main/default/classes/OpportunityController.cls +0 -25
  442. package/test-projects/salesforce-cli/force-app/main/default/objects/Project__c.object.xml +0 -45
  443. package/test-projects/salesforce-cli/force-app/main/default/triggers/AccountTrigger.trigger +0 -33
  444. package/test-projects/salesforce-cli/sfdx-project.json +0 -11
  445. package/test-projects/spring-boot-app/.ai-dev/ai_context.md +0 -91
  446. package/test-projects/spring-boot-app/.ai-dev/ai_rules.md +0 -48
  447. package/test-projects/spring-boot-app/.ai-dev/architecture.md +0 -39
  448. package/test-projects/spring-boot-app/.ai-dev/cache.json +0 -173
  449. package/test-projects/spring-boot-app/.ai-dev/context/features/src.json +0 -26
  450. package/test-projects/spring-boot-app/.ai-dev/context/flows/PostController.json +0 -19
  451. package/test-projects/spring-boot-app/.ai-dev/context/flows/UserController.json +0 -19
  452. package/test-projects/spring-boot-app/.ai-dev/context/flows/comment.json +0 -11
  453. package/test-projects/spring-boot-app/.ai-dev/context/flows/post.json +0 -14
  454. package/test-projects/spring-boot-app/.ai-dev/context/flows/user.json +0 -14
  455. package/test-projects/spring-boot-app/.ai-dev/conventions.md +0 -52
  456. package/test-projects/spring-boot-app/.ai-dev/dependencies.json +0 -326
  457. package/test-projects/spring-boot-app/.ai-dev/entrypoints.md +0 -4
  458. package/test-projects/spring-boot-app/.ai-dev/files.json +0 -214
  459. package/test-projects/spring-boot-app/.ai-dev/graph/knowledge-graph.json +0 -231
  460. package/test-projects/spring-boot-app/.ai-dev/graph/module-graph.json +0 -22
  461. package/test-projects/spring-boot-app/.ai-dev/graph/symbol-graph.json +0 -794
  462. package/test-projects/spring-boot-app/.ai-dev/graph/symbol-references.json +0 -70
  463. package/test-projects/spring-boot-app/.ai-dev/index-state.json +0 -301
  464. package/test-projects/spring-boot-app/.ai-dev/modules.json +0 -21
  465. package/test-projects/spring-boot-app/.ai-dev/project.json +0 -17
  466. package/test-projects/spring-boot-app/.ai-dev/repo_map.json +0 -461
  467. package/test-projects/spring-boot-app/.ai-dev/repo_map.md +0 -109
  468. package/test-projects/spring-boot-app/.ai-dev/schema.json +0 -5
  469. package/test-projects/spring-boot-app/.ai-dev/summary.md +0 -12
  470. package/test-projects/spring-boot-app/.ai-dev/symbols.json +0 -1
  471. package/test-projects/spring-boot-app/.ai-dev/tech_stack.md +0 -32
  472. package/test-projects/spring-boot-app/.ai-dev/tools.json +0 -10
  473. package/test-projects/spring-boot-app/.classpath +0 -57
  474. package/test-projects/spring-boot-app/.factorypath +0 -69
  475. package/test-projects/spring-boot-app/.project +0 -34
  476. package/test-projects/spring-boot-app/.settings/org.eclipse.core.resources.prefs +0 -4
  477. package/test-projects/spring-boot-app/.settings/org.eclipse.jdt.apt.core.prefs +0 -4
  478. package/test-projects/spring-boot-app/.settings/org.eclipse.jdt.core.prefs +0 -10
  479. package/test-projects/spring-boot-app/.settings/org.eclipse.m2e.core.prefs +0 -4
  480. package/test-projects/spring-boot-app/README.md +0 -122
  481. package/test-projects/spring-boot-app/pom.xml +0 -79
  482. package/test-projects/spring-boot-app/src/main/java/com/example/demo/DemoApplication.java +0 -12
  483. package/test-projects/spring-boot-app/src/main/java/com/example/demo/controllers/CommentController.java +0 -89
  484. package/test-projects/spring-boot-app/src/main/java/com/example/demo/controllers/PostController.java +0 -92
  485. package/test-projects/spring-boot-app/src/main/java/com/example/demo/controllers/UserController.java +0 -84
  486. package/test-projects/spring-boot-app/src/main/java/com/example/demo/models/Comment.java +0 -38
  487. package/test-projects/spring-boot-app/src/main/java/com/example/demo/models/Post.java +0 -56
  488. package/test-projects/spring-boot-app/src/main/java/com/example/demo/models/User.java +0 -44
  489. package/test-projects/spring-boot-app/src/main/java/com/example/demo/repositories/CommentRepository.java +0 -21
  490. package/test-projects/spring-boot-app/src/main/java/com/example/demo/repositories/PostRepository.java +0 -18
  491. package/test-projects/spring-boot-app/src/main/java/com/example/demo/repositories/UserRepository.java +0 -15
  492. package/test-projects/spring-boot-app/src/main/java/com/example/demo/services/PostService.java +0 -83
  493. package/test-projects/spring-boot-app/src/main/java/com/example/demo/services/UserService.java +0 -62
  494. package/test-projects/spring-boot-app/src/main/resources/application.properties +0 -22
  495. package/test-projects/spring-boot-app/target/classes/com/example/demo/DemoApplication.class +0 -0
  496. package/test-projects/spring-boot-app/target/classes/com/example/demo/controllers/CommentController$CommentCreateRequest.class +0 -0
  497. package/test-projects/spring-boot-app/target/classes/com/example/demo/controllers/CommentController$CommentUpdateRequest.class +0 -0
  498. package/test-projects/spring-boot-app/target/classes/com/example/demo/controllers/CommentController.class +0 -0
  499. package/test-projects/spring-boot-app/target/classes/com/example/demo/controllers/PostController$PostCreateRequest.class +0 -0
  500. package/test-projects/spring-boot-app/target/classes/com/example/demo/controllers/PostController$PostUpdateRequest.class +0 -0
  501. package/test-projects/spring-boot-app/target/classes/com/example/demo/controllers/PostController.class +0 -0
  502. package/test-projects/spring-boot-app/target/classes/com/example/demo/controllers/UserController$UserCreateRequest.class +0 -0
  503. package/test-projects/spring-boot-app/target/classes/com/example/demo/controllers/UserController$UserUpdateRequest.class +0 -0
  504. package/test-projects/spring-boot-app/target/classes/com/example/demo/controllers/UserController.class +0 -0
  505. package/test-projects/spring-boot-app/target/classes/com/example/demo/models/Comment.class +0 -0
  506. package/test-projects/spring-boot-app/target/classes/com/example/demo/models/Post.class +0 -0
  507. package/test-projects/spring-boot-app/target/classes/com/example/demo/models/User.class +0 -0
  508. package/test-projects/spring-boot-app/target/classes/com/example/demo/repositories/CommentRepository.class +0 -0
  509. package/test-projects/spring-boot-app/target/classes/com/example/demo/repositories/PostRepository.class +0 -0
  510. package/test-projects/spring-boot-app/target/classes/com/example/demo/repositories/UserRepository.class +0 -0
  511. package/test-projects/spring-boot-app/target/classes/com/example/demo/services/PostService.class +0 -0
  512. package/test-projects/spring-boot-app/target/classes/com/example/demo/services/UserService.class +0 -0
  513. package/tests/e2e/run-e2e.sh +0 -88
  514. /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
+ });