use super::parser::{CynefinAst, DomainBlockAst, TransitionAst};
use crate::js::chars::{drop_indents, trim_start};
use crate::js::map::Ordered;
#[derive(Clone, Debug, Default, PartialEq)]
pub(crate) struct CynefinDomain {
pub(crate) name: String,
pub(crate) items: Vec<String>,
}
#[derive(Clone, Debug, Default, PartialEq)]
pub(crate) struct CynefinTransition {
pub(crate) from: String,
pub(crate) to: String,
pub(crate) label: Option<String>,
}
#[derive(Clone, Debug, Default)]
pub(crate) struct CynefinModel {
pub(crate) title: Option<String>,
pub(crate) acc_title: Option<String>,
pub(crate) acc_descr: Option<String>,
pub(crate) domains: Ordered<CynefinDomain>,
pub(crate) transitions: Vec<CynefinTransition>,
}
#[derive(Default)]
struct CynefinDb {
domains: Ordered<CynefinDomain>,
transitions: Vec<CynefinTransition>,
}
impl CynefinDb {
fn set_domains(&mut self, blocks: Vec<DomainBlockAst>) {
for block in blocks {
let domain = CynefinDomain {
name: block.domain.clone(),
items: block.items,
};
self.domains.set(&block.domain, domain);
}
}
fn set_transitions(&mut self, transitions: Vec<TransitionAst>) {
self.transitions = transitions
.into_iter()
.filter(|t| t.from != t.to)
.map(|t| CynefinTransition {
from: t.from,
to: t.to,
label: t.label.filter(|l| !l.is_empty()),
})
.collect();
}
}
pub(crate) fn build_cynefin(ast: CynefinAst, title: Option<&str>) -> CynefinModel {
let mut db = CynefinDb::default();
db.set_domains(ast.domains);
db.set_transitions(ast.transitions);
let given = |s: Option<String>| s.filter(|s| !s.is_empty());
CynefinModel {
title: given(ast.title).or_else(|| title.map(str::to_string)),
acc_title: given(ast.acc_title).map(|s| trim_start(&s).to_string()),
acc_descr: given(ast.acc_descr).map(|s| drop_indents(&s)),
domains: db.domains,
transitions: db.transitions,
}
}