diff options
author | gennyble <gen@nyble.dev> | 2023-12-27 15:50:30 -0600 |
---|---|---|
committer | gennyble <gen@nyble.dev> | 2023-12-27 15:50:30 -0600 |
commit | 7b29f709893598d760fe2d4938e9bdc76423fb5d (patch) | |
tree | a13e7e3060765806fab382fb74d39ffd9e2df089 /src | |
parent | 848b70d0cf67ccbc4634b4f28ada285d6691eecd (diff) | |
download | cutie-7b29f709893598d760fe2d4938e9bdc76423fb5d.tar.gz cutie-7b29f709893598d760fe2d4938e9bdc76423fb5d.zip |
refactor Tag to it's own struct
Diffstat (limited to 'src')
-rw-r--r-- | src/lib.rs | 146 |
1 files changed, 83 insertions, 63 deletions
diff --git a/src/lib.rs b/src/lib.rs index 36a9075..b766109 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -39,8 +39,20 @@ impl Html { fn parse_tag(raw: &str) -> Consumed { let (root_tag, mut rest) = Self::is_tag(raw).unwrap(); + let mut tag = if root_tag.body.is_empty() { + Tag { + name: root_tag.name.to_owned(), + body: None, + children: vec![], + } + } else { + Tag { + name: root_tag.name.into(), + body: Some(root_tag.body.to_owned()), + children: vec![], + } + }; - //println!("- {raw}"); if root_tag.closing { panic!( "found closing tag when not expected! {:?}\n{raw}", @@ -48,17 +60,11 @@ impl Html { ) } else if root_tag.self_closing { return Consumed { - node: Node::Tag { - self_closing: true, - name: root_tag.name.into(), - children: vec![], - }, + node: Node::Tag(tag), remaining: rest, }; } - let mut children = vec![]; - loop { // Special case <script> and <style> if root_tag.name == "script" || root_tag.name == "style" { @@ -75,12 +81,9 @@ impl Html { Some(remaining) }; + tag.children.push(text!(text)); return Consumed { - node: Node::Tag { - self_closing: false, - name: root_tag.name.into(), - children: vec![text!(text)], - }, + node: Node::Tag(tag), remaining, }; } @@ -91,11 +94,7 @@ impl Html { if let Some((parsed, remaining)) = Self::is_tag(rest.unwrap()) { if parsed.closing && parsed.name == root_tag.name { break Consumed { - node: Node::Tag { - self_closing: false, - name: root_tag.name.to_owned(), - children, - }, + node: Node::Tag(tag), remaining, }; } @@ -104,11 +103,11 @@ impl Html { // Not our closing root? parse and push let cons = Self::parse_node(rest.unwrap()); rest = cons.remaining; - children.push(cons.node); + tag.children.push(cons.node); } } - fn special_parse<'a>(mut raw: &'a str, looking_for_name: &str) -> Option<(&'a str, &'a str)> { + fn special_parse<'a>(raw: &'a str, looking_for_name: &str) -> Option<(&'a str, &'a str)> { let close = format!("</{looking_for_name}>"); let mut offset = 0; @@ -129,8 +128,6 @@ impl Html { } } } - - None } fn parse_comment(raw: &str) -> Option<Consumed> { @@ -257,29 +254,81 @@ struct ParsedTag<'a> { self_closing: bool, } -#[derive(Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq)] pub enum Node { Text(String), - Tag { - // for roundtripping - self_closing: bool, - name: String, - children: Vec<Node>, - }, + Tag(Tag), Comment(String), } +#[derive(Clone, Debug, PartialEq)] +pub struct Tag { + pub name: String, + /// Everything inside the tag that's not it's name. Includes a + /// self-close if there is one. + pub body: Option<String>, + pub children: Vec<Node>, +} + +impl Tag { + pub fn self_closing(&self) -> bool { + self.body + .as_deref() + .map(|s| s.trim_end().ends_with('/')) + .unwrap_or(false) + } + + pub fn get_attribute<'a>(&'a self, key: &str) -> Option<&'a str> { + todo!() + } +} + +#[macro_export] +macro_rules! tag { + ($name:expr) => { + $crate::Node::Tag($crate::Tag { + name: String::from($name), + body: None, + children: vec![], + }) + }; + + ($name:expr, [$($children:expr),+]) => { + $crate::Node::Tag($crate::Tag { + name: String::from($name), + body: None, + children: vec![$($children),+], + }) + }; + + ($name:expr, $body:expr) => { + $crate::Node::Tag($crate::Tag { + name: String::from($name), + body: Some(String::from($body)), + children: vec![], + }) + }; + + ($name:expr, $body:expr, [$($children:expr),+]) => { + $crate::Node::Tag($crate::Tag { + name: String::from($name), + body: Some(String::from($body)), + children: vec![$($children),+], + }) + }; +} + #[macro_export] macro_rules! text { ($text:expr) => { - Node::Text(String::from($text)) + $crate::Node::Text(String::from($text)) }; } #[macro_export] macro_rules! comment { ($text:expr) => { - Node::Comment(String::from($text)) + $crate::Node::Comment(String::from($text)) }; } @@ -366,14 +415,7 @@ mod test { let basic = "<p>Hello!</p>"; let hh = Html::parse_node(basic); - assert_eq!( - hh.node, - Node::Tag { - self_closing: false, - name: "p".into(), - children: vec![text!("Hello!")] - } - ) + assert_eq!(hh.node, tag!("p", [text!("Hello!")])) } #[test] @@ -381,18 +423,7 @@ mod test { let nested = "<p><p>Hello!</p></p>"; let hh = Html::parse_node(nested); - assert_eq!( - hh.node, - Node::Tag { - self_closing: false, - name: "p".into(), - children: vec![Node::Tag { - self_closing: false, - name: "p".into(), - children: vec![text!("Hello!")] - }] - } - ) + assert_eq!(hh.node, tag!("p", [tag!("p", [text!("Hello!")])])) } #[test] @@ -402,18 +433,7 @@ mod test { let hh = Html::parse(nested); assert_eq!( hh.nodes, - vec![ - Node::Tag { - self_closing: false, - name: "p".into(), - children: vec![text!("Hello ")] - }, - Node::Tag { - self_closing: false, - name: "p".into(), - children: vec![text!("World!")] - } - ] + vec![tag!("p", [text!("Hello ")]), tag!("p", [text!("World!")])] ) } } |