mod array;
mod boolean;
mod combo;
mod container;
mod directives;
mod dom;
mod enum_axis;
mod tree_diff;
mod variant;
use std::collections::HashSet;
use crate::Axis;
use array::{process_array, process_array_with_children};
use boolean::process_boolean;
use combo::classify_axes;
use dom::{DomNode, parse_html, serialize};
use enum_axis::process_enum;
fn is_directive_comment(node: &DomNode) -> bool {
match node {
DomNode::Comment(c) => {
c.starts_with("seam:if:")
|| c.starts_with("seam:endif:")
|| c == "seam:else"
|| c.starts_with("seam:each:")
|| c == "seam:endeach"
|| c.starts_with("seam:match:")
|| c.starts_with("seam:when:")
|| c == "seam:endmatch"
}
_ => false,
}
}
fn content_indices(tree: &[DomNode]) -> Vec<usize> {
tree.iter().enumerate().filter(|(_, n)| !is_directive_comment(n)).map(|(i, _)| i).collect()
}
fn nth_content_index(tree: &[DomNode], n: usize) -> Option<usize> {
tree.iter().enumerate().filter(|(_, n)| !is_directive_comment(n)).nth(n).map(|(i, _)| i)
}
fn rename_slot_markers(nodes: &mut [DomNode], prefix: &str) {
let old = format!("seam:{prefix}.");
for node in nodes.iter_mut() {
match node {
DomNode::Comment(c) if c.starts_with(&old) => {
*c = format!("seam:{}", &c[old.len()..]);
}
DomNode::Element { children, .. } => rename_slot_markers(children, prefix),
_ => {}
}
}
}
fn navigate_to_children<'a>(nodes: &'a [DomNode], path: &[usize]) -> &'a [DomNode] {
if path.is_empty() {
return nodes;
}
match &nodes[path[0]] {
DomNode::Element { children, .. } => navigate_to_children(children, &path[1..]),
_ => nodes,
}
}
fn extract_template_inner(axes: &[Axis], variants: &[String]) -> String {
if variants.is_empty() {
return String::new();
}
if variants.len() == 1 || axes.is_empty() {
return variants[0].clone();
}
let mut result = parse_html(&variants[0]);
let (top_level, groups) = classify_axes(axes);
let mut handled: HashSet<usize> = HashSet::new();
for group in &groups {
handled.insert(group.parent_axis_idx);
for &child in &group.children {
handled.insert(child);
}
result = process_array_with_children(result, axes, variants, group);
}
for &idx in &top_level {
if handled.contains(&idx) {
continue;
}
let axis = &axes[idx];
result = match axis.kind.as_str() {
"boolean" | "nullable" => process_boolean(result, axes, variants, idx),
"enum" => {
let (new_result, consumed_siblings) = process_enum(result, axes, variants, idx);
if consumed_siblings {
for &other in &top_level {
if other != idx {
handled.insert(other);
}
}
}
new_result
}
"array" => process_array(result, axes, variants, idx),
_ => result,
};
}
serialize(&result)
}
pub fn extract_template(axes: &[Axis], variants: &[String]) -> String {
extract_template_inner(axes, variants)
}
#[cfg(test)]
mod tests;