@codeyam/codeyam-cli 0.1.0-staging.596f0eb → 0.1.0-staging.76566f9

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 (354) hide show
  1. package/analyzer-template/.build-info.json +7 -7
  2. package/analyzer-template/log.txt +3 -3
  3. package/analyzer-template/package.json +2 -1
  4. package/analyzer-template/packages/ai/src/lib/analyzeScope.ts +2 -0
  5. package/analyzer-template/packages/ai/src/lib/astScopes/astScopeAnalyzer.ts +22 -0
  6. package/analyzer-template/packages/ai/src/lib/astScopes/patterns/switchStatementHandler.ts +23 -1
  7. package/analyzer-template/packages/ai/src/lib/astScopes/processExpression.ts +401 -106
  8. package/analyzer-template/packages/ai/src/lib/astScopes/types.ts +60 -0
  9. package/analyzer-template/packages/ai/src/lib/dataStructure/ScopeDataStructure.ts +734 -45
  10. package/analyzer-template/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/JavascriptFrameworkManager.ts +2 -1
  11. package/analyzer-template/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/MuiManager.ts +715 -0
  12. package/analyzer-template/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/ReactFrameworkManager.ts +233 -75
  13. package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/cleanKnownObjectFunctions.ts +19 -1
  14. package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/cleanNonObjectFunctions.ts +34 -1
  15. package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/convertDotNotation.ts +23 -0
  16. package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/convertNullToUndefinedBySchema.ts +98 -0
  17. package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/fillInSchemaGapsAndUnknowns.ts +34 -1
  18. package/analyzer-template/packages/ai/src/lib/gatherRelevantDependentKeyAttributes.ts +236 -24
  19. package/analyzer-template/packages/ai/src/lib/generateChangesEntityKeyAttributes.ts +18 -1
  20. package/analyzer-template/packages/ai/src/lib/generateChangesEntityScenarioData.ts +41 -0
  21. package/analyzer-template/packages/ai/src/lib/generateChangesEntityScenarios.ts +37 -4
  22. package/analyzer-template/packages/ai/src/lib/generateEntityDataStructure.ts +5 -0
  23. package/analyzer-template/packages/ai/src/lib/generateEntityKeyAttributes.ts +213 -12
  24. package/analyzer-template/packages/ai/src/lib/generateEntityScenarioData.ts +36 -25
  25. package/analyzer-template/packages/ai/src/lib/generateEntityScenarios.ts +114 -11
  26. package/analyzer-template/packages/ai/src/lib/getConditionalUsagesFromCode.ts +143 -31
  27. package/analyzer-template/packages/ai/src/lib/guessScenarioDataFromDescription.ts +8 -2
  28. package/analyzer-template/packages/ai/src/lib/promptGenerators/gatherAttributesMap.ts +7 -0
  29. package/analyzer-template/packages/ai/src/lib/promptGenerators/generateChangesEntityScenariosGenerator.ts +42 -2
  30. package/analyzer-template/packages/ai/src/lib/promptGenerators/generateEntityScenariosGenerator.ts +38 -2
  31. package/analyzer-template/packages/ai/src/lib/promptGenerators/guessNewScenarioDataFromDescriptionGenerator.ts +28 -2
  32. package/analyzer-template/packages/ai/src/lib/worker/SerializableDataStructure.ts +5 -0
  33. package/analyzer-template/packages/ai/src/lib/worker/analyzeScopeWorker.ts +8 -1
  34. package/analyzer-template/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.ts +127 -43
  35. package/analyzer-template/packages/analyze/src/lib/files/scenarios/enrichArrayTypesFromChildSignatures.ts +158 -0
  36. package/analyzer-template/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.ts +405 -45
  37. package/analyzer-template/packages/analyze/src/lib/files/scenarios/generateChangesScenarioData.ts +1 -1
  38. package/analyzer-template/packages/analyze/src/lib/files/scenarios/generateDataStructure.ts +260 -133
  39. package/analyzer-template/packages/analyze/src/lib/files/scenarios/generateKeyAttributes.ts +10 -5
  40. package/analyzer-template/packages/analyze/src/lib/files/scenarios/generateScenarioData.ts +77 -83
  41. package/analyzer-template/packages/analyze/src/lib/files/scenarios/generateScenarios.ts +2 -5
  42. package/analyzer-template/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.ts +196 -86
  43. package/analyzer-template/packages/aws/dist/src/lib/s3/checkS3ObjectExists.d.ts +15 -0
  44. package/analyzer-template/packages/aws/dist/src/lib/s3/checkS3ObjectExists.d.ts.map +1 -0
  45. package/analyzer-template/packages/aws/dist/src/lib/s3/checkS3ObjectExists.js +31 -0
  46. package/analyzer-template/packages/aws/dist/src/lib/s3/checkS3ObjectExists.js.map +1 -0
  47. package/analyzer-template/packages/aws/package.json +1 -1
  48. package/analyzer-template/packages/aws/s3/index.ts +1 -0
  49. package/analyzer-template/packages/aws/src/lib/s3/checkS3ObjectExists.ts +47 -0
  50. package/analyzer-template/packages/database/src/lib/kysely/db.ts +4 -4
  51. package/analyzer-template/packages/database/src/lib/kysely/tableRelations.ts +2 -2
  52. package/analyzer-template/packages/database/src/lib/kysely/tables/debugReportsTable.ts +20 -9
  53. package/analyzer-template/packages/generate/src/lib/componentScenarioPage/getIFrameMessageListenerCode.ts +9 -4
  54. package/analyzer-template/packages/generate/src/lib/deepMerge.ts +26 -1
  55. package/analyzer-template/packages/github/dist/database/src/lib/kysely/db.d.ts +2 -2
  56. package/analyzer-template/packages/github/dist/database/src/lib/kysely/db.js +2 -2
  57. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tableRelations.d.ts +2 -2
  58. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/analysesTable.d.ts +8 -1
  59. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/analysesTable.d.ts.map +1 -1
  60. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/debugReportsTable.d.ts +14 -7
  61. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/debugReportsTable.d.ts.map +1 -1
  62. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/debugReportsTable.js +9 -3
  63. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/debugReportsTable.js.map +1 -1
  64. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/scenariosTable.d.ts +1 -1
  65. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/scenariosTable.d.ts.map +1 -1
  66. package/analyzer-template/packages/github/dist/generate/src/lib/componentScenarioPage/getIFrameMessageListenerCode.d.ts.map +1 -1
  67. package/analyzer-template/packages/github/dist/generate/src/lib/componentScenarioPage/getIFrameMessageListenerCode.js +8 -4
  68. package/analyzer-template/packages/github/dist/generate/src/lib/componentScenarioPage/getIFrameMessageListenerCode.js.map +1 -1
  69. package/analyzer-template/packages/github/dist/generate/src/lib/deepMerge.d.ts.map +1 -1
  70. package/analyzer-template/packages/github/dist/generate/src/lib/deepMerge.js +27 -1
  71. package/analyzer-template/packages/github/dist/generate/src/lib/deepMerge.js.map +1 -1
  72. package/analyzer-template/packages/github/dist/types/index.d.ts +4 -3
  73. package/analyzer-template/packages/github/dist/types/index.d.ts.map +1 -1
  74. package/analyzer-template/packages/github/dist/types/index.js +1 -0
  75. package/analyzer-template/packages/github/dist/types/index.js.map +1 -1
  76. package/analyzer-template/packages/github/dist/types/src/types/Analysis.d.ts +31 -1
  77. package/analyzer-template/packages/github/dist/types/src/types/Analysis.d.ts.map +1 -1
  78. package/analyzer-template/packages/github/dist/types/src/types/Scenario.d.ts +51 -1
  79. package/analyzer-template/packages/github/dist/types/src/types/Scenario.d.ts.map +1 -1
  80. package/analyzer-template/packages/github/dist/types/src/types/Scenario.js +21 -1
  81. package/analyzer-template/packages/github/dist/types/src/types/Scenario.js.map +1 -1
  82. package/analyzer-template/packages/github/dist/types/src/types/ScenariosDataStructure.d.ts +48 -0
  83. package/analyzer-template/packages/github/dist/types/src/types/ScenariosDataStructure.d.ts.map +1 -1
  84. package/analyzer-template/packages/github/dist/utils/src/lib/lightweightEntityExtractor.d.ts.map +1 -1
  85. package/analyzer-template/packages/github/dist/utils/src/lib/lightweightEntityExtractor.js +25 -0
  86. package/analyzer-template/packages/github/dist/utils/src/lib/lightweightEntityExtractor.js.map +1 -1
  87. package/analyzer-template/packages/types/index.ts +8 -0
  88. package/analyzer-template/packages/types/src/types/Analysis.ts +32 -1
  89. package/analyzer-template/packages/types/src/types/Scenario.ts +75 -6
  90. package/analyzer-template/packages/types/src/types/ScenariosDataStructure.ts +49 -0
  91. package/analyzer-template/packages/ui-components/src/components/ScenarioDetailInteractiveView.tsx +23 -7
  92. package/analyzer-template/packages/utils/dist/types/index.d.ts +4 -3
  93. package/analyzer-template/packages/utils/dist/types/index.d.ts.map +1 -1
  94. package/analyzer-template/packages/utils/dist/types/index.js +1 -0
  95. package/analyzer-template/packages/utils/dist/types/index.js.map +1 -1
  96. package/analyzer-template/packages/utils/dist/types/src/types/Analysis.d.ts +31 -1
  97. package/analyzer-template/packages/utils/dist/types/src/types/Analysis.d.ts.map +1 -1
  98. package/analyzer-template/packages/utils/dist/types/src/types/Scenario.d.ts +51 -1
  99. package/analyzer-template/packages/utils/dist/types/src/types/Scenario.d.ts.map +1 -1
  100. package/analyzer-template/packages/utils/dist/types/src/types/Scenario.js +21 -1
  101. package/analyzer-template/packages/utils/dist/types/src/types/Scenario.js.map +1 -1
  102. package/analyzer-template/packages/utils/dist/types/src/types/ScenariosDataStructure.d.ts +48 -0
  103. package/analyzer-template/packages/utils/dist/types/src/types/ScenariosDataStructure.d.ts.map +1 -1
  104. package/analyzer-template/packages/utils/dist/utils/src/lib/lightweightEntityExtractor.d.ts.map +1 -1
  105. package/analyzer-template/packages/utils/dist/utils/src/lib/lightweightEntityExtractor.js +25 -0
  106. package/analyzer-template/packages/utils/dist/utils/src/lib/lightweightEntityExtractor.js.map +1 -1
  107. package/analyzer-template/packages/utils/src/lib/lightweightEntityExtractor.ts +27 -0
  108. package/analyzer-template/playwright/takeElementScreenshot.ts +26 -11
  109. package/analyzer-template/playwright/takeScreenshot.ts +9 -7
  110. package/analyzer-template/project/constructMockCode.ts +286 -84
  111. package/analyzer-template/project/orchestrateCapture/SequentialCaptureTaskRunner.ts +77 -37
  112. package/analyzer-template/project/reconcileMockDataKeys.ts +5 -2
  113. package/analyzer-template/project/runMultiScenarioServer.ts +11 -10
  114. package/analyzer-template/project/serverOnlyModules.ts +71 -23
  115. package/analyzer-template/project/start.ts +10 -0
  116. package/analyzer-template/project/startScenarioCapture.ts +73 -41
  117. package/analyzer-template/project/writeMockDataTsx.ts +115 -54
  118. package/analyzer-template/project/writeScenarioComponents.ts +571 -162
  119. package/analyzer-template/project/writeSimpleRoot.ts +11 -13
  120. package/background/src/lib/virtualized/project/constructMockCode.js +265 -75
  121. package/background/src/lib/virtualized/project/constructMockCode.js.map +1 -1
  122. package/background/src/lib/virtualized/project/orchestrateCapture/SequentialCaptureTaskRunner.js +67 -32
  123. package/background/src/lib/virtualized/project/orchestrateCapture/SequentialCaptureTaskRunner.js.map +1 -1
  124. package/background/src/lib/virtualized/project/reconcileMockDataKeys.js +5 -2
  125. package/background/src/lib/virtualized/project/reconcileMockDataKeys.js.map +1 -1
  126. package/background/src/lib/virtualized/project/runMultiScenarioServer.js +11 -9
  127. package/background/src/lib/virtualized/project/runMultiScenarioServer.js.map +1 -1
  128. package/background/src/lib/virtualized/project/serverOnlyModules.js +62 -25
  129. package/background/src/lib/virtualized/project/serverOnlyModules.js.map +1 -1
  130. package/background/src/lib/virtualized/project/start.js +6 -0
  131. package/background/src/lib/virtualized/project/start.js.map +1 -1
  132. package/background/src/lib/virtualized/project/startScenarioCapture.js +54 -31
  133. package/background/src/lib/virtualized/project/startScenarioCapture.js.map +1 -1
  134. package/background/src/lib/virtualized/project/writeMockDataTsx.js +106 -46
  135. package/background/src/lib/virtualized/project/writeMockDataTsx.js.map +1 -1
  136. package/background/src/lib/virtualized/project/writeScenarioComponents.js +399 -106
  137. package/background/src/lib/virtualized/project/writeScenarioComponents.js.map +1 -1
  138. package/background/src/lib/virtualized/project/writeSimpleRoot.js +11 -11
  139. package/background/src/lib/virtualized/project/writeSimpleRoot.js.map +1 -1
  140. package/codeyam-cli/src/cli.js +2 -0
  141. package/codeyam-cli/src/cli.js.map +1 -1
  142. package/codeyam-cli/src/commands/debug.js +14 -2
  143. package/codeyam-cli/src/commands/debug.js.map +1 -1
  144. package/codeyam-cli/src/commands/recapture.js +215 -0
  145. package/codeyam-cli/src/commands/recapture.js.map +1 -0
  146. package/codeyam-cli/src/commands/report.js +26 -23
  147. package/codeyam-cli/src/commands/report.js.map +1 -1
  148. package/codeyam-cli/src/utils/backgroundServer.js +2 -2
  149. package/codeyam-cli/src/utils/backgroundServer.js.map +1 -1
  150. package/codeyam-cli/src/utils/generateReport.js +252 -106
  151. package/codeyam-cli/src/utils/generateReport.js.map +1 -1
  152. package/codeyam-cli/src/utils/install-skills.js +2 -2
  153. package/codeyam-cli/src/utils/install-skills.js.map +1 -1
  154. package/codeyam-cli/src/utils/queue/__tests__/manager.test.js +38 -0
  155. package/codeyam-cli/src/utils/queue/__tests__/manager.test.js.map +1 -1
  156. package/codeyam-cli/src/utils/queue/job.js +140 -16
  157. package/codeyam-cli/src/utils/queue/job.js.map +1 -1
  158. package/codeyam-cli/src/utils/queue/manager.js +19 -7
  159. package/codeyam-cli/src/utils/queue/manager.js.map +1 -1
  160. package/codeyam-cli/src/utils/queue/persistence.js.map +1 -1
  161. package/codeyam-cli/src/webserver/app/lib/database.js +47 -0
  162. package/codeyam-cli/src/webserver/app/lib/database.js.map +1 -1
  163. package/codeyam-cli/src/webserver/app/lib/dbNotifier.js.map +1 -1
  164. package/codeyam-cli/src/webserver/backgroundServer.js +5 -10
  165. package/codeyam-cli/src/webserver/backgroundServer.js.map +1 -1
  166. package/codeyam-cli/src/webserver/bootstrap.js +9 -0
  167. package/codeyam-cli/src/webserver/bootstrap.js.map +1 -0
  168. package/codeyam-cli/src/webserver/build/client/assets/EntityItem-wXL1Z2Aq.js +1 -0
  169. package/codeyam-cli/src/webserver/build/client/assets/{EntityTypeBadge-efWKDYMr.js → EntityTypeBadge-CzGX-miz.js} +1 -1
  170. package/codeyam-cli/src/webserver/build/client/assets/EntityTypeIcon-CXFKsCOD.js +41 -0
  171. package/codeyam-cli/src/webserver/build/client/assets/InteractivePreview-D-9pXIaY.js +25 -0
  172. package/codeyam-cli/src/webserver/build/client/assets/LibraryFunctionPreview-CBQPrpT0.js +3 -0
  173. package/codeyam-cli/src/webserver/build/client/assets/LoadingDots-D1CdlbrV.js +6 -0
  174. package/codeyam-cli/src/webserver/build/client/assets/LogViewer-wDPcZNKx.js +3 -0
  175. package/codeyam-cli/src/webserver/build/client/assets/ReportIssueModal-4lcOlid-.js +11 -0
  176. package/codeyam-cli/src/webserver/build/client/assets/SafeScreenshot-BfmDgXxG.js +1 -0
  177. package/codeyam-cli/src/webserver/build/client/assets/ScenarioViewer-CUxUNEEC.js +15 -0
  178. package/codeyam-cli/src/webserver/build/client/assets/{TruncatedFilePath-COPstp9J.js → TruncatedFilePath-6J7zDUD5.js} +1 -1
  179. package/codeyam-cli/src/webserver/build/client/assets/_index-DHImXdXq.js +11 -0
  180. package/codeyam-cli/src/webserver/build/client/assets/activity.(_tab)-CVP_WGQ3.js +32 -0
  181. package/codeyam-cli/src/webserver/build/client/assets/api.link-scenario-value-l0sNRNKZ.js +1 -0
  182. package/codeyam-cli/src/webserver/build/client/assets/api.update-key-attributes-l0sNRNKZ.js +1 -0
  183. package/codeyam-cli/src/webserver/build/client/assets/api.update-valid-values-l0sNRNKZ.js +1 -0
  184. package/codeyam-cli/src/webserver/build/client/assets/chevron-down-BYimnrHg.js +6 -0
  185. package/codeyam-cli/src/webserver/build/client/assets/chunk-JMJ3UQ3L-BambyYE_.js +51 -0
  186. package/codeyam-cli/src/webserver/build/client/assets/circle-check-CaVsIRxt.js +6 -0
  187. package/codeyam-cli/src/webserver/build/client/assets/createLucideIcon-CgUsG7ib.js +21 -0
  188. package/codeyam-cli/src/webserver/build/client/assets/cy-logo-cli-CKnwPCDr.js +1 -0
  189. package/codeyam-cli/src/webserver/build/client/assets/dev.empty-DW_hdGUc.js +1 -0
  190. package/codeyam-cli/src/webserver/build/client/assets/entity._sha._-Dt-SjPsw.js +23 -0
  191. package/codeyam-cli/src/webserver/build/client/assets/entity._sha.scenarios._scenarioId.fullscreen-DyB90fWk.js +1 -0
  192. package/codeyam-cli/src/webserver/build/client/assets/entity._sha_.create-scenario-D_3ero5o.js +1 -0
  193. package/codeyam-cli/src/webserver/build/client/assets/entity._sha_.edit._scenarioId-CfLCUi9S.js +5 -0
  194. package/codeyam-cli/src/webserver/build/client/assets/entry.client-DKJyZfAY.js +29 -0
  195. package/codeyam-cli/src/webserver/build/client/assets/fileTableUtils-DAtOlaWE.js +1 -0
  196. package/codeyam-cli/src/webserver/build/client/assets/files-ClR0d32A.js +1 -0
  197. package/codeyam-cli/src/webserver/build/client/assets/git-D62Lxxmv.js +15 -0
  198. package/codeyam-cli/src/webserver/build/client/assets/globals-C9s7Lhdl.css +1 -0
  199. package/codeyam-cli/src/webserver/build/client/assets/html2canvas-pro.esm-fmIEn3Bc.js +9 -0
  200. package/codeyam-cli/src/webserver/build/client/assets/index-BosqDOlH.js +3 -0
  201. package/codeyam-cli/src/webserver/build/client/assets/index-CzNNiTkw.js +9 -0
  202. package/codeyam-cli/src/webserver/build/client/assets/keyAttributeCoverage-CTlFMihX.js +1 -0
  203. package/codeyam-cli/src/webserver/build/client/assets/loader-circle-CNp9QFCX.js +6 -0
  204. package/codeyam-cli/src/webserver/build/client/assets/manifest-0d27da29.js +1 -0
  205. package/codeyam-cli/src/webserver/build/client/assets/preload-helper-ckwbz45p.js +1 -0
  206. package/codeyam-cli/src/webserver/build/client/assets/root-B_wIKCIf.js +56 -0
  207. package/codeyam-cli/src/webserver/build/client/assets/scenarioStatus-B_8jpV3e.js +1 -0
  208. package/codeyam-cli/src/webserver/build/client/assets/search-DDGjYAMJ.js +6 -0
  209. package/codeyam-cli/src/webserver/build/client/assets/settings-DgTyB-Wg.js +1 -0
  210. package/codeyam-cli/src/webserver/build/client/assets/simulations-CoNWGt0K.js +1 -0
  211. package/codeyam-cli/src/webserver/build/client/assets/triangle-alert-CBc5dE1s.js +6 -0
  212. package/codeyam-cli/src/webserver/build/client/assets/useCustomSizes-BMIGFP-m.js +1 -0
  213. package/codeyam-cli/src/webserver/build/client/assets/useInteractiveMode-Dk_FQqWJ.js +1 -0
  214. package/codeyam-cli/src/webserver/build/client/assets/{useLastLogLine-3pmpUQB-.js → useLastLogLine-BqPPNjAl.js} +1 -1
  215. package/codeyam-cli/src/webserver/build/client/assets/useReportContext-DsJbgMY9.js +1 -0
  216. package/codeyam-cli/src/webserver/build/client/assets/{useToast-DEyawJ8r.js → useToast-DWHcCcl1.js} +1 -1
  217. package/codeyam-cli/src/webserver/build/server/assets/index-CU58-Ttc.js +1 -0
  218. package/codeyam-cli/src/webserver/build/server/assets/server-build-D35o2uae.js +175 -0
  219. package/codeyam-cli/src/webserver/build/server/index.js +1 -1
  220. package/codeyam-cli/src/webserver/build-info.json +5 -5
  221. package/codeyam-cli/src/webserver/devServer.js +1 -3
  222. package/codeyam-cli/src/webserver/devServer.js.map +1 -1
  223. package/codeyam-cli/templates/codeyam-setup-skill.md +138 -3
  224. package/codeyam-cli/templates/debug-codeyam.md +625 -0
  225. package/package.json +14 -14
  226. package/packages/ai/src/lib/analyzeScope.js +2 -0
  227. package/packages/ai/src/lib/analyzeScope.js.map +1 -1
  228. package/packages/ai/src/lib/astScopes/astScopeAnalyzer.js +16 -0
  229. package/packages/ai/src/lib/astScopes/astScopeAnalyzer.js.map +1 -1
  230. package/packages/ai/src/lib/astScopes/patterns/switchStatementHandler.js +16 -0
  231. package/packages/ai/src/lib/astScopes/patterns/switchStatementHandler.js.map +1 -1
  232. package/packages/ai/src/lib/astScopes/processExpression.js +305 -88
  233. package/packages/ai/src/lib/astScopes/processExpression.js.map +1 -1
  234. package/packages/ai/src/lib/dataStructure/ScopeDataStructure.js +582 -41
  235. package/packages/ai/src/lib/dataStructure/ScopeDataStructure.js.map +1 -1
  236. package/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/JavascriptFrameworkManager.js +2 -1
  237. package/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/JavascriptFrameworkManager.js.map +1 -1
  238. package/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/MuiManager.js +454 -0
  239. package/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/MuiManager.js.map +1 -0
  240. package/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/ReactFrameworkManager.js +173 -55
  241. package/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/ReactFrameworkManager.js.map +1 -1
  242. package/packages/ai/src/lib/dataStructure/helpers/cleanKnownObjectFunctions.js +16 -1
  243. package/packages/ai/src/lib/dataStructure/helpers/cleanKnownObjectFunctions.js.map +1 -1
  244. package/packages/ai/src/lib/dataStructure/helpers/cleanNonObjectFunctions.js +30 -1
  245. package/packages/ai/src/lib/dataStructure/helpers/cleanNonObjectFunctions.js.map +1 -1
  246. package/packages/ai/src/lib/dataStructure/helpers/convertDotNotation.js +20 -0
  247. package/packages/ai/src/lib/dataStructure/helpers/convertDotNotation.js.map +1 -1
  248. package/packages/ai/src/lib/dataStructure/helpers/convertNullToUndefinedBySchema.js +86 -0
  249. package/packages/ai/src/lib/dataStructure/helpers/convertNullToUndefinedBySchema.js.map +1 -0
  250. package/packages/ai/src/lib/dataStructure/helpers/fillInSchemaGapsAndUnknowns.js +28 -2
  251. package/packages/ai/src/lib/dataStructure/helpers/fillInSchemaGapsAndUnknowns.js.map +1 -1
  252. package/packages/ai/src/lib/gatherRelevantDependentKeyAttributes.js +179 -17
  253. package/packages/ai/src/lib/gatherRelevantDependentKeyAttributes.js.map +1 -1
  254. package/packages/ai/src/lib/generateChangesEntityKeyAttributes.js +6 -0
  255. package/packages/ai/src/lib/generateChangesEntityKeyAttributes.js.map +1 -1
  256. package/packages/ai/src/lib/generateChangesEntityScenarioData.js +41 -0
  257. package/packages/ai/src/lib/generateChangesEntityScenarioData.js.map +1 -1
  258. package/packages/ai/src/lib/generateChangesEntityScenarios.js +37 -4
  259. package/packages/ai/src/lib/generateChangesEntityScenarios.js.map +1 -1
  260. package/packages/ai/src/lib/generateEntityDataStructure.js +4 -0
  261. package/packages/ai/src/lib/generateEntityDataStructure.js.map +1 -1
  262. package/packages/ai/src/lib/generateEntityKeyAttributes.js +176 -9
  263. package/packages/ai/src/lib/generateEntityKeyAttributes.js.map +1 -1
  264. package/packages/ai/src/lib/generateEntityScenarioData.js +29 -25
  265. package/packages/ai/src/lib/generateEntityScenarioData.js.map +1 -1
  266. package/packages/ai/src/lib/generateEntityScenarios.js +105 -9
  267. package/packages/ai/src/lib/generateEntityScenarios.js.map +1 -1
  268. package/packages/ai/src/lib/getConditionalUsagesFromCode.js +84 -14
  269. package/packages/ai/src/lib/getConditionalUsagesFromCode.js.map +1 -1
  270. package/packages/ai/src/lib/guessScenarioDataFromDescription.js +2 -1
  271. package/packages/ai/src/lib/guessScenarioDataFromDescription.js.map +1 -1
  272. package/packages/ai/src/lib/promptGenerators/gatherAttributesMap.js +6 -0
  273. package/packages/ai/src/lib/promptGenerators/gatherAttributesMap.js.map +1 -1
  274. package/packages/ai/src/lib/promptGenerators/generateChangesEntityScenariosGenerator.js +38 -2
  275. package/packages/ai/src/lib/promptGenerators/generateChangesEntityScenariosGenerator.js.map +1 -1
  276. package/packages/ai/src/lib/promptGenerators/generateEntityScenariosGenerator.js +38 -2
  277. package/packages/ai/src/lib/promptGenerators/generateEntityScenariosGenerator.js.map +1 -1
  278. package/packages/ai/src/lib/promptGenerators/guessNewScenarioDataFromDescriptionGenerator.js +16 -3
  279. package/packages/ai/src/lib/promptGenerators/guessNewScenarioDataFromDescriptionGenerator.js.map +1 -1
  280. package/packages/ai/src/lib/worker/SerializableDataStructure.js.map +1 -1
  281. package/packages/ai/src/lib/worker/analyzeScopeWorker.js +4 -0
  282. package/packages/ai/src/lib/worker/analyzeScopeWorker.js.map +1 -1
  283. package/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.js +100 -23
  284. package/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.js.map +1 -1
  285. package/packages/analyze/src/lib/files/scenarios/enrichArrayTypesFromChildSignatures.js +125 -0
  286. package/packages/analyze/src/lib/files/scenarios/enrichArrayTypesFromChildSignatures.js.map +1 -0
  287. package/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.js +298 -45
  288. package/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.js.map +1 -1
  289. package/packages/analyze/src/lib/files/scenarios/generateChangesScenarioData.js +1 -1
  290. package/packages/analyze/src/lib/files/scenarios/generateChangesScenarioData.js.map +1 -1
  291. package/packages/analyze/src/lib/files/scenarios/generateDataStructure.js +201 -80
  292. package/packages/analyze/src/lib/files/scenarios/generateDataStructure.js.map +1 -1
  293. package/packages/analyze/src/lib/files/scenarios/generateKeyAttributes.js +10 -5
  294. package/packages/analyze/src/lib/files/scenarios/generateKeyAttributes.js.map +1 -1
  295. package/packages/analyze/src/lib/files/scenarios/generateScenarioData.js +55 -69
  296. package/packages/analyze/src/lib/files/scenarios/generateScenarioData.js.map +1 -1
  297. package/packages/analyze/src/lib/files/scenarios/generateScenarios.js +2 -5
  298. package/packages/analyze/src/lib/files/scenarios/generateScenarios.js.map +1 -1
  299. package/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.js +171 -81
  300. package/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.js.map +1 -1
  301. package/packages/database/src/lib/kysely/db.js +2 -2
  302. package/packages/database/src/lib/kysely/tables/debugReportsTable.js +9 -3
  303. package/packages/database/src/lib/kysely/tables/debugReportsTable.js.map +1 -1
  304. package/packages/generate/src/lib/componentScenarioPage/getIFrameMessageListenerCode.js +8 -4
  305. package/packages/generate/src/lib/componentScenarioPage/getIFrameMessageListenerCode.js.map +1 -1
  306. package/packages/generate/src/lib/deepMerge.js +27 -1
  307. package/packages/generate/src/lib/deepMerge.js.map +1 -1
  308. package/packages/types/index.js +1 -0
  309. package/packages/types/index.js.map +1 -1
  310. package/packages/types/src/types/Scenario.js +21 -1
  311. package/packages/types/src/types/Scenario.js.map +1 -1
  312. package/packages/utils/src/lib/lightweightEntityExtractor.js +25 -0
  313. package/packages/utils/src/lib/lightweightEntityExtractor.js.map +1 -1
  314. package/scripts/finalize-analyzer.cjs +3 -1
  315. package/codeyam-cli/scripts/fixtures/cal.com/universal-mocks/packages/prisma/index.js +0 -238
  316. package/codeyam-cli/scripts/fixtures/cal.com/universal-mocks/packages/prisma/index.js.map +0 -1
  317. package/codeyam-cli/src/webserver/build/client/assets/EntityItem-CVbSvOjo.js +0 -1
  318. package/codeyam-cli/src/webserver/build/client/assets/EntityTypeIcon-DcwcHyl5.js +0 -1
  319. package/codeyam-cli/src/webserver/build/client/assets/InteractivePreview-WgwC1GfJ.js +0 -26
  320. package/codeyam-cli/src/webserver/build/client/assets/LibraryFunctionPreview-IEKom9O2.js +0 -3
  321. package/codeyam-cli/src/webserver/build/client/assets/LogViewer-BYnfxbUG.js +0 -3
  322. package/codeyam-cli/src/webserver/build/client/assets/ReportIssueModal-_lBPJCzG.js +0 -1
  323. package/codeyam-cli/src/webserver/build/client/assets/SafeScreenshot-lHVhvsu_.js +0 -1
  324. package/codeyam-cli/src/webserver/build/client/assets/ScenarioViewer-d_TBk4GQ.js +0 -5
  325. package/codeyam-cli/src/webserver/build/client/assets/_index-kGT7VUqj.js +0 -1
  326. package/codeyam-cli/src/webserver/build/client/assets/activity.(_tab)-DDGmhu7P.js +0 -7
  327. package/codeyam-cli/src/webserver/build/client/assets/chevron-down-n_HPRfM_.js +0 -1
  328. package/codeyam-cli/src/webserver/build/client/assets/chunk-WWGJGFF6-CbVoyx1U.js +0 -26
  329. package/codeyam-cli/src/webserver/build/client/assets/circle-check-D1VOYveA.js +0 -1
  330. package/codeyam-cli/src/webserver/build/client/assets/createLucideIcon-YR8jjAlu.js +0 -1
  331. package/codeyam-cli/src/webserver/build/client/assets/dev.empty-B8vP3V_s.js +0 -1
  332. package/codeyam-cli/src/webserver/build/client/assets/entity._sha._-CN6aLCT1.js +0 -16
  333. package/codeyam-cli/src/webserver/build/client/assets/entity._sha_.create-scenario-DA5Jeu2P.js +0 -1
  334. package/codeyam-cli/src/webserver/build/client/assets/entity._sha_.edit._scenarioId-BTeitalf.js +0 -5
  335. package/codeyam-cli/src/webserver/build/client/assets/entry.client-du6UEYD-.js +0 -13
  336. package/codeyam-cli/src/webserver/build/client/assets/fileTableUtils-BpjkhMoi.js +0 -1
  337. package/codeyam-cli/src/webserver/build/client/assets/files-BQGvk4lJ.js +0 -1
  338. package/codeyam-cli/src/webserver/build/client/assets/git-DVdYRT-I.js +0 -12
  339. package/codeyam-cli/src/webserver/build/client/assets/globals-CO-U8Bpo.css +0 -1
  340. package/codeyam-cli/src/webserver/build/client/assets/html2canvas-pro.esm-XQCGvadH.js +0 -5
  341. package/codeyam-cli/src/webserver/build/client/assets/index-DCG-vks0.js +0 -1
  342. package/codeyam-cli/src/webserver/build/client/assets/loader-circle-GazdNeLl.js +0 -1
  343. package/codeyam-cli/src/webserver/build/client/assets/manifest-0b694d28.js +0 -1
  344. package/codeyam-cli/src/webserver/build/client/assets/root-D3tQP7hx.js +0 -16
  345. package/codeyam-cli/src/webserver/build/client/assets/search-CIY6XmtE.js +0 -1
  346. package/codeyam-cli/src/webserver/build/client/assets/server-build-CMKNK2uU.css +0 -1
  347. package/codeyam-cli/src/webserver/build/client/assets/settings-CoMDgElu.js +0 -1
  348. package/codeyam-cli/src/webserver/build/client/assets/simulations-agkniXp2.js +0 -1
  349. package/codeyam-cli/src/webserver/build/client/assets/triangle-alert-B2VUcygF.js +0 -1
  350. package/codeyam-cli/src/webserver/build/client/assets/useReportContext-EvdK-zXP.js +0 -1
  351. package/codeyam-cli/src/webserver/build/server/assets/index-DGVHQEXD.js +0 -1
  352. package/codeyam-cli/src/webserver/build/server/assets/server-build-CghkTkIL.js +0 -166
  353. package/codeyam-cli/templates/debug-command.md +0 -303
  354. /package/codeyam-cli/src/webserver/build/client/assets/{InteractivePreview-CMKNK2uU.css → styles-CMKNK2uU.css} +0 -0
@@ -221,6 +221,22 @@ export interface FunctionCallInfo {
221
221
  * For example: { "db.select(query1)": "result1", "db.select(query2)": "result2" }
222
222
  */
223
223
  callSignatureToVariable?: Record<string, string>;
224
+ /**
225
+ * Stores individual schemas per call signature BEFORE merging.
226
+ * When multiple calls to the same function are merged into one FunctionCallInfo,
227
+ * this preserves each call's distinct schema.
228
+ * Key is the call signature (e.g., "useFetcher()").
229
+ * Used internally; converted to perVariableSchemas in toSerializable().
230
+ */
231
+ perCallSignatureSchemas?: Record<string, Record<string, string>>;
232
+ /**
233
+ * Stores individual return value schemas per receiving variable, BEFORE merging.
234
+ * When multiple calls to the same function have different return types
235
+ * (e.g., useFetcher<UserData>() vs useFetcher<ReportData>()), this preserves
236
+ * each call's distinct schema for mock data generation.
237
+ * Key is the receiving variable name (e.g., "userFetcher", "reportFetcher").
238
+ */
239
+ perVariableSchemas?: Record<string, Record<string, string>>;
224
240
  }
225
241
 
226
242
  /**
@@ -320,6 +336,10 @@ const ALLOWED_EQUIVALENCY_REASONS = new Set([
320
336
  'propagated function call return sub-property equivalency',
321
337
  'propagated parent-variable equivalency', // Added: propagate child scope equivalencies to parent scope when variable is defined in parent
322
338
  'where was this function called from', // Added: tracks which scope called an external function
339
+ 'MUI DataGrid renderCell params.row equivalency', // Added: links DataGrid renderCell params.row to rows array elements
340
+ 'MUI Autocomplete getOptionLabel option equivalency', // Added: links Autocomplete getOptionLabel callback param to options array
341
+ 'MUI Autocomplete renderOption option equivalency', // Added: links Autocomplete renderOption callback param to options array
342
+ 'MUI Autocomplete option property equivalency', // Added: propagates property accesses from Autocomplete callbacks
323
343
  ]);
324
344
 
325
345
  const SILENTLY_IGNORED_EQUIVALENCY_REASONS = new Set([
@@ -382,6 +402,10 @@ export class ScopeDataStructure {
382
402
  private externalFunctionCallsIndex: Map<string, FunctionCallInfo> | null =
383
403
  null;
384
404
 
405
+ // Tracks internal functions that have been filtered out during captureCompleteSchema
406
+ // Prevents re-adding them via subsequent equivalency propagation (e.g., from getReturnValue)
407
+ private filteredInternalFunctions: Set<string> = new Set();
408
+
385
409
  // Debug tracer for selective path/scope tracing
386
410
  // Enable via: CODEYAM_DEBUG=true CODEYAM_DEBUG_PATHS="user.*,signature" npm test
387
411
  private tracer: DebugTracer = new DebugTracer({
@@ -540,6 +564,8 @@ export class ScopeDataStructure {
540
564
  const efcName = this.pathManager.stripGenerics(efc.name);
541
565
  for (const manager of this.equivalencyManagers) {
542
566
  if (manager.internalFunctions.has(efcName)) {
567
+ // Track this so we don't re-add it via subsequent finalize calls
568
+ this.filteredInternalFunctions.add(efcName);
543
569
  return false;
544
570
  }
545
571
  }
@@ -567,13 +593,51 @@ export class ScopeDataStructure {
567
593
  const baseName = this.pathManager.stripGenerics(
568
594
  candidate.scopeNodeName,
569
595
  );
596
+ // Check if this is a local variable path (doesn't contain function call pattern)
597
+ // Local variables like "surveys[]" or "items[]" are important for tracing data flow
598
+ // from parent to child components (e.g., surveys[] -> SurveyCard().signature[0].survey)
599
+ const isLocalVariablePath =
600
+ !candidate.schemaPath.includes('()') &&
601
+ !candidate.schemaPath.startsWith('signature[') &&
602
+ !candidate.schemaPath.startsWith('returnValue');
603
+
570
604
  return (
571
605
  validExternalFacingScopeNames.has(baseName) &&
572
606
  (candidate.schemaPath.startsWith('signature[') ||
573
- candidate.schemaPath.startsWith(baseName)) &&
607
+ candidate.schemaPath.startsWith(baseName) ||
608
+ isLocalVariablePath) &&
574
609
  !containsArrayMethod(candidate.schemaPath)
575
610
  );
576
611
  });
612
+
613
+ // If all sourceCandidates were filtered out (e.g., because they belonged to
614
+ // internal functions like useState), look for the highest-order intermediate
615
+ // that belongs to a valid external-facing scope
616
+ if (
617
+ entry.sourceCandidates.length === 0 &&
618
+ Object.keys(entry.intermediatesOrder).length > 0
619
+ ) {
620
+ // Find intermediates that belong to valid external-facing scopes
621
+ const validIntermediates = Object.entries(entry.intermediatesOrder)
622
+ .filter(([pathId]) => {
623
+ const [scopeNodeName, schemaPath] = pathId.split('::');
624
+ if (!scopeNodeName || !schemaPath) return false;
625
+ const baseName = this.pathManager.stripGenerics(scopeNodeName);
626
+ return (
627
+ validExternalFacingScopeNames.has(baseName) &&
628
+ !containsArrayMethod(schemaPath)
629
+ );
630
+ })
631
+ .sort((a, b) => b[1] - a[1]); // Sort by order descending (highest first)
632
+
633
+ if (validIntermediates.length > 0) {
634
+ const [pathId] = validIntermediates[0];
635
+ const [scopeNodeName, schemaPath] = pathId.split('::');
636
+ if (scopeNodeName && schemaPath) {
637
+ entry.sourceCandidates.push({ scopeNodeName, schemaPath });
638
+ }
639
+ }
640
+ }
577
641
  }
578
642
 
579
643
  this.propagateSourceAndUsageEquivalencies(
@@ -1151,10 +1215,38 @@ export class ScopeDataStructure {
1151
1215
  const existingFunctionCall =
1152
1216
  this.getExternalFunctionCallsIndex().get(searchKey);
1153
1217
  if (existingFunctionCall) {
1154
- existingFunctionCall.schema = {
1218
+ // Preserve per-call schemas BEFORE merging to enable per-variable mock data.
1219
+ // This is critical for hooks like useFetcher<UserData>() vs useFetcher<ReportData>()
1220
+ // where each call returns different typed data.
1221
+ if (!existingFunctionCall.perCallSignatureSchemas) {
1222
+ // First merge - save the existing call's schema
1223
+ existingFunctionCall.perCallSignatureSchemas = {
1224
+ [existingFunctionCall.callSignature]: {
1225
+ ...existingFunctionCall.schema,
1226
+ },
1227
+ };
1228
+ }
1229
+ // Save the new call's schema before it gets merged
1230
+ existingFunctionCall.perCallSignatureSchemas[
1231
+ functionCallInfo.callSignature
1232
+ ] = { ...functionCallInfo.schema };
1233
+
1234
+ // Merge schemas using selectBestValue to preserve specific types like 'null'
1235
+ // over generic types like 'unknown'. This ensures ref variables detected
1236
+ // earlier (marked as 'null') aren't overwritten by later 'unknown' values.
1237
+ const mergedSchema: Record<string, string> = {
1155
1238
  ...existingFunctionCall.schema,
1156
- ...functionCallInfo.schema,
1157
1239
  };
1240
+ for (const key in functionCallInfo.schema) {
1241
+ const existingValue = existingFunctionCall.schema[key];
1242
+ const newValue = functionCallInfo.schema[key];
1243
+ mergedSchema[key] = selectBestValue(
1244
+ existingValue,
1245
+ newValue,
1246
+ newValue,
1247
+ );
1248
+ }
1249
+ existingFunctionCall.schema = mergedSchema;
1158
1250
 
1159
1251
  existingFunctionCall.equivalencies = {
1160
1252
  ...existingFunctionCall.equivalencies,
@@ -1187,8 +1279,15 @@ export class ScopeDataStructure {
1187
1279
  );
1188
1280
 
1189
1281
  if (isExternal) {
1190
- this.externalFunctionCalls.push(functionCallInfo);
1191
- this.invalidateExternalFunctionCallsIndex();
1282
+ // Check if this function was already filtered out as an internal function
1283
+ // (e.g., useState was filtered in captureCompleteSchema but finalize is trying to re-add it)
1284
+ const strippedName = this.pathManager.stripGenerics(
1285
+ functionCallInfo.name,
1286
+ );
1287
+ if (!this.filteredInternalFunctions.has(strippedName)) {
1288
+ this.externalFunctionCalls.push(functionCallInfo);
1289
+ this.invalidateExternalFunctionCallsIndex();
1290
+ }
1192
1291
  }
1193
1292
  }
1194
1293
  }
@@ -1296,6 +1395,18 @@ export class ScopeDataStructure {
1296
1395
  const equivalentSchemaPath = equivalentSchemaPathMap.get(remainingKey);
1297
1396
 
1298
1397
  if (equivalentSchemaPath) {
1398
+ // Skip propagation when there's a structural mismatch:
1399
+ // - schemaPath ends with [] (array element, represents an object)
1400
+ // - equivalentSchemaPath doesn't end with [] (non-array prop, usually a scalar)
1401
+ // This prevents incorrectly typing array elements as strings when they're
1402
+ // equivalent to scalar props like JSX keys (e.g., workouts[] ↔ Card().key)
1403
+ const schemaPathEndsWithArray = schemaPath.endsWith('[]');
1404
+ const equivalentEndsWithArray = equivalentSchemaPath.endsWith('[]');
1405
+ if (schemaPathEndsWithArray !== equivalentEndsWithArray) {
1406
+ // Don't propagate between array element paths and non-array paths
1407
+ continue;
1408
+ }
1409
+
1299
1410
  const value1 = scopeNode.schema[schemaPath];
1300
1411
  const value2 = equivalentScopeNode.schema[equivalentSchemaPath];
1301
1412
 
@@ -3160,7 +3271,12 @@ export class ScopeDataStructure {
3160
3271
  );
3161
3272
  }
3162
3273
 
3274
+ // CRITICAL: Set onlyEquivalencies to true to prevent database modifications
3275
+ // during this "getter" method. See comment in getFunctionSignature.
3276
+ const wasOnlyEquivalencies = this.onlyEquivalencies;
3277
+ this.onlyEquivalencies = true;
3163
3278
  this.validateSchema(scopeNode, true, fillInUnknowns);
3279
+ this.onlyEquivalencies = wasOnlyEquivalencies;
3164
3280
 
3165
3281
  const { schema } = scopeNode;
3166
3282
 
@@ -3261,6 +3377,7 @@ export class ScopeDataStructure {
3261
3377
  (candidate) => candidate.scopeNodeName === scopeNode.name,
3262
3378
  ),
3263
3379
  );
3380
+
3264
3381
  return entries.reduce(
3265
3382
  (acc, entry) => {
3266
3383
  if (entry.usages.length === 0) return acc;
@@ -3304,12 +3421,14 @@ export class ScopeDataStructure {
3304
3421
  );
3305
3422
 
3306
3423
  const equivalencies = this.getEquivalencies(functionName);
3424
+ const scopeName = functionName ?? this.scopeTreeManager.getRootName();
3425
+
3307
3426
  for (const equivalenceKey in equivalencies ?? {}) {
3308
3427
  for (const equivalenceValue of equivalencies[equivalenceKey]) {
3309
3428
  const schemaPath = equivalenceValue.schemaPath;
3310
3429
  if (
3311
3430
  schemaPath.startsWith('signature[') &&
3312
- equivalenceValue.scopeNodeName === functionName &&
3431
+ equivalenceValue.scopeNodeName === scopeName &&
3313
3432
  !signatureInSchema[schemaPath]
3314
3433
  ) {
3315
3434
  signatureInSchema[schemaPath] = 'unknown';
@@ -3325,6 +3444,59 @@ export class ScopeDataStructure {
3325
3444
 
3326
3445
  this.validateSchema(tempScopeNode, true, fillInUnknowns);
3327
3446
 
3447
+ // After validateSchema has filled in types, propagate nested paths from
3448
+ // variables to their signature equivalents.
3449
+ // e.g., workouts[].activity_type -> signature[0].workouts[].activity_type
3450
+ //
3451
+ // Build a map of variable names that are equivalent to signature paths
3452
+ // e.g., { 'workouts': 'signature[0].workouts' }
3453
+ const variableToSignatureMap: Record<string, string> = {};
3454
+
3455
+ for (const equivalenceKey in equivalencies ?? {}) {
3456
+ for (const equivalenceValue of equivalencies[equivalenceKey]) {
3457
+ const schemaPath = equivalenceValue.schemaPath;
3458
+ // Track which variables map to signature paths
3459
+ // equivalenceKey is the variable name (e.g., 'workouts')
3460
+ // schemaPath is where it comes from (e.g., 'signature[0].workouts')
3461
+ if (
3462
+ schemaPath.startsWith('signature[') &&
3463
+ equivalenceValue.scopeNodeName === scopeName
3464
+ ) {
3465
+ variableToSignatureMap[equivalenceKey] = schemaPath;
3466
+ }
3467
+ }
3468
+ }
3469
+
3470
+ // Propagate nested paths from variables to their signature equivalents
3471
+ // e.g., if workouts = signature[0].workouts, then workouts[].title becomes
3472
+ // signature[0].workouts[].title
3473
+ for (const schemaKey in schema) {
3474
+ // Skip keys that already start with signature[
3475
+ if (schemaKey.startsWith('signature[')) continue;
3476
+
3477
+ // Check if this key starts with a variable that maps to a signature path
3478
+ for (const [variableName, signaturePath] of Object.entries(
3479
+ variableToSignatureMap,
3480
+ )) {
3481
+ // Check if schemaKey starts with variableName followed by a property accessor
3482
+ // e.g., 'workouts[]' starts with 'workouts'
3483
+ if (
3484
+ schemaKey === variableName ||
3485
+ schemaKey.startsWith(variableName + '.') ||
3486
+ schemaKey.startsWith(variableName + '[')
3487
+ ) {
3488
+ // Transform the path: replace the variable prefix with the signature path
3489
+ const suffix = schemaKey.slice(variableName.length);
3490
+ const signatureKey = signaturePath + suffix;
3491
+
3492
+ // Add to schema if not already present
3493
+ if (!tempScopeNode.schema[signatureKey]) {
3494
+ tempScopeNode.schema[signatureKey] = schema[schemaKey];
3495
+ }
3496
+ }
3497
+ }
3498
+ }
3499
+
3328
3500
  return tempScopeNode.schema;
3329
3501
  }
3330
3502
 
@@ -3335,6 +3507,15 @@ export class ScopeDataStructure {
3335
3507
  functionName?: string;
3336
3508
  fillInUnknowns?: boolean;
3337
3509
  }) {
3510
+ // Trigger finalization on all managers to apply any pending updates
3511
+ // (e.g., ref type propagation to external function call schemas)
3512
+ const rootScope = this.scopeNodes[this.scopeTreeManager.getRootName()];
3513
+ if (rootScope) {
3514
+ for (const manager of this.equivalencyManagers) {
3515
+ manager.finalize(rootScope, this);
3516
+ }
3517
+ }
3518
+
3338
3519
  const scopeName = functionName ?? this.scopeTreeManager.getRootName();
3339
3520
  const scopeNode = this.scopeNodes[scopeName];
3340
3521
 
@@ -3345,7 +3526,8 @@ export class ScopeDataStructure {
3345
3526
  scopeNode: scopeNode,
3346
3527
  });
3347
3528
  } else {
3348
- for (const externalFunctionCall of this.externalFunctionCalls) {
3529
+ // Use getExternalFunctionCalls() which cleans cyScope from schemas
3530
+ for (const externalFunctionCall of this.getExternalFunctionCalls()) {
3349
3531
  const functionNameParts = this.splitPath(functionName).map((p) =>
3350
3532
  this.functionOrScopeName(p),
3351
3533
  );
@@ -3401,7 +3583,12 @@ export class ScopeDataStructure {
3401
3583
 
3402
3584
  const tempScopeNode = this.createTempScopeNode(scopeName, resolvedSchema);
3403
3585
 
3586
+ // CRITICAL: Set onlyEquivalencies to true to prevent database modifications
3587
+ // during this "getter" method. See comment in getFunctionSignature.
3588
+ const wasOnlyEquivalencies = this.onlyEquivalencies;
3589
+ this.onlyEquivalencies = true;
3404
3590
  this.validateSchema(tempScopeNode, true, fillInUnknowns);
3591
+ this.onlyEquivalencies = wasOnlyEquivalencies;
3405
3592
 
3406
3593
  return tempScopeNode.schema;
3407
3594
  }
@@ -3409,6 +3596,8 @@ export class ScopeDataStructure {
3409
3596
  /**
3410
3597
  * Replaces cyScope placeholder references (e.g., cyScope10()) in schema keys
3411
3598
  * with the actual callback function text from the corresponding scope node.
3599
+ * If the scope text can't be found, uses a generic fallback to avoid leaking
3600
+ * internal cyScope names into stored data.
3412
3601
  */
3413
3602
  private replaceCyScopePlaceholders(
3414
3603
  schema: Record<string, string>,
@@ -3424,10 +3613,10 @@ export class ScopeDataStructure {
3424
3613
  for (const match of matches) {
3425
3614
  const cyScopeName = `cyScope${match[1]}`;
3426
3615
  const scopeText = this.findCyScopeText(cyScopeName);
3427
- if (scopeText) {
3428
- // Replace cyScope10() with the actual callback text
3429
- newKey = newKey.replace(match[0], scopeText);
3430
- }
3616
+ // Always replace cyScope references - use actual text if available,
3617
+ // otherwise use a generic callback placeholder
3618
+ const replacement = scopeText || '() => {}';
3619
+ newKey = newKey.replace(match[0], replacement);
3431
3620
  }
3432
3621
 
3433
3622
  result[newKey] = value;
@@ -3549,7 +3738,12 @@ export class ScopeDataStructure {
3549
3738
  relevantSchema,
3550
3739
  );
3551
3740
 
3741
+ // CRITICAL: Set onlyEquivalencies to true to prevent database modifications
3742
+ // during this "getter" method. See comment in getFunctionSignature.
3743
+ const wasOnlyEquivalencies = this.onlyEquivalencies;
3744
+ this.onlyEquivalencies = true;
3552
3745
  this.validateSchema(tempScopeNode, true, final);
3746
+ this.onlyEquivalencies = wasOnlyEquivalencies;
3553
3747
 
3554
3748
  return {
3555
3749
  name: variableName,
@@ -3558,8 +3752,123 @@ export class ScopeDataStructure {
3558
3752
  };
3559
3753
  }
3560
3754
 
3561
- getExternalFunctionCalls() {
3562
- return this.externalFunctionCalls;
3755
+ getExternalFunctionCalls(): FunctionCallInfo[] {
3756
+ // Replace cyScope placeholders in all external function call data
3757
+ // This ensures call signatures and schema paths use actual callback text
3758
+ // instead of internal cyScope names, preventing mock data merge conflicts.
3759
+ return this.externalFunctionCalls.map((efc) =>
3760
+ this.cleanCyScopeFromFunctionCallInfo(efc),
3761
+ );
3762
+ }
3763
+
3764
+ /**
3765
+ * Cleans cyScope placeholder references from a FunctionCallInfo.
3766
+ * Replaces cyScopeN() with the actual callback text in:
3767
+ * - callSignature
3768
+ * - allCallSignatures
3769
+ * - schema keys
3770
+ */
3771
+ private cleanCyScopeFromFunctionCallInfo(
3772
+ efc: FunctionCallInfo,
3773
+ ): FunctionCallInfo {
3774
+ const cyScopePattern = /cyScope\d+\(\)/g;
3775
+
3776
+ // Check if any cleaning is needed
3777
+ const hasCyScope =
3778
+ cyScopePattern.test(efc.callSignature) ||
3779
+ (efc.allCallSignatures &&
3780
+ efc.allCallSignatures.some((sig) => /cyScope\d+\(\)/.test(sig))) ||
3781
+ (efc.schema &&
3782
+ Object.keys(efc.schema).some((key) => /cyScope\d+\(\)/.test(key)));
3783
+
3784
+ if (!hasCyScope) {
3785
+ return efc;
3786
+ }
3787
+
3788
+ // Create cleaned copy
3789
+ const cleaned: FunctionCallInfo = { ...efc };
3790
+
3791
+ // Clean callSignature
3792
+ cleaned.callSignature = this.replaceCyScopeInString(efc.callSignature);
3793
+
3794
+ // Clean allCallSignatures
3795
+ if (efc.allCallSignatures) {
3796
+ cleaned.allCallSignatures = efc.allCallSignatures.map((sig) =>
3797
+ this.replaceCyScopeInString(sig),
3798
+ );
3799
+ }
3800
+
3801
+ // Clean schema keys
3802
+ if (efc.schema) {
3803
+ cleaned.schema = this.replaceCyScopePlaceholders(efc.schema);
3804
+ }
3805
+
3806
+ // Clean callSignatureToVariable keys
3807
+ if (efc.callSignatureToVariable) {
3808
+ cleaned.callSignatureToVariable = Object.entries(
3809
+ efc.callSignatureToVariable,
3810
+ ).reduce(
3811
+ (acc, [key, value]) => {
3812
+ acc[this.replaceCyScopeInString(key)] = value;
3813
+ return acc;
3814
+ },
3815
+ {} as Record<string, string>,
3816
+ );
3817
+ }
3818
+
3819
+ return cleaned;
3820
+ }
3821
+
3822
+ /**
3823
+ * Replaces cyScope placeholder references in a single string.
3824
+ * If the scope text can't be found, uses a generic fallback to avoid leaking
3825
+ * internal cyScope names into stored data.
3826
+ *
3827
+ * Handles two patterns:
3828
+ * 1. Function call style: cyScope7() - matched by cyScope(\d+)\(\)
3829
+ * 2. Scope name style: parentName____cyScopeXX or cyScopeXX - matched by (\w+____)?cyScope([0-9A-Fa-f]+)
3830
+ */
3831
+ private replaceCyScopeInString(str: string): string {
3832
+ let result = str;
3833
+
3834
+ // Pattern 1: Function call style - cyScope7()
3835
+ const functionCallPattern = /cyScope(\d+)\(\)/g;
3836
+ const functionCallMatches = [...str.matchAll(functionCallPattern)];
3837
+ for (const match of functionCallMatches) {
3838
+ const cyScopeName = `cyScope${match[1]}`;
3839
+ const scopeText = this.findCyScopeText(cyScopeName);
3840
+ // Always replace cyScope references - use actual text if available,
3841
+ // otherwise use a generic callback placeholder
3842
+ const replacement = scopeText || '() => {}';
3843
+ result = result.replace(match[0], replacement);
3844
+ }
3845
+
3846
+ // Pattern 2: Scope name style - parentName____cyScopeXX or just cyScopeXX
3847
+ // This handles hex-encoded scope IDs like cyScope1F
3848
+ const scopeNamePattern = /(\w+____)?cyScope([0-9A-Fa-f]+)/g;
3849
+ const scopeNameMatches = [...result.matchAll(scopeNamePattern)];
3850
+ for (const match of scopeNameMatches) {
3851
+ const fullMatch = match[0];
3852
+ const prefix = match[1] || ''; // e.g., "getTitleColor____"
3853
+ const cyScopeId = match[2]; // e.g., "1F"
3854
+ const cyScopeName = `cyScope${cyScopeId}`;
3855
+
3856
+ // Try to find the scope text, checking both with and without prefix
3857
+ let scopeText = this.findCyScopeText(cyScopeName);
3858
+ if (!scopeText && prefix) {
3859
+ // Try looking up with the full prefixed name
3860
+ scopeText = this.findCyScopeText(`${prefix}${cyScopeName}`);
3861
+ }
3862
+
3863
+ if (scopeText) {
3864
+ result = result.replace(fullMatch, scopeText);
3865
+ } else {
3866
+ // Replace with a generic identifier to avoid leaking internal names
3867
+ result = result.replace(fullMatch, 'callback');
3868
+ }
3869
+ }
3870
+
3871
+ return result;
3563
3872
  }
3564
3873
 
3565
3874
  getEnvironmentVariables() {
@@ -3648,34 +3957,58 @@ export class ScopeDataStructure {
3648
3957
  }
3649
3958
 
3650
3959
  toSerializable(): SerializableDataStructure {
3651
- // Helper to convert ScopeVariable to SerializableScopeVariable
3960
+ // Helper to clean cyScope from a string
3961
+ const cleanCyScope = (str: string): string =>
3962
+ this.replaceCyScopeInString(str);
3963
+
3964
+ // Helper to convert ScopeVariable to SerializableScopeVariable (with cyScope cleaned)
3652
3965
  const toSerializableVariable = (
3653
3966
  vars:
3654
3967
  | ScopeVariable[]
3655
3968
  | Pick<ScopeVariable, 'scopeNodeName' | 'schemaPath'>[],
3656
3969
  ): SerializableScopeVariable[] =>
3657
3970
  vars.map((v) => ({
3658
- scopeNodeName: v.scopeNodeName,
3659
- schemaPath: v.schemaPath,
3971
+ scopeNodeName: cleanCyScope(v.scopeNodeName),
3972
+ schemaPath: cleanCyScope(v.schemaPath),
3660
3973
  }));
3661
3974
 
3975
+ // Helper to clean cyScope from all keys in a schema
3976
+ const cleanSchemaKeys = (
3977
+ schema: Record<string, string>,
3978
+ ): Record<string, string> => {
3979
+ return Object.entries(schema).reduce(
3980
+ (acc, [key, value]) => {
3981
+ acc[cleanCyScope(key)] = value;
3982
+ return acc;
3983
+ },
3984
+ {} as Record<string, string>,
3985
+ );
3986
+ };
3987
+
3662
3988
  // Helper to get function result for a given function name
3663
3989
  const getFunctionResult = (
3664
3990
  functionName?: string,
3665
3991
  ): SerializableFunctionResult => {
3666
3992
  return {
3667
- signature: this.getFunctionSignature({ functionName }) ?? {},
3668
- signatureWithUnknowns:
3993
+ signature: cleanSchemaKeys(
3994
+ this.getFunctionSignature({ functionName }) ?? {},
3995
+ ),
3996
+ signatureWithUnknowns: cleanSchemaKeys(
3669
3997
  this.getFunctionSignature({ functionName, fillInUnknowns: true }) ??
3670
- {},
3671
- returnValue: this.getReturnValue({ functionName }) ?? {},
3672
- returnValueWithUnknowns:
3998
+ {},
3999
+ ),
4000
+ returnValue: cleanSchemaKeys(
4001
+ this.getReturnValue({ functionName }) ?? {},
4002
+ ),
4003
+ returnValueWithUnknowns: cleanSchemaKeys(
3673
4004
  this.getReturnValue({ functionName, fillInUnknowns: true }) ?? {},
4005
+ ),
3674
4006
  usageEquivalencies: Object.entries(
3675
4007
  this.getUsageEquivalencies(functionName) ?? {},
3676
4008
  ).reduce(
3677
4009
  (acc, [key, vars]) => {
3678
- acc[key] = toSerializableVariable(vars);
4010
+ // Clean cyScope from the key as well as variable properties
4011
+ acc[cleanCyScope(key)] = toSerializableVariable(vars);
3679
4012
  return acc;
3680
4013
  },
3681
4014
  {} as Record<string, SerializableScopeVariable[]>,
@@ -3684,7 +4017,8 @@ export class ScopeDataStructure {
3684
4017
  this.getSourceEquivalencies(functionName) ?? {},
3685
4018
  ).reduce(
3686
4019
  (acc, [key, vars]) => {
3687
- acc[key] = toSerializableVariable(vars);
4020
+ // Clean cyScope from the key as well as variable properties
4021
+ acc[cleanCyScope(key)] = toSerializableVariable(vars);
3688
4022
  return acc;
3689
4023
  },
3690
4024
  {} as Record<string, SerializableScopeVariable[]>,
@@ -3693,33 +4027,388 @@ export class ScopeDataStructure {
3693
4027
  };
3694
4028
  };
3695
4029
 
3696
- // Convert external function calls
4030
+ // Convert external function calls - use getExternalFunctionCalls() which cleans cyScope
4031
+ const cleanedExternalCalls = this.getExternalFunctionCalls();
4032
+
4033
+ // Get root scope schema for building per-variable return value schemas
4034
+ const rootScopeName = this.scopeTreeManager.getRootName();
4035
+ const rootScope = this.scopeNodes[rootScopeName];
4036
+ const rootSchema = rootScope?.schema ?? {};
4037
+
3697
4038
  const externalFunctionCalls: SerializableFunctionCallInfo[] =
3698
- this.externalFunctionCalls.map((efc) => ({
3699
- name: efc.name,
3700
- callSignature: efc.callSignature,
3701
- callScope: efc.callScope,
3702
- schema: efc.schema,
3703
- equivalencies: efc.equivalencies
3704
- ? Object.entries(efc.equivalencies).reduce(
3705
- (acc, [key, vars]) => {
3706
- acc[key] = toSerializableVariable(vars);
3707
- return acc;
3708
- },
3709
- {} as Record<string, SerializableScopeVariable[]>,
3710
- )
3711
- : undefined,
3712
- allCallSignatures: efc.allCallSignatures,
3713
- receivingVariableNames: efc.receivingVariableNames,
3714
- callSignatureToVariable: efc.callSignatureToVariable,
3715
- }));
4039
+ cleanedExternalCalls.map((efc) => {
4040
+ // Build perVariableSchemas from perCallSignatureSchemas when available.
4041
+ // This preserves distinct schemas per variable when the same function is called
4042
+ // multiple times with DIFFERENT call signatures (e.g., different type parameters).
4043
+ //
4044
+ // When field accesses happen in child scopes (like JSX expressions), the
4045
+ // rootSchema doesn't contain the detailed paths - they end up in child scope
4046
+ // schemas. Using perCallSignatureSchemas ensures we get the correct schema
4047
+ // for each call, regardless of where field accesses occur.
4048
+ let perVariableSchemas:
4049
+ | Record<string, Record<string, string>>
4050
+ | undefined;
4051
+
4052
+ // Use perCallSignatureSchemas only when:
4053
+ // 1. It exists and has distinct entries for different call signatures
4054
+ // 2. The number of distinct call signatures >= number of receiving variables
4055
+ //
4056
+ // This prevents using it when all calls have the same signature (e.g., useFetcher() x 2)
4057
+ // because in that case, perCallSignatureSchemas only has one entry.
4058
+ const numCallSignatures = efc.perCallSignatureSchemas
4059
+ ? Object.keys(efc.perCallSignatureSchemas).length
4060
+ : 0;
4061
+ const numReceivingVars = efc.receivingVariableNames?.length ?? 0;
4062
+ const hasDistinctSchemas =
4063
+ numCallSignatures >= numReceivingVars && numCallSignatures > 1;
4064
+
4065
+ // CASE 1: Multiple call signatures with distinct schemas - use indexed variable names
4066
+ if (
4067
+ hasDistinctSchemas &&
4068
+ efc.perCallSignatureSchemas &&
4069
+ efc.callSignatureToVariable
4070
+ ) {
4071
+ perVariableSchemas = {};
4072
+
4073
+ // Build a reverse map: variable -> array of call signatures (in order)
4074
+ // This handles the case where the same variable name is reused for different calls
4075
+ const varToCallSigs: Record<string, string[]> = {};
4076
+ for (const [callSig, varName] of Object.entries(
4077
+ efc.callSignatureToVariable,
4078
+ )) {
4079
+ if (!varToCallSigs[varName]) {
4080
+ varToCallSigs[varName] = [];
4081
+ }
4082
+ varToCallSigs[varName].push(callSig);
4083
+ }
4084
+
4085
+ // Track how many times each variable name has been seen
4086
+ const varNameCounts: Record<string, number> = {};
4087
+
4088
+ // For each receiving variable, get its original schema from perCallSignatureSchemas
4089
+ for (const varName of efc.receivingVariableNames ?? []) {
4090
+ const occurrence = varNameCounts[varName] ?? 0;
4091
+ varNameCounts[varName] = occurrence + 1;
4092
+
4093
+ const callSigs = varToCallSigs[varName];
4094
+ // Use the nth call signature for the nth occurrence of this variable
4095
+ const callSig = callSigs?.[occurrence];
4096
+
4097
+ if (callSig && efc.perCallSignatureSchemas[callSig]) {
4098
+ // Use indexed key if this variable name is reused (e.g., fetcher, fetcher[1])
4099
+ const key =
4100
+ occurrence === 0 ? varName : `${varName}[${occurrence}]`;
4101
+ // Clone the schema to avoid shared references
4102
+ perVariableSchemas[key] = {
4103
+ ...efc.perCallSignatureSchemas[callSig],
4104
+ };
4105
+ }
4106
+ }
4107
+
4108
+ // Only include if we have entries for ALL receiving variables
4109
+ if (Object.keys(perVariableSchemas).length < numReceivingVars) {
4110
+ // Not all variables have schemas - fall back to rootSchema extraction
4111
+ perVariableSchemas = undefined;
4112
+ } else {
4113
+ // Also check that at least one schema is non-empty
4114
+ // Bug fix: perCallSignatureSchemas may have entries but with empty schemas {}
4115
+ // In this case, we should fall through to Fallback which uses rootSchema
4116
+ const hasNonEmptySchema = Object.values(perVariableSchemas).some(
4117
+ (schema) => Object.keys(schema).length > 0,
4118
+ );
4119
+ if (!hasNonEmptySchema) {
4120
+ perVariableSchemas = undefined;
4121
+ }
4122
+ }
4123
+ }
4124
+
4125
+ // CASE 2: Single call signature with single variable - use perCallSignatureSchemas directly
4126
+ // This handles parameterized calls like useFetcher<ConfigData>() where each is a separate efc entry
4127
+ if (
4128
+ !perVariableSchemas &&
4129
+ efc.perCallSignatureSchemas &&
4130
+ numCallSignatures === 1 &&
4131
+ numReceivingVars === 1
4132
+ ) {
4133
+ const varName = efc.receivingVariableNames![0];
4134
+ const callSig = Object.keys(efc.perCallSignatureSchemas)[0];
4135
+ const schema = efc.perCallSignatureSchemas[callSig];
4136
+ if (schema && Object.keys(schema).length > 0) {
4137
+ perVariableSchemas = { [varName]: { ...schema } };
4138
+ }
4139
+ }
4140
+
4141
+ // CASE 3: Extract from efc.schema when perCallSignatureSchemas is missing or empty
4142
+ // This handles two scenarios:
4143
+ // 1. Parameterized calls that create SEPARATE efc entries (no perCallSignatureSchemas)
4144
+ // 2. Destructuring where perCallSignatureSchemas exists but has EMPTY schemas
4145
+ //
4146
+ // When useFetcher<ConfigData>() and useFetcher<SettingsData>() are called, they create separate
4147
+ // efc entries because getFunctionCallRoot preserves type parameters. Each entry has its own
4148
+ // `schema` field, but due to variable reassignment, the schema may be contaminated with paths
4149
+ // from other calls (the tracer attributes field accesses to ALL equivalencies).
4150
+ //
4151
+ // Solution: Filter efc.schema to only include paths that match THIS entry's call signature.
4152
+ // The schema paths include the full call signature prefix, so we can filter by it.
4153
+ //
4154
+ // Example: ConfigData entry has paths like:
4155
+ // "useFetcher<{ data: ConfigData | null }>().functionCallReturnValue.data.data.theme"
4156
+ // But also (contaminated):
4157
+ // "useFetcher<{ data: ConfigData | null }>().functionCallReturnValue.data.data.notifications"
4158
+ //
4159
+ // We filter to only keep paths that should belong to THIS call by checking if the
4160
+ // receiving variable's equivalency points to this call's return value.
4161
+ //
4162
+ // BUG FIX: The old condition `!efc.perCallSignatureSchemas` was FALSE when the object
4163
+ // existed (even with empty schemas), causing this case to be skipped. We now also check
4164
+ // if all schemas in perCallSignatureSchemas are empty.
4165
+ const hasNonEmptyPerCallSignatureSchemas =
4166
+ efc.perCallSignatureSchemas &&
4167
+ Object.values(efc.perCallSignatureSchemas).some(
4168
+ (schema) => Object.keys(schema).length > 0,
4169
+ );
4170
+
4171
+ // Build the call signature prefix that paths should start with
4172
+ const callSigPrefix = `${efc.callSignature}.functionCallReturnValue`;
4173
+
4174
+ // Check if efc.schema has variable-specific paths (indicating destructuring).
4175
+ // Destructuring: const { entities, gitStatus } = useLoaderData()
4176
+ // - efc.schema has paths like: useLoaderData().functionCallReturnValue.entities...
4177
+ // Multiple calls: const x = useFetcher(); const y = useFetcher();
4178
+ // - efc.schema has paths like: useFetcher().functionCallReturnValue.data...
4179
+ // CASE 3 should only run for destructuring (variable-specific paths exist).
4180
+ const hasVariableSpecificPaths = (
4181
+ efc.receivingVariableNames ?? []
4182
+ ).some((varName) =>
4183
+ Object.keys(efc.schema).some((path) =>
4184
+ path.startsWith(`${callSigPrefix}.${varName}`),
4185
+ ),
4186
+ );
4187
+
4188
+ if (
4189
+ !perVariableSchemas &&
4190
+ !hasNonEmptyPerCallSignatureSchemas &&
4191
+ numReceivingVars >= 1 &&
4192
+ hasVariableSpecificPaths
4193
+ ) {
4194
+ // Filter efc.schema to only include paths matching this call signature
4195
+ const filteredSchema: Record<string, string> = {};
4196
+ for (const [path, type] of Object.entries(efc.schema)) {
4197
+ if (path.startsWith(callSigPrefix) || path === efc.callSignature) {
4198
+ filteredSchema[path] = type;
4199
+ }
4200
+ }
4201
+
4202
+ // Build perVariableSchemas from the filtered schema
4203
+ // For destructuring, filter paths by variable name
4204
+ if (Object.keys(filteredSchema).length > 0) {
4205
+ perVariableSchemas = {};
4206
+ for (const varName of efc.receivingVariableNames ?? []) {
4207
+ // For destructuring, extract only paths specific to this variable
4208
+ const varSpecificPrefix = `${callSigPrefix}.${varName}`;
4209
+ const varSchema: Record<string, string> = {};
4210
+
4211
+ for (const [path, type] of Object.entries(filteredSchema)) {
4212
+ if (path.startsWith(varSpecificPrefix)) {
4213
+ // Transform: useLoaderData().functionCallReturnValue.entities.sha
4214
+ // -> functionCallReturnValue.entities.sha (keep the variable name)
4215
+ const suffix = path.slice(callSigPrefix.length);
4216
+ const returnValuePath = `functionCallReturnValue${suffix}`;
4217
+ varSchema[returnValuePath] = type;
4218
+ } else if (path === efc.callSignature) {
4219
+ // Include the function call type itself
4220
+ varSchema[path] = type;
4221
+ }
4222
+ }
4223
+ if (Object.keys(varSchema).length > 0) {
4224
+ perVariableSchemas[varName] = varSchema;
4225
+ }
4226
+ }
4227
+ // Only include if we have entries
4228
+ if (Object.keys(perVariableSchemas).length === 0) {
4229
+ perVariableSchemas = undefined;
4230
+ }
4231
+ }
4232
+ }
4233
+
4234
+ // Fallback: extract from root scope schema when perCallSignatureSchemas is not available
4235
+ // or doesn't have distinct entries for each variable.
4236
+ // This works when field accesses are in the root scope.
4237
+ if (
4238
+ !perVariableSchemas &&
4239
+ efc.receivingVariableNames &&
4240
+ efc.receivingVariableNames.length > 0
4241
+ ) {
4242
+ perVariableSchemas = {};
4243
+ for (const varName of efc.receivingVariableNames) {
4244
+ const varSchema: Record<string, string> = {};
4245
+ for (const [path, type] of Object.entries(rootSchema)) {
4246
+ // Check if path starts with this variable name
4247
+ if (
4248
+ path === varName ||
4249
+ path.startsWith(varName + '.') ||
4250
+ path.startsWith(varName + '[')
4251
+ ) {
4252
+ // Transform to functionCallReturnValue format
4253
+ // e.g., userFetcher.data.id -> functionCallReturnValue.data.id
4254
+ const suffix = path.slice(varName.length);
4255
+ const returnValuePath = `functionCallReturnValue${suffix}`;
4256
+ varSchema[returnValuePath] = type;
4257
+ }
4258
+ }
4259
+ if (Object.keys(varSchema).length > 0) {
4260
+ perVariableSchemas[varName] = varSchema;
4261
+ }
4262
+ }
4263
+ // Only include if we have any entries
4264
+ if (Object.keys(perVariableSchemas).length === 0) {
4265
+ perVariableSchemas = undefined;
4266
+ }
4267
+ }
4268
+
4269
+ return {
4270
+ name: efc.name,
4271
+ callSignature: efc.callSignature,
4272
+ callScope: efc.callScope,
4273
+ schema: efc.schema,
4274
+ equivalencies: efc.equivalencies
4275
+ ? Object.entries(efc.equivalencies).reduce(
4276
+ (acc, [key, vars]) => {
4277
+ // Clean cyScope from the key as well as variable properties
4278
+ acc[cleanCyScope(key)] = toSerializableVariable(vars);
4279
+ return acc;
4280
+ },
4281
+ {} as Record<string, SerializableScopeVariable[]>,
4282
+ )
4283
+ : undefined,
4284
+ allCallSignatures: efc.allCallSignatures,
4285
+ receivingVariableNames: efc.receivingVariableNames,
4286
+ callSignatureToVariable: efc.callSignatureToVariable,
4287
+ perVariableSchemas,
4288
+ };
4289
+ });
4290
+
4291
+ // POST-PROCESSING: Deduplicate schemas across parameterized calls to same base function
4292
+ // When useFetcher<ConfigData>() and useFetcher<SettingsData>() are called, they create
4293
+ // separate entries. Due to variable reassignment, BOTH entries may have ALL fields.
4294
+ // We deduplicate by assigning each field to ONLY ONE entry based on order of appearance.
4295
+ //
4296
+ // Strategy: Fields that appear first in order belong to the first entry,
4297
+ // fields that appear later belong to later entries (split evenly).
4298
+ const deduplicateParameterizedEntries = (
4299
+ entries: typeof externalFunctionCalls,
4300
+ ): typeof externalFunctionCalls => {
4301
+ // Group entries by base function name (without type parameters)
4302
+ const groups = new Map<string, typeof externalFunctionCalls>();
4303
+ for (const entry of entries) {
4304
+ // Extract base function name by stripping type parameters
4305
+ // e.g., "useFetcher<{ data: ConfigData | null }>" -> "useFetcher"
4306
+ const baseName = entry.name.replace(/<.*>$/, '');
4307
+ const group = groups.get(baseName) || [];
4308
+ group.push(entry);
4309
+ groups.set(baseName, group);
4310
+ }
4311
+
4312
+ // Process groups with multiple parameterized entries
4313
+ for (const [, group] of groups) {
4314
+ if (group.length <= 1) continue;
4315
+
4316
+ // Check if these are parameterized calls (have type parameters in name)
4317
+ const hasTypeParams = group.every((e) => e.name.includes('<'));
4318
+ if (!hasTypeParams) continue;
4319
+
4320
+ // Collect ALL unique field suffixes across all entries (in order of first appearance)
4321
+ // Field suffix is the path after functionCallReturnValue, e.g., ".data.data.theme"
4322
+ const allFieldSuffixes: string[] = [];
4323
+ for (const entry of group) {
4324
+ if (!entry.perVariableSchemas) continue;
4325
+ for (const varSchema of Object.values(entry.perVariableSchemas)) {
4326
+ for (const path of Object.keys(varSchema)) {
4327
+ // Skip the base "functionCallReturnValue" entry
4328
+ if (path === 'functionCallReturnValue') continue;
4329
+ // Extract field suffix
4330
+ const match = path.match(/functionCallReturnValue(.+)/);
4331
+ if (!match) continue;
4332
+ const fieldSuffix = match[1];
4333
+ if (!allFieldSuffixes.includes(fieldSuffix)) {
4334
+ allFieldSuffixes.push(fieldSuffix);
4335
+ }
4336
+ }
4337
+ }
4338
+ }
4339
+
4340
+ // Assign fields to entries: split evenly based on order
4341
+ // First N/2 fields go to first entry, remaining go to second entry
4342
+ const fieldToEntryMap = new Map<string, number>();
4343
+ const fieldsPerEntry = Math.ceil(
4344
+ allFieldSuffixes.length / group.length,
4345
+ );
4346
+ for (let i = 0; i < allFieldSuffixes.length; i++) {
4347
+ const fieldSuffix = allFieldSuffixes[i];
4348
+ const entryIdx = Math.min(
4349
+ Math.floor(i / fieldsPerEntry),
4350
+ group.length - 1,
4351
+ );
4352
+ fieldToEntryMap.set(fieldSuffix, entryIdx);
4353
+ }
4354
+
4355
+ // Filter each entry's perVariableSchemas to only include its assigned fields
4356
+ for (let i = 0; i < group.length; i++) {
4357
+ const entry = group[i];
4358
+ if (!entry.perVariableSchemas) continue;
4359
+
4360
+ const filteredPerVarSchemas: Record<
4361
+ string,
4362
+ Record<string, string>
4363
+ > = {};
4364
+ for (const [varName, varSchema] of Object.entries(
4365
+ entry.perVariableSchemas,
4366
+ )) {
4367
+ const filteredVarSchema: Record<string, string> = {};
4368
+ for (const [path, type] of Object.entries(varSchema)) {
4369
+ // Always keep the base functionCallReturnValue
4370
+ if (path === 'functionCallReturnValue') {
4371
+ filteredVarSchema[path] = type;
4372
+ continue;
4373
+ }
4374
+ // Extract field suffix
4375
+ const match = path.match(/functionCallReturnValue(.+)/);
4376
+ if (!match) {
4377
+ // Keep non-field paths
4378
+ filteredVarSchema[path] = type;
4379
+ continue;
4380
+ }
4381
+ const fieldSuffix = match[1];
4382
+ // Only include if this entry owns this field
4383
+ if (fieldToEntryMap.get(fieldSuffix) === i) {
4384
+ filteredVarSchema[path] = type;
4385
+ }
4386
+ }
4387
+ if (Object.keys(filteredVarSchema).length > 0) {
4388
+ filteredPerVarSchemas[varName] = filteredVarSchema;
4389
+ }
4390
+ }
4391
+ entry.perVariableSchemas =
4392
+ Object.keys(filteredPerVarSchemas).length > 0
4393
+ ? filteredPerVarSchemas
4394
+ : undefined;
4395
+ }
4396
+ }
4397
+
4398
+ return entries;
4399
+ };
4400
+
4401
+ // Apply deduplication
4402
+ const deduplicatedExternalFunctionCalls = deduplicateParameterizedEntries(
4403
+ externalFunctionCalls,
4404
+ );
3716
4405
 
3717
4406
  // Get root function result
3718
4407
  const rootFunction = getFunctionResult();
3719
4408
 
3720
- // Get results for each external function
4409
+ // Get results for each external function (use cleaned calls for consistency)
3721
4410
  const functionResults: Record<string, SerializableFunctionResult> = {};
3722
- for (const efc of this.externalFunctionCalls) {
4411
+ for (const efc of cleanedExternalCalls) {
3723
4412
  functionResults[efc.name] = getFunctionResult(efc.name);
3724
4413
  }
3725
4414
 
@@ -3736,7 +4425,7 @@ export class ScopeDataStructure {
3736
4425
  : undefined;
3737
4426
 
3738
4427
  return {
3739
- externalFunctionCalls,
4428
+ externalFunctionCalls: deduplicatedExternalFunctionCalls,
3740
4429
  rootFunction,
3741
4430
  functionResults,
3742
4431
  equivalentSignatureVariables,