@codeyam/codeyam-cli 0.1.0-staging.1669d45 → 0.1.0-staging.1a2737b
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 +19 -19
- package/analyzer-template/packages/ai/index.ts +16 -2
- package/analyzer-template/packages/ai/package.json +2 -2
- package/analyzer-template/packages/ai/src/lib/analyzeScope.ts +110 -52
- 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/forInStatementHandler.ts +10 -17
- package/analyzer-template/packages/ai/src/lib/astScopes/patterns/variableDeclarationHandler.ts +6 -126
- package/analyzer-template/packages/ai/src/lib/astScopes/processExpression.ts +656 -28
- package/analyzer-template/packages/ai/src/lib/astScopes/sharedPatterns.ts +28 -0
- package/analyzer-template/packages/ai/src/lib/astScopes/types.ts +94 -7
- package/analyzer-template/packages/ai/src/lib/completionCall.ts +198 -34
- package/analyzer-template/packages/ai/src/lib/dataStructure/ScopeDataStructure.ts +1331 -254
- package/analyzer-template/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/JavascriptFrameworkManager.ts +5 -1
- 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 +54 -3
- package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/cleanNonObjectFunctions.ts +124 -17
- package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/coerceObjectsToPrimitivesBySchema.ts +70 -0
- package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/convertDotNotation.ts +140 -14
- package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/convertTypeAnnotationsToValues.ts +179 -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 +393 -97
- package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/fixNullIdsBySchema.ts +129 -0
- package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/stripNullableMarkers.ts +35 -0
- package/analyzer-template/packages/ai/src/lib/dataStructureChunking.ts +183 -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/generateEntityDataStructure.ts +58 -3
- package/analyzer-template/packages/ai/src/lib/generateEntityScenarioData.ts +936 -7
- package/analyzer-template/packages/ai/src/lib/generateEntityScenarios.ts +35 -6
- package/analyzer-template/packages/ai/src/lib/generateExecutionFlows.ts +515 -6
- package/analyzer-template/packages/ai/src/lib/generateExecutionFlowsFromConditionalEffects.ts +1 -1
- package/analyzer-template/packages/ai/src/lib/generateExecutionFlowsFromConditionals.ts +1540 -75
- package/analyzer-template/packages/ai/src/lib/generateExecutionFlowsFromJsxUsages.ts +239 -0
- package/analyzer-template/packages/ai/src/lib/isolateScopes.ts +51 -3
- package/analyzer-template/packages/ai/src/lib/mergeJsonTypeDefinitions.ts +5 -0
- package/analyzer-template/packages/ai/src/lib/mergeStatements.ts +90 -96
- package/analyzer-template/packages/ai/src/lib/promptGenerators/collapseNullableObjects.ts +118 -0
- 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 +44 -7
- 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/index.ts +2 -0
- 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/nodes/getNodeType.ts +1 -0
- 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 +99 -22
- package/analyzer-template/packages/analyze/src/lib/files/analyze/analyzeEntities.ts +19 -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/TransformationTracer.ts +1315 -0
- package/analyzer-template/packages/analyze/src/lib/files/scenarios/enrichArrayTypesFromChildSignatures.ts +193 -76
- package/analyzer-template/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.ts +87 -25
- package/analyzer-template/packages/analyze/src/lib/files/scenarios/generateDataStructure.ts +269 -22
- package/analyzer-template/packages/analyze/src/lib/files/scenarios/generateExecutionFlows.ts +118 -10
- package/analyzer-template/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.ts +647 -73
- 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/index.ts +1 -0
- package/analyzer-template/packages/analyze/src/lib/utils/getFileByPath.ts +19 -0
- package/analyzer-template/packages/aws/package.json +10 -10
- package/analyzer-template/packages/database/package.json +1 -1
- package/analyzer-template/packages/database/src/lib/analysisBranchToDb.ts +1 -1
- package/analyzer-template/packages/database/src/lib/analysisToDb.ts +1 -1
- package/analyzer-template/packages/database/src/lib/branchToDb.ts +1 -1
- package/analyzer-template/packages/database/src/lib/commitBranchToDb.ts +1 -1
- package/analyzer-template/packages/database/src/lib/commitToDb.ts +1 -1
- package/analyzer-template/packages/database/src/lib/fileToDb.ts +1 -1
- package/analyzer-template/packages/database/src/lib/kysely/db.ts +14 -1
- package/analyzer-template/packages/database/src/lib/kysely/tables/commitsTable.ts +6 -0
- package/analyzer-template/packages/database/src/lib/kysely/tables/debugReportsTable.ts +1 -1
- package/analyzer-template/packages/database/src/lib/kysely/tables/labsRequestsTable.ts +52 -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/projectToDb.ts +1 -1
- package/analyzer-template/packages/database/src/lib/saveFiles.ts +1 -1
- package/analyzer-template/packages/database/src/lib/scenarioToDb.ts +1 -1
- package/analyzer-template/packages/database/src/lib/updateCommitMetadata.ts +7 -14
- package/analyzer-template/packages/database/src/lib/userScenarioToDb.ts +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/analysisBranchToDb.js +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/analysisBranchToDb.js.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/analysisToDb.js +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/analysisToDb.js.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/branchToDb.js +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/branchToDb.js.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/commitBranchToDb.js +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/commitBranchToDb.js.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/commitToDb.js +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/commitToDb.js.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/fileToDb.js +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/fileToDb.js.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/kysely/db.d.ts +2 -0
- 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 +11 -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/kysely/tables/debugReportsTable.d.ts +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/labsRequestsTable.d.ts +23 -0
- package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/labsRequestsTable.d.ts.map +1 -0
- package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/labsRequestsTable.js +35 -0
- package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/labsRequestsTable.js.map +1 -0
- 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/projectToDb.js +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/projectToDb.js.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/saveFiles.js +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/saveFiles.js.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/scenarioToDb.js +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/scenarioToDb.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/ProjectMetadata.d.ts +7 -0
- package/analyzer-template/packages/github/dist/types/src/types/ProjectMetadata.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/ProjectMetadata.ts +7 -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/ProjectMetadata.d.ts +7 -0
- package/analyzer-template/packages/utils/dist/types/src/types/ProjectMetadata.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/fs/rsyncCopy.d.ts.map +1 -1
- package/analyzer-template/packages/utils/dist/utils/src/lib/fs/rsyncCopy.js +93 -2
- package/analyzer-template/packages/utils/dist/utils/src/lib/fs/rsyncCopy.js.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/fs/rsyncCopy.ts +108 -2
- 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 +436 -44
- 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 +75 -7
- 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 +295 -10
- package/analyzer-template/project/writeScenarioComponents.ts +237 -32
- package/analyzer-template/project/writeSimpleRoot.ts +21 -11
- package/analyzer-template/scripts/comboWorkerLoop.cjs +98 -50
- package/background/src/lib/local/createLocalAnalyzer.js +1 -1
- package/background/src/lib/local/createLocalAnalyzer.js.map +1 -1
- 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 +359 -14
- 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 +62 -7
- 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 +251 -6
- package/background/src/lib/virtualized/project/writeMockDataTsx.js.map +1 -1
- package/background/src/lib/virtualized/project/writeScenarioComponents.js +173 -30
- package/background/src/lib/virtualized/project/writeScenarioComponents.js.map +1 -1
- package/background/src/lib/virtualized/project/writeSimpleRoot.js +21 -11
- package/background/src/lib/virtualized/project/writeSimpleRoot.js.map +1 -1
- package/codeyam-cli/scripts/apply-setup.js +180 -0
- package/codeyam-cli/scripts/apply-setup.js.map +1 -1
- package/codeyam-cli/src/cli.js +32 -18
- package/codeyam-cli/src/cli.js.map +1 -1
- package/codeyam-cli/src/codeyam-cli.js +18 -2
- package/codeyam-cli/src/codeyam-cli.js.map +1 -1
- package/codeyam-cli/src/commands/analyze.js +4 -2
- package/codeyam-cli/src/commands/analyze.js.map +1 -1
- package/codeyam-cli/src/commands/baseline.js +2 -0
- package/codeyam-cli/src/commands/baseline.js.map +1 -1
- package/codeyam-cli/src/commands/debug.js +9 -5
- package/codeyam-cli/src/commands/debug.js.map +1 -1
- package/codeyam-cli/src/commands/default.js +31 -20
- package/codeyam-cli/src/commands/default.js.map +1 -1
- package/codeyam-cli/src/commands/detect-universal-mocks.js +2 -0
- package/codeyam-cli/src/commands/detect-universal-mocks.js.map +1 -1
- package/codeyam-cli/src/commands/init.js +49 -257
- package/codeyam-cli/src/commands/init.js.map +1 -1
- package/codeyam-cli/src/commands/memory.js +307 -0
- package/codeyam-cli/src/commands/memory.js.map +1 -0
- package/codeyam-cli/src/commands/recapture.js +2 -0
- package/codeyam-cli/src/commands/recapture.js.map +1 -1
- package/codeyam-cli/src/commands/setup-sandbox.js +2 -0
- package/codeyam-cli/src/commands/setup-sandbox.js.map +1 -1
- package/codeyam-cli/src/commands/setup-simulations.js +284 -0
- package/codeyam-cli/src/commands/setup-simulations.js.map +1 -0
- package/codeyam-cli/src/commands/test-startup.js +2 -0
- package/codeyam-cli/src/commands/test-startup.js.map +1 -1
- package/codeyam-cli/src/commands/verify.js +14 -2
- package/codeyam-cli/src/commands/verify.js.map +1 -1
- package/codeyam-cli/src/utils/__tests__/npmVersionCheck.test.js +179 -0
- package/codeyam-cli/src/utils/__tests__/npmVersionCheck.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/setupClaudeCodeSettings.test.js +128 -82
- 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/analyzer.js +7 -0
- package/codeyam-cli/src/utils/analyzer.js.map +1 -1
- package/codeyam-cli/src/utils/backgroundServer.js +90 -19
- package/codeyam-cli/src/utils/backgroundServer.js.map +1 -1
- package/codeyam-cli/src/utils/generateReport.js +2 -2
- package/codeyam-cli/src/utils/install-skills.js +77 -38
- package/codeyam-cli/src/utils/install-skills.js.map +1 -1
- package/codeyam-cli/src/utils/labsAutoCheck.js +19 -0
- package/codeyam-cli/src/utils/labsAutoCheck.js.map +1 -0
- package/codeyam-cli/src/utils/npmVersionCheck.js +76 -0
- package/codeyam-cli/src/utils/npmVersionCheck.js.map +1 -0
- package/codeyam-cli/src/utils/progress.js +7 -0
- package/codeyam-cli/src/utils/progress.js.map +1 -1
- package/codeyam-cli/src/utils/queue/job.js +5 -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/requireSimulations.js +10 -0
- package/codeyam-cli/src/utils/requireSimulations.js.map +1 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/confusionDetector.test.js +82 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/confusionDetector.test.js.map +1 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/contextBuilder.test.js +230 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/contextBuilder.test.js.map +1 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/helpers/assertRules.js +67 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/helpers/assertRules.js.map +1 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/helpers/captureFixture.js +105 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/helpers/captureFixture.js.map +1 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/helpers/loadCapturedFixture.js +34 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/helpers/loadCapturedFixture.js.map +1 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/helpers/runClaude.js +162 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/helpers/runClaude.js.map +1 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/helpers/setupTempProject.js +74 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/helpers/setupTempProject.js.map +1 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/ruleReflectionE2E.test.js +376 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/ruleReflectionE2E.test.js.map +1 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/promptBuilder.test.js +116 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/promptBuilder.test.js.map +1 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/transcriptParser.test.js +127 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/transcriptParser.test.js.map +1 -0
- package/codeyam-cli/src/utils/ruleReflection/confusionDetector.js +50 -0
- package/codeyam-cli/src/utils/ruleReflection/confusionDetector.js.map +1 -0
- package/codeyam-cli/src/utils/ruleReflection/contextBuilder.js +116 -0
- package/codeyam-cli/src/utils/ruleReflection/contextBuilder.js.map +1 -0
- package/codeyam-cli/src/utils/ruleReflection/index.js +5 -0
- package/codeyam-cli/src/utils/ruleReflection/index.js.map +1 -0
- package/codeyam-cli/src/utils/ruleReflection/promptBuilder.js +44 -0
- package/codeyam-cli/src/utils/ruleReflection/promptBuilder.js.map +1 -0
- package/codeyam-cli/src/utils/ruleReflection/transcriptParser.js +85 -0
- package/codeyam-cli/src/utils/ruleReflection/transcriptParser.js.map +1 -0
- package/codeyam-cli/src/utils/ruleReflection/types.js +5 -0
- package/codeyam-cli/src/utils/ruleReflection/types.js.map +1 -0
- package/codeyam-cli/src/utils/rules/__tests__/ruleState.test.js +293 -0
- package/codeyam-cli/src/utils/rules/__tests__/ruleState.test.js.map +1 -0
- package/codeyam-cli/src/utils/rules/index.js +6 -0
- package/codeyam-cli/src/utils/rules/index.js.map +1 -0
- package/codeyam-cli/src/utils/rules/parser.js +83 -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/ruleState.js +150 -0
- package/codeyam-cli/src/utils/rules/ruleState.js.map +1 -0
- package/codeyam-cli/src/utils/rules/staleness.js +137 -0
- package/codeyam-cli/src/utils/rules/staleness.js.map +1 -0
- package/codeyam-cli/src/utils/serverState.js +37 -10
- package/codeyam-cli/src/utils/serverState.js.map +1 -1
- package/codeyam-cli/src/utils/setupClaudeCodeSettings.js +21 -42
- package/codeyam-cli/src/utils/setupClaudeCodeSettings.js.map +1 -1
- package/codeyam-cli/src/utils/simulationGateMiddleware.js +138 -0
- package/codeyam-cli/src/utils/simulationGateMiddleware.js.map +1 -0
- package/codeyam-cli/src/utils/syncMocksMiddleware.js +5 -24
- package/codeyam-cli/src/utils/syncMocksMiddleware.js.map +1 -1
- package/codeyam-cli/src/utils/versionInfo.js +25 -0
- package/codeyam-cli/src/utils/versionInfo.js.map +1 -1
- package/codeyam-cli/src/webserver/__tests__/dependency-smoke.test.js +66 -0
- package/codeyam-cli/src/webserver/__tests__/dependency-smoke.test.js.map +1 -0
- package/codeyam-cli/src/webserver/app/lib/database.js +22 -6
- package/codeyam-cli/src/webserver/app/lib/database.js.map +1 -1
- package/codeyam-cli/src/webserver/app/lib/dbNotifier.js.map +1 -1
- package/codeyam-cli/src/webserver/backgroundServer.js +50 -0
- package/codeyam-cli/src/webserver/backgroundServer.js.map +1 -1
- package/codeyam-cli/src/webserver/bootstrap.js +51 -0
- package/codeyam-cli/src/webserver/bootstrap.js.map +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/CopyButton-jNYXRRNI.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/EntityItem-bwuHPyTa.js +11 -0
- package/codeyam-cli/src/webserver/build/client/assets/{EntityTypeBadge-COi5OvsN.js → EntityTypeBadge-CvzqMxcu.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{EntityTypeIcon-BwdQv49w.js → EntityTypeIcon-BH0XDim7.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{InlineSpinner-CEleMv_j.js → InlineSpinner-EhOseatT.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{InteractivePreview-D68KarMg.js → InteractivePreview-yjIHlOGa.js} +2 -2
- package/codeyam-cli/src/webserver/build/client/assets/{LibraryFunctionPreview-L75Wvqgw.js → LibraryFunctionPreview-Cq5o8jL4.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{LoadingDots-C53WM8qn.js → LoadingDots-BvMu2i-g.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{LogViewer-CrNkmy4i.js → LogViewer-kgBTLoJD.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/ReportIssueModal-BzPgx-xO.js +11 -0
- package/codeyam-cli/src/webserver/build/client/assets/{SafeScreenshot-CQifa1n-.js → SafeScreenshot-CwZrv-Ok.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{ScenarioViewer-CyaBFX7l.js → ScenarioViewer-BX2Ny2Qj.js} +3 -13
- package/codeyam-cli/src/webserver/build/client/assets/{TruncatedFilePath-D36O1rzU.js → TruncatedFilePath-CDpEprKa.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/_index-BRx8ZGZo.js +11 -0
- package/codeyam-cli/src/webserver/build/client/assets/activity.(_tab)-4S4yPfFw.js +27 -0
- package/codeyam-cli/src/webserver/build/client/assets/agent-transcripts-DHKuQSmR.js +17 -0
- package/codeyam-cli/src/webserver/build/client/assets/api.agent-transcripts-l0sNRNKZ.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/api.health-l0sNRNKZ.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/api.labs-unlock-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/api.save-fixture-l0sNRNKZ.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/book-open-D4IPYH_y.js +6 -0
- package/codeyam-cli/src/webserver/build/client/assets/{chevron-down-DgTPh8H-.js → chevron-down-CG65viiV.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{chunk-EPOLDU6W-DdQKK6on.js → chunk-JZWAC4HX-DB3aFuEO.js} +12 -12
- package/codeyam-cli/src/webserver/build/client/assets/{circle-check-Dmr2bb1R.js → circle-check-igfMr5DY.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/copy-Coc4o_8c.js +11 -0
- package/codeyam-cli/src/webserver/build/client/assets/{createLucideIcon-Do4ZLUYa.js → createLucideIcon-D1zB-pYc.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/dev.empty-JTAjQ54M.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/{entity._sha._-CbdFyxZh.js → entity._sha._-B0h9AqE6.js} +12 -12
- package/codeyam-cli/src/webserver/build/client/assets/{entity._sha.scenarios._scenarioId.fullscreen-B4iCfs5M.js → entity._sha.scenarios._scenarioId.fullscreen-DjLxr2JB.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{entity._sha_.create-scenario-wDWZZO1W.js → entity._sha_.create-scenario-CtYowLOt.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{entity._sha_.edit._scenarioId-BMbl7MeQ.js → entity._sha_.edit._scenarioId-PePWg17F.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{entry.client-5wRKRIH9.js → entry.client-I-Wo99C_.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{fileTableUtils-DD3SDH7t.js → fileTableUtils-9sMMAiWJ.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/files-Co65J0s3.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/{git-zXjT7J0G.js → git-BdHOxVfg.js} +8 -8
- package/codeyam-cli/src/webserver/build/client/assets/globals-BSZfYCkU.css +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/{index-DLbXwndH.js → index-CUM5iXwc.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{index-gPZ-lad1.js → index-_417gcQW.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/labs-BK0C1H1T.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/{loader-circle-BsPXJ81F.js → loader-circle-TzRHMVog.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/manifest-040dab1c.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/memory-UIDVz141.js +92 -0
- package/codeyam-cli/src/webserver/build/client/assets/pause-hjzB7t2z.js +11 -0
- package/codeyam-cli/src/webserver/build/client/assets/root-D1WadSdf.js +62 -0
- package/codeyam-cli/src/webserver/build/client/assets/{search-P2FKIUql.js → search-DcAwD_Ln.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/settings-CclxrcPK.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/{simulations-L18M6-kN.js → simulations-DVNJVQgD.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/terminal-DbEAHMbA.js +11 -0
- package/codeyam-cli/src/webserver/build/client/assets/{triangle-alert-BDz7kbVA.js → triangle-alert-CAD5b1o_.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{useCustomSizes-29dDmbH8.js → useCustomSizes-BqgrAzs3.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{useLastLogLine-BUm0UVJm.js → useLastLogLine-DAFqfEDH.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{useReportContext-CkIOKTrZ.js → useReportContext-DZlYx2c4.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{useToast-KKw5kTn-.js → useToast-ihdMtlf6.js} +1 -1
- package/codeyam-cli/src/webserver/build/server/assets/index-B3dE0r28.js +1 -0
- package/codeyam-cli/src/webserver/build/server/assets/server-build-DYbfdxa3.js +273 -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:debug.md → codeyam-debug.md} +48 -4
- package/codeyam-cli/templates/codeyam-diagnose.md +481 -0
- package/codeyam-cli/templates/codeyam-memory-hook.sh +199 -0
- package/codeyam-cli/templates/codeyam-memory.md +396 -0
- package/codeyam-cli/templates/codeyam-new-rule.md +13 -0
- package/codeyam-cli/templates/{codeyam:setup.md → codeyam-setup.md} +13 -1
- package/codeyam-cli/templates/{codeyam:sim.md → codeyam-sim.md} +1 -1
- package/codeyam-cli/templates/{codeyam:test.md → codeyam-test.md} +1 -1
- package/codeyam-cli/templates/{codeyam:verify.md → codeyam-verify.md} +1 -1
- package/codeyam-cli/templates/rule-notification-hook.py +56 -0
- package/codeyam-cli/templates/rule-reflection-hook.py +627 -0
- package/codeyam-cli/templates/rules-instructions.md +132 -0
- package/package.json +18 -15
- package/packages/ai/index.js +7 -3
- package/packages/ai/index.js.map +1 -1
- package/packages/ai/src/lib/analyzeScope.js +91 -30
- 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/forInStatementHandler.js +10 -14
- package/packages/ai/src/lib/astScopes/patterns/forInStatementHandler.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 +518 -28
- package/packages/ai/src/lib/astScopes/processExpression.js.map +1 -1
- package/packages/ai/src/lib/astScopes/sharedPatterns.js +25 -0
- package/packages/ai/src/lib/astScopes/sharedPatterns.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 +1061 -174
- package/packages/ai/src/lib/dataStructure/ScopeDataStructure.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/JavascriptFrameworkManager.js +5 -1
- package/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/JavascriptFrameworkManager.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 +52 -3
- package/packages/ai/src/lib/dataStructure/helpers/cleanKnownObjectFunctions.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/helpers/cleanNonObjectFunctions.js +106 -13
- package/packages/ai/src/lib/dataStructure/helpers/cleanNonObjectFunctions.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/helpers/coerceObjectsToPrimitivesBySchema.js +63 -0
- package/packages/ai/src/lib/dataStructure/helpers/coerceObjectsToPrimitivesBySchema.js.map +1 -0
- package/packages/ai/src/lib/dataStructure/helpers/convertDotNotation.js +122 -12
- package/packages/ai/src/lib/dataStructure/helpers/convertDotNotation.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/helpers/convertTypeAnnotationsToValues.js +173 -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 +333 -86
- 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 +130 -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/generateEntityDataStructure.js +46 -2
- package/packages/ai/src/lib/generateEntityDataStructure.js.map +1 -1
- package/packages/ai/src/lib/generateEntityScenarioData.js +734 -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 +376 -4
- package/packages/ai/src/lib/generateExecutionFlows.js.map +1 -1
- package/packages/ai/src/lib/generateExecutionFlowsFromConditionals.js +1124 -59
- 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/isolateScopes.js +39 -3
- package/packages/ai/src/lib/isolateScopes.js.map +1 -1
- package/packages/ai/src/lib/mergeJsonTypeDefinitions.js +5 -0
- package/packages/ai/src/lib/mergeJsonTypeDefinitions.js.map +1 -1
- 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/collapseNullableObjects.js +97 -0
- package/packages/ai/src/lib/promptGenerators/collapseNullableObjects.js.map +1 -0
- 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 +30 -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/index.js +1 -0
- package/packages/analyze/index.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/nodes/getNodeType.js +1 -0
- package/packages/analyze/src/lib/asts/nodes/getNodeType.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 +72 -10
- package/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.js.map +1 -1
- package/packages/analyze/src/lib/files/analyze/analyzeEntities.js +17 -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/TransformationTracer.js +880 -0
- package/packages/analyze/src/lib/files/scenarios/TransformationTracer.js.map +1 -0
- package/packages/analyze/src/lib/files/scenarios/enrichArrayTypesFromChildSignatures.js +164 -68
- package/packages/analyze/src/lib/files/scenarios/enrichArrayTypesFromChildSignatures.js.map +1 -1
- package/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.js +75 -21
- package/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.js.map +1 -1
- package/packages/analyze/src/lib/files/scenarios/generateDataStructure.js +185 -20
- 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 +542 -53
- 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/index.js +1 -0
- package/packages/analyze/src/lib/index.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/analysisBranchToDb.js +1 -1
- package/packages/database/src/lib/analysisBranchToDb.js.map +1 -1
- package/packages/database/src/lib/analysisToDb.js +1 -1
- package/packages/database/src/lib/analysisToDb.js.map +1 -1
- package/packages/database/src/lib/branchToDb.js +1 -1
- package/packages/database/src/lib/branchToDb.js.map +1 -1
- package/packages/database/src/lib/commitBranchToDb.js +1 -1
- package/packages/database/src/lib/commitBranchToDb.js.map +1 -1
- package/packages/database/src/lib/commitToDb.js +1 -1
- package/packages/database/src/lib/commitToDb.js.map +1 -1
- package/packages/database/src/lib/fileToDb.js +1 -1
- package/packages/database/src/lib/fileToDb.js.map +1 -1
- package/packages/database/src/lib/kysely/db.js +11 -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/kysely/tables/labsRequestsTable.js +35 -0
- package/packages/database/src/lib/kysely/tables/labsRequestsTable.js.map +1 -0
- 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/projectToDb.js +1 -1
- package/packages/database/src/lib/projectToDb.js.map +1 -1
- package/packages/database/src/lib/saveFiles.js +1 -1
- package/packages/database/src/lib/saveFiles.js.map +1 -1
- package/packages/database/src/lib/scenarioToDb.js +1 -1
- package/packages/database/src/lib/scenarioToDb.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/fs/rsyncCopy.js +93 -2
- package/packages/utils/src/lib/fs/rsyncCopy.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 +8 -76
- 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/client/assets/settings-B2eDuBj8.js +0 -1
- 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
- package/codeyam-cli/templates/codeyam:diagnose.md +0 -625
|
@@ -12,6 +12,78 @@
|
|
|
12
12
|
* - compound conditionals → one flow with all conditions (only if ALL paths controllable)
|
|
13
13
|
*/
|
|
14
14
|
import resolvePathToControllable from "./resolvePathToControllable.js";
|
|
15
|
+
import cleanPathOfNonTransformingFunctions from "./dataStructure/helpers/cleanPathOfNonTransformingFunctions.js";
|
|
16
|
+
/**
|
|
17
|
+
* Recursively expands a derived variable to its leaf data sources.
|
|
18
|
+
*
|
|
19
|
+
* For OR expressions like `isAnalyzing = a || b || c`:
|
|
20
|
+
* - Returns all source paths [a, b, c] so they can all be set appropriately
|
|
21
|
+
*
|
|
22
|
+
* For nested derivations like `isAnalyzing = isInCurrentRun || isInQueue`:
|
|
23
|
+
* - Where `isInCurrentRun` is derived from `currentRun.entityShas.includes(x)`
|
|
24
|
+
* - Returns the final data sources: [currentRun.entityShas, queueState.jobs]
|
|
25
|
+
*
|
|
26
|
+
* @param path The variable path to expand
|
|
27
|
+
* @param conditionalUsages All conditional usages (to look up derivedFrom info)
|
|
28
|
+
* @param attributesMap Map of controllable paths
|
|
29
|
+
* @param equivalentSignatureVariables Variable-to-path mappings
|
|
30
|
+
* @param fullToShortPathMap Full-to-short path mappings
|
|
31
|
+
* @param visited Set of already-visited paths (prevents infinite recursion)
|
|
32
|
+
* @param derivedVariables Optional map of all derived variables (for intermediate tracing)
|
|
33
|
+
* @returns Array of resolved source paths that are controllable
|
|
34
|
+
*/
|
|
35
|
+
function expandDerivedVariableToSources(path, conditionalUsages, attributesMap, equivalentSignatureVariables, fullToShortPathMap, visited = new Set(), derivedVariables) {
|
|
36
|
+
// Prevent infinite recursion
|
|
37
|
+
if (visited.has(path)) {
|
|
38
|
+
return [];
|
|
39
|
+
}
|
|
40
|
+
visited.add(path);
|
|
41
|
+
// First, check if this path is directly controllable
|
|
42
|
+
const directResolution = resolvePathToControllable(path, attributesMap, equivalentSignatureVariables, fullToShortPathMap);
|
|
43
|
+
if (directResolution.isControllable && directResolution.resolvedPath) {
|
|
44
|
+
return [{ path: directResolution.resolvedPath }];
|
|
45
|
+
}
|
|
46
|
+
// Look up derivedFrom info for this path
|
|
47
|
+
// First check conditionalUsages, then fall back to derivedVariables
|
|
48
|
+
const usage = conditionalUsages[path]?.[0];
|
|
49
|
+
let derivedFrom = usage?.derivedFrom;
|
|
50
|
+
// CRITICAL: If not found in conditionalUsages, check derivedVariables
|
|
51
|
+
// This handles intermediate derived variables like `isInCurrentRun` that aren't
|
|
52
|
+
// directly used in conditionals but ARE derived from data sources
|
|
53
|
+
if (!derivedFrom && derivedVariables?.[path]) {
|
|
54
|
+
derivedFrom = derivedVariables[path];
|
|
55
|
+
}
|
|
56
|
+
if (!derivedFrom) {
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
59
|
+
const { operation, sourcePath, sourcePaths } = derivedFrom;
|
|
60
|
+
// For OR/AND operations, recursively expand all source paths
|
|
61
|
+
if ((operation === 'or' || operation === 'and') && sourcePaths) {
|
|
62
|
+
const allSources = [];
|
|
63
|
+
for (const sp of sourcePaths) {
|
|
64
|
+
const expanded = expandDerivedVariableToSources(sp, conditionalUsages, attributesMap, equivalentSignatureVariables, fullToShortPathMap, visited, derivedVariables);
|
|
65
|
+
// Add all expanded sources
|
|
66
|
+
for (const source of expanded) {
|
|
67
|
+
// Avoid duplicates
|
|
68
|
+
if (!allSources.some((s) => s.path === source.path)) {
|
|
69
|
+
allSources.push(source);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return allSources;
|
|
74
|
+
}
|
|
75
|
+
// For single-source operations (arrayIncludes, arraySome, notNull, etc.)
|
|
76
|
+
if (sourcePath) {
|
|
77
|
+
// Try to resolve the source path directly
|
|
78
|
+
const sourceResolution = resolvePathToControllable(sourcePath, attributesMap, equivalentSignatureVariables, fullToShortPathMap);
|
|
79
|
+
if (sourceResolution.isControllable && sourceResolution.resolvedPath) {
|
|
80
|
+
return [{ path: sourceResolution.resolvedPath, operation }];
|
|
81
|
+
}
|
|
82
|
+
// If not directly resolvable, recursively expand
|
|
83
|
+
return expandDerivedVariableToSources(sourcePath, conditionalUsages, attributesMap, equivalentSignatureVariables, fullToShortPathMap, visited, derivedVariables);
|
|
84
|
+
}
|
|
85
|
+
return [];
|
|
86
|
+
}
|
|
15
87
|
/**
|
|
16
88
|
* Clean up sourceDataPath by removing redundant scope prefixes.
|
|
17
89
|
*
|
|
@@ -33,11 +105,13 @@ function cleanSourceDataPath(sourceDataPath) {
|
|
|
33
105
|
// 2. Patterns like functionName(...) - closing paren followed by dot or end
|
|
34
106
|
const emptyFnCalls = (sourceDataPath.match(/\(\)/g) || []).length;
|
|
35
107
|
const fnCallReturnValues = (sourceDataPath.match(/\.functionCallReturnValue/g) || []).length;
|
|
36
|
-
//
|
|
37
|
-
//
|
|
108
|
+
// For chained function calls (e.g., fetch().json()) or paths with non-standard
|
|
109
|
+
// fn call patterns, return the original path so findInAttributesMapForPath can
|
|
110
|
+
// try to look it up in fullToShortPathMap. If it doesn't match, the caller
|
|
111
|
+
// falls through to fallback resolution anyway.
|
|
38
112
|
if (fnCallReturnValues > 1 || emptyFnCalls !== 1) {
|
|
39
|
-
|
|
40
|
-
return
|
|
113
|
+
console.log(`[cleanSourceDataPath] chained/non-standard path (fnCallRVs=${fnCallReturnValues}, emptyFnCalls=${emptyFnCalls}), returning original: "${sourceDataPath}"`);
|
|
114
|
+
return sourceDataPath;
|
|
41
115
|
}
|
|
42
116
|
// Find the "()" which marks the function call
|
|
43
117
|
const fnCallIndex = sourceDataPath.indexOf('()');
|
|
@@ -59,6 +133,112 @@ function cleanSourceDataPath(sourceDataPath) {
|
|
|
59
133
|
}
|
|
60
134
|
return actualPath;
|
|
61
135
|
}
|
|
136
|
+
/**
|
|
137
|
+
* Strip .length suffix from a path if present.
|
|
138
|
+
*
|
|
139
|
+
* When we have a path like "items.length", the controllable attribute is "items"
|
|
140
|
+
* (the array), not "items.length". The length is derived from the array contents.
|
|
141
|
+
*
|
|
142
|
+
* This ensures that execution flows reference the actual controllable attribute
|
|
143
|
+
* rather than the derived .length property.
|
|
144
|
+
*/
|
|
145
|
+
function stripLengthSuffix(path) {
|
|
146
|
+
if (path.endsWith('.length')) {
|
|
147
|
+
return path.slice(0, -7); // Remove ".length" (7 characters)
|
|
148
|
+
}
|
|
149
|
+
return path;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Remove contradictory required values from a compound flow.
|
|
153
|
+
*
|
|
154
|
+
* When a lifecycle boolean (like isLoadingAuditData) is traced to a fetch call's
|
|
155
|
+
* return value, a negated condition (!isLoadingAuditData) produces "falsy" on
|
|
156
|
+
* the fetch path. But if another condition in the same compound requires data
|
|
157
|
+
* from a sub-path of that fetch (e.g., topPaths length > 0), the "falsy" on the
|
|
158
|
+
* parent path contradicts it — a null/falsy response has no .json() to call.
|
|
159
|
+
*
|
|
160
|
+
* This function removes "falsy" required values whose attributePath is a prefix
|
|
161
|
+
* of another required value's attributePath. The child data requirement already
|
|
162
|
+
* implies the parent (fetch) succeeded.
|
|
163
|
+
*/
|
|
164
|
+
function removeContradictoryFalsyValues(requiredValues) {
|
|
165
|
+
return requiredValues.filter((rv) => {
|
|
166
|
+
if (rv.comparison === 'falsy') {
|
|
167
|
+
const hasChildRequirement = requiredValues.some((other) => other !== rv &&
|
|
168
|
+
other.attributePath.startsWith(rv.attributePath + '.'));
|
|
169
|
+
if (hasChildRequirement) {
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return true;
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Generate a human-readable description snippet for a required value,
|
|
178
|
+
* incorporating the comparison type so the LLM understands the intent.
|
|
179
|
+
*/
|
|
180
|
+
function describeRequiredValue(rv) {
|
|
181
|
+
const name = generateNameFromPath(rv.attributePath).toLowerCase();
|
|
182
|
+
switch (rv.comparison) {
|
|
183
|
+
case 'truthy':
|
|
184
|
+
return `${name} is present`;
|
|
185
|
+
case 'falsy':
|
|
186
|
+
return `${name} is absent`;
|
|
187
|
+
case 'length>':
|
|
188
|
+
return rv.value === '0'
|
|
189
|
+
? `${name} has items`
|
|
190
|
+
: `${name} has more than ${rv.value} items`;
|
|
191
|
+
case 'length<':
|
|
192
|
+
return `${name} has fewer than ${rv.value} items`;
|
|
193
|
+
case 'equals':
|
|
194
|
+
return `${name} is ${rv.value}`;
|
|
195
|
+
case 'exists':
|
|
196
|
+
return `${name} exists`;
|
|
197
|
+
case 'not-exists':
|
|
198
|
+
return `${name} does not exist`;
|
|
199
|
+
default:
|
|
200
|
+
return `${name} is ${rv.value}`;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Check whether a resolved path has child entries in the fullToShortPathMap.
|
|
205
|
+
*
|
|
206
|
+
* When a lifecycle boolean (e.g., isLoadingAuditData) resolves to a parent path
|
|
207
|
+
* like fetch(...).functionCallReturnValue, and that path has children (like
|
|
208
|
+
* .json().functionCallReturnValue.topPaths), individual truthy/falsy flows on
|
|
209
|
+
* the parent are misleading. Compound flows with specific child requirements
|
|
210
|
+
* provide better guidance for mock data generation.
|
|
211
|
+
*/
|
|
212
|
+
function hasChildPathsInMap(resolvedPath, fullToShortPathMap) {
|
|
213
|
+
return Object.keys(fullToShortPathMap).some((fullPath) => fullPath.startsWith(resolvedPath + '.') ||
|
|
214
|
+
fullPath.startsWith(resolvedPath + '['));
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Extract the controllable base path from a path that may contain method calls.
|
|
218
|
+
*
|
|
219
|
+
* This handles complex expressions like:
|
|
220
|
+
* - `scenarios.filter((s) => s.active).length` → `scenarios`
|
|
221
|
+
* - `users.some((u) => u.role === 'admin')` → `users`
|
|
222
|
+
* - `items.map(x => x.name).join(', ')` → `items`
|
|
223
|
+
*
|
|
224
|
+
* The controllable base is the path that can be mocked - we can control
|
|
225
|
+
* what `scenarios` contains, but we can't control what `.filter()` returns.
|
|
226
|
+
*
|
|
227
|
+
* @param path - The path that may contain method calls
|
|
228
|
+
* @returns The controllable base path with method calls stripped
|
|
229
|
+
*/
|
|
230
|
+
function extractControllableBase(path) {
|
|
231
|
+
// First strip .length suffix if present
|
|
232
|
+
const pathWithoutLength = stripLengthSuffix(path);
|
|
233
|
+
// Use cleanPathOfNonTransformingFunctions to strip method calls like .filter(), .some()
|
|
234
|
+
const cleanedPath = cleanPathOfNonTransformingFunctions(pathWithoutLength);
|
|
235
|
+
// If the cleaned path is different, return it
|
|
236
|
+
if (cleanedPath !== pathWithoutLength) {
|
|
237
|
+
return cleanedPath;
|
|
238
|
+
}
|
|
239
|
+
// Otherwise, return the path with just .length stripped
|
|
240
|
+
return pathWithoutLength;
|
|
241
|
+
}
|
|
62
242
|
/**
|
|
63
243
|
* Find a path in attributesMap, using fullToShortPathMap to verify the path is controllable.
|
|
64
244
|
*
|
|
@@ -71,9 +251,10 @@ function cleanSourceDataPath(sourceDataPath) {
|
|
|
71
251
|
* The sourceDataPath contains full paths (e.g., "useLoaderData<LoaderData>().functionCallReturnValue.entity.sha")
|
|
72
252
|
* The fullToShortPathMap maps full paths to short paths
|
|
73
253
|
*/
|
|
74
|
-
function findInAttributesMapForPath(path, attributesMap, fullToShortPathMap) {
|
|
254
|
+
export function findInAttributesMapForPath(path, attributesMap, fullToShortPathMap) {
|
|
75
255
|
// Direct match in attributesMap (already a short path)
|
|
76
256
|
if (path in attributesMap) {
|
|
257
|
+
console.log(`[findInAttributesMapForPath] "${path}" → DIRECT match in attributesMap`);
|
|
77
258
|
return path;
|
|
78
259
|
}
|
|
79
260
|
// Try looking up the path in fullToShortPathMap to verify it's controllable
|
|
@@ -81,18 +262,22 @@ function findInAttributesMapForPath(path, attributesMap, fullToShortPathMap) {
|
|
|
81
262
|
if (path in fullToShortPathMap) {
|
|
82
263
|
const shortPath = fullToShortPathMap[path];
|
|
83
264
|
if (shortPath in attributesMap) {
|
|
265
|
+
console.log(`[findInAttributesMapForPath] "${path}" → fullToShortPathMap match: shortPath="${shortPath}" found in attributesMap`);
|
|
84
266
|
return path; // Return FULL path to preserve data source context
|
|
85
267
|
}
|
|
268
|
+
console.log(`[findInAttributesMapForPath] "${path}" → fullToShortPathMap match shortPath="${shortPath}" but NOT in attributesMap`);
|
|
86
269
|
}
|
|
87
270
|
// Normalized match (array indices [N] → [])
|
|
88
271
|
const normalizedPath = path.replace(/\[\d+\]/g, '[]');
|
|
89
272
|
if (normalizedPath !== path) {
|
|
90
273
|
if (normalizedPath in attributesMap) {
|
|
274
|
+
console.log(`[findInAttributesMapForPath] "${path}" → normalized "${normalizedPath}" DIRECT match in attributesMap`);
|
|
91
275
|
return normalizedPath;
|
|
92
276
|
}
|
|
93
277
|
if (normalizedPath in fullToShortPathMap) {
|
|
94
278
|
const shortPath = fullToShortPathMap[normalizedPath];
|
|
95
279
|
if (shortPath in attributesMap) {
|
|
280
|
+
console.log(`[findInAttributesMapForPath] "${path}" → normalized "${normalizedPath}" fullToShortPathMap match: shortPath="${shortPath}"`);
|
|
96
281
|
return normalizedPath; // Return normalized FULL path
|
|
97
282
|
}
|
|
98
283
|
}
|
|
@@ -103,20 +288,70 @@ function findInAttributesMapForPath(path, attributesMap, fullToShortPathMap) {
|
|
|
103
288
|
// and we need to find matching short path prefix
|
|
104
289
|
for (const attrPath of Object.keys(attributesMap)) {
|
|
105
290
|
if (path.startsWith(attrPath + '.') || path.startsWith(attrPath + '[')) {
|
|
106
|
-
|
|
291
|
+
console.log(`[findInAttributesMapForPath] "${path}" → PREFIX match: starts with attributesMap key "${attrPath}"`);
|
|
107
292
|
return path;
|
|
108
293
|
}
|
|
109
294
|
}
|
|
110
295
|
// Try suffix matching: if the path ends with ".X.Y.Z" and attributesMap has "X.Y.Z"
|
|
111
296
|
// Return the FULL input path to preserve data source context
|
|
112
|
-
for
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
297
|
+
// Skip suffix matching for chained function calls (multiple .functionCallReturnValue segments)
|
|
298
|
+
// to avoid false matches: e.g., fetch(...).json().functionCallReturnValue.data falsely matching
|
|
299
|
+
// "data" from a completely different data source like useFetcher
|
|
300
|
+
const fnCallReturnValueCount = (path.match(/\.functionCallReturnValue/g) || []).length;
|
|
301
|
+
if (fnCallReturnValueCount <= 1) {
|
|
302
|
+
for (const attrPath of Object.keys(attributesMap)) {
|
|
303
|
+
if (path.endsWith('.' + attrPath) ||
|
|
304
|
+
path.endsWith('.' + attrPath.replace(/\[\d+\]/g, '[]'))) {
|
|
305
|
+
console.log(`[findInAttributesMapForPath] "${path}" → SUFFIX match: ends with attributesMap key "${attrPath}"`);
|
|
306
|
+
return path; // Return FULL path, not short attrPath
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
// Try child path matching against fullToShortPathMap keys
|
|
311
|
+
// If the path starts with a known full path + '.' or '[', it's a child
|
|
312
|
+
// of a controllable path. Build the equivalent short child path.
|
|
313
|
+
// e.g., path = "fetch(...).fCRV.json().fCRV.topPaths.length"
|
|
314
|
+
// fullToShortPathMap has "fetch(...).fCRV.json().fCRV.topPaths" → "json().fCRV.topPaths"
|
|
315
|
+
// → check if "json().fCRV.topPaths.length" is in attributesMap
|
|
316
|
+
for (const [fullPath, shortPath] of Object.entries(fullToShortPathMap)) {
|
|
317
|
+
if (path.startsWith(fullPath + '.') || path.startsWith(fullPath + '[')) {
|
|
318
|
+
const suffix = path.slice(fullPath.length); // e.g., ".length"
|
|
319
|
+
const shortChildPath = shortPath + suffix;
|
|
320
|
+
if (shortChildPath in attributesMap) {
|
|
321
|
+
console.log(`[findInAttributesMapForPath] "${path}" → CHILD of fullToShortPathMap key "${fullPath}": shortChildPath="${shortChildPath}" found in attributesMap`);
|
|
322
|
+
return path; // Return full path to preserve data source context
|
|
323
|
+
}
|
|
324
|
+
// Also check if the base short path is an array and suffix is .length
|
|
325
|
+
if (suffix === '.length' && shortPath in attributesMap) {
|
|
326
|
+
console.log(`[findInAttributesMapForPath] "${path}" → CHILD .length of fullToShortPathMap key "${fullPath}": base shortPath="${shortPath}" is in attributesMap (array .length)`);
|
|
327
|
+
return path; // Array .length is controllable via the array
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
// Try parent matching: if the path is a prefix of any fullToShortPathMap key,
|
|
332
|
+
// it's a parent of controllable data and therefore controllable itself
|
|
333
|
+
for (const fullPath of Object.keys(fullToShortPathMap)) {
|
|
334
|
+
if (fullPath.startsWith(path + '.') || fullPath.startsWith(path + '[')) {
|
|
335
|
+
console.log(`[findInAttributesMapForPath] "${path}" → PARENT match: fullToShortPathMap key "${fullPath}" starts with this path`);
|
|
336
|
+
return path;
|
|
116
337
|
}
|
|
117
338
|
}
|
|
339
|
+
console.log(`[findInAttributesMapForPath] "${path}" → NO MATCH (checked ${Object.keys(attributesMap).length} attributesMap keys, ${Object.keys(fullToShortPathMap).length} fullToShortPathMap keys)`);
|
|
118
340
|
return null;
|
|
119
341
|
}
|
|
342
|
+
/**
|
|
343
|
+
* Generate a slug from a path for use in flow IDs and exclusive groups.
|
|
344
|
+
*/
|
|
345
|
+
function pathToSlug(path) {
|
|
346
|
+
return path
|
|
347
|
+
.replace(/\[\d+\]/g, '')
|
|
348
|
+
.replace(/\[\]/g, '')
|
|
349
|
+
.replace(/\(\)/g, '')
|
|
350
|
+
.replace(/\.functionCallReturnValue/g, '')
|
|
351
|
+
.replace(/[<>]/g, '')
|
|
352
|
+
.replace(/\./g, '-')
|
|
353
|
+
.toLowerCase();
|
|
354
|
+
}
|
|
120
355
|
/**
|
|
121
356
|
* Generate a human-readable name from a path.
|
|
122
357
|
* Extracts the last meaningful part of the path.
|
|
@@ -173,6 +408,12 @@ function inferValueType(value) {
|
|
|
173
408
|
/**
|
|
174
409
|
* Generate flows from a single conditional usage.
|
|
175
410
|
* Sets impact to 'high' if the conditional controls JSX rendering.
|
|
411
|
+
*
|
|
412
|
+
* When the usage has a `constraintExpression`, it represents a complex expression
|
|
413
|
+
* that can't be simply resolved (e.g., `scenarios.filter(x => x.active).length > 1`).
|
|
414
|
+
* In this case:
|
|
415
|
+
* - `attributePath` is set to the controllable base (e.g., `scenarios`)
|
|
416
|
+
* - `constraint` is set to the full expression for LLM reasoning
|
|
176
417
|
*/
|
|
177
418
|
function generateFlowsFromUsage(usage, resolvedPath) {
|
|
178
419
|
const flows = [];
|
|
@@ -182,6 +423,13 @@ function generateFlowsFromUsage(usage, resolvedPath) {
|
|
|
182
423
|
const impact = usage.controlsJsxRendering
|
|
183
424
|
? 'high'
|
|
184
425
|
: 'medium';
|
|
426
|
+
// When there's a constraintExpression, use the controllable base for attributePath
|
|
427
|
+
// and pass through the constraint for LLM reasoning
|
|
428
|
+
const hasConstraint = !!usage.constraintExpression;
|
|
429
|
+
const attributePath = hasConstraint
|
|
430
|
+
? extractControllableBase(resolvedPath)
|
|
431
|
+
: stripLengthSuffix(resolvedPath);
|
|
432
|
+
const constraint = usage.constraintExpression;
|
|
185
433
|
if (usage.conditionType === 'truthiness') {
|
|
186
434
|
// Generate both truthy and falsy flows
|
|
187
435
|
const isNegated = usage.isNegated ?? false;
|
|
@@ -192,10 +440,11 @@ function generateFlowsFromUsage(usage, resolvedPath) {
|
|
|
192
440
|
description: `When ${baseName.toLowerCase()} is ${isNegated ? 'falsy' : 'truthy'}`,
|
|
193
441
|
requiredValues: [
|
|
194
442
|
{
|
|
195
|
-
attributePath
|
|
443
|
+
attributePath,
|
|
196
444
|
value: isNegated ? 'falsy' : 'truthy',
|
|
197
445
|
comparison: isNegated ? 'falsy' : 'truthy',
|
|
198
446
|
valueType: 'boolean',
|
|
447
|
+
constraint,
|
|
199
448
|
},
|
|
200
449
|
],
|
|
201
450
|
impact,
|
|
@@ -214,10 +463,11 @@ function generateFlowsFromUsage(usage, resolvedPath) {
|
|
|
214
463
|
description: `When ${baseName.toLowerCase()} is ${isNegated ? 'truthy' : 'falsy'}`,
|
|
215
464
|
requiredValues: [
|
|
216
465
|
{
|
|
217
|
-
attributePath
|
|
466
|
+
attributePath,
|
|
218
467
|
value: isNegated ? 'truthy' : 'falsy',
|
|
219
468
|
comparison: isNegated ? 'truthy' : 'falsy',
|
|
220
469
|
valueType: 'boolean',
|
|
470
|
+
constraint,
|
|
221
471
|
},
|
|
222
472
|
],
|
|
223
473
|
impact,
|
|
@@ -241,10 +491,11 @@ function generateFlowsFromUsage(usage, resolvedPath) {
|
|
|
241
491
|
description: `When ${baseName.toLowerCase()} equals "${value}"`,
|
|
242
492
|
requiredValues: [
|
|
243
493
|
{
|
|
244
|
-
attributePath
|
|
494
|
+
attributePath,
|
|
245
495
|
value: value,
|
|
246
496
|
comparison: 'equals',
|
|
247
497
|
valueType: inferValueType(value),
|
|
498
|
+
constraint,
|
|
248
499
|
},
|
|
249
500
|
],
|
|
250
501
|
impact,
|
|
@@ -290,29 +541,47 @@ function generateFlowFromCompound(compound, resolvedPaths) {
|
|
|
290
541
|
condition.requiredValue?.toString() ??
|
|
291
542
|
condition.comparedValues?.[0] ??
|
|
292
543
|
'truthy';
|
|
293
|
-
comparison
|
|
544
|
+
// Map comparison operator to flow comparison type
|
|
545
|
+
const op = condition.comparisonOperator;
|
|
546
|
+
if (op === '>' || op === '>=') {
|
|
547
|
+
comparison = 'length>';
|
|
548
|
+
}
|
|
549
|
+
else if (op === '<' || op === '<=') {
|
|
550
|
+
comparison = 'length<';
|
|
551
|
+
}
|
|
552
|
+
else {
|
|
553
|
+
comparison = 'equals';
|
|
554
|
+
}
|
|
294
555
|
}
|
|
295
556
|
requiredValues.push({
|
|
296
|
-
attributePath: resolvedPath,
|
|
557
|
+
attributePath: stripLengthSuffix(resolvedPath),
|
|
297
558
|
value,
|
|
298
559
|
comparison,
|
|
299
560
|
valueType: inferValueType(value),
|
|
300
561
|
});
|
|
301
562
|
}
|
|
302
|
-
//
|
|
303
|
-
const
|
|
563
|
+
// Remove contradictory "falsy" values where a child path requires data
|
|
564
|
+
const cleanedValues = removeContradictoryFalsyValues(requiredValues);
|
|
565
|
+
if (cleanedValues.length === 0) {
|
|
566
|
+
return null;
|
|
567
|
+
}
|
|
568
|
+
// Generate a combined ID from all paths + values to distinguish different comparisons
|
|
569
|
+
const pathParts = cleanedValues
|
|
304
570
|
.map((rv) => {
|
|
305
571
|
const name = generateNameFromPath(rv.attributePath);
|
|
306
|
-
|
|
572
|
+
const suffix = rv.comparison === 'truthy' || rv.comparison === 'falsy'
|
|
573
|
+
? `-${rv.comparison}`
|
|
574
|
+
: `-${rv.comparison}-${rv.value}`;
|
|
575
|
+
return name.toLowerCase().replace(/\s+/g, '-') + suffix;
|
|
307
576
|
})
|
|
308
577
|
.join('-and-');
|
|
309
578
|
return {
|
|
310
579
|
id: `compound-${pathParts}`,
|
|
311
|
-
name:
|
|
580
|
+
name: cleanedValues
|
|
312
581
|
.map((rv) => generateNameFromPath(rv.attributePath))
|
|
313
582
|
.join(' + '),
|
|
314
|
-
description: `When ${
|
|
315
|
-
requiredValues,
|
|
583
|
+
description: `When ${cleanedValues.map((rv) => describeRequiredValue(rv)).join(' and ')}`,
|
|
584
|
+
requiredValues: cleanedValues,
|
|
316
585
|
impact,
|
|
317
586
|
sourceLocation: {
|
|
318
587
|
lineNumber: compound.sourceLocation.lineNumber,
|
|
@@ -321,6 +590,48 @@ function generateFlowFromCompound(compound, resolvedPaths) {
|
|
|
321
590
|
codeSnippet: compound.sourceLocation.codeSnippet,
|
|
322
591
|
};
|
|
323
592
|
}
|
|
593
|
+
/**
|
|
594
|
+
* Expand a compound conditional with OR groups into multiple condition sets.
|
|
595
|
+
*
|
|
596
|
+
* For a compound like `A && (B || C)`:
|
|
597
|
+
* - Conditions: [{ path: 'A' }, { path: 'B', orGroupId: 'or_xxx' }, { path: 'C', orGroupId: 'or_xxx' }]
|
|
598
|
+
* - Returns: [[A, B], [A, C]] - two sets of conditions
|
|
599
|
+
*
|
|
600
|
+
* For multiple OR groups like `A && (B || C) && (D || E)`:
|
|
601
|
+
* - Returns: [[A, B, D], [A, B, E], [A, C, D], [A, C, E]]
|
|
602
|
+
*/
|
|
603
|
+
function expandOrGroups(conditions) {
|
|
604
|
+
// Separate conditions into mandatory (no orGroupId) and OR groups
|
|
605
|
+
const mandatory = conditions.filter((c) => !c.orGroupId);
|
|
606
|
+
const orGroups = new Map();
|
|
607
|
+
for (const condition of conditions) {
|
|
608
|
+
if (condition.orGroupId) {
|
|
609
|
+
const group = orGroups.get(condition.orGroupId) ?? [];
|
|
610
|
+
group.push(condition);
|
|
611
|
+
orGroups.set(condition.orGroupId, group);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
// If no OR groups, return the original conditions
|
|
615
|
+
if (orGroups.size === 0) {
|
|
616
|
+
return [conditions];
|
|
617
|
+
}
|
|
618
|
+
// Generate all combinations by picking one condition from each OR group
|
|
619
|
+
const groupArrays = Array.from(orGroups.values());
|
|
620
|
+
const combinations = [];
|
|
621
|
+
function generateCombinations(index, current) {
|
|
622
|
+
if (index === groupArrays.length) {
|
|
623
|
+
// We've picked one from each OR group - combine with mandatory conditions
|
|
624
|
+
combinations.push([...mandatory, ...current]);
|
|
625
|
+
return;
|
|
626
|
+
}
|
|
627
|
+
// Pick each option from the current OR group
|
|
628
|
+
for (const option of groupArrays[index]) {
|
|
629
|
+
generateCombinations(index + 1, [...current, option]);
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
generateCombinations(0, []);
|
|
633
|
+
return combinations;
|
|
634
|
+
}
|
|
324
635
|
/**
|
|
325
636
|
* Generate execution flows from conditional usages using pure static analysis.
|
|
326
637
|
*
|
|
@@ -386,7 +697,11 @@ function translateChildPathToParent(childPath, childEquivalentSignatureVariables
|
|
|
386
697
|
}
|
|
387
698
|
// Look up the child's equivalence for this root variable
|
|
388
699
|
// e.g., childEquiv[selectedScenario] = "signature[0].selectedScenario"
|
|
389
|
-
|
|
700
|
+
// Handle array case (OR expressions) - use first element if array
|
|
701
|
+
const rawChildPropPath = childEquivalentSignatureVariables[rootVar];
|
|
702
|
+
const childPropPath = Array.isArray(rawChildPropPath)
|
|
703
|
+
? rawChildPropPath[0]
|
|
704
|
+
: rawChildPropPath;
|
|
390
705
|
if (!childPropPath) {
|
|
391
706
|
// No mapping found - this might be internal state, not a prop
|
|
392
707
|
return null;
|
|
@@ -396,7 +711,11 @@ function translateChildPathToParent(childPath, childEquivalentSignatureVariables
|
|
|
396
711
|
const fullChildPropPath = `${childName}().${childPropPath}`;
|
|
397
712
|
// Look up parent's equivalence to find what value was passed to this prop
|
|
398
713
|
// e.g., parentEquiv["ChildName().signature[0].selectedScenario"] = "selectedScenario"
|
|
399
|
-
|
|
714
|
+
// Handle array case (OR expressions) - use first element if array
|
|
715
|
+
const rawParentValue = parentEquivalentSignatureVariables[fullChildPropPath];
|
|
716
|
+
const parentValue = Array.isArray(rawParentValue)
|
|
717
|
+
? rawParentValue[0]
|
|
718
|
+
: rawParentValue;
|
|
400
719
|
if (!parentValue) {
|
|
401
720
|
// No parent mapping found - log ALL parent keys that contain the childName
|
|
402
721
|
const relevantParentKeys = Object.keys(parentEquivalentSignatureVariables).filter((k) => k.includes(childName));
|
|
@@ -408,9 +727,14 @@ function translateChildPathToParent(childPath, childEquivalentSignatureVariables
|
|
|
408
727
|
return result;
|
|
409
728
|
}
|
|
410
729
|
export default function generateExecutionFlowsFromConditionals(args) {
|
|
411
|
-
const { conditionalUsages, compoundConditionals, attributesMap, equivalentSignatureVariables, fullToShortPathMap, childComponentData, } = args;
|
|
730
|
+
const { conditionalUsages, compoundConditionals, attributesMap, equivalentSignatureVariables, fullToShortPathMap, childComponentData, derivedVariables, sourceEquivalencies, } = args;
|
|
412
731
|
const flows = [];
|
|
413
732
|
const seenFlowIds = new Set();
|
|
733
|
+
console.log(`[genFlowsFromConditionals] INPUT: ${Object.keys(conditionalUsages).length} conditional paths, ${Object.keys(attributesMap).length} attributesMap entries, ${Object.keys(fullToShortPathMap).length} fullToShortPathMap entries, ${Object.keys(equivalentSignatureVariables).length} equivSigVars, ${compoundConditionals.length} compound conditionals`);
|
|
734
|
+
console.log(`[genFlowsFromConditionals] conditionalUsages keys: [${Object.keys(conditionalUsages).join(', ')}]`);
|
|
735
|
+
console.log(`[genFlowsFromConditionals] attributesMap keys: [${Object.keys(attributesMap).join(', ')}]`);
|
|
736
|
+
console.log(`[genFlowsFromConditionals] fullToShortPathMap: ${JSON.stringify(fullToShortPathMap)}`);
|
|
737
|
+
console.log(`[genFlowsFromConditionals] equivalentSignatureVariables: ${JSON.stringify(equivalentSignatureVariables)}`);
|
|
414
738
|
// Track normalized resolved paths to prevent duplicate flows
|
|
415
739
|
// This handles the case where we have usages for both:
|
|
416
740
|
// - "hasNewerVersion" (short path from destructured variable)
|
|
@@ -424,8 +748,10 @@ export default function generateExecutionFlowsFromConditionals(args) {
|
|
|
424
748
|
for (const usage of usages) {
|
|
425
749
|
// Skip usages that are part of compound conditionals (handled separately)
|
|
426
750
|
if (usage.chainId && compoundChainIds.has(usage.chainId)) {
|
|
751
|
+
console.log(`[genFlowsFromConditionals] "${usage.path}" SKIP: part of compound conditional chain=${usage.chainId}`);
|
|
427
752
|
continue;
|
|
428
753
|
}
|
|
754
|
+
console.log(`[genFlowsFromConditionals] --- Processing "${usage.path}" (type=${usage.conditionType}, negated=${usage.isNegated}, sourceDataPath="${usage.sourceDataPath ?? '(none)'}", derivedFrom=${usage.derivedFrom ? JSON.stringify(usage.derivedFrom) : 'none'})`);
|
|
429
755
|
// First, try to use pre-computed sourceDataPath if available
|
|
430
756
|
let resolvedPath = null;
|
|
431
757
|
if (usage.sourceDataPath) {
|
|
@@ -434,9 +760,11 @@ export default function generateExecutionFlowsFromConditionals(args) {
|
|
|
434
760
|
// should become "useLoaderData<LoaderData>().functionCallReturnValue.entity.sha"
|
|
435
761
|
// Returns null for malformed paths (e.g., chained function calls like fetch().json())
|
|
436
762
|
const cleanedPath = cleanSourceDataPath(usage.sourceDataPath);
|
|
763
|
+
console.log(`[genFlowsFromConditionals] "${usage.path}" cleanSourceDataPath("${usage.sourceDataPath}") → "${cleanedPath}"`);
|
|
437
764
|
if (cleanedPath) {
|
|
438
765
|
// Verify the cleaned path exists in attributesMap
|
|
439
766
|
const pathMatch = findInAttributesMapForPath(cleanedPath, attributesMap, fullToShortPathMap);
|
|
767
|
+
console.log(`[genFlowsFromConditionals] "${usage.path}" findInAttributesMapForPath("${cleanedPath}") → ${pathMatch ? `"${pathMatch}"` : 'null (not found)'}`);
|
|
440
768
|
if (pathMatch) {
|
|
441
769
|
resolvedPath = pathMatch;
|
|
442
770
|
}
|
|
@@ -445,7 +773,9 @@ export default function generateExecutionFlowsFromConditionals(args) {
|
|
|
445
773
|
}
|
|
446
774
|
// Fall back to resolution via equivalentSignatureVariables
|
|
447
775
|
if (!resolvedPath) {
|
|
776
|
+
console.log(`[genFlowsFromConditionals] "${usage.path}" sourceDataPath resolution failed, trying resolvePathToControllable("${usage.path}")...`);
|
|
448
777
|
const resolution = resolvePathToControllable(usage.path, attributesMap, equivalentSignatureVariables, fullToShortPathMap);
|
|
778
|
+
console.log(`[genFlowsFromConditionals] "${usage.path}" resolvePathToControllable → isControllable=${resolution.isControllable}, resolvedPath="${resolution.resolvedPath ?? '(none)'}"`);
|
|
449
779
|
if (resolution.isControllable && resolution.resolvedPath) {
|
|
450
780
|
resolvedPath = resolution.resolvedPath;
|
|
451
781
|
}
|
|
@@ -454,7 +784,8 @@ export default function generateExecutionFlowsFromConditionals(args) {
|
|
|
454
784
|
// This handles cases like: const hasAnalysis = analysis !== null
|
|
455
785
|
// where hasAnalysis is not in attributesMap but analysis is
|
|
456
786
|
if (!resolvedPath && usage.derivedFrom) {
|
|
457
|
-
const { sourcePath, sourcePaths } = usage.derivedFrom;
|
|
787
|
+
const { operation, sourcePath, sourcePaths, comparedValue } = usage.derivedFrom;
|
|
788
|
+
console.log(`[genFlowsFromConditionals] "${usage.path}" trying derivedFrom: operation=${operation}, sourcePath="${sourcePath ?? '(none)'}", sourcePaths=${sourcePaths ? JSON.stringify(sourcePaths) : '(none)'}, comparedValue="${comparedValue ?? '(none)'}"`);
|
|
458
789
|
// For single-source derivations (notNull, equals, etc.)
|
|
459
790
|
if (sourcePath) {
|
|
460
791
|
const resolution = resolvePathToControllable(sourcePath, attributesMap, equivalentSignatureVariables, fullToShortPathMap);
|
|
@@ -462,8 +793,232 @@ export default function generateExecutionFlowsFromConditionals(args) {
|
|
|
462
793
|
resolvedPath = resolution.resolvedPath;
|
|
463
794
|
}
|
|
464
795
|
}
|
|
465
|
-
// For
|
|
466
|
-
//
|
|
796
|
+
// For equals/notEquals derivations with comparedValue, generate comparison flows
|
|
797
|
+
// e.g., canEdit derived from user.role === 'admin'
|
|
798
|
+
// When canEdit is used in truthiness check, we need:
|
|
799
|
+
// - Truthy flow: user.role = 'admin' (comparison: 'equals')
|
|
800
|
+
// - Falsy flow: user.role != 'admin' (comparison: 'notEquals')
|
|
801
|
+
if ((operation === 'equals' || operation === 'notEquals') &&
|
|
802
|
+
comparedValue !== undefined &&
|
|
803
|
+
resolvedPath &&
|
|
804
|
+
usage.conditionType === 'truthiness') {
|
|
805
|
+
const baseName = generateNameFromPath(usage.path);
|
|
806
|
+
const impact = usage.controlsJsxRendering
|
|
807
|
+
? 'high'
|
|
808
|
+
: 'medium';
|
|
809
|
+
const isNegated = usage.isNegated ?? false;
|
|
810
|
+
// For equals derivation:
|
|
811
|
+
// - Truthy check (!negated): needs value = comparedValue (equals)
|
|
812
|
+
// - Falsy check (negated): needs value != comparedValue (notEquals)
|
|
813
|
+
// For notEquals derivation: inverse of above
|
|
814
|
+
const isEqualsDerivation = operation === 'equals';
|
|
815
|
+
const truthyNeedsEquals = isEqualsDerivation !== isNegated;
|
|
816
|
+
// Generate truthy flow
|
|
817
|
+
const truthyFlow = {
|
|
818
|
+
id: generateFlowId(usage.path, 'truthy'),
|
|
819
|
+
name: `${baseName} True`,
|
|
820
|
+
description: `When ${baseName.toLowerCase()} is truthy (${resolvedPath} ${truthyNeedsEquals ? '=' : '!='} ${comparedValue})`,
|
|
821
|
+
requiredValues: [
|
|
822
|
+
{
|
|
823
|
+
attributePath: stripLengthSuffix(resolvedPath),
|
|
824
|
+
value: comparedValue,
|
|
825
|
+
comparison: truthyNeedsEquals ? 'equals' : 'notEquals',
|
|
826
|
+
valueType: inferValueType(comparedValue),
|
|
827
|
+
},
|
|
828
|
+
],
|
|
829
|
+
impact,
|
|
830
|
+
sourceLocation: usage.sourceLocation
|
|
831
|
+
? {
|
|
832
|
+
lineNumber: usage.sourceLocation.lineNumber,
|
|
833
|
+
column: usage.sourceLocation.column,
|
|
834
|
+
}
|
|
835
|
+
: undefined,
|
|
836
|
+
codeSnippet: usage.sourceLocation?.codeSnippet,
|
|
837
|
+
};
|
|
838
|
+
// Generate falsy flow
|
|
839
|
+
const falsyFlow = {
|
|
840
|
+
id: generateFlowId(usage.path, 'falsy'),
|
|
841
|
+
name: `${baseName} False`,
|
|
842
|
+
description: `When ${baseName.toLowerCase()} is falsy (${resolvedPath} ${truthyNeedsEquals ? '!=' : '='} ${comparedValue})`,
|
|
843
|
+
requiredValues: [
|
|
844
|
+
{
|
|
845
|
+
attributePath: stripLengthSuffix(resolvedPath),
|
|
846
|
+
value: comparedValue,
|
|
847
|
+
comparison: truthyNeedsEquals ? 'notEquals' : 'equals',
|
|
848
|
+
valueType: inferValueType(comparedValue),
|
|
849
|
+
},
|
|
850
|
+
],
|
|
851
|
+
impact,
|
|
852
|
+
sourceLocation: usage.sourceLocation
|
|
853
|
+
? {
|
|
854
|
+
lineNumber: usage.sourceLocation.lineNumber,
|
|
855
|
+
column: usage.sourceLocation.column,
|
|
856
|
+
}
|
|
857
|
+
: undefined,
|
|
858
|
+
codeSnippet: usage.sourceLocation?.codeSnippet,
|
|
859
|
+
};
|
|
860
|
+
// Add flows and skip normal flow generation
|
|
861
|
+
if (!seenFlowIds.has(truthyFlow.id)) {
|
|
862
|
+
seenFlowIds.add(truthyFlow.id);
|
|
863
|
+
flows.push(truthyFlow);
|
|
864
|
+
}
|
|
865
|
+
if (!seenFlowIds.has(falsyFlow.id)) {
|
|
866
|
+
seenFlowIds.add(falsyFlow.id);
|
|
867
|
+
flows.push(falsyFlow);
|
|
868
|
+
}
|
|
869
|
+
continue;
|
|
870
|
+
}
|
|
871
|
+
// For OR derivations with negation, we need ALL sources to be falsy
|
|
872
|
+
// e.g., !isBusy where isBusy = isRunning || isQueued || isPending
|
|
873
|
+
// For the falsy flow, ALL sources must be falsy
|
|
874
|
+
if (operation === 'or' &&
|
|
875
|
+
usage.conditionType === 'truthiness' &&
|
|
876
|
+
usage.isNegated === true &&
|
|
877
|
+
sourcePaths &&
|
|
878
|
+
sourcePaths.length > 0) {
|
|
879
|
+
// Use expandDerivedVariableToSources to recursively resolve all sources
|
|
880
|
+
const allSources = expandDerivedVariableToSources(usage.path, conditionalUsages, attributesMap, equivalentSignatureVariables, fullToShortPathMap, new Set(), derivedVariables);
|
|
881
|
+
if (allSources.length > 0) {
|
|
882
|
+
// Generate a compound-style flow with all sources set to falsy
|
|
883
|
+
const baseName = generateNameFromPath(usage.path);
|
|
884
|
+
const impact = usage.controlsJsxRendering
|
|
885
|
+
? 'high'
|
|
886
|
+
: 'medium';
|
|
887
|
+
const requiredValues = allSources.map((source) => ({
|
|
888
|
+
attributePath: source.path,
|
|
889
|
+
value: 'falsy',
|
|
890
|
+
comparison: 'falsy',
|
|
891
|
+
valueType: 'boolean',
|
|
892
|
+
}));
|
|
893
|
+
// Create a single falsy flow with all sources
|
|
894
|
+
const falsyFlow = {
|
|
895
|
+
id: generateFlowId(usage.path, 'falsy'),
|
|
896
|
+
name: `${baseName} False`,
|
|
897
|
+
description: `When ${baseName.toLowerCase()} is falsy (all sources are falsy)`,
|
|
898
|
+
requiredValues,
|
|
899
|
+
impact,
|
|
900
|
+
sourceLocation: usage.sourceLocation
|
|
901
|
+
? {
|
|
902
|
+
lineNumber: usage.sourceLocation.lineNumber,
|
|
903
|
+
column: usage.sourceLocation.column,
|
|
904
|
+
}
|
|
905
|
+
: undefined,
|
|
906
|
+
codeSnippet: usage.sourceLocation?.codeSnippet,
|
|
907
|
+
};
|
|
908
|
+
// Create a truthy flow - for OR, ANY source being truthy is sufficient
|
|
909
|
+
// We use the first resolvable source for the truthy flow
|
|
910
|
+
const firstSource = allSources[0];
|
|
911
|
+
const truthyFlow = {
|
|
912
|
+
id: generateFlowId(usage.path, 'truthy'),
|
|
913
|
+
name: `${baseName} True`,
|
|
914
|
+
description: `When ${baseName.toLowerCase()} is truthy`,
|
|
915
|
+
requiredValues: [
|
|
916
|
+
{
|
|
917
|
+
attributePath: firstSource.path,
|
|
918
|
+
value: 'truthy',
|
|
919
|
+
comparison: 'truthy',
|
|
920
|
+
valueType: 'boolean',
|
|
921
|
+
},
|
|
922
|
+
],
|
|
923
|
+
impact,
|
|
924
|
+
sourceLocation: usage.sourceLocation
|
|
925
|
+
? {
|
|
926
|
+
lineNumber: usage.sourceLocation.lineNumber,
|
|
927
|
+
column: usage.sourceLocation.column,
|
|
928
|
+
}
|
|
929
|
+
: undefined,
|
|
930
|
+
codeSnippet: usage.sourceLocation?.codeSnippet,
|
|
931
|
+
};
|
|
932
|
+
// Add both flows (falsy needs all sources, truthy needs one)
|
|
933
|
+
if (!seenFlowIds.has(falsyFlow.id)) {
|
|
934
|
+
seenFlowIds.add(falsyFlow.id);
|
|
935
|
+
flows.push(falsyFlow);
|
|
936
|
+
}
|
|
937
|
+
if (!seenFlowIds.has(truthyFlow.id)) {
|
|
938
|
+
seenFlowIds.add(truthyFlow.id);
|
|
939
|
+
flows.push(truthyFlow);
|
|
940
|
+
}
|
|
941
|
+
// Skip the normal flow generation for this usage
|
|
942
|
+
continue;
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
// For AND derivations without negation, we need ALL sources to be truthy
|
|
946
|
+
// e.g., isReady where isReady = hasData && isLoaded && isValid
|
|
947
|
+
// For the truthy flow, ALL sources must be truthy
|
|
948
|
+
// For negated AND (!isReady), ANY source being falsy is sufficient (fallback behavior)
|
|
949
|
+
if (operation === 'and' &&
|
|
950
|
+
usage.conditionType === 'truthiness' &&
|
|
951
|
+
usage.isNegated !== true &&
|
|
952
|
+
sourcePaths &&
|
|
953
|
+
sourcePaths.length > 0) {
|
|
954
|
+
// Use expandDerivedVariableToSources to recursively resolve all sources
|
|
955
|
+
const allSources = expandDerivedVariableToSources(usage.path, conditionalUsages, attributesMap, equivalentSignatureVariables, fullToShortPathMap, new Set(), derivedVariables);
|
|
956
|
+
if (allSources.length > 0) {
|
|
957
|
+
// Generate a compound-style flow with all sources set to truthy
|
|
958
|
+
const baseName = generateNameFromPath(usage.path);
|
|
959
|
+
const impact = usage.controlsJsxRendering
|
|
960
|
+
? 'high'
|
|
961
|
+
: 'medium';
|
|
962
|
+
const requiredValues = allSources.map((source) => ({
|
|
963
|
+
attributePath: source.path,
|
|
964
|
+
value: 'truthy',
|
|
965
|
+
comparison: 'truthy',
|
|
966
|
+
valueType: 'boolean',
|
|
967
|
+
}));
|
|
968
|
+
// Create a truthy flow with all sources
|
|
969
|
+
const truthyFlow = {
|
|
970
|
+
id: generateFlowId(usage.path, 'truthy'),
|
|
971
|
+
name: `${baseName} True`,
|
|
972
|
+
description: `When ${baseName.toLowerCase()} is truthy (all sources are truthy)`,
|
|
973
|
+
requiredValues,
|
|
974
|
+
impact,
|
|
975
|
+
sourceLocation: usage.sourceLocation
|
|
976
|
+
? {
|
|
977
|
+
lineNumber: usage.sourceLocation.lineNumber,
|
|
978
|
+
column: usage.sourceLocation.column,
|
|
979
|
+
}
|
|
980
|
+
: undefined,
|
|
981
|
+
codeSnippet: usage.sourceLocation?.codeSnippet,
|
|
982
|
+
};
|
|
983
|
+
// Create a falsy flow - for AND, ANY source being falsy is sufficient
|
|
984
|
+
// We use the first resolvable source for the falsy flow
|
|
985
|
+
const firstSource = allSources[0];
|
|
986
|
+
const falsyFlow = {
|
|
987
|
+
id: generateFlowId(usage.path, 'falsy'),
|
|
988
|
+
name: `${baseName} False`,
|
|
989
|
+
description: `When ${baseName.toLowerCase()} is falsy`,
|
|
990
|
+
requiredValues: [
|
|
991
|
+
{
|
|
992
|
+
attributePath: firstSource.path,
|
|
993
|
+
value: 'falsy',
|
|
994
|
+
comparison: 'falsy',
|
|
995
|
+
valueType: 'boolean',
|
|
996
|
+
},
|
|
997
|
+
],
|
|
998
|
+
impact,
|
|
999
|
+
sourceLocation: usage.sourceLocation
|
|
1000
|
+
? {
|
|
1001
|
+
lineNumber: usage.sourceLocation.lineNumber,
|
|
1002
|
+
column: usage.sourceLocation.column,
|
|
1003
|
+
}
|
|
1004
|
+
: undefined,
|
|
1005
|
+
codeSnippet: usage.sourceLocation?.codeSnippet,
|
|
1006
|
+
};
|
|
1007
|
+
// Add both flows (truthy needs all sources, falsy needs one)
|
|
1008
|
+
if (!seenFlowIds.has(truthyFlow.id)) {
|
|
1009
|
+
seenFlowIds.add(truthyFlow.id);
|
|
1010
|
+
flows.push(truthyFlow);
|
|
1011
|
+
}
|
|
1012
|
+
if (!seenFlowIds.has(falsyFlow.id)) {
|
|
1013
|
+
seenFlowIds.add(falsyFlow.id);
|
|
1014
|
+
flows.push(falsyFlow);
|
|
1015
|
+
}
|
|
1016
|
+
// Skip the normal flow generation for this usage
|
|
1017
|
+
continue;
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
// For multi-source derivations (or, and) without special handling,
|
|
1021
|
+
// try the first resolvable path as a fallback
|
|
467
1022
|
if (!resolvedPath && sourcePaths && sourcePaths.length > 0) {
|
|
468
1023
|
for (const sp of sourcePaths) {
|
|
469
1024
|
const resolution = resolvePathToControllable(sp, attributesMap, equivalentSignatureVariables, fullToShortPathMap);
|
|
@@ -476,6 +1031,7 @@ export default function generateExecutionFlowsFromConditionals(args) {
|
|
|
476
1031
|
}
|
|
477
1032
|
if (!resolvedPath) {
|
|
478
1033
|
// Path is not controllable - skip (no invalid flows possible)
|
|
1034
|
+
console.log(`[genFlowsFromConditionals] "${usage.path}" SKIP: not controllable (no resolvedPath after all attempts)`);
|
|
479
1035
|
continue;
|
|
480
1036
|
}
|
|
481
1037
|
// Normalize the resolved path to detect duplicates
|
|
@@ -485,9 +1041,22 @@ export default function generateExecutionFlowsFromConditionals(args) {
|
|
|
485
1041
|
// Skip if we've already generated flows for this normalized path
|
|
486
1042
|
// This prevents duplicate flows when we have usages for both short and full paths
|
|
487
1043
|
if (seenNormalizedPaths.has(normalizedPath)) {
|
|
1044
|
+
console.log(`[genFlowsFromConditionals] "${usage.path}" SKIP: duplicate normalizedPath="${normalizedPath}" (resolvedPath="${resolvedPath}")`);
|
|
488
1045
|
continue;
|
|
489
1046
|
}
|
|
490
1047
|
seenNormalizedPaths.add(normalizedPath);
|
|
1048
|
+
// Skip individual truthy/falsy flows on parent paths that have child data entries.
|
|
1049
|
+
// Lifecycle booleans (like isLoadingAuditData) traced to fetch(...).functionCallReturnValue
|
|
1050
|
+
// produce misleading truthy/falsy flows: "truthy" can't show loading (mock resolves instantly),
|
|
1051
|
+
// "falsy" tells the LLM to return null (breaking .json()). Compound flows with specific child
|
|
1052
|
+
// data requirements provide the correct mock guidance.
|
|
1053
|
+
if (usage.conditionType === 'truthiness' &&
|
|
1054
|
+
resolvedPath &&
|
|
1055
|
+
hasChildPathsInMap(resolvedPath, fullToShortPathMap)) {
|
|
1056
|
+
console.log(`[genFlowsFromConditionals] "${usage.path}" SKIP: parent path "${resolvedPath}" has child data paths — compound flows will handle this`);
|
|
1057
|
+
continue;
|
|
1058
|
+
}
|
|
1059
|
+
console.log(`[genFlowsFromConditionals] "${usage.path}" RESOLVED → resolvedPath="${resolvedPath}", normalizedPath="${normalizedPath}" — generating flows`);
|
|
491
1060
|
// Generate flows for this controllable usage
|
|
492
1061
|
const usageFlows = generateFlowsFromUsage(usage, resolvedPath);
|
|
493
1062
|
for (const flow of usageFlows) {
|
|
@@ -495,29 +1064,226 @@ export default function generateExecutionFlowsFromConditionals(args) {
|
|
|
495
1064
|
if (!seenFlowIds.has(flow.id)) {
|
|
496
1065
|
seenFlowIds.add(flow.id);
|
|
497
1066
|
flows.push(flow);
|
|
1067
|
+
console.log(`[genFlowsFromConditionals] "${usage.path}" FLOW ADDED: id="${flow.id}", requiredValues=${JSON.stringify(flow.requiredValues.map((rv) => ({ attr: rv.attributePath, val: rv.value })))}`);
|
|
498
1068
|
}
|
|
499
1069
|
}
|
|
500
1070
|
}
|
|
501
1071
|
}
|
|
502
1072
|
// Process compound conditionals
|
|
503
1073
|
for (const compound of compoundConditionals) {
|
|
504
|
-
//
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
if (
|
|
510
|
-
|
|
511
|
-
|
|
1074
|
+
// Expand OR groups into separate condition sets
|
|
1075
|
+
// For example, `A && (B || C)` becomes [[A, B], [A, C]]
|
|
1076
|
+
const expandedConditionSets = expandOrGroups(compound.conditions);
|
|
1077
|
+
// Process each expanded condition set as a separate potential flow
|
|
1078
|
+
for (const conditionSet of expandedConditionSets) {
|
|
1079
|
+
// First, check if ALL paths in this condition set are controllable (or can be expanded to controllable sources)
|
|
1080
|
+
const resolvedPaths = new Map();
|
|
1081
|
+
// Track expanded sources for derived variables (path -> array of expanded sources)
|
|
1082
|
+
const expandedSources = new Map();
|
|
1083
|
+
let allControllable = true;
|
|
1084
|
+
for (const condition of conditionSet) {
|
|
1085
|
+
// Check if this condition path has derivation info
|
|
1086
|
+
// First check conditionalUsages, then fall back to derivedVariables
|
|
1087
|
+
const usagesForPath = conditionalUsages[condition.path];
|
|
1088
|
+
let derivedFromInfo = usagesForPath?.find((u) => u.derivedFrom?.operation)?.derivedFrom;
|
|
1089
|
+
// CRITICAL: Also check derivedVariables for intermediate derived variables
|
|
1090
|
+
if (!derivedFromInfo && derivedVariables?.[condition.path]) {
|
|
1091
|
+
derivedFromInfo = derivedVariables[condition.path];
|
|
1092
|
+
}
|
|
1093
|
+
if (derivedFromInfo) {
|
|
1094
|
+
// This is a derived variable - expand to its sources
|
|
1095
|
+
const sources = expandDerivedVariableToSources(condition.path, conditionalUsages, attributesMap, equivalentSignatureVariables, fullToShortPathMap, new Set(), derivedVariables);
|
|
1096
|
+
if (sources.length > 0) {
|
|
1097
|
+
// Store the expanded sources for this condition
|
|
1098
|
+
expandedSources.set(condition.path, sources);
|
|
1099
|
+
// Use the first source's path for the resolvedPaths map (for ID generation)
|
|
1100
|
+
resolvedPaths.set(condition.path, sources[0].path);
|
|
1101
|
+
}
|
|
1102
|
+
else {
|
|
1103
|
+
// Derived variable expansion failed — try sourceDataPath fallback
|
|
1104
|
+
// This handles cases where the derivation chain goes through useMemo/useState
|
|
1105
|
+
// but the enriched sourceDataPath already traced to the actual data source
|
|
1106
|
+
const usageWithSource = usagesForPath?.find((u) => u.sourceDataPath);
|
|
1107
|
+
let derivedFallbackPath = null;
|
|
1108
|
+
if (usageWithSource?.sourceDataPath) {
|
|
1109
|
+
const cleanedPath = cleanSourceDataPath(usageWithSource.sourceDataPath);
|
|
1110
|
+
if (cleanedPath) {
|
|
1111
|
+
const pathMatch = findInAttributesMapForPath(cleanedPath, attributesMap, fullToShortPathMap);
|
|
1112
|
+
if (pathMatch) {
|
|
1113
|
+
derivedFallbackPath = pathMatch;
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
if (derivedFallbackPath) {
|
|
1118
|
+
resolvedPaths.set(condition.path, derivedFallbackPath);
|
|
1119
|
+
console.log(`[genFlowsFromConditionals] COMPOUND "${condition.path}" derived expansion failed but sourceDataPath fallback resolved → "${derivedFallbackPath}"`);
|
|
1120
|
+
}
|
|
1121
|
+
else {
|
|
1122
|
+
// Truly not controllable
|
|
1123
|
+
console.log(`[genFlowsFromConditionals] COMPOUND "${condition.path}" derived but no controllable sources and no sourceDataPath fallback → NOT controllable`);
|
|
1124
|
+
allControllable = false;
|
|
1125
|
+
break;
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
else {
|
|
1130
|
+
// Not a derived variable - resolve directly
|
|
1131
|
+
// First try sourceDataPath from the usage (same as individual processing)
|
|
1132
|
+
let compoundResolvedPath = null;
|
|
1133
|
+
const usageWithSource = usagesForPath?.find((u) => u.sourceDataPath);
|
|
1134
|
+
if (usageWithSource?.sourceDataPath) {
|
|
1135
|
+
const cleanedPath = cleanSourceDataPath(usageWithSource.sourceDataPath);
|
|
1136
|
+
if (cleanedPath) {
|
|
1137
|
+
const pathMatch = findInAttributesMapForPath(cleanedPath, attributesMap, fullToShortPathMap);
|
|
1138
|
+
if (pathMatch) {
|
|
1139
|
+
compoundResolvedPath = pathMatch;
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
if (!compoundResolvedPath) {
|
|
1144
|
+
const resolution = resolvePathToControllable(condition.path, attributesMap, equivalentSignatureVariables, fullToShortPathMap);
|
|
1145
|
+
if (resolution.isControllable && resolution.resolvedPath) {
|
|
1146
|
+
compoundResolvedPath = resolution.resolvedPath;
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
if (!compoundResolvedPath) {
|
|
1150
|
+
allControllable = false;
|
|
1151
|
+
break;
|
|
1152
|
+
}
|
|
1153
|
+
resolvedPaths.set(condition.path, compoundResolvedPath);
|
|
1154
|
+
}
|
|
512
1155
|
}
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
1156
|
+
// Only create a flow if ALL paths are controllable
|
|
1157
|
+
if (allControllable && resolvedPaths.size > 0) {
|
|
1158
|
+
// If any conditions were expanded from derived variables, we need to build a custom flow
|
|
1159
|
+
if (expandedSources.size > 0) {
|
|
1160
|
+
const requiredValues = [];
|
|
1161
|
+
for (const condition of conditionSet) {
|
|
1162
|
+
const sources = expandedSources.get(condition.path);
|
|
1163
|
+
if (sources) {
|
|
1164
|
+
// This condition was expanded - add all its sources
|
|
1165
|
+
// Determine the required value based on condition type and derivation operation
|
|
1166
|
+
const usagesForPath = conditionalUsages[condition.path];
|
|
1167
|
+
let expandedDerivedFrom = usagesForPath?.find((u) => u.derivedFrom?.operation)?.derivedFrom;
|
|
1168
|
+
// Also check derivedVariables for intermediate derived variables
|
|
1169
|
+
if (!expandedDerivedFrom && derivedVariables?.[condition.path]) {
|
|
1170
|
+
expandedDerivedFrom = derivedVariables[condition.path];
|
|
1171
|
+
}
|
|
1172
|
+
const operation = expandedDerivedFrom?.operation;
|
|
1173
|
+
for (const source of sources) {
|
|
1174
|
+
// For OR-derived truthy: ANY source truthy
|
|
1175
|
+
// For AND-derived truthy: ALL sources truthy
|
|
1176
|
+
// For negated: inverse
|
|
1177
|
+
let value;
|
|
1178
|
+
let comparison;
|
|
1179
|
+
if (condition.conditionType === 'truthiness') {
|
|
1180
|
+
const isNegated = condition.isNegated === true;
|
|
1181
|
+
// For OR: truthy needs ANY source truthy, falsy needs ALL sources falsy
|
|
1182
|
+
// For AND: truthy needs ALL sources truthy, falsy needs ANY source falsy
|
|
1183
|
+
// In compound conditionals, we generate the truthy path by default
|
|
1184
|
+
// (the compound expression must be truthy)
|
|
1185
|
+
if (operation === 'or') {
|
|
1186
|
+
// For OR-derived, truthy means we need at least one source truthy
|
|
1187
|
+
// We'll use the first source as truthy (simplification)
|
|
1188
|
+
value = isNegated ? 'falsy' : 'truthy';
|
|
1189
|
+
}
|
|
1190
|
+
else if (operation === 'and') {
|
|
1191
|
+
// For AND-derived, truthy means ALL sources truthy
|
|
1192
|
+
value = isNegated ? 'falsy' : 'truthy';
|
|
1193
|
+
}
|
|
1194
|
+
else {
|
|
1195
|
+
value = isNegated ? 'falsy' : 'truthy';
|
|
1196
|
+
}
|
|
1197
|
+
comparison = isNegated ? 'falsy' : 'truthy';
|
|
1198
|
+
}
|
|
1199
|
+
else {
|
|
1200
|
+
value = 'truthy';
|
|
1201
|
+
comparison = 'truthy';
|
|
1202
|
+
}
|
|
1203
|
+
requiredValues.push({
|
|
1204
|
+
attributePath: source.path,
|
|
1205
|
+
value,
|
|
1206
|
+
comparison,
|
|
1207
|
+
valueType: 'boolean',
|
|
1208
|
+
});
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1211
|
+
else {
|
|
1212
|
+
// This condition was resolved directly
|
|
1213
|
+
const resolvedPath = resolvedPaths.get(condition.path);
|
|
1214
|
+
if (resolvedPath) {
|
|
1215
|
+
let value;
|
|
1216
|
+
let comparison;
|
|
1217
|
+
if (condition.conditionType === 'truthiness') {
|
|
1218
|
+
value = condition.isNegated ? 'falsy' : 'truthy';
|
|
1219
|
+
comparison = condition.isNegated ? 'falsy' : 'truthy';
|
|
1220
|
+
}
|
|
1221
|
+
else {
|
|
1222
|
+
value =
|
|
1223
|
+
condition.requiredValue?.toString() ??
|
|
1224
|
+
condition.comparedValues?.[0] ??
|
|
1225
|
+
'truthy';
|
|
1226
|
+
const op = condition.comparisonOperator;
|
|
1227
|
+
if (op === '>' || op === '>=') {
|
|
1228
|
+
comparison = 'length>';
|
|
1229
|
+
}
|
|
1230
|
+
else if (op === '<' || op === '<=') {
|
|
1231
|
+
comparison = 'length<';
|
|
1232
|
+
}
|
|
1233
|
+
else {
|
|
1234
|
+
comparison = 'equals';
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
requiredValues.push({
|
|
1238
|
+
attributePath: stripLengthSuffix(resolvedPath),
|
|
1239
|
+
value,
|
|
1240
|
+
comparison,
|
|
1241
|
+
valueType: inferValueType(value),
|
|
1242
|
+
});
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
// Remove contradictory "falsy" values where a child path requires data
|
|
1247
|
+
const cleanedValues = removeContradictoryFalsyValues(requiredValues);
|
|
1248
|
+
if (cleanedValues.length > 0) {
|
|
1249
|
+
const impact = compound.controlsJsxRendering ? 'high' : 'medium';
|
|
1250
|
+
// Generate a combined ID from all paths + values
|
|
1251
|
+
const pathParts = cleanedValues
|
|
1252
|
+
.map((rv) => {
|
|
1253
|
+
const name = generateNameFromPath(rv.attributePath);
|
|
1254
|
+
const suffix = rv.comparison === 'truthy' || rv.comparison === 'falsy'
|
|
1255
|
+
? `-${rv.comparison}`
|
|
1256
|
+
: `-${rv.comparison}-${rv.value}`;
|
|
1257
|
+
return name.toLowerCase().replace(/\s+/g, '-') + suffix;
|
|
1258
|
+
})
|
|
1259
|
+
.join('-and-');
|
|
1260
|
+
const compoundFlow = {
|
|
1261
|
+
id: `${pathParts}`,
|
|
1262
|
+
name: generateNameFromPath(cleanedValues[0].attributePath),
|
|
1263
|
+
description: `When ${cleanedValues.map((rv) => describeRequiredValue(rv)).join(' and ')}`,
|
|
1264
|
+
impact,
|
|
1265
|
+
requiredValues: cleanedValues,
|
|
1266
|
+
sourceLocation: compound.sourceLocation,
|
|
1267
|
+
};
|
|
1268
|
+
if (!seenFlowIds.has(compoundFlow.id)) {
|
|
1269
|
+
seenFlowIds.add(compoundFlow.id);
|
|
1270
|
+
flows.push(compoundFlow);
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
else {
|
|
1275
|
+
// No derived variables - use the original generateFlowFromCompound
|
|
1276
|
+
// Create a modified compound with just this condition set
|
|
1277
|
+
const modifiedCompound = {
|
|
1278
|
+
...compound,
|
|
1279
|
+
conditions: conditionSet,
|
|
1280
|
+
};
|
|
1281
|
+
const compoundFlow = generateFlowFromCompound(modifiedCompound, resolvedPaths);
|
|
1282
|
+
if (compoundFlow && !seenFlowIds.has(compoundFlow.id)) {
|
|
1283
|
+
seenFlowIds.add(compoundFlow.id);
|
|
1284
|
+
flows.push(compoundFlow);
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
521
1287
|
}
|
|
522
1288
|
}
|
|
523
1289
|
}
|
|
@@ -541,7 +1307,17 @@ export default function generateExecutionFlowsFromConditionals(args) {
|
|
|
541
1307
|
const [, varName, operator, comparedValue] = comparisonMatch;
|
|
542
1308
|
// Try to resolve the variable name
|
|
543
1309
|
const varResolution = resolvePathToControllable(varName, attributesMap, equivalentSignatureVariables, fullToShortPathMap);
|
|
1310
|
+
// Only use controllable paths for gating conditions (whitelist approach).
|
|
1311
|
+
// Do NOT fall back to equivalentSignatureVariables because those may contain
|
|
1312
|
+
// uncontrollable paths like useState that cannot be mocked.
|
|
1313
|
+
let resolvedVarPath = null;
|
|
544
1314
|
if (varResolution.isControllable && varResolution.resolvedPath) {
|
|
1315
|
+
resolvedVarPath = varResolution.resolvedPath;
|
|
1316
|
+
}
|
|
1317
|
+
// Note: We intentionally do NOT fall back to equivalentSignatureVariables here
|
|
1318
|
+
// because that would allow uncontrollable paths (like useState) to be added
|
|
1319
|
+
// as gating conditions.
|
|
1320
|
+
if (resolvedVarPath) {
|
|
545
1321
|
const isNegated = gatingCondition.isNegated === true;
|
|
546
1322
|
const isNotEquals = operator === '!=' || operator === '!==';
|
|
547
1323
|
// Determine the effective value for this gating condition
|
|
@@ -551,7 +1327,7 @@ export default function generateExecutionFlowsFromConditionals(args) {
|
|
|
551
1327
|
// XOR logic: isNegated XOR isNotEquals
|
|
552
1328
|
const needsExactValue = isNegated !== isNotEquals;
|
|
553
1329
|
gatingRequiredValues.push({
|
|
554
|
-
attributePath:
|
|
1330
|
+
attributePath: resolvedVarPath,
|
|
555
1331
|
value: needsExactValue ? 'falsy' : comparedValue,
|
|
556
1332
|
comparison: needsExactValue ? 'falsy' : 'equals',
|
|
557
1333
|
});
|
|
@@ -604,7 +1380,7 @@ export default function generateExecutionFlowsFromConditionals(args) {
|
|
|
604
1380
|
// For non-negated &&: all parts must be truthy
|
|
605
1381
|
// For negated ||: all parts must be falsy (DeMorgan: !(A || B) = !A && !B)
|
|
606
1382
|
gatingRequiredValues.push({
|
|
607
|
-
attributePath: partResolution.resolvedPath,
|
|
1383
|
+
attributePath: stripLengthSuffix(partResolution.resolvedPath),
|
|
608
1384
|
value: isNegated ? 'falsy' : 'truthy',
|
|
609
1385
|
comparison: isNegated ? 'falsy' : 'truthy',
|
|
610
1386
|
});
|
|
@@ -616,14 +1392,24 @@ export default function generateExecutionFlowsFromConditionals(args) {
|
|
|
616
1392
|
// Simple gating condition (single path)
|
|
617
1393
|
// Resolve the gating path in parent context
|
|
618
1394
|
const gatingResolution = resolvePathToControllable(gatingPath, attributesMap, equivalentSignatureVariables, fullToShortPathMap);
|
|
1395
|
+
// Only use controllable paths for gating conditions (whitelist approach).
|
|
1396
|
+
// Do NOT fall back to equivalentSignatureVariables because those may contain
|
|
1397
|
+
// uncontrollable paths like useState that cannot be mocked.
|
|
1398
|
+
let resolvedGatingPath = null;
|
|
619
1399
|
if (gatingResolution.isControllable &&
|
|
620
1400
|
gatingResolution.resolvedPath) {
|
|
1401
|
+
resolvedGatingPath = gatingResolution.resolvedPath;
|
|
1402
|
+
}
|
|
1403
|
+
// Note: We intentionally do NOT fall back to equivalentSignatureVariables here
|
|
1404
|
+
// because that would allow uncontrollable paths (like useState) to be added
|
|
1405
|
+
// as gating conditions.
|
|
1406
|
+
if (resolvedGatingPath) {
|
|
621
1407
|
// For truthiness conditions on gating, check if the condition is negated
|
|
622
1408
|
// e.g., ternary else branch: isError ? <ErrorView /> : <SuccessView />
|
|
623
1409
|
// SuccessView has isNegated: true, meaning it renders when isError is falsy
|
|
624
1410
|
const isNegated = gatingCondition.isNegated === true;
|
|
625
1411
|
gatingRequiredValues.push({
|
|
626
|
-
attributePath:
|
|
1412
|
+
attributePath: resolvedGatingPath,
|
|
627
1413
|
value: isNegated ? 'falsy' : 'truthy',
|
|
628
1414
|
comparison: isNegated ? 'falsy' : 'truthy',
|
|
629
1415
|
});
|
|
@@ -662,12 +1448,97 @@ export default function generateExecutionFlowsFromConditionals(args) {
|
|
|
662
1448
|
continue;
|
|
663
1449
|
}
|
|
664
1450
|
// Now resolve the translated path in the parent context
|
|
1451
|
+
// First, try standard resolution
|
|
665
1452
|
const resolution = resolvePathToControllable(translatedPath, attributesMap, equivalentSignatureVariables, fullToShortPathMap);
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
1453
|
+
// Only create flows for controllable paths (whitelist approach).
|
|
1454
|
+
// If the path doesn't resolve to something in attributesMap, skip it.
|
|
1455
|
+
// This prevents creating flows for useState values which are not
|
|
1456
|
+
// controllable via mock data injection.
|
|
1457
|
+
let resolvedPath = resolution.resolvedPath;
|
|
1458
|
+
if (!resolution.isControllable || !resolvedPath) {
|
|
1459
|
+
// Path is not controllable via standard resolution.
|
|
1460
|
+
// Try fallback: For useState values (cyScope*().functionCallReturnValue),
|
|
1461
|
+
// look for a related URL parameter like "varNameFromUrl" that might
|
|
1462
|
+
// control the initial state.
|
|
1463
|
+
//
|
|
1464
|
+
// Example: viewMode → cyScope20().functionCallReturnValue (useState value)
|
|
1465
|
+
// Fallback: viewModeFromUrl → segments[2] (URL param that initializes the useState)
|
|
1466
|
+
const useStateMatch = translatedPath.match(/^cyScope\d+\(\)\.functionCallReturnValue$/);
|
|
1467
|
+
if (useStateMatch) {
|
|
1468
|
+
// Find what variable this useState value corresponds to by looking
|
|
1469
|
+
// for entries like "varName": "cyScope20()" in equivalentSignatureVariables
|
|
1470
|
+
const useStatePattern = translatedPath.replace(/\.functionCallReturnValue$/, ''); // e.g., "cyScope20()"
|
|
1471
|
+
// Find the variable name that maps to this useState
|
|
1472
|
+
let useStateVarName = null;
|
|
1473
|
+
for (const [varName, varPath] of Object.entries(equivalentSignatureVariables)) {
|
|
1474
|
+
if (varPath === useStatePattern) {
|
|
1475
|
+
useStateVarName = varName;
|
|
1476
|
+
break;
|
|
1477
|
+
}
|
|
1478
|
+
}
|
|
1479
|
+
if (useStateVarName) {
|
|
1480
|
+
// Look for a related URL param like "varNameFromUrl"
|
|
1481
|
+
const urlParamName = `${useStateVarName}FromUrl`;
|
|
1482
|
+
const urlParamPath = equivalentSignatureVariables[urlParamName];
|
|
1483
|
+
if (urlParamPath) {
|
|
1484
|
+
// For useState values initialized from URL params, use the
|
|
1485
|
+
// URL param variable name directly (e.g., "viewModeFromUrl")
|
|
1486
|
+
// rather than fully resolving it. This keeps the path meaningful
|
|
1487
|
+
// for scenario generation and avoids overly generic paths like
|
|
1488
|
+
// "useParams().functionCallReturnValue.*".
|
|
1489
|
+
//
|
|
1490
|
+
// The flow will use the URL param name as the attributePath,
|
|
1491
|
+
// which gets properly resolved when generating mock data.
|
|
1492
|
+
resolvedPath = urlParamName;
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1495
|
+
}
|
|
1496
|
+
// Fallback 2: Try sourceEquivalencies to find the actual data source
|
|
1497
|
+
// This handles the case where props flow through useState but originate
|
|
1498
|
+
// from a mockable data source (e.g., API call, fetcher).
|
|
1499
|
+
//
|
|
1500
|
+
// Example: WorkoutsView receives `workouts` prop which in parent is stored
|
|
1501
|
+
// in useState, but ultimately comes from a Supabase query.
|
|
1502
|
+
// sourceEquivalencies tells us: "WorkoutsView().signature[0].workouts" → "createClient()...data"
|
|
1503
|
+
if (!resolvedPath && sourceEquivalencies) {
|
|
1504
|
+
// Build the child prop path to look up in sourceEquivalencies
|
|
1505
|
+
// Format: "ChildName().signature[0].propName"
|
|
1506
|
+
// First, find what prop this child path maps to
|
|
1507
|
+
let childPropName = null;
|
|
1508
|
+
for (const [varName, varPath] of Object.entries(childData.equivalentSignatureVariables)) {
|
|
1509
|
+
// Check if childPath starts with this variable name
|
|
1510
|
+
// e.g., childPath = "workouts.length", varName = "workouts", varPath = "signature[0].workouts"
|
|
1511
|
+
if (childPath === varName ||
|
|
1512
|
+
childPath.startsWith(`${varName}.`)) {
|
|
1513
|
+
childPropName = varName;
|
|
1514
|
+
break;
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
1517
|
+
if (childPropName) {
|
|
1518
|
+
// Build the full sourceEquivalencies key
|
|
1519
|
+
const sourceEquivKey = `${childName}().signature[0].${childPropName}`;
|
|
1520
|
+
const sourceEquivEntry = sourceEquivalencies[sourceEquivKey];
|
|
1521
|
+
if (sourceEquivEntry && sourceEquivEntry.length > 0) {
|
|
1522
|
+
const dataSourcePath = sourceEquivEntry[0].schemaPath;
|
|
1523
|
+
// Check if this data source path is controllable
|
|
1524
|
+
const dataSourceResolution = resolvePathToControllable(dataSourcePath, attributesMap, equivalentSignatureVariables, fullToShortPathMap);
|
|
1525
|
+
if (dataSourceResolution.isControllable &&
|
|
1526
|
+
dataSourceResolution.resolvedPath) {
|
|
1527
|
+
// Preserve any suffix from the child path
|
|
1528
|
+
// e.g., childPath = "workouts.length" → suffix = ".length"
|
|
1529
|
+
const suffix = childPath.startsWith(`${childPropName}.`)
|
|
1530
|
+
? childPath.slice(childPropName.length)
|
|
1531
|
+
: '';
|
|
1532
|
+
resolvedPath = dataSourceResolution.resolvedPath + suffix;
|
|
1533
|
+
}
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1537
|
+
// If still not resolved after fallback, skip
|
|
1538
|
+
if (!resolvedPath) {
|
|
1539
|
+
continue;
|
|
1540
|
+
}
|
|
669
1541
|
}
|
|
670
|
-
const resolvedPath = resolution.resolvedPath;
|
|
671
1542
|
// Check for duplicates
|
|
672
1543
|
const normalizedPath = normalizePathForDeduplication(resolvedPath, fullToShortPathMap);
|
|
673
1544
|
if (seenNormalizedPaths.has(normalizedPath)) {
|
|
@@ -710,33 +1581,227 @@ export default function generateExecutionFlowsFromConditionals(args) {
|
|
|
710
1581
|
// Process child's compound conditionals
|
|
711
1582
|
for (const compound of childData.compoundConditionals) {
|
|
712
1583
|
const resolvedPaths = new Map();
|
|
713
|
-
let
|
|
1584
|
+
let allResolvable = true;
|
|
714
1585
|
for (const condition of compound.conditions) {
|
|
715
1586
|
// Determine the child path to translate
|
|
716
1587
|
const childPath = condition.path;
|
|
717
1588
|
// Translate the child path to a parent path
|
|
718
1589
|
const translatedPath = translateChildPathToParent(childPath, childData.equivalentSignatureVariables, equivalentSignatureVariables, childName);
|
|
719
1590
|
if (!translatedPath) {
|
|
720
|
-
|
|
1591
|
+
allResolvable = false;
|
|
721
1592
|
break;
|
|
722
1593
|
}
|
|
723
1594
|
const resolution = resolvePathToControllable(translatedPath, attributesMap, equivalentSignatureVariables, fullToShortPathMap);
|
|
724
|
-
|
|
725
|
-
|
|
1595
|
+
// Only create flows for controllable paths (whitelist approach).
|
|
1596
|
+
// If the path doesn't resolve to something in attributesMap, skip it.
|
|
1597
|
+
// This prevents creating flows for useState values which are not
|
|
1598
|
+
// controllable via mock data injection.
|
|
1599
|
+
let resolvedPath = resolution.resolvedPath;
|
|
1600
|
+
if (!resolution.isControllable || !resolvedPath) {
|
|
1601
|
+
// Path is not controllable via standard resolution.
|
|
1602
|
+
// Try fallback: For useState values (cyScope*().functionCallReturnValue),
|
|
1603
|
+
// look for a related URL parameter like "varNameFromUrl" that might
|
|
1604
|
+
// control the initial state.
|
|
1605
|
+
const useStateMatch = translatedPath.match(/^cyScope\d+\(\)\.functionCallReturnValue$/);
|
|
1606
|
+
if (useStateMatch) {
|
|
1607
|
+
const useStatePattern = translatedPath.replace(/\.functionCallReturnValue$/, '');
|
|
1608
|
+
// Find the variable name that maps to this useState
|
|
1609
|
+
let useStateVarName = null;
|
|
1610
|
+
for (const [varName, varPath] of Object.entries(equivalentSignatureVariables)) {
|
|
1611
|
+
if (varPath === useStatePattern) {
|
|
1612
|
+
useStateVarName = varName;
|
|
1613
|
+
break;
|
|
1614
|
+
}
|
|
1615
|
+
}
|
|
1616
|
+
if (useStateVarName) {
|
|
1617
|
+
const urlParamName = `${useStateVarName}FromUrl`;
|
|
1618
|
+
const urlParamPath = equivalentSignatureVariables[urlParamName];
|
|
1619
|
+
if (urlParamPath) {
|
|
1620
|
+
resolvedPath = urlParamName;
|
|
1621
|
+
}
|
|
1622
|
+
}
|
|
1623
|
+
}
|
|
1624
|
+
}
|
|
1625
|
+
if (!resolvedPath) {
|
|
1626
|
+
allResolvable = false;
|
|
726
1627
|
break;
|
|
727
1628
|
}
|
|
728
|
-
resolvedPaths.set(condition.path,
|
|
1629
|
+
resolvedPaths.set(condition.path, resolvedPath);
|
|
729
1630
|
}
|
|
730
|
-
if (
|
|
1631
|
+
if (allResolvable && resolvedPaths.size > 0) {
|
|
731
1632
|
const compoundFlow = generateFlowFromCompound(compound, resolvedPaths);
|
|
732
|
-
if (compoundFlow
|
|
733
|
-
|
|
734
|
-
|
|
1633
|
+
if (compoundFlow) {
|
|
1634
|
+
// Add gating conditions to compound flow (same as regular usage flows)
|
|
1635
|
+
if (gatingRequiredValues.length > 0) {
|
|
1636
|
+
// Filter out any gating values that are already in the flow
|
|
1637
|
+
const existingPaths = new Set(compoundFlow.requiredValues.map((rv) => rv.attributePath));
|
|
1638
|
+
const newGatingValues = gatingRequiredValues.filter((gv) => !existingPaths.has(gv.attributePath));
|
|
1639
|
+
compoundFlow.requiredValues = [
|
|
1640
|
+
...compoundFlow.requiredValues,
|
|
1641
|
+
...newGatingValues,
|
|
1642
|
+
];
|
|
1643
|
+
// Update the flow ID to include gating conditions
|
|
1644
|
+
if (newGatingValues.length > 0) {
|
|
1645
|
+
const gatingIdPart = newGatingValues
|
|
1646
|
+
.map((gv) => `${gv.attributePath}-${gv.value}`)
|
|
1647
|
+
.join('-');
|
|
1648
|
+
compoundFlow.id = `${compoundFlow.id}-gated-${gatingIdPart}`;
|
|
1649
|
+
}
|
|
1650
|
+
}
|
|
1651
|
+
if (!seenFlowIds.has(compoundFlow.id)) {
|
|
1652
|
+
seenFlowIds.add(compoundFlow.id);
|
|
1653
|
+
flows.push(compoundFlow);
|
|
1654
|
+
}
|
|
1655
|
+
}
|
|
1656
|
+
}
|
|
1657
|
+
}
|
|
1658
|
+
// Process child's jsxRenderingUsages (array.map flows)
|
|
1659
|
+
// This generates array variation flows (empty, few, many) for arrays rendered in child
|
|
1660
|
+
if (childData.jsxRenderingUsages) {
|
|
1661
|
+
for (const jsxUsage of childData.jsxRenderingUsages) {
|
|
1662
|
+
// Translate the child path to a parent path
|
|
1663
|
+
const translatedPath = translateChildPathToParent(jsxUsage.path, childData.equivalentSignatureVariables, equivalentSignatureVariables, childName);
|
|
1664
|
+
if (!translatedPath) {
|
|
1665
|
+
continue;
|
|
1666
|
+
}
|
|
1667
|
+
// Resolve to controllable path in parent context
|
|
1668
|
+
const resolution = resolvePathToControllable(translatedPath, attributesMap, equivalentSignatureVariables, fullToShortPathMap);
|
|
1669
|
+
let resolvedPath = resolution.resolvedPath;
|
|
1670
|
+
// Try sourceEquivalencies fallback if not controllable
|
|
1671
|
+
if (!resolution.isControllable || !resolvedPath) {
|
|
1672
|
+
if (sourceEquivalencies) {
|
|
1673
|
+
// Build the sourceEquivalencies key
|
|
1674
|
+
// The child path (e.g., "workouts") maps to a prop path (e.g., "signature[0].workouts")
|
|
1675
|
+
let childPropName = null;
|
|
1676
|
+
for (const [varName, varPath] of Object.entries(childData.equivalentSignatureVariables)) {
|
|
1677
|
+
if (jsxUsage.path === varName ||
|
|
1678
|
+
jsxUsage.path.startsWith(`${varName}.`)) {
|
|
1679
|
+
childPropName = varName;
|
|
1680
|
+
break;
|
|
1681
|
+
}
|
|
1682
|
+
}
|
|
1683
|
+
if (childPropName) {
|
|
1684
|
+
const sourceEquivKey = `${childName}().signature[0].${childPropName}`;
|
|
1685
|
+
const sourceEquivEntry = sourceEquivalencies[sourceEquivKey];
|
|
1686
|
+
if (sourceEquivEntry && sourceEquivEntry.length > 0) {
|
|
1687
|
+
const dataSourcePath = sourceEquivEntry[0].schemaPath;
|
|
1688
|
+
const dataSourceResolution = resolvePathToControllable(dataSourcePath, attributesMap, equivalentSignatureVariables, fullToShortPathMap);
|
|
1689
|
+
if (dataSourceResolution.isControllable &&
|
|
1690
|
+
dataSourceResolution.resolvedPath) {
|
|
1691
|
+
resolvedPath = dataSourceResolution.resolvedPath;
|
|
1692
|
+
}
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1695
|
+
}
|
|
1696
|
+
}
|
|
1697
|
+
if (!resolvedPath) {
|
|
1698
|
+
continue;
|
|
1699
|
+
}
|
|
1700
|
+
// Check for duplicates
|
|
1701
|
+
const normalizedPath = normalizePathForDeduplication(resolvedPath, fullToShortPathMap);
|
|
1702
|
+
const dedupeKey = `${normalizedPath}:${jsxUsage.renderingType}`;
|
|
1703
|
+
if (seenNormalizedPaths.has(dedupeKey)) {
|
|
1704
|
+
continue;
|
|
1705
|
+
}
|
|
1706
|
+
seenNormalizedPaths.add(dedupeKey);
|
|
1707
|
+
// Generate array variation flows for array-map rendering
|
|
1708
|
+
if (jsxUsage.renderingType === 'array-map') {
|
|
1709
|
+
const baseName = generateNameFromPath(resolvedPath);
|
|
1710
|
+
const pathSlug = pathToSlug(resolvedPath);
|
|
1711
|
+
const exclusiveGroup = `array-length-${pathSlug}`;
|
|
1712
|
+
// Empty array flow
|
|
1713
|
+
const emptyFlow = {
|
|
1714
|
+
id: `${pathSlug}-empty-array`,
|
|
1715
|
+
name: `${baseName} Empty`,
|
|
1716
|
+
description: `When ${baseName.toLowerCase()} array is empty`,
|
|
1717
|
+
requiredValues: [
|
|
1718
|
+
{
|
|
1719
|
+
attributePath: resolvedPath,
|
|
1720
|
+
value: '0',
|
|
1721
|
+
comparison: 'length<',
|
|
1722
|
+
valueType: 'array',
|
|
1723
|
+
},
|
|
1724
|
+
...gatingRequiredValues,
|
|
1725
|
+
],
|
|
1726
|
+
impact: 'medium',
|
|
1727
|
+
exclusiveGroup,
|
|
1728
|
+
sourceLocation: jsxUsage.sourceLocation
|
|
1729
|
+
? {
|
|
1730
|
+
lineNumber: jsxUsage.sourceLocation.lineNumber,
|
|
1731
|
+
column: jsxUsage.sourceLocation.column,
|
|
1732
|
+
}
|
|
1733
|
+
: undefined,
|
|
1734
|
+
codeSnippet: jsxUsage.sourceLocation?.codeSnippet,
|
|
1735
|
+
};
|
|
1736
|
+
if (!seenFlowIds.has(emptyFlow.id)) {
|
|
1737
|
+
seenFlowIds.add(emptyFlow.id);
|
|
1738
|
+
flows.push(emptyFlow);
|
|
1739
|
+
}
|
|
1740
|
+
// Few items flow (1-3)
|
|
1741
|
+
const fewFlow = {
|
|
1742
|
+
id: `${pathSlug}-few-items`,
|
|
1743
|
+
name: `${baseName} Few Items`,
|
|
1744
|
+
description: `When ${baseName.toLowerCase()} array has 1-3 items`,
|
|
1745
|
+
requiredValues: [
|
|
1746
|
+
{
|
|
1747
|
+
attributePath: resolvedPath,
|
|
1748
|
+
value: '3',
|
|
1749
|
+
comparison: 'length<',
|
|
1750
|
+
valueType: 'array',
|
|
1751
|
+
},
|
|
1752
|
+
...gatingRequiredValues,
|
|
1753
|
+
],
|
|
1754
|
+
impact: 'low',
|
|
1755
|
+
exclusiveGroup,
|
|
1756
|
+
sourceLocation: jsxUsage.sourceLocation
|
|
1757
|
+
? {
|
|
1758
|
+
lineNumber: jsxUsage.sourceLocation.lineNumber,
|
|
1759
|
+
column: jsxUsage.sourceLocation.column,
|
|
1760
|
+
}
|
|
1761
|
+
: undefined,
|
|
1762
|
+
codeSnippet: jsxUsage.sourceLocation?.codeSnippet,
|
|
1763
|
+
};
|
|
1764
|
+
if (!seenFlowIds.has(fewFlow.id)) {
|
|
1765
|
+
seenFlowIds.add(fewFlow.id);
|
|
1766
|
+
flows.push(fewFlow);
|
|
1767
|
+
}
|
|
1768
|
+
// Many items flow (10+)
|
|
1769
|
+
const manyFlow = {
|
|
1770
|
+
id: `${pathSlug}-many-items`,
|
|
1771
|
+
name: `${baseName} Many Items`,
|
|
1772
|
+
description: `When ${baseName.toLowerCase()} array has many items`,
|
|
1773
|
+
requiredValues: [
|
|
1774
|
+
{
|
|
1775
|
+
attributePath: resolvedPath,
|
|
1776
|
+
value: '10',
|
|
1777
|
+
comparison: 'length>',
|
|
1778
|
+
valueType: 'array',
|
|
1779
|
+
},
|
|
1780
|
+
...gatingRequiredValues,
|
|
1781
|
+
],
|
|
1782
|
+
impact: 'low',
|
|
1783
|
+
exclusiveGroup,
|
|
1784
|
+
sourceLocation: jsxUsage.sourceLocation
|
|
1785
|
+
? {
|
|
1786
|
+
lineNumber: jsxUsage.sourceLocation.lineNumber,
|
|
1787
|
+
column: jsxUsage.sourceLocation.column,
|
|
1788
|
+
}
|
|
1789
|
+
: undefined,
|
|
1790
|
+
codeSnippet: jsxUsage.sourceLocation?.codeSnippet,
|
|
1791
|
+
};
|
|
1792
|
+
if (!seenFlowIds.has(manyFlow.id)) {
|
|
1793
|
+
seenFlowIds.add(manyFlow.id);
|
|
1794
|
+
flows.push(manyFlow);
|
|
1795
|
+
}
|
|
735
1796
|
}
|
|
736
1797
|
}
|
|
737
1798
|
}
|
|
738
1799
|
}
|
|
739
1800
|
}
|
|
1801
|
+
console.log(`[genFlowsFromConditionals] RESULT: ${flows.length} total flows generated`);
|
|
1802
|
+
for (const flow of flows) {
|
|
1803
|
+
console.log(`[genFlowsFromConditionals] FLOW: id="${flow.id}" requiredValues=[${flow.requiredValues.map((rv) => `${rv.attributePath}=${rv.value}`).join(', ')}]`);
|
|
1804
|
+
}
|
|
740
1805
|
return flows;
|
|
741
1806
|
}
|
|
742
1807
|
//# sourceMappingURL=generateExecutionFlowsFromConditionals.js.map
|