1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
mod code;
mod html;
mod list;
mod table;

use crate::{ExtensionHandler, ExtensionRegistrar, Result, ToNotedown};
use comrak::{
    arena_tree::Children,
    nodes::{Ast, AstNode, NodeValue},
    parse_document, Arena, ComrakExtensionOptions, ComrakOptions, ComrakParseOptions,
};
use notedown_ast::{ASTKind, ASTNode, ASTNodes};
use std::{cell::RefCell, collections::BTreeSet, iter::FromIterator};

pub fn register_common_markdown(r: &mut ExtensionRegistrar) {
    let ext = vec!["markdown", "md"];
    let new = ExtensionHandler {
        name: String::from("markdown"),
        try_extension: BTreeSet::from_iter(ext.into_iter().map(String::from)),
        parser: parse_common_markdown,
    };
    r.insert(new)
}

pub fn parse_common_markdown(input: &str) -> Result<ASTNode> {
    let arena = Arena::new();
    let options = ComrakOptions {
        extension: ComrakExtensionOptions {
            strikethrough: true,
            tagfilter: true,
            table: true,
            autolink: true,
            tasklist: true,
            superscript: true,
            header_ids: None,
            footnotes: true,
            description_lists: true,
            front_matter_delimiter: Some(String::from("---")),
        },
        parse: ComrakParseOptions { smart: true, default_info_string: None },
        render: Default::default(),
    };
    let parsed = parse_document(&arena, input, &options);
    return Ok(parsed.into_notedown());
}

impl<'a> ToNotedown for &'a AstNode<'a> {
    fn into_notedown(self) -> ASTNode {
        let node: NodeValue = self.data.borrow().value.to_owned();
        match node {
            NodeValue::Document => ASTKind::statements(self.children().into_notedown_list(), None),
            NodeValue::FrontMatter(v) => {
                let _front = String::from_utf8_lossy(&v);
                todo!()
            }
            NodeValue::BlockQuote => todo!(),
            NodeValue::List(v) => v.into_notedown(),
            NodeValue::Item(_) => {
                todo!()
            }
            NodeValue::DescriptionList => todo!(),
            NodeValue::DescriptionItem(v) => v.into_notedown(),
            NodeValue::DescriptionTerm => {
                todo!()
            }
            NodeValue::DescriptionDetails => {
                todo!()
            }
            NodeValue::CodeBlock(v) => v.into_notedown(),
            NodeValue::HtmlBlock(v) => v.into_notedown(),
            NodeValue::Paragraph => ASTKind::paragraph(self.children().into_notedown_list(), None),
            NodeValue::Heading(v) => ASTKind::header(self.children().into_notedown_list(), v.level as u8, None),
            NodeValue::ThematicBreak => ASTKind::hr(None),
            NodeValue::FootnoteDefinition(_) => {
                todo!()
            }
            NodeValue::Table(v) => v.into_notedown(),
            NodeValue::TableRow(_) => {
                todo!()
            }
            NodeValue::TableCell => {
                todo!()
            }
            NodeValue::Text(v) => ASTKind::text(String::from_utf8_lossy(&v), None),
            NodeValue::TaskItem(_) => {
                todo!()
            }
            NodeValue::SoftBreak => ASTKind::soft_break(None),
            NodeValue::LineBreak => ASTKind::hard_break(None),
            NodeValue::Code(v) => v.into_notedown(),
            NodeValue::HtmlInline(v) => {
                let _html = String::from_utf8_lossy(&v);
                todo!()
            }
            NodeValue::Emph => ASTKind::emphasis(self.children().into_notedown_list(), None),
            NodeValue::Strong => ASTKind::strong(self.children().into_notedown_list(), None),
            NodeValue::Strikethrough => ASTKind::delete(self.children().into_notedown_list(), None),
            NodeValue::Superscript => ASTKind::superscript(self.children().into_notedown_list(), None),
            NodeValue::Link(v) => {
                let url = String::from_utf8_lossy(&v.url);
                match v.title.is_empty() {
                    true => ASTKind::hyper_link(url, None),
                    false => {
                        let text = String::from_utf8_lossy(&v.title);
                        ASTKind::hyper_link_text(url, text, None)
                    }
                }
            }
            NodeValue::Image(v) => {
                let url = String::from_utf8_lossy(&v.url);
                match v.title.is_empty() {
                    true => ASTKind::image_link(url, None),
                    false => {
                        let alt = String::from_utf8_lossy(&v.title);
                        ASTKind::image_link_alt(url, alt, None)
                    }
                }
            }
            NodeValue::FootnoteReference(v) => {
                let _foot = String::from_utf8_lossy(&v);
                todo!()
            }
        }
    }
}

impl ToNotedown for Children<'_, RefCell<Ast>> {
    fn into_notedown(self) -> ASTNode {
        todo!()
    }

    fn into_notedown_list(self) -> ASTNodes {
        let mut children = vec![];
        for node in self {
            children.push(node.into_notedown())
        }
        return children;
    }
}