katana-markdown-engine 0.1.0

Renderer-neutral Markdown document model for the KatanA ecosystem
Documentation
use super::types::{KmeDocument, KmeNode, KmeNodeId, KmeNodeKind};
use crate::TextFingerprint;

impl KmeDocument {
    pub fn nodes_by_kind(&self, predicate: impl Fn(&KmeNodeKind) -> bool) -> Vec<&KmeNode> {
        self.nodes
            .iter()
            .filter(|node| predicate(&node.kind))
            .collect()
    }

    pub fn node_by_id(&self, id: &KmeNodeId) -> Option<&KmeNode> {
        self.nodes.iter().find(|node| &node.id == id)
    }
}

impl KmeNode {
    pub(crate) fn new(
        kind: KmeNodeKind,
        raw: &str,
        ordinal: usize,
        source: crate::SourceSpan,
    ) -> Self {
        Self {
            id: KmeNodeId::from_parts(&kind, raw, ordinal),
            kind,
            source,
            children: Vec::new(),
        }
    }
}

impl KmeNodeId {
    pub(crate) fn from_parts(kind: &KmeNodeKind, raw: &str, ordinal: usize) -> Self {
        let seed = format!("{}\0{}\0{}", kind.label(), raw, ordinal);
        Self(format!("kme-{}", TextFingerprint::for_text(&seed).value))
    }
}

impl KmeNodeKind {
    pub fn label(&self) -> &'static str {
        match self {
            Self::Heading(_) => "heading",
            Self::Paragraph => "paragraph",
            Self::Emoji(_) => "emoji",
            Self::HtmlBlock(_) => "html-block",
            Self::List(_) => "list",
            Self::CodeBlock(_) => "code-block",
            Self::Table(_) => "table",
            Self::BlockQuote => "blockquote",
            Self::Alert { .. } => "alert",
            Self::DescriptionList { .. } => "description-list",
            Self::ThematicBreak => "thematic-break",
            Self::RawBlock { .. } => "raw-block",
        }
    }
}