katana_markdown_engine/document/
impls.rs1use super::types::{KmeDocument, KmeNode, KmeNodeId, KmeNodeKind};
2use crate::TextFingerprint;
3
4impl KmeDocument {
5 pub fn nodes_by_kind(&self, predicate: impl Fn(&KmeNodeKind) -> bool) -> Vec<&KmeNode> {
6 self.nodes
7 .iter()
8 .filter(|node| predicate(&node.kind))
9 .collect()
10 }
11
12 pub fn node_by_id(&self, id: &KmeNodeId) -> Option<&KmeNode> {
13 self.nodes.iter().find(|node| &node.id == id)
14 }
15}
16
17impl KmeNode {
18 pub(crate) fn new(
19 kind: KmeNodeKind,
20 raw: &str,
21 ordinal: usize,
22 source: crate::SourceSpan,
23 ) -> Self {
24 Self {
25 id: KmeNodeId::from_parts(&kind, raw, ordinal),
26 kind,
27 source,
28 children: Vec::new(),
29 }
30 }
31}
32
33impl KmeNodeId {
34 pub(crate) fn from_parts(kind: &KmeNodeKind, raw: &str, ordinal: usize) -> Self {
35 let seed = format!("{}\0{}\0{}", kind.label(), raw, ordinal);
36 Self(format!("kme-{}", TextFingerprint::for_text(&seed).value))
37 }
38}
39
40impl KmeNodeKind {
41 pub fn label(&self) -> &'static str {
42 match self {
43 Self::Heading(_) => "heading",
44 Self::Paragraph => "paragraph",
45 Self::Emoji(_) => "emoji",
46 Self::HtmlBlock(_) => "html-block",
47 Self::List(_) => "list",
48 Self::CodeBlock(_) => "code-block",
49 Self::Table(_) => "table",
50 Self::BlockQuote => "blockquote",
51 Self::Alert { .. } => "alert",
52 Self::DescriptionList { .. } => "description-list",
53 Self::ThematicBreak => "thematic-break",
54 Self::RawBlock { .. } => "raw-block",
55 }
56 }
57}