Link REST endpoints via source-proven call-graph scoping and branch expansion.

Scope machines from call-chain type evidence, expand path bindings from switch/if literals, unify external trigger policy, add linkResolution export metadata, and built-in trigger detection without hints.json.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-13 17:46:14 +02:00
parent 1bf75c8a34
commit f8f64487d1
57 changed files with 3202 additions and 297 deletions

View File

@@ -494,7 +494,8 @@
const parts = step.split("->");
targetAnon = "#link_anon_" + normalize(parts[0]) + "_" + normalize(parts[1]);
} else {
targetLinkKey = "__" + normalize(formatForLinkId(step));
// Event-only string steps without source are not precise enough to highlight.
return;
}
if (!targetLinkKey && !targetAnon) return;
@@ -506,11 +507,8 @@
let matches = false;
if (targetAnon) {
matches = (href === targetAnon);
} else if (targetLinkKey.includes("__")) {
} else if (targetLinkKey) {
matches = (href === "#link_" + targetLinkKey);
} else {
// Business-flow step: event name only, match that event from any source
matches = href.startsWith("#link_") && href.endsWith(targetLinkKey);
}
if (matches) {

View File

@@ -114,7 +114,41 @@ class HtmlTransitionLinkConsistencyTest {
}
@Test
void enterpriseAstExportHtmlShouldContainTransitionLinkKeys(@TempDir Path tempDir) throws Exception {
void flowHighlightShouldRequireSourceAndEventNotEventSuffixOnly(@TempDir Path tempDir) throws Exception {
writeSampleProject(tempDir);
AnalysisResult finalizedShape = AnalysisResult.builder()
.name("com.example.config.OrderStateMachineConfiguration")
.stateTypeFqn("com.example.order.OrderState")
.eventTypeFqn("com.example.order.OrderEvent")
.transitions(List.of(
shortTransition(
"com.example.order.OrderEvent.PAY",
"com.example.order.OrderState.NEW",
"com.example.order.OrderState.PAID"),
shortTransition(
"com.example.order.OrderEvent.SHIP",
"com.example.order.OrderState.PAID",
"com.example.order.OrderState.SHIPPED")))
.startStates(Set.of("com.example.order.OrderState.NEW"))
.endStates(Set.of("com.example.order.OrderState.SHIPPED"))
.metadata(CodebaseMetadata.builder()
.flows(List.of(click.kamil.springstatemachineexporter.analysis.model.BusinessFlow.builder()
.name("Ship only")
.description("Should not light PAY")
.steps(List.of("SHIP"))
.build()))
.build())
.build();
String html = new HtmlExporter().export(finalizedShape, ExportOptions.builder().build());
assertThat(html).contains("function highlightEvents(steps)");
assertThat(html).contains("Event-only string steps without source are not precise enough");
assertThat(html).doesNotContain("match that event from any source");
}
@Test
void enterpriseHtmlShouldContainMatchedTransitionLinkKeys(@TempDir Path tempDir) throws Exception {
Path enterprise = findProjectRoot().resolve("state_machines/state_machine_enterprise");
Path outputDir = tempDir.resolve("enterprise-out");