From 56bf6599921b6655cbe8924b2c3b1b0d386e9e4f Mon Sep 17 00:00:00 2001 From: tupe12334 Date: Mon, 12 Oct 2026 03:06:34 +0300 Subject: [PATCH 1/2] fix(flow): ignore transition labels in flow.mmd A labeled transition such as `a --> b : text` is valid Mermaid stateDiagram-v2 syntax, but parse_mmd stored `b : text` as the target state. The flow then failed with a false "no path to [*]" error. Strip the label from the transition target. Fixes #232 Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 3 +++ core/src/flow.rs | 5 ++++- core/src/flow_tests.rs | 19 +++++++++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 96844fb..1e78645 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Fixed +- A `flow.mmd` with a transition label (`a --> b : text`) failed with `state 'a' has no path to [*]`. steplock read `b : text` as the target state. It now ignores the label (#232) + ## [0.2.2] - 2026-10-04 ### Fixed diff --git a/core/src/flow.rs b/core/src/flow.rs index fef04bf..0d786d8 100644 --- a/core/src/flow.rs +++ b/core/src/flow.rs @@ -128,7 +128,10 @@ pub fn parse_mmd(path: &str, content: &str) -> Result { } fn split_transition(line: &str) -> Option<(&str, &str)> { - line.split_once("-->") + let (lhs, rhs) = line.split_once("-->")?; + // Drop a transition label (`a --> b : text`) so the target is just `b`. + let rhs = rhs.split_once(':').map_or(rhs, |(target, _)| target); + Some((lhs, rhs)) } fn split_label(line: &str) -> Option<(&str, &str)> { diff --git a/core/src/flow_tests.rs b/core/src/flow_tests.rs index ce02b93..56797af 100644 --- a/core/src/flow_tests.rs +++ b/core/src/flow_tests.rs @@ -52,6 +52,25 @@ stateDiagram-v2 assert!(g.is_terminal("skip_reason")); } +#[test] +fn ignores_transition_labels() { + let mmd = r" +stateDiagram-v2 + [*] --> tests + tests --> docs : yes + tests --> fix : no + fix --> docs + docs --> [*] : done + tests : Did all tests pass? +"; + let g = parse_mmd("test.mmd", mmd).unwrap(); + let mut nexts = g.next_states("tests"); + nexts.sort(); + assert_eq!(nexts, vec!["docs", "fix"]); + assert!(g.is_terminal("docs")); + assert_eq!(g.labels["tests"], "Did all tests pass?"); +} + #[test] fn error_on_missing_initial_state() { let mmd = "stateDiagram-v2\n a --> b\n"; From 89f34851f50993c99f45afc6dcd51072fbd46f92 Mon Sep 17 00:00:00 2001 From: tupe12334 Date: Mon, 12 Oct 2026 03:09:28 +0300 Subject: [PATCH 2/2] chore(lint): deny clippy::explicit_into_iter_loop Pre-push checklist ratchet. No existing violations. Co-Authored-By: Claude Opus 5.5 --- core/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/core/Cargo.toml b/core/Cargo.toml index 8111cd8..b7199e2 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -89,6 +89,7 @@ manual_let_else = "deny" items_after_statements = "deny" needless_pass_by_value = "deny" trivially_copy_pass_by_ref = "deny" +explicit_into_iter_loop = "deny" [dependencies] cel-interpreter = "0.10"