@codeyam/codeyam-cli 0.1.0-staging.8e7b1bd → 0.1.0-staging.b8a55ba

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 (385) 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 +7 -6
  4. package/analyzer-template/packages/ai/package.json +1 -1
  5. package/analyzer-template/packages/ai/src/lib/analyzeScope.ts +2 -0
  6. package/analyzer-template/packages/ai/src/lib/astScopes/astScopeAnalyzer.ts +22 -0
  7. package/analyzer-template/packages/ai/src/lib/astScopes/patterns/switchStatementHandler.ts +23 -1
  8. package/analyzer-template/packages/ai/src/lib/astScopes/processExpression.ts +401 -106
  9. package/analyzer-template/packages/ai/src/lib/astScopes/types.ts +60 -0
  10. package/analyzer-template/packages/ai/src/lib/dataStructure/ScopeDataStructure.ts +661 -50
  11. package/analyzer-template/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/JavascriptFrameworkManager.ts +14 -2
  12. package/analyzer-template/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/MuiManager.ts +715 -0
  13. package/analyzer-template/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/ReactFrameworkManager.ts +123 -1
  14. package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/cleanKnownObjectFunctions.ts +19 -1
  15. package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/cleanNonObjectFunctions.ts +23 -1
  16. package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/convertDotNotation.ts +23 -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/generateChangesEntityScenarios.ts +37 -4
  21. package/analyzer-template/packages/ai/src/lib/generateEntityDataStructure.ts +5 -0
  22. package/analyzer-template/packages/ai/src/lib/generateEntityKeyAttributes.ts +213 -12
  23. package/analyzer-template/packages/ai/src/lib/generateEntityScenarioData.ts +11 -15
  24. package/analyzer-template/packages/ai/src/lib/generateEntityScenarios.ts +114 -11
  25. package/analyzer-template/packages/ai/src/lib/getConditionalUsagesFromCode.ts +143 -31
  26. package/analyzer-template/packages/ai/src/lib/guessScenarioDataFromDescription.ts +8 -2
  27. package/analyzer-template/packages/ai/src/lib/promptGenerators/gatherAttributesMap.ts +7 -0
  28. package/analyzer-template/packages/ai/src/lib/promptGenerators/generateChangesEntityScenariosGenerator.ts +42 -2
  29. package/analyzer-template/packages/ai/src/lib/promptGenerators/generateEntityScenariosGenerator.ts +38 -2
  30. package/analyzer-template/packages/ai/src/lib/promptGenerators/guessNewScenarioDataFromDescriptionGenerator.ts +28 -2
  31. package/analyzer-template/packages/ai/src/lib/worker/SerializableDataStructure.ts +5 -0
  32. package/analyzer-template/packages/ai/src/lib/worker/analyzeScopeWorker.ts +8 -1
  33. package/analyzer-template/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.ts +339 -145
  34. package/analyzer-template/packages/analyze/src/lib/files/analyze/analyzeEntities.ts +20 -0
  35. package/analyzer-template/packages/analyze/src/lib/files/getImportedExports.ts +8 -1
  36. package/analyzer-template/packages/analyze/src/lib/files/scenarios/enrichArrayTypesFromChildSignatures.ts +158 -0
  37. package/analyzer-template/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.ts +107 -18
  38. package/analyzer-template/packages/analyze/src/lib/files/scenarios/generateChangesScenarioData.ts +1 -1
  39. package/analyzer-template/packages/analyze/src/lib/files/scenarios/generateDataStructure.ts +223 -103
  40. package/analyzer-template/packages/analyze/src/lib/files/scenarios/generateKeyAttributes.ts +10 -5
  41. package/analyzer-template/packages/analyze/src/lib/files/scenarios/generateScenarioData.ts +172 -83
  42. package/analyzer-template/packages/analyze/src/lib/files/scenarios/generateScenarios.ts +2 -5
  43. package/analyzer-template/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.ts +97 -27
  44. package/analyzer-template/packages/aws/dist/src/lib/s3/checkS3ObjectExists.d.ts +15 -0
  45. package/analyzer-template/packages/aws/dist/src/lib/s3/checkS3ObjectExists.d.ts.map +1 -0
  46. package/analyzer-template/packages/aws/dist/src/lib/s3/checkS3ObjectExists.js +31 -0
  47. package/analyzer-template/packages/aws/dist/src/lib/s3/checkS3ObjectExists.js.map +1 -0
  48. package/analyzer-template/packages/aws/package.json +1 -1
  49. package/analyzer-template/packages/aws/s3/index.ts +1 -0
  50. package/analyzer-template/packages/aws/src/lib/s3/checkS3ObjectExists.ts +47 -0
  51. package/analyzer-template/packages/database/src/lib/kysely/db.ts +4 -4
  52. package/analyzer-template/packages/database/src/lib/kysely/tableRelations.ts +2 -2
  53. package/analyzer-template/packages/database/src/lib/kysely/tables/debugReportsTable.ts +20 -9
  54. package/analyzer-template/packages/database/src/lib/loadReadyToBeCapturedAnalyses.ts +3 -2
  55. package/analyzer-template/packages/generate/src/lib/componentScenarioPage/getIFrameMessageListenerCode.ts +9 -4
  56. package/analyzer-template/packages/generate/src/lib/deepMerge.ts +26 -1
  57. package/analyzer-template/packages/generate/src/lib/getComponentScenarioPath.ts +8 -3
  58. package/analyzer-template/packages/github/dist/database/src/lib/kysely/db.d.ts +2 -2
  59. package/analyzer-template/packages/github/dist/database/src/lib/kysely/db.js +2 -2
  60. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tableRelations.d.ts +2 -2
  61. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/analysesTable.d.ts +8 -1
  62. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/analysesTable.d.ts.map +1 -1
  63. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/debugReportsTable.d.ts +14 -7
  64. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/debugReportsTable.d.ts.map +1 -1
  65. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/debugReportsTable.js +9 -3
  66. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/debugReportsTable.js.map +1 -1
  67. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/scenariosTable.d.ts +1 -1
  68. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/scenariosTable.d.ts.map +1 -1
  69. package/analyzer-template/packages/github/dist/database/src/lib/loadReadyToBeCapturedAnalyses.d.ts.map +1 -1
  70. package/analyzer-template/packages/github/dist/database/src/lib/loadReadyToBeCapturedAnalyses.js +4 -2
  71. package/analyzer-template/packages/github/dist/database/src/lib/loadReadyToBeCapturedAnalyses.js.map +1 -1
  72. package/analyzer-template/packages/github/dist/generate/src/lib/componentScenarioPage/getIFrameMessageListenerCode.d.ts.map +1 -1
  73. package/analyzer-template/packages/github/dist/generate/src/lib/componentScenarioPage/getIFrameMessageListenerCode.js +8 -4
  74. package/analyzer-template/packages/github/dist/generate/src/lib/componentScenarioPage/getIFrameMessageListenerCode.js.map +1 -1
  75. package/analyzer-template/packages/github/dist/generate/src/lib/deepMerge.d.ts.map +1 -1
  76. package/analyzer-template/packages/github/dist/generate/src/lib/deepMerge.js +27 -1
  77. package/analyzer-template/packages/github/dist/generate/src/lib/deepMerge.js.map +1 -1
  78. package/analyzer-template/packages/github/dist/generate/src/lib/getComponentScenarioPath.d.ts.map +1 -1
  79. package/analyzer-template/packages/github/dist/generate/src/lib/getComponentScenarioPath.js +7 -3
  80. package/analyzer-template/packages/github/dist/generate/src/lib/getComponentScenarioPath.js.map +1 -1
  81. package/analyzer-template/packages/github/dist/types/index.d.ts +4 -3
  82. package/analyzer-template/packages/github/dist/types/index.d.ts.map +1 -1
  83. package/analyzer-template/packages/github/dist/types/index.js +1 -0
  84. package/analyzer-template/packages/github/dist/types/index.js.map +1 -1
  85. package/analyzer-template/packages/github/dist/types/src/types/Analysis.d.ts +31 -1
  86. package/analyzer-template/packages/github/dist/types/src/types/Analysis.d.ts.map +1 -1
  87. package/analyzer-template/packages/github/dist/types/src/types/Scenario.d.ts +51 -1
  88. package/analyzer-template/packages/github/dist/types/src/types/Scenario.d.ts.map +1 -1
  89. package/analyzer-template/packages/github/dist/types/src/types/Scenario.js +21 -1
  90. package/analyzer-template/packages/github/dist/types/src/types/Scenario.js.map +1 -1
  91. package/analyzer-template/packages/github/dist/types/src/types/ScenariosDataStructure.d.ts +48 -0
  92. package/analyzer-template/packages/github/dist/types/src/types/ScenariosDataStructure.d.ts.map +1 -1
  93. package/analyzer-template/packages/github/dist/utils/src/lib/applyUniversalMocks.d.ts.map +1 -1
  94. package/analyzer-template/packages/github/dist/utils/src/lib/applyUniversalMocks.js +26 -2
  95. package/analyzer-template/packages/github/dist/utils/src/lib/applyUniversalMocks.js.map +1 -1
  96. package/analyzer-template/packages/github/dist/utils/src/lib/lightweightEntityExtractor.d.ts.map +1 -1
  97. package/analyzer-template/packages/github/dist/utils/src/lib/lightweightEntityExtractor.js +25 -0
  98. package/analyzer-template/packages/github/dist/utils/src/lib/lightweightEntityExtractor.js.map +1 -1
  99. package/analyzer-template/packages/types/index.ts +8 -0
  100. package/analyzer-template/packages/types/src/types/Analysis.ts +32 -1
  101. package/analyzer-template/packages/types/src/types/Scenario.ts +75 -6
  102. package/analyzer-template/packages/types/src/types/ScenariosDataStructure.ts +49 -0
  103. package/analyzer-template/packages/ui-components/package.json +4 -4
  104. package/analyzer-template/packages/ui-components/src/components/ScenarioDetailInteractiveView.tsx +23 -7
  105. package/analyzer-template/packages/utils/dist/types/index.d.ts +4 -3
  106. package/analyzer-template/packages/utils/dist/types/index.d.ts.map +1 -1
  107. package/analyzer-template/packages/utils/dist/types/index.js +1 -0
  108. package/analyzer-template/packages/utils/dist/types/index.js.map +1 -1
  109. package/analyzer-template/packages/utils/dist/types/src/types/Analysis.d.ts +31 -1
  110. package/analyzer-template/packages/utils/dist/types/src/types/Analysis.d.ts.map +1 -1
  111. package/analyzer-template/packages/utils/dist/types/src/types/Scenario.d.ts +51 -1
  112. package/analyzer-template/packages/utils/dist/types/src/types/Scenario.d.ts.map +1 -1
  113. package/analyzer-template/packages/utils/dist/types/src/types/Scenario.js +21 -1
  114. package/analyzer-template/packages/utils/dist/types/src/types/Scenario.js.map +1 -1
  115. package/analyzer-template/packages/utils/dist/types/src/types/ScenariosDataStructure.d.ts +48 -0
  116. package/analyzer-template/packages/utils/dist/types/src/types/ScenariosDataStructure.d.ts.map +1 -1
  117. package/analyzer-template/packages/utils/dist/utils/src/lib/applyUniversalMocks.d.ts.map +1 -1
  118. package/analyzer-template/packages/utils/dist/utils/src/lib/applyUniversalMocks.js +26 -2
  119. package/analyzer-template/packages/utils/dist/utils/src/lib/applyUniversalMocks.js.map +1 -1
  120. package/analyzer-template/packages/utils/dist/utils/src/lib/lightweightEntityExtractor.d.ts.map +1 -1
  121. package/analyzer-template/packages/utils/dist/utils/src/lib/lightweightEntityExtractor.js +25 -0
  122. package/analyzer-template/packages/utils/dist/utils/src/lib/lightweightEntityExtractor.js.map +1 -1
  123. package/analyzer-template/packages/utils/src/lib/applyUniversalMocks.ts +28 -2
  124. package/analyzer-template/packages/utils/src/lib/lightweightEntityExtractor.ts +27 -0
  125. package/analyzer-template/playwright/takeElementScreenshot.ts +26 -11
  126. package/analyzer-template/playwright/takeScreenshot.ts +9 -7
  127. package/analyzer-template/project/TESTING.md +83 -0
  128. package/analyzer-template/project/constructMockCode.ts +151 -30
  129. package/analyzer-template/project/loadReadyToBeCaptured.ts +17 -1
  130. package/analyzer-template/project/orchestrateCapture/KyselyAnalysisLoader.ts +16 -9
  131. package/analyzer-template/project/orchestrateCapture/SequentialCaptureTaskRunner.ts +77 -37
  132. package/analyzer-template/project/reconcileMockDataKeys.ts +104 -3
  133. package/analyzer-template/project/runMultiScenarioServer.ts +11 -10
  134. package/analyzer-template/project/serverOnlyModules.ts +288 -0
  135. package/analyzer-template/project/start.ts +10 -0
  136. package/analyzer-template/project/startScenarioCapture.ts +73 -41
  137. package/analyzer-template/project/writeMockDataTsx.ts +103 -40
  138. package/analyzer-template/project/writeScenarioComponents.ts +1162 -203
  139. package/analyzer-template/project/writeSimpleRoot.ts +26 -4
  140. package/analyzer-template/project/writeUniversalMocks.ts +32 -11
  141. package/background/src/lib/virtualized/project/constructMockCode.js +132 -25
  142. package/background/src/lib/virtualized/project/constructMockCode.js.map +1 -1
  143. package/background/src/lib/virtualized/project/loadReadyToBeCaptured.js +15 -1
  144. package/background/src/lib/virtualized/project/loadReadyToBeCaptured.js.map +1 -1
  145. package/background/src/lib/virtualized/project/orchestrateCapture/KyselyAnalysisLoader.js +11 -6
  146. package/background/src/lib/virtualized/project/orchestrateCapture/KyselyAnalysisLoader.js.map +1 -1
  147. package/background/src/lib/virtualized/project/orchestrateCapture/SequentialCaptureTaskRunner.js +67 -32
  148. package/background/src/lib/virtualized/project/orchestrateCapture/SequentialCaptureTaskRunner.js.map +1 -1
  149. package/background/src/lib/virtualized/project/reconcileMockDataKeys.js +65 -4
  150. package/background/src/lib/virtualized/project/reconcileMockDataKeys.js.map +1 -1
  151. package/background/src/lib/virtualized/project/runMultiScenarioServer.js +11 -9
  152. package/background/src/lib/virtualized/project/runMultiScenarioServer.js.map +1 -1
  153. package/background/src/lib/virtualized/project/serverOnlyModules.js +235 -0
  154. package/background/src/lib/virtualized/project/serverOnlyModules.js.map +1 -0
  155. package/background/src/lib/virtualized/project/start.js +6 -0
  156. package/background/src/lib/virtualized/project/start.js.map +1 -1
  157. package/background/src/lib/virtualized/project/startScenarioCapture.js +54 -31
  158. package/background/src/lib/virtualized/project/startScenarioCapture.js.map +1 -1
  159. package/background/src/lib/virtualized/project/writeMockDataTsx.js +87 -34
  160. package/background/src/lib/virtualized/project/writeMockDataTsx.js.map +1 -1
  161. package/background/src/lib/virtualized/project/writeScenarioComponents.js +852 -133
  162. package/background/src/lib/virtualized/project/writeScenarioComponents.js.map +1 -1
  163. package/background/src/lib/virtualized/project/writeSimpleRoot.js +25 -2
  164. package/background/src/lib/virtualized/project/writeSimpleRoot.js.map +1 -1
  165. package/background/src/lib/virtualized/project/writeUniversalMocks.js +27 -12
  166. package/background/src/lib/virtualized/project/writeUniversalMocks.js.map +1 -1
  167. package/codeyam-cli/scripts/fixtures/formbricks/universal-mocks/apps/web/lib/instance/service.js +7 -0
  168. package/codeyam-cli/scripts/fixtures/formbricks/universal-mocks/apps/web/lib/instance/service.js.map +1 -0
  169. package/codeyam-cli/src/cli.js +2 -0
  170. package/codeyam-cli/src/cli.js.map +1 -1
  171. package/codeyam-cli/src/commands/debug.js +14 -2
  172. package/codeyam-cli/src/commands/debug.js.map +1 -1
  173. package/codeyam-cli/src/commands/recapture.js +215 -0
  174. package/codeyam-cli/src/commands/recapture.js.map +1 -0
  175. package/codeyam-cli/src/commands/report.js +26 -23
  176. package/codeyam-cli/src/commands/report.js.map +1 -1
  177. package/codeyam-cli/src/utils/backgroundServer.js +2 -2
  178. package/codeyam-cli/src/utils/backgroundServer.js.map +1 -1
  179. package/codeyam-cli/src/utils/generateReport.js +252 -106
  180. package/codeyam-cli/src/utils/generateReport.js.map +1 -1
  181. package/codeyam-cli/src/utils/install-skills.js +2 -7
  182. package/codeyam-cli/src/utils/install-skills.js.map +1 -1
  183. package/codeyam-cli/src/utils/queue/__tests__/manager.test.js +38 -0
  184. package/codeyam-cli/src/utils/queue/__tests__/manager.test.js.map +1 -1
  185. package/codeyam-cli/src/utils/queue/job.js +140 -16
  186. package/codeyam-cli/src/utils/queue/job.js.map +1 -1
  187. package/codeyam-cli/src/utils/queue/manager.js +19 -7
  188. package/codeyam-cli/src/utils/queue/manager.js.map +1 -1
  189. package/codeyam-cli/src/utils/queue/persistence.js.map +1 -1
  190. package/codeyam-cli/src/webserver/app/lib/database.js +47 -0
  191. package/codeyam-cli/src/webserver/app/lib/database.js.map +1 -1
  192. package/codeyam-cli/src/webserver/app/lib/dbNotifier.js.map +1 -1
  193. package/codeyam-cli/src/webserver/backgroundServer.js +5 -10
  194. package/codeyam-cli/src/webserver/backgroundServer.js.map +1 -1
  195. package/codeyam-cli/src/webserver/bootstrap.js +9 -0
  196. package/codeyam-cli/src/webserver/bootstrap.js.map +1 -0
  197. package/codeyam-cli/src/webserver/build/client/assets/EntityItem-wXL1Z2Aq.js +1 -0
  198. package/codeyam-cli/src/webserver/build/client/assets/{EntityTypeBadge-DQeyk25_.js → EntityTypeBadge-CzGX-miz.js} +1 -1
  199. package/codeyam-cli/src/webserver/build/client/assets/EntityTypeIcon-CXFKsCOD.js +41 -0
  200. package/codeyam-cli/src/webserver/build/client/assets/InteractivePreview-D-9pXIaY.js +25 -0
  201. package/codeyam-cli/src/webserver/build/client/assets/LibraryFunctionPreview-CBQPrpT0.js +3 -0
  202. package/codeyam-cli/src/webserver/build/client/assets/LoadingDots-D1CdlbrV.js +6 -0
  203. package/codeyam-cli/src/webserver/build/client/assets/LogViewer-wDPcZNKx.js +3 -0
  204. package/codeyam-cli/src/webserver/build/client/assets/ReportIssueModal-4lcOlid-.js +11 -0
  205. package/codeyam-cli/src/webserver/build/client/assets/SafeScreenshot-BfmDgXxG.js +1 -0
  206. package/codeyam-cli/src/webserver/build/client/assets/ScenarioViewer-CUxUNEEC.js +15 -0
  207. package/codeyam-cli/src/webserver/build/client/assets/{TruncatedFilePath-ayCJdUAc.js → TruncatedFilePath-6J7zDUD5.js} +1 -1
  208. package/codeyam-cli/src/webserver/build/client/assets/_index-DHImXdXq.js +11 -0
  209. package/codeyam-cli/src/webserver/build/client/assets/activity.(_tab)-2mG6mjVb.js +32 -0
  210. package/codeyam-cli/src/webserver/build/client/assets/api.link-scenario-value-l0sNRNKZ.js +1 -0
  211. package/codeyam-cli/src/webserver/build/client/assets/api.update-key-attributes-l0sNRNKZ.js +1 -0
  212. package/codeyam-cli/src/webserver/build/client/assets/api.update-valid-values-l0sNRNKZ.js +1 -0
  213. package/codeyam-cli/src/webserver/build/client/assets/chevron-down-BYimnrHg.js +6 -0
  214. package/codeyam-cli/src/webserver/build/client/assets/chunk-JMJ3UQ3L-BambyYE_.js +51 -0
  215. package/codeyam-cli/src/webserver/build/client/assets/circle-check-CaVsIRxt.js +6 -0
  216. package/codeyam-cli/src/webserver/build/client/assets/createLucideIcon-CgUsG7ib.js +21 -0
  217. package/codeyam-cli/src/webserver/build/client/assets/cy-logo-cli-CKnwPCDr.js +1 -0
  218. package/codeyam-cli/src/webserver/build/client/assets/dev.empty-DW_hdGUc.js +1 -0
  219. package/codeyam-cli/src/webserver/build/client/assets/{entity._sha._-FHOVOgFN.js → entity._sha._-zUEpfPsu.js} +22 -15
  220. package/codeyam-cli/src/webserver/build/client/assets/entity._sha.scenarios._scenarioId.fullscreen-DyB90fWk.js +1 -0
  221. package/codeyam-cli/src/webserver/build/client/assets/entity._sha_.create-scenario-D_3ero5o.js +1 -0
  222. package/codeyam-cli/src/webserver/build/client/assets/entity._sha_.edit._scenarioId-CfLCUi9S.js +5 -0
  223. package/codeyam-cli/src/webserver/build/client/assets/entry.client-DKJyZfAY.js +29 -0
  224. package/codeyam-cli/src/webserver/build/client/assets/fileTableUtils-DAtOlaWE.js +1 -0
  225. package/codeyam-cli/src/webserver/build/client/assets/files-ClR0d32A.js +1 -0
  226. package/codeyam-cli/src/webserver/build/client/assets/git-D62Lxxmv.js +15 -0
  227. package/codeyam-cli/src/webserver/build/client/assets/globals-C6vQASxy.css +1 -0
  228. package/codeyam-cli/src/webserver/build/client/assets/html2canvas-pro.esm-fmIEn3Bc.js +9 -0
  229. package/codeyam-cli/src/webserver/build/client/assets/index-BosqDOlH.js +3 -0
  230. package/codeyam-cli/src/webserver/build/client/assets/index-CzNNiTkw.js +9 -0
  231. package/codeyam-cli/src/webserver/build/client/assets/keyAttributeCoverage-CTlFMihX.js +1 -0
  232. package/codeyam-cli/src/webserver/build/client/assets/loader-circle-CNp9QFCX.js +6 -0
  233. package/codeyam-cli/src/webserver/build/client/assets/manifest-09d684be.js +1 -0
  234. package/codeyam-cli/src/webserver/build/client/assets/preload-helper-ckwbz45p.js +1 -0
  235. package/codeyam-cli/src/webserver/build/client/assets/root-BxJUvKau.js +56 -0
  236. package/codeyam-cli/src/webserver/build/client/assets/scenarioStatus-B_8jpV3e.js +1 -0
  237. package/codeyam-cli/src/webserver/build/client/assets/search-DDGjYAMJ.js +6 -0
  238. package/codeyam-cli/src/webserver/build/client/assets/settings-DgTyB-Wg.js +1 -0
  239. package/codeyam-cli/src/webserver/build/client/assets/simulations-CoNWGt0K.js +1 -0
  240. package/codeyam-cli/src/webserver/build/client/assets/triangle-alert-CBc5dE1s.js +6 -0
  241. package/codeyam-cli/src/webserver/build/client/assets/useCustomSizes-BMIGFP-m.js +1 -0
  242. package/codeyam-cli/src/webserver/build/client/assets/useInteractiveMode-Dk_FQqWJ.js +1 -0
  243. package/codeyam-cli/src/webserver/build/client/assets/{useLastLogLine-DOGXmJcI.js → useLastLogLine-BqPPNjAl.js} +1 -1
  244. package/codeyam-cli/src/webserver/build/client/assets/useReportContext-DsJbgMY9.js +1 -0
  245. package/codeyam-cli/src/webserver/build/client/assets/{useToast-C07gRg7Z.js → useToast-DWHcCcl1.js} +1 -1
  246. package/codeyam-cli/src/webserver/build/server/assets/index-CV6i1S1A.js +1 -0
  247. package/codeyam-cli/src/webserver/build/server/assets/server-build-BDlyhfrv.js +175 -0
  248. package/codeyam-cli/src/webserver/build/server/index.js +1 -1
  249. package/codeyam-cli/src/webserver/build-info.json +5 -5
  250. package/codeyam-cli/src/webserver/devServer.js +1 -3
  251. package/codeyam-cli/src/webserver/devServer.js.map +1 -1
  252. package/codeyam-cli/templates/debug-codeyam.md +620 -0
  253. package/package.json +14 -14
  254. package/packages/ai/src/lib/analyzeScope.js +2 -0
  255. package/packages/ai/src/lib/analyzeScope.js.map +1 -1
  256. package/packages/ai/src/lib/astScopes/astScopeAnalyzer.js +16 -0
  257. package/packages/ai/src/lib/astScopes/astScopeAnalyzer.js.map +1 -1
  258. package/packages/ai/src/lib/astScopes/patterns/switchStatementHandler.js +16 -0
  259. package/packages/ai/src/lib/astScopes/patterns/switchStatementHandler.js.map +1 -1
  260. package/packages/ai/src/lib/astScopes/processExpression.js +305 -88
  261. package/packages/ai/src/lib/astScopes/processExpression.js.map +1 -1
  262. package/packages/ai/src/lib/dataStructure/ScopeDataStructure.js +523 -42
  263. package/packages/ai/src/lib/dataStructure/ScopeDataStructure.js.map +1 -1
  264. package/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/JavascriptFrameworkManager.js +12 -2
  265. package/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/JavascriptFrameworkManager.js.map +1 -1
  266. package/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/MuiManager.js +454 -0
  267. package/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/MuiManager.js.map +1 -0
  268. package/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/ReactFrameworkManager.js +103 -1
  269. package/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/ReactFrameworkManager.js.map +1 -1
  270. package/packages/ai/src/lib/dataStructure/helpers/cleanKnownObjectFunctions.js +16 -1
  271. package/packages/ai/src/lib/dataStructure/helpers/cleanKnownObjectFunctions.js.map +1 -1
  272. package/packages/ai/src/lib/dataStructure/helpers/cleanNonObjectFunctions.js +19 -1
  273. package/packages/ai/src/lib/dataStructure/helpers/cleanNonObjectFunctions.js.map +1 -1
  274. package/packages/ai/src/lib/dataStructure/helpers/convertDotNotation.js +20 -0
  275. package/packages/ai/src/lib/dataStructure/helpers/convertDotNotation.js.map +1 -1
  276. package/packages/ai/src/lib/dataStructure/helpers/fillInSchemaGapsAndUnknowns.js +28 -2
  277. package/packages/ai/src/lib/dataStructure/helpers/fillInSchemaGapsAndUnknowns.js.map +1 -1
  278. package/packages/ai/src/lib/gatherRelevantDependentKeyAttributes.js +179 -17
  279. package/packages/ai/src/lib/gatherRelevantDependentKeyAttributes.js.map +1 -1
  280. package/packages/ai/src/lib/generateChangesEntityKeyAttributes.js +6 -0
  281. package/packages/ai/src/lib/generateChangesEntityKeyAttributes.js.map +1 -1
  282. package/packages/ai/src/lib/generateChangesEntityScenarios.js +37 -4
  283. package/packages/ai/src/lib/generateChangesEntityScenarios.js.map +1 -1
  284. package/packages/ai/src/lib/generateEntityDataStructure.js +4 -0
  285. package/packages/ai/src/lib/generateEntityDataStructure.js.map +1 -1
  286. package/packages/ai/src/lib/generateEntityKeyAttributes.js +176 -9
  287. package/packages/ai/src/lib/generateEntityKeyAttributes.js.map +1 -1
  288. package/packages/ai/src/lib/generateEntityScenarioData.js +11 -15
  289. package/packages/ai/src/lib/generateEntityScenarioData.js.map +1 -1
  290. package/packages/ai/src/lib/generateEntityScenarios.js +105 -9
  291. package/packages/ai/src/lib/generateEntityScenarios.js.map +1 -1
  292. package/packages/ai/src/lib/getConditionalUsagesFromCode.js +84 -14
  293. package/packages/ai/src/lib/getConditionalUsagesFromCode.js.map +1 -1
  294. package/packages/ai/src/lib/guessScenarioDataFromDescription.js +2 -1
  295. package/packages/ai/src/lib/guessScenarioDataFromDescription.js.map +1 -1
  296. package/packages/ai/src/lib/promptGenerators/gatherAttributesMap.js +6 -0
  297. package/packages/ai/src/lib/promptGenerators/gatherAttributesMap.js.map +1 -1
  298. package/packages/ai/src/lib/promptGenerators/generateChangesEntityScenariosGenerator.js +38 -2
  299. package/packages/ai/src/lib/promptGenerators/generateChangesEntityScenariosGenerator.js.map +1 -1
  300. package/packages/ai/src/lib/promptGenerators/generateEntityScenariosGenerator.js +38 -2
  301. package/packages/ai/src/lib/promptGenerators/generateEntityScenariosGenerator.js.map +1 -1
  302. package/packages/ai/src/lib/promptGenerators/guessNewScenarioDataFromDescriptionGenerator.js +16 -3
  303. package/packages/ai/src/lib/promptGenerators/guessNewScenarioDataFromDescriptionGenerator.js.map +1 -1
  304. package/packages/ai/src/lib/worker/SerializableDataStructure.js.map +1 -1
  305. package/packages/ai/src/lib/worker/analyzeScopeWorker.js +4 -0
  306. package/packages/ai/src/lib/worker/analyzeScopeWorker.js.map +1 -1
  307. package/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.js +258 -110
  308. package/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.js.map +1 -1
  309. package/packages/analyze/src/lib/files/analyze/analyzeEntities.js +18 -0
  310. package/packages/analyze/src/lib/files/analyze/analyzeEntities.js.map +1 -1
  311. package/packages/analyze/src/lib/files/getImportedExports.js +6 -1
  312. package/packages/analyze/src/lib/files/getImportedExports.js.map +1 -1
  313. package/packages/analyze/src/lib/files/scenarios/enrichArrayTypesFromChildSignatures.js +125 -0
  314. package/packages/analyze/src/lib/files/scenarios/enrichArrayTypesFromChildSignatures.js.map +1 -0
  315. package/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.js +74 -19
  316. package/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.js.map +1 -1
  317. package/packages/analyze/src/lib/files/scenarios/generateChangesScenarioData.js +1 -1
  318. package/packages/analyze/src/lib/files/scenarios/generateChangesScenarioData.js.map +1 -1
  319. package/packages/analyze/src/lib/files/scenarios/generateDataStructure.js +175 -58
  320. package/packages/analyze/src/lib/files/scenarios/generateDataStructure.js.map +1 -1
  321. package/packages/analyze/src/lib/files/scenarios/generateKeyAttributes.js +10 -5
  322. package/packages/analyze/src/lib/files/scenarios/generateKeyAttributes.js.map +1 -1
  323. package/packages/analyze/src/lib/files/scenarios/generateScenarioData.js +127 -69
  324. package/packages/analyze/src/lib/files/scenarios/generateScenarioData.js.map +1 -1
  325. package/packages/analyze/src/lib/files/scenarios/generateScenarios.js +2 -5
  326. package/packages/analyze/src/lib/files/scenarios/generateScenarios.js.map +1 -1
  327. package/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.js +74 -23
  328. package/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.js.map +1 -1
  329. package/packages/database/src/lib/kysely/db.js +2 -2
  330. package/packages/database/src/lib/kysely/tables/debugReportsTable.js +9 -3
  331. package/packages/database/src/lib/kysely/tables/debugReportsTable.js.map +1 -1
  332. package/packages/database/src/lib/loadReadyToBeCapturedAnalyses.js +4 -2
  333. package/packages/database/src/lib/loadReadyToBeCapturedAnalyses.js.map +1 -1
  334. package/packages/generate/src/lib/componentScenarioPage/getIFrameMessageListenerCode.js +8 -4
  335. package/packages/generate/src/lib/componentScenarioPage/getIFrameMessageListenerCode.js.map +1 -1
  336. package/packages/generate/src/lib/deepMerge.js +27 -1
  337. package/packages/generate/src/lib/deepMerge.js.map +1 -1
  338. package/packages/generate/src/lib/getComponentScenarioPath.js +7 -3
  339. package/packages/generate/src/lib/getComponentScenarioPath.js.map +1 -1
  340. package/packages/types/index.js +1 -0
  341. package/packages/types/index.js.map +1 -1
  342. package/packages/types/src/types/Scenario.js +21 -1
  343. package/packages/types/src/types/Scenario.js.map +1 -1
  344. package/packages/utils/src/lib/applyUniversalMocks.js +26 -2
  345. package/packages/utils/src/lib/applyUniversalMocks.js.map +1 -1
  346. package/packages/utils/src/lib/lightweightEntityExtractor.js +25 -0
  347. package/packages/utils/src/lib/lightweightEntityExtractor.js.map +1 -1
  348. package/scripts/finalize-analyzer.cjs +3 -1
  349. package/codeyam-cli/src/webserver/build/client/assets/EntityItem-CWKV2GEz.js +0 -1
  350. package/codeyam-cli/src/webserver/build/client/assets/EntityTypeIcon-D2hFeDeg.js +0 -1
  351. package/codeyam-cli/src/webserver/build/client/assets/InteractivePreview-C8K-4kKP.js +0 -26
  352. package/codeyam-cli/src/webserver/build/client/assets/LibraryFunctionPreview-DgXLv61M.js +0 -3
  353. package/codeyam-cli/src/webserver/build/client/assets/LogViewer-DFdLQbPS.js +0 -3
  354. package/codeyam-cli/src/webserver/build/client/assets/ReportIssueModal-DlRDjT4h.js +0 -1
  355. package/codeyam-cli/src/webserver/build/client/assets/SafeScreenshot-7UkVL-UI.js +0 -1
  356. package/codeyam-cli/src/webserver/build/client/assets/ScenarioViewer-XjtsGuPo.js +0 -5
  357. package/codeyam-cli/src/webserver/build/client/assets/_index-D2eJjWLf.js +0 -1
  358. package/codeyam-cli/src/webserver/build/client/assets/activity.(_tab)-w6sbwlOd.js +0 -7
  359. package/codeyam-cli/src/webserver/build/client/assets/chevron-down-BBNQ8hup.js +0 -1
  360. package/codeyam-cli/src/webserver/build/client/assets/chunk-WWGJGFF6-Bex4RrGs.js +0 -26
  361. package/codeyam-cli/src/webserver/build/client/assets/circle-check-cdhjVtom.js +0 -1
  362. package/codeyam-cli/src/webserver/build/client/assets/createLucideIcon-DkgmwwRC.js +0 -1
  363. package/codeyam-cli/src/webserver/build/client/assets/dev.empty-CwLmCS0J.js +0 -1
  364. package/codeyam-cli/src/webserver/build/client/assets/entity._sha_.create-scenario-YZ-kM3ZG.js +0 -1
  365. package/codeyam-cli/src/webserver/build/client/assets/entity._sha_.edit._scenarioId-BeQlz94_.js +0 -5
  366. package/codeyam-cli/src/webserver/build/client/assets/entry.client-DN2XXM7Z.js +0 -5
  367. package/codeyam-cli/src/webserver/build/client/assets/fileTableUtils-CUeAIQNI.js +0 -1
  368. package/codeyam-cli/src/webserver/build/client/assets/files-ccMQfhGf.js +0 -1
  369. package/codeyam-cli/src/webserver/build/client/assets/git-JmESAHx5.js +0 -12
  370. package/codeyam-cli/src/webserver/build/client/assets/globals-CO-U8Bpo.css +0 -1
  371. package/codeyam-cli/src/webserver/build/client/assets/html2canvas-pro.esm-XQCGvadH.js +0 -5
  372. package/codeyam-cli/src/webserver/build/client/assets/index-DsL9BiOc.js +0 -8
  373. package/codeyam-cli/src/webserver/build/client/assets/loader-circle-COYCR2oZ.js +0 -1
  374. package/codeyam-cli/src/webserver/build/client/assets/manifest-90adba57.js +0 -1
  375. package/codeyam-cli/src/webserver/build/client/assets/root-DfbVEEjF.js +0 -16
  376. package/codeyam-cli/src/webserver/build/client/assets/search-DvK9iMBu.js +0 -1
  377. package/codeyam-cli/src/webserver/build/client/assets/server-build-CMKNK2uU.css +0 -1
  378. package/codeyam-cli/src/webserver/build/client/assets/settings-9LTbit4Z.js +0 -1
  379. package/codeyam-cli/src/webserver/build/client/assets/simulations-BrxN5ZtV.js +0 -1
  380. package/codeyam-cli/src/webserver/build/client/assets/triangle-alert-Iv0p8T-1.js +0 -1
  381. package/codeyam-cli/src/webserver/build/client/assets/useReportContext-BWmSRPH6.js +0 -1
  382. package/codeyam-cli/src/webserver/build/server/assets/index-CE_1qXCG.js +0 -1
  383. package/codeyam-cli/src/webserver/build/server/assets/server-build-BY_VDhiD.js +0 -166
  384. package/codeyam-cli/templates/debug-command.md +0 -141
  385. /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(
@@ -965,12 +1029,35 @@ export class ScopeDataStructure {
965
1029
  }
966
1030
 
967
1031
  if (!equivalentScopeName) {
968
- console.warn('Debug Propagation: missing equivalent scope name', {
969
- path,
970
- equivalentPath,
971
- equivalentScopeName,
972
- scopeNodeName: scopeNode.name,
973
- });
1032
+ console.error(
1033
+ 'CodeYam Error: Missing equivalent scope name - FULL CONTEXT:',
1034
+ JSON.stringify(
1035
+ {
1036
+ path,
1037
+ equivalentPath,
1038
+ equivalentScopeName,
1039
+ scopeNodeName: scopeNode.name,
1040
+ equivalencyReason,
1041
+ tree: scopeNode.tree,
1042
+ equivalencyValueChain: equivalencyValueChain?.map((ev) => ({
1043
+ id: ev.id,
1044
+ source: ev.source,
1045
+ reason: ev.reason,
1046
+ currentPath: ev.currentPath,
1047
+ previousPath: ev.previousPath,
1048
+ })),
1049
+ scopeNodeFunctionCalls: scopeNode.functionCalls?.map((fc) => ({
1050
+ name: fc.name,
1051
+ callSignature: fc.callSignature,
1052
+ callScope: fc.callScope,
1053
+ })),
1054
+ instantiatedVariables: scopeNode.instantiatedVariables,
1055
+ parentInstantiatedVariables: scopeNode.parentInstantiatedVariables,
1056
+ },
1057
+ null,
1058
+ 2,
1059
+ ),
1060
+ );
974
1061
  throw new Error('CodeYam Error: Missing equivalent scope name');
975
1062
  }
976
1063
 
@@ -1128,10 +1215,38 @@ export class ScopeDataStructure {
1128
1215
  const existingFunctionCall =
1129
1216
  this.getExternalFunctionCallsIndex().get(searchKey);
1130
1217
  if (existingFunctionCall) {
1131
- 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> = {
1132
1238
  ...existingFunctionCall.schema,
1133
- ...functionCallInfo.schema,
1134
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;
1135
1250
 
1136
1251
  existingFunctionCall.equivalencies = {
1137
1252
  ...existingFunctionCall.equivalencies,
@@ -1164,8 +1279,15 @@ export class ScopeDataStructure {
1164
1279
  );
1165
1280
 
1166
1281
  if (isExternal) {
1167
- this.externalFunctionCalls.push(functionCallInfo);
1168
- 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
+ }
1169
1291
  }
1170
1292
  }
1171
1293
  }
@@ -3137,7 +3259,12 @@ export class ScopeDataStructure {
3137
3259
  );
3138
3260
  }
3139
3261
 
3262
+ // CRITICAL: Set onlyEquivalencies to true to prevent database modifications
3263
+ // during this "getter" method. See comment in getFunctionSignature.
3264
+ const wasOnlyEquivalencies = this.onlyEquivalencies;
3265
+ this.onlyEquivalencies = true;
3140
3266
  this.validateSchema(scopeNode, true, fillInUnknowns);
3267
+ this.onlyEquivalencies = wasOnlyEquivalencies;
3141
3268
 
3142
3269
  const { schema } = scopeNode;
3143
3270
 
@@ -3238,6 +3365,7 @@ export class ScopeDataStructure {
3238
3365
  (candidate) => candidate.scopeNodeName === scopeNode.name,
3239
3366
  ),
3240
3367
  );
3368
+
3241
3369
  return entries.reduce(
3242
3370
  (acc, entry) => {
3243
3371
  if (entry.usages.length === 0) return acc;
@@ -3300,7 +3428,14 @@ export class ScopeDataStructure {
3300
3428
  equivalencies,
3301
3429
  );
3302
3430
 
3431
+ // CRITICAL: Set onlyEquivalencies to true to prevent database modifications
3432
+ // during this "getter" method. validateSchema triggers manager.finalize which
3433
+ // can call addToSchema -> addToEquivalencyDatabase -> mergeEquivalencyDatabaseEntries,
3434
+ // which would incorrectly remove entries from the database.
3435
+ const wasOnlyEquivalencies = this.onlyEquivalencies;
3436
+ this.onlyEquivalencies = true;
3303
3437
  this.validateSchema(tempScopeNode, true, fillInUnknowns);
3438
+ this.onlyEquivalencies = wasOnlyEquivalencies;
3304
3439
 
3305
3440
  return tempScopeNode.schema;
3306
3441
  }
@@ -3312,6 +3447,15 @@ export class ScopeDataStructure {
3312
3447
  functionName?: string;
3313
3448
  fillInUnknowns?: boolean;
3314
3449
  }) {
3450
+ // Trigger finalization on all managers to apply any pending updates
3451
+ // (e.g., ref type propagation to external function call schemas)
3452
+ const rootScope = this.scopeNodes[this.scopeTreeManager.getRootName()];
3453
+ if (rootScope) {
3454
+ for (const manager of this.equivalencyManagers) {
3455
+ manager.finalize(rootScope, this);
3456
+ }
3457
+ }
3458
+
3315
3459
  const scopeName = functionName ?? this.scopeTreeManager.getRootName();
3316
3460
  const scopeNode = this.scopeNodes[scopeName];
3317
3461
 
@@ -3322,7 +3466,8 @@ export class ScopeDataStructure {
3322
3466
  scopeNode: scopeNode,
3323
3467
  });
3324
3468
  } else {
3325
- for (const externalFunctionCall of this.externalFunctionCalls) {
3469
+ // Use getExternalFunctionCalls() which cleans cyScope from schemas
3470
+ for (const externalFunctionCall of this.getExternalFunctionCalls()) {
3326
3471
  const functionNameParts = this.splitPath(functionName).map((p) =>
3327
3472
  this.functionOrScopeName(p),
3328
3473
  );
@@ -3378,7 +3523,12 @@ export class ScopeDataStructure {
3378
3523
 
3379
3524
  const tempScopeNode = this.createTempScopeNode(scopeName, resolvedSchema);
3380
3525
 
3526
+ // CRITICAL: Set onlyEquivalencies to true to prevent database modifications
3527
+ // during this "getter" method. See comment in getFunctionSignature.
3528
+ const wasOnlyEquivalencies = this.onlyEquivalencies;
3529
+ this.onlyEquivalencies = true;
3381
3530
  this.validateSchema(tempScopeNode, true, fillInUnknowns);
3531
+ this.onlyEquivalencies = wasOnlyEquivalencies;
3382
3532
 
3383
3533
  return tempScopeNode.schema;
3384
3534
  }
@@ -3386,6 +3536,8 @@ export class ScopeDataStructure {
3386
3536
  /**
3387
3537
  * Replaces cyScope placeholder references (e.g., cyScope10()) in schema keys
3388
3538
  * with the actual callback function text from the corresponding scope node.
3539
+ * If the scope text can't be found, uses a generic fallback to avoid leaking
3540
+ * internal cyScope names into stored data.
3389
3541
  */
3390
3542
  private replaceCyScopePlaceholders(
3391
3543
  schema: Record<string, string>,
@@ -3401,10 +3553,10 @@ export class ScopeDataStructure {
3401
3553
  for (const match of matches) {
3402
3554
  const cyScopeName = `cyScope${match[1]}`;
3403
3555
  const scopeText = this.findCyScopeText(cyScopeName);
3404
- if (scopeText) {
3405
- // Replace cyScope10() with the actual callback text
3406
- newKey = newKey.replace(match[0], scopeText);
3407
- }
3556
+ // Always replace cyScope references - use actual text if available,
3557
+ // otherwise use a generic callback placeholder
3558
+ const replacement = scopeText || '() => {}';
3559
+ newKey = newKey.replace(match[0], replacement);
3408
3560
  }
3409
3561
 
3410
3562
  result[newKey] = value;
@@ -3526,7 +3678,12 @@ export class ScopeDataStructure {
3526
3678
  relevantSchema,
3527
3679
  );
3528
3680
 
3681
+ // CRITICAL: Set onlyEquivalencies to true to prevent database modifications
3682
+ // during this "getter" method. See comment in getFunctionSignature.
3683
+ const wasOnlyEquivalencies = this.onlyEquivalencies;
3684
+ this.onlyEquivalencies = true;
3529
3685
  this.validateSchema(tempScopeNode, true, final);
3686
+ this.onlyEquivalencies = wasOnlyEquivalencies;
3530
3687
 
3531
3688
  return {
3532
3689
  name: variableName,
@@ -3535,8 +3692,123 @@ export class ScopeDataStructure {
3535
3692
  };
3536
3693
  }
3537
3694
 
3538
- getExternalFunctionCalls() {
3539
- return this.externalFunctionCalls;
3695
+ getExternalFunctionCalls(): FunctionCallInfo[] {
3696
+ // Replace cyScope placeholders in all external function call data
3697
+ // This ensures call signatures and schema paths use actual callback text
3698
+ // instead of internal cyScope names, preventing mock data merge conflicts.
3699
+ return this.externalFunctionCalls.map((efc) =>
3700
+ this.cleanCyScopeFromFunctionCallInfo(efc),
3701
+ );
3702
+ }
3703
+
3704
+ /**
3705
+ * Cleans cyScope placeholder references from a FunctionCallInfo.
3706
+ * Replaces cyScopeN() with the actual callback text in:
3707
+ * - callSignature
3708
+ * - allCallSignatures
3709
+ * - schema keys
3710
+ */
3711
+ private cleanCyScopeFromFunctionCallInfo(
3712
+ efc: FunctionCallInfo,
3713
+ ): FunctionCallInfo {
3714
+ const cyScopePattern = /cyScope\d+\(\)/g;
3715
+
3716
+ // Check if any cleaning is needed
3717
+ const hasCyScope =
3718
+ cyScopePattern.test(efc.callSignature) ||
3719
+ (efc.allCallSignatures &&
3720
+ efc.allCallSignatures.some((sig) => /cyScope\d+\(\)/.test(sig))) ||
3721
+ (efc.schema &&
3722
+ Object.keys(efc.schema).some((key) => /cyScope\d+\(\)/.test(key)));
3723
+
3724
+ if (!hasCyScope) {
3725
+ return efc;
3726
+ }
3727
+
3728
+ // Create cleaned copy
3729
+ const cleaned: FunctionCallInfo = { ...efc };
3730
+
3731
+ // Clean callSignature
3732
+ cleaned.callSignature = this.replaceCyScopeInString(efc.callSignature);
3733
+
3734
+ // Clean allCallSignatures
3735
+ if (efc.allCallSignatures) {
3736
+ cleaned.allCallSignatures = efc.allCallSignatures.map((sig) =>
3737
+ this.replaceCyScopeInString(sig),
3738
+ );
3739
+ }
3740
+
3741
+ // Clean schema keys
3742
+ if (efc.schema) {
3743
+ cleaned.schema = this.replaceCyScopePlaceholders(efc.schema);
3744
+ }
3745
+
3746
+ // Clean callSignatureToVariable keys
3747
+ if (efc.callSignatureToVariable) {
3748
+ cleaned.callSignatureToVariable = Object.entries(
3749
+ efc.callSignatureToVariable,
3750
+ ).reduce(
3751
+ (acc, [key, value]) => {
3752
+ acc[this.replaceCyScopeInString(key)] = value;
3753
+ return acc;
3754
+ },
3755
+ {} as Record<string, string>,
3756
+ );
3757
+ }
3758
+
3759
+ return cleaned;
3760
+ }
3761
+
3762
+ /**
3763
+ * Replaces cyScope placeholder references in a single string.
3764
+ * If the scope text can't be found, uses a generic fallback to avoid leaking
3765
+ * internal cyScope names into stored data.
3766
+ *
3767
+ * Handles two patterns:
3768
+ * 1. Function call style: cyScope7() - matched by cyScope(\d+)\(\)
3769
+ * 2. Scope name style: parentName____cyScopeXX or cyScopeXX - matched by (\w+____)?cyScope([0-9A-Fa-f]+)
3770
+ */
3771
+ private replaceCyScopeInString(str: string): string {
3772
+ let result = str;
3773
+
3774
+ // Pattern 1: Function call style - cyScope7()
3775
+ const functionCallPattern = /cyScope(\d+)\(\)/g;
3776
+ const functionCallMatches = [...str.matchAll(functionCallPattern)];
3777
+ for (const match of functionCallMatches) {
3778
+ const cyScopeName = `cyScope${match[1]}`;
3779
+ const scopeText = this.findCyScopeText(cyScopeName);
3780
+ // Always replace cyScope references - use actual text if available,
3781
+ // otherwise use a generic callback placeholder
3782
+ const replacement = scopeText || '() => {}';
3783
+ result = result.replace(match[0], replacement);
3784
+ }
3785
+
3786
+ // Pattern 2: Scope name style - parentName____cyScopeXX or just cyScopeXX
3787
+ // This handles hex-encoded scope IDs like cyScope1F
3788
+ const scopeNamePattern = /(\w+____)?cyScope([0-9A-Fa-f]+)/g;
3789
+ const scopeNameMatches = [...result.matchAll(scopeNamePattern)];
3790
+ for (const match of scopeNameMatches) {
3791
+ const fullMatch = match[0];
3792
+ const prefix = match[1] || ''; // e.g., "getTitleColor____"
3793
+ const cyScopeId = match[2]; // e.g., "1F"
3794
+ const cyScopeName = `cyScope${cyScopeId}`;
3795
+
3796
+ // Try to find the scope text, checking both with and without prefix
3797
+ let scopeText = this.findCyScopeText(cyScopeName);
3798
+ if (!scopeText && prefix) {
3799
+ // Try looking up with the full prefixed name
3800
+ scopeText = this.findCyScopeText(`${prefix}${cyScopeName}`);
3801
+ }
3802
+
3803
+ if (scopeText) {
3804
+ result = result.replace(fullMatch, scopeText);
3805
+ } else {
3806
+ // Replace with a generic identifier to avoid leaking internal names
3807
+ result = result.replace(fullMatch, 'callback');
3808
+ }
3809
+ }
3810
+
3811
+ return result;
3540
3812
  }
3541
3813
 
3542
3814
  getEnvironmentVariables() {
@@ -3625,34 +3897,58 @@ export class ScopeDataStructure {
3625
3897
  }
3626
3898
 
3627
3899
  toSerializable(): SerializableDataStructure {
3628
- // Helper to convert ScopeVariable to SerializableScopeVariable
3900
+ // Helper to clean cyScope from a string
3901
+ const cleanCyScope = (str: string): string =>
3902
+ this.replaceCyScopeInString(str);
3903
+
3904
+ // Helper to convert ScopeVariable to SerializableScopeVariable (with cyScope cleaned)
3629
3905
  const toSerializableVariable = (
3630
3906
  vars:
3631
3907
  | ScopeVariable[]
3632
3908
  | Pick<ScopeVariable, 'scopeNodeName' | 'schemaPath'>[],
3633
3909
  ): SerializableScopeVariable[] =>
3634
3910
  vars.map((v) => ({
3635
- scopeNodeName: v.scopeNodeName,
3636
- schemaPath: v.schemaPath,
3911
+ scopeNodeName: cleanCyScope(v.scopeNodeName),
3912
+ schemaPath: cleanCyScope(v.schemaPath),
3637
3913
  }));
3638
3914
 
3915
+ // Helper to clean cyScope from all keys in a schema
3916
+ const cleanSchemaKeys = (
3917
+ schema: Record<string, string>,
3918
+ ): Record<string, string> => {
3919
+ return Object.entries(schema).reduce(
3920
+ (acc, [key, value]) => {
3921
+ acc[cleanCyScope(key)] = value;
3922
+ return acc;
3923
+ },
3924
+ {} as Record<string, string>,
3925
+ );
3926
+ };
3927
+
3639
3928
  // Helper to get function result for a given function name
3640
3929
  const getFunctionResult = (
3641
3930
  functionName?: string,
3642
3931
  ): SerializableFunctionResult => {
3643
3932
  return {
3644
- signature: this.getFunctionSignature({ functionName }) ?? {},
3645
- signatureWithUnknowns:
3933
+ signature: cleanSchemaKeys(
3934
+ this.getFunctionSignature({ functionName }) ?? {},
3935
+ ),
3936
+ signatureWithUnknowns: cleanSchemaKeys(
3646
3937
  this.getFunctionSignature({ functionName, fillInUnknowns: true }) ??
3647
- {},
3648
- returnValue: this.getReturnValue({ functionName }) ?? {},
3649
- returnValueWithUnknowns:
3938
+ {},
3939
+ ),
3940
+ returnValue: cleanSchemaKeys(
3941
+ this.getReturnValue({ functionName }) ?? {},
3942
+ ),
3943
+ returnValueWithUnknowns: cleanSchemaKeys(
3650
3944
  this.getReturnValue({ functionName, fillInUnknowns: true }) ?? {},
3945
+ ),
3651
3946
  usageEquivalencies: Object.entries(
3652
3947
  this.getUsageEquivalencies(functionName) ?? {},
3653
3948
  ).reduce(
3654
3949
  (acc, [key, vars]) => {
3655
- acc[key] = toSerializableVariable(vars);
3950
+ // Clean cyScope from the key as well as variable properties
3951
+ acc[cleanCyScope(key)] = toSerializableVariable(vars);
3656
3952
  return acc;
3657
3953
  },
3658
3954
  {} as Record<string, SerializableScopeVariable[]>,
@@ -3661,7 +3957,8 @@ export class ScopeDataStructure {
3661
3957
  this.getSourceEquivalencies(functionName) ?? {},
3662
3958
  ).reduce(
3663
3959
  (acc, [key, vars]) => {
3664
- acc[key] = toSerializableVariable(vars);
3960
+ // Clean cyScope from the key as well as variable properties
3961
+ acc[cleanCyScope(key)] = toSerializableVariable(vars);
3665
3962
  return acc;
3666
3963
  },
3667
3964
  {} as Record<string, SerializableScopeVariable[]>,
@@ -3670,33 +3967,347 @@ export class ScopeDataStructure {
3670
3967
  };
3671
3968
  };
3672
3969
 
3673
- // Convert external function calls
3970
+ // Convert external function calls - use getExternalFunctionCalls() which cleans cyScope
3971
+ const cleanedExternalCalls = this.getExternalFunctionCalls();
3972
+
3973
+ // Get root scope schema for building per-variable return value schemas
3974
+ const rootScopeName = this.scopeTreeManager.getRootName();
3975
+ const rootScope = this.scopeNodes[rootScopeName];
3976
+ const rootSchema = rootScope?.schema ?? {};
3977
+
3674
3978
  const externalFunctionCalls: SerializableFunctionCallInfo[] =
3675
- this.externalFunctionCalls.map((efc) => ({
3676
- name: efc.name,
3677
- callSignature: efc.callSignature,
3678
- callScope: efc.callScope,
3679
- schema: efc.schema,
3680
- equivalencies: efc.equivalencies
3681
- ? Object.entries(efc.equivalencies).reduce(
3682
- (acc, [key, vars]) => {
3683
- acc[key] = toSerializableVariable(vars);
3684
- return acc;
3685
- },
3686
- {} as Record<string, SerializableScopeVariable[]>,
3687
- )
3688
- : undefined,
3689
- allCallSignatures: efc.allCallSignatures,
3690
- receivingVariableNames: efc.receivingVariableNames,
3691
- callSignatureToVariable: efc.callSignatureToVariable,
3692
- }));
3979
+ cleanedExternalCalls.map((efc) => {
3980
+ // Build perVariableSchemas from perCallSignatureSchemas when available.
3981
+ // This preserves distinct schemas per variable when the same function is called
3982
+ // multiple times with DIFFERENT call signatures (e.g., different type parameters).
3983
+ //
3984
+ // When field accesses happen in child scopes (like JSX expressions), the
3985
+ // rootSchema doesn't contain the detailed paths - they end up in child scope
3986
+ // schemas. Using perCallSignatureSchemas ensures we get the correct schema
3987
+ // for each call, regardless of where field accesses occur.
3988
+ let perVariableSchemas:
3989
+ | Record<string, Record<string, string>>
3990
+ | undefined;
3991
+
3992
+ // Use perCallSignatureSchemas only when:
3993
+ // 1. It exists and has distinct entries for different call signatures
3994
+ // 2. The number of distinct call signatures >= number of receiving variables
3995
+ //
3996
+ // This prevents using it when all calls have the same signature (e.g., useFetcher() x 2)
3997
+ // because in that case, perCallSignatureSchemas only has one entry.
3998
+ const numCallSignatures = efc.perCallSignatureSchemas
3999
+ ? Object.keys(efc.perCallSignatureSchemas).length
4000
+ : 0;
4001
+ const numReceivingVars = efc.receivingVariableNames?.length ?? 0;
4002
+ const hasDistinctSchemas =
4003
+ numCallSignatures >= numReceivingVars && numCallSignatures > 1;
4004
+
4005
+ // CASE 1: Multiple call signatures with distinct schemas - use indexed variable names
4006
+ if (
4007
+ hasDistinctSchemas &&
4008
+ efc.perCallSignatureSchemas &&
4009
+ efc.callSignatureToVariable
4010
+ ) {
4011
+ perVariableSchemas = {};
4012
+
4013
+ // Build a reverse map: variable -> array of call signatures (in order)
4014
+ // This handles the case where the same variable name is reused for different calls
4015
+ const varToCallSigs: Record<string, string[]> = {};
4016
+ for (const [callSig, varName] of Object.entries(
4017
+ efc.callSignatureToVariable,
4018
+ )) {
4019
+ if (!varToCallSigs[varName]) {
4020
+ varToCallSigs[varName] = [];
4021
+ }
4022
+ varToCallSigs[varName].push(callSig);
4023
+ }
4024
+
4025
+ // Track how many times each variable name has been seen
4026
+ const varNameCounts: Record<string, number> = {};
4027
+
4028
+ // For each receiving variable, get its original schema from perCallSignatureSchemas
4029
+ for (const varName of efc.receivingVariableNames ?? []) {
4030
+ const occurrence = varNameCounts[varName] ?? 0;
4031
+ varNameCounts[varName] = occurrence + 1;
4032
+
4033
+ const callSigs = varToCallSigs[varName];
4034
+ // Use the nth call signature for the nth occurrence of this variable
4035
+ const callSig = callSigs?.[occurrence];
4036
+
4037
+ if (callSig && efc.perCallSignatureSchemas[callSig]) {
4038
+ // Use indexed key if this variable name is reused (e.g., fetcher, fetcher[1])
4039
+ const key =
4040
+ occurrence === 0 ? varName : `${varName}[${occurrence}]`;
4041
+ // Clone the schema to avoid shared references
4042
+ perVariableSchemas[key] = {
4043
+ ...efc.perCallSignatureSchemas[callSig],
4044
+ };
4045
+ }
4046
+ }
4047
+
4048
+ // Only include if we have entries for ALL receiving variables
4049
+ if (Object.keys(perVariableSchemas).length < numReceivingVars) {
4050
+ // Not all variables have schemas - fall back to rootSchema extraction
4051
+ perVariableSchemas = undefined;
4052
+ }
4053
+ }
4054
+
4055
+ // CASE 2: Single call signature with single variable - use perCallSignatureSchemas directly
4056
+ // This handles parameterized calls like useFetcher<ConfigData>() where each is a separate efc entry
4057
+ if (
4058
+ !perVariableSchemas &&
4059
+ efc.perCallSignatureSchemas &&
4060
+ numCallSignatures === 1 &&
4061
+ numReceivingVars === 1
4062
+ ) {
4063
+ const varName = efc.receivingVariableNames![0];
4064
+ const callSig = Object.keys(efc.perCallSignatureSchemas)[0];
4065
+ const schema = efc.perCallSignatureSchemas[callSig];
4066
+ if (schema && Object.keys(schema).length > 0) {
4067
+ perVariableSchemas = { [varName]: { ...schema } };
4068
+ }
4069
+ }
4070
+
4071
+ // CASE 3: Parameterized calls that create SEPARATE efc entries (no perCallSignatureSchemas)
4072
+ // When useFetcher<ConfigData>() and useFetcher<SettingsData>() are called, they create separate
4073
+ // efc entries because getFunctionCallRoot preserves type parameters. Each entry has its own
4074
+ // `schema` field, but due to variable reassignment, the schema may be contaminated with paths
4075
+ // from other calls (the tracer attributes field accesses to ALL equivalencies).
4076
+ //
4077
+ // Solution: Filter efc.schema to only include paths that match THIS entry's call signature.
4078
+ // The schema paths include the full call signature prefix, so we can filter by it.
4079
+ //
4080
+ // Example: ConfigData entry has paths like:
4081
+ // "useFetcher<{ data: ConfigData | null }>().functionCallReturnValue.data.data.theme"
4082
+ // But also (contaminated):
4083
+ // "useFetcher<{ data: ConfigData | null }>().functionCallReturnValue.data.data.notifications"
4084
+ //
4085
+ // We filter to only keep paths that should belong to THIS call by checking if the
4086
+ // receiving variable's equivalency points to this call's return value.
4087
+ if (
4088
+ !perVariableSchemas &&
4089
+ !efc.perCallSignatureSchemas &&
4090
+ numReceivingVars >= 1
4091
+ ) {
4092
+ // Build the call signature prefix that paths should start with
4093
+ const callSigPrefix = `${efc.callSignature}.functionCallReturnValue`;
4094
+
4095
+ // Filter efc.schema to only include paths matching this call signature
4096
+ const filteredSchema: Record<string, string> = {};
4097
+ for (const [path, type] of Object.entries(efc.schema)) {
4098
+ if (path.startsWith(callSigPrefix) || path === efc.callSignature) {
4099
+ filteredSchema[path] = type;
4100
+ }
4101
+ }
4102
+
4103
+ // Build perVariableSchemas from the filtered schema
4104
+ if (Object.keys(filteredSchema).length > 0) {
4105
+ perVariableSchemas = {};
4106
+ for (const varName of efc.receivingVariableNames ?? []) {
4107
+ // For each variable, extract paths and transform to functionCallReturnValue format
4108
+ const varSchema: Record<string, string> = {};
4109
+ for (const [path, type] of Object.entries(filteredSchema)) {
4110
+ if (path.startsWith(callSigPrefix)) {
4111
+ // Transform to generic functionCallReturnValue path
4112
+ // e.g., "useFetcher<ConfigData>().functionCallReturnValue.data.data.theme"
4113
+ // -> "functionCallReturnValue.data.data.theme"
4114
+ const suffix = path.slice(callSigPrefix.length);
4115
+ const returnValuePath = `functionCallReturnValue${suffix}`;
4116
+ varSchema[returnValuePath] = type;
4117
+ } else if (path === efc.callSignature) {
4118
+ // Include the function call type itself
4119
+ varSchema[path] = type;
4120
+ }
4121
+ }
4122
+ if (Object.keys(varSchema).length > 0) {
4123
+ perVariableSchemas[varName] = varSchema;
4124
+ }
4125
+ }
4126
+ // Only include if we have entries
4127
+ if (Object.keys(perVariableSchemas).length === 0) {
4128
+ perVariableSchemas = undefined;
4129
+ }
4130
+ }
4131
+ }
4132
+
4133
+ // Fallback: extract from root scope schema when perCallSignatureSchemas is not available
4134
+ // or doesn't have distinct entries for each variable.
4135
+ // This works when field accesses are in the root scope.
4136
+ if (
4137
+ !perVariableSchemas &&
4138
+ efc.receivingVariableNames &&
4139
+ efc.receivingVariableNames.length > 0
4140
+ ) {
4141
+ perVariableSchemas = {};
4142
+ for (const varName of efc.receivingVariableNames) {
4143
+ const varSchema: Record<string, string> = {};
4144
+ for (const [path, type] of Object.entries(rootSchema)) {
4145
+ // Check if path starts with this variable name
4146
+ if (
4147
+ path === varName ||
4148
+ path.startsWith(varName + '.') ||
4149
+ path.startsWith(varName + '[')
4150
+ ) {
4151
+ // Transform to functionCallReturnValue format
4152
+ // e.g., userFetcher.data.id -> functionCallReturnValue.data.id
4153
+ const suffix = path.slice(varName.length);
4154
+ const returnValuePath = `functionCallReturnValue${suffix}`;
4155
+ varSchema[returnValuePath] = type;
4156
+ }
4157
+ }
4158
+ if (Object.keys(varSchema).length > 0) {
4159
+ perVariableSchemas[varName] = varSchema;
4160
+ }
4161
+ }
4162
+ // Only include if we have any entries
4163
+ if (Object.keys(perVariableSchemas).length === 0) {
4164
+ perVariableSchemas = undefined;
4165
+ }
4166
+ }
4167
+
4168
+ return {
4169
+ name: efc.name,
4170
+ callSignature: efc.callSignature,
4171
+ callScope: efc.callScope,
4172
+ schema: efc.schema,
4173
+ equivalencies: efc.equivalencies
4174
+ ? Object.entries(efc.equivalencies).reduce(
4175
+ (acc, [key, vars]) => {
4176
+ // Clean cyScope from the key as well as variable properties
4177
+ acc[cleanCyScope(key)] = toSerializableVariable(vars);
4178
+ return acc;
4179
+ },
4180
+ {} as Record<string, SerializableScopeVariable[]>,
4181
+ )
4182
+ : undefined,
4183
+ allCallSignatures: efc.allCallSignatures,
4184
+ receivingVariableNames: efc.receivingVariableNames,
4185
+ callSignatureToVariable: efc.callSignatureToVariable,
4186
+ perVariableSchemas,
4187
+ };
4188
+ });
4189
+
4190
+ // POST-PROCESSING: Deduplicate schemas across parameterized calls to same base function
4191
+ // When useFetcher<ConfigData>() and useFetcher<SettingsData>() are called, they create
4192
+ // separate entries. Due to variable reassignment, BOTH entries may have ALL fields.
4193
+ // We deduplicate by assigning each field to ONLY ONE entry based on order of appearance.
4194
+ //
4195
+ // Strategy: Fields that appear first in order belong to the first entry,
4196
+ // fields that appear later belong to later entries (split evenly).
4197
+ const deduplicateParameterizedEntries = (
4198
+ entries: typeof externalFunctionCalls,
4199
+ ): typeof externalFunctionCalls => {
4200
+ // Group entries by base function name (without type parameters)
4201
+ const groups = new Map<string, typeof externalFunctionCalls>();
4202
+ for (const entry of entries) {
4203
+ // Extract base function name by stripping type parameters
4204
+ // e.g., "useFetcher<{ data: ConfigData | null }>" -> "useFetcher"
4205
+ const baseName = entry.name.replace(/<.*>$/, '');
4206
+ const group = groups.get(baseName) || [];
4207
+ group.push(entry);
4208
+ groups.set(baseName, group);
4209
+ }
4210
+
4211
+ // Process groups with multiple parameterized entries
4212
+ for (const [, group] of groups) {
4213
+ if (group.length <= 1) continue;
4214
+
4215
+ // Check if these are parameterized calls (have type parameters in name)
4216
+ const hasTypeParams = group.every((e) => e.name.includes('<'));
4217
+ if (!hasTypeParams) continue;
4218
+
4219
+ // Collect ALL unique field suffixes across all entries (in order of first appearance)
4220
+ // Field suffix is the path after functionCallReturnValue, e.g., ".data.data.theme"
4221
+ const allFieldSuffixes: string[] = [];
4222
+ for (const entry of group) {
4223
+ if (!entry.perVariableSchemas) continue;
4224
+ for (const varSchema of Object.values(entry.perVariableSchemas)) {
4225
+ for (const path of Object.keys(varSchema)) {
4226
+ // Skip the base "functionCallReturnValue" entry
4227
+ if (path === 'functionCallReturnValue') continue;
4228
+ // Extract field suffix
4229
+ const match = path.match(/functionCallReturnValue(.+)/);
4230
+ if (!match) continue;
4231
+ const fieldSuffix = match[1];
4232
+ if (!allFieldSuffixes.includes(fieldSuffix)) {
4233
+ allFieldSuffixes.push(fieldSuffix);
4234
+ }
4235
+ }
4236
+ }
4237
+ }
4238
+
4239
+ // Assign fields to entries: split evenly based on order
4240
+ // First N/2 fields go to first entry, remaining go to second entry
4241
+ const fieldToEntryMap = new Map<string, number>();
4242
+ const fieldsPerEntry = Math.ceil(
4243
+ allFieldSuffixes.length / group.length,
4244
+ );
4245
+ for (let i = 0; i < allFieldSuffixes.length; i++) {
4246
+ const fieldSuffix = allFieldSuffixes[i];
4247
+ const entryIdx = Math.min(
4248
+ Math.floor(i / fieldsPerEntry),
4249
+ group.length - 1,
4250
+ );
4251
+ fieldToEntryMap.set(fieldSuffix, entryIdx);
4252
+ }
4253
+
4254
+ // Filter each entry's perVariableSchemas to only include its assigned fields
4255
+ for (let i = 0; i < group.length; i++) {
4256
+ const entry = group[i];
4257
+ if (!entry.perVariableSchemas) continue;
4258
+
4259
+ const filteredPerVarSchemas: Record<
4260
+ string,
4261
+ Record<string, string>
4262
+ > = {};
4263
+ for (const [varName, varSchema] of Object.entries(
4264
+ entry.perVariableSchemas,
4265
+ )) {
4266
+ const filteredVarSchema: Record<string, string> = {};
4267
+ for (const [path, type] of Object.entries(varSchema)) {
4268
+ // Always keep the base functionCallReturnValue
4269
+ if (path === 'functionCallReturnValue') {
4270
+ filteredVarSchema[path] = type;
4271
+ continue;
4272
+ }
4273
+ // Extract field suffix
4274
+ const match = path.match(/functionCallReturnValue(.+)/);
4275
+ if (!match) {
4276
+ // Keep non-field paths
4277
+ filteredVarSchema[path] = type;
4278
+ continue;
4279
+ }
4280
+ const fieldSuffix = match[1];
4281
+ // Only include if this entry owns this field
4282
+ if (fieldToEntryMap.get(fieldSuffix) === i) {
4283
+ filteredVarSchema[path] = type;
4284
+ }
4285
+ }
4286
+ if (Object.keys(filteredVarSchema).length > 0) {
4287
+ filteredPerVarSchemas[varName] = filteredVarSchema;
4288
+ }
4289
+ }
4290
+ entry.perVariableSchemas =
4291
+ Object.keys(filteredPerVarSchemas).length > 0
4292
+ ? filteredPerVarSchemas
4293
+ : undefined;
4294
+ }
4295
+ }
4296
+
4297
+ return entries;
4298
+ };
4299
+
4300
+ // Apply deduplication
4301
+ const deduplicatedExternalFunctionCalls = deduplicateParameterizedEntries(
4302
+ externalFunctionCalls,
4303
+ );
3693
4304
 
3694
4305
  // Get root function result
3695
4306
  const rootFunction = getFunctionResult();
3696
4307
 
3697
- // Get results for each external function
4308
+ // Get results for each external function (use cleaned calls for consistency)
3698
4309
  const functionResults: Record<string, SerializableFunctionResult> = {};
3699
- for (const efc of this.externalFunctionCalls) {
4310
+ for (const efc of cleanedExternalCalls) {
3700
4311
  functionResults[efc.name] = getFunctionResult(efc.name);
3701
4312
  }
3702
4313
 
@@ -3713,7 +4324,7 @@ export class ScopeDataStructure {
3713
4324
  : undefined;
3714
4325
 
3715
4326
  return {
3716
- externalFunctionCalls,
4327
+ externalFunctionCalls: deduplicatedExternalFunctionCalls,
3717
4328
  rootFunction,
3718
4329
  functionResults,
3719
4330
  equivalentSignatureVariables,