rustdoc_to_markdown: Fix code blocks (#12460)

This PR fixes an issue in `rustdoc_to_markdown` with code blocks being
trimmed incorrectly.

We were erroneously popping from the current element stack even if we
didn't push an element onto the stack.

Added test coverage for this case as well, so we don't regress.

Release Notes:

- N/A
This commit is contained in:
Marshall Bowers 2024-05-29 19:23:06 -04:00 committed by GitHub
parent a5011996fb
commit bdf627ce07
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 53 additions and 2 deletions

1
Cargo.lock generated
View File

@ -8640,6 +8640,7 @@ dependencies = [
"html5ever", "html5ever",
"indoc", "indoc",
"markup5ever_rcdom", "markup5ever_rcdom",
"pretty_assertions",
"regex", "regex",
] ]

View File

@ -19,3 +19,4 @@ regex.workspace = true
[dev-dependencies] [dev-dependencies]
indoc.workspace = true indoc.workspace = true
pretty_assertions.workspace = true

View File

@ -114,9 +114,8 @@ impl MarkdownWriter {
self.visit_node(child)?; self.visit_node(child)?;
} }
self.current_element_stack.pop_back();
if let Some(current_element) = current_element { if let Some(current_element) = current_element {
self.current_element_stack.pop_back();
self.end_tag(&current_element); self.end_tag(&current_element);
} }

View File

@ -36,3 +36,53 @@ pub fn convert_rustdoc_to_markdown(mut html: impl Read) -> Result<String> {
Ok(markdown) Ok(markdown)
} }
#[cfg(test)]
mod tests {
use indoc::indoc;
use pretty_assertions::assert_eq;
use super::*;
#[test]
fn test_code_blocks() {
let html = indoc! {r#"
<pre class="rust rust-example-rendered"><code><span class="kw">use </span>axum::extract::{Path, Query, Json};
<span class="kw">use </span>std::collections::HashMap;
<span class="comment">// `Path` gives you the path parameters and deserializes them.
</span><span class="kw">async fn </span>path(Path(user_id): Path&lt;u32&gt;) {}
<span class="comment">// `Query` gives you the query parameters and deserializes them.
</span><span class="kw">async fn </span>query(Query(params): Query&lt;HashMap&lt;String, String&gt;&gt;) {}
<span class="comment">// Buffer the request body and deserialize it as JSON into a
// `serde_json::Value`. `Json` supports any type that implements
// `serde::Deserialize`.
</span><span class="kw">async fn </span>json(Json(payload): Json&lt;serde_json::Value&gt;) {}</code></pre>
"#};
let expected = indoc! {"
```rs
use axum::extract::{Path, Query, Json};
use std::collections::HashMap;
// `Path` gives you the path parameters and deserializes them.
async fn path(Path(user_id): Path<u32>) {}
// `Query` gives you the query parameters and deserializes them.
async fn query(Query(params): Query<HashMap<String, String>>) {}
// Buffer the request body and deserialize it as JSON into a
// `serde_json::Value`. `Json` supports any type that implements
// `serde::Deserialize`.
async fn json(Json(payload): Json<serde_json::Value>) {}
```
"}
.trim();
assert_eq!(
convert_rustdoc_to_markdown(html.as_bytes()).unwrap(),
expected
)
}
}