@codeyam/codeyam-cli 0.1.0-staging.c9dc00c → 0.1.0-staging.d3e886e
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 +1 -1
- package/analyzer-template/packages/ai/index.ts +1 -0
- package/analyzer-template/packages/ai/src/lib/analyzeScope.ts +14 -0
- package/analyzer-template/packages/ai/src/lib/astScopes/processExpression.ts +101 -0
- package/analyzer-template/packages/ai/src/lib/astScopes/sharedPatterns.ts +28 -0
- package/analyzer-template/packages/ai/src/lib/astScopes/types.ts +6 -0
- package/analyzer-template/packages/ai/src/lib/dataStructure/ScopeDataStructure.ts +172 -8
- package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/convertDotNotation.ts +70 -19
- package/analyzer-template/packages/ai/src/lib/dataStructureChunking.ts +40 -13
- package/analyzer-template/packages/ai/src/lib/generateEntityScenarioData.ts +32 -5
- package/analyzer-template/packages/ai/src/lib/generateExecutionFlows.ts +134 -2
- package/analyzer-template/packages/ai/src/lib/generateExecutionFlowsFromConditionals.ts +359 -142
- package/analyzer-template/packages/ai/src/lib/mergeJsonTypeDefinitions.ts +5 -0
- package/analyzer-template/packages/ai/src/lib/promptGenerators/collapseNullableObjects.ts +118 -0
- package/analyzer-template/packages/ai/src/lib/promptGenerators/generateEntityScenarioDataGenerator.ts +24 -4
- package/analyzer-template/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.ts +18 -0
- package/analyzer-template/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.ts +50 -25
- package/analyzer-template/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.ts +153 -76
- package/analyzer-template/packages/database/src/lib/kysely/tables/debugReportsTable.ts +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/debugReportsTable.d.ts +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/src/lib/fs/rsyncCopy.ts +108 -2
- package/analyzer-template/project/constructMockCode.ts +2 -2
- package/analyzer-template/project/writeScenarioComponents.ts +14 -0
- package/background/src/lib/virtualized/project/constructMockCode.js +2 -2
- package/background/src/lib/virtualized/project/constructMockCode.js.map +1 -1
- package/background/src/lib/virtualized/project/writeScenarioComponents.js +10 -0
- package/background/src/lib/virtualized/project/writeScenarioComponents.js.map +1 -1
- package/codeyam-cli/scripts/apply-setup.js +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 +2 -2
- package/codeyam-cli/src/commands/analyze.js.map +1 -1
- package/codeyam-cli/src/commands/default.js +18 -17
- package/codeyam-cli/src/commands/default.js.map +1 -1
- package/codeyam-cli/src/commands/init.js +27 -93
- package/codeyam-cli/src/commands/init.js.map +1 -1
- package/codeyam-cli/src/commands/memory.js +9 -9
- package/codeyam-cli/src/commands/memory.js.map +1 -1
- package/codeyam-cli/src/commands/setup-simulations.js +1 -1
- package/codeyam-cli/src/commands/verify.js +12 -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 +11 -11
- package/codeyam-cli/src/utils/backgroundServer.js +90 -23
- 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 +13 -13
- package/codeyam-cli/src/utils/labsAutoCheck.js +0 -29
- package/codeyam-cli/src/utils/labsAutoCheck.js.map +1 -1
- package/codeyam-cli/src/utils/npmVersionCheck.js +76 -0
- package/codeyam-cli/src/utils/npmVersionCheck.js.map +1 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/contextBuilder.test.js +4 -4
- package/codeyam-cli/src/utils/ruleReflection/__tests__/contextBuilder.test.js.map +1 -1
- package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/ruleReflectionE2E.test.js +2 -2
- package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/ruleReflectionE2E.test.js.map +1 -1
- package/codeyam-cli/src/utils/ruleReflection/__tests__/promptBuilder.test.js +4 -4
- package/codeyam-cli/src/utils/ruleReflection/__tests__/promptBuilder.test.js.map +1 -1
- package/codeyam-cli/src/utils/ruleReflection/contextBuilder.js +3 -3
- package/codeyam-cli/src/utils/ruleReflection/contextBuilder.js.map +1 -1
- package/codeyam-cli/src/utils/rules/__tests__/ruleState.test.js +23 -23
- package/codeyam-cli/src/utils/rules/__tests__/ruleState.test.js.map +1 -1
- package/codeyam-cli/src/utils/rules/ruleState.js +10 -10
- package/codeyam-cli/src/utils/rules/ruleState.js.map +1 -1
- package/codeyam-cli/src/utils/rules/staleness.js +6 -6
- package/codeyam-cli/src/utils/rules/staleness.js.map +1 -1
- 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 +7 -7
- 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/dbNotifier.js.map +1 -1
- package/codeyam-cli/src/webserver/backgroundServer.js +26 -7
- package/codeyam-cli/src/webserver/backgroundServer.js.map +1 -1
- package/codeyam-cli/src/webserver/bootstrap.js +11 -0
- package/codeyam-cli/src/webserver/bootstrap.js.map +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{CopyButton-CA3JxPb7.js → CopyButton-jNYXRRNI.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{EntityItem-B86KKU7e.js → EntityItem-bwuHPyTa.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{EntityTypeBadge-B5ctlSYt.js → EntityTypeBadge-CvzqMxcu.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{EntityTypeIcon-BqY8gDAW.js → EntityTypeIcon-BH0XDim7.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{InlineSpinner-ClaLpuOo.js → InlineSpinner-EhOseatT.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{InteractivePreview-BDhPilK7.js → InteractivePreview-yjIHlOGa.js} +2 -2
- package/codeyam-cli/src/webserver/build/client/assets/{LibraryFunctionPreview-VeqEBv9v.js → LibraryFunctionPreview-Cq5o8jL4.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{LoadingDots-Bs7Nn1Jr.js → LoadingDots-BvMu2i-g.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{LogViewer-Bm3PmcCz.js → LogViewer-kgBTLoJD.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{ReportIssueModal-C6PKeMYR.js → ReportIssueModal-BzPgx-xO.js} +2 -2
- package/codeyam-cli/src/webserver/build/client/assets/{SafeScreenshot-Gq3Ocjo6.js → SafeScreenshot-CwZrv-Ok.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{ScenarioViewer-BNLaXBHR.js → ScenarioViewer-BX2Ny2Qj.js} +2 -2
- package/codeyam-cli/src/webserver/build/client/assets/{TruncatedFilePath-CiwXDxLh.js → TruncatedFilePath-CDpEprKa.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{_index-B3TDXxnk.js → _index-BRx8ZGZo.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{activity.(_tab)-BtBFH820.js → activity.(_tab)-4S4yPfFw.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/agent-transcripts-DHKuQSmR.js +17 -0
- package/codeyam-cli/src/webserver/build/client/assets/{book-open-PttOB2SF.js → book-open-D4IPYH_y.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{chevron-down-TJp6ofnp.js → chevron-down-CG65viiV.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{chunk-JZWAC4HX-JE9ZIoBl.js → chunk-JZWAC4HX-DB3aFuEO.js} +9 -9
- package/codeyam-cli/src/webserver/build/client/assets/{circle-check-CXhHQYrI.js → circle-check-igfMr5DY.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{copy-6y9ALfGT.js → copy-Coc4o_8c.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{createLucideIcon-Ca9fAY46.js → createLucideIcon-D1zB-pYc.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{dev.empty-C5lqplTC.js → dev.empty-JTAjQ54M.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{entity._sha._-n38keI1k.js → entity._sha._-B0h9AqE6.js} +2 -2
- package/codeyam-cli/src/webserver/build/client/assets/{entity._sha.scenarios._scenarioId.fullscreen-CBoafmVs.js → entity._sha.scenarios._scenarioId.fullscreen-DjLxr2JB.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{entity._sha_.create-scenario-DGgZjdFg.js → entity._sha_.create-scenario-CtYowLOt.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{entity._sha_.edit._scenarioId-38yPijoD.js → entity._sha_.edit._scenarioId-PePWg17F.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{entry.client-BSHEfydn.js → entry.client-I-Wo99C_.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{fileTableUtils-DCPhhSMo.js → fileTableUtils-9sMMAiWJ.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{files-0N0YJQv7.js → files-Co65J0s3.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{git-DXnyr8uP.js → git-BdHOxVfg.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/globals-CCgBKWy4.css +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/{index-ChN9-fAY.js → index-CUM5iXwc.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{index-CcsFv748.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-CTqLEAGU.js → loader-circle-TzRHMVog.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/manifest-390cb8fa.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/memory-CzZySbBE.js +78 -0
- package/codeyam-cli/src/webserver/build/client/assets/{pause-D6vreykR.js → pause-hjzB7t2z.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/root-DnbDhvTU.js +62 -0
- package/codeyam-cli/src/webserver/build/client/assets/{search-B8VUL8nl.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-CPoAg7Zo.js → simulations-DVNJVQgD.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{terminal-BrCP7uQo.js → terminal-DbEAHMbA.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{triangle-alert-BZz2NjYa.js → triangle-alert-CAD5b1o_.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{useCustomSizes-DNwUduNu.js → useCustomSizes-BqgrAzs3.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{useLastLogLine-COky1GVF.js → useLastLogLine-DAFqfEDH.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{useReportContext-CpZgwliL.js → useReportContext-DZlYx2c4.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{useToast-Bv9JFvUO.js → useToast-ihdMtlf6.js} +1 -1
- package/codeyam-cli/src/webserver/build/server/assets/{index-Cz2RkDCa.js → index-CxaRxKVt.js} +1 -1
- package/codeyam-cli/src/webserver/build/server/assets/server-build-D4DT0nM_.js +259 -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} +1 -1
- package/codeyam-cli/templates/{codeyam:diagnose.md → codeyam-diagnose.md} +1 -1
- package/codeyam-cli/templates/codeyam-memory-hook.sh +14 -14
- package/codeyam-cli/templates/{codeyam:memory.md → codeyam-memory.md} +16 -23
- package/codeyam-cli/templates/{codeyam:new-rule.md → codeyam-new-rule.md} +1 -1
- package/codeyam-cli/templates/{codeyam:setup.md → codeyam-setup.md} +1 -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-reflection-hook.py +5 -5
- package/codeyam-cli/templates/rules-instructions.md +11 -15
- package/package.json +8 -8
- package/packages/ai/index.js +1 -1
- package/packages/ai/index.js.map +1 -1
- package/packages/ai/src/lib/analyzeScope.js +14 -0
- package/packages/ai/src/lib/analyzeScope.js.map +1 -1
- package/packages/ai/src/lib/astScopes/processExpression.js +78 -1
- 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/dataStructure/ScopeDataStructure.js +124 -7
- package/packages/ai/src/lib/dataStructure/ScopeDataStructure.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/helpers/convertDotNotation.js +59 -17
- package/packages/ai/src/lib/dataStructure/helpers/convertDotNotation.js.map +1 -1
- package/packages/ai/src/lib/dataStructureChunking.js +30 -11
- package/packages/ai/src/lib/dataStructureChunking.js.map +1 -1
- package/packages/ai/src/lib/generateEntityScenarioData.js +22 -3
- package/packages/ai/src/lib/generateEntityScenarioData.js.map +1 -1
- package/packages/ai/src/lib/generateExecutionFlows.js +97 -2
- package/packages/ai/src/lib/generateExecutionFlows.js.map +1 -1
- package/packages/ai/src/lib/generateExecutionFlowsFromConditionals.js +242 -81
- package/packages/ai/src/lib/generateExecutionFlowsFromConditionals.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/promptGenerators/collapseNullableObjects.js +97 -0
- package/packages/ai/src/lib/promptGenerators/collapseNullableObjects.js.map +1 -0
- package/packages/ai/src/lib/promptGenerators/generateEntityScenarioDataGenerator.js +17 -2
- package/packages/ai/src/lib/promptGenerators/generateEntityScenarioDataGenerator.js.map +1 -1
- package/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.js +11 -1
- package/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.js.map +1 -1
- package/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.js +42 -13
- package/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.js.map +1 -1
- package/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.js +123 -67
- package/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.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/codeyam-cli/src/webserver/build/client/assets/agent-transcripts-CN61MOMa.js +0 -11
- package/codeyam-cli/src/webserver/build/client/assets/api.labs-survey-l0sNRNKZ.js +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/globals-EVn6Z9pz.css +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/labs-CmBYA0PH.js +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/manifest-aa4ff97b.js +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/memory-BSlqS1QA.js +0 -81
- package/codeyam-cli/src/webserver/build/client/assets/root-DVAbJY8B.js +0 -62
- package/codeyam-cli/src/webserver/build/client/assets/settings-BK-cnzp-.js +0 -1
- package/codeyam-cli/src/webserver/build/server/assets/server-build-CUVsWicu.js +0 -260
|
@@ -259,11 +259,15 @@ function cleanSourceDataPath(sourceDataPath: string): string | null {
|
|
|
259
259
|
sourceDataPath.match(/\.functionCallReturnValue/g) || []
|
|
260
260
|
).length;
|
|
261
261
|
|
|
262
|
-
//
|
|
263
|
-
//
|
|
262
|
+
// For chained function calls (e.g., fetch().json()) or paths with non-standard
|
|
263
|
+
// fn call patterns, return the original path so findInAttributesMapForPath can
|
|
264
|
+
// try to look it up in fullToShortPathMap. If it doesn't match, the caller
|
|
265
|
+
// falls through to fallback resolution anyway.
|
|
264
266
|
if (fnCallReturnValues > 1 || emptyFnCalls !== 1) {
|
|
265
|
-
|
|
266
|
-
|
|
267
|
+
console.log(
|
|
268
|
+
`[cleanSourceDataPath] chained/non-standard path (fnCallRVs=${fnCallReturnValues}, emptyFnCalls=${emptyFnCalls}), returning original: "${sourceDataPath}"`,
|
|
269
|
+
);
|
|
270
|
+
return sourceDataPath;
|
|
267
271
|
}
|
|
268
272
|
|
|
269
273
|
// Find the "()" which marks the function call
|
|
@@ -308,6 +312,85 @@ function stripLengthSuffix(path: string): string {
|
|
|
308
312
|
return path;
|
|
309
313
|
}
|
|
310
314
|
|
|
315
|
+
/**
|
|
316
|
+
* Remove contradictory required values from a compound flow.
|
|
317
|
+
*
|
|
318
|
+
* When a lifecycle boolean (like isLoadingAuditData) is traced to a fetch call's
|
|
319
|
+
* return value, a negated condition (!isLoadingAuditData) produces "falsy" on
|
|
320
|
+
* the fetch path. But if another condition in the same compound requires data
|
|
321
|
+
* from a sub-path of that fetch (e.g., topPaths length > 0), the "falsy" on the
|
|
322
|
+
* parent path contradicts it — a null/falsy response has no .json() to call.
|
|
323
|
+
*
|
|
324
|
+
* This function removes "falsy" required values whose attributePath is a prefix
|
|
325
|
+
* of another required value's attributePath. The child data requirement already
|
|
326
|
+
* implies the parent (fetch) succeeded.
|
|
327
|
+
*/
|
|
328
|
+
function removeContradictoryFalsyValues(
|
|
329
|
+
requiredValues: ExecutionFlow['requiredValues'],
|
|
330
|
+
): ExecutionFlow['requiredValues'] {
|
|
331
|
+
return requiredValues.filter((rv) => {
|
|
332
|
+
if (rv.comparison === 'falsy') {
|
|
333
|
+
const hasChildRequirement = requiredValues.some(
|
|
334
|
+
(other) =>
|
|
335
|
+
other !== rv &&
|
|
336
|
+
other.attributePath.startsWith(rv.attributePath + '.'),
|
|
337
|
+
);
|
|
338
|
+
if (hasChildRequirement) {
|
|
339
|
+
return false;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
return true;
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* Generate a human-readable description snippet for a required value,
|
|
348
|
+
* incorporating the comparison type so the LLM understands the intent.
|
|
349
|
+
*/
|
|
350
|
+
function describeRequiredValue(rv: ExecutionFlow['requiredValues'][0]): string {
|
|
351
|
+
const name = generateNameFromPath(rv.attributePath).toLowerCase();
|
|
352
|
+
switch (rv.comparison) {
|
|
353
|
+
case 'truthy':
|
|
354
|
+
return `${name} is present`;
|
|
355
|
+
case 'falsy':
|
|
356
|
+
return `${name} is absent`;
|
|
357
|
+
case 'length>':
|
|
358
|
+
return rv.value === '0'
|
|
359
|
+
? `${name} has items`
|
|
360
|
+
: `${name} has more than ${rv.value} items`;
|
|
361
|
+
case 'length<':
|
|
362
|
+
return `${name} has fewer than ${rv.value} items`;
|
|
363
|
+
case 'equals':
|
|
364
|
+
return `${name} is ${rv.value}`;
|
|
365
|
+
case 'exists':
|
|
366
|
+
return `${name} exists`;
|
|
367
|
+
case 'not-exists':
|
|
368
|
+
return `${name} does not exist`;
|
|
369
|
+
default:
|
|
370
|
+
return `${name} is ${rv.value}`;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Check whether a resolved path has child entries in the fullToShortPathMap.
|
|
376
|
+
*
|
|
377
|
+
* When a lifecycle boolean (e.g., isLoadingAuditData) resolves to a parent path
|
|
378
|
+
* like fetch(...).functionCallReturnValue, and that path has children (like
|
|
379
|
+
* .json().functionCallReturnValue.topPaths), individual truthy/falsy flows on
|
|
380
|
+
* the parent are misleading. Compound flows with specific child requirements
|
|
381
|
+
* provide better guidance for mock data generation.
|
|
382
|
+
*/
|
|
383
|
+
function hasChildPathsInMap(
|
|
384
|
+
resolvedPath: string,
|
|
385
|
+
fullToShortPathMap: Record<string, string>,
|
|
386
|
+
): boolean {
|
|
387
|
+
return Object.keys(fullToShortPathMap).some(
|
|
388
|
+
(fullPath) =>
|
|
389
|
+
fullPath.startsWith(resolvedPath + '.') ||
|
|
390
|
+
fullPath.startsWith(resolvedPath + '['),
|
|
391
|
+
);
|
|
392
|
+
}
|
|
393
|
+
|
|
311
394
|
/**
|
|
312
395
|
* Extract the controllable base path from a path that may contain method calls.
|
|
313
396
|
*
|
|
@@ -350,13 +433,16 @@ function extractControllableBase(path: string): string {
|
|
|
350
433
|
* The sourceDataPath contains full paths (e.g., "useLoaderData<LoaderData>().functionCallReturnValue.entity.sha")
|
|
351
434
|
* The fullToShortPathMap maps full paths to short paths
|
|
352
435
|
*/
|
|
353
|
-
function findInAttributesMapForPath(
|
|
436
|
+
export function findInAttributesMapForPath(
|
|
354
437
|
path: string,
|
|
355
438
|
attributesMap: Record<string, string>,
|
|
356
439
|
fullToShortPathMap: Record<string, string>,
|
|
357
440
|
): string | null {
|
|
358
441
|
// Direct match in attributesMap (already a short path)
|
|
359
442
|
if (path in attributesMap) {
|
|
443
|
+
console.log(
|
|
444
|
+
`[findInAttributesMapForPath] "${path}" → DIRECT match in attributesMap`,
|
|
445
|
+
);
|
|
360
446
|
return path;
|
|
361
447
|
}
|
|
362
448
|
|
|
@@ -365,19 +451,31 @@ function findInAttributesMapForPath(
|
|
|
365
451
|
if (path in fullToShortPathMap) {
|
|
366
452
|
const shortPath = fullToShortPathMap[path];
|
|
367
453
|
if (shortPath in attributesMap) {
|
|
454
|
+
console.log(
|
|
455
|
+
`[findInAttributesMapForPath] "${path}" → fullToShortPathMap match: shortPath="${shortPath}" found in attributesMap`,
|
|
456
|
+
);
|
|
368
457
|
return path; // Return FULL path to preserve data source context
|
|
369
458
|
}
|
|
459
|
+
console.log(
|
|
460
|
+
`[findInAttributesMapForPath] "${path}" → fullToShortPathMap match shortPath="${shortPath}" but NOT in attributesMap`,
|
|
461
|
+
);
|
|
370
462
|
}
|
|
371
463
|
|
|
372
464
|
// Normalized match (array indices [N] → [])
|
|
373
465
|
const normalizedPath = path.replace(/\[\d+\]/g, '[]');
|
|
374
466
|
if (normalizedPath !== path) {
|
|
375
467
|
if (normalizedPath in attributesMap) {
|
|
468
|
+
console.log(
|
|
469
|
+
`[findInAttributesMapForPath] "${path}" → normalized "${normalizedPath}" DIRECT match in attributesMap`,
|
|
470
|
+
);
|
|
376
471
|
return normalizedPath;
|
|
377
472
|
}
|
|
378
473
|
if (normalizedPath in fullToShortPathMap) {
|
|
379
474
|
const shortPath = fullToShortPathMap[normalizedPath];
|
|
380
475
|
if (shortPath in attributesMap) {
|
|
476
|
+
console.log(
|
|
477
|
+
`[findInAttributesMapForPath] "${path}" → normalized "${normalizedPath}" fullToShortPathMap match: shortPath="${shortPath}"`,
|
|
478
|
+
);
|
|
381
479
|
return normalizedPath; // Return normalized FULL path
|
|
382
480
|
}
|
|
383
481
|
}
|
|
@@ -389,22 +487,75 @@ function findInAttributesMapForPath(
|
|
|
389
487
|
// and we need to find matching short path prefix
|
|
390
488
|
for (const attrPath of Object.keys(attributesMap)) {
|
|
391
489
|
if (path.startsWith(attrPath + '.') || path.startsWith(attrPath + '[')) {
|
|
392
|
-
|
|
490
|
+
console.log(
|
|
491
|
+
`[findInAttributesMapForPath] "${path}" → PREFIX match: starts with attributesMap key "${attrPath}"`,
|
|
492
|
+
);
|
|
393
493
|
return path;
|
|
394
494
|
}
|
|
395
495
|
}
|
|
396
496
|
|
|
397
497
|
// Try suffix matching: if the path ends with ".X.Y.Z" and attributesMap has "X.Y.Z"
|
|
398
498
|
// Return the FULL input path to preserve data source context
|
|
399
|
-
for
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
)
|
|
404
|
-
|
|
499
|
+
// Skip suffix matching for chained function calls (multiple .functionCallReturnValue segments)
|
|
500
|
+
// to avoid false matches: e.g., fetch(...).json().functionCallReturnValue.data falsely matching
|
|
501
|
+
// "data" from a completely different data source like useFetcher
|
|
502
|
+
const fnCallReturnValueCount = (
|
|
503
|
+
path.match(/\.functionCallReturnValue/g) || []
|
|
504
|
+
).length;
|
|
505
|
+
if (fnCallReturnValueCount <= 1) {
|
|
506
|
+
for (const attrPath of Object.keys(attributesMap)) {
|
|
507
|
+
if (
|
|
508
|
+
path.endsWith('.' + attrPath) ||
|
|
509
|
+
path.endsWith('.' + attrPath.replace(/\[\d+\]/g, '[]'))
|
|
510
|
+
) {
|
|
511
|
+
console.log(
|
|
512
|
+
`[findInAttributesMapForPath] "${path}" → SUFFIX match: ends with attributesMap key "${attrPath}"`,
|
|
513
|
+
);
|
|
514
|
+
return path; // Return FULL path, not short attrPath
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
// Try child path matching against fullToShortPathMap keys
|
|
520
|
+
// If the path starts with a known full path + '.' or '[', it's a child
|
|
521
|
+
// of a controllable path. Build the equivalent short child path.
|
|
522
|
+
// e.g., path = "fetch(...).fCRV.json().fCRV.topPaths.length"
|
|
523
|
+
// fullToShortPathMap has "fetch(...).fCRV.json().fCRV.topPaths" → "json().fCRV.topPaths"
|
|
524
|
+
// → check if "json().fCRV.topPaths.length" is in attributesMap
|
|
525
|
+
for (const [fullPath, shortPath] of Object.entries(fullToShortPathMap)) {
|
|
526
|
+
if (path.startsWith(fullPath + '.') || path.startsWith(fullPath + '[')) {
|
|
527
|
+
const suffix = path.slice(fullPath.length); // e.g., ".length"
|
|
528
|
+
const shortChildPath = shortPath + suffix;
|
|
529
|
+
if (shortChildPath in attributesMap) {
|
|
530
|
+
console.log(
|
|
531
|
+
`[findInAttributesMapForPath] "${path}" → CHILD of fullToShortPathMap key "${fullPath}": shortChildPath="${shortChildPath}" found in attributesMap`,
|
|
532
|
+
);
|
|
533
|
+
return path; // Return full path to preserve data source context
|
|
534
|
+
}
|
|
535
|
+
// Also check if the base short path is an array and suffix is .length
|
|
536
|
+
if (suffix === '.length' && shortPath in attributesMap) {
|
|
537
|
+
console.log(
|
|
538
|
+
`[findInAttributesMapForPath] "${path}" → CHILD .length of fullToShortPathMap key "${fullPath}": base shortPath="${shortPath}" is in attributesMap (array .length)`,
|
|
539
|
+
);
|
|
540
|
+
return path; // Array .length is controllable via the array
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
// Try parent matching: if the path is a prefix of any fullToShortPathMap key,
|
|
546
|
+
// it's a parent of controllable data and therefore controllable itself
|
|
547
|
+
for (const fullPath of Object.keys(fullToShortPathMap)) {
|
|
548
|
+
if (fullPath.startsWith(path + '.') || fullPath.startsWith(path + '[')) {
|
|
549
|
+
console.log(
|
|
550
|
+
`[findInAttributesMapForPath] "${path}" → PARENT match: fullToShortPathMap key "${fullPath}" starts with this path`,
|
|
551
|
+
);
|
|
552
|
+
return path;
|
|
405
553
|
}
|
|
406
554
|
}
|
|
407
555
|
|
|
556
|
+
console.log(
|
|
557
|
+
`[findInAttributesMapForPath] "${path}" → NO MATCH (checked ${Object.keys(attributesMap).length} attributesMap keys, ${Object.keys(fullToShortPathMap).length} fullToShortPathMap keys)`,
|
|
558
|
+
);
|
|
408
559
|
return null;
|
|
409
560
|
}
|
|
410
561
|
|
|
@@ -633,7 +784,15 @@ function generateFlowFromCompound(
|
|
|
633
784
|
condition.requiredValue?.toString() ??
|
|
634
785
|
condition.comparedValues?.[0] ??
|
|
635
786
|
'truthy';
|
|
636
|
-
comparison
|
|
787
|
+
// Map comparison operator to flow comparison type
|
|
788
|
+
const op = condition.comparisonOperator;
|
|
789
|
+
if (op === '>' || op === '>=') {
|
|
790
|
+
comparison = 'length>';
|
|
791
|
+
} else if (op === '<' || op === '<=') {
|
|
792
|
+
comparison = 'length<';
|
|
793
|
+
} else {
|
|
794
|
+
comparison = 'equals';
|
|
795
|
+
}
|
|
637
796
|
}
|
|
638
797
|
|
|
639
798
|
requiredValues.push({
|
|
@@ -644,21 +803,32 @@ function generateFlowFromCompound(
|
|
|
644
803
|
});
|
|
645
804
|
}
|
|
646
805
|
|
|
647
|
-
//
|
|
648
|
-
const
|
|
806
|
+
// Remove contradictory "falsy" values where a child path requires data
|
|
807
|
+
const cleanedValues = removeContradictoryFalsyValues(requiredValues);
|
|
808
|
+
|
|
809
|
+
if (cleanedValues.length === 0) {
|
|
810
|
+
return null;
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
// Generate a combined ID from all paths + values to distinguish different comparisons
|
|
814
|
+
const pathParts = cleanedValues
|
|
649
815
|
.map((rv) => {
|
|
650
816
|
const name = generateNameFromPath(rv.attributePath);
|
|
651
|
-
|
|
817
|
+
const suffix =
|
|
818
|
+
rv.comparison === 'truthy' || rv.comparison === 'falsy'
|
|
819
|
+
? `-${rv.comparison}`
|
|
820
|
+
: `-${rv.comparison}-${rv.value}`;
|
|
821
|
+
return name.toLowerCase().replace(/\s+/g, '-') + suffix;
|
|
652
822
|
})
|
|
653
823
|
.join('-and-');
|
|
654
824
|
|
|
655
825
|
return {
|
|
656
826
|
id: `compound-${pathParts}`,
|
|
657
|
-
name:
|
|
827
|
+
name: cleanedValues
|
|
658
828
|
.map((rv) => generateNameFromPath(rv.attributePath))
|
|
659
829
|
.join(' + '),
|
|
660
|
-
description: `When ${
|
|
661
|
-
requiredValues,
|
|
830
|
+
description: `When ${cleanedValues.map((rv) => describeRequiredValue(rv)).join(' and ')}`,
|
|
831
|
+
requiredValues: cleanedValues,
|
|
662
832
|
impact,
|
|
663
833
|
sourceLocation: {
|
|
664
834
|
lineNumber: compound.sourceLocation.lineNumber,
|
|
@@ -849,6 +1019,22 @@ export default function generateExecutionFlowsFromConditionals(
|
|
|
849
1019
|
const flows: ExecutionFlow[] = [];
|
|
850
1020
|
const seenFlowIds = new Set<string>();
|
|
851
1021
|
|
|
1022
|
+
console.log(
|
|
1023
|
+
`[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`,
|
|
1024
|
+
);
|
|
1025
|
+
console.log(
|
|
1026
|
+
`[genFlowsFromConditionals] conditionalUsages keys: [${Object.keys(conditionalUsages).join(', ')}]`,
|
|
1027
|
+
);
|
|
1028
|
+
console.log(
|
|
1029
|
+
`[genFlowsFromConditionals] attributesMap keys: [${Object.keys(attributesMap).join(', ')}]`,
|
|
1030
|
+
);
|
|
1031
|
+
console.log(
|
|
1032
|
+
`[genFlowsFromConditionals] fullToShortPathMap: ${JSON.stringify(fullToShortPathMap)}`,
|
|
1033
|
+
);
|
|
1034
|
+
console.log(
|
|
1035
|
+
`[genFlowsFromConditionals] equivalentSignatureVariables: ${JSON.stringify(equivalentSignatureVariables)}`,
|
|
1036
|
+
);
|
|
1037
|
+
|
|
852
1038
|
// Track normalized resolved paths to prevent duplicate flows
|
|
853
1039
|
// This handles the case where we have usages for both:
|
|
854
1040
|
// - "hasNewerVersion" (short path from destructured variable)
|
|
@@ -866,9 +1052,16 @@ export default function generateExecutionFlowsFromConditionals(
|
|
|
866
1052
|
for (const usage of usages) {
|
|
867
1053
|
// Skip usages that are part of compound conditionals (handled separately)
|
|
868
1054
|
if (usage.chainId && compoundChainIds.has(usage.chainId)) {
|
|
1055
|
+
console.log(
|
|
1056
|
+
`[genFlowsFromConditionals] "${usage.path}" SKIP: part of compound conditional chain=${usage.chainId}`,
|
|
1057
|
+
);
|
|
869
1058
|
continue;
|
|
870
1059
|
}
|
|
871
1060
|
|
|
1061
|
+
console.log(
|
|
1062
|
+
`[genFlowsFromConditionals] --- Processing "${usage.path}" (type=${usage.conditionType}, negated=${usage.isNegated}, sourceDataPath="${usage.sourceDataPath ?? '(none)'}", derivedFrom=${usage.derivedFrom ? JSON.stringify(usage.derivedFrom) : 'none'})`,
|
|
1063
|
+
);
|
|
1064
|
+
|
|
872
1065
|
// First, try to use pre-computed sourceDataPath if available
|
|
873
1066
|
let resolvedPath: string | null = null;
|
|
874
1067
|
|
|
@@ -878,7 +1071,9 @@ export default function generateExecutionFlowsFromConditionals(
|
|
|
878
1071
|
// should become "useLoaderData<LoaderData>().functionCallReturnValue.entity.sha"
|
|
879
1072
|
// Returns null for malformed paths (e.g., chained function calls like fetch().json())
|
|
880
1073
|
const cleanedPath = cleanSourceDataPath(usage.sourceDataPath);
|
|
881
|
-
|
|
1074
|
+
console.log(
|
|
1075
|
+
`[genFlowsFromConditionals] "${usage.path}" cleanSourceDataPath("${usage.sourceDataPath}") → "${cleanedPath}"`,
|
|
1076
|
+
);
|
|
882
1077
|
if (cleanedPath) {
|
|
883
1078
|
// Verify the cleaned path exists in attributesMap
|
|
884
1079
|
const pathMatch = findInAttributesMapForPath(
|
|
@@ -886,6 +1081,9 @@ export default function generateExecutionFlowsFromConditionals(
|
|
|
886
1081
|
attributesMap,
|
|
887
1082
|
fullToShortPathMap,
|
|
888
1083
|
);
|
|
1084
|
+
console.log(
|
|
1085
|
+
`[genFlowsFromConditionals] "${usage.path}" findInAttributesMapForPath("${cleanedPath}") → ${pathMatch ? `"${pathMatch}"` : 'null (not found)'}`,
|
|
1086
|
+
);
|
|
889
1087
|
if (pathMatch) {
|
|
890
1088
|
resolvedPath = pathMatch;
|
|
891
1089
|
}
|
|
@@ -895,13 +1093,18 @@ export default function generateExecutionFlowsFromConditionals(
|
|
|
895
1093
|
|
|
896
1094
|
// Fall back to resolution via equivalentSignatureVariables
|
|
897
1095
|
if (!resolvedPath) {
|
|
1096
|
+
console.log(
|
|
1097
|
+
`[genFlowsFromConditionals] "${usage.path}" sourceDataPath resolution failed, trying resolvePathToControllable("${usage.path}")...`,
|
|
1098
|
+
);
|
|
898
1099
|
const resolution = resolvePathToControllable(
|
|
899
1100
|
usage.path,
|
|
900
1101
|
attributesMap,
|
|
901
1102
|
equivalentSignatureVariables,
|
|
902
1103
|
fullToShortPathMap,
|
|
903
1104
|
);
|
|
904
|
-
|
|
1105
|
+
console.log(
|
|
1106
|
+
`[genFlowsFromConditionals] "${usage.path}" resolvePathToControllable → isControllable=${resolution.isControllable}, resolvedPath="${resolution.resolvedPath ?? '(none)'}"`,
|
|
1107
|
+
);
|
|
905
1108
|
if (resolution.isControllable && resolution.resolvedPath) {
|
|
906
1109
|
resolvedPath = resolution.resolvedPath;
|
|
907
1110
|
}
|
|
@@ -913,7 +1116,9 @@ export default function generateExecutionFlowsFromConditionals(
|
|
|
913
1116
|
if (!resolvedPath && usage.derivedFrom) {
|
|
914
1117
|
const { operation, sourcePath, sourcePaths, comparedValue } =
|
|
915
1118
|
usage.derivedFrom;
|
|
916
|
-
|
|
1119
|
+
console.log(
|
|
1120
|
+
`[genFlowsFromConditionals] "${usage.path}" trying derivedFrom: operation=${operation}, sourcePath="${sourcePath ?? '(none)'}", sourcePaths=${sourcePaths ? JSON.stringify(sourcePaths) : '(none)'}, comparedValue="${comparedValue ?? '(none)'}"`,
|
|
1121
|
+
);
|
|
917
1122
|
// For single-source derivations (notNull, equals, etc.)
|
|
918
1123
|
if (sourcePath) {
|
|
919
1124
|
const resolution = resolvePathToControllable(
|
|
@@ -922,7 +1127,6 @@ export default function generateExecutionFlowsFromConditionals(
|
|
|
922
1127
|
equivalentSignatureVariables,
|
|
923
1128
|
fullToShortPathMap,
|
|
924
1129
|
);
|
|
925
|
-
|
|
926
1130
|
if (resolution.isControllable && resolution.resolvedPath) {
|
|
927
1131
|
resolvedPath = resolution.resolvedPath;
|
|
928
1132
|
}
|
|
@@ -1218,6 +1422,9 @@ export default function generateExecutionFlowsFromConditionals(
|
|
|
1218
1422
|
|
|
1219
1423
|
if (!resolvedPath) {
|
|
1220
1424
|
// Path is not controllable - skip (no invalid flows possible)
|
|
1425
|
+
console.log(
|
|
1426
|
+
`[genFlowsFromConditionals] "${usage.path}" SKIP: not controllable (no resolvedPath after all attempts)`,
|
|
1427
|
+
);
|
|
1221
1428
|
continue;
|
|
1222
1429
|
}
|
|
1223
1430
|
|
|
@@ -1232,10 +1439,33 @@ export default function generateExecutionFlowsFromConditionals(
|
|
|
1232
1439
|
// Skip if we've already generated flows for this normalized path
|
|
1233
1440
|
// This prevents duplicate flows when we have usages for both short and full paths
|
|
1234
1441
|
if (seenNormalizedPaths.has(normalizedPath)) {
|
|
1442
|
+
console.log(
|
|
1443
|
+
`[genFlowsFromConditionals] "${usage.path}" SKIP: duplicate normalizedPath="${normalizedPath}" (resolvedPath="${resolvedPath}")`,
|
|
1444
|
+
);
|
|
1235
1445
|
continue;
|
|
1236
1446
|
}
|
|
1237
1447
|
seenNormalizedPaths.add(normalizedPath);
|
|
1238
1448
|
|
|
1449
|
+
// Skip individual truthy/falsy flows on parent paths that have child data entries.
|
|
1450
|
+
// Lifecycle booleans (like isLoadingAuditData) traced to fetch(...).functionCallReturnValue
|
|
1451
|
+
// produce misleading truthy/falsy flows: "truthy" can't show loading (mock resolves instantly),
|
|
1452
|
+
// "falsy" tells the LLM to return null (breaking .json()). Compound flows with specific child
|
|
1453
|
+
// data requirements provide the correct mock guidance.
|
|
1454
|
+
if (
|
|
1455
|
+
usage.conditionType === 'truthiness' &&
|
|
1456
|
+
resolvedPath &&
|
|
1457
|
+
hasChildPathsInMap(resolvedPath, fullToShortPathMap)
|
|
1458
|
+
) {
|
|
1459
|
+
console.log(
|
|
1460
|
+
`[genFlowsFromConditionals] "${usage.path}" SKIP: parent path "${resolvedPath}" has child data paths — compound flows will handle this`,
|
|
1461
|
+
);
|
|
1462
|
+
continue;
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
console.log(
|
|
1466
|
+
`[genFlowsFromConditionals] "${usage.path}" RESOLVED → resolvedPath="${resolvedPath}", normalizedPath="${normalizedPath}" — generating flows`,
|
|
1467
|
+
);
|
|
1468
|
+
|
|
1239
1469
|
// Generate flows for this controllable usage
|
|
1240
1470
|
const usageFlows = generateFlowsFromUsage(usage, resolvedPath);
|
|
1241
1471
|
|
|
@@ -1244,6 +1474,9 @@ export default function generateExecutionFlowsFromConditionals(
|
|
|
1244
1474
|
if (!seenFlowIds.has(flow.id)) {
|
|
1245
1475
|
seenFlowIds.add(flow.id);
|
|
1246
1476
|
flows.push(flow);
|
|
1477
|
+
console.log(
|
|
1478
|
+
`[genFlowsFromConditionals] "${usage.path}" FLOW ADDED: id="${flow.id}", requiredValues=${JSON.stringify(flow.requiredValues.map((rv) => ({ attr: rv.attributePath, val: rv.value })))}`,
|
|
1479
|
+
);
|
|
1247
1480
|
}
|
|
1248
1481
|
}
|
|
1249
1482
|
}
|
|
@@ -1297,25 +1530,85 @@ export default function generateExecutionFlowsFromConditionals(
|
|
|
1297
1530
|
// Use the first source's path for the resolvedPaths map (for ID generation)
|
|
1298
1531
|
resolvedPaths.set(condition.path, sources[0].path);
|
|
1299
1532
|
} else {
|
|
1300
|
-
// Derived variable
|
|
1301
|
-
|
|
1302
|
-
|
|
1533
|
+
// Derived variable expansion failed — try sourceDataPath fallback
|
|
1534
|
+
// This handles cases where the derivation chain goes through useMemo/useState
|
|
1535
|
+
// but the enriched sourceDataPath already traced to the actual data source
|
|
1536
|
+
const usageWithSource = usagesForPath?.find(
|
|
1537
|
+
(u) => u.sourceDataPath,
|
|
1538
|
+
);
|
|
1539
|
+
let derivedFallbackPath: string | null = null;
|
|
1540
|
+
|
|
1541
|
+
if (usageWithSource?.sourceDataPath) {
|
|
1542
|
+
const cleanedPath = cleanSourceDataPath(
|
|
1543
|
+
usageWithSource.sourceDataPath,
|
|
1544
|
+
);
|
|
1545
|
+
if (cleanedPath) {
|
|
1546
|
+
const pathMatch = findInAttributesMapForPath(
|
|
1547
|
+
cleanedPath,
|
|
1548
|
+
attributesMap,
|
|
1549
|
+
fullToShortPathMap,
|
|
1550
|
+
);
|
|
1551
|
+
if (pathMatch) {
|
|
1552
|
+
derivedFallbackPath = pathMatch;
|
|
1553
|
+
}
|
|
1554
|
+
}
|
|
1555
|
+
}
|
|
1556
|
+
|
|
1557
|
+
if (derivedFallbackPath) {
|
|
1558
|
+
resolvedPaths.set(condition.path, derivedFallbackPath);
|
|
1559
|
+
console.log(
|
|
1560
|
+
`[genFlowsFromConditionals] COMPOUND "${condition.path}" derived expansion failed but sourceDataPath fallback resolved → "${derivedFallbackPath}"`,
|
|
1561
|
+
);
|
|
1562
|
+
} else {
|
|
1563
|
+
// Truly not controllable
|
|
1564
|
+
console.log(
|
|
1565
|
+
`[genFlowsFromConditionals] COMPOUND "${condition.path}" derived but no controllable sources and no sourceDataPath fallback → NOT controllable`,
|
|
1566
|
+
);
|
|
1567
|
+
allControllable = false;
|
|
1568
|
+
break;
|
|
1569
|
+
}
|
|
1303
1570
|
}
|
|
1304
1571
|
} else {
|
|
1305
1572
|
// Not a derived variable - resolve directly
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
attributesMap,
|
|
1309
|
-
equivalentSignatureVariables,
|
|
1310
|
-
fullToShortPathMap,
|
|
1311
|
-
);
|
|
1573
|
+
// First try sourceDataPath from the usage (same as individual processing)
|
|
1574
|
+
let compoundResolvedPath: string | null = null;
|
|
1312
1575
|
|
|
1313
|
-
|
|
1576
|
+
const usageWithSource = usagesForPath?.find((u) => u.sourceDataPath);
|
|
1577
|
+
if (usageWithSource?.sourceDataPath) {
|
|
1578
|
+
const cleanedPath = cleanSourceDataPath(
|
|
1579
|
+
usageWithSource.sourceDataPath,
|
|
1580
|
+
);
|
|
1581
|
+
if (cleanedPath) {
|
|
1582
|
+
const pathMatch = findInAttributesMapForPath(
|
|
1583
|
+
cleanedPath,
|
|
1584
|
+
attributesMap,
|
|
1585
|
+
fullToShortPathMap,
|
|
1586
|
+
);
|
|
1587
|
+
if (pathMatch) {
|
|
1588
|
+
compoundResolvedPath = pathMatch;
|
|
1589
|
+
}
|
|
1590
|
+
}
|
|
1591
|
+
}
|
|
1592
|
+
|
|
1593
|
+
if (!compoundResolvedPath) {
|
|
1594
|
+
const resolution = resolvePathToControllable(
|
|
1595
|
+
condition.path,
|
|
1596
|
+
attributesMap,
|
|
1597
|
+
equivalentSignatureVariables,
|
|
1598
|
+
fullToShortPathMap,
|
|
1599
|
+
);
|
|
1600
|
+
|
|
1601
|
+
if (resolution.isControllable && resolution.resolvedPath) {
|
|
1602
|
+
compoundResolvedPath = resolution.resolvedPath;
|
|
1603
|
+
}
|
|
1604
|
+
}
|
|
1605
|
+
|
|
1606
|
+
if (!compoundResolvedPath) {
|
|
1314
1607
|
allControllable = false;
|
|
1315
1608
|
break;
|
|
1316
1609
|
}
|
|
1317
1610
|
|
|
1318
|
-
resolvedPaths.set(condition.path,
|
|
1611
|
+
resolvedPaths.set(condition.path, compoundResolvedPath);
|
|
1319
1612
|
}
|
|
1320
1613
|
}
|
|
1321
1614
|
|
|
@@ -1393,7 +1686,14 @@ export default function generateExecutionFlowsFromConditionals(
|
|
|
1393
1686
|
condition.requiredValue?.toString() ??
|
|
1394
1687
|
condition.comparedValues?.[0] ??
|
|
1395
1688
|
'truthy';
|
|
1396
|
-
|
|
1689
|
+
const op = condition.comparisonOperator;
|
|
1690
|
+
if (op === '>' || op === '>=') {
|
|
1691
|
+
comparison = 'length>';
|
|
1692
|
+
} else if (op === '<' || op === '<=') {
|
|
1693
|
+
comparison = 'length<';
|
|
1694
|
+
} else {
|
|
1695
|
+
comparison = 'equals';
|
|
1696
|
+
}
|
|
1397
1697
|
}
|
|
1398
1698
|
|
|
1399
1699
|
requiredValues.push({
|
|
@@ -1406,24 +1706,31 @@ export default function generateExecutionFlowsFromConditionals(
|
|
|
1406
1706
|
}
|
|
1407
1707
|
}
|
|
1408
1708
|
|
|
1409
|
-
|
|
1709
|
+
// Remove contradictory "falsy" values where a child path requires data
|
|
1710
|
+
const cleanedValues = removeContradictoryFalsyValues(requiredValues);
|
|
1711
|
+
|
|
1712
|
+
if (cleanedValues.length > 0) {
|
|
1410
1713
|
const impact: ExecutionFlow['impact'] =
|
|
1411
1714
|
compound.controlsJsxRendering ? 'high' : 'medium';
|
|
1412
1715
|
|
|
1413
|
-
// Generate a combined ID from all paths
|
|
1414
|
-
const pathParts =
|
|
1716
|
+
// Generate a combined ID from all paths + values
|
|
1717
|
+
const pathParts = cleanedValues
|
|
1415
1718
|
.map((rv) => {
|
|
1416
1719
|
const name = generateNameFromPath(rv.attributePath);
|
|
1417
|
-
|
|
1720
|
+
const suffix =
|
|
1721
|
+
rv.comparison === 'truthy' || rv.comparison === 'falsy'
|
|
1722
|
+
? `-${rv.comparison}`
|
|
1723
|
+
: `-${rv.comparison}-${rv.value}`;
|
|
1724
|
+
return name.toLowerCase().replace(/\s+/g, '-') + suffix;
|
|
1418
1725
|
})
|
|
1419
1726
|
.join('-and-');
|
|
1420
1727
|
|
|
1421
1728
|
const compoundFlow: ExecutionFlow = {
|
|
1422
|
-
id: `${pathParts}
|
|
1423
|
-
name: generateNameFromPath(
|
|
1424
|
-
description: `When ${
|
|
1729
|
+
id: `${pathParts}`,
|
|
1730
|
+
name: generateNameFromPath(cleanedValues[0].attributePath),
|
|
1731
|
+
description: `When ${cleanedValues.map((rv) => describeRequiredValue(rv)).join(' and ')}`,
|
|
1425
1732
|
impact,
|
|
1426
|
-
requiredValues,
|
|
1733
|
+
requiredValues: cleanedValues,
|
|
1427
1734
|
sourceLocation: compound.sourceLocation,
|
|
1428
1735
|
};
|
|
1429
1736
|
|
|
@@ -1640,9 +1947,6 @@ export default function generateExecutionFlowsFromConditionals(
|
|
|
1640
1947
|
childData.conditionalUsages,
|
|
1641
1948
|
)) {
|
|
1642
1949
|
for (const usage of usages) {
|
|
1643
|
-
// Debug logging (disabled - set to true for troubleshooting child flow resolution)
|
|
1644
|
-
const shouldDebugChild = false;
|
|
1645
|
-
|
|
1646
1950
|
// Skip usages that are part of compound conditionals (handled separately)
|
|
1647
1951
|
// Fix 33: Only skip if the chainId is in the child's compound conditionals
|
|
1648
1952
|
if (usage.chainId && childCompoundChainIds.has(usage.chainId)) {
|
|
@@ -1657,18 +1961,6 @@ export default function generateExecutionFlowsFromConditionals(
|
|
|
1657
1961
|
childPath = usage.derivedFrom.sourcePath;
|
|
1658
1962
|
}
|
|
1659
1963
|
|
|
1660
|
-
if (shouldDebugChild) {
|
|
1661
|
-
console.log(
|
|
1662
|
-
`[DEBUG CHILD ${childName}] Processing usage path: ${usage.path}`,
|
|
1663
|
-
);
|
|
1664
|
-
console.log(
|
|
1665
|
-
`[DEBUG CHILD ${childName}] childPath (after derivedFrom): ${childPath}`,
|
|
1666
|
-
);
|
|
1667
|
-
console.log(
|
|
1668
|
-
`[DEBUG CHILD ${childName}] sourceDataPath: ${usage.sourceDataPath}`,
|
|
1669
|
-
);
|
|
1670
|
-
}
|
|
1671
|
-
|
|
1672
1964
|
// Translate the child path to a parent path
|
|
1673
1965
|
let translatedPath = translateChildPathToParent(
|
|
1674
1966
|
childPath,
|
|
@@ -1677,12 +1969,6 @@ export default function generateExecutionFlowsFromConditionals(
|
|
|
1677
1969
|
childName,
|
|
1678
1970
|
);
|
|
1679
1971
|
|
|
1680
|
-
if (shouldDebugChild) {
|
|
1681
|
-
console.log(
|
|
1682
|
-
`[DEBUG CHILD ${childName}] translatedPath (from translateChildPathToParent): ${translatedPath}`,
|
|
1683
|
-
);
|
|
1684
|
-
}
|
|
1685
|
-
|
|
1686
1972
|
// If translation failed but we have sourceDataPath, try to extract the prop path from it
|
|
1687
1973
|
// sourceDataPath format: "ChildName.signature[n].propPath.rest" → extract "propPath.rest"
|
|
1688
1974
|
if (!translatedPath && usage.sourceDataPath) {
|
|
@@ -1691,21 +1977,11 @@ export default function generateExecutionFlowsFromConditionals(
|
|
|
1691
1977
|
);
|
|
1692
1978
|
if (signatureMatch) {
|
|
1693
1979
|
translatedPath = signatureMatch[1];
|
|
1694
|
-
if (shouldDebugChild) {
|
|
1695
|
-
console.log(
|
|
1696
|
-
`[DEBUG CHILD ${childName}] translatedPath (from sourceDataPath regex): ${translatedPath}`,
|
|
1697
|
-
);
|
|
1698
|
-
}
|
|
1699
1980
|
}
|
|
1700
1981
|
}
|
|
1701
1982
|
|
|
1702
1983
|
if (!translatedPath) {
|
|
1703
1984
|
// Could not translate - skip this usage
|
|
1704
|
-
if (shouldDebugChild) {
|
|
1705
|
-
console.log(
|
|
1706
|
-
`[DEBUG CHILD ${childName}] SKIPPED - no translation found`,
|
|
1707
|
-
);
|
|
1708
|
-
}
|
|
1709
1985
|
continue;
|
|
1710
1986
|
}
|
|
1711
1987
|
|
|
@@ -1718,21 +1994,6 @@ export default function generateExecutionFlowsFromConditionals(
|
|
|
1718
1994
|
fullToShortPathMap,
|
|
1719
1995
|
);
|
|
1720
1996
|
|
|
1721
|
-
if (shouldDebugChild) {
|
|
1722
|
-
console.log(
|
|
1723
|
-
`[DEBUG CHILD ${childName}] resolvePathToControllable result:`,
|
|
1724
|
-
);
|
|
1725
|
-
console.log(
|
|
1726
|
-
`[DEBUG CHILD ${childName}] isControllable: ${resolution.isControllable}`,
|
|
1727
|
-
);
|
|
1728
|
-
console.log(
|
|
1729
|
-
`[DEBUG CHILD ${childName}] resolvedPath: ${resolution.resolvedPath}`,
|
|
1730
|
-
);
|
|
1731
|
-
console.log(
|
|
1732
|
-
`[DEBUG CHILD ${childName}] chain: ${resolution.resolutionChain.join(' -> ')}`,
|
|
1733
|
-
);
|
|
1734
|
-
}
|
|
1735
|
-
|
|
1736
1997
|
// Only create flows for controllable paths (whitelist approach).
|
|
1737
1998
|
// If the path doesn't resolve to something in attributesMap, skip it.
|
|
1738
1999
|
// This prevents creating flows for useState values which are not
|
|
@@ -1770,32 +2031,11 @@ export default function generateExecutionFlowsFromConditionals(
|
|
|
1770
2031
|
}
|
|
1771
2032
|
}
|
|
1772
2033
|
|
|
1773
|
-
if (shouldDebugChild) {
|
|
1774
|
-
console.log(
|
|
1775
|
-
`[DEBUG CHILD ${childName}] useState fallback: looking for URL param`,
|
|
1776
|
-
);
|
|
1777
|
-
console.log(
|
|
1778
|
-
`[DEBUG CHILD ${childName}] useStatePattern: ${useStatePattern}`,
|
|
1779
|
-
);
|
|
1780
|
-
console.log(
|
|
1781
|
-
`[DEBUG CHILD ${childName}] useStateVarName: ${useStateVarName}`,
|
|
1782
|
-
);
|
|
1783
|
-
}
|
|
1784
|
-
|
|
1785
2034
|
if (useStateVarName) {
|
|
1786
2035
|
// Look for a related URL param like "varNameFromUrl"
|
|
1787
2036
|
const urlParamName = `${useStateVarName}FromUrl`;
|
|
1788
2037
|
const urlParamPath = equivalentSignatureVariables[urlParamName];
|
|
1789
2038
|
|
|
1790
|
-
if (shouldDebugChild) {
|
|
1791
|
-
console.log(
|
|
1792
|
-
`[DEBUG CHILD ${childName}] urlParamName: ${urlParamName}`,
|
|
1793
|
-
);
|
|
1794
|
-
console.log(
|
|
1795
|
-
`[DEBUG CHILD ${childName}] urlParamPath: ${urlParamPath}`,
|
|
1796
|
-
);
|
|
1797
|
-
}
|
|
1798
|
-
|
|
1799
2039
|
if (urlParamPath) {
|
|
1800
2040
|
// For useState values initialized from URL params, use the
|
|
1801
2041
|
// URL param variable name directly (e.g., "viewModeFromUrl")
|
|
@@ -1806,11 +2046,6 @@ export default function generateExecutionFlowsFromConditionals(
|
|
|
1806
2046
|
// The flow will use the URL param name as the attributePath,
|
|
1807
2047
|
// which gets properly resolved when generating mock data.
|
|
1808
2048
|
resolvedPath = urlParamName;
|
|
1809
|
-
if (shouldDebugChild) {
|
|
1810
|
-
console.log(
|
|
1811
|
-
`[DEBUG CHILD ${childName}] useState fallback SUCCESS: using URL param name ${resolvedPath}`,
|
|
1812
|
-
);
|
|
1813
|
-
}
|
|
1814
2049
|
}
|
|
1815
2050
|
}
|
|
1816
2051
|
}
|
|
@@ -1867,12 +2102,6 @@ export default function generateExecutionFlowsFromConditionals(
|
|
|
1867
2102
|
? childPath.slice(childPropName.length)
|
|
1868
2103
|
: '';
|
|
1869
2104
|
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
2105
|
}
|
|
1877
2106
|
}
|
|
1878
2107
|
}
|
|
@@ -1880,11 +2109,6 @@ export default function generateExecutionFlowsFromConditionals(
|
|
|
1880
2109
|
|
|
1881
2110
|
// If still not resolved after fallback, skip
|
|
1882
2111
|
if (!resolvedPath) {
|
|
1883
|
-
if (shouldDebugChild) {
|
|
1884
|
-
console.log(
|
|
1885
|
-
`[DEBUG CHILD ${childName}] SKIPPED - path not controllable`,
|
|
1886
|
-
);
|
|
1887
|
-
}
|
|
1888
2112
|
continue;
|
|
1889
2113
|
}
|
|
1890
2114
|
}
|
|
@@ -1896,11 +2120,6 @@ export default function generateExecutionFlowsFromConditionals(
|
|
|
1896
2120
|
);
|
|
1897
2121
|
|
|
1898
2122
|
if (seenNormalizedPaths.has(normalizedPath)) {
|
|
1899
|
-
if (shouldDebugChild) {
|
|
1900
|
-
console.log(
|
|
1901
|
-
`[DEBUG CHILD ${childName}] SKIPPED - duplicate normalized path: ${normalizedPath}`,
|
|
1902
|
-
);
|
|
1903
|
-
}
|
|
1904
2123
|
continue;
|
|
1905
2124
|
}
|
|
1906
2125
|
seenNormalizedPaths.add(normalizedPath);
|
|
@@ -1917,17 +2136,6 @@ export default function generateExecutionFlowsFromConditionals(
|
|
|
1917
2136
|
resolvedPath,
|
|
1918
2137
|
);
|
|
1919
2138
|
|
|
1920
|
-
if (shouldDebugChild) {
|
|
1921
|
-
console.log(
|
|
1922
|
-
`[DEBUG CHILD ${childName}] GENERATING ${usageFlows.length} flows with resolvedPath: ${resolvedPath}`,
|
|
1923
|
-
);
|
|
1924
|
-
for (const f of usageFlows) {
|
|
1925
|
-
console.log(
|
|
1926
|
-
`[DEBUG CHILD ${childName}] - Flow ID: ${f.id}, path: ${f.requiredValues[0]?.attributePath}`,
|
|
1927
|
-
);
|
|
1928
|
-
}
|
|
1929
|
-
}
|
|
1930
|
-
|
|
1931
2139
|
// Add gating conditions to each flow
|
|
1932
2140
|
for (const flow of usageFlows) {
|
|
1933
2141
|
// Add gating required values to the flow
|
|
@@ -2263,5 +2471,14 @@ export default function generateExecutionFlowsFromConditionals(
|
|
|
2263
2471
|
}
|
|
2264
2472
|
}
|
|
2265
2473
|
|
|
2474
|
+
console.log(
|
|
2475
|
+
`[genFlowsFromConditionals] RESULT: ${flows.length} total flows generated`,
|
|
2476
|
+
);
|
|
2477
|
+
for (const flow of flows) {
|
|
2478
|
+
console.log(
|
|
2479
|
+
`[genFlowsFromConditionals] FLOW: id="${flow.id}" requiredValues=[${flow.requiredValues.map((rv) => `${rv.attributePath}=${rv.value}`).join(', ')}]`,
|
|
2480
|
+
);
|
|
2481
|
+
}
|
|
2482
|
+
|
|
2266
2483
|
return flows;
|
|
2267
2484
|
}
|