1pub fn format_markdown_list_item(message: &str) -> String {
11 let mut out = String::new();
12 let mut lines = message.lines();
13 if let Some(first) = lines.next() {
14 out.push_str("- ");
15 out.push_str(first);
16 out.push('\n');
17 } else {
18 out.push_str("- \n");
22 return out;
23 }
24
25 for line in lines {
28 out.push_str(" ");
29 out.push_str(line);
30 out.push('\n');
31 }
32
33 out
34}
35
36pub fn compose_markdown_with_affixes(message: &str, prefix: &str, suffix: &str) -> String {
41 if suffix.is_empty() {
42 return format!("{}{}", prefix, message);
43 }
44
45 let ends_with_fence = message.trim_end().ends_with("```");
46 if ends_with_fence {
47 format!("{}{}\n{}", prefix, message, suffix)
48 } else {
49 format!("{}{}{}", prefix, message, suffix)
50 }
51}
52
53#[cfg(test)]
54mod tests {
55 use super::*;
56
57 #[test]
58 fn list_item_single_line() {
59 let out = format_markdown_list_item("feat: add new feature");
60 assert_eq!(out, "- feat: add new feature\n");
61 }
62
63 #[test]
64 fn list_item_multiline_with_nested_list() {
65 let msg = "feat: big change\n- add A\n- add B";
66 let out = format_markdown_list_item(msg);
67 let expected = "- feat: big change\n - add A\n - add B\n";
68 assert_eq!(out, expected);
69 }
70
71 #[test]
72 fn list_item_with_empty_message() {
73 let out = format_markdown_list_item("");
74 assert_eq!(out, "- \n");
75 }
76
77 #[test]
78 fn compose_affixes_simple() {
79 let msg = compose_markdown_with_affixes(
80 "feat: add new feature",
81 "[abcd](link) ",
82 " — Thanks @user!",
83 );
84 assert_eq!(msg, "[abcd](link) feat: add new feature — Thanks @user!");
85 }
86
87 #[test]
88 fn compose_affixes_preserves_code_fence() {
89 let message = "Here is code:\n```rust\nfn main() {}\n```";
90 let result = compose_markdown_with_affixes(message, "[abcd](link) ", " — Thanks @user!");
91 let expected = "[abcd](link) Here is code:\n```rust\nfn main() {}\n```\n — Thanks @user!";
92 assert_eq!(result, expected);
93 }
94}