about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorgennyble <gen@nyble.dev>2023-12-27 15:50:30 -0600
committergennyble <gen@nyble.dev>2023-12-27 15:50:30 -0600
commit7b29f709893598d760fe2d4938e9bdc76423fb5d (patch)
treea13e7e3060765806fab382fb74d39ffd9e2df089 /src
parent848b70d0cf67ccbc4634b4f28ada285d6691eecd (diff)
downloadcutie-7b29f709893598d760fe2d4938e9bdc76423fb5d.tar.gz
cutie-7b29f709893598d760fe2d4938e9bdc76423fb5d.zip
refactor Tag to it's own struct
Diffstat (limited to 'src')
-rw-r--r--src/lib.rs146
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!")])]
 		)
 	}
 }