yamd 0.18.1

Yet Another Markdown Document (flavour)
Documentation
//! YAMD - Yet Another Markdown Document (flavour)
//!
//! Simplified version of [CommonMark](https://spec.commonmark.org/).
//!
//! For formatting check [`YAMD`](nodes::Yamd) struct documentation.
//!
//! # Quick start
//!
//! ```rust
//! use yamd::deserialize;
//!
//! let input = "# Hello\n\nA paragraph with **bold** text.";
//! let yamd = deserialize(input);
//!
//! // Access the AST
//! assert_eq!(yamd.body.len(), 2);
//!
//! // Round-trip back to markdown
//! assert_eq!(yamd.to_string(), input);
//! ```
//!
//! # Reasoning
//!
//! Simplified set of rules allows to have simpler, more efficient, parser and renderer.
//! [YAMD](nodes::Yamd) does not provide render functionality, instead it is a [serde]
//! serializable structure that allows you to write any renderer for that structure. All HTML
//! equivalents in this doc are provided as an example to what it can be rendered.
//!
//! # Difference from CommonMark
//!
//! While YAMD tries to utilize as much CommonMark syntax as possible, there are differences.
//!
//! ## Escaping
//!
//! Escaping done on a [lexer] level. Every symbol following the `\` symbol will be treated as a
//! [literal](lexer::TokenKind::Literal).
//!
//! Example:
//!
//! | YAMD      | HTML equivalent |
//! |-----------|-----------------|
//! | `\**foo**`|`<p>**foo**</p>` |
//!
//! ## Precedence
//!
//! [CommonMark](https://spec.commonmark.org/0.31.2/#precedence) defines container blocks and leaf
//! blocks. And that container block indicator has higher precedence. YAMD does not discriminate by
//! block type, every node (block) is the same. In practice, there are no additional rules to encode
//! and remember.
//!
//! Example:
//!
//! | YAMD                  | HTML equivalent                               |
//! |-----------------------|-----------------------------------------------|
//! | ``- `one\n- two` ``   | `<ol><li><code>one\n- two</code></li></ol>`   |
//!
//!
//! If you want to have two [ListItem](nodes::ListItem)'s use escaping:
//!
//! | YAMD                      | HTML equivalent                           |
//! |---------------------------|-------------------------------------------|
//! | ``- \`one\n- two\` ``     | ``<ol><li>`one</li><li>two`</li><ol>``    |
//!
//! The reasoning is that those kind issues can be caught with tooling like linters/lsp. That tooling
//! does not exist yet.
//!
//! ## Nodes
//!
//! List of supported [nodes] and their formatting. The best starting point is [YAMD](nodes::Yamd).
//!
//! # MSRV
//!
//! YAMD minimal supported Rust version is 1.80.0 due to [Option::take_if] usage

#[deny(missing_docs, rustdoc::broken_intra_doc_links)]
pub mod lexer;
pub mod nodes;
pub mod op;

#[doc(inline)]
pub use nodes::Yamd;
pub use op::parse;
pub use op::to_yamd;

/// Deserialize a string into a Yamd struct
/// # Example
/// ```
/// use yamd::deserialize;
/// let input = "# header";
/// let yamd = deserialize(input);
/// ```
pub fn deserialize(input: &str) -> Yamd {
    let ops = op::parse(input);
    op::to_yamd(&ops, input)
}

#[cfg(test)]
mod tests {
    use pretty_assertions::assert_eq;

    use crate::{
        deserialize,
        nodes::{Anchor, Heading, Paragraph, Yamd},
    };

    #[test]
    fn test_deserialize() {
        let input = "# header";
        let expected = Yamd::new(
            None,
            vec![Heading::new(1, vec![String::from("header").into()]).into()],
        );
        let actual = deserialize(input);
        assert_eq!(expected, actual);
    }

    #[test]
    fn deserialize_text_containing_utf8() {
        let input = "## 🤔\n\n[link 😉](url)";
        let expected = Yamd::new(
            None,
            vec![
                Heading::new(2, vec![String::from("🤔").into()]).into(),
                Paragraph::new(vec![Anchor::new("link 😉", "url").into()]).into(),
            ],
        );
        let actual = deserialize(input);
        assert_eq!(expected, actual);
    }
}