Skip to main content

core_markdown/
mdast.rs

1// Released under the MIT License.
2// Copyright, 2022, by Bernhard Berger.
3// Copyright, 2022-2025, by Titus Wormer.
4// Copyright, 2023, by Kyle McCarthy.
5// Copyright, 2023, by Mia.
6// Copyright, 2023, by Rafael Bachmann.
7// Copyright, 2024, by Harsha Teja Kanna.
8// Copyright, 2026, by Samuel Williams.
9
10//! markdown syntax tree: [mdast][].
11//!
12//! [mdast]: https://github.com/syntax-tree/mdast
13use crate::unist::Position;
14use alloc::{
15    fmt,
16    string::{String, ToString},
17    vec::Vec,
18};
19
20mod headings;
21pub use headings::{HeadingEntry, HeadingOptions, Headings};
22mod code;
23pub use code::Code;
24mod code_fence;
25pub use code_fence::CodeFence;
26mod frontmatter;
27pub use frontmatter::Frontmatter;
28
29/// MDX: relative byte index into a string, to an absolute byte index into the
30/// whole document.
31pub type Stop = (usize, usize);
32
33/// Explicitness of a reference.
34#[derive(Clone, Copy, Debug, Eq, PartialEq)]
35#[cfg_attr(
36    feature = "serde",
37    derive(serde::Serialize, serde::Deserialize),
38    serde(rename_all = "lowercase")
39)]
40pub enum ReferenceKind {
41    /// The reference is implicit, its identifier inferred from its content.
42    Shortcut,
43    /// The reference is explicit, its identifier inferred from its content.
44    Collapsed,
45    /// The reference is explicit, its identifier explicitly set.
46    Full,
47}
48
49/// GFM: alignment of phrasing content.
50///
51/// Used to align the contents of table cells within a table.
52#[derive(Clone, Copy, Debug, Eq, PartialEq)]
53pub enum AlignKind {
54    /// Left alignment.
55    ///
56    /// See the `left` value of the `text-align` CSS property.
57    ///
58    /// ```markdown
59    ///   | | aaa |
60    /// > | | :-- |
61    ///       ^^^
62    /// ```
63    Left,
64    /// Right alignment.
65    ///
66    /// See the `right` value of the `text-align` CSS property.
67    ///
68    /// ```markdown
69    ///   | | aaa |
70    /// > | | --: |
71    ///       ^^^
72    /// ```
73    Right,
74    /// Center alignment.
75    ///
76    /// See the `center` value of the `text-align` CSS property.
77    ///
78    /// ```markdown
79    ///   | | aaa |
80    /// > | | :-: |
81    ///       ^^^
82    /// ```
83    Center,
84    /// No alignment.
85    ///
86    /// Phrasing content is aligned as defined by the host environment.
87    ///
88    /// ```markdown
89    ///   | | aaa |
90    /// > | | --- |
91    ///       ^^^
92    /// ```
93    None,
94}
95
96/// Implement serde according to <https://github.com/syntax-tree/mdast#aligntype>
97#[cfg(feature = "serde")]
98impl serde::ser::Serialize for AlignKind {
99    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
100    where
101        S: serde::ser::Serializer,
102    {
103        match self {
104            AlignKind::Left => serializer.serialize_unit_variant("AlignKind", 0, "left"),
105            AlignKind::Right => serializer.serialize_unit_variant("AlignKind", 1, "right"),
106            AlignKind::Center => serializer.serialize_unit_variant("AlignKind", 2, "center"),
107            AlignKind::None => serializer.serialize_none(),
108        }
109    }
110}
111
112#[cfg(feature = "serde")]
113struct AlignKindVisitor;
114
115#[cfg(feature = "serde")]
116impl serde::de::Visitor<'_> for AlignKindVisitor {
117    type Value = AlignKind;
118
119    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
120        formatter.write_str("'left', 'right', 'center' or null")
121    }
122
123    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
124    where
125        E: serde::de::Error,
126    {
127        match v {
128            "left" => Ok(AlignKind::Left),
129            "right" => Ok(AlignKind::Right),
130            "center" => Ok(AlignKind::Center),
131            &_ => Err(serde::de::Error::invalid_type(
132                serde::de::Unexpected::Str(v),
133                &self,
134            )),
135        }
136    }
137
138    fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
139    where
140        E: serde::de::Error,
141    {
142        match v {
143            b"left" => Ok(AlignKind::Left),
144            b"right" => Ok(AlignKind::Right),
145            b"center" => Ok(AlignKind::Center),
146            &_ => Err(serde::de::Error::invalid_type(
147                serde::de::Unexpected::Bytes(v),
148                &self,
149            )),
150        }
151    }
152
153    fn visit_none<E>(self) -> Result<Self::Value, E>
154    where
155        E: serde::de::Error,
156    {
157        Ok(AlignKind::None)
158    }
159
160    fn visit_unit<E>(self) -> Result<Self::Value, E>
161    where
162        E: serde::de::Error,
163    {
164        Ok(AlignKind::None)
165    }
166}
167
168#[cfg(feature = "serde")]
169impl<'de> serde::de::Deserialize<'de> for AlignKind {
170    fn deserialize<D>(deserializer: D) -> Result<AlignKind, D::Error>
171    where
172        D: serde::de::Deserializer<'de>,
173    {
174        deserializer.deserialize_any(AlignKindVisitor)
175    }
176}
177
178/// Nodes.
179#[derive(Clone, Eq, PartialEq)]
180#[cfg_attr(
181    feature = "serde",
182    derive(serde::Serialize, serde::Deserialize),
183    serde(tag = "type", rename_all = "camelCase")
184)]
185pub enum Node {
186    // Document:
187    /// Root.
188    Root(Root),
189
190    // Container:
191    /// A transparent fragment containing a sequence of nodes.
192    ///
193    /// Fragments are useful for holding children extracted from another node.
194    Fragment(Fragment),
195    /// Block quote.
196    Blockquote(Blockquote),
197    /// Footnote definition.
198    FootnoteDefinition(FootnoteDefinition),
199    /// MDX: JSX element (container).
200    MdxJsxFlowElement(MdxJsxFlowElement),
201    /// List.
202    List(List),
203
204    // Frontmatter:
205    /// Language-agnostic frontmatter with an optional format hint.
206    Frontmatter(Frontmatter),
207    /// MDX.js ESM.
208    MdxjsEsm(MdxjsEsm),
209
210    // Phrasing:
211    /// Break.
212    Break(Break),
213    /// Code (phrasing).
214    InlineCode(InlineCode),
215    /// Math (phrasing).
216    InlineMath(InlineMath),
217    /// Delete.
218    Delete(Delete),
219    /// Emphasis.
220    Emphasis(Emphasis),
221    // MDX: expression (text).
222    MdxTextExpression(MdxTextExpression),
223    /// Footnote reference.
224    FootnoteReference(FootnoteReference),
225    /// Html (phrasing).
226    Html(Html),
227    /// Image.
228    Image(Image),
229    /// Image reference.
230    ImageReference(ImageReference),
231    // MDX: JSX element (text).
232    MdxJsxTextElement(MdxJsxTextElement),
233    /// Link.
234    Link(Link),
235    /// Link reference.
236    LinkReference(LinkReference),
237    /// Strong
238    Strong(Strong),
239    /// Text.
240    Text(Text),
241
242    // Flow:
243    /// Code (flow).
244    Code(Code),
245    /// Math (flow).
246    Math(Math),
247    // MDX: expression (flow).
248    MdxFlowExpression(MdxFlowExpression),
249    /// Heading.
250    Heading(Heading),
251    /// Html (flow).
252    // Html(Html),
253    /// Table.
254    Table(Table),
255    /// Thematic break.
256    ThematicBreak(ThematicBreak),
257
258    // Table content.
259    /// Table row.
260    TableRow(TableRow),
261
262    // Row content.
263    /// Table cell.
264    TableCell(TableCell),
265
266    // List content.
267    /// List item.
268    ListItem(ListItem),
269
270    // Content.
271    /// Definition.
272    Definition(Definition),
273    /// Paragraph.
274    Paragraph(Paragraph),
275}
276
277impl fmt::Debug for Node {
278    // Debug the wrapped struct.
279    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
280        match self {
281            Node::Root(x) => x.fmt(f),
282            Node::Fragment(x) => x.fmt(f),
283            Node::Blockquote(x) => x.fmt(f),
284            Node::FootnoteDefinition(x) => x.fmt(f),
285            Node::MdxJsxFlowElement(x) => x.fmt(f),
286            Node::List(x) => x.fmt(f),
287            Node::MdxjsEsm(x) => x.fmt(f),
288            Node::Frontmatter(x) => x.fmt(f),
289            Node::Break(x) => x.fmt(f),
290            Node::InlineCode(x) => x.fmt(f),
291            Node::InlineMath(x) => x.fmt(f),
292            Node::Delete(x) => x.fmt(f),
293            Node::Emphasis(x) => x.fmt(f),
294            Node::MdxTextExpression(x) => x.fmt(f),
295            Node::FootnoteReference(x) => x.fmt(f),
296            Node::Html(x) => x.fmt(f),
297            Node::Image(x) => x.fmt(f),
298            Node::ImageReference(x) => x.fmt(f),
299            Node::MdxJsxTextElement(x) => x.fmt(f),
300            Node::Link(x) => x.fmt(f),
301            Node::LinkReference(x) => x.fmt(f),
302            Node::Strong(x) => x.fmt(f),
303            Node::Text(x) => x.fmt(f),
304            Node::Code(x) => x.fmt(f),
305            Node::Math(x) => x.fmt(f),
306            Node::MdxFlowExpression(x) => x.fmt(f),
307            Node::Heading(x) => x.fmt(f),
308            Node::Table(x) => x.fmt(f),
309            Node::ThematicBreak(x) => x.fmt(f),
310            Node::TableRow(x) => x.fmt(f),
311            Node::TableCell(x) => x.fmt(f),
312            Node::ListItem(x) => x.fmt(f),
313            Node::Definition(x) => x.fmt(f),
314            Node::Paragraph(x) => x.fmt(f),
315        }
316    }
317}
318
319fn children_to_string(children: &[Node]) -> String {
320    children.iter().map(ToString::to_string).collect()
321}
322
323// To do: clippy may be right but that’s a breaking change.
324#[allow(clippy::to_string_trait_impl)]
325impl ToString for Node {
326    fn to_string(&self) -> String {
327        match self {
328            // Parents.
329            Node::Root(x) => children_to_string(&x.children),
330            Node::Fragment(x) => children_to_string(&x.children),
331            Node::Blockquote(x) => children_to_string(&x.children),
332            Node::FootnoteDefinition(x) => children_to_string(&x.children),
333            Node::MdxJsxFlowElement(x) => children_to_string(&x.children),
334            Node::List(x) => children_to_string(&x.children),
335            Node::Delete(x) => children_to_string(&x.children),
336            Node::Emphasis(x) => children_to_string(&x.children),
337            Node::MdxJsxTextElement(x) => children_to_string(&x.children),
338            Node::Link(x) => children_to_string(&x.children),
339            Node::LinkReference(x) => children_to_string(&x.children),
340            Node::Strong(x) => children_to_string(&x.children),
341            Node::Heading(x) => children_to_string(&x.children),
342            Node::Table(x) => children_to_string(&x.children),
343            Node::TableRow(x) => children_to_string(&x.children),
344            Node::TableCell(x) => children_to_string(&x.children),
345            Node::ListItem(x) => children_to_string(&x.children),
346            Node::Paragraph(x) => children_to_string(&x.children),
347
348            // Literals.
349            Node::MdxjsEsm(x) => x.value.clone(),
350            Node::Frontmatter(x) => x.value.clone(),
351            Node::InlineCode(x) => x.value.clone(),
352            Node::InlineMath(x) => x.value.clone(),
353            Node::MdxTextExpression(x) => x.value.clone(),
354            Node::Html(x) => x.value.clone(),
355            Node::Text(x) => x.value.clone(),
356            Node::Code(x) => x.value.clone(),
357            Node::Math(x) => x.value.clone(),
358            Node::MdxFlowExpression(x) => x.value.clone(),
359
360            // Voids.
361            Node::Break(_)
362            | Node::FootnoteReference(_)
363            | Node::Image(_)
364            | Node::ImageReference(_)
365            | Node::ThematicBreak(_)
366            | Node::Definition(_) => String::new(),
367        }
368    }
369}
370
371impl Node {
372    #[must_use]
373    pub fn children(&self) -> Option<&Vec<Node>> {
374        match self {
375            // Parent.
376            Node::Root(x) => Some(&x.children),
377            Node::Fragment(x) => Some(&x.children),
378            Node::Paragraph(x) => Some(&x.children),
379            Node::Heading(x) => Some(&x.children),
380            Node::Blockquote(x) => Some(&x.children),
381            Node::List(x) => Some(&x.children),
382            Node::ListItem(x) => Some(&x.children),
383            Node::Emphasis(x) => Some(&x.children),
384            Node::Strong(x) => Some(&x.children),
385            Node::Link(x) => Some(&x.children),
386            Node::LinkReference(x) => Some(&x.children),
387            Node::FootnoteDefinition(x) => Some(&x.children),
388            Node::Table(x) => Some(&x.children),
389            Node::TableRow(x) => Some(&x.children),
390            Node::TableCell(x) => Some(&x.children),
391            Node::Delete(x) => Some(&x.children),
392            Node::MdxJsxFlowElement(x) => Some(&x.children),
393            Node::MdxJsxTextElement(x) => Some(&x.children),
394            // Non-parent.
395            _ => None,
396        }
397    }
398
399    pub fn children_mut(&mut self) -> Option<&mut Vec<Node>> {
400        match self {
401            // Parent.
402            Node::Root(x) => Some(&mut x.children),
403            Node::Fragment(x) => Some(&mut x.children),
404            Node::Paragraph(x) => Some(&mut x.children),
405            Node::Heading(x) => Some(&mut x.children),
406            Node::Blockquote(x) => Some(&mut x.children),
407            Node::List(x) => Some(&mut x.children),
408            Node::ListItem(x) => Some(&mut x.children),
409            Node::Emphasis(x) => Some(&mut x.children),
410            Node::Strong(x) => Some(&mut x.children),
411            Node::Link(x) => Some(&mut x.children),
412            Node::LinkReference(x) => Some(&mut x.children),
413            Node::FootnoteDefinition(x) => Some(&mut x.children),
414            Node::Table(x) => Some(&mut x.children),
415            Node::TableRow(x) => Some(&mut x.children),
416            Node::TableCell(x) => Some(&mut x.children),
417            Node::Delete(x) => Some(&mut x.children),
418            Node::MdxJsxFlowElement(x) => Some(&mut x.children),
419            Node::MdxJsxTextElement(x) => Some(&mut x.children),
420            // Non-parent.
421            _ => None,
422        }
423    }
424
425    #[must_use]
426    pub fn position(&self) -> Option<&Position> {
427        match self {
428            Node::Root(x) => x.position.as_ref(),
429            Node::Fragment(_) => None,
430            Node::Blockquote(x) => x.position.as_ref(),
431            Node::FootnoteDefinition(x) => x.position.as_ref(),
432            Node::MdxJsxFlowElement(x) => x.position.as_ref(),
433            Node::List(x) => x.position.as_ref(),
434            Node::MdxjsEsm(x) => x.position.as_ref(),
435            Node::Frontmatter(x) => x.position.as_ref(),
436            Node::Break(x) => x.position.as_ref(),
437            Node::InlineCode(x) => x.position.as_ref(),
438            Node::InlineMath(x) => x.position.as_ref(),
439            Node::Delete(x) => x.position.as_ref(),
440            Node::Emphasis(x) => x.position.as_ref(),
441            Node::MdxTextExpression(x) => x.position.as_ref(),
442            Node::FootnoteReference(x) => x.position.as_ref(),
443            Node::Html(x) => x.position.as_ref(),
444            Node::Image(x) => x.position.as_ref(),
445            Node::ImageReference(x) => x.position.as_ref(),
446            Node::MdxJsxTextElement(x) => x.position.as_ref(),
447            Node::Link(x) => x.position.as_ref(),
448            Node::LinkReference(x) => x.position.as_ref(),
449            Node::Strong(x) => x.position.as_ref(),
450            Node::Text(x) => x.position.as_ref(),
451            Node::Code(x) => x.position.as_ref(),
452            Node::Math(x) => x.position.as_ref(),
453            Node::MdxFlowExpression(x) => x.position.as_ref(),
454            Node::Heading(x) => x.position.as_ref(),
455            Node::Table(x) => x.position.as_ref(),
456            Node::ThematicBreak(x) => x.position.as_ref(),
457            Node::TableRow(x) => x.position.as_ref(),
458            Node::TableCell(x) => x.position.as_ref(),
459            Node::ListItem(x) => x.position.as_ref(),
460            Node::Definition(x) => x.position.as_ref(),
461            Node::Paragraph(x) => x.position.as_ref(),
462        }
463    }
464
465    pub fn position_mut(&mut self) -> Option<&mut Position> {
466        match self {
467            Node::Root(x) => x.position.as_mut(),
468            Node::Fragment(_) => None,
469            Node::Blockquote(x) => x.position.as_mut(),
470            Node::FootnoteDefinition(x) => x.position.as_mut(),
471            Node::MdxJsxFlowElement(x) => x.position.as_mut(),
472            Node::List(x) => x.position.as_mut(),
473            Node::MdxjsEsm(x) => x.position.as_mut(),
474            Node::Frontmatter(x) => x.position.as_mut(),
475            Node::Break(x) => x.position.as_mut(),
476            Node::InlineCode(x) => x.position.as_mut(),
477            Node::InlineMath(x) => x.position.as_mut(),
478            Node::Delete(x) => x.position.as_mut(),
479            Node::Emphasis(x) => x.position.as_mut(),
480            Node::MdxTextExpression(x) => x.position.as_mut(),
481            Node::FootnoteReference(x) => x.position.as_mut(),
482            Node::Html(x) => x.position.as_mut(),
483            Node::Image(x) => x.position.as_mut(),
484            Node::ImageReference(x) => x.position.as_mut(),
485            Node::MdxJsxTextElement(x) => x.position.as_mut(),
486            Node::Link(x) => x.position.as_mut(),
487            Node::LinkReference(x) => x.position.as_mut(),
488            Node::Strong(x) => x.position.as_mut(),
489            Node::Text(x) => x.position.as_mut(),
490            Node::Code(x) => x.position.as_mut(),
491            Node::Math(x) => x.position.as_mut(),
492            Node::MdxFlowExpression(x) => x.position.as_mut(),
493            Node::Heading(x) => x.position.as_mut(),
494            Node::Table(x) => x.position.as_mut(),
495            Node::ThematicBreak(x) => x.position.as_mut(),
496            Node::TableRow(x) => x.position.as_mut(),
497            Node::TableCell(x) => x.position.as_mut(),
498            Node::ListItem(x) => x.position.as_mut(),
499            Node::Definition(x) => x.position.as_mut(),
500            Node::Paragraph(x) => x.position.as_mut(),
501        }
502    }
503
504    pub fn position_set(&mut self, position: Option<Position>) {
505        match self {
506            Node::Root(x) => x.position = position,
507            Node::Fragment(_) => (),
508            Node::Blockquote(x) => x.position = position,
509            Node::FootnoteDefinition(x) => x.position = position,
510            Node::MdxJsxFlowElement(x) => x.position = position,
511            Node::List(x) => x.position = position,
512            Node::MdxjsEsm(x) => x.position = position,
513            Node::Frontmatter(x) => x.position = position,
514            Node::Break(x) => x.position = position,
515            Node::InlineCode(x) => x.position = position,
516            Node::InlineMath(x) => x.position = position,
517            Node::Delete(x) => x.position = position,
518            Node::Emphasis(x) => x.position = position,
519            Node::MdxTextExpression(x) => x.position = position,
520            Node::FootnoteReference(x) => x.position = position,
521            Node::Html(x) => x.position = position,
522            Node::Image(x) => x.position = position,
523            Node::ImageReference(x) => x.position = position,
524            Node::MdxJsxTextElement(x) => x.position = position,
525            Node::Link(x) => x.position = position,
526            Node::LinkReference(x) => x.position = position,
527            Node::Strong(x) => x.position = position,
528            Node::Text(x) => x.position = position,
529            Node::Code(x) => x.position = position,
530            Node::Math(x) => x.position = position,
531            Node::MdxFlowExpression(x) => x.position = position,
532            Node::Heading(x) => x.position = position,
533            Node::Table(x) => x.position = position,
534            Node::ThematicBreak(x) => x.position = position,
535            Node::TableRow(x) => x.position = position,
536            Node::TableCell(x) => x.position = position,
537            Node::ListItem(x) => x.position = position,
538            Node::Definition(x) => x.position = position,
539            Node::Paragraph(x) => x.position = position,
540        }
541    }
542
543    /// Visit this node and its descendants in depth-first, pre-order.
544    pub fn walk<'a>(&'a self, mut visitor: impl FnMut(&'a Node)) {
545        fn visit<'a>(node: &'a Node, visitor: &mut impl FnMut(&'a Node)) {
546            visitor(node);
547            if let Some(children) = node.children() {
548                for child in children {
549                    visit(child, visitor);
550                }
551            }
552        }
553
554        visit(self, &mut visitor);
555    }
556
557    /// Mutably visit this node and its descendants in depth-first, pre-order.
558    pub fn walk_mut(&mut self, mut visitor: impl FnMut(&mut Node)) {
559        fn visit(node: &mut Node, visitor: &mut impl FnMut(&mut Node)) {
560            visitor(node);
561            if let Some(children) = node.children_mut() {
562                for child in children {
563                    visit(child, visitor);
564                }
565            }
566        }
567
568        visit(self, &mut visitor);
569    }
570
571    /// Return the concatenated text represented by this node.
572    ///
573    /// Image nodes contribute their alt text and hard breaks contribute a
574    /// newline. Structural nodes concatenate the text of their children.
575    #[must_use]
576    pub fn text_content(&self) -> String {
577        match self {
578            Node::Image(node) => node.alt.clone(),
579            Node::ImageReference(node) => node.alt.clone(),
580            Node::Break(_) => "\n".into(),
581            Node::Definition(_) | Node::FootnoteReference(_) | Node::ThematicBreak(_) => {
582                String::new()
583            }
584            _ => {
585                if let Some(children) = self.children() {
586                    children.iter().map(Node::text_content).collect()
587                } else {
588                    self.to_string()
589                }
590            }
591        }
592    }
593
594    /// Find a direct child heading with the requested text.
595    #[must_use]
596    pub fn find_heading(&self, title: &str) -> Option<&Node> {
597        self.children()?
598            .iter()
599            .find(|child| matches!(child, Node::Heading(_)) && child.text_content() == title)
600    }
601
602    /// Return the language identifier of inline code, fenced code, or frontmatter.
603    #[must_use]
604    pub fn code_language(&self) -> Option<&str> {
605        match self {
606            Node::InlineCode(node) => node.lang.as_deref(),
607            Node::Code(node) => node.lang.as_deref(),
608            Node::Frontmatter(node) => node.language(),
609            _ => None,
610        }
611    }
612
613    /// Return opening fence details for code blocks and frontmatter.
614    ///
615    /// `indent` is measured in columns relative to the containing block, not
616    /// the absolute source column. Inline code, indented code, and nodes without
617    /// retained fence metadata return `None`. Frontmatter fences have no indentation.
618    #[must_use]
619    pub fn code_fence(&self) -> Option<CodeFence> {
620        match self {
621            Node::Code(node) => node.fence,
622            Node::Frontmatter(node) => Some(CodeFence {
623                character: node.fence,
624                length: node.fence_length,
625                indent: 0,
626            }),
627            _ => None,
628        }
629    }
630
631    /// Return the info string for inline code, fenced code, or frontmatter.
632    ///
633    /// Inline code metadata is its language token. Fenced code metadata is
634    /// reconstructed from `lang` and `meta` when either is present.
635    /// Frontmatter returns its authored info string, empty for an implicit language.
636    #[must_use]
637    pub fn code_info(&self) -> Option<String> {
638        match self {
639            Node::InlineCode(node) => node.lang.clone(),
640            Node::Frontmatter(node) => Some(node.info.clone()),
641            Node::Code(node) => match (&node.lang, &node.meta) {
642                (Some(lang), Some(meta)) => Some(alloc::format!("{lang} {meta}")),
643                (Some(lang), None) => Some(lang.clone()),
644                (None, Some(meta)) => Some(meta.clone()),
645                (None, None) => None,
646            },
647            _ => None,
648        }
649    }
650
651    /// Take all direct children from this node and return them in a fragment.
652    ///
653    /// Returns `None` for nodes that cannot contain children. The extracted
654    /// child nodes retain their own positions; the new fragment has no source
655    /// position of its own.
656    pub fn extract_children(&mut self) -> Option<Node> {
657        self.children_mut().map(|children| {
658            Node::Fragment(Fragment {
659                children: core::mem::take(children),
660            })
661        })
662    }
663
664    /// Render this node with a user-provided renderer.
665    pub fn render_with<R: crate::renderer::Renderer>(&self, renderer: &mut R) -> String {
666        renderer.render(self)
667    }
668
669    /// Serialize this AST node or fragment as Markdown.
670    ///
671    /// Markdown output ends with a newline. For custom formatting, use
672    /// [`to_markdown_with_options`][crate::markdown::to_markdown_with_options].
673    ///
674    /// # Example
675    ///
676    /// ```ignore
677    /// let markdown = node.to_markdown();
678    /// ```
679    #[must_use]
680    pub fn to_markdown(&self) -> String {
681        crate::markdown::to_markdown(self).expect("Markdown serialization failed for this AST node")
682    }
683
684    /// Serialize this AST node or fragment as Markdown with custom options.
685    ///
686    /// # Errors
687    ///
688    /// Returns an error if an option contains an invalid marker or the AST
689    /// contains a node that cannot be serialized.
690    pub fn to_markdown_with_options(
691        &self,
692        options: &crate::markdown::Options,
693    ) -> Result<String, crate::message::Message> {
694        crate::markdown::to_markdown_with_options(self, options)
695    }
696
697    /// Replace a heading and the section below it in this node's children.
698    ///
699    /// `heading_index` is the direct-child index of the heading. When
700    /// `replace_heading` is false, the heading stays and only its section
701    /// content is replaced. When `remove_subsections` is true, nested heading
702    /// sections are included through the next heading of the same or higher
703    /// level. Returns `false` if the index is not a heading.
704    pub fn replace_heading_section(
705        &mut self,
706        heading_index: usize,
707        replacement: Vec<Node>,
708        replace_heading: bool,
709        remove_subsections: bool,
710    ) -> bool {
711        let Some(children) = self.children_mut() else {
712            return false;
713        };
714        let depth = match children.get(heading_index) {
715            Some(Node::Heading(heading)) => heading.depth,
716            _ => return false,
717        };
718        let end = children
719            .iter()
720            .enumerate()
721            .skip(heading_index + 1)
722            .find_map(|(index, node)| {
723                let Node::Heading(next) = node else {
724                    return None;
725                };
726                if !remove_subsections || next.depth <= depth {
727                    Some(index)
728                } else {
729                    None
730                }
731            })
732            .unwrap_or(children.len());
733        let start = if replace_heading {
734            heading_index
735        } else {
736            heading_index + 1
737        };
738
739        children.splice(start..end, replacement);
740        true
741    }
742}
743
744/// MDX: attribute content.
745#[derive(Clone, Debug, Eq, PartialEq)]
746#[cfg_attr(
747    feature = "serde",
748    derive(serde::Serialize, serde::Deserialize),
749    serde(untagged)
750)]
751pub enum AttributeContent {
752    /// JSX expression.
753    ///
754    /// ```markdown
755    /// > | <a {...b} />
756    ///        ^^^^^^
757    /// ```
758    Expression(MdxJsxExpressionAttribute),
759    /// JSX property.
760    ///
761    /// ```markdown
762    /// > | <a b />
763    ///        ^
764    /// ```
765    Property(MdxJsxAttribute),
766}
767//
768#[derive(Clone, Debug, Eq, PartialEq)]
769#[cfg_attr(
770    feature = "serde",
771    derive(serde::Serialize, serde::Deserialize),
772    serde(tag = "type", rename = "mdxJsxAttributeValueExpression")
773)]
774pub struct AttributeValueExpression {
775    pub value: String,
776    #[cfg_attr(feature = "serde", serde(rename = "_markdownRsStops"))]
777    pub stops: Vec<Stop>,
778}
779
780/// MDX: attribute value.
781#[derive(Clone, Debug, Eq, PartialEq)]
782#[cfg_attr(
783    feature = "serde",
784    derive(serde::Serialize, serde::Deserialize),
785    serde(untagged)
786)]
787pub enum AttributeValue {
788    /// Expression value.
789    ///
790    /// ```markdown
791    /// > | <a b={c} />
792    ///          ^^^
793    /// ```
794    Expression(AttributeValueExpression),
795    /// Static value.
796    ///
797    /// ```markdown
798    /// > | <a b="c" />
799    ///          ^^^
800    /// ```
801    Literal(String),
802}
803
804/// A transparent container for a sequence of AST nodes.
805///
806/// Fragments have no source position of their own. They are useful for holding
807/// the children extracted from another node.
808#[derive(Clone, Debug, Eq, PartialEq)]
809#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
810pub struct Fragment {
811    /// Content model.
812    pub children: Vec<Node>,
813}
814
815/// Document.
816///
817/// ```markdown
818/// > | a
819///     ^
820/// ```
821#[derive(Clone, Debug, Eq, PartialEq)]
822#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
823pub struct Root {
824    // Parent.
825    /// Content model.
826    pub children: Vec<Node>,
827    /// Positional info.
828    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
829    pub position: Option<Position>,
830}
831
832/// Paragraph.
833///
834/// ```markdown
835/// > | a
836///     ^
837/// ```
838#[derive(Clone, Debug, Eq, PartialEq)]
839#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
840pub struct Paragraph {
841    // Parent.
842    /// Content model.
843    pub children: Vec<Node>,
844    /// Positional info.
845    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
846    pub position: Option<Position>,
847}
848
849/// Heading.
850///
851/// ```markdown
852/// > | # a
853///     ^^^
854/// ```
855#[derive(Clone, Debug, Eq, PartialEq)]
856#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
857pub struct Heading {
858    // Parent.
859    /// Content model.
860    pub children: Vec<Node>,
861    /// Positional info.
862    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
863    pub position: Option<Position>,
864    // Extra.
865    /// Rank (between `1` and `6`, both including).
866    pub depth: u8,
867}
868
869/// Thematic break.
870///
871/// ```markdown
872/// > | ***
873///     ^^^
874/// ```
875#[derive(Clone, Debug, Eq, PartialEq)]
876#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
877pub struct ThematicBreak {
878    // Void.
879    /// Positional info.
880    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
881    pub position: Option<Position>,
882}
883
884/// Block quote.
885///
886/// ```markdown
887/// > | > a
888///     ^^^
889/// ```
890#[derive(Clone, Debug, Eq, PartialEq)]
891#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
892pub struct Blockquote {
893    // Parent.
894    /// Content model.
895    pub children: Vec<Node>,
896    /// Positional info.
897    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
898    pub position: Option<Position>,
899}
900
901/// List.
902///
903/// ```markdown
904/// > | * a
905///     ^^^
906/// ```
907#[derive(Clone, Debug, Eq, PartialEq)]
908#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
909pub struct List {
910    // Parent.
911    /// Content model.
912    pub children: Vec<Node>,
913    /// Positional info.
914    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
915    pub position: Option<Position>,
916    // Extra.
917    /// Ordered (`true`) or unordered (`false`).
918    pub ordered: bool,
919    /// Starting number of the list.
920    /// `None` when unordered.
921    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
922    pub start: Option<u32>,
923    /// One or more of its children are separated with a blank line from its
924    /// siblings (when `true`), or not (when `false`).
925    pub spread: bool,
926}
927
928/// List item.
929///
930/// ```markdown
931/// > | * a
932///     ^^^
933/// ```
934#[derive(Clone, Debug, Eq, PartialEq)]
935#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
936pub struct ListItem {
937    // Parent.
938    /// Content model.
939    pub children: Vec<Node>,
940    /// Positional info.
941    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
942    pub position: Option<Position>,
943    // Extra.
944    /// The item contains two or more children separated by a blank line
945    /// (when `true`), or not (when `false`).
946    pub spread: bool,
947    /// GFM: whether the item is done (when `true`), not done (when `false`),
948    /// or indeterminate or not applicable (`None`).
949    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
950    pub checked: Option<bool>,
951}
952
953/// Html (flow or phrasing).
954///
955/// ```markdown
956/// > | <a>
957///     ^^^
958/// ```
959#[derive(Clone, Debug, Eq, PartialEq)]
960#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
961pub struct Html {
962    // Text.
963    /// Content model.
964    pub value: String,
965    /// Positional info.
966    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
967    pub position: Option<Position>,
968}
969
970/// Math (flow).
971///
972/// ```markdown
973/// > | $$
974///     ^^
975/// > | a
976///     ^
977/// > | $$
978///     ^^
979/// ```
980#[derive(Clone, Debug, Eq, PartialEq)]
981#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
982pub struct Math {
983    // Text.
984    /// Content model.
985    pub value: String,
986    /// Positional info.
987    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
988    pub position: Option<Position>,
989    // Extra.
990    /// Custom info relating to the node.
991    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
992    pub meta: Option<String>,
993}
994
995/// Definition.
996///
997/// ```markdown
998/// > | [a]: b
999///     ^^^^^^
1000/// ```
1001#[derive(Clone, Debug, Eq, PartialEq)]
1002#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1003pub struct Definition {
1004    // Void.
1005    /// Positional info.
1006    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1007    pub position: Option<Position>,
1008    // Resource.
1009    /// URL to the referenced resource.
1010    pub url: String,
1011    /// Advisory info for the resource, such as something that would be
1012    /// appropriate for a tooltip.
1013    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1014    pub title: Option<String>,
1015    // Association.
1016    /// Value that can match another node.
1017    /// `identifier` is a source value: character escapes and character references
1018    /// are *not* parsed.
1019    /// Its value must be normalized.
1020    pub identifier: String,
1021    /// `label` is a string value: it works just like `title` on a link or a
1022    /// `lang` on code: character escapes and character references are parsed.
1023    ///
1024    /// To normalize a value, collapse markdown whitespace (`[\t\n\r ]+`) to a
1025    /// space, trim the optional initial and/or final space, and perform
1026    /// case-folding.
1027    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1028    pub label: Option<String>,
1029}
1030
1031/// Text.
1032///
1033/// ```markdown
1034/// > | a
1035///     ^
1036/// ```
1037#[derive(Clone, Debug, Eq, PartialEq)]
1038#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1039pub struct Text {
1040    // Text.
1041    /// Content model.
1042    pub value: String,
1043    /// Positional info.
1044    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1045    pub position: Option<Position>,
1046}
1047
1048/// Emphasis.
1049///
1050/// ```markdown
1051/// > | *a*
1052///     ^^^
1053/// ```
1054#[derive(Clone, Debug, Eq, PartialEq)]
1055#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1056pub struct Emphasis {
1057    // Parent.
1058    /// Content model.
1059    pub children: Vec<Node>,
1060    /// Positional info.
1061    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1062    pub position: Option<Position>,
1063}
1064
1065/// Strong.
1066///
1067/// ```markdown
1068/// > | **a**
1069///     ^^^^^
1070/// ```
1071#[derive(Clone, Debug, Eq, PartialEq)]
1072#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1073pub struct Strong {
1074    // Parent.
1075    /// Content model.
1076    pub children: Vec<Node>,
1077    /// Positional info.
1078    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1079    pub position: Option<Position>,
1080}
1081
1082/// Code (phrasing).
1083///
1084/// ```markdown
1085/// > | `a`
1086///     ^^^
1087/// ```
1088#[derive(Clone, Debug, Eq, PartialEq)]
1089#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1090pub struct InlineCode {
1091    // Text.
1092    /// Content model.
1093    pub value: String,
1094    /// Positional info.
1095    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1096    pub position: Option<Position>,
1097    /// Optional language identifier parsed from an inline code prefix.
1098    ///
1099    /// This is a Socketry Markdown extension; standard mdast inline code
1100    /// nodes do not have a language field.
1101    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1102    pub lang: Option<String>,
1103}
1104
1105/// Math (phrasing).
1106///
1107/// ```markdown
1108/// > | $a$
1109///     ^^^
1110/// ```
1111#[derive(Clone, Debug, Eq, PartialEq)]
1112#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1113pub struct InlineMath {
1114    // Text.
1115    /// Content model.
1116    pub value: String,
1117    /// Positional info.
1118    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1119    pub position: Option<Position>,
1120}
1121
1122/// Break.
1123///
1124/// ```markdown
1125/// > | a\
1126///      ^
1127///   | b
1128/// ```
1129#[derive(Clone, Debug, Eq, PartialEq)]
1130#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1131pub struct Break {
1132    // Void.
1133    /// Positional info.
1134    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1135    pub position: Option<Position>,
1136}
1137
1138/// Link.
1139///
1140/// ```markdown
1141/// > | [a](b)
1142///     ^^^^^^
1143/// ```
1144#[derive(Clone, Debug, Eq, PartialEq)]
1145#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1146pub struct Link {
1147    // Parent.
1148    /// Content model.
1149    pub children: Vec<Node>,
1150    /// Positional info.
1151    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1152    pub position: Option<Position>,
1153    // Resource.
1154    /// URL to the referenced resource.
1155    pub url: String,
1156    /// Advisory info for the resource, such as something that would be
1157    /// appropriate for a tooltip.
1158    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1159    pub title: Option<String>,
1160}
1161
1162/// Image.
1163///
1164/// ```markdown
1165/// > | ![a](b)
1166///     ^^^^^^^
1167/// ```
1168#[derive(Clone, Debug, Eq, PartialEq)]
1169#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1170pub struct Image {
1171    // Void.
1172    /// Positional info.
1173    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1174    pub position: Option<Position>,
1175    // Alternative.
1176    /// Equivalent content for environments that cannot represent the node as
1177    /// intended.
1178    pub alt: String,
1179    // Resource.
1180    /// URL to the referenced resource.
1181    pub url: String,
1182    /// Advisory info for the resource, such as something that would be
1183    /// appropriate for a tooltip.
1184    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1185    pub title: Option<String>,
1186}
1187
1188/// Link reference.
1189///
1190/// ```markdown
1191/// > | [a]
1192///     ^^^
1193/// ```
1194#[derive(Clone, Debug, Eq, PartialEq)]
1195#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1196pub struct LinkReference {
1197    // Parent.
1198    /// Content model.
1199    pub children: Vec<Node>,
1200    /// Positional info.
1201    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1202    pub position: Option<Position>,
1203    // Reference.
1204    /// Explicitness of a reference.
1205    #[cfg_attr(feature = "serde", serde(rename = "referenceType"))]
1206    pub reference_kind: ReferenceKind,
1207    // Association.
1208    /// Value that can match another node.
1209    /// `identifier` is a source value: character escapes and character references
1210    /// are *not* parsed.
1211    /// Its value must be normalized.
1212    pub identifier: String,
1213    /// `label` is a string value: it works just like `title` on a link or a
1214    /// `lang` on code: character escapes and character references are parsed.
1215    ///
1216    /// To normalize a value, collapse markdown whitespace (`[\t\n\r ]+`) to a
1217    /// space, trim the optional initial and/or final space, and perform
1218    /// case-folding.
1219    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1220    pub label: Option<String>,
1221}
1222
1223/// Image reference.
1224///
1225/// ```markdown
1226/// > | ![a]
1227///     ^^^^
1228/// ```
1229#[derive(Clone, Debug, Eq, PartialEq)]
1230#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1231pub struct ImageReference {
1232    // Void.
1233    /// Positional info.
1234    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1235    pub position: Option<Position>,
1236    // Alternative.
1237    /// Equivalent content for environments that cannot represent the node as
1238    /// intended.
1239    pub alt: String,
1240    // Reference.
1241    /// Explicitness of a reference.
1242    #[cfg_attr(feature = "serde", serde(rename = "referenceType"))]
1243    pub reference_kind: ReferenceKind,
1244    // Association.
1245    /// Value that can match another node.
1246    /// `identifier` is a source value: character escapes and character references
1247    /// are *not* parsed.
1248    /// Its value must be normalized.
1249    pub identifier: String,
1250    /// `label` is a string value: it works just like `title` on a link or a
1251    /// `lang` on code: character escapes and character references are parsed.
1252    ///
1253    /// To normalize a value, collapse markdown whitespace (`[\t\n\r ]+`) to a
1254    /// space, trim the optional initial and/or final space, and perform
1255    /// case-folding.
1256    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1257    pub label: Option<String>,
1258}
1259
1260/// GFM: footnote definition.
1261///
1262/// ```markdown
1263/// > | [^a]: b
1264///     ^^^^^^^
1265/// ```
1266#[derive(Clone, Debug, Eq, PartialEq)]
1267#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1268pub struct FootnoteDefinition {
1269    // Parent.
1270    /// Content model.
1271    pub children: Vec<Node>,
1272    /// Positional info.
1273    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1274    pub position: Option<Position>,
1275    // Association.
1276    /// Value that can match another node.
1277    /// `identifier` is a source value: character escapes and character references
1278    /// are *not* parsed.
1279    /// Its value must be normalized.
1280    pub identifier: String,
1281    /// `label` is a string value: it works just like `title` on a link or a
1282    /// `lang` on code: character escapes and character references are parsed.
1283    ///
1284    /// To normalize a value, collapse markdown whitespace (`[\t\n\r ]+`) to a
1285    /// space, trim the optional initial and/or final space, and perform
1286    /// case-folding.
1287    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1288    pub label: Option<String>,
1289}
1290
1291/// GFM: footnote reference.
1292///
1293/// ```markdown
1294/// > | [^a]
1295///     ^^^^
1296/// ```
1297#[derive(Clone, Debug, Eq, PartialEq)]
1298#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1299pub struct FootnoteReference {
1300    // Void.
1301    /// Positional info.
1302    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1303    pub position: Option<Position>,
1304    // Association.
1305    /// Value that can match another node.
1306    /// `identifier` is a source value: character escapes and character references
1307    /// are *not* parsed.
1308    /// Its value must be normalized.
1309    pub identifier: String,
1310    /// `label` is a string value: it works just like `title` on a link or a
1311    /// `lang` on code: character escapes and character references are parsed.
1312    ///
1313    /// To normalize a value, collapse markdown whitespace (`[\t\n\r ]+`) to a
1314    /// space, trim the optional initial and/or final space, and perform
1315    /// case-folding.
1316    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1317    pub label: Option<String>,
1318}
1319
1320/// GFM: table.
1321///
1322/// ```markdown
1323/// > | | a |
1324///     ^^^^^
1325/// > | | - |
1326///     ^^^^^
1327/// ```
1328#[derive(Clone, Debug, Eq, PartialEq)]
1329#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1330pub struct Table {
1331    // Parent.
1332    /// Content model.
1333    pub children: Vec<Node>,
1334    /// Positional info.
1335    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1336    pub position: Option<Position>,
1337    // Extra.
1338    /// Represents how cells in columns are aligned.
1339    pub align: Vec<AlignKind>,
1340}
1341
1342/// GFM: table row.
1343///
1344/// ```markdown
1345/// > | | a |
1346///     ^^^^^
1347/// ```
1348#[derive(Clone, Debug, Eq, PartialEq)]
1349#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1350pub struct TableRow {
1351    // Parent.
1352    /// Content model.
1353    pub children: Vec<Node>,
1354    /// Positional info.
1355    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1356    pub position: Option<Position>,
1357}
1358
1359/// GFM: table cell.
1360///
1361/// ```markdown
1362/// > | | a |
1363///     ^^^^^
1364/// ```
1365#[derive(Clone, Debug, Eq, PartialEq)]
1366#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1367pub struct TableCell {
1368    // Parent.
1369    /// Content model.
1370    pub children: Vec<Node>,
1371    /// Positional info.
1372    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1373    pub position: Option<Position>,
1374}
1375
1376/// GFM: delete.
1377///
1378/// ```markdown
1379/// > | ~~a~~
1380///     ^^^^^
1381/// ```
1382#[derive(Clone, Debug, Eq, PartialEq)]
1383#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1384pub struct Delete {
1385    // Parent.
1386    /// Content model.
1387    pub children: Vec<Node>,
1388    /// Positional info.
1389    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1390    pub position: Option<Position>,
1391}
1392
1393/// MDX: ESM.
1394///
1395/// ```markdown
1396/// > | import a from 'b'
1397///     ^^^^^^^^^^^^^^^^^
1398/// ```
1399#[derive(Clone, Debug, Eq, PartialEq)]
1400#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1401pub struct MdxjsEsm {
1402    // Literal.
1403    /// Content model.
1404    pub value: String,
1405    /// Positional info.
1406    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1407    pub position: Option<Position>,
1408
1409    // Custom data on where each slice of `value` came from.
1410    #[cfg_attr(feature = "serde", serde(rename = "_markdownRsStops"))]
1411    pub stops: Vec<Stop>,
1412}
1413
1414/// MDX: expression (flow).
1415///
1416/// ```markdown
1417/// > | {a}
1418///     ^^^
1419/// ```
1420#[derive(Clone, Debug, Eq, PartialEq)]
1421#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1422pub struct MdxFlowExpression {
1423    // Literal.
1424    /// Content model.
1425    pub value: String,
1426    /// Positional info.
1427    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1428    pub position: Option<Position>,
1429
1430    // Custom data on where each slice of `value` came from.
1431    #[cfg_attr(feature = "serde", serde(rename = "_markdownRsStops"))]
1432    pub stops: Vec<Stop>,
1433}
1434
1435/// MDX: expression (text).
1436///
1437/// ```markdown
1438/// > | a {b}
1439///       ^^^
1440/// ```
1441#[derive(Clone, Debug, Eq, PartialEq)]
1442#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1443pub struct MdxTextExpression {
1444    // Literal.
1445    /// Content model.
1446    pub value: String,
1447    /// Positional info.
1448    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1449    pub position: Option<Position>,
1450
1451    // Custom data on where each slice of `value` came from.
1452    #[cfg_attr(feature = "serde", serde(rename = "_markdownRsStops"))]
1453    pub stops: Vec<Stop>,
1454}
1455
1456/// MDX: JSX element (container).
1457///
1458/// ```markdown
1459/// > | <a />
1460///     ^^^^^
1461/// ```
1462#[derive(Clone, Debug, Eq, PartialEq)]
1463#[cfg_attr(
1464    feature = "serde",
1465    derive(serde::Serialize, serde::Deserialize),
1466    serde(rename_all = "camelCase")
1467)]
1468pub struct MdxJsxFlowElement {
1469    // Parent.
1470    /// Content model.
1471    pub children: Vec<Node>,
1472    /// Positional info.
1473    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1474    pub position: Option<Position>,
1475    // JSX element.
1476    /// Name.
1477    ///
1478    /// Fragments have no name.
1479    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1480    pub name: Option<String>,
1481    /// Attributes.
1482    pub attributes: Vec<AttributeContent>,
1483}
1484
1485/// MDX: JSX element (text).
1486///
1487/// ```markdown
1488/// > | <a />.
1489///     ^^^^^
1490/// ```
1491#[derive(Clone, Debug, Eq, PartialEq)]
1492#[cfg_attr(
1493    feature = "serde",
1494    derive(serde::Serialize, serde::Deserialize),
1495    serde(rename_all = "camelCase")
1496)]
1497pub struct MdxJsxTextElement {
1498    // Parent.
1499    /// Content model.
1500    pub children: Vec<Node>,
1501    /// Positional info.
1502    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1503    pub position: Option<Position>,
1504    // JSX element.
1505    /// Name.
1506    ///
1507    /// Fragments have no name.
1508    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1509    pub name: Option<String>,
1510    /// Attributes.
1511    pub attributes: Vec<AttributeContent>,
1512}
1513
1514/// MDX: JSX attribute.
1515///
1516/// ```markdown
1517/// > | <a b />
1518///        ^
1519/// ```
1520#[derive(Clone, Debug, Eq, PartialEq)]
1521#[cfg_attr(
1522    feature = "serde",
1523    derive(serde::Serialize, serde::Deserialize),
1524    serde(tag = "type", rename = "mdxJsxAttribute")
1525)]
1526pub struct MdxJsxAttribute {
1527    // Void.
1528    /// Positional info.
1529    // pub position: Option<Position>,
1530    /// Key.
1531    pub name: String,
1532    /// Value.
1533    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1534    pub value: Option<AttributeValue>,
1535}
1536
1537/// MDX: JSX expression attribute.
1538///
1539/// ```markdown
1540/// > | <a {...b} />
1541///        ^
1542/// ```
1543#[derive(Clone, Debug, Eq, PartialEq)]
1544#[cfg_attr(
1545    feature = "serde",
1546    derive(serde::Serialize, serde::Deserialize),
1547    serde(tag = "type", rename = "mdxJsxExpressionAttribute")
1548)]
1549pub struct MdxJsxExpressionAttribute {
1550    /// Value.
1551    pub value: String,
1552    /// Stops
1553    #[cfg_attr(feature = "serde", serde(rename = "_markdownRsStops"))]
1554    pub stops: Vec<Stop>,
1555}
1556
1557#[cfg(test)]
1558mod tests {
1559    use super::*;
1560    use crate::unist::Position;
1561    use alloc::{format, string::ToString, vec};
1562
1563    // Literals.
1564
1565    #[test]
1566    fn text() {
1567        let mut node = Node::Text(Text {
1568            value: "a".into(),
1569            position: None,
1570        });
1571
1572        assert_eq!(
1573            format!("{node:?}"),
1574            "Text { value: \"a\", position: None }",
1575            "should support `Debug`"
1576        );
1577        assert_eq!(node.to_string(), "a", "should support `ToString`");
1578        assert_eq!(node.children_mut(), None, "should support `children_mut`");
1579        assert_eq!(node.children(), None, "should support `children`");
1580        assert_eq!(node.position(), None, "should support `position`");
1581        assert_eq!(node.position_mut(), None, "should support `position`");
1582        node.position_set(Some(Position::new(1, 1, 0, 1, 2, 1)));
1583        assert_eq!(
1584            format!("{node:?}"),
1585            "Text { value: \"a\", position: Some(1:1-1:2 (0-1)) }",
1586            "should support `position_set`"
1587        );
1588    }
1589
1590    #[test]
1591    fn inline_code() {
1592        let mut node = Node::InlineCode(InlineCode {
1593            value: "a".into(),
1594            position: None,
1595            lang: None,
1596        });
1597
1598        assert_eq!(
1599            format!("{node:?}"),
1600            "InlineCode { value: \"a\", position: None, lang: None }",
1601            "should support `Debug`"
1602        );
1603        assert_eq!(node.to_string(), "a", "should support `ToString`");
1604        assert_eq!(node.children_mut(), None, "should support `children_mut`");
1605        assert_eq!(node.children(), None, "should support `children`");
1606        assert_eq!(node.position(), None, "should support `position`");
1607        assert_eq!(node.position_mut(), None, "should support `position`");
1608        node.position_set(Some(Position::new(1, 1, 0, 1, 2, 1)));
1609        assert_eq!(
1610            format!("{node:?}"),
1611            "InlineCode { value: \"a\", position: Some(1:1-1:2 (0-1)), lang: None }",
1612            "should support `position_set`"
1613        );
1614    }
1615
1616    #[test]
1617    fn code() {
1618        let mut node = Node::Code(Code {
1619            fence: None,
1620            value: "a".into(),
1621            position: None,
1622            lang: None,
1623            meta: None,
1624        });
1625
1626        assert_eq!(
1627            format!("{node:?}"),
1628            "Code { value: \"a\", position: None, lang: None, meta: None, fence: None }",
1629            "should support `Debug`"
1630        );
1631        assert_eq!(node.to_string(), "a", "should support `ToString`");
1632        assert_eq!(node.children_mut(), None, "should support `children_mut`");
1633        assert_eq!(node.children(), None, "should support `children`");
1634        assert_eq!(node.position(), None, "should support `position`");
1635        assert_eq!(node.position_mut(), None, "should support `position`");
1636        node.position_set(Some(Position::new(1, 1, 0, 1, 2, 1)));
1637        assert_eq!(
1638            format!("{node:?}"),
1639            "Code { value: \"a\", position: Some(1:1-1:2 (0-1)), lang: None, meta: None, fence: None }",
1640            "should support `position_set`"
1641        );
1642    }
1643
1644    #[test]
1645    fn inline_math() {
1646        let mut node = Node::InlineMath(InlineMath {
1647            value: "a".into(),
1648            position: None,
1649        });
1650
1651        assert_eq!(
1652            format!("{node:?}"),
1653            "InlineMath { value: \"a\", position: None }",
1654            "should support `Debug`"
1655        );
1656        assert_eq!(node.to_string(), "a", "should support `ToString`");
1657        assert_eq!(node.children_mut(), None, "should support `children_mut`");
1658        assert_eq!(node.children(), None, "should support `children`");
1659        assert_eq!(node.position(), None, "should support `position`");
1660        assert_eq!(node.position_mut(), None, "should support `position`");
1661        node.position_set(Some(Position::new(1, 1, 0, 1, 2, 1)));
1662        assert_eq!(
1663            format!("{node:?}"),
1664            "InlineMath { value: \"a\", position: Some(1:1-1:2 (0-1)) }",
1665            "should support `position_set`"
1666        );
1667    }
1668
1669    #[test]
1670    fn math() {
1671        let mut node = Node::Math(Math {
1672            value: "a".into(),
1673            position: None,
1674            meta: None,
1675        });
1676
1677        assert_eq!(
1678            format!("{node:?}"),
1679            "Math { value: \"a\", position: None, meta: None }",
1680            "should support `Debug`"
1681        );
1682        assert_eq!(node.to_string(), "a", "should support `ToString`");
1683        assert_eq!(node.children_mut(), None, "should support `children_mut`");
1684        assert_eq!(node.children(), None, "should support `children`");
1685        assert_eq!(node.position(), None, "should support `position`");
1686        assert_eq!(node.position_mut(), None, "should support `position`");
1687        node.position_set(Some(Position::new(1, 1, 0, 1, 2, 1)));
1688        assert_eq!(
1689            format!("{node:?}"),
1690            "Math { value: \"a\", position: Some(1:1-1:2 (0-1)), meta: None }",
1691            "should support `position_set`"
1692        );
1693    }
1694
1695    #[test]
1696    fn html() {
1697        let mut node = Node::Html(Html {
1698            value: "a".into(),
1699            position: None,
1700        });
1701
1702        assert_eq!(
1703            format!("{node:?}"),
1704            "Html { value: \"a\", position: None }",
1705            "should support `Debug`"
1706        );
1707        assert_eq!(node.to_string(), "a", "should support `ToString`");
1708        assert_eq!(node.children_mut(), None, "should support `children_mut`");
1709        assert_eq!(node.children(), None, "should support `children`");
1710        assert_eq!(node.position(), None, "should support `position`");
1711        assert_eq!(node.position_mut(), None, "should support `position`");
1712        node.position_set(Some(Position::new(1, 1, 0, 1, 2, 1)));
1713        assert_eq!(
1714            format!("{node:?}"),
1715            "Html { value: \"a\", position: Some(1:1-1:2 (0-1)) }",
1716            "should support `position_set`"
1717        );
1718    }
1719
1720    #[test]
1721    fn mdx_text_expression() {
1722        let mut node = Node::MdxTextExpression(MdxTextExpression {
1723            value: "a".into(),
1724            stops: vec![],
1725            position: None,
1726        });
1727
1728        assert_eq!(
1729            format!("{node:?}"),
1730            "MdxTextExpression { value: \"a\", position: None, stops: [] }",
1731            "should support `Debug`"
1732        );
1733        assert_eq!(node.to_string(), "a", "should support `ToString`");
1734        assert_eq!(node.children_mut(), None, "should support `children_mut`");
1735        assert_eq!(node.children(), None, "should support `children`");
1736        assert_eq!(node.position(), None, "should support `position`");
1737        assert_eq!(node.position_mut(), None, "should support `position`");
1738        node.position_set(Some(Position::new(1, 1, 0, 1, 2, 1)));
1739        assert_eq!(
1740            format!("{node:?}"),
1741            "MdxTextExpression { value: \"a\", position: Some(1:1-1:2 (0-1)), stops: [] }",
1742            "should support `position_set`"
1743        );
1744    }
1745
1746    #[test]
1747    fn mdx_flow_expression() {
1748        let mut node = Node::MdxFlowExpression(MdxFlowExpression {
1749            value: "a".into(),
1750            stops: vec![],
1751            position: None,
1752        });
1753
1754        assert_eq!(
1755            format!("{node:?}"),
1756            "MdxFlowExpression { value: \"a\", position: None, stops: [] }",
1757            "should support `Debug`"
1758        );
1759        assert_eq!(node.to_string(), "a", "should support `ToString`");
1760        assert_eq!(node.children_mut(), None, "should support `children_mut`");
1761        assert_eq!(node.children(), None, "should support `children`");
1762        assert_eq!(node.position(), None, "should support `position`");
1763        assert_eq!(node.position_mut(), None, "should support `position`");
1764        node.position_set(Some(Position::new(1, 1, 0, 1, 2, 1)));
1765        assert_eq!(
1766            format!("{node:?}"),
1767            "MdxFlowExpression { value: \"a\", position: Some(1:1-1:2 (0-1)), stops: [] }",
1768            "should support `position_set`"
1769        );
1770    }
1771
1772    #[test]
1773    fn mdxjs_esm() {
1774        let mut node = Node::MdxjsEsm(MdxjsEsm {
1775            value: "a".into(),
1776            stops: vec![],
1777            position: None,
1778        });
1779
1780        assert_eq!(
1781            format!("{node:?}"),
1782            "MdxjsEsm { value: \"a\", position: None, stops: [] }",
1783            "should support `Debug`"
1784        );
1785        assert_eq!(node.to_string(), "a", "should support `ToString`");
1786        assert_eq!(node.children_mut(), None, "should support `children_mut`");
1787        assert_eq!(node.children(), None, "should support `children`");
1788        assert_eq!(node.position(), None, "should support `position`");
1789        assert_eq!(node.position_mut(), None, "should support `position`");
1790        node.position_set(Some(Position::new(1, 1, 0, 1, 2, 1)));
1791        assert_eq!(
1792            format!("{node:?}"),
1793            "MdxjsEsm { value: \"a\", position: Some(1:1-1:2 (0-1)), stops: [] }",
1794            "should support `position_set`"
1795        );
1796    }
1797
1798    // Voids.
1799
1800    #[test]
1801    fn break_node() {
1802        let mut node = Node::Break(Break { position: None });
1803
1804        assert_eq!(
1805            format!("{node:?}"),
1806            "Break { position: None }",
1807            "should support `Debug`"
1808        );
1809        assert_eq!(node.to_string(), "", "should support `ToString`");
1810        assert_eq!(node.children_mut(), None, "should support `children_mut`");
1811        assert_eq!(node.children(), None, "should support `children`");
1812        assert_eq!(node.position(), None, "should support `position`");
1813        assert_eq!(node.position_mut(), None, "should support `position`");
1814        node.position_set(Some(Position::new(1, 1, 0, 1, 2, 1)));
1815        assert_eq!(
1816            format!("{node:?}"),
1817            "Break { position: Some(1:1-1:2 (0-1)) }",
1818            "should support `position_set`"
1819        );
1820    }
1821
1822    #[test]
1823    fn thematic_break() {
1824        let mut node = Node::ThematicBreak(ThematicBreak { position: None });
1825
1826        assert_eq!(
1827            format!("{node:?}"),
1828            "ThematicBreak { position: None }",
1829            "should support `Debug`"
1830        );
1831        assert_eq!(node.to_string(), "", "should support `ToString`");
1832        assert_eq!(node.children_mut(), None, "should support `children_mut`");
1833        assert_eq!(node.children(), None, "should support `children`");
1834        assert_eq!(node.position(), None, "should support `position`");
1835        assert_eq!(node.position_mut(), None, "should support `position`");
1836        node.position_set(Some(Position::new(1, 1, 0, 1, 2, 1)));
1837        assert_eq!(
1838            format!("{node:?}"),
1839            "ThematicBreak { position: Some(1:1-1:2 (0-1)) }",
1840            "should support `position_set`"
1841        );
1842    }
1843
1844    #[test]
1845    fn footnote_reference() {
1846        let mut node = Node::FootnoteReference(FootnoteReference {
1847            position: None,
1848            identifier: "a".into(),
1849            label: Some("b".into()),
1850        });
1851
1852        assert_eq!(
1853            format!("{node:?}"),
1854            "FootnoteReference { position: None, identifier: \"a\", label: Some(\"b\") }",
1855            "should support `Debug`"
1856        );
1857        assert_eq!(node.to_string(), "", "should support `ToString`");
1858        assert_eq!(node.children_mut(), None, "should support `children_mut`");
1859        assert_eq!(node.children(), None, "should support `children`");
1860        assert_eq!(node.position(), None, "should support `position`");
1861        assert_eq!(node.position_mut(), None, "should support `position`");
1862        node.position_set(Some(Position::new(1, 1, 0, 1, 2, 1)));
1863        assert_eq!(
1864            format!("{node:?}"),
1865            "FootnoteReference { position: Some(1:1-1:2 (0-1)), identifier: \"a\", label: Some(\"b\") }",
1866            "should support `position_set`"
1867        );
1868    }
1869
1870    #[test]
1871    fn image_reference() {
1872        let mut node = Node::ImageReference(ImageReference {
1873            position: None,
1874            alt: "a".into(),
1875            identifier: "b".into(),
1876            label: Some("c".into()),
1877            reference_kind: ReferenceKind::Full,
1878        });
1879
1880        assert_eq!(
1881            format!("{node:?}"),
1882            "ImageReference { position: None, alt: \"a\", reference_kind: Full, identifier: \"b\", label: Some(\"c\") }",
1883            "should support `Debug`"
1884        );
1885        assert_eq!(node.to_string(), "", "should support `ToString`");
1886        assert_eq!(node.children_mut(), None, "should support `children_mut`");
1887        assert_eq!(node.children(), None, "should support `children`");
1888        assert_eq!(node.position(), None, "should support `position`");
1889        assert_eq!(node.position_mut(), None, "should support `position`");
1890        node.position_set(Some(Position::new(1, 1, 0, 1, 2, 1)));
1891        assert_eq!(
1892            format!("{node:?}"),
1893            "ImageReference { position: Some(1:1-1:2 (0-1)), alt: \"a\", reference_kind: Full, identifier: \"b\", label: Some(\"c\") }",
1894            "should support `position_set`"
1895        );
1896    }
1897
1898    #[test]
1899    fn image() {
1900        let mut node = Node::Image(Image {
1901            position: None,
1902            alt: "a".into(),
1903            url: "b".into(),
1904            title: None,
1905        });
1906
1907        assert_eq!(
1908            format!("{node:?}"),
1909            "Image { position: None, alt: \"a\", url: \"b\", title: None }",
1910            "should support `Debug`"
1911        );
1912        assert_eq!(node.to_string(), "", "should support `ToString`");
1913        assert_eq!(node.children_mut(), None, "should support `children_mut`");
1914        assert_eq!(node.children(), None, "should support `children`");
1915        assert_eq!(node.position(), None, "should support `position`");
1916        assert_eq!(node.position_mut(), None, "should support `position`");
1917        node.position_set(Some(Position::new(1, 1, 0, 1, 2, 1)));
1918        assert_eq!(
1919            format!("{node:?}"),
1920            "Image { position: Some(1:1-1:2 (0-1)), alt: \"a\", url: \"b\", title: None }",
1921            "should support `position_set`"
1922        );
1923    }
1924
1925    #[test]
1926    fn definition() {
1927        let mut node = Node::Definition(Definition {
1928            position: None,
1929            identifier: "a".into(),
1930            label: None,
1931            url: "b".into(),
1932            title: None,
1933        });
1934
1935        assert_eq!(
1936            format!("{node:?}"),
1937            "Definition { position: None, url: \"b\", title: None, identifier: \"a\", label: None }",
1938            "should support `Debug`"
1939        );
1940        assert_eq!(node.to_string(), "", "should support `ToString`");
1941        assert_eq!(node.children_mut(), None, "should support `children_mut`");
1942        assert_eq!(node.children(), None, "should support `children`");
1943        assert_eq!(node.position(), None, "should support `position`");
1944        assert_eq!(node.position_mut(), None, "should support `position`");
1945        node.position_set(Some(Position::new(1, 1, 0, 1, 2, 1)));
1946        assert_eq!(
1947            format!("{node:?}"),
1948            "Definition { position: Some(1:1-1:2 (0-1)), url: \"b\", title: None, identifier: \"a\", label: None }",
1949            "should support `position_set`"
1950        );
1951    }
1952
1953    // Parents.
1954
1955    #[test]
1956    fn root() {
1957        let mut node = Node::Root(Root {
1958            position: None,
1959            children: vec![],
1960        });
1961
1962        assert_eq!(
1963            format!("{node:?}"),
1964            "Root { children: [], position: None }",
1965            "should support `Debug`"
1966        );
1967        assert_eq!(node.to_string(), "", "should support `ToString`");
1968        assert_eq!(
1969            node.children_mut(),
1970            Some(&mut vec![]),
1971            "should support `children_mut`"
1972        );
1973        assert_eq!(node.children(), Some(&vec![]), "should support `children`");
1974        assert_eq!(node.position(), None, "should support `position`");
1975        assert_eq!(node.position_mut(), None, "should support `position`");
1976        node.position_set(Some(Position::new(1, 1, 0, 1, 2, 1)));
1977        assert_eq!(
1978            format!("{node:?}"),
1979            "Root { children: [], position: Some(1:1-1:2 (0-1)) }",
1980            "should support `position_set`"
1981        );
1982    }
1983
1984    #[test]
1985    fn block_quote() {
1986        let mut node = Node::Blockquote(Blockquote {
1987            position: None,
1988            children: vec![],
1989        });
1990
1991        assert_eq!(
1992            format!("{node:?}"),
1993            "Blockquote { children: [], position: None }",
1994            "should support `Debug`"
1995        );
1996        assert_eq!(node.to_string(), "", "should support `ToString`");
1997        assert_eq!(
1998            node.children_mut(),
1999            Some(&mut vec![]),
2000            "should support `children_mut`"
2001        );
2002        assert_eq!(node.children(), Some(&vec![]), "should support `children`");
2003        assert_eq!(node.position(), None, "should support `position`");
2004        assert_eq!(node.position_mut(), None, "should support `position`");
2005        node.position_set(Some(Position::new(1, 1, 0, 1, 2, 1)));
2006        assert_eq!(
2007            format!("{node:?}"),
2008            "Blockquote { children: [], position: Some(1:1-1:2 (0-1)) }",
2009            "should support `position_set`"
2010        );
2011    }
2012
2013    #[test]
2014    fn delete() {
2015        let mut node = Node::Delete(Delete {
2016            position: None,
2017            children: vec![],
2018        });
2019
2020        assert_eq!(
2021            format!("{node:?}"),
2022            "Delete { children: [], position: None }",
2023            "should support `Debug`"
2024        );
2025        assert_eq!(node.to_string(), "", "should support `ToString`");
2026        assert_eq!(
2027            node.children_mut(),
2028            Some(&mut vec![]),
2029            "should support `children_mut`"
2030        );
2031        assert_eq!(node.children(), Some(&vec![]), "should support `children`");
2032        assert_eq!(node.position(), None, "should support `position`");
2033        assert_eq!(node.position_mut(), None, "should support `position`");
2034        node.position_set(Some(Position::new(1, 1, 0, 1, 2, 1)));
2035        assert_eq!(
2036            format!("{node:?}"),
2037            "Delete { children: [], position: Some(1:1-1:2 (0-1)) }",
2038            "should support `position_set`"
2039        );
2040    }
2041
2042    #[test]
2043    fn emphasis() {
2044        let mut node = Node::Emphasis(Emphasis {
2045            position: None,
2046            children: vec![],
2047        });
2048
2049        assert_eq!(
2050            format!("{node:?}"),
2051            "Emphasis { children: [], position: None }",
2052            "should support `Debug`"
2053        );
2054        assert_eq!(node.to_string(), "", "should support `ToString`");
2055        assert_eq!(
2056            node.children_mut(),
2057            Some(&mut vec![]),
2058            "should support `children_mut`"
2059        );
2060        assert_eq!(node.children(), Some(&vec![]), "should support `children`");
2061        assert_eq!(node.position(), None, "should support `position`");
2062        assert_eq!(node.position_mut(), None, "should support `position`");
2063        node.position_set(Some(Position::new(1, 1, 0, 1, 2, 1)));
2064        assert_eq!(
2065            format!("{node:?}"),
2066            "Emphasis { children: [], position: Some(1:1-1:2 (0-1)) }",
2067            "should support `position_set`"
2068        );
2069    }
2070
2071    #[test]
2072    fn strong() {
2073        let mut node = Node::Strong(Strong {
2074            position: None,
2075            children: vec![],
2076        });
2077
2078        assert_eq!(
2079            format!("{node:?}"),
2080            "Strong { children: [], position: None }",
2081            "should support `Debug`"
2082        );
2083        assert_eq!(node.to_string(), "", "should support `ToString`");
2084        assert_eq!(
2085            node.children_mut(),
2086            Some(&mut vec![]),
2087            "should support `children_mut`"
2088        );
2089        assert_eq!(node.children(), Some(&vec![]), "should support `children`");
2090        assert_eq!(node.position(), None, "should support `position`");
2091        assert_eq!(node.position_mut(), None, "should support `position`");
2092        node.position_set(Some(Position::new(1, 1, 0, 1, 2, 1)));
2093        assert_eq!(
2094            format!("{node:?}"),
2095            "Strong { children: [], position: Some(1:1-1:2 (0-1)) }",
2096            "should support `position_set`"
2097        );
2098    }
2099
2100    #[test]
2101    fn paragraph() {
2102        let mut node = Node::Paragraph(Paragraph {
2103            position: None,
2104            children: vec![],
2105        });
2106
2107        assert_eq!(
2108            format!("{node:?}"),
2109            "Paragraph { children: [], position: None }",
2110            "should support `Debug`"
2111        );
2112        assert_eq!(node.to_string(), "", "should support `ToString`");
2113        assert_eq!(
2114            node.children_mut(),
2115            Some(&mut vec![]),
2116            "should support `children_mut`"
2117        );
2118        assert_eq!(node.children(), Some(&vec![]), "should support `children`");
2119        assert_eq!(node.position(), None, "should support `position`");
2120        assert_eq!(node.position_mut(), None, "should support `position`");
2121        node.position_set(Some(Position::new(1, 1, 0, 1, 2, 1)));
2122        assert_eq!(
2123            format!("{node:?}"),
2124            "Paragraph { children: [], position: Some(1:1-1:2 (0-1)) }",
2125            "should support `position_set`"
2126        );
2127    }
2128
2129    #[test]
2130    fn table_row() {
2131        let mut node = Node::TableRow(TableRow {
2132            position: None,
2133            children: vec![],
2134        });
2135
2136        assert_eq!(
2137            format!("{node:?}"),
2138            "TableRow { children: [], position: None }",
2139            "should support `Debug`"
2140        );
2141        assert_eq!(node.to_string(), "", "should support `ToString`");
2142        assert_eq!(
2143            node.children_mut(),
2144            Some(&mut vec![]),
2145            "should support `children_mut`"
2146        );
2147        assert_eq!(node.children(), Some(&vec![]), "should support `children`");
2148        assert_eq!(node.position(), None, "should support `position`");
2149        assert_eq!(node.position_mut(), None, "should support `position`");
2150        node.position_set(Some(Position::new(1, 1, 0, 1, 2, 1)));
2151        assert_eq!(
2152            format!("{node:?}"),
2153            "TableRow { children: [], position: Some(1:1-1:2 (0-1)) }",
2154            "should support `position_set`"
2155        );
2156    }
2157
2158    #[test]
2159    fn table_cell() {
2160        let mut node = Node::TableCell(TableCell {
2161            position: None,
2162            children: vec![],
2163        });
2164
2165        assert_eq!(
2166            format!("{node:?}"),
2167            "TableCell { children: [], position: None }",
2168            "should support `Debug`"
2169        );
2170        assert_eq!(node.to_string(), "", "should support `ToString`");
2171        assert_eq!(
2172            node.children_mut(),
2173            Some(&mut vec![]),
2174            "should support `children_mut`"
2175        );
2176        assert_eq!(node.children(), Some(&vec![]), "should support `children`");
2177        assert_eq!(node.position(), None, "should support `position`");
2178        assert_eq!(node.position_mut(), None, "should support `position`");
2179        node.position_set(Some(Position::new(1, 1, 0, 1, 2, 1)));
2180        assert_eq!(
2181            format!("{node:?}"),
2182            "TableCell { children: [], position: Some(1:1-1:2 (0-1)) }",
2183            "should support `position_set`"
2184        );
2185    }
2186
2187    #[test]
2188    fn heading() {
2189        let mut node = Node::Heading(Heading {
2190            position: None,
2191            depth: 1,
2192            children: vec![],
2193        });
2194
2195        assert_eq!(
2196            format!("{node:?}"),
2197            "Heading { children: [], position: None, depth: 1 }",
2198            "should support `Debug`"
2199        );
2200        assert_eq!(node.to_string(), "", "should support `ToString`");
2201        assert_eq!(
2202            node.children_mut(),
2203            Some(&mut vec![]),
2204            "should support `children_mut`"
2205        );
2206        assert_eq!(node.children(), Some(&vec![]), "should support `children`");
2207        assert_eq!(node.position(), None, "should support `position`");
2208        assert_eq!(node.position_mut(), None, "should support `position`");
2209        node.position_set(Some(Position::new(1, 1, 0, 1, 2, 1)));
2210        assert_eq!(
2211            format!("{node:?}"),
2212            "Heading { children: [], position: Some(1:1-1:2 (0-1)), depth: 1 }",
2213            "should support `position_set`"
2214        );
2215    }
2216
2217    #[test]
2218    fn table() {
2219        let mut node = Node::Table(Table {
2220            position: None,
2221            align: vec![],
2222            children: vec![],
2223        });
2224
2225        assert_eq!(
2226            format!("{node:?}"),
2227            "Table { children: [], position: None, align: [] }",
2228            "should support `Debug`"
2229        );
2230        assert_eq!(node.to_string(), "", "should support `ToString`");
2231        assert_eq!(
2232            node.children_mut(),
2233            Some(&mut vec![]),
2234            "should support `children_mut`"
2235        );
2236        assert_eq!(node.children(), Some(&vec![]), "should support `children`");
2237        assert_eq!(node.position(), None, "should support `position`");
2238        assert_eq!(node.position_mut(), None, "should support `position`");
2239        node.position_set(Some(Position::new(1, 1, 0, 1, 2, 1)));
2240        assert_eq!(
2241            format!("{node:?}"),
2242            "Table { children: [], position: Some(1:1-1:2 (0-1)), align: [] }",
2243            "should support `position_set`"
2244        );
2245    }
2246
2247    #[test]
2248    fn list_item() {
2249        let mut node = Node::ListItem(ListItem {
2250            position: None,
2251            spread: false,
2252            checked: None,
2253            children: vec![],
2254        });
2255
2256        assert_eq!(
2257            format!("{node:?}"),
2258            "ListItem { children: [], position: None, spread: false, checked: None }",
2259            "should support `Debug`"
2260        );
2261        assert_eq!(node.to_string(), "", "should support `ToString`");
2262        assert_eq!(
2263            node.children_mut(),
2264            Some(&mut vec![]),
2265            "should support `children_mut`"
2266        );
2267        assert_eq!(node.children(), Some(&vec![]), "should support `children`");
2268        assert_eq!(node.position(), None, "should support `position`");
2269        assert_eq!(node.position_mut(), None, "should support `position`");
2270        node.position_set(Some(Position::new(1, 1, 0, 1, 2, 1)));
2271        assert_eq!(
2272            format!("{node:?}"),
2273            "ListItem { children: [], position: Some(1:1-1:2 (0-1)), spread: false, checked: None }",
2274            "should support `position_set`"
2275        );
2276    }
2277
2278    #[test]
2279    fn list() {
2280        let mut node = Node::List(List {
2281            position: None,
2282            spread: false,
2283            ordered: false,
2284            start: None,
2285            children: vec![],
2286        });
2287
2288        assert_eq!(
2289            format!("{node:?}"),
2290            "List { children: [], position: None, ordered: false, start: None, spread: false }",
2291            "should support `Debug`"
2292        );
2293        assert_eq!(node.to_string(), "", "should support `ToString`");
2294        assert_eq!(
2295            node.children_mut(),
2296            Some(&mut vec![]),
2297            "should support `children_mut`"
2298        );
2299        assert_eq!(node.children(), Some(&vec![]), "should support `children`");
2300        assert_eq!(node.position(), None, "should support `position`");
2301        assert_eq!(node.position_mut(), None, "should support `position`");
2302        node.position_set(Some(Position::new(1, 1, 0, 1, 2, 1)));
2303        assert_eq!(
2304            format!("{node:?}"),
2305            "List { children: [], position: Some(1:1-1:2 (0-1)), ordered: false, start: None, spread: false }",
2306            "should support `position_set`"
2307        );
2308    }
2309
2310    #[test]
2311    fn link_reference() {
2312        let mut node = Node::LinkReference(LinkReference {
2313            position: None,
2314            identifier: "a".into(),
2315            label: None,
2316            reference_kind: ReferenceKind::Full,
2317            children: vec![],
2318        });
2319
2320        assert_eq!(
2321            format!("{node:?}"),
2322            "LinkReference { children: [], position: None, reference_kind: Full, identifier: \"a\", label: None }",
2323            "should support `Debug`"
2324        );
2325        assert_eq!(node.to_string(), "", "should support `ToString`");
2326        assert_eq!(
2327            node.children_mut(),
2328            Some(&mut vec![]),
2329            "should support `children_mut`"
2330        );
2331        assert_eq!(node.children(), Some(&vec![]), "should support `children`");
2332        assert_eq!(node.position(), None, "should support `position`");
2333        assert_eq!(node.position_mut(), None, "should support `position`");
2334        node.position_set(Some(Position::new(1, 1, 0, 1, 2, 1)));
2335        assert_eq!(
2336            format!("{node:?}"),
2337            "LinkReference { children: [], position: Some(1:1-1:2 (0-1)), reference_kind: Full, identifier: \"a\", label: None }",
2338            "should support `position_set`"
2339        );
2340    }
2341
2342    #[test]
2343    fn link() {
2344        let mut node = Node::Link(Link {
2345            position: None,
2346            url: "a".into(),
2347            title: None,
2348            children: vec![],
2349        });
2350
2351        assert_eq!(
2352            format!("{node:?}"),
2353            "Link { children: [], position: None, url: \"a\", title: None }",
2354            "should support `Debug`"
2355        );
2356        assert_eq!(node.to_string(), "", "should support `ToString`");
2357        assert_eq!(
2358            node.children_mut(),
2359            Some(&mut vec![]),
2360            "should support `children_mut`"
2361        );
2362        assert_eq!(node.children(), Some(&vec![]), "should support `children`");
2363        assert_eq!(node.position(), None, "should support `position`");
2364        assert_eq!(node.position_mut(), None, "should support `position`");
2365        node.position_set(Some(Position::new(1, 1, 0, 1, 2, 1)));
2366        assert_eq!(
2367            format!("{node:?}"),
2368            "Link { children: [], position: Some(1:1-1:2 (0-1)), url: \"a\", title: None }",
2369            "should support `position_set`"
2370        );
2371    }
2372
2373    #[test]
2374    fn footnote_definition() {
2375        let mut node = Node::FootnoteDefinition(FootnoteDefinition {
2376            position: None,
2377            identifier: "a".into(),
2378            label: None,
2379            children: vec![],
2380        });
2381
2382        assert_eq!(
2383            format!("{node:?}"),
2384            "FootnoteDefinition { children: [], position: None, identifier: \"a\", label: None }",
2385            "should support `Debug`"
2386        );
2387        assert_eq!(node.to_string(), "", "should support `ToString`");
2388        assert_eq!(
2389            node.children_mut(),
2390            Some(&mut vec![]),
2391            "should support `children_mut`"
2392        );
2393        assert_eq!(node.children(), Some(&vec![]), "should support `children`");
2394        assert_eq!(node.position(), None, "should support `position`");
2395        assert_eq!(node.position_mut(), None, "should support `position`");
2396        node.position_set(Some(Position::new(1, 1, 0, 1, 2, 1)));
2397        assert_eq!(
2398            format!("{node:?}"),
2399            "FootnoteDefinition { children: [], position: Some(1:1-1:2 (0-1)), identifier: \"a\", label: None }",
2400            "should support `position_set`"
2401        );
2402    }
2403
2404    #[test]
2405    fn mdx_jsx_flow_element() {
2406        let mut node = Node::MdxJsxFlowElement(MdxJsxFlowElement {
2407            position: None,
2408            name: None,
2409            attributes: vec![],
2410            children: vec![],
2411        });
2412
2413        assert_eq!(
2414            format!("{node:?}"),
2415            "MdxJsxFlowElement { children: [], position: None, name: None, attributes: [] }",
2416            "should support `Debug`"
2417        );
2418        assert_eq!(node.to_string(), "", "should support `ToString`");
2419        assert_eq!(
2420            node.children_mut(),
2421            Some(&mut vec![]),
2422            "should support `children_mut`"
2423        );
2424        assert_eq!(node.children(), Some(&vec![]), "should support `children`");
2425        assert_eq!(node.position(), None, "should support `position`");
2426        assert_eq!(node.position_mut(), None, "should support `position`");
2427        node.position_set(Some(Position::new(1, 1, 0, 1, 2, 1)));
2428        assert_eq!(
2429            format!("{node:?}"),
2430            "MdxJsxFlowElement { children: [], position: Some(1:1-1:2 (0-1)), name: None, attributes: [] }",
2431            "should support `position_set`"
2432        );
2433    }
2434
2435    #[test]
2436    fn mdx_jsx_text_element() {
2437        let mut node = Node::MdxJsxTextElement(MdxJsxTextElement {
2438            position: None,
2439            name: None,
2440            attributes: vec![],
2441            children: vec![],
2442        });
2443
2444        assert_eq!(
2445            format!("{node:?}"),
2446            "MdxJsxTextElement { children: [], position: None, name: None, attributes: [] }",
2447            "should support `Debug`"
2448        );
2449        assert_eq!(node.to_string(), "", "should support `ToString`");
2450        assert_eq!(
2451            node.children_mut(),
2452            Some(&mut vec![]),
2453            "should support `children_mut`"
2454        );
2455        assert_eq!(node.children(), Some(&vec![]), "should support `children`");
2456        assert_eq!(node.position(), None, "should support `position`");
2457        assert_eq!(node.position_mut(), None, "should support `position`");
2458        node.position_set(Some(Position::new(1, 1, 0, 1, 2, 1)));
2459        assert_eq!(
2460            format!("{node:?}"),
2461            "MdxJsxTextElement { children: [], position: Some(1:1-1:2 (0-1)), name: None, attributes: [] }",
2462            "should support `position_set`"
2463        );
2464    }
2465
2466    #[test]
2467    fn fragment_node_methods() {
2468        let text = Node::Text(Text {
2469            value: "fragment".into(),
2470            position: None,
2471        });
2472        let mut node = Node::Fragment(Fragment {
2473            children: vec![text],
2474        });
2475
2476        assert_eq!(
2477            format!("{node:?}"),
2478            "Fragment { children: [Text { value: \"fragment\", position: None }] }"
2479        );
2480        assert_eq!(node.to_string(), "fragment");
2481        assert_eq!(node.children().map(Vec::len), Some(1));
2482        assert_eq!(node.position(), None);
2483        assert_eq!(node.position_mut(), None);
2484        node.position_set(Some(Position::new(1, 1, 0, 1, 2, 1)));
2485        assert_eq!(node.position(), None);
2486
2487        let extracted = node.extract_children().expect("extract fragment children");
2488        assert_eq!(extracted.to_string(), "fragment");
2489        assert_eq!(node.children().unwrap(), &[]);
2490        assert!(node.extract_children().is_some());
2491    }
2492
2493    #[test]
2494    fn walks_and_mutates_nested_children() {
2495        let mut node = Node::Root(Root {
2496            position: None,
2497            children: vec![Node::Paragraph(Paragraph {
2498                position: None,
2499                children: vec![Node::Text(Text {
2500                    value: "before".into(),
2501                    position: None,
2502                })],
2503            })],
2504        });
2505
2506        let mut visited = Vec::new();
2507        node.walk(|node| visited.push(node.to_string()));
2508        assert_eq!(visited, ["before", "before", "before"]);
2509
2510        node.walk_mut(|node| {
2511            if let Node::Text(text) = node {
2512                text.value.push_str(" after");
2513            }
2514        });
2515        assert_eq!(node.text_content(), "before after");
2516    }
2517
2518    #[test]
2519    fn node_text_and_heading_helpers() {
2520        let image = Node::Image(Image {
2521            position: None,
2522            alt: "image alt".into(),
2523            url: "image.png".into(),
2524            title: None,
2525        });
2526        let image_reference = Node::ImageReference(ImageReference {
2527            position: None,
2528            alt: "reference alt".into(),
2529            reference_kind: ReferenceKind::Full,
2530            identifier: "image".into(),
2531            label: None,
2532        });
2533        let heading = Node::Heading(Heading {
2534            position: None,
2535            depth: 2,
2536            children: vec![Node::Text(Text {
2537                value: "Target".into(),
2538                position: None,
2539            })],
2540        });
2541        let root = Node::Root(Root {
2542            position: None,
2543            children: vec![image.clone(), image_reference.clone(), heading.clone()],
2544        });
2545
2546        assert_eq!(image.text_content(), "image alt");
2547        assert_eq!(image_reference.text_content(), "reference alt");
2548        assert_eq!(Node::Break(Break { position: None }).text_content(), "\n");
2549        assert_eq!(
2550            Node::ThematicBreak(ThematicBreak { position: None }).text_content(),
2551            ""
2552        );
2553        assert_eq!(
2554            Node::Definition(Definition {
2555                position: None,
2556                identifier: "x".into(),
2557                label: None,
2558                url: "x".into(),
2559                title: None
2560            })
2561            .text_content(),
2562            ""
2563        );
2564        assert_eq!(root.find_heading("Target"), Some(&heading));
2565        assert_eq!(root.find_heading("missing"), None);
2566        assert_eq!(image.find_heading("Target"), None);
2567        assert_eq!(
2568            Node::Text(Text {
2569                value: "x".into(),
2570                position: None
2571            })
2572            .code_language(),
2573            None
2574        );
2575    }
2576
2577    #[test]
2578    fn code_accessors_cover_optional_metadata() {
2579        let inline = Node::InlineCode(InlineCode {
2580            value: "code".into(),
2581            position: None,
2582            lang: Some("rust".into()),
2583        });
2584        assert_eq!(inline.code_language(), Some("rust"));
2585        assert_eq!(inline.code_info().as_deref(), Some("rust"));
2586
2587        for (lang, meta, expected) in [
2588            (Some("rust"), Some("ignore"), Some("rust ignore")),
2589            (Some("rust"), None, Some("rust")),
2590            (None, Some("ignore"), Some("ignore")),
2591            (None, None, None),
2592        ] {
2593            let code = Node::Code(Code {
2594                fence: None,
2595                value: "code".into(),
2596                position: None,
2597                lang: lang.map(Into::into),
2598                meta: meta.map(Into::into),
2599            });
2600            assert_eq!(code.code_language(), lang);
2601            assert_eq!(code.code_info().as_deref(), expected);
2602        }
2603
2604        assert_eq!(
2605            Node::Text(Text {
2606                value: "plain".into(),
2607                position: None,
2608            })
2609            .code_info(),
2610            None
2611        );
2612    }
2613
2614    #[test]
2615    fn node_serializes_markdown_with_custom_options() {
2616        let node = Node::Text(Text {
2617            value: "text".into(),
2618            position: None,
2619        });
2620        let options = crate::markdown::Options::default();
2621
2622        assert_eq!(node.to_markdown_with_options(&options).unwrap(), "text\n");
2623    }
2624
2625    #[test]
2626    fn replaces_heading_sections_with_all_options() {
2627        let heading = |depth, title: &str| {
2628            Node::Heading(Heading {
2629                position: None,
2630                depth,
2631                children: vec![Node::Text(Text {
2632                    value: title.into(),
2633                    position: None,
2634                })],
2635            })
2636        };
2637        let text = |value: &str| {
2638            Node::Text(Text {
2639                value: value.into(),
2640                position: None,
2641            })
2642        };
2643        let replacement = || vec![text("replacement")];
2644
2645        let mut root = Node::Root(Root {
2646            position: None,
2647            children: vec![
2648                heading(1, "one"),
2649                text("body"),
2650                heading(2, "nested"),
2651                text("nested body"),
2652                heading(1, "two"),
2653            ],
2654        });
2655        assert!(!root.replace_heading_section(1, replacement(), true, false));
2656        assert!(!text("not a parent").replace_heading_section(0, replacement(), true, false));
2657        assert!(root.replace_heading_section(0, replacement(), false, true));
2658        assert_eq!(root.to_string(), "onereplacementtwo");
2659
2660        let mut root = Node::Root(Root {
2661            position: None,
2662            children: vec![
2663                heading(1, "one"),
2664                text("body"),
2665                heading(2, "nested"),
2666                text("nested body"),
2667                heading(1, "two"),
2668            ],
2669        });
2670        assert!(root.replace_heading_section(0, replacement(), true, false));
2671        assert_eq!(root.to_string(), "replacementnestednested bodytwo");
2672
2673        let mut root = Node::Root(Root {
2674            position: None,
2675            children: vec![
2676                heading(1, "one"),
2677                text("body"),
2678                heading(2, "nested"),
2679                text("nested body"),
2680                heading(1, "two"),
2681            ],
2682        });
2683        assert!(root.replace_heading_section(0, replacement(), true, true));
2684        assert_eq!(root.to_string(), "replacementtwo");
2685    }
2686
2687    #[cfg(feature = "serde")]
2688    #[test]
2689    fn align_kind_serialization_and_visitors() {
2690        use serde::de::Visitor;
2691
2692        assert_eq!(serde_json::to_string(&AlignKind::Left).unwrap(), "\"left\"");
2693        assert_eq!(
2694            serde_json::to_string(&AlignKind::Right).unwrap(),
2695            "\"right\""
2696        );
2697        assert_eq!(
2698            serde_json::to_string(&AlignKind::Center).unwrap(),
2699            "\"center\""
2700        );
2701        assert_eq!(serde_json::to_string(&AlignKind::None).unwrap(), "null");
2702        assert_eq!(
2703            serde_json::from_str::<AlignKind>("\"left\"").unwrap(),
2704            AlignKind::Left
2705        );
2706        assert_eq!(
2707            serde_json::from_str::<AlignKind>("null").unwrap(),
2708            AlignKind::None
2709        );
2710
2711        assert_eq!(
2712            AlignKindVisitor
2713                .visit_bytes::<serde_json::Error>(b"right")
2714                .unwrap(),
2715            AlignKind::Right
2716        );
2717        assert_eq!(
2718            AlignKindVisitor
2719                .visit_bytes::<serde_json::Error>(b"left")
2720                .unwrap(),
2721            AlignKind::Left
2722        );
2723        assert_eq!(
2724            AlignKindVisitor
2725                .visit_bytes::<serde_json::Error>(b"center")
2726                .unwrap(),
2727            AlignKind::Center
2728        );
2729        assert_eq!(
2730            AlignKindVisitor.visit_none::<serde_json::Error>().unwrap(),
2731            AlignKind::None
2732        );
2733        assert_eq!(
2734            AlignKindVisitor.visit_unit::<serde_json::Error>().unwrap(),
2735            AlignKind::None
2736        );
2737        assert!(AlignKindVisitor
2738            .visit_str::<serde_json::Error>("invalid")
2739            .is_err());
2740        assert!(AlignKindVisitor
2741            .visit_bytes::<serde_json::Error>(b"invalid")
2742            .is_err());
2743    }
2744}