Types
At the top of the type hierachy we have AbstractEdges and AbstractNodes. These are pretty abstract in the sense that they capture anything that might somehow be interpreted as an edge or node. More concrete (but still not concrete concrete) are Edge and Node.
StenoGraphs.AbstractNode — TypeAbstractNodeAt the top of the type hierarchy of StenoGraphs. Anything that might resemble a node.
StenoGraphs.AbstractEdge — TypeAbstractEdgeAt the top of the type hierarchy of StenoGraphs. Anything that might resemble an edge.
Edge/Node
Edge and Node are still not concrete but have fields of reliable types to interface with.
StenoGraphs implements DirectedEdge and UndirectedEdge  as concrete subtypes of Edge as well as SimpleNode as concrete subtype of Node.
StenoGraphs.Node — TypeNodeSubtype of AbstractNode. Any subtype of Node must have the field node (and no other) that uniquily identifies the node.
StenoGraphs.Edge — TypeEdgeSubtype of AbstractEdge. Any subtype of Edge must have the fields src and dst (and no other), which must be a subtype of AbstractNode. Any implementation might be stricter about typing.
SimpleNode/UndirectedEdge/DirectedEdge
These are the concrete Node and Edge types implemented by StenoGraphs.
StenoGraphs.SimpleNode — TypeStenoGraphs.DirectedEdge — TypeDirectedEdge(src, dst)Subtype of Edge. Directed edge from src to dst.
Example
julia> DirectedEdge(Node(:a), Node(:b))
a → bStenoGraphs.UndirectedEdge — TypeUndirectedEdge(src, dst)Subtype of Edge. Undirected edge from src to dst. What is what does not matter.
Example
julia> e1 = UndirectedEdge(Node(:a), Node(:b))
a ↔ b
julia> e2 = UndirectedEdge(Node(:b), Node(:a))
b ↔ a
julia> isequal(e1, e2)
true
julia> unique([e1, e2])
a ↔ bMetaEdge/MetaNode
These types store a node/edge alongside metadata.
StenoGraphs.MetaNode — TypeMetaNodeSubtype of AbstractNode. Any subtype of MetaNode must have a field node of subtype Node, but may have any number of other fields containing metadata.
StenoGraphs.MetaEdge — TypeMetaEdgeSubtype of AbstractEdge. Any subtype of MetaEdge must have a field edge of subtype Edge, but may have any number of other fields containing metadata.
Modified Nodes and Edges
These concrete types store a node/edge alongside modifiers (either NodeModifiers or EdgeModifiers) as metadata.
StenoGraphs.ModifiedNode — TypeModifiedNodeSubtype of MetaNode that contains two fields (node and modifiers). modifiers is a Dict{Symbol, NodeModifier} where the keys are nameof(typeof(NodeModifier)). Modifiying a node with several modifiers of the same type will therefore overwrite old modifiers.
Example
julia> struct Observed <: NodeModifier end
julia> struct Label{N <: String} <: NodeModifier s::N end
julia> Node(:b) ^ Label("some label") ^ Observed()
b^[Observed(), Label{String}("some label")]
julia> Node(:b) ^ Label("some label") ^ Observed() ^ Label("some other label")
b^[Observed(), Label{String}("some other label")]StenoGraphs.ModifyingNode — TypeModifyingNodeSubtype of MetaNode that contains two fields (node and modifiers). modifiers is a Dict{Symbol, EdgeModifier} where the keys are nameof(typeof(EdgeModifier)). Modifiying an node with several modifiers of the same type will therefore overwrite old modifiers. A ModifyingNode is created by multiplying it (*) with an EdgeModifier since it will modify edges build upon it. If you want to modify the node use ^ and see ModifiedNode.
Example
julia> struct Weight{N <: Number} <: EdgeModifier w::N end
julia> struct Start{N <: Number} <: EdgeModifier s::N end
julia> @StenoGraph a → b * Weight(3) * Start(2)
a → b * [Start{Int64}(2), Weight{Int64}(3)]
julia> @StenoGraph a → b * Weight(3) * Start(2) * Weight(2)
a → b * [Start{Int64}(2), Weight{Int64}(2)]StenoGraphs.ModifiedEdge — TypeModifiedEdgeSubtype of MetaEdge that contains two fields (edge and modifiers). modifiers is a Dict{Symbol, EdgeModifier} where the keys are nameof(typeof(EdgeModifier)). Modifiying an edge with several modifiers of the same type will therefore overwrite old modifiers. A ModifiedEdge is created by modifying an edge directly (with *) or via ModifyingNodes where a node is modified that than modifies the edge.
Example
julia> struct Weight{N <: Number} <: EdgeModifier w::N end
julia> struct Start{N <: Number} <: EdgeModifier s::N end
julia> ModifiedEdge(Edge(Node(:a), Node(:b)), Weight(3))
a → b * Weight{Int64}(3)
julia> ModifiedEdge(Edge(Node(:a), Node(:b)), Weight(3)) == Edge(Node(:a), Node(:b)) * Weight(3)
true
julia> ModifiedEdge(Edge(Node(:a), Node(:b)), [Weight(3), Start(2)])
a → b * [Start{Int64}(2), Weight{Int64}(3)]
julia> @StenoGraph a → b * Weight(3) * Start(2)
a → b * [Start{Int64}(2), Weight{Int64}(3)]
julia> @StenoGraph a → b * Weight(3) * Start(2) * Weight(2)
a → b * [Start{Int64}(2), Weight{Int64}(2)]Modifiers
StenoGraphs.Modifier — TypeModifierThe abstract type that powers EdgeModifier and NodeModifier. StenoGraphs does not implement any concrete modifiers.
StenoGraphs.NodeModifier — TypeNodeModifierSubtype of Modifier. ModifiedNodes require NodeModifiers. NodeModifiers usually make use of ^ for creating ModifiedNodes. Since StenoGraphs does not implement any NodeModifier users must implement them. If these may contain any mutable fields (i.e. strings, vectors, arrays, etc.) users must take care to implement comparison methods.
Example
# `StenoGraphs` does not implement any `NodeModifier`s
julia> struct Label <: NodeModifier l end
julia> import Base.==
julia> ==(x::Label, y::Label) = x.l == y.l;
julia> ModifiedNode(Node(:a), Label("hi")) == Node(:a)^Label("hi")
true
StenoGraphs.EdgeModifier — TypeEdgeModifierSubtype of Modifier. ModifiedEdges require EdgeModifiers. EdgeModifiers usually make use of * for creating ModifiedEdges/ModifyingNodes. One special application for EdgeModifiers is the creation of ModifyingNodes. Since StenoGraphs does not implement any EdgeModifier users must implement them. If these are not atomic they must take care to implement comparison methods (see examples in NodeModifier)
Example
# `StenoGraphs` does not implement any `EdgeModifier`s
julia> struct Weight{N <: Number} <: EdgeModifier w::N end
julia> ModifiedEdge(Edge(Node(:a), Node(:b)), Weight(.5)) == # directly create ModifiedEdge
        Edge(Node(:a), Node(:b)) * Weight(.5) == # modify an edge
        Edge(Node(:a), Node(:b) * Weight(.5)) # modify Edge through a ModifyingNode
true