/// Normalize whitespace in the final markdown output. /// /// - Collapse runs of 3+ newlines into 2 (one blank line) /// - Trim leading/trailing whitespace /// - Remove trailing whitespace from each line pub fn normalize(input: &str) -> String { let mut result = String::with_capacity(input.len()); let mut consecutive_newlines = 0u32; for ch in input.chars() { if ch == '\n' { consecutive_newlines += 1; if consecutive_newlines <= 2 { result.push('\n'); } } else { consecutive_newlines = 0; result.push(ch); } } // Trim trailing whitespace from each line let lines: Vec<&str> = result.lines().map(|l| l.trim_end()).collect(); let joined = lines.join("\n"); joined.trim().to_string() } #[cfg(test)] mod tests { use super::*; #[test] fn collapse_excessive_newlines() { assert_eq!(normalize("a\n\n\n\nb"), "a\n\nb"); } #[test] fn preserve_single_blank_line() { assert_eq!(normalize("a\n\nb"), "a\n\nb"); } #[test] fn trim_trailing_whitespace() { assert_eq!(normalize("hello \nworld "), "hello\nworld"); } #[test] fn trim_outer_whitespace() { assert_eq!(normalize("\n\nhello\n\n"), "hello"); } #[test] fn empty_input() { assert_eq!(normalize(""), ""); } }