Skip to content

Node API

The Node enum is the fundamental building block of the document structure in cmark-writer. It represents all possible elements in a CommonMark document.

Node Types

The Node enum includes the following variants:

Block Elements

Block-level elements form the structure of a document:

Node VariantDescriptionExample
DocumentRoot container for all contentThe entire Markdown document
HeadingSection heading (levels 1-6)# Heading
ParagraphText paragraphNormal text blocks
BlockQuoteQuoted content> Quoted text
CodeBlockBlock of code with optional language````rust`
ThematicBreakHorizontal rule---
OrderedListNumbered list1. Item
UnorderedListBullet list- Item
TableTabular dataA data table
HtmlBlockBlock-level HTML<div>
LinkReferenceDefinitionLink reference[ref]: url

Inline Elements

Inline elements appear within block elements:

Node VariantDescriptionExample
TextPlain text contentNormal text
EmphasisEmphasized text*italic*
StrongStrongly emphasized text**bold**
InlineCodeCode within text`code`
LinkHyperlink[text](url)
ReferenceLinkReference-style link[text][ref]
ImageImage reference![alt](src)
AutolinkURI/email in angle brackets<https://example.com>
HardBreakHard line break\\ or two spaces
SoftBreakSoft line breakA simple newline
HtmlElementInline HTML<span>

GFM Extensions

When the gfm feature is enabled:

Node VariantDescriptionExample
StrikethroughCrossed-out text~~text~~
Table with alignmentsTable with column alignmentLeft/center/right aligned columns
Task list itemsCheckable items- [ ] or - [x]
ExtendedAutolinkAuto-detected linksURLs without angle brackets

Creating Nodes

There are several ways to create nodes:

Using Enum Variants Directly

rust
let heading = Node::Heading {
    level: 1,
    content: vec![Node::Text("Title".to_string())],
    heading_type: HeadingType::Atx,
};

Using Convenience Methods

rust
let heading = Node::heading(1, vec![Node::Text("Title".to_string())]);

Building Complex Structures

rust
let document = Node::Document(vec![
    Node::heading(1, vec![Node::Text("Document Title".to_string())]),
    Node::Paragraph(vec![
        Node::Text("This is a paragraph with ".to_string()),
        Node::Strong(vec![Node::Text("bold".to_string())]),
        Node::Text(" and ".to_string()),
        Node::Emphasis(vec![Node::Text("italic".to_string())]),
        Node::Text(" text.".to_string()),
    ]),
    Node::UnorderedList(vec![
        ListItem::Unordered { 
            content: vec![Node::Paragraph(vec![Node::Text("Item 1".to_string())])] 
        },
        ListItem::Unordered { 
            content: vec![Node::Paragraph(vec![Node::Text("Item 2".to_string())])] 
        },
    ]),
]);

Working with List Items

List items have their own types to support different list styles:

rust
// Unordered list item
let unordered_item = ListItem::Unordered {
    content: vec![Node::Paragraph(vec![Node::Text("Bullet point".to_string())])],
};

// Ordered list item
let ordered_item = ListItem::Ordered {
    number: Some(1), // Optional explicit numbering
    content: vec![Node::Paragraph(vec![Node::Text("Numbered item".to_string())])],
};

// GFM task list item (with gfm feature)
#[cfg(feature = "gfm")]
let task_item = ListItem::Task {
    status: TaskListStatus::Unchecked,
    content: vec![Node::Paragraph(vec![Node::Text("Task to do".to_string())])],
};

Tables

The library provides a fluent API for creating tables:

rust
use cmark_writer::ast::{Node, tables::TableBuilder};

// Create a simple table using the builder pattern
let table = TableBuilder::new()
    .headers(vec![
        Node::Text("Name".to_string()), 
        Node::Text("Age".to_string())
    ])
    .add_row(vec![
        Node::Text("Alice".to_string()),
        Node::Text("30".to_string()),
    ])
    .add_row(vec![
        Node::Text("Bob".to_string()),
        Node::Text("25".to_string()),
    ])
    .build();

// Or use the convenience function
let simple_table = cmark_writer::ast::tables::simple_table(
    vec![Node::Text("Header".to_string())],
    vec![vec![Node::Text("Data".to_string())]]
);

Utility Methods

The Node enum provides useful methods for working with nodes:

Type Checking

rust
let heading = Node::heading(1, vec![Node::Text("Title".to_string())]);
let is_block = heading.is_block();  // true
let is_inline = heading.is_inline(); // false

let text = Node::Text("Hello".to_string());
let is_inline = text.is_inline();   // true
let is_block = text.is_block();     // false

Custom Nodes

The Node::Custom variant allows you to implement custom node behavior by implementing the CustomNode trait:

rust
use cmark_writer::{custom_node, ast::CustomNode};

#[custom_node]
#[derive(Debug, Clone, PartialEq)]
struct MyCustomNode {
    content: String,
}

// Use as: Node::Custom(Box::new(MyCustomNode { content: "Hello".to_string() }))

For more details on custom nodes, see the Custom Nodes guide.