socketry_markdown/renderer.rs
1// Released under the MIT License.
2// Copyright, 2026, by Samuel Williams.
3
4//! Traits for rendering Markdown AST nodes.
5mod html;
6mod markdown;
7
8pub use html::HTMLRenderer;
9pub use markdown::MarkdownRenderer;
10
11use crate::mdast::Node;
12use alloc::string::String;
13
14/// A renderer for an AST node tree.
15///
16/// Implement [`render_node`][Self::render_node] to decide how each node is
17/// emitted. Call [`render_children`][Self::render_children] for transparent
18/// containers or when a node's children should be rendered recursively.
19/// Renderers choose their output format and escaping rules.
20///
21/// This is separate from [`crate::to_html`], which parses Markdown source and
22/// renders the parser's events with the built-in HTML compiler.
23///
24/// # Example
25///
26/// ```ignore
27/// use socketry_markdown::{mdast::Node, renderer::Renderer};
28///
29/// struct PlainText;
30///
31/// impl Renderer for PlainText {
32/// fn render_node(&mut self, node: &Node) -> String {
33/// match node {
34/// Node::Text(text) => text.value.clone(),
35/// Node::InlineCode(code) => code.value.clone(),
36/// Node::Code(code) => code.value.clone(),
37/// Node::Break(_) => "\n".into(),
38/// Node::Image(image) => image.alt.clone(),
39/// Node::ImageReference(image) => image.alt.clone(),
40/// Node::Definition(_) | Node::FootnoteReference(_) | Node::ThematicBreak(_) => {
41/// String::new()
42/// }
43/// _ => self.render_children(node),
44/// }
45/// }
46/// }
47///
48/// let node = Node::Fragment(socketry_markdown::mdast::Fragment {
49/// children: vec![Node::Text(socketry_markdown::mdast::Text {
50/// value: "hello".into(),
51/// position: None,
52/// })],
53/// });
54/// let mut renderer = PlainText;
55/// let plain_text = node.render_with(&mut renderer);
56/// ```
57pub trait Renderer {
58 /// Render one AST node into this renderer's output.
59 fn render_node(&mut self, node: &Node) -> String;
60
61 /// Render a node and its descendants.
62 fn render(&mut self, node: &Node) -> String {
63 self.render_node(node)
64 }
65
66 /// Render the direct children of a parent node in order.
67 fn render_children(&mut self, node: &Node) -> String {
68 let mut output = String::new();
69
70 if let Some(children) = node.children() {
71 for child in children {
72 output.push_str(&self.render(child));
73 }
74 }
75
76 output
77 }
78}