diff --git a/Cargo.toml b/Cargo.toml
index 8a53c928..45bfd139 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -32,6 +32,7 @@ serde = { version = "1", features = ["derive"], optional = true }
env_logger = "0.11"
criterion = "0.5"
pretty_assertions = "1"
+serde_json = { version = "1" }
swc_core = { version = "0.100", features = [
"ecma_ast",
"ecma_visit",
diff --git a/readme.md b/readme.md
index ad24a61f..acf4e9b0 100644
--- a/readme.md
+++ b/readme.md
@@ -264,6 +264,9 @@ The following bash scripts are useful when working on this project:
```sh
RUST_BACKTRACE=1 cargo test
```
+ ```sh
+ RUST_BACKTRACE=1 cargo test --features json
+ ```
* docs:
```sh
cargo doc --document-private-items
diff --git a/src/mdast.rs b/src/mdast.rs
index 1a9e0ee3..580df4b2 100644
--- a/src/mdast.rs
+++ b/src/mdast.rs
@@ -86,7 +86,7 @@ pub enum AlignKind {
#[cfg_attr(
feature = "serde",
derive(serde::Serialize, serde::Deserialize),
- serde(tag = "type", rename = "type")
+ serde(tag = "type", rename_all = "camelCase")
)]
pub enum Node {
// Document:
@@ -448,7 +448,7 @@ impl Node {
#[cfg_attr(
feature = "serde",
derive(serde::Serialize, serde::Deserialize),
- serde(tag = "type", rename = "mdxJsxExpressionAttribute")
+ serde(untagged, rename = "mdxJsxExpressionAttribute")
)]
pub enum AttributeContent {
/// JSX expression.
@@ -483,7 +483,7 @@ pub struct AttributeValueExpression {
#[cfg_attr(
feature = "serde",
derive(serde::Serialize, serde::Deserialize),
- serde(tag = "type", rename = "type")
+ serde(untagged)
)]
pub enum AttributeValue {
/// Expression value.
@@ -499,7 +499,6 @@ pub enum AttributeValue {
/// > |
/// ^^^
/// ```
- #[cfg_attr(feature = "serde", serde(rename = "literal"))]
Literal(String),
}
@@ -510,11 +509,7 @@ pub enum AttributeValue {
/// ^
/// ```
#[derive(Clone, Debug, Eq, PartialEq)]
-#[cfg_attr(
- feature = "serde",
- derive(serde::Serialize, serde::Deserialize),
- serde(tag = "type", rename = "root")
-)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Root {
// Parent.
/// Content model.
@@ -530,11 +525,7 @@ pub struct Root {
/// ^
/// ```
#[derive(Clone, Debug, Eq, PartialEq)]
-#[cfg_attr(
- feature = "serde",
- derive(serde::Serialize, serde::Deserialize),
- serde(tag = "type", rename = "paragraph")
-)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Paragraph {
// Parent.
/// Content model.
@@ -550,11 +541,7 @@ pub struct Paragraph {
/// ^^^
/// ```
#[derive(Clone, Debug, Eq, PartialEq)]
-#[cfg_attr(
- feature = "serde",
- derive(serde::Serialize, serde::Deserialize),
- serde(tag = "type", rename = "heading")
-)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Heading {
// Parent.
/// Content model.
@@ -573,11 +560,7 @@ pub struct Heading {
/// ^^^
/// ```
#[derive(Clone, Debug, Eq, PartialEq)]
-#[cfg_attr(
- feature = "serde",
- derive(serde::Serialize, serde::Deserialize),
- serde(tag = "type", rename = "thematicBreak")
-)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ThematicBreak {
// Void.
/// Positional info.
@@ -591,11 +574,7 @@ pub struct ThematicBreak {
/// ^^^
/// ```
#[derive(Clone, Debug, Eq, PartialEq)]
-#[cfg_attr(
- feature = "serde",
- derive(serde::Serialize, serde::Deserialize),
- serde(tag = "type", rename = "blockquote")
-)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct BlockQuote {
// Parent.
/// Content model.
@@ -611,11 +590,7 @@ pub struct BlockQuote {
/// ^^^
/// ```
#[derive(Clone, Debug, Eq, PartialEq)]
-#[cfg_attr(
- feature = "serde",
- derive(serde::Serialize, serde::Deserialize),
- serde(tag = "type", rename = "list")
-)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct List {
// Parent.
/// Content model.
@@ -640,11 +615,7 @@ pub struct List {
/// ^^^
/// ```
#[derive(Clone, Debug, Eq, PartialEq)]
-#[cfg_attr(
- feature = "serde",
- derive(serde::Serialize, serde::Deserialize),
- serde(tag = "type", rename = "listItem")
-)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ListItem {
// Parent.
/// Content model.
@@ -667,11 +638,7 @@ pub struct ListItem {
/// ^^^
/// ```
#[derive(Clone, Debug, Eq, PartialEq)]
-#[cfg_attr(
- feature = "serde",
- derive(serde::Serialize, serde::Deserialize),
- serde(tag = "type", rename = "html")
-)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Html {
// Text.
/// Content model.
@@ -691,11 +658,7 @@ pub struct Html {
/// ^^^
/// ```
#[derive(Clone, Debug, Eq, PartialEq)]
-#[cfg_attr(
- feature = "serde",
- derive(serde::Serialize, serde::Deserialize),
- serde(tag = "type", rename = "code")
-)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Code {
// Text.
/// Content model.
@@ -720,11 +683,7 @@ pub struct Code {
/// ^^
/// ```
#[derive(Clone, Debug, Eq, PartialEq)]
-#[cfg_attr(
- feature = "serde",
- derive(serde::Serialize, serde::Deserialize),
- serde(tag = "type", rename = "math")
-)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Math {
// Text.
/// Content model.
@@ -743,11 +702,7 @@ pub struct Math {
/// ^^^^^^
/// ```
#[derive(Clone, Debug, Eq, PartialEq)]
-#[cfg_attr(
- feature = "serde",
- derive(serde::Serialize, serde::Deserialize),
- serde(tag = "type", rename = "definition")
-)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Definition {
// Void.
/// Positional info.
@@ -780,11 +735,7 @@ pub struct Definition {
/// ^
/// ```
#[derive(Clone, Debug, Eq, PartialEq)]
-#[cfg_attr(
- feature = "serde",
- derive(serde::Serialize, serde::Deserialize),
- serde(tag = "type", rename = "text")
-)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Text {
// Text.
/// Content model.
@@ -800,11 +751,7 @@ pub struct Text {
/// ^^^
/// ```
#[derive(Clone, Debug, Eq, PartialEq)]
-#[cfg_attr(
- feature = "serde",
- derive(serde::Serialize, serde::Deserialize),
- serde(tag = "type", rename = "emphasis")
-)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Emphasis {
// Parent.
/// Content model.
@@ -820,11 +767,7 @@ pub struct Emphasis {
/// ^^^^^
/// ```
#[derive(Clone, Debug, Eq, PartialEq)]
-#[cfg_attr(
- feature = "serde",
- derive(serde::Serialize, serde::Deserialize),
- serde(tag = "type", rename = "strong")
-)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Strong {
// Parent.
/// Content model.
@@ -840,11 +783,7 @@ pub struct Strong {
/// ^^^
/// ```
#[derive(Clone, Debug, Eq, PartialEq)]
-#[cfg_attr(
- feature = "serde",
- derive(serde::Serialize, serde::Deserialize),
- serde(tag = "type", rename = "inlineCode")
-)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct InlineCode {
// Text.
/// Content model.
@@ -860,11 +799,7 @@ pub struct InlineCode {
/// ^^^
/// ```
#[derive(Clone, Debug, Eq, PartialEq)]
-#[cfg_attr(
- feature = "serde",
- derive(serde::Serialize, serde::Deserialize),
- serde(tag = "type", rename = "inlineMath")
-)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct InlineMath {
// Text.
/// Content model.
@@ -881,11 +816,7 @@ pub struct InlineMath {
/// | b
/// ```
#[derive(Clone, Debug, Eq, PartialEq)]
-#[cfg_attr(
- feature = "serde",
- derive(serde::Serialize, serde::Deserialize),
- serde(tag = "type", rename = "break")
-)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Break {
// Void.
/// Positional info.
@@ -899,11 +830,7 @@ pub struct Break {
/// ^^^^^^
/// ```
#[derive(Clone, Debug, Eq, PartialEq)]
-#[cfg_attr(
- feature = "serde",
- derive(serde::Serialize, serde::Deserialize),
- serde(tag = "type", rename = "link")
-)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Link {
// Parent.
/// Content model.
@@ -925,11 +852,7 @@ pub struct Link {
/// ^^^^^^^
/// ```
#[derive(Clone, Debug, Eq, PartialEq)]
-#[cfg_attr(
- feature = "serde",
- derive(serde::Serialize, serde::Deserialize),
- serde(tag = "type", rename = "image")
-)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Image {
// Void.
/// Positional info.
@@ -953,11 +876,7 @@ pub struct Image {
/// ^^^
/// ```
#[derive(Clone, Debug, Eq, PartialEq)]
-#[cfg_attr(
- feature = "serde",
- derive(serde::Serialize, serde::Deserialize),
- serde(tag = "type", rename = "linkReference")
-)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct LinkReference {
// Parent.
/// Content model.
@@ -990,11 +909,7 @@ pub struct LinkReference {
/// ^^^^
/// ```
#[derive(Clone, Debug, Eq, PartialEq)]
-#[cfg_attr(
- feature = "serde",
- derive(serde::Serialize, serde::Deserialize),
- serde(tag = "type", rename = "imageReference")
-)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ImageReference {
// Void.
/// Positional info.
@@ -1029,11 +944,7 @@ pub struct ImageReference {
/// ^^^^^^^
/// ```
#[derive(Clone, Debug, Eq, PartialEq)]
-#[cfg_attr(
- feature = "serde",
- derive(serde::Serialize, serde::Deserialize),
- serde(tag = "type", rename = "footnoteDefinition")
-)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct FootnoteDefinition {
// Parent.
/// Content model.
@@ -1062,11 +973,7 @@ pub struct FootnoteDefinition {
/// ^^^^
/// ```
#[derive(Clone, Debug, Eq, PartialEq)]
-#[cfg_attr(
- feature = "serde",
- derive(serde::Serialize, serde::Deserialize),
- serde(tag = "type", rename = "footnoteReference")
-)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct FootnoteReference {
// Void.
/// Positional info.
@@ -1095,11 +1002,7 @@ pub struct FootnoteReference {
/// ^^^^^
/// ```
#[derive(Clone, Debug, Eq, PartialEq)]
-#[cfg_attr(
- feature = "serde",
- derive(serde::Serialize, serde::Deserialize),
- serde(tag = "type", rename = "table")
-)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Table {
// Parent.
/// Content model.
@@ -1118,11 +1021,7 @@ pub struct Table {
/// ^^^^^
/// ```
#[derive(Clone, Debug, Eq, PartialEq)]
-#[cfg_attr(
- feature = "serde",
- derive(serde::Serialize, serde::Deserialize),
- serde(tag = "type", rename = "tableRow")
-)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TableRow {
// Parent.
/// Content model.
@@ -1138,11 +1037,7 @@ pub struct TableRow {
/// ^^^^^
/// ```
#[derive(Clone, Debug, Eq, PartialEq)]
-#[cfg_attr(
- feature = "serde",
- derive(serde::Serialize, serde::Deserialize),
- serde(tag = "type", rename = "tableCell")
-)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TableCell {
// Parent.
/// Content model.
@@ -1158,11 +1053,7 @@ pub struct TableCell {
/// ^^^^^
/// ```
#[derive(Clone, Debug, Eq, PartialEq)]
-#[cfg_attr(
- feature = "serde",
- derive(serde::Serialize, serde::Deserialize),
- serde(tag = "type", rename = "delete")
-)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Delete {
// Parent.
/// Content model.
@@ -1182,11 +1073,7 @@ pub struct Delete {
/// ^^^
/// ```
#[derive(Clone, Debug, Eq, PartialEq)]
-#[cfg_attr(
- feature = "serde",
- derive(serde::Serialize, serde::Deserialize),
- serde(tag = "type", rename = "yaml")
-)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Yaml {
// Void.
/// Content model.
@@ -1206,11 +1093,7 @@ pub struct Yaml {
/// ^^^
/// ```
#[derive(Clone, Debug, Eq, PartialEq)]
-#[cfg_attr(
- feature = "serde",
- derive(serde::Serialize, serde::Deserialize),
- serde(tag = "type", rename = "toml")
-)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Toml {
// Void.
/// Content model.
@@ -1226,11 +1109,7 @@ pub struct Toml {
/// ^^^^^^^^^^^^^^^^^
/// ```
#[derive(Clone, Debug, Eq, PartialEq)]
-#[cfg_attr(
- feature = "serde",
- derive(serde::Serialize, serde::Deserialize),
- serde(tag = "type", rename = "mdxjsEsm")
-)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct MdxjsEsm {
// Literal.
/// Content model.
@@ -1249,11 +1128,7 @@ pub struct MdxjsEsm {
/// ^^^
/// ```
#[derive(Clone, Debug, Eq, PartialEq)]
-#[cfg_attr(
- feature = "serde",
- derive(serde::Serialize, serde::Deserialize),
- serde(tag = "type", rename = "mdxFlowExpression")
-)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct MdxFlowExpression {
// Literal.
/// Content model.
@@ -1272,11 +1147,7 @@ pub struct MdxFlowExpression {
/// ^^^
/// ```
#[derive(Clone, Debug, Eq, PartialEq)]
-#[cfg_attr(
- feature = "serde",
- derive(serde::Serialize, serde::Deserialize),
- serde(tag = "type", rename = "mdxTextExpression")
-)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct MdxTextExpression {
// Literal.
/// Content model.
@@ -1298,7 +1169,7 @@ pub struct MdxTextExpression {
#[cfg_attr(
feature = "serde",
derive(serde::Serialize, serde::Deserialize),
- serde(tag = "type", rename = "mdxJsxFlowElement")
+ serde(rename_all = "camelCase")
)]
pub struct MdxJsxFlowElement {
// Parent.
@@ -1325,7 +1196,7 @@ pub struct MdxJsxFlowElement {
#[cfg_attr(
feature = "serde",
derive(serde::Serialize, serde::Deserialize),
- serde(tag = "type", rename = "mdxJsxTextElement")
+ serde(rename_all = "camelCase")
)]
pub struct MdxJsxTextElement {
// Parent.
diff --git a/tests/serde.rs b/tests/serde.rs
new file mode 100644
index 00000000..243a98d3
--- /dev/null
+++ b/tests/serde.rs
@@ -0,0 +1,117 @@
+use markdown::mdast::Node;
+use markdown::message::Message;
+
+#[allow(unused)]
+#[derive(Debug)]
+enum Error {
+ Mdast(Message),
+ Serde(serde_json::Error),
+}
+
+#[cfg_attr(feature = "serde", test)]
+fn serde() -> Result<(), Error> {
+ let source = markdown::to_mdast(
+ r#"
+---
+title: Serde
+---
+
+import Test from 'test';
+import Inner from 'test';
+import {Another, YetAnother} from 'another';
+
+# , {username}!
+
+> Blockquote
+Add test constructs below!
+
+## Test serialization and deserialization of mdast
+
+
+
+ ## Inner
+ [Link](./link.md)
+
+
+
+
+
+{test} this is text expression
+
+
+
+# Text
+
+~~The world is flat.~~ We now know that the world is round.
+
+*Emphasis*
+
+*Strong Emphasis*
+
+$This is math$
+
+Let's break\
+yes!
+
+***
+
+## List
+
+* item1
+* item2
+* item3
+
+## Code block
+
+```shell
+cargo test --features json
+```
+
+## Inline
+
+`Inline code` with backticks
+
+## Image
+
+![Image](http://url/a.png)
+
+## Table
+
+| Syntax | Description |
+|-----------|-------------|
+| Header | Title |
+| Paragraph | Text |
+
+## Task lists
+
+- [x] Write the press release
+- [ ] Update the website
+- [ ] Contact the media
+
+## Footnotes
+
+Here's a simple footnote,[^1] and here's a longer one.[^bignote]
+
+[^1]: This is the first footnote.
+
+[^bignote]: Here's one with multiple paragraphs and code.
+
+ Indent paragraphs to include them in the footnote.
+
+ `{ my code }`
+
+ Add as many paragraphs as you like.
+
+"#,
+ &markdown::ParseOptions::mdx(),
+ )
+ .map_err(Error::Mdast)?;
+
+ let value: String = serde_json::to_string(&source).map_err(Error::Serde)?;
+
+ let target: Node = serde_json::from_slice(value.as_bytes()).map_err(Error::Serde)?;
+
+ pretty_assertions::assert_eq!(source, target);
+
+ Ok(())
+}