# Spring State Machine Explorer

Static analysis tool to extract and visualize Spring State Machines with deep code traceability.

## Core Modules
- **`state_machine_exporter`**: Java AST analyzer. Scans source code, resolves local Maven/Gradle dependencies, and extracts logic (Lambdas, Actions, Guards) into JSON/PUML.
- **`state_machine_exporter_html`**: Generates an interactive HTML portal with SVG diagrams and rich tooltips.

## Usage

Analysis is **source-first**: the exporter reads project source and build metadata (`pom.xml`, `settings.gradle`) statically. It does **not** run Maven or Gradle against the project being analyzed.

### 1. Extract Metadata (JSON)
```bash
./gradlew :state_machine_exporter:run --args="-i ./my-project -o ./out -f json"
```

Common options:

| Flag | Description |
|------|-------------|
| `-i, --input` | Project directory to scan (defaults to `.`) |
| `-j, --json` | Re-render from an existing JSON export instead of scanning source |
| `-o, --output` | Output directory (default `./out`) |
| `-f, --format` | Comma-separated formats: `json`, `dot`, `puml`, `scxml` |
| `-p, --profiles` | Spring profiles for property placeholder resolution |
| `--event`, `--state` | Enum formatting: `fn` (default), `fqn`, `sn` |
| `--debug` | Verbose analysis logging and unresolved chain diagnostics |
| `--no-diamonds` | Render choice/junction states as regular nodes (default: diamonds) |
| `--include-generated-sources` | Also scan `target/` / `build/` generated `.java` trees (default: on) |
| `--no-inline-accessors` | Disable accessor indexing/inlining (enabled by default) |

### 2. Generate Interactive Portal (HTML)
```bash
./gradlew :state_machine_exporter_html:run --args="-i ./my-project -o ./out_html"
```

HTML-specific options:

| Flag | Description |
|------|-------------|
| `-f, --flows` | Custom `flows.json` path |
| `-m, --machine` | Export only machines whose name contains this filter |
| `--open` | Open the generated portal in the default browser |
| `--no-metadata-pane` | Hide the left metadata pane (entry points, flows) |
| `--no-diamonds` | Render choice pseudostates as normal nodes |
| `--debug` | Same diagnostic mode as the core exporter |
| `--include-generated-sources` | Same generated-source scanning as the core exporter |
| `--no-inline-accessors` | Disable accessor indexing/inlining (enabled by default) |
| `-p, --profiles` | Spring profiles for property resolution |

## Business Flows
Define sequence of events in `src/main/resources/flows.json`:
```json
[
  {
    "name": "Order Success",
    "description": "Happy path for order placement",
    "steps": [
      "PAY",
      "CHECK_AVAILABILITY->PENDING",
      { "source": "com.example.order.OrderState.PAID", "event": "com.example.order.OrderEvent.SHIP" }
    ]
  }
]
```

Event-only strings remain supported but do not highlight in the HTML explorer unless paired with a source state. Use `{source, event}` objects for precise transition highlighting.

## JSON Structure
- `metadata.entryPoints`: REST, WebFlux, and JMS entry points.
- `metadata.callChains`: Trace from API call to machine trigger (`sendEvent`).
- `transitions.actions[].internalLogic`: Extracted source code/lambdas.
- `metadata.properties`: Dictionary of all detected Spring profiles.

## Static analysis: accessor inlining

During scan, the exporter builds an **accessor index** of trivial getters, setters, record components, and constant-returning methods. At analysis time, `AccessorResolver` uses this index first (O(1) lookup), then falls back to constructor/field tracing and method-body evaluation.

This improves resolution of DTO/event chains such as `request.getPayload().getType()` without running Maven or Gradle on the target project.

```bash
# Enabled by default; disable for debugging or A/B comparison
./gradlew :state_machine_exporter:run --args="-i ./my-project -o ./out --no-inline-accessors"
```

Pipeline components live under `analysis/pipeline/` (`AccessorResolver`, `ResolutionBudget`, `MethodInvocationUnwrapper`, `FieldInitializerFinder`, `LibraryUnwrapRegistry`).
