@codeyam/codeyam-cli 0.1.0-staging.596f0eb → 0.1.0-staging.6e699e5

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 (696) hide show
  1. package/analyzer-template/.build-info.json +8 -8
  2. package/analyzer-template/common/execAsync.ts +1 -1
  3. package/analyzer-template/log.txt +3 -3
  4. package/analyzer-template/package.json +10 -6
  5. package/analyzer-template/packages/ai/index.ts +10 -3
  6. package/analyzer-template/packages/ai/package.json +1 -1
  7. package/analyzer-template/packages/ai/src/lib/__mocks__/completionCall.ts +122 -0
  8. package/analyzer-template/packages/ai/src/lib/analyzeScope.ts +128 -6
  9. package/analyzer-template/packages/ai/src/lib/astScopes/arrayDerivationDetector.ts +199 -0
  10. package/analyzer-template/packages/ai/src/lib/astScopes/astScopeAnalyzer.ts +138 -1
  11. package/analyzer-template/packages/ai/src/lib/astScopes/conditionalEffectsExtractor.ts +644 -0
  12. package/analyzer-template/packages/ai/src/lib/astScopes/methodSemantics.ts +140 -6
  13. package/analyzer-template/packages/ai/src/lib/astScopes/patterns/ifStatementHandler.ts +18 -0
  14. package/analyzer-template/packages/ai/src/lib/astScopes/patterns/switchStatementHandler.ts +38 -1
  15. package/analyzer-template/packages/ai/src/lib/astScopes/patterns/variableDeclarationHandler.ts +181 -1
  16. package/analyzer-template/packages/ai/src/lib/astScopes/processExpression.ts +1239 -104
  17. package/analyzer-template/packages/ai/src/lib/astScopes/types.ts +304 -0
  18. package/analyzer-template/packages/ai/src/lib/checkAllAttributes.ts +29 -10
  19. package/analyzer-template/packages/ai/src/lib/completionCall.ts +216 -36
  20. package/analyzer-template/packages/ai/src/lib/dataStructure/ScopeDataStructure.ts +1501 -138
  21. package/analyzer-template/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/JavascriptFrameworkManager.ts +2 -1
  22. package/analyzer-template/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/MuiManager.ts +976 -0
  23. package/analyzer-template/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/ReactFrameworkManager.ts +243 -77
  24. package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/cleanKnownObjectFunctions.ts +19 -1
  25. package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/cleanNonObjectFunctions.ts +103 -6
  26. package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/convertDotNotation.ts +23 -0
  27. package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/convertNullToUndefinedBySchema.ts +98 -0
  28. package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/fillInSchemaGapsAndUnknowns.ts +42 -2
  29. package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/fixNullIdsBySchema.ts +129 -0
  30. package/analyzer-template/packages/ai/src/lib/dataStructureChunking.ts +156 -0
  31. package/analyzer-template/packages/ai/src/lib/deepEqual.ts +30 -0
  32. package/analyzer-template/packages/ai/src/lib/e2eDataTracking.ts +334 -0
  33. package/analyzer-template/packages/ai/src/lib/extractCriticalDataKeys.ts +120 -0
  34. package/analyzer-template/packages/ai/src/lib/generateChangesEntityScenarioData.ts +74 -7
  35. package/analyzer-template/packages/ai/src/lib/generateChangesEntityScenarios.ts +89 -112
  36. package/analyzer-template/packages/ai/src/lib/generateEntityDataStructure.ts +6 -0
  37. package/analyzer-template/packages/ai/src/lib/generateEntityScenarioData.ts +1111 -91
  38. package/analyzer-template/packages/ai/src/lib/generateEntityScenarios.ts +207 -104
  39. package/analyzer-template/packages/ai/src/lib/generateExecutionFlows.ts +570 -0
  40. package/analyzer-template/packages/ai/src/lib/generateExecutionFlowsFromConditionalEffects.ts +528 -0
  41. package/analyzer-template/packages/ai/src/lib/generateExecutionFlowsFromConditionals.ts +1977 -0
  42. package/analyzer-template/packages/ai/src/lib/generateExecutionFlowsFromJsxUsages.ts +239 -0
  43. package/analyzer-template/packages/ai/src/lib/getConditionalUsagesFromCode.ts +143 -31
  44. package/analyzer-template/packages/ai/src/lib/guessScenarioDataFromDescription.ts +8 -2
  45. package/analyzer-template/packages/ai/src/lib/isolateScopes.ts +276 -3
  46. package/analyzer-template/packages/ai/src/lib/mergeStatements.ts +33 -3
  47. package/analyzer-template/packages/ai/src/lib/promptGenerators/gatherAttributesMap.ts +7 -0
  48. package/analyzer-template/packages/ai/src/lib/promptGenerators/generateChangesEntityScenarioDataGenerator.ts +1 -1
  49. package/analyzer-template/packages/ai/src/lib/promptGenerators/generateChangesEntityScenariosGenerator.ts +32 -102
  50. package/analyzer-template/packages/ai/src/lib/promptGenerators/generateChunkPrompt.ts +82 -0
  51. package/analyzer-template/packages/ai/src/lib/promptGenerators/generateCriticalKeysPrompt.ts +103 -0
  52. package/analyzer-template/packages/ai/src/lib/promptGenerators/generateEntityScenarioDataGenerator.ts +90 -6
  53. package/analyzer-template/packages/ai/src/lib/promptGenerators/generateEntityScenariosGenerator.ts +14 -53
  54. package/analyzer-template/packages/ai/src/lib/promptGenerators/generateMissingKeysPrompt.ts +58 -0
  55. package/analyzer-template/packages/ai/src/lib/promptGenerators/guessNewScenarioDataFromDescriptionGenerator.ts +28 -2
  56. package/analyzer-template/packages/ai/src/lib/promptGenerators/simplifyKeysForLLM.ts +391 -0
  57. package/analyzer-template/packages/ai/src/lib/resolvePathToControllable.ts +812 -0
  58. package/analyzer-template/packages/ai/src/lib/splitOutsideParentheses.ts +5 -1
  59. package/analyzer-template/packages/ai/src/lib/validateExecutionFlowPaths.ts +531 -0
  60. package/analyzer-template/packages/ai/src/lib/worker/SerializableDataStructure.ts +123 -0
  61. package/analyzer-template/packages/ai/src/lib/worker/analyzeScopeWorker.ts +8 -1
  62. package/analyzer-template/packages/analyze/src/lib/FileAnalyzer.ts +14 -0
  63. package/analyzer-template/packages/analyze/src/lib/analysisContext.ts +44 -4
  64. package/analyzer-template/packages/analyze/src/lib/asts/nodes/index.ts +1 -0
  65. package/analyzer-template/packages/analyze/src/lib/asts/nodes/isAsyncFunction.ts +67 -0
  66. package/analyzer-template/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.ts +455 -267
  67. package/analyzer-template/packages/analyze/src/lib/files/analyze/analyzeEntities.ts +18 -0
  68. package/analyzer-template/packages/analyze/src/lib/files/analyze/findOrCreateEntity.ts +3 -0
  69. package/analyzer-template/packages/analyze/src/lib/files/analyze/validateDependencyAnalyses.ts +33 -7
  70. package/analyzer-template/packages/analyze/src/lib/files/analyzeChange.ts +31 -15
  71. package/analyzer-template/packages/analyze/src/lib/files/analyzeEntity.ts +11 -7
  72. package/analyzer-template/packages/analyze/src/lib/files/analyzeInitial.ts +11 -12
  73. package/analyzer-template/packages/analyze/src/lib/files/enums/steps.ts +1 -1
  74. package/analyzer-template/packages/analyze/src/lib/files/scenarios/enrichArrayTypesFromChildSignatures.ts +265 -0
  75. package/analyzer-template/packages/analyze/src/lib/files/scenarios/enrichUnknownTypesFromSourceEquivalencies.ts +102 -0
  76. package/analyzer-template/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.ts +588 -52
  77. package/analyzer-template/packages/analyze/src/lib/files/scenarios/generateChangesScenarioData.ts +1 -1
  78. package/analyzer-template/packages/analyze/src/lib/files/scenarios/generateChangesScenarios.ts +28 -62
  79. package/analyzer-template/packages/analyze/src/lib/files/scenarios/generateDataStructure.ts +336 -133
  80. package/analyzer-template/packages/analyze/src/lib/files/scenarios/generateExecutionFlows.ts +156 -0
  81. package/analyzer-template/packages/analyze/src/lib/files/scenarios/generateScenarioData.ts +78 -83
  82. package/analyzer-template/packages/analyze/src/lib/files/scenarios/generateScenarios.ts +4 -8
  83. package/analyzer-template/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.ts +461 -94
  84. package/analyzer-template/packages/analyze/src/lib/files/scenarios/mergeValidatedDataStructures.ts +56 -11
  85. package/analyzer-template/packages/aws/codebuild/index.ts +1 -0
  86. package/analyzer-template/packages/aws/dist/src/lib/codebuild/waitForBuild.d.ts +11 -1
  87. package/analyzer-template/packages/aws/dist/src/lib/codebuild/waitForBuild.d.ts.map +1 -1
  88. package/analyzer-template/packages/aws/dist/src/lib/codebuild/waitForBuild.js +29 -18
  89. package/analyzer-template/packages/aws/dist/src/lib/codebuild/waitForBuild.js.map +1 -1
  90. package/analyzer-template/packages/aws/dist/src/lib/ecs/ecsDefineContainer.d.ts +2 -2
  91. package/analyzer-template/packages/aws/dist/src/lib/ecs/ecsDefineContainer.d.ts.map +1 -1
  92. package/analyzer-template/packages/aws/dist/src/lib/ecs/ecsDefineContainer.js +2 -2
  93. package/analyzer-template/packages/aws/dist/src/lib/ecs/ecsDefineContainer.js.map +1 -1
  94. package/analyzer-template/packages/aws/dist/src/lib/ecs/ecsTaskFactory.d.ts +8 -18
  95. package/analyzer-template/packages/aws/dist/src/lib/ecs/ecsTaskFactory.d.ts.map +1 -1
  96. package/analyzer-template/packages/aws/dist/src/lib/ecs/ecsTaskFactory.js +17 -61
  97. package/analyzer-template/packages/aws/dist/src/lib/ecs/ecsTaskFactory.js.map +1 -1
  98. package/analyzer-template/packages/aws/dist/src/lib/s3/checkS3ObjectExists.d.ts +15 -0
  99. package/analyzer-template/packages/aws/dist/src/lib/s3/checkS3ObjectExists.d.ts.map +1 -0
  100. package/analyzer-template/packages/aws/dist/src/lib/s3/checkS3ObjectExists.js +31 -0
  101. package/analyzer-template/packages/aws/dist/src/lib/s3/checkS3ObjectExists.js.map +1 -0
  102. package/analyzer-template/packages/aws/dist/src/lib/s3/uploadFileToS3.d.ts.map +1 -1
  103. package/analyzer-template/packages/aws/dist/src/lib/s3/uploadFileToS3.js +8 -1
  104. package/analyzer-template/packages/aws/dist/src/lib/s3/uploadFileToS3.js.map +1 -1
  105. package/analyzer-template/packages/aws/package.json +3 -3
  106. package/analyzer-template/packages/aws/s3/index.ts +1 -0
  107. package/analyzer-template/packages/aws/src/lib/codebuild/waitForBuild.ts +43 -19
  108. package/analyzer-template/packages/aws/src/lib/ecs/ecsDefineContainer.ts +3 -3
  109. package/analyzer-template/packages/aws/src/lib/ecs/ecsTaskFactory.ts +17 -69
  110. package/analyzer-template/packages/aws/src/lib/s3/checkS3ObjectExists.ts +47 -0
  111. package/analyzer-template/packages/aws/src/lib/s3/uploadFileToS3.ts +8 -1
  112. package/analyzer-template/packages/database/src/lib/kysely/db.ts +4 -4
  113. package/analyzer-template/packages/database/src/lib/kysely/tableRelations.ts +2 -2
  114. package/analyzer-template/packages/database/src/lib/kysely/tables/debugReportsTable.ts +36 -9
  115. package/analyzer-template/packages/database/src/lib/loadReadyToBeCapturedAnalyses.ts +7 -3
  116. package/analyzer-template/packages/generate/index.ts +3 -0
  117. package/analyzer-template/packages/generate/src/lib/componentScenarioPage/componentScenarioPageNext.ts +17 -1
  118. package/analyzer-template/packages/generate/src/lib/componentScenarioPage/generateScenarioClientWrapper.ts +193 -0
  119. package/analyzer-template/packages/generate/src/lib/componentScenarioPage/generateScenarioServerComponent.ts +73 -0
  120. package/analyzer-template/packages/generate/src/lib/componentScenarioPage/getIFrameMessageListenerCode.ts +9 -4
  121. package/analyzer-template/packages/generate/src/lib/deepMerge.ts +26 -1
  122. package/analyzer-template/packages/generate/src/lib/scenarioComponentForServer.ts +114 -0
  123. package/analyzer-template/packages/github/dist/database/src/lib/kysely/db.d.ts +2 -2
  124. package/analyzer-template/packages/github/dist/database/src/lib/kysely/db.js +2 -2
  125. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tableRelations.d.ts +2 -2
  126. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/analysesTable.d.ts +1 -11
  127. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/analysesTable.d.ts.map +1 -1
  128. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/debugReportsTable.d.ts +30 -7
  129. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/debugReportsTable.d.ts.map +1 -1
  130. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/debugReportsTable.js +9 -3
  131. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/debugReportsTable.js.map +1 -1
  132. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/entitiesTable.d.ts +1 -0
  133. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/entitiesTable.d.ts.map +1 -1
  134. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/scenariosTable.d.ts +2 -6
  135. package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/scenariosTable.d.ts.map +1 -1
  136. package/analyzer-template/packages/github/dist/database/src/lib/loadReadyToBeCapturedAnalyses.d.ts.map +1 -1
  137. package/analyzer-template/packages/github/dist/database/src/lib/loadReadyToBeCapturedAnalyses.js +7 -4
  138. package/analyzer-template/packages/github/dist/database/src/lib/loadReadyToBeCapturedAnalyses.js.map +1 -1
  139. package/analyzer-template/packages/github/dist/generate/index.d.ts +3 -0
  140. package/analyzer-template/packages/github/dist/generate/index.d.ts.map +1 -1
  141. package/analyzer-template/packages/github/dist/generate/index.js +3 -0
  142. package/analyzer-template/packages/github/dist/generate/index.js.map +1 -1
  143. package/analyzer-template/packages/github/dist/generate/src/lib/componentScenarioPage/componentScenarioPageNext.d.ts.map +1 -1
  144. package/analyzer-template/packages/github/dist/generate/src/lib/componentScenarioPage/componentScenarioPageNext.js +16 -1
  145. package/analyzer-template/packages/github/dist/generate/src/lib/componentScenarioPage/componentScenarioPageNext.js.map +1 -1
  146. package/analyzer-template/packages/github/dist/generate/src/lib/componentScenarioPage/generateScenarioClientWrapper.d.ts +9 -0
  147. package/analyzer-template/packages/github/dist/generate/src/lib/componentScenarioPage/generateScenarioClientWrapper.d.ts.map +1 -0
  148. package/analyzer-template/packages/github/dist/generate/src/lib/componentScenarioPage/generateScenarioClientWrapper.js +189 -0
  149. package/analyzer-template/packages/github/dist/generate/src/lib/componentScenarioPage/generateScenarioClientWrapper.js.map +1 -0
  150. package/analyzer-template/packages/github/dist/generate/src/lib/componentScenarioPage/generateScenarioServerComponent.d.ts +20 -0
  151. package/analyzer-template/packages/github/dist/generate/src/lib/componentScenarioPage/generateScenarioServerComponent.d.ts.map +1 -0
  152. package/analyzer-template/packages/github/dist/generate/src/lib/componentScenarioPage/generateScenarioServerComponent.js +53 -0
  153. package/analyzer-template/packages/github/dist/generate/src/lib/componentScenarioPage/generateScenarioServerComponent.js.map +1 -0
  154. package/analyzer-template/packages/github/dist/generate/src/lib/componentScenarioPage/getIFrameMessageListenerCode.d.ts.map +1 -1
  155. package/analyzer-template/packages/github/dist/generate/src/lib/componentScenarioPage/getIFrameMessageListenerCode.js +8 -4
  156. package/analyzer-template/packages/github/dist/generate/src/lib/componentScenarioPage/getIFrameMessageListenerCode.js.map +1 -1
  157. package/analyzer-template/packages/github/dist/generate/src/lib/deepMerge.d.ts.map +1 -1
  158. package/analyzer-template/packages/github/dist/generate/src/lib/deepMerge.js +27 -1
  159. package/analyzer-template/packages/github/dist/generate/src/lib/deepMerge.js.map +1 -1
  160. package/analyzer-template/packages/github/dist/generate/src/lib/scenarioComponentForServer.d.ts +8 -0
  161. package/analyzer-template/packages/github/dist/generate/src/lib/scenarioComponentForServer.d.ts.map +1 -0
  162. package/analyzer-template/packages/github/dist/generate/src/lib/scenarioComponentForServer.js +89 -0
  163. package/analyzer-template/packages/github/dist/generate/src/lib/scenarioComponentForServer.js.map +1 -0
  164. package/analyzer-template/packages/github/dist/github/src/lib/loadOrCreateCommit.d.ts.map +1 -1
  165. package/analyzer-template/packages/github/dist/github/src/lib/loadOrCreateCommit.js +10 -0
  166. package/analyzer-template/packages/github/dist/github/src/lib/loadOrCreateCommit.js.map +1 -1
  167. package/analyzer-template/packages/github/dist/github/src/lib/syncPrimaryBranch.d.ts.map +1 -1
  168. package/analyzer-template/packages/github/dist/github/src/lib/syncPrimaryBranch.js +3 -0
  169. package/analyzer-template/packages/github/dist/github/src/lib/syncPrimaryBranch.js.map +1 -1
  170. package/analyzer-template/packages/github/dist/types/index.d.ts +2 -2
  171. package/analyzer-template/packages/github/dist/types/index.d.ts.map +1 -1
  172. package/analyzer-template/packages/github/dist/types/index.js.map +1 -1
  173. package/analyzer-template/packages/github/dist/types/src/types/Analysis.d.ts +87 -13
  174. package/analyzer-template/packages/github/dist/types/src/types/Analysis.d.ts.map +1 -1
  175. package/analyzer-template/packages/github/dist/types/src/types/Entity.d.ts +2 -0
  176. package/analyzer-template/packages/github/dist/types/src/types/Entity.d.ts.map +1 -1
  177. package/analyzer-template/packages/github/dist/types/src/types/Scenario.d.ts +11 -6
  178. package/analyzer-template/packages/github/dist/types/src/types/Scenario.d.ts.map +1 -1
  179. package/analyzer-template/packages/github/dist/types/src/types/ScenariosDataStructure.d.ts +196 -0
  180. package/analyzer-template/packages/github/dist/types/src/types/ScenariosDataStructure.d.ts.map +1 -1
  181. package/analyzer-template/packages/github/dist/types/src/types/StatementInfo.d.ts +2 -0
  182. package/analyzer-template/packages/github/dist/types/src/types/StatementInfo.d.ts.map +1 -1
  183. package/analyzer-template/packages/github/dist/utils/src/lib/lightweightEntityExtractor.d.ts.map +1 -1
  184. package/analyzer-template/packages/github/dist/utils/src/lib/lightweightEntityExtractor.js +25 -0
  185. package/analyzer-template/packages/github/dist/utils/src/lib/lightweightEntityExtractor.js.map +1 -1
  186. package/analyzer-template/packages/github/dist/utils/src/lib/safeFileName.d.ts +9 -1
  187. package/analyzer-template/packages/github/dist/utils/src/lib/safeFileName.d.ts.map +1 -1
  188. package/analyzer-template/packages/github/dist/utils/src/lib/safeFileName.js +29 -3
  189. package/analyzer-template/packages/github/dist/utils/src/lib/safeFileName.js.map +1 -1
  190. package/analyzer-template/packages/github/src/lib/loadOrCreateCommit.ts +14 -0
  191. package/analyzer-template/packages/github/src/lib/syncPrimaryBranch.ts +2 -0
  192. package/analyzer-template/packages/process/index.ts +2 -0
  193. package/analyzer-template/packages/process/package.json +12 -0
  194. package/analyzer-template/packages/process/tsconfig.json +8 -0
  195. package/analyzer-template/packages/types/index.ts +5 -0
  196. package/analyzer-template/packages/types/src/types/Analysis.ts +104 -13
  197. package/analyzer-template/packages/types/src/types/Entity.ts +2 -0
  198. package/analyzer-template/packages/types/src/types/Scenario.ts +11 -10
  199. package/analyzer-template/packages/types/src/types/ScenariosDataStructure.ts +224 -0
  200. package/analyzer-template/packages/types/src/types/StatementInfo.ts +2 -0
  201. package/analyzer-template/packages/ui-components/src/components/ScenarioDetailInteractiveView.tsx +23 -7
  202. package/analyzer-template/packages/utils/dist/types/index.d.ts +2 -2
  203. package/analyzer-template/packages/utils/dist/types/index.d.ts.map +1 -1
  204. package/analyzer-template/packages/utils/dist/types/index.js.map +1 -1
  205. package/analyzer-template/packages/utils/dist/types/src/types/Analysis.d.ts +87 -13
  206. package/analyzer-template/packages/utils/dist/types/src/types/Analysis.d.ts.map +1 -1
  207. package/analyzer-template/packages/utils/dist/types/src/types/Entity.d.ts +2 -0
  208. package/analyzer-template/packages/utils/dist/types/src/types/Entity.d.ts.map +1 -1
  209. package/analyzer-template/packages/utils/dist/types/src/types/Scenario.d.ts +11 -6
  210. package/analyzer-template/packages/utils/dist/types/src/types/Scenario.d.ts.map +1 -1
  211. package/analyzer-template/packages/utils/dist/types/src/types/ScenariosDataStructure.d.ts +196 -0
  212. package/analyzer-template/packages/utils/dist/types/src/types/ScenariosDataStructure.d.ts.map +1 -1
  213. package/analyzer-template/packages/utils/dist/types/src/types/StatementInfo.d.ts +2 -0
  214. package/analyzer-template/packages/utils/dist/types/src/types/StatementInfo.d.ts.map +1 -1
  215. package/analyzer-template/packages/utils/dist/utils/src/lib/lightweightEntityExtractor.d.ts.map +1 -1
  216. package/analyzer-template/packages/utils/dist/utils/src/lib/lightweightEntityExtractor.js +25 -0
  217. package/analyzer-template/packages/utils/dist/utils/src/lib/lightweightEntityExtractor.js.map +1 -1
  218. package/analyzer-template/packages/utils/dist/utils/src/lib/safeFileName.d.ts +9 -1
  219. package/analyzer-template/packages/utils/dist/utils/src/lib/safeFileName.d.ts.map +1 -1
  220. package/analyzer-template/packages/utils/dist/utils/src/lib/safeFileName.js +29 -3
  221. package/analyzer-template/packages/utils/dist/utils/src/lib/safeFileName.js.map +1 -1
  222. package/analyzer-template/packages/utils/src/lib/lightweightEntityExtractor.ts +27 -0
  223. package/analyzer-template/packages/utils/src/lib/safeFileName.ts +48 -3
  224. package/analyzer-template/playwright/capture.ts +37 -18
  225. package/analyzer-template/playwright/getCodeYamInfo.ts +12 -7
  226. package/analyzer-template/playwright/takeElementScreenshot.ts +26 -11
  227. package/analyzer-template/playwright/takeScreenshot.ts +9 -7
  228. package/analyzer-template/playwright/waitForServer.ts +21 -6
  229. package/analyzer-template/project/analyzeBaselineCommit.ts +4 -0
  230. package/analyzer-template/project/analyzeBranchCommit.ts +4 -0
  231. package/analyzer-template/project/analyzeFileEntities.ts +4 -0
  232. package/analyzer-template/project/analyzeRegularCommit.ts +4 -0
  233. package/analyzer-template/project/constructMockCode.ts +1181 -160
  234. package/analyzer-template/project/controller/startController.ts +16 -1
  235. package/analyzer-template/project/executeLibraryFunctionDirect.ts +7 -3
  236. package/analyzer-template/project/mocks/analyzeFileMock.ts +8 -7
  237. package/analyzer-template/project/orchestrateCapture/KyselyAnalysisLoader.ts +3 -6
  238. package/analyzer-template/project/orchestrateCapture/SequentialCaptureTaskRunner.ts +82 -36
  239. package/analyzer-template/project/orchestrateCapture.ts +36 -3
  240. package/analyzer-template/project/reconcileMockDataKeys.ts +245 -2
  241. package/analyzer-template/project/runAnalysis.ts +11 -0
  242. package/analyzer-template/project/runMultiScenarioServer.ts +11 -10
  243. package/analyzer-template/project/serverOnlyModules.ts +194 -21
  244. package/analyzer-template/project/start.ts +26 -4
  245. package/analyzer-template/project/startScenarioCapture.ts +79 -41
  246. package/analyzer-template/project/writeMockDataTsx.ts +232 -57
  247. package/analyzer-template/project/writeScenarioClientWrapper.ts +21 -0
  248. package/analyzer-template/project/writeScenarioComponents.ts +769 -181
  249. package/analyzer-template/project/writeScenarioFiles.ts +26 -0
  250. package/analyzer-template/project/writeSimpleRoot.ts +13 -15
  251. package/analyzer-template/scripts/comboWorkerLoop.cjs +1 -0
  252. package/analyzer-template/scripts/defaultCmd.sh +9 -0
  253. package/analyzer-template/tsconfig.json +2 -1
  254. package/background/src/lib/local/createLocalAnalyzer.js +1 -29
  255. package/background/src/lib/local/createLocalAnalyzer.js.map +1 -1
  256. package/background/src/lib/local/execAsync.js +1 -1
  257. package/background/src/lib/local/execAsync.js.map +1 -1
  258. package/background/src/lib/virtualized/common/execAsync.js +1 -1
  259. package/background/src/lib/virtualized/common/execAsync.js.map +1 -1
  260. package/background/src/lib/virtualized/project/analyzeBaselineCommit.js +2 -1
  261. package/background/src/lib/virtualized/project/analyzeBaselineCommit.js.map +1 -1
  262. package/background/src/lib/virtualized/project/analyzeBranchCommit.js +2 -1
  263. package/background/src/lib/virtualized/project/analyzeBranchCommit.js.map +1 -1
  264. package/background/src/lib/virtualized/project/analyzeFileEntities.js +2 -1
  265. package/background/src/lib/virtualized/project/analyzeFileEntities.js.map +1 -1
  266. package/background/src/lib/virtualized/project/analyzeRegularCommit.js +2 -1
  267. package/background/src/lib/virtualized/project/analyzeRegularCommit.js.map +1 -1
  268. package/background/src/lib/virtualized/project/constructMockCode.js +1053 -124
  269. package/background/src/lib/virtualized/project/constructMockCode.js.map +1 -1
  270. package/background/src/lib/virtualized/project/controller/startController.js +11 -1
  271. package/background/src/lib/virtualized/project/controller/startController.js.map +1 -1
  272. package/background/src/lib/virtualized/project/executeLibraryFunctionDirect.js +6 -3
  273. package/background/src/lib/virtualized/project/executeLibraryFunctionDirect.js.map +1 -1
  274. package/background/src/lib/virtualized/project/mocks/analyzeFileMock.js +7 -7
  275. package/background/src/lib/virtualized/project/mocks/analyzeFileMock.js.map +1 -1
  276. package/background/src/lib/virtualized/project/orchestrateCapture/KyselyAnalysisLoader.js +3 -2
  277. package/background/src/lib/virtualized/project/orchestrateCapture/KyselyAnalysisLoader.js.map +1 -1
  278. package/background/src/lib/virtualized/project/orchestrateCapture/SequentialCaptureTaskRunner.js +69 -32
  279. package/background/src/lib/virtualized/project/orchestrateCapture/SequentialCaptureTaskRunner.js.map +1 -1
  280. package/background/src/lib/virtualized/project/orchestrateCapture.js +27 -4
  281. package/background/src/lib/virtualized/project/orchestrateCapture.js.map +1 -1
  282. package/background/src/lib/virtualized/project/reconcileMockDataKeys.js +204 -2
  283. package/background/src/lib/virtualized/project/reconcileMockDataKeys.js.map +1 -1
  284. package/background/src/lib/virtualized/project/runAnalysis.js +9 -0
  285. package/background/src/lib/virtualized/project/runAnalysis.js.map +1 -1
  286. package/background/src/lib/virtualized/project/runMultiScenarioServer.js +11 -9
  287. package/background/src/lib/virtualized/project/runMultiScenarioServer.js.map +1 -1
  288. package/background/src/lib/virtualized/project/serverOnlyModules.js +163 -23
  289. package/background/src/lib/virtualized/project/serverOnlyModules.js.map +1 -1
  290. package/background/src/lib/virtualized/project/start.js +21 -4
  291. package/background/src/lib/virtualized/project/start.js.map +1 -1
  292. package/background/src/lib/virtualized/project/startScenarioCapture.js +61 -31
  293. package/background/src/lib/virtualized/project/startScenarioCapture.js.map +1 -1
  294. package/background/src/lib/virtualized/project/writeMockDataTsx.js +199 -50
  295. package/background/src/lib/virtualized/project/writeMockDataTsx.js.map +1 -1
  296. package/background/src/lib/virtualized/project/writeScenarioClientWrapper.js +15 -0
  297. package/background/src/lib/virtualized/project/writeScenarioClientWrapper.js.map +1 -0
  298. package/background/src/lib/virtualized/project/writeScenarioComponents.js +552 -125
  299. package/background/src/lib/virtualized/project/writeScenarioComponents.js.map +1 -1
  300. package/background/src/lib/virtualized/project/writeScenarioFiles.js +19 -0
  301. package/background/src/lib/virtualized/project/writeScenarioFiles.js.map +1 -1
  302. package/background/src/lib/virtualized/project/writeSimpleRoot.js +13 -13
  303. package/background/src/lib/virtualized/project/writeSimpleRoot.js.map +1 -1
  304. package/codeyam-cli/src/cli.js +7 -1
  305. package/codeyam-cli/src/cli.js.map +1 -1
  306. package/codeyam-cli/src/commands/analyze.js +1 -1
  307. package/codeyam-cli/src/commands/analyze.js.map +1 -1
  308. package/codeyam-cli/src/commands/baseline.js +174 -0
  309. package/codeyam-cli/src/commands/baseline.js.map +1 -0
  310. package/codeyam-cli/src/commands/debug.js +40 -18
  311. package/codeyam-cli/src/commands/debug.js.map +1 -1
  312. package/codeyam-cli/src/commands/default.js +0 -15
  313. package/codeyam-cli/src/commands/default.js.map +1 -1
  314. package/codeyam-cli/src/commands/recapture.js +226 -0
  315. package/codeyam-cli/src/commands/recapture.js.map +1 -0
  316. package/codeyam-cli/src/commands/report.js +72 -24
  317. package/codeyam-cli/src/commands/report.js.map +1 -1
  318. package/codeyam-cli/src/commands/start.js +8 -12
  319. package/codeyam-cli/src/commands/start.js.map +1 -1
  320. package/codeyam-cli/src/commands/status.js +23 -1
  321. package/codeyam-cli/src/commands/status.js.map +1 -1
  322. package/codeyam-cli/src/commands/test-startup.js +1 -1
  323. package/codeyam-cli/src/commands/test-startup.js.map +1 -1
  324. package/codeyam-cli/src/commands/wipe.js +108 -0
  325. package/codeyam-cli/src/commands/wipe.js.map +1 -0
  326. package/codeyam-cli/src/utils/__tests__/serverVersionStaleness.test.js +81 -0
  327. package/codeyam-cli/src/utils/__tests__/serverVersionStaleness.test.js.map +1 -0
  328. package/codeyam-cli/src/utils/__tests__/setupClaudeCodeSettings.test.js +31 -27
  329. package/codeyam-cli/src/utils/__tests__/setupClaudeCodeSettings.test.js.map +1 -1
  330. package/codeyam-cli/src/utils/analysisRunner.js +8 -13
  331. package/codeyam-cli/src/utils/analysisRunner.js.map +1 -1
  332. package/codeyam-cli/src/utils/backgroundServer.js +14 -4
  333. package/codeyam-cli/src/utils/backgroundServer.js.map +1 -1
  334. package/codeyam-cli/src/utils/database.js +91 -5
  335. package/codeyam-cli/src/utils/database.js.map +1 -1
  336. package/codeyam-cli/src/utils/generateReport.js +253 -106
  337. package/codeyam-cli/src/utils/generateReport.js.map +1 -1
  338. package/codeyam-cli/src/utils/git.js +79 -0
  339. package/codeyam-cli/src/utils/git.js.map +1 -0
  340. package/codeyam-cli/src/utils/install-skills.js +31 -17
  341. package/codeyam-cli/src/utils/install-skills.js.map +1 -1
  342. package/codeyam-cli/src/utils/queue/__tests__/manager.test.js +38 -0
  343. package/codeyam-cli/src/utils/queue/__tests__/manager.test.js.map +1 -1
  344. package/codeyam-cli/src/utils/queue/job.js +245 -16
  345. package/codeyam-cli/src/utils/queue/job.js.map +1 -1
  346. package/codeyam-cli/src/utils/queue/manager.js +25 -7
  347. package/codeyam-cli/src/utils/queue/manager.js.map +1 -1
  348. package/codeyam-cli/src/utils/queue/persistence.js.map +1 -1
  349. package/codeyam-cli/src/utils/serverState.js.map +1 -1
  350. package/codeyam-cli/src/utils/setupClaudeCodeSettings.js +7 -5
  351. package/codeyam-cli/src/utils/setupClaudeCodeSettings.js.map +1 -1
  352. package/codeyam-cli/src/utils/versionInfo.js +25 -19
  353. package/codeyam-cli/src/utils/versionInfo.js.map +1 -1
  354. package/codeyam-cli/src/utils/wipe.js +128 -0
  355. package/codeyam-cli/src/utils/wipe.js.map +1 -0
  356. package/codeyam-cli/src/webserver/app/lib/database.js +98 -1
  357. package/codeyam-cli/src/webserver/app/lib/database.js.map +1 -1
  358. package/codeyam-cli/src/webserver/app/lib/dbNotifier.js.map +1 -1
  359. package/codeyam-cli/src/webserver/backgroundServer.js +5 -10
  360. package/codeyam-cli/src/webserver/backgroundServer.js.map +1 -1
  361. package/codeyam-cli/src/webserver/bootstrap.js +49 -0
  362. package/codeyam-cli/src/webserver/bootstrap.js.map +1 -0
  363. package/codeyam-cli/src/webserver/build/client/assets/EntityItem-BXhEawa3.js +1 -0
  364. package/codeyam-cli/src/webserver/build/client/assets/{EntityTypeBadge-efWKDYMr.js → EntityTypeBadge-DLqD3qNt.js} +1 -1
  365. package/codeyam-cli/src/webserver/build/client/assets/EntityTypeIcon-Ba2JVPzP.js +41 -0
  366. package/codeyam-cli/src/webserver/build/client/assets/InlineSpinner-C8lyxW9k.js +34 -0
  367. package/codeyam-cli/src/webserver/build/client/assets/InteractivePreview-aht4aafF.js +25 -0
  368. package/codeyam-cli/src/webserver/build/client/assets/LibraryFunctionPreview-CVtiBnY5.js +3 -0
  369. package/codeyam-cli/src/webserver/build/client/assets/LoadingDots-B0GLXMsr.js +6 -0
  370. package/codeyam-cli/src/webserver/build/client/assets/LogViewer-xgeCVgSM.js +3 -0
  371. package/codeyam-cli/src/webserver/build/client/assets/ReportIssueModal-D4TZhLuw.js +21 -0
  372. package/codeyam-cli/src/webserver/build/client/assets/SafeScreenshot-DuDvi0jm.js +1 -0
  373. package/codeyam-cli/src/webserver/build/client/assets/ScenarioViewer-DEx02QDa.js +10 -0
  374. package/codeyam-cli/src/webserver/build/client/assets/{TruncatedFilePath-COPstp9J.js → TruncatedFilePath-DyFZkK0l.js} +1 -1
  375. package/codeyam-cli/src/webserver/build/client/assets/_index-BwqWJOgH.js +11 -0
  376. package/codeyam-cli/src/webserver/build/client/assets/activity.(_tab)-DoLIqZX2.js +37 -0
  377. package/codeyam-cli/src/webserver/build/client/assets/api.health-l0sNRNKZ.js +1 -0
  378. package/codeyam-cli/src/webserver/build/client/assets/api.restart-server-l0sNRNKZ.js +1 -0
  379. package/codeyam-cli/src/webserver/build/client/assets/api.rules-l0sNRNKZ.js +1 -0
  380. package/codeyam-cli/src/webserver/build/client/assets/chevron-down-Cx24_aWc.js +6 -0
  381. package/codeyam-cli/src/webserver/build/client/assets/chunk-EPOLDU6W-CXRTFQ3F.js +51 -0
  382. package/codeyam-cli/src/webserver/build/client/assets/circle-check-BOARzkeR.js +6 -0
  383. package/codeyam-cli/src/webserver/build/client/assets/createLucideIcon-BdhJEx6B.js +21 -0
  384. package/codeyam-cli/src/webserver/build/client/assets/{cy-logo-cli-C1gnJVOL.svg → cy-logo-cli-CCKUIm0S.svg} +2 -2
  385. package/codeyam-cli/src/webserver/build/client/assets/cy-logo-cli-DcX-ZS3p.js +1 -0
  386. package/codeyam-cli/src/webserver/build/client/assets/dev.empty-BRb-0kQl.js +1 -0
  387. package/codeyam-cli/src/webserver/build/client/assets/entity._sha._-C2N4Op8e.js +23 -0
  388. package/codeyam-cli/src/webserver/build/client/assets/entity._sha.scenarios._scenarioId.fullscreen-DavjRmOY.js +6 -0
  389. package/codeyam-cli/src/webserver/build/client/assets/entity._sha_.create-scenario-D1T4TGjf.js +6 -0
  390. package/codeyam-cli/src/webserver/build/client/assets/entity._sha_.edit._scenarioId-CTBG2mmz.js +5 -0
  391. package/codeyam-cli/src/webserver/build/client/assets/entry.client-CS2cb_eZ.js +29 -0
  392. package/codeyam-cli/src/webserver/build/client/assets/executionFlowCoverage-BWhdfn70.js +1 -0
  393. package/codeyam-cli/src/webserver/build/client/assets/fileTableUtils-DMJ7zii9.js +1 -0
  394. package/codeyam-cli/src/webserver/build/client/assets/files-Cs4MdYtv.js +1 -0
  395. package/codeyam-cli/src/webserver/build/client/assets/git-B4RJRvYB.js +15 -0
  396. package/codeyam-cli/src/webserver/build/client/assets/git-commit-horizontal-CysbcZxi.js +6 -0
  397. package/codeyam-cli/src/webserver/build/client/assets/globals-DMUaGAqV.css +1 -0
  398. package/codeyam-cli/src/webserver/build/client/assets/html2canvas-pro.esm-fmIEn3Bc.js +9 -0
  399. package/codeyam-cli/src/webserver/build/client/assets/index-B1h680n5.js +9 -0
  400. package/codeyam-cli/src/webserver/build/client/assets/index-lzqtyFU8.js +3 -0
  401. package/codeyam-cli/src/webserver/build/client/assets/loader-circle-B7B9V-bu.js +6 -0
  402. package/codeyam-cli/src/webserver/build/client/assets/manifest-f874c610.js +1 -0
  403. package/codeyam-cli/src/webserver/build/client/assets/preload-helper-ckwbz45p.js +1 -0
  404. package/codeyam-cli/src/webserver/build/client/assets/root-Bz5TunQg.js +57 -0
  405. package/codeyam-cli/src/webserver/build/client/assets/rules-hEkvVw2-.js +97 -0
  406. package/codeyam-cli/src/webserver/build/client/assets/scenarioStatus-B_8jpV3e.js +1 -0
  407. package/codeyam-cli/src/webserver/build/client/assets/search-CxXUmBSd.js +6 -0
  408. package/codeyam-cli/src/webserver/build/client/assets/settings-CS5f3WzT.js +1 -0
  409. package/codeyam-cli/src/webserver/build/client/assets/simulations-DwFIBT09.js +1 -0
  410. package/codeyam-cli/src/webserver/build/client/assets/triangle-alert-B6LgvRJg.js +6 -0
  411. package/codeyam-cli/src/webserver/build/client/assets/useCustomSizes-C1v1PQzo.js +1 -0
  412. package/codeyam-cli/src/webserver/build/client/assets/{useLastLogLine-3pmpUQB-.js → useLastLogLine-aSv48UbS.js} +1 -1
  413. package/codeyam-cli/src/webserver/build/client/assets/useReportContext-DYxHZQuP.js +1 -0
  414. package/codeyam-cli/src/webserver/build/client/assets/{useToast-DEyawJ8r.js → useToast-mBRpZPiu.js} +1 -1
  415. package/codeyam-cli/src/webserver/build/server/assets/index-967OuJoF.js +1 -0
  416. package/codeyam-cli/src/webserver/build/server/assets/server-build-DRTmerg9.js +257 -0
  417. package/codeyam-cli/src/webserver/build/server/index.js +1 -1
  418. package/codeyam-cli/src/webserver/build-info.json +5 -5
  419. package/codeyam-cli/src/webserver/devServer.js +1 -3
  420. package/codeyam-cli/src/webserver/devServer.js.map +1 -1
  421. package/codeyam-cli/src/webserver/server.js +35 -25
  422. package/codeyam-cli/src/webserver/server.js.map +1 -1
  423. package/codeyam-cli/templates/codeyam-power-rules-hook.sh +200 -0
  424. package/codeyam-cli/templates/{codeyam-debug-skill.md → codeyam:debug.md} +48 -4
  425. package/codeyam-cli/templates/codeyam:diagnose.md +650 -0
  426. package/codeyam-cli/templates/codeyam:new-rule.md +13 -0
  427. package/codeyam-cli/templates/codeyam:power-rules.md +447 -0
  428. package/codeyam-cli/templates/{codeyam-setup-skill.md → codeyam:setup.md} +139 -4
  429. package/codeyam-cli/templates/{codeyam-sim-skill.md → codeyam:sim.md} +1 -1
  430. package/codeyam-cli/templates/{codeyam-test-skill.md → codeyam:test.md} +1 -1
  431. package/codeyam-cli/templates/{codeyam-verify-skill.md → codeyam:verify.md} +1 -1
  432. package/package.json +17 -16
  433. package/packages/ai/index.js +5 -4
  434. package/packages/ai/index.js.map +1 -1
  435. package/packages/ai/src/lib/analyzeScope.js +99 -0
  436. package/packages/ai/src/lib/analyzeScope.js.map +1 -1
  437. package/packages/ai/src/lib/astScopes/arrayDerivationDetector.js +150 -0
  438. package/packages/ai/src/lib/astScopes/arrayDerivationDetector.js.map +1 -0
  439. package/packages/ai/src/lib/astScopes/astScopeAnalyzer.js +100 -1
  440. package/packages/ai/src/lib/astScopes/astScopeAnalyzer.js.map +1 -1
  441. package/packages/ai/src/lib/astScopes/conditionalEffectsExtractor.js +435 -0
  442. package/packages/ai/src/lib/astScopes/conditionalEffectsExtractor.js.map +1 -0
  443. package/packages/ai/src/lib/astScopes/methodSemantics.js +97 -6
  444. package/packages/ai/src/lib/astScopes/methodSemantics.js.map +1 -1
  445. package/packages/ai/src/lib/astScopes/patterns/ifStatementHandler.js +8 -0
  446. package/packages/ai/src/lib/astScopes/patterns/ifStatementHandler.js.map +1 -1
  447. package/packages/ai/src/lib/astScopes/patterns/switchStatementHandler.js +23 -0
  448. package/packages/ai/src/lib/astScopes/patterns/switchStatementHandler.js.map +1 -1
  449. package/packages/ai/src/lib/astScopes/patterns/variableDeclarationHandler.js +138 -1
  450. package/packages/ai/src/lib/astScopes/patterns/variableDeclarationHandler.js.map +1 -1
  451. package/packages/ai/src/lib/astScopes/processExpression.js +945 -87
  452. package/packages/ai/src/lib/astScopes/processExpression.js.map +1 -1
  453. package/packages/ai/src/lib/checkAllAttributes.js +24 -9
  454. package/packages/ai/src/lib/checkAllAttributes.js.map +1 -1
  455. package/packages/ai/src/lib/completionCall.js +178 -31
  456. package/packages/ai/src/lib/completionCall.js.map +1 -1
  457. package/packages/ai/src/lib/dataStructure/ScopeDataStructure.js +1198 -82
  458. package/packages/ai/src/lib/dataStructure/ScopeDataStructure.js.map +1 -1
  459. package/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/JavascriptFrameworkManager.js +2 -1
  460. package/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/JavascriptFrameworkManager.js.map +1 -1
  461. package/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/MuiManager.js +661 -0
  462. package/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/MuiManager.js.map +1 -0
  463. package/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/ReactFrameworkManager.js +180 -56
  464. package/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/ReactFrameworkManager.js.map +1 -1
  465. package/packages/ai/src/lib/dataStructure/helpers/cleanKnownObjectFunctions.js +16 -1
  466. package/packages/ai/src/lib/dataStructure/helpers/cleanKnownObjectFunctions.js.map +1 -1
  467. package/packages/ai/src/lib/dataStructure/helpers/cleanNonObjectFunctions.js +86 -4
  468. package/packages/ai/src/lib/dataStructure/helpers/cleanNonObjectFunctions.js.map +1 -1
  469. package/packages/ai/src/lib/dataStructure/helpers/convertDotNotation.js +20 -0
  470. package/packages/ai/src/lib/dataStructure/helpers/convertDotNotation.js.map +1 -1
  471. package/packages/ai/src/lib/dataStructure/helpers/convertNullToUndefinedBySchema.js +86 -0
  472. package/packages/ai/src/lib/dataStructure/helpers/convertNullToUndefinedBySchema.js.map +1 -0
  473. package/packages/ai/src/lib/dataStructure/helpers/fillInSchemaGapsAndUnknowns.js +34 -3
  474. package/packages/ai/src/lib/dataStructure/helpers/fillInSchemaGapsAndUnknowns.js.map +1 -1
  475. package/packages/ai/src/lib/dataStructure/helpers/fixNullIdsBySchema.js +107 -0
  476. package/packages/ai/src/lib/dataStructure/helpers/fixNullIdsBySchema.js.map +1 -0
  477. package/packages/ai/src/lib/dataStructureChunking.js +111 -0
  478. package/packages/ai/src/lib/dataStructureChunking.js.map +1 -0
  479. package/packages/ai/src/lib/deepEqual.js +32 -0
  480. package/packages/ai/src/lib/deepEqual.js.map +1 -0
  481. package/packages/ai/src/lib/e2eDataTracking.js +241 -0
  482. package/packages/ai/src/lib/e2eDataTracking.js.map +1 -0
  483. package/packages/ai/src/lib/extractCriticalDataKeys.js +96 -0
  484. package/packages/ai/src/lib/extractCriticalDataKeys.js.map +1 -0
  485. package/packages/ai/src/lib/generateChangesEntityScenarioData.js +62 -5
  486. package/packages/ai/src/lib/generateChangesEntityScenarioData.js.map +1 -1
  487. package/packages/ai/src/lib/generateChangesEntityScenarios.js +81 -90
  488. package/packages/ai/src/lib/generateChangesEntityScenarios.js.map +1 -1
  489. package/packages/ai/src/lib/generateEntityDataStructure.js +5 -0
  490. package/packages/ai/src/lib/generateEntityDataStructure.js.map +1 -1
  491. package/packages/ai/src/lib/generateEntityScenarioData.js +904 -84
  492. package/packages/ai/src/lib/generateEntityScenarioData.js.map +1 -1
  493. package/packages/ai/src/lib/generateEntityScenarios.js +186 -82
  494. package/packages/ai/src/lib/generateEntityScenarios.js.map +1 -1
  495. package/packages/ai/src/lib/generateExecutionFlows.js +392 -0
  496. package/packages/ai/src/lib/generateExecutionFlows.js.map +1 -0
  497. package/packages/ai/src/lib/generateExecutionFlowsFromConditionalEffects.js +380 -0
  498. package/packages/ai/src/lib/generateExecutionFlowsFromConditionalEffects.js.map +1 -0
  499. package/packages/ai/src/lib/generateExecutionFlowsFromConditionals.js +1440 -0
  500. package/packages/ai/src/lib/generateExecutionFlowsFromConditionals.js.map +1 -0
  501. package/packages/ai/src/lib/generateExecutionFlowsFromJsxUsages.js +194 -0
  502. package/packages/ai/src/lib/generateExecutionFlowsFromJsxUsages.js.map +1 -0
  503. package/packages/ai/src/lib/getConditionalUsagesFromCode.js +84 -14
  504. package/packages/ai/src/lib/getConditionalUsagesFromCode.js.map +1 -1
  505. package/packages/ai/src/lib/guessScenarioDataFromDescription.js +2 -1
  506. package/packages/ai/src/lib/guessScenarioDataFromDescription.js.map +1 -1
  507. package/packages/ai/src/lib/isolateScopes.js +231 -4
  508. package/packages/ai/src/lib/isolateScopes.js.map +1 -1
  509. package/packages/ai/src/lib/mergeStatements.js +26 -3
  510. package/packages/ai/src/lib/mergeStatements.js.map +1 -1
  511. package/packages/ai/src/lib/promptGenerators/gatherAttributesMap.js +6 -0
  512. package/packages/ai/src/lib/promptGenerators/gatherAttributesMap.js.map +1 -1
  513. package/packages/ai/src/lib/promptGenerators/generateChangesEntityScenarioDataGenerator.js +1 -1
  514. package/packages/ai/src/lib/promptGenerators/generateChangesEntityScenarioDataGenerator.js.map +1 -1
  515. package/packages/ai/src/lib/promptGenerators/generateChangesEntityScenariosGenerator.js +21 -64
  516. package/packages/ai/src/lib/promptGenerators/generateChangesEntityScenariosGenerator.js.map +1 -1
  517. package/packages/ai/src/lib/promptGenerators/generateChunkPrompt.js +54 -0
  518. package/packages/ai/src/lib/promptGenerators/generateChunkPrompt.js.map +1 -0
  519. package/packages/ai/src/lib/promptGenerators/generateEntityScenarioDataGenerator.js +68 -6
  520. package/packages/ai/src/lib/promptGenerators/generateEntityScenarioDataGenerator.js.map +1 -1
  521. package/packages/ai/src/lib/promptGenerators/generateEntityScenariosGenerator.js +10 -34
  522. package/packages/ai/src/lib/promptGenerators/generateEntityScenariosGenerator.js.map +1 -1
  523. package/packages/ai/src/lib/promptGenerators/generateMissingKeysPrompt.js +45 -0
  524. package/packages/ai/src/lib/promptGenerators/generateMissingKeysPrompt.js.map +1 -0
  525. package/packages/ai/src/lib/promptGenerators/guessNewScenarioDataFromDescriptionGenerator.js +16 -3
  526. package/packages/ai/src/lib/promptGenerators/guessNewScenarioDataFromDescriptionGenerator.js.map +1 -1
  527. package/packages/ai/src/lib/promptGenerators/simplifyKeysForLLM.js +335 -0
  528. package/packages/ai/src/lib/promptGenerators/simplifyKeysForLLM.js.map +1 -0
  529. package/packages/ai/src/lib/resolvePathToControllable.js +667 -0
  530. package/packages/ai/src/lib/resolvePathToControllable.js.map +1 -0
  531. package/packages/ai/src/lib/splitOutsideParentheses.js +3 -1
  532. package/packages/ai/src/lib/splitOutsideParentheses.js.map +1 -1
  533. package/packages/ai/src/lib/worker/SerializableDataStructure.js +29 -0
  534. package/packages/ai/src/lib/worker/SerializableDataStructure.js.map +1 -1
  535. package/packages/ai/src/lib/worker/analyzeScopeWorker.js +4 -0
  536. package/packages/ai/src/lib/worker/analyzeScopeWorker.js.map +1 -1
  537. package/packages/analyze/src/lib/FileAnalyzer.js +15 -0
  538. package/packages/analyze/src/lib/FileAnalyzer.js.map +1 -1
  539. package/packages/analyze/src/lib/analysisContext.js +30 -5
  540. package/packages/analyze/src/lib/analysisContext.js.map +1 -1
  541. package/packages/analyze/src/lib/asts/nodes/index.js +1 -0
  542. package/packages/analyze/src/lib/asts/nodes/index.js.map +1 -1
  543. package/packages/analyze/src/lib/asts/nodes/isAsyncFunction.js +52 -0
  544. package/packages/analyze/src/lib/asts/nodes/isAsyncFunction.js.map +1 -0
  545. package/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.js +218 -50
  546. package/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.js.map +1 -1
  547. package/packages/analyze/src/lib/files/analyze/analyzeEntities.js +10 -0
  548. package/packages/analyze/src/lib/files/analyze/analyzeEntities.js.map +1 -1
  549. package/packages/analyze/src/lib/files/analyze/findOrCreateEntity.js +2 -0
  550. package/packages/analyze/src/lib/files/analyze/findOrCreateEntity.js.map +1 -1
  551. package/packages/analyze/src/lib/files/analyze/validateDependencyAnalyses.js +31 -7
  552. package/packages/analyze/src/lib/files/analyze/validateDependencyAnalyses.js.map +1 -1
  553. package/packages/analyze/src/lib/files/analyzeChange.js +21 -11
  554. package/packages/analyze/src/lib/files/analyzeChange.js.map +1 -1
  555. package/packages/analyze/src/lib/files/analyzeEntity.js +9 -8
  556. package/packages/analyze/src/lib/files/analyzeEntity.js.map +1 -1
  557. package/packages/analyze/src/lib/files/analyzeInitial.js +9 -10
  558. package/packages/analyze/src/lib/files/analyzeInitial.js.map +1 -1
  559. package/packages/analyze/src/lib/files/enums/steps.js +1 -1
  560. package/packages/analyze/src/lib/files/enums/steps.js.map +1 -1
  561. package/packages/analyze/src/lib/files/scenarios/enrichArrayTypesFromChildSignatures.js +209 -0
  562. package/packages/analyze/src/lib/files/scenarios/enrichArrayTypesFromChildSignatures.js.map +1 -0
  563. package/packages/analyze/src/lib/files/scenarios/enrichUnknownTypesFromSourceEquivalencies.js +85 -0
  564. package/packages/analyze/src/lib/files/scenarios/enrichUnknownTypesFromSourceEquivalencies.js.map +1 -0
  565. package/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.js +458 -48
  566. package/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.js.map +1 -1
  567. package/packages/analyze/src/lib/files/scenarios/generateChangesScenarioData.js +1 -1
  568. package/packages/analyze/src/lib/files/scenarios/generateChangesScenarioData.js.map +1 -1
  569. package/packages/analyze/src/lib/files/scenarios/generateChangesScenarios.js +29 -34
  570. package/packages/analyze/src/lib/files/scenarios/generateChangesScenarios.js.map +1 -1
  571. package/packages/analyze/src/lib/files/scenarios/generateDataStructure.js +264 -78
  572. package/packages/analyze/src/lib/files/scenarios/generateDataStructure.js.map +1 -1
  573. package/packages/analyze/src/lib/files/scenarios/generateExecutionFlows.js +96 -0
  574. package/packages/analyze/src/lib/files/scenarios/generateExecutionFlows.js.map +1 -0
  575. package/packages/analyze/src/lib/files/scenarios/generateScenarioData.js +56 -69
  576. package/packages/analyze/src/lib/files/scenarios/generateScenarioData.js.map +1 -1
  577. package/packages/analyze/src/lib/files/scenarios/generateScenarios.js +4 -8
  578. package/packages/analyze/src/lib/files/scenarios/generateScenarios.js.map +1 -1
  579. package/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.js +372 -89
  580. package/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.js.map +1 -1
  581. package/packages/analyze/src/lib/files/scenarios/mergeValidatedDataStructures.js +46 -9
  582. package/packages/analyze/src/lib/files/scenarios/mergeValidatedDataStructures.js.map +1 -1
  583. package/packages/aws/src/lib/ecs/ecsDefineContainer.js +2 -2
  584. package/packages/aws/src/lib/ecs/ecsDefineContainer.js.map +1 -1
  585. package/packages/aws/src/lib/ecs/ecsTaskFactory.js +17 -61
  586. package/packages/aws/src/lib/ecs/ecsTaskFactory.js.map +1 -1
  587. package/packages/database/src/lib/kysely/db.js +2 -2
  588. package/packages/database/src/lib/kysely/tables/debugReportsTable.js +9 -3
  589. package/packages/database/src/lib/kysely/tables/debugReportsTable.js.map +1 -1
  590. package/packages/database/src/lib/loadReadyToBeCapturedAnalyses.js +7 -4
  591. package/packages/database/src/lib/loadReadyToBeCapturedAnalyses.js.map +1 -1
  592. package/packages/generate/index.js +3 -0
  593. package/packages/generate/index.js.map +1 -1
  594. package/packages/generate/src/lib/componentScenarioPage/componentScenarioPageNext.js +16 -1
  595. package/packages/generate/src/lib/componentScenarioPage/componentScenarioPageNext.js.map +1 -1
  596. package/packages/generate/src/lib/componentScenarioPage/generateScenarioClientWrapper.js +189 -0
  597. package/packages/generate/src/lib/componentScenarioPage/generateScenarioClientWrapper.js.map +1 -0
  598. package/packages/generate/src/lib/componentScenarioPage/generateScenarioServerComponent.js +53 -0
  599. package/packages/generate/src/lib/componentScenarioPage/generateScenarioServerComponent.js.map +1 -0
  600. package/packages/generate/src/lib/componentScenarioPage/getIFrameMessageListenerCode.js +8 -4
  601. package/packages/generate/src/lib/componentScenarioPage/getIFrameMessageListenerCode.js.map +1 -1
  602. package/packages/generate/src/lib/deepMerge.js +27 -1
  603. package/packages/generate/src/lib/deepMerge.js.map +1 -1
  604. package/packages/generate/src/lib/scenarioComponentForServer.js +89 -0
  605. package/packages/generate/src/lib/scenarioComponentForServer.js.map +1 -0
  606. package/packages/github/src/lib/loadOrCreateCommit.js +10 -0
  607. package/packages/github/src/lib/loadOrCreateCommit.js.map +1 -1
  608. package/packages/github/src/lib/syncPrimaryBranch.js +3 -0
  609. package/packages/github/src/lib/syncPrimaryBranch.js.map +1 -1
  610. package/packages/process/index.js +3 -0
  611. package/packages/process/index.js.map +1 -0
  612. package/packages/process/src/GlobalProcessManager.js.map +1 -0
  613. package/{background/src/lib/process → packages/process/src}/ProcessManager.js +1 -1
  614. package/packages/process/src/ProcessManager.js.map +1 -0
  615. package/packages/process/src/index.js.map +1 -0
  616. package/packages/process/src/managedExecAsync.js.map +1 -0
  617. package/packages/types/index.js.map +1 -1
  618. package/packages/utils/src/lib/lightweightEntityExtractor.js +25 -0
  619. package/packages/utils/src/lib/lightweightEntityExtractor.js.map +1 -1
  620. package/packages/utils/src/lib/safeFileName.js +29 -3
  621. package/packages/utils/src/lib/safeFileName.js.map +1 -1
  622. package/scripts/finalize-analyzer.cjs +6 -4
  623. package/analyzer-template/packages/ai/src/lib/findMatchingAttribute.ts +0 -102
  624. package/analyzer-template/packages/ai/src/lib/gatherRelevantDependentKeyAttributes.ts +0 -197
  625. package/analyzer-template/packages/ai/src/lib/generateChangesEntityKeyAttributes.ts +0 -271
  626. package/analyzer-template/packages/ai/src/lib/generateEntityKeyAttributes.ts +0 -294
  627. package/analyzer-template/packages/ai/src/lib/promptGenerators/generateEntityKeyAttributesGenerator.ts +0 -67
  628. package/analyzer-template/packages/analyze/src/lib/files/scenarios/generateKeyAttributes.ts +0 -115
  629. package/analyzer-template/process/INTEGRATION_COMPLETE.md +0 -333
  630. package/analyzer-template/process/INTEGRATION_EXAMPLE.md +0 -525
  631. package/analyzer-template/process/README.md +0 -507
  632. package/background/src/lib/process/GlobalProcessManager.js.map +0 -1
  633. package/background/src/lib/process/ProcessManager.js.map +0 -1
  634. package/background/src/lib/process/index.js.map +0 -1
  635. package/background/src/lib/process/managedExecAsync.js.map +0 -1
  636. package/codeyam-cli/scripts/fixtures/cal.com/universal-mocks/packages/prisma/index.js +0 -238
  637. package/codeyam-cli/scripts/fixtures/cal.com/universal-mocks/packages/prisma/index.js.map +0 -1
  638. package/codeyam-cli/src/webserver/build/client/assets/EntityItem-CVbSvOjo.js +0 -1
  639. package/codeyam-cli/src/webserver/build/client/assets/EntityTypeIcon-DcwcHyl5.js +0 -1
  640. package/codeyam-cli/src/webserver/build/client/assets/InteractivePreview-WgwC1GfJ.js +0 -26
  641. package/codeyam-cli/src/webserver/build/client/assets/LibraryFunctionPreview-IEKom9O2.js +0 -3
  642. package/codeyam-cli/src/webserver/build/client/assets/LogViewer-BYnfxbUG.js +0 -3
  643. package/codeyam-cli/src/webserver/build/client/assets/ReportIssueModal-_lBPJCzG.js +0 -1
  644. package/codeyam-cli/src/webserver/build/client/assets/SafeScreenshot-lHVhvsu_.js +0 -1
  645. package/codeyam-cli/src/webserver/build/client/assets/ScenarioViewer-d_TBk4GQ.js +0 -5
  646. package/codeyam-cli/src/webserver/build/client/assets/_index-kGT7VUqj.js +0 -1
  647. package/codeyam-cli/src/webserver/build/client/assets/activity.(_tab)-DDGmhu7P.js +0 -7
  648. package/codeyam-cli/src/webserver/build/client/assets/chevron-down-n_HPRfM_.js +0 -1
  649. package/codeyam-cli/src/webserver/build/client/assets/chunk-WWGJGFF6-CbVoyx1U.js +0 -26
  650. package/codeyam-cli/src/webserver/build/client/assets/circle-check-D1VOYveA.js +0 -1
  651. package/codeyam-cli/src/webserver/build/client/assets/createLucideIcon-YR8jjAlu.js +0 -1
  652. package/codeyam-cli/src/webserver/build/client/assets/dev.empty-B8vP3V_s.js +0 -1
  653. package/codeyam-cli/src/webserver/build/client/assets/entity._sha._-CN6aLCT1.js +0 -16
  654. package/codeyam-cli/src/webserver/build/client/assets/entity._sha_.create-scenario-DA5Jeu2P.js +0 -1
  655. package/codeyam-cli/src/webserver/build/client/assets/entity._sha_.edit._scenarioId-BTeitalf.js +0 -5
  656. package/codeyam-cli/src/webserver/build/client/assets/entry.client-du6UEYD-.js +0 -13
  657. package/codeyam-cli/src/webserver/build/client/assets/fileTableUtils-BpjkhMoi.js +0 -1
  658. package/codeyam-cli/src/webserver/build/client/assets/files-BQGvk4lJ.js +0 -1
  659. package/codeyam-cli/src/webserver/build/client/assets/git-DVdYRT-I.js +0 -12
  660. package/codeyam-cli/src/webserver/build/client/assets/globals-CO-U8Bpo.css +0 -1
  661. package/codeyam-cli/src/webserver/build/client/assets/html2canvas-pro.esm-XQCGvadH.js +0 -5
  662. package/codeyam-cli/src/webserver/build/client/assets/index-DCG-vks0.js +0 -1
  663. package/codeyam-cli/src/webserver/build/client/assets/loader-circle-GazdNeLl.js +0 -1
  664. package/codeyam-cli/src/webserver/build/client/assets/manifest-0b694d28.js +0 -1
  665. package/codeyam-cli/src/webserver/build/client/assets/root-D3tQP7hx.js +0 -16
  666. package/codeyam-cli/src/webserver/build/client/assets/search-CIY6XmtE.js +0 -1
  667. package/codeyam-cli/src/webserver/build/client/assets/server-build-CMKNK2uU.css +0 -1
  668. package/codeyam-cli/src/webserver/build/client/assets/settings-CoMDgElu.js +0 -1
  669. package/codeyam-cli/src/webserver/build/client/assets/simulations-agkniXp2.js +0 -1
  670. package/codeyam-cli/src/webserver/build/client/assets/triangle-alert-B2VUcygF.js +0 -1
  671. package/codeyam-cli/src/webserver/build/client/assets/useReportContext-EvdK-zXP.js +0 -1
  672. package/codeyam-cli/src/webserver/build/server/assets/index-DGVHQEXD.js +0 -1
  673. package/codeyam-cli/src/webserver/build/server/assets/server-build-CghkTkIL.js +0 -166
  674. package/codeyam-cli/templates/debug-command.md +0 -303
  675. package/packages/ai/src/lib/findMatchingAttribute.js +0 -77
  676. package/packages/ai/src/lib/findMatchingAttribute.js.map +0 -1
  677. package/packages/ai/src/lib/gatherRelevantDependentKeyAttributes.js +0 -136
  678. package/packages/ai/src/lib/gatherRelevantDependentKeyAttributes.js.map +0 -1
  679. package/packages/ai/src/lib/generateChangesEntityKeyAttributes.js +0 -220
  680. package/packages/ai/src/lib/generateChangesEntityKeyAttributes.js.map +0 -1
  681. package/packages/ai/src/lib/generateEntityKeyAttributes.js +0 -241
  682. package/packages/ai/src/lib/generateEntityKeyAttributes.js.map +0 -1
  683. package/packages/ai/src/lib/isFrontend.js +0 -5
  684. package/packages/ai/src/lib/isFrontend.js.map +0 -1
  685. package/packages/ai/src/lib/promptGenerators/generateEntityKeyAttributesGenerator.js +0 -40
  686. package/packages/ai/src/lib/promptGenerators/generateEntityKeyAttributesGenerator.js.map +0 -1
  687. package/packages/analyze/src/lib/files/scenarios/generateKeyAttributes.js +0 -72
  688. package/packages/analyze/src/lib/files/scenarios/generateKeyAttributes.js.map +0 -1
  689. /package/analyzer-template/{process → packages/process/src}/GlobalProcessManager.ts +0 -0
  690. /package/analyzer-template/{process → packages/process/src}/ProcessManager.ts +0 -0
  691. /package/analyzer-template/{process → packages/process/src}/index.ts +0 -0
  692. /package/analyzer-template/{process → packages/process/src}/managedExecAsync.ts +0 -0
  693. /package/codeyam-cli/src/webserver/build/client/assets/{InteractivePreview-CMKNK2uU.css → styles-CMKNK2uU.css} +0 -0
  694. /package/{background/src/lib/process → packages/process/src}/GlobalProcessManager.js +0 -0
  695. /package/{background/src/lib/process → packages/process/src}/index.js +0 -0
  696. /package/{background/src/lib/process → packages/process/src}/managedExecAsync.js +0 -0
@@ -1,5 +1,10 @@
1
1
  import ts from 'typescript';
2
- import { AnalysisContext, ConditionalUsage } from './types';
2
+ import * as crypto from 'crypto';
3
+ import {
4
+ AnalysisContext,
5
+ CompoundConditional,
6
+ ConditionalUsage,
7
+ } from './types';
3
8
  import { StructuredPath } from './paths';
4
9
  import { nodeToSource } from './nodeToSource';
5
10
  import { methodRegistry, ArrayPushSemantics } from './methodSemantics';
@@ -14,6 +19,236 @@ import {
14
19
  unwrapExpression,
15
20
  } from './sharedPatterns';
16
21
  import { processBindingPattern } from './processBindings';
22
+ import {
23
+ extractConditionalEffectsFromTernary,
24
+ findUseStateSetters,
25
+ } from './conditionalEffectsExtractor';
26
+ import { detectArrayDerivedPattern } from './arrayDerivationDetector';
27
+
28
+ /**
29
+ * Extracts the component name from a JSX element.
30
+ * Returns null for intrinsic elements (div, span, etc.) since we only care about
31
+ * custom components for gating condition tracking.
32
+ *
33
+ * Examples:
34
+ * - <ChildViewer /> → "ChildViewer"
35
+ * - <ScenarioViewer scenario={...} /> → "ScenarioViewer"
36
+ * - <div> → null (intrinsic element)
37
+ */
38
+ function getComponentNameFromJsx(
39
+ node: ts.JsxElement | ts.JsxSelfClosingElement,
40
+ ): string | null {
41
+ let tagName: ts.JsxTagNameExpression;
42
+
43
+ if (ts.isJsxElement(node)) {
44
+ tagName = node.openingElement.tagName;
45
+ } else {
46
+ tagName = node.tagName;
47
+ }
48
+
49
+ // Get the text of the tag name
50
+ const name = tagName.getText();
51
+
52
+ // Check if it's a custom component (starts with uppercase) vs intrinsic element
53
+ // Custom components start with uppercase: <MyComponent />
54
+ // Intrinsic elements start with lowercase: <div />
55
+ if (
56
+ name &&
57
+ name[0] === name[0].toUpperCase() &&
58
+ name[0] !== name[0].toLowerCase()
59
+ ) {
60
+ return name;
61
+ }
62
+
63
+ return null;
64
+ }
65
+
66
+ /**
67
+ * Extracts condition paths from a logical AND chain expression.
68
+ * Used for creating gating conditions for child components.
69
+ *
70
+ * Example: `hasData && isReady && <Component />` returns ['hasData', 'isReady']
71
+ */
72
+ function extractConditionPathsFromAndChain(
73
+ expr: ts.Expression,
74
+ sourceFile: ts.SourceFile,
75
+ ): string[] {
76
+ const paths: string[] = [];
77
+ const unwrapped = unwrapExpression(expr);
78
+
79
+ if (
80
+ ts.isBinaryExpression(unwrapped) &&
81
+ unwrapped.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken
82
+ ) {
83
+ // Recursively get conditions from left side
84
+ paths.push(
85
+ ...extractConditionPathsFromAndChain(unwrapped.left, sourceFile),
86
+ );
87
+
88
+ // Process right side if it's not JSX (JSX is the consequence, not a condition)
89
+ const rightUnwrapped = unwrapExpression(unwrapped.right);
90
+ if (
91
+ !ts.isJsxElement(rightUnwrapped) &&
92
+ !ts.isJsxSelfClosingElement(rightUnwrapped) &&
93
+ !ts.isJsxFragment(rightUnwrapped)
94
+ ) {
95
+ paths.push(
96
+ ...extractConditionPathsFromAndChain(unwrapped.right, sourceFile),
97
+ );
98
+ }
99
+ } else {
100
+ // Base case: extract path from this expression
101
+ const path = StructuredPath.fromNode(unwrapped, sourceFile);
102
+ if (path) {
103
+ paths.push(path.toString());
104
+ }
105
+ }
106
+
107
+ return paths;
108
+ }
109
+
110
+ /**
111
+ * Finds the rightmost JSX element in an && chain.
112
+ * Example: `a && b && <Component />` returns <Component />
113
+ */
114
+ function findJsxInAndChain(
115
+ expr: ts.Expression,
116
+ ): ts.JsxElement | ts.JsxSelfClosingElement | null {
117
+ const unwrapped = unwrapExpression(expr);
118
+
119
+ if (ts.isJsxElement(unwrapped) || ts.isJsxSelfClosingElement(unwrapped)) {
120
+ return unwrapped;
121
+ }
122
+
123
+ if (
124
+ ts.isBinaryExpression(unwrapped) &&
125
+ unwrapped.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken
126
+ ) {
127
+ // Check right side first (most common case: condition && <Jsx />)
128
+ const rightResult = findJsxInAndChain(unwrapped.right);
129
+ if (rightResult) return rightResult;
130
+
131
+ // Also check left side for rare cases
132
+ return findJsxInAndChain(unwrapped.left);
133
+ }
134
+
135
+ return null;
136
+ }
137
+
138
+ /**
139
+ * Fix 32: Finds a JSX fragment in an && chain.
140
+ * Example: `activeTab && <><ChildA /><ChildB /></>` returns the fragment
141
+ * This is needed to propagate parent conditions through fragments.
142
+ */
143
+ function findJsxFragmentInAndChain(expr: ts.Expression): ts.JsxFragment | null {
144
+ const unwrapped = unwrapExpression(expr);
145
+
146
+ if (ts.isJsxFragment(unwrapped)) {
147
+ return unwrapped;
148
+ }
149
+
150
+ if (
151
+ ts.isBinaryExpression(unwrapped) &&
152
+ unwrapped.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken
153
+ ) {
154
+ // Check right side first (most common case: condition && <></>)
155
+ const rightResult = findJsxFragmentInAndChain(unwrapped.right);
156
+ if (rightResult) return rightResult;
157
+
158
+ // Also check left side for rare cases
159
+ return findJsxFragmentInAndChain(unwrapped.left);
160
+ }
161
+
162
+ return null;
163
+ }
164
+
165
+ /**
166
+ * Detects if a property access looks like an environment variable store access.
167
+ * Matches patterns like `env.DATABASE_URL`, `env.IS_FORMBRICKS_CLOUD`, etc.
168
+ * where the object is named "env" and the property looks like an env var name.
169
+ */
170
+ function isEnvStoreAccess(fullText: string): boolean {
171
+ // Match: env.SOME_VAR or env.someVar (but object must be exactly "env")
172
+ // This catches patterns from @t3-oss/env-nextjs and similar packages
173
+ const envStorePattern = /^env\.[A-Z_][A-Z0-9_]*$/;
174
+ return envStorePattern.test(fullText);
175
+ }
176
+
177
+ /**
178
+ * Converts a call expression argument to a StructuredPath.
179
+ *
180
+ * IMPORTANT: We always use the original source text for callbacks, never cyScope names.
181
+ * cyScope names are internal identifiers for child scopes and should NEVER appear
182
+ * in schema paths or call signatures. Using cyScope names causes data merge conflicts
183
+ * because the same callback gets different identifiers in different contexts.
184
+ */
185
+ function getArgPathForCallSignature(
186
+ arg: ts.Expression,
187
+ context: AnalysisContext,
188
+ ): StructuredPath {
189
+ // Always use the standard path conversion - never replace with cyScope names
190
+ return (
191
+ StructuredPath.fromNode(arg, context.sourceFile) ||
192
+ nodeToSource(arg, context.sourceFile)
193
+ );
194
+ }
195
+
196
+ /**
197
+ * Builds a StructuredPath for a call expression using the original source text.
198
+ *
199
+ * IMPORTANT: This function ensures consistent call signatures by always using
200
+ * the original callback text, never cyScope names. This prevents schema path
201
+ * conflicts where the same call would have different paths.
202
+ */
203
+ function buildCallPathFromSource(
204
+ node: ts.CallExpression,
205
+ context: AnalysisContext,
206
+ ): StructuredPath | null {
207
+ const expression = node.expression;
208
+
209
+ // Convert arguments using original source text
210
+ const argPaths = node.arguments.map((arg) =>
211
+ getArgPathForCallSignature(arg, context),
212
+ );
213
+
214
+ // Handle type arguments if present
215
+ let typeArgs: string[] | undefined = undefined;
216
+ if (node.typeArguments && node.typeArguments.length > 0) {
217
+ typeArgs = node.typeArguments.map((typeArg) =>
218
+ typeArg.getText(context.sourceFile),
219
+ );
220
+ }
221
+
222
+ if (ts.isIdentifier(expression)) {
223
+ // Simple function call: func(arg1, arg2)
224
+ return StructuredPath.fromFunction(expression.text, argPaths, typeArgs);
225
+ } else if (ts.isPropertyAccessExpression(expression)) {
226
+ // Method call: obj.method(arg1, arg2)
227
+ const objPath = StructuredPath.fromNode(
228
+ expression.expression,
229
+ context.sourceFile,
230
+ );
231
+ if (!objPath) return null;
232
+ return objPath
233
+ .withProperty(expression.name.text)
234
+ .withFunctionCall(argPaths, typeArgs);
235
+ } else if (ts.isCallExpression(expression)) {
236
+ // Chained call: func(arg1)(arg2)
237
+ const funcPath = buildCallPathFromSource(expression, context);
238
+ if (!funcPath) return null;
239
+ return funcPath.withFunctionCall(argPaths, typeArgs);
240
+ } else if (ts.isElementAccessExpression(expression)) {
241
+ // Element access call: obj[key](args)
242
+ const basePath = StructuredPath.fromNode(expression, context.sourceFile);
243
+ if (!basePath) return null;
244
+ return basePath.withFunctionCall(argPaths, typeArgs);
245
+ } else {
246
+ // Complex call expression
247
+ const basePath = StructuredPath.fromNode(expression, context.sourceFile);
248
+ if (!basePath) return null;
249
+ return basePath.withFunctionCall(argPaths, typeArgs);
250
+ }
251
+ }
17
252
 
18
253
  /**
19
254
  * Checks if an expression is likely an array type.
@@ -114,131 +349,946 @@ export function markConditionVariablesAsNullable(
114
349
  }
115
350
 
116
351
  /**
117
- * Extracts conditional usages from a condition expression for key attribute detection.
118
- * This function identifies which attributes are used in conditionals and how they're used.
352
+ * Helper to extract source location from an AST node
353
+ */
354
+ function getSourceLocation(
355
+ node: ts.Node,
356
+ sourceFile: ts.SourceFile,
357
+ ): ConditionalUsage['sourceLocation'] {
358
+ const start = node.getStart(sourceFile);
359
+ const { line, character } = sourceFile.getLineAndCharacterOfPosition(start);
360
+ const codeSnippet = node.getText(sourceFile);
361
+
362
+ return {
363
+ lineNumber: line + 1, // Convert to 1-based
364
+ column: character,
365
+ codeSnippet:
366
+ codeSnippet.length > 100
367
+ ? codeSnippet.slice(0, 100) + '...'
368
+ : codeSnippet,
369
+ };
370
+ }
371
+
372
+ /**
373
+ * Extracts the root array path from an expression that ends with .map().
374
+ * Handles chained methods like .filter().map(), .slice().map(), etc.
119
375
  *
120
- * @param condition The condition expression to analyze
376
+ * Examples:
377
+ * - items.map(...) → "items"
378
+ * - data.users.map(...) → "data.users"
379
+ * - items.filter(...).map(...) → "items"
380
+ * - items.slice(0, 5).map(...) → "items"
381
+ */
382
+ function extractArrayPathFromMapCall(
383
+ expr: ts.CallExpression,
384
+ sourceFile: ts.SourceFile,
385
+ ): string | null {
386
+ // Walk up the chain to find the root array
387
+ let current: ts.Expression = expr.expression;
388
+
389
+ while (ts.isPropertyAccessExpression(current)) {
390
+ const methodName = current.name.getText(sourceFile);
391
+
392
+ // Common array methods that return arrays (so we keep going up)
393
+ const arrayReturningMethods = [
394
+ 'map',
395
+ 'filter',
396
+ 'slice',
397
+ 'concat',
398
+ 'flat',
399
+ 'flatMap',
400
+ 'reverse',
401
+ 'sort',
402
+ 'toReversed',
403
+ 'toSorted',
404
+ 'toSpliced',
405
+ ];
406
+
407
+ if (arrayReturningMethods.includes(methodName)) {
408
+ const objectExpr = current.expression;
409
+
410
+ // If the object is a call expression (chained method), keep going
411
+ if (ts.isCallExpression(objectExpr)) {
412
+ current = objectExpr.expression;
413
+ } else {
414
+ // Found the root - it's an identifier or property access
415
+ const path = StructuredPath.fromNode(objectExpr, sourceFile);
416
+ return path ? path.toString() : null;
417
+ }
418
+ } else {
419
+ // Not an array method we recognize
420
+ break;
421
+ }
422
+ }
423
+
424
+ return null;
425
+ }
426
+
427
+ /**
428
+ * Extracts JSX rendering usages from a JSX expression.
429
+ * Detects:
430
+ * - array.map() calls → 'array-map' type
431
+ * - string interpolations (identifiers/property access) → 'text-interpolation' type
432
+ *
433
+ * Recursively searches inside && chains and ternary expressions.
434
+ *
435
+ * @param expr The expression inside {expr}
121
436
  * @param context The analysis context
122
- * @param location Where this condition appears (if, ternary, logical-and, switch)
123
437
  */
124
- export function extractConditionalUsage(
125
- condition: ts.Expression,
438
+ function extractJsxRenderingUsage(
439
+ expr: ts.Expression,
126
440
  context: AnalysisContext,
127
- location: ConditionalUsage['location'],
128
441
  ): void {
129
- const unwrapped = unwrapExpression(condition);
442
+ const unwrapped = unwrapExpression(expr);
443
+ const sourceLocation = getSourceLocation(expr, context.sourceFile);
130
444
 
131
- // Handle binary expressions with && (logical AND chains)
132
- // Example: `a && b && <Component />` - both a and b are conditional checks
133
- if (
445
+ // Detect array.map() calls
446
+ if (ts.isCallExpression(unwrapped)) {
447
+ const calleeExpr = unwrapped.expression;
448
+
449
+ if (ts.isPropertyAccessExpression(calleeExpr)) {
450
+ const methodName = calleeExpr.name.getText(context.sourceFile);
451
+
452
+ if (methodName === 'map') {
453
+ const arrayPath = extractArrayPathFromMapCall(
454
+ unwrapped,
455
+ context.sourceFile,
456
+ );
457
+
458
+ if (arrayPath) {
459
+ context.addJsxRenderingUsage({
460
+ path: arrayPath,
461
+ renderingType: 'array-map',
462
+ valueType: 'array',
463
+ sourceLocation,
464
+ });
465
+ }
466
+ }
467
+ }
468
+ }
469
+ // Detect simple string interpolations: {title} or {user.name}
470
+ else if (
471
+ ts.isIdentifier(unwrapped) ||
472
+ ts.isPropertyAccessExpression(unwrapped)
473
+ ) {
474
+ const path = StructuredPath.fromNode(unwrapped, context.sourceFile);
475
+
476
+ if (path) {
477
+ const pathStr = path.toString();
478
+ const typeInfo = context.getTypeInfo(path);
479
+
480
+ // Only track as text interpolation if it's a string type
481
+ // Check for 'string' type, or types that contain 'string' (but not 'string[]')
482
+ if (
483
+ typeInfo === 'string' ||
484
+ (typeInfo &&
485
+ typeInfo.includes('string') &&
486
+ !typeInfo.includes('string[]'))
487
+ ) {
488
+ context.addJsxRenderingUsage({
489
+ path: pathStr,
490
+ renderingType: 'text-interpolation',
491
+ valueType: 'string',
492
+ sourceLocation,
493
+ });
494
+ }
495
+ }
496
+ }
497
+ // Recursively search inside && chains: {showList && items.map(...)}
498
+ else if (
134
499
  ts.isBinaryExpression(unwrapped) &&
135
500
  unwrapped.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken
136
501
  ) {
137
- // Recursively process left side
138
- extractConditionalUsage(unwrapped.left, context, location);
502
+ // Check the right side of the && chain (where .map() typically appears)
503
+ const rightSide = unwrapExpression(unwrapped.right);
504
+ extractJsxRenderingUsage(rightSide, context);
505
+ // Also check nested && chains on the left
506
+ extractJsxRenderingUsage(unwrapped.left, context);
507
+ }
508
+ // Recursively search inside ternaries: {isEmpty ? null : items.map(...)}
509
+ else if (ts.isConditionalExpression(unwrapped)) {
510
+ extractJsxRenderingUsage(unwrapped.whenTrue, context);
511
+ extractJsxRenderingUsage(unwrapped.whenFalse, context);
512
+ }
513
+ }
139
514
 
140
- // Process right side if it's not JSX (JSX is the consequence, not the condition)
515
+ /**
516
+ * Counts the number of conditions in an && chain (excluding JSX consequence)
517
+ */
518
+ function countConditionsInAndChain(expr: ts.Expression): number {
519
+ const unwrapped = unwrapExpression(expr);
520
+
521
+ if (
522
+ ts.isBinaryExpression(unwrapped) &&
523
+ unwrapped.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken
524
+ ) {
525
+ const leftCount = countConditionsInAndChain(unwrapped.left);
141
526
  const rightUnwrapped = unwrapExpression(unwrapped.right);
142
527
  const isJsxConsequence =
143
528
  ts.isJsxElement(rightUnwrapped) ||
144
529
  ts.isJsxSelfClosingElement(rightUnwrapped) ||
145
530
  ts.isJsxFragment(rightUnwrapped);
146
531
 
147
- if (!isJsxConsequence) {
148
- extractConditionalUsage(unwrapped.right, context, location);
532
+ if (isJsxConsequence) {
533
+ return leftCount;
149
534
  }
150
- return;
535
+ return leftCount + countConditionsInAndChain(unwrapped.right);
151
536
  }
152
537
 
153
- // Handle binary expressions with || (logical OR)
154
- if (
155
- ts.isBinaryExpression(unwrapped) &&
156
- unwrapped.operatorToken.kind === ts.SyntaxKind.BarBarToken
157
- ) {
158
- // Both sides of || are conditional checks
159
- extractConditionalUsage(unwrapped.left, context, location);
160
- extractConditionalUsage(unwrapped.right, context, location);
538
+ // Single condition (not an && chain)
539
+ return 1;
540
+ }
541
+
542
+ /**
543
+ * Chain tracking info for compound conditionals
544
+ */
545
+ interface ChainInfo {
546
+ chainId: string;
547
+ chainLength: number;
548
+ chainExpression: string;
549
+ currentPosition: number;
550
+ compound: CompoundConditional;
551
+ /**
552
+ * When processing OR expressions within an && chain, this tracks the
553
+ * current OR group ID. Conditions added while this is set will be marked
554
+ * as OR alternatives (only one needs to be true).
555
+ */
556
+ currentOrGroupId?: string;
557
+ }
558
+
559
+ /**
560
+ * Parent gating condition accumulated during JSX traversal.
561
+ * Used to track conditions from parent && chains that gate child components.
562
+ */
563
+ interface ParentGatingCondition {
564
+ path: string;
565
+ sourceLocation: { lineNumber: number; column: number; codeSnippet: string };
566
+ isNegated?: boolean;
567
+ }
568
+
569
+ /**
570
+ * Extracts conditionals from JSX elements by recursively traversing children.
571
+ *
572
+ * This is CRITICAL for extracting compound conditionals from JSX expressions
573
+ * like `{hasNewerVersion && !isActive && <Banner />}`.
574
+ *
575
+ * This function is called BEFORE the child boundary check in processExpression
576
+ * because JSX elements are NOT scopes - their expressions use variables from
577
+ * the parent scope and should have their conditionals extracted regardless of
578
+ * whether the JSX is within a child boundary.
579
+ *
580
+ * Fix 32: Added parentConditions parameter to track gating conditions from
581
+ * parent && chains. When we find a component nested inside multiple conditionals
582
+ * like `{activeTab && <>{ternary ? ... : <Component />}</>}`, ALL parent
583
+ * conditions should be added as gating conditions for the component.
584
+ *
585
+ * @param node The JSX element, self-closing element, or fragment to traverse
586
+ * @param context The analysis context
587
+ * @param parentConditions Accumulated gating conditions from parent && chains
588
+ */
589
+ function extractConditionalsFromJsx(
590
+ node: ts.JsxElement | ts.JsxSelfClosingElement | ts.JsxFragment,
591
+ context: AnalysisContext,
592
+ parentConditions: ParentGatingCondition[] = [],
593
+ ): void {
594
+ // Get children to process
595
+ let children: ts.NodeArray<ts.JsxChild> | undefined;
596
+
597
+ if (ts.isJsxElement(node)) {
598
+ children = node.children;
599
+ } else if (ts.isJsxFragment(node)) {
600
+ children = node.children;
601
+ }
602
+ // JsxSelfClosingElement has no children
603
+
604
+ if (!children) {
161
605
  return;
162
606
  }
163
607
 
164
- // Handle comparison operators (===, !==, <, >, <=, >=)
165
- // Example: `if (status === 'active')` - status is compared against 'active'
166
- if (
167
- ts.isBinaryExpression(unwrapped) &&
168
- isComparisonOperator(unwrapped.operatorToken.kind)
169
- ) {
170
- // Try to extract the variable and the compared value
171
- const leftPath = StructuredPath.fromNode(
172
- unwrapped.left,
173
- context.sourceFile,
174
- );
175
- const rightPath = StructuredPath.fromNode(
176
- unwrapped.right,
177
- context.sourceFile,
178
- );
608
+ for (const child of children) {
609
+ // Process JSX expressions: {expr}
610
+ if (ts.isJsxExpression(child) && child.expression) {
611
+ const expr = unwrapExpression(child.expression);
179
612
 
180
- // Check if left is a variable and right is a literal
181
- if (leftPath && isLiteralExpression(unwrapped.right)) {
182
- const literalValue = getLiteralValue(unwrapped.right, context);
183
- context.addConditionalUsage({
184
- path: leftPath.toLeftHandSideString(),
185
- conditionType: 'comparison',
186
- comparedValues: literalValue !== undefined ? [literalValue] : undefined,
187
- location,
188
- });
613
+ // Extract JSX rendering usages (array.map, text interpolation)
614
+ // This handles direct usages like {items.map(...)} or {user.name}
615
+ extractJsxRenderingUsage(expr, context);
616
+
617
+ // If the expression is an && chain, extract its conditional usages
618
+ if (
619
+ ts.isBinaryExpression(expr) &&
620
+ expr.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken
621
+ ) {
622
+ // Mark nullable variables
623
+ markConditionVariablesAsNullable(expr, context);
624
+ // Extract conditional usage (this handles compound conditionals)
625
+ // Pass controlsJsxRendering: true since this conditional controls JSX rendering
626
+ extractConditionalUsage(expr, context, 'logical-and', {
627
+ controlsJsxRendering: true,
628
+ });
629
+
630
+ // Extract all condition paths from the && chain for gating tracking
631
+ const conditionPaths = extractConditionPathsFromAndChain(
632
+ expr,
633
+ context.sourceFile,
634
+ );
635
+ const sourceLocation = getSourceLocation(expr, context.sourceFile);
636
+
637
+ // Fix 32: Build accumulated conditions including parent conditions
638
+ const accumulatedConditions: ParentGatingCondition[] = [
639
+ ...parentConditions,
640
+ ...conditionPaths.map((path) => ({
641
+ path,
642
+ sourceLocation,
643
+ isNegated: false,
644
+ })),
645
+ ];
646
+
647
+ // Track gating conditions for child components
648
+ // Example: {hasAnalysis && <ScenarioViewer />}
649
+ const jsxElement = findJsxInAndChain(expr);
650
+ if (jsxElement) {
651
+ const componentName = getComponentNameFromJsx(jsxElement);
652
+ if (componentName) {
653
+ // Fix 32: Add ALL accumulated conditions (parent + current) as gating conditions
654
+ for (const condition of accumulatedConditions) {
655
+ context.addChildBoundaryGatingCondition(componentName, {
656
+ path: condition.path,
657
+ conditionType: 'truthiness',
658
+ location: 'logical-and',
659
+ sourceLocation: condition.sourceLocation,
660
+ controlsJsxRendering: true,
661
+ isNegated: condition.isNegated,
662
+ });
663
+ }
664
+ }
665
+
666
+ // Fix 32: Recursively process nested JSX with accumulated conditions
667
+ if (
668
+ ts.isJsxElement(jsxElement) ||
669
+ ts.isJsxSelfClosingElement(jsxElement)
670
+ ) {
671
+ extractConditionalsFromJsx(
672
+ jsxElement,
673
+ context,
674
+ accumulatedConditions,
675
+ );
676
+ }
677
+ }
678
+
679
+ // Fix 32: Also check for nested JSX fragments
680
+ const jsxFragment = findJsxFragmentInAndChain(expr);
681
+ if (jsxFragment) {
682
+ extractConditionalsFromJsx(
683
+ jsxFragment,
684
+ context,
685
+ accumulatedConditions,
686
+ );
687
+ }
688
+ }
689
+ // If the expression is a ternary, extract its conditional
690
+ else if (ts.isConditionalExpression(expr)) {
691
+ // Pass controlsJsxRendering: true since this conditional controls JSX rendering
692
+ extractConditionalUsage(expr.condition, context, 'ternary', {
693
+ controlsJsxRendering: true,
694
+ });
695
+
696
+ // Track gating conditions for components in both branches of the ternary
697
+ // Example: {isError ? <ErrorView /> : <SuccessView />}
698
+ const conditionPath = StructuredPath.fromNode(
699
+ unwrapExpression(expr.condition),
700
+ context.sourceFile,
701
+ );
702
+ const sourceLocation = getSourceLocation(expr, context.sourceFile);
703
+
704
+ // Recursively process the whenTrue and whenFalse branches for JSX
705
+ const whenTrue = unwrapExpression(expr.whenTrue);
706
+ const whenFalse = unwrapExpression(expr.whenFalse);
707
+
708
+ // Fix 32: Build conditions for whenTrue branch (parent conditions + ternary condition truthy)
709
+ const whenTrueConditions: ParentGatingCondition[] = [
710
+ ...parentConditions,
711
+ ...(conditionPath
712
+ ? [
713
+ {
714
+ path: conditionPath.toString(),
715
+ sourceLocation,
716
+ isNegated: false,
717
+ },
718
+ ]
719
+ : []),
720
+ ];
721
+
722
+ // Fix 32: Build conditions for whenFalse branch (parent conditions + ternary condition falsy)
723
+ const whenFalseConditions: ParentGatingCondition[] = [
724
+ ...parentConditions,
725
+ ...(conditionPath
726
+ ? [
727
+ {
728
+ path: conditionPath.toString(),
729
+ sourceLocation,
730
+ isNegated: true,
731
+ },
732
+ ]
733
+ : []),
734
+ ];
735
+
736
+ // Handle whenTrue branch (condition is truthy)
737
+ if (ts.isJsxElement(whenTrue) || ts.isJsxSelfClosingElement(whenTrue)) {
738
+ const componentName = getComponentNameFromJsx(whenTrue);
739
+ if (componentName) {
740
+ // Fix 32: Add ALL conditions (parent + ternary) as gating conditions
741
+ for (const condition of whenTrueConditions) {
742
+ context.addChildBoundaryGatingCondition(componentName, {
743
+ path: condition.path,
744
+ conditionType: 'truthiness',
745
+ location: 'ternary',
746
+ sourceLocation: condition.sourceLocation,
747
+ controlsJsxRendering: true,
748
+ isNegated: condition.isNegated,
749
+ });
750
+ }
751
+ }
752
+ }
753
+ if (
754
+ ts.isJsxElement(whenTrue) ||
755
+ ts.isJsxSelfClosingElement(whenTrue) ||
756
+ ts.isJsxFragment(whenTrue)
757
+ ) {
758
+ extractConditionalsFromJsx(whenTrue, context, whenTrueConditions);
759
+ }
760
+
761
+ // Handle whenFalse branch (condition is falsy/negated)
762
+ if (
763
+ ts.isJsxElement(whenFalse) ||
764
+ ts.isJsxSelfClosingElement(whenFalse)
765
+ ) {
766
+ const componentName = getComponentNameFromJsx(whenFalse);
767
+ if (componentName) {
768
+ // Fix 32: Add ALL conditions (parent + ternary) as gating conditions
769
+ for (const condition of whenFalseConditions) {
770
+ context.addChildBoundaryGatingCondition(componentName, {
771
+ path: condition.path,
772
+ conditionType: 'truthiness',
773
+ location: 'ternary',
774
+ sourceLocation: condition.sourceLocation,
775
+ controlsJsxRendering: true,
776
+ isNegated: condition.isNegated,
777
+ });
778
+ }
779
+ }
780
+ }
781
+ if (
782
+ ts.isJsxElement(whenFalse) ||
783
+ ts.isJsxSelfClosingElement(whenFalse) ||
784
+ ts.isJsxFragment(whenFalse)
785
+ ) {
786
+ extractConditionalsFromJsx(whenFalse, context, whenFalseConditions);
787
+ }
788
+ // Handle chained ternaries: a ? <A/> : b ? <B/> : <C/>
789
+ // When whenFalse is another ConditionalExpression, recursively process it
790
+ else if (ts.isConditionalExpression(whenFalse)) {
791
+ // Extract conditional usage for the nested ternary's condition
792
+ extractConditionalUsage(whenFalse.condition, context, 'ternary', {
793
+ controlsJsxRendering: true,
794
+ });
795
+
796
+ // Get the nested condition path
797
+ const nestedConditionPath = StructuredPath.fromNode(
798
+ unwrapExpression(whenFalse.condition),
799
+ context.sourceFile,
800
+ );
801
+ const nestedSourceLocation = getSourceLocation(
802
+ whenFalse,
803
+ context.sourceFile,
804
+ );
805
+
806
+ const nestedWhenTrue = unwrapExpression(whenFalse.whenTrue);
807
+ const nestedWhenFalse = unwrapExpression(whenFalse.whenFalse);
808
+
809
+ // Fix 32: Build conditions for nested whenTrue (parent falsy + nested truthy)
810
+ const nestedWhenTrueConditions: ParentGatingCondition[] = [
811
+ ...whenFalseConditions, // Parent ternary was falsy to get here
812
+ ...(nestedConditionPath
813
+ ? [
814
+ {
815
+ path: nestedConditionPath.toString(),
816
+ sourceLocation: nestedSourceLocation,
817
+ isNegated: false,
818
+ },
819
+ ]
820
+ : []),
821
+ ];
822
+
823
+ // Fix 32: Build conditions for nested whenFalse (parent falsy + nested falsy)
824
+ const nestedWhenFalseConditions: ParentGatingCondition[] = [
825
+ ...whenFalseConditions, // Parent ternary was falsy to get here
826
+ ...(nestedConditionPath
827
+ ? [
828
+ {
829
+ path: nestedConditionPath.toString(),
830
+ sourceLocation: nestedSourceLocation,
831
+ isNegated: true,
832
+ },
833
+ ]
834
+ : []),
835
+ ];
836
+
837
+ // Handle nested whenTrue branch
838
+ if (
839
+ ts.isJsxElement(nestedWhenTrue) ||
840
+ ts.isJsxSelfClosingElement(nestedWhenTrue)
841
+ ) {
842
+ const componentName = getComponentNameFromJsx(nestedWhenTrue);
843
+ if (componentName) {
844
+ // Fix 32: Add ALL accumulated conditions
845
+ for (const condition of nestedWhenTrueConditions) {
846
+ context.addChildBoundaryGatingCondition(componentName, {
847
+ path: condition.path,
848
+ conditionType: 'truthiness',
849
+ location: 'ternary',
850
+ sourceLocation: condition.sourceLocation,
851
+ controlsJsxRendering: true,
852
+ isNegated: condition.isNegated,
853
+ });
854
+ }
855
+ }
856
+ }
857
+ if (
858
+ ts.isJsxElement(nestedWhenTrue) ||
859
+ ts.isJsxSelfClosingElement(nestedWhenTrue) ||
860
+ ts.isJsxFragment(nestedWhenTrue)
861
+ ) {
862
+ extractConditionalsFromJsx(
863
+ nestedWhenTrue,
864
+ context,
865
+ nestedWhenTrueConditions,
866
+ );
867
+ }
868
+
869
+ // Handle nested whenFalse branch (this could be another chained ternary or JSX)
870
+ if (
871
+ ts.isJsxElement(nestedWhenFalse) ||
872
+ ts.isJsxSelfClosingElement(nestedWhenFalse)
873
+ ) {
874
+ const componentName = getComponentNameFromJsx(nestedWhenFalse);
875
+ if (componentName) {
876
+ // Fix 32: Add ALL accumulated conditions
877
+ for (const condition of nestedWhenFalseConditions) {
878
+ context.addChildBoundaryGatingCondition(componentName, {
879
+ path: condition.path,
880
+ conditionType: 'truthiness',
881
+ location: 'ternary',
882
+ sourceLocation: condition.sourceLocation,
883
+ controlsJsxRendering: true,
884
+ isNegated: condition.isNegated,
885
+ });
886
+ }
887
+ }
888
+ }
889
+ if (
890
+ ts.isJsxElement(nestedWhenFalse) ||
891
+ ts.isJsxSelfClosingElement(nestedWhenFalse) ||
892
+ ts.isJsxFragment(nestedWhenFalse)
893
+ ) {
894
+ extractConditionalsFromJsx(
895
+ nestedWhenFalse,
896
+ context,
897
+ nestedWhenFalseConditions,
898
+ );
899
+ }
900
+ // If nestedWhenFalse is yet another ConditionalExpression, the recursion
901
+ // will handle it on the next iteration when this function processes it
902
+ else if (ts.isConditionalExpression(nestedWhenFalse)) {
903
+ // Recursively handle deeper nesting by wrapping in a synthetic process
904
+ // We create a fake JsxExpression context to reuse the same logic
905
+ const syntheticChild = {
906
+ kind: ts.SyntaxKind.JsxExpression,
907
+ expression: nestedWhenFalse,
908
+ } as unknown as ts.JsxExpression;
909
+ // Process via the main JSX expression handler by recursing
910
+ // For now, just extract conditionals directly
911
+ extractConditionalUsage(
912
+ nestedWhenFalse.condition,
913
+ context,
914
+ 'ternary',
915
+ { controlsJsxRendering: true },
916
+ );
917
+ }
918
+ }
919
+ }
920
+ }
921
+ // Recursively process nested JSX elements - Fix 32: pass parent conditions
922
+ else if (ts.isJsxElement(child)) {
923
+ // Check if this is a user-defined component (vs intrinsic element like div)
924
+ // If it's a component AND there are parent conditions, record the gating conditions
925
+ const componentName = getComponentNameFromJsx(child);
926
+ if (componentName && parentConditions.length > 0) {
927
+ for (const condition of parentConditions) {
928
+ context.addChildBoundaryGatingCondition(componentName, {
929
+ path: condition.path,
930
+ conditionType: 'truthiness',
931
+ location: 'ternary',
932
+ sourceLocation: condition.sourceLocation,
933
+ controlsJsxRendering: true,
934
+ isNegated: condition.isNegated,
935
+ });
936
+ }
937
+ }
938
+ extractConditionalsFromJsx(child, context, parentConditions);
939
+ }
940
+ // Handle self-closing JSX elements (e.g., <ScenarioViewer />)
941
+ else if (ts.isJsxSelfClosingElement(child)) {
942
+ // Check if this is a user-defined component (vs intrinsic element like div)
943
+ // If it's a component AND there are parent conditions, record the gating conditions
944
+ const componentName = getComponentNameFromJsx(child);
945
+ if (componentName && parentConditions.length > 0) {
946
+ for (const condition of parentConditions) {
947
+ context.addChildBoundaryGatingCondition(componentName, {
948
+ path: condition.path,
949
+ conditionType: 'truthiness',
950
+ location: 'ternary',
951
+ sourceLocation: condition.sourceLocation,
952
+ controlsJsxRendering: true,
953
+ isNegated: condition.isNegated,
954
+ });
955
+ }
956
+ }
957
+ // Self-closing elements have no children, so no recursion needed
958
+ }
959
+ // Recursively process nested JSX fragments - Fix 32: pass parent conditions
960
+ else if (ts.isJsxFragment(child)) {
961
+ extractConditionalsFromJsx(child, context, parentConditions);
962
+ }
963
+ }
964
+ }
965
+
966
+ /**
967
+ * Options for extractConditionalUsage
968
+ */
969
+ interface ExtractConditionalOptions {
970
+ /**
971
+ * Whether this conditional controls JSX rendering.
972
+ * Set to true when the conditional appears in a JSX expression like {cond && <Component />}
973
+ */
974
+ controlsJsxRendering?: boolean;
975
+ }
976
+
977
+ /**
978
+ * Extracts conditional usages from a condition expression for key attribute detection.
979
+ * This function identifies which attributes are used in conditionals and how they're used.
980
+ * It also tracks compound conditionals (&&-chains) where all conditions must be true together.
981
+ *
982
+ * @param condition The condition expression to analyze
983
+ * @param context The analysis context
984
+ * @param location Where this condition appears (if, ternary, logical-and, switch)
985
+ * @param options Additional options including controlsJsxRendering flag
986
+ */
987
+ export function extractConditionalUsage(
988
+ condition: ts.Expression,
989
+ context: AnalysisContext,
990
+ location: ConditionalUsage['location'],
991
+ options: ExtractConditionalOptions = {},
992
+ ): void {
993
+ const { controlsJsxRendering } = options;
994
+ // Internal recursive function with chain tracking
995
+ function extractWithChainTracking(
996
+ expr: ts.Expression,
997
+ chainInfo: ChainInfo | null,
998
+ isNegated: boolean,
999
+ ): void {
1000
+ const unwrapped = unwrapExpression(expr);
1001
+
1002
+ // Handle binary expressions with && (logical AND chains)
1003
+ // Example: `a && b && <Component />` - both a and b are conditional checks
1004
+ if (
1005
+ ts.isBinaryExpression(unwrapped) &&
1006
+ unwrapped.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken
1007
+ ) {
1008
+ // Track if we're creating the chain at this level (root of the chain)
1009
+ const isChainRoot = !chainInfo;
1010
+
1011
+ // If no chainInfo, this is the root of a new chain
1012
+ if (isChainRoot) {
1013
+ const chainLength = countConditionsInAndChain(unwrapped);
1014
+ // Only create chain tracking for chains with 2+ conditions
1015
+ if (chainLength >= 2) {
1016
+ const chainId = `chain_${crypto.randomUUID().slice(0, 8)}`;
1017
+ const chainExpression = unwrapped.getText(context.sourceFile);
1018
+ const compound: CompoundConditional = {
1019
+ chainId,
1020
+ expression:
1021
+ chainExpression.length > 200
1022
+ ? chainExpression.slice(0, 200) + '...'
1023
+ : chainExpression,
1024
+ conditions: [],
1025
+ location,
1026
+ sourceLocation: getSourceLocation(unwrapped, context.sourceFile),
1027
+ controlsJsxRendering,
1028
+ };
1029
+ chainInfo = {
1030
+ chainId,
1031
+ chainLength,
1032
+ chainExpression: compound.expression,
1033
+ currentPosition: 0,
1034
+ compound,
1035
+ };
1036
+ }
1037
+ }
1038
+
1039
+ // Recursively process left side
1040
+ extractWithChainTracking(unwrapped.left, chainInfo, false);
1041
+
1042
+ // Process right side if it's not JSX (JSX is the consequence, not the condition)
1043
+ const rightUnwrapped = unwrapExpression(unwrapped.right);
1044
+ const isJsxConsequence =
1045
+ ts.isJsxElement(rightUnwrapped) ||
1046
+ ts.isJsxSelfClosingElement(rightUnwrapped) ||
1047
+ ts.isJsxFragment(rightUnwrapped);
1048
+
1049
+ if (!isJsxConsequence) {
1050
+ extractWithChainTracking(unwrapped.right, chainInfo, false);
1051
+ }
1052
+
1053
+ // If this is the root of the chain, register the compound conditional
1054
+ if (isChainRoot && chainInfo) {
1055
+ context.addCompoundConditional(chainInfo.compound);
1056
+ }
189
1057
  return;
190
1058
  }
191
1059
 
192
- // Check if right is a variable and left is a literal
193
- if (rightPath && isLiteralExpression(unwrapped.left)) {
194
- const literalValue = getLiteralValue(unwrapped.left, context);
195
- context.addConditionalUsage({
196
- path: rightPath.toLeftHandSideString(),
197
- conditionType: 'comparison',
198
- comparedValues: literalValue !== undefined ? [literalValue] : undefined,
199
- location,
200
- });
1060
+ // Handle binary expressions with || (logical OR)
1061
+ // When OR is inside an && chain, we need to continue chain tracking
1062
+ // and mark conditions as OR alternatives
1063
+ if (
1064
+ ts.isBinaryExpression(unwrapped) &&
1065
+ unwrapped.operatorToken.kind === ts.SyntaxKind.BarBarToken
1066
+ ) {
1067
+ if (chainInfo) {
1068
+ // We're inside an && chain - continue tracking but mark as OR alternatives
1069
+ // Generate an orGroupId so conditions from both sides can be grouped
1070
+ const orGroupId =
1071
+ chainInfo.currentOrGroupId ?? `or_${crypto.randomUUID().slice(0, 8)}`;
1072
+
1073
+ // Process left side with OR group tracking
1074
+ const leftChainInfo = {
1075
+ ...chainInfo,
1076
+ currentOrGroupId: orGroupId,
1077
+ };
1078
+ extractWithChainTracking(unwrapped.left, leftChainInfo, false);
1079
+
1080
+ // Process right side with same OR group
1081
+ // Note: we use leftChainInfo's currentPosition which may have been updated
1082
+ const rightChainInfo = {
1083
+ ...leftChainInfo,
1084
+ currentPosition: chainInfo.currentPosition,
1085
+ };
1086
+ extractWithChainTracking(unwrapped.right, rightChainInfo, false);
1087
+ } else {
1088
+ // Not inside a chain - OR breaks into independent conditional checks
1089
+ extractWithChainTracking(unwrapped.left, null, false);
1090
+ extractWithChainTracking(unwrapped.right, null, false);
1091
+ }
201
1092
  return;
202
1093
  }
203
1094
 
204
- // Both sides are variables - record both as comparisons without specific values
205
- if (leftPath) {
206
- context.addConditionalUsage({
207
- path: leftPath.toLeftHandSideString(),
208
- conditionType: 'comparison',
209
- location,
210
- });
1095
+ // Handle comparison operators (===, !==, <, >, <=, >=)
1096
+ // Example: `if (status === 'active')` - status is compared against 'active'
1097
+ if (
1098
+ ts.isBinaryExpression(unwrapped) &&
1099
+ isComparisonOperator(unwrapped.operatorToken.kind)
1100
+ ) {
1101
+ // Try to extract the variable and the compared value
1102
+ const leftPath = StructuredPath.fromNode(
1103
+ unwrapped.left,
1104
+ context.sourceFile,
1105
+ );
1106
+ const rightPath = StructuredPath.fromNode(
1107
+ unwrapped.right,
1108
+ context.sourceFile,
1109
+ );
1110
+
1111
+ // Determine the compared value for computing requiredValue
1112
+ const getRequiredValue = (
1113
+ literalValue: string | undefined,
1114
+ isNegatedComparison: boolean,
1115
+ ): string | boolean | undefined => {
1116
+ if (literalValue === undefined) return undefined;
1117
+ // For !== comparisons, the condition is true when NOT equal to the value
1118
+ // For === comparisons, the condition is true when equal to the value
1119
+ const isNotEqual =
1120
+ unwrapped.operatorToken.kind ===
1121
+ ts.SyntaxKind.ExclamationEqualsEqualsToken ||
1122
+ unwrapped.operatorToken.kind === ts.SyntaxKind.ExclamationEqualsToken;
1123
+ if (isNotEqual) {
1124
+ // !== 'value' means requiredValue is NOT 'value', but we express this as "not 'value'"
1125
+ return `not ${literalValue}`;
1126
+ }
1127
+ return literalValue;
1128
+ };
1129
+
1130
+ // Helper to add a condition
1131
+ const addCondition = (
1132
+ path: string,
1133
+ conditionType: 'comparison' | 'truthiness',
1134
+ comparedValues?: string[],
1135
+ requiredValue?: string | boolean,
1136
+ sourceExpr?: ts.Expression,
1137
+ ) => {
1138
+ const usage: ConditionalUsage = {
1139
+ path,
1140
+ conditionType,
1141
+ comparedValues,
1142
+ location,
1143
+ sourceLocation: getSourceLocation(unwrapped, context.sourceFile),
1144
+ isNegated,
1145
+ controlsJsxRendering,
1146
+ };
1147
+
1148
+ // Check for inline array-derived patterns (.length) on the source expression
1149
+ if (sourceExpr) {
1150
+ const arrayDerived = detectArrayDerivedPattern(sourceExpr);
1151
+ if (arrayDerived) {
1152
+ usage.derivedFrom = {
1153
+ operation: arrayDerived.operation,
1154
+ sourcePath: arrayDerived.sourcePath,
1155
+ };
1156
+ }
1157
+ }
1158
+
1159
+ // Add chain info if part of a compound conditional
1160
+ if (chainInfo) {
1161
+ usage.chainId = chainInfo.chainId;
1162
+ usage.chainPosition = chainInfo.currentPosition;
1163
+ usage.chainLength = chainInfo.chainLength;
1164
+ usage.chainExpression = chainInfo.chainExpression;
1165
+ chainInfo.currentPosition++;
1166
+
1167
+ // Add to compound conditional conditions
1168
+ chainInfo.compound.conditions.push({
1169
+ path,
1170
+ conditionType,
1171
+ comparedValues,
1172
+ isNegated,
1173
+ requiredValue,
1174
+ ...(chainInfo.currentOrGroupId && {
1175
+ orGroupId: chainInfo.currentOrGroupId,
1176
+ }),
1177
+ });
1178
+ }
1179
+
1180
+ context.addConditionalUsage(usage);
1181
+ };
1182
+
1183
+ // Check if left is a variable and right is a literal
1184
+ if (leftPath && isLiteralExpression(unwrapped.right)) {
1185
+ const literalValue = getLiteralValue(unwrapped.right, context);
1186
+ addCondition(
1187
+ leftPath.toLeftHandSideString(),
1188
+ 'comparison',
1189
+ literalValue !== undefined ? [literalValue] : undefined,
1190
+ getRequiredValue(literalValue, isNegated),
1191
+ unwrapped.left, // Pass source expression for array derivation detection
1192
+ );
1193
+ return;
1194
+ }
1195
+
1196
+ // Check if right is a variable and left is a literal
1197
+ if (rightPath && isLiteralExpression(unwrapped.left)) {
1198
+ const literalValue = getLiteralValue(unwrapped.left, context);
1199
+ addCondition(
1200
+ rightPath.toLeftHandSideString(),
1201
+ 'comparison',
1202
+ literalValue !== undefined ? [literalValue] : undefined,
1203
+ getRequiredValue(literalValue, isNegated),
1204
+ unwrapped.right, // Pass source expression for array derivation detection
1205
+ );
1206
+ return;
1207
+ }
1208
+
1209
+ // Both sides are variables - record both as comparisons without specific values
1210
+ if (leftPath) {
1211
+ addCondition(
1212
+ leftPath.toLeftHandSideString(),
1213
+ 'comparison',
1214
+ undefined,
1215
+ undefined,
1216
+ unwrapped.left,
1217
+ );
1218
+ }
1219
+ if (rightPath) {
1220
+ addCondition(
1221
+ rightPath.toLeftHandSideString(),
1222
+ 'comparison',
1223
+ undefined,
1224
+ undefined,
1225
+ unwrapped.right,
1226
+ );
1227
+ }
1228
+ return;
211
1229
  }
212
- if (rightPath) {
213
- context.addConditionalUsage({
214
- path: rightPath.toLeftHandSideString(),
215
- conditionType: 'comparison',
216
- location,
217
- });
1230
+
1231
+ // Handle prefix unary NOT expression: !variable
1232
+ // Example: `if (!isVisible)` - isVisible is a truthiness check (negated)
1233
+ if (
1234
+ ts.isPrefixUnaryExpression(unwrapped) &&
1235
+ unwrapped.operator === ts.SyntaxKind.ExclamationToken
1236
+ ) {
1237
+ extractWithChainTracking(unwrapped.operand, chainInfo, !isNegated);
1238
+ return;
218
1239
  }
219
- return;
220
- }
221
1240
 
222
- // Handle prefix unary NOT expression: !variable
223
- // Example: `if (!isVisible)` - isVisible is a truthiness check
224
- if (
225
- ts.isPrefixUnaryExpression(unwrapped) &&
226
- unwrapped.operator === ts.SyntaxKind.ExclamationToken
227
- ) {
228
- extractConditionalUsage(unwrapped.operand, context, location);
229
- return;
230
- }
1241
+ // Handle simple identifiers or property accesses (truthiness checks)
1242
+ // Example: `if (x)` or `x && <JSX />` - x is checked for truthiness
1243
+ const path = StructuredPath.fromNode(unwrapped, context.sourceFile);
1244
+ if (path && !path.isLiteral()) {
1245
+ const pathStr = path.toLeftHandSideString();
1246
+ const usage: ConditionalUsage = {
1247
+ path: pathStr,
1248
+ conditionType: 'truthiness',
1249
+ location,
1250
+ sourceLocation: getSourceLocation(unwrapped, context.sourceFile),
1251
+ isNegated,
1252
+ controlsJsxRendering,
1253
+ };
1254
+
1255
+ // Check for inline array-derived patterns (.some(), .every(), .includes(), .length)
1256
+ // This populates derivedFrom so downstream code can resolve to the base array path
1257
+ const arrayDerived = detectArrayDerivedPattern(unwrapped);
1258
+ if (arrayDerived) {
1259
+ usage.derivedFrom = {
1260
+ operation: arrayDerived.operation,
1261
+ sourcePath: arrayDerived.sourcePath,
1262
+ };
1263
+ }
231
1264
 
232
- // Handle simple identifiers or property accesses (truthiness checks)
233
- // Example: `if (x)` or `x && <JSX />` - x is checked for truthiness
234
- const path = StructuredPath.fromNode(unwrapped, context.sourceFile);
235
- if (path && !path.isLiteral()) {
236
- context.addConditionalUsage({
237
- path: path.toLeftHandSideString(),
238
- conditionType: 'truthiness',
239
- location,
240
- });
1265
+ // Add chain info if part of a compound conditional
1266
+ if (chainInfo) {
1267
+ usage.chainId = chainInfo.chainId;
1268
+ usage.chainPosition = chainInfo.currentPosition;
1269
+ usage.chainLength = chainInfo.chainLength;
1270
+ usage.chainExpression = chainInfo.chainExpression;
1271
+ chainInfo.currentPosition++;
1272
+
1273
+ // Add to compound conditional conditions
1274
+ // For truthiness, requiredValue is true if not negated, false if negated
1275
+ chainInfo.compound.conditions.push({
1276
+ path: pathStr,
1277
+ conditionType: 'truthiness',
1278
+ isNegated,
1279
+ requiredValue: !isNegated,
1280
+ ...(chainInfo.currentOrGroupId && {
1281
+ orGroupId: chainInfo.currentOrGroupId,
1282
+ }),
1283
+ });
1284
+ }
1285
+
1286
+ context.addConditionalUsage(usage);
1287
+ }
241
1288
  }
1289
+
1290
+ // Start extraction with no chain info
1291
+ extractWithChainTracking(condition, null, false);
242
1292
  }
243
1293
 
244
1294
  /**
@@ -341,7 +1391,28 @@ export function processExpression({
341
1391
  ) {
342
1392
  markConditionVariablesAsNullable(unwrappedNode, context);
343
1393
  // Extract conditional usages for key attribute detection
344
- extractConditionalUsage(unwrappedNode, context, 'logical-and');
1394
+ // Only call from the OUTERMOST && expression to avoid duplicates
1395
+ // Check if parent is also a && (meaning we're nested)
1396
+ const parent = unwrappedNode.parent;
1397
+ const parentIsAndChain =
1398
+ parent &&
1399
+ ts.isBinaryExpression(parent) &&
1400
+ parent.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken;
1401
+ if (!parentIsAndChain) {
1402
+ extractConditionalUsage(unwrappedNode, context, 'logical-and');
1403
+ }
1404
+ }
1405
+
1406
+ // CRITICAL: Extract conditionals from JSX BEFORE checking child boundaries
1407
+ // JSX elements are NOT scopes - their expressions use variables from the parent scope.
1408
+ // Even if the JSX element is within a child boundary (e.g., because it contains callbacks),
1409
+ // we must still extract conditionals from JSX expression children like {x && <div>...</div>}
1410
+ if (
1411
+ ts.isJsxElement(unwrappedNode) ||
1412
+ ts.isJsxSelfClosingElement(unwrappedNode) ||
1413
+ ts.isJsxFragment(unwrappedNode)
1414
+ ) {
1415
+ extractConditionalsFromJsx(unwrappedNode, context);
345
1416
  }
346
1417
 
347
1418
  // If the node falls within an excluded child scope, stop processing it.
@@ -535,7 +1606,8 @@ export function processExpression({
535
1606
  // Check if this is an environment variable access
536
1607
  const fullText = unwrappedNode.getText(context.sourceFile);
537
1608
  if (
538
- fullText.includes('.env.') // simple heuristic for env var access but not great
1609
+ fullText.includes('.env.') || // process.env.X, window.env.X
1610
+ isEnvStoreAccess(fullText) // env.X where env is likely an env config object
539
1611
  ) {
540
1612
  context.addEnvironmentVariable(fullText);
541
1613
  }
@@ -842,6 +1914,14 @@ export function processExpression({
842
1914
  // e.g., `const tab = segments[0] || 'default'` should trace tab back to segments[0]
843
1915
  if (operatorKind === ts.SyntaxKind.QuestionQuestionToken) {
844
1916
  // specifically for ?? we create an equivalence to the left side
1917
+ // IMPORTANT: Also process the left side recursively to apply method semantics
1918
+ // (e.g., for `const segments = splat?.split('/') ?? []`, we need split semantics)
1919
+ processExpression({
1920
+ node: unwrappedNode.left,
1921
+ context,
1922
+ // Don't pass targetPath here - we'll establish equivalence separately below
1923
+ });
1924
+
845
1925
  if (targetPath) {
846
1926
  resultPath = StructuredPath.fromNode(
847
1927
  unwrappedNode.left,
@@ -859,15 +1939,31 @@ export function processExpression({
859
1939
  );
860
1940
  }
861
1941
  } else if (operatorKind === ts.SyntaxKind.BarBarToken) {
862
- // For ||, also create an equivalence to the left side
1942
+ // For ||, create equivalences to BOTH sides
863
1943
  // This enables data flow tracing through fallback expressions
1944
+ // e.g., `const item = items.find(...) || null` should trace to both:
1945
+ // - items[] (from the find result)
1946
+ // - null (from the fallback)
864
1947
  if (targetPath) {
1948
+ // Process left side recursively to capture its full equivalency chain
1949
+ processExpression({
1950
+ node: unwrappedNode.left,
1951
+ context,
1952
+ targetPath,
1953
+ });
1954
+ // Process right side recursively for completeness
1955
+ processExpression({
1956
+ node: unwrappedNode.right,
1957
+ context,
1958
+ targetPath,
1959
+ });
1960
+ // Set resultPath to left side for type inference
865
1961
  resultPath = StructuredPath.fromNode(
866
1962
  unwrappedNode.left,
867
1963
  context.sourceFile,
868
1964
  );
869
1965
  }
870
- // Note: Unlike ??, we don't set targetPath when there's no target
1966
+ // Note: When there's no targetPath, we don't recursively process
871
1967
  // because || is often used in boolean contexts where the full expression matters
872
1968
  }
873
1969
  } else if (operatorKind === ts.SyntaxKind.InstanceOfKeyword) {
@@ -930,9 +2026,10 @@ export function processExpression({
930
2026
  return false;
931
2027
  }
932
2028
 
933
- // Construct empty arguments list just to get the call path
934
- // We'll process each argument with its parameter path as targetPath
935
- const callPath = StructuredPath.fromNode(unwrappedNode, context.sourceFile);
2029
+ // Build call path using original source text for consistent schema paths.
2030
+ // IMPORTANT: Never use cyScope names in call paths - they are internal identifiers
2031
+ // that should not appear in schema paths or call signatures.
2032
+ const callPath = buildCallPathFromSource(unwrappedNode, context);
936
2033
 
937
2034
  // 2. Process all arguments recursively WITH targetPath for proper equivalence
938
2035
  for (let i = 0; i < unwrappedNode.arguments.length; i++) {
@@ -1099,6 +2196,13 @@ export function processExpression({
1099
2196
  // Create a path for this property within the base
1100
2197
  const propPath = targetPath.withProperty(propName);
1101
2198
 
2199
+ // Handle child boundaries (callback functions) in object properties
2200
+ // This establishes equivalency between the property path and the child scope
2201
+ // e.g., columns[0].renderCell → cyScope1()
2202
+ if (context.isChildBoundary(property.initializer)) {
2203
+ context.addChildBoundaryEquivalence(propPath, property.initializer);
2204
+ }
2205
+
1102
2206
  // Process the property value with propPath as targetPath
1103
2207
  // This allows nested object literals to work correctly
1104
2208
  processExpression({
@@ -1398,14 +2502,30 @@ export function processExpression({
1398
2502
  // Extract conditional usages for key attribute detection
1399
2503
  extractConditionalUsage(unwrappedNode.condition, context, 'ternary');
1400
2504
 
2505
+ // Extract conditional effects (setter calls in ternary branches)
2506
+ const knownSetters = findUseStateSetters(context.sourceFile);
2507
+ const effects = extractConditionalEffectsFromTernary(
2508
+ unwrappedNode,
2509
+ context,
2510
+ knownSetters,
2511
+ );
2512
+ for (const effect of effects) {
2513
+ context.addConditionalEffect(effect);
2514
+ }
2515
+
1401
2516
  // Process all parts recursively
1402
2517
  processExpression({
1403
2518
  node: unwrappedNode.condition,
1404
2519
  context,
1405
2520
  typeHint: 'boolean | unknown',
1406
2521
  }); //TODO: could we capture that this is evidence of a boolean type?
1407
- processExpression({ node: unwrappedNode.whenTrue, context });
1408
- processExpression({ node: unwrappedNode.whenFalse, context });
2522
+
2523
+ // Process both branches WITH targetPath to establish equivalencies
2524
+ // This is critical for tracing nested properties through ternary assignments
2525
+ // e.g., const items = condition ? arr1 : arr2; items.map(i => i.prop)
2526
+ // We need items to be equivalent to both arr1 AND arr2 for proper tracing
2527
+ processExpression({ node: unwrappedNode.whenTrue, context, targetPath });
2528
+ processExpression({ node: unwrappedNode.whenFalse, context, targetPath });
1409
2529
 
1410
2530
  // Create a path for the whole expression
1411
2531
  const expressionSourcePath = nodeToSource(
@@ -1428,10 +2548,22 @@ export function processExpression({
1428
2548
  // Register type for the expression
1429
2549
  context.addType(expressionSourcePath, resultType);
1430
2550
 
1431
- // If targetPath is provided, establish equivalence and register type
2551
+ // If targetPath is provided, only register type (don't overwrite branch equivalencies)
2552
+ // The equivalencies to individual branches (set above) are more useful for tracing
2553
+ // than an equivalency to the entire ternary expression text
1432
2554
  if (targetPath) {
1433
- context.addEquivalence(targetPath, expressionSourcePath);
1434
- context.addType(targetPath, resultType);
2555
+ // NOTE: We intentionally do NOT add equivalence here.
2556
+ // The branch processing above already added equivalencies:
2557
+ // targetPath -> whenTrue branch
2558
+ // targetPath -> whenFalse branch
2559
+ // Adding an equivalence to expressionSourcePath would overwrite those
2560
+ // with a useless equivalence to the ternary text itself.
2561
+ //
2562
+ // Use updateSchemaType instead of addType because:
2563
+ // 1. Branch processing may have already set a type on targetPath
2564
+ // 2. addType has a guard that prevents overwriting specific types with 'unknown'
2565
+ // 3. updateSchemaType bypasses this guard, ensuring the ternary's computed type is used
2566
+ context.updateSchemaType(targetPath, resultType);
1435
2567
  }
1436
2568
 
1437
2569
  return true;
@@ -2232,6 +3364,9 @@ function processJsxAttribute(
2232
3364
  if (ts.isJsxExpression(attr.initializer) && attr.initializer.expression) {
2233
3365
  const expression = attr.initializer.expression;
2234
3366
  if (context.isChildBoundary(expression)) {
3367
+ // Create equivalency between attribute path and child scope
3368
+ // e.g., Grid().signature[0].renderRow → cyScope1()
3369
+ context.addChildBoundaryEquivalence(attributePath, expression);
2235
3370
  return true;
2236
3371
  }
2237
3372