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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (354) hide show
  1. package/analyzer-template/.build-info.json +7 -7
  2. package/analyzer-template/log.txt +3 -3
  3. package/analyzer-template/package.json +2 -1
  4. package/analyzer-template/packages/ai/src/lib/analyzeScope.ts +2 -0
  5. package/analyzer-template/packages/ai/src/lib/astScopes/astScopeAnalyzer.ts +22 -0
  6. package/analyzer-template/packages/ai/src/lib/astScopes/patterns/switchStatementHandler.ts +23 -1
  7. package/analyzer-template/packages/ai/src/lib/astScopes/processExpression.ts +401 -106
  8. package/analyzer-template/packages/ai/src/lib/astScopes/types.ts +60 -0
  9. package/analyzer-template/packages/ai/src/lib/dataStructure/ScopeDataStructure.ts +734 -45
  10. package/analyzer-template/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/JavascriptFrameworkManager.ts +2 -1
  11. package/analyzer-template/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/MuiManager.ts +715 -0
  12. package/analyzer-template/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/ReactFrameworkManager.ts +233 -75
  13. package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/cleanKnownObjectFunctions.ts +19 -1
  14. package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/cleanNonObjectFunctions.ts +34 -1
  15. package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/convertDotNotation.ts +23 -0
  16. package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/convertNullToUndefinedBySchema.ts +98 -0
  17. package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/fillInSchemaGapsAndUnknowns.ts +34 -1
  18. package/analyzer-template/packages/ai/src/lib/gatherRelevantDependentKeyAttributes.ts +236 -24
  19. package/analyzer-template/packages/ai/src/lib/generateChangesEntityKeyAttributes.ts +18 -1
  20. package/analyzer-template/packages/ai/src/lib/generateChangesEntityScenarioData.ts +41 -0
  21. package/analyzer-template/packages/ai/src/lib/generateChangesEntityScenarios.ts +37 -4
  22. package/analyzer-template/packages/ai/src/lib/generateEntityDataStructure.ts +5 -0
  23. package/analyzer-template/packages/ai/src/lib/generateEntityKeyAttributes.ts +213 -12
  24. package/analyzer-template/packages/ai/src/lib/generateEntityScenarioData.ts +36 -25
  25. package/analyzer-template/packages/ai/src/lib/generateEntityScenarios.ts +114 -11
  26. package/analyzer-template/packages/ai/src/lib/getConditionalUsagesFromCode.ts +143 -31
  27. package/analyzer-template/packages/ai/src/lib/guessScenarioDataFromDescription.ts +8 -2
  28. package/analyzer-template/packages/ai/src/lib/promptGenerators/gatherAttributesMap.ts +7 -0
  29. package/analyzer-template/packages/ai/src/lib/promptGenerators/generateChangesEntityScenariosGenerator.ts +42 -2
  30. package/analyzer-template/packages/ai/src/lib/promptGenerators/generateEntityScenariosGenerator.ts +38 -2
  31. package/analyzer-template/packages/ai/src/lib/promptGenerators/guessNewScenarioDataFromDescriptionGenerator.ts +28 -2
  32. package/analyzer-template/packages/ai/src/lib/worker/SerializableDataStructure.ts +5 -0
  33. package/analyzer-template/packages/ai/src/lib/worker/analyzeScopeWorker.ts +8 -1
  34. package/analyzer-template/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.ts +127 -43
  35. package/analyzer-template/packages/analyze/src/lib/files/scenarios/enrichArrayTypesFromChildSignatures.ts +158 -0
  36. package/analyzer-template/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.ts +405 -45
  37. package/analyzer-template/packages/analyze/src/lib/files/scenarios/generateChangesScenarioData.ts +1 -1
  38. package/analyzer-template/packages/analyze/src/lib/files/scenarios/generateDataStructure.ts +260 -133
  39. package/analyzer-template/packages/analyze/src/lib/files/scenarios/generateKeyAttributes.ts +10 -5
  40. package/analyzer-template/packages/analyze/src/lib/files/scenarios/generateScenarioData.ts +77 -83
  41. package/analyzer-template/packages/analyze/src/lib/files/scenarios/generateScenarios.ts +2 -5
  42. package/analyzer-template/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.ts +196 -86
  43. package/analyzer-template/packages/aws/dist/src/lib/s3/checkS3ObjectExists.d.ts +15 -0
  44. package/analyzer-template/packages/aws/dist/src/lib/s3/checkS3ObjectExists.d.ts.map +1 -0
  45. package/analyzer-template/packages/aws/dist/src/lib/s3/checkS3ObjectExists.js +31 -0
  46. package/analyzer-template/packages/aws/dist/src/lib/s3/checkS3ObjectExists.js.map +1 -0
  47. package/analyzer-template/packages/aws/package.json +1 -1
  48. package/analyzer-template/packages/aws/s3/index.ts +1 -0
  49. package/analyzer-template/packages/aws/src/lib/s3/checkS3ObjectExists.ts +47 -0
  50. package/analyzer-template/packages/database/src/lib/kysely/db.ts +4 -4
  51. package/analyzer-template/packages/database/src/lib/kysely/tableRelations.ts +2 -2
  52. package/analyzer-template/packages/database/src/lib/kysely/tables/debugReportsTable.ts +20 -9
  53. package/analyzer-template/packages/generate/src/lib/componentScenarioPage/getIFrameMessageListenerCode.ts +9 -4
  54. package/analyzer-template/packages/generate/src/lib/deepMerge.ts +26 -1
  55. package/analyzer-template/packages/github/dist/database/src/lib/kysely/db.d.ts +2 -2
  56. package/analyzer-template/packages/github/dist/database/src/lib/kysely/db.js +2 -2
  57. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tableRelations.d.ts +2 -2
  58. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/analysesTable.d.ts +8 -1
  59. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/analysesTable.d.ts.map +1 -1
  60. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/debugReportsTable.d.ts +14 -7
  61. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/debugReportsTable.d.ts.map +1 -1
  62. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/debugReportsTable.js +9 -3
  63. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/debugReportsTable.js.map +1 -1
  64. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/scenariosTable.d.ts +1 -1
  65. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/scenariosTable.d.ts.map +1 -1
  66. package/analyzer-template/packages/github/dist/generate/src/lib/componentScenarioPage/getIFrameMessageListenerCode.d.ts.map +1 -1
  67. package/analyzer-template/packages/github/dist/generate/src/lib/componentScenarioPage/getIFrameMessageListenerCode.js +8 -4
  68. package/analyzer-template/packages/github/dist/generate/src/lib/componentScenarioPage/getIFrameMessageListenerCode.js.map +1 -1
  69. package/analyzer-template/packages/github/dist/generate/src/lib/deepMerge.d.ts.map +1 -1
  70. package/analyzer-template/packages/github/dist/generate/src/lib/deepMerge.js +27 -1
  71. package/analyzer-template/packages/github/dist/generate/src/lib/deepMerge.js.map +1 -1
  72. package/analyzer-template/packages/github/dist/types/index.d.ts +4 -3
  73. package/analyzer-template/packages/github/dist/types/index.d.ts.map +1 -1
  74. package/analyzer-template/packages/github/dist/types/index.js +1 -0
  75. package/analyzer-template/packages/github/dist/types/index.js.map +1 -1
  76. package/analyzer-template/packages/github/dist/types/src/types/Analysis.d.ts +31 -1
  77. package/analyzer-template/packages/github/dist/types/src/types/Analysis.d.ts.map +1 -1
  78. package/analyzer-template/packages/github/dist/types/src/types/Scenario.d.ts +51 -1
  79. package/analyzer-template/packages/github/dist/types/src/types/Scenario.d.ts.map +1 -1
  80. package/analyzer-template/packages/github/dist/types/src/types/Scenario.js +21 -1
  81. package/analyzer-template/packages/github/dist/types/src/types/Scenario.js.map +1 -1
  82. package/analyzer-template/packages/github/dist/types/src/types/ScenariosDataStructure.d.ts +48 -0
  83. package/analyzer-template/packages/github/dist/types/src/types/ScenariosDataStructure.d.ts.map +1 -1
  84. package/analyzer-template/packages/github/dist/utils/src/lib/lightweightEntityExtractor.d.ts.map +1 -1
  85. package/analyzer-template/packages/github/dist/utils/src/lib/lightweightEntityExtractor.js +25 -0
  86. package/analyzer-template/packages/github/dist/utils/src/lib/lightweightEntityExtractor.js.map +1 -1
  87. package/analyzer-template/packages/types/index.ts +8 -0
  88. package/analyzer-template/packages/types/src/types/Analysis.ts +32 -1
  89. package/analyzer-template/packages/types/src/types/Scenario.ts +75 -6
  90. package/analyzer-template/packages/types/src/types/ScenariosDataStructure.ts +49 -0
  91. package/analyzer-template/packages/ui-components/src/components/ScenarioDetailInteractiveView.tsx +23 -7
  92. package/analyzer-template/packages/utils/dist/types/index.d.ts +4 -3
  93. package/analyzer-template/packages/utils/dist/types/index.d.ts.map +1 -1
  94. package/analyzer-template/packages/utils/dist/types/index.js +1 -0
  95. package/analyzer-template/packages/utils/dist/types/index.js.map +1 -1
  96. package/analyzer-template/packages/utils/dist/types/src/types/Analysis.d.ts +31 -1
  97. package/analyzer-template/packages/utils/dist/types/src/types/Analysis.d.ts.map +1 -1
  98. package/analyzer-template/packages/utils/dist/types/src/types/Scenario.d.ts +51 -1
  99. package/analyzer-template/packages/utils/dist/types/src/types/Scenario.d.ts.map +1 -1
  100. package/analyzer-template/packages/utils/dist/types/src/types/Scenario.js +21 -1
  101. package/analyzer-template/packages/utils/dist/types/src/types/Scenario.js.map +1 -1
  102. package/analyzer-template/packages/utils/dist/types/src/types/ScenariosDataStructure.d.ts +48 -0
  103. package/analyzer-template/packages/utils/dist/types/src/types/ScenariosDataStructure.d.ts.map +1 -1
  104. package/analyzer-template/packages/utils/dist/utils/src/lib/lightweightEntityExtractor.d.ts.map +1 -1
  105. package/analyzer-template/packages/utils/dist/utils/src/lib/lightweightEntityExtractor.js +25 -0
  106. package/analyzer-template/packages/utils/dist/utils/src/lib/lightweightEntityExtractor.js.map +1 -1
  107. package/analyzer-template/packages/utils/src/lib/lightweightEntityExtractor.ts +27 -0
  108. package/analyzer-template/playwright/takeElementScreenshot.ts +26 -11
  109. package/analyzer-template/playwright/takeScreenshot.ts +9 -7
  110. package/analyzer-template/project/constructMockCode.ts +286 -84
  111. package/analyzer-template/project/orchestrateCapture/SequentialCaptureTaskRunner.ts +77 -37
  112. package/analyzer-template/project/reconcileMockDataKeys.ts +5 -2
  113. package/analyzer-template/project/runMultiScenarioServer.ts +11 -10
  114. package/analyzer-template/project/serverOnlyModules.ts +71 -23
  115. package/analyzer-template/project/start.ts +10 -0
  116. package/analyzer-template/project/startScenarioCapture.ts +73 -41
  117. package/analyzer-template/project/writeMockDataTsx.ts +115 -54
  118. package/analyzer-template/project/writeScenarioComponents.ts +571 -162
  119. package/analyzer-template/project/writeSimpleRoot.ts +11 -13
  120. package/background/src/lib/virtualized/project/constructMockCode.js +265 -75
  121. package/background/src/lib/virtualized/project/constructMockCode.js.map +1 -1
  122. package/background/src/lib/virtualized/project/orchestrateCapture/SequentialCaptureTaskRunner.js +67 -32
  123. package/background/src/lib/virtualized/project/orchestrateCapture/SequentialCaptureTaskRunner.js.map +1 -1
  124. package/background/src/lib/virtualized/project/reconcileMockDataKeys.js +5 -2
  125. package/background/src/lib/virtualized/project/reconcileMockDataKeys.js.map +1 -1
  126. package/background/src/lib/virtualized/project/runMultiScenarioServer.js +11 -9
  127. package/background/src/lib/virtualized/project/runMultiScenarioServer.js.map +1 -1
  128. package/background/src/lib/virtualized/project/serverOnlyModules.js +62 -25
  129. package/background/src/lib/virtualized/project/serverOnlyModules.js.map +1 -1
  130. package/background/src/lib/virtualized/project/start.js +6 -0
  131. package/background/src/lib/virtualized/project/start.js.map +1 -1
  132. package/background/src/lib/virtualized/project/startScenarioCapture.js +54 -31
  133. package/background/src/lib/virtualized/project/startScenarioCapture.js.map +1 -1
  134. package/background/src/lib/virtualized/project/writeMockDataTsx.js +106 -46
  135. package/background/src/lib/virtualized/project/writeMockDataTsx.js.map +1 -1
  136. package/background/src/lib/virtualized/project/writeScenarioComponents.js +399 -106
  137. package/background/src/lib/virtualized/project/writeScenarioComponents.js.map +1 -1
  138. package/background/src/lib/virtualized/project/writeSimpleRoot.js +11 -11
  139. package/background/src/lib/virtualized/project/writeSimpleRoot.js.map +1 -1
  140. package/codeyam-cli/src/cli.js +2 -0
  141. package/codeyam-cli/src/cli.js.map +1 -1
  142. package/codeyam-cli/src/commands/debug.js +14 -2
  143. package/codeyam-cli/src/commands/debug.js.map +1 -1
  144. package/codeyam-cli/src/commands/recapture.js +215 -0
  145. package/codeyam-cli/src/commands/recapture.js.map +1 -0
  146. package/codeyam-cli/src/commands/report.js +26 -23
  147. package/codeyam-cli/src/commands/report.js.map +1 -1
  148. package/codeyam-cli/src/utils/backgroundServer.js +2 -2
  149. package/codeyam-cli/src/utils/backgroundServer.js.map +1 -1
  150. package/codeyam-cli/src/utils/generateReport.js +252 -106
  151. package/codeyam-cli/src/utils/generateReport.js.map +1 -1
  152. package/codeyam-cli/src/utils/install-skills.js +2 -2
  153. package/codeyam-cli/src/utils/install-skills.js.map +1 -1
  154. package/codeyam-cli/src/utils/queue/__tests__/manager.test.js +38 -0
  155. package/codeyam-cli/src/utils/queue/__tests__/manager.test.js.map +1 -1
  156. package/codeyam-cli/src/utils/queue/job.js +140 -16
  157. package/codeyam-cli/src/utils/queue/job.js.map +1 -1
  158. package/codeyam-cli/src/utils/queue/manager.js +19 -7
  159. package/codeyam-cli/src/utils/queue/manager.js.map +1 -1
  160. package/codeyam-cli/src/utils/queue/persistence.js.map +1 -1
  161. package/codeyam-cli/src/webserver/app/lib/database.js +47 -0
  162. package/codeyam-cli/src/webserver/app/lib/database.js.map +1 -1
  163. package/codeyam-cli/src/webserver/app/lib/dbNotifier.js.map +1 -1
  164. package/codeyam-cli/src/webserver/backgroundServer.js +5 -10
  165. package/codeyam-cli/src/webserver/backgroundServer.js.map +1 -1
  166. package/codeyam-cli/src/webserver/bootstrap.js +9 -0
  167. package/codeyam-cli/src/webserver/bootstrap.js.map +1 -0
  168. package/codeyam-cli/src/webserver/build/client/assets/EntityItem-wXL1Z2Aq.js +1 -0
  169. package/codeyam-cli/src/webserver/build/client/assets/{EntityTypeBadge-efWKDYMr.js → EntityTypeBadge-CzGX-miz.js} +1 -1
  170. package/codeyam-cli/src/webserver/build/client/assets/EntityTypeIcon-CXFKsCOD.js +41 -0
  171. package/codeyam-cli/src/webserver/build/client/assets/InteractivePreview-D-9pXIaY.js +25 -0
  172. package/codeyam-cli/src/webserver/build/client/assets/LibraryFunctionPreview-CBQPrpT0.js +3 -0
  173. package/codeyam-cli/src/webserver/build/client/assets/LoadingDots-D1CdlbrV.js +6 -0
  174. package/codeyam-cli/src/webserver/build/client/assets/LogViewer-wDPcZNKx.js +3 -0
  175. package/codeyam-cli/src/webserver/build/client/assets/ReportIssueModal-4lcOlid-.js +11 -0
  176. package/codeyam-cli/src/webserver/build/client/assets/SafeScreenshot-BfmDgXxG.js +1 -0
  177. package/codeyam-cli/src/webserver/build/client/assets/ScenarioViewer-CUxUNEEC.js +15 -0
  178. package/codeyam-cli/src/webserver/build/client/assets/{TruncatedFilePath-COPstp9J.js → TruncatedFilePath-6J7zDUD5.js} +1 -1
  179. package/codeyam-cli/src/webserver/build/client/assets/_index-DHImXdXq.js +11 -0
  180. package/codeyam-cli/src/webserver/build/client/assets/activity.(_tab)-CVP_WGQ3.js +32 -0
  181. package/codeyam-cli/src/webserver/build/client/assets/api.link-scenario-value-l0sNRNKZ.js +1 -0
  182. package/codeyam-cli/src/webserver/build/client/assets/api.update-key-attributes-l0sNRNKZ.js +1 -0
  183. package/codeyam-cli/src/webserver/build/client/assets/api.update-valid-values-l0sNRNKZ.js +1 -0
  184. package/codeyam-cli/src/webserver/build/client/assets/chevron-down-BYimnrHg.js +6 -0
  185. package/codeyam-cli/src/webserver/build/client/assets/chunk-JMJ3UQ3L-BambyYE_.js +51 -0
  186. package/codeyam-cli/src/webserver/build/client/assets/circle-check-CaVsIRxt.js +6 -0
  187. package/codeyam-cli/src/webserver/build/client/assets/createLucideIcon-CgUsG7ib.js +21 -0
  188. package/codeyam-cli/src/webserver/build/client/assets/cy-logo-cli-CKnwPCDr.js +1 -0
  189. package/codeyam-cli/src/webserver/build/client/assets/dev.empty-DW_hdGUc.js +1 -0
  190. package/codeyam-cli/src/webserver/build/client/assets/entity._sha._-Dt-SjPsw.js +23 -0
  191. package/codeyam-cli/src/webserver/build/client/assets/entity._sha.scenarios._scenarioId.fullscreen-DyB90fWk.js +1 -0
  192. package/codeyam-cli/src/webserver/build/client/assets/entity._sha_.create-scenario-D_3ero5o.js +1 -0
  193. package/codeyam-cli/src/webserver/build/client/assets/entity._sha_.edit._scenarioId-CfLCUi9S.js +5 -0
  194. package/codeyam-cli/src/webserver/build/client/assets/entry.client-DKJyZfAY.js +29 -0
  195. package/codeyam-cli/src/webserver/build/client/assets/fileTableUtils-DAtOlaWE.js +1 -0
  196. package/codeyam-cli/src/webserver/build/client/assets/files-ClR0d32A.js +1 -0
  197. package/codeyam-cli/src/webserver/build/client/assets/git-D62Lxxmv.js +15 -0
  198. package/codeyam-cli/src/webserver/build/client/assets/globals-C9s7Lhdl.css +1 -0
  199. package/codeyam-cli/src/webserver/build/client/assets/html2canvas-pro.esm-fmIEn3Bc.js +9 -0
  200. package/codeyam-cli/src/webserver/build/client/assets/index-BosqDOlH.js +3 -0
  201. package/codeyam-cli/src/webserver/build/client/assets/index-CzNNiTkw.js +9 -0
  202. package/codeyam-cli/src/webserver/build/client/assets/keyAttributeCoverage-CTlFMihX.js +1 -0
  203. package/codeyam-cli/src/webserver/build/client/assets/loader-circle-CNp9QFCX.js +6 -0
  204. package/codeyam-cli/src/webserver/build/client/assets/manifest-0d27da29.js +1 -0
  205. package/codeyam-cli/src/webserver/build/client/assets/preload-helper-ckwbz45p.js +1 -0
  206. package/codeyam-cli/src/webserver/build/client/assets/root-B_wIKCIf.js +56 -0
  207. package/codeyam-cli/src/webserver/build/client/assets/scenarioStatus-B_8jpV3e.js +1 -0
  208. package/codeyam-cli/src/webserver/build/client/assets/search-DDGjYAMJ.js +6 -0
  209. package/codeyam-cli/src/webserver/build/client/assets/settings-DgTyB-Wg.js +1 -0
  210. package/codeyam-cli/src/webserver/build/client/assets/simulations-CoNWGt0K.js +1 -0
  211. package/codeyam-cli/src/webserver/build/client/assets/triangle-alert-CBc5dE1s.js +6 -0
  212. package/codeyam-cli/src/webserver/build/client/assets/useCustomSizes-BMIGFP-m.js +1 -0
  213. package/codeyam-cli/src/webserver/build/client/assets/useInteractiveMode-Dk_FQqWJ.js +1 -0
  214. package/codeyam-cli/src/webserver/build/client/assets/{useLastLogLine-3pmpUQB-.js → useLastLogLine-BqPPNjAl.js} +1 -1
  215. package/codeyam-cli/src/webserver/build/client/assets/useReportContext-DsJbgMY9.js +1 -0
  216. package/codeyam-cli/src/webserver/build/client/assets/{useToast-DEyawJ8r.js → useToast-DWHcCcl1.js} +1 -1
  217. package/codeyam-cli/src/webserver/build/server/assets/index-CU58-Ttc.js +1 -0
  218. package/codeyam-cli/src/webserver/build/server/assets/server-build-D35o2uae.js +175 -0
  219. package/codeyam-cli/src/webserver/build/server/index.js +1 -1
  220. package/codeyam-cli/src/webserver/build-info.json +5 -5
  221. package/codeyam-cli/src/webserver/devServer.js +1 -3
  222. package/codeyam-cli/src/webserver/devServer.js.map +1 -1
  223. package/codeyam-cli/templates/codeyam-setup-skill.md +138 -3
  224. package/codeyam-cli/templates/debug-codeyam.md +625 -0
  225. package/package.json +14 -14
  226. package/packages/ai/src/lib/analyzeScope.js +2 -0
  227. package/packages/ai/src/lib/analyzeScope.js.map +1 -1
  228. package/packages/ai/src/lib/astScopes/astScopeAnalyzer.js +16 -0
  229. package/packages/ai/src/lib/astScopes/astScopeAnalyzer.js.map +1 -1
  230. package/packages/ai/src/lib/astScopes/patterns/switchStatementHandler.js +16 -0
  231. package/packages/ai/src/lib/astScopes/patterns/switchStatementHandler.js.map +1 -1
  232. package/packages/ai/src/lib/astScopes/processExpression.js +305 -88
  233. package/packages/ai/src/lib/astScopes/processExpression.js.map +1 -1
  234. package/packages/ai/src/lib/dataStructure/ScopeDataStructure.js +582 -41
  235. package/packages/ai/src/lib/dataStructure/ScopeDataStructure.js.map +1 -1
  236. package/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/JavascriptFrameworkManager.js +2 -1
  237. package/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/JavascriptFrameworkManager.js.map +1 -1
  238. package/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/MuiManager.js +454 -0
  239. package/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/MuiManager.js.map +1 -0
  240. package/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/ReactFrameworkManager.js +173 -55
  241. package/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/ReactFrameworkManager.js.map +1 -1
  242. package/packages/ai/src/lib/dataStructure/helpers/cleanKnownObjectFunctions.js +16 -1
  243. package/packages/ai/src/lib/dataStructure/helpers/cleanKnownObjectFunctions.js.map +1 -1
  244. package/packages/ai/src/lib/dataStructure/helpers/cleanNonObjectFunctions.js +30 -1
  245. package/packages/ai/src/lib/dataStructure/helpers/cleanNonObjectFunctions.js.map +1 -1
  246. package/packages/ai/src/lib/dataStructure/helpers/convertDotNotation.js +20 -0
  247. package/packages/ai/src/lib/dataStructure/helpers/convertDotNotation.js.map +1 -1
  248. package/packages/ai/src/lib/dataStructure/helpers/convertNullToUndefinedBySchema.js +86 -0
  249. package/packages/ai/src/lib/dataStructure/helpers/convertNullToUndefinedBySchema.js.map +1 -0
  250. package/packages/ai/src/lib/dataStructure/helpers/fillInSchemaGapsAndUnknowns.js +28 -2
  251. package/packages/ai/src/lib/dataStructure/helpers/fillInSchemaGapsAndUnknowns.js.map +1 -1
  252. package/packages/ai/src/lib/gatherRelevantDependentKeyAttributes.js +179 -17
  253. package/packages/ai/src/lib/gatherRelevantDependentKeyAttributes.js.map +1 -1
  254. package/packages/ai/src/lib/generateChangesEntityKeyAttributes.js +6 -0
  255. package/packages/ai/src/lib/generateChangesEntityKeyAttributes.js.map +1 -1
  256. package/packages/ai/src/lib/generateChangesEntityScenarioData.js +41 -0
  257. package/packages/ai/src/lib/generateChangesEntityScenarioData.js.map +1 -1
  258. package/packages/ai/src/lib/generateChangesEntityScenarios.js +37 -4
  259. package/packages/ai/src/lib/generateChangesEntityScenarios.js.map +1 -1
  260. package/packages/ai/src/lib/generateEntityDataStructure.js +4 -0
  261. package/packages/ai/src/lib/generateEntityDataStructure.js.map +1 -1
  262. package/packages/ai/src/lib/generateEntityKeyAttributes.js +176 -9
  263. package/packages/ai/src/lib/generateEntityKeyAttributes.js.map +1 -1
  264. package/packages/ai/src/lib/generateEntityScenarioData.js +29 -25
  265. package/packages/ai/src/lib/generateEntityScenarioData.js.map +1 -1
  266. package/packages/ai/src/lib/generateEntityScenarios.js +105 -9
  267. package/packages/ai/src/lib/generateEntityScenarios.js.map +1 -1
  268. package/packages/ai/src/lib/getConditionalUsagesFromCode.js +84 -14
  269. package/packages/ai/src/lib/getConditionalUsagesFromCode.js.map +1 -1
  270. package/packages/ai/src/lib/guessScenarioDataFromDescription.js +2 -1
  271. package/packages/ai/src/lib/guessScenarioDataFromDescription.js.map +1 -1
  272. package/packages/ai/src/lib/promptGenerators/gatherAttributesMap.js +6 -0
  273. package/packages/ai/src/lib/promptGenerators/gatherAttributesMap.js.map +1 -1
  274. package/packages/ai/src/lib/promptGenerators/generateChangesEntityScenariosGenerator.js +38 -2
  275. package/packages/ai/src/lib/promptGenerators/generateChangesEntityScenariosGenerator.js.map +1 -1
  276. package/packages/ai/src/lib/promptGenerators/generateEntityScenariosGenerator.js +38 -2
  277. package/packages/ai/src/lib/promptGenerators/generateEntityScenariosGenerator.js.map +1 -1
  278. package/packages/ai/src/lib/promptGenerators/guessNewScenarioDataFromDescriptionGenerator.js +16 -3
  279. package/packages/ai/src/lib/promptGenerators/guessNewScenarioDataFromDescriptionGenerator.js.map +1 -1
  280. package/packages/ai/src/lib/worker/SerializableDataStructure.js.map +1 -1
  281. package/packages/ai/src/lib/worker/analyzeScopeWorker.js +4 -0
  282. package/packages/ai/src/lib/worker/analyzeScopeWorker.js.map +1 -1
  283. package/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.js +100 -23
  284. package/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.js.map +1 -1
  285. package/packages/analyze/src/lib/files/scenarios/enrichArrayTypesFromChildSignatures.js +125 -0
  286. package/packages/analyze/src/lib/files/scenarios/enrichArrayTypesFromChildSignatures.js.map +1 -0
  287. package/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.js +298 -45
  288. package/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.js.map +1 -1
  289. package/packages/analyze/src/lib/files/scenarios/generateChangesScenarioData.js +1 -1
  290. package/packages/analyze/src/lib/files/scenarios/generateChangesScenarioData.js.map +1 -1
  291. package/packages/analyze/src/lib/files/scenarios/generateDataStructure.js +201 -80
  292. package/packages/analyze/src/lib/files/scenarios/generateDataStructure.js.map +1 -1
  293. package/packages/analyze/src/lib/files/scenarios/generateKeyAttributes.js +10 -5
  294. package/packages/analyze/src/lib/files/scenarios/generateKeyAttributes.js.map +1 -1
  295. package/packages/analyze/src/lib/files/scenarios/generateScenarioData.js +55 -69
  296. package/packages/analyze/src/lib/files/scenarios/generateScenarioData.js.map +1 -1
  297. package/packages/analyze/src/lib/files/scenarios/generateScenarios.js +2 -5
  298. package/packages/analyze/src/lib/files/scenarios/generateScenarios.js.map +1 -1
  299. package/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.js +171 -81
  300. package/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.js.map +1 -1
  301. package/packages/database/src/lib/kysely/db.js +2 -2
  302. package/packages/database/src/lib/kysely/tables/debugReportsTable.js +9 -3
  303. package/packages/database/src/lib/kysely/tables/debugReportsTable.js.map +1 -1
  304. package/packages/generate/src/lib/componentScenarioPage/getIFrameMessageListenerCode.js +8 -4
  305. package/packages/generate/src/lib/componentScenarioPage/getIFrameMessageListenerCode.js.map +1 -1
  306. package/packages/generate/src/lib/deepMerge.js +27 -1
  307. package/packages/generate/src/lib/deepMerge.js.map +1 -1
  308. package/packages/types/index.js +1 -0
  309. package/packages/types/index.js.map +1 -1
  310. package/packages/types/src/types/Scenario.js +21 -1
  311. package/packages/types/src/types/Scenario.js.map +1 -1
  312. package/packages/utils/src/lib/lightweightEntityExtractor.js +25 -0
  313. package/packages/utils/src/lib/lightweightEntityExtractor.js.map +1 -1
  314. package/scripts/finalize-analyzer.cjs +3 -1
  315. package/codeyam-cli/scripts/fixtures/cal.com/universal-mocks/packages/prisma/index.js +0 -238
  316. package/codeyam-cli/scripts/fixtures/cal.com/universal-mocks/packages/prisma/index.js.map +0 -1
  317. package/codeyam-cli/src/webserver/build/client/assets/EntityItem-CVbSvOjo.js +0 -1
  318. package/codeyam-cli/src/webserver/build/client/assets/EntityTypeIcon-DcwcHyl5.js +0 -1
  319. package/codeyam-cli/src/webserver/build/client/assets/InteractivePreview-WgwC1GfJ.js +0 -26
  320. package/codeyam-cli/src/webserver/build/client/assets/LibraryFunctionPreview-IEKom9O2.js +0 -3
  321. package/codeyam-cli/src/webserver/build/client/assets/LogViewer-BYnfxbUG.js +0 -3
  322. package/codeyam-cli/src/webserver/build/client/assets/ReportIssueModal-_lBPJCzG.js +0 -1
  323. package/codeyam-cli/src/webserver/build/client/assets/SafeScreenshot-lHVhvsu_.js +0 -1
  324. package/codeyam-cli/src/webserver/build/client/assets/ScenarioViewer-d_TBk4GQ.js +0 -5
  325. package/codeyam-cli/src/webserver/build/client/assets/_index-kGT7VUqj.js +0 -1
  326. package/codeyam-cli/src/webserver/build/client/assets/activity.(_tab)-DDGmhu7P.js +0 -7
  327. package/codeyam-cli/src/webserver/build/client/assets/chevron-down-n_HPRfM_.js +0 -1
  328. package/codeyam-cli/src/webserver/build/client/assets/chunk-WWGJGFF6-CbVoyx1U.js +0 -26
  329. package/codeyam-cli/src/webserver/build/client/assets/circle-check-D1VOYveA.js +0 -1
  330. package/codeyam-cli/src/webserver/build/client/assets/createLucideIcon-YR8jjAlu.js +0 -1
  331. package/codeyam-cli/src/webserver/build/client/assets/dev.empty-B8vP3V_s.js +0 -1
  332. package/codeyam-cli/src/webserver/build/client/assets/entity._sha._-CN6aLCT1.js +0 -16
  333. package/codeyam-cli/src/webserver/build/client/assets/entity._sha_.create-scenario-DA5Jeu2P.js +0 -1
  334. package/codeyam-cli/src/webserver/build/client/assets/entity._sha_.edit._scenarioId-BTeitalf.js +0 -5
  335. package/codeyam-cli/src/webserver/build/client/assets/entry.client-du6UEYD-.js +0 -13
  336. package/codeyam-cli/src/webserver/build/client/assets/fileTableUtils-BpjkhMoi.js +0 -1
  337. package/codeyam-cli/src/webserver/build/client/assets/files-BQGvk4lJ.js +0 -1
  338. package/codeyam-cli/src/webserver/build/client/assets/git-DVdYRT-I.js +0 -12
  339. package/codeyam-cli/src/webserver/build/client/assets/globals-CO-U8Bpo.css +0 -1
  340. package/codeyam-cli/src/webserver/build/client/assets/html2canvas-pro.esm-XQCGvadH.js +0 -5
  341. package/codeyam-cli/src/webserver/build/client/assets/index-DCG-vks0.js +0 -1
  342. package/codeyam-cli/src/webserver/build/client/assets/loader-circle-GazdNeLl.js +0 -1
  343. package/codeyam-cli/src/webserver/build/client/assets/manifest-0b694d28.js +0 -1
  344. package/codeyam-cli/src/webserver/build/client/assets/root-D3tQP7hx.js +0 -16
  345. package/codeyam-cli/src/webserver/build/client/assets/search-CIY6XmtE.js +0 -1
  346. package/codeyam-cli/src/webserver/build/client/assets/server-build-CMKNK2uU.css +0 -1
  347. package/codeyam-cli/src/webserver/build/client/assets/settings-CoMDgElu.js +0 -1
  348. package/codeyam-cli/src/webserver/build/client/assets/simulations-agkniXp2.js +0 -1
  349. package/codeyam-cli/src/webserver/build/client/assets/triangle-alert-B2VUcygF.js +0 -1
  350. package/codeyam-cli/src/webserver/build/client/assets/useReportContext-EvdK-zXP.js +0 -1
  351. package/codeyam-cli/src/webserver/build/server/assets/index-DGVHQEXD.js +0 -1
  352. package/codeyam-cli/src/webserver/build/server/assets/server-build-CghkTkIL.js +0 -166
  353. package/codeyam-cli/templates/debug-command.md +0 -303
  354. /package/codeyam-cli/src/webserver/build/client/assets/{InteractivePreview-CMKNK2uU.css → styles-CMKNK2uU.css} +0 -0
@@ -27,6 +27,67 @@ import ts from 'typescript';
27
27
  import { LazyFileStore } from './LazyFileStore';
28
28
  import { applyServerOnlyMocks } from './serverOnlyModules';
29
29
 
30
+ // Debug timing helper for tracking where time is spent
31
+ const DEBUG_TIMING = process.env.DEBUG_WRITE_SCENARIO === 'true';
32
+ let debugStartTime: number;
33
+ let debugLastTime: number;
34
+
35
+ // Timeout protection to prevent infinite hangs
36
+ const WRITE_SCENARIO_TIMEOUT_MS = parseInt(
37
+ process.env.WRITE_SCENARIO_TIMEOUT_MS || '300000', // Default 5 minutes
38
+ 10,
39
+ );
40
+
41
+ class WriteScenarioTimeoutError extends Error {
42
+ constructor(operation: string, timeoutMs: number) {
43
+ super(
44
+ `WriteScenarioComponents timed out after ${timeoutMs}ms during: ${operation}`,
45
+ );
46
+ this.name = 'WriteScenarioTimeoutError';
47
+ }
48
+ }
49
+
50
+ async function withTimeout<T>(
51
+ operation: string,
52
+ promise: Promise<T>,
53
+ timeoutMs: number = WRITE_SCENARIO_TIMEOUT_MS,
54
+ ): Promise<T> {
55
+ let timeoutId: NodeJS.Timeout | undefined;
56
+
57
+ const timeoutPromise = new Promise<never>((_, reject) => {
58
+ timeoutId = setTimeout(() => {
59
+ reject(new WriteScenarioTimeoutError(operation, timeoutMs));
60
+ }, timeoutMs);
61
+ });
62
+
63
+ try {
64
+ return await Promise.race([promise, timeoutPromise]);
65
+ } finally {
66
+ if (timeoutId) clearTimeout(timeoutId);
67
+ }
68
+ }
69
+
70
+ function debugLog(message: string, extra?: Record<string, unknown>): void {
71
+ if (!DEBUG_TIMING) return;
72
+ const now = Date.now();
73
+ if (!debugStartTime) {
74
+ debugStartTime = now;
75
+ debugLastTime = now;
76
+ }
77
+ const elapsed = now - debugStartTime;
78
+ const delta = now - debugLastTime;
79
+ debugLastTime = now;
80
+ console.log(
81
+ `[WriteScenario +${elapsed}ms Δ${delta}ms] ${message}`,
82
+ extra ? JSON.stringify(extra, null, 2) : '',
83
+ );
84
+ }
85
+
86
+ function resetDebugTiming(): void {
87
+ debugStartTime = 0;
88
+ debugLastTime = 0;
89
+ }
90
+
30
91
  /**
31
92
  * Find the end position of the last import/export-from statement using TypeScript AST.
32
93
  * This is more reliable than regex for handling multiline imports, comments, etc.
@@ -36,11 +97,15 @@ import { applyServerOnlyMocks } from './serverOnlyModules';
36
97
  */
37
98
  function findEndOfImports(content: string): number {
38
99
  try {
100
+ // Use temp.tsx to enable JSX parsing - otherwise TypeScript may misparse
101
+ // JSX content containing the word "import" (e.g., "Entities that import this")
102
+ // as an import statement, causing mock code to be inserted in the wrong location.
39
103
  const sourceFile = ts.createSourceFile(
40
- 'temp.ts',
104
+ 'temp.tsx',
41
105
  content,
42
106
  ts.ScriptTarget.Latest,
43
107
  true,
108
+ ts.ScriptKind.TSX,
44
109
  );
45
110
 
46
111
  let lastImportEnd = 0;
@@ -75,6 +140,125 @@ function escapeRegExp(str: string): string {
75
140
  return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
76
141
  }
77
142
 
143
+ /**
144
+ * Remove a named import from file content using TypeScript AST.
145
+ * Handles both regular imports (`EntityName`) and type-only imports (`type EntityName`).
146
+ *
147
+ * @param fileContent - The file content to modify
148
+ * @param entityName - The name of the entity to remove from imports
149
+ * @returns The modified file content with the entity removed from imports
150
+ */
151
+ function removeNamedImportAst(fileContent: string, entityName: string): string {
152
+ try {
153
+ const sourceFile = ts.createSourceFile(
154
+ 'temp.tsx',
155
+ fileContent,
156
+ ts.ScriptTarget.Latest,
157
+ true,
158
+ ts.ScriptKind.TSX,
159
+ );
160
+
161
+ const replacements: { start: number; end: number; replacement: string }[] =
162
+ [];
163
+
164
+ for (const statement of sourceFile.statements) {
165
+ if (!ts.isImportDeclaration(statement)) continue;
166
+ if (!statement.importClause?.namedBindings) continue;
167
+ if (!ts.isNamedImports(statement.importClause.namedBindings)) continue;
168
+
169
+ const namedImports = statement.importClause.namedBindings;
170
+ const elements = namedImports.elements;
171
+
172
+ // Find the element that matches our entity name
173
+ const matchingIndex = elements.findIndex(
174
+ (el) => el.name.text === entityName,
175
+ );
176
+ if (matchingIndex === -1) continue;
177
+
178
+ // Check if there's a default import (e.g., `import DefaultName, { NamedImport } from '...'`)
179
+ const hasDefaultImport = !!statement.importClause.name;
180
+
181
+ // If this is the only named import AND there's no default import, remove the entire statement
182
+ if (elements.length === 1 && !hasDefaultImport) {
183
+ // Find the end including any trailing newline
184
+ let end = statement.getEnd();
185
+ const afterStatement = fileContent.slice(end);
186
+ const trailingNewline = afterStatement.match(/^\r?\n/);
187
+ if (trailingNewline) {
188
+ end += trailingNewline[0].length;
189
+ }
190
+ replacements.push({
191
+ start: statement.getStart(sourceFile),
192
+ end,
193
+ replacement: '',
194
+ });
195
+ continue;
196
+ }
197
+
198
+ // Otherwise, rebuild the import without this element
199
+ const remainingElements = elements.filter((_, i) => i !== matchingIndex);
200
+
201
+ // Get the module specifier
202
+ const moduleSpecifier = statement.moduleSpecifier;
203
+ if (!ts.isStringLiteral(moduleSpecifier)) continue;
204
+
205
+ // Preserve import type modifier if present
206
+ const importTypePrefix = statement.importClause.isTypeOnly ? 'type ' : '';
207
+
208
+ // Get the default import name if present
209
+ const defaultImportName = statement.importClause.name?.text;
210
+
211
+ let newImport: string;
212
+
213
+ if (remainingElements.length === 0) {
214
+ // All named imports were removed, but there's a default import to preserve
215
+ // (we only get here when hasDefaultImport is true, because otherwise we'd have
216
+ // removed the whole statement at the elements.length === 1 check above)
217
+ newImport = `import ${defaultImportName} from ${moduleSpecifier.getText(sourceFile)};`;
218
+ } else {
219
+ // Build the new named imports string
220
+ const newNamedImports = remainingElements
221
+ .map((el) => {
222
+ const isTypeOnly = el.isTypeOnly;
223
+ const name = el.name.text;
224
+ const propertyName = el.propertyName?.text;
225
+ if (propertyName) {
226
+ return isTypeOnly
227
+ ? `type ${propertyName} as ${name}`
228
+ : `${propertyName} as ${name}`;
229
+ }
230
+ return isTypeOnly ? `type ${name}` : name;
231
+ })
232
+ .join(', ');
233
+
234
+ // Build the new import statement, preserving default import if present
235
+ const defaultImportPrefix = defaultImportName
236
+ ? `${defaultImportName}, `
237
+ : '';
238
+ newImport = `import ${importTypePrefix}${defaultImportPrefix}{ ${newNamedImports} } from ${moduleSpecifier.getText(sourceFile)};`;
239
+ }
240
+
241
+ replacements.push({
242
+ start: statement.getStart(sourceFile),
243
+ end: statement.getEnd(),
244
+ replacement: newImport,
245
+ });
246
+ }
247
+
248
+ // Apply replacements in reverse order to preserve positions
249
+ let result = fileContent;
250
+ replacements.sort((a, b) => b.start - a.start);
251
+ for (const { start, end, replacement } of replacements) {
252
+ result = result.slice(0, start) + replacement + result.slice(end);
253
+ }
254
+
255
+ return result;
256
+ } catch (error) {
257
+ console.warn('[removeNamedImportAst] Failed to parse file:', error);
258
+ return fileContent; // Return original content on error
259
+ }
260
+ }
261
+
78
262
  /**
79
263
  * Map nested dist paths to src paths.
80
264
  * Some build tools create nested structures like:
@@ -518,27 +702,49 @@ function stripServerOnlyImport(fileContent: string): string {
518
702
  * Excludes node_modules imports (bare specifiers like 'react', '@prisma/client').
519
703
  */
520
704
  function extractInternalImportPaths(fileContent: string): string[] {
705
+ // Always use AST parsing - regex with nested quantifiers can cause catastrophic
706
+ // backtracking that hangs on a single .exec() call (before iteration limits kick in)
707
+ return extractInternalImportPathsAst(fileContent);
708
+ }
709
+
710
+ /**
711
+ * Extract internal import paths using TypeScript AST - more reliable for large files
712
+ */
713
+ function extractInternalImportPathsAst(fileContent: string): string[] {
521
714
  const importPaths: string[] = [];
522
715
 
523
- // Match import statements with their paths
524
- // Handles: import x from "path", import { x } from "path", import * as x from "path"
525
- const importRegex =
526
- /import\s+(?:(?:\{[^}]*\}|\*\s+as\s+\w+|\w+)\s*,?\s*)*\s*from\s*["']([^"']+)["']/g;
527
-
528
- let match;
529
- while ((match = importRegex.exec(fileContent)) !== null) {
530
- const importPath = match[1];
531
-
532
- // Skip node_modules imports (bare specifiers)
533
- // Internal imports start with '.', '@/', '~/' or similar path aliases
534
- if (
535
- importPath.startsWith('.') ||
536
- importPath.startsWith('@/') ||
537
- importPath.startsWith('~/') ||
538
- importPath.startsWith('#')
539
- ) {
540
- importPaths.push(importPath);
716
+ try {
717
+ // Use temp.tsx to enable JSX parsing for consistent handling of JSX files
718
+ const sourceFile = ts.createSourceFile(
719
+ 'temp.tsx',
720
+ fileContent,
721
+ ts.ScriptTarget.Latest,
722
+ true,
723
+ ts.ScriptKind.TSX,
724
+ );
725
+
726
+ for (const statement of sourceFile.statements) {
727
+ if (ts.isImportDeclaration(statement) && statement.moduleSpecifier) {
728
+ const moduleSpecifier = statement.moduleSpecifier;
729
+ if (ts.isStringLiteral(moduleSpecifier)) {
730
+ const importPath = moduleSpecifier.text;
731
+ // Skip node_modules imports (bare specifiers)
732
+ if (
733
+ importPath.startsWith('.') ||
734
+ importPath.startsWith('@/') ||
735
+ importPath.startsWith('~/') ||
736
+ importPath.startsWith('#')
737
+ ) {
738
+ importPaths.push(importPath);
739
+ }
740
+ }
741
+ }
541
742
  }
743
+ } catch (error) {
744
+ console.warn(
745
+ '[extractInternalImportPathsAst] Failed to parse file:',
746
+ error,
747
+ );
542
748
  }
543
749
 
544
750
  return importPaths;
@@ -675,8 +881,21 @@ function addMockToContent(
675
881
 
676
882
  if (hasMultipleCallsWithVariables) {
677
883
  // Generate separate mock functions for each variable-qualified call
678
- // Track variable name occurrences to disambiguate when same variable is reused
679
- // (mirrors the logic in gatherDataForMocks)
884
+ // Look up canonical keys from dataForMocks and track variable names for function naming
885
+
886
+ // Get all call signature keys for this hook from dataForMocks
887
+ const dataForMocks =
888
+ rootAnalysis.metadata?.scenariosDataStructure?.dataForMocks;
889
+ // Match keys that start with the hook name (e.g., "useFetcher" matches "useFetcher<User>()")
890
+ const callSignatureKeysForHook = dataForMocks
891
+ ? Object.keys(dataForMocks).filter((key) => {
892
+ const hookBaseName = importedExport.name.split(/[<(]/)[0];
893
+ const keyBaseName = key.split(/[<(]/)[0];
894
+ return keyBaseName === hookBaseName;
895
+ })
896
+ : [];
897
+
898
+ // Track variable name occurrences for unique function naming
680
899
  const variableNameCounts: Record<string, number> = {};
681
900
 
682
901
  for (let i = 0; i < importedExport.calls!.length; i++) {
@@ -687,18 +906,29 @@ function addMockToContent(
687
906
  const occurrence = variableNameCounts[variableName] ?? 0;
688
907
  variableNameCounts[variableName] = occurrence + 1;
689
908
 
690
- // If this is a reused variable name (occurrence > 0), append index
691
- // e.g., "fetcher[1] <- useFetcher" for the second usage of "fetcher"
909
+ // Build indexed variable name for function naming
692
910
  const indexedVariableName =
693
911
  occurrence > 0 ? `${variableName}[${occurrence}]` : variableName;
694
912
 
695
- // Generate mock code for this specific call using variable-qualified name
696
- // Format: "variableName <- functionName" (reads as "variableName receives from functionName")
697
- const qualifiedName = `${indexedVariableName} <- ${importedExport.name}`;
913
+ // Use safe function name with underscores instead of brackets
914
+ // e.g., fetcher[1] -> fetcher_1
915
+ const safeFunctionName = indexedVariableName.replace(/\[(\d+)\]/g, '_$1');
916
+ // Compute unique mock function name for call site replacement
917
+ // e.g., useFetcher_entityDiffFetcher, useFetcher_reportFetcher
918
+ const mockFunctionName = `${importedExport.name}_${safeFunctionName}`;
919
+
920
+ // Use the call signature from importedExport.calls[i] as the data key
921
+ // This matches what's stored in dataForMocks
922
+ const callSignature = importedExport.calls![i];
923
+
924
+ // Generate mock code using the call signature directly
925
+ // This prevents "symbol already declared" errors when multiple calls exist
698
926
  const variableMockCode = constructMockCode(
699
- qualifiedName,
927
+ callSignature, // Use call signature format for data lookup
700
928
  dependencySchemas,
701
929
  importedExport.entityType,
930
+ undefined, // No need for separate canonical key
931
+ { uniqueFunctionSuffix: safeFunctionName }, // Use variable name for unique function naming
702
932
  );
703
933
 
704
934
  if (variableMockCode) {
@@ -707,8 +937,6 @@ function addMockToContent(
707
937
  // Replace the call site with the variable-specific mock function
708
938
  // e.g., useFetcher<BranchEntityDiffResult>() -> useFetcher_entityDiffFetcher()
709
939
  // e.g., useFetcher() -> useFetcher_reportFetcher()
710
- // For indexed variables: useFetcher() -> useFetcher_fetcher_1()
711
- const callSignature = importedExport.calls![i];
712
940
  // Escape special regex characters in the call signature
713
941
  const escapedCallSignature = callSignature.replace(
714
942
  /[.*+?^${}()|[\]\\]/g,
@@ -719,13 +947,6 @@ function addMockToContent(
719
947
  escapedCallSignature.replace(/\s+/g, '\\s*'),
720
948
  'g',
721
949
  );
722
- // Use safe function name with underscores instead of brackets
723
- // e.g., fetcher[1] -> fetcher_1
724
- const safeFunctionName = indexedVariableName.replace(
725
- /\[(\d+)\]/g,
726
- '_$1',
727
- );
728
- const mockFunctionName = `${importedExport.name}_${safeFunctionName}`;
729
950
  fileContent = fileContent.replace(callRegex, `${mockFunctionName}()`);
730
951
  }
731
952
  }
@@ -741,83 +962,89 @@ function addMockToContent(
741
962
  : undefined;
742
963
 
743
964
  if (singleCallVariableName) {
744
- // For single variable assignments, use the variable-qualified key for data lookup
745
- // Use constructMockCode to generate proper dispatch functions for nested function calls
746
- // (e.g., useTranslation returns { t } where t() needs to dispatch based on translation key)
747
- const qualifiedKey = `${singleCallVariableName} <- ${importedExport.name}`;
748
- // Keep the original function name since there's only one call - no need for unique names
965
+ // For single variable assignments, use the call signature directly from dataForMocks
966
+ const dataForMocks =
967
+ rootAnalysis.metadata?.scenariosDataStructure?.dataForMocks;
968
+
969
+ // Find matching call signature key in dataForMocks
970
+ const hookBaseName = importedExport.name.split(/[<(]/)[0];
971
+ const callSignatureKey = dataForMocks
972
+ ? Object.keys(dataForMocks).find((key) => {
973
+ const keyBaseName = key.split(/[<(]/)[0];
974
+ return keyBaseName === hookBaseName;
975
+ })
976
+ : undefined;
977
+
978
+ // Use the call signature if found, otherwise construct it
979
+ const dataKey =
980
+ callSignatureKey ??
981
+ importedExport.calls?.[0] ??
982
+ `${importedExport.name}()`;
983
+
984
+ // Keep the original function name since there's only one call
749
985
  mockCode = constructMockCode(
750
- qualifiedKey,
986
+ dataKey, // Use call signature format
751
987
  dependencySchemas,
752
988
  importedExport.entityType,
989
+ undefined,
753
990
  { keepOriginalFunctionName: true },
754
991
  );
755
992
  // If constructMockCode didn't generate code, fall back to simple return
756
993
  if (!mockCode) {
757
- mockCode = `const ${importedExport.name}ReturnValue = scenarios().data()?.["${qualifiedKey}"];
994
+ mockCode = `const ${importedExport.name}ReturnValue = scenarios().data()?.["${dataKey}"];
758
995
 
759
996
  function ${importedExport.name}() {
760
997
  return ${importedExport.name}ReturnValue;
761
998
  }`;
762
999
  }
763
1000
  } else {
764
- // Check if any analysis (fileAnalyses or rootAnalysis) has this function's data
765
- // under a variable-qualified key. The entity that CALLS the function (e.g., FileTableRow)
766
- // has the dataForMocks with the variable-qualified key, not the root analysis (e.g., GitView).
767
- let variableQualifiedKey: string | undefined;
768
-
769
- // First check fileAnalyses (the analyses for the entity being written)
770
- for (const analysis of fileAnalyses) {
771
- const dataForMocks =
772
- analysis.metadata?.scenariosDataStructure?.dataForMocks;
773
- if (dataForMocks) {
774
- variableQualifiedKey = Object.keys(dataForMocks).find((key) => {
775
- const match = key.match(/^([a-zA-Z_][a-zA-Z0-9_]*)\s*<-\s*(.+)$/);
776
- return match && match[2] === importedExport.name;
777
- });
778
- if (variableQualifiedKey) {
779
- break;
780
- }
781
- }
782
- }
1001
+ // Helper to find matching call signature key from dataForMocks
1002
+ const hookBaseName = importedExport.name.split(/[<(]/)[0];
1003
+ const findMatchingKey = (
1004
+ dataForMocks: Record<string, unknown> | undefined,
1005
+ ): string | undefined => {
1006
+ if (!dataForMocks) return undefined;
1007
+ return Object.keys(dataForMocks).find((key) => {
1008
+ const keyBaseName = key.split(/[<(]/)[0];
1009
+ return keyBaseName === hookBaseName;
1010
+ });
1011
+ };
783
1012
 
784
- // If not found in fileAnalyses, fall back to rootAnalysis
785
- if (!variableQualifiedKey) {
786
- const dataForMocks =
787
- rootAnalysis.metadata?.scenariosDataStructure?.dataForMocks;
788
- if (dataForMocks) {
789
- variableQualifiedKey = Object.keys(dataForMocks).find((key) => {
790
- const match = key.match(/^([a-zA-Z_][a-zA-Z0-9_]*)\s*<-\s*(.+)$/);
791
- return match && match[2] === importedExport.name;
792
- });
1013
+ // Check rootAnalysis FIRST for matching keys.
1014
+ // The mock DATA is generated from rootAnalysis, so the mock CODE must
1015
+ // also use rootAnalysis keys to ensure the lookup succeeds.
1016
+ let dataKey = findMatchingKey(
1017
+ rootAnalysis.metadata?.scenariosDataStructure?.dataForMocks,
1018
+ );
1019
+
1020
+ // If not found in rootAnalysis, fall back to fileAnalyses
1021
+ if (!dataKey) {
1022
+ for (const analysis of fileAnalyses) {
1023
+ dataKey = findMatchingKey(
1024
+ analysis.metadata?.scenariosDataStructure?.dataForMocks,
1025
+ );
1026
+ if (dataKey) break;
793
1027
  }
794
1028
  }
795
1029
 
796
- if (variableQualifiedKey) {
797
- // Use the variable-qualified key found in the analysis
798
- // Use constructMockCode to generate proper dispatch functions for nested function calls
799
- // Keep the original function name since there's only one call - no need for unique names
800
- mockCode = constructMockCode(
801
- variableQualifiedKey,
802
- dependencySchemas,
803
- importedExport.entityType,
804
- { keepOriginalFunctionName: true },
805
- );
806
- // If constructMockCode didn't generate code, fall back to simple return
807
- if (!mockCode) {
808
- mockCode = `const ${importedExport.name}ReturnValue = scenarios().data()?.["${variableQualifiedKey}"];
1030
+ // Use the data key if found, otherwise use call signature or function name
1031
+ const mockNameToUse =
1032
+ dataKey ?? importedExport.calls?.[0] ?? `${importedExport.name}()`;
1033
+
1034
+ mockCode = constructMockCode(
1035
+ mockNameToUse,
1036
+ dependencySchemas,
1037
+ importedExport.entityType,
1038
+ undefined,
1039
+ { keepOriginalFunctionName: true },
1040
+ );
1041
+ // If constructMockCode didn't generate code, fall back to simple return
1042
+ if (!mockCode && dataKey) {
1043
+ mockCode = `const ${importedExport.name}ReturnValue = scenarios().data()?.["${dataKey}"];
809
1044
 
810
1045
  function ${importedExport.name}() {
811
1046
  return ${importedExport.name}ReturnValue;
812
1047
  }`;
813
- }
814
- } else {
815
- // Original behavior for calls without variable names
816
- mockCode = constructMockCode(
817
- importedExport.name,
818
- dependencySchemas,
819
- importedExport.entityType,
820
- );
821
1048
  }
822
1049
  }
823
1050
  }
@@ -1108,6 +1335,15 @@ export default async function writeScenarioComponents({
1108
1335
  scenarioComponentPaths: string[];
1109
1336
  writtenScenarioComponents: { [key: string]: string[] };
1110
1337
  }> {
1338
+ // Reset debug timing for this invocation
1339
+ resetDebugTiming();
1340
+ debugLog('START writeScenarioComponents', {
1341
+ filePath: file.path,
1342
+ entityName: entity.name,
1343
+ scenarioName: scenario.name,
1344
+ isRootFile: !rootFile || rootFile === file,
1345
+ });
1346
+
1111
1347
  // Capture arguments for testing if debug mode is enabled
1112
1348
  captureArgumentsForTesting({
1113
1349
  project,
@@ -1327,7 +1563,24 @@ export default async function writeScenarioComponents({
1327
1563
  return 0;
1328
1564
  });
1329
1565
 
1566
+ debugLog('Starting main importedExports loop', {
1567
+ count: sortedImportedExports.length,
1568
+ fileContentLength: fileContent.length,
1569
+ });
1570
+
1571
+ let importedExportIndex = 0;
1330
1572
  for (const importedExport of sortedImportedExports) {
1573
+ importedExportIndex++;
1574
+ if (importedExportIndex % 5 === 0 || importedExportIndex === 1) {
1575
+ debugLog(
1576
+ `Processing importedExport ${importedExportIndex}/${sortedImportedExports.length}`,
1577
+ {
1578
+ name: importedExport.name,
1579
+ filePath: importedExport.filePath,
1580
+ isMocked: importedExport.isMocked,
1581
+ },
1582
+ );
1583
+ }
1331
1584
  // IMPORTANT: The import mapping keys may be either absolute or relative paths
1332
1585
  // depending on how they were created by the file analyzer. We try multiple formats.
1333
1586
  // Also need to normalize paths to handle /tmp vs /private/tmp on macOS
@@ -1506,28 +1759,42 @@ export default async function writeScenarioComponents({
1506
1759
  importedExport.resolvedIsDefault === true &&
1507
1760
  importedExport.isDefault === false;
1508
1761
 
1762
+ debugLog(
1763
+ `Recursing into writeScenarioComponents for ${importedExportEntity.name}`,
1764
+ {
1765
+ entityName: importedExportEntity.name,
1766
+ filePath: fileNotMocked.path,
1767
+ },
1768
+ );
1509
1769
  const {
1510
1770
  scenarioComponentPaths: newScenarioComponentPaths,
1511
1771
  writtenScenarioComponents: updatedWrittenScenarioComponents,
1512
- } = await writeScenarioComponents({
1513
- project,
1514
- file: fileNotMocked,
1515
- entity: importedExportEntity,
1516
- rootAnalysis,
1517
- scenario,
1518
- context,
1519
- projectAnalyzer,
1520
- framework,
1521
- mocksDir,
1522
- rootFile,
1523
- namespaceMocks,
1524
- writtenScenarioComponents,
1525
- fileStore,
1526
- // Pass the import name so we can add `export { default as Name };`
1527
- exportAsNamed: needsNamedReExport
1528
- ? importedExport.name
1529
- : undefined,
1530
- });
1772
+ } = await withTimeout(
1773
+ `recursive writeScenarioComponents for ${importedExportEntity.name}`,
1774
+ writeScenarioComponents({
1775
+ project,
1776
+ file: fileNotMocked,
1777
+ entity: importedExportEntity,
1778
+ rootAnalysis,
1779
+ scenario,
1780
+ context,
1781
+ projectAnalyzer,
1782
+ framework,
1783
+ mocksDir,
1784
+ rootFile,
1785
+ namespaceMocks,
1786
+ writtenScenarioComponents,
1787
+ fileStore,
1788
+ // Pass the import name so we can add `export { default as Name };`
1789
+ exportAsNamed: needsNamedReExport
1790
+ ? importedExport.name
1791
+ : undefined,
1792
+ }),
1793
+ 60000, // 1 minute timeout for recursive calls
1794
+ );
1795
+ debugLog(
1796
+ `Completed recursive writeScenarioComponents for ${importedExportEntity.name}`,
1797
+ );
1531
1798
  writtenScenarioComponents = updatedWrittenScenarioComponents;
1532
1799
  scenarioComponentPaths.push(...newScenarioComponentPaths);
1533
1800
  }
@@ -1831,9 +2098,7 @@ ${exportKeyword}const ${functionName} = new Proxy(() => scenarios().data()?.["${
1831
2098
 
1832
2099
  // First, try to remove this entity from the already-rewritten grouped import
1833
2100
  // This prevents duplicate/conflicting imports
1834
- // IMPORTANT: Only remove from import statements, NOT from the entire file!
1835
- // The global patterns used previously would also match type annotations like:
1836
- // "param: MyType," in function signatures, corrupting the syntax.
2101
+ // Use AST-based removal to properly handle type-only imports like `type EntityName`
1837
2102
  const escapedEntityName = escapeRegExp(entityImportName);
1838
2103
 
1839
2104
  // For default imports: remove "DefaultName, " from "import DefaultName, { ... }"
@@ -1846,33 +2111,12 @@ ${exportKeyword}const ${functionName} = new Proxy(() => scenarios().data()?.["${
1846
2111
  fileContent = fileContent.replace(defaultImportPattern, '$1$2');
1847
2112
  }
1848
2113
 
1849
- // Match import statements that contain this entity and remove just the entity
1850
- // Pattern: import { ... EntityName, ... } from '...'
1851
- // We match the full import and use a replacer function to remove the entity name
1852
- const importWithEntityPattern = new RegExp(
1853
- `(import\\s*\\{)([^}]*\\b${escapedEntityName}\\b[^}]*)(\\}\\s*from\\s*['"][^'"]*['"];?)`,
1854
- 'gm',
1855
- );
1856
- fileContent = fileContent.replace(
1857
- importWithEntityPattern,
1858
- (match, prefix, namedImports, suffix) => {
1859
- // Remove the entity name from the named imports
1860
- let cleaned = namedImports
1861
- .replace(new RegExp(`\\b${escapedEntityName}\\s*,\\s*`), '') // "EntityName, "
1862
- .replace(new RegExp(`\\s*,\\s*${escapedEntityName}\\b`), '') // ", EntityName"
1863
- .replace(new RegExp(`\\b${escapedEntityName}\\b`), ''); // "EntityName" (only one)
1864
- // Clean up any double commas or leading/trailing commas
1865
- cleaned = cleaned
1866
- .replace(/,\s*,/g, ',')
1867
- .replace(/^\s*,\s*/, '')
1868
- .replace(/\s*,\s*$/, '');
1869
- // If no imports left, remove the entire import statement
1870
- if (cleaned.trim() === '') {
1871
- return '';
1872
- }
1873
- return prefix + cleaned + suffix;
1874
- },
1875
- );
2114
+ // Remove the named import using AST parsing
2115
+ // This properly handles:
2116
+ // - Regular imports: `import { EntityName } from '...'`
2117
+ // - Type-only imports: `import { type EntityName } from '...'`
2118
+ // - Mixed imports: `import { type EntityName, OtherName } from '...'`
2119
+ fileContent = removeNamedImportAst(fileContent, entityImportName);
1876
2120
 
1877
2121
  // Add the new import at the beginning of fileContent
1878
2122
  // Note: The header comment (// Scenario:) doesn't exist yet - it's prepended at writeFile time
@@ -1888,9 +2132,28 @@ ${exportKeyword}const ${functionName} = new Proxy(() => scenarios().data()?.["${
1888
2132
  }
1889
2133
  }
1890
2134
 
2135
+ // Collect universal mocks BEFORE processing nodeModuleImports
2136
+ // This is needed to check if a node module import is handled by a universal mock
2137
+ const universalMocks = project.metadata?.universalMocks ?? [];
2138
+ const nodeModuleUniversalMocks = universalMocks.filter(
2139
+ (mock) => mock.nodeModule && mock.content,
2140
+ );
2141
+
2142
+ // Create a set of import paths that have universal mocks for quick lookup
2143
+ const universalMockPaths = new Set(
2144
+ nodeModuleUniversalMocks.map((mock) => mock.filePath),
2145
+ );
2146
+
1891
2147
  for (const nodeModuleImport of nodeModuleImports) {
1892
2148
  if (!nodeModuleImport.isMocked) continue;
1893
2149
 
2150
+ // Skip generating local mock functions for imports that have universal mocks.
2151
+ // Universal mocks provide the exports via rewritten import paths (handled below).
2152
+ // Generating a local mock function would cause "name defined multiple times" errors.
2153
+ if (universalMockPaths.has(nodeModuleImport.filePath)) {
2154
+ continue;
2155
+ }
2156
+
1894
2157
  fileContent = addMockToContent(
1895
2158
  fileContent,
1896
2159
  nodeModuleImport,
@@ -1906,10 +2169,6 @@ ${exportKeyword}const ${functionName} = new Proxy(() => scenarios().data()?.["${
1906
2169
  // Universal mocks create mock files at __codeyamMocks__/{safeFileName}.tsx
1907
2170
  // We need to rewrite imports like `import { logger } from "@formbricks/logger"`
1908
2171
  // to `import { logger } from "../__codeyamMocks__/_formbricks_logger"`
1909
- const universalMocks = project.metadata?.universalMocks ?? [];
1910
- const nodeModuleUniversalMocks = universalMocks.filter(
1911
- (mock) => mock.nodeModule && mock.content,
1912
- );
1913
2172
 
1914
2173
  for (const universalMock of nodeModuleUniversalMocks) {
1915
2174
  const originalPath = universalMock.filePath;
@@ -1973,31 +2232,42 @@ ${exportKeyword}const ${functionName} = new Proxy(() => scenarios().data()?.["${
1973
2232
  });
1974
2233
  }
1975
2234
 
2235
+ debugLog('Route path computed', { scenarioComponentPath });
2236
+
1976
2237
  // Strip <html> and <body> tags from root layout files for Next.js
1977
2238
  // These tags cause hydration errors when the scenario layout is nested under the real root
2239
+ debugLog('Starting stripHtmlBodyTags');
1978
2240
  fileContent = stripHtmlBodyTags(fileContent, file.path, framework);
2241
+ debugLog('Completed stripHtmlBodyTags');
1979
2242
 
1980
2243
  // Strip "server-only" imports for Next.js
1981
2244
  // These cause errors when the scenario component is rendered client-side
2245
+ debugLog('Starting stripServerOnlyImport');
1982
2246
  fileContent = stripServerOnlyImport(fileContent);
2247
+ debugLog('Starting applyServerOnlyMocks');
1983
2248
  fileContent = applyServerOnlyMocks(fileContent);
2249
+ debugLog('Completed server-only processing');
1984
2250
 
1985
2251
  // Rewrite asset imports (CSS, images, fonts, etc.) to correct relative paths
1986
2252
  // The original file path is relative to PROJECT_RELATIVE_PATH, the new path is scenarioComponentPath
2253
+ debugLog('Starting rewriteAssetImports');
1987
2254
  fileContent = rewriteAssetImports(
1988
2255
  fileContent,
1989
2256
  `${PROJECT_RELATIVE_PATH}/${file.path}`,
1990
2257
  scenarioComponentPath,
1991
2258
  );
2259
+ debugLog('Completed rewriteAssetImports');
1992
2260
 
1993
2261
  // Rewrite relative TypeScript/JavaScript module imports to correct relative paths
1994
2262
  // This handles cases where the file is moved (e.g., from [environmentId]/ to _environmentId_/)
1995
2263
  // and relative imports like "./lib/organization" need to be rewritten
2264
+ debugLog('Starting rewriteRelativeModuleImports');
1996
2265
  fileContent = rewriteRelativeModuleImports(
1997
2266
  fileContent,
1998
2267
  `${PROJECT_RELATIVE_PATH}/${file.path}`,
1999
2268
  scenarioComponentPath,
2000
2269
  );
2270
+ debugLog('Completed rewriteRelativeModuleImports');
2001
2271
 
2002
2272
  /**
2003
2273
  * Recursively process a file's imports to create transitive copies with server-only stripped.
@@ -2015,21 +2285,65 @@ ${exportKeyword}const ${functionName} = new Proxy(() => scenarios().data()?.["${
2015
2285
  sourceFilePath: string,
2016
2286
  targetFilePath: string,
2017
2287
  visitedPaths: Set<string> = new Set(),
2288
+ depth: number = 0,
2289
+ startTime: number = Date.now(),
2018
2290
  ): Promise<string> {
2291
+ // Global timeout for entire transitive processing
2292
+ const GLOBAL_TIMEOUT_MS = 60000; // 1 minute max for all transitive processing
2293
+ const elapsed = Date.now() - startTime;
2294
+ if (elapsed > GLOBAL_TIMEOUT_MS) {
2295
+ throw new Error(
2296
+ `processTransitiveImportsRecursively exceeded ${GLOBAL_TIMEOUT_MS}ms (elapsed: ${elapsed}ms) at depth=${depth} for ${sourceFilePath}`,
2297
+ );
2298
+ }
2299
+
2019
2300
  const importPaths = extractInternalImportPaths(content);
2301
+ debugLog(`processTransitiveImportsRecursively depth=${depth}`, {
2302
+ sourceFilePath,
2303
+ importCount: importPaths.length,
2304
+ visitedCount: visitedPaths.size,
2305
+ });
2020
2306
  let modifiedContent = content;
2021
2307
 
2022
- for (const importPath of importPaths) {
2308
+ // Safety check: limit iterations to prevent infinite loops
2309
+ const MAX_IMPORTS_PER_FILE = 100;
2310
+ if (importPaths.length > MAX_IMPORTS_PER_FILE) {
2311
+ console.warn(
2312
+ `[WriteScenario] WARNING: File ${sourceFilePath} has ${importPaths.length} imports (> ${MAX_IMPORTS_PER_FILE}), limiting processing`,
2313
+ );
2314
+ }
2315
+
2316
+ let importIndex = 0;
2317
+ debugLog(
2318
+ `Starting import loop at depth=${depth}, ${importPaths.length} imports to process`,
2319
+ );
2320
+ const slicedImports = importPaths.slice(0, MAX_IMPORTS_PER_FILE);
2321
+ for (const importPath of slicedImports) {
2322
+ if (!importPath) {
2323
+ continue;
2324
+ }
2325
+ importIndex++;
2326
+ debugLog(
2327
+ `[LOOP] depth=${depth} import ${importIndex}/${Math.min(importPaths.length, MAX_IMPORTS_PER_FILE)}: ${importPath}`,
2328
+ );
2329
+ debugLog(`[LOOP] Calling resolveImportPath...`);
2023
2330
  const resolvedPath = resolveImportPath(
2024
2331
  importPath,
2025
2332
  sourceFilePath,
2026
2333
  project,
2027
2334
  );
2335
+ debugLog(
2336
+ `[LOOP] resolveImportPath returned: ${resolvedPath?.slice(0, 80) ?? 'null'}`,
2337
+ );
2028
2338
  if (!resolvedPath) continue;
2029
2339
 
2340
+ debugLog(`[LOOP] Looking up importFile...`);
2030
2341
  let importFile = fileStore
2031
2342
  ? fileStore.getByPath(resolvedPath)
2032
2343
  : project.files?.find((f) => f.path === resolvedPath);
2344
+ debugLog(
2345
+ `[LOOP] importFile lookup result: ${importFile ? 'found' : 'not found'}`,
2346
+ );
2033
2347
  if (!importFile) continue;
2034
2348
 
2035
2349
  // Build the transitive file path (needed for import rewriting even if we skip creating)
@@ -2064,14 +2378,37 @@ ${exportKeyword}const ${functionName} = new Proxy(() => scenarios().data()?.["${
2064
2378
  // Strip server-only and mock server-only packages, then recursively process imports
2065
2379
  let transitiveContent = stripServerOnlyImport(importFile.content);
2066
2380
  transitiveContent = applyServerOnlyMocks(transitiveContent);
2067
- transitiveContent = await processTransitiveImportsRecursively(
2068
- transitiveContent,
2069
- importFile.path,
2070
- transitiveFilePath,
2071
- visitedPaths,
2381
+ debugLog(
2382
+ `processTransitiveImportsRecursively depth=${depth} for ${importFile.path}`,
2383
+ );
2384
+ debugLog(
2385
+ `Calling processTransitiveImportsRecursively depth=${depth + 1} for ${importFile.path}`,
2386
+ );
2387
+ transitiveContent = await withTimeout(
2388
+ `processTransitiveImportsRecursively depth=${depth} for ${path.basename(importFile.path)}`,
2389
+ processTransitiveImportsRecursively(
2390
+ transitiveContent,
2391
+ importFile.path,
2392
+ transitiveFilePath,
2393
+ visitedPaths,
2394
+ depth + 1,
2395
+ startTime, // Pass through the original start time
2396
+ ),
2397
+ 30000, // 30 second timeout per transitive import
2398
+ );
2399
+ debugLog(
2400
+ `withTimeout returned for depth=${depth}, transitiveContent length=${transitiveContent.length}`,
2401
+ );
2402
+ debugLog(
2403
+ `Completed processTransitiveImportsRecursively depth=${depth} for ${importFile.path}`,
2072
2404
  );
2073
2405
 
2406
+ debugLog(`Writing transitive file depth=${depth}`, {
2407
+ transitiveFilePath: path.basename(transitiveFilePath),
2408
+ contentLength: transitiveContent.length,
2409
+ });
2074
2410
  await writeFile(transitiveFilePath, transitiveContent);
2411
+ debugLog(`Wrote transitive file depth=${depth}`);
2075
2412
  scenarioComponentPaths.push(transitiveFilePath);
2076
2413
 
2077
2414
  if (!writtenScenarioComponents[resolvedPath]) {
@@ -2085,6 +2422,10 @@ ${exportKeyword}const ${functionName} = new Proxy(() => scenarios().data()?.["${
2085
2422
 
2086
2423
  // ALWAYS rewrite the import to point to the transitive copy
2087
2424
  // (even for circular imports or already-processed files)
2425
+ debugLog(`Rewriting import path depth=${depth}`, {
2426
+ importPath,
2427
+ resolvedPath,
2428
+ });
2088
2429
  const relativePath = getRelativePath(targetFilePath, transitiveFilePath);
2089
2430
  const relativePathWithoutExt = relativePath.replace(
2090
2431
  /\.(ts|tsx|js|jsx)$/,
@@ -2095,30 +2436,75 @@ ${exportKeyword}const ${functionName} = new Proxy(() => scenarios().data()?.["${
2095
2436
  /[.*+?^${}()|[\]\\]/g,
2096
2437
  '\\$&',
2097
2438
  );
2098
- const importRegex = new RegExp(
2099
- `(from\\s*["'])${escapedImportPath}(["'])`,
2100
- 'g',
2101
- );
2102
- modifiedContent = modifiedContent.replace(
2103
- importRegex,
2104
- `$1${safeRelativePath}$2`,
2439
+ debugLog(`Applying regex depth=${depth}`, {
2440
+ escapedImportPath,
2441
+ contentLength: modifiedContent.length,
2442
+ });
2443
+ // Quick check if the import path even exists in content
2444
+ const simpleCheck = modifiedContent.includes(importPath);
2445
+ debugLog(
2446
+ `Simple check: importPath "${importPath}" exists: ${simpleCheck}`,
2105
2447
  );
2448
+ if (!simpleCheck) {
2449
+ debugLog(`Skipping regex - import path not found in content`);
2450
+ } else {
2451
+ const regexPattern = `(from\\s*["'])${escapedImportPath}(["'])`;
2452
+ debugLog(`Regex pattern: ${regexPattern.slice(0, 100)}`);
2453
+ const importRegex = new RegExp(regexPattern, 'g');
2454
+ debugLog(`About to call replace...`);
2455
+
2456
+ // Timing for regex replace to detect slow operations
2457
+ const replaceStart = Date.now();
2458
+ modifiedContent = modifiedContent.replace(
2459
+ importRegex,
2460
+ `$1${safeRelativePath}$2`,
2461
+ );
2462
+ const replaceTime = Date.now() - replaceStart;
2463
+ if (replaceTime > 100) {
2464
+ console.warn(
2465
+ `[WriteScenario] SLOW regex replace: ${replaceTime}ms for pattern ${regexPattern.slice(0, 50)} on ${modifiedContent.length} bytes`,
2466
+ );
2467
+ }
2468
+ debugLog(`Regex applied depth=${depth} in ${replaceTime}ms`);
2469
+ }
2470
+ debugLog(`[LOOP END] depth=${depth} import ${importIndex} completed`);
2106
2471
  }
2107
2472
 
2473
+ debugLog(`[LOOP DONE] Exiting import loop at depth=${depth}`);
2474
+ debugLog(
2475
+ `Returning from processTransitiveImportsRecursively depth=${depth}`,
2476
+ );
2108
2477
  return modifiedContent;
2109
2478
  }
2110
2479
 
2111
2480
  // Process remaining internal imports that weren't in importedExports
2112
2481
  // This handles transitive dependencies: when the file content includes code (e.g., from
2113
2482
  // other functions in the same file) that imports from files with "server-only"
2483
+ debugLog('Extracting remaining import paths');
2114
2484
  const remainingImportPaths = extractInternalImportPaths(fileContent);
2485
+ debugLog('Found remaining import paths', {
2486
+ count: remainingImportPaths.length,
2487
+ });
2115
2488
 
2116
2489
  // Get all file paths that are in importedExports - these are handled by main processing
2117
2490
  const importedExportFilePaths = new Set(
2118
2491
  allImportedExports.map((ie) => ie.resolvedFilePath || ie.filePath),
2119
2492
  );
2120
2493
 
2494
+ debugLog('Starting remaining imports loop', {
2495
+ remainingCount: remainingImportPaths.length,
2496
+ importedExportCount: importedExportFilePaths.size,
2497
+ });
2498
+
2499
+ let remainingImportIndex = 0;
2500
+ debugLog(
2501
+ `[REMAINING] Starting remaining imports loop, ${remainingImportPaths.length} imports`,
2502
+ );
2121
2503
  for (const importPath of remainingImportPaths) {
2504
+ remainingImportIndex++;
2505
+ debugLog(
2506
+ `[REMAINING LOOP] import ${remainingImportIndex}/${remainingImportPaths.length}: ${importPath}`,
2507
+ );
2122
2508
  // Resolve the import path to a project file path
2123
2509
  const resolvedFilePath = resolveImportPath(importPath, file.path, project);
2124
2510
 
@@ -2194,7 +2580,15 @@ ${exportKeyword}const ${functionName} = new Proxy(() => scenarios().data()?.["${
2194
2580
  // Recursively process this transitive file's imports
2195
2581
  // This handles the nested case: service.ts → brevo.ts → constants.ts
2196
2582
  const nestedImportPaths = extractInternalImportPaths(transformedContent);
2583
+ debugLog(
2584
+ `[NESTED] Processing ${nestedImportPaths.length} nested imports for ${targetFile.path}`,
2585
+ );
2586
+ let nestedIndex = 0;
2197
2587
  for (const nestedImportPath of nestedImportPaths) {
2588
+ nestedIndex++;
2589
+ debugLog(
2590
+ `[NESTED LOOP] import ${nestedIndex}/${nestedImportPaths.length}: ${nestedImportPath}`,
2591
+ );
2198
2592
  const nestedResolvedPath = resolveImportPath(
2199
2593
  nestedImportPath,
2200
2594
  targetFile.path,
@@ -2235,10 +2629,20 @@ ${exportKeyword}const ${functionName} = new Proxy(() => scenarios().data()?.["${
2235
2629
  // This handles chains of any depth: A -> B -> C -> D
2236
2630
  let nestedContent = stripServerOnlyImport(nestedFile.content);
2237
2631
  nestedContent = applyServerOnlyMocks(nestedContent);
2238
- nestedContent = await processTransitiveImportsRecursively(
2239
- nestedContent,
2240
- nestedFile.path,
2241
- nestedTransformedPath,
2632
+ debugLog(
2633
+ `processTransitiveImportsRecursively (nested) for ${nestedFile.path}`,
2634
+ );
2635
+ nestedContent = await withTimeout(
2636
+ `processTransitiveImportsRecursively (nested) for ${path.basename(nestedFile.path)}`,
2637
+ processTransitiveImportsRecursively(
2638
+ nestedContent,
2639
+ nestedFile.path,
2640
+ nestedTransformedPath,
2641
+ ),
2642
+ 30000, // 30 second timeout per nested transitive import
2643
+ );
2644
+ debugLog(
2645
+ `Completed processTransitiveImportsRecursively (nested) for ${nestedFile.path}`,
2242
2646
  );
2243
2647
 
2244
2648
  await writeFile(nestedTransformedPath, nestedContent);
@@ -2350,7 +2754,12 @@ ${exportKeyword}const ${functionName} = new Proxy(() => scenarios().data()?.["${
2350
2754
  finalContent = `${scenarioComponentComment}\n\n${fileContent}`;
2351
2755
  }
2352
2756
 
2757
+ debugLog('About to write final scenario file', {
2758
+ scenarioComponentPath,
2759
+ contentLength: finalContent.length,
2760
+ });
2353
2761
  await writeFile(scenarioComponentPath, finalContent);
2762
+ debugLog('Successfully wrote scenario file');
2354
2763
  scenarioComponentPaths.push(scenarioComponentPath);
2355
2764
 
2356
2765
  return { scenarioComponentPaths, writtenScenarioComponents };