bake_markdown/lib.rs
1// Released under the MIT License.
2// Copyright, 2026, by Samuel Williams.
3
4//! Markdown normalization tasks for Bake.
5//!
6//! [`normalize_document`] parses CommonMark, GFM, front matter, and math, then
7//! serializes the result with soft source line breaks unwrapped. CommonMark
8//! includes inline code. The `markdown:normalize` Bake task applies this to
9//! one or more files.
10use socketry_markdown::{
11 LineWrapping, MarkdownOptions, ParseOptions, message::Message, to_markdown_with_options,
12 to_mdast,
13};
14
15/// Normalize a Markdown document by joining soft source line breaks.
16///
17/// CommonMark, GFM, front matter, and math syntax are parsed so these features
18/// survive the round trip. This includes inline code, fenced code, tables,
19/// task lists, footnotes, and strikethrough. Explicit hard breaks, code
20/// content, and block boundaries are preserved. The result ends with a newline
21/// when it is non-empty.
22///
23/// # Errors
24///
25/// Returns an error if the Markdown syntax tree cannot be parsed or serialized.
26pub fn normalize_document(source: &str) -> Result<String, Message> {
27 let mut options = ParseOptions::gfm();
28 options.constructs.frontmatter = true;
29 options.constructs.math_flow = true;
30 options.constructs.math_text = true;
31
32 normalize_document_with_options(source, &options)
33}
34
35/// Normalize a Markdown document using explicit parser options.
36///
37/// Use this for syntax beyond the default GitHub Flavored Markdown, front
38/// matter, and math support, such as MDX.
39///
40/// # Errors
41///
42/// Returns an error if the Markdown syntax tree cannot be parsed or serialized.
43pub fn normalize_document_with_options(
44 source: &str,
45 parse_options: &ParseOptions,
46) -> Result<String, Message> {
47 let tree = to_mdast(source, parse_options)?;
48
49 to_markdown_with_options(
50 &tree,
51 &MarkdownOptions {
52 line_wrapping: LineWrapping::Unwrap,
53 ..MarkdownOptions::default()
54 },
55 )
56}
57
58mod file_system;
59
60use std::path::PathBuf;
61
62/// Normalize Markdown files beneath the Bake project root.
63#[bake::task]
64pub fn normalize(
65 context: &mut bake::Context,
66 #[bake(positional, help = "Markdown files, relative to the project root.")] paths: Vec<PathBuf>,
67) -> bake::Result<String> {
68 let changed = file_system::normalize_files(context.root(), &paths)?;
69 Ok(format!(
70 "Normalized {changed} of {} Markdown files",
71 paths.len()
72 ))
73}
74
75#[cfg(test)]
76#[path = "tests.rs"]
77mod tests;