diff --git a/.credo.exs b/.credo.exs
index 63133c0..e533ac4 100644
--- a/.credo.exs
+++ b/.credo.exs
@@ -84,7 +84,7 @@
# Priority values are: `low, normal, high, higher`
#
{Credo.Check.Design.AliasUsage,
- [priority: :low, if_nested_deeper_than: 2, if_called_more_often_than: 0]},
+ [priority: :low, if_nested_deeper_than: 1, if_called_more_often_than: 0]},
{Credo.Check.Design.TagFIXME, []},
# You can also customize the exit_status of each check.
# If you don't want TODO comments to cause `mix credo` to fail, just
diff --git a/.githooks/pre-push b/.githooks/pre-push
index 8a488b9..448dd93 100755
--- a/.githooks/pre-push
+++ b/.githooks/pre-push
@@ -26,6 +26,31 @@ if ! mix format --check-formatted; then
fi
fi
+# Check for markdown files and lint them if markdownlint-cli2 is available
+if command -v markdownlint-cli2 >/dev/null 2>&1; then
+ # Check if any .md files are in the repository
+ if find . -name "*.md" -not -path "./deps/*" -not -path "./_build/*" | head -1 | grep -q .; then
+ echo "๐ Checking markdown formatting..."
+ # Get list of project markdown files (excluding deps and _build)
+ md_files=$(find . -name "*.md" -not -path "./deps/*" -not -path "./_build/*")
+ if ! echo "$md_files" | xargs markdownlint-cli2 --config .markdownlint.json 2>/dev/null; then
+ echo "โ Markdown linting failed!"
+ echo "๐ก Fix markdown issues manually or run:"
+ echo " find . -name \"*.md\" -not -path \"./deps/*\" -not -path \"./_build/*\" | xargs markdownlint-cli2 --config .markdownlint.json --fix"
+ echo "๐ก Install markdownlint-cli2 with: npm install -g markdownlint-cli2"
+ exit 1
+ fi
+ echo "โ
Markdown formatting looks good"
+ fi
+else
+ # Check if any .md files exist to give helpful message
+ if find . -name "*.md" -not -path "./deps/*" -not -path "./_build/*" | head -1 | grep -q .; then
+ echo "โน๏ธ markdownlint-cli2 not found - skipping markdown linting"
+ echo "๐ก Install with: npm install -g markdownlint-cli2"
+ echo "๐ก Or run manually: find . -name \"*.md\" -not -path \"./deps/*\" -not -path \"./_build/*\" | xargs markdownlint-cli2"
+ fi
+fi
+
# Run regression tests (critical - these should never break)
echo "๐งช Running regression tests..."
if ! mix test.regression; then
@@ -48,4 +73,4 @@ fi
# exit 1
# fi
-echo "โ
All validation checks passed! Ready to push."
\ No newline at end of file
+echo "โ
All validation checks passed! Ready to push."
diff --git a/.github/workflows/README.md b/.github/workflows/README.md
new file mode 100644
index 0000000..24432c8
--- /dev/null
+++ b/.github/workflows/README.md
@@ -0,0 +1,59 @@
+# GitHub Workflows
+
+This directory contains the CI/CD workflows for the SC project.
+
+## Workflow Strategy
+
+### **Conditional Execution Based on File Changes**
+
+The workflows are designed to run conditionally based on what files have been changed:
+
+#### **Code Changes** โ `ci.yml`
+
+- **Triggers**: Changes to `.ex`, `.exs`, `mix.exs`, `mix.lock`, `config/`, etc.
+- **Skips**: Documentation files (`.md`), license files, `.gitignore`
+- **Jobs**: Full CI pipeline (compile, format, test, credo, dialyzer, regression tests)
+- **Purpose**: Validates code quality, functionality, and compatibility
+
+#### **Documentation Changes** โ `docs.yml`
+
+- **Triggers**: Changes to `.md` files, `docs/` directory
+- **Jobs**: Markdown linting, link checking, documentation validation
+- **Purpose**: Ensures documentation quality and consistency
+
+### **Benefits**
+
+- โ
**Faster feedback** - Documentation changes don't run expensive code tests
+- โ
**Resource efficient** - Saves CI minutes on documentation-only changes
+- โ
**Focused validation** - Each workflow validates what actually changed
+- โ
**Clear separation** - Code and documentation validation are distinct concerns
+
+### **Example Scenarios**
+
+| Change | ci.yml | docs.yml | Result |
+|--------|--------|----------|---------|
+| `lib/sc/validator.ex` | โ
Runs | โ Skipped | Full code validation |
+| `README.md` | โ Skipped | โ
Runs | Documentation validation only |
+| `lib/sc/state.ex` + `CLAUDE.md` | โ
Runs | โ
Runs | Both workflows run |
+
+## Workflows
+
+### **`ci.yml`** - Main CI Pipeline
+
+- **Compilation** - Compile with warnings as errors
+- **Code Formatting** - Verify `mix format` compliance
+- **Testing** - Multi-version testing with coverage (Elixir 1.17+ / OTP 26+)
+- **Static Analysis** - Credo strict mode validation
+- **Type Checking** - Dialyzer static analysis
+- **Regression Testing** - Critical functionality validation
+
+### **`docs.yml`** - Documentation Pipeline
+
+- **Markdown Linting** - Style and structure validation
+- **Link Checking** - Verify external links are valid
+- **Memory Validation** - Ensure CLAUDE.md and README.md have required sections
+- **API Consistency** - Check that documentation references current API
+
+## Configuration Files
+
+- **`markdown-link-check-config.json`** - Link checker configuration with retry policies
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 239dfbb..79053fc 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -3,8 +3,22 @@ name: CI
on:
push:
branches: [ main ]
+ paths-ignore:
+ - '**/*.md'
+ - 'CLAUDE.md'
+ - 'README.md'
+ - 'LICENSE*'
+ - 'docs/**'
+ - '.gitignore'
pull_request:
branches: [ main ]
+ paths-ignore:
+ - '**/*.md'
+ - 'CLAUDE.md'
+ - 'README.md'
+ - 'LICENSE*'
+ - 'docs/**'
+ - '.gitignore'
env:
MIX_ENV: test
diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
new file mode 100644
index 0000000..510c478
--- /dev/null
+++ b/.github/workflows/docs.yml
@@ -0,0 +1,87 @@
+name: Documentation
+
+on:
+ push:
+ branches: [ main ]
+ paths:
+ - '**/*.md'
+ - 'CLAUDE.md'
+ - 'README.md'
+ - 'docs/**'
+ pull_request:
+ branches: [ main ]
+ paths:
+ - '**/*.md'
+ - 'CLAUDE.md'
+ - 'README.md'
+ - 'docs/**'
+
+jobs:
+ lint-docs:
+ name: Lint Documentation
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Lint Markdown files
+ uses: DavidAnson/markdownlint-cli2-action@v13
+ with:
+ globs: |
+ **/*.md
+ !node_modules/**/*.md
+
+ - name: Check for broken links
+ uses: gaurav-nelson/github-action-markdown-link-check@v1
+ with:
+ use-quiet-mode: 'yes'
+ use-verbose-mode: 'yes'
+ config-file: '.github/workflows/markdown-link-check-config.json'
+
+ validate-memory:
+ name: Validate Memory Files
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Check CLAUDE.md structure
+ run: |
+ echo "Validating CLAUDE.md structure..."
+ if ! grep -q "## Commands" CLAUDE.md; then
+ echo "โ CLAUDE.md missing Commands section"
+ exit 1
+ fi
+ if ! grep -q "## Architecture" CLAUDE.md; then
+ echo "โ CLAUDE.md missing Architecture section"
+ exit 1
+ fi
+ echo "โ
CLAUDE.md structure looks good"
+
+ - name: Check README.md structure
+ run: |
+ echo "Validating README.md structure..."
+ if ! grep -q "## Features" README.md; then
+ echo "โ README.md missing Features section"
+ exit 1
+ fi
+ if ! grep -q "## Current Status" README.md; then
+ echo "โ README.md missing Current Status section"
+ exit 1
+ fi
+ echo "โ
README.md structure looks good"
+
+ - name: Validate documentation consistency
+ run: |
+ echo "Checking for API consistency between CLAUDE.md and README.md..."
+
+ # Check that both files reference SC.Validator (not SC.Document.Validator)
+ if grep -q "SC\.Document\.Validator" CLAUDE.md README.md; then
+ echo "โ Found outdated SC.Document.Validator references - should be SC.Validator"
+ grep -n "SC\.Document\.Validator" CLAUDE.md README.md || true
+ exit 1
+ fi
+
+ echo "โ
API references look consistent"
\ No newline at end of file
diff --git a/.github/workflows/markdown-link-check-config.json b/.github/workflows/markdown-link-check-config.json
new file mode 100644
index 0000000..5a5717d
--- /dev/null
+++ b/.github/workflows/markdown-link-check-config.json
@@ -0,0 +1,22 @@
+{
+ "ignorePatterns": [
+ {
+ "pattern": "^http://localhost"
+ },
+ {
+ "pattern": "^https://codecov.io"
+ }
+ ],
+ "timeout": "20s",
+ "retryOn429": true,
+ "retryCount": 3,
+ "fallbackHttpStatus": [
+ 400,
+ 401,
+ 403,
+ 404,
+ 500,
+ 502,
+ 503
+ ]
+}
\ No newline at end of file
diff --git a/.markdownlint.json b/.markdownlint.json
new file mode 100644
index 0000000..d865928
--- /dev/null
+++ b/.markdownlint.json
@@ -0,0 +1,33 @@
+{
+ "default": true,
+ "line-length": false,
+ "no-duplicate-heading": false,
+ "no-inline-html": {
+ "allowed_elements": ["br", "kbd", "sub", "sup"]
+ },
+ "whitespace": true,
+ "no-hard-tabs": true,
+ "no-trailing-spaces": true,
+ "no-multiple-blanks": {
+ "maximum": 2
+ },
+ "blanks-around-headings": {
+ "lines_above": 1,
+ "lines_below": 1
+ },
+ "heading-increment": true,
+ "no-missing-space-atx": true,
+ "no-missing-space-closed-atx": true,
+ "ul-style": {
+ "style": "dash"
+ },
+ "ol-prefix": {
+ "style": "one_or_ordered"
+ },
+ "list-indent": true,
+ "blanks-around-fences": true,
+ "fenced-code-language": false,
+ "first-line-h1": false,
+ "heading-start-left": true,
+ "single-trailing-newline": true
+}
\ No newline at end of file
diff --git a/CLAUDE.md b/CLAUDE.md
index 9be6e47..6eee849 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -6,24 +6,28 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
**Local Validation Workflow:**
When verifying code changes, always follow this sequence (also automated via pre-push git hook):
+
1. `mix format` - Auto-fix formatting issues (trailing whitespace, final newlines, etc.)
2. `mix test --cover` - Ensure functionality and maintain 95%+ test coverage
3. `mix credo --strict` - Run static code analysis only after tests pass
4. `mix dialyzer` - Run Dialyzer static analysis for type checking
**Git Hooks:**
+
- `./scripts/setup-git-hooks.sh` - Install pre-push hook for validation pipeline
- Pre-push hook automatically runs the validation workflow to catch issues before CI
- Located at `.git/hooks/pre-push` (executable)
- Blocks push if any validation step fails
**Regression Testing:**
+
- `test/passing_tests.json` - Registry of tests that should always pass
- Tracks internal tests, SCION tests, and W3C tests separately
- Updated manually when new tests start passing consistently
- Used by CI pipeline to catch regressions early
**Testing:**
+
- `mix test` - Run all internal tests (excludes SCION/W3C by default)
- `mix test --include scion --include scxml_w3` - Run all tests including SCION and W3C tests
- `mix test.regression` - Run regression tests that should always pass
@@ -36,6 +40,7 @@ When verifying code changes, always follow this sequence (also automated via pre
- `mix test test/sc/interpreter/compound_state_test.exs` - Run compound state tests
**Development:**
+
- `mix deps.get` - Install dependencies
- `mix compile` - Compile the project
- `mix docs` - Generate documentation
@@ -48,15 +53,16 @@ When verifying code changes, always follow this sequence (also automated via pre
This is an Elixir implementation of SCXML (State Chart XML) state machines with a focus on W3C compliance.
-The State Chart reference XML is here: https://www.w3.org/TR/scxml/
+The State Chart reference XML is here:
This project uses Elixir Structs for the data structures, and MapSets for sets.
-Also use this initial Elixir implementation as reference: https://github.com/camshaft/ex_statechart
+Also use this initial Elixir implementation as reference:
## Core Components
### Data Structures
+
- **`SC.Document`** - Root SCXML document structure with:
- Attributes: `name`, `initial`, `datamodel`, `version`, `xmlns`
- Collections: `states`, `datamodel_elements`
@@ -67,6 +73,7 @@ Also use this initial Elixir implementation as reference: https://github.com/cam
- **`SC.DataElement`** - Datamodel elements with required `id` and optional `expr` and `src` attributes
### Parsers (Parse Phase)
+
- **`SC.Parser.SCXML`** - Main SCXML parser using Saxy SAX parser for accurate location tracking
- Parses XML strings into `SC.Document` structs with precise source location information
- Event-driven SAX parsing for better memory efficiency and location tracking
@@ -84,14 +91,21 @@ Also use this initial Elixir implementation as reference: https://github.com/cam
- **`SC.Parser.SCXML.StateStack`** - Manages parsing state stack for hierarchical document construction
### Validation and Optimization (Validate + Optimize Phases)
-- **`SC.Document.Validator`** - Document validation and optimization
+
+- **`SC.Validator`** - Main validation orchestrator
+ - **Modular architecture**: Split into focused sub-validators for maintainability
- **Validation**: Structural correctness, semantic consistency, reference validation
- **Optimization**: Builds O(1) lookup maps via `finalize/2` for valid documents only
- Returns `{:ok, optimized_document, warnings}` or `{:error, errors, warnings}`
- **Clean architecture**: Only optimizes documents that pass validation
- - Uses `find_state_by_id_linear/2` during validation, switches to O(1) after optimization
+- **`SC.Validator.StateValidator`** - State ID uniqueness and validation
+- **`SC.Validator.TransitionValidator`** - Transition target validation
+- **`SC.Validator.InitialStateValidator`** - All initial state constraints (attributes, elements, conflicts)
+- **`SC.Validator.ReachabilityAnalyzer`** - State reachability graph analysis
+- **`SC.Validator.Utils`** - Shared utilities across validators
### Interpreter and Runtime
+
- **`SC.Interpreter`** - Core SCXML interpreter with synchronous API
- Initializes state charts from validated + optimized documents
- **Compound state support**: Automatically enters initial child states recursively
@@ -110,6 +124,7 @@ Also use this initial Elixir implementation as reference: https://github.com/cam
- **`SC.Event`** - Event representation with internal/external origins
- Supports event data and origin tracking
- Used for state machine event processing
+
### Architecture Flow
The implementation follows a clean **Parse โ Validate โ Optimize** architecture:
@@ -119,19 +134,26 @@ The implementation follows a clean **Parse โ Validate โ Optimize** architect
{:ok, document} = SC.Parser.SCXML.parse(xml_string)
# 2. Validate + Optimize Phase: Check semantics + build lookup maps
-{:ok, optimized_document, warnings} = SC.Document.Validator.validate(document)
+{:ok, optimized_document, warnings} = SC.Validator.validate(document)
# 3. Interpret Phase: Use optimized document for runtime
{:ok, state_chart} = SC.Interpreter.initialize(optimized_document)
```
**Benefits:**
+
- Parsers focus purely on structure (supports future JSON/YAML parsers)
- Validation catches semantic errors before optimization
- Only valid documents get expensive optimization treatment
- Clear separation of concerns across phases
-### Test Infrastructure
+### Feature Detection and Test Infrastructure
+
+- **`SC.FeatureDetector`** - Detects SCXML features used in documents
+ - Enables proper test validation by failing tests that depend on unsupported features
+ - Prevents false positive test results from unsupported feature usage
+ - Supports both XML string and parsed document analysis
+ - Tracks feature support status (`:supported`, `:unsupported`, `:partial`)
- **`SC.Case`** - Test case template module for SCXML testing
- Provides `test_scxml/4` function for testing state machine behavior
- Uses SC.Interpreter for document initialization and event processing
@@ -139,6 +161,7 @@ The implementation follows a clean **Parse โ Validate โ Optimize** architect
- Used by both SCION and W3C test suites
### Location Tracking
+
All parsed SCXML elements include precise source location information for validation error reporting:
- **Element locations**: Each parsed element (`SC.Document`, `SC.State`, `SC.Transition`, `SC.DataElement`) includes a `source_location` field with line/column information
@@ -160,18 +183,21 @@ All parsed SCXML elements include precise source location information for valida
This project includes comprehensive test coverage:
### SCION Test Suite (`test/scion_tests/`)
+
- 127+ test files from the SCION project
- Module naming: `SCIONTest.Category.TestNameTest` (e.g., `SCIONTest.ActionSend.Send1Test`)
- Uses `SC.Case` for test infrastructure
- Tests cover basic state machines, transitions, parallel states, history, etc.
### W3C SCXML Test Suite (`test/scxml_tests/`)
+
- 59+ test files from W3C SCXML conformance tests
- Module naming: `Test.StateChart.W3.Category.TestName` (e.g., `Test.StateChart.W3.Events.Test396`)
- Uses `SC.Case` for test infrastructure
- Organized by SCXML specification sections (mandatory tests)
### Parser Tests (`test/sc/parser/scxml_test.exs`)
+
- Unit tests for `SC.Parser.SCXML`
- **Uses pattern matching** instead of multiple individual asserts for cleaner, more informative tests
- Tests parsing of simple documents, transitions, datamodels, nested states
@@ -179,6 +205,7 @@ This project includes comprehensive test coverage:
- Ensures proper attribute handling (nil for empty values)
### Location Tracking Tests (`test/sc/location_test.exs`)
+
- Tests for precise source location tracking in SCXML documents
- Validates line number accuracy for elements and attributes
- Tests both single-line and multiline XML element definitions
@@ -215,15 +242,19 @@ XML content within triple quotes uses 4-space base indentation.
**Current Status:** 107/225 tests passing (47.6% pass rate)
**Working Features:**
+
- โ
Basic state transitions (basic1, basic2 tests pass)
- โ
**Compound states** with automatic initial child entry
+- โ
**Initial state elements** (`` with transitions) - W3C compliant
- โ
Hierarchical states with O(1) optimized lookups
- โ
Event-driven state changes
-- โ
Initial state configuration
+- โ
Initial state configuration (both `initial="id"` attributes and `` elements)
- โ
Document validation and error reporting
- โ
**Parse โ Validate โ Optimize** architecture
+- โ
**Modular validator architecture** with focused sub-validators
**Main Failure Categories:**
+
- **Document parsing failures**: Complex SCXML with parallel states, history states, executable content
- **Validation too strict**: Rejecting valid but complex SCXML documents
- **Missing SCXML features**: Parallel states, conditional transitions, targetless transitions, internal transitions
@@ -233,6 +264,7 @@ XML content within triple quotes uses 4-space base indentation.
## Implementation Status
โ
**Completed:**
+
- Core data structures (Document, State, Transition, DataElement) with location tracking
- SCXML parser using Saxy SAX parser for accurate position tracking
- **Parse โ Validate โ Optimize architecture** with clean separation of concerns
@@ -251,8 +283,12 @@ XML content within triple quotes uses 4-space base indentation.
- Active state tracking with hierarchical ancestor computation using O(1) lookups
- **Git pre-push hook** for automated local validation workflow
- 95%+ test coverage maintained
+- **Initial state elements** (`` with ``) with comprehensive validation
+- **Modular validator architecture** - refactored from 386-line monolith into focused modules
+- **Full Credo compliance** - all 43 alias-related issues resolved
๐ง **Future Extensions:**
+
- Parallel states (``) - major gap in current implementation
- History states (``) - missing from parser and interpreter
- Conditional transitions with `cond` attribute evaluation
@@ -266,4 +302,4 @@ XML content within triple quotes uses 4-space base indentation.
The implementation follows the W3C SCXML specification closely and includes comprehensive test coverage from both W3C and SCION test suites. The current interpreter provides a solid foundation for basic SCXML functionality with clear areas identified for future enhancement.
- Always refer to state machines as state charts
-- Always run 'mix format' after writing an Elixir file.
\ No newline at end of file
+- Always run 'mix format' after writing an Elixir file.
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..6538f2c
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2025 John Thornton
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/README.md b/README.md
index 96c6218..aba534f 100644
--- a/README.md
+++ b/README.md
@@ -9,15 +9,18 @@ An Elixir implementation of SCXML (State Chart XML) state charts with a focus on
- โ
**Complete SCXML Parser** - Converts XML documents to structured data with precise location tracking
- โ
**State Chart Interpreter** - Runtime engine for executing SCXML state charts
-- โ
**Comprehensive Validation** - Document validation with detailed error reporting
+- โ
**Modular Validation** - Document validation with focused sub-validators for maintainability
- โ
**Compound States** - Support for hierarchical states with automatic initial child entry
+- โ
**Initial State Elements** - Full support for `` elements with transitions (W3C compliant)
- โ
**Parallel States** - Support for concurrent state regions with simultaneous execution
- โ
**O(1) Performance** - Optimized state and transition lookups via Maps
- โ
**Event Processing** - Internal and external event queues per SCXML specification
- โ
**Parse โ Validate โ Optimize Architecture** - Clean separation of concerns
+- โ
**Feature Detection** - Automatic SCXML feature detection for test validation
- โ
**Regression Testing** - Automated tracking of passing tests to prevent regressions
- โ
**Git Hooks** - Pre-push validation workflow to catch issues early
- โ
**Test Infrastructure** - Compatible with SCION and W3C test suites
+- โ
**Code Quality** - Full Credo compliance with proper module aliasing
## Current Status
@@ -26,54 +29,75 @@ An Elixir implementation of SCXML (State Chart XML) state charts with a focus on
**Regression Suite:** 22 tests (all critical functionality)
### Working Features
+
- โ
**Basic state transitions** and event-driven changes
- โ
**Hierarchical states** with optimized O(1) state lookup and automatic initial child entry
+- โ
**Initial state elements** - Full `` element support with transitions and comprehensive validation
- โ
**Parallel states** with concurrent execution of multiple regions
-- โ
**Document validation** and error reporting with comprehensive structural checks
+- โ
**Modular validation** - Refactored from 386-line monolith into focused sub-validators
+- โ
**Feature detection** - Automatic SCXML feature detection prevents false positive test results
- โ
**SAX-based XML parsing** with accurate location tracking for error reporting
- โ
**Performance optimizations** - O(1) state/transition lookups, optimized active configuration
- โ
**Source field optimization** - Transitions include source state for faster event processing
+- โ
**Code quality** - Full Credo compliance with proper module aliasing throughout codebase
### Planned Features
-- History states (``)
+
+- History states (``)
- Conditional transitions with expression evaluation (`cond` attribute)
- Internal and targetless transitions
- Executable content (`