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