use core::fmt;
pub struct Html {
pub nodes: Vec,
}
impl Html {
pub fn parse>(raw: S) -> Self {
let mut raw = raw.as_ref();
let mut nodes = vec![];
loop {
let Consumed { node, remaining } = Self::parse_node(raw);
nodes.push(node);
match remaining {
None => break Self { nodes },
Some(rem) => raw = rem,
}
}
}
fn parse_node(raw: &str) -> Consumed {
match Self::is_tag(raw) {
Some(_) => {
if let Some(cmt) = Self::parse_comment(raw) {
cmt
} else {
Self::parse_tag(raw)
}
}
None => {
let cons = Self::parse_text(raw);
cons
}
}
}
fn parse_tag(raw: &str) -> Consumed {
let (root_tag, mut rest) = Self::is_tag(raw).unwrap();
//println!("- {raw}");
if root_tag.closing {
panic!(
"found closing tag when not expected! {:?}\n{raw}",
root_tag.name
)
} else if root_tag.self_closing {
return Consumed {
node: Node::Tag {
self_closing: true,
name: root_tag.name.into(),
children: vec![],
},
remaining: rest,
};
}
let mut children = vec![];
loop {
// Special case ";
let special = Html::special_parse(basic, "script");
assert_eq!(special.unwrap().0, "words words\n");
assert!(special.unwrap().1.is_empty());
}
#[test]
fn special_parse_correctly_ignore_non_start() {
let nonstart = "first_line\nlet end = '';\n";
let special = Html::special_parse(nonstart, "script");
assert!(special.is_none());
}
#[test]
fn special_parse_correctly_handles_leading_whitespace() {
let white = "words words\n \t\t";
let special = Html::special_parse(white, "script");
assert_eq!(special.unwrap().0, "words words\n \t\t");
}
#[test]
fn parse_node_parses_comment() {
let cmt = "";
let node = Html::parse_node(cmt);
assert_eq!(node.node, comment!(" Comment! "));
}
#[test]
fn parse_node_parses_tag() {
let basic = "Hello!
";
let hh = Html::parse_node(basic);
assert_eq!(
hh.node,
Node::Tag {
self_closing: false,
name: "p".into(),
children: vec![text!("Hello!")]
}
)
}
#[test]
fn parse_node_parses_nested_tags() {
let nested = "Hello!
";
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!")]
}]
}
)
}
#[test]
fn parse_multiple_toplevel() {
let nested = "Hello
World!
";
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!")]
}
]
)
}
}