Skip to content
This repository was archived by the owner on Sep 12, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### ⚠️ DEPRECATED

**This `sc` package has been renamed to `statifier`**

- **Migration Required**: All users must migrate to the new `statifier` package
- **Repository**: <https://github.com/riddler/statifier>
- **Hex Package**: `{:statifier, "~> 1.1"}`
- **Code Changes**: Replace all `SC.` references with `Statifier.`
- **Deprecation Warnings**: All public functions now emit deprecation warnings
- **No New Features**: All future development continues in the `statifier` package

### Added

#### Phase 1 Enhanced Expression Evaluation
Expand Down Expand Up @@ -209,7 +220,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
#### ActionExecutor API Modernization

- **REMOVED**: `SC.Actions.ActionExecutor.execute_onentry_actions/2` function clause that accepted `%Document{}` as second parameter
- **REMOVED**: `SC.Actions.ActionExecutor.execute_onexit_actions/2` function clause that accepted `%Document{}` as second parameter
- **REMOVED**: `SC.Actions.ActionExecutor.execute_onexit_actions/2` function clause that accepted `%Document{}` as second parameter
- **BREAKING**: These functions now only accept `%StateChart{}` as the second parameter for proper event queue integration
- **Migration**: Replace `ActionExecutor.execute_*_actions(states, document)` with `ActionExecutor.execute_*_actions(states, state_chart)`
- **Benefit**: Action execution now properly integrates with the StateChart event queue system, enabling raised events to be processed correctly
Expand Down
62 changes: 45 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,27 @@
# SC - StateCharts for Elixir
# ⚠️ DEPRECATED: SC - StateCharts for Elixir

> **This project has been renamed to [Statifier](https://github.com/riddler/statifier)**
> All active development continues at **<https://github.com/riddler/statifier>**
> Please migrate to `{:statifier, "~> 1.1"}` for ongoing updates and support.

[![CI](https://github.com/riddler/sc/workflows/CI/badge.svg?branch=main)](https://github.com/riddler/sc/actions)
[![Coverage](https://codecov.io/gh/riddler/sc/branch/main/graph/badge.svg)](https://codecov.io/gh/riddler/sc)

---

**⚠️ MIGRATION NOTICE**: This SC project has been renamed to **[Statifier](https://github.com/riddler/statifier)** for better discoverability and communication. All modules have been renamed from `SC.*` to `Statifier.*`.

**New Repository**: <https://github.com/riddler/statifier>
**New Hex Package**: `{:statifier, "~> 1.1"}`

---

An Elixir implementation of SCXML (State Chart XML) state charts with a focus on W3C compliance.

## Features

- ✅ **Complete SCXML Parser** - Converts XML documents to structured data with precise location tracking
- ✅ **State Chart Interpreter** - Runtime engine for executing SCXML state charts
- ✅ **State Chart Interpreter** - Runtime engine for executing SCXML state charts
- ✅ **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 `<initial>` elements with transitions (W3C compliant)
Expand All @@ -32,7 +45,7 @@ An Elixir implementation of SCXML (State Chart XML) state charts with a focus on
### Working Features

- ✅ **Basic state transitions** and event-driven changes
- ✅ **Hierarchical states** with optimized O(1) state lookup and automatic initial child entry
- ✅ **Hierarchical states** with optimized O(1) state lookup and automatic initial child entry
- ✅ **Initial state elements** - Full `<initial>` element support with transitions and comprehensive validation
- ✅ **Parallel states** with concurrent execution of multiple regions and proper cross-boundary exit semantics
- ✅ **Eventless transitions** - Automatic transitions without event attributes (also called NULL transitions in SCXML spec), with cycle detection and microstep processing
Expand Down Expand Up @@ -72,23 +85,23 @@ An Elixir implementation of SCXML (State Chart XML) state charts with a focus on
### **✅ Enhanced Parallel State Support**

- **`Cross-Parallel Boundaries`** - Proper exit semantics when transitions leave parallel regions
- **`Sibling State Management`** - Automatic exit of parallel siblings when transitions exit their shared parent
- **`Sibling State Management`** - Automatic exit of parallel siblings when transitions exit their shared parent
- **`Self-Transitions`** - Transitions within parallel regions preserve unaffected parallel regions
- **`SCION Compatibility`** - All 4 `cond_js` tests now pass, 6 parallel interrupt tests fixed
- **`Regression Prevention`** - 62 regression tests now validate all critical functionality

### **✅ Feature-Based Test Validation System**

- **`SC.FeatureDetector`** - Analyzes SCXML documents to detect used features
- **Feature validation** - Tests fail when they depend on unsupported features
- **Feature validation** - Tests fail when they depend on unsupported features
- **False positive prevention** - No more "passing" tests that silently ignore unsupported features
- **Capability tracking** - Clear visibility into which SCXML features are supported

### **✅ Modular Validator Architecture**

- **`SC.Validator`** - Main orchestrator (from 386-line monolith)
- **`SC.Validator.StateValidator`** - State ID validation
- **`SC.Validator.TransitionValidator`** - Transition target validation
- **`SC.Validator.TransitionValidator`** - Transition target validation
- **`SC.Validator.InitialStateValidator`** - All initial state constraints
- **`SC.Validator.ReachabilityAnalyzer`** - State reachability analysis
- **`SC.Validator.Utils`** - Shared utilities
Expand All @@ -110,25 +123,40 @@ The next major areas for development focus on expanding SCXML feature support:
- **Datamodel Support** - `<data>` elements with expression evaluation
- **History States** - Shallow and deep history state support

### **Medium Priority Features**
### **Medium Priority Features**

- **Internal Transitions** - `type="internal"` transition support
- **Targetless Transitions** - Transitions without target for pure actions
- **Enhanced Error Handling** - Better error messages with source locations
- **Performance Benchmarking** - Establish performance baselines and optimize hot paths

## Installation
## ⚠️ Deprecated Installation (Use Statifier Instead)

Add `sc` to your list of dependencies in `mix.exs`:
**⚠️ DO NOT USE**: This package is deprecated. Use the new `statifier` package instead:

```elixir
def deps do
[
{:sc, "~> 1.0.0"}
{:statifier, "~> 1.1"} # ✅ USE THIS
# {:sc, "~> 1.0.0"} # ❌ DEPRECATED
]
end
```

**Migration Guide**: Simply replace `SC.` with `Statifier.` in your code:

```elixir
# Old (deprecated)
{:ok, document} = SC.parse(xml)
{:ok, state_chart} = SC.interpret(document)
active_states = SC.Interpreter.active_states(state_chart)

# New (current)
{:ok, document} = Statifier.parse(xml)
{:ok, state_chart} = Statifier.interpret(document)
active_states = Statifier.Interpreter.active_states(state_chart)
```

## Usage

### Basic Example
Expand Down Expand Up @@ -227,7 +255,7 @@ active_states = SC.Interpreter.active_states(state_chart)
{:ok, document} = SC.parse(xml)

case SC..validate(document) do
{:ok, optimized_document, warnings} ->
{:ok, optimized_document, warnings} ->
# Document is valid and optimized, warnings are non-fatal
IO.puts("Valid document with #{length(warnings)} warnings")
# optimized_document now has O(1) lookup maps built
Expand All @@ -253,7 +281,7 @@ xml = """
</onentry>
<transition target="working"/>
</state>

<state id="working">
<onentry>
<assign location="counter" expr="counter + 1"/>
Expand All @@ -264,7 +292,7 @@ xml = """
</onexit>
<transition event="finish" target="done"/>
</state>

<final id="done"/>
</scxml>
"""
Expand Down Expand Up @@ -375,7 +403,7 @@ mix test test/sc/parser/scxml_test.exs
# 1. Parse: XML → Document structure
{:ok, document} = SC.parse(xml)

# 2. Validate: Check semantics + optimize with lookup maps
# 2. Validate: Check semantics + optimize with lookup maps
{:ok, optimized_document, warnings} = SC..validate(document)

# 3. Interpret: Run state chart with optimized lookups
Expand All @@ -389,7 +417,7 @@ The implementation includes several key optimizations for production use:
### **O(1) State and Transition Lookups**

- **State Lookup Map**: `%{state_id => state}` for instant state access
- **Transition Lookup Map**: `%{state_id => [transitions]}` for fast transition queries
- **Transition Lookup Map**: `%{state_id => [transitions]}` for fast transition queries
- **Built During Validation**: Lookup maps only created for valid documents
- **Memory Efficient**: Uses existing document structure, no duplication

Expand All @@ -402,7 +430,7 @@ active_states = SC.Interpreter.active_states(state_chart)
# Returns only leaf states (compound/parallel states entered automatically)

# Fast ancestor computation when needed
ancestors = SC.Interpreter.active_ancestors(state_chart)
ancestors = SC.Interpreter.active_ancestors(state_chart)
# O(1) state lookups + O(d) ancestor traversal

# Parallel states enter ALL child regions simultaneously
Expand All @@ -418,7 +446,7 @@ ancestors = SC.Interpreter.active_ancestors(state_chart)
**Performance Impact:**

- O(1) vs O(n) state lookups during interpretation
- O(1) vs O(n) transition queries for event processing
- O(1) vs O(n) transition queries for event processing
- Source field optimization eliminates expensive lookups during event processing
- Critical for responsive event processing in complex state charts

Expand Down
38 changes: 37 additions & 1 deletion lib/sc.ex
Original file line number Diff line number Diff line change
@@ -1,11 +1,47 @@
defmodule SC do
@moduledoc """
Documentation for `SC`.
⚠️ **DEPRECATED**: This package has been renamed to **Statifier**.

## Migration

This `sc` package is deprecated. Please migrate to the new `statifier` package:

```elixir
# In mix.exs
def deps do
[
{:statifier, "~> 1.1"} # ✅ Use this instead
# {:sc, "~> 1.0"} # ❌ Deprecated
]
end
```

## Code Migration

Simply replace `SC.` with `Statifier.` throughout your codebase:

```elixir
# Old (deprecated)
{:ok, document} = SC.parse(xml)
{:ok, state_chart} = SC.interpret(document)

# New (current)
{:ok, document} = Statifier.parse(xml)
{:ok, state_chart} = Statifier.interpret(document)
```

**New Repository**: https://github.com/riddler/statifier
**Documentation**: https://hexdocs.pm/statifier
"""

alias SC.{Interpreter, Parser.SCXML, Validator}

@deprecated "Use Statifier.parse/1 instead. Add {:statifier, \"~> 1.1\"} to deps and replace SC with Statifier."
defdelegate parse(source_string), to: SCXML

@deprecated "Use Statifier.validate/1 instead. Add {:statifier, \"~> 1.1\"} to deps and replace SC with Statifier."
defdelegate validate(document), to: Validator

@deprecated "Use Statifier.interpret/1 instead. Add {:statifier, \"~> 1.1\"} to deps and replace SC with Statifier."
defdelegate interpret(document), to: Interpreter, as: :initialize
end
8 changes: 6 additions & 2 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ defmodule SC.MixProject do
use Mix.Project

@app :sc
@version "1.0.0"
@description "StateCharts for Elixir"
@version "1.0.1"
@description "[DEPRECATED] Use 'statifier' package instead: https://github.com/riddler/statifier"
@source_url "https://github.com/riddler/sc"
@deps [
# Documentation (split out to reduce compile time in dev/test)
Expand Down Expand Up @@ -32,6 +32,10 @@ defmodule SC.MixProject do
docs: docs(),
description: @description,
package: package(),
deprecated: [
reason: "Package renamed to 'statifier'. Use {:statifier, \"~> 1.1\"} instead.",
replacement: :statifier
],
test_coverage: [tool: ExCoveralls],
preferred_cli_env: [
coveralls: :test,
Expand Down