v2.1 extended analysis render update

This commit is contained in:
2026-06-14 22:14:47 +02:00
parent 38d708f85b
commit 71bcfe65d7
63 changed files with 1382 additions and 2394 deletions

View File

@@ -1,10 +1,10 @@
package click.kamil.springstatemachineexporter.html;
import click.kamil.springstatemachineexporter.command.ExporterCommand;
import click.kamil.springstatemachineexporter.exporter.Dot;
import click.kamil.springstatemachineexporter.exporter.JsonExporter;
import click.kamil.springstatemachineexporter.exporter.PlantUml;
import click.kamil.springstatemachineexporter.exporter.Scxml;
import click.kamil.springstatemachineexporter.html.command.HtmlExporterCommand;
import click.kamil.springstatemachineexporter.html.exporter.HtmlExporter;
import click.kamil.springstatemachineexporter.service.ExportService;
import picocli.CommandLine;
@@ -13,10 +13,10 @@ import java.util.List;
public class Main {
public static void main(String[] args) {
// Wiring including the new HTML exporter
// Wiring including the specialized HTML exporter
var exporters = List.of(new PlantUml(), new Dot(), new Scxml(), new JsonExporter(), new HtmlExporter());
var exportService = new ExportService(exporters);
var command = new ExporterCommand(exportService);
var command = new HtmlExporterCommand(exportService);
int exitCode = new CommandLine(command).execute(args);
System.exit(exitCode);

View File

@@ -0,0 +1,110 @@
package click.kamil.springstatemachineexporter.html.command;
import click.kamil.springstatemachineexporter.service.ExportService;
import lombok.RequiredArgsConstructor;
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
import java.awt.*;
import java.io.File;
import java.nio.file.Path;
import java.util.List;
import java.util.concurrent.Callable;
@Command(
name = "spring-sm-html-exporter",
mixinStandardHelpOptions = true,
version = "1.0.0",
description = "Generates interactive HTML documentation portals for Spring State Machines.",
headerHeading = "@|bold,underline Usage:|@%n%n",
synopsisHeading = "%n",
descriptionHeading = "%n@|bold,underline Description:|@%n%n",
parameterListHeading = "%n@|bold,underline Parameters:|@%n",
optionListHeading = "%n@|bold,underline Options:|@%n",
header = "Welcome to the @|bold,red Interactive State Machine Explorer|@!%n"
)
@RequiredArgsConstructor
public class HtmlExporterCommand implements Callable<Integer> {
private final ExportService exportService;
@CommandLine.Spec
CommandLine.Model.CommandSpec spec;
@Option(names = {"-i", "--input"}, description = "Input directory containing the Spring Boot project source code.")
private Path inputDir;
@Option(names = {"-o", "--output"}, description = "Output directory for the generated portal.", defaultValue = "./out_html")
private Path outputDir;
@Option(names = {"-f", "--flows"}, description = "Optional path to a custom flows.json file.")
private Path flowsFile;
@Option(names = {"-m", "--machine"}, description = "Filter to only export state machines whose name contains this string.")
private String machineFilter;
@Option(names = {"-p", "--profiles"}, description = "Spring profiles to activate for property resolution.", split = ",")
private List<String> activeProfiles;
@Option(names = {"--open"}, description = "Automatically open the generated HTML portal in your default browser.")
private boolean openPortal;
@Override
public Integer call() throws Exception {
var out = spec.commandLine().getOut();
var err = spec.commandLine().getErr();
if (inputDir == null) {
inputDir = Path.of(".");
}
out.println(CommandLine.Help.Ansi.AUTO.string("@|bold,red Initializing Interactive Portal Generation...|@"));
out.println(CommandLine.Help.Ansi.AUTO.string("@|yellow Input Directory:|@ " + inputDir.toAbsolutePath()));
out.println(CommandLine.Help.Ansi.AUTO.string("@|yellow Output Directory:|@ " + outputDir.toAbsolutePath()));
if (flowsFile != null) {
out.println(CommandLine.Help.Ansi.AUTO.string("@|yellow Custom Flows:|@ " + flowsFile.toAbsolutePath()));
}
if (machineFilter != null) {
out.println(CommandLine.Help.Ansi.AUTO.string("@|yellow Machine Filter:|@ " + machineFilter));
}
try {
// Force HTML and JSON formats for the interactive portal
List<String> formats = List.of("html", "json");
exportService.runExporter(inputDir, outputDir, formats, true,
activeProfiles != null ? activeProfiles : java.util.Collections.emptyList(),
flowsFile, machineFilter);
out.println(CommandLine.Help.Ansi.AUTO.string("%n@|bold,green SUCCESS:|@ Interactive documentation generated successfully."));
if (openPortal) {
out.println(CommandLine.Help.Ansi.AUTO.string("@|cyan Attempting to open portal in browser...|@"));
openInBrowser(outputDir);
}
return 0;
} catch (Exception e) {
err.println(CommandLine.Help.Ansi.AUTO.string("%n@|bold,red ERROR:|@ Generation failed: " + e.getMessage()));
e.printStackTrace(err);
return 1;
}
}
private void openInBrowser(Path outputDir) {
try {
// Find the first HTML file in the output dir
File dir = outputDir.toFile();
File[] subDirs = dir.listFiles(File::isDirectory);
if (subDirs != null && subDirs.length > 0) {
File[] htmlFiles = subDirs[0].listFiles((d, name) -> name.endsWith(".html"));
if (htmlFiles != null && htmlFiles.length > 0) {
Desktop.getDesktop().browse(htmlFiles[0].toURI());
}
}
} catch (Exception e) {
spec.commandLine().getErr().println("Failed to open browser: " + e.getMessage());
}
}
}

View File

@@ -8,12 +8,11 @@ public class SvgDecorator {
public String decorate(String rawSvg) {
String result = rawSvg;
// 1. Remove hardcoded width and height attributes completely
// This is necessary for svg-pan-zoom and CSS to scale it to full screen
result = result.replaceFirst("(?i)width=\"[^\"]*\"", "");
result = result.replaceFirst("(?i)height=\"[^\"]*\"", "");
// 1. Properly replace width/height with 100% on the root <svg> tag
result = result.replaceFirst("(?i)width=\"[^\"]*\"", "width=\"100%\"");
result = result.replaceFirst("(?i)height=\"[^\"]*\"", "height=\"100%\"");
// 2. Remove the hardcoded 'style' attribute which often contains fixed pixel sizes
// 2. Remove the hardcoded 'style' attribute if present
result = result.replaceFirst("(?i)style=\"[^\"]*\"", "");
// 3. Maintain layout integrity