use markdown::{
ParseOptions,
mdast::{Link, Node, Paragraph, Root, Text},
};
use serde_json::{Value, json};
pub fn from_str<T: AsRef<str>>(
markdown: T,
options: &ParseOptions,
) -> Result<Value, markdown::message::Message> {
Ok(markdown::to_mdast(markdown.as_ref(), options)?.to_adf())
}
pub trait ToAdf {
fn to_adf(&self) -> serde_json::Value;
}
impl ToAdf for Node {
fn to_adf(&self) -> Value {
json!({
"body": {
"content": to_adf(self),
"type": "doc",
"version": 1,
}
})
}
}
fn to_adf(node: &Node) -> Value {
match node {
Node::Root(Root {
children,
..
}) => Value::Array(children.iter().map(to_adf).collect()),
Node::Blockquote(blockquote) => todo!(),
Node::Break(_) => todo!(),
Node::Code(code) => todo!(),
Node::Definition(definition) => todo!(),
Node::Delete(delete) => todo!(),
Node::Emphasis(emphasis) => todo!(),
Node::FootnoteDefinition(footnote_definition) => todo!(),
Node::FootnoteReference(footnote_reference) => todo!(),
Node::Heading(heading) => todo!(),
Node::Html(html) => todo!(),
Node::Image(image) => todo!(),
Node::ImageReference(image_reference) => todo!(),
Node::InlineCode(inline_code) => todo!(),
Node::InlineMath(inline_math) => todo!(),
Node::Link(Link {
url,
title,
children,
..
}) => {
let Some(Node::Text(Text {
value,
..
})) = children.first()
else {
panic!("missing text on link");
};
json!({
"type": "text",
"text": value,
"marks": [{
"type": "link",
"attrs": [{
"href": url,
"title": title,
}],
}],
})
},
Node::LinkReference(link_reference) => todo!(),
Node::List(list) => todo!(),
Node::ListItem(list_item) => todo!(),
Node::Math(math) => todo!(),
Node::MdxFlowExpression(mdx_flow_expression) => todo!(),
Node::MdxJsxFlowElement(mdx_jsx_flow_element) => todo!(),
Node::MdxJsxTextElement(mdx_jsx_text_element) => todo!(),
Node::MdxTextExpression(mdx_text_expression) => todo!(),
Node::MdxjsEsm(mdxjs_esm) => todo!(),
Node::Paragraph(Paragraph {
children,
..
}) => json!({
"content": Value::Array(children.iter().map(to_adf).collect()),
"type": "paragraph",
}),
Node::Strong(strong) => todo!(),
Node::Table(table) => todo!(),
Node::TableCell(table_cell) => todo!(),
Node::TableRow(table_row) => todo!(),
Node::Text(Text {
value,
..
}) => json!({
"text": value,
"type": "text",
}),
Node::ThematicBreak(thematic_break) => todo!(),
Node::Toml(toml) => todo!(),
Node::Yaml(yaml) => todo!(),
}
}
#[cfg(test)]
mod tests {
use super::*;
mod to_adf {
use super::*;
use markdown::{
ParseOptions,
mdast::{Paragraph, Root},
};
use pretty_assertions::assert_eq;
#[test]
fn test_empty_root() {
assert_eq!(
Node::Root(Root {
children: vec![],
position: None,
})
.to_adf(),
json!({
"body": {
"content": [],
"type": "doc",
"version": 1,
},
}),
);
}
#[test]
fn test_paragraph() {
let node = markdown::to_mdast(
"This is a paragraph.",
&ParseOptions::default(),
)
.unwrap();
assert_eq!(
node.to_adf(),
json!({
"body": {
"content": [{
"content": [{
"text": "This is a paragraph.",
"type": "text",
}],
"type": "paragraph",
}],
"type": "doc",
"version": 1,
},
}),
"{node:#?}",
);
let node =
markdown::to_mdast("", &ParseOptions::default()).unwrap();
assert_eq!(
node.to_adf(),
json!({
"body": {
"content": [],
"type": "doc",
"version": 1,
},
}),
"{:#?}",
node,
);
}
#[test]
fn test_multiline_paragraph() {
let node = markdown::to_mdast(
"This is a\nmultiline paragraph.",
&ParseOptions::default(),
)
.unwrap();
assert_eq!(
node.to_adf(),
json!({
"body": {
"content": [{
"content": [{
"text": "This is a\nmultiline paragraph.",
"type": "text",
}],
"type": "paragraph",
}],
"type": "doc",
"version": 1,
},
}),
"{node:#?}",
);
}
#[test]
fn test_multi_paragraph() {
let node = markdown::to_mdast(
"This is a paragraph.\n\nAnd another one.",
&ParseOptions::default(),
)
.unwrap();
assert_eq!(
node.to_adf(),
json!({
"body": {
"content": [{
"content": [{
"text": "This is a paragraph.",
"type": "text",
}],
"type": "paragraph",
},{
"content": [{
"text": "And another one.",
"type": "text",
}],
"type": "paragraph",
}],
"type": "doc",
"version": 1,
},
}),
"{node:#?}",
);
}
#[test]
fn test_link() {
let node = markdown::to_mdast(
"This is a paragraph [with](https://example.com).",
&ParseOptions::default(),
)
.unwrap();
assert_eq!(
node.to_adf(),
json!({
"body": {
"content": [{
"content": [{
"text": "This is a paragraph ",
"type": "text",
},{
"text": "with",
"type": "text",
"marks": [{
"attrs": [{
"href": "https://example.com",
"title": null,
}],
"type": "link",
}],
},{
"text": ".",
"type": "text",
}],
"type": "paragraph",
}],
"type": "doc",
"version": 1,
},
}),
"{node:#?}",
);
}
#[test]
fn test_link_with_title() {
let node = markdown::to_mdast(
r#"This is a paragraph [with](https://example.com "my title")."#,
&ParseOptions::default(),
)
.unwrap();
assert_eq!(
node.to_adf(),
json!({
"body": {
"content": [{
"content": [{
"text": "This is a paragraph ",
"type": "text",
},{
"text": "with",
"type": "text",
"marks": [{
"attrs": [{
"href": "https://example.com",
"title": "my title",
}],
"type": "link",
}],
},{
"text": ".",
"type": "text",
}],
"type": "paragraph",
}],
"type": "doc",
"version": 1,
},
}),
"{node:#?}",
);
}
}
}