Handle unclosed HTML tags inside a markdown element
This fixes an issue where it was panicking due to an unbalanced HTML tag when exiting a markdown element. The problem was that the tag stack was left non-empty when processing was finished due to `end_tag` being out of sync with the pulldown-cmark event tags. There really should be better validation that the stack is in sync and balanced, but this should address the main culprit of the interplay of raw HTML tags and pulldown-cmark events.
This commit is contained in:
parent
152132458e
commit
700839f77f
2 changed files with 31 additions and 12 deletions
|
|
@ -583,8 +583,28 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn end_tag(&mut self, tag: TagEnd) {
|
fn end_tag(&mut self, tag: TagEnd) {
|
||||||
// TODO: This should validate that the event stack is
|
// TODO: This should validate that the event stack is properly
|
||||||
// properly synchronized with the tag stack.
|
// synchronized with the tag stack. That, would likely require keeping
|
||||||
|
// a parallel "expected end tag" with the tag stack, since mapping a
|
||||||
|
// pulldown-cmark event tag to an HTML tag isn't always clear.
|
||||||
|
//
|
||||||
|
// Check for unclosed HTML tags when exiting a markdown event.
|
||||||
|
while let Some(node_id) = self.tag_stack.last() {
|
||||||
|
let node = self.tree.get(*node_id).unwrap().value();
|
||||||
|
let Node::Element(el) = node else {
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
if !el.was_raw {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
warn!(
|
||||||
|
"unclosed HTML tag `<{}>` found in `{}` while exiting {tag:?}\n\
|
||||||
|
HTML tags must be closed before exiting a markdown element.",
|
||||||
|
el.name.local,
|
||||||
|
self.options.path.display(),
|
||||||
|
);
|
||||||
|
self.pop();
|
||||||
|
}
|
||||||
self.pop();
|
self.pop();
|
||||||
match tag {
|
match tag {
|
||||||
TagEnd::TableHead => {
|
TagEnd::TableHead => {
|
||||||
|
|
|
||||||
|
|
@ -290,18 +290,17 @@ fn heading_with_unbalanced_html() {
|
||||||
BookTest::init(|_| {})
|
BookTest::init(|_| {})
|
||||||
.change_file("src/chapter_1.md", "### Option<T>")
|
.change_file("src/chapter_1.md", "### Option<T>")
|
||||||
.run("build", |cmd| {
|
.run("build", |cmd| {
|
||||||
cmd.expect_failure().expect_stderr(str![[r#"
|
cmd.expect_stderr(str![[r#"
|
||||||
INFO Book building has started
|
INFO Book building has started
|
||||||
INFO Running the html backend
|
INFO Running the html backend
|
||||||
|
WARN unclosed HTML tag `<t>` found in `chapter_1.md` while exiting Heading(H3)
|
||||||
thread 'main' ([..]) panicked at crates/mdbook-html/src/html/tree.rs:[..]
|
HTML tags must be closed before exiting a markdown element.
|
||||||
internal error: expected empty tag stack.
|
INFO HTML book written to `[ROOT]/book`
|
||||||
|
|
||||||
path: `chapter_1.md`
|
|
||||||
element=Element { name: QualName { prefix: None, ns: Atom('http://www.w3.org/1999/xhtml' type=static), local: Atom('h3' type=inline) }, attrs: {}, self_closing: false, was_raw: false }
|
|
||||||
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
|
|
||||||
|
|
||||||
"#]]);
|
"#]]);
|
||||||
});
|
})
|
||||||
// .check_main_file("book/chapter_1.html", str![[""]]);
|
.check_main_file(
|
||||||
|
"book/chapter_1.html",
|
||||||
|
str![[r##"<h3 id="option"><a class="header" href="#option">Option<t></t></a></h3>"##]],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue