use alloc::{string::String, vec::Vec};
use crate::span::Span;
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct NodeMeta {
pub span: Option<Span>,
}
impl NodeMeta {
pub const fn new(span: Option<Span>) -> Self {
Self { span }
}
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct Document {
pub meta: NodeMeta,
pub children: Vec<Block>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Block {
Paragraph(Paragraph),
Heading(Heading),
ThematicBreak(ThematicBreak),
BlockQuote(BlockQuote),
Alert(Alert),
List(List),
CodeBlock(CodeBlock),
HtmlBlock(HtmlBlock),
HtmlContainer(HtmlContainer),
Definition(Definition),
FootnoteDefinition(FootnoteDefinition),
Table(Table),
MathBlock(MathBlock),
Frontmatter(Frontmatter),
LeafDirective(LeafDirective),
ContainerDirective(ContainerDirective),
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Paragraph {
pub meta: NodeMeta,
pub children: Vec<Inline>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Heading {
pub meta: NodeMeta,
pub depth: u8,
pub kind: HeadingKind,
pub children: Vec<Inline>,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum HeadingKind {
Atx,
Setext,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ThematicBreak {
pub meta: NodeMeta,
pub marker: ThematicBreakMarker,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ThematicBreakMarker {
Dash,
Asterisk,
Underscore,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct BlockQuote {
pub meta: NodeMeta,
pub children: Vec<Block>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Alert {
pub meta: NodeMeta,
pub kind: AlertKind,
pub title: Option<String>,
pub children: Vec<Block>,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum AlertKind {
Note,
Tip,
Important,
Warning,
Caution,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct List {
pub meta: NodeMeta,
pub ordered: bool,
pub start: Option<u64>,
pub delimiter: ListDelimiter,
pub tight: bool,
pub children: Vec<ListItem>,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ListDelimiter {
Dash,
Asterisk,
Plus,
Period,
Paren,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ListItem {
pub meta: NodeMeta,
pub checked: Option<bool>,
pub children: Vec<Block>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct CodeBlock {
pub meta: NodeMeta,
pub kind: CodeBlockKind,
pub info: Option<String>,
pub value: String,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum CodeBlockKind {
Fenced {
marker: FenceMarker,
length: usize,
},
Indented,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum FenceMarker {
Backtick,
Tilde,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct HtmlBlock {
pub meta: NodeMeta,
pub value: String,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct HtmlContainer {
pub meta: NodeMeta,
pub opening: HtmlTag,
pub content: HtmlContainerContent,
pub closing: HtmlTag,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct HtmlTag {
pub meta: NodeMeta,
pub name: String,
pub raw: String,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum HtmlContainerContent {
Blocks(Vec<Block>),
Inlines(Vec<Inline>),
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Definition {
pub meta: NodeMeta,
pub label: String,
pub identifier: String,
pub destination: String,
pub destination_kind: LinkDestinationKind,
pub title: Option<Title>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct FootnoteDefinition {
pub meta: NodeMeta,
pub label: String,
pub identifier: String,
pub children: Vec<Block>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Table {
pub meta: NodeMeta,
pub alignments: Vec<TableAlignment>,
pub rows: Vec<TableRow>,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum TableAlignment {
None,
Left,
Center,
Right,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct TableRow {
pub meta: NodeMeta,
pub cells: Vec<TableCell>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct TableCell {
pub meta: NodeMeta,
pub children: Vec<Inline>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct MathBlock {
pub meta: NodeMeta,
pub value: String,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Frontmatter {
pub meta: NodeMeta,
pub kind: FrontmatterKind,
pub value: String,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum FrontmatterKind {
Yaml,
Toml,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct LeafDirective {
pub meta: NodeMeta,
pub name: String,
pub label: Vec<Inline>,
pub attributes: Vec<DirectiveAttribute>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ContainerDirective {
pub meta: NodeMeta,
pub name: String,
pub label: Vec<Inline>,
pub attributes: Vec<DirectiveAttribute>,
pub children: Vec<Block>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Inline {
Text(Text),
Escape(Escape),
CharacterReference(CharacterReference),
Emphasis(Emphasis),
Strong(Strong),
Delete(Delete),
Mark(Mark),
Shortcode(Shortcode),
Code(CodeInline),
Link(Link),
Autolink(Autolink),
Image(Image),
LinkReference(LinkReference),
ImageReference(ImageReference),
Html(HtmlInline),
SoftBreak(SoftBreak),
LineBreak(LineBreak),
Math(MathInline),
FootnoteReference(FootnoteReference),
InlineFootnote(InlineFootnote),
WikiLink(WikiLink),
TextDirective(TextDirective),
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Text {
pub meta: NodeMeta,
pub value: String,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Escape {
pub meta: NodeMeta,
pub value: char,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct CharacterReference {
pub meta: NodeMeta,
pub reference: String,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Emphasis {
pub meta: NodeMeta,
pub delimiter: EmphasisDelimiter,
pub children: Vec<Inline>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Strong {
pub meta: NodeMeta,
pub delimiter: EmphasisDelimiter,
pub children: Vec<Inline>,
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub enum EmphasisDelimiter {
#[default]
Asterisk,
Underscore,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Delete {
pub meta: NodeMeta,
pub children: Vec<Inline>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Mark {
pub meta: NodeMeta,
pub children: Vec<Inline>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Shortcode {
pub meta: NodeMeta,
pub name: String,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct CodeInline {
pub meta: NodeMeta,
pub value: String,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Link {
pub meta: NodeMeta,
pub destination: String,
pub destination_kind: LinkDestinationKind,
pub title: Option<Title>,
pub children: Vec<Inline>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Autolink {
pub meta: NodeMeta,
pub form: AutolinkForm,
pub text: String,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum AutolinkForm {
Angle,
Literal,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Image {
pub meta: NodeMeta,
pub destination: String,
pub destination_kind: LinkDestinationKind,
pub title: Option<Title>,
pub alt: Vec<Inline>,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum LinkDestinationKind {
Bare,
Angle,
Omitted,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum LinkTitleKind {
DoubleQuote,
SingleQuote,
Paren,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Title {
pub value: String,
pub kind: LinkTitleKind,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct LinkReference {
pub meta: NodeMeta,
pub identifier: String,
pub label: String,
pub kind: ReferenceKind,
pub children: Vec<Inline>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ImageReference {
pub meta: NodeMeta,
pub identifier: String,
pub label: String,
pub kind: ReferenceKind,
pub alt: Vec<Inline>,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ReferenceKind {
Full,
Collapsed,
Shortcut,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct HtmlInline {
pub meta: NodeMeta,
pub value: String,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct SoftBreak {
pub meta: NodeMeta,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct LineBreak {
pub meta: NodeMeta,
pub kind: LineBreakKind,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum LineBreakKind {
Backslash,
Spaces,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum MathInlineKind {
Dollar {
dollars: u8,
},
Code,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct MathInline {
pub meta: NodeMeta,
pub value: String,
pub kind: MathInlineKind,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct FootnoteReference {
pub meta: NodeMeta,
pub label: String,
pub identifier: String,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct InlineFootnote {
pub meta: NodeMeta,
pub children: Vec<Inline>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct WikiLink {
pub meta: NodeMeta,
pub target: String,
pub label: String,
pub embed: bool,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct TextDirective {
pub meta: NodeMeta,
pub name: String,
pub label: Vec<Inline>,
pub attributes: Vec<DirectiveAttribute>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct DirectiveAttribute {
pub name: String,
pub value: Option<String>,
}
macro_rules! impl_meta_accessors {
($enum:ident { $($variant:ident),+ $(,)? }) => {
impl $enum {
pub fn meta(&self) -> &NodeMeta {
match self { $( $enum::$variant(node) => &node.meta, )+ }
}
pub fn span(&self) -> Option<Span> {
self.meta().span
}
}
};
}
macro_rules! impl_from_variants {
($enum:ident { $($variant:ident($ty:ty)),+ $(,)? }) => {
$(
impl From<$ty> for $enum {
fn from(node: $ty) -> Self {
$enum::$variant(node)
}
}
)+
};
}
impl_meta_accessors!(Block {
Paragraph,
Heading,
ThematicBreak,
BlockQuote,
Alert,
List,
CodeBlock,
HtmlBlock,
HtmlContainer,
Definition,
FootnoteDefinition,
Table,
MathBlock,
Frontmatter,
LeafDirective,
ContainerDirective,
});
impl_from_variants!(Block {
Paragraph(Paragraph), Heading(Heading), ThematicBreak(ThematicBreak),
BlockQuote(BlockQuote), Alert(Alert), List(List),
CodeBlock(CodeBlock), HtmlBlock(HtmlBlock), Definition(Definition),
HtmlContainer(HtmlContainer),
FootnoteDefinition(FootnoteDefinition), Table(Table), MathBlock(MathBlock),
Frontmatter(Frontmatter), LeafDirective(LeafDirective), ContainerDirective(ContainerDirective),
});
impl_meta_accessors!(Inline {
Text,
Escape,
CharacterReference,
Emphasis,
Strong,
Delete,
Mark,
Shortcode,
Code,
Link,
Autolink,
Image,
LinkReference,
ImageReference,
Html,
SoftBreak,
LineBreak,
Math,
FootnoteReference,
InlineFootnote,
WikiLink,
TextDirective,
});
impl_from_variants!(Inline {
Text(Text), Escape(Escape), CharacterReference(CharacterReference),
Emphasis(Emphasis), Strong(Strong), Delete(Delete), Mark(Mark),
Shortcode(Shortcode), Code(CodeInline), Link(Link), Autolink(Autolink), Image(Image),
LinkReference(LinkReference), ImageReference(ImageReference), Html(HtmlInline),
SoftBreak(SoftBreak), LineBreak(LineBreak), Math(MathInline),
FootnoteReference(FootnoteReference), InlineFootnote(InlineFootnote), WikiLink(WikiLink),
TextDirective(TextDirective),
});
impl Inline {
pub fn children(&self) -> &[Inline] {
match self {
Inline::Emphasis(n) => &n.children,
Inline::Strong(n) => &n.children,
Inline::Delete(n) => &n.children,
Inline::Mark(n) => &n.children,
Inline::Link(n) => &n.children,
Inline::Image(n) => &n.alt,
Inline::LinkReference(n) => &n.children,
Inline::ImageReference(n) => &n.alt,
Inline::InlineFootnote(n) => &n.children,
Inline::TextDirective(n) => &n.label,
_ => &[],
}
}
}
impl CharacterReference {
pub fn new(reference: impl Into<String>) -> Self {
Self {
meta: NodeMeta::default(),
reference: reference.into(),
}
}
pub fn value(&self) -> Option<String> {
crate::decode::decode_character_reference(&self.reference)
}
}
impl Autolink {
pub fn new(form: AutolinkForm, text: impl Into<String>) -> Self {
Self {
meta: NodeMeta::default(),
form,
text: text.into(),
}
}
pub fn destination(&self) -> Option<String> {
match self.form {
AutolinkForm::Angle => crate::parse::angle_autolink_destination(&self.text),
AutolinkForm::Literal => crate::parse::literal_autolink_destination(&self.text),
}
}
}
impl Title {
pub fn new(value: impl Into<String>, kind: LinkTitleKind) -> Self {
Self {
value: value.into(),
kind,
}
}
}
impl Shortcode {
pub fn glyph(&self) -> Option<&'static str> {
crate::gemoji::glyph(&self.name)
}
}
impl WikiLink {
pub fn decoded_target(&self) -> String {
crate::decode::decode_escapes_and_references(&self.target)
}
pub fn decoded_label(&self) -> String {
crate::decode::decode_escapes_and_references(&self.label)
}
}
impl Text {
pub fn new(value: impl Into<String>) -> Self {
Self {
meta: NodeMeta::default(),
value: value.into(),
}
}
}
impl From<&str> for Text {
fn from(value: &str) -> Self {
Text::new(value)
}
}
impl From<String> for Text {
fn from(value: String) -> Self {
Text::new(value)
}
}
impl Paragraph {
pub fn new<I, T>(children: I) -> Self
where
I: IntoIterator<Item = T>,
T: Into<Inline>,
{
Self {
meta: NodeMeta::default(),
children: children.into_iter().map(Into::into).collect(),
}
}
}
impl Heading {
pub fn new<I, T>(depth: u8, children: I) -> Self
where
I: IntoIterator<Item = T>,
T: Into<Inline>,
{
Self {
meta: NodeMeta::default(),
depth,
kind: HeadingKind::Atx,
children: children.into_iter().map(Into::into).collect(),
}
}
}
impl Link {
pub fn new<I, T>(destination: impl Into<String>, children: I) -> Self
where
I: IntoIterator<Item = T>,
T: Into<Inline>,
{
Self {
meta: NodeMeta::default(),
destination: destination.into(),
destination_kind: LinkDestinationKind::Bare,
title: None,
children: children.into_iter().map(Into::into).collect(),
}
}
}
impl CodeInline {
pub fn new(value: impl Into<String>) -> Self {
Self {
meta: NodeMeta::default(),
value: value.into(),
}
}
}
impl List {
pub fn new<I>(children: I) -> Self
where
I: IntoIterator<Item = ListItem>,
{
Self {
meta: NodeMeta::default(),
ordered: false,
start: None,
delimiter: ListDelimiter::Dash,
tight: true,
children: children.into_iter().collect(),
}
}
}