@codeyam/codeyam-cli 0.1.0-staging.b8a55ba → 0.1.0-staging.d0ad4ae

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 (340) hide show
  1. package/analyzer-template/.build-info.json +7 -7
  2. package/analyzer-template/common/execAsync.ts +1 -1
  3. package/analyzer-template/log.txt +3 -3
  4. package/analyzer-template/package.json +7 -4
  5. package/analyzer-template/packages/ai/package.json +1 -1
  6. package/analyzer-template/packages/ai/src/lib/astScopes/processExpression.ts +14 -1
  7. package/analyzer-template/packages/ai/src/lib/checkAllAttributes.ts +29 -10
  8. package/analyzer-template/packages/ai/src/lib/dataStructure/ScopeDataStructure.ts +120 -19
  9. package/analyzer-template/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/JavascriptFrameworkManager.ts +2 -1
  10. package/analyzer-template/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/MuiManager.ts +91 -35
  11. package/analyzer-template/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/ReactFrameworkManager.ts +110 -74
  12. package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/cleanNonObjectFunctions.ts +11 -0
  13. package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/convertNullToUndefinedBySchema.ts +98 -0
  14. package/analyzer-template/packages/ai/src/lib/deepEqual.ts +30 -0
  15. package/analyzer-template/packages/ai/src/lib/findMatchingAttribute.ts +24 -17
  16. package/analyzer-template/packages/ai/src/lib/gatherRelevantDependentKeyAttributes.ts +214 -39
  17. package/analyzer-template/packages/ai/src/lib/generateChangesEntityKeyAttributes.ts +54 -1
  18. package/analyzer-template/packages/ai/src/lib/generateChangesEntityScenarioData.ts +72 -6
  19. package/analyzer-template/packages/ai/src/lib/generateChangesEntityScenarios.ts +12 -5
  20. package/analyzer-template/packages/ai/src/lib/generateEntityScenarioData.ts +39 -23
  21. package/analyzer-template/packages/ai/src/lib/promptGenerators/generateChangesEntityScenariosGenerator.ts +32 -0
  22. package/analyzer-template/packages/analyze/src/lib/FileAnalyzer.ts +14 -0
  23. package/analyzer-template/packages/analyze/src/lib/asts/nodes/index.ts +1 -0
  24. package/analyzer-template/packages/analyze/src/lib/asts/nodes/isAsyncFunction.ts +67 -0
  25. package/analyzer-template/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.ts +73 -69
  26. package/analyzer-template/packages/analyze/src/lib/files/analyze/analyzeEntities.ts +6 -0
  27. package/analyzer-template/packages/analyze/src/lib/files/analyze/findOrCreateEntity.ts +3 -0
  28. package/analyzer-template/packages/analyze/src/lib/files/analyzeChange.ts +22 -6
  29. package/analyzer-template/packages/analyze/src/lib/files/analyzeEntity.ts +9 -5
  30. package/analyzer-template/packages/analyze/src/lib/files/scenarios/enrichArrayTypesFromChildSignatures.ts +49 -11
  31. package/analyzer-template/packages/analyze/src/lib/files/scenarios/enrichUnknownTypesFromSourceEquivalencies.ts +102 -0
  32. package/analyzer-template/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.ts +399 -52
  33. package/analyzer-template/packages/analyze/src/lib/files/scenarios/generateChangesScenarios.ts +128 -2
  34. package/analyzer-template/packages/analyze/src/lib/files/scenarios/generateDataStructure.ts +114 -70
  35. package/analyzer-template/packages/analyze/src/lib/files/scenarios/generateScenarioData.ts +34 -129
  36. package/analyzer-template/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.ts +155 -79
  37. package/analyzer-template/packages/aws/codebuild/index.ts +1 -0
  38. package/analyzer-template/packages/aws/dist/src/lib/codebuild/waitForBuild.d.ts +11 -1
  39. package/analyzer-template/packages/aws/dist/src/lib/codebuild/waitForBuild.d.ts.map +1 -1
  40. package/analyzer-template/packages/aws/dist/src/lib/codebuild/waitForBuild.js +29 -18
  41. package/analyzer-template/packages/aws/dist/src/lib/codebuild/waitForBuild.js.map +1 -1
  42. package/analyzer-template/packages/aws/dist/src/lib/ecs/ecsDefineContainer.d.ts +2 -2
  43. package/analyzer-template/packages/aws/dist/src/lib/ecs/ecsDefineContainer.d.ts.map +1 -1
  44. package/analyzer-template/packages/aws/dist/src/lib/ecs/ecsDefineContainer.js +2 -2
  45. package/analyzer-template/packages/aws/dist/src/lib/ecs/ecsDefineContainer.js.map +1 -1
  46. package/analyzer-template/packages/aws/dist/src/lib/ecs/ecsTaskFactory.d.ts +8 -18
  47. package/analyzer-template/packages/aws/dist/src/lib/ecs/ecsTaskFactory.d.ts.map +1 -1
  48. package/analyzer-template/packages/aws/dist/src/lib/ecs/ecsTaskFactory.js +17 -61
  49. package/analyzer-template/packages/aws/dist/src/lib/ecs/ecsTaskFactory.js.map +1 -1
  50. package/analyzer-template/packages/aws/dist/src/lib/s3/uploadFileToS3.d.ts.map +1 -1
  51. package/analyzer-template/packages/aws/dist/src/lib/s3/uploadFileToS3.js +8 -1
  52. package/analyzer-template/packages/aws/dist/src/lib/s3/uploadFileToS3.js.map +1 -1
  53. package/analyzer-template/packages/aws/package.json +1 -1
  54. package/analyzer-template/packages/aws/src/lib/codebuild/waitForBuild.ts +43 -19
  55. package/analyzer-template/packages/aws/src/lib/ecs/ecsDefineContainer.ts +3 -3
  56. package/analyzer-template/packages/aws/src/lib/ecs/ecsTaskFactory.ts +17 -69
  57. package/analyzer-template/packages/aws/src/lib/s3/uploadFileToS3.ts +8 -1
  58. package/analyzer-template/packages/generate/index.ts +3 -0
  59. package/analyzer-template/packages/generate/src/lib/componentScenarioPage/componentScenarioPageNext.ts +17 -1
  60. package/analyzer-template/packages/generate/src/lib/componentScenarioPage/generateScenarioClientWrapper.ts +193 -0
  61. package/analyzer-template/packages/generate/src/lib/componentScenarioPage/generateScenarioServerComponent.ts +73 -0
  62. package/analyzer-template/packages/generate/src/lib/scenarioComponentForServer.ts +114 -0
  63. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/entitiesTable.d.ts +1 -0
  64. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/entitiesTable.d.ts.map +1 -1
  65. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/scenariosTable.d.ts +1 -0
  66. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/scenariosTable.d.ts.map +1 -1
  67. package/analyzer-template/packages/github/dist/generate/index.d.ts +3 -0
  68. package/analyzer-template/packages/github/dist/generate/index.d.ts.map +1 -1
  69. package/analyzer-template/packages/github/dist/generate/index.js +3 -0
  70. package/analyzer-template/packages/github/dist/generate/index.js.map +1 -1
  71. package/analyzer-template/packages/github/dist/generate/src/lib/componentScenarioPage/componentScenarioPageNext.d.ts.map +1 -1
  72. package/analyzer-template/packages/github/dist/generate/src/lib/componentScenarioPage/componentScenarioPageNext.js +16 -1
  73. package/analyzer-template/packages/github/dist/generate/src/lib/componentScenarioPage/componentScenarioPageNext.js.map +1 -1
  74. package/analyzer-template/packages/github/dist/generate/src/lib/componentScenarioPage/generateScenarioClientWrapper.d.ts +9 -0
  75. package/analyzer-template/packages/github/dist/generate/src/lib/componentScenarioPage/generateScenarioClientWrapper.d.ts.map +1 -0
  76. package/analyzer-template/packages/github/dist/generate/src/lib/componentScenarioPage/generateScenarioClientWrapper.js +189 -0
  77. package/analyzer-template/packages/github/dist/generate/src/lib/componentScenarioPage/generateScenarioClientWrapper.js.map +1 -0
  78. package/analyzer-template/packages/github/dist/generate/src/lib/componentScenarioPage/generateScenarioServerComponent.d.ts +20 -0
  79. package/analyzer-template/packages/github/dist/generate/src/lib/componentScenarioPage/generateScenarioServerComponent.d.ts.map +1 -0
  80. package/analyzer-template/packages/github/dist/generate/src/lib/componentScenarioPage/generateScenarioServerComponent.js +53 -0
  81. package/analyzer-template/packages/github/dist/generate/src/lib/componentScenarioPage/generateScenarioServerComponent.js.map +1 -0
  82. package/analyzer-template/packages/github/dist/generate/src/lib/scenarioComponentForServer.d.ts +8 -0
  83. package/analyzer-template/packages/github/dist/generate/src/lib/scenarioComponentForServer.d.ts.map +1 -0
  84. package/analyzer-template/packages/github/dist/generate/src/lib/scenarioComponentForServer.js +89 -0
  85. package/analyzer-template/packages/github/dist/generate/src/lib/scenarioComponentForServer.js.map +1 -0
  86. package/analyzer-template/packages/github/dist/github/src/lib/loadOrCreateCommit.d.ts.map +1 -1
  87. package/analyzer-template/packages/github/dist/github/src/lib/loadOrCreateCommit.js +10 -0
  88. package/analyzer-template/packages/github/dist/github/src/lib/loadOrCreateCommit.js.map +1 -1
  89. package/analyzer-template/packages/github/dist/github/src/lib/syncPrimaryBranch.d.ts.map +1 -1
  90. package/analyzer-template/packages/github/dist/github/src/lib/syncPrimaryBranch.js +3 -0
  91. package/analyzer-template/packages/github/dist/github/src/lib/syncPrimaryBranch.js.map +1 -1
  92. package/analyzer-template/packages/github/dist/types/src/types/Entity.d.ts +2 -0
  93. package/analyzer-template/packages/github/dist/types/src/types/Entity.d.ts.map +1 -1
  94. package/analyzer-template/packages/github/dist/types/src/types/Scenario.d.ts +6 -0
  95. package/analyzer-template/packages/github/dist/types/src/types/Scenario.d.ts.map +1 -1
  96. package/analyzer-template/packages/github/src/lib/loadOrCreateCommit.ts +14 -0
  97. package/analyzer-template/packages/github/src/lib/syncPrimaryBranch.ts +2 -0
  98. package/analyzer-template/packages/process/index.ts +2 -0
  99. package/analyzer-template/packages/process/package.json +12 -0
  100. package/analyzer-template/packages/process/tsconfig.json +8 -0
  101. package/analyzer-template/packages/types/src/types/Entity.ts +2 -0
  102. package/analyzer-template/packages/types/src/types/Scenario.ts +6 -0
  103. package/analyzer-template/packages/utils/dist/types/src/types/Entity.d.ts +2 -0
  104. package/analyzer-template/packages/utils/dist/types/src/types/Entity.d.ts.map +1 -1
  105. package/analyzer-template/packages/utils/dist/types/src/types/Scenario.d.ts +6 -0
  106. package/analyzer-template/packages/utils/dist/types/src/types/Scenario.d.ts.map +1 -1
  107. package/analyzer-template/playwright/capture.ts +37 -18
  108. package/analyzer-template/playwright/waitForServer.ts +21 -6
  109. package/analyzer-template/project/constructMockCode.ts +781 -140
  110. package/analyzer-template/project/orchestrateCapture/KyselyAnalysisLoader.ts +3 -6
  111. package/analyzer-template/project/orchestrateCapture.ts +10 -3
  112. package/analyzer-template/project/reconcileMockDataKeys.ts +28 -100
  113. package/analyzer-template/project/runAnalysis.ts +5 -0
  114. package/analyzer-template/project/serverOnlyModules.ts +127 -2
  115. package/analyzer-template/project/start.ts +5 -3
  116. package/analyzer-template/project/startScenarioCapture.ts +6 -0
  117. package/analyzer-template/project/writeMockDataTsx.ts +50 -22
  118. package/analyzer-template/project/writeScenarioClientWrapper.ts +21 -0
  119. package/analyzer-template/project/writeScenarioComponents.ts +162 -100
  120. package/analyzer-template/project/writeScenarioFiles.ts +26 -0
  121. package/analyzer-template/project/writeSimpleRoot.ts +11 -35
  122. package/analyzer-template/scripts/comboWorkerLoop.cjs +1 -0
  123. package/analyzer-template/scripts/defaultCmd.sh +9 -0
  124. package/background/src/lib/local/createLocalAnalyzer.js +1 -29
  125. package/background/src/lib/local/createLocalAnalyzer.js.map +1 -1
  126. package/background/src/lib/local/execAsync.js +1 -1
  127. package/background/src/lib/local/execAsync.js.map +1 -1
  128. package/background/src/lib/virtualized/common/execAsync.js +1 -1
  129. package/background/src/lib/virtualized/common/execAsync.js.map +1 -1
  130. package/background/src/lib/virtualized/project/constructMockCode.js +718 -127
  131. package/background/src/lib/virtualized/project/constructMockCode.js.map +1 -1
  132. package/background/src/lib/virtualized/project/orchestrateCapture/KyselyAnalysisLoader.js +3 -2
  133. package/background/src/lib/virtualized/project/orchestrateCapture/KyselyAnalysisLoader.js.map +1 -1
  134. package/background/src/lib/virtualized/project/orchestrateCapture.js +7 -4
  135. package/background/src/lib/virtualized/project/orchestrateCapture.js.map +1 -1
  136. package/background/src/lib/virtualized/project/reconcileMockDataKeys.js +25 -61
  137. package/background/src/lib/virtualized/project/reconcileMockDataKeys.js.map +1 -1
  138. package/background/src/lib/virtualized/project/runAnalysis.js +4 -0
  139. package/background/src/lib/virtualized/project/runAnalysis.js.map +1 -1
  140. package/background/src/lib/virtualized/project/serverOnlyModules.js +106 -3
  141. package/background/src/lib/virtualized/project/serverOnlyModules.js.map +1 -1
  142. package/background/src/lib/virtualized/project/start.js +5 -3
  143. package/background/src/lib/virtualized/project/start.js.map +1 -1
  144. package/background/src/lib/virtualized/project/startScenarioCapture.js +7 -0
  145. package/background/src/lib/virtualized/project/startScenarioCapture.js.map +1 -1
  146. package/background/src/lib/virtualized/project/writeMockDataTsx.js +52 -23
  147. package/background/src/lib/virtualized/project/writeMockDataTsx.js.map +1 -1
  148. package/background/src/lib/virtualized/project/writeScenarioClientWrapper.js +15 -0
  149. package/background/src/lib/virtualized/project/writeScenarioClientWrapper.js.map +1 -0
  150. package/background/src/lib/virtualized/project/writeScenarioComponents.js +136 -83
  151. package/background/src/lib/virtualized/project/writeScenarioComponents.js.map +1 -1
  152. package/background/src/lib/virtualized/project/writeScenarioFiles.js +19 -0
  153. package/background/src/lib/virtualized/project/writeScenarioFiles.js.map +1 -1
  154. package/background/src/lib/virtualized/project/writeSimpleRoot.js +11 -34
  155. package/background/src/lib/virtualized/project/writeSimpleRoot.js.map +1 -1
  156. package/codeyam-cli/src/cli.js +5 -1
  157. package/codeyam-cli/src/cli.js.map +1 -1
  158. package/codeyam-cli/src/commands/analyze.js +1 -1
  159. package/codeyam-cli/src/commands/analyze.js.map +1 -1
  160. package/codeyam-cli/src/commands/baseline.js +177 -0
  161. package/codeyam-cli/src/commands/baseline.js.map +1 -0
  162. package/codeyam-cli/src/commands/status.js +23 -1
  163. package/codeyam-cli/src/commands/status.js.map +1 -1
  164. package/codeyam-cli/src/commands/test-startup.js +1 -1
  165. package/codeyam-cli/src/commands/test-startup.js.map +1 -1
  166. package/codeyam-cli/src/commands/wipe.js +108 -0
  167. package/codeyam-cli/src/commands/wipe.js.map +1 -0
  168. package/codeyam-cli/src/utils/database.js +91 -5
  169. package/codeyam-cli/src/utils/database.js.map +1 -1
  170. package/codeyam-cli/src/utils/git.js +79 -0
  171. package/codeyam-cli/src/utils/git.js.map +1 -0
  172. package/codeyam-cli/src/utils/queue/job.js +104 -0
  173. package/codeyam-cli/src/utils/queue/job.js.map +1 -1
  174. package/codeyam-cli/src/utils/queue/persistence.js.map +1 -1
  175. package/codeyam-cli/src/utils/wipe.js +128 -0
  176. package/codeyam-cli/src/utils/wipe.js.map +1 -0
  177. package/codeyam-cli/src/webserver/app/lib/database.js +66 -17
  178. package/codeyam-cli/src/webserver/app/lib/database.js.map +1 -1
  179. package/codeyam-cli/src/webserver/build/client/assets/{EntityItem-wXL1Z2Aq.js → EntityItem-Cmysw5OP.js} +1 -1
  180. package/codeyam-cli/src/webserver/build/client/assets/{EntityTypeBadge-CzGX-miz.js → EntityTypeBadge-DLqD3qNt.js} +1 -1
  181. package/codeyam-cli/src/webserver/build/client/assets/{EntityTypeIcon-CXFKsCOD.js → EntityTypeIcon-CAneekK2.js} +1 -1
  182. package/codeyam-cli/src/webserver/build/client/assets/{InteractivePreview-D-9pXIaY.js → InteractivePreview-Cu16OUmx.js} +2 -2
  183. package/codeyam-cli/src/webserver/build/client/assets/{LibraryFunctionPreview-CBQPrpT0.js → LibraryFunctionPreview-CVtiBnY5.js} +1 -1
  184. package/codeyam-cli/src/webserver/build/client/assets/{LoadingDots-D1CdlbrV.js → LoadingDots-B0GLXMsr.js} +1 -1
  185. package/codeyam-cli/src/webserver/build/client/assets/{LogViewer-wDPcZNKx.js → LogViewer-xgeCVgSM.js} +1 -1
  186. package/codeyam-cli/src/webserver/build/client/assets/{ReportIssueModal-4lcOlid-.js → ReportIssueModal-DcAUIpD_.js} +1 -1
  187. package/codeyam-cli/src/webserver/build/client/assets/{SafeScreenshot-BfmDgXxG.js → SafeScreenshot-DuDvi0jm.js} +1 -1
  188. package/codeyam-cli/src/webserver/build/client/assets/ScenarioViewer-BMKg0SAF.js +15 -0
  189. package/codeyam-cli/src/webserver/build/client/assets/{TruncatedFilePath-6J7zDUD5.js → TruncatedFilePath-DyFZkK0l.js} +1 -1
  190. package/codeyam-cli/src/webserver/build/client/assets/_index-DSmTpjmK.js +11 -0
  191. package/codeyam-cli/src/webserver/build/client/assets/activity.(_tab)-BF_aK4y6.js +32 -0
  192. package/codeyam-cli/src/webserver/build/client/assets/{chevron-down-BYimnrHg.js → chevron-down-Cx24_aWc.js} +1 -1
  193. package/codeyam-cli/src/webserver/build/client/assets/chunk-EPOLDU6W-CXRTFQ3F.js +51 -0
  194. package/codeyam-cli/src/webserver/build/client/assets/{circle-check-CaVsIRxt.js → circle-check-BOARzkeR.js} +1 -1
  195. package/codeyam-cli/src/webserver/build/client/assets/{createLucideIcon-CgUsG7ib.js → createLucideIcon-BdhJEx6B.js} +1 -1
  196. package/codeyam-cli/src/webserver/build/client/assets/{dev.empty-DW_hdGUc.js → dev.empty-RJCf3Tvw.js} +1 -1
  197. package/codeyam-cli/src/webserver/build/client/assets/{entity._sha._-zUEpfPsu.js → entity._sha._-D0-YwkBh.js} +12 -12
  198. package/codeyam-cli/src/webserver/build/client/assets/entity._sha.scenarios._scenarioId.fullscreen-EylcgScH.js +1 -0
  199. package/codeyam-cli/src/webserver/build/client/assets/{entity._sha_.create-scenario-D_3ero5o.js → entity._sha_.create-scenario-DMe7kvgo.js} +1 -1
  200. package/codeyam-cli/src/webserver/build/client/assets/{entity._sha_.edit._scenarioId-CfLCUi9S.js → entity._sha_.edit._scenarioId-C1H_a_Y3.js} +1 -1
  201. package/codeyam-cli/src/webserver/build/client/assets/{entry.client-DKJyZfAY.js → entry.client-CS2cb_eZ.js} +6 -6
  202. package/codeyam-cli/src/webserver/build/client/assets/{fileTableUtils-DAtOlaWE.js → fileTableUtils-DMJ7zii9.js} +1 -1
  203. package/codeyam-cli/src/webserver/build/client/assets/{files-ClR0d32A.js → files-BW7Cyeyi.js} +1 -1
  204. package/codeyam-cli/src/webserver/build/client/assets/{git-D62Lxxmv.js → git-CZu4fif0.js} +2 -2
  205. package/codeyam-cli/src/webserver/build/client/assets/globals-wHVy_II5.css +1 -0
  206. package/codeyam-cli/src/webserver/build/client/assets/{index-CzNNiTkw.js → index-B1h680n5.js} +1 -1
  207. package/codeyam-cli/src/webserver/build/client/assets/{index-BosqDOlH.js → index-lzqtyFU8.js} +1 -1
  208. package/codeyam-cli/src/webserver/build/client/assets/{loader-circle-CNp9QFCX.js → loader-circle-B7B9V-bu.js} +1 -1
  209. package/codeyam-cli/src/webserver/build/client/assets/{manifest-09d684be.js → manifest-2d191949.js} +1 -1
  210. package/codeyam-cli/src/webserver/build/client/assets/root-FHgpM6gc.js +56 -0
  211. package/codeyam-cli/src/webserver/build/client/assets/{search-DDGjYAMJ.js → search-CxXUmBSd.js} +1 -1
  212. package/codeyam-cli/src/webserver/build/client/assets/{settings-DgTyB-Wg.js → settings-6D8k8Jp5.js} +1 -1
  213. package/codeyam-cli/src/webserver/build/client/assets/simulations-CDJZnWhN.js +1 -0
  214. package/codeyam-cli/src/webserver/build/client/assets/{triangle-alert-CBc5dE1s.js → triangle-alert-B6LgvRJg.js} +1 -1
  215. package/codeyam-cli/src/webserver/build/client/assets/{useCustomSizes-BMIGFP-m.js → useCustomSizes-Dv18q8LD.js} +1 -1
  216. package/codeyam-cli/src/webserver/build/client/assets/{useInteractiveMode-Dk_FQqWJ.js → useInteractiveMode-0ToGk4K3.js} +1 -1
  217. package/codeyam-cli/src/webserver/build/client/assets/{useLastLogLine-BqPPNjAl.js → useLastLogLine-aSv48UbS.js} +1 -1
  218. package/codeyam-cli/src/webserver/build/client/assets/{useReportContext-DsJbgMY9.js → useReportContext-1BX144Eg.js} +1 -1
  219. package/codeyam-cli/src/webserver/build/client/assets/{useToast-DWHcCcl1.js → useToast-mBRpZPiu.js} +1 -1
  220. package/codeyam-cli/src/webserver/build/server/assets/{index-CV6i1S1A.js → index-pU0o5t1o.js} +1 -1
  221. package/codeyam-cli/src/webserver/build/server/assets/server-build-YzfkRwdn.js +178 -0
  222. package/codeyam-cli/src/webserver/build/server/index.js +1 -1
  223. package/codeyam-cli/src/webserver/build-info.json +5 -5
  224. package/codeyam-cli/templates/codeyam-setup-skill.md +138 -3
  225. package/codeyam-cli/templates/debug-codeyam.md +7 -2
  226. package/package.json +5 -5
  227. package/packages/ai/src/lib/astScopes/processExpression.js +13 -1
  228. package/packages/ai/src/lib/astScopes/processExpression.js.map +1 -1
  229. package/packages/ai/src/lib/checkAllAttributes.js +24 -9
  230. package/packages/ai/src/lib/checkAllAttributes.js.map +1 -1
  231. package/packages/ai/src/lib/dataStructure/ScopeDataStructure.js +94 -18
  232. package/packages/ai/src/lib/dataStructure/ScopeDataStructure.js.map +1 -1
  233. package/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/JavascriptFrameworkManager.js +2 -1
  234. package/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/JavascriptFrameworkManager.js.map +1 -1
  235. package/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/MuiManager.js +51 -23
  236. package/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/MuiManager.js.map +1 -1
  237. package/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/ReactFrameworkManager.js +70 -54
  238. package/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/ReactFrameworkManager.js.map +1 -1
  239. package/packages/ai/src/lib/dataStructure/helpers/cleanNonObjectFunctions.js +11 -0
  240. package/packages/ai/src/lib/dataStructure/helpers/cleanNonObjectFunctions.js.map +1 -1
  241. package/packages/ai/src/lib/dataStructure/helpers/convertNullToUndefinedBySchema.js +86 -0
  242. package/packages/ai/src/lib/dataStructure/helpers/convertNullToUndefinedBySchema.js.map +1 -0
  243. package/packages/ai/src/lib/deepEqual.js +32 -0
  244. package/packages/ai/src/lib/deepEqual.js.map +1 -0
  245. package/packages/ai/src/lib/findMatchingAttribute.js +20 -16
  246. package/packages/ai/src/lib/findMatchingAttribute.js.map +1 -1
  247. package/packages/ai/src/lib/gatherRelevantDependentKeyAttributes.js +168 -41
  248. package/packages/ai/src/lib/gatherRelevantDependentKeyAttributes.js.map +1 -1
  249. package/packages/ai/src/lib/generateChangesEntityKeyAttributes.js +42 -1
  250. package/packages/ai/src/lib/generateChangesEntityKeyAttributes.js.map +1 -1
  251. package/packages/ai/src/lib/generateChangesEntityScenarioData.js +59 -3
  252. package/packages/ai/src/lib/generateChangesEntityScenarioData.js.map +1 -1
  253. package/packages/ai/src/lib/generateChangesEntityScenarios.js +6 -6
  254. package/packages/ai/src/lib/generateChangesEntityScenarios.js.map +1 -1
  255. package/packages/ai/src/lib/generateEntityScenarioData.js +32 -23
  256. package/packages/ai/src/lib/generateEntityScenarioData.js.map +1 -1
  257. package/packages/ai/src/lib/promptGenerators/generateChangesEntityScenariosGenerator.js +20 -1
  258. package/packages/ai/src/lib/promptGenerators/generateChangesEntityScenariosGenerator.js.map +1 -1
  259. package/packages/analyze/src/lib/FileAnalyzer.js +15 -0
  260. package/packages/analyze/src/lib/FileAnalyzer.js.map +1 -1
  261. package/packages/analyze/src/lib/asts/nodes/index.js +1 -0
  262. package/packages/analyze/src/lib/asts/nodes/index.js.map +1 -1
  263. package/packages/analyze/src/lib/asts/nodes/isAsyncFunction.js +52 -0
  264. package/packages/analyze/src/lib/asts/nodes/isAsyncFunction.js.map +1 -0
  265. package/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.js +59 -50
  266. package/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.js.map +1 -1
  267. package/packages/analyze/src/lib/files/analyze/analyzeEntities.js +6 -0
  268. package/packages/analyze/src/lib/files/analyze/analyzeEntities.js.map +1 -1
  269. package/packages/analyze/src/lib/files/analyze/findOrCreateEntity.js +2 -0
  270. package/packages/analyze/src/lib/files/analyze/findOrCreateEntity.js.map +1 -1
  271. package/packages/analyze/src/lib/files/analyzeChange.js +14 -4
  272. package/packages/analyze/src/lib/files/analyzeChange.js.map +1 -1
  273. package/packages/analyze/src/lib/files/analyzeEntity.js +7 -6
  274. package/packages/analyze/src/lib/files/analyzeEntity.js.map +1 -1
  275. package/packages/analyze/src/lib/files/scenarios/enrichArrayTypesFromChildSignatures.js +44 -10
  276. package/packages/analyze/src/lib/files/scenarios/enrichArrayTypesFromChildSignatures.js.map +1 -1
  277. package/packages/analyze/src/lib/files/scenarios/enrichUnknownTypesFromSourceEquivalencies.js +85 -0
  278. package/packages/analyze/src/lib/files/scenarios/enrichUnknownTypesFromSourceEquivalencies.js.map +1 -0
  279. package/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.js +314 -52
  280. package/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.js.map +1 -1
  281. package/packages/analyze/src/lib/files/scenarios/generateChangesScenarios.js +97 -2
  282. package/packages/analyze/src/lib/files/scenarios/generateChangesScenarios.js.map +1 -1
  283. package/packages/analyze/src/lib/files/scenarios/generateDataStructure.js +88 -52
  284. package/packages/analyze/src/lib/files/scenarios/generateDataStructure.js.map +1 -1
  285. package/packages/analyze/src/lib/files/scenarios/generateScenarioData.js +26 -98
  286. package/packages/analyze/src/lib/files/scenarios/generateScenarioData.js.map +1 -1
  287. package/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.js +141 -75
  288. package/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.js.map +1 -1
  289. package/packages/aws/src/lib/ecs/ecsDefineContainer.js +2 -2
  290. package/packages/aws/src/lib/ecs/ecsDefineContainer.js.map +1 -1
  291. package/packages/aws/src/lib/ecs/ecsTaskFactory.js +17 -61
  292. package/packages/aws/src/lib/ecs/ecsTaskFactory.js.map +1 -1
  293. package/packages/generate/index.js +3 -0
  294. package/packages/generate/index.js.map +1 -1
  295. package/packages/generate/src/lib/componentScenarioPage/componentScenarioPageNext.js +16 -1
  296. package/packages/generate/src/lib/componentScenarioPage/componentScenarioPageNext.js.map +1 -1
  297. package/packages/generate/src/lib/componentScenarioPage/generateScenarioClientWrapper.js +189 -0
  298. package/packages/generate/src/lib/componentScenarioPage/generateScenarioClientWrapper.js.map +1 -0
  299. package/packages/generate/src/lib/componentScenarioPage/generateScenarioServerComponent.js +53 -0
  300. package/packages/generate/src/lib/componentScenarioPage/generateScenarioServerComponent.js.map +1 -0
  301. package/packages/generate/src/lib/scenarioComponentForServer.js +89 -0
  302. package/packages/generate/src/lib/scenarioComponentForServer.js.map +1 -0
  303. package/packages/github/src/lib/loadOrCreateCommit.js +10 -0
  304. package/packages/github/src/lib/loadOrCreateCommit.js.map +1 -1
  305. package/packages/github/src/lib/syncPrimaryBranch.js +3 -0
  306. package/packages/github/src/lib/syncPrimaryBranch.js.map +1 -1
  307. package/packages/process/index.js +3 -0
  308. package/packages/process/index.js.map +1 -0
  309. package/packages/process/src/GlobalProcessManager.js.map +1 -0
  310. package/{background/src/lib/process → packages/process/src}/ProcessManager.js +1 -1
  311. package/packages/process/src/ProcessManager.js.map +1 -0
  312. package/packages/process/src/index.js.map +1 -0
  313. package/packages/process/src/managedExecAsync.js.map +1 -0
  314. package/analyzer-template/process/INTEGRATION_COMPLETE.md +0 -333
  315. package/analyzer-template/process/INTEGRATION_EXAMPLE.md +0 -525
  316. package/analyzer-template/process/README.md +0 -507
  317. package/background/src/lib/process/GlobalProcessManager.js.map +0 -1
  318. package/background/src/lib/process/ProcessManager.js.map +0 -1
  319. package/background/src/lib/process/index.js.map +0 -1
  320. package/background/src/lib/process/managedExecAsync.js.map +0 -1
  321. package/codeyam-cli/scripts/fixtures/cal.com/universal-mocks/packages/prisma/index.js +0 -238
  322. package/codeyam-cli/scripts/fixtures/cal.com/universal-mocks/packages/prisma/index.js.map +0 -1
  323. package/codeyam-cli/scripts/fixtures/formbricks/universal-mocks/apps/web/lib/instance/service.js +0 -7
  324. package/codeyam-cli/scripts/fixtures/formbricks/universal-mocks/apps/web/lib/instance/service.js.map +0 -1
  325. package/codeyam-cli/src/webserver/build/client/assets/ScenarioViewer-CUxUNEEC.js +0 -15
  326. package/codeyam-cli/src/webserver/build/client/assets/_index-DHImXdXq.js +0 -11
  327. package/codeyam-cli/src/webserver/build/client/assets/activity.(_tab)-2mG6mjVb.js +0 -32
  328. package/codeyam-cli/src/webserver/build/client/assets/chunk-JMJ3UQ3L-BambyYE_.js +0 -51
  329. package/codeyam-cli/src/webserver/build/client/assets/entity._sha.scenarios._scenarioId.fullscreen-DyB90fWk.js +0 -1
  330. package/codeyam-cli/src/webserver/build/client/assets/globals-C6vQASxy.css +0 -1
  331. package/codeyam-cli/src/webserver/build/client/assets/root-BxJUvKau.js +0 -56
  332. package/codeyam-cli/src/webserver/build/client/assets/simulations-CoNWGt0K.js +0 -1
  333. package/codeyam-cli/src/webserver/build/server/assets/server-build-BDlyhfrv.js +0 -175
  334. /package/analyzer-template/{process → packages/process/src}/GlobalProcessManager.ts +0 -0
  335. /package/analyzer-template/{process → packages/process/src}/ProcessManager.ts +0 -0
  336. /package/analyzer-template/{process → packages/process/src}/index.ts +0 -0
  337. /package/analyzer-template/{process → packages/process/src}/managedExecAsync.ts +0 -0
  338. /package/{background/src/lib/process → packages/process/src}/GlobalProcessManager.js +0 -0
  339. /package/{background/src/lib/process → packages/process/src}/index.js +0 -0
  340. /package/{background/src/lib/process → packages/process/src}/managedExecAsync.js +0 -0
@@ -1,12 +1,93 @@
1
1
  import { joinParenthesesAndArrays, splitOutsideParenthesesAndArrays, functionArguments, cleanOutBoundary, fillInDirectSchemaGapsAndUnknowns, removeDuplicateFunctionCalls, } from "../../../../../packages/ai/index.js";
2
2
  /**
3
- * Converts a variable qualifier to a safe identifier for use in function/const names.
4
- * Handles indexed format like "data[1]" -> "data_1"
3
+ * Converts a call signature to a valid JavaScript identifier (function name).
4
+ * The original signature is preserved for data access - this only creates the function name.
5
+ *
6
+ * Examples:
7
+ * - "useAuth()" → "useAuth"
8
+ * - "db.select(usersQuery)" → "db_select_usersQuery"
9
+ * - "db.select(postsQuery)" → "db_select_postsQuery"
10
+ * - "useFetcher<User>()" → "useFetcher_User"
11
+ * - "useFetcher<{ data: UserData | null }>()" → "useFetcher_data_UserData_null"
12
+ * - "eq('user_id', value)" → "eq_user_id_value"
13
+ * - "from('workouts')" → "from_workouts"
5
14
  */
6
- function safeVariableQualifier(qualifier) {
7
- // Replace brackets with underscores for valid JS identifier
8
- // "data[1]" -> "data_1"
9
- return qualifier.replace(/\[(\d+)\]/g, '_$1');
15
+ function callSignatureToFunctionName(signature) {
16
+ // Extract components from the signature
17
+ const components = [];
18
+ // 1. Extract function path (parts separated by dots outside parens/brackets)
19
+ const pathMatch = signature.match(/^([^<(]+)/);
20
+ if (pathMatch) {
21
+ const path = pathMatch[1];
22
+ // Split on dots but preserve the parts
23
+ components.push(...path.split('.').filter(Boolean));
24
+ }
25
+ // 2. Extract generic type parameters (content between < and >)
26
+ const genericMatch = signature.match(/<([^>]+)>/);
27
+ if (genericMatch) {
28
+ const genericContent = genericMatch[1];
29
+ // Extract meaningful identifiers from generic type
30
+ // Handle complex types like "{ data: UserData | null }"
31
+ const typeIdentifiers = genericContent
32
+ .replace(/[{}:;,]/g, ' ') // Remove structural chars
33
+ .replace(/\|/g, ' ') // Handle union types
34
+ .split(/\s+/)
35
+ .filter(Boolean)
36
+ .filter((s) => /^[A-Za-z_][A-Za-z0-9_]*$/.test(s)) // Only valid identifiers
37
+ .filter((s) => ![
38
+ 'null',
39
+ 'undefined',
40
+ 'void',
41
+ 'never',
42
+ 'any',
43
+ 'unknown',
44
+ 'data',
45
+ 'typeof',
46
+ ].includes(s)); // Skip common non-meaningful keywords
47
+ if (typeIdentifiers.length > 0) {
48
+ components.push(...typeIdentifiers.slice(0, 2)); // Limit to first 2 for reasonable length
49
+ }
50
+ }
51
+ // 3. Extract function arguments (first 2 for disambiguation)
52
+ const argsMatch = signature.match(/\(([^)]*)\)/);
53
+ if (argsMatch && argsMatch[1]) {
54
+ const argsContent = argsMatch[1].trim();
55
+ if (argsContent) {
56
+ const args = argsContent.split(',').map((arg) => arg.trim());
57
+ for (const arg of args.slice(0, 2)) {
58
+ // For quoted strings, extract the content
59
+ const stringMatch = arg.match(/^['"`](.+)['"`]$/);
60
+ if (stringMatch) {
61
+ // Split on dots for string paths like 'users.id'
62
+ const parts = stringMatch[1].split('.').filter(Boolean);
63
+ components.push(...parts);
64
+ }
65
+ else if (/^[A-Za-z_][A-Za-z0-9_]*$/.test(arg)) {
66
+ // Valid identifier - use as-is
67
+ components.push(arg);
68
+ }
69
+ else if (/^\d+$/.test(arg)) {
70
+ // Number - use as-is
71
+ components.push(arg);
72
+ }
73
+ // Skip complex expressions
74
+ }
75
+ }
76
+ }
77
+ // Build the function name from components
78
+ const functionName = components
79
+ .join('_')
80
+ .replace(/[^a-zA-Z0-9_]/g, '_') // Sanitize special chars
81
+ .replace(/_+/g, '_') // Collapse multiple underscores
82
+ .replace(/^_|_$/g, ''); // Trim underscores
83
+ return functionName || 'mock';
84
+ }
85
+ /**
86
+ * Check if a mock name is a call signature (e.g., "useFetcher<User>()", "db.select(query)")
87
+ */
88
+ function isCallSignature(mockName) {
89
+ // Call signatures contain parentheses (function calls)
90
+ return mockName.includes('(');
10
91
  }
11
92
  /**
12
93
  * Extract property names that are jsx-components and should be preserved from original.
@@ -134,23 +215,30 @@ function funcArgs(functionSignature) {
134
215
  }
135
216
  // isValidKey ensures that the key does not contain any characters that would make it invalid in a JavaScript object.
136
217
  // For example, it should not contain spaces, special characters, or start with a number.
218
+ // Also rejects keys that are pure function calls like "()" or "(args)" - these aren't property names.
137
219
  function isValidKey(key) {
138
220
  if (!key || key.length === 0)
139
221
  return false;
140
222
  const keyWithOutArguments = key.split('(')[0];
223
+ // Reject empty keys (happens when key is "()" or "(args)") - these are function calls, not property names
224
+ if (!keyWithOutArguments || keyWithOutArguments.length === 0)
225
+ return false;
141
226
  return !/\s/.test(keyWithOutArguments);
142
227
  }
143
- export default function constructMockCode(mockName, dependencySchemas, entityType, canonicalKey, options) {
144
- // Check for variable-qualified mock name (e.g., "entityDiffFetcher <- useFetcher")
145
- // Format: "variableName <- functionName" which reads naturally as "variableName receives from functionName"
146
- // Also handles indexed format: "data[1] <- useFetch" for disambiguating reused variable names
147
- const variableQualifierMatch = mockName.match(/^([a-zA-Z_][a-zA-Z0-9_]*(?:\[\d+\])?)\s*<-\s*/);
148
- let variableQualifier = variableQualifierMatch
149
- ? variableQualifierMatch[1]
228
+ export default function constructMockCode(mockName, dependencySchemas, entityType, _canonicalKey, // DEPRECATED: No longer used, kept for API compatibility
229
+ options) {
230
+ // Check if mockName is a call signature (e.g., "useFetcher<User>()", "db.select(query)")
231
+ const mockNameIsCallSignature = isCallSignature(mockName);
232
+ // For call signatures, use the original signature for data access but generate
233
+ // a valid JS function name from it
234
+ const derivedFunctionName = mockNameIsCallSignature
235
+ ? callSignatureToFunctionName(mockName)
150
236
  : null;
151
- const baseMockName = variableQualifier
152
- ? mockName.slice(variableQualifierMatch[0].length)
153
- : mockName;
237
+ // The baseMockName is the function name without type params and args
238
+ // e.g., "useFetcher<User>()" -> "useFetcher", "db.select(query)" -> "db"
239
+ const baseMockName = mockName.split(/[<(]/)[0];
240
+ // The data key is the mockName (call signature) for data access
241
+ let dataKey;
154
242
  const mockNameParts = splitOutsideParenthesesAndArrays(baseMockName);
155
243
  let relevantReturnValueSchema;
156
244
  let dataStructurePath;
@@ -159,26 +247,9 @@ export default function constructMockCode(mockName, dependencySchemas, entityTyp
159
247
  let signatureSchema;
160
248
  for (const filePath in dependencySchemas) {
161
249
  for (const entityName in dependencySchemas[filePath]) {
162
- // For variable-qualified mocks, look for the full qualified name first
163
- // Format: "variableName <- functionName" (e.g., "entityDiffFetcher <- useFetcher")
164
- const targetEntityName = variableQualifier
165
- ? `${variableQualifier} <- ${baseMockName}`
166
- : mockNameParts[0];
167
- // Check for direct match
168
- let matches = entityName === targetEntityName || entityName === mockNameParts[0];
169
- // If no direct match and no qualifier was provided, check if the entity
170
- // is stored under a variable-qualified key (e.g., "stateBadge <- getStateBadge")
171
- // This handles the case where gatherDataForMocks stored the entity with a variable
172
- // qualifier but writeScenarioComponents called constructMockCode without one.
173
- if (!matches && !variableQualifier) {
174
- const qualifiedKeyMatch = entityName.match(new RegExp(`^([a-zA-Z_][a-zA-Z0-9_]*)\\s*<-\\s*${mockNameParts[0]}$`));
175
- if (qualifiedKeyMatch) {
176
- matches = true;
177
- // Extract the variable qualifier from the entity name so we can use
178
- // it for the data lookup key later
179
- variableQualifier = qualifiedKeyMatch[1];
180
- }
181
- }
250
+ // Match entity by base name (without generics/args)
251
+ const entityBaseName = entityName.split(/[<(]/)[0];
252
+ const matches = entityBaseName === baseMockName || entityName === mockNameParts[0];
182
253
  if (!matches)
183
254
  continue;
184
255
  // Track if we found the entity and it has a signature (is a function)
@@ -210,6 +281,39 @@ export default function constructMockCode(mockName, dependencySchemas, entityTyp
210
281
  }
211
282
  }
212
283
  }
284
+ // Check if the entity is used as a function (called with ()) vs an object/namespace.
285
+ // Look for paths in the schema that start with "baseMockName(" or "baseMockName<" indicating function calls.
286
+ // The "<" handles generic type parameters like useLoaderData<T>().
287
+ // Also check dataStructurePath === 'returnValue' which indicates a function return value.
288
+ const entityIsFunction = foundEntityWithSignature ||
289
+ dataStructurePath === 'returnValue' ||
290
+ Object.keys(relevantReturnValueSchema ?? {}).some((key) => key.startsWith(`${baseMockName}(`) ||
291
+ key.startsWith(`${baseMockName}<`));
292
+ // Calculate the data key - use the call signature (mockName) for data access
293
+ // For simple names without parentheses:
294
+ // - Append () ONLY if the entity is a function/hook (detected above)
295
+ // - Don't append () for object/namespace mocks like "supabase"
296
+ if (mockNameIsCallSignature || mockName.includes('(')) {
297
+ dataKey = mockName;
298
+ }
299
+ else if (entityIsFunction) {
300
+ // Entity is a function/hook - append () to match call signature format
301
+ dataKey = `${mockName}()`;
302
+ }
303
+ else {
304
+ // Entity is an object/namespace - use bare name as key
305
+ dataKey = mockName;
306
+ }
307
+ // Helper to wrap key in appropriate quotes for computed property access
308
+ // Use single quotes when key contains double quotes to avoid syntax errors
309
+ const quotePropertyKey = (key) => {
310
+ const escaped = key.replace(/\n/g, '\\n');
311
+ if (escaped.includes('"')) {
312
+ // Use single quotes, escaping any single quotes in the key
313
+ return `['${escaped.replace(/'/g, "\\'")}']`;
314
+ }
315
+ return `["${escaped}"]`;
316
+ };
213
317
  // Check if the return value schema only contains function type markers
214
318
  // (e.g., "validateInputs()": "function") without actual return data
215
319
  // (no functionCallReturnValue entries)
@@ -232,6 +336,8 @@ export default function constructMockCode(mockName, dependencySchemas, entityTyp
232
336
  // Count the number of arguments from signature schema
233
337
  const argCount = Object.keys(signatureSchema).filter((key) => key.startsWith('signature[')).length;
234
338
  const args = Array.from({ length: argCount }, (_, i) => `arg${i + 1}`);
339
+ // Always add ...rest to accept extra arguments beyond the signature
340
+ args.push('...rest');
235
341
  const argsString = args.join(', ');
236
342
  // Generate empty mock function
237
343
  return `function ${mockName}(${argsString}) {
@@ -250,7 +356,33 @@ export default function constructMockCode(mockName, dependencySchemas, entityTyp
250
356
  !hasMeaningfulReturnData(relevantReturnValueSchema)) {
251
357
  const argCount = Object.keys(signatureSchema).filter((key) => key.startsWith('signature[')).length;
252
358
  const args = Array.from({ length: argCount }, (_, i) => `arg${i + 1}`);
359
+ // Always add ...rest to accept extra arguments beyond the signature
360
+ args.push('...rest');
253
361
  const argsString = args.join(', ');
362
+ // Check for Higher-Order Component (HOC) pattern:
363
+ // - First argument is a function (component) or unknown (couldn't trace type)
364
+ // - Returns a function
365
+ // HOCs like memo, forwardRef, createContext should return their first argument
366
+ //
367
+ // The return value key can be either:
368
+ // - 'memo()' (clean format)
369
+ // - 'memo(({ value, width }: Props) => { ... })' (full component code format)
370
+ const firstArgIsFunctionOrUnknown = signatureSchema['signature[0]'] === 'function' ||
371
+ signatureSchema['signature[0]'] === 'unknown';
372
+ const returnsFunction = relevantReturnValueSchema
373
+ ? Object.entries(relevantReturnValueSchema).some(([key, value]) => {
374
+ // Check if key represents a function call that returns a function
375
+ // Key should start with the mock name, contain '(', end with ')', and have value 'function'
376
+ const isFunctionCall = key.startsWith(mockName + '(') && key.endsWith(')');
377
+ return isFunctionCall && value === 'function';
378
+ })
379
+ : false;
380
+ if (firstArgIsFunctionOrUnknown && returnsFunction) {
381
+ // HOC pattern detected - return the first argument
382
+ return `function ${mockName}(${argsString}) {
383
+ return arg1;
384
+ }`;
385
+ }
254
386
  // Generate empty mock function
255
387
  return `function ${mockName}(${argsString}) {
256
388
  // Empty mock - original function mocked out
@@ -287,23 +419,19 @@ export default function constructMockCode(mockName, dependencySchemas, entityTyp
287
419
  // Strip type parameters like <typeof loader> from function names
288
420
  // so "useLoaderData<typeof loader>()" becomes "useLoaderData()"
289
421
  name = cleanOutTypes(name);
290
- // For root data access, use the canonical key if provided
291
- // Canonical keys use format: EntityName::hookName::index (e.g., "Dashboard::useLoaderData::0")
292
- if (isRootAccess && canonicalKey) {
293
- return `?.["${canonicalKey}"]`;
294
- }
295
- // Fallback for variable-qualified mocks when no canonical key provided
296
- // Format: "variableName <- functionName" (legacy format)
297
- if (isRootAccess && variableQualifier) {
298
- const baseName = name.replace(/\(\)$/, '');
299
- name = `${variableQualifier} <- ${baseName}`;
422
+ // For root data access, use the dataKey (original call signature or canonical key)
423
+ // This preserves the original call signature for LLM clarity
424
+ if (isRootAccess) {
425
+ // For call signature format, use the original mockName as the data key
426
+ // e.g., scenarios().data()?.["useFetcher<User>()"]
427
+ // e.g., scenarios().data()?.["db.select(usersQuery)"]
428
+ return `?.${quotePropertyKey(dataKey)}`;
300
429
  }
301
430
  // Only use unquoted array access syntax for pure array indices like [0], [1]
302
- // NOT for variable-qualified names like "fetcher[1] <- useFetcher" which need quotes
303
- if (name.match(/^\[\d+\]$/) && !name.includes(' <- ')) {
431
+ if (name.match(/^\[\d+\]$/)) {
304
432
  return `?.${name}`;
305
433
  }
306
- return `?.["${name.replace(/\n/g, '\\n')}"]`;
434
+ return `?.${quotePropertyKey(name)}`;
307
435
  };
308
436
  const constructDataPaths = () => {
309
437
  // For structural elements, return modified base paths for children
@@ -351,7 +479,17 @@ export default function constructMockCode(mockName, dependencySchemas, entityTyp
351
479
  };
352
480
  const constructContent = (dataPaths) => {
353
481
  const { name, args, nested, isArray, isGenericArray, returnsFunctionArgs, returnsFunctionArray, isAsyncFunction, hasNoReturnData, } = returnValue;
354
- const nestedContent = (nested ?? []).map((nestedItem) => {
482
+ // When an array has differentiated indices ([0], [1], etc.), filter out any
483
+ // non-index items from nested. These non-index items come from generic [] paths
484
+ // like [].filter or [].sort, which describe element properties, not array elements.
485
+ // Including them would generate invalid syntax like "sort: ..." inside an array literal.
486
+ const hasDifferentiatedIndices = isArray &&
487
+ nested &&
488
+ nested.some((n) => n.name.match(/^\[\d+\]$/) && n.name !== '[0]');
489
+ const filteredNested = hasDifferentiatedIndices && nested
490
+ ? nested.filter((n) => n.name.match(/^\[\d+\]$/))
491
+ : nested;
492
+ const nestedContent = (filteredNested ?? []).map((nestedItem) => {
355
493
  const nestedContent = constructReturnValueString(nestedItem, dataPaths);
356
494
  return nestedContent;
357
495
  });
@@ -425,52 +563,110 @@ export default function constructMockCode(mockName, dependencySchemas, entityTyp
425
563
  (!returnValue.isStructural || isStructuralArrayElementWithNested)) {
426
564
  levelContentItems.push(...dataPaths.map((path) => `...${path}`));
427
565
  }
428
- levelContentItems.push(...nestedContent);
566
+ // Filter out nested content that would be invalid as object properties
567
+ // (e.g., bare arrow functions like "() => {...}" without a property name)
568
+ // Only apply this filter when building object content, not array content.
569
+ // Bare arrow functions ARE valid as array elements (like [0] = {...}, [1] = () => {...})
570
+ // Check both isArray (item IS an array) and returnsFunctionArray (item returns an array)
571
+ const inArrayContext = isArray || returnsFunctionArray;
572
+ const validNestedContent = nestedContent.filter((content) => {
573
+ if (!content)
574
+ return false;
575
+ // Only filter bare arrow functions when NOT in array context
576
+ // In arrays, bare arrow functions are valid elements
577
+ if (!inArrayContext && content.match(/^\s*\([^)]*\)\s*=>/)) {
578
+ return false;
579
+ }
580
+ return true;
581
+ });
582
+ levelContentItems.push(...validNestedContent);
429
583
  let levelContents = levelContentItems.filter(Boolean).join(',\n');
430
584
  if (returnsFunctionArgs) {
431
- const argsString = returnsFunctionArgs
432
- .map((_, index) => `arg${index + 1}`)
433
- .join(', ');
434
- let funcContents = '';
435
- if (returnsFunctionArray) {
436
- if (hasNoReturnData) {
437
- // Function has no return data (only signatures) - return empty array
438
- funcContents = 'return []';
439
- }
440
- else if (levelContents.length === 0 && dataPaths.length === 1) {
441
- // When returning an array with no nested content, return the data path directly
442
- // (the data path points to the array in scenario data)
443
- funcContents = `return ${dataPaths[0]}`;
444
- }
445
- else if (levelContents.length === 0) {
446
- funcContents = 'return []';
447
- }
448
- else {
449
- funcContents = `return [\n${indent(levelContents)}\n]`;
585
+ // When returnsFunctionArgs is empty [] OR has a single literal string argument,
586
+ // the function returns a callable function (e.g., getTranslate() returns t,
587
+ // where t('key') looks up translations)
588
+ // Generate a dispatch function that looks up keys based on the argument
589
+ //
590
+ // Detect translation-like pattern:
591
+ // - Data path ends with ["('some.literal')"] - a literal string key
592
+ // - This means the mock data has keys like "('common.surveys')": "Surveys"
593
+ // - Exclude ["()"] which is an empty function call (not a translation pattern)
594
+ const dataPath = dataPaths[0];
595
+ // Pattern matches ?.["('...')"] at end of path, but NOT ?.["()"] (empty args)
596
+ const literalKeyPattern = dataPath?.match(/\?\.\["\('.+'\)"\]$/);
597
+ if (!returnsFunctionArray &&
598
+ dataPaths.length === 1 &&
599
+ literalKeyPattern // Only dispatch when there's a literal key pattern
600
+ ) {
601
+ // Function returns a function - generate dispatch function
602
+ // Strip the literal key from the path and use dynamic lookup
603
+ const dataPathBase = literalKeyPattern
604
+ ? dataPath.replace(/\?\.\["\('.+'\)"\]$/, '')
605
+ : dataPath;
606
+ const funcContents = `return ${dataPathBase}?.[\`('\${arg1}')\`]`;
607
+ levelContents = `(arg1) => {\n${indent(funcContents)}\n}`;
608
+ if (!isArray) {
609
+ return levelContents;
450
610
  }
451
611
  }
452
612
  else {
453
- // Check if function has no actual return data (only signatures)
454
- const hasNestedItems = nested && nested.length > 0;
455
- const hasActualNestedContent = nestedContent.filter(Boolean).length > 0;
456
- if (levelContentItems.length === 1 && dataPaths.length === 1) {
457
- if (hasNoReturnData ||
458
- (hasNestedItems && !hasActualNestedContent)) {
613
+ const argsString = returnsFunctionArgs
614
+ .map((_, index) => `arg${index + 1}`)
615
+ .join(', ');
616
+ let funcContents = '';
617
+ if (returnsFunctionArray) {
618
+ if (hasNoReturnData) {
459
619
  // Function has no return data (only signatures) - return empty array
460
620
  funcContents = 'return []';
461
621
  }
462
- else {
463
- // Has return data - return data path
622
+ else if (levelContents.length === 0 && dataPaths.length === 1) {
623
+ // When returning an array with no nested content, return the data path directly
624
+ // (the data path points to the array in scenario data)
464
625
  funcContents = `return ${dataPaths[0]}`;
465
626
  }
627
+ else if (levelContents.length === 0) {
628
+ funcContents = 'return []';
629
+ }
630
+ else {
631
+ funcContents = `return [\n${indent(levelContents)}\n]`;
632
+ }
466
633
  }
467
634
  else {
468
- funcContents = `return {\n${indent(levelContents)}\n}`;
635
+ // Check if function has no actual return data (only signatures)
636
+ const hasNestedItems = nested && nested.length > 0;
637
+ const hasActualNestedContent = nestedContent.filter(Boolean).length > 0;
638
+ if (levelContentItems.length === 1 && dataPaths.length === 1) {
639
+ if (hasNoReturnData ||
640
+ (hasNestedItems && !hasActualNestedContent)) {
641
+ // Function has no return data (only signatures) - return empty array
642
+ funcContents = 'return []';
643
+ }
644
+ else {
645
+ // Has return data - return data path
646
+ funcContents = `return ${dataPaths[0]}`;
647
+ }
648
+ }
649
+ else {
650
+ funcContents = `return {\n${indent(levelContents)}\n}`;
651
+ }
652
+ }
653
+ levelContents = `(${argsString}) => {\n${indent(funcContents)}\n}`;
654
+ if (!isArray) {
655
+ return levelContents;
469
656
  }
470
657
  }
471
- levelContents = `(${argsString}) => {\n${indent(funcContents)}\n}`;
472
- if (!isArray) {
473
- return levelContents;
658
+ // For generic arrays of functions WITH nested properties (e.g., functionCallReturnValue[] = "function"
659
+ // with nested .filter, .sort, etc.), the levelContents would be a bare arrow function "() => {...}"
660
+ // that wraps object content. Using this in a .map(({...})) creates invalid syntax like "({ () => {...} })".
661
+ // When isGenericArray is true AND there are nested properties, we're accessing data from the elements,
662
+ // not calling them - so skip the function wrapping.
663
+ // But if there are NO nested properties, keep the wrapper because callers may want to call the elements.
664
+ const hasNonStructuralNestedItems = nested &&
665
+ nested.length > 0 &&
666
+ nested.some((n) => !n.name.match(/^\[\d*\]$/));
667
+ if (isGenericArray && hasNonStructuralNestedItems) {
668
+ // Skip the arrow function wrapper - just use the nested content directly
669
+ levelContents = levelContentItems.filter(Boolean).join(',\n');
474
670
  }
475
671
  }
476
672
  // Check if all nested items are array prototype methods
@@ -516,14 +712,314 @@ export default function constructMockCode(mockName, dependencySchemas, entityTyp
516
712
  // Get the array base path (without the [0])
517
713
  const arrayBasePath = dataPaths[0].replace(/\?\.\[0\]$/, '');
518
714
  // Replace [0] references with [__idx__] in level contents
519
- const mappedContents = levelContents.replace(/\?\.\[0\]/g, '?.[__idx__]');
715
+ let mappedContents = levelContents.replace(/\?\.\[0\]/g, '?.[__idx__]');
520
716
  // levelContents may already be wrapped in {...} from structural [0] element,
521
717
  // so check if we need to add the wrapper or not
522
718
  const needsWrapper = !mappedContents.trim().startsWith('{');
719
+ // Helper to check if a position is inside a string literal
720
+ // Returns the end position of the string if inside one, -1 otherwise
721
+ // Defined here so it's accessible in both needsWrapper branches
722
+ const skipStringLiteral = (content, pos) => {
723
+ const char = content[pos];
724
+ if (char !== '"' && char !== "'" && char !== '`')
725
+ return -1;
726
+ // Find the matching closing quote
727
+ let j = pos + 1;
728
+ while (j < content.length) {
729
+ if (content[j] === '\\') {
730
+ j += 2; // Skip escaped character
731
+ continue;
732
+ }
733
+ if (content[j] === char) {
734
+ return j + 1; // Return position after closing quote
735
+ }
736
+ j++;
737
+ }
738
+ return content.length; // Unclosed string, skip to end
739
+ };
740
+ // Filter out bare arrow functions which are invalid as object properties.
741
+ // Arrow functions can be multi-line, so we need to match the entire function body, not just the first line.
742
+ // Pattern: starts with "(args) =>", followed by either:
743
+ // - A single-line body: "() => expression"
744
+ // - A multi-line body: "() => { ... }" (with matching braces)
745
+ // IMPORTANT: Only filter BARE arrow functions (without property names).
746
+ // "() => {...}" is invalid, but "get: (arg1) => {...}" is valid.
747
+ // We use a function to properly handle nested braces.
748
+ // Defined here so it's accessible in both needsWrapper branches
749
+ const filterOutArrowFunctions = (content) => {
750
+ const result = [];
751
+ let i = 0;
752
+ while (i < content.length) {
753
+ // Skip over string literals entirely
754
+ const stringEnd = skipStringLiteral(content, i);
755
+ if (stringEnd !== -1) {
756
+ result.push(content.slice(i, stringEnd));
757
+ i = stringEnd;
758
+ continue;
759
+ }
760
+ // Check if we're at the start of an arrow function (with optional leading whitespace)
761
+ const arrowMatch = content
762
+ .slice(i)
763
+ .match(/^(\s*)\([^)]*\)\s*=>\s*/);
764
+ if (arrowMatch) {
765
+ // Check if this is a bare arrow function or a named property with arrow function value
766
+ // Look back to see if there's a "key:" pattern before this position
767
+ const before = content.slice(0, i);
768
+ const beforeTrimmed = before.trim();
769
+ // Valid patterns where arrow function is NOT bare:
770
+ // 1. Property value: "key: (arg) => ..." - ends with ':'
771
+ // 2. Function argument: ".map((arg) => ..." - ends with '('
772
+ // NOTE: We don't include ',' because "{ prop, () => {} }" is invalid
773
+ // (can't distinguish function argument from object property context)
774
+ const isPropertyValue = beforeTrimmed.endsWith(':');
775
+ const isFunctionArg = beforeTrimmed.endsWith('(');
776
+ const hasPropertyName = isPropertyValue || isFunctionArg;
777
+ if (!hasPropertyName) {
778
+ // This is a bare arrow function - filter it out
779
+ // Found arrow function start, need to find its end
780
+ const afterArrow = i + arrowMatch[0].length;
781
+ if (content[afterArrow] === '{') {
782
+ // Multi-line arrow function - find matching closing brace
783
+ // Must respect string literals when counting braces
784
+ let braceCount = 1;
785
+ let j = afterArrow + 1;
786
+ while (j < content.length && braceCount > 0) {
787
+ const strEnd = skipStringLiteral(content, j);
788
+ if (strEnd !== -1) {
789
+ j = strEnd;
790
+ continue;
791
+ }
792
+ if (content[j] === '{')
793
+ braceCount++;
794
+ if (content[j] === '}')
795
+ braceCount--;
796
+ j++;
797
+ }
798
+ // Skip past the arrow function
799
+ i = j;
800
+ // Only skip trailing comma, keep newlines
801
+ while (i < content.length && content[i] === ' ') {
802
+ i++;
803
+ }
804
+ if (content[i] === ',') {
805
+ i++; // Skip the comma after the arrow function
806
+ }
807
+ }
808
+ else {
809
+ // Single expression arrow function - skip to next comma or newline
810
+ let j = afterArrow;
811
+ while (j < content.length &&
812
+ content[j] !== ',' &&
813
+ content[j] !== '\n') {
814
+ j++;
815
+ }
816
+ i = j;
817
+ if (content[i] === ',')
818
+ i++; // Skip the comma
819
+ }
820
+ continue;
821
+ }
822
+ }
823
+ // Not a bare arrow function, keep this character
824
+ result.push(content[i]);
825
+ i++;
826
+ }
827
+ return result.join('');
828
+ };
829
+ // Filter out bare object blocks (e.g., "{ ...spread, props }," without a property name)
830
+ // These are invalid in object literal context - you need "key: { ... }" not just "{ ... }"
831
+ // Defined here so it's accessible in both needsWrapper branches
832
+ // The skipFirstBrace parameter allows the else branch to preserve the outer object
833
+ const filterOutBareObjects = (content, skipFirstBrace = false) => {
834
+ const result = [];
835
+ let i = 0;
836
+ let firstBraceSkipped = false;
837
+ while (i < content.length) {
838
+ // Skip over string literals entirely - braces inside strings should not be processed
839
+ const stringEnd = skipStringLiteral(content, i);
840
+ if (stringEnd !== -1) {
841
+ result.push(content.slice(i, stringEnd));
842
+ i = stringEnd;
843
+ continue;
844
+ }
845
+ // Check if we're at a bare object start (newline/comma followed by { without : before it)
846
+ // Look back to see if there's a colon (property assignment) before this brace
847
+ const isStartOfLine = i === 0 ||
848
+ content[i - 1] === '\n' ||
849
+ content.slice(0, i).trim().endsWith(',');
850
+ if (content[i] === '{' && isStartOfLine) {
851
+ // Check if this is actually a bare object (not "key: {")
852
+ const beforeTrimmed = content.slice(0, i).trim();
853
+ const isBareObject = beforeTrimmed.endsWith(',') ||
854
+ beforeTrimmed === '' ||
855
+ beforeTrimmed.endsWith('(');
856
+ if (isBareObject) {
857
+ // If skipFirstBrace is true and this is the first bare brace at position 0,
858
+ // don't filter it - it's the intentional outer object wrapper
859
+ if (skipFirstBrace && !firstBraceSkipped && i === 0) {
860
+ firstBraceSkipped = true;
861
+ result.push(content[i]);
862
+ i++;
863
+ continue;
864
+ }
865
+ // Find matching closing brace, respecting string literals
866
+ let braceCount = 1;
867
+ let j = i + 1;
868
+ while (j < content.length && braceCount > 0) {
869
+ const strEnd = skipStringLiteral(content, j);
870
+ if (strEnd !== -1) {
871
+ j = strEnd;
872
+ continue;
873
+ }
874
+ if (content[j] === '{')
875
+ braceCount++;
876
+ if (content[j] === '}')
877
+ braceCount--;
878
+ j++;
879
+ }
880
+ // Skip past the object
881
+ i = j;
882
+ // Skip trailing comma
883
+ while (i < content.length && content[i] === ' ') {
884
+ i++;
885
+ }
886
+ if (content[i] === ',') {
887
+ i++;
888
+ }
889
+ continue;
890
+ }
891
+ }
892
+ result.push(content[i]);
893
+ i++;
894
+ }
895
+ return result.join('');
896
+ };
897
+ // Helper to clean up formatting issues after filtering
898
+ const cleanupContent = (content) => {
899
+ return (content
900
+ .replace(/,\s*,/g, ',') // Double commas
901
+ .replace(/,(\s*\n\s*\})/g, '$1') // Trailing comma before closing brace
902
+ .replace(/\{\s*\n\s*,/g, '{\n') // Leading comma after opening brace
903
+ // Remove incomplete .map calls where callback was filtered out
904
+ // Pattern: ".map" followed by newline/whitespace without "(" for args
905
+ .replace(/\?\.map(?=\s*[\n\r,}\]])/g, '')
906
+ .replace(/\.map(?=\s*[\n\r,}\]])/g, '')
907
+ // Clean up orphan })) sequences (from nested filtered map callbacks)
908
+ .replace(/\s*\}\)\)\s*\n\s*\}/g, '\n}')
909
+ .replace(/^\s*\n/gm, '') // Empty lines
910
+ .trim());
911
+ };
523
912
  if (needsWrapper) {
524
- returnValueContents = `${arrayBasePath}?.map((__item__, __idx__) => ({\n${indent(mappedContents)}\n}))`;
913
+ // Apply filters to remove invalid content
914
+ mappedContents = filterOutArrowFunctions(mappedContents);
915
+ mappedContents = filterOutBareObjects(mappedContents);
916
+ mappedContents = cleanupContent(mappedContents);
917
+ // If mappedContents is empty after filtering, don't generate .map() at all
918
+ // Just use the array path directly with spread or as-is
919
+ // This prevents orphan )) from empty .map() callbacks
920
+ const cleanedForEmptyCheck = mappedContents
921
+ .replace(/\s+/g, '')
922
+ .replace(/,+/g, '');
923
+ if (cleanedForEmptyCheck.length === 0) {
924
+ // Content is empty - just return the array directly
925
+ returnValueContents = arrayBasePath;
926
+ }
927
+ else {
928
+ // Check if mappedContents is just a bare expression (no property names)
929
+ // A bare expression like "scenarios().data()?.["key"]?.[__idx__]," cannot be
930
+ // wrapped in ({ }) because it's not a valid object property.
931
+ // Pattern: content has no ":" that's not inside brackets/parens/strings
932
+ const hasBareExpression = (() => {
933
+ const trimmed = mappedContents.trim().replace(/,\s*$/, ''); // Remove trailing comma
934
+ let depth = 0;
935
+ let inString = false;
936
+ let stringChar = '';
937
+ for (let i = 0; i < trimmed.length; i++) {
938
+ const char = trimmed[i];
939
+ if (inString) {
940
+ if (char === '\\') {
941
+ i++; // Skip escaped char
942
+ continue;
943
+ }
944
+ if (char === stringChar) {
945
+ inString = false;
946
+ }
947
+ continue;
948
+ }
949
+ if (char === '"' || char === "'" || char === '`') {
950
+ inString = true;
951
+ stringChar = char;
952
+ continue;
953
+ }
954
+ if (char === '(' || char === '[' || char === '{') {
955
+ depth++;
956
+ continue;
957
+ }
958
+ if (char === ')' || char === ']' || char === '}') {
959
+ depth--;
960
+ continue;
961
+ }
962
+ // Found a colon at depth 0 = has property name
963
+ if (char === ':' && depth === 0) {
964
+ return false;
965
+ }
966
+ }
967
+ return true;
968
+ })();
969
+ if (hasBareExpression) {
970
+ // Content is just an expression - return it directly without object wrapper
971
+ const trimmedContent = mappedContents
972
+ .trim()
973
+ .replace(/,\s*$/, '');
974
+ returnValueContents = `${arrayBasePath}?.map((__item__, __idx__) => (\n${indent(trimmedContent)}\n))`;
975
+ }
976
+ else {
977
+ returnValueContents = `${arrayBasePath}?.map((__item__, __idx__) => ({\n${indent(mappedContents)}\n}))`;
978
+ }
979
+ } // Close the empty content check else block
525
980
  }
526
981
  else {
982
+ // Content already starts with '{'. Check if there are additional properties after the inner object.
983
+ // If so, we need to merge them INTO the object, not leave them outside.
984
+ // Pattern: "{ ...spread, props },\nfilter: ...,\nsort: ..."
985
+ // Should become: "{ ...spread, props, filter: ..., sort: ... }"
986
+ const trimmed = mappedContents.trim();
987
+ // Find first }, that is NOT inside a string literal
988
+ // This prevents splitting keys like ?.["useQuery({ id }, { enabled })"]
989
+ const findBraceCommaOutsideStrings = (content) => {
990
+ let i = 0;
991
+ while (i < content.length - 1) {
992
+ // Skip over string literals
993
+ const strEnd = skipStringLiteral(content, i);
994
+ if (strEnd !== -1) {
995
+ i = strEnd;
996
+ continue;
997
+ }
998
+ // Check for }, pattern
999
+ if (content[i] === '}' && content[i + 1] === ',') {
1000
+ return i;
1001
+ }
1002
+ i++;
1003
+ }
1004
+ return -1;
1005
+ };
1006
+ const firstBraceEnd = findBraceCommaOutsideStrings(trimmed);
1007
+ if (firstBraceEnd !== -1) {
1008
+ // Found pattern "{ ... }," followed by more content
1009
+ // Extract the inner object and the trailing properties
1010
+ const innerObject = trimmed.slice(0, firstBraceEnd);
1011
+ const trailingContent = trimmed.slice(firstBraceEnd + 2).trim();
1012
+ if (trailingContent) {
1013
+ // Merge trailing properties into the inner object
1014
+ mappedContents = `${innerObject},\n${trailingContent}\n}`;
1015
+ }
1016
+ }
1017
+ // Even when content starts with {, we need to filter out invalid properties inside
1018
+ // (arrow functions and bare objects that were generated from the schema)
1019
+ // Pass skipFirstBrace=true because the content's outer { is the intentional wrapper
1020
+ mappedContents = filterOutArrowFunctions(mappedContents);
1021
+ mappedContents = filterOutBareObjects(mappedContents, true);
1022
+ mappedContents = cleanupContent(mappedContents);
527
1023
  returnValueContents = `${arrayBasePath}?.map((__item__, __idx__) => (\n${indent(mappedContents)}\n))`;
528
1024
  }
529
1025
  }
@@ -608,7 +1104,18 @@ export default function constructMockCode(mockName, dependencySchemas, entityTyp
608
1104
  }
609
1105
  else {
610
1106
  // No argument variants - use existing behavior
611
- const funcContents = `return ${returnValueContents}`;
1107
+ // But if there's nested content, we need to include it in the return object
1108
+ // (similar to how argument variant branches handle this at line 1070-1072)
1109
+ const hasNestedContent = validNestedContent.length > 0;
1110
+ let funcReturnContents;
1111
+ if (hasNestedContent && levelContentItems.length > 1) {
1112
+ // Include both spread and nested content in the return
1113
+ funcReturnContents = `{\n${indent(levelContents)}\n}`;
1114
+ }
1115
+ else {
1116
+ funcReturnContents = returnValueContents;
1117
+ }
1118
+ const funcContents = `return ${funcReturnContents}`;
612
1119
  content = `${cleanOutTypes(name)}: ${isAsyncFunction ? 'async ' : ''}(${argsString}) => {\n${indent(funcContents)}\n}`;
613
1120
  }
614
1121
  }
@@ -617,8 +1124,14 @@ export default function constructMockCode(mockName, dependencySchemas, entityTyp
617
1124
  return;
618
1125
  }
619
1126
  else if (name.match(/\[\d*\]/)) {
1127
+ // Numeric array index like [0], [1] - can be used as computed property
620
1128
  content = returnValueContents;
621
1129
  }
1130
+ else if (name.match(/^\[[a-zA-Z_]\w*\]$/)) {
1131
+ // Variable-based index like [currentItemIndex] - must be quoted string key
1132
+ // Otherwise JavaScript would try to evaluate the variable name
1133
+ content = `"${safeString(name)}": ${returnValueContents}`;
1134
+ }
622
1135
  else {
623
1136
  content = `${safeString(name)}: ${returnValueContents}`;
624
1137
  }
@@ -681,8 +1194,8 @@ export default function constructMockCode(mockName, dependencySchemas, entityTyp
681
1194
  parts.splice(i, 1);
682
1195
  }
683
1196
  }
684
- // For variable-qualified mocks like "revalidator <- useRevalidator",
685
- // compare against baseMockName ("useRevalidator"), not the full mockName
1197
+ // Compare against baseMockName (without generics/args), not the full mockName
1198
+ // e.g., for "useFetcher<User>()", baseMockName is "useFetcher"
686
1199
  if (parts[0].split('(')[0] !== baseMockName)
687
1200
  continue;
688
1201
  // Include paths with functionCallReturnValue OR function-typed paths that need mocking
@@ -778,6 +1291,16 @@ export default function constructMockCode(mockName, dependencySchemas, entityTyp
778
1291
  const nextIsArray = !!nextPart?.match(/^\[\d*\]/);
779
1292
  const isDifferentiatedArray = !!part?.match(/^\[\d+\]/);
780
1293
  const nextIsDifferentiatedArray = !!nextPart?.match(/^\[\d+\]/);
1294
+ // Variable index patterns like [currentItemIndex] or [targetIndex] indicate array access
1295
+ // but don't represent actual data structure - they're markers from variable-based index tracking.
1296
+ // Skip them AND all remaining parts to avoid creating spurious nested structure that breaks array iteration.
1297
+ // The remaining parts (e.g., .missing_attributes) describe properties of array elements, which are
1298
+ // already handled by the generic [] accessor path.
1299
+ const isVariableIndex = !!part?.match(/^\[[a-zA-Z_]\w*\]$/);
1300
+ if (isVariableIndex) {
1301
+ // Break out of the loop entirely - don't process any remaining parts
1302
+ break;
1303
+ }
781
1304
  // Find the correct value for the current part being processed
782
1305
  let partValue = value; // default to the final value
783
1306
  if (isFunctionCallReturnValue(part) && nextIsArray) {
@@ -869,7 +1392,35 @@ export default function constructMockCode(mockName, dependencySchemas, entityTyp
869
1392
  }
870
1393
  }
871
1394
  else {
872
- returnValueSection.returnsFunctionArgs = [];
1395
+ // Before setting returnsFunctionArgs on the parent (for generic [] = function),
1396
+ // check if there are specific array indices (like [0], [1]) that are NOT functions.
1397
+ // If so, don't set returnsFunctionArgs because those specific indices take precedence.
1398
+ // This prevents adding ["()"] to paths like [0] when [0] is 'unknown' but [] is 'function'.
1399
+ //
1400
+ // Use parts.slice(0, i + 1) to get the current path INCLUDING functionCallReturnValue.
1401
+ // For example, if parts = ['useAtom()','functionCallReturnValue','[]']
1402
+ // and i = 1, we want to check 'useAtom().functionCallReturnValue[0]' etc.
1403
+ const arrayContainerPath = joinParenthesesAndArrays(parts.slice(0, i + 1));
1404
+ const hasNonFunctionSpecificIndices = Object.entries(relevantReturnValueSchema).some(([k, v]) => {
1405
+ // Look for paths like "arrayContainerPath[0]", "arrayContainerPath[1]" etc.
1406
+ const indexMatch = k.match(new RegExp(`^${arrayContainerPath.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\[(\\d+)\\]$`));
1407
+ // If found and it's NOT a function type, we have a conflict
1408
+ return (indexMatch &&
1409
+ !['function', 'async-function'].includes(v));
1410
+ });
1411
+ // Also check if [] has nested object properties (like [].filter, [].name)
1412
+ // If so, [] items are objects with properties, not pure functions to be called
1413
+ // This handles cases where the schema shows [].filter = object but doesn't
1414
+ // have explicit [0] entries
1415
+ const genericArrayPath = `${arrayContainerPath}[]`;
1416
+ const hasNestedProperties = Object.keys(relevantReturnValueSchema).some((k) => {
1417
+ // Check for paths like "arrayContainerPath[].propertyName" (not [].())
1418
+ return (k.startsWith(genericArrayPath + '.') &&
1419
+ !k.startsWith(genericArrayPath + '.('));
1420
+ });
1421
+ if (!hasNonFunctionSpecificIndices && !hasNestedProperties) {
1422
+ returnValueSection.returnsFunctionArgs = [];
1423
+ }
873
1424
  }
874
1425
  }
875
1426
  }
@@ -890,7 +1441,8 @@ export default function constructMockCode(mockName, dependencySchemas, entityTyp
890
1441
  }
891
1442
  // If the next part is an object with nested content, continue processing
892
1443
  // This handles paths like functionCallReturnValue.selectedOptions.elementOptions[]
893
- if (nextValue === 'object' || nextValue === 'array') {
1444
+ // Also handles union types like 'array | undefined' or 'object | undefined'
1445
+ if (nextValue?.includes('object') || nextValue?.includes('array')) {
894
1446
  continue;
895
1447
  }
896
1448
  }
@@ -1020,7 +1572,12 @@ export default function constructMockCode(mockName, dependencySchemas, entityTyp
1020
1572
  relevantPart.isArray = true;
1021
1573
  relevantPart.isGenericArray = true;
1022
1574
  }
1023
- if (!hasNestedFunction) {
1575
+ // Check if there are remaining parts after functionCallReturnValue that need processing
1576
+ // (e.g., data properties like useQuery().functionCallReturnValue.data)
1577
+ const hasRemainingPartsAfterReturnValue = nextPart &&
1578
+ (isFunctionCallReturnValue(nextPart) ||
1579
+ (isFunctionCallReturnValue(parts[i]) && i < parts.length - 1));
1580
+ if (!hasNestedFunction && !hasRemainingPartsAfterReturnValue) {
1024
1581
  // Before breaking, check if this function returns an array
1025
1582
  // by looking for a functionCallReturnValue: 'array' entry in the schema
1026
1583
  if (relevantPart && part.endsWith(')')) {
@@ -1048,6 +1605,7 @@ export default function constructMockCode(mockName, dependencySchemas, entityTyp
1048
1605
  const contents = constructReturnValueString(returnValueParts);
1049
1606
  if (mockNameParts.length > 1) {
1050
1607
  const originalLib = `${mockNameParts[0]}__cyOriginal`;
1608
+ const skipOriginalSpread = options?.skipOriginalSpread;
1051
1609
  const subPart = (parts, originalLib) => {
1052
1610
  const part = parts.shift();
1053
1611
  if (!isValidKey(part))
@@ -1055,7 +1613,9 @@ export default function constructMockCode(mockName, dependencySchemas, entityTyp
1055
1613
  const isLast = parts.length === 0;
1056
1614
  const partContents = isLast
1057
1615
  ? contents
1058
- : `...${originalLib}.${part},\n${subPart(parts, originalLib)}`;
1616
+ : skipOriginalSpread
1617
+ ? subPart(parts, originalLib)
1618
+ : `...${originalLib}.${part},\n${subPart(parts, originalLib)}`;
1059
1619
  let code = `${part}: {\n${indent(partContents)}\n}`;
1060
1620
  if (part.includes('(') || (isFunction && isLast)) {
1061
1621
  const args = funcArgs(part)
@@ -1065,28 +1625,30 @@ export default function constructMockCode(mockName, dependencySchemas, entityTyp
1065
1625
  }
1066
1626
  return code;
1067
1627
  };
1068
- const returnParts = [
1069
- `...${mockNameParts[0]}__cyOriginal`,
1070
- subPart(mockNameParts.slice(1), originalLib),
1071
- ].filter(Boolean);
1072
- return `const ${mockNameParts[0]} = {\n${indent(returnParts.join(',\n'))}\n};`;
1628
+ const returnParts = skipOriginalSpread
1629
+ ? [subPart(mockNameParts.slice(1), originalLib)]
1630
+ : [
1631
+ `...${mockNameParts[0]}__cyOriginal`,
1632
+ subPart(mockNameParts.slice(1), originalLib),
1633
+ ];
1634
+ return `const ${mockNameParts[0]} = {\n${indent(returnParts.filter(Boolean).join(',\n'))}\n};`;
1073
1635
  }
1074
1636
  else if (isFunction) {
1075
1637
  // For headers() and cookies() from next/headers, add common iterator methods
1076
1638
  // These are needed when the mock is passed to functions that use .entries(), .keys(), etc.
1077
1639
  // (e.g., Object.fromEntries(headers.entries()) in buildLegacyHeaders)
1078
- const needsIteratorMethods = mockName === 'headers' || mockName === 'cookies';
1640
+ const needsIteratorMethods = baseMockName === 'headers' || baseMockName === 'cookies';
1079
1641
  let enhancedContents = contents;
1080
1642
  if (needsIteratorMethods && contents.trim().startsWith('{')) {
1081
1643
  // Add iterator methods that operate on the scenario data
1082
- // Use canonical key if provided, otherwise fall back to legacy format
1083
- const dataKey = canonicalKey || `${mockName}()`;
1644
+ // Use the dataKey (original call signature or canonical key)
1645
+ const quotedDataKey = quotePropertyKey(dataKey);
1084
1646
  const iteratorMethods = `,
1085
- entries: () => Object.entries(scenarios().data()?.["${dataKey}"] || {}),
1086
- keys: () => Object.keys(scenarios().data()?.["${dataKey}"] || {}),
1087
- values: () => Object.values(scenarios().data()?.["${dataKey}"] || {}),
1088
- forEach: (fn) => Object.entries(scenarios().data()?.["${dataKey}"] || {}).forEach(([k, v]) => fn(v, k)),
1089
- has: (key) => Object.prototype.hasOwnProperty.call(scenarios().data()?.["${dataKey}"] || {}, key)`;
1647
+ entries: () => Object.entries(scenarios().data()?.${quotedDataKey} || {}),
1648
+ keys: () => Object.keys(scenarios().data()?.${quotedDataKey} || {}),
1649
+ values: () => Object.values(scenarios().data()?.${quotedDataKey} || {}),
1650
+ forEach: (fn) => Object.entries(scenarios().data()?.${quotedDataKey} || {}).forEach(([k, v]) => fn(v, k)),
1651
+ has: (key) => Object.prototype.hasOwnProperty.call(scenarios().data()?.${quotedDataKey} || {}, key)`;
1090
1652
  // Insert before the closing brace (handle trailing whitespace)
1091
1653
  enhancedContents = contents.replace(/\}\s*$/, iteratorMethods + '\n}');
1092
1654
  }
@@ -1096,29 +1658,43 @@ export default function constructMockCode(mockName, dependencySchemas, entityTyp
1096
1658
  // `new ClassName("arg")` wouldn't create the expected instance.
1097
1659
  // For Error subclasses (detected by name ending in "Error"), extend Error for proper error handling.
1098
1660
  if (entityType === 'class') {
1099
- const isErrorSubclass = mockName.endsWith('Error');
1100
- const baseClass = isErrorSubclass ? 'Error' : 'Object';
1661
+ const isErrorSubclass = baseMockName.endsWith('Error');
1101
1662
  const superCall = isErrorSubclass ? 'super(message);' : '';
1102
1663
  const nameAssignment = isErrorSubclass
1103
- ? `this.name = '${mockName}';`
1664
+ ? `this.name = '${baseMockName}';`
1104
1665
  : '';
1105
- // Use canonical key if provided, otherwise fall back to legacy format
1106
- const dataKey = canonicalKey || `${mockName}()`;
1107
- return `class ${mockName}${isErrorSubclass ? ' extends Error' : ''} {
1666
+ // Use the safe function name for the class definition
1667
+ const className = mockNameIsCallSignature
1668
+ ? derivedFunctionName
1669
+ : baseMockName;
1670
+ return `class ${className}${isErrorSubclass ? ' extends Error' : ''} {
1108
1671
  constructor(message) {
1109
1672
  ${superCall}
1110
1673
  ${nameAssignment}
1111
- Object.assign(this, scenarios().data()?.["${dataKey}"] || {});
1674
+ Object.assign(this, scenarios().data()?.${quotePropertyKey(dataKey)} || {});
1112
1675
  }
1113
1676
  }`;
1114
1677
  }
1115
- // For variable-qualified mocks, use underscore separator in the function name
1116
- // e.g., "entityDiffFetcher <- useFetcher" becomes "useFetcher_entityDiffFetcher"
1117
- // For indexed qualifiers like "data[1]", convert to safe identifier: "useFetcher_data_1"
1118
- // EXCEPTION: When keepOriginalFunctionName is true (for single-call cases), use the base name
1119
- const safeFunctionName = variableQualifier && !options?.keepOriginalFunctionName
1120
- ? `${baseMockName}_${safeVariableQualifier(variableQualifier)}`
1121
- : baseMockName;
1678
+ // Generate safe function name:
1679
+ // 1. For call signatures: use derivedFunctionName
1680
+ // e.g., "useFetcher<User>()" becomes "useFetcher_User"
1681
+ // e.g., "db.select(usersQuery)" becomes "db_select_usersQuery"
1682
+ // 2. With uniqueFunctionSuffix option: append suffix for unique naming
1683
+ // e.g., baseMockName = "useFetcher", suffix = "entityDiffFetcher" -> "useFetcher_entityDiffFetcher"
1684
+ // 3. EXCEPTION: When keepOriginalFunctionName is true (for single-call cases), use the base name
1685
+ let safeFunctionName;
1686
+ if (options?.keepOriginalFunctionName) {
1687
+ safeFunctionName = baseMockName;
1688
+ }
1689
+ else if (options?.uniqueFunctionSuffix) {
1690
+ safeFunctionName = `${baseMockName}_${options.uniqueFunctionSuffix}`;
1691
+ }
1692
+ else if (mockNameIsCallSignature && derivedFunctionName) {
1693
+ safeFunctionName = derivedFunctionName;
1694
+ }
1695
+ else {
1696
+ safeFunctionName = baseMockName;
1697
+ }
1122
1698
  // Check if this function returns a function (detected by double-call pattern: mockName(args)())
1123
1699
  // This happens when the schema has keys like "wrapThrows(() => JSON.parse(savedFilters))()"
1124
1700
  // where the function call is immediately followed by another call.
@@ -1154,20 +1730,35 @@ export default function constructMockCode(mockName, dependencySchemas, entityTyp
1154
1730
  return true;
1155
1731
  return false;
1156
1732
  });
1733
+ // Use ...args to accept any number of arguments - prevents TypeScript errors
1734
+ // like "Expected 0 arguments, but got X" when caller passes arguments
1157
1735
  // For higher-order functions, wrap the return in an arrow function
1158
1736
  // so that mockFunc(arg)() works correctly (outer call returns a function, inner call gets the data)
1159
1737
  const returnValue = isHigherOrderFunction
1160
- ? `() => ${safeFunctionName}ReturnValue`
1161
- : `${safeFunctionName}ReturnValue`;
1162
- return `const ${safeFunctionName}ReturnValue = ${enhancedContents};\n\n${isRootAsyncFunction ? 'async ' : ''}function ${safeFunctionName}() {\n${indent(`return ${returnValue};`)}\n}`;
1738
+ ? `() => (${enhancedContents})`
1739
+ : enhancedContents;
1740
+ // Inline the return value directly in the function to avoid module-level const
1741
+ // that would be evaluated before scenario context is ready
1742
+ return `${isRootAsyncFunction ? 'async ' : ''}function ${safeFunctionName}(...args) {\n${indent(`return ${returnValue};`)}\n}`;
1163
1743
  }
1164
1744
  else {
1165
- // For variable-qualified mocks, use underscore separator in the const name
1166
- // For indexed qualifiers like "data[1]", convert to safe identifier: "useFetcher_data_1"
1167
- // EXCEPTION: When keepOriginalFunctionName is true (for single-call cases), use the base name
1168
- const safeName = variableQualifier && !options?.keepOriginalFunctionName
1169
- ? `${baseMockName}_${safeVariableQualifier(variableQualifier)}`
1170
- : baseMockName;
1745
+ // Generate safe const name:
1746
+ // 1. For call signatures: use derivedFunctionName
1747
+ // 2. With uniqueFunctionSuffix option: append suffix for unique naming
1748
+ // 3. EXCEPTION: When keepOriginalFunctionName is true (for single-call cases), use the base name
1749
+ let safeName;
1750
+ if (options?.keepOriginalFunctionName) {
1751
+ safeName = baseMockName;
1752
+ }
1753
+ else if (options?.uniqueFunctionSuffix) {
1754
+ safeName = `${baseMockName}_${options.uniqueFunctionSuffix}`;
1755
+ }
1756
+ else if (mockNameIsCallSignature && derivedFunctionName) {
1757
+ safeName = derivedFunctionName;
1758
+ }
1759
+ else {
1760
+ safeName = baseMockName;
1761
+ }
1171
1762
  // Get any jsx-component properties that need to be preserved from the original
1172
1763
  const jsxProperties = getJsxComponentProperties(mockName, relevantReturnValueSchema);
1173
1764
  // If there are jsx-component properties, add them as references to the original