diff --git a/crates/mdbook-html/src/html/tree.rs b/crates/mdbook-html/src/html/tree.rs index 432cf7bea0..0c7c2e4d10 100644 --- a/crates/mdbook-html/src/html/tree.rs +++ b/crates/mdbook-html/src/html/tree.rs @@ -306,25 +306,7 @@ where trace!("event={event:?}"); match event { Event::Start(tag) => self.start_tag(tag), - Event::End(tag) => { - // TODO: This should validate that the event stack is - // properly synchronized with the tag stack. - self.pop(); - match tag { - TagEnd::TableHead => { - self.table_state = TableState::Body; - self.push(Node::Element(Element::new("tbody"))); - } - TagEnd::TableCell => { - self.table_cell_index += 1; - } - TagEnd::Table => { - // Pop tbody or thead - self.pop(); - } - _ => {} - } - } + Event::End(tag) => self.end_tag(tag), Event::Text(text) => { self.append_text(text.into_tendril()); } @@ -600,6 +582,46 @@ where self.push(Node::Element(element)); } + fn end_tag(&mut self, tag: TagEnd) { + // TODO: This should validate that the event stack is properly + // 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(); + match tag { + TagEnd::TableHead => { + self.table_state = TableState::Body; + self.push(Node::Element(Element::new("tbody"))); + } + TagEnd::TableCell => { + self.table_cell_index += 1; + } + TagEnd::Table => { + // Pop tbody or thead + self.pop(); + } + _ => {} + } + } + /// Given some HTML, parse it into [`Node`] elements and append them to /// the current node. fn append_html(&mut self, html: &str) { diff --git a/tests/testsuite/rendering.rs b/tests/testsuite/rendering.rs index e0e770398d..421aa5d45c 100644 --- a/tests/testsuite/rendering.rs +++ b/tests/testsuite/rendering.rs @@ -283,3 +283,24 @@ Check that the HTML tags are properly balanced. }) .check_main_file("book/chapter_1.html", str!["