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,963 @@
1
+ import { describe, it, expect, beforeAll, afterAll } from "vitest";
2
+ import { extractSymbols } from "../src/analyzers/symbols";
3
+ import { FileInfo } from "../src/core/repoScanner";
4
+ import { detectAdapter } from "../src/core/adapters/index.js";
5
+ import fs from "fs";
6
+ import path from "path";
7
+ import os from "os";
8
+
9
+ const SALESFORCE_ENTERPRISE_PATH = path.join(process.cwd(), "test-projects/salesforce-enterprise");
10
+
11
+ describe("Salesforce LWC Detection", () => {
12
+ let tempDir: string;
13
+
14
+ beforeAll(() => {
15
+ tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "lwc-test-"));
16
+ });
17
+
18
+ afterAll(() => {
19
+ fs.rmSync(tempDir, { recursive: true, force: true });
20
+ });
21
+
22
+ const createFileInfo = (filePath: string, extension: string, content: string): FileInfo => {
23
+ const fullPath = path.join(tempDir, filePath);
24
+ fs.mkdirSync(path.dirname(fullPath), { recursive: true });
25
+ fs.writeFileSync(fullPath, content);
26
+
27
+ return {
28
+ path: fullPath,
29
+ relativePath: filePath,
30
+ extension,
31
+ name: filePath.split("/").pop()?.replace(`.${extension}`, "") || "",
32
+ };
33
+ };
34
+
35
+ // =========================================================================
36
+ // INTEGRATION TESTS - Using real Salesforce Enterprise test project
37
+ // =========================================================================
38
+
39
+ describe("Integration: Real Salesforce Enterprise Project", () => {
40
+ it("should detect Salesforce adapter from sfdx-project.json", () => {
41
+ const adapter = detectAdapter(SALESFORCE_ENTERPRISE_PATH);
42
+ expect(adapter.name).toBe("salesforce");
43
+ });
44
+
45
+ it("should detect LWC directory in the enterprise project", () => {
46
+ const lwcDir = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc");
47
+ const exists = fs.existsSync(lwcDir);
48
+ expect(exists).toBe(true);
49
+
50
+ const components = fs.readdirSync(lwcDir);
51
+ expect(components).toContain("accountList");
52
+ expect(components).toContain("opportunityCard");
53
+ });
54
+
55
+ it("should have 2 LWC components in the enterprise project", () => {
56
+ const lwcDir = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc");
57
+ const components = fs.readdirSync(lwcDir).filter(f => {
58
+ const componentDir = path.join(lwcDir, f);
59
+ return fs.statSync(componentDir).isDirectory();
60
+ });
61
+
62
+ expect(components).toHaveLength(2);
63
+ expect(components).toContain("accountList");
64
+ expect(components).toContain("opportunityCard");
65
+ });
66
+ });
67
+
68
+ // =========================================================================
69
+ // accountList LWC Component - All 4 Files
70
+ // =========================================================================
71
+
72
+ describe("accountList LWC Component", () => {
73
+ const accountListPath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/accountList");
74
+
75
+ it("should have accountList.js file with LWC class", () => {
76
+ const jsPath = path.join(accountListPath, "accountList.js");
77
+ expect(fs.existsSync(jsPath)).toBe(true);
78
+
79
+ const content = fs.readFileSync(jsPath, "utf-8");
80
+ expect(content).toContain("import { LightningElement");
81
+ expect(content).toContain("export default class AccountList");
82
+ expect(content).toContain("extends LightningElement");
83
+ });
84
+
85
+ it("should have accountList.html file with template markup", () => {
86
+ const htmlPath = path.join(accountListPath, "accountList.html");
87
+ expect(fs.existsSync(htmlPath)).toBe(true);
88
+
89
+ const content = fs.readFileSync(htmlPath, "utf-8");
90
+ expect(content).toContain("<template>");
91
+ expect(content).toContain("<lightning-card");
92
+ expect(content).toContain("for:each={filteredAccounts}");
93
+ expect(content).toContain("onchange={handleSearchTermChange}");
94
+ });
95
+
96
+ it("should have accountList.css file with styling", () => {
97
+ const cssPath = path.join(accountListPath, "accountList.css");
98
+ expect(fs.existsSync(cssPath)).toBe(true);
99
+
100
+ const content = fs.readFileSync(cssPath, "utf-8");
101
+ expect(content).toContain(".slds-table");
102
+ expect(content).toContain(".slds-truncate");
103
+ expect(content).toContain(".account-link");
104
+ });
105
+
106
+ it("should have accountList.js-meta.xml file with exposed targets", () => {
107
+ const metaPath = path.join(accountListPath, "accountList.js-meta.xml");
108
+ expect(fs.existsSync(metaPath)).toBe(true);
109
+
110
+ const content = fs.readFileSync(metaPath, "utf-8");
111
+ expect(content).toContain("isExposed");
112
+ expect(content).toContain("lightning__RecordPage");
113
+ expect(content).toContain("lightning__AppPage");
114
+ expect(content).toContain("lightning__HomePage");
115
+ });
116
+ });
117
+
118
+ // =========================================================================
119
+ // opportunityCard LWC Component - All 4 Files
120
+ // =========================================================================
121
+
122
+ describe("opportunityCard LWC Component", () => {
123
+ const opportunityCardPath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/opportunityCard");
124
+
125
+ it("should have opportunityCard.js file with LWC class", () => {
126
+ const jsPath = path.join(opportunityCardPath, "opportunityCard.js");
127
+ expect(fs.existsSync(jsPath)).toBe(true);
128
+
129
+ const content = fs.readFileSync(jsPath, "utf-8");
130
+ expect(content).toContain("import { LightningElement");
131
+ expect(content).toContain("export default class OpportunityCard");
132
+ expect(content).toContain("NavigationMixin(LightningElement)");
133
+ expect(content).toContain("NavigationMixin");
134
+ });
135
+
136
+ it("should have opportunityCard.html file with card markup", () => {
137
+ const htmlPath = path.join(opportunityCardPath, "opportunityCard.html");
138
+ expect(fs.existsSync(htmlPath)).toBe(true);
139
+
140
+ const content = fs.readFileSync(htmlPath, "utf-8");
141
+ expect(content).toContain("<template>");
142
+ expect(content).toContain("<lightning-card");
143
+ expect(content).toContain("if:true={");
144
+ expect(content).toContain("onclick={handleViewRecord}");
145
+ });
146
+
147
+ it("should have opportunityCard.css file with urgency styling", () => {
148
+ const cssPath = path.join(opportunityCardPath, "opportunityCard.css");
149
+ expect(fs.existsSync(cssPath)).toBe(true);
150
+
151
+ const content = fs.readFileSync(cssPath, "utf-8");
152
+ expect(content).toContain(".urgency-past");
153
+ expect(content).toContain(".urgency-critical");
154
+ expect(content).toContain(".urgency-warning");
155
+ expect(content).toContain(".urgency-normal");
156
+ });
157
+
158
+ it("should have opportunityCard.js-meta.xml file with exposed targets", () => {
159
+ const metaPath = path.join(opportunityCardPath, "opportunityCard.js-meta.xml");
160
+ expect(fs.existsSync(metaPath)).toBe(true);
161
+
162
+ const content = fs.readFileSync(metaPath, "utf-8");
163
+ expect(content).toContain("isExposed");
164
+ expect(content).toContain("lightning__RecordPage");
165
+ expect(content).toContain("lightning__AppPage");
166
+ });
167
+ });
168
+
169
+ // =========================================================================
170
+ // accountList JS - LWC Decorators and Features
171
+ // =========================================================================
172
+
173
+ describe("accountList.js - LWC Decorators and Features", () => {
174
+ it("should detect @track decorator for reactive properties", () => {
175
+ const content = fs.readFileSync(
176
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/accountList/accountList.js"),
177
+ "utf-8"
178
+ );
179
+
180
+ // @track decorator pattern
181
+ expect(content).toContain("@track");
182
+ expect(content).toMatch(/@track\s+accounts\s*=/);
183
+ expect(content).toMatch(/@track\s+filteredAccounts\s*=/);
184
+ expect(content).toMatch(/@track\s+searchTerm\s*=/);
185
+ expect(content).toMatch(/@track\s+industryFilter\s*=/);
186
+ expect(content).toMatch(/@track\s+isLoading\s*=/);
187
+ expect(content).toMatch(/@track\s+error\s*=/);
188
+ });
189
+
190
+ it("should detect @wire decorator for apex methods", () => {
191
+ const content = fs.readFileSync(
192
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/accountList/accountList.js"),
193
+ "utf-8"
194
+ );
195
+
196
+ expect(content).toContain("@wire");
197
+ expect(content).toContain("getAccounts");
198
+ expect(content).toContain("@salesforce/apex");
199
+ });
200
+
201
+ it("should detect LightningElement as base class", () => {
202
+ const content = fs.readFileSync(
203
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/accountList/accountList.js"),
204
+ "utf-8"
205
+ );
206
+
207
+ expect(content).toContain("extends LightningElement");
208
+ });
209
+
210
+ it("should detect getAccounts import from @salesforce/apex", () => {
211
+ const content = fs.readFileSync(
212
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/accountList/accountList.js"),
213
+ "utf-8"
214
+ );
215
+
216
+ expect(content).toContain("import getAccounts from '@salesforce/apex/AccountController.getAccounts'");
217
+ });
218
+
219
+ it("should detect ShowToastEvent import", () => {
220
+ const content = fs.readFileSync(
221
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/accountList/accountList.js"),
222
+ "utf-8"
223
+ );
224
+
225
+ expect(content).toContain("import { ShowToastEvent } from 'lightning/platformShowToastEvent'");
226
+ });
227
+
228
+ it("should detect getter for hasAccounts", () => {
229
+ const content = fs.readFileSync(
230
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/accountList/accountList.js"),
231
+ "utf-8"
232
+ );
233
+
234
+ expect(content).toContain("get hasAccounts");
235
+ expect(content).toMatch(/get\s+hasAccounts\s*\(\)\s*\{/);
236
+ });
237
+
238
+ it("should detect event handlers", () => {
239
+ const content = fs.readFileSync(
240
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/accountList/accountList.js"),
241
+ "utf-8"
242
+ );
243
+
244
+ expect(content).toContain("handleSearchTermChange");
245
+ expect(content).toContain("handleIndustryChange");
246
+ expect(content).toContain("handleRefresh");
247
+ expect(content).toContain("handleAccountClick");
248
+ });
249
+
250
+ it("should detect custom event dispatch", () => {
251
+ const content = fs.readFileSync(
252
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/accountList/accountList.js"),
253
+ "utf-8"
254
+ );
255
+
256
+ expect(content).toContain("dispatchEvent(new CustomEvent('accountselect'");
257
+ });
258
+
259
+ it("should extract symbols from accountList.js", () => {
260
+ const content = fs.readFileSync(
261
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/accountList/accountList.js"),
262
+ "utf-8"
263
+ );
264
+
265
+ const file = createFileInfo("force-app/main/default/lwc/accountList/accountList.js", "js", content);
266
+ const result = extractSymbols([file]);
267
+
268
+ // Should detect the class
269
+ const classSymbols = result.symbols.filter(s => s.type === "class");
270
+ const accountListClass = classSymbols.find(s => s.name === "AccountList");
271
+ expect(accountListClass).toBeDefined();
272
+ });
273
+ });
274
+
275
+ // =========================================================================
276
+ // opportunityCard JS - LWC Decorators and Features
277
+ // =========================================================================
278
+
279
+ describe("opportunityCard.js - LWC Decorators and Features", () => {
280
+ it("should detect @api decorator for public properties", () => {
281
+ const content = fs.readFileSync(
282
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/opportunityCard/opportunityCard.js"),
283
+ "utf-8"
284
+ );
285
+
286
+ expect(content).toContain("@api");
287
+ expect(content).toMatch(/@api\s+recordId/);
288
+ });
289
+
290
+ it("should detect @track decorator for reactive properties", () => {
291
+ const content = fs.readFileSync(
292
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/opportunityCard/opportunityCard.js"),
293
+ "utf-8"
294
+ );
295
+
296
+ expect(content).toContain("@track");
297
+ expect(content).toMatch(/@track\s+opportunity\s*=/);
298
+ expect(content).toMatch(/@track\s+isLoading\s*=/);
299
+ });
300
+
301
+ it("should detect @wire decorator for uiRecordApi", () => {
302
+ const content = fs.readFileSync(
303
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/opportunityCard/opportunityCard.js"),
304
+ "utf-8"
305
+ );
306
+
307
+ expect(content).toContain("@wire");
308
+ expect(content).toContain("getRecord");
309
+ expect(content).toContain("lightning/uiRecordApi");
310
+ });
311
+
312
+ it("should detect NavigationMixin import", () => {
313
+ const content = fs.readFileSync(
314
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/opportunityCard/opportunityCard.js"),
315
+ "utf-8"
316
+ );
317
+
318
+ expect(content).toContain("import { NavigationMixin } from 'lightning/navigation'");
319
+ expect(content).toContain("extends NavigationMixin(LightningElement)");
320
+ });
321
+
322
+ it("should detect lightning/uiRecordApi imports", () => {
323
+ const content = fs.readFileSync(
324
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/opportunityCard/opportunityCard.js"),
325
+ "utf-8"
326
+ );
327
+
328
+ expect(content).toContain("import { getRecord, getFieldValue } from 'lightning/uiRecordApi'");
329
+ });
330
+
331
+ it("should detect @salesforce/schema imports", () => {
332
+ const content = fs.readFileSync(
333
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/opportunityCard/opportunityCard.js"),
334
+ "utf-8"
335
+ );
336
+
337
+ expect(content).toContain("@salesforce/schema/Opportunity.Name");
338
+ expect(content).toContain("@salesforce/schema/Opportunity.StageName");
339
+ expect(content).toContain("@salesforce/schema/Opportunity.Amount");
340
+ expect(content).toContain("@salesforce/schema/Opportunity.CloseDate");
341
+ expect(content).toContain("@salesforce/schema/Opportunity.Account.Name");
342
+ });
343
+
344
+ it("should detect getter methods for computed properties", () => {
345
+ const content = fs.readFileSync(
346
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/opportunityCard/opportunityCard.js"),
347
+ "utf-8"
348
+ );
349
+
350
+ expect(content).toContain("get name");
351
+ expect(content).toContain("get stage");
352
+ expect(content).toContain("get amount");
353
+ expect(content).toContain("get closeDate");
354
+ expect(content).toContain("get accountName");
355
+ expect(content).toContain("get stageColor");
356
+ expect(content).toContain("get formattedAmount");
357
+ expect(content).toContain("get formattedCloseDate");
358
+ expect(content).toContain("get daysUntilClose");
359
+ expect(content).toContain("get urgencyClass");
360
+ });
361
+
362
+ it("should detect NavigationMixin.Navigate usage", () => {
363
+ const content = fs.readFileSync(
364
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/opportunityCard/opportunityCard.js"),
365
+ "utf-8"
366
+ );
367
+
368
+ expect(content).toContain("NavigationMixin.Navigate");
369
+ expect(content).toContain("handleViewRecord");
370
+ expect(content).toContain("handleEditRecord");
371
+ });
372
+
373
+ it("should extract symbols from opportunityCard.js", () => {
374
+ const content = fs.readFileSync(
375
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/opportunityCard/opportunityCard.js"),
376
+ "utf-8"
377
+ );
378
+
379
+ const file = createFileInfo("force-app/main/default/lwc/opportunityCard/opportunityCard.js", "js", content);
380
+ const result = extractSymbols([file]);
381
+
382
+ // Should detect the class
383
+ const classSymbols = result.symbols.filter(s => s.type === "class");
384
+ const opportunityCardClass = classSymbols.find(s => s.name === "OpportunityCard");
385
+ expect(opportunityCardClass).toBeDefined();
386
+ });
387
+ });
388
+
389
+ // =========================================================================
390
+ // LWC HTML Template Tests
391
+ // =========================================================================
392
+
393
+ describe("LWC HTML Templates", () => {
394
+ describe("accountList.html", () => {
395
+ it("should have proper template tag", () => {
396
+ const content = fs.readFileSync(
397
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/accountList/accountList.html"),
398
+ "utf-8"
399
+ );
400
+
401
+ expect(content).toContain("<template>");
402
+ expect(content).toContain("</template>");
403
+ });
404
+
405
+ it("should use lightning-base components", () => {
406
+ const content = fs.readFileSync(
407
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/accountList/accountList.html"),
408
+ "utf-8"
409
+ );
410
+
411
+ expect(content).toContain("<lightning-card");
412
+ expect(content).toContain("<lightning-input");
413
+ expect(content).toContain("<lightning-combobox");
414
+ expect(content).toContain("<lightning-button");
415
+ expect(content).toContain("<lightning-spinner");
416
+ expect(content).toContain("<lightning-layout");
417
+ expect(content).toContain("<lightning-formatted-number");
418
+ });
419
+
420
+ it("should have for:each iteration", () => {
421
+ const content = fs.readFileSync(
422
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/accountList/accountList.html"),
423
+ "utf-8"
424
+ );
425
+
426
+ expect(content).toContain("for:each={filteredAccounts}");
427
+ expect(content).toContain("for:item=");
428
+ });
429
+
430
+ it("should have conditional rendering with if:true/if:false", () => {
431
+ const content = fs.readFileSync(
432
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/accountList/accountList.html"),
433
+ "utf-8"
434
+ );
435
+
436
+ expect(content).toContain("if:true={isLoading}");
437
+ expect(content).toContain("if:true={hasAccounts}");
438
+ expect(content).toContain("if:false={hasAccounts}");
439
+ });
440
+
441
+ it("should have slot elements", () => {
442
+ const content = fs.readFileSync(
443
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/accountList/accountList.html"),
444
+ "utf-8"
445
+ );
446
+
447
+ expect(content).toContain("slot=");
448
+ });
449
+
450
+ it("should reference JS methods as event handlers", () => {
451
+ const content = fs.readFileSync(
452
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/accountList/accountList.html"),
453
+ "utf-8"
454
+ );
455
+
456
+ expect(content).toContain("onchange={handleSearchTermChange}");
457
+ expect(content).toContain("onchange={handleIndustryChange}");
458
+ expect(content).toContain("onclick={handleRefresh}");
459
+ expect(content).toContain("onclick={handleAccountClick}");
460
+ });
461
+ });
462
+
463
+ describe("opportunityCard.html", () => {
464
+ it("should have proper template tag", () => {
465
+ const content = fs.readFileSync(
466
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/opportunityCard/opportunityCard.html"),
467
+ "utf-8"
468
+ );
469
+
470
+ expect(content).toContain("<template>");
471
+ expect(content).toContain("</template>");
472
+ });
473
+
474
+ it("should use lightning-base components", () => {
475
+ const content = fs.readFileSync(
476
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/opportunityCard/opportunityCard.html"),
477
+ "utf-8"
478
+ );
479
+
480
+ expect(content).toContain("<lightning-card");
481
+ expect(content).toContain("<lightning-button");
482
+ expect(content).toContain("<lightning-button-group");
483
+ expect(content).toContain("<lightning-icon");
484
+ });
485
+
486
+ it("should have conditional rendering", () => {
487
+ const content = fs.readFileSync(
488
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/opportunityCard/opportunityCard.html"),
489
+ "utf-8"
490
+ );
491
+
492
+ expect(content).toContain("if:true={");
493
+ expect(content).toContain("if:true={daysUntilClose}");
494
+ });
495
+
496
+ it("should reference computed getters", () => {
497
+ const content = fs.readFileSync(
498
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/opportunityCard/opportunityCard.html"),
499
+ "utf-8"
500
+ );
501
+
502
+ expect(content).toContain("{name}");
503
+ expect(content).toContain("{stage}");
504
+ expect(content).toContain("{formattedAmount}");
505
+ expect(content).toContain("{formattedCloseDate}");
506
+ expect(content).toContain("{urgencyClass}");
507
+ expect(content).toContain("{stageColor}");
508
+ expect(content).toContain("{daysUntilClose}");
509
+ });
510
+
511
+ it("should reference JS methods as event handlers", () => {
512
+ const content = fs.readFileSync(
513
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/opportunityCard/opportunityCard.html"),
514
+ "utf-8"
515
+ );
516
+
517
+ expect(content).toContain("onclick={handleViewRecord}");
518
+ expect(content).toContain("onclick={handleEditRecord}");
519
+ });
520
+ });
521
+ });
522
+
523
+ // =========================================================================
524
+ // LWC CSS Tests
525
+ // =========================================================================
526
+
527
+ describe("LWC CSS", () => {
528
+ describe("accountList.css", () => {
529
+ it("should have CSS class selectors", () => {
530
+ const content = fs.readFileSync(
531
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/accountList/accountList.css"),
532
+ "utf-8"
533
+ );
534
+
535
+ expect(content).toContain(".slds-table");
536
+ expect(content).toContain(".slds-card");
537
+ expect(content).toContain(".account-link");
538
+ });
539
+
540
+ it("should have SLDS design tokens", () => {
541
+ const content = fs.readFileSync(
542
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/accountList/accountList.css"),
543
+ "utf-8"
544
+ );
545
+
546
+ // SLDS color tokens
547
+ expect(content).toMatch(/rgb\(\d+,\s*\d+,\s*\d+\)/);
548
+ expect(content).toContain("background-color");
549
+ expect(content).toContain("border");
550
+ expect(content).toContain("padding");
551
+ });
552
+
553
+ it("should define hover states", () => {
554
+ const content = fs.readFileSync(
555
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/accountList/accountList.css"),
556
+ "utf-8"
557
+ );
558
+
559
+ expect(content).toContain(":hover");
560
+ expect(content).toContain(".account-link:hover");
561
+ });
562
+ });
563
+
564
+ describe("opportunityCard.css", () => {
565
+ it("should have CSS class selectors", () => {
566
+ const content = fs.readFileSync(
567
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/opportunityCard/opportunityCard.css"),
568
+ "utf-8"
569
+ );
570
+
571
+ expect(content).toContain(".opportunity-card");
572
+ expect(content).toContain(".opportunity-name");
573
+ expect(content).toContain(".info-label");
574
+ expect(content).toContain(".info-value");
575
+ });
576
+
577
+ it("should have urgency color classes", () => {
578
+ const content = fs.readFileSync(
579
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/opportunityCard/opportunityCard.css"),
580
+ "utf-8"
581
+ );
582
+
583
+ expect(content).toContain(".urgency-past");
584
+ expect(content).toContain(".urgency-critical");
585
+ expect(content).toContain(".urgency-warning");
586
+ expect(content).toContain(".urgency-normal");
587
+ });
588
+
589
+ it("should have SLDS theme classes", () => {
590
+ const content = fs.readFileSync(
591
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/opportunityCard/opportunityCard.css"),
592
+ "utf-8"
593
+ );
594
+
595
+ expect(content).toContain(".slds-theme_warning");
596
+ expect(content).toContain(".slds-theme_info");
597
+ expect(content).toContain(".slds-theme_success");
598
+ expect(content).toContain(".slds-theme_error");
599
+ });
600
+
601
+ it("should have urgency styling classes", () => {
602
+ const content = fs.readFileSync(
603
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/opportunityCard/opportunityCard.css"),
604
+ "utf-8"
605
+ );
606
+
607
+ expect(content).toContain(".urgency-past");
608
+ expect(content).toContain(".urgency-critical");
609
+ expect(content).toContain(".urgency-warning");
610
+ expect(content).toContain(".urgency-normal");
611
+ });
612
+ });
613
+ });
614
+
615
+ // =========================================================================
616
+ // LWC Metadata Tests
617
+ // =========================================================================
618
+
619
+ describe("LWC Metadata (js-meta.xml)", () => {
620
+ describe("accountList.js-meta.xml", () => {
621
+ it("should be valid JSON or XML metadata", () => {
622
+ const content = fs.readFileSync(
623
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/accountList/accountList.js-meta.xml"),
624
+ "utf-8"
625
+ );
626
+
627
+ // Should contain key metadata fields
628
+ expect(content).toContain("apiVersion");
629
+ expect(content).toContain("isExposed");
630
+ expect(content).toContain("masterLabel");
631
+ expect(content).toContain("targets");
632
+ });
633
+
634
+ it("should expose targets for Lightning Experience", () => {
635
+ const content = fs.readFileSync(
636
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/accountList/accountList.js-meta.xml"),
637
+ "utf-8"
638
+ );
639
+
640
+ expect(content).toContain("lightning__RecordPage");
641
+ expect(content).toContain("lightning__AppPage");
642
+ expect(content).toContain("lightning__HomePage");
643
+ });
644
+
645
+ it("should define properties for component configuration", () => {
646
+ const content = fs.readFileSync(
647
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/accountList/accountList.js-meta.xml"),
648
+ "utf-8"
649
+ );
650
+
651
+ expect(content).toContain("properties");
652
+ expect(content).toContain("searchTerm");
653
+ expect(content).toContain("industryFilter");
654
+ });
655
+
656
+ it("should have correct API version", () => {
657
+ const content = fs.readFileSync(
658
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/accountList/accountList.js-meta.xml"),
659
+ "utf-8"
660
+ );
661
+
662
+ expect(content).toContain("59.0");
663
+ });
664
+ });
665
+
666
+ describe("opportunityCard.js-meta.xml", () => {
667
+ it("should be valid JSON or XML metadata", () => {
668
+ const content = fs.readFileSync(
669
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/opportunityCard/opportunityCard.js-meta.xml"),
670
+ "utf-8"
671
+ );
672
+
673
+ expect(content).toContain("apiVersion");
674
+ expect(content).toContain("isExposed");
675
+ expect(content).toContain("masterLabel");
676
+ expect(content).toContain("targets");
677
+ });
678
+
679
+ it("should expose targets for Lightning Experience", () => {
680
+ const content = fs.readFileSync(
681
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/opportunityCard/opportunityCard.js-meta.xml"),
682
+ "utf-8"
683
+ );
684
+
685
+ expect(content).toContain("lightning__RecordPage");
686
+ expect(content).toContain("lightning__AppPage");
687
+ });
688
+
689
+ it("should define properties for component configuration", () => {
690
+ const content = fs.readFileSync(
691
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/opportunityCard/opportunityCard.js-meta.xml"),
692
+ "utf-8"
693
+ );
694
+
695
+ expect(content).toContain("properties");
696
+ expect(content).toContain("recordId");
697
+ });
698
+
699
+ it("should have correct API version", () => {
700
+ const content = fs.readFileSync(
701
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/opportunityCard/opportunityCard.js-meta.xml"),
702
+ "utf-8"
703
+ );
704
+
705
+ expect(content).toContain("59.0");
706
+ });
707
+ });
708
+ });
709
+
710
+ // =========================================================================
711
+ // LWC Component Detection Tests
712
+ // =========================================================================
713
+
714
+ describe("LWC Component Detection", () => {
715
+ it("should detect LWC JavaScript files as entrypoints", () => {
716
+ const accountListJs = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/accountList/accountList.js");
717
+ const opportunityCardJs = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/opportunityCard/opportunityCard.js");
718
+
719
+ expect(fs.existsSync(accountListJs)).toBe(true);
720
+ expect(fs.existsSync(opportunityCardJs)).toBe(true);
721
+ });
722
+
723
+ it("should detect LWC HTML templates", () => {
724
+ const accountListHtml = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/accountList/accountList.html");
725
+ const opportunityCardHtml = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/opportunityCard/opportunityCard.html");
726
+
727
+ expect(fs.existsSync(accountListHtml)).toBe(true);
728
+ expect(fs.existsSync(opportunityCardHtml)).toBe(true);
729
+ });
730
+
731
+ it("should detect LWC CSS files", () => {
732
+ const accountListCss = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/accountList/accountList.css");
733
+ const opportunityCardCss = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/opportunityCard/opportunityCard.css");
734
+
735
+ expect(fs.existsSync(accountListCss)).toBe(true);
736
+ expect(fs.existsSync(opportunityCardCss)).toBe(true);
737
+ });
738
+
739
+ it("should detect LWC metadata files", () => {
740
+ const accountListMeta = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/accountList/accountList.js-meta.xml");
741
+ const opportunityCardMeta = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/opportunityCard/opportunityCard.js-meta.xml");
742
+
743
+ expect(fs.existsSync(accountListMeta)).toBe(true);
744
+ expect(fs.existsSync(opportunityCardMeta)).toBe(true);
745
+ });
746
+
747
+ it("should verify all 4 files exist for each LWC component", () => {
748
+ const components = ["accountList", "opportunityCard"];
749
+
750
+ for (const component of components) {
751
+ const basePath = path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc", component);
752
+ expect(fs.existsSync(path.join(basePath, `${component}.js`))).toBe(true);
753
+ expect(fs.existsSync(path.join(basePath, `${component}.html`))).toBe(true);
754
+ expect(fs.existsSync(path.join(basePath, `${component}.css`))).toBe(true);
755
+ expect(fs.existsSync(path.join(basePath, `${component}.js-meta.xml`))).toBe(true);
756
+ }
757
+ });
758
+
759
+ it("should detect LightningElement imports from lwc", () => {
760
+ const accountListContent = fs.readFileSync(
761
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/accountList/accountList.js"),
762
+ "utf-8"
763
+ );
764
+ const opportunityCardContent = fs.readFileSync(
765
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/opportunityCard/opportunityCard.js"),
766
+ "utf-8"
767
+ );
768
+
769
+ expect(accountListContent).toContain("from 'lwc'");
770
+ expect(opportunityCardContent).toContain("from 'lwc'");
771
+ });
772
+ });
773
+
774
+ // =========================================================================
775
+ // UNIT TESTS - LWC Patterns
776
+ // =========================================================================
777
+
778
+ describe("Unit: LWC JavaScript patterns", () => {
779
+ it("should parse LWC class declaration", () => {
780
+ const content = `import { LightningElement } from 'lwc';
781
+ export default class MyComponent extends LightningElement {}`;
782
+
783
+ const file = createFileInfo("test.js", "js", content);
784
+ const result = extractSymbols([file]);
785
+
786
+ const classSymbol = result.symbols.find(s => s.name === "MyComponent");
787
+ expect(classSymbol).toBeDefined();
788
+ expect(classSymbol?.type).toBe("class");
789
+ });
790
+
791
+ it("should detect @api decorator pattern", () => {
792
+ const content = `import { LightningElement, api } from 'lwc';
793
+ export default class TestComponent extends LightningElement {
794
+ @api recordId;
795
+ }`;
796
+
797
+ const file = createFileInfo("test.js", "js", content);
798
+ const result = extractSymbols([file]);
799
+
800
+ // Class should be detected
801
+ const classSymbol = result.symbols.find(s => s.name === "TestComponent");
802
+ expect(classSymbol).toBeDefined();
803
+ expect(content).toContain("@api");
804
+ });
805
+
806
+ it("should detect @track decorator pattern", () => {
807
+ const content = `import { LightningElement, track } from 'lwc';
808
+ export default class TestComponent extends LightningElement {
809
+ @track items = [];
810
+ }`;
811
+
812
+ const file = createFileInfo("test.js", "js", content);
813
+ const result = extractSymbols([file]);
814
+
815
+ const classSymbol = result.symbols.find(s => s.name === "TestComponent");
816
+ expect(classSymbol).toBeDefined();
817
+ expect(content).toContain("@track");
818
+ });
819
+
820
+ it("should detect @wire decorator pattern", () => {
821
+ const content = `import { LightningElement, wire } from 'lwc';
822
+ import getRecords from '@salesforce/apex/MyController.getRecords';
823
+ export default class TestComponent extends LightningElement {
824
+ @wire(getRecords, { object: 'Account' })
825
+ wiredRecords;
826
+ }`;
827
+
828
+ const file = createFileInfo("test.js", "js", content);
829
+ const result = extractSymbols([file]);
830
+
831
+ const classSymbol = result.symbols.find(s => s.name === "TestComponent");
832
+ expect(classSymbol).toBeDefined();
833
+ expect(content).toContain("@wire");
834
+ });
835
+
836
+ it("should detect getter methods", () => {
837
+ const content = `import { LightningElement } from 'lwc';
838
+ export default class TestComponent extends LightningElement {
839
+ get items() { return this._items; }
840
+ }`;
841
+
842
+ const file = createFileInfo("test.js", "js", content);
843
+ const result = extractSymbols([file]);
844
+
845
+ const classSymbol = result.symbols.find(s => s.name === "TestComponent");
846
+ expect(classSymbol).toBeDefined();
847
+ expect(content).toContain("get items");
848
+ });
849
+
850
+ it("should detect NavigationMixin pattern", () => {
851
+ const content = `import { LightningElement } from 'lwc';
852
+ import { NavigationMixin } from 'lightning/navigation';
853
+ export default class TestComponent extends NavigationMixin(LightningElement) {}`;
854
+
855
+ const file = createFileInfo("test.js", "js", content);
856
+ const result = extractSymbols([file]);
857
+
858
+ expect(content).toContain("NavigationMixin");
859
+ expect(content).toContain("NavigationMixin(LightningElement)");
860
+ });
861
+ });
862
+
863
+ // =========================================================================
864
+ // Symbol Extraction Accuracy
865
+ // =========================================================================
866
+
867
+ describe("Symbol Extraction Accuracy for LWC", () => {
868
+ it("should extract class symbol from accountList.js", () => {
869
+ const content = fs.readFileSync(
870
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/accountList/accountList.js"),
871
+ "utf-8"
872
+ );
873
+
874
+ const file = createFileInfo("force-app/main/default/lwc/accountList/accountList.js", "js", content);
875
+ const result = extractSymbols([file]);
876
+
877
+ const classSymbol = result.symbols.find(s => s.type === "class" && s.name === "AccountList");
878
+ expect(classSymbol).toBeDefined();
879
+ expect(classSymbol?.file).toBe("force-app/main/default/lwc/accountList/accountList.js");
880
+ });
881
+
882
+ it("should extract class symbol from opportunityCard.js", () => {
883
+ const content = fs.readFileSync(
884
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/opportunityCard/opportunityCard.js"),
885
+ "utf-8"
886
+ );
887
+
888
+ const file = createFileInfo("force-app/main/default/lwc/opportunityCard/opportunityCard.js", "js", content);
889
+ const result = extractSymbols([file]);
890
+
891
+ const classSymbol = result.symbols.find(s => s.type === "class" && s.name === "OpportunityCard");
892
+ expect(classSymbol).toBeDefined();
893
+ expect(classSymbol?.file).toBe("force-app/main/default/lwc/opportunityCard/opportunityCard.js");
894
+ });
895
+
896
+ it("should detect exported LWC classes", () => {
897
+ const accountListContent = fs.readFileSync(
898
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/accountList/accountList.js"),
899
+ "utf-8"
900
+ );
901
+
902
+ const file = createFileInfo("force-app/main/default/lwc/accountList/accountList.js", "js", accountListContent);
903
+ const result = extractSymbols([file]);
904
+
905
+ // Find AccountList class - it should be exported
906
+ const accountListClass = result.symbols.find(s => s.name === "AccountList");
907
+ expect(accountListClass).toBeDefined();
908
+ expect(accountListClass?.export).toBe(true);
909
+ });
910
+ });
911
+
912
+ // =========================================================================
913
+ // Entrypoint Detection for LWC
914
+ // =========================================================================
915
+
916
+ describe("Entrypoint Detection for LWC Components", () => {
917
+ it("should identify LWC components as entrypoints", () => {
918
+ const accountListContent = fs.readFileSync(
919
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/accountList/accountList.js"),
920
+ "utf-8"
921
+ );
922
+
923
+ const opportunityCardContent = fs.readFileSync(
924
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/opportunityCard/opportunityCard.js"),
925
+ "utf-8"
926
+ );
927
+
928
+ // LWC components are always entrypoints - they extend LightningElement
929
+ expect(accountListContent).toContain("extends LightningElement");
930
+ expect(opportunityCardContent).toContain("LightningElement");
931
+
932
+ // LWC components use decorators
933
+ expect(accountListContent).toMatch(/@(?:api|track|wire)/);
934
+ expect(opportunityCardContent).toMatch(/@(?:api|track|wire)/);
935
+ });
936
+
937
+ it("should identify LWC as frontend component type", () => {
938
+ const accountListContent = fs.readFileSync(
939
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/accountList/accountList.js"),
940
+ "utf-8"
941
+ );
942
+
943
+ // LWC components have specific patterns
944
+ expect(accountListContent).toContain("LightningElement");
945
+ expect(accountListContent).toContain("from 'lwc'");
946
+ });
947
+
948
+ it("should verify LWC metadata marks components as exposed", () => {
949
+ const accountListMeta = fs.readFileSync(
950
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/accountList/accountList.js-meta.xml"),
951
+ "utf-8"
952
+ );
953
+
954
+ const opportunityCardMeta = fs.readFileSync(
955
+ path.join(SALESFORCE_ENTERPRISE_PATH, "force-app/main/default/lwc/opportunityCard/opportunityCard.js-meta.xml"),
956
+ "utf-8"
957
+ );
958
+
959
+ expect(accountListMeta).toContain("isExposed");
960
+ expect(opportunityCardMeta).toContain("isExposed");
961
+ });
962
+ });
963
+ });