pub struct Case {
pub index: usize,
pub data: String,
pub fragment: Option<String>,
pub scripting: Option<bool>,
pub document: String,
}
pub fn parse(text: &str) -> Vec<Case> {
let mut cases = Vec::new();
let mut section = "";
let mut cur: Option<Case> = None;
for line in text.split('\n') {
let starts_case = line == "#data" && matches!(section, "" | "#document" | "#description");
if starts_case {
if let Some(c) = cur.take() {
cases.push(finish(c));
}
cur = Some(Case {
index: cases.len(),
data: String::new(),
fragment: None,
scripting: None,
document: String::new(),
});
section = "#data";
continue;
}
if line == "#description" && (section.is_empty() || section == "#document") {
if let Some(c) = cur.take() {
cases.push(finish(c));
}
section = "#description";
continue;
}
let Some(c) = cur.as_mut() else { continue };
match line {
"#errors" | "#new-errors" if section != "#document" => section = "#errors",
"#document-fragment" if section != "#data" && section != "#document" => {
section = "#document-fragment"
}
"#script-on" if section != "#data" && section != "#document" => {
c.scripting = Some(true)
}
"#script-off" if section != "#data" && section != "#document" => {
c.scripting = Some(false)
}
"#document" if section != "#data" => section = "#document",
_ => match section {
"#data" => {
c.data.push_str(line);
c.data.push('\n');
}
"#document-fragment" => c.fragment = Some(line.to_string()),
"#document" => {
c.document.push_str(line);
c.document.push('\n');
}
_ => {}
},
}
}
if let Some(c) = cur.take() {
cases.push(finish(c));
}
cases
}
fn finish(mut c: Case) -> Case {
if c.data.ends_with('\n') {
c.data.pop();
}
while c.document.ends_with("\n\n") {
c.document.pop();
}
c
}