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