liwe 0.0.66

IWE core library
Documentation
use crate::model::graph::{GraphBlock, GraphInline};
use crate::model::node::{Node, NodeIter, ReferenceType};

pub struct Projector {
    header_level: usize,
    parent: String,
}

impl Projector {
    pub fn project<'a>(iter: impl NodeIter<'a>, parent: &str) -> Vec<GraphBlock> {
        Projector {
            header_level: 0,
            parent: parent.to_string(),
        }
        .project_node(iter)
    }

    fn with(&self, header_level: usize) -> Projector {
        Projector {
            header_level,
            parent: self.parent.clone(),
        }
    }

    fn project_node<'a>(&self, iter: impl NodeIter<'a>) -> Vec<GraphBlock> {
        let mut blocks = vec![];

        if iter.node().is_none() {
            return blocks;
        }

        match iter.node().unwrap() {
            Node::Document(_, metadata) => {
                if let Some(metadata_content) = metadata {
                    blocks.push(GraphBlock::Frontmatter(metadata_content.clone()));
                }
                if let Some(child) = iter.child() {
                    blocks.extend(self.with(self.header_level).project_node(child));
                }
            }
            Node::Section(_) => {
                blocks.push(GraphBlock::Header(
                    self.header_level as u8 + 1,
                    iter.inlines(),
                ));

                if let Some(child) = iter.child() {
                    blocks.extend(self.with(self.header_level + 1).project_node(child));
                }
            }
            Node::Quote() => {
                if let Some(child) = iter.child() {
                    blocks.push(GraphBlock::BlockQuote(self.with(0).project_node(child)));
                }
            }
            Node::BulletList() => {
                if let Some(child) = iter.child() {
                    blocks.push(GraphBlock::BulletList(
                        self.with(0).project_list_item(child),
                    ));
                }
            }
            Node::OrderedList() => {
                if let Some(child) = iter.child() {
                    blocks.push(GraphBlock::OrderedList(
                        self.with(0).project_list_item(child),
                    ));
                }
            }
            Node::Leaf(_) => {
                blocks.push(GraphBlock::Para(iter.inlines()));
            }
            Node::Raw(_, _) => {
                blocks.push(GraphBlock::CodeBlock(
                    iter.lang(),
                    iter.content().unwrap_or_default(),
                ));
            }
            Node::HorizontalRule() => {
                blocks.push(GraphBlock::HorizontalRule);
            }
            Node::Reference(_) => {
                let inlines = match iter.ref_type().unwrap() {
                    ReferenceType::Regular => iter.inlines(),
                    ReferenceType::WikiLink => vec![],
                    ReferenceType::WikiLinkPiped => {
                        vec![GraphInline::Str(iter.ref_text().unwrap_or_default())]
                    }
                };

                let link = GraphInline::Link(
                    iter.ref_key2().unwrap().to_rel_link_url(&self.parent),
                    String::default(),
                    iter.ref_type().unwrap().to_link_type(),
                    inlines,
                );

                blocks.push(GraphBlock::Para(vec![link]));
            }
            Node::Table(_) => {
                blocks.push(GraphBlock::Table(
                    iter.table_header().unwrap_or_default().to_vec(),
                    iter.table_alignment().unwrap_or_default(),
                    iter.table_rows()
                        .unwrap_or_default()
                        .iter()
                        .map(|row| row.to_vec())
                        .collect(),
                ));
            }
        }
        if let Some(next) = iter.next() {
            blocks.extend(self.with(self.header_level).project_node(next));
        }
        blocks
    }

    fn project_list_item<'a>(&self, iter: impl NodeIter<'a>) -> Vec<Vec<GraphBlock>> {
        let mut items: Vec<Vec<GraphBlock>> = vec![];

        if iter.node().is_none() {
            return items;
        }

        if iter.child().map(|n| n.is_leaf()).unwrap_or(false) {
            items.push(vec![GraphBlock::Para(iter.inlines())]);
        } else {
            items.push(vec![GraphBlock::Plain(iter.inlines())]);
        }

        if let Some(sub_list) = iter.child().map(|child| self.with(0).project_node(child)) {
            sub_list
                .iter()
                .for_each(|item| items.last_mut().unwrap().push(item.clone()))
        }

        if let Some(blocks) = iter
            .next()
            .map(|next| self.with(self.header_level).project_list_item(next))
        {
            items.append(blocks.clone().as_mut())
        }

        items
    }
}