v2.2 extended analysis render update

This commit is contained in:
2026-06-15 16:37:19 +02:00
parent 71bcfe65d7
commit bd44049e5e
37 changed files with 1964 additions and 836 deletions

View File

@@ -29,6 +29,7 @@ public class PlantUml implements StateMachineExporter {
StringBuilder sb = new StringBuilder();
sb.append("@startuml\n");
sb.append("!pragma layout smetana\n");
sb.append("set separator none\n");
sb.append("hide empty description\n");
sb.append("hide stereotype\n");
@@ -51,13 +52,6 @@ public class PlantUml implements StateMachineExporter {
sb.append("skinparam dpi 110\n");
sb.append("skinparam svgLinkTarget _self\n");
// Pre-declare all unique states for layout stability
Set<String> allUniqueStates = new LinkedHashSet<>();
transitions.forEach(t -> {
t.getSourceStates().forEach(s -> allUniqueStates.add(simplify(s.toString())));
t.getTargetStates().forEach(s -> allUniqueStates.add(simplify(s.toString())));
});
allUniqueStates.forEach(s -> sb.append("state ").append(s).append("\n"));
sb.append("\n");
for (String start : startStates) {
@@ -127,14 +121,16 @@ public class PlantUml implements StateMachineExporter {
}
String label = buildLabel(t, options.isUseLambdaGuards());
if (!label.isEmpty()) {
sb.append(" : ");
if (options.isEmbedIdentifiers() && t.getEvent() != null && !t.getEvent().isBlank()) {
// Link the label text - this forces PlantUML to create an <a> tag
sb.append("[[#link_").append(normalize(t.getEvent())).append(" ").append(label).append("]]");
} else {
sb.append(label);
}
if (options.isEmbedIdentifiers()) {
String linkId = t.getEvent() != null ? "link_" + normalize(t.getEvent()) : "link_anon_" + normalize(source) + "_" + normalize(target);
// Force a label even if empty to ensure the link group exists in SVG
String displayLabel = label.isEmpty() ? " " : label;
// Brackets [...] in the label break PlantUML link syntax [[url label]],
// so we strip them for the interactive identification label.
String safeLabel = displayLabel.replaceAll("[\\[\\]]", "");
sb.append(" : ").append("[[#").append(linkId).append(" ").append(safeLabel).append("]]");
} else if (!label.isEmpty()) {
sb.append(" : ").append(label);
}
sb.append("\n");
}
@@ -192,7 +188,7 @@ public class PlantUml implements StateMachineExporter {
public String simplify(String state) {
if (state == null) return "";
if (state.contains("\"")) return state;
return state.replaceAll("[^a-zA-Z0-9_]", "");
return state.replaceAll("[^a-zA-Z0-9_.]", "");
}
private String buildLabel(Transition t, boolean useLambdaGuards) {
@@ -205,12 +201,12 @@ public class PlantUml implements StateMachineExporter {
if (useLambdaGuards && g.contains("->")) {
parts.add("[" + LAMBDA + "]");
} else {
parts.add("[" + g + "]");
parts.add("[" + g.replace("\r", "").replace("\n", "\\n") + "]");
}
}
if (t.getActions() != null && !t.getActions().isEmpty()) {
parts.add("/ " + t.getActions().stream()
.map(a -> a.expression().contains("->") ? LAMBDA : a.expression())
.map(a -> a.expression().contains("->") ? LAMBDA : a.expression().replace("\r", "").replace("\n", "\\n"))
.collect(Collectors.joining(", ")));
}
Optional.ofNullable(t.getOrder())