///|
pub enum ReferenceKind {
ComponentToken
ComponentState
PaletteRole
ThemeAlias
} derive(Debug, Eq)
///|
pub struct ReferenceEdge {
source : String
target : String
kind : ReferenceKind
} derive(Debug, Eq)
///|
pub struct ReferenceGraph {
edges : Array[ReferenceEdge]
} derive(Debug, Eq)
///|
pub fn ReferenceGraph::empty() -> ReferenceGraph {
{ edges: [] }
}
///|
pub fn ReferenceGraph::add(
self : ReferenceGraph,
source : String,
target : String,
kind : ReferenceKind,
) -> ReferenceGraph {
let edges : Array[ReferenceEdge] = []
for edge in self.edges {
edges.push(edge)
}
edges.push(ReferenceEdge::{ source, target, kind })
{ edges, }
}
///|
pub fn ReferenceGraph::add_alias(
self : ReferenceGraph,
source : String,
target : String,
) -> ReferenceGraph {
self.add(source, target, ThemeAlias)
}
///|
pub fn ReferenceGraph::edge_count(self : ReferenceGraph) -> Int {
self.edges.length()
}
///|
pub fn ReferenceGraph::node_count(self : ReferenceGraph) -> Int {
let nodes : Array[String] = []
for edge in self.edges {
if !nodes.any(fn(item) { item == edge.source }) {
nodes.push(edge.source)
}
if !nodes.any(fn(item) { item == edge.target }) {
nodes.push(edge.target)
}
}
nodes.length()
}
///|
pub fn ReferenceGraph::targets_for(
self : ReferenceGraph,
source : String,
) -> Array[String] {
let result : Array[String] = []
for edge in self.edges {
if edge.source == source && !result.any(fn(item) { item == edge.target }) {
result.push(edge.target)
}
}
result
}
///|
pub fn ReferenceGraph::sources_for(
self : ReferenceGraph,
target : String,
) -> Array[String] {
let result : Array[String] = []
for edge in self.edges {
if edge.target == target && !result.any(fn(item) { item == edge.source }) {
result.push(edge.source)
}
}
result
}
///|
pub fn ReferenceGraph::edges_of(
self : ReferenceGraph,
kind : ReferenceKind,
) -> Array[ReferenceEdge] {
let result : Array[ReferenceEdge] = []
for edge in self.edges {
if edge.kind == kind {
result.push(edge)
}
}
result
}
///|
pub fn ReferenceGraph::missing_targets(
self : ReferenceGraph,
known : Array[String],
) -> Array[String] {
let missing : Array[String] = []
for edge in self.edges {
if !known.any(fn(item) { item == edge.target }) &&
!missing.any(fn(item) { item == edge.target }) {
missing.push(edge.target)
}
}
missing
}
///|
pub fn ReferenceGraph::to_markdown(self : ReferenceGraph) -> String {
let lines : Array[String] = [
"## Reference graph", "", "| Source | Target | Kind |", "| --- | --- | --- |",
]
for edge in self.edges {
lines.push(
"| " +
edge.source +
" | " +
edge.target +
" | " +
reference_kind_name(edge.kind) +
" |",
)
}
lines.join("\n")
}
///|
pub fn BrandBook::reference_graph(self : BrandBook) -> ReferenceGraph {
let graph = ReferenceGraph::empty()
let mut result = graph
for component in self.components {
for token in component.tokens {
result = result.add(component.name, token, ComponentToken)
}
for state in component.states {
result = result.add(component.name, state, ComponentState)
}
}
for color in self.palette.colors {
if color.role != "" {
result = result.add(color.role, color.name, PaletteRole)
}
}
result
}
///|
fn reference_kind_name(kind : ReferenceKind) -> String {
match kind {
ComponentToken => "component-token"
ComponentState => "component-state"
PaletteRole => "palette-role"
ThemeAlias => "theme-alias"
}
}
///|
pub fn BrandBook::missing_references(self : BrandBook) -> Array[String] {
let known : Array[String] = []
for color in self.palette.colors {
known.push(color.name)
}
for font in self.typography.families {
known.push(font.name)
}
for step in self.typography.scale {
known.push(step.name)
}
self.reference_graph().missing_targets(known)
}