kotlin
This commit is contained in:
@@ -32,6 +32,9 @@ dependencies {
|
||||
// deps for parsing java AST
|
||||
implementation 'org.eclipse.jdt:org.eclipse.jdt.core:3.36.0'
|
||||
|
||||
// Kotlin plugin integration via ServiceLoader
|
||||
runtimeOnly project(':state_machine_exporter_kotlin')
|
||||
|
||||
// Jackson for JSON support
|
||||
implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.1'
|
||||
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.17.1'
|
||||
|
||||
@@ -8,4 +8,8 @@ import java.util.List;
|
||||
|
||||
public interface CallGraphEngine {
|
||||
List<CallChain> findChains(List<EntryPoint> entryPoints, List<TriggerPoint> triggers);
|
||||
|
||||
default java.util.Map<String, java.util.List<click.kamil.springstatemachineexporter.analysis.model.CallEdge>> getCallGraph() {
|
||||
return java.util.Collections.emptyMap();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
package click.kamil.springstatemachineexporter.analysis.service;
|
||||
|
||||
import click.kamil.springstatemachineexporter.analysis.model.CallChain;
|
||||
import click.kamil.springstatemachineexporter.analysis.model.CallEdge;
|
||||
import click.kamil.springstatemachineexporter.analysis.model.EntryPoint;
|
||||
import click.kamil.springstatemachineexporter.analysis.model.TriggerPoint;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class CompositeCallGraphEngine implements CallGraphEngine {
|
||||
private final List<CallGraphEngine> engines;
|
||||
private final Map<String, List<CallEdge>> mergedGraph = new HashMap<>();
|
||||
|
||||
public CompositeCallGraphEngine(List<CallGraphEngine> engines) {
|
||||
this.engines = engines;
|
||||
mergeGraphs();
|
||||
}
|
||||
|
||||
private void mergeGraphs() {
|
||||
for (CallGraphEngine engine : engines) {
|
||||
Map<String, List<CallEdge>> graph = engine.getCallGraph();
|
||||
if (graph != null) {
|
||||
for (Map.Entry<String, List<CallEdge>> entry : graph.entrySet()) {
|
||||
String caller = normalizeCompanionFqn(entry.getKey());
|
||||
List<CallEdge> edges = mergedGraph.computeIfAbsent(caller, k -> new ArrayList<>());
|
||||
for (CallEdge edge : entry.getValue()) {
|
||||
String target = normalizeCompanionFqn(edge.getTargetMethod());
|
||||
edges.add(new CallEdge(target, edge.getArguments(), edge.getReceiver()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String normalizeCompanionFqn(String fqn) {
|
||||
if (fqn == null) return null;
|
||||
return fqn.replace(".Companion.", ".");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, List<CallEdge>> getCallGraph() {
|
||||
return mergedGraph;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CallChain> findChains(List<EntryPoint> entryPoints, List<TriggerPoint> triggers) {
|
||||
List<CallChain> chains = new ArrayList<>();
|
||||
for (EntryPoint ep : entryPoints) {
|
||||
String startMethod = normalizeCompanionFqn(ep.getClassName() + "." + ep.getMethodName());
|
||||
for (TriggerPoint tp : triggers) {
|
||||
String targetMethod = normalizeCompanionFqn(tp.getClassName() + "." + tp.getMethodName());
|
||||
List<List<String>> paths = findAllPaths(startMethod, targetMethod, new LinkedHashSet<>());
|
||||
for (List<String> path : paths) {
|
||||
chains.add(CallChain.builder()
|
||||
.entryPoint(ep)
|
||||
.methodChain(path)
|
||||
.triggerPoint(tp)
|
||||
.build());
|
||||
}
|
||||
}
|
||||
}
|
||||
return chains;
|
||||
}
|
||||
|
||||
private List<List<String>> findAllPaths(String start, String target, Set<String> visited) {
|
||||
List<List<String>> result = new ArrayList<>();
|
||||
if (start.equals(target)) {
|
||||
result.add(new ArrayList<>(List.of(start)));
|
||||
return result;
|
||||
}
|
||||
if (!visited.add(start)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
List<CallEdge> neighbors = mergedGraph.get(start);
|
||||
if (neighbors != null) {
|
||||
for (CallEdge edge : neighbors) {
|
||||
String neighbor = edge.getTargetMethod();
|
||||
if (neighbor.startsWith("java.") || neighbor.startsWith("javax.") ||
|
||||
neighbor.startsWith("jakarta.") || neighbor.startsWith("org.springframework.")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (neighbor.equals(target) || isHeuristicMatch(neighbor, target)) {
|
||||
List<String> path = new ArrayList<>(List.of(start, target));
|
||||
result.add(path);
|
||||
} else {
|
||||
List<List<String>> subPaths = findAllPaths(neighbor, target, visited);
|
||||
for (List<String> subPath : subPaths) {
|
||||
List<String> path = new ArrayList<>();
|
||||
path.add(start);
|
||||
path.addAll(subPath);
|
||||
result.add(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
visited.remove(start);
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean isHeuristicMatch(String neighbor, String target) {
|
||||
if (neighbor == null || target == null) return false;
|
||||
if (neighbor.equals(target)) return true;
|
||||
if (neighbor.contains(".") && target.contains(".")) {
|
||||
String methodNeighbor = neighbor.substring(neighbor.lastIndexOf('.') + 1);
|
||||
String methodTarget = target.substring(target.lastIndexOf('.') + 1);
|
||||
if (methodNeighbor.equals(methodTarget)) {
|
||||
String classNeighbor = neighbor.substring(0, neighbor.lastIndexOf('.'));
|
||||
String classTarget = target.substring(0, target.lastIndexOf('.'));
|
||||
String simpleClassNeighbor = classNeighbor.contains(".") ? classNeighbor.substring(classNeighbor.lastIndexOf('.') + 1) : classNeighbor;
|
||||
String simpleClassTarget = classTarget.contains(".") ? classTarget.substring(classTarget.lastIndexOf('.') + 1) : classTarget;
|
||||
return simpleClassNeighbor.equalsIgnoreCase(simpleClassTarget);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package click.kamil.springstatemachineexporter.analysis.service;
|
||||
|
||||
import click.kamil.springstatemachineexporter.analysis.model.CallChain;
|
||||
import click.kamil.springstatemachineexporter.analysis.model.EntryPoint;
|
||||
import click.kamil.springstatemachineexporter.analysis.model.TriggerPoint;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class CompositeIntelligenceProvider implements CodebaseIntelligenceProvider {
|
||||
private final List<CodebaseIntelligenceProvider> providers;
|
||||
private final List<CallGraphEngine> engines;
|
||||
|
||||
public CompositeIntelligenceProvider(List<CodebaseIntelligenceProvider> providers, List<CallGraphEngine> engines) {
|
||||
this.providers = providers;
|
||||
this.engines = engines;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TriggerPoint> findTriggerPoints() {
|
||||
List<TriggerPoint> result = new ArrayList<>();
|
||||
for (CodebaseIntelligenceProvider provider : providers) {
|
||||
result.addAll(provider.findTriggerPoints());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<EntryPoint> findEntryPoints() {
|
||||
List<EntryPoint> result = new ArrayList<>();
|
||||
for (CodebaseIntelligenceProvider provider : providers) {
|
||||
result.addAll(provider.findEntryPoints());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CallChain> findCallChains(List<EntryPoint> entryPoints, List<TriggerPoint> triggers) {
|
||||
CompositeCallGraphEngine compositeEngine = new CompositeCallGraphEngine(engines);
|
||||
return compositeEngine.findChains(entryPoints, triggers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Map<String, String>> resolveProperties() {
|
||||
Map<String, Map<String, String>> result = new HashMap<>();
|
||||
for (CodebaseIntelligenceProvider provider : providers) {
|
||||
Map<String, Map<String, String>> props = provider.resolveProperties();
|
||||
if (props != null) {
|
||||
result.putAll(props);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,11 @@ public class JdtCallGraphEngine extends AbstractCallGraphEngine {
|
||||
this.injectionAnalyzer = injectionAnalyzer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, List<CallEdge>> getCallGraph() {
|
||||
return buildCallGraph();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected Map<String, List<CallEdge>> buildCallGraph() {
|
||||
Map<String, List<CallEdge>> cached = (Map<String, List<CallEdge>>) context.getCache().get("jdtCallGraph");
|
||||
|
||||
@@ -22,9 +22,10 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import click.kamil.springstatemachineexporter.spi.SourceContext;
|
||||
|
||||
@Slf4j
|
||||
public class CodebaseContext {
|
||||
public class CodebaseContext implements SourceContext {
|
||||
private final Map<String, CompilationUnit> classes = new HashMap<>();
|
||||
private final Map<String, Path> classPaths = new HashMap<>();
|
||||
private final Map<String, String> simpleNameToFqn = new HashMap<>();
|
||||
@@ -51,6 +52,11 @@ public class CodebaseContext {
|
||||
this.projectRoot = root;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getProjectRoot() {
|
||||
return projectRoot;
|
||||
}
|
||||
|
||||
public String getRelativePath(Path fullPath) {
|
||||
if (projectRoot != null && fullPath.isAbsolute() && fullPath.startsWith(projectRoot)) {
|
||||
return projectRoot.relativize(fullPath).toString();
|
||||
@@ -88,6 +94,10 @@ public class CodebaseContext {
|
||||
this.classpath = classpath.toArray(new String[0]);
|
||||
}
|
||||
|
||||
public List<String> getClasspath() {
|
||||
return java.util.Arrays.asList(classpath);
|
||||
}
|
||||
|
||||
public void setSourcepath(List<String> sourcepath) {
|
||||
this.sourcepath = sourcepath.toArray(new String[0]);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
package click.kamil.springstatemachineexporter.plugin.java;
|
||||
|
||||
import click.kamil.springstatemachineexporter.analysis.model.AnalysisResult;
|
||||
import click.kamil.springstatemachineexporter.analysis.service.CallGraphEngine;
|
||||
import click.kamil.springstatemachineexporter.analysis.service.CodebaseIntelligenceProvider;
|
||||
import click.kamil.springstatemachineexporter.analysis.service.JdtCallGraphEngine;
|
||||
import click.kamil.springstatemachineexporter.analysis.service.JdtIntelligenceProvider;
|
||||
import click.kamil.springstatemachineexporter.ast.app.AstTransitionParser;
|
||||
import click.kamil.springstatemachineexporter.ast.app.StateMachineAggregator;
|
||||
import click.kamil.springstatemachineexporter.ast.app.TransitionStateUtils;
|
||||
import click.kamil.springstatemachineexporter.ast.common.CodebaseContext;
|
||||
import click.kamil.springstatemachineexporter.model.Transition;
|
||||
import click.kamil.springstatemachineexporter.spi.LanguageAnalyzerPlugin;
|
||||
import click.kamil.springstatemachineexporter.spi.SourceContext;
|
||||
import org.eclipse.jdt.core.dom.MethodDeclaration;
|
||||
import org.eclipse.jdt.core.dom.TypeDeclaration;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
|
||||
public class JavaLanguageAnalyzerPlugin implements LanguageAnalyzerPlugin {
|
||||
|
||||
@Override
|
||||
public boolean supports(Path projectRoot) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceContext parseProject(Path projectRoot, List<String> classpath, Set<Path> sourcePaths) {
|
||||
CodebaseContext context = new CodebaseContext();
|
||||
context.setProjectRoot(projectRoot);
|
||||
if (classpath != null && !classpath.isEmpty()) {
|
||||
context.setClasspath(classpath);
|
||||
}
|
||||
|
||||
Path hintsFile = projectRoot.resolve("hints.json");
|
||||
if (!java.nio.file.Files.exists(hintsFile)) {
|
||||
hintsFile = projectRoot.resolve("src/main/resources/hints.json");
|
||||
}
|
||||
if (java.nio.file.Files.exists(hintsFile)) {
|
||||
try {
|
||||
context.loadLibraryHints(hintsFile);
|
||||
} catch (java.io.IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
List<String> sp = sourcePaths.stream()
|
||||
.map(p -> p.resolve("src/main/java"))
|
||||
.filter(p -> java.nio.file.Files.exists(p))
|
||||
.map(Path::toString)
|
||||
.toList();
|
||||
if (sp.isEmpty()) {
|
||||
sp = sourcePaths.stream().map(Path::toString).toList();
|
||||
}
|
||||
context.setSourcepath(sp);
|
||||
|
||||
context.setResolveBindings(true);
|
||||
try {
|
||||
context.scan(sourcePaths, Collections.emptySet());
|
||||
} catch (java.io.IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CallGraphEngine createCallGraphEngine(SourceContext context) {
|
||||
if (context instanceof CodebaseContext jdtContext) {
|
||||
return new JdtCallGraphEngine(jdtContext, null);
|
||||
}
|
||||
throw new IllegalArgumentException("Expected CodebaseContext");
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodebaseIntelligenceProvider createIntelligenceProvider(SourceContext context) {
|
||||
if (context instanceof CodebaseContext jdtContext) {
|
||||
return new JdtIntelligenceProvider(jdtContext, jdtContext.getProjectRoot());
|
||||
}
|
||||
throw new IllegalArgumentException("Expected CodebaseContext");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AnalysisResult> extractStateMachines(SourceContext context, boolean renderChoicesAsDiamonds) {
|
||||
if (context instanceof CodebaseContext jdtContext) {
|
||||
List<AnalysisResult> results = new ArrayList<>();
|
||||
|
||||
// 1. Find entry point classes (annotated or extending adapter)
|
||||
List<TypeDeclaration> entryPoints = jdtContext.findEntryPointClasses(List.of("EnableStateMachineFactory", "EnableStateMachine"));
|
||||
for (TypeDeclaration td : entryPoints) {
|
||||
String className = jdtContext.getFqn(td);
|
||||
StateMachineAggregator aggregator = new StateMachineAggregator(jdtContext);
|
||||
List<Transition> transitions = aggregator.aggregateTransitions(td);
|
||||
aggregator.aggregateStates(td);
|
||||
Set<String> initialStatesAst = aggregator.getInitialStates();
|
||||
Set<String> endStatesAst = aggregator.getEndStates();
|
||||
|
||||
Set<String> startStates = TransitionStateUtils.findStartStates(transitions, initialStatesAst);
|
||||
Set<String> endStates = TransitionStateUtils.findEndStates(transitions, endStatesAst);
|
||||
Set<click.kamil.springstatemachineexporter.model.State> allStates = TransitionStateUtils.findAllStates(transitions, initialStatesAst, endStatesAst);
|
||||
|
||||
if (allStates.isEmpty() && transitions.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
results.add(AnalysisResult.builder()
|
||||
.name(className)
|
||||
.states(allStates)
|
||||
.transitions(transitions)
|
||||
.startStates(startStates)
|
||||
.endStates(endStates)
|
||||
.renderChoicesAsDiamonds(renderChoicesAsDiamonds)
|
||||
.build());
|
||||
}
|
||||
|
||||
// 2. Find methods returning StateMachine beans
|
||||
List<MethodDeclaration> beanMethods = jdtContext.findBeanMethodsReturning(Set.of("StateMachine", "StateMachineFactory", "StateMachineModelFactory"));
|
||||
for (MethodDeclaration m : beanMethods) {
|
||||
TypeDeclaration parentClass = (TypeDeclaration) m.getParent();
|
||||
String parentFqn = jdtContext.getFqn(parentClass);
|
||||
String methodName = m.getName().getIdentifier();
|
||||
String uniqueName = parentFqn + "#" + methodName;
|
||||
|
||||
List<Transition> transitions = AstTransitionParser.parseTransitions(m, jdtContext);
|
||||
|
||||
Set<String> startStates = TransitionStateUtils.findStartStates(transitions, null);
|
||||
Set<String> endStates = TransitionStateUtils.findEndStates(transitions, null);
|
||||
Set<click.kamil.springstatemachineexporter.model.State> allStates = TransitionStateUtils.findAllStates(transitions, null, null);
|
||||
|
||||
if (allStates.isEmpty() && transitions.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
results.add(AnalysisResult.builder()
|
||||
.name(uniqueName)
|
||||
.states(allStates)
|
||||
.transitions(transitions)
|
||||
.startStates(startStates)
|
||||
.endStates(endStates)
|
||||
.renderChoicesAsDiamonds(renderChoicesAsDiamonds)
|
||||
.build());
|
||||
}
|
||||
return results;
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,11 @@ import click.kamil.springstatemachineexporter.exporter.StateMachineExporter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.jdt.core.dom.MethodDeclaration;
|
||||
import org.eclipse.jdt.core.dom.TypeDeclaration;
|
||||
import click.kamil.springstatemachineexporter.spi.LanguageAnalyzerPlugin;
|
||||
import click.kamil.springstatemachineexporter.spi.SourceContext;
|
||||
import click.kamil.springstatemachineexporter.analysis.service.CompositeIntelligenceProvider;
|
||||
import click.kamil.springstatemachineexporter.analysis.service.CallGraphEngine;
|
||||
import click.kamil.springstatemachineexporter.analysis.service.JdtCallGraphEngine;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
@@ -137,8 +142,57 @@ public class ExportService {
|
||||
|
||||
context.scan(allPaths, Collections.emptySet());
|
||||
|
||||
CodebaseIntelligenceProvider intelligence = new JdtIntelligenceProvider(context, inputDir);
|
||||
exportAll(context, intelligence, outputDir, selectedFormats, renderChoicesAsDiamonds, flows, machineFilter, activeProfiles != null ? activeProfiles : Collections.emptyList(), eventFormat, stateFormat);
|
||||
// Load SPI plugins dynamically
|
||||
ServiceLoader<LanguageAnalyzerPlugin> loader = ServiceLoader.load(LanguageAnalyzerPlugin.class);
|
||||
List<LanguageAnalyzerPlugin> plugins = new ArrayList<>();
|
||||
for (LanguageAnalyzerPlugin plugin : loader) {
|
||||
if (plugin.supports(inputDir)) {
|
||||
plugins.add(plugin);
|
||||
}
|
||||
}
|
||||
if (plugins.isEmpty()) {
|
||||
plugins.add(new click.kamil.springstatemachineexporter.plugin.java.JavaLanguageAnalyzerPlugin());
|
||||
}
|
||||
|
||||
List<SourceContext> sourceContexts = new ArrayList<>();
|
||||
List<CodebaseIntelligenceProvider> providers = new ArrayList<>();
|
||||
List<CallGraphEngine> engines = new ArrayList<>();
|
||||
List<AnalysisResult> extractedResults = new ArrayList<>();
|
||||
|
||||
for (LanguageAnalyzerPlugin plugin : plugins) {
|
||||
SourceContext sc = plugin.parseProject(projectRoot, context.getClasspath(), allPaths);
|
||||
sourceContexts.add(sc);
|
||||
providers.add(plugin.createIntelligenceProvider(sc));
|
||||
engines.add(plugin.createCallGraphEngine(sc));
|
||||
extractedResults.addAll(plugin.extractStateMachines(sc, renderChoicesAsDiamonds));
|
||||
}
|
||||
|
||||
CodebaseContext codebaseContext = context;
|
||||
CodebaseIntelligenceProvider unifiedIntelligence;
|
||||
if (plugins.size() == 1) {
|
||||
unifiedIntelligence = providers.get(0);
|
||||
if (sourceContexts.get(0) instanceof CodebaseContext jdtCtx) {
|
||||
codebaseContext = jdtCtx;
|
||||
}
|
||||
} else {
|
||||
unifiedIntelligence = new CompositeIntelligenceProvider(providers, engines);
|
||||
}
|
||||
|
||||
// Process all extracted state machines
|
||||
for (AnalysisResult result : extractedResults) {
|
||||
String name = result.getName();
|
||||
if (machineFilter != null && !name.contains(machineFilter)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (result.getFlows() == null || result.getFlows().isEmpty()) {
|
||||
result.setFlows(flows);
|
||||
}
|
||||
|
||||
enrichmentService.enrich(result, codebaseContext, unifiedIntelligence);
|
||||
resolveProperties(result, activeProfiles);
|
||||
generateOutputs(outputDir, result, selectedFormats, eventFormat, stateFormat);
|
||||
}
|
||||
}
|
||||
|
||||
public void runJsonExporter(Path jsonFile, Path outputDir, List<String> selectedFormats) throws IOException {
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
package click.kamil.springstatemachineexporter.spi;
|
||||
|
||||
import click.kamil.springstatemachineexporter.analysis.service.CallGraphEngine;
|
||||
import click.kamil.springstatemachineexporter.analysis.service.CodebaseIntelligenceProvider;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Service Provider Interface (SPI) for introducing support for different languages (Java, Kotlin, etc.).
|
||||
*/
|
||||
public interface LanguageAnalyzerPlugin {
|
||||
|
||||
/**
|
||||
* Determines if this plugin is capable of handling the provided project root.
|
||||
* Often checks for file extensions (.kt, .java) within the root.
|
||||
*/
|
||||
boolean supports(Path projectRoot);
|
||||
|
||||
/**
|
||||
* Parses the codebase and sets up a SourceContext loaded with the language's AST structures.
|
||||
*/
|
||||
SourceContext parseProject(Path projectRoot, List<String> classpath, Set<Path> sourcePaths);
|
||||
|
||||
/**
|
||||
* Creates a CallGraphEngine specialized for this language's syntax and paradigms.
|
||||
*/
|
||||
CallGraphEngine createCallGraphEngine(SourceContext context);
|
||||
|
||||
/**
|
||||
* Creates a CodebaseIntelligenceProvider specialized for this language to discover
|
||||
* Spring State Machine configurations, entry points, and transitions.
|
||||
*/
|
||||
CodebaseIntelligenceProvider createIntelligenceProvider(SourceContext context);
|
||||
|
||||
/**
|
||||
* Finds and extracts all Spring State Machine models (configurations and beans) from the project.
|
||||
*/
|
||||
default List<click.kamil.springstatemachineexporter.analysis.model.AnalysisResult> extractStateMachines(SourceContext context, boolean renderChoicesAsDiamonds) {
|
||||
return java.util.Collections.emptyList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package click.kamil.springstatemachineexporter.spi;
|
||||
|
||||
import click.kamil.springstatemachineexporter.analysis.model.LibraryHint;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* An abstraction over a parsed source codebase (Java, Kotlin, etc.).
|
||||
* Provides access to common metadata required by analysis engines.
|
||||
*/
|
||||
public interface SourceContext {
|
||||
/**
|
||||
* Gets the root directory of the scanned project.
|
||||
*/
|
||||
Path getProjectRoot();
|
||||
|
||||
/**
|
||||
* Relativizes an absolute path against the project root.
|
||||
*/
|
||||
String getRelativePath(Path fullPath);
|
||||
|
||||
/**
|
||||
* Returns a relative file path for a given fully qualified class/type name.
|
||||
*/
|
||||
String getRelativePath(String fqn);
|
||||
|
||||
/**
|
||||
* Retrieves any loaded library hints (e.g. from hints.json).
|
||||
*/
|
||||
List<LibraryHint> getLibraryHints();
|
||||
|
||||
/**
|
||||
* Retrieves application properties (e.g. from application.yml).
|
||||
*/
|
||||
Map<String, Map<String, String>> getProperties();
|
||||
|
||||
/**
|
||||
* Gets an unstructured cache map that plugins can use to share data across processing phases.
|
||||
*/
|
||||
Map<String, Object> getCache();
|
||||
}
|
||||
Reference in New Issue
Block a user