use markdown::{ mdast::{List, ListItem, Node, Paragraph, Root, Text}, to_html, to_html_with_options, to_mdast, unist::Position, CompileOptions, Constructs, Options, ParseOptions, }; use pretty_assertions::assert_eq; #[test] fn list() -> Result<(), String> { let danger = Options { compile: CompileOptions { allow_dangerous_html: true, allow_dangerous_protocol: true, ..Default::default() }, ..Default::default() }; assert_eq!( to_html( "A paragraph\nwith two lines.\n\n indented code\n\n> A block quote."), "

A paragraph\nwith two lines.

\n
indented code\n
\n
\n

A block quote.

\n
", "should support documents" ); assert_eq!( to_html("1. a\n b.\n\n c\n\n > d."), "
    \n
  1. \n

    a\nb.

    \n
    c\n
    \n
    \n

    d.

    \n
    \n
  2. \n
", "should support documents in list items" ); assert_eq!( to_html("- one\n\n two"), "\n

two

", "should not support 1 space for a two-character list prefix" ); assert_eq!( to_html("- a\n\n b"), "", "should support blank lines in list items" ); assert_eq!( to_html(" - one\n\n two"), "\n
 two\n
", "should support indented code after lists" ); assert_eq!( to_html(" > > 1. one\n>>\n>> two"), "
\n
\n
    \n
  1. \n

    one

    \n

    two

    \n
  2. \n
\n
\n
", "should support proper indent mixed w/ block quotes (1)" ); assert_eq!( to_html(">>- one\n>>\n > > two"), "
\n
\n\n

two

\n
\n
", "should support proper indent mixed w/ block quotes (2)" ); assert_eq!( to_html("-one\n\n2.two"), "

-one

\n

2.two

", "should not support a missing space after marker" ); assert_eq!( to_html("- foo\n\n\n bar"), "", "should support multiple blank lines between items" ); assert_eq!( to_html("1. foo\n\n ```\n bar\n ```\n\n baz\n\n > bam"), "
    \n
  1. \n

    foo

    \n
    bar\n
    \n

    baz

    \n
    \n

    bam

    \n
    \n
  2. \n
", "should support flow in items" ); assert_eq!( to_html("- Foo\n\n bar\n\n\n baz"), "", "should support blank lines in indented code in items" ); assert_eq!( to_html("123456789. ok"), "
    \n
  1. ok
  2. \n
", "should support start on the first list item" ); assert_eq!( to_html("1234567890. not ok"), "

1234567890. not ok

", "should not support ordered item values over 10 digits" ); assert_eq!( to_html("0. ok"), "
    \n
  1. ok
  2. \n
", "should support ordered item values of `0`" ); assert_eq!( to_html("003. ok"), "
    \n
  1. ok
  2. \n
", "should support ordered item values starting w/ `0`s" ); assert_eq!( to_html("-1. not ok"), "

-1. not ok

", "should not support “negative” ordered item values" ); assert_eq!( to_html("- foo\n\n bar"), "", "should support indented code in list items (1)" ); assert_eq!( to_html(" 10. foo\n\n bar"), "
    \n
  1. \n

    foo

    \n
    bar\n
    \n
  2. \n
", "should support indented code in list items (2)" ); assert_eq!( to_html(" indented code\n\nparagraph\n\n more code"), "
indented code\n
\n

paragraph

\n
more code\n
", "should support indented code in list items (3)" ); assert_eq!( to_html("1. indented code\n\n paragraph\n\n more code"), "
    \n
  1. \n
    indented code\n
    \n

    paragraph

    \n
    more code\n
    \n
  2. \n
", "should support indented code in list items (4)" ); assert_eq!( to_html("1. indented code\n\n paragraph\n\n more code"), "
    \n
  1. \n
     indented code\n
    \n

    paragraph

    \n
    more code\n
    \n
  2. \n
", "should support indented code in list items (5)" ); assert_eq!( to_html(" foo\n\nbar"), "

foo

\n

bar

", "should support indented code in list items (6)" ); assert_eq!( to_html("- foo\n\n bar"), "\n

bar

", "should support indented code in list items (7)" ); assert_eq!( to_html("- foo\n\n bar"), "", "should support indented code in list items (8)" ); assert_eq!( to_html("-\n foo\n-\n ```\n bar\n ```\n-\n baz"), "", "should support blank first lines (1)" ); assert_eq!( to_html("- \n foo"), "", "should support blank first lines (2)" ); assert_eq!( to_html("-\n\n foo"), "\n

foo

", "should support empty only items" ); assert_eq!( to_html("- foo\n-\n- bar"), "", "should support empty continued items" ); assert_eq!( to_html("- foo\n- \n- bar"), "", "should support blank continued items" ); assert_eq!( to_html("1. foo\n2.\n3. bar"), "
    \n
  1. foo
  2. \n
  3. \n
  4. bar
  5. \n
", "should support empty continued items (ordered)" ); assert_eq!( to_html("*"), "", "should support a single empty item" ); assert_eq!( to_html("foo\n*\n\nfoo\n1."), "

foo\n*

\n

foo\n1.

", "should not support empty items to interrupt paragraphs" ); assert_eq!( to_html( " 1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote."), "
    \n
  1. \n

    A paragraph\nwith two lines.

    \n
    indented code\n
    \n
    \n

    A block quote.

    \n
    \n
  2. \n
", "should support indenting w/ 1 space" ); assert_eq!( to_html( " 1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote."), "
    \n
  1. \n

    A paragraph\nwith two lines.

    \n
    indented code\n
    \n
    \n

    A block quote.

    \n
    \n
  2. \n
", "should support indenting w/ 2 spaces" ); assert_eq!( to_html( " 1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote."), "
    \n
  1. \n

    A paragraph\nwith two lines.

    \n
    indented code\n
    \n
    \n

    A block quote.

    \n
    \n
  2. \n
", "should support indenting w/ 3 spaces" ); assert_eq!( to_html( " 1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote."), "
1.  A paragraph\n    with two lines.\n\n        indented code\n\n    > A block quote.\n
", "should not support indenting w/ 4 spaces" ); assert_eq!( to_html( " 1. A paragraph\nwith two lines.\n\n indented code\n\n > A block quote."), "
    \n
  1. \n

    A paragraph\nwith two lines.

    \n
    indented code\n
    \n
    \n

    A block quote.

    \n
    \n
  2. \n
", "should support lazy lines" ); assert_eq!( to_html(" 1. A paragraph\n with two lines."), "
    \n
  1. A paragraph\nwith two lines.
  2. \n
", "should support partially lazy lines" ); assert_eq!( to_html("> 1. > Blockquote\ncontinued here."), "
\n
    \n
  1. \n
    \n

    Blockquote\ncontinued here.

    \n
    \n
  2. \n
\n
", "should support lazy lines combined w/ other containers" ); assert_eq!( to_html("> 1. > Blockquote\n> continued here."), "
\n
    \n
  1. \n
    \n

    Blockquote\ncontinued here.

    \n
    \n
  2. \n
\n
", "should support partially continued, partially lazy lines combined w/ other containers" ); assert_eq!( to_html("- [\na"), "", "should support lazy, definition-like lines" ); assert_eq!( to_html("- [a]: b\nc"), "", "should support a definition, followed by a lazy paragraph" ); assert_eq!( to_html("- foo\n - bar\n - baz\n - boo"), "", "should support sublists w/ enough spaces (1)" ); assert_eq!( to_html("- foo\n - bar\n - baz\n - boo"), "", "should not support sublists w/ too few spaces" ); assert_eq!( to_html("10) foo\n - bar"), "
    \n
  1. foo\n\n
  2. \n
", "should support sublists w/ enough spaces (2)" ); assert_eq!( to_html("10) foo\n - bar"), "
    \n
  1. foo
  2. \n
\n", "should not support sublists w/ too few spaces (2)" ); assert_eq!( to_html("- - foo"), "", "should support sublists (1)" ); assert_eq!( to_html("1. - 2. foo"), "
    \n
  1. \n\n
  2. \n
", "should support sublists (2)" ); assert_eq!( to_html("- # Foo\n- Bar\n ---\n baz"), "", "should support headings in list items" ); assert_eq!( to_html("- foo\n- bar\n+ baz"), "\n", "should support a new list by changing the marker (unordered)" ); assert_eq!( to_html("1. foo\n2. bar\n3) baz"), "
    \n
  1. foo
  2. \n
  3. bar
  4. \n
\n
    \n
  1. baz
  2. \n
", "should support a new list by changing the marker (ordered)" ); assert_eq!( to_html("Foo\n- bar\n- baz"), "

Foo

\n", "should support interrupting a paragraph" ); assert_eq!( to_html("a\n2. b"), "

a\n2. b

", "should not support interrupting a paragraph with a non-1 numbered item" ); assert_eq!( to_html("\n2. a"), "
    \n
  1. a
  2. \n
", "should “interrupt” a blank line (1)" ); assert_eq!( to_html("a\n\n2. b"), "

a

\n
    \n
  1. b
  2. \n
", "should “interrupt” a blank line (2)" ); assert_eq!( to_html("a\n1. b"), "

a

\n
    \n
  1. b
  2. \n
", "should support interrupting a paragraph with a 1 numbered item" ); assert_eq!( to_html("- foo\n\n- bar\n\n\n- baz"), "", "should support blank lines between items (1)" ); assert_eq!( to_html("- foo\n - bar\n - baz\n\n\n bim"), "", "should support blank lines between items (2)" ); assert_eq!( to_html_with_options("- foo\n- bar\n\n\n\n- baz\n- bim", &danger)?, "\n\n", "should support HTML comments between lists" ); assert_eq!( to_html_with_options("- foo\n\n notcode\n\n- foo\n\n\n\n code", &danger)?, "\n\n
code\n
", "should support HTML comments between lists and indented code" ); assert_eq!( to_html("- a\n - b\n - c\n - d\n - e\n - f\n- g"), "", "should not support lists in lists w/ too few spaces (1)" ); assert_eq!( to_html("1. a\n\n 2. b\n\n 3. c"), "
    \n
  1. \n

    a

    \n
  2. \n
  3. \n

    b

    \n
  4. \n
  5. \n

    c

    \n
  6. \n
", "should not support lists in lists w/ too few spaces (2)" ); assert_eq!( to_html("- a\n - b\n - c\n - d\n - e"), "", "should not support lists in lists w/ too few spaces (3)" ); assert_eq!( to_html("1. a\n\n 2. b\n\n 3. c"), "
    \n
  1. \n

    a

    \n
  2. \n
  3. \n

    b

    \n
  4. \n
\n
3. c\n
", "should not support lists in lists w/ too few spaces (3)" ); assert_eq!( to_html("- a\n- b\n\n- c"), "", "should support loose lists w/ a blank line between (1)" ); assert_eq!( to_html("* a\n*\n\n* c"), "", "should support loose lists w/ a blank line between (2)" ); assert_eq!( to_html("- a\n- b\n\n c\n- d"), "", "should support loose lists w/ a blank line in an item (1)" ); assert_eq!( to_html("- a\n- b\n\n [ref]: /url\n- d"), "", "should support loose lists w/ a blank line in an item (2)" ); assert_eq!( to_html("- a\n- ```\n b\n\n\n ```\n- c"), "", "should support tight lists w/ a blank line in fenced code" ); assert_eq!( to_html("- a\n - b\n\n c\n- d"), "", "should support tight lists w/ a blank line in a sublist" ); assert_eq!( to_html("* a\n > b\n >\n* c"), "", "should support tight lists w/ a blank line in a block quote" ); assert_eq!( to_html("- a\n > b\n ```\n c\n ```\n- d"), "", "should support tight lists w/ flow w/o blank line" ); assert_eq!( to_html("- a"), "", "should support tight lists w/ a single content" ); assert_eq!( to_html("- a\n - b"), "", "should support tight lists w/ a sublist" ); assert_eq!( to_html("1. ```\n foo\n ```\n\n bar"), "
    \n
  1. \n
    foo\n
    \n

    bar

    \n
  2. \n
", "should support loose lists w/ a blank line in an item" ); assert_eq!( to_html("* foo\n * bar\n\n baz"), "", "should support loose lists w/ tight sublists (1)" ); assert_eq!( to_html("- a\n - b\n - c\n\n- d\n - e\n - f"), "", "should support loose lists w/ tight sublists (2)" ); // Extra. assert_eq!( to_html("* a\n*\n\n \n\t\n* b"), "", "should support continued list items after an empty list item w/ many blank lines" ); assert_eq!( to_html("*\n ~~~p\n\n ~~~"), "", "should support blank lines in code after an initial blank line" ); assert_eq!( to_html( "* a tight item that ends with an html element: `x`\n\nParagraph"), "\n

Paragraph

", "should ignore line endings after tight items ending in tags" ); assert_eq!( to_html("* foo\n\n*\n\n* bar"), "", "should support empty items in a spread list" ); assert_eq!( to_html("- ```\n\n ```"), "", "should remove indent of code (fenced) in list (0 space)" ); assert_eq!( to_html("- ```\n \n ```"), "", "should remove indent of code (fenced) in list (1 space)" ); assert_eq!( to_html("- ```\n \n ```"), "", "should remove indent of code (fenced) in list (2 spaces)" ); assert_eq!( to_html("- ```\n \n ```"), "", "should remove indent of code (fenced) in list (3 spaces)" ); assert_eq!( to_html("- ```\n \n ```"), "", "should remove indent of code (fenced) in list (4 spaces)" ); assert_eq!( to_html("- ```\n\t\n ```"), "", "should remove indent of code (fenced) in list (1 tab)" ); assert_eq!( to_html("- +\n-"), "", "should support complex nested and empty lists (1)" ); assert_eq!( to_html("- 1.\n-"), "", "should support complex nested and empty lists (2)" ); assert_eq!( to_html("* - +\n* -"), "", "should support complex nested and empty lists (3)" ); assert_eq!( to_html_with_options("* a\n\n\n\n* b", &danger)?, "\n\n", "should support the common list breaking comment method" ); assert_eq!( to_html_with_options( "- one\n\n two", &Options { parse: ParseOptions { constructs: Constructs { list_item: false, ..Default::default() }, ..Default::default() }, ..Default::default() } )?, "

- one

\n

two

", "should support turning off lists" ); assert_eq!( to_mdast("* a", &Default::default())?, Node::Root(Root { children: vec![Node::List(List { ordered: false, spread: false, start: None, children: vec![Node::ListItem(ListItem { checked: None, spread: false, children: vec![Node::Paragraph(Paragraph { children: vec![Node::Text(Text { value: "a".into(), position: Some(Position::new(1, 3, 2, 1, 4, 3)) }),], position: Some(Position::new(1, 3, 2, 1, 4, 3)) })], position: Some(Position::new(1, 1, 0, 1, 4, 3)) })], position: Some(Position::new(1, 1, 0, 1, 4, 3)) })], position: Some(Position::new(1, 1, 0, 1, 4, 3)) }), "should support lists, list items as `List`, `ListItem`s in mdast" ); assert_eq!( to_mdast("3. a\n4. b", &Default::default())?, Node::Root(Root { children: vec![Node::List(List { ordered: true, spread: false, start: Some(3), children: vec![ Node::ListItem(ListItem { checked: None, spread: false, children: vec![Node::Paragraph(Paragraph { children: vec![Node::Text(Text { value: "a".into(), position: Some(Position::new(1, 4, 3, 1, 5, 4)) }),], position: Some(Position::new(1, 4, 3, 1, 5, 4)) })], position: Some(Position::new(1, 1, 0, 1, 5, 4)) }), Node::ListItem(ListItem { checked: None, spread: false, children: vec![Node::Paragraph(Paragraph { children: vec![Node::Text(Text { value: "b".into(), position: Some(Position::new(2, 4, 8, 2, 5, 9)) }),], position: Some(Position::new(2, 4, 8, 2, 5, 9)) })], position: Some(Position::new(2, 1, 5, 2, 5, 9)) }) ], position: Some(Position::new(1, 1, 0, 2, 5, 9)) })], position: Some(Position::new(1, 1, 0, 2, 5, 9)) }), "should support `start` fields on `List` w/ `ordered: true` in mdast" ); assert_eq!( to_mdast("* a\n\n b\n* c", &Default::default())?, Node::Root(Root { children: vec![Node::List(List { ordered: false, spread: false, start: None, children: vec![ Node::ListItem(ListItem { checked: None, spread: true, children: vec![ Node::Paragraph(Paragraph { children: vec![Node::Text(Text { value: "a".into(), position: Some(Position::new(1, 3, 2, 1, 4, 3)) }),], position: Some(Position::new(1, 3, 2, 1, 4, 3)) }), Node::Paragraph(Paragraph { children: vec![Node::Text(Text { value: "b".into(), position: Some(Position::new(3, 3, 7, 3, 4, 8)) }),], position: Some(Position::new(3, 3, 7, 3, 4, 8)) }) ], position: Some(Position::new(1, 1, 0, 3, 4, 8)) }), Node::ListItem(ListItem { checked: None, spread: false, children: vec![Node::Paragraph(Paragraph { children: vec![Node::Text(Text { value: "c".into(), position: Some(Position::new(4, 3, 11, 4, 4, 12)) }),], position: Some(Position::new(4, 3, 11, 4, 4, 12)) })], position: Some(Position::new(4, 1, 9, 4, 4, 12)) }) ], position: Some(Position::new(1, 1, 0, 4, 4, 12)) })], position: Some(Position::new(1, 1, 0, 4, 4, 12)) }), "should support `spread` fields on `List`, `ListItem`s in mdast" ); Ok(()) }