Skip to main content

base_markdown/markdown/
mod.rs

1// Released under the MIT License.
2// Copyright, 2024, by Bnchi.
3// Copyright, 2024, by Titus Wormer.
4// Copyright, 2026, by Samuel Williams.
5
6//! API.
7//!
8//! JS equivalent: https://github.com/syntax-tree/mdast-util-to-markdown/blob/main/lib/index.js.
9
10// Formatting rules are adapted from `mdast-util-to-markdown`; keep the parser's stricter lints on the surrounding API.
11#![allow(clippy::pedantic)]
12
13pub use self::configure::{IndentOptions, LineWrapping, Options};
14use self::state::{Info, State};
15use crate::{message::Message, Document, NodeId};
16use alloc::string::String;
17
18extern crate alloc;
19mod configure;
20mod construct_name;
21mod escape;
22mod handle;
23mod state;
24mod util;
25
26/// Serialize an arena document to Markdown.
27///
28/// # Errors
29/// Returns invalid formatting options, unsupported syntax metadata, or unsupported content shapes.
30pub fn to_markdown<S: AsRef<str>>(document: &Document<S>) -> Result<String, Message> {
31    to_markdown_with_options(document, &Options::default())
32}
33
34/// Serialize an arena document with formatting options.
35///
36/// # Errors
37/// Returns invalid formatting options, unsupported syntax metadata, or unsupported content shapes.
38pub fn to_markdown_with_options<S: AsRef<str>>(
39    document: &Document<S>,
40    options: &Options,
41) -> Result<String, Message> {
42    to_markdown_node(document, document.root(), options)
43}
44
45/// Serialize a document subtree with formatting options.
46///
47/// # Errors
48/// Returns an invalid node index, invalid formatting options, unsupported syntax metadata, or unsupported content shapes.
49pub fn to_markdown_node<S: AsRef<str>>(
50    document: &Document<S>,
51    node: NodeId,
52    options: &Options,
53) -> Result<String, Message> {
54    if document.node(node).is_none() {
55        return Err(state::invalid_node());
56    }
57    let mut state = State::new(options);
58    state.serialization_root = Some(node);
59    let mut result = state.handle(document, node, &Info::new("\n", "\n"))?;
60    if !result.is_empty() && !result.ends_with(['\r', '\n']) {
61        result.push('\n');
62    }
63    Ok(result)
64}