use markdown::mdast::{List, ListItem, Node, Paragraph, Root, Text, ThematicBreak}; use mdast_util_to_markdown::{ to_markdown as to, to_markdown_with_options as to_md_with_opts, IndentOptions, Options, }; use pretty_assertions::assert_eq; #[test] fn list_item() { assert_eq!( to(&Node::ListItem(ListItem { children: vec![], position: None, spread: false, checked: None })) .unwrap(), "*\n", "should support a list item" ); assert_eq!( to_md_with_opts( &Node::ListItem(ListItem { children: Vec::new(), position: None, spread: false, checked: None }), &Options { bullet: '+', ..Default::default() } ) .unwrap(), "+\n", "should serialize an item w/ a plus as bullet when `bullet: \" + \"`" ); assert_eq!( to(&Node::ListItem(ListItem { children: vec![Node::Paragraph(Paragraph { children: vec![Node::Text(Text { value: String::from("a"), position: None })], position: None })], position: None, spread: false, checked: None })) .unwrap(), "* a\n", "should support a list item w/ a child" ); assert_eq!( to(&Node::ListItem(ListItem { children: vec![ Node::Paragraph(Paragraph { children: vec![Node::Text(Text { value: String::from("a"), position: None })], position: None }), Node::ThematicBreak(ThematicBreak { position: None }), Node::Paragraph(Paragraph { children: vec![Node::Text(Text { value: String::from("b"), position: None })], position: None }), ], position: None, spread: false, checked: None })) .unwrap(), "* a\n ***\n b\n", "should support a list item w/ children" ); assert_eq!( to_md_with_opts( &Node::ListItem(ListItem { children: vec![ Node::Paragraph(Paragraph { children: vec![Node::Text(Text { value: String::from("a"), position: None })], position: None }), Node::ThematicBreak(ThematicBreak { position: None }) ], position: None, spread: false, checked: None }), &Options { list_item_indent: IndentOptions::One, ..Default::default() } ) .unwrap(), "* a\n ***\n", "should use one space after the bullet for `list_item_indent: \"IndentOptions::One\"`" ); assert_eq!( to_md_with_opts( &Node::ListItem(ListItem { children: vec![Node::Paragraph(Paragraph { children: vec![Node::Text(Text { value: String::from("a"), position: None })], position: None }),], position: None, spread: false, checked: None }), &Options { list_item_indent: IndentOptions::Mixed, ..Default::default() } ) .unwrap(), "* a\n", "should use one space after the bullet for `list_item_indent: \"IndentOptions::Mixed\"`, when the item is not spread" ); assert_eq!( to_md_with_opts( &Node::ListItem(ListItem { children: vec![Node::Paragraph(Paragraph { children: vec![Node::Text(Text { value: String::from("a"), position: None })], position: None }), Node::ThematicBreak(ThematicBreak { position: None })], position: None, spread: true, checked: None }), &Options { list_item_indent: IndentOptions::Mixed, ..Default::default() } ) .unwrap(), "* a\n\n ***\n", "should use a tab stop of spaces after the bullet for `list_item_indent: \"IndentOptions::Mixed\"`, when the item is spread" ); assert_eq!( to(&Node::ListItem(ListItem { children: vec![ Node::Paragraph(Paragraph { children: vec![Node::Text(Text { value: String::from("a"), position: None })], position: None }), Node::ThematicBreak(ThematicBreak { position: None }), ], position: None, spread: false, checked: None })) .unwrap(), "* a\n ***\n", "should not use blank lines between child blocks for items w/ `spread: false`" ); assert_eq!( to_md_with_opts( &create_list(create_list(create_list::>(None))), &Options { bullet_other: '+', ..Default::default() } ) .unwrap(), "* * +\n", "should support `bullet_other`" ); assert_eq!( to_md_with_opts( &create_list(create_list(create_list::>(None))), &Options { bullet: '-', ..Default::default() } ) .unwrap(), "- - *\n", "should default to an `bullet_other` different from `bullet` (1)" ); assert_eq!( to_md_with_opts( &create_list(create_list(create_list::>(None))), &Options { bullet: '*', ..Default::default() } ) .unwrap(), "* * -\n", "should default to an `bullet_other` different from `bullet` (2)" ); assert_eq!( to(&Node::List(List { children: vec![ Node::ListItem(ListItem { children: vec![Node::Paragraph(Paragraph { children: vec![Node::Text(Text { value: String::from("a"), position: None })], position: None }),], position: None, spread: false, checked: None }), Node::ListItem(ListItem { children: vec![Node::ThematicBreak(ThematicBreak { position: None })], position: None, spread: false, checked: None }) ], position: None, ordered: false, start: None, spread: false })) .unwrap(), "- a\n- ***\n", "should use a different bullet than a thematic rule marker, if the first child of a list item is a thematic break (2)" ); assert_eq!( to(&create_list(create_list::>(None))).unwrap(), "* *\n", "should *not* use a different bullet for an empty list item in two lists" ); assert_eq!( to(&create_list(create_list(create_list::>(None)))).unwrap(), "* * -\n", "should use a different bullet for an empty list item in three lists (1)" ); assert_eq!( to(&Node::List(List { children: vec![ Node::ListItem(ListItem { children: vec![], position: None, spread: false, checked: None }), Node::ListItem(ListItem { children: vec![create_list(create_list::>(None))], position: None, spread: false, checked: None }) ], position: None, ordered: false, start: None, spread: false })) .unwrap(), "*\n* * -\n", "should use a different bullet for an empty list item in three lists (2)" ); assert_eq!( to_md_with_opts( &create_list(create_list(create_list::>(None))), &Options { bullet: '+', ..Default::default() } ) .unwrap(), "+ + +\n", "should not use a different bullet for an empty list item in three lists if `bullet` isn’t a thematic rule marker" ); assert_eq!( to(&create_list(create_list(create_list(create_list::< Option, >(None))))) .unwrap(), "* * * -\n", "should use a different bullet for an empty list item in four lists" ); assert_eq!( to(&create_list(create_list(create_list(create_list( create_list::>(None) ))))) .unwrap(), "* * * * -\n", "should use a different bullet for an empty list item in five lists" ); assert_eq!( to(&create_list(create_list(vec![ create_list(Node::Paragraph(Paragraph { children: vec![Node::Text(Text { value: String::from("a"), position: None })], position: None })), create_list::>(None) ]))) .unwrap(), "* * * a\n -\n", "should not use a different bullet for an empty list item at non-head in two lists" ); assert_eq!( to_md_with_opts( &Node::List(List { children: vec![Node::ListItem(ListItem { children: vec![], position: None, spread: false, checked: None })], position: None, ordered: true, start: None, spread: false }), &Options { bullet_ordered: ')', ..Default::default() } ) .unwrap(), "1)\n", "should support `bullet_ordered`" ); assert_eq!( to_md_with_opts( &Node::Root(Root { children: vec![ Node::List(List { children: vec![Node::ListItem(ListItem { children: vec![], position: None, spread: false, checked: None })], position: None, ordered: true, start: None, spread: false }), Node::List(List { children: vec![Node::ListItem(ListItem { children: vec![], position: None, spread: false, checked: None })], position: None, ordered: true, start: None, spread: false }), ], position: None }), &Options { bullet_ordered: ')', ..Default::default() } ) .unwrap(), "1)\n\n1.\n", "should use a different bullet for adjacent ordered lists" ); } trait IntoVecNode { fn into_vec(self) -> Vec; } impl IntoVecNode for Node { fn into_vec(self) -> Vec { vec![self] } } impl IntoVecNode for Option { fn into_vec(self) -> Vec { self.map(|n| vec![n]).unwrap_or_default() } } impl IntoVecNode for Vec { fn into_vec(self) -> Vec { self } } fn create_list(d: T) -> Node where T: IntoVecNode, { Node::List(List { children: vec![Node::ListItem(ListItem { children: d.into_vec(), position: None, spread: false, checked: None, })], position: None, ordered: false, start: None, spread: false, }) }