@codeyam/codeyam-cli 0.1.0-staging.323686 → 0.1.0-staging.483fdc2
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 +7 -7
- package/analyzer-template/log.txt +3 -3
- package/analyzer-template/package.json +2 -2
- package/analyzer-template/packages/ai/index.ts +6 -1
- package/analyzer-template/packages/ai/src/lib/analyzeScope.ts +39 -17
- package/analyzer-template/packages/ai/src/lib/astScopes/astScopeAnalyzer.ts +67 -9
- package/analyzer-template/packages/ai/src/lib/astScopes/processExpression.ts +308 -50
- package/analyzer-template/packages/ai/src/lib/astScopes/types.ts +15 -6
- package/analyzer-template/packages/ai/src/lib/dataStructure/ScopeDataStructure.ts +664 -242
- 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 +20 -1
- package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/cleanNonObjectFunctions.ts +35 -13
- package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/convertTypeAnnotationsToValues.ts +160 -0
- package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/deduplicateFunctionSchemas.ts +40 -30
- package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/fillInSchemaGapsAndUnknowns.ts +289 -83
- package/analyzer-template/packages/ai/src/lib/generateEntityScenarioData.ts +269 -1
- package/analyzer-template/packages/ai/src/lib/generateEntityScenarios.ts +9 -5
- package/analyzer-template/packages/ai/src/lib/generateExecutionFlows.ts +11 -3
- package/analyzer-template/packages/ai/src/lib/generateExecutionFlowsFromConditionalEffects.ts +1 -1
- package/analyzer-template/packages/ai/src/lib/generateExecutionFlowsFromConditionals.ts +297 -7
- package/analyzer-template/packages/ai/src/lib/generateExecutionFlowsFromJsxUsages.ts +1 -1
- package/analyzer-template/packages/ai/src/lib/mergeStatements.ts +90 -96
- package/analyzer-template/packages/ai/src/lib/promptGenerators/gatherAttributesMap.ts +10 -7
- package/analyzer-template/packages/ai/src/lib/resolvePathToControllable.ts +25 -13
- package/analyzer-template/packages/ai/src/lib/worker/SerializableDataStructure.ts +4 -3
- 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/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 +20 -6
- package/analyzer-template/packages/analyze/src/lib/files/analyze/analyzeEntities.ts +14 -4
- package/analyzer-template/packages/analyze/src/lib/files/analyze/gatherEntityMap.ts +4 -2
- package/analyzer-template/packages/analyze/src/lib/files/analyze/validateDependencyAnalyses.ts +0 -3
- package/analyzer-template/packages/analyze/src/lib/files/analyzeRemixRoute.ts +4 -5
- package/analyzer-template/packages/analyze/src/lib/files/getImportedExports.ts +14 -12
- package/analyzer-template/packages/analyze/src/lib/files/scenarios/enrichArrayTypesFromChildSignatures.ts +57 -13
- package/analyzer-template/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.ts +29 -0
- package/analyzer-template/packages/analyze/src/lib/files/scenarios/generateDataStructure.ts +35 -4
- package/analyzer-template/packages/analyze/src/lib/files/scenarios/generateExecutionFlows.ts +117 -9
- package/analyzer-template/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.ts +199 -17
- package/analyzer-template/packages/analyze/src/lib/files/scenarios/propagateArrayItemSchemas.ts +474 -0
- package/analyzer-template/packages/analyze/src/lib/files/setImportedExports.ts +2 -1
- package/analyzer-template/packages/analyze/src/lib/utils/getFileByPath.ts +19 -0
- package/analyzer-template/packages/aws/package.json +1 -1
- package/analyzer-template/packages/github/dist/types/src/types/ScenariosDataStructure.d.ts +5 -5
- 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/package.json +1 -1
- package/analyzer-template/packages/types/src/types/ScenariosDataStructure.ts +6 -5
- package/analyzer-template/packages/types/src/types/ScopeAnalysis.ts +6 -1
- package/analyzer-template/packages/utils/dist/types/src/types/ScenariosDataStructure.d.ts +5 -5
- 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/project/constructMockCode.ts +54 -9
- package/analyzer-template/project/writeMockDataTsx.ts +73 -2
- package/background/src/lib/virtualized/project/constructMockCode.js +45 -3
- package/background/src/lib/virtualized/project/constructMockCode.js.map +1 -1
- package/background/src/lib/virtualized/project/writeMockDataTsx.js +71 -2
- package/background/src/lib/virtualized/project/writeMockDataTsx.js.map +1 -1
- package/codeyam-cli/scripts/apply-setup.js +146 -0
- package/codeyam-cli/scripts/apply-setup.js.map +1 -1
- package/codeyam-cli/src/commands/debug.js +7 -5
- package/codeyam-cli/src/commands/debug.js.map +1 -1
- package/codeyam-cli/src/utils/install-skills.js +22 -0
- package/codeyam-cli/src/utils/install-skills.js.map +1 -1
- package/codeyam-cli/src/utils/reviewedRules.js +92 -0
- package/codeyam-cli/src/utils/reviewedRules.js.map +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/globals-CX9f-5xM.css +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/{manifest-7522edd4.js → manifest-bba56ec1.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/memory-DuTFSyJ2.js +92 -0
- package/codeyam-cli/src/webserver/build/client/assets/{root-eVAaavTS.js → root-DTfSQARG.js} +6 -6
- package/codeyam-cli/src/webserver/build/server/assets/{index-DVzYx8PN.js → index-TD1f-DHV.js} +1 -1
- package/codeyam-cli/src/webserver/build/server/assets/server-build-BQ-1XyEa.js +258 -0
- package/codeyam-cli/src/webserver/build/server/index.js +1 -1
- package/codeyam-cli/src/webserver/build-info.json +5 -5
- package/codeyam-cli/templates/codeyam:memory.md +174 -233
- package/codeyam-cli/templates/codeyam:new-rule.md +41 -2
- package/codeyam-cli/templates/rule-reflection-hook.py +161 -0
- package/codeyam-cli/templates/rules-instructions.md +126 -0
- package/package.json +1 -1
- package/packages/ai/index.js +2 -1
- package/packages/ai/index.js.map +1 -1
- package/packages/ai/src/lib/analyzeScope.js +29 -12
- package/packages/ai/src/lib/analyzeScope.js.map +1 -1
- package/packages/ai/src/lib/astScopes/astScopeAnalyzer.js +54 -8
- package/packages/ai/src/lib/astScopes/astScopeAnalyzer.js.map +1 -1
- package/packages/ai/src/lib/astScopes/processExpression.js +239 -43
- package/packages/ai/src/lib/astScopes/processExpression.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/ScopeDataStructure.js +503 -165
- package/packages/ai/src/lib/dataStructure/ScopeDataStructure.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 +22 -1
- package/packages/ai/src/lib/dataStructure/helpers/cleanKnownObjectFunctions.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/helpers/cleanNonObjectFunctions.js +34 -9
- package/packages/ai/src/lib/dataStructure/helpers/cleanNonObjectFunctions.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/helpers/convertTypeAnnotationsToValues.js +159 -0
- package/packages/ai/src/lib/dataStructure/helpers/convertTypeAnnotationsToValues.js.map +1 -0
- package/packages/ai/src/lib/dataStructure/helpers/deduplicateFunctionSchemas.js +37 -20
- package/packages/ai/src/lib/dataStructure/helpers/deduplicateFunctionSchemas.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/helpers/fillInSchemaGapsAndUnknowns.js +237 -73
- package/packages/ai/src/lib/dataStructure/helpers/fillInSchemaGapsAndUnknowns.js.map +1 -1
- package/packages/ai/src/lib/generateEntityScenarioData.js +195 -1
- package/packages/ai/src/lib/generateEntityScenarioData.js.map +1 -1
- package/packages/ai/src/lib/generateEntityScenarios.js +7 -1
- package/packages/ai/src/lib/generateEntityScenarios.js.map +1 -1
- package/packages/ai/src/lib/generateExecutionFlows.js +10 -2
- package/packages/ai/src/lib/generateExecutionFlows.js.map +1 -1
- package/packages/ai/src/lib/generateExecutionFlowsFromConditionals.js +209 -3
- package/packages/ai/src/lib/generateExecutionFlowsFromConditionals.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/gatherAttributesMap.js +10 -4
- package/packages/ai/src/lib/promptGenerators/gatherAttributesMap.js.map +1 -1
- package/packages/ai/src/lib/resolvePathToControllable.js +24 -14
- package/packages/ai/src/lib/resolvePathToControllable.js.map +1 -1
- package/packages/ai/src/lib/worker/SerializableDataStructure.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/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 +13 -5
- package/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.js.map +1 -1
- package/packages/analyze/src/lib/files/analyze/analyzeEntities.js +14 -4
- package/packages/analyze/src/lib/files/analyze/analyzeEntities.js.map +1 -1
- package/packages/analyze/src/lib/files/analyze/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 +0 -3
- package/packages/analyze/src/lib/files/analyze/validateDependencyAnalyses.js.map +1 -1
- package/packages/analyze/src/lib/files/analyzeRemixRoute.js +3 -2
- package/packages/analyze/src/lib/files/analyzeRemixRoute.js.map +1 -1
- package/packages/analyze/src/lib/files/getImportedExports.js +11 -7
- package/packages/analyze/src/lib/files/getImportedExports.js.map +1 -1
- package/packages/analyze/src/lib/files/scenarios/enrichArrayTypesFromChildSignatures.js +52 -10
- package/packages/analyze/src/lib/files/scenarios/enrichArrayTypesFromChildSignatures.js.map +1 -1
- package/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.js +25 -8
- package/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.js.map +1 -1
- package/packages/analyze/src/lib/files/scenarios/generateDataStructure.js +34 -4
- package/packages/analyze/src/lib/files/scenarios/generateDataStructure.js.map +1 -1
- package/packages/analyze/src/lib/files/scenarios/generateExecutionFlows.js +56 -8
- package/packages/analyze/src/lib/files/scenarios/generateExecutionFlows.js.map +1 -1
- package/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.js +168 -9
- package/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.js.map +1 -1
- package/packages/analyze/src/lib/files/setImportedExports.js +2 -1
- package/packages/analyze/src/lib/files/setImportedExports.js.map +1 -1
- package/packages/analyze/src/lib/utils/getFileByPath.js +12 -0
- package/packages/analyze/src/lib/utils/getFileByPath.js.map +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/globals-D3yhhV8x.css +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/memory-yxFcrxBX.js +0 -92
- package/codeyam-cli/src/webserver/build/server/assets/server-build-4Cr0uToj.js +0 -257
|
@@ -18,6 +18,7 @@ import type {
|
|
|
18
18
|
CompoundConditional,
|
|
19
19
|
DerivedVariableOperation,
|
|
20
20
|
DerivedVariableInfo,
|
|
21
|
+
JsxRenderingUsage,
|
|
21
22
|
} from './astScopes/types';
|
|
22
23
|
import type { EnrichedConditionalUsage } from './worker/SerializableDataStructure';
|
|
23
24
|
import resolvePathToControllable from './resolvePathToControllable';
|
|
@@ -32,7 +33,7 @@ export interface ChildComponentConditionalData {
|
|
|
32
33
|
/** Child's conditional usages keyed by variable name (may include sourceDataPath from enrichment) */
|
|
33
34
|
conditionalUsages: Record<string, ExtendedConditionalUsage[]>;
|
|
34
35
|
/** Child's equivalent signature variables (maps internal paths to prop paths) */
|
|
35
|
-
equivalentSignatureVariables: Record<string, string>;
|
|
36
|
+
equivalentSignatureVariables: Record<string, string | string[]>;
|
|
36
37
|
/** Child's compound conditionals */
|
|
37
38
|
compoundConditionals: CompoundConditional[];
|
|
38
39
|
/**
|
|
@@ -41,6 +42,11 @@ export interface ChildComponentConditionalData {
|
|
|
41
42
|
* then `hasAnalysis` is a gating condition for all of ChildComponent's flows.
|
|
42
43
|
*/
|
|
43
44
|
gatingConditions?: ConditionalUsage[];
|
|
45
|
+
/**
|
|
46
|
+
* Child's JSX rendering usages (arrays rendered via .map(), text interpolation).
|
|
47
|
+
* These generate "variation flows" for different array lengths.
|
|
48
|
+
*/
|
|
49
|
+
jsxRenderingUsages?: JsxRenderingUsage[];
|
|
44
50
|
}
|
|
45
51
|
|
|
46
52
|
export interface GenerateFlowsFromConditionalsArgs {
|
|
@@ -51,7 +57,7 @@ export interface GenerateFlowsFromConditionalsArgs {
|
|
|
51
57
|
/** Map of controllable paths to their types */
|
|
52
58
|
attributesMap: Record<string, string>;
|
|
53
59
|
/** Map from local variable names to data sources */
|
|
54
|
-
equivalentSignatureVariables: Record<string, string>;
|
|
60
|
+
equivalentSignatureVariables: Record<string, string | string[]>;
|
|
55
61
|
/** Map from full paths to short paths */
|
|
56
62
|
fullToShortPathMap: Record<string, string>;
|
|
57
63
|
/**
|
|
@@ -73,6 +79,21 @@ export interface GenerateFlowsFromConditionalsArgs {
|
|
|
73
79
|
* to `currentRun.entityShas` when `isInCurrentRun` isn't in conditionalUsages.
|
|
74
80
|
*/
|
|
75
81
|
derivedVariables?: Record<string, DerivedVariableInfo>;
|
|
82
|
+
/**
|
|
83
|
+
* Optional map of child prop paths to their actual data sources.
|
|
84
|
+
* Used when child props flow through useState but ultimately come from
|
|
85
|
+
* mockable data sources (e.g., API calls, fetchers).
|
|
86
|
+
*
|
|
87
|
+
* Example:
|
|
88
|
+
* - "WorkoutsView().signature[0].workouts" → "createClient()...functionCallReturnValue.data"
|
|
89
|
+
*
|
|
90
|
+
* When a child path translates to a useState value, we check this map
|
|
91
|
+
* to find the real data source that can be mocked.
|
|
92
|
+
*/
|
|
93
|
+
sourceEquivalencies?: Record<
|
|
94
|
+
string,
|
|
95
|
+
Array<{ scopeNodeName: string; schemaPath: string }>
|
|
96
|
+
>;
|
|
76
97
|
}
|
|
77
98
|
|
|
78
99
|
/**
|
|
@@ -117,7 +138,7 @@ function expandDerivedVariableToSources(
|
|
|
117
138
|
path: string,
|
|
118
139
|
conditionalUsages: Record<string, ConditionalUsage[]>,
|
|
119
140
|
attributesMap: Record<string, string>,
|
|
120
|
-
equivalentSignatureVariables: Record<string, string>,
|
|
141
|
+
equivalentSignatureVariables: Record<string, string | string[]>,
|
|
121
142
|
fullToShortPathMap: Record<string, string>,
|
|
122
143
|
visited: Set<string> = new Set(),
|
|
123
144
|
derivedVariables?: Record<string, DerivedVariableInfo>,
|
|
@@ -387,6 +408,20 @@ function findInAttributesMapForPath(
|
|
|
387
408
|
return null;
|
|
388
409
|
}
|
|
389
410
|
|
|
411
|
+
/**
|
|
412
|
+
* Generate a slug from a path for use in flow IDs and exclusive groups.
|
|
413
|
+
*/
|
|
414
|
+
function pathToSlug(path: string): string {
|
|
415
|
+
return path
|
|
416
|
+
.replace(/\[\d+\]/g, '')
|
|
417
|
+
.replace(/\[\]/g, '')
|
|
418
|
+
.replace(/\(\)/g, '')
|
|
419
|
+
.replace(/\.functionCallReturnValue/g, '')
|
|
420
|
+
.replace(/[<>]/g, '')
|
|
421
|
+
.replace(/\./g, '-')
|
|
422
|
+
.toLowerCase();
|
|
423
|
+
}
|
|
424
|
+
|
|
390
425
|
/**
|
|
391
426
|
* Generate a human-readable name from a path.
|
|
392
427
|
* Extracts the last meaningful part of the path.
|
|
@@ -732,8 +767,8 @@ function normalizePathForDeduplication(
|
|
|
732
767
|
*/
|
|
733
768
|
function translateChildPathToParent(
|
|
734
769
|
childPath: string,
|
|
735
|
-
childEquivalentSignatureVariables: Record<string, string>,
|
|
736
|
-
parentEquivalentSignatureVariables: Record<string, string>,
|
|
770
|
+
childEquivalentSignatureVariables: Record<string, string | string[]>,
|
|
771
|
+
parentEquivalentSignatureVariables: Record<string, string | string[]>,
|
|
737
772
|
childName: string,
|
|
738
773
|
): string | null {
|
|
739
774
|
// Extract the root variable from the child path
|
|
@@ -760,7 +795,11 @@ function translateChildPathToParent(
|
|
|
760
795
|
|
|
761
796
|
// Look up the child's equivalence for this root variable
|
|
762
797
|
// e.g., childEquiv[selectedScenario] = "signature[0].selectedScenario"
|
|
763
|
-
|
|
798
|
+
// Handle array case (OR expressions) - use first element if array
|
|
799
|
+
const rawChildPropPath = childEquivalentSignatureVariables[rootVar];
|
|
800
|
+
const childPropPath = Array.isArray(rawChildPropPath)
|
|
801
|
+
? rawChildPropPath[0]
|
|
802
|
+
: rawChildPropPath;
|
|
764
803
|
|
|
765
804
|
if (!childPropPath) {
|
|
766
805
|
// No mapping found - this might be internal state, not a prop
|
|
@@ -773,7 +812,11 @@ function translateChildPathToParent(
|
|
|
773
812
|
|
|
774
813
|
// Look up parent's equivalence to find what value was passed to this prop
|
|
775
814
|
// e.g., parentEquiv["ChildName().signature[0].selectedScenario"] = "selectedScenario"
|
|
776
|
-
|
|
815
|
+
// Handle array case (OR expressions) - use first element if array
|
|
816
|
+
const rawParentValue = parentEquivalentSignatureVariables[fullChildPropPath];
|
|
817
|
+
const parentValue = Array.isArray(rawParentValue)
|
|
818
|
+
? rawParentValue[0]
|
|
819
|
+
: rawParentValue;
|
|
777
820
|
|
|
778
821
|
if (!parentValue) {
|
|
779
822
|
// No parent mapping found - log ALL parent keys that contain the childName
|
|
@@ -800,6 +843,7 @@ export default function generateExecutionFlowsFromConditionals(
|
|
|
800
843
|
fullToShortPathMap,
|
|
801
844
|
childComponentData,
|
|
802
845
|
derivedVariables,
|
|
846
|
+
sourceEquivalencies,
|
|
803
847
|
} = args;
|
|
804
848
|
|
|
805
849
|
const flows: ExecutionFlow[] = [];
|
|
@@ -1771,6 +1815,69 @@ export default function generateExecutionFlowsFromConditionals(
|
|
|
1771
1815
|
}
|
|
1772
1816
|
}
|
|
1773
1817
|
|
|
1818
|
+
// Fallback 2: Try sourceEquivalencies to find the actual data source
|
|
1819
|
+
// This handles the case where props flow through useState but originate
|
|
1820
|
+
// from a mockable data source (e.g., API call, fetcher).
|
|
1821
|
+
//
|
|
1822
|
+
// Example: WorkoutsView receives `workouts` prop which in parent is stored
|
|
1823
|
+
// in useState, but ultimately comes from a Supabase query.
|
|
1824
|
+
// sourceEquivalencies tells us: "WorkoutsView().signature[0].workouts" → "createClient()...data"
|
|
1825
|
+
if (!resolvedPath && sourceEquivalencies) {
|
|
1826
|
+
// Build the child prop path to look up in sourceEquivalencies
|
|
1827
|
+
// Format: "ChildName().signature[0].propName"
|
|
1828
|
+
// First, find what prop this child path maps to
|
|
1829
|
+
let childPropName: string | null = null;
|
|
1830
|
+
for (const [varName, varPath] of Object.entries(
|
|
1831
|
+
childData.equivalentSignatureVariables,
|
|
1832
|
+
)) {
|
|
1833
|
+
// Check if childPath starts with this variable name
|
|
1834
|
+
// e.g., childPath = "workouts.length", varName = "workouts", varPath = "signature[0].workouts"
|
|
1835
|
+
if (
|
|
1836
|
+
childPath === varName ||
|
|
1837
|
+
childPath.startsWith(`${varName}.`)
|
|
1838
|
+
) {
|
|
1839
|
+
childPropName = varName;
|
|
1840
|
+
break;
|
|
1841
|
+
}
|
|
1842
|
+
}
|
|
1843
|
+
|
|
1844
|
+
if (childPropName) {
|
|
1845
|
+
// Build the full sourceEquivalencies key
|
|
1846
|
+
const sourceEquivKey = `${childName}().signature[0].${childPropName}`;
|
|
1847
|
+
|
|
1848
|
+
const sourceEquivEntry = sourceEquivalencies[sourceEquivKey];
|
|
1849
|
+
if (sourceEquivEntry && sourceEquivEntry.length > 0) {
|
|
1850
|
+
const dataSourcePath = sourceEquivEntry[0].schemaPath;
|
|
1851
|
+
|
|
1852
|
+
// Check if this data source path is controllable
|
|
1853
|
+
const dataSourceResolution = resolvePathToControllable(
|
|
1854
|
+
dataSourcePath,
|
|
1855
|
+
attributesMap,
|
|
1856
|
+
equivalentSignatureVariables,
|
|
1857
|
+
fullToShortPathMap,
|
|
1858
|
+
);
|
|
1859
|
+
|
|
1860
|
+
if (
|
|
1861
|
+
dataSourceResolution.isControllable &&
|
|
1862
|
+
dataSourceResolution.resolvedPath
|
|
1863
|
+
) {
|
|
1864
|
+
// Preserve any suffix from the child path
|
|
1865
|
+
// e.g., childPath = "workouts.length" → suffix = ".length"
|
|
1866
|
+
const suffix = childPath.startsWith(`${childPropName}.`)
|
|
1867
|
+
? childPath.slice(childPropName.length)
|
|
1868
|
+
: '';
|
|
1869
|
+
resolvedPath = dataSourceResolution.resolvedPath + suffix;
|
|
1870
|
+
|
|
1871
|
+
if (shouldDebugChild) {
|
|
1872
|
+
console.log(
|
|
1873
|
+
`[DEBUG CHILD ${childName}] sourceEquivalencies fallback SUCCESS: using data source ${resolvedPath}`,
|
|
1874
|
+
);
|
|
1875
|
+
}
|
|
1876
|
+
}
|
|
1877
|
+
}
|
|
1878
|
+
}
|
|
1879
|
+
}
|
|
1880
|
+
|
|
1774
1881
|
// If still not resolved after fallback, skip
|
|
1775
1882
|
if (!resolvedPath) {
|
|
1776
1883
|
if (shouldDebugChild) {
|
|
@@ -1970,6 +2077,189 @@ export default function generateExecutionFlowsFromConditionals(
|
|
|
1970
2077
|
}
|
|
1971
2078
|
}
|
|
1972
2079
|
}
|
|
2080
|
+
|
|
2081
|
+
// Process child's jsxRenderingUsages (array.map flows)
|
|
2082
|
+
// This generates array variation flows (empty, few, many) for arrays rendered in child
|
|
2083
|
+
if (childData.jsxRenderingUsages) {
|
|
2084
|
+
for (const jsxUsage of childData.jsxRenderingUsages) {
|
|
2085
|
+
// Translate the child path to a parent path
|
|
2086
|
+
const translatedPath = translateChildPathToParent(
|
|
2087
|
+
jsxUsage.path,
|
|
2088
|
+
childData.equivalentSignatureVariables,
|
|
2089
|
+
equivalentSignatureVariables,
|
|
2090
|
+
childName,
|
|
2091
|
+
);
|
|
2092
|
+
|
|
2093
|
+
if (!translatedPath) {
|
|
2094
|
+
continue;
|
|
2095
|
+
}
|
|
2096
|
+
|
|
2097
|
+
// Resolve to controllable path in parent context
|
|
2098
|
+
const resolution = resolvePathToControllable(
|
|
2099
|
+
translatedPath,
|
|
2100
|
+
attributesMap,
|
|
2101
|
+
equivalentSignatureVariables,
|
|
2102
|
+
fullToShortPathMap,
|
|
2103
|
+
);
|
|
2104
|
+
|
|
2105
|
+
let resolvedPath = resolution.resolvedPath;
|
|
2106
|
+
|
|
2107
|
+
// Try sourceEquivalencies fallback if not controllable
|
|
2108
|
+
if (!resolution.isControllable || !resolvedPath) {
|
|
2109
|
+
if (sourceEquivalencies) {
|
|
2110
|
+
// Build the sourceEquivalencies key
|
|
2111
|
+
// The child path (e.g., "workouts") maps to a prop path (e.g., "signature[0].workouts")
|
|
2112
|
+
let childPropName: string | null = null;
|
|
2113
|
+
for (const [varName, varPath] of Object.entries(
|
|
2114
|
+
childData.equivalentSignatureVariables,
|
|
2115
|
+
)) {
|
|
2116
|
+
if (
|
|
2117
|
+
jsxUsage.path === varName ||
|
|
2118
|
+
jsxUsage.path.startsWith(`${varName}.`)
|
|
2119
|
+
) {
|
|
2120
|
+
childPropName = varName;
|
|
2121
|
+
break;
|
|
2122
|
+
}
|
|
2123
|
+
}
|
|
2124
|
+
|
|
2125
|
+
if (childPropName) {
|
|
2126
|
+
const sourceEquivKey = `${childName}().signature[0].${childPropName}`;
|
|
2127
|
+
const sourceEquivEntry = sourceEquivalencies[sourceEquivKey];
|
|
2128
|
+
|
|
2129
|
+
if (sourceEquivEntry && sourceEquivEntry.length > 0) {
|
|
2130
|
+
const dataSourcePath = sourceEquivEntry[0].schemaPath;
|
|
2131
|
+
|
|
2132
|
+
const dataSourceResolution = resolvePathToControllable(
|
|
2133
|
+
dataSourcePath,
|
|
2134
|
+
attributesMap,
|
|
2135
|
+
equivalentSignatureVariables,
|
|
2136
|
+
fullToShortPathMap,
|
|
2137
|
+
);
|
|
2138
|
+
|
|
2139
|
+
if (
|
|
2140
|
+
dataSourceResolution.isControllable &&
|
|
2141
|
+
dataSourceResolution.resolvedPath
|
|
2142
|
+
) {
|
|
2143
|
+
resolvedPath = dataSourceResolution.resolvedPath;
|
|
2144
|
+
}
|
|
2145
|
+
}
|
|
2146
|
+
}
|
|
2147
|
+
}
|
|
2148
|
+
}
|
|
2149
|
+
|
|
2150
|
+
if (!resolvedPath) {
|
|
2151
|
+
continue;
|
|
2152
|
+
}
|
|
2153
|
+
|
|
2154
|
+
// Check for duplicates
|
|
2155
|
+
const normalizedPath = normalizePathForDeduplication(
|
|
2156
|
+
resolvedPath,
|
|
2157
|
+
fullToShortPathMap,
|
|
2158
|
+
);
|
|
2159
|
+
const dedupeKey = `${normalizedPath}:${jsxUsage.renderingType}`;
|
|
2160
|
+
if (seenNormalizedPaths.has(dedupeKey)) {
|
|
2161
|
+
continue;
|
|
2162
|
+
}
|
|
2163
|
+
seenNormalizedPaths.add(dedupeKey);
|
|
2164
|
+
|
|
2165
|
+
// Generate array variation flows for array-map rendering
|
|
2166
|
+
if (jsxUsage.renderingType === 'array-map') {
|
|
2167
|
+
const baseName = generateNameFromPath(resolvedPath);
|
|
2168
|
+
const pathSlug = pathToSlug(resolvedPath);
|
|
2169
|
+
const exclusiveGroup = `array-length-${pathSlug}`;
|
|
2170
|
+
|
|
2171
|
+
// Empty array flow
|
|
2172
|
+
const emptyFlow: ExecutionFlow = {
|
|
2173
|
+
id: `${pathSlug}-empty-array`,
|
|
2174
|
+
name: `${baseName} Empty`,
|
|
2175
|
+
description: `When ${baseName.toLowerCase()} array is empty`,
|
|
2176
|
+
requiredValues: [
|
|
2177
|
+
{
|
|
2178
|
+
attributePath: resolvedPath,
|
|
2179
|
+
value: '0',
|
|
2180
|
+
comparison: 'length<',
|
|
2181
|
+
valueType: 'array',
|
|
2182
|
+
},
|
|
2183
|
+
...gatingRequiredValues,
|
|
2184
|
+
],
|
|
2185
|
+
impact: 'medium',
|
|
2186
|
+
exclusiveGroup,
|
|
2187
|
+
sourceLocation: jsxUsage.sourceLocation
|
|
2188
|
+
? {
|
|
2189
|
+
lineNumber: jsxUsage.sourceLocation.lineNumber,
|
|
2190
|
+
column: jsxUsage.sourceLocation.column,
|
|
2191
|
+
}
|
|
2192
|
+
: undefined,
|
|
2193
|
+
codeSnippet: jsxUsage.sourceLocation?.codeSnippet,
|
|
2194
|
+
};
|
|
2195
|
+
|
|
2196
|
+
if (!seenFlowIds.has(emptyFlow.id)) {
|
|
2197
|
+
seenFlowIds.add(emptyFlow.id);
|
|
2198
|
+
flows.push(emptyFlow);
|
|
2199
|
+
}
|
|
2200
|
+
|
|
2201
|
+
// Few items flow (1-3)
|
|
2202
|
+
const fewFlow: ExecutionFlow = {
|
|
2203
|
+
id: `${pathSlug}-few-items`,
|
|
2204
|
+
name: `${baseName} Few Items`,
|
|
2205
|
+
description: `When ${baseName.toLowerCase()} array has 1-3 items`,
|
|
2206
|
+
requiredValues: [
|
|
2207
|
+
{
|
|
2208
|
+
attributePath: resolvedPath,
|
|
2209
|
+
value: '3',
|
|
2210
|
+
comparison: 'length<',
|
|
2211
|
+
valueType: 'array',
|
|
2212
|
+
},
|
|
2213
|
+
...gatingRequiredValues,
|
|
2214
|
+
],
|
|
2215
|
+
impact: 'low',
|
|
2216
|
+
exclusiveGroup,
|
|
2217
|
+
sourceLocation: jsxUsage.sourceLocation
|
|
2218
|
+
? {
|
|
2219
|
+
lineNumber: jsxUsage.sourceLocation.lineNumber,
|
|
2220
|
+
column: jsxUsage.sourceLocation.column,
|
|
2221
|
+
}
|
|
2222
|
+
: undefined,
|
|
2223
|
+
codeSnippet: jsxUsage.sourceLocation?.codeSnippet,
|
|
2224
|
+
};
|
|
2225
|
+
|
|
2226
|
+
if (!seenFlowIds.has(fewFlow.id)) {
|
|
2227
|
+
seenFlowIds.add(fewFlow.id);
|
|
2228
|
+
flows.push(fewFlow);
|
|
2229
|
+
}
|
|
2230
|
+
|
|
2231
|
+
// Many items flow (10+)
|
|
2232
|
+
const manyFlow: ExecutionFlow = {
|
|
2233
|
+
id: `${pathSlug}-many-items`,
|
|
2234
|
+
name: `${baseName} Many Items`,
|
|
2235
|
+
description: `When ${baseName.toLowerCase()} array has many items`,
|
|
2236
|
+
requiredValues: [
|
|
2237
|
+
{
|
|
2238
|
+
attributePath: resolvedPath,
|
|
2239
|
+
value: '10',
|
|
2240
|
+
comparison: 'length>',
|
|
2241
|
+
valueType: 'array',
|
|
2242
|
+
},
|
|
2243
|
+
...gatingRequiredValues,
|
|
2244
|
+
],
|
|
2245
|
+
impact: 'low',
|
|
2246
|
+
exclusiveGroup,
|
|
2247
|
+
sourceLocation: jsxUsage.sourceLocation
|
|
2248
|
+
? {
|
|
2249
|
+
lineNumber: jsxUsage.sourceLocation.lineNumber,
|
|
2250
|
+
column: jsxUsage.sourceLocation.column,
|
|
2251
|
+
}
|
|
2252
|
+
: undefined,
|
|
2253
|
+
codeSnippet: jsxUsage.sourceLocation?.codeSnippet,
|
|
2254
|
+
};
|
|
2255
|
+
|
|
2256
|
+
if (!seenFlowIds.has(manyFlow.id)) {
|
|
2257
|
+
seenFlowIds.add(manyFlow.id);
|
|
2258
|
+
flows.push(manyFlow);
|
|
2259
|
+
}
|
|
2260
|
+
}
|
|
2261
|
+
}
|
|
2262
|
+
}
|
|
1973
2263
|
}
|
|
1974
2264
|
}
|
|
1975
2265
|
|
|
@@ -19,7 +19,7 @@ export interface GenerateFlowsFromJsxUsagesArgs {
|
|
|
19
19
|
/** Map of controllable paths to their types */
|
|
20
20
|
attributesMap: Record<string, string>;
|
|
21
21
|
/** Map from local variable names to data sources */
|
|
22
|
-
equivalentSignatureVariables: Record<string, string>;
|
|
22
|
+
equivalentSignatureVariables: Record<string, string | string[]>;
|
|
23
23
|
/** Map from full paths to short paths */
|
|
24
24
|
fullToShortPathMap: Record<string, string>;
|
|
25
25
|
/** Structure map for type lookup */
|
|
@@ -7,58 +7,12 @@ import {
|
|
|
7
7
|
|
|
8
8
|
export interface Statement {
|
|
9
9
|
structure: { [key: string]: string };
|
|
10
|
-
|
|
10
|
+
// Supports multiple equivalencies per key for OR expressions (e.g., x = a || b)
|
|
11
|
+
equivalentVariables: { [key: string]: string | string[] };
|
|
11
12
|
llmCall?: LlmCall;
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
export default function mergeStatements(statements: Statement[]) {
|
|
15
|
-
// Debug: Log input statements to understand what we're merging
|
|
16
|
-
const hasStateStructure = statements.some((s) =>
|
|
17
|
-
Object.keys(s.structure || {}).some(
|
|
18
|
-
(k) => k === 'state' || k.includes('state'),
|
|
19
|
-
),
|
|
20
|
-
);
|
|
21
|
-
const hasStateEquiv = statements.some((s) =>
|
|
22
|
-
Object.keys(s.equivalentVariables || {}).some(
|
|
23
|
-
(k) => k === 'state' || k.includes('state'),
|
|
24
|
-
),
|
|
25
|
-
);
|
|
26
|
-
if (hasStateStructure || hasStateEquiv) {
|
|
27
|
-
console.log(
|
|
28
|
-
`[UNION-TYPE] mergeStatements INPUT: ${statements.length} statements`,
|
|
29
|
-
);
|
|
30
|
-
statements.forEach((s, i) => {
|
|
31
|
-
const stateInStructure = Object.entries(s.structure || {}).filter(
|
|
32
|
-
([k]) => k === 'state' || k.includes('state'),
|
|
33
|
-
);
|
|
34
|
-
const stateInEquiv = Object.entries(s.equivalentVariables || {}).filter(
|
|
35
|
-
([k]) => k === 'state' || k.includes('state'),
|
|
36
|
-
);
|
|
37
|
-
const sigInEquiv = Object.entries(s.equivalentVariables || {}).filter(
|
|
38
|
-
([k, v]) => k === 'state' || v === 'signature[0]',
|
|
39
|
-
);
|
|
40
|
-
if (
|
|
41
|
-
stateInStructure.length > 0 ||
|
|
42
|
-
stateInEquiv.length > 0 ||
|
|
43
|
-
sigInEquiv.length > 0
|
|
44
|
-
) {
|
|
45
|
-
console.log(`[UNION-TYPE] Statement ${i}:`);
|
|
46
|
-
if (stateInStructure.length > 0)
|
|
47
|
-
console.log(
|
|
48
|
-
`[UNION-TYPE] structure: ${JSON.stringify(Object.fromEntries(stateInStructure))}`,
|
|
49
|
-
);
|
|
50
|
-
if (stateInEquiv.length > 0)
|
|
51
|
-
console.log(
|
|
52
|
-
`[UNION-TYPE] equivalentVariables (state): ${JSON.stringify(Object.fromEntries(stateInEquiv))}`,
|
|
53
|
-
);
|
|
54
|
-
if (sigInEquiv.length > 0)
|
|
55
|
-
console.log(
|
|
56
|
-
`[UNION-TYPE] equivalentVariables (sig): ${JSON.stringify(Object.fromEntries(sigInEquiv))}`,
|
|
57
|
-
);
|
|
58
|
-
}
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
|
|
62
16
|
// This should be handled by the AST Analyzer but it currently has a bug
|
|
63
17
|
const ensureFunctionCallReturnValue = (path: string, value: string) => {
|
|
64
18
|
if (path.endsWith(')') && value !== 'function') {
|
|
@@ -172,12 +126,54 @@ export default function mergeStatements(statements: Statement[]) {
|
|
|
172
126
|
// settingsData → fetcher.data.data uses fetcher::cyDuplicateKey1::.data.data
|
|
173
127
|
const activeRemappings: Record<string, string> = {};
|
|
174
128
|
|
|
129
|
+
// Helper to normalize value to array and process
|
|
130
|
+
const normalizeValue = (value: string | string[]): string[] =>
|
|
131
|
+
Array.isArray(value) ? value : [value];
|
|
132
|
+
|
|
175
133
|
const equivalentVariables = statements.reduce((acc: any, result) => {
|
|
176
|
-
for (const [key,
|
|
134
|
+
for (const [key, rawValue] of Object.entries(
|
|
177
135
|
result.equivalentVariables ?? {},
|
|
178
136
|
)) {
|
|
137
|
+
// Handle arrays from AST analyzer (OR expressions like x = a || b)
|
|
138
|
+
// These should be preserved as arrays to track all sources
|
|
139
|
+
if (Array.isArray(rawValue)) {
|
|
140
|
+
const keyOptions = deBinaryPath(key);
|
|
141
|
+
const validValues = rawValue.filter(
|
|
142
|
+
(v): v is string => typeof v === 'string' && v.length > 0,
|
|
143
|
+
);
|
|
144
|
+
if (validValues.length === 0) continue;
|
|
145
|
+
|
|
146
|
+
// Process each array value through deBinaryPath
|
|
147
|
+
const allValueOptions: string[] = [];
|
|
148
|
+
for (const value of validValues) {
|
|
149
|
+
const valueOptions = deBinaryPath(value);
|
|
150
|
+
allValueOptions.push(...valueOptions);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Remove duplicates while preserving order
|
|
154
|
+
const uniqueValueOptions = [...new Set(allValueOptions)];
|
|
155
|
+
const finalValue =
|
|
156
|
+
uniqueValueOptions.length === 1
|
|
157
|
+
? uniqueValueOptions[0]
|
|
158
|
+
: uniqueValueOptions;
|
|
159
|
+
|
|
160
|
+
delete result.equivalentVariables[key];
|
|
161
|
+
if (keyOptions.length >= 2) {
|
|
162
|
+
for (const keyOption of keyOptions) {
|
|
163
|
+
result.equivalentVariables[keyOption] = finalValue;
|
|
164
|
+
}
|
|
165
|
+
} else {
|
|
166
|
+
result.equivalentVariables[keyOptions[0]] = finalValue;
|
|
167
|
+
}
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Original logic for string values with potential binary expressions in the string
|
|
172
|
+
const firstValue = rawValue;
|
|
173
|
+
if (!firstValue) continue;
|
|
174
|
+
|
|
179
175
|
const keyOptions = deBinaryPath(key);
|
|
180
|
-
const valueOptions = deBinaryPath(
|
|
176
|
+
const valueOptions = deBinaryPath(firstValue);
|
|
181
177
|
delete result.equivalentVariables[key];
|
|
182
178
|
if (keyOptions.length === 2) {
|
|
183
179
|
if (valueOptions.length === 2) {
|
|
@@ -199,27 +195,38 @@ export default function mergeStatements(statements: Statement[]) {
|
|
|
199
195
|
}
|
|
200
196
|
}
|
|
201
197
|
|
|
202
|
-
for (const [key,
|
|
198
|
+
for (const [key, rawValue] of Object.entries(
|
|
203
199
|
result.equivalentVariables ?? {},
|
|
204
200
|
)) {
|
|
201
|
+
// Normalize to array for consistent handling
|
|
202
|
+
const values = normalizeValue(rawValue);
|
|
203
|
+
|
|
205
204
|
// Apply any active remappings to the VALUE, but ONLY for property paths
|
|
206
205
|
// e.g., if fetcher was remapped to fetcher::cyDuplicateKey1::,
|
|
207
206
|
// then "fetcher.data.data" should become "fetcher::cyDuplicateKey1::.data.data"
|
|
208
207
|
// However, we should NOT remap standalone variable references like "description"
|
|
209
208
|
// because that would lose type information from the original variable.
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
209
|
+
const remappedValues = values.map((value) => {
|
|
210
|
+
let remappedValue = value;
|
|
211
|
+
for (const [originalKey, remappedKey] of Object.entries(
|
|
212
|
+
activeRemappings,
|
|
213
|
+
)) {
|
|
214
|
+
// Only remap if the value is a property path (contains a dot after the key)
|
|
215
|
+
// This preserves type information for simple variable references
|
|
216
|
+
const keyRegex = new RegExp(
|
|
217
|
+
`^${originalKey.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}(?=\\.)`,
|
|
218
|
+
);
|
|
219
|
+
if (keyRegex.test(remappedValue)) {
|
|
220
|
+
remappedValue = remappedValue.replace(keyRegex, remappedKey);
|
|
221
|
+
}
|
|
221
222
|
}
|
|
222
|
-
|
|
223
|
+
return remappedValue;
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
// Use array if multiple values, string if single
|
|
227
|
+
const remappedValue =
|
|
228
|
+
remappedValues.length === 1 ? remappedValues[0] : remappedValues;
|
|
229
|
+
const firstRemappedValue = remappedValues[0];
|
|
223
230
|
|
|
224
231
|
if (acc[key]) {
|
|
225
232
|
if (acc[key] === remappedValue) continue;
|
|
@@ -247,45 +254,32 @@ export default function mergeStatements(statements: Statement[]) {
|
|
|
247
254
|
// If we have equivalentVariables[A] = B, and structure[A] is more specific than structure[B],
|
|
248
255
|
// then update structure[B] to match structure[A]
|
|
249
256
|
// This handles cases like: "state" -> "signature[0]" where "state" has a union type
|
|
250
|
-
|
|
251
|
-
// Debug: Log union types in merged structure
|
|
252
|
-
const unionTypesInStructure = Object.entries(structure).filter(
|
|
253
|
-
([_, v]) => typeof v === 'string' && v.includes("'") && v.includes(' | '),
|
|
254
|
-
);
|
|
255
|
-
if (unionTypesInStructure.length > 0) {
|
|
256
|
-
console.log(
|
|
257
|
-
`[UNION-TYPE] mergeStatements: Found ${unionTypesInStructure.length} union types in merged structure`,
|
|
258
|
-
);
|
|
259
|
-
unionTypesInStructure.forEach(([k, v]) =>
|
|
260
|
-
console.log(`[UNION-TYPE] structure["${k}"] = ${v}`),
|
|
261
|
-
);
|
|
262
|
-
console.log(
|
|
263
|
-
`[UNION-TYPE] mergeStatements: equivalentVariables = ${JSON.stringify(equivalentVariables)}`,
|
|
264
|
-
);
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
for (const [source, target] of Object.entries(equivalentVariables) as [
|
|
268
|
-
string,
|
|
257
|
+
for (const [source, rawTarget] of Object.entries(equivalentVariables) as [
|
|
269
258
|
string,
|
|
259
|
+
string | string[],
|
|
270
260
|
][]) {
|
|
261
|
+
// Normalize to array for consistent handling
|
|
262
|
+
const targets = Array.isArray(rawTarget) ? rawTarget : [rawTarget];
|
|
271
263
|
const sourceType = structure[source];
|
|
272
|
-
const targetType = structure[target];
|
|
273
264
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
const sourceIsUnion =
|
|
277
|
-
sourceType.includes("'") && sourceType.includes(' | ');
|
|
265
|
+
for (const target of targets) {
|
|
266
|
+
if (typeof target !== 'string') continue;
|
|
278
267
|
|
|
279
|
-
|
|
280
|
-
// Target doesn't exist or is generic - propagate the union type
|
|
281
|
-
const targetIsGeneric =
|
|
282
|
-
!targetType || targetType === 'string' || targetType === 'unknown';
|
|
268
|
+
const targetType = structure[target];
|
|
283
269
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
);
|
|
288
|
-
|
|
270
|
+
// Check if source has a more specific type (union type vs generic type)
|
|
271
|
+
if (sourceType) {
|
|
272
|
+
const sourceIsUnion =
|
|
273
|
+
sourceType.includes("'") && sourceType.includes(' | ');
|
|
274
|
+
|
|
275
|
+
if (sourceIsUnion) {
|
|
276
|
+
// Target doesn't exist or is generic - propagate the union type
|
|
277
|
+
const targetIsGeneric =
|
|
278
|
+
!targetType || targetType === 'string' || targetType === 'unknown';
|
|
279
|
+
|
|
280
|
+
if (targetIsGeneric) {
|
|
281
|
+
structure[target] = sourceType;
|
|
282
|
+
}
|
|
289
283
|
}
|
|
290
284
|
}
|
|
291
285
|
}
|
|
@@ -139,16 +139,19 @@ export function gatherAttributesMap(
|
|
|
139
139
|
// Use merged type if available, otherwise fall back to isolated type
|
|
140
140
|
const typeValue =
|
|
141
141
|
mergedSignatureSchema[key] ?? isolatedSignatureSchema[key];
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
|
|
142
|
+
// Handle array case (OR expressions) - use first element if array
|
|
143
|
+
const rawEquivalent = equivalentSignatureVariables[keyParts[0]];
|
|
144
|
+
const equivalentSignatureVariable = Array.isArray(rawEquivalent)
|
|
145
|
+
? rawEquivalent[0]
|
|
146
|
+
: rawEquivalent;
|
|
147
|
+
const equivalentSignatureVariableParts = equivalentSignatureVariable
|
|
148
|
+
? splitOutsideParenthesesAndArrays(equivalentSignatureVariable)
|
|
149
|
+
: [];
|
|
147
150
|
if (
|
|
148
151
|
equivalentSignatureVariable &&
|
|
149
|
-
!equivalentSignatureVariableParts[0]
|
|
152
|
+
!equivalentSignatureVariableParts[0]?.includes('(')
|
|
150
153
|
) {
|
|
151
|
-
const equivalentKey =
|
|
154
|
+
const equivalentKey = equivalentSignatureVariable;
|
|
152
155
|
const equivalentPath = joinParenthesesAndArrays([
|
|
153
156
|
equivalentKey,
|
|
154
157
|
...keyParts.slice(1),
|