Skip to main content

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;