use crate::span::Span;
use crate::syntax::ast::{Child, Link, Node, TextNode};
use std::collections::HashSet;
pub fn declared_ids(children: &[Child]) -> HashSet<String> {
children
.iter()
.filter_map(|c| match c {
Child::Box(n) => n.id.clone(),
Child::Text(_) => None,
})
.collect()
}
pub fn auto_created_ids(links: &[&Link], declared: &HashSet<String>) -> Vec<(String, Span)> {
let mut seen = HashSet::new();
let mut out = Vec::new();
for w in links {
for group in &w.chain {
for ep in &group.endpoints {
if ep.path.len() != 1 {
continue; }
let id = &ep.path[0];
if declared.contains(id) || !seen.insert(id.clone()) {
continue;
}
out.push((id.clone(), ep.span));
}
}
}
out
}
pub fn auto_box(id: &str, span: Span) -> Node {
Node {
id: Some(id.to_string()),
ty: Some("box".to_string()),
label: Some(TextNode {
text: id.to_string(),
style: Vec::new(),
style_span: None,
span,
}),
classes: Vec::new(),
style: Vec::new(),
style_span: None,
children: Vec::new(),
links: Vec::new(),
span,
}
}
#[cfg(test)]
mod tests {
use super::*;
fn parse(src: &str) -> crate::syntax::ast::File {
crate::syntax::parser::parse(&crate::lexer::lex(src).expect("lex")).expect("parse")
}
fn auto_ids(src: &str) -> Vec<String> {
let f = parse(src);
let declared = declared_ids(&f.instances);
let links: Vec<&Link> = f.links.iter().collect();
auto_created_ids(&links, &declared)
.into_iter()
.map(|(s, _)| s)
.collect()
}
#[test]
fn undeclared_root_link_ids_are_auto_created() {
assert_eq!(auto_ids("cat -> dog\n"), vec!["cat", "dog"]);
}
#[test]
fn a_declared_id_is_not_auto_created() {
assert_eq!(auto_ids("|box#cat|\ncat -> dog\n"), vec!["dog"]);
}
#[test]
fn a_multi_segment_path_never_creates() {
assert_eq!(auto_ids("|group#g| [ |box#x| ]\ng.x -> y\n"), vec!["y"]);
}
}