@codeyam/codeyam-cli 0.1.0-staging.1669d45 → 0.1.0-staging.2a88920
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.
- package/analyzer-template/.build-info.json +8 -8
- package/analyzer-template/log.txt +3 -3
- package/analyzer-template/package.json +5 -5
- package/analyzer-template/packages/ai/index.ts +15 -2
- package/analyzer-template/packages/ai/src/lib/analyzeScope.ts +87 -51
- package/analyzer-template/packages/ai/src/lib/astScopes/arrayDerivationDetector.ts +199 -0
- package/analyzer-template/packages/ai/src/lib/astScopes/astScopeAnalyzer.ts +98 -9
- package/analyzer-template/packages/ai/src/lib/astScopes/methodSemantics.ts +139 -23
- package/analyzer-template/packages/ai/src/lib/astScopes/patterns/variableDeclarationHandler.ts +6 -126
- package/analyzer-template/packages/ai/src/lib/astScopes/processExpression.ts +555 -28
- package/analyzer-template/packages/ai/src/lib/astScopes/types.ts +88 -7
- package/analyzer-template/packages/ai/src/lib/completionCall.ts +198 -34
- package/analyzer-template/packages/ai/src/lib/dataStructure/ScopeDataStructure.ts +772 -243
- package/analyzer-template/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/MuiManager.ts +205 -0
- package/analyzer-template/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/ReactFrameworkManager.ts +10 -2
- package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/BatchSchemaProcessor.ts +16 -3
- package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/ScopeTreeManager.ts +6 -4
- package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/cleanKnownObjectFunctions.ts +43 -1
- package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/cleanNonObjectFunctions.ts +122 -15
- package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/convertTypeAnnotationsToValues.ts +160 -0
- package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/deduplicateFunctionSchemas.ts +40 -30
- package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/fillInSchemaGapsAndUnknowns.ts +319 -88
- package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/fixNullIdsBySchema.ts +129 -0
- package/analyzer-template/packages/ai/src/lib/dataStructureChunking.ts +156 -0
- package/analyzer-template/packages/ai/src/lib/e2eDataTracking.ts +334 -0
- package/analyzer-template/packages/ai/src/lib/extractCriticalDataKeys.ts +120 -0
- package/analyzer-template/packages/ai/src/lib/generateEntityScenarioData.ts +642 -7
- package/analyzer-template/packages/ai/src/lib/generateEntityScenarios.ts +35 -6
- package/analyzer-template/packages/ai/src/lib/generateExecutionFlows.ts +383 -6
- package/analyzer-template/packages/ai/src/lib/generateExecutionFlowsFromConditionalEffects.ts +1 -1
- package/analyzer-template/packages/ai/src/lib/generateExecutionFlowsFromConditionals.ts +1299 -51
- package/analyzer-template/packages/ai/src/lib/generateExecutionFlowsFromJsxUsages.ts +239 -0
- package/analyzer-template/packages/ai/src/lib/mergeStatements.ts +90 -96
- package/analyzer-template/packages/ai/src/lib/promptGenerators/gatherAttributesMap.ts +10 -7
- package/analyzer-template/packages/ai/src/lib/promptGenerators/generateChunkPrompt.ts +82 -0
- package/analyzer-template/packages/ai/src/lib/promptGenerators/generateCriticalKeysPrompt.ts +103 -0
- package/analyzer-template/packages/ai/src/lib/promptGenerators/generateEntityScenarioDataGenerator.ts +23 -6
- package/analyzer-template/packages/ai/src/lib/promptGenerators/simplifyKeysForLLM.ts +391 -0
- package/analyzer-template/packages/ai/src/lib/resolvePathToControllable.ts +179 -45
- package/analyzer-template/packages/ai/src/lib/worker/SerializableDataStructure.ts +26 -4
- package/analyzer-template/packages/ai/src/lib/worker/analyzeScopeWorker.ts +114 -2
- package/analyzer-template/packages/analyze/src/lib/FileAnalyzer.ts +65 -59
- package/analyzer-template/packages/analyze/src/lib/ProjectAnalyzer.ts +113 -26
- package/analyzer-template/packages/analyze/src/lib/analysisContext.ts +44 -4
- package/analyzer-template/packages/analyze/src/lib/asts/sourceFiles/getAllDeclaredEntityNodes.ts +19 -0
- package/analyzer-template/packages/analyze/src/lib/asts/sourceFiles/getAllEntityNodes.ts +19 -0
- package/analyzer-template/packages/analyze/src/lib/asts/sourceFiles/getAllExports.ts +11 -0
- package/analyzer-template/packages/analyze/src/lib/asts/sourceFiles/getImportsAnalysis.ts +8 -0
- package/analyzer-template/packages/analyze/src/lib/asts/sourceFiles/getResolvedModule.ts +49 -1
- package/analyzer-template/packages/analyze/src/lib/asts/sourceFiles/getSourceFilesForAllImports.ts +2 -1
- package/analyzer-template/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.ts +30 -19
- package/analyzer-template/packages/analyze/src/lib/files/analyze/analyzeEntities.ts +14 -4
- package/analyzer-template/packages/analyze/src/lib/files/analyze/dependencyResolver.ts +6 -0
- package/analyzer-template/packages/analyze/src/lib/files/analyze/gatherEntityMap.ts +4 -2
- package/analyzer-template/packages/analyze/src/lib/files/analyze/validateDependencyAnalyses.ts +33 -10
- package/analyzer-template/packages/analyze/src/lib/files/analyzeRemixRoute.ts +4 -5
- package/analyzer-template/packages/analyze/src/lib/files/getImportedExports.ts +14 -12
- package/analyzer-template/packages/analyze/src/lib/files/scenarios/enrichArrayTypesFromChildSignatures.ts +189 -76
- package/analyzer-template/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.ts +29 -0
- package/analyzer-template/packages/analyze/src/lib/files/scenarios/generateDataStructure.ts +77 -9
- package/analyzer-template/packages/analyze/src/lib/files/scenarios/generateExecutionFlows.ts +118 -10
- package/analyzer-template/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.ts +276 -17
- package/analyzer-template/packages/analyze/src/lib/files/scenarios/mergeValidatedDataStructures.ts +56 -11
- package/analyzer-template/packages/analyze/src/lib/files/scenarios/propagateArrayItemSchemas.ts +474 -0
- package/analyzer-template/packages/analyze/src/lib/files/setImportedExports.ts +2 -1
- package/analyzer-template/packages/analyze/src/lib/utils/getFileByPath.ts +19 -0
- package/analyzer-template/packages/aws/package.json +2 -2
- package/analyzer-template/packages/database/src/lib/kysely/db.ts +8 -1
- package/analyzer-template/packages/database/src/lib/kysely/tables/commitsTable.ts +6 -0
- package/analyzer-template/packages/database/src/lib/loadAnalyses.ts +58 -1
- package/analyzer-template/packages/database/src/lib/loadAnalysis.ts +13 -0
- package/analyzer-template/packages/database/src/lib/loadBranch.ts +16 -1
- package/analyzer-template/packages/database/src/lib/loadCommit.ts +11 -0
- package/analyzer-template/packages/database/src/lib/loadCommits.ts +28 -0
- package/analyzer-template/packages/database/src/lib/loadEntities.ts +26 -3
- package/analyzer-template/packages/database/src/lib/loadEntityBranches.ts +12 -0
- package/analyzer-template/packages/database/src/lib/updateCommitMetadata.ts +7 -14
- package/analyzer-template/packages/github/dist/database/src/lib/kysely/db.d.ts.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/kysely/db.js +8 -1
- package/analyzer-template/packages/github/dist/database/src/lib/kysely/db.js.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/analysesTable.d.ts.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/commitsTable.d.ts +1 -0
- package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/commitsTable.d.ts.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/commitsTable.js +3 -0
- package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/commitsTable.js.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/loadAnalyses.d.ts +2 -0
- package/analyzer-template/packages/github/dist/database/src/lib/loadAnalyses.d.ts.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/loadAnalyses.js +45 -2
- package/analyzer-template/packages/github/dist/database/src/lib/loadAnalyses.js.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/loadAnalysis.d.ts.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/loadAnalysis.js +8 -0
- package/analyzer-template/packages/github/dist/database/src/lib/loadAnalysis.js.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/loadBranch.js +11 -1
- package/analyzer-template/packages/github/dist/database/src/lib/loadBranch.js.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/loadCommit.d.ts.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/loadCommit.js +7 -0
- package/analyzer-template/packages/github/dist/database/src/lib/loadCommit.js.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/loadCommits.d.ts +3 -1
- package/analyzer-template/packages/github/dist/database/src/lib/loadCommits.d.ts.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/loadCommits.js +22 -1
- package/analyzer-template/packages/github/dist/database/src/lib/loadCommits.js.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/loadEntities.d.ts +3 -1
- package/analyzer-template/packages/github/dist/database/src/lib/loadEntities.d.ts.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/loadEntities.js +23 -4
- package/analyzer-template/packages/github/dist/database/src/lib/loadEntities.js.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/loadEntityBranches.d.ts.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/loadEntityBranches.js +9 -0
- package/analyzer-template/packages/github/dist/database/src/lib/loadEntityBranches.js.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/updateCommitMetadata.d.ts +2 -2
- package/analyzer-template/packages/github/dist/database/src/lib/updateCommitMetadata.d.ts.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/updateCommitMetadata.js +5 -4
- package/analyzer-template/packages/github/dist/database/src/lib/updateCommitMetadata.js.map +1 -1
- package/analyzer-template/packages/github/dist/types/index.d.ts +1 -1
- package/analyzer-template/packages/github/dist/types/index.d.ts.map +1 -1
- package/analyzer-template/packages/github/dist/types/index.js.map +1 -1
- package/analyzer-template/packages/github/dist/types/src/types/Analysis.d.ts +25 -1
- package/analyzer-template/packages/github/dist/types/src/types/Analysis.d.ts.map +1 -1
- package/analyzer-template/packages/github/dist/types/src/types/Commit.d.ts +2 -0
- package/analyzer-template/packages/github/dist/types/src/types/Commit.d.ts.map +1 -1
- package/analyzer-template/packages/github/dist/types/src/types/ScenariosDataStructure.d.ts +56 -6
- package/analyzer-template/packages/github/dist/types/src/types/ScenariosDataStructure.d.ts.map +1 -1
- package/analyzer-template/packages/github/dist/types/src/types/ScopeAnalysis.d.ts +6 -1
- package/analyzer-template/packages/github/dist/types/src/types/ScopeAnalysis.d.ts.map +1 -1
- package/analyzer-template/packages/github/dist/utils/src/lib/safeFileName.d.ts +9 -1
- package/analyzer-template/packages/github/dist/utils/src/lib/safeFileName.d.ts.map +1 -1
- package/analyzer-template/packages/github/dist/utils/src/lib/safeFileName.js +29 -3
- package/analyzer-template/packages/github/dist/utils/src/lib/safeFileName.js.map +1 -1
- package/analyzer-template/packages/github/package.json +1 -1
- package/analyzer-template/packages/types/index.ts +1 -0
- package/analyzer-template/packages/types/src/types/Analysis.ts +25 -0
- package/analyzer-template/packages/types/src/types/Commit.ts +2 -0
- package/analyzer-template/packages/types/src/types/ScenariosDataStructure.ts +70 -6
- package/analyzer-template/packages/types/src/types/ScopeAnalysis.ts +6 -1
- package/analyzer-template/packages/utils/dist/types/index.d.ts +1 -1
- package/analyzer-template/packages/utils/dist/types/index.d.ts.map +1 -1
- package/analyzer-template/packages/utils/dist/types/index.js.map +1 -1
- package/analyzer-template/packages/utils/dist/types/src/types/Analysis.d.ts +25 -1
- package/analyzer-template/packages/utils/dist/types/src/types/Analysis.d.ts.map +1 -1
- package/analyzer-template/packages/utils/dist/types/src/types/Commit.d.ts +2 -0
- package/analyzer-template/packages/utils/dist/types/src/types/Commit.d.ts.map +1 -1
- package/analyzer-template/packages/utils/dist/types/src/types/ScenariosDataStructure.d.ts +56 -6
- package/analyzer-template/packages/utils/dist/types/src/types/ScenariosDataStructure.d.ts.map +1 -1
- package/analyzer-template/packages/utils/dist/types/src/types/ScopeAnalysis.d.ts +6 -1
- package/analyzer-template/packages/utils/dist/types/src/types/ScopeAnalysis.d.ts.map +1 -1
- package/analyzer-template/packages/utils/dist/utils/src/lib/safeFileName.d.ts +9 -1
- package/analyzer-template/packages/utils/dist/utils/src/lib/safeFileName.d.ts.map +1 -1
- package/analyzer-template/packages/utils/dist/utils/src/lib/safeFileName.js +29 -3
- package/analyzer-template/packages/utils/dist/utils/src/lib/safeFileName.js.map +1 -1
- package/analyzer-template/packages/utils/src/lib/safeFileName.ts +48 -3
- package/analyzer-template/playwright/capture.ts +20 -8
- package/analyzer-template/playwright/captureStatic.ts +1 -1
- package/analyzer-template/project/analyzeBaselineCommit.ts +5 -0
- package/analyzer-template/project/analyzeRegularCommit.ts +5 -0
- package/analyzer-template/project/captureLibraryFunctionDirect.ts +29 -26
- package/analyzer-template/project/constructMockCode.ts +367 -37
- package/analyzer-template/project/createEntitiesAndSortFiles.ts +83 -0
- package/analyzer-template/project/loadReadyToBeCaptured.ts +65 -41
- package/analyzer-template/project/orchestrateCapture/AwsCaptureTaskRunner.ts +12 -4
- package/analyzer-template/project/orchestrateCapture/SequentialCaptureTaskRunner.ts +18 -7
- package/analyzer-template/project/orchestrateCapture/taskRunner.ts +4 -2
- package/analyzer-template/project/orchestrateCapture.ts +71 -6
- package/analyzer-template/project/reconcileMockDataKeys.ts +152 -9
- package/analyzer-template/project/runAnalysis.ts +4 -0
- package/analyzer-template/project/start.ts +35 -11
- package/analyzer-template/project/writeMockDataTsx.ts +127 -4
- package/analyzer-template/project/writeScenarioComponents.ts +101 -8
- package/analyzer-template/scripts/comboWorkerLoop.cjs +98 -50
- package/background/src/lib/virtualized/project/analyzeBaselineCommit.js +5 -0
- package/background/src/lib/virtualized/project/analyzeBaselineCommit.js.map +1 -1
- package/background/src/lib/virtualized/project/analyzeRegularCommit.js +5 -0
- package/background/src/lib/virtualized/project/analyzeRegularCommit.js.map +1 -1
- package/background/src/lib/virtualized/project/captureLibraryFunctionDirect.js +3 -3
- package/background/src/lib/virtualized/project/captureLibraryFunctionDirect.js.map +1 -1
- package/background/src/lib/virtualized/project/constructMockCode.js +300 -7
- package/background/src/lib/virtualized/project/constructMockCode.js.map +1 -1
- package/background/src/lib/virtualized/project/createEntitiesAndSortFiles.js +73 -1
- package/background/src/lib/virtualized/project/createEntitiesAndSortFiles.js.map +1 -1
- package/background/src/lib/virtualized/project/loadReadyToBeCaptured.js +19 -8
- package/background/src/lib/virtualized/project/loadReadyToBeCaptured.js.map +1 -1
- package/background/src/lib/virtualized/project/orchestrateCapture/AwsCaptureTaskRunner.js +2 -2
- package/background/src/lib/virtualized/project/orchestrateCapture/AwsCaptureTaskRunner.js.map +1 -1
- package/background/src/lib/virtualized/project/orchestrateCapture/SequentialCaptureTaskRunner.js +7 -5
- package/background/src/lib/virtualized/project/orchestrateCapture/SequentialCaptureTaskRunner.js.map +1 -1
- package/background/src/lib/virtualized/project/orchestrateCapture.js +58 -6
- package/background/src/lib/virtualized/project/orchestrateCapture.js.map +1 -1
- package/background/src/lib/virtualized/project/reconcileMockDataKeys.js +126 -9
- package/background/src/lib/virtualized/project/reconcileMockDataKeys.js.map +1 -1
- package/background/src/lib/virtualized/project/runAnalysis.js +3 -0
- package/background/src/lib/virtualized/project/runAnalysis.js.map +1 -1
- package/background/src/lib/virtualized/project/start.js +32 -11
- package/background/src/lib/virtualized/project/start.js.map +1 -1
- package/background/src/lib/virtualized/project/writeMockDataTsx.js +101 -4
- package/background/src/lib/virtualized/project/writeMockDataTsx.js.map +1 -1
- package/background/src/lib/virtualized/project/writeScenarioComponents.js +57 -8
- package/background/src/lib/virtualized/project/writeScenarioComponents.js.map +1 -1
- package/codeyam-cli/src/cli.js +2 -0
- package/codeyam-cli/src/cli.js.map +1 -1
- package/codeyam-cli/src/commands/debug.js +7 -5
- package/codeyam-cli/src/commands/debug.js.map +1 -1
- package/codeyam-cli/src/commands/memory.js +273 -0
- package/codeyam-cli/src/commands/memory.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/setupClaudeCodeSettings.test.js +4 -0
- package/codeyam-cli/src/utils/__tests__/setupClaudeCodeSettings.test.js.map +1 -1
- package/codeyam-cli/src/utils/analysisRunner.js +21 -2
- package/codeyam-cli/src/utils/analysisRunner.js.map +1 -1
- package/codeyam-cli/src/utils/install-skills.js +42 -6
- package/codeyam-cli/src/utils/install-skills.js.map +1 -1
- package/codeyam-cli/src/utils/queue/job.js +1 -0
- package/codeyam-cli/src/utils/queue/job.js.map +1 -1
- package/codeyam-cli/src/utils/queue/manager.js +6 -0
- package/codeyam-cli/src/utils/queue/manager.js.map +1 -1
- package/codeyam-cli/src/utils/rules/index.js +5 -0
- package/codeyam-cli/src/utils/rules/index.js.map +1 -0
- package/codeyam-cli/src/utils/rules/parser.js +106 -0
- package/codeyam-cli/src/utils/rules/parser.js.map +1 -0
- package/codeyam-cli/src/utils/rules/pathMatcher.js +18 -0
- package/codeyam-cli/src/utils/rules/pathMatcher.js.map +1 -0
- package/codeyam-cli/src/utils/rules/staleness.js +132 -0
- package/codeyam-cli/src/utils/rules/staleness.js.map +1 -0
- package/codeyam-cli/src/utils/setupClaudeCodeSettings.js +2 -0
- package/codeyam-cli/src/utils/setupClaudeCodeSettings.js.map +1 -1
- package/codeyam-cli/src/webserver/app/lib/database.js +7 -3
- package/codeyam-cli/src/webserver/app/lib/database.js.map +1 -1
- package/codeyam-cli/src/webserver/bootstrap.js +40 -0
- package/codeyam-cli/src/webserver/bootstrap.js.map +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/EntityItem-DsN1wKrm.js +11 -0
- package/codeyam-cli/src/webserver/build/client/assets/{EntityTypeBadge-COi5OvsN.js → EntityTypeBadge-DLqD3qNt.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{EntityTypeIcon-BwdQv49w.js → EntityTypeIcon-Ba2JVPzP.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{InlineSpinner-CEleMv_j.js → InlineSpinner-C8lyxW9k.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{InteractivePreview-D68KarMg.js → InteractivePreview-aht4aafF.js} +2 -2
- package/codeyam-cli/src/webserver/build/client/assets/{LibraryFunctionPreview-L75Wvqgw.js → LibraryFunctionPreview-CVtiBnY5.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{LoadingDots-C53WM8qn.js → LoadingDots-B0GLXMsr.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{LogViewer-CrNkmy4i.js → LogViewer-xgeCVgSM.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/ReportIssueModal-OApQuNyq.js +16 -0
- package/codeyam-cli/src/webserver/build/client/assets/{SafeScreenshot-CQifa1n-.js → SafeScreenshot-DuDvi0jm.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{ScenarioViewer-CyaBFX7l.js → ScenarioViewer-DzccYyI8.js} +3 -13
- package/codeyam-cli/src/webserver/build/client/assets/{TruncatedFilePath-D36O1rzU.js → TruncatedFilePath-DyFZkK0l.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/_index-BwqWJOgH.js +11 -0
- package/codeyam-cli/src/webserver/build/client/assets/activity.(_tab)-BwavGCpm.js +32 -0
- package/codeyam-cli/src/webserver/build/client/assets/api.health-l0sNRNKZ.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/api.memory-profile-l0sNRNKZ.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/api.restart-server-l0sNRNKZ.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/{chevron-down-DgTPh8H-.js → chevron-down-Cx24_aWc.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{chunk-EPOLDU6W-DdQKK6on.js → chunk-EPOLDU6W-CXRTFQ3F.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{circle-check-Dmr2bb1R.js → circle-check-BOARzkeR.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/copy-Bb-80kDT.js +6 -0
- package/codeyam-cli/src/webserver/build/client/assets/{createLucideIcon-Do4ZLUYa.js → createLucideIcon-BdhJEx6B.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/dev.empty-BBnGWYga.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/{entity._sha._-CbdFyxZh.js → entity._sha._-BJUiQqZF.js} +12 -12
- package/codeyam-cli/src/webserver/build/client/assets/{entity._sha.scenarios._scenarioId.fullscreen-B4iCfs5M.js → entity._sha.scenarios._scenarioId.fullscreen-DavjRmOY.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{entity._sha_.create-scenario-wDWZZO1W.js → entity._sha_.create-scenario-D1T4TGjf.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{entity._sha_.edit._scenarioId-BMbl7MeQ.js → entity._sha_.edit._scenarioId-CTBG2mmz.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{entry.client-5wRKRIH9.js → entry.client-CS2cb_eZ.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/file-code-Dhef1kWN.js +6 -0
- package/codeyam-cli/src/webserver/build/client/assets/{fileTableUtils-DD3SDH7t.js → fileTableUtils-DMJ7zii9.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/files-CJ6lTdTA.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/{git-zXjT7J0G.js → git-CPTZZ-JZ.js} +8 -8
- package/codeyam-cli/src/webserver/build/client/assets/globals-D3yhhV8x.css +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/{index-DLbXwndH.js → index-B1h680n5.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{index-gPZ-lad1.js → index-lzqtyFU8.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{loader-circle-BsPXJ81F.js → loader-circle-B7B9V-bu.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/manifest-a78b90a2.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/memory--GCbFsBE.js +92 -0
- package/codeyam-cli/src/webserver/build/client/assets/root-eVAaavTS.js +62 -0
- package/codeyam-cli/src/webserver/build/client/assets/{search-P2FKIUql.js → search-CxXUmBSd.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{settings-B2eDuBj8.js → settings-CS5f3WzT.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{simulations-L18M6-kN.js → simulations-DwFIBT09.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{triangle-alert-BDz7kbVA.js → triangle-alert-B6LgvRJg.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{useCustomSizes-29dDmbH8.js → useCustomSizes-C1v1PQzo.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{useLastLogLine-BUm0UVJm.js → useLastLogLine-aSv48UbS.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{useReportContext-CkIOKTrZ.js → useReportContext-DYxHZQuP.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{useToast-KKw5kTn-.js → useToast-mBRpZPiu.js} +1 -1
- package/codeyam-cli/src/webserver/build/server/assets/index-BM6TDT1Y.js +1 -0
- package/codeyam-cli/src/webserver/build/server/assets/server-build-dYC34MHw.js +257 -0
- package/codeyam-cli/src/webserver/build/server/index.js +1 -1
- package/codeyam-cli/src/webserver/build-info.json +5 -5
- package/codeyam-cli/templates/codeyam-memory-hook.sh +200 -0
- package/codeyam-cli/templates/codeyam:debug.md +47 -3
- package/codeyam-cli/templates/codeyam:diagnose.md +203 -25
- package/codeyam-cli/templates/codeyam:memory.md +341 -0
- package/codeyam-cli/templates/codeyam:new-rule.md +13 -0
- package/codeyam-cli/templates/rule-reflection-hook.py +160 -0
- package/codeyam-cli/templates/rules-instructions.md +93 -0
- package/package.json +8 -5
- package/packages/ai/index.js +7 -3
- package/packages/ai/index.js.map +1 -1
- package/packages/ai/src/lib/analyzeScope.js +70 -29
- package/packages/ai/src/lib/analyzeScope.js.map +1 -1
- package/packages/ai/src/lib/astScopes/arrayDerivationDetector.js +150 -0
- package/packages/ai/src/lib/astScopes/arrayDerivationDetector.js.map +1 -0
- package/packages/ai/src/lib/astScopes/astScopeAnalyzer.js +78 -8
- package/packages/ai/src/lib/astScopes/astScopeAnalyzer.js.map +1 -1
- package/packages/ai/src/lib/astScopes/methodSemantics.js +109 -23
- package/packages/ai/src/lib/astScopes/methodSemantics.js.map +1 -1
- package/packages/ai/src/lib/astScopes/patterns/variableDeclarationHandler.js +1 -102
- package/packages/ai/src/lib/astScopes/patterns/variableDeclarationHandler.js.map +1 -1
- package/packages/ai/src/lib/astScopes/processExpression.js +440 -27
- package/packages/ai/src/lib/astScopes/processExpression.js.map +1 -1
- package/packages/ai/src/lib/completionCall.js +161 -30
- package/packages/ai/src/lib/completionCall.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/ScopeDataStructure.js +589 -166
- package/packages/ai/src/lib/dataStructure/ScopeDataStructure.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/MuiManager.js +179 -0
- package/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/MuiManager.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/ReactFrameworkManager.js +7 -1
- package/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/ReactFrameworkManager.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/helpers/BatchSchemaProcessor.js +13 -3
- package/packages/ai/src/lib/dataStructure/helpers/BatchSchemaProcessor.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/helpers/ScopeTreeManager.js +6 -4
- package/packages/ai/src/lib/dataStructure/helpers/ScopeTreeManager.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/helpers/cleanKnownObjectFunctions.js +41 -1
- package/packages/ai/src/lib/dataStructure/helpers/cleanKnownObjectFunctions.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/helpers/cleanNonObjectFunctions.js +104 -11
- package/packages/ai/src/lib/dataStructure/helpers/cleanNonObjectFunctions.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/helpers/convertTypeAnnotationsToValues.js +159 -0
- package/packages/ai/src/lib/dataStructure/helpers/convertTypeAnnotationsToValues.js.map +1 -0
- package/packages/ai/src/lib/dataStructure/helpers/deduplicateFunctionSchemas.js +37 -20
- package/packages/ai/src/lib/dataStructure/helpers/deduplicateFunctionSchemas.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/helpers/fillInSchemaGapsAndUnknowns.js +265 -79
- package/packages/ai/src/lib/dataStructure/helpers/fillInSchemaGapsAndUnknowns.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/helpers/fixNullIdsBySchema.js +107 -0
- package/packages/ai/src/lib/dataStructure/helpers/fixNullIdsBySchema.js.map +1 -0
- package/packages/ai/src/lib/dataStructureChunking.js +111 -0
- package/packages/ai/src/lib/dataStructureChunking.js.map +1 -0
- package/packages/ai/src/lib/e2eDataTracking.js +241 -0
- package/packages/ai/src/lib/e2eDataTracking.js.map +1 -0
- package/packages/ai/src/lib/extractCriticalDataKeys.js +96 -0
- package/packages/ai/src/lib/extractCriticalDataKeys.js.map +1 -0
- package/packages/ai/src/lib/generateEntityScenarioData.js +525 -8
- package/packages/ai/src/lib/generateEntityScenarioData.js.map +1 -1
- package/packages/ai/src/lib/generateEntityScenarios.js +26 -2
- package/packages/ai/src/lib/generateEntityScenarios.js.map +1 -1
- package/packages/ai/src/lib/generateExecutionFlows.js +281 -4
- package/packages/ai/src/lib/generateExecutionFlows.js.map +1 -1
- package/packages/ai/src/lib/generateExecutionFlowsFromConditionals.js +946 -42
- package/packages/ai/src/lib/generateExecutionFlowsFromConditionals.js.map +1 -1
- package/packages/ai/src/lib/generateExecutionFlowsFromJsxUsages.js +194 -0
- package/packages/ai/src/lib/generateExecutionFlowsFromJsxUsages.js.map +1 -0
- package/packages/ai/src/lib/mergeStatements.js +70 -51
- package/packages/ai/src/lib/mergeStatements.js.map +1 -1
- package/packages/ai/src/lib/promptGenerators/gatherAttributesMap.js +10 -4
- package/packages/ai/src/lib/promptGenerators/gatherAttributesMap.js.map +1 -1
- package/packages/ai/src/lib/promptGenerators/generateChunkPrompt.js +54 -0
- package/packages/ai/src/lib/promptGenerators/generateChunkPrompt.js.map +1 -0
- package/packages/ai/src/lib/promptGenerators/generateEntityScenarioDataGenerator.js +15 -7
- package/packages/ai/src/lib/promptGenerators/generateEntityScenarioDataGenerator.js.map +1 -1
- package/packages/ai/src/lib/promptGenerators/simplifyKeysForLLM.js +335 -0
- package/packages/ai/src/lib/promptGenerators/simplifyKeysForLLM.js.map +1 -0
- package/packages/ai/src/lib/resolvePathToControllable.js +155 -41
- package/packages/ai/src/lib/resolvePathToControllable.js.map +1 -1
- package/packages/ai/src/lib/worker/SerializableDataStructure.js +7 -0
- package/packages/ai/src/lib/worker/SerializableDataStructure.js.map +1 -1
- package/packages/ai/src/lib/worker/analyzeScopeWorker.js +94 -1
- package/packages/ai/src/lib/worker/analyzeScopeWorker.js.map +1 -1
- package/packages/analyze/src/lib/FileAnalyzer.js +60 -36
- package/packages/analyze/src/lib/FileAnalyzer.js.map +1 -1
- package/packages/analyze/src/lib/ProjectAnalyzer.js +96 -26
- package/packages/analyze/src/lib/ProjectAnalyzer.js.map +1 -1
- package/packages/analyze/src/lib/analysisContext.js +30 -5
- package/packages/analyze/src/lib/analysisContext.js.map +1 -1
- package/packages/analyze/src/lib/asts/sourceFiles/getAllDeclaredEntityNodes.js +14 -0
- package/packages/analyze/src/lib/asts/sourceFiles/getAllDeclaredEntityNodes.js.map +1 -1
- package/packages/analyze/src/lib/asts/sourceFiles/getAllEntityNodes.js +14 -0
- package/packages/analyze/src/lib/asts/sourceFiles/getAllEntityNodes.js.map +1 -1
- package/packages/analyze/src/lib/asts/sourceFiles/getAllExports.js +6 -0
- package/packages/analyze/src/lib/asts/sourceFiles/getAllExports.js.map +1 -1
- package/packages/analyze/src/lib/asts/sourceFiles/getImportsAnalysis.js +6 -0
- package/packages/analyze/src/lib/asts/sourceFiles/getImportsAnalysis.js.map +1 -1
- package/packages/analyze/src/lib/asts/sourceFiles/getResolvedModule.js +39 -1
- package/packages/analyze/src/lib/asts/sourceFiles/getResolvedModule.js.map +1 -1
- package/packages/analyze/src/lib/asts/sourceFiles/getSourceFilesForAllImports.js +2 -1
- package/packages/analyze/src/lib/asts/sourceFiles/getSourceFilesForAllImports.js.map +1 -1
- package/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.js +21 -9
- package/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.js.map +1 -1
- package/packages/analyze/src/lib/files/analyze/analyzeEntities.js +14 -4
- package/packages/analyze/src/lib/files/analyze/analyzeEntities.js.map +1 -1
- package/packages/analyze/src/lib/files/analyze/dependencyResolver.js +5 -0
- package/packages/analyze/src/lib/files/analyze/dependencyResolver.js.map +1 -1
- package/packages/analyze/src/lib/files/analyze/gatherEntityMap.js +2 -1
- package/packages/analyze/src/lib/files/analyze/gatherEntityMap.js.map +1 -1
- package/packages/analyze/src/lib/files/analyze/validateDependencyAnalyses.js +31 -10
- package/packages/analyze/src/lib/files/analyze/validateDependencyAnalyses.js.map +1 -1
- package/packages/analyze/src/lib/files/analyzeRemixRoute.js +3 -2
- package/packages/analyze/src/lib/files/analyzeRemixRoute.js.map +1 -1
- package/packages/analyze/src/lib/files/getImportedExports.js +11 -7
- package/packages/analyze/src/lib/files/getImportedExports.js.map +1 -1
- package/packages/analyze/src/lib/files/scenarios/enrichArrayTypesFromChildSignatures.js +160 -68
- package/packages/analyze/src/lib/files/scenarios/enrichArrayTypesFromChildSignatures.js.map +1 -1
- package/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.js +25 -8
- package/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.js.map +1 -1
- package/packages/analyze/src/lib/files/scenarios/generateDataStructure.js +71 -9
- package/packages/analyze/src/lib/files/scenarios/generateDataStructure.js.map +1 -1
- package/packages/analyze/src/lib/files/scenarios/generateExecutionFlows.js +57 -9
- package/packages/analyze/src/lib/files/scenarios/generateExecutionFlows.js.map +1 -1
- package/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.js +233 -9
- package/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.js.map +1 -1
- package/packages/analyze/src/lib/files/scenarios/mergeValidatedDataStructures.js +46 -9
- package/packages/analyze/src/lib/files/scenarios/mergeValidatedDataStructures.js.map +1 -1
- package/packages/analyze/src/lib/files/setImportedExports.js +2 -1
- package/packages/analyze/src/lib/files/setImportedExports.js.map +1 -1
- package/packages/analyze/src/lib/utils/getFileByPath.js +12 -0
- package/packages/analyze/src/lib/utils/getFileByPath.js.map +1 -0
- package/packages/database/src/lib/kysely/db.js +8 -1
- package/packages/database/src/lib/kysely/db.js.map +1 -1
- package/packages/database/src/lib/kysely/tables/commitsTable.js +3 -0
- package/packages/database/src/lib/kysely/tables/commitsTable.js.map +1 -1
- package/packages/database/src/lib/loadAnalyses.js +45 -2
- package/packages/database/src/lib/loadAnalyses.js.map +1 -1
- package/packages/database/src/lib/loadAnalysis.js +8 -0
- package/packages/database/src/lib/loadAnalysis.js.map +1 -1
- package/packages/database/src/lib/loadBranch.js +11 -1
- package/packages/database/src/lib/loadBranch.js.map +1 -1
- package/packages/database/src/lib/loadCommit.js +7 -0
- package/packages/database/src/lib/loadCommit.js.map +1 -1
- package/packages/database/src/lib/loadCommits.js +22 -1
- package/packages/database/src/lib/loadCommits.js.map +1 -1
- package/packages/database/src/lib/loadEntities.js +23 -4
- package/packages/database/src/lib/loadEntities.js.map +1 -1
- package/packages/database/src/lib/loadEntityBranches.js +9 -0
- package/packages/database/src/lib/loadEntityBranches.js.map +1 -1
- package/packages/database/src/lib/updateCommitMetadata.js +5 -4
- package/packages/database/src/lib/updateCommitMetadata.js.map +1 -1
- package/packages/types/index.js.map +1 -1
- package/packages/utils/src/lib/safeFileName.js +29 -3
- package/packages/utils/src/lib/safeFileName.js.map +1 -1
- package/scripts/finalize-analyzer.cjs +3 -3
- package/codeyam-cli/src/webserver/build/client/assets/EntityItem-vauWK972.js +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/ReportIssueModal-DzJRkCkr.js +0 -11
- package/codeyam-cli/src/webserver/build/client/assets/_index-Be83mo_j.js +0 -11
- package/codeyam-cli/src/webserver/build/client/assets/activity.(_tab)-BN6wu6Y-.js +0 -37
- package/codeyam-cli/src/webserver/build/client/assets/dev.empty-Bn6aCAy_.js +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/files-DKyMFI90.js +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/globals-DTTQ3gY7.css +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/manifest-22590fcf.js +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/root-BsAarjAM.js +0 -57
- package/codeyam-cli/src/webserver/build/server/assets/index-BND5I5fv.js +0 -1
- package/codeyam-cli/src/webserver/build/server/assets/server-build-CFXnd7MG.js +0 -228
|
@@ -82,6 +82,8 @@
|
|
|
82
82
|
import { ScopeAnalysis } from '~codeyam/types';
|
|
83
83
|
import { EquivalencyManager } from './equivalencyManagers/EquivalencyManager';
|
|
84
84
|
import fillInSchemaGapsAndUnknowns from './helpers/fillInSchemaGapsAndUnknowns';
|
|
85
|
+
import { clearCleanKnownObjectFunctionsCache } from './helpers/cleanKnownObjectFunctions';
|
|
86
|
+
import { clearCleanNonObjectFunctionsCache } from './helpers/cleanNonObjectFunctions';
|
|
85
87
|
|
|
86
88
|
/**
|
|
87
89
|
* Patterns that indicate recursive type structures in schema paths.
|
|
@@ -150,7 +152,7 @@ export interface ScopeInfo {
|
|
|
150
152
|
[childComponentName: string]: Array<{
|
|
151
153
|
path: string;
|
|
152
154
|
conditionType: 'truthiness' | 'comparison';
|
|
153
|
-
location: 'if' | 'ternary' | 'logical-and' | 'switch';
|
|
155
|
+
location: 'if' | 'ternary' | 'logical-and' | 'switch' | 'unconditional';
|
|
154
156
|
isNegated?: boolean;
|
|
155
157
|
}>;
|
|
156
158
|
};
|
|
@@ -332,6 +334,19 @@ export function resetScopeDataStructureMetrics() {
|
|
|
332
334
|
followEquivalenciesEarlyExitPhase1Count = 0;
|
|
333
335
|
followEquivalenciesWithWorkCount = 0;
|
|
334
336
|
addEquivalencyCallCount = 0;
|
|
337
|
+
|
|
338
|
+
// Clear module-level caches to prevent unbounded memory growth across entities
|
|
339
|
+
const knownObjectCache = clearCleanKnownObjectFunctionsCache();
|
|
340
|
+
const nonObjectCache = clearCleanNonObjectFunctionsCache();
|
|
341
|
+
if (knownObjectCache.count > 0 || nonObjectCache.count > 0) {
|
|
342
|
+
const totalBytes =
|
|
343
|
+
knownObjectCache.estimatedBytes + nonObjectCache.estimatedBytes;
|
|
344
|
+
console.log('CodeYam: Cleared analysis caches', {
|
|
345
|
+
knownObjectCache: `${knownObjectCache.count} entries, ${(knownObjectCache.estimatedBytes / 1024).toFixed(1)}KB`,
|
|
346
|
+
nonObjectCache: `${nonObjectCache.count} entries, ${(nonObjectCache.estimatedBytes / 1024).toFixed(1)}KB`,
|
|
347
|
+
totalKB: `${(totalBytes / 1024).toFixed(1)}KB`,
|
|
348
|
+
});
|
|
349
|
+
}
|
|
335
350
|
}
|
|
336
351
|
|
|
337
352
|
// Performance: Pre-computed Sets for equivalency reason filtering (O(1) vs O(n))
|
|
@@ -409,7 +424,7 @@ export class ScopeDataStructure {
|
|
|
409
424
|
path: string;
|
|
410
425
|
conditionType: 'truthiness' | 'comparison' | 'switch';
|
|
411
426
|
comparedValues?: string[];
|
|
412
|
-
location: 'if' | 'ternary' | 'logical-and' | 'switch';
|
|
427
|
+
location: 'if' | 'ternary' | 'logical-and' | 'switch' | 'unconditional';
|
|
413
428
|
}>
|
|
414
429
|
> = {};
|
|
415
430
|
|
|
@@ -436,6 +451,13 @@ export class ScopeDataStructure {
|
|
|
436
451
|
import('../astScopes/types').ConditionalUsage[]
|
|
437
452
|
> = {};
|
|
438
453
|
|
|
454
|
+
/**
|
|
455
|
+
* JSX rendering usages collected during AST analysis.
|
|
456
|
+
* Tracks arrays rendered via .map() and strings interpolated in JSX.
|
|
457
|
+
*/
|
|
458
|
+
private rawJsxRenderingUsages: import('../astScopes/types').JsxRenderingUsage[] =
|
|
459
|
+
[];
|
|
460
|
+
|
|
439
461
|
private lastAddToSchemaId = 0;
|
|
440
462
|
private lastEquivalencyId = 0;
|
|
441
463
|
private lastEquivalencyDatabaseId = 0;
|
|
@@ -1628,17 +1650,26 @@ export class ScopeDataStructure {
|
|
|
1628
1650
|
private setInstantiatedVariables(scopeNode: ScopeNode) {
|
|
1629
1651
|
let instantiatedVariables = scopeNode.analysis?.instantiatedVariables ?? [];
|
|
1630
1652
|
|
|
1631
|
-
for (const [path,
|
|
1653
|
+
for (const [path, rawEquivalentPath] of Object.entries(
|
|
1632
1654
|
scopeNode.analysis.isolatedEquivalentVariables ?? {},
|
|
1633
1655
|
)) {
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1656
|
+
// Normalize to array for consistent handling (supports both string and string[])
|
|
1657
|
+
const equivalentPaths = Array.isArray(rawEquivalentPath)
|
|
1658
|
+
? rawEquivalentPath
|
|
1659
|
+
: rawEquivalentPath
|
|
1660
|
+
? [rawEquivalentPath]
|
|
1661
|
+
: [];
|
|
1662
|
+
|
|
1663
|
+
for (const equivalentPath of equivalentPaths) {
|
|
1664
|
+
if (typeof equivalentPath !== 'string') {
|
|
1665
|
+
continue;
|
|
1666
|
+
}
|
|
1637
1667
|
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1668
|
+
if (equivalentPath.startsWith('signature[')) {
|
|
1669
|
+
const equivalentPathParts = this.splitPath(equivalentPath);
|
|
1670
|
+
instantiatedVariables.push(equivalentPathParts[0]);
|
|
1671
|
+
instantiatedVariables.push(path);
|
|
1672
|
+
}
|
|
1642
1673
|
}
|
|
1643
1674
|
|
|
1644
1675
|
const duplicateInstantiated = instantiatedVariables.find(
|
|
@@ -1651,9 +1682,14 @@ export class ScopeDataStructure {
|
|
|
1651
1682
|
}
|
|
1652
1683
|
}
|
|
1653
1684
|
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1685
|
+
const instantiatedSeen = new Set<string>();
|
|
1686
|
+
instantiatedVariables = instantiatedVariables.filter((varName) => {
|
|
1687
|
+
if (instantiatedSeen.has(varName)) {
|
|
1688
|
+
return false;
|
|
1689
|
+
}
|
|
1690
|
+
instantiatedSeen.add(varName);
|
|
1691
|
+
return true;
|
|
1692
|
+
});
|
|
1657
1693
|
|
|
1658
1694
|
scopeNode.instantiatedVariables = instantiatedVariables;
|
|
1659
1695
|
|
|
@@ -1674,13 +1710,19 @@ export class ScopeDataStructure {
|
|
|
1674
1710
|
...parentScopeNode.instantiatedVariables.filter(
|
|
1675
1711
|
(v) => !v.startsWith('signature[') && !v.startsWith('returnValue'),
|
|
1676
1712
|
),
|
|
1677
|
-
].filter(
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1713
|
+
].filter((varName) => !instantiatedSeen.has(varName));
|
|
1714
|
+
|
|
1715
|
+
const parentInstantiatedSeen = new Set<string>();
|
|
1716
|
+
const dedupedParentInstantiatedVariables =
|
|
1717
|
+
parentInstantiatedVariables.filter((varName) => {
|
|
1718
|
+
if (parentInstantiatedSeen.has(varName)) {
|
|
1719
|
+
return false;
|
|
1720
|
+
}
|
|
1721
|
+
parentInstantiatedSeen.add(varName);
|
|
1722
|
+
return true;
|
|
1723
|
+
});
|
|
1682
1724
|
|
|
1683
|
-
scopeNode.parentInstantiatedVariables =
|
|
1725
|
+
scopeNode.parentInstantiatedVariables = dedupedParentInstantiatedVariables;
|
|
1684
1726
|
}
|
|
1685
1727
|
|
|
1686
1728
|
private trackFunctionCalls(scopeNode: ScopeNode) {
|
|
@@ -1696,172 +1738,198 @@ export class ScopeDataStructure {
|
|
|
1696
1738
|
const { isolatedStructure, isolatedEquivalentVariables } =
|
|
1697
1739
|
scopeNode.analysis;
|
|
1698
1740
|
|
|
1741
|
+
// Flatten isolatedEquivalentVariables values for allPaths (handles both string and string[])
|
|
1742
|
+
const flattenedEquivValues = Object.values(
|
|
1743
|
+
isolatedEquivalentVariables || {},
|
|
1744
|
+
).flatMap((v) => (Array.isArray(v) ? v : [v]));
|
|
1745
|
+
|
|
1699
1746
|
const allPaths = Array.from(
|
|
1700
1747
|
new Set([
|
|
1701
1748
|
...Object.keys(isolatedStructure || {}),
|
|
1702
1749
|
...Object.keys(isolatedEquivalentVariables || {}),
|
|
1703
|
-
...
|
|
1750
|
+
...flattenedEquivValues,
|
|
1704
1751
|
]),
|
|
1705
1752
|
);
|
|
1706
1753
|
|
|
1707
1754
|
for (let path in isolatedEquivalentVariables) {
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1755
|
+
const rawEquivalentValue = isolatedEquivalentVariables?.[path];
|
|
1756
|
+
// Normalize to array for consistent handling
|
|
1757
|
+
const equivalentValues = Array.isArray(rawEquivalentValue)
|
|
1758
|
+
? rawEquivalentValue
|
|
1759
|
+
: [rawEquivalentValue];
|
|
1760
|
+
|
|
1761
|
+
for (let equivalentValue of equivalentValues) {
|
|
1762
|
+
if (equivalentValue && this.isValidPath(equivalentValue)) {
|
|
1763
|
+
// IMPORTANT: DO NOT strip ::cyDuplicateKey:: markers from equivalencies.
|
|
1764
|
+
// These markers are critical for distinguishing variable reassignments.
|
|
1765
|
+
// For example, with:
|
|
1766
|
+
// let fetcher = useFetcher<ConfigData>();
|
|
1767
|
+
// const configData = fetcher.data?.data;
|
|
1768
|
+
// fetcher = useFetcher<SettingsData>();
|
|
1769
|
+
// const settingsData = fetcher.data?.data;
|
|
1770
|
+
//
|
|
1771
|
+
// mergeStatements creates:
|
|
1772
|
+
// fetcher → useFetcher<ConfigData>()...
|
|
1773
|
+
// fetcher::cyDuplicateKey1:: → useFetcher<SettingsData>()...
|
|
1774
|
+
// configData → fetcher.data.data
|
|
1775
|
+
// settingsData → fetcher::cyDuplicateKey1::.data.data
|
|
1776
|
+
//
|
|
1777
|
+
// If we strip ::cyDuplicateKey::, settingsData would incorrectly trace
|
|
1778
|
+
// to useFetcher<ConfigData>() instead of useFetcher<SettingsData>().
|
|
1779
|
+
path = cleanPath(path, allPaths);
|
|
1780
|
+
equivalentValue = cleanPath(equivalentValue, allPaths);
|
|
1781
|
+
|
|
1782
|
+
this.addEquivalency(
|
|
1783
|
+
path,
|
|
1784
|
+
equivalentValue,
|
|
1785
|
+
scopeNode.name,
|
|
1786
|
+
scopeNode,
|
|
1787
|
+
'original equivalency',
|
|
1788
|
+
);
|
|
1737
1789
|
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1790
|
+
// Propagate equivalencies involving parent-scope variables to those parent scopes.
|
|
1791
|
+
// This handles patterns like: collected.push({...entity}) where 'collected' is defined
|
|
1792
|
+
// in a parent scope. The equivalency collected[] -> push().signature[0] needs to be
|
|
1793
|
+
// visible when tracing from the parent scope.
|
|
1794
|
+
const rootVariable = this.extractRootVariable(path);
|
|
1795
|
+
const equivalentRootVariable =
|
|
1796
|
+
this.extractRootVariable(equivalentValue);
|
|
1797
|
+
|
|
1798
|
+
// Skip propagation for self-referential reassignment patterns like:
|
|
1799
|
+
// x = x.method().functionCallReturnValue
|
|
1800
|
+
// where the path IS the variable itself (not a sub-path like x[] or x.prop).
|
|
1801
|
+
// These create circular references since both sides reference the same variable.
|
|
1802
|
+
//
|
|
1803
|
+
// But DO propagate for patterns like collected[] -> collected.push(...).signature[0]
|
|
1804
|
+
// where the path has additional segments beyond the root variable.
|
|
1805
|
+
const pathIsJustRootVariable = path === rootVariable;
|
|
1806
|
+
const isSelfReferentialReassignment =
|
|
1807
|
+
pathIsJustRootVariable && rootVariable === equivalentRootVariable;
|
|
1756
1808
|
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1809
|
+
if (
|
|
1810
|
+
rootVariable &&
|
|
1811
|
+
!isSelfReferentialReassignment &&
|
|
1812
|
+
scopeNode.parentInstantiatedVariables?.includes(rootVariable)
|
|
1813
|
+
) {
|
|
1814
|
+
// Find the parent scope where this variable is defined
|
|
1815
|
+
for (const parentScopeName of scopeNode.tree || []) {
|
|
1816
|
+
const parentScope = this.scopeNodes[parentScopeName];
|
|
1817
|
+
if (parentScope?.instantiatedVariables?.includes(rootVariable)) {
|
|
1818
|
+
// Add the equivalency to the parent scope as well
|
|
1819
|
+
this.addEquivalency(
|
|
1820
|
+
path,
|
|
1821
|
+
equivalentValue,
|
|
1822
|
+
scopeNode.name, // The equivalent path's scope remains the child scope
|
|
1823
|
+
parentScope, // But store it in the parent scope's equivalencies
|
|
1824
|
+
'propagated parent-variable equivalency',
|
|
1825
|
+
);
|
|
1826
|
+
break;
|
|
1827
|
+
}
|
|
1775
1828
|
}
|
|
1776
1829
|
}
|
|
1777
|
-
}
|
|
1778
1830
|
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
const
|
|
1810
|
-
|
|
1811
|
-
|
|
1831
|
+
// Propagate sub-property equivalencies when the equivalentValue is a simple variable
|
|
1832
|
+
// that has sub-properties defined in the isolatedEquivalentVariables.
|
|
1833
|
+
// This handles cases like: dataItem={{ structure: completeDataStructure }}
|
|
1834
|
+
// where completeDataStructure has sub-properties like completeDataStructure['Function Arguments']
|
|
1835
|
+
// We need to propagate these to create: dataItem.structure['Function Arguments'] equivalencies
|
|
1836
|
+
const isSimpleVariable =
|
|
1837
|
+
!equivalentValue.startsWith('signature[') &&
|
|
1838
|
+
!equivalentValue.includes('functionCallReturnValue') &&
|
|
1839
|
+
!equivalentValue.includes('.') &&
|
|
1840
|
+
!equivalentValue.includes('[');
|
|
1841
|
+
|
|
1842
|
+
if (isSimpleVariable) {
|
|
1843
|
+
// Look in current scope and all parent scopes for sub-properties
|
|
1844
|
+
const scopesToCheck = [scopeNode.name, ...scopeNode.tree];
|
|
1845
|
+
for (const scopeName of scopesToCheck) {
|
|
1846
|
+
const checkScope = this.scopeNodes[scopeName];
|
|
1847
|
+
if (!checkScope?.analysis?.isolatedEquivalentVariables) continue;
|
|
1848
|
+
|
|
1849
|
+
for (const [subPath, rawSubValue] of Object.entries(
|
|
1850
|
+
checkScope.analysis.isolatedEquivalentVariables,
|
|
1851
|
+
)) {
|
|
1852
|
+
// Normalize to array for consistent handling
|
|
1853
|
+
const subValues = Array.isArray(rawSubValue)
|
|
1854
|
+
? rawSubValue
|
|
1855
|
+
: rawSubValue
|
|
1856
|
+
? [rawSubValue]
|
|
1857
|
+
: [];
|
|
1858
|
+
|
|
1859
|
+
// Check if this is a sub-property of the equivalentValue variable
|
|
1860
|
+
// e.g., completeDataStructure['Function Arguments'] or completeDataStructure.foo
|
|
1861
|
+
const matchesDot = subPath.startsWith(equivalentValue + '.');
|
|
1862
|
+
const matchesBracket = subPath.startsWith(
|
|
1863
|
+
equivalentValue + '[',
|
|
1812
1864
|
);
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
this.isValidPath(newEquivalentValue)
|
|
1817
|
-
) {
|
|
1818
|
-
this.addEquivalency(
|
|
1819
|
-
newPath,
|
|
1820
|
-
newEquivalentValue,
|
|
1821
|
-
checkScope.name, // Use the scope where the sub-property was found
|
|
1822
|
-
scopeNode,
|
|
1823
|
-
'propagated sub-property equivalency',
|
|
1865
|
+
if (matchesDot || matchesBracket) {
|
|
1866
|
+
const subPropertyPath = subPath.substring(
|
|
1867
|
+
equivalentValue.length,
|
|
1824
1868
|
);
|
|
1869
|
+
const newPath = cleanPath(path + subPropertyPath, allPaths);
|
|
1870
|
+
|
|
1871
|
+
for (const subValue of subValues) {
|
|
1872
|
+
if (typeof subValue !== 'string') continue;
|
|
1873
|
+
const newEquivalentValue = cleanPath(
|
|
1874
|
+
subValue.replace(/::cyDuplicateKey\d+::/g, ''),
|
|
1875
|
+
allPaths,
|
|
1876
|
+
);
|
|
1877
|
+
|
|
1878
|
+
if (
|
|
1879
|
+
newEquivalentValue &&
|
|
1880
|
+
this.isValidPath(newEquivalentValue)
|
|
1881
|
+
) {
|
|
1882
|
+
this.addEquivalency(
|
|
1883
|
+
newPath,
|
|
1884
|
+
newEquivalentValue,
|
|
1885
|
+
checkScope.name, // Use the scope where the sub-property was found
|
|
1886
|
+
scopeNode,
|
|
1887
|
+
'propagated sub-property equivalency',
|
|
1888
|
+
);
|
|
1889
|
+
}
|
|
1890
|
+
}
|
|
1825
1891
|
}
|
|
1826
|
-
}
|
|
1827
1892
|
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1893
|
+
// Also check if equivalentValue itself maps to a functionCallReturnValue
|
|
1894
|
+
// e.g., result = useMemo(...).functionCallReturnValue
|
|
1895
|
+
for (const subValue of subValues) {
|
|
1896
|
+
if (
|
|
1897
|
+
subPath === equivalentValue &&
|
|
1898
|
+
typeof subValue === 'string' &&
|
|
1899
|
+
subValue.endsWith('.functionCallReturnValue')
|
|
1900
|
+
) {
|
|
1901
|
+
this.propagateFunctionCallReturnSubProperties(
|
|
1902
|
+
path,
|
|
1903
|
+
subValue,
|
|
1904
|
+
scopeNode,
|
|
1905
|
+
allPaths,
|
|
1906
|
+
);
|
|
1907
|
+
}
|
|
1908
|
+
}
|
|
1841
1909
|
}
|
|
1842
1910
|
}
|
|
1843
1911
|
}
|
|
1844
|
-
}
|
|
1845
1912
|
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1913
|
+
// Handle function call return values by propagating returnValue.* sub-properties
|
|
1914
|
+
// from the callback scope to the usage path
|
|
1915
|
+
if (equivalentValue.endsWith('.functionCallReturnValue')) {
|
|
1916
|
+
this.propagateFunctionCallReturnSubProperties(
|
|
1917
|
+
path,
|
|
1918
|
+
equivalentValue,
|
|
1919
|
+
scopeNode,
|
|
1920
|
+
allPaths,
|
|
1921
|
+
);
|
|
1855
1922
|
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1923
|
+
// Track which variable receives the return value of each function call
|
|
1924
|
+
// This enables generating separate mock data for each call site
|
|
1925
|
+
this.trackReceivingVariable(path, equivalentValue);
|
|
1926
|
+
}
|
|
1860
1927
|
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1928
|
+
// Also track variables that receive destructured properties from function call return values
|
|
1929
|
+
// e.g., "userData" -> "db.query('users').functionCallReturnValue.data"
|
|
1930
|
+
if (equivalentValue.includes('.functionCallReturnValue.')) {
|
|
1931
|
+
this.trackReceivingVariable(path, equivalentValue);
|
|
1932
|
+
}
|
|
1865
1933
|
}
|
|
1866
1934
|
}
|
|
1867
1935
|
}
|
|
@@ -2042,9 +2110,18 @@ export class ScopeDataStructure {
|
|
|
2042
2110
|
const checkScope = this.scopeNodes[scopeName];
|
|
2043
2111
|
if (!checkScope?.analysis?.isolatedEquivalentVariables) continue;
|
|
2044
2112
|
|
|
2045
|
-
const
|
|
2113
|
+
const rawFunctionRef =
|
|
2046
2114
|
checkScope.analysis.isolatedEquivalentVariables[functionName];
|
|
2047
|
-
|
|
2115
|
+
// Normalize to array and find first string ending with 'F'
|
|
2116
|
+
const functionRefs = Array.isArray(rawFunctionRef)
|
|
2117
|
+
? rawFunctionRef
|
|
2118
|
+
: rawFunctionRef
|
|
2119
|
+
? [rawFunctionRef]
|
|
2120
|
+
: [];
|
|
2121
|
+
const functionRef = functionRefs.find(
|
|
2122
|
+
(r) => typeof r === 'string' && r.endsWith('F'),
|
|
2123
|
+
);
|
|
2124
|
+
if (typeof functionRef === 'string') {
|
|
2048
2125
|
callbackScopeName = functionRef.slice(0, -1);
|
|
2049
2126
|
break;
|
|
2050
2127
|
}
|
|
@@ -2072,19 +2149,24 @@ export class ScopeDataStructure {
|
|
|
2072
2149
|
|
|
2073
2150
|
const isolatedVars = callbackScope.analysis.isolatedEquivalentVariables;
|
|
2074
2151
|
|
|
2152
|
+
// Get the first returnValue equivalency (normalize array to single value for these checks)
|
|
2153
|
+
const rawReturnValue = isolatedVars.returnValue;
|
|
2154
|
+
const firstReturnValue = Array.isArray(rawReturnValue)
|
|
2155
|
+
? rawReturnValue[0]
|
|
2156
|
+
: rawReturnValue;
|
|
2157
|
+
|
|
2075
2158
|
// First, check if returnValue is an alias to another variable (e.g., returnValue = intermediate)
|
|
2076
2159
|
// If so, we need to look for that variable's sub-properties too
|
|
2077
2160
|
const returnValueAlias =
|
|
2078
|
-
typeof
|
|
2079
|
-
|
|
2080
|
-
? isolatedVars.returnValue
|
|
2161
|
+
typeof firstReturnValue === 'string' && !firstReturnValue.includes('.')
|
|
2162
|
+
? firstReturnValue
|
|
2081
2163
|
: undefined;
|
|
2082
2164
|
|
|
2083
2165
|
// Pattern 3: Object.keys(X).reduce() - the reduce result has the same sub-properties as X
|
|
2084
2166
|
// When returnValue = "Object.keys(source).reduce(...).functionCallReturnValue", look for source.* sub-properties
|
|
2085
2167
|
let reduceSourceVar: string | undefined;
|
|
2086
|
-
if (typeof
|
|
2087
|
-
const reduceMatch =
|
|
2168
|
+
if (typeof firstReturnValue === 'string') {
|
|
2169
|
+
const reduceMatch = firstReturnValue.match(
|
|
2088
2170
|
/^Object\.keys\((\w+)\)\.reduce\(.*\)\.functionCallReturnValue$/,
|
|
2089
2171
|
);
|
|
2090
2172
|
if (reduceMatch) {
|
|
@@ -2092,7 +2174,14 @@ export class ScopeDataStructure {
|
|
|
2092
2174
|
}
|
|
2093
2175
|
}
|
|
2094
2176
|
|
|
2095
|
-
for (const [subPath,
|
|
2177
|
+
for (const [subPath, rawSubValue] of Object.entries(isolatedVars)) {
|
|
2178
|
+
// Normalize to array for consistent handling
|
|
2179
|
+
const subValues = Array.isArray(rawSubValue)
|
|
2180
|
+
? rawSubValue
|
|
2181
|
+
: rawSubValue
|
|
2182
|
+
? [rawSubValue]
|
|
2183
|
+
: [];
|
|
2184
|
+
|
|
2096
2185
|
// Check for direct returnValue.* sub-properties
|
|
2097
2186
|
const isReturnValueSub =
|
|
2098
2187
|
subPath.startsWith('returnValue.') ||
|
|
@@ -2110,57 +2199,59 @@ export class ScopeDataStructure {
|
|
|
2110
2199
|
(subPath.startsWith(reduceSourceVar + '.') ||
|
|
2111
2200
|
subPath.startsWith(reduceSourceVar + '['));
|
|
2112
2201
|
|
|
2113
|
-
if (
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2202
|
+
if (!isReturnValueSub && !isAliasSub && !isReduceSourceSub) continue;
|
|
2203
|
+
|
|
2204
|
+
for (const subValue of subValues) {
|
|
2205
|
+
if (typeof subValue !== 'string') continue;
|
|
2206
|
+
|
|
2207
|
+
// Convert alias/reduceSource paths to returnValue paths
|
|
2208
|
+
let effectiveSubPath = subPath;
|
|
2209
|
+
if (isAliasSub && !isReturnValueSub) {
|
|
2210
|
+
// Replace the alias prefix with returnValue
|
|
2211
|
+
effectiveSubPath =
|
|
2212
|
+
'returnValue' + subPath.substring(returnValueAlias!.length);
|
|
2213
|
+
} else if (isReduceSourceSub && !isReturnValueSub && !isAliasSub) {
|
|
2214
|
+
// Replace the reduce source prefix with returnValue
|
|
2215
|
+
effectiveSubPath =
|
|
2216
|
+
'returnValue' + subPath.substring(reduceSourceVar!.length);
|
|
2217
|
+
}
|
|
2218
|
+
const subPropertyPath = effectiveSubPath.substring(
|
|
2219
|
+
'returnValue'.length,
|
|
2220
|
+
);
|
|
2221
|
+
const newPath = cleanPath(path + subPropertyPath, allPaths);
|
|
2222
|
+
let newEquivalentValue = cleanPath(
|
|
2223
|
+
subValue.replace(/::cyDuplicateKey\d+::/g, ''),
|
|
2224
|
+
allPaths,
|
|
2225
|
+
);
|
|
2136
2226
|
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2227
|
+
// Resolve variable references through parent scope equivalencies
|
|
2228
|
+
const resolved = this.resolveVariableThroughParentScopes(
|
|
2229
|
+
newEquivalentValue,
|
|
2230
|
+
callbackScope,
|
|
2231
|
+
allPaths,
|
|
2232
|
+
);
|
|
2233
|
+
newEquivalentValue = resolved.resolvedPath;
|
|
2234
|
+
const equivalentScopeName = resolved.scopeName;
|
|
2145
2235
|
|
|
2146
|
-
|
|
2147
|
-
|
|
2236
|
+
if (!newEquivalentValue || !this.isValidPath(newEquivalentValue))
|
|
2237
|
+
continue;
|
|
2148
2238
|
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2239
|
+
this.addEquivalency(
|
|
2240
|
+
newPath,
|
|
2241
|
+
newEquivalentValue,
|
|
2242
|
+
equivalentScopeName,
|
|
2243
|
+
scopeNode,
|
|
2244
|
+
'propagated function call return sub-property equivalency',
|
|
2245
|
+
);
|
|
2156
2246
|
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2247
|
+
// Ensure the database entry has the usage path
|
|
2248
|
+
this.addUsageToEquivalencyDatabaseEntry(
|
|
2249
|
+
newPath,
|
|
2250
|
+
newEquivalentValue,
|
|
2251
|
+
equivalentScopeName,
|
|
2252
|
+
scopeNode.name,
|
|
2253
|
+
);
|
|
2254
|
+
}
|
|
2164
2255
|
}
|
|
2165
2256
|
}
|
|
2166
2257
|
|
|
@@ -2200,8 +2291,15 @@ export class ScopeDataStructure {
|
|
|
2200
2291
|
const parentScope = this.scopeNodes[parentScopeName];
|
|
2201
2292
|
if (!parentScope?.analysis?.isolatedEquivalentVariables) continue;
|
|
2202
2293
|
|
|
2203
|
-
const
|
|
2294
|
+
const rawRootEquiv =
|
|
2204
2295
|
parentScope.analysis.isolatedEquivalentVariables[rootVar];
|
|
2296
|
+
// Normalize to array and use first string value
|
|
2297
|
+
const rootEquivs = Array.isArray(rawRootEquiv)
|
|
2298
|
+
? rawRootEquiv
|
|
2299
|
+
: rawRootEquiv
|
|
2300
|
+
? [rawRootEquiv]
|
|
2301
|
+
: [];
|
|
2302
|
+
const rootEquiv = rootEquivs.find((r) => typeof r === 'string');
|
|
2205
2303
|
if (typeof rootEquiv === 'string') {
|
|
2206
2304
|
return {
|
|
2207
2305
|
resolvedPath: cleanPath(rootEquiv + restOfPath, allPaths),
|
|
@@ -2867,10 +2965,105 @@ export class ScopeDataStructure {
|
|
|
2867
2965
|
this.intermediatesOrderIndex.set(pathId, databaseEntry);
|
|
2868
2966
|
|
|
2869
2967
|
if (intermediateIndex === 0) {
|
|
2870
|
-
|
|
2968
|
+
let isValidSourceCandidate =
|
|
2871
2969
|
pathInfo.schemaPath.startsWith('signature[') ||
|
|
2872
2970
|
pathInfo.schemaPath.includes('functionCallReturnValue');
|
|
2873
|
-
|
|
2971
|
+
|
|
2972
|
+
// Check if path STARTS with a spread pattern like [...var]
|
|
2973
|
+
// This handles cases like [...files][][0] or [...files].sort(...).functionCallReturnValue[][0]
|
|
2974
|
+
// where the spread source variable needs to be resolved to a signature path.
|
|
2975
|
+
// We do this REGARDLESS of isValidSourceCandidate because even paths containing
|
|
2976
|
+
// functionCallReturnValue may need spread resolution to trace back to the signature.
|
|
2977
|
+
const spreadMatch = pathInfo.schemaPath.match(/^\[\.\.\.(\w+)\]/);
|
|
2978
|
+
if (spreadMatch) {
|
|
2979
|
+
const spreadVar = spreadMatch[1];
|
|
2980
|
+
const spreadPattern = spreadMatch[0]; // The full [...var] match
|
|
2981
|
+
const scopeNode = this.scopeNodes[pathInfo.scopeNodeName];
|
|
2982
|
+
|
|
2983
|
+
if (scopeNode?.equivalencies) {
|
|
2984
|
+
// Follow the equivalency chain to find a signature path
|
|
2985
|
+
// e.g., files (cyScope1) → files (root) → signature[0].files
|
|
2986
|
+
const resolveToSignature = (
|
|
2987
|
+
varName: string,
|
|
2988
|
+
currentScopeName: string,
|
|
2989
|
+
visited: Set<string>,
|
|
2990
|
+
): { schemaPath: string; scopeNodeName: string } | null => {
|
|
2991
|
+
const visitKey = `${currentScopeName}::${varName}`;
|
|
2992
|
+
if (visited.has(visitKey)) return null;
|
|
2993
|
+
visited.add(visitKey);
|
|
2994
|
+
|
|
2995
|
+
const currentScope = this.scopeNodes[currentScopeName];
|
|
2996
|
+
if (!currentScope?.equivalencies) return null;
|
|
2997
|
+
|
|
2998
|
+
const varEquivs = currentScope.equivalencies[varName];
|
|
2999
|
+
if (!varEquivs) return null;
|
|
3000
|
+
|
|
3001
|
+
// First check if any equivalency directly points to a signature path
|
|
3002
|
+
const signatureEquiv = varEquivs.find((eq) =>
|
|
3003
|
+
eq.schemaPath.startsWith('signature['),
|
|
3004
|
+
);
|
|
3005
|
+
if (signatureEquiv) {
|
|
3006
|
+
return signatureEquiv;
|
|
3007
|
+
}
|
|
3008
|
+
|
|
3009
|
+
// Otherwise, follow the chain to other scopes
|
|
3010
|
+
for (const equiv of varEquivs) {
|
|
3011
|
+
// If the equivalency points to the same variable in a different scope,
|
|
3012
|
+
// follow the chain
|
|
3013
|
+
if (
|
|
3014
|
+
equiv.schemaPath === varName &&
|
|
3015
|
+
equiv.scopeNodeName !== currentScopeName
|
|
3016
|
+
) {
|
|
3017
|
+
const result = resolveToSignature(
|
|
3018
|
+
varName,
|
|
3019
|
+
equiv.scopeNodeName,
|
|
3020
|
+
visited,
|
|
3021
|
+
);
|
|
3022
|
+
if (result) return result;
|
|
3023
|
+
}
|
|
3024
|
+
}
|
|
3025
|
+
|
|
3026
|
+
return null;
|
|
3027
|
+
};
|
|
3028
|
+
|
|
3029
|
+
const signatureEquiv = resolveToSignature(
|
|
3030
|
+
spreadVar,
|
|
3031
|
+
pathInfo.scopeNodeName,
|
|
3032
|
+
new Set(),
|
|
3033
|
+
);
|
|
3034
|
+
if (signatureEquiv) {
|
|
3035
|
+
// Replace ONLY the [...var] part with the resolved signature path
|
|
3036
|
+
// This preserves any suffix like .sort(...).functionCallReturnValue[][0]
|
|
3037
|
+
const resolvedPath = pathInfo.schemaPath.replace(
|
|
3038
|
+
spreadPattern,
|
|
3039
|
+
signatureEquiv.schemaPath,
|
|
3040
|
+
);
|
|
3041
|
+
// Add the resolved path as a source candidate
|
|
3042
|
+
if (
|
|
3043
|
+
!databaseEntry.sourceCandidates.some(
|
|
3044
|
+
(sc) =>
|
|
3045
|
+
sc.schemaPath === resolvedPath &&
|
|
3046
|
+
sc.scopeNodeName === pathInfo.scopeNodeName,
|
|
3047
|
+
)
|
|
3048
|
+
) {
|
|
3049
|
+
databaseEntry.sourceCandidates.push({
|
|
3050
|
+
scopeNodeName: pathInfo.scopeNodeName,
|
|
3051
|
+
schemaPath: resolvedPath,
|
|
3052
|
+
});
|
|
3053
|
+
}
|
|
3054
|
+
isValidSourceCandidate = true;
|
|
3055
|
+
}
|
|
3056
|
+
}
|
|
3057
|
+
}
|
|
3058
|
+
|
|
3059
|
+
if (
|
|
3060
|
+
isValidSourceCandidate &&
|
|
3061
|
+
!databaseEntry.sourceCandidates.some(
|
|
3062
|
+
(sc) =>
|
|
3063
|
+
sc.schemaPath === pathInfo.schemaPath &&
|
|
3064
|
+
sc.scopeNodeName === pathInfo.scopeNodeName,
|
|
3065
|
+
)
|
|
3066
|
+
) {
|
|
2874
3067
|
databaseEntry.sourceCandidates.push(pathInfo);
|
|
2875
3068
|
}
|
|
2876
3069
|
} else {
|
|
@@ -3457,18 +3650,171 @@ export class ScopeDataStructure {
|
|
|
3457
3650
|
return {};
|
|
3458
3651
|
}
|
|
3459
3652
|
|
|
3653
|
+
// Collect all descendant scope names (including the scope itself)
|
|
3654
|
+
// This ensures we include external calls from nested scopes like cyScope2
|
|
3655
|
+
const getAllDescendantScopeNames = (
|
|
3656
|
+
node: import('./helpers/ScopeTreeManager').ScopeTreeNode,
|
|
3657
|
+
): Set<string> => {
|
|
3658
|
+
const names = new Set<string>([node.name]);
|
|
3659
|
+
for (const child of node.children) {
|
|
3660
|
+
for (const name of getAllDescendantScopeNames(child)) {
|
|
3661
|
+
names.add(name);
|
|
3662
|
+
}
|
|
3663
|
+
}
|
|
3664
|
+
return names;
|
|
3665
|
+
};
|
|
3666
|
+
|
|
3667
|
+
const treeNode = this.scopeTreeManager.findNode(scopeNode.name);
|
|
3668
|
+
const descendantScopeNames = treeNode
|
|
3669
|
+
? getAllDescendantScopeNames(treeNode)
|
|
3670
|
+
: new Set<string>([scopeNode.name]);
|
|
3671
|
+
|
|
3672
|
+
// Get all external function calls made from this scope or any descendant scope
|
|
3673
|
+
// This allows us to include prop equivalencies from JSX components
|
|
3674
|
+
// that were rendered in nested scopes (e.g., FileTableRow called from cyScope2)
|
|
3675
|
+
const externalCallsFromScope = this.externalFunctionCalls.filter((efc) =>
|
|
3676
|
+
descendantScopeNames.has(efc.callScope),
|
|
3677
|
+
);
|
|
3678
|
+
const externalCallNames = new Set(
|
|
3679
|
+
externalCallsFromScope.map((efc) => efc.name),
|
|
3680
|
+
);
|
|
3681
|
+
|
|
3682
|
+
// Helper to check if a usage belongs to this scope (directly, via descendant, or via external call)
|
|
3683
|
+
const usageMatchesScope = (usage: { scopeNodeName: string }) =>
|
|
3684
|
+
descendantScopeNames.has(usage.scopeNodeName) ||
|
|
3685
|
+
externalCallNames.has(usage.scopeNodeName);
|
|
3686
|
+
|
|
3460
3687
|
const entries = this.equivalencyDatabase.filter((entry) =>
|
|
3461
|
-
entry.usages.some(
|
|
3688
|
+
entry.usages.some(usageMatchesScope),
|
|
3462
3689
|
);
|
|
3690
|
+
|
|
3691
|
+
// Helper to resolve a source candidate through equivalency chains to find signature paths
|
|
3692
|
+
const resolveToSignature = (
|
|
3693
|
+
source: Pick<ScopeVariable, 'scopeNodeName' | 'schemaPath'>,
|
|
3694
|
+
visited: Set<string>,
|
|
3695
|
+
): Pick<ScopeVariable, 'scopeNodeName' | 'schemaPath'>[] => {
|
|
3696
|
+
const visitKey = `${source.scopeNodeName}::${source.schemaPath}`;
|
|
3697
|
+
if (visited.has(visitKey)) return [];
|
|
3698
|
+
visited.add(visitKey);
|
|
3699
|
+
|
|
3700
|
+
// If already a signature path, return as-is
|
|
3701
|
+
if (source.schemaPath.startsWith('signature[')) {
|
|
3702
|
+
return [source];
|
|
3703
|
+
}
|
|
3704
|
+
|
|
3705
|
+
const currentScope = this.scopeNodes[source.scopeNodeName];
|
|
3706
|
+
if (!currentScope?.equivalencies) return [source];
|
|
3707
|
+
|
|
3708
|
+
// Check for direct equivalencies FIRST (full path match)
|
|
3709
|
+
// This ensures paths like "useMemo(...).functionCallReturnValue" follow to "cyScope1::returnValue"
|
|
3710
|
+
// before prefix matching tries "useMemo(...)" which goes to the useMemo scope
|
|
3711
|
+
const directEquivs = currentScope.equivalencies[source.schemaPath];
|
|
3712
|
+
if (directEquivs?.length > 0) {
|
|
3713
|
+
const results: Pick<ScopeVariable, 'scopeNodeName' | 'schemaPath'>[] =
|
|
3714
|
+
[];
|
|
3715
|
+
for (const equiv of directEquivs) {
|
|
3716
|
+
const resolved = resolveToSignature(
|
|
3717
|
+
{
|
|
3718
|
+
scopeNodeName: equiv.scopeNodeName,
|
|
3719
|
+
schemaPath: equiv.schemaPath,
|
|
3720
|
+
},
|
|
3721
|
+
visited,
|
|
3722
|
+
);
|
|
3723
|
+
results.push(...resolved);
|
|
3724
|
+
}
|
|
3725
|
+
if (results.length > 0) return results;
|
|
3726
|
+
}
|
|
3727
|
+
|
|
3728
|
+
// Handle spread patterns like [...items].sort().functionCallReturnValue
|
|
3729
|
+
// Extract the spread variable and resolve it through the equivalency chain
|
|
3730
|
+
const spreadMatch = source.schemaPath.match(/^\[\.\.\.(\w+)\]/);
|
|
3731
|
+
if (spreadMatch) {
|
|
3732
|
+
const spreadVar = spreadMatch[1];
|
|
3733
|
+
const spreadPattern = spreadMatch[0];
|
|
3734
|
+
const varEquivs = currentScope.equivalencies[spreadVar];
|
|
3735
|
+
|
|
3736
|
+
if (varEquivs?.length > 0) {
|
|
3737
|
+
const results: Pick<ScopeVariable, 'scopeNodeName' | 'schemaPath'>[] =
|
|
3738
|
+
[];
|
|
3739
|
+
for (const equiv of varEquivs) {
|
|
3740
|
+
// Follow the variable equivalency and then resolve from there
|
|
3741
|
+
const resolvedVar = resolveToSignature(
|
|
3742
|
+
{
|
|
3743
|
+
scopeNodeName: equiv.scopeNodeName,
|
|
3744
|
+
schemaPath: equiv.schemaPath,
|
|
3745
|
+
},
|
|
3746
|
+
visited,
|
|
3747
|
+
);
|
|
3748
|
+
// For each resolved variable path, create the full path with array element suffix
|
|
3749
|
+
for (const rv of resolvedVar) {
|
|
3750
|
+
if (rv.schemaPath.startsWith('signature[')) {
|
|
3751
|
+
// Get the suffix after the spread pattern
|
|
3752
|
+
let suffix = source.schemaPath.slice(spreadPattern.length);
|
|
3753
|
+
|
|
3754
|
+
// Clean the suffix: strip array method chains like .sort(...).functionCallReturnValue[]
|
|
3755
|
+
// These don't change the data identity, just transform it.
|
|
3756
|
+
// Keep only the final element access parts like [0], [1], etc.
|
|
3757
|
+
// Pattern: strip everything from a method call up through functionCallReturnValue[]
|
|
3758
|
+
suffix = suffix.replace(
|
|
3759
|
+
/\.\w+\([^)]*\)\.functionCallReturnValue\[\]/g,
|
|
3760
|
+
'',
|
|
3761
|
+
);
|
|
3762
|
+
// Also handle simpler case without nested parens
|
|
3763
|
+
suffix = suffix.replace(
|
|
3764
|
+
/\.sort\(\w*\(\)\)\.functionCallReturnValue\[\]/g,
|
|
3765
|
+
'',
|
|
3766
|
+
);
|
|
3767
|
+
|
|
3768
|
+
// Add [] to indicate array element access from the spread
|
|
3769
|
+
const resolvedPath = rv.schemaPath + '[]' + suffix;
|
|
3770
|
+
results.push({
|
|
3771
|
+
scopeNodeName: rv.scopeNodeName,
|
|
3772
|
+
schemaPath: resolvedPath,
|
|
3773
|
+
});
|
|
3774
|
+
}
|
|
3775
|
+
}
|
|
3776
|
+
}
|
|
3777
|
+
if (results.length > 0) return results;
|
|
3778
|
+
}
|
|
3779
|
+
}
|
|
3780
|
+
|
|
3781
|
+
// Try to find prefix equivalencies that can resolve this path
|
|
3782
|
+
// For path like "cyScope3().signature[0][0]", check "cyScope3().signature[0]", etc.
|
|
3783
|
+
const pathParts = this.splitPath(source.schemaPath);
|
|
3784
|
+
for (let i = pathParts.length - 1; i > 0; i--) {
|
|
3785
|
+
const prefix = this.joinPathParts(pathParts.slice(0, i));
|
|
3786
|
+
const suffix = this.joinPathParts(pathParts.slice(i));
|
|
3787
|
+
const prefixEquivs = currentScope.equivalencies[prefix];
|
|
3788
|
+
|
|
3789
|
+
if (prefixEquivs?.length > 0) {
|
|
3790
|
+
const results: Pick<ScopeVariable, 'scopeNodeName' | 'schemaPath'>[] =
|
|
3791
|
+
[];
|
|
3792
|
+
for (const equiv of prefixEquivs) {
|
|
3793
|
+
const newPath = this.joinPathParts([equiv.schemaPath, suffix]);
|
|
3794
|
+
const resolved = resolveToSignature(
|
|
3795
|
+
{ scopeNodeName: equiv.scopeNodeName, schemaPath: newPath },
|
|
3796
|
+
visited,
|
|
3797
|
+
);
|
|
3798
|
+
results.push(...resolved);
|
|
3799
|
+
}
|
|
3800
|
+
if (results.length > 0) return results;
|
|
3801
|
+
}
|
|
3802
|
+
}
|
|
3803
|
+
|
|
3804
|
+
return [source];
|
|
3805
|
+
};
|
|
3806
|
+
|
|
3463
3807
|
return entries.reduce(
|
|
3464
3808
|
(acc, entry) => {
|
|
3465
3809
|
if (entry.sourceCandidates.length === 0) return acc;
|
|
3466
|
-
const usages = entry.usages.filter(
|
|
3467
|
-
(u) => u.scopeNodeName === scopeNode.name,
|
|
3468
|
-
);
|
|
3810
|
+
const usages = entry.usages.filter(usageMatchesScope);
|
|
3469
3811
|
for (const usage of usages) {
|
|
3470
3812
|
acc[usage.schemaPath] ||= [];
|
|
3471
|
-
|
|
3813
|
+
// Resolve each source candidate through the equivalency chain
|
|
3814
|
+
for (const source of entry.sourceCandidates) {
|
|
3815
|
+
const resolvedSources = resolveToSignature(source, new Set());
|
|
3816
|
+
acc[usage.schemaPath].push(...resolvedSources);
|
|
3817
|
+
}
|
|
3472
3818
|
}
|
|
3473
3819
|
return acc;
|
|
3474
3820
|
},
|
|
@@ -3853,10 +4199,32 @@ export class ScopeDataStructure {
|
|
|
3853
4199
|
return scopeText;
|
|
3854
4200
|
}
|
|
3855
4201
|
|
|
3856
|
-
getEquivalentSignatureVariables() {
|
|
4202
|
+
getEquivalentSignatureVariables(): Record<string, string | string[]> {
|
|
3857
4203
|
const scopeNode = this.scopeNodes[this.scopeTreeManager.getRootName()];
|
|
3858
4204
|
|
|
3859
|
-
const equivalentSignatureVariables: Record<string, string> = {};
|
|
4205
|
+
const equivalentSignatureVariables: Record<string, string | string[]> = {};
|
|
4206
|
+
|
|
4207
|
+
// Helper to add equivalencies - accumulates into array if multiple values for same key
|
|
4208
|
+
// This is critical for OR expressions like `x = a || b` where x should map to both a and b
|
|
4209
|
+
const addEquivalency = (key: string, value: string) => {
|
|
4210
|
+
const existing = equivalentSignatureVariables[key];
|
|
4211
|
+
if (existing === undefined) {
|
|
4212
|
+
// First value - store as string
|
|
4213
|
+
equivalentSignatureVariables[key] = value;
|
|
4214
|
+
} else if (typeof existing === 'string') {
|
|
4215
|
+
if (existing !== value) {
|
|
4216
|
+
// Second different value - convert to array
|
|
4217
|
+
equivalentSignatureVariables[key] = [existing, value];
|
|
4218
|
+
}
|
|
4219
|
+
// Same value - no change needed
|
|
4220
|
+
} else {
|
|
4221
|
+
// Already an array - add if not already present
|
|
4222
|
+
if (!existing.includes(value)) {
|
|
4223
|
+
existing.push(value);
|
|
4224
|
+
}
|
|
4225
|
+
}
|
|
4226
|
+
};
|
|
4227
|
+
|
|
3860
4228
|
for (const [path, equivalentValues] of Object.entries(
|
|
3861
4229
|
scopeNode.equivalencies,
|
|
3862
4230
|
)) {
|
|
@@ -3865,7 +4233,7 @@ export class ScopeDataStructure {
|
|
|
3865
4233
|
// Maps local variable names to their signature paths
|
|
3866
4234
|
// e.g., "propValue" -> "signature[0].prop"
|
|
3867
4235
|
if (path.startsWith('signature[')) {
|
|
3868
|
-
|
|
4236
|
+
addEquivalency(equivalentValue.schemaPath, path);
|
|
3869
4237
|
}
|
|
3870
4238
|
|
|
3871
4239
|
// Case 2: Hook variable equivalencies (new behavior)
|
|
@@ -3876,14 +4244,30 @@ export class ScopeDataStructure {
|
|
|
3876
4244
|
// "useFetcher<...>().state" for execution flow validation
|
|
3877
4245
|
if (equivalentValue.schemaPath.endsWith('.functionCallReturnValue')) {
|
|
3878
4246
|
// Extract the hook call path (everything before .functionCallReturnValue)
|
|
3879
|
-
|
|
4247
|
+
let hookCallPath = equivalentValue.schemaPath.slice(
|
|
3880
4248
|
0,
|
|
3881
4249
|
-'.functionCallReturnValue'.length,
|
|
3882
4250
|
);
|
|
3883
4251
|
// Only include if it looks like a hook call (contains parentheses)
|
|
3884
4252
|
// and the variable name (path) is a simple identifier (no dots)
|
|
3885
4253
|
if (hookCallPath.includes('(') && !path.includes('.')) {
|
|
3886
|
-
|
|
4254
|
+
// Special case: If hookCallPath is a callback scope (cyScope pattern),
|
|
4255
|
+
// trace through it to find what the callback actually returns.
|
|
4256
|
+
// This handles useState(() => { return prop; }) patterns.
|
|
4257
|
+
const cyScopeMatch = hookCallPath.match(/^(cyScope\d+)\(\)$/);
|
|
4258
|
+
if (cyScopeMatch) {
|
|
4259
|
+
// Use the equivalency database to trace the callback's return value
|
|
4260
|
+
// to its actual source (e.g., viewModeFromUrl -> segments -> params -> useParams)
|
|
4261
|
+
const dbEntry = this.getEquivalenciesDatabaseEntry(
|
|
4262
|
+
scopeNode.name, // Component scope
|
|
4263
|
+
path, // variable name (e.g., viewMode)
|
|
4264
|
+
);
|
|
4265
|
+
if (dbEntry?.sourceCandidates?.length > 0) {
|
|
4266
|
+
// Use the traced source instead of the callback scope
|
|
4267
|
+
hookCallPath = dbEntry.sourceCandidates[0].schemaPath;
|
|
4268
|
+
}
|
|
4269
|
+
}
|
|
4270
|
+
addEquivalency(path, hookCallPath);
|
|
3887
4271
|
}
|
|
3888
4272
|
}
|
|
3889
4273
|
|
|
@@ -3897,10 +4281,8 @@ export class ScopeDataStructure {
|
|
|
3897
4281
|
!equivalentValue.schemaPath.startsWith('signature[') && // not a signature path
|
|
3898
4282
|
!equivalentValue.schemaPath.endsWith('.functionCallReturnValue') // not already handled above
|
|
3899
4283
|
) {
|
|
3900
|
-
//
|
|
3901
|
-
|
|
3902
|
-
equivalentSignatureVariables[path] = equivalentValue.schemaPath;
|
|
3903
|
-
}
|
|
4284
|
+
// Add equivalency (will accumulate if multiple values for OR expressions)
|
|
4285
|
+
addEquivalency(path, equivalentValue.schemaPath);
|
|
3904
4286
|
}
|
|
3905
4287
|
|
|
3906
4288
|
// Case 4: Child component prop mappings (Fix 22)
|
|
@@ -3913,7 +4295,7 @@ export class ScopeDataStructure {
|
|
|
3913
4295
|
path.includes('().signature[') &&
|
|
3914
4296
|
!equivalentValue.schemaPath.includes('()') // schemaPath is a simple variable, not a function call
|
|
3915
4297
|
) {
|
|
3916
|
-
|
|
4298
|
+
addEquivalency(path, equivalentValue.schemaPath);
|
|
3917
4299
|
}
|
|
3918
4300
|
|
|
3919
4301
|
// Case 5: Destructured function parameters (Fix 25)
|
|
@@ -3928,7 +4310,7 @@ export class ScopeDataStructure {
|
|
|
3928
4310
|
!path.includes('.') && // path is a simple identifier (destructured prop name)
|
|
3929
4311
|
equivalentValue.schemaPath.startsWith('signature[') // schemaPath IS a signature path
|
|
3930
4312
|
) {
|
|
3931
|
-
|
|
4313
|
+
addEquivalency(path, equivalentValue.schemaPath);
|
|
3932
4314
|
}
|
|
3933
4315
|
|
|
3934
4316
|
// Case 7: Method calls on variables that result in .functionCallReturnValue (Fix 33)
|
|
@@ -3942,8 +4324,7 @@ export class ScopeDataStructure {
|
|
|
3942
4324
|
if (
|
|
3943
4325
|
!path.includes('.') && // path is a simple identifier
|
|
3944
4326
|
equivalentValue.schemaPath.endsWith('.functionCallReturnValue') && // ends with function return
|
|
3945
|
-
equivalentValue.schemaPath.includes('.')
|
|
3946
|
-
!(path in equivalentSignatureVariables) // not already captured
|
|
4327
|
+
equivalentValue.schemaPath.includes('.') // has property access (method call)
|
|
3947
4328
|
) {
|
|
3948
4329
|
// Check if this looks like a method call on a variable (not a hook call)
|
|
3949
4330
|
// Hook calls look like: hookName() or hookName<T>()
|
|
@@ -3957,7 +4338,7 @@ export class ScopeDataStructure {
|
|
|
3957
4338
|
const parenPos = hookCallPath.indexOf('(');
|
|
3958
4339
|
if (dotBeforeParen !== -1 && dotBeforeParen < parenPos) {
|
|
3959
4340
|
// This is a method call like "splat.split('/')", not a hook call
|
|
3960
|
-
|
|
4341
|
+
addEquivalency(path, equivalentValue.schemaPath);
|
|
3961
4342
|
}
|
|
3962
4343
|
}
|
|
3963
4344
|
}
|
|
@@ -3988,8 +4369,9 @@ export class ScopeDataStructure {
|
|
|
3988
4369
|
!equivalentValue.schemaPath.includes('()') // schemaPath is a simple variable
|
|
3989
4370
|
) {
|
|
3990
4371
|
// Only add if not already present from the root scope
|
|
4372
|
+
// Root scope values take precedence over child scope values
|
|
3991
4373
|
if (!(path in equivalentSignatureVariables)) {
|
|
3992
|
-
|
|
4374
|
+
addEquivalency(path, equivalentValue.schemaPath);
|
|
3993
4375
|
}
|
|
3994
4376
|
}
|
|
3995
4377
|
}
|
|
@@ -4000,12 +4382,84 @@ export class ScopeDataStructure {
|
|
|
4000
4382
|
// E.g., analysis → currentEntityAnalysis → useLoaderData().functionCallReturnValue.currentEntityAnalysis
|
|
4001
4383
|
// We need multiple passes because resolutions can depend on each other
|
|
4002
4384
|
const maxIterations = 5; // Prevent infinite loops
|
|
4385
|
+
|
|
4386
|
+
// Helper function to resolve a single source path using equivalencies
|
|
4387
|
+
const resolveSourcePath = (
|
|
4388
|
+
sourcePath: string,
|
|
4389
|
+
equivMap: Record<string, string | string[]>,
|
|
4390
|
+
): string | null => {
|
|
4391
|
+
// Extract base variable from the path
|
|
4392
|
+
const dotIndex = sourcePath.indexOf('.');
|
|
4393
|
+
const bracketIndex = sourcePath.indexOf('[');
|
|
4394
|
+
|
|
4395
|
+
let baseVar: string;
|
|
4396
|
+
let rest: string;
|
|
4397
|
+
|
|
4398
|
+
if (dotIndex === -1 && bracketIndex === -1) {
|
|
4399
|
+
baseVar = sourcePath;
|
|
4400
|
+
rest = '';
|
|
4401
|
+
} else if (dotIndex === -1) {
|
|
4402
|
+
baseVar = sourcePath.slice(0, bracketIndex);
|
|
4403
|
+
rest = sourcePath.slice(bracketIndex);
|
|
4404
|
+
} else if (bracketIndex === -1) {
|
|
4405
|
+
baseVar = sourcePath.slice(0, dotIndex);
|
|
4406
|
+
rest = sourcePath.slice(dotIndex);
|
|
4407
|
+
} else {
|
|
4408
|
+
const firstIndex = Math.min(dotIndex, bracketIndex);
|
|
4409
|
+
baseVar = sourcePath.slice(0, firstIndex);
|
|
4410
|
+
rest = sourcePath.slice(firstIndex);
|
|
4411
|
+
}
|
|
4412
|
+
|
|
4413
|
+
// Look up the base variable in equivalencies
|
|
4414
|
+
if (baseVar in equivMap && equivMap[baseVar] !== sourcePath) {
|
|
4415
|
+
const baseResolved = equivMap[baseVar];
|
|
4416
|
+
// Skip if baseResolved is an array (handle later)
|
|
4417
|
+
if (Array.isArray(baseResolved)) return null;
|
|
4418
|
+
// If it resolves to a signature path, build the full resolved path
|
|
4419
|
+
if (
|
|
4420
|
+
baseResolved.startsWith('signature[') ||
|
|
4421
|
+
baseResolved.includes('()')
|
|
4422
|
+
) {
|
|
4423
|
+
if (baseResolved.endsWith('()')) {
|
|
4424
|
+
return baseResolved + '.functionCallReturnValue' + rest;
|
|
4425
|
+
}
|
|
4426
|
+
return baseResolved + rest;
|
|
4427
|
+
}
|
|
4428
|
+
}
|
|
4429
|
+
return null;
|
|
4430
|
+
};
|
|
4431
|
+
|
|
4003
4432
|
for (let iteration = 0; iteration < maxIterations; iteration++) {
|
|
4004
4433
|
let changed = false;
|
|
4005
4434
|
|
|
4006
|
-
for (const [varName,
|
|
4435
|
+
for (const [varName, sourcePathOrArray] of Object.entries(
|
|
4007
4436
|
equivalentSignatureVariables,
|
|
4008
4437
|
)) {
|
|
4438
|
+
// Handle arrays (OR expressions) by resolving each element
|
|
4439
|
+
if (Array.isArray(sourcePathOrArray)) {
|
|
4440
|
+
const resolvedArray: string[] = [];
|
|
4441
|
+
let arrayChanged = false;
|
|
4442
|
+
for (const sourcePath of sourcePathOrArray) {
|
|
4443
|
+
// Try to resolve this path using transitive resolution
|
|
4444
|
+
const resolved = resolveSourcePath(
|
|
4445
|
+
sourcePath,
|
|
4446
|
+
equivalentSignatureVariables,
|
|
4447
|
+
);
|
|
4448
|
+
if (resolved && resolved !== sourcePath) {
|
|
4449
|
+
resolvedArray.push(resolved);
|
|
4450
|
+
arrayChanged = true;
|
|
4451
|
+
} else {
|
|
4452
|
+
resolvedArray.push(sourcePath);
|
|
4453
|
+
}
|
|
4454
|
+
}
|
|
4455
|
+
if (arrayChanged) {
|
|
4456
|
+
equivalentSignatureVariables[varName] = resolvedArray;
|
|
4457
|
+
changed = true;
|
|
4458
|
+
}
|
|
4459
|
+
continue;
|
|
4460
|
+
}
|
|
4461
|
+
const sourcePath = sourcePathOrArray;
|
|
4462
|
+
|
|
4009
4463
|
// Skip if already fully resolved (contains function call syntax)
|
|
4010
4464
|
// BUT first check for computed value patterns that need resolution (Fix 28)
|
|
4011
4465
|
// AND method call patterns that need base variable resolution (Fix 33)
|
|
@@ -4067,6 +4521,8 @@ export class ScopeDataStructure {
|
|
|
4067
4521
|
baseVar !== varName
|
|
4068
4522
|
) {
|
|
4069
4523
|
const baseResolved = equivalentSignatureVariables[baseVar];
|
|
4524
|
+
// Skip if baseResolved is an array (OR expression)
|
|
4525
|
+
if (Array.isArray(baseResolved)) continue;
|
|
4070
4526
|
// Only resolve if the base resolved to something useful (contains () or .)
|
|
4071
4527
|
if (baseResolved.includes('()') || baseResolved.includes('.')) {
|
|
4072
4528
|
const newPath = baseResolved + rest;
|
|
@@ -4078,6 +4534,40 @@ export class ScopeDataStructure {
|
|
|
4078
4534
|
}
|
|
4079
4535
|
}
|
|
4080
4536
|
|
|
4537
|
+
// Fix 38: Handle cyScope lazy initializer return values
|
|
4538
|
+
// When we have viewMode -> cyScope20(), trace through to find what cyScope20 returns.
|
|
4539
|
+
// The lazy initializer's return value should be the controllable data source.
|
|
4540
|
+
// Pattern: cyScopeN() where N is a number
|
|
4541
|
+
const cyScopeMatch = sourcePath.match(/^(cyScope\d+)\(\)$/);
|
|
4542
|
+
if (cyScopeMatch) {
|
|
4543
|
+
const cyScopeName = cyScopeMatch[1];
|
|
4544
|
+
const cyScopeNode = this.scopeNodes[cyScopeName];
|
|
4545
|
+
|
|
4546
|
+
if (cyScopeNode?.equivalencies) {
|
|
4547
|
+
// Look for returnValue equivalency in the cyScope
|
|
4548
|
+
const returnValueEquivs =
|
|
4549
|
+
cyScopeNode.equivalencies['returnValue'];
|
|
4550
|
+
if (returnValueEquivs && returnValueEquivs.length > 0) {
|
|
4551
|
+
// Get the first return value source
|
|
4552
|
+
const returnSource = returnValueEquivs[0].schemaPath;
|
|
4553
|
+
|
|
4554
|
+
// If the return source is a simple variable (not a complex path),
|
|
4555
|
+
// resolve varName directly to that variable
|
|
4556
|
+
if (
|
|
4557
|
+
returnSource &&
|
|
4558
|
+
!returnSource.includes('(') &&
|
|
4559
|
+
!returnSource.includes('[')
|
|
4560
|
+
) {
|
|
4561
|
+
// Update varName to point to the return source
|
|
4562
|
+
if (equivalentSignatureVariables[varName] !== returnSource) {
|
|
4563
|
+
equivalentSignatureVariables[varName] = returnSource;
|
|
4564
|
+
changed = true;
|
|
4565
|
+
}
|
|
4566
|
+
}
|
|
4567
|
+
}
|
|
4568
|
+
}
|
|
4569
|
+
}
|
|
4570
|
+
|
|
4081
4571
|
continue;
|
|
4082
4572
|
}
|
|
4083
4573
|
|
|
@@ -4097,7 +4587,12 @@ export class ScopeDataStructure {
|
|
|
4097
4587
|
}
|
|
4098
4588
|
|
|
4099
4589
|
if (baseVar in equivalentSignatureVariables && baseVar !== varName) {
|
|
4100
|
-
|
|
4590
|
+
// Handle array case (OR expressions) - use first element
|
|
4591
|
+
const rawBaseResolved = equivalentSignatureVariables[baseVar];
|
|
4592
|
+
const baseResolved = Array.isArray(rawBaseResolved)
|
|
4593
|
+
? rawBaseResolved[0]
|
|
4594
|
+
: rawBaseResolved;
|
|
4595
|
+
if (!baseResolved) continue;
|
|
4101
4596
|
// If the base resolves to a hook call, add .functionCallReturnValue
|
|
4102
4597
|
if (baseResolved.endsWith('()')) {
|
|
4103
4598
|
const newPath = baseResolved + '.functionCallReturnValue' + rest;
|
|
@@ -4317,7 +4812,7 @@ export class ScopeDataStructure {
|
|
|
4317
4812
|
path: string;
|
|
4318
4813
|
conditionType: 'truthiness' | 'comparison' | 'switch';
|
|
4319
4814
|
comparedValues?: string[];
|
|
4320
|
-
location: 'if' | 'ternary' | 'logical-and' | 'switch';
|
|
4815
|
+
location: 'if' | 'ternary' | 'logical-and' | 'switch' | 'unconditional';
|
|
4321
4816
|
}>
|
|
4322
4817
|
>,
|
|
4323
4818
|
): void {
|
|
@@ -4503,6 +4998,33 @@ export class ScopeDataStructure {
|
|
|
4503
4998
|
return enriched;
|
|
4504
4999
|
}
|
|
4505
5000
|
|
|
5001
|
+
/**
|
|
5002
|
+
* Add JSX rendering usages from AST analysis.
|
|
5003
|
+
* These track arrays rendered via .map() and strings interpolated in JSX.
|
|
5004
|
+
*/
|
|
5005
|
+
addJsxRenderingUsages(
|
|
5006
|
+
usages: import('../astScopes/types').JsxRenderingUsage[],
|
|
5007
|
+
): void {
|
|
5008
|
+
// Add usages, avoiding duplicates based on path and renderingType
|
|
5009
|
+
for (const usage of usages) {
|
|
5010
|
+
const exists = this.rawJsxRenderingUsages.some(
|
|
5011
|
+
(existing) =>
|
|
5012
|
+
existing.path === usage.path &&
|
|
5013
|
+
existing.renderingType === usage.renderingType,
|
|
5014
|
+
);
|
|
5015
|
+
if (!exists) {
|
|
5016
|
+
this.rawJsxRenderingUsages.push(usage);
|
|
5017
|
+
}
|
|
5018
|
+
}
|
|
5019
|
+
}
|
|
5020
|
+
|
|
5021
|
+
/**
|
|
5022
|
+
* Get JSX rendering usages collected during analysis.
|
|
5023
|
+
*/
|
|
5024
|
+
getJsxRenderingUsages(): import('../astScopes/types').JsxRenderingUsage[] {
|
|
5025
|
+
return this.rawJsxRenderingUsages;
|
|
5026
|
+
}
|
|
5027
|
+
|
|
4506
5028
|
toSerializable(): SerializableDataStructure {
|
|
4507
5029
|
// Helper to clean cyScope and cyDuplicateKey from a string for output
|
|
4508
5030
|
const cleanCyScope = (str: string): string =>
|
|
@@ -5003,6 +5525,12 @@ export class ScopeDataStructure {
|
|
|
5003
5525
|
? enrichedGatingConditions
|
|
5004
5526
|
: undefined;
|
|
5005
5527
|
|
|
5528
|
+
// Get JSX rendering usages (arrays via .map(), strings via interpolation)
|
|
5529
|
+
const jsxRenderingUsages =
|
|
5530
|
+
this.rawJsxRenderingUsages.length > 0
|
|
5531
|
+
? this.rawJsxRenderingUsages
|
|
5532
|
+
: undefined;
|
|
5533
|
+
|
|
5006
5534
|
return {
|
|
5007
5535
|
externalFunctionCalls: deduplicatedExternalFunctionCalls,
|
|
5008
5536
|
rootFunction,
|
|
@@ -5013,6 +5541,7 @@ export class ScopeDataStructure {
|
|
|
5013
5541
|
conditionalEffects,
|
|
5014
5542
|
compoundConditionals,
|
|
5015
5543
|
childBoundaryGatingConditions,
|
|
5544
|
+
jsxRenderingUsages,
|
|
5016
5545
|
};
|
|
5017
5546
|
}
|
|
5018
5547
|
|