diff --git a/src/html_element.rs b/src/html_element.rs
index 166f1f5..cb0a04c 100644
--- a/src/html_element.rs
+++ b/src/html_element.rs
@@ -26,6 +26,7 @@ pub(crate) struct HtmlPartWithLine {
pub(crate) struct Element {
pub(crate) name: String,
pub(crate) self_closing: bool,
+ pub(crate) is_component: bool,
pub(crate) open_attrs: Vec<(String, String)>,
pub(crate) close_attrs: Vec<(String, String)>,
pub(crate) children: Vec,
diff --git a/src/sink.rs b/src/sink.rs
index 2e44cac..ca7caf7 100644
--- a/src/sink.rs
+++ b/src/sink.rs
@@ -17,34 +17,51 @@ impl<'a> TokenSink for HtmlSink<'a> {
let mut element = Element {
name: tag.name.to_string(),
self_closing: tag.self_closing,
+ is_component: false,
open_attrs: tag.attrs.into_iter().map(|a| (a.name.local.to_string(), a.value.to_string())).collect(),
close_attrs: Vec::new(),
children: Vec::new(),
};
+
if element.name == "comp" || element.name == "component" {
let Some(real_name) = element.open_attrs.iter().find(|(k, _)| k == "name").map(|(_, v)| v) else {
abort!(self.args.path_span, "Missing name attribute on component tag at line {line_number}");
};
+
element.name = real_name.to_owned();
+ element.is_component = true;
element.open_attrs.retain(|(k, _)| k != "name");
}
- match element.self_closing {
- true => match self.opened_elements.last_mut() {
+
+ if element.self_closing {
+ match self.opened_elements.last_mut() {
Some(container) => container.children.push(HtmlPartWithLine { part: HtmlPart::Element(element), line: line_number as usize }),
None => self.html_parts.push(HtmlPartWithLine { part: HtmlPart::Element(element), line: line_number as usize }),
- },
- false => self.opened_elements.push(element)
+ }
+ } else {
+ self.opened_elements.push(element)
}
},
TagKind::EndTag => {
let mut element = self.opened_elements.pop().unwrap_or_else(|| abort!(self.args.path_span, "Unexpected closing tag {} at line {line_number}", tag.name));
- if tag.name != element.name {
- abort!(self.args.path_span, "Unexpected closing tag {} at line {line_number}", tag.name);
+
+ if element.is_component {
+ if !["comp", "component"].contains(&tag.name.to_string().as_str()) {
+ abort!(self.args.path_span, "Unexpected closing tag {} at line {line_number}", tag.name);
+ }
+ } else {
+ if tag.name != element.name {
+ abort!(self.args.path_span, "Unexpected closing tag {} at line {line_number}", tag.name);
+ }
}
+
element.close_attrs = tag.attrs.into_iter().map(|a| (a.name.local.to_string(), a.value.to_string())).collect();
+
+ let html_part = HtmlPartWithLine { part: HtmlPart::Element(element), line: line_number as usize };
+
match self.opened_elements.last_mut() {
- Some(container) => container.children.push(HtmlPartWithLine { part: HtmlPart::Element(element), line: line_number as usize }),
- None => self.html_parts.push(HtmlPartWithLine { part: HtmlPart::Element(element), line: line_number as usize }),
+ Some(container) => container.children.push(html_part),
+ None => self.html_parts.push(html_part),
}
},
},
@@ -64,6 +81,7 @@ pub(crate) fn read_template(args: &Args) -> Element {
Ok(template) => template,
Err(e) => abort!(args.path_span, "Failed to read template file at {}: {}", args.path, e),
};
+
let mut html_parts = Vec::new();
let html_sink = HtmlSink { html_parts: &mut html_parts, opened_elements: Vec::new(), args };
let mut html_tokenizer = Tokenizer::new(html_sink, TokenizerOpts::default());
@@ -71,13 +89,16 @@ pub(crate) fn read_template(args: &Args) -> Element {
buffer_queue.push_back(template.into());
let _ = html_tokenizer.feed(&mut buffer_queue);
html_tokenizer.end();
+
let mut root = Element {
name: "".to_string(),
open_attrs: Vec::new(),
close_attrs: Vec::new(),
self_closing: false,
+ is_component: false,
children: html_parts,
};
+
root.clean_text();
root
}