1use 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
29pub type Stop = (usize, usize);
32
33#[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 Shortcut,
43 Collapsed,
45 Full,
47}
48
49#[derive(Clone, Copy, Debug, Eq, PartialEq)]
53pub enum AlignKind {
54 Left,
64 Right,
74 Center,
84 None,
94}
95
96#[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#[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 Root(Root),
189
190 Fragment(Fragment),
195 Blockquote(Blockquote),
197 FootnoteDefinition(FootnoteDefinition),
199 MdxJsxFlowElement(MdxJsxFlowElement),
201 List(List),
203
204 Frontmatter(Frontmatter),
207 MdxjsEsm(MdxjsEsm),
209
210 Break(Break),
213 InlineCode(InlineCode),
215 InlineMath(InlineMath),
217 Delete(Delete),
219 Emphasis(Emphasis),
221 MdxTextExpression(MdxTextExpression),
223 FootnoteReference(FootnoteReference),
225 Html(Html),
227 Image(Image),
229 ImageReference(ImageReference),
231 MdxJsxTextElement(MdxJsxTextElement),
233 Link(Link),
235 LinkReference(LinkReference),
237 Strong(Strong),
239 Text(Text),
241
242 Code(Code),
245 Math(Math),
247 MdxFlowExpression(MdxFlowExpression),
249 Heading(Heading),
251 Table(Table),
255 ThematicBreak(ThematicBreak),
257
258 TableRow(TableRow),
261
262 TableCell(TableCell),
265
266 ListItem(ListItem),
269
270 Definition(Definition),
273 Paragraph(Paragraph),
275}
276
277impl fmt::Debug for Node {
278 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#[allow(clippy::to_string_trait_impl)]
325impl ToString for Node {
326 fn to_string(&self) -> String {
327 match self {
328 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 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 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 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 _ => None,
396 }
397 }
398
399 pub fn children_mut(&mut self) -> Option<&mut Vec<Node>> {
400 match self {
401 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 _ => 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 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 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 #[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 #[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 #[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 #[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 #[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 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 pub fn render_with<R: crate::renderer::Renderer>(&self, renderer: &mut R) -> String {
666 renderer.render(self)
667 }
668
669 #[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 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 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#[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 Expression(MdxJsxExpressionAttribute),
759 Property(MdxJsxAttribute),
766}
767#[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#[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(AttributeValueExpression),
795 Literal(String),
802}
803
804#[derive(Clone, Debug, Eq, PartialEq)]
809#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
810pub struct Fragment {
811 pub children: Vec<Node>,
813}
814
815#[derive(Clone, Debug, Eq, PartialEq)]
822#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
823pub struct Root {
824 pub children: Vec<Node>,
827 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
829 pub position: Option<Position>,
830}
831
832#[derive(Clone, Debug, Eq, PartialEq)]
839#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
840pub struct Paragraph {
841 pub children: Vec<Node>,
844 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
846 pub position: Option<Position>,
847}
848
849#[derive(Clone, Debug, Eq, PartialEq)]
856#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
857pub struct Heading {
858 pub children: Vec<Node>,
861 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
863 pub position: Option<Position>,
864 pub depth: u8,
867}
868
869#[derive(Clone, Debug, Eq, PartialEq)]
876#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
877pub struct ThematicBreak {
878 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
881 pub position: Option<Position>,
882}
883
884#[derive(Clone, Debug, Eq, PartialEq)]
891#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
892pub struct Blockquote {
893 pub children: Vec<Node>,
896 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
898 pub position: Option<Position>,
899}
900
901#[derive(Clone, Debug, Eq, PartialEq)]
908#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
909pub struct List {
910 pub children: Vec<Node>,
913 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
915 pub position: Option<Position>,
916 pub ordered: bool,
919 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
922 pub start: Option<u32>,
923 pub spread: bool,
926}
927
928#[derive(Clone, Debug, Eq, PartialEq)]
935#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
936pub struct ListItem {
937 pub children: Vec<Node>,
940 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
942 pub position: Option<Position>,
943 pub spread: bool,
947 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
950 pub checked: Option<bool>,
951}
952
953#[derive(Clone, Debug, Eq, PartialEq)]
960#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
961pub struct Html {
962 pub value: String,
965 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
967 pub position: Option<Position>,
968}
969
970#[derive(Clone, Debug, Eq, PartialEq)]
981#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
982pub struct Math {
983 pub value: String,
986 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
988 pub position: Option<Position>,
989 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
992 pub meta: Option<String>,
993}
994
995#[derive(Clone, Debug, Eq, PartialEq)]
1002#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1003pub struct Definition {
1004 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1007 pub position: Option<Position>,
1008 pub url: String,
1011 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1014 pub title: Option<String>,
1015 pub identifier: String,
1021 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1028 pub label: Option<String>,
1029}
1030
1031#[derive(Clone, Debug, Eq, PartialEq)]
1038#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1039pub struct Text {
1040 pub value: String,
1043 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1045 pub position: Option<Position>,
1046}
1047
1048#[derive(Clone, Debug, Eq, PartialEq)]
1055#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1056pub struct Emphasis {
1057 pub children: Vec<Node>,
1060 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1062 pub position: Option<Position>,
1063}
1064
1065#[derive(Clone, Debug, Eq, PartialEq)]
1072#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1073pub struct Strong {
1074 pub children: Vec<Node>,
1077 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1079 pub position: Option<Position>,
1080}
1081
1082#[derive(Clone, Debug, Eq, PartialEq)]
1089#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1090pub struct InlineCode {
1091 pub value: String,
1094 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1096 pub position: Option<Position>,
1097 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1102 pub lang: Option<String>,
1103}
1104
1105#[derive(Clone, Debug, Eq, PartialEq)]
1112#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1113pub struct InlineMath {
1114 pub value: String,
1117 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1119 pub position: Option<Position>,
1120}
1121
1122#[derive(Clone, Debug, Eq, PartialEq)]
1130#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1131pub struct Break {
1132 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1135 pub position: Option<Position>,
1136}
1137
1138#[derive(Clone, Debug, Eq, PartialEq)]
1145#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1146pub struct Link {
1147 pub children: Vec<Node>,
1150 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1152 pub position: Option<Position>,
1153 pub url: String,
1156 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1159 pub title: Option<String>,
1160}
1161
1162#[derive(Clone, Debug, Eq, PartialEq)]
1169#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1170pub struct Image {
1171 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1174 pub position: Option<Position>,
1175 pub alt: String,
1179 pub url: String,
1182 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1185 pub title: Option<String>,
1186}
1187
1188#[derive(Clone, Debug, Eq, PartialEq)]
1195#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1196pub struct LinkReference {
1197 pub children: Vec<Node>,
1200 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1202 pub position: Option<Position>,
1203 #[cfg_attr(feature = "serde", serde(rename = "referenceType"))]
1206 pub reference_kind: ReferenceKind,
1207 pub identifier: String,
1213 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1220 pub label: Option<String>,
1221}
1222
1223#[derive(Clone, Debug, Eq, PartialEq)]
1230#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1231pub struct ImageReference {
1232 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1235 pub position: Option<Position>,
1236 pub alt: String,
1240 #[cfg_attr(feature = "serde", serde(rename = "referenceType"))]
1243 pub reference_kind: ReferenceKind,
1244 pub identifier: String,
1250 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1257 pub label: Option<String>,
1258}
1259
1260#[derive(Clone, Debug, Eq, PartialEq)]
1267#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1268pub struct FootnoteDefinition {
1269 pub children: Vec<Node>,
1272 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1274 pub position: Option<Position>,
1275 pub identifier: String,
1281 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1288 pub label: Option<String>,
1289}
1290
1291#[derive(Clone, Debug, Eq, PartialEq)]
1298#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1299pub struct FootnoteReference {
1300 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1303 pub position: Option<Position>,
1304 pub identifier: String,
1310 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1317 pub label: Option<String>,
1318}
1319
1320#[derive(Clone, Debug, Eq, PartialEq)]
1329#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1330pub struct Table {
1331 pub children: Vec<Node>,
1334 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1336 pub position: Option<Position>,
1337 pub align: Vec<AlignKind>,
1340}
1341
1342#[derive(Clone, Debug, Eq, PartialEq)]
1349#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1350pub struct TableRow {
1351 pub children: Vec<Node>,
1354 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1356 pub position: Option<Position>,
1357}
1358
1359#[derive(Clone, Debug, Eq, PartialEq)]
1366#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1367pub struct TableCell {
1368 pub children: Vec<Node>,
1371 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1373 pub position: Option<Position>,
1374}
1375
1376#[derive(Clone, Debug, Eq, PartialEq)]
1383#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1384pub struct Delete {
1385 pub children: Vec<Node>,
1388 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1390 pub position: Option<Position>,
1391}
1392
1393#[derive(Clone, Debug, Eq, PartialEq)]
1400#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1401pub struct MdxjsEsm {
1402 pub value: String,
1405 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1407 pub position: Option<Position>,
1408
1409 #[cfg_attr(feature = "serde", serde(rename = "_markdownRsStops"))]
1411 pub stops: Vec<Stop>,
1412}
1413
1414#[derive(Clone, Debug, Eq, PartialEq)]
1421#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1422pub struct MdxFlowExpression {
1423 pub value: String,
1426 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1428 pub position: Option<Position>,
1429
1430 #[cfg_attr(feature = "serde", serde(rename = "_markdownRsStops"))]
1432 pub stops: Vec<Stop>,
1433}
1434
1435#[derive(Clone, Debug, Eq, PartialEq)]
1442#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1443pub struct MdxTextExpression {
1444 pub value: String,
1447 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1449 pub position: Option<Position>,
1450
1451 #[cfg_attr(feature = "serde", serde(rename = "_markdownRsStops"))]
1453 pub stops: Vec<Stop>,
1454}
1455
1456#[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 pub children: Vec<Node>,
1472 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1474 pub position: Option<Position>,
1475 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1480 pub name: Option<String>,
1481 pub attributes: Vec<AttributeContent>,
1483}
1484
1485#[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 pub children: Vec<Node>,
1501 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1503 pub position: Option<Position>,
1504 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1509 pub name: Option<String>,
1510 pub attributes: Vec<AttributeContent>,
1512}
1513
1514#[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 pub name: String,
1532 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
1534 pub value: Option<AttributeValue>,
1535}
1536
1537#[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 pub value: String,
1552 #[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 #[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 #[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 #[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}