pub struct Diagram {
pub schema: String,
pub id: String,
pub title: String,
pub kind: Kind,
pub orientation: Orientation,
pub provenance: Provenance,
pub nodes: Vec<Node>,
pub edges: Vec<Edge>,
pub groups: Vec<Group>,
}Expand description
A diagram, canonically. Every renderer is a function of this; nothing is a function of a renderer’s output.
The whole point is that the structure survives without the syntax: a caller can ask this value a question — is every outcome the tool accepts drawn? — which a Mermaid string could only be asked by re-parsing a picture.
use majordomus_cli::diagram::{lifecycle, outcomes, Diagram};
let shell = " case \"$outcome\" in completed|partial|failed) ;;";
let drawn: Diagram = lifecycle(shell).expect("the vocabulary is readable");
// the question, asked of the model rather than of the picture
for outcome in outcomes(shell).expect("a vocabulary") {
assert!(drawn.nodes.iter().any(|n| n.id == outcome), "{outcome} is not drawn");
assert!(drawn.edges.iter().any(|e| e.to == outcome), "nothing reaches {outcome}");
}
assert!(drawn.to_mermaid().starts_with("stateDiagram-v2"), "Mermaid is one reader of it");Fields§
§schema: String§id: StringStable identity: the key the site and every other surface holds this diagram under.
title: StringThe heading a reader sees above the drawing.
kind: KindWhat it draws, and therefore which dialect renders it.
orientation: OrientationWhich way a flowchart runs; ignored for Kind::State.
provenance: ProvenanceWhat the structure was derived from.
nodes: Vec<Node>The nodes, in the order the derivation built them, which is the order they are drawn.
edges: Vec<Edge>The edges, in derivation order.
groups: Vec<Group>The boxes drawn around groups of nodes; empty for most diagrams.
Implementations§
Source§impl Diagram
impl Diagram
Sourcepub fn new(
id: impl Into<String>,
title: impl Into<String>,
kind: Kind,
provenance: Provenance,
) -> Diagram
pub fn new( id: impl Into<String>, title: impl Into<String>, kind: Kind, provenance: Provenance, ) -> Diagram
An empty diagram of this kind, which a derivation then fills.
use majordomus_cli::diagram::{Diagram, Kind, Provenance, DIAGRAM_SCHEMA};
let drawn = Diagram::new("x", "X", Kind::Flow, Provenance::new("a", "b"));
assert_eq!(drawn.schema, DIAGRAM_SCHEMA);
assert!(drawn.nodes.is_empty());Sourcepub fn oriented(self, orientation: Orientation) -> Diagram
pub fn oriented(self, orientation: Orientation) -> Diagram
The same diagram laid out the other way.
use majordomus_cli::diagram::{Diagram, Kind, Orientation, Provenance};
let drawn = Diagram::new("x", "X", Kind::Flow, Provenance::new("a", "b"))
.oriented(Orientation::LeftRight);
assert_eq!(drawn.orientation, Orientation::LeftRight);Sourcepub fn with_node(self, node: Node) -> Diagram
pub fn with_node(self, node: Node) -> Diagram
The same diagram with one more node, appended in drawing order.
use majordomus_cli::diagram::{Diagram, Kind, Node, Provenance};
let drawn = Diagram::new("x", "X", Kind::Flow, Provenance::new("a", "b"))
.with_node(Node::new("a", "A"));
assert_eq!(drawn.nodes.len(), 1);Sourcepub fn with_edge(self, edge: Edge) -> Diagram
pub fn with_edge(self, edge: Edge) -> Diagram
The same diagram with one more edge, appended in drawing order.
use majordomus_cli::diagram::{Diagram, Edge, Kind, Node, Provenance};
let drawn = Diagram::new("x", "X", Kind::Flow, Provenance::new("a", "b"))
.with_node(Node::new("a", "A"))
.with_node(Node::new("b", "B"))
.with_edge(Edge::new("a", "b"));
assert_eq!(drawn.edges.len(), 1);Sourcepub fn with_group(self, group: Group) -> Diagram
pub fn with_group(self, group: Group) -> Diagram
The same diagram with one more group.
use majordomus_cli::diagram::{Diagram, Group, Kind, Node, Provenance};
let drawn = Diagram::new("x", "X", Kind::Flow, Provenance::new("a", "b"))
.with_node(Node::new("a", "A"))
.with_group(Group::new("g", "Group", ["a"]));
assert_eq!(drawn.groups.len(), 1);Sourcepub fn validate(&self) -> Vec<String>
pub fn validate(&self) -> Vec<String>
Everything wrong with the model, in the order it was found, as lines a report can print. Empty means the model renders to Mermaid a parser accepts.
A renderer must never be the thing that discovers a dangling edge, because by then the only way to say so is broken output:
use majordomus_cli::diagram::{Diagram, Edge, Kind, Node, Provenance};
let drawn = Diagram::new("x", "X", Kind::Flow, Provenance::new("a", "b"))
.with_node(Node::new("a", "A"))
.with_edge(Edge::new("a", "nowhere"));
let found = drawn.validate();
assert_eq!(found.len(), 1);
assert!(found[0].contains("nowhere"), "{found:?}");Sourcepub fn to_mermaid(&self) -> String
pub fn to_mermaid(&self) -> String
This diagram as Mermaid source — one renderer of the model, with no authority over it. No trailing newline: the result is a value a JSON field holds, not a file.
use majordomus_cli::diagram::{Diagram, Edge, Kind, Node, Orientation, Provenance};
let drawn = Diagram::new("x", "X", Kind::Flow, Provenance::new("a", "b"))
.oriented(Orientation::LeftRight)
.with_node(Node::new("a", "A"))
.with_node(Node::new("b", "B"))
.with_edge(Edge::new("a", "b").labelled("moves"));
assert_eq!(
drawn.to_mermaid(),
"flowchart LR\n a[\"A\"]\n b[\"B\"]\n a -->|moves| b",
);A diagram with no nodes still renders to something a parser accepts, rather than to a bare header that may or may not be a document:
use majordomus_cli::diagram::{Diagram, Kind, Provenance};
let empty = Diagram::new("x", "X", Kind::State, Provenance::new("a", "b"));
assert_eq!(empty.to_mermaid(), "stateDiagram-v2\n %% no nodes were derived");Trait Implementations§
Source§impl<'de> Deserialize<'de> for Diagram
impl<'de> Deserialize<'de> for Diagram
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
impl Eq for Diagram
Source§impl JsonSchema for Diagram
impl JsonSchema for Diagram
Source§fn schema_id() -> Cow<'static, str>
fn schema_id() -> Cow<'static, str>
Source§fn json_schema(generator: &mut SchemaGenerator) -> Schema
fn json_schema(generator: &mut SchemaGenerator) -> Schema
Source§fn inline_schema() -> bool
fn inline_schema() -> bool
$ref keyword. Read moreimpl StructuralPartialEq for Diagram
Auto Trait Implementations§
impl Freeze for Diagram
impl RefUnwindSafe for Diagram
impl Send for Diagram
impl Sync for Diagram
impl Unpin for Diagram
impl UnsafeUnpin for Diagram
impl UnwindSafe for Diagram
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.