//! markdown syntax tree: [mdast][]. //! //! [mdast]: https://github.com/syntax-tree/mdast use crate::unist::Position; use alloc::{ fmt, string::{String, ToString}, vec::Vec, }; /// Relative byte index into a string, to an absolute byte index into the /// whole document. pub type Stop = (usize, usize); /// Explicitness of a reference. #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum ReferenceKind { /// The reference is implicit, its identifier inferred from its content. Shortcut, /// The reference is explicit, its identifier inferred from its content. Collapsed, /// The reference is explicit, its identifier explicitly set. Full, } /// Represents how phrasing content is aligned. #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum AlignKind { /// Left alignment. /// /// See the `left` value of the `text-align` CSS property. /// /// ```markdown /// | | aaa | /// > | | :-- | /// ^^^ /// ``` Left, /// Right alignment. /// /// See the `right` value of the `text-align` CSS property. /// /// ```markdown /// | | aaa | /// > | | --: | /// ^^^ /// ``` Right, /// Center alignment. /// /// See the `center` value of the `text-align` CSS property. /// /// ```markdown /// | | aaa | /// > | | :-: | /// ^^^ /// ``` Center, /// No alignment. /// /// Phrasing content is aligned as defined by the host environment. /// /// ```markdown /// | | aaa | /// > | | --- | /// ^^^ /// ``` None, } /// Nodes. #[derive(Clone, Eq, PartialEq)] pub enum Node { // Document: /// Root. Root(Root), // Container: /// Block quote. BlockQuote(BlockQuote), /// Footnote definition. FootnoteDefinition(FootnoteDefinition), /// MDX: JSX element (container). MdxJsxFlowElement(MdxJsxFlowElement), /// List. List(List), // Frontmatter: /// MDX.js ESM. MdxjsEsm(MdxjsEsm), /// Toml. Toml(Toml), /// Yaml. Yaml(Yaml), // Phrasing: /// Break. Break(Break), /// Code (phrasing). InlineCode(InlineCode), /// Math (phrasing). InlineMath(InlineMath), /// Delete. Delete(Delete), /// Emphasis. Emphasis(Emphasis), // MDX: expression (text). MdxTextExpression(MdxTextExpression), /// Footnote reference. FootnoteReference(FootnoteReference), /// Html (phrasing). Html(Html), /// Image. Image(Image), /// Image reference. ImageReference(ImageReference), // MDX: JSX element (text). MdxJsxTextElement(MdxJsxTextElement), /// Link. Link(Link), /// Link reference. LinkReference(LinkReference), /// Strong Strong(Strong), /// Text. Text(Text), // Flow: /// Code (flow). Code(Code), /// Math (flow). Math(Math), // MDX: expression (flow). MdxFlowExpression(MdxFlowExpression), /// Heading. Heading(Heading), /// Html (flow). // Html(Html), /// Table. Table(Table), /// Thematic break. ThematicBreak(ThematicBreak), // Table content. /// Table row. TableRow(TableRow), // Row content. /// Table cell. TableCell(TableCell), // List content. /// List item. ListItem(ListItem), // Content. /// Definition. Definition(Definition), /// Paragraph. Paragraph(Paragraph), } impl fmt::Debug for Node { // Debug the wrapped struct. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Node::Root(x) => write!(f, "{:?}", x), Node::BlockQuote(x) => write!(f, "{:?}", x), Node::FootnoteDefinition(x) => write!(f, "{:?}", x), Node::MdxJsxFlowElement(x) => write!(f, "{:?}", x), Node::List(x) => write!(f, "{:?}", x), Node::MdxjsEsm(x) => write!(f, "{:?}", x), Node::Toml(x) => write!(f, "{:?}", x), Node::Yaml(x) => write!(f, "{:?}", x), Node::Break(x) => write!(f, "{:?}", x), Node::InlineCode(x) => write!(f, "{:?}", x), Node::InlineMath(x) => write!(f, "{:?}", x), Node::Delete(x) => write!(f, "{:?}", x), Node::Emphasis(x) => write!(f, "{:?}", x), Node::MdxTextExpression(x) => write!(f, "{:?}", x), Node::FootnoteReference(x) => write!(f, "{:?}", x), Node::Html(x) => write!(f, "{:?}", x), Node::Image(x) => write!(f, "{:?}", x), Node::ImageReference(x) => write!(f, "{:?}", x), Node::MdxJsxTextElement(x) => write!(f, "{:?}", x), Node::Link(x) => write!(f, "{:?}", x), Node::LinkReference(x) => write!(f, "{:?}", x), Node::Strong(x) => write!(f, "{:?}", x), Node::Text(x) => write!(f, "{:?}", x), Node::Code(x) => write!(f, "{:?}", x), Node::Math(x) => write!(f, "{:?}", x), Node::MdxFlowExpression(x) => write!(f, "{:?}", x), Node::Heading(x) => write!(f, "{:?}", x), Node::Table(x) => write!(f, "{:?}", x), Node::ThematicBreak(x) => write!(f, "{:?}", x), Node::TableRow(x) => write!(f, "{:?}", x), Node::TableCell(x) => write!(f, "{:?}", x), Node::ListItem(x) => write!(f, "{:?}", x), Node::Definition(x) => write!(f, "{:?}", x), Node::Paragraph(x) => write!(f, "{:?}", x), } } } fn children_to_string(children: &[Node]) -> String { children.iter().map(ToString::to_string).collect() } impl ToString for Node { fn to_string(&self) -> String { match self { // Parents. Node::Root(x) => children_to_string(&x.children), Node::BlockQuote(x) => children_to_string(&x.children), Node::FootnoteDefinition(x) => children_to_string(&x.children), Node::MdxJsxFlowElement(x) => children_to_string(&x.children), Node::List(x) => children_to_string(&x.children), Node::Delete(x) => children_to_string(&x.children), Node::Emphasis(x) => children_to_string(&x.children), Node::MdxJsxTextElement(x) => children_to_string(&x.children), Node::Link(x) => children_to_string(&x.children), Node::LinkReference(x) => children_to_string(&x.children), Node::Strong(x) => children_to_string(&x.children), Node::Heading(x) => children_to_string(&x.children), Node::Table(x) => children_to_string(&x.children), Node::TableRow(x) => children_to_string(&x.children), Node::TableCell(x) => children_to_string(&x.children), Node::ListItem(x) => children_to_string(&x.children), Node::Paragraph(x) => children_to_string(&x.children), // Literals. Node::MdxjsEsm(x) => x.value.clone(), Node::Toml(x) => x.value.clone(), Node::Yaml(x) => x.value.clone(), Node::InlineCode(x) => x.value.clone(), Node::InlineMath(x) => x.value.clone(), Node::MdxTextExpression(x) => x.value.clone(), Node::Html(x) => x.value.clone(), Node::Text(x) => x.value.clone(), Node::Code(x) => x.value.clone(), Node::Math(x) => x.value.clone(), Node::MdxFlowExpression(x) => x.value.clone(), // Voids. Node::Break(_) | Node::FootnoteReference(_) | Node::Image(_) | Node::ImageReference(_) | Node::ThematicBreak(_) | Node::Definition(_) => "".to_string(), } } } impl Node { #[must_use] pub fn children(&self) -> Option<&Vec> { match self { // Parent. Node::Root(x) => Some(&x.children), Node::Paragraph(x) => Some(&x.children), Node::Heading(x) => Some(&x.children), Node::BlockQuote(x) => Some(&x.children), Node::List(x) => Some(&x.children), Node::ListItem(x) => Some(&x.children), Node::Emphasis(x) => Some(&x.children), Node::Strong(x) => Some(&x.children), Node::Link(x) => Some(&x.children), Node::LinkReference(x) => Some(&x.children), Node::FootnoteDefinition(x) => Some(&x.children), Node::Table(x) => Some(&x.children), Node::TableRow(x) => Some(&x.children), Node::TableCell(x) => Some(&x.children), Node::Delete(x) => Some(&x.children), Node::MdxJsxFlowElement(x) => Some(&x.children), Node::MdxJsxTextElement(x) => Some(&x.children), // Non-parent. _ => None, } } pub fn children_mut(&mut self) -> Option<&mut Vec> { match self { // Parent. Node::Root(x) => Some(&mut x.children), Node::Paragraph(x) => Some(&mut x.children), Node::Heading(x) => Some(&mut x.children), Node::BlockQuote(x) => Some(&mut x.children), Node::List(x) => Some(&mut x.children), Node::ListItem(x) => Some(&mut x.children), Node::Emphasis(x) => Some(&mut x.children), Node::Strong(x) => Some(&mut x.children), Node::Link(x) => Some(&mut x.children), Node::LinkReference(x) => Some(&mut x.children), Node::FootnoteDefinition(x) => Some(&mut x.children), Node::Table(x) => Some(&mut x.children), Node::TableRow(x) => Some(&mut x.children), Node::TableCell(x) => Some(&mut x.children), Node::Delete(x) => Some(&mut x.children), Node::MdxJsxFlowElement(x) => Some(&mut x.children), Node::MdxJsxTextElement(x) => Some(&mut x.children), // Non-parent. _ => None, } } #[must_use] pub fn position(&self) -> Option<&Position> { match self { Node::Root(x) => x.position.as_ref(), Node::BlockQuote(x) => x.position.as_ref(), Node::FootnoteDefinition(x) => x.position.as_ref(), Node::MdxJsxFlowElement(x) => x.position.as_ref(), Node::List(x) => x.position.as_ref(), Node::MdxjsEsm(x) => x.position.as_ref(), Node::Toml(x) => x.position.as_ref(), Node::Yaml(x) => x.position.as_ref(), Node::Break(x) => x.position.as_ref(), Node::InlineCode(x) => x.position.as_ref(), Node::InlineMath(x) => x.position.as_ref(), Node::Delete(x) => x.position.as_ref(), Node::Emphasis(x) => x.position.as_ref(), Node::MdxTextExpression(x) => x.position.as_ref(), Node::FootnoteReference(x) => x.position.as_ref(), Node::Html(x) => x.position.as_ref(), Node::Image(x) => x.position.as_ref(), Node::ImageReference(x) => x.position.as_ref(), Node::MdxJsxTextElement(x) => x.position.as_ref(), Node::Link(x) => x.position.as_ref(), Node::LinkReference(x) => x.position.as_ref(), Node::Strong(x) => x.position.as_ref(), Node::Text(x) => x.position.as_ref(), Node::Code(x) => x.position.as_ref(), Node::Math(x) => x.position.as_ref(), Node::MdxFlowExpression(x) => x.position.as_ref(), Node::Heading(x) => x.position.as_ref(), Node::Table(x) => x.position.as_ref(), Node::ThematicBreak(x) => x.position.as_ref(), Node::TableRow(x) => x.position.as_ref(), Node::TableCell(x) => x.position.as_ref(), Node::ListItem(x) => x.position.as_ref(), Node::Definition(x) => x.position.as_ref(), Node::Paragraph(x) => x.position.as_ref(), } } pub fn position_mut(&mut self) -> Option<&mut Position> { match self { Node::Root(x) => x.position.as_mut(), Node::BlockQuote(x) => x.position.as_mut(), Node::FootnoteDefinition(x) => x.position.as_mut(), Node::MdxJsxFlowElement(x) => x.position.as_mut(), Node::List(x) => x.position.as_mut(), Node::MdxjsEsm(x) => x.position.as_mut(), Node::Toml(x) => x.position.as_mut(), Node::Yaml(x) => x.position.as_mut(), Node::Break(x) => x.position.as_mut(), Node::InlineCode(x) => x.position.as_mut(), Node::InlineMath(x) => x.position.as_mut(), Node::Delete(x) => x.position.as_mut(), Node::Emphasis(x) => x.position.as_mut(), Node::MdxTextExpression(x) => x.position.as_mut(), Node::FootnoteReference(x) => x.position.as_mut(), Node::Html(x) => x.position.as_mut(), Node::Image(x) => x.position.as_mut(), Node::ImageReference(x) => x.position.as_mut(), Node::MdxJsxTextElement(x) => x.position.as_mut(), Node::Link(x) => x.position.as_mut(), Node::LinkReference(x) => x.position.as_mut(), Node::Strong(x) => x.position.as_mut(), Node::Text(x) => x.position.as_mut(), Node::Code(x) => x.position.as_mut(), Node::Math(x) => x.position.as_mut(), Node::MdxFlowExpression(x) => x.position.as_mut(), Node::Heading(x) => x.position.as_mut(), Node::Table(x) => x.position.as_mut(), Node::ThematicBreak(x) => x.position.as_mut(), Node::TableRow(x) => x.position.as_mut(), Node::TableCell(x) => x.position.as_mut(), Node::ListItem(x) => x.position.as_mut(), Node::Definition(x) => x.position.as_mut(), Node::Paragraph(x) => x.position.as_mut(), } } pub fn position_set(&mut self, position: Option) { match self { Node::Root(x) => x.position = position, Node::BlockQuote(x) => x.position = position, Node::FootnoteDefinition(x) => x.position = position, Node::MdxJsxFlowElement(x) => x.position = position, Node::List(x) => x.position = position, Node::MdxjsEsm(x) => x.position = position, Node::Toml(x) => x.position = position, Node::Yaml(x) => x.position = position, Node::Break(x) => x.position = position, Node::InlineCode(x) => x.position = position, Node::InlineMath(x) => x.position = position, Node::Delete(x) => x.position = position, Node::Emphasis(x) => x.position = position, Node::MdxTextExpression(x) => x.position = position, Node::FootnoteReference(x) => x.position = position, Node::Html(x) => x.position = position, Node::Image(x) => x.position = position, Node::ImageReference(x) => x.position = position, Node::MdxJsxTextElement(x) => x.position = position, Node::Link(x) => x.position = position, Node::LinkReference(x) => x.position = position, Node::Strong(x) => x.position = position, Node::Text(x) => x.position = position, Node::Code(x) => x.position = position, Node::Math(x) => x.position = position, Node::MdxFlowExpression(x) => x.position = position, Node::Heading(x) => x.position = position, Node::Table(x) => x.position = position, Node::ThematicBreak(x) => x.position = position, Node::TableRow(x) => x.position = position, Node::TableCell(x) => x.position = position, Node::ListItem(x) => x.position = position, Node::Definition(x) => x.position = position, Node::Paragraph(x) => x.position = position, } } } /// MDX: attribute content. #[derive(Clone, Debug, Eq, PartialEq)] pub enum AttributeContent { /// JSX expression. /// /// ```markdown /// > | /// ^^^^^^ /// ``` Expression(String, Vec), /// JSX property. /// /// ```markdown /// > | /// ^ /// ``` Property(MdxJsxAttribute), } /// MDX: attribute value. #[derive(Clone, Debug, Eq, PartialEq)] pub enum AttributeValue { /// Expression value. /// /// ```markdown /// > | /// ^^^ /// ``` Expression(String, Vec), /// Static value. /// /// ```markdown /// > | /// ^^^ /// ``` Literal(String), } /// Document. /// /// ```markdown /// > | a /// ^ /// ``` #[derive(Clone, Debug, Eq, PartialEq)] pub struct Root { // Parent. /// Content model. pub children: Vec, /// Positional info. pub position: Option, } /// Paragraph. /// /// ```markdown /// > | a /// ^ /// ``` #[derive(Clone, Debug, Eq, PartialEq)] pub struct Paragraph { // Parent. /// Content model. pub children: Vec, /// Positional info. pub position: Option, } /// Heading. /// /// ```markdown /// > | # a /// ^^^ /// ``` #[derive(Clone, Debug, Eq, PartialEq)] pub struct Heading { // Parent. /// Content model. pub children: Vec, /// Positional info. pub position: Option, // Extra. /// Rank (between `1` and `6`, both including). pub depth: u8, } /// Thematic break. /// /// ```markdown /// > | *** /// ^^^ /// ``` #[derive(Clone, Debug, Eq, PartialEq)] pub struct ThematicBreak { // Void. /// Positional info. pub position: Option, } /// Block quote. /// /// ```markdown /// > | > a /// ^^^ /// ``` #[derive(Clone, Debug, Eq, PartialEq)] pub struct BlockQuote { // Parent. /// Content model. pub children: Vec, /// Positional info. pub position: Option, } /// List. /// /// ```markdown /// > | * a /// ^^^ /// ``` #[derive(Clone, Debug, Eq, PartialEq)] pub struct List { // Parent. /// Content model. pub children: Vec, /// Positional info. pub position: Option, // Extra. /// Ordered (`true`) or unordered (`false`). pub ordered: bool, /// Starting number of the list. /// `None` when unordered. pub start: Option, /// One or more of its children are separated with a blank line from its /// siblings (when `true`), or not (when `false`). pub spread: bool, } /// List item. /// /// ```markdown /// > | * a /// ^^^ /// ``` #[derive(Clone, Debug, Eq, PartialEq)] pub struct ListItem { // Parent. /// Content model. pub children: Vec, /// Positional info. pub position: Option, // Extra. /// The item contains two or more children separated by a blank line /// (when `true`), or not (when `false`). pub spread: bool, /// GFM: whether the item is done (when `true`), not done (when `false`), /// or indeterminate or not applicable (`None`). pub checked: Option, } /// Html (flow or phrasing). /// /// ```markdown /// > | /// ^^^ /// ``` #[derive(Clone, Debug, Eq, PartialEq)] pub struct Html { // Text. /// Content model. pub value: String, /// Positional info. pub position: Option, } /// Code (flow). /// /// ```markdown /// > | ~~~ /// ^^^ /// > | a /// ^ /// > | ~~~ /// ^^^ /// ``` #[derive(Clone, Debug, Eq, PartialEq)] pub struct Code { // Text. /// Content model. pub value: String, /// Positional info. pub position: Option, // Extra. /// The language of computer code being marked up. pub lang: Option, /// Custom info relating to the node. pub meta: Option, } /// Math (flow). /// /// ```markdown /// > | $$ /// ^^ /// > | a /// ^ /// > | $$ /// ^^ /// ``` #[derive(Clone, Debug, Eq, PartialEq)] pub struct Math { // Text. /// Content model. pub value: String, /// Positional info. pub position: Option, // Extra. /// Custom info relating to the node. pub meta: Option, } /// Definition. /// /// ```markdown /// > | [a]: b /// ^^^^^^ /// ``` #[derive(Clone, Debug, Eq, PartialEq)] pub struct Definition { // Void. /// Positional info. pub position: Option, // Resource. /// URL to the referenced resource. pub url: String, /// Advisory info for the resource, such as something that would be /// appropriate for a tooltip. pub title: Option, // Association. /// Value that can match another node. /// `identifier` is a source value: character escapes and character references /// are *not* parsed. /// Its value must be normalized. pub identifier: String, /// `label` is a string value: it works just like `title` on a link or a /// `lang` on code: character escapes and character references are parsed. /// /// To normalize a value, collapse markdown whitespace (`[\t\n\r ]+`) to a /// space, trim the optional initial and/or final space, and perform /// case-folding. pub label: Option, } /// Text. /// /// ```markdown /// > | a /// ^ /// ``` #[derive(Clone, Debug, Eq, PartialEq)] pub struct Text { // Text. /// Content model. pub value: String, /// Positional info. pub position: Option, } /// Emphasis. /// /// ```markdown /// > | *a* /// ^^^ /// ``` #[derive(Clone, Debug, Eq, PartialEq)] pub struct Emphasis { // Parent. /// Content model. pub children: Vec, /// Positional info. pub position: Option, } /// Strong. /// /// ```markdown /// > | **a** /// ^^^^^ /// ``` #[derive(Clone, Debug, Eq, PartialEq)] pub struct Strong { // Parent. /// Content model. pub children: Vec, /// Positional info. pub position: Option, } /// Code (phrasing). /// /// ```markdown /// > | `a` /// ^^^ /// ``` #[derive(Clone, Debug, Eq, PartialEq)] pub struct InlineCode { // Text. /// Content model. pub value: String, /// Positional info. pub position: Option, } /// Math (phrasing). /// /// ```markdown /// > | $a$ /// ^^^ /// ``` #[derive(Clone, Debug, Eq, PartialEq)] pub struct InlineMath { // Text. /// Content model. pub value: String, /// Positional info. pub position: Option, } /// Break. /// /// ```markdown /// > | a\ /// ^ /// | b /// ``` #[derive(Clone, Debug, Eq, PartialEq)] pub struct Break { // Void. /// Positional info. pub position: Option, } /// Link. /// /// ```markdown /// > | [a](b) /// ^^^^^^ /// ``` #[derive(Clone, Debug, Eq, PartialEq)] pub struct Link { // Parent. /// Content model. pub children: Vec, /// Positional info. pub position: Option, // Resource. /// URL to the referenced resource. pub url: String, /// Advisory info for the resource, such as something that would be /// appropriate for a tooltip. pub title: Option, } /// Image. /// /// ```markdown /// > | ![a](b) /// ^^^^^^^ /// ``` #[derive(Clone, Debug, Eq, PartialEq)] pub struct Image { // Void. /// Positional info. pub position: Option, // Alternative. /// Equivalent content for environments that cannot represent the node as /// intended. pub alt: String, // Resource. /// URL to the referenced resource. pub url: String, /// Advisory info for the resource, such as something that would be /// appropriate for a tooltip. pub title: Option, } /// Link reference. /// /// ```markdown /// > | [a] /// ^^^ /// ``` #[derive(Clone, Debug, Eq, PartialEq)] pub struct LinkReference { // Parent. /// Content model. pub children: Vec, /// Positional info. pub position: Option, // Reference. /// Explicitness of a reference. pub reference_kind: ReferenceKind, // Association. /// Value that can match another node. /// `identifier` is a source value: character escapes and character references /// are *not* parsed. /// Its value must be normalized. pub identifier: String, /// `label` is a string value: it works just like `title` on a link or a /// `lang` on code: character escapes and character references are parsed. /// /// To normalize a value, collapse markdown whitespace (`[\t\n\r ]+`) to a /// space, trim the optional initial and/or final space, and perform /// case-folding. pub label: Option, } /// Image reference. /// /// ```markdown /// > | ![a] /// ^^^^ /// ``` #[derive(Clone, Debug, Eq, PartialEq)] pub struct ImageReference { // Void. /// Positional info. pub position: Option, // Alternative. /// Equivalent content for environments that cannot represent the node as /// intended. pub alt: String, // Reference. /// Explicitness of a reference. pub reference_kind: ReferenceKind, // Association. /// Value that can match another node. /// `identifier` is a source value: character escapes and character references /// are *not* parsed. /// Its value must be normalized. pub identifier: String, /// `label` is a string value: it works just like `title` on a link or a /// `lang` on code: character escapes and character references are parsed. /// /// To normalize a value, collapse markdown whitespace (`[\t\n\r ]+`) to a /// space, trim the optional initial and/or final space, and perform /// case-folding. pub label: Option, } /// Footnote definition (GFM). /// /// ```markdown /// > | [^a]: b /// ^^^^^^^ /// ``` #[derive(Clone, Debug, Eq, PartialEq)] pub struct FootnoteDefinition { // Parent. /// Content model. pub children: Vec, /// Positional info. pub position: Option, // Association. /// Value that can match another node. /// `identifier` is a source value: character escapes and character references /// are *not* parsed. /// Its value must be normalized. pub identifier: String, /// `label` is a string value: it works just like `title` on a link or a /// `lang` on code: character escapes and character references are parsed. /// /// To normalize a value, collapse markdown whitespace (`[\t\n\r ]+`) to a /// space, trim the optional initial and/or final space, and perform /// case-folding. pub label: Option, } /// Footnote reference (GFM). /// /// ```markdown /// > | [^a] /// ^^^^ /// ``` #[derive(Clone, Debug, Eq, PartialEq)] pub struct FootnoteReference { // Void. /// Positional info. pub position: Option, // Association. /// Value that can match another node. /// `identifier` is a source value: character escapes and character references /// are *not* parsed. /// Its value must be normalized. pub identifier: String, /// `label` is a string value: it works just like `title` on a link or a /// `lang` on code: character escapes and character references are parsed. /// /// To normalize a value, collapse markdown whitespace (`[\t\n\r ]+`) to a /// space, trim the optional initial and/or final space, and perform /// case-folding. pub label: Option, } /// Table (GFM). /// /// ```markdown /// > | | a | /// ^^^^^ /// > | | - | /// ^^^^^ /// ``` #[derive(Clone, Debug, Eq, PartialEq)] pub struct Table { // Parent. /// Content model. pub children: Vec, /// Positional info. pub position: Option, // Extra. /// Represents how cells in columns are aligned. pub align: Vec, } /// Table row (GFM). /// /// ```markdown /// > | | a | /// ^^^^^ /// ``` #[derive(Clone, Debug, Eq, PartialEq)] pub struct TableRow { // Parent. /// Content model. pub children: Vec, /// Positional info. pub position: Option, } /// Table cell (GFM). /// /// ```markdown /// > | | a | /// ^^^^^ /// ``` #[derive(Clone, Debug, Eq, PartialEq)] pub struct TableCell { // Parent. /// Content model. pub children: Vec, /// Positional info. pub position: Option, } /// Delete (GFM). /// /// ```markdown /// > | ~~a~~ /// ^^^^^ /// ``` #[derive(Clone, Debug, Eq, PartialEq)] pub struct Delete { // Parent. /// Content model. pub children: Vec, /// Positional info. pub position: Option, } /// Yaml (frontmatter). /// /// ```markdown /// > | --- /// ^^^ /// > | a: b /// ^^^^ /// > | --- /// ^^^ /// ``` #[derive(Clone, Debug, Eq, PartialEq)] pub struct Yaml { // Void. /// Content model. pub value: String, /// Positional info. pub position: Option, } /// Toml (frontmatter). /// /// ```markdown /// > | +++ /// ^^^ /// > | a: b /// ^^^^ /// > | +++ /// ^^^ /// ``` #[derive(Clone, Debug, Eq, PartialEq)] pub struct Toml { // Void. /// Content model. pub value: String, /// Positional info. pub position: Option, } /// MDX: ESM. /// /// ```markdown /// > | import a from 'b' /// ^^^^^^^^^^^^^^^^^ /// ``` #[derive(Clone, Debug, Eq, PartialEq)] pub struct MdxjsEsm { // Literal. /// Content model. pub value: String, /// Positional info. pub position: Option, // Custom data on where each slice of `value` came from. pub stops: Vec, } /// MDX: expression (flow). /// /// ```markdown /// > | {a} /// ^^^ /// ``` #[derive(Clone, Debug, Eq, PartialEq)] pub struct MdxFlowExpression { // Literal. /// Content model. pub value: String, /// Positional info. pub position: Option, // Custom data on where each slice of `value` came from. pub stops: Vec, } /// MDX: expression (text). /// /// ```markdown /// > | a {b} /// ^^^ /// ``` #[derive(Clone, Debug, Eq, PartialEq)] pub struct MdxTextExpression { // Literal. /// Content model. pub value: String, /// Positional info. pub position: Option, // Custom data on where each slice of `value` came from. pub stops: Vec, } /// MDX: JSX element (container). /// /// ```markdown /// > | /// ^^^^^ /// ``` #[derive(Clone, Debug, Eq, PartialEq)] pub struct MdxJsxFlowElement { // Parent. /// Content model. pub children: Vec, /// Positional info. pub position: Option, // JSX element. /// Name. /// /// Fragments have no name. pub name: Option, /// Attributes. pub attributes: Vec, } /// MDX: JSX element (text). /// /// ```markdown /// > | . /// ^^^^^ /// ``` #[derive(Clone, Debug, Eq, PartialEq)] pub struct MdxJsxTextElement { // Parent. /// Content model. pub children: Vec, /// Positional info. pub position: Option, // JSX element. /// Name. /// /// Fragments have no name. pub name: Option, /// Attributes. pub attributes: Vec, } /// MDX: JSX attribute. /// /// ```markdown /// > | /// ^ /// ``` #[derive(Clone, Debug, Eq, PartialEq)] pub struct MdxJsxAttribute { // Void. /// Positional info. // pub position: Option, /// Key. pub name: String, /// Value. pub value: Option, } #[cfg(test)] mod tests { use super::*; use crate::unist::{Point, Position}; use alloc::{string::ToString, vec}; #[test] fn test() { let text = Text { value: "a".to_string(), position: Some(Position { start: Point { line: 1, column: 1, offset: 0, }, end: Point { line: 1, column: 2, offset: 1, }, }), }; let paragraph = Paragraph { children: vec![Node::Text(text)], position: Some(Position { start: Point { line: 1, column: 1, offset: 0, }, end: Point { line: 1, column: 2, offset: 1, }, }), }; assert_eq!(paragraph.children.len(), 1); assert!(matches!(¶graph.children[0], Node::Text(_))); } }