feat: add match visualization DSL to docs#38
Conversation
There was a problem hiding this comment.
Pull request overview
Adds match expr => Arm -> target as a first-class diagram DSL construct across the mdBook Rhai→Mermaid preprocessor and the live docs editor, expanding docs/CI to validate the new visualization behaviors.
Changes:
- Extend the Rust parser/emitter to support
matchnodes with labeled outgoing arms (plus tests). - Upgrade the live docs editor to support match-arm parsing and add an isometric SVG renderer with a view-mode toggle (plus JS unit tests).
- Expand documentation with a new “Match Visualization Plan” chapter and tighten
docgen-check/CI to run the real docs validation gate.
Reviewed changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| crates/mdbook-rhai-mermaid/src/parser.rs | Adds NodeKind::Match, parses match-arm statements, and groups them into a single match node. |
| crates/mdbook-rhai-mermaid/src/emitter.rs | Renders match nodes as diamonds and escapes edge labels; adds match-focused tests. |
| crates/mdbook-rhai-mermaid/src/main.rs | Adds an injection test ensuring match blocks produce Mermaid output. |
| book/theme/rhai-live.js | Adds view-mode toggle (Mermaid vs isometric), persistence, improved error rendering, and updated UI copy. |
| book/theme/rhai-live.css | Styles the new toolbar/switcher and adds isometric-scene styling. |
| book/theme/rhai-live-core.js | Adds match parsing, Mermaid label escaping, deterministic isometric layout + SVG renderer, and richer diagnostics helpers. |
| book/theme/rhai-live-core.test.js | Adds tests for match parsing/Mermaid output, deterministic layout, SVG rendering/animation, and failure guidance. |
| book/src/visualize.md | Documents the match DSL, new dual-view editor, and adds a sample gallery including a match example. |
| book/src/theory.md | Adds a cross-link to the match visualization plan from match-heavy examples. |
| book/src/match-visualization-plan.md | New chapter describing intended match rendering semantics and acceptance criteria. |
| book/src/SUMMARY.md | Adds the new chapter to the mdBook navigation (and adjusts Ledger Ops placement). |
| README.md | Notes the dual-view live editor modes and their intent. |
| Justfile | Strengthens docgen-check (new link/content assertions + JS syntax checks). |
| .github/workflows/ci.yml | Updates CI to run just docgen-check (and installs required tooling). |
| AGENTS.md | Updates contributor guidance to include match DSL and the new live editor rendering contract. |
Comments suppressed due to low confidence (1)
crates/mdbook-rhai-mermaid/src/parser.rs:95
- The docstring for
parsesays it “ReturnsNoneonly if the source contains no parseable statements”, butparsereturnsGraph(neverOption). This is misleading for callers/readers; please update the comment to reflect the current return type/behavior (e.g., “returns an empty Graph when no statements are found”).
/// Parse the rhai pseudo-DSL source into a `Graph`.
///
/// Returns `None` only if the source contains no parseable statements at all
/// (empty/comment-only). Malformed lines are silently skipped so a partial
/// parse always succeeds.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const stored = window.localStorage ? window.localStorage.getItem(STORAGE_KEY) : null; | ||
| return stored === "mermaid-2d" ? "mermaid-2d" : "isometric-3d"; | ||
| } | ||
|
|
||
| function persistViewMode(mode) { | ||
| if (window.localStorage) { | ||
| window.localStorage.setItem(STORAGE_KEY, mode); |
There was a problem hiding this comment.
selectedViewMode() / persistViewMode() assume window.localStorage is always readable/writable when present, but in some browsers/privacy modes localStorage.getItem/setItem can throw (e.g. SecurityError) and would break the live editor initialization. Wrap the storage access in try/catch and fall back to the default mode when storage is unavailable.
| const stored = window.localStorage ? window.localStorage.getItem(STORAGE_KEY) : null; | |
| return stored === "mermaid-2d" ? "mermaid-2d" : "isometric-3d"; | |
| } | |
| function persistViewMode(mode) { | |
| if (window.localStorage) { | |
| window.localStorage.setItem(STORAGE_KEY, mode); | |
| try { | |
| const stored = window.localStorage ? window.localStorage.getItem(STORAGE_KEY) : null; | |
| return stored === "mermaid-2d" ? "mermaid-2d" : "isometric-3d"; | |
| } catch (error) { | |
| return "isometric-3d"; | |
| } | |
| } | |
| function persistViewMode(mode) { | |
| try { | |
| if (window.localStorage) { | |
| window.localStorage.setItem(STORAGE_KEY, mode); | |
| } | |
| } catch (error) { |
| ```rhai | ||
| fn verify_result() -> match_disposition | ||
| match result.disposition => Disposition::Unrecoverable -> halt_pipeline | ||
| match result.disposition => Disposition::Recoverable -> repair_and_retry | ||
| match result.disposition => Disposition::Advisory -> record_note | ||
| fn repair_and_retry() -> requeue_validation | ||
| ``` |
There was a problem hiding this comment.
The “Match-Style Disposition Routing” sample includes fn verify_result() -> match_disposition, but the match-arm DSL here (match result.disposition => …) generates a separate match node id derived from the expression (match_result_disposition). As a result the rendered graph will contain an unconnected match_disposition step plus a disconnected match result.disposition diamond. Update the sample (or the DSL/ID scheme) so the match node can be reached from the pipeline edge and the example renders as a single connected flow.
1. localStorage try/catch (rhai-live.js): wrap getItem/setItem in try/catch so SecurityError in Firefox private mode or iOS Safari privacy settings does not break live editor initialization. 2. Disconnected match node (visualize.md, match-visualization-plan.md): the parser generates the match node ID as `match_` + sanitize_id(expr), so `match result.disposition` → `match_result_disposition`. Samples that used `fn verify_result() -> match_disposition` produced an unreachable orphan node. Updated all samples and the documentation guidance to use the full sanitized form. 3. Misleading docstring (parser.rs): `parse()` returns Graph (never Option). Updated the doc comment to say "returns an empty Graph" rather than "Returns None". Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
promptexecutionerr
left a comment
There was a problem hiding this comment.
Addressed all three review comments in commit 0cf7c7f:
-
localStorage SecurityError (rhai-live.js): wrapped both getItem and setItem in try/catch with isometric-3d as the safe fallback. Matches the suggested fix exactly.
-
Disconnected match node (visualize.md, match-visualization-plan.md): the parser generates match node IDs as
match_+ sanitize_id(expr), somatch result.disposition→match_result_disposition. Updated both samples and the documentation guidance. Also updated the 'stable example names' section in the plan doc to explain the derivation rule so authors don't make the same mistake. -
Misleading docstring (parser.rs, suppressed comment): fixed
ReturnsNone→ `Returns an empty `Graphto match the actual return type.
What changed
match expr => Arm -> targetsupport to the mdBook Rhai->Mermaid preprocessorjust docgen-checkgate runs in GitHub ActionsValidation
cargo test -p mdbook-rhai-mermaidnode --test book/theme/rhai-live-core.test.jsjust docgen-check