enrichment schema

This commit is contained in:
2026-06-12 22:59:02 +02:00
parent f87d41223e
commit 8641c7266f
20 changed files with 986 additions and 12 deletions

View File

@@ -1,5 +1,6 @@
package click.kamil.springstatemachineexporter;
import click.kamil.springstatemachineexporter.analysis.service.EnrichmentService;
import click.kamil.springstatemachineexporter.exporter.Dot;
import click.kamil.springstatemachineexporter.exporter.JsonExporter;
import click.kamil.springstatemachineexporter.exporter.PlantUml;
@@ -8,13 +9,15 @@ import click.kamil.springstatemachineexporter.command.ExporterCommand;
import click.kamil.springstatemachineexporter.service.ExportService;
import picocli.CommandLine;
import java.util.Collections;
import java.util.List;
public class Main {
public static void main(String[] args) {
// Manual DI / Wiring
var exporters = List.of(new PlantUml(), new Dot(), new Scxml(), new JsonExporter());
var exportService = new ExportService(exporters);
var enrichmentService = new EnrichmentService(Collections.emptyList());
var exportService = new ExportService(exporters, enrichmentService);
var command = new ExporterCommand(exportService);
int exitCode = new CommandLine(command).execute(args);

View File

@@ -0,0 +1,8 @@
package click.kamil.springstatemachineexporter.analysis.enricher;
import click.kamil.springstatemachineexporter.analysis.model.AnalysisResult;
import click.kamil.springstatemachineexporter.ast.common.CodebaseContext;
public interface AnalysisEnricher {
void enrich(AnalysisResult result, CodebaseContext context);
}

View File

@@ -0,0 +1,41 @@
package click.kamil.springstatemachineexporter.analysis.model;
import click.kamil.springstatemachineexporter.model.Transition;
import lombok.Builder;
import lombok.Getter;
import java.util.Collections;
import java.util.List;
import java.util.Set;
@Getter
@Builder
public class AnalysisResult {
private final String name;
private final List<Transition> transitions;
private final Set<String> startStates;
private final Set<String> endStates;
private final boolean renderChoicesAsDiamonds;
@Builder.Default
private CodebaseMetadata metadata = CodebaseMetadata.empty();
public void addMetadata(CodebaseMetadata newMetadata) {
if (newMetadata == null) return;
List<CodebaseMetadata.TriggerPoint> combinedTriggers = new java.util.ArrayList<>(this.metadata.getTriggers());
combinedTriggers.addAll(newMetadata.getTriggers());
List<CodebaseMetadata.EntryPoint> combinedEntryPoints = new java.util.ArrayList<>(this.metadata.getEntryPoints());
combinedEntryPoints.addAll(newMetadata.getEntryPoints());
java.util.Map<String, String> combinedProperties = new java.util.HashMap<>(this.metadata.getProperties());
combinedProperties.putAll(newMetadata.getProperties());
this.metadata = CodebaseMetadata.builder()
.triggers(Collections.unmodifiableList(combinedTriggers))
.entryPoints(Collections.unmodifiableList(combinedEntryPoints))
.properties(Collections.unmodifiableMap(combinedProperties))
.build();
}
}

View File

@@ -0,0 +1,28 @@
package click.kamil.springstatemachineexporter.analysis.model;
import lombok.Builder;
import lombok.Getter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@Getter
@Builder(toBuilder = true)
public class CodebaseMetadata {
private final List<TriggerPoint> triggers;
private final List<EntryPoint> entryPoints;
private final Map<String, String> properties;
public static CodebaseMetadata empty() {
return CodebaseMetadata.builder()
.triggers(Collections.emptyList())
.entryPoints(Collections.emptyList())
.properties(Collections.emptyMap())
.build();
}
public record TriggerPoint(String className, String methodName, String event, Map<String, String> metadata) {}
public record EntryPoint(String className, String methodName, String type, Map<String, String> metadata) {}
}

View File

@@ -0,0 +1,19 @@
package click.kamil.springstatemachineexporter.analysis.service;
import click.kamil.springstatemachineexporter.analysis.enricher.AnalysisEnricher;
import click.kamil.springstatemachineexporter.analysis.model.AnalysisResult;
import click.kamil.springstatemachineexporter.ast.common.CodebaseContext;
import lombok.RequiredArgsConstructor;
import java.util.List;
@RequiredArgsConstructor
public class EnrichmentService {
private final List<AnalysisEnricher> enrichers;
public void enrich(AnalysisResult result, CodebaseContext context) {
for (AnalysisEnricher enricher : enrichers) {
enricher.enrich(result, context);
}
}
}

View File

@@ -1,5 +1,7 @@
package click.kamil.springstatemachineexporter.service;
import click.kamil.springstatemachineexporter.analysis.model.AnalysisResult;
import click.kamil.springstatemachineexporter.analysis.service.EnrichmentService;
import click.kamil.springstatemachineexporter.ast.app.AstTransitionParser;
import click.kamil.springstatemachineexporter.ast.app.StateMachineAggregator;
import click.kamil.springstatemachineexporter.ast.app.TransitionStateUtils;
@@ -17,6 +19,7 @@ import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -26,6 +29,7 @@ import java.util.Set;
public class ExportService {
private final List<StateMachineExporter> exporters;
private final EnrichmentService enrichmentService;
private static final List<String> TARGET_ANNOTATIONS = List.of("EnableStateMachineFactory", "EnableStateMachine");
public static final Set<String> STATE_MACHINE_RETURN_TYPES = Set.of("StateMachine", "StateMachineFactory", "StateMachineModelFactory");
@@ -38,7 +42,16 @@ public class ExportService {
public void runJsonExporter(Path jsonFile, Path outputDir, List<String> selectedFormats) throws IOException {
JsonImportService jsonImportService = new JsonImportService();
StateMachineModel model = jsonImportService.importJson(jsonFile);
generateOutputs(outputDir, model.getName(), model.getTransitions(), model.getStartStates(), model.getEndStates(), selectedFormats, model.isRenderChoicesAsDiamonds());
AnalysisResult result = AnalysisResult.builder()
.name(model.getName())
.transitions(model.getTransitions())
.startStates(model.getStartStates())
.endStates(model.getEndStates())
.renderChoicesAsDiamonds(model.isRenderChoicesAsDiamonds())
.build();
generateOutputs(outputDir, result, selectedFormats);
}
private void exportAll(CodebaseContext context, Path outputDir, List<String> selectedFormats, boolean renderChoicesAsDiamonds) throws IOException {
@@ -84,7 +97,17 @@ public class ExportService {
Set<String> startStates = TransitionStateUtils.findStartStates(transitions, initialStatesAst);
Set<String> endStates = TransitionStateUtils.findEndStates(transitions, endStatesAst);
generateOutputs(outputDir, className, transitions, startStates, endStates, selectedFormats, renderChoicesAsDiamonds);
AnalysisResult result = AnalysisResult.builder()
.name(className)
.transitions(transitions)
.startStates(startStates)
.endStates(endStates)
.renderChoicesAsDiamonds(renderChoicesAsDiamonds)
.build();
enrichmentService.enrich(result, context);
generateOutputs(outputDir, result, selectedFormats);
}
private void processBeanMethod(MethodDeclaration m, Path outputDir, CodebaseContext context, List<String> selectedFormats, boolean renderChoicesAsDiamonds) throws IOException {
@@ -100,18 +123,27 @@ public class ExportService {
Set<String> startStates = TransitionStateUtils.findStartStates(transitions);
Set<String> endStates = TransitionStateUtils.findEndStates(transitions);
generateOutputs(outputDir, uniqueName, transitions, startStates, endStates, selectedFormats, renderChoicesAsDiamonds);
AnalysisResult result = AnalysisResult.builder()
.name(uniqueName)
.transitions(transitions)
.startStates(startStates)
.endStates(endStates)
.renderChoicesAsDiamonds(renderChoicesAsDiamonds)
.build();
enrichmentService.enrich(result, context);
generateOutputs(outputDir, result, selectedFormats);
}
private void generateOutputs(Path outputDir, String baseName, List<Transition> transitions,
Set<String> startStates, Set<String> endStates, List<String> selectedFormats, boolean renderChoicesAsDiamonds) throws IOException {
private void generateOutputs(Path outputDir, AnalysisResult result, List<String> selectedFormats) throws IOException {
Path targetDir = outputDir.resolve(baseName);
Path targetDir = outputDir.resolve(result.getName());
Files.createDirectories(targetDir);
ExportOptions options = ExportOptions.builder()
.useLambdaGuards(true)
.renderChoicesAsDiamonds(renderChoicesAsDiamonds)
.renderChoicesAsDiamonds(result.isRenderChoicesAsDiamonds())
.build();
for (StateMachineExporter output : exporters) {
@@ -120,8 +152,8 @@ public class ExportService {
if (!match) continue;
}
String content = output.export(baseName, transitions, startStates, endStates, options);
String fileName = baseName + output.getFileExtension();
String content = output.export(result.getName(), result.getTransitions(), result.getStartStates(), result.getEndStates(), options);
String fileName = result.getName() + output.getFileExtension();
try (PrintWriter out = new PrintWriter(targetDir.resolve(fileName).toFile())) {
out.println(content);

View File

@@ -1,5 +1,6 @@
package click.kamil.springstatemachineexporter;
import click.kamil.springstatemachineexporter.analysis.service.EnrichmentService;
import click.kamil.springstatemachineexporter.exporter.PlantUml;
import click.kamil.springstatemachineexporter.exporter.StateMachineExporter;
import click.kamil.springstatemachineexporter.service.ExportService;
@@ -12,6 +13,7 @@ import org.junit.jupiter.params.provider.MethodSource;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
@@ -20,7 +22,8 @@ import static org.assertj.core.api.Assertions.assertThat;
public class PlantUmlRenderTest {
private final List<StateMachineExporter> exporters = List.of(new PlantUml());
private final ExportService exportService = new ExportService(exporters);
private final EnrichmentService enrichmentService = new EnrichmentService(Collections.emptyList());
private final ExportService exportService = new ExportService(exporters, enrichmentService);
private static List<TestScenario> provideTestScenarios() {
return List.of(

View File

@@ -1,5 +1,6 @@
package click.kamil.springstatemachineexporter;
import click.kamil.springstatemachineexporter.analysis.service.EnrichmentService;
import click.kamil.springstatemachineexporter.exporter.Dot;
import click.kamil.springstatemachineexporter.exporter.JsonExporter;
import click.kamil.springstatemachineexporter.exporter.PlantUml;
@@ -13,6 +14,7 @@ import org.junit.jupiter.params.provider.MethodSource;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
@@ -20,7 +22,8 @@ import static org.assertj.core.api.Assertions.assertThat;
public class RegressionTest {
private final List<StateMachineExporter> exporters = List.of(new PlantUml(), new Dot(), new Scxml(), new JsonExporter());
private final ExportService exportService = new ExportService(exporters);
private final EnrichmentService enrichmentService = new EnrichmentService(Collections.emptyList());
private final ExportService exportService = new ExportService(exporters, enrichmentService);
private static List<TestScenario> provideTestScenarios() {
return List.of(