git_cliff_core/
markdown.rs1use pulldown_cmark::{Options, Parser};
4use pulldown_cmark_to_cmark::cmark_with_options;
5
6use crate::error::Result;
7
8pub fn format_markdown(input: &str) -> Result<String> {
22 let mut options = Options::empty();
23 options.insert(Options::ENABLE_TABLES);
24 options.insert(Options::ENABLE_STRIKETHROUGH);
25 options.insert(Options::ENABLE_TASKLISTS);
26 options.insert(Options::ENABLE_FOOTNOTES);
27 options.insert(Options::ENABLE_GFM);
28
29 let parser = Parser::new_ext(input, options);
30 let mut formatted = String::with_capacity(input.len());
31 let format_options = pulldown_cmark_to_cmark::Options {
34 list_token: '-',
35 ..Default::default()
36 };
37 cmark_with_options(parser, &mut formatted, format_options)?;
38
39 if input.ends_with('\n') && !formatted.ends_with('\n') {
42 formatted.push('\n');
43 }
44 Ok(formatted)
45}
46
47#[cfg(test)]
48mod test {
49 use super::*;
50
51 #[test]
52 fn normalizes_messy_markdown() -> Result<()> {
53 let input = "\
56Changelog
57=========
58
59
60## 1.0.0
61### Features
62
63- first change
64- second change
65
66
67
68some text
69";
70 let formatted = format_markdown(input)?;
71 let expected = "\
72# Changelog
73
74## 1.0.0
75
76### Features
77
78- first change
79- second change
80
81some text
82";
83 assert_eq!(expected, formatted);
84 assert_eq!(formatted, format_markdown(&formatted)?);
86 Ok(())
87 }
88
89 #[test]
90 fn keeps_clean_markdown_stable() -> Result<()> {
91 let input = "\
92# Changelog
93
94## 1.0.0
95
96### Features
97
98- add a thing
99
100### Bug Fixes
101
102- fix a thing
103";
104 assert_eq!(input, format_markdown(input)?);
105 Ok(())
106 }
107}