planning
All checks were successful
Publish To Prod / deploy_and_publish (push) Successful in 35s

This commit is contained in:
2024-10-14 09:15:30 +02:00
parent bcba00a730
commit 6e64e138e2
21059 changed files with 2317811 additions and 1 deletions

View File

@@ -0,0 +1,625 @@
{
"\tfoo\tbaz\t\tbim\n": "NOT_TO_EQUAL",
" \tfoo\tbaz\t\tbim\n": "NOT_TO_EQUAL",
" a\ta\n ὐ\ta\n": "NOT_TO_EQUAL",
" - foo\n\n\tbar\n": "NOT_TO_EQUAL",
"- foo\n\n\t\tbar\n": "NOT_TO_EQUAL",
">\t\tfoo\n": "NOT_TO_EQUAL",
"-\t\tfoo\n": "NOT_TO_EQUAL",
" foo\n\tbar\n": "TO_EQUAL",
" - foo\n - bar\n\t - baz\n": "NOT_TO_EQUAL",
"#\tFoo\n": "TO_EQUAL",
"*\t*\t*\t\n": "TO_ERROR",
"- `one\n- two`\n": "TO_EQUAL",
"***\n---\n___\n": "NOT_TO_EQUAL",
"+++\n": "TO_EQUAL",
"===\n": "TO_EQUAL",
"--\n**\n__\n": "TO_EQUAL",
" ***\n ***\n ***\n": "NOT_TO_EQUAL",
" ***\n": "TO_EQUAL",
"Foo\n ***\n": "TO_EQUAL",
"_____________________________________\n": "NOT_TO_EQUAL",
" - - -\n": "NOT_TO_EQUAL",
" ** * ** * ** * **\n": "NOT_TO_EQUAL",
"- - - -\n": "NOT_TO_EQUAL",
"- - - - \n": "NOT_TO_EQUAL",
"_ _ _ _ a\n\na------\n\n---a---\n": "TO_EQUAL",
" *-*\n": "NOT_TO_EQUAL",
"- foo\n***\n- bar\n": "NOT_TO_EQUAL",
"Foo\n***\nbar\n": "NOT_TO_EQUAL",
"Foo\n---\nbar\n": "TO_EQUAL",
"* Foo\n* * *\n* Bar\n": "NOT_TO_EQUAL",
"- Foo\n- * * *\n": "NOT_TO_EQUAL",
"# foo\n## foo\n### foo\n#### foo\n##### foo\n###### foo\n": "TO_EQUAL",
"####### foo\n": "TO_EQUAL",
"#5 bolt\n\n#hashtag\n": "TO_EQUAL",
"\\## foo\n": "TO_EQUAL",
"# foo *bar* \\*baz\\*\n": "NOT_TO_EQUAL",
"# foo \n": "TO_EQUAL",
" ### foo\n ## foo\n # foo\n": "TO_EQUAL",
" # foo\n": "TO_EQUAL",
"foo\n # bar\n": "TO_EQUAL",
"## foo ##\n ### bar ###\n": "TO_EQUAL",
"# foo ##################################\n##### foo ##\n": "TO_EQUAL",
"### foo ### \n": "TO_EQUAL",
"### foo ### b\n": "TO_EQUAL",
"# foo#\n": "NOT_TO_EQUAL",
"### foo \\###\n## foo #\\##\n# foo \\#\n": "NOT_TO_EQUAL",
"****\n## foo\n****\n": "NOT_TO_EQUAL",
"Foo bar\n# baz\nBar foo\n": "TO_EQUAL",
"## \n#\n### ###\n": "TO_ERROR",
"Foo *bar*\n=========\n\nFoo *bar*\n---------\n": "TO_EQUAL",
"Foo *bar\nbaz*\n====\n": "NOT_TO_EQUAL",
"Foo\n-------------------------\n\nFoo\n=\n": "TO_EQUAL",
" Foo\n---\n\n Foo\n-----\n\n Foo\n ===\n": "NOT_TO_EQUAL",
" Foo\n ---\n\n Foo\n---\n": "NOT_TO_EQUAL",
"Foo\n ---- \n": "NOT_TO_EQUAL",
"Foo\n ---\n": "TO_EQUAL",
"Foo\n= =\n\nFoo\n--- -\n": "NOT_TO_EQUAL",
"Foo \n-----\n": "TO_EQUAL",
"Foo\\\n----\n": "TO_EQUAL",
"`Foo\n----\n`\n\n<a title=\"a lot\n---\nof dashes\"/>\n": "NOT_TO_EQUAL",
"> Foo\n---\n": "NOT_TO_EQUAL",
"> foo\nbar\n===\n": "NOT_TO_EQUAL",
"- Foo\n---\n": "NOT_TO_EQUAL",
"Foo\nBar\n---\n": "NOT_TO_EQUAL",
"---\nFoo\n---\nBar\n---\nBaz\n": "NOT_TO_EQUAL",
"\n====\n": "TO_EQUAL",
"---\n---\n": "TO_ERROR",
"- foo\n-----\n": "NOT_TO_EQUAL",
" foo\n---\n": "NOT_TO_EQUAL",
"> foo\n-----\n": "NOT_TO_EQUAL",
"\\> foo\n------\n": "NOT_TO_EQUAL",
"Foo\n\nbar\n---\nbaz\n": "TO_EQUAL",
"Foo\nbar\n\n---\n\nbaz\n": "NOT_TO_EQUAL",
"Foo\nbar\n* * *\nbaz\n": "NOT_TO_EQUAL",
"Foo\nbar\n\\---\nbaz\n": "NOT_TO_EQUAL",
" a simple\n indented code block\n": "TO_EQUAL",
" - foo\n\n bar\n": "NOT_TO_EQUAL",
"1. foo\n\n - bar\n": "TO_EQUAL",
" <a/>\n *hi*\n\n - one\n": "NOT_TO_EQUAL",
" chunk1\n\n chunk2\n \n \n \n chunk3\n": "TO_EQUAL",
" chunk1\n \n chunk2\n": "TO_EQUAL",
"Foo\n bar\n\n": "TO_EQUAL",
" foo\nbar\n": "TO_EQUAL",
"# Heading\n foo\nHeading\n------\n foo\n----\n": "NOT_TO_EQUAL",
" foo\n bar\n": "TO_EQUAL",
"\n \n foo\n \n\n": "TO_EQUAL",
" foo \n": "TO_EQUAL",
"```\n<\n >\n```\n": "NOT_TO_EQUAL",
"~~~\n<\n >\n~~~\n": "NOT_TO_EQUAL",
"``\nfoo\n``\n": "TO_EQUAL",
"```\naaa\n~~~\n```\n": "NOT_TO_EQUAL",
"~~~\naaa\n```\n~~~\n": "NOT_TO_EQUAL",
"````\naaa\n```\n``````\n": "NOT_TO_EQUAL",
"~~~~\naaa\n~~~\n~~~~\n": "NOT_TO_EQUAL",
"```\n": "TO_EQUAL",
"`````\n\n```\naaa\n": "NOT_TO_EQUAL",
"> ```\n> aaa\n\nbbb\n": "TO_EQUAL",
"```\n\n \n```\n": "NOT_TO_EQUAL",
"```\n```\n": "TO_EQUAL",
" ```\n aaa\naaa\n```\n": "TO_EQUAL",
" ```\naaa\n aaa\naaa\n ```\n": "TO_EQUAL",
" ```\n aaa\n aaa\n aaa\n ```\n": "TO_EQUAL",
" ```\n aaa\n ```\n": "NOT_TO_EQUAL",
"```\naaa\n ```\n": "TO_EQUAL",
" ```\naaa\n ```\n": "TO_EQUAL",
"```\naaa\n ```\n": "NOT_TO_EQUAL",
"``` ```\naaa\n": "TO_EQUAL",
"~~~~~~\naaa\n~~~ ~~\n": "NOT_TO_EQUAL",
"foo\n```\nbar\n```\nbaz\n": "TO_EQUAL",
"foo\n---\n~~~\nbar\n~~~\n# baz\n": "TO_EQUAL",
"```ruby\ndef foo(x)\n return 3\nend\n```\n": "TO_EQUAL",
"~~~~ ruby startline=3 $%@#$\ndef foo(x)\n return 3\nend\n~~~~~~~\n": "TO_EQUAL",
"````;\n````\n": "TO_EQUAL",
"``` aa ```\nfoo\n": "TO_EQUAL",
"```\n``` aaa\n```\n": "NOT_TO_EQUAL",
"<table><tr><td>\n<pre>\n**Hello**,\n\n_world_.\n</pre>\n</td></tr></table>\n": "NOT_TO_EQUAL",
"<table>\n <tr>\n <td>\n hi\n </td>\n </tr>\n</table>\n\nokay.\n": "TO_EQUAL",
" <div>\n *hello*\n <foo><a>\n": "NOT_TO_EQUAL",
"</div>\n*foo*\n": "NOT_TO_EQUAL",
"<DIV CLASS=\"foo\">\n\n*Markdown*\n\n</DIV>\n": "TO_EQUAL",
"<div id=\"foo\"\n class=\"bar\">\n</div>\n": "TO_EQUAL",
"<div id=\"foo\" class=\"bar\n baz\">\n</div>\n": "TO_EQUAL",
"<div>\n*foo*\n\n*bar*\n": "NOT_TO_EQUAL",
"<div id=\"foo\"\n*hi*\n": "NOT_TO_EQUAL",
"<div class\nfoo\n": "TO_EQUAL",
"<div *???-&&&-<---\n*foo*\n": "NOT_TO_EQUAL",
"<div><a href=\"bar\">*foo*</a></div>\n": "NOT_TO_EQUAL",
"<table><tr><td>\nfoo\n</td></tr></table>\n": "TO_EQUAL",
"<div></div>\n``` c\nint x = 33;\n```\n": "NOT_TO_EQUAL",
"<a href=\"foo\">\n*bar*\n</a>\n": "NOT_TO_EQUAL",
"<Warning>\n*bar*\n</Warning>\n": "NOT_TO_EQUAL",
"<i class=\"foo\">\n*bar*\n</i>\n": "NOT_TO_EQUAL",
"</ins>\n*bar*\n": "NOT_TO_EQUAL",
"<del>\n*foo*\n</del>\n": "NOT_TO_EQUAL",
"<del>\n\n*foo*\n\n</del>\n": "TO_EQUAL",
"<del>*foo*</del>\n": "TO_EQUAL",
"<pre language=\"haskell\"><code>\nimport Text.HTML.TagSoup\n\nmain :: IO ()\nmain = print $ parseTags tags\n</code></pre>\nokay\n": "TO_EQUAL",
"<script type=\"text/javascript\">\n// JavaScript example\n\ndocument.getElementById(\"demo\").innerHTML = \"Hello JavaScript!\";\n</script>\nokay\n": "TO_EQUAL",
"<style\n type=\"text/css\">\nh1 {color:red;}\n\np {color:blue;}\n</style>\nokay\n": "TO_EQUAL",
"<style\n type=\"text/css\">\n\nfoo\n": "TO_EQUAL",
"> <div>\n> foo\n\nbar\n": "TO_EQUAL",
"- <div>\n- foo\n": "TO_EQUAL",
"<style>p{color:red;}</style>\n*foo*\n": "TO_EQUAL",
"<!-- foo -->*bar*\n*baz*\n": "NOT_TO_EQUAL",
"<script>\nfoo\n</script>1. *bar*\n": "NOT_TO_EQUAL",
"<!-- Foo\n\nbar\n baz -->\nokay\n": "TO_EQUAL",
"<?php\n\n echo '>';\n\n?>\nokay\n": "TO_EQUAL",
"<!DOCTYPE html>\n": "TO_EQUAL",
"<![CDATA[\nfunction matchwo(a,b)\n{\n if (a < b && a < 0) then {\n return 1;\n\n } else {\n\n return 0;\n }\n}\n]]>\nokay\n": "NOT_TO_EQUAL",
" <!-- foo -->\n\n <!-- foo -->\n": "NOT_TO_EQUAL",
" <div>\n\n <div>\n": "NOT_TO_EQUAL",
"Foo\n<div>\nbar\n</div>\n": "TO_EQUAL",
"<div>\nbar\n</div>\n*foo*\n": "NOT_TO_EQUAL",
"Foo\n<a href=\"bar\">\nbaz\n": "TO_EQUAL",
"<div>\n\n*Emphasized* text.\n\n</div>\n": "TO_EQUAL",
"<div>\n*Emphasized* text.\n</div>\n": "NOT_TO_EQUAL",
"<table>\n\n<tr>\n\n<td>\nHi\n</td>\n\n</tr>\n\n</table>\n": "TO_EQUAL",
"<table>\n\n <tr>\n\n <td>\n Hi\n </td>\n\n </tr>\n\n</table>\n": "NOT_TO_EQUAL",
"[foo]: /url \"title\"\n\n[foo]\n": "TO_EQUAL",
" [foo]: \n /url \n 'the title' \n\n[foo]\n": "TO_EQUAL",
"[Foo*bar\\]]:my_(url) 'title (with parens)'\n\n[Foo*bar\\]]\n": "NOT_TO_EQUAL",
"[Foo bar]:\n<my%20url>\n'title'\n\n[Foo bar]\n": "TO_EQUAL",
"[foo]: /url '\ntitle\nline1\nline2\n'\n\n[foo]\n": "NOT_TO_EQUAL",
"[foo]: /url 'title\n\nwith blank line'\n\n[foo]\n": "TO_EQUAL",
"[foo]:\n/url\n\n[foo]\n": "TO_EQUAL",
"[foo]:\n\n[foo]\n": "TO_EQUAL",
"[foo]: /url\\bar\\*baz \"foo\\\"bar\\baz\"\n\n[foo]\n": "NOT_TO_EQUAL",
"[foo]\n\n[foo]: url\n": "TO_EQUAL",
"[foo]\n\n[foo]: first\n[foo]: second\n": "NOT_TO_EQUAL",
"[FOO]: /url\n\n[Foo]\n": "TO_EQUAL",
"[ΑΓΩ]: /φου\n\n[αγω]\n": "TO_EQUAL",
"[foo]: /url\n": "TO_ERROR",
"[\nfoo\n]: /url\nbar\n": "TO_EQUAL",
"[foo]: /url \"title\" ok\n": "NOT_TO_EQUAL",
"[foo]: /url\n\"title\" ok\n": "NOT_TO_EQUAL",
" [foo]: /url \"title\"\n\n[foo]\n": "NOT_TO_EQUAL",
"```\n[foo]: /url\n```\n\n[foo]\n": "TO_EQUAL",
"Foo\n[bar]: /baz\n\n[bar]\n": "TO_EQUAL",
"# [Foo]\n[foo]: /url\n> bar\n": "TO_EQUAL",
"[foo]: /foo-url \"foo\"\n[bar]: /bar-url\n \"bar\"\n[baz]: /baz-url\n\n[foo],\n[bar],\n[baz]\n": "TO_EQUAL",
"[foo]\n\n> [foo]: /url\n": "NOT_TO_EQUAL",
"aaa\n\nbbb\n": "TO_EQUAL",
"aaa\nbbb\n\nccc\nddd\n": "TO_EQUAL",
"aaa\n\n\nbbb\n": "TO_EQUAL",
" aaa\n bbb\n": "NOT_TO_EQUAL",
"aaa\n bbb\n ccc\n": "TO_EQUAL",
" aaa\nbbb\n": "NOT_TO_EQUAL",
" aaa\nbbb\n": "TO_EQUAL",
"aaa \nbbb \n": "NOT_TO_EQUAL",
" \n\naaa\n \n\n# aaa\n\n \n": "TO_EQUAL",
"> # Foo\n> bar\n> baz\n": "TO_EQUAL",
"># Foo\n>bar\n> baz\n": "TO_EQUAL",
" > # Foo\n > bar\n > baz\n": "TO_EQUAL",
" > # Foo\n > bar\n > baz\n": "NOT_TO_EQUAL",
"> # Foo\n> bar\nbaz\n": "TO_EQUAL",
"> bar\nbaz\n> foo\n": "TO_EQUAL",
"> foo\n---\n": "NOT_TO_EQUAL",
"> - foo\n- bar\n": "TO_EQUAL",
"> foo\n bar\n": "TO_EQUAL",
"> ```\nfoo\n```\n": "NOT_TO_EQUAL",
"> foo\n - bar\n": "NOT_TO_EQUAL",
">\n": "TO_ERROR",
">\n> \n> \n": "TO_ERROR",
">\n> foo\n> \n": "TO_EQUAL",
"> foo\n\n> bar\n": "NOT_TO_EQUAL",
"> foo\n> bar\n": "TO_EQUAL",
"> foo\n>\n> bar\n": "TO_EQUAL",
"foo\n> bar\n": "TO_EQUAL",
"> aaa\n***\n> bbb\n": "NOT_TO_EQUAL",
"> bar\nbaz\n": "TO_EQUAL",
"> bar\n\nbaz\n": "TO_EQUAL",
"> bar\n>\nbaz\n": "NOT_TO_EQUAL",
"> > > foo\nbar\n": "TO_EQUAL",
">>> foo\n> bar\n>>baz\n": "TO_EQUAL",
"> code\n\n> not code\n": "NOT_TO_EQUAL",
"A paragraph\nwith two lines.\n\n indented code\n\n> A block quote.\n": "TO_EQUAL",
"1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote.\n": "TO_EQUAL",
"- one\n\n two\n": "NOT_TO_EQUAL",
"- one\n\n two\n": "NOT_TO_EQUAL",
" - one\n\n two\n": "NOT_TO_EQUAL",
" - one\n\n two\n": "NOT_TO_EQUAL",
" > > 1. one\n>>\n>> two\n": "NOT_TO_EQUAL",
">>- one\n>>\n > > two\n": "TO_EQUAL",
"-one\n\n2.two\n": "TO_EQUAL",
"- foo\n\n\n bar\n": "TO_EQUAL",
"1. foo\n\n ```\n bar\n ```\n\n baz\n\n > bam\n": "TO_EQUAL",
"- Foo\n\n bar\n\n\n baz\n": "NOT_TO_EQUAL",
"123456789. ok\n": "TO_EQUAL",
"1234567890. not ok\n": "NOT_TO_EQUAL",
"0. ok\n": "NOT_TO_EQUAL",
"003. ok\n": "TO_EQUAL",
"-1. not ok\n": "TO_EQUAL",
"- foo\n\n bar\n": "TO_EQUAL",
" 10. foo\n\n bar\n": "TO_EQUAL",
" indented code\n\nparagraph\n\n more code\n": "TO_EQUAL",
"1. indented code\n\n paragraph\n\n more code\n": "TO_EQUAL",
"1. indented code\n\n paragraph\n\n more code\n": "TO_EQUAL",
" foo\n\nbar\n": "NOT_TO_EQUAL",
"- foo\n\n bar\n": "NOT_TO_EQUAL",
"- foo\n\n bar\n": "NOT_TO_EQUAL",
"-\n foo\n-\n ```\n bar\n ```\n-\n baz\n": "NOT_TO_EQUAL",
"- \n foo\n": "TO_ERROR",
"-\n\n foo\n": "NOT_TO_EQUAL",
"- foo\n-\n- bar\n": "TO_ERROR",
"- foo\n- \n- bar\n": "TO_ERROR",
"1. foo\n2.\n3. bar\n": "TO_ERROR",
"*\n": "NOT_TO_EQUAL",
"foo\n*\n\nfoo\n1.\n": "TO_EQUAL",
" 1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote.\n": "TO_EQUAL",
" 1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote.\n": "TO_EQUAL",
" 1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote.\n": "TO_EQUAL",
" 1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote.\n": "NOT_TO_EQUAL",
" 1. A paragraph\nwith two lines.\n\n indented code\n\n > A block quote.\n": "NOT_TO_EQUAL",
" 1. A paragraph\n with two lines.\n": "TO_EQUAL",
"> 1. > Blockquote\ncontinued here.\n": "TO_EQUAL",
"> 1. > Blockquote\n> continued here.\n": "TO_EQUAL",
"- foo\n - bar\n - baz\n - boo\n": "NOT_TO_EQUAL",
"- foo\n - bar\n - baz\n - boo\n": "TO_EQUAL",
"10) foo\n - bar\n": "NOT_TO_EQUAL",
"10) foo\n - bar\n": "TO_EQUAL",
"- - foo\n": "TO_EQUAL",
"1. - 2. foo\n": "TO_EQUAL",
"- # Foo\n- Bar\n ---\n baz\n": "NOT_TO_EQUAL",
"- foo\n- bar\n+ baz\n": "TO_EQUAL",
"1. foo\n2. bar\n3) baz\n": "TO_EQUAL",
"Foo\n- bar\n- baz\n": "TO_EQUAL",
"The number of windows in my house is\n14. The number of doors is 6.\n": "NOT_TO_EQUAL",
"The number of windows in my house is\n1. The number of doors is 6.\n": "TO_EQUAL",
"- foo\n\n- bar\n\n\n- baz\n": "NOT_TO_EQUAL",
"- foo\n - bar\n - baz\n\n\n bim\n": "NOT_TO_EQUAL",
"- foo\n- bar\n\n<!-- -->\n\n- baz\n- bim\n": "TO_EQUAL",
"- foo\n\n notcode\n\n- foo\n\n<!-- -->\n\n code\n": "NOT_TO_EQUAL",
"- a\n - b\n - c\n - d\n - e\n - f\n - g\n - h\n- i\n": "NOT_TO_EQUAL",
"1. a\n\n 2. b\n\n 3. c\n": "NOT_TO_EQUAL",
"- a\n- b\n\n- c\n": "NOT_TO_EQUAL",
"* a\n*\n\n* c\n": "TO_ERROR",
"- a\n- b\n\n c\n- d\n": "NOT_TO_EQUAL",
"- a\n- b\n\n [ref]: /url\n- d\n": "NOT_TO_EQUAL",
"- a\n- ```\n b\n\n\n ```\n- c\n": "NOT_TO_EQUAL",
"- a\n - b\n\n c\n- d\n": "NOT_TO_EQUAL",
"* a\n > b\n >\n* c\n": "NOT_TO_EQUAL",
"- a\n > b\n ```\n c\n ```\n- d\n": "NOT_TO_EQUAL",
"- a\n": "TO_EQUAL",
"- a\n - b\n": "NOT_TO_EQUAL",
"1. ```\n foo\n ```\n\n bar\n": "TO_EQUAL",
"* foo\n * bar\n\n baz\n": "NOT_TO_EQUAL",
"- a\n - b\n - c\n\n- d\n - e\n - f\n": "TO_EQUAL",
"`hi`lo`\n": "TO_EQUAL",
"\\!\\\"\\#\\$\\%\\&\\'\\(\\)\\*\\+\\,\\-\\.\\/\\:\\;\\<\\=\\>\\?\\@\\[\\\\\\]\\^\\_\\`\\{\\|\\}\\~\n": "NOT_TO_EQUAL",
"\\\t\\A\\a\\ \\3\\φ\\«\n": "TO_EQUAL",
"\\*not emphasized*\n\\<br/> not a tag\n\\[not a link](/foo)\n\\`not code`\n1\\. not a list\n\\* not a list\n\\# not a heading\n\\[foo]: /url \"not a reference\"\n": "NOT_TO_EQUAL",
"\\\\*emphasis*\n": "NOT_TO_EQUAL",
"foo\\\nbar\n": "NOT_TO_EQUAL",
"`` \\[\\` ``\n": "TO_EQUAL",
" \\[\\]\n": "TO_EQUAL",
"~~~\n\\[\\]\n~~~\n": "TO_EQUAL",
"<http://example.com?find=\\*>\n": "NOT_TO_EQUAL",
"<a href=\"/bar\\/)\">\n": "TO_EQUAL",
"[foo](/bar\\* \"ti\\*tle\")\n": "TO_EQUAL",
"[foo]\n\n[foo]: /bar\\* \"ti\\*tle\"\n": "TO_EQUAL",
"``` foo\\+bar\nfoo\n```\n": "TO_EQUAL",
"&nbsp; &amp; &copy; &AElig; &Dcaron;\n&frac34; &HilbertSpace; &DifferentialD;\n&ClockwiseContourIntegral; &ngE;\n": "NOT_TO_EQUAL",
"&#35; &#1234; &#992; &#98765432; &#0;\n": "NOT_TO_EQUAL",
"&#X22; &#XD06; &#xcab;\n": "NOT_TO_EQUAL",
"&nbsp &x; &#; &#x;\n&ThisIsNotDefined; &hi?;\n": "NOT_TO_EQUAL",
"&copy\n": "NOT_TO_EQUAL",
"&MadeUpEntity;\n": "NOT_TO_EQUAL",
"<a href=\"&ouml;&ouml;.html\">\n": "TO_EQUAL",
"[foo](/f&ouml;&ouml; \"f&ouml;&ouml;\")\n": "TO_EQUAL",
"[foo]\n\n[foo]: /f&ouml;&ouml; \"f&ouml;&ouml;\"\n": "TO_EQUAL",
"``` f&ouml;&ouml;\nfoo\n```\n": "TO_EQUAL",
"`f&ouml;&ouml;`\n": "NOT_TO_EQUAL",
" f&ouml;f&ouml;\n": "NOT_TO_EQUAL",
"`foo`\n": "TO_EQUAL",
"`` foo ` bar ``\n": "TO_EQUAL",
"` `` `\n": "TO_EQUAL",
"`foo bar\n baz`\n": "TO_EQUAL",
"`a b`\n": "NOT_TO_EQUAL",
"`foo `` bar`\n": "TO_EQUAL",
"`foo\\`bar`\n": "TO_EQUAL",
"*foo`*`\n": "NOT_TO_EQUAL",
"[not a `link](/foo`)\n": "NOT_TO_EQUAL",
"`<a href=\"`\">`\n": "NOT_TO_EQUAL",
"<a href=\"`\">`\n": "TO_EQUAL",
"`<http://foo.bar.`baz>`\n": "NOT_TO_EQUAL",
"<http://foo.bar.`baz>`\n": "TO_EQUAL",
"```foo``\n": "NOT_TO_EQUAL",
"`foo\n": "TO_EQUAL",
"`foo``bar``\n": "NOT_TO_EQUAL",
"*foo bar*\n": "TO_EQUAL",
"a * foo bar*\n": "NOT_TO_EQUAL",
"a*\"foo\"*\n": "NOT_TO_EQUAL",
"* a *\n": "NOT_TO_EQUAL",
"foo*bar*\n": "TO_EQUAL",
"5*6*78\n": "NOT_TO_EQUAL",
"_foo bar_\n": "TO_EQUAL",
"_ foo bar_\n": "NOT_TO_EQUAL",
"a_\"foo\"_\n": "NOT_TO_EQUAL",
"foo_bar_\n": "NOT_TO_EQUAL",
"5_6_78\n": "TO_EQUAL",
"пристаням_стремятся_\n": "NOT_TO_EQUAL",
"aa_\"bb\"_cc\n": "NOT_TO_EQUAL",
"foo-_(bar)_\n": "TO_EQUAL",
"_foo*\n": "TO_EQUAL",
"*foo bar *\n": "NOT_TO_EQUAL",
"*foo bar\n*\n": "NOT_TO_EQUAL",
"*(*foo)\n": "NOT_TO_EQUAL",
"*(*foo*)*\n": "NOT_TO_EQUAL",
"*foo*bar\n": "NOT_TO_EQUAL",
"_foo bar _\n": "NOT_TO_EQUAL",
"_(_foo)\n": "TO_EQUAL",
"_(_foo_)_\n": "NOT_TO_EQUAL",
"_foo_bar\n": "TO_EQUAL",
"_пристаням_стремятся\n": "NOT_TO_EQUAL",
"_foo_bar_baz_\n": "TO_EQUAL",
"_(bar)_.\n": "TO_EQUAL",
"**foo bar**\n": "TO_EQUAL",
"** foo bar**\n": "NOT_TO_EQUAL",
"a**\"foo\"**\n": "NOT_TO_EQUAL",
"foo**bar**\n": "TO_EQUAL",
"__foo bar__\n": "TO_EQUAL",
"__ foo bar__\n": "NOT_TO_EQUAL",
"__\nfoo bar__\n": "NOT_TO_EQUAL",
"a__\"foo\"__\n": "NOT_TO_EQUAL",
"foo__bar__\n": "NOT_TO_EQUAL",
"5__6__78\n": "NOT_TO_EQUAL",
"пристаням__стремятся__\n": "NOT_TO_EQUAL",
"__foo, __bar__, baz__\n": "NOT_TO_EQUAL",
"foo-__(bar)__\n": "TO_EQUAL",
"**foo bar **\n": "NOT_TO_EQUAL",
"**(**foo)\n": "NOT_TO_EQUAL",
"*(**foo**)*\n": "TO_EQUAL",
"**Gomphocarpus (*Gomphocarpus physocarpus*, syn.\n*Asclepias physocarpa*)**\n": "TO_EQUAL",
"**foo \"*bar*\" foo**\n": "NOT_TO_EQUAL",
"**foo**bar\n": "TO_EQUAL",
"__foo bar __\n": "NOT_TO_EQUAL",
"__(__foo)\n": "NOT_TO_EQUAL",
"_(__foo__)_\n": "TO_EQUAL",
"__foo__bar\n": "NOT_TO_EQUAL",
"__пристаням__стремятся\n": "NOT_TO_EQUAL",
"__foo__bar__baz__\n": "NOT_TO_EQUAL",
"__(bar)__.\n": "TO_EQUAL",
"*foo [bar](/url)*\n": "TO_EQUAL",
"*foo\nbar*\n": "TO_EQUAL",
"_foo __bar__ baz_\n": "TO_EQUAL",
"_foo _bar_ baz_\n": "NOT_TO_EQUAL",
"__foo_ bar_\n": "NOT_TO_EQUAL",
"*foo *bar**\n": "NOT_TO_EQUAL",
"*foo **bar** baz*\n": "TO_EQUAL",
"*foo**bar**baz*\n": "TO_EQUAL",
"***foo** bar*\n": "NOT_TO_EQUAL",
"*foo **bar***\n": "NOT_TO_EQUAL",
"*foo**bar***\n": "NOT_TO_EQUAL",
"*foo **bar *baz* bim** bop*\n": "NOT_TO_EQUAL",
"*foo [*bar*](/url)*\n": "NOT_TO_EQUAL",
"** is not an empty emphasis\n": "TO_EQUAL",
"**** is not an empty strong emphasis\n": "TO_EQUAL",
"**foo [bar](/url)**\n": "TO_EQUAL",
"**foo\nbar**\n": "TO_EQUAL",
"__foo _bar_ baz__\n": "TO_EQUAL",
"__foo __bar__ baz__\n": "NOT_TO_EQUAL",
"____foo__ bar__\n": "NOT_TO_EQUAL",
"**foo **bar****\n": "NOT_TO_EQUAL",
"**foo *bar* baz**\n": "TO_EQUAL",
"**foo*bar*baz**\n": "NOT_TO_EQUAL",
"***foo* bar**\n": "TO_EQUAL",
"**foo *bar***\n": "TO_EQUAL",
"**foo *bar **baz**\nbim* bop**\n": "NOT_TO_EQUAL",
"**foo [*bar*](/url)**\n": "TO_EQUAL",
"__ is not an empty emphasis\n": "TO_EQUAL",
"____ is not an empty strong emphasis\n": "TO_EQUAL",
"foo ***\n": "TO_EQUAL",
"foo *\\**\n": "NOT_TO_EQUAL",
"foo *_*\n": "NOT_TO_EQUAL",
"foo *****\n": "NOT_TO_EQUAL",
"foo **\\***\n": "TO_EQUAL",
"foo **_**\n": "TO_EQUAL",
"**foo*\n": "TO_EQUAL",
"*foo**\n": "NOT_TO_EQUAL",
"***foo**\n": "NOT_TO_EQUAL",
"****foo*\n": "NOT_TO_EQUAL",
"**foo***\n": "NOT_TO_EQUAL",
"*foo****\n": "NOT_TO_EQUAL",
"foo ___\n": "TO_EQUAL",
"foo _\\__\n": "NOT_TO_EQUAL",
"foo _*_\n": "TO_EQUAL",
"foo _____\n": "NOT_TO_EQUAL",
"foo __\\___\n": "TO_EQUAL",
"foo __*__\n": "TO_EQUAL",
"__foo_\n": "TO_EQUAL",
"_foo__\n": "NOT_TO_EQUAL",
"___foo__\n": "NOT_TO_EQUAL",
"____foo_\n": "NOT_TO_EQUAL",
"__foo___\n": "NOT_TO_EQUAL",
"_foo____\n": "NOT_TO_EQUAL",
"**foo**\n": "TO_EQUAL",
"*_foo_*\n": "NOT_TO_EQUAL",
"__foo__\n": "TO_EQUAL",
"_*foo*_\n": "NOT_TO_EQUAL",
"****foo****\n": "NOT_TO_EQUAL",
"____foo____\n": "NOT_TO_EQUAL",
"******foo******\n": "NOT_TO_EQUAL",
"***foo***\n": "TO_EQUAL",
"_____foo_____\n": "NOT_TO_EQUAL",
"*foo _bar* baz_\n": "TO_EQUAL",
"*foo __bar *baz bim__ bam*\n": "NOT_TO_EQUAL",
"**foo **bar baz**\n": "NOT_TO_EQUAL",
"*foo *bar baz*\n": "NOT_TO_EQUAL",
"*[bar*](/url)\n": "NOT_TO_EQUAL",
"_foo [bar_](/url)\n": "NOT_TO_EQUAL",
"*<img src=\"foo\" title=\"*\"/>\n": "NOT_TO_EQUAL",
"**<a href=\"**\">\n": "NOT_TO_EQUAL",
"__<a href=\"__\">\n": "NOT_TO_EQUAL",
"*a `*`*\n": "NOT_TO_EQUAL",
"_a `_`_\n": "NOT_TO_EQUAL",
"**a<http://foo.bar/?q=**>\n": "NOT_TO_EQUAL",
"__a<http://foo.bar/?q=__>\n": "NOT_TO_EQUAL",
"[link](/uri \"title\")\n": "TO_EQUAL",
"[link](/uri)\n": "TO_EQUAL",
"[link]()\n": "TO_EQUAL",
"[link](<>)\n": "TO_EQUAL",
"[link](/my uri)\n": "TO_EQUAL",
"[link](</my uri>)\n": "NOT_TO_EQUAL",
"[link](foo\nbar)\n": "TO_EQUAL",
"[link](<foo\nbar>)\n": "TO_EQUAL",
"[link](\\(foo\\))\n": "TO_EQUAL",
"[link](foo(and(bar)))\n": "TO_EQUAL",
"[link](foo\\(and\\(bar\\))\n": "TO_EQUAL",
"[link](<foo(and(bar)>)\n": "TO_EQUAL",
"[link](foo\\)\\:)\n": "TO_EQUAL",
"[link](#fragment)\n\n[link](http://example.com#fragment)\n\n[link](http://example.com?foo=3#frag)\n": "TO_EQUAL",
"[link](foo\\bar)\n": "TO_EQUAL",
"[link](foo%20b&auml;)\n": "TO_EQUAL",
"[link](\"title\")\n": "TO_EQUAL",
"[link](/url \"title\")\n[link](/url 'title')\n[link](/url (title))\n": "TO_EQUAL",
"[link](/url \"title \\\"&quot;\")\n": "NOT_TO_EQUAL",
"[link](/url \"title\")\n": "NOT_TO_EQUAL",
"[link](/url \"title \"and\" title\")\n": "NOT_TO_EQUAL",
"[link](/url 'title \"and\" title')\n": "NOT_TO_EQUAL",
"[link]( /uri\n \"title\" )\n": "TO_EQUAL",
"[link] (/uri)\n": "NOT_TO_EQUAL",
"[link [foo [bar]]](/uri)\n": "NOT_TO_EQUAL",
"[link] bar](/uri)\n": "TO_EQUAL",
"[link [bar](/uri)\n": "TO_EQUAL",
"[link \\[bar](/uri)\n": "NOT_TO_EQUAL",
"[link *foo **bar** `#`*](/uri)\n": "TO_EQUAL",
"[![moon](moon.jpg)](/uri)\n": "NOT_TO_EQUAL",
"[foo [bar](/uri)](/uri)\n": "NOT_TO_EQUAL",
"[foo *[bar [baz](/uri)](/uri)*](/uri)\n": "NOT_TO_EQUAL",
"![[[foo](uri1)](uri2)](uri3)\n": "NOT_TO_EQUAL",
"*[foo*](/uri)\n": "NOT_TO_EQUAL",
"[foo *bar](baz*)\n": "TO_EQUAL",
"*foo [bar* baz]\n": "TO_EQUAL",
"[foo <bar attr=\"](baz)\">\n": "NOT_TO_EQUAL",
"[foo`](/uri)`\n": "NOT_TO_EQUAL",
"[foo<http://example.com/?search=](uri)>\n": "NOT_TO_EQUAL",
"[foo][bar]\n\n[bar]: /url \"title\"\n": "TO_EQUAL",
"[link [foo [bar]]][ref]\n\n[ref]: /uri\n": "NOT_TO_EQUAL",
"[link \\[bar][ref]\n\n[ref]: /uri\n": "NOT_TO_EQUAL",
"[link *foo **bar** `#`*][ref]\n\n[ref]: /uri\n": "TO_EQUAL",
"[![moon](moon.jpg)][ref]\n\n[ref]: /uri\n": "NOT_TO_EQUAL",
"[foo [bar](/uri)][ref]\n\n[ref]: /uri\n": "NOT_TO_EQUAL",
"[foo *bar [baz][ref]*][ref]\n\n[ref]: /uri\n": "NOT_TO_EQUAL",
"*[foo*][ref]\n\n[ref]: /uri\n": "NOT_TO_EQUAL",
"[foo *bar][ref]\n\n[ref]: /uri\n": "TO_EQUAL",
"[foo <bar attr=\"][ref]\">\n\n[ref]: /uri\n": "NOT_TO_EQUAL",
"[foo`][ref]`\n\n[ref]: /uri\n": "NOT_TO_EQUAL",
"[foo<http://example.com/?search=][ref]>\n\n[ref]: /uri\n": "NOT_TO_EQUAL",
"[foo][BaR]\n\n[bar]: /url \"title\"\n": "TO_EQUAL",
"[Толпой][Толпой] is a Russian word.\n\n[ТОЛПОЙ]: /url\n": "TO_EQUAL",
"[Foo\n bar]: /url\n\n[Baz][Foo bar]\n": "TO_EQUAL",
"[foo] [bar]\n\n[bar]: /url \"title\"\n": "NOT_TO_EQUAL",
"[foo]\n[bar]\n\n[bar]: /url \"title\"\n": "NOT_TO_EQUAL",
"[foo]: /url1\n\n[foo]: /url2\n\n[bar][foo]\n": "NOT_TO_EQUAL",
"[bar][foo\\!]\n\n[foo!]: /url\n": "NOT_TO_EQUAL",
"[foo][ref[]\n\n[ref[]: /uri\n": "NOT_TO_EQUAL",
"[foo][ref[bar]]\n\n[ref[bar]]: /uri\n": "NOT_TO_EQUAL",
"[[[foo]]]\n\n[[[foo]]]: /url\n": "TO_EQUAL",
"[foo][ref\\[]\n\n[ref\\[]: /uri\n": "TO_EQUAL",
"[bar\\\\]: /uri\n\n[bar\\\\]\n": "NOT_TO_EQUAL",
"[]\n\n[]: /uri\n": "TO_EQUAL",
"[\n ]\n\n[\n ]: /uri\n": "NOT_TO_EQUAL",
"[foo][]\n\n[foo]: /url \"title\"\n": "TO_EQUAL",
"[*foo* bar][]\n\n[*foo* bar]: /url \"title\"\n": "TO_EQUAL",
"[Foo][]\n\n[foo]: /url \"title\"\n": "TO_EQUAL",
"[foo] \n[]\n\n[foo]: /url \"title\"\n": "NOT_TO_EQUAL",
"[foo]\n\n[foo]: /url \"title\"\n": "TO_EQUAL",
"[*foo* bar]\n\n[*foo* bar]: /url \"title\"\n": "TO_EQUAL",
"[[*foo* bar]]\n\n[*foo* bar]: /url \"title\"\n": "TO_EQUAL",
"[[bar [foo]\n\n[foo]: /url\n": "TO_EQUAL",
"[Foo]\n\n[foo]: /url \"title\"\n": "TO_EQUAL",
"[foo] bar\n\n[foo]: /url\n": "TO_EQUAL",
"\\[foo]\n\n[foo]: /url \"title\"\n": "TO_EQUAL",
"[foo*]: /url\n\n*[foo*]\n": "NOT_TO_EQUAL",
"[foo][bar]\n\n[foo]: /url1\n[bar]: /url2\n": "TO_EQUAL",
"[foo][]\n\n[foo]: /url1\n": "TO_EQUAL",
"[foo]()\n\n[foo]: /url1\n": "TO_EQUAL",
"[foo](not a link)\n\n[foo]: /url1\n": "TO_EQUAL",
"[foo][bar][baz]\n\n[baz]: /url\n": "NOT_TO_EQUAL",
"[foo][bar][baz]\n\n[baz]: /url1\n[bar]: /url2\n": "TO_EQUAL",
"[foo][bar][baz]\n\n[baz]: /url1\n[foo]: /url2\n": "NOT_TO_EQUAL",
"![foo](/url \"title\")\n": "NOT_TO_EQUAL",
"![foo *bar*]\n\n[foo *bar*]: train.jpg \"train & tracks\"\n": "NOT_TO_EQUAL",
"![foo ![bar](/url)](/url2)\n": "NOT_TO_EQUAL",
"![foo [bar](/url)](/url2)\n": "NOT_TO_EQUAL",
"![foo *bar*][]\n\n[foo *bar*]: train.jpg \"train & tracks\"\n": "NOT_TO_EQUAL",
"![foo *bar*][foobar]\n\n[FOOBAR]: train.jpg \"train & tracks\"\n": "NOT_TO_EQUAL",
"![foo](train.jpg)\n": "NOT_TO_EQUAL",
"My ![foo bar](/path/to/train.jpg \"title\" )\n": "NOT_TO_EQUAL",
"![foo](<url>)\n": "NOT_TO_EQUAL",
"![](/url)\n": "NOT_TO_EQUAL",
"![foo][bar]\n\n[bar]: /url\n": "NOT_TO_EQUAL",
"![foo][bar]\n\n[BAR]: /url\n": "NOT_TO_EQUAL",
"![foo][]\n\n[foo]: /url \"title\"\n": "NOT_TO_EQUAL",
"![*foo* bar][]\n\n[*foo* bar]: /url \"title\"\n": "NOT_TO_EQUAL",
"![Foo][]\n\n[foo]: /url \"title\"\n": "NOT_TO_EQUAL",
"![foo] \n[]\n\n[foo]: /url \"title\"\n": "NOT_TO_EQUAL",
"![foo]\n\n[foo]: /url \"title\"\n": "NOT_TO_EQUAL",
"![*foo* bar]\n\n[*foo* bar]: /url \"title\"\n": "NOT_TO_EQUAL",
"![[foo]]\n\n[[foo]]: /url \"title\"\n": "NOT_TO_EQUAL",
"![Foo]\n\n[foo]: /url \"title\"\n": "NOT_TO_EQUAL",
"!\\[foo]\n\n[foo]: /url \"title\"\n": "TO_EQUAL",
"\\![foo]\n\n[foo]: /url \"title\"\n": "NOT_TO_EQUAL",
"<http://foo.bar.baz>\n": "TO_EQUAL",
"<http://foo.bar.baz/test?q=hello&id=22&boolean>\n": "NOT_TO_EQUAL",
"<irc://foo.bar:2233/baz>\n": "TO_EQUAL",
"<MAILTO:FOO@BAR.BAZ>\n": "NOT_TO_EQUAL",
"<a+b+c:d>\n": "NOT_TO_EQUAL",
"<made-up-scheme://foo,bar>\n": "TO_EQUAL",
"<http://../>\n": "TO_EQUAL",
"<localhost:5001/foo>\n": "NOT_TO_EQUAL",
"<http://foo.bar/baz bim>\n": "NOT_TO_EQUAL",
"<http://example.com/\\[\\>\n": "NOT_TO_EQUAL",
"<foo@bar.example.com>\n": "TO_EQUAL",
"<foo+special@Bar.baz-bar0.com>\n": "TO_EQUAL",
"<foo\\+@bar.example.com>\n": "NOT_TO_EQUAL",
"<>\n": "NOT_TO_EQUAL",
"< http://foo.bar >\n": "NOT_TO_EQUAL",
"<m:abc>\n": "NOT_TO_EQUAL",
"<foo.bar.baz>\n": "NOT_TO_EQUAL",
"http://example.com\n": "TO_EQUAL",
"foo@bar.example.com\n": "TO_EQUAL",
"<a><bab><c2c>\n": "TO_EQUAL",
"<a/><b2/>\n": "TO_EQUAL",
"<a /><b2\ndata=\"foo\" >\n": "TO_EQUAL",
"<a foo=\"bar\" bam = 'baz <em>\"</em>'\n_boolean zoop:33=zoop:33 />\n": "TO_EQUAL",
"Foo <responsive-image src=\"foo.jpg\" />\n": "TO_EQUAL",
"<33> <__>\n": "NOT_TO_EQUAL",
"<a h*#ref=\"hi\">\n": "NOT_TO_EQUAL",
"<a href=\"hi'> <a href=hi'>\n": "NOT_TO_EQUAL",
"< a><\nfoo><bar/ >\n": "NOT_TO_EQUAL",
"<a href='bar'title=title>\n": "NOT_TO_EQUAL",
"</a></foo >\n": "TO_EQUAL",
"</a href=\"foo\">\n": "NOT_TO_EQUAL",
"foo <!-- this is a\ncomment - with hyphen -->\n": "TO_EQUAL",
"foo <!-- not a comment -- two hyphens -->\n": "NOT_TO_EQUAL",
"foo <!--> foo -->\n\nfoo <!-- foo--->\n": "NOT_TO_EQUAL",
"foo <?php echo $a; ?>\n": "TO_EQUAL",
"foo <!ELEMENT br EMPTY>\n": "TO_EQUAL",
"foo <![CDATA[>&<]]>\n": "NOT_TO_EQUAL",
"foo <a href=\"&ouml;\">\n": "TO_EQUAL",
"foo <a href=\"\\*\">\n": "TO_EQUAL",
"<a href=\"\\\"\">\n": "NOT_TO_EQUAL",
"foo \nbaz\n": "NOT_TO_EQUAL",
"foo\\\nbaz\n": "NOT_TO_EQUAL",
"foo \nbaz\n": "NOT_TO_EQUAL",
"foo \n bar\n": "NOT_TO_EQUAL",
"foo\\\n bar\n": "NOT_TO_EQUAL",
"*foo \nbar*\n": "NOT_TO_EQUAL",
"*foo\\\nbar*\n": "NOT_TO_EQUAL",
"`code \nspan`\n": "TO_EQUAL",
"`code\\\nspan`\n": "TO_EQUAL",
"<a href=\"foo \nbar\">\n": "TO_EQUAL",
"<a href=\"foo\\\nbar\">\n": "TO_EQUAL",
"foo\\\n": "TO_EQUAL",
"foo \n": "TO_EQUAL",
"### foo\\\n": "TO_EQUAL",
"### foo \n": "TO_EQUAL",
"foo\nbaz\n": "TO_EQUAL",
"foo \n baz\n": "TO_EQUAL",
"hello $.;'there\n": "TO_EQUAL",
"Foo χρῆν\n": "TO_EQUAL",
"Multiple spaces\n": "TO_EQUAL"
}

View File

@@ -0,0 +1 @@
Fill to_*this*_mark, and your charge is but a penny; to_*this*_a penny more; and so on to the full glass—the Cape Horn measure, which you may gulp down for a shilling.\n\nUpon entering the place I found a number of young seamen gathered about a table, examining by a dim light divers specimens of_*skrimshander*.

View File

@@ -0,0 +1,110 @@
import { flow } from 'lodash';
import { tests as commonmarkSpec } from 'commonmark-spec';
import * as commonmark from 'commonmark';
import { markdownToSlate, slateToMarkdown } from '../index.js';
const skips = [
{
number: [456],
reason: 'Remark ¯\\_(ツ)_/¯',
},
{
number: [416, 417, 424, 425, 426, 431, 457, 460, 462, 464, 467],
reason: 'Remark does not support infinite (redundant) nested marks',
},
{
number: [455, 469, 470, 471],
reason: 'Remark parses the initial set of identical nested delimiters first',
},
{
number: [473, 476, 478, 480],
reason: 'we convert underscores to asterisks for strong/emphasis',
},
{ number: 490, reason: 'Remark strips pointy enclosing pointy brackets from link url' },
{ number: 503, reason: 'Remark allows non-breaking space between link url and title' },
{ number: 507, reason: 'Remark allows a space between link alt and url' },
{
number: [
511, 516, 525, 528, 529, 530, 532, 533, 534, 540, 541, 542, 543, 546, 548, 560, 565, 567,
],
reason: 'we convert link references to standard links, but Remark also fails these',
},
{
number: [569, 570, 571, 572, 573, 581, 585],
reason: 'Remark does not recognize or remove marks in image alt text',
},
{ number: 589, reason: 'Remark does not honor backslash escape of image exclamation point' },
{ number: 593, reason: 'Remark removes "mailto:" from autolink text' },
{ number: 599, reason: 'Remark does not escape all expected entities' },
{ number: 602, reason: 'Remark allows autolink emails to contain backslashes' },
];
const onlys = [
// just add the spec number, eg:
// 431,
];
/**
* Each test receives input markdown and output html as expected for Commonmark
* compliance. To test all of our handling in one go, we serialize the markdown
* into our Slate AST, then back to raw markdown, and finally to HTML.
*/
const reader = new commonmark.Parser();
const writer = new commonmark.HtmlRenderer();
function parseWithCommonmark(markdown) {
const parsed = reader.parse(markdown);
return writer.render(parsed);
}
const parse = flow([markdownToSlate, slateToMarkdown]);
/**
* Passing this test suite requires 100% Commonmark compliance. There are 624
* tests, of which we're passing about 300 as of introduction of this suite. To
* work on improving Commonmark support, update __fixtures__/commonmarkExpected.json
*/
describe.skip('Commonmark support', function () {
const specs =
onlys.length > 0
? commonmarkSpec.filter(({ number }) => onlys.includes(number))
: commonmarkSpec;
specs.forEach(spec => {
const skip = skips.find(({ number }) => {
return Array.isArray(number) ? number.includes(spec.number) : number === spec.number;
});
const specUrl = `https://spec.commonmark.org/0.29/#example-${spec.number}`;
const parsed = parse(spec.markdown);
const commonmarkParsedHtml = parseWithCommonmark(parsed);
const description = `
${spec.section}
${specUrl}
Spec:
${JSON.stringify(spec, null, 2)}
Markdown input:
${spec.markdown}
Markdown parsed through Slate/Remark and back to Markdown:
${parsed}
HTML output:
${commonmarkParsedHtml}
Expected HTML output:
${spec.html}
`;
if (skip) {
const showMessage = Array.isArray(skip.number) ? skip.number[0] === spec.number : true;
if (showMessage) {
//console.log(`skipping spec ${skip.number}\n${skip.reason}\n${specUrl}`);
}
}
const testFn = skip ? test.skip : test;
testFn(description, () => {
expect(commonmarkParsedHtml).toEqual(spec.html);
});
});
});

View File

@@ -0,0 +1,52 @@
import path from 'path';
import fs from 'fs';
import { markdownToSlate, htmlToSlate } from '../';
describe('markdownToSlate', () => {
it('should not add duplicate identical marks under the same node (GitHub Issue 3280)', () => {
const mdast = fs.readFileSync(
path.join(__dirname, '__fixtures__', 'duplicate_marks_github_issue_3280.md'),
);
const slate = markdownToSlate(mdast);
expect(slate).toEqual([
{
type: 'paragraph',
children: [
{
text: 'Fill to',
},
{
italic: true,
marks: [{ type: 'italic' }],
text: 'this_mark, and your charge is but a penny; tothisa penny more; and so on to the full glass—the Cape Horn measure, which you may gulp down for a shilling.\\n\\nUpon entering the place I found a number of young seamen gathered about a table, examining by a dim light divers specimens ofskrimshander',
},
{
text: '.',
},
],
},
]);
});
});
describe('htmlToSlate', () => {
it('should preserve spaces in rich html (GitHub Issue 3727)', () => {
const html = `<strong>Bold Text</strong><span><span> </span>regular text<span> </span></span>`;
const actual = htmlToSlate(html);
expect(actual).toEqual({
type: 'root',
children: [
{
type: 'paragraph',
children: [
{ text: 'Bold Text', bold: true, marks: [{ type: 'bold' }] },
{ text: ' regular text' },
],
},
],
});
});
});

View File

@@ -0,0 +1,25 @@
import unified from 'unified';
import markdownToRemark from 'remark-parse';
import remarkAllowHtmlEntities from '../remarkAllowHtmlEntities';
function process(markdown) {
const mdast = unified().use(markdownToRemark).use(remarkAllowHtmlEntities).parse(markdown);
/**
* The MDAST will look like:
*
* { type: 'root', children: [
* { type: 'paragraph', children: [
* // results here
* ]}
* ]}
*/
return mdast.children[0].children[0].value;
}
describe('remarkAllowHtmlEntities', () => {
it('should not decode HTML entities', () => {
expect(process('&lt;div&gt;')).toEqual('&lt;div&gt;');
});
});

View File

@@ -0,0 +1,171 @@
import u from 'unist-builder';
import remarkAssertParents from '../remarkAssertParents';
const transform = remarkAssertParents();
describe('remarkAssertParents', () => {
it('should unnest invalidly nested blocks', () => {
const input = u('root', [
u('paragraph', [
u('paragraph', [u('text', 'Paragraph text.')]),
u('heading', { depth: 1 }, [u('text', 'Heading text.')]),
u('code', 'someCode()'),
u('blockquote', [u('text', 'Quote text.')]),
u('list', [u('listItem', [u('text', 'A list item.')])]),
u('table', [u('tableRow', [u('tableCell', [u('text', 'Text in a table cell.')])])]),
u('thematicBreak'),
]),
]);
const output = u('root', [
u('paragraph', [u('text', 'Paragraph text.')]),
u('heading', { depth: 1 }, [u('text', 'Heading text.')]),
u('code', 'someCode()'),
u('blockquote', [u('text', 'Quote text.')]),
u('list', [u('listItem', [u('text', 'A list item.')])]),
u('table', [u('tableRow', [u('tableCell', [u('text', 'Text in a table cell.')])])]),
u('thematicBreak'),
]);
expect(transform(input)).toEqual(output);
});
it('should unnest deeply nested blocks', () => {
const input = u('root', [
u('paragraph', [
u('paragraph', [
u('paragraph', [
u('paragraph', [u('text', 'Paragraph text.')]),
u('heading', { depth: 1 }, [u('text', 'Heading text.')]),
u('code', 'someCode()'),
u('blockquote', [
u('paragraph', [u('strong', [u('heading', [u('text', 'Quote text.')])])]),
]),
u('list', [u('listItem', [u('text', 'A list item.')])]),
u('table', [u('tableRow', [u('tableCell', [u('text', 'Text in a table cell.')])])]),
u('thematicBreak'),
]),
]),
]),
]);
const output = u('root', [
u('paragraph', [u('text', 'Paragraph text.')]),
u('heading', { depth: 1 }, [u('text', 'Heading text.')]),
u('code', 'someCode()'),
u('blockquote', [u('heading', [u('text', 'Quote text.')])]),
u('list', [u('listItem', [u('text', 'A list item.')])]),
u('table', [u('tableRow', [u('tableCell', [u('text', 'Text in a table cell.')])])]),
u('thematicBreak'),
]);
expect(transform(input)).toEqual(output);
});
it('should remove blocks that are emptied as a result of denesting', () => {
const input = u('root', [
u('paragraph', [u('heading', { depth: 1 }, [u('text', 'Heading text.')])]),
]);
const output = u('root', [u('heading', { depth: 1 }, [u('text', 'Heading text.')])]);
expect(transform(input)).toEqual(output);
});
it('should remove blocks that are emptied as a result of denesting', () => {
const input = u('root', [
u('paragraph', [u('heading', { depth: 1 }, [u('text', 'Heading text.')])]),
]);
const output = u('root', [u('heading', { depth: 1 }, [u('text', 'Heading text.')])]);
expect(transform(input)).toEqual(output);
});
it('should handle asymmetrical splits', () => {
const input = u('root', [
u('paragraph', [u('heading', { depth: 1 }, [u('text', 'Heading text.')])]),
]);
const output = u('root', [u('heading', { depth: 1 }, [u('text', 'Heading text.')])]);
expect(transform(input)).toEqual(output);
});
it('should nest invalidly nested blocks in the nearest valid ancestor', () => {
const input = u('root', [
u('paragraph', [
u('blockquote', [u('strong', [u('heading', { depth: 1 }, [u('text', 'Heading text.')])])]),
]),
]);
const output = u('root', [
u('blockquote', [u('heading', { depth: 1 }, [u('text', 'Heading text.')])]),
]);
expect(transform(input)).toEqual(output);
});
it('should preserve validly nested siblings of invalidly nested blocks', () => {
const input = u('root', [
u('paragraph', [
u('blockquote', [
u('strong', [
u('text', 'Deep validly nested text a.'),
u('heading', { depth: 1 }, [u('text', 'Heading text.')]),
u('text', 'Deep validly nested text b.'),
]),
]),
u('text', 'Validly nested text.'),
]),
]);
const output = u('root', [
u('blockquote', [
u('strong', [u('text', 'Deep validly nested text a.')]),
u('heading', { depth: 1 }, [u('text', 'Heading text.')]),
u('strong', [u('text', 'Deep validly nested text b.')]),
]),
u('paragraph', [u('text', 'Validly nested text.')]),
]);
expect(transform(input)).toEqual(output);
});
it('should allow intermediate parents like list and table to contain required block children', () => {
const input = u('root', [
u('blockquote', [
u('list', [
u('listItem', [
u('table', [
u('tableRow', [
u('tableCell', [
u('heading', { depth: 1 }, [u('text', 'Validly nested heading text.')]),
]),
]),
]),
]),
]),
]),
]);
const output = u('root', [
u('blockquote', [
u('list', [
u('listItem', [
u('table', [
u('tableRow', [
u('tableCell', [
u('heading', { depth: 1 }, [u('text', 'Validly nested heading text.')]),
]),
]),
]),
]),
]),
]),
]);
expect(transform(input)).toEqual(output);
});
});

View File

@@ -0,0 +1,84 @@
import unified from 'unified';
import u from 'unist-builder';
import remarkEscapeMarkdownEntities from '../remarkEscapeMarkdownEntities';
function process(text) {
const tree = u('root', [u('text', text)]);
const escapedMdast = unified().use(remarkEscapeMarkdownEntities).runSync(tree);
return escapedMdast.children[0].value;
}
describe('remarkEscapeMarkdownEntities', () => {
it('should escape common markdown entities', () => {
expect(process('*a*')).toEqual('\\*a\\*');
expect(process('**a**')).toEqual('\\*\\*a\\*\\*');
expect(process('***a***')).toEqual('\\*\\*\\*a\\*\\*\\*');
expect(process('_a_')).toEqual('\\_a\\_');
expect(process('__a__')).toEqual('\\_\\_a\\_\\_');
expect(process('~~a~~')).toEqual('\\~\\~a\\~\\~');
expect(process('[]')).toEqual('\\[]');
expect(process('[]()')).toEqual('\\[]()');
expect(process('[a](b)')).toEqual('\\[a](b)');
expect(process('[Test sentence.](https://www.example.com)')).toEqual(
'\\[Test sentence.](https://www.example.com)',
);
expect(process('![a](b)')).toEqual('!\\[a](b)');
});
it('should not escape inactive, single markdown entities', () => {
expect(process('a*b')).toEqual('a*b');
expect(process('_')).toEqual('_');
expect(process('~')).toEqual('~');
expect(process('[')).toEqual('[');
});
it('should escape leading markdown entities', () => {
expect(process('#')).toEqual('\\#');
expect(process('-')).toEqual('\\-');
expect(process('*')).toEqual('\\*');
expect(process('>')).toEqual('\\>');
expect(process('=')).toEqual('\\=');
expect(process('|')).toEqual('\\|');
expect(process('```')).toEqual('\\`\\``');
expect(process(' ')).toEqual('\\ ');
});
it('should escape leading markdown entities preceded by whitespace', () => {
expect(process('\n #')).toEqual('\\#');
expect(process(' \n-')).toEqual('\\-');
});
it('should not escape leading markdown entities preceded by non-whitespace characters', () => {
expect(process('a# # b #')).toEqual('a# # b #');
expect(process('a- - b -')).toEqual('a- - b -');
});
it('should not escape html tags', () => {
expect(process('<a attr="**a**">')).toEqual('<a attr="**a**">');
expect(process('a b <c attr="**d**"> e')).toEqual('a b <c attr="**d**"> e');
});
it('should escape the contents of html blocks', () => {
expect(process('<div>*a*</div>')).toEqual('<div>\\*a\\*</div>');
});
it('should not escape the contents of preformatted html blocks', () => {
expect(process('<pre>*a*</pre>')).toEqual('<pre>*a*</pre>');
expect(process('<script>*a*</script>')).toEqual('<script>*a*</script>');
expect(process('<style>*a*</style>')).toEqual('<style>*a*</style>');
expect(process('<pre>\n*a*\n</pre>')).toEqual('<pre>\n*a*\n</pre>');
expect(process('a b <pre>*c*</pre> d e')).toEqual('a b <pre>*c*</pre> d e');
});
it('should not escape footnote references', () => {
expect(process('[^a]')).toEqual('[^a]');
expect(process('[^1]')).toEqual('[^1]');
});
it('should not escape footnotes', () => {
expect(process('[^a]:')).toEqual('[^a]:');
expect(process('[^1]:')).toEqual('[^1]:');
});
});

View File

@@ -0,0 +1,43 @@
import unified from 'unified';
import markdownToRemark from 'remark-parse';
import remarkToMarkdown from 'remark-stringify';
import remarkPaddedLinks from '../remarkPaddedLinks';
function input(markdown) {
return unified()
.use(markdownToRemark)
.use(remarkPaddedLinks)
.use(remarkToMarkdown)
.processSync(markdown).contents;
}
function output(markdown) {
return unified().use(markdownToRemark).use(remarkToMarkdown).processSync(markdown).contents;
}
describe('remarkPaddedLinks', () => {
it('should move leading and trailing spaces outside of a link', () => {
expect(input('[ a ](b)')).toEqual(output(' [a](b) '));
});
it('should convert multiple leading or trailing spaces to a single space', () => {
expect(input('[ a ](b)')).toEqual(output(' [a](b) '));
});
it('should work with only a leading space or only a trailing space', () => {
expect(input('[ a](b)[c ](d)')).toEqual(output(' [a](b)[c](d) '));
});
it('should work for nested links', () => {
expect(input('* # a[ b ](c)d')).toEqual(output('* # a [b](c) d'));
});
it('should work for parents with multiple links that are not siblings', () => {
expect(input('# a[ b ](c)d **[ e ](f)**')).toEqual(output('# a [b](c) d ** [e](f) **'));
});
it('should work for links with arbitrarily nested children', () => {
expect(input('[ a __*b*__ _c_ ](d)')).toEqual(output(' [a __*b*__ _c_](d) '));
});
});

View File

@@ -0,0 +1,299 @@
import visit from 'unist-util-visit';
import { markdownToRemark, remarkToMarkdown } from '..';
describe('registered remark plugins', () => {
function withNetlifyLinks() {
return function transformer(tree) {
visit(tree, 'link', function onLink(node) {
node.url = 'https://netlify.com';
});
};
}
it('should use remark transformer plugins when converting mdast to markdown', () => {
const plugins = [withNetlifyLinks];
const result = remarkToMarkdown(
{
type: 'root',
children: [
{
type: 'paragraph',
children: [
{
type: 'text',
value: 'Some ',
},
{
type: 'emphasis',
children: [
{
type: 'text',
value: 'important',
},
],
},
{
type: 'text',
value: ' text with ',
},
{
type: 'link',
title: null,
url: 'https://this-value-should-be-replaced.com',
children: [
{
type: 'text',
value: 'a link',
},
],
},
{
type: 'text',
value: ' in it.',
},
],
},
],
},
plugins,
);
expect(result).toMatchInlineSnapshot(
`"Some *important* text with [a link](https://netlify.com) in it."`,
);
});
it('should use remark transformer plugins when converting markdown to mdast', () => {
const plugins = [withNetlifyLinks];
const result = markdownToRemark(
'Some text with [a link](https://this-value-should-be-replaced.com) in it.',
plugins,
);
expect(result).toMatchInlineSnapshot(`
Object {
"children": Array [
Object {
"children": Array [
Object {
"children": Array [],
"position": Position {
"end": Object {
"column": 16,
"line": 1,
"offset": 15,
},
"indent": Array [],
"start": Object {
"column": 1,
"line": 1,
"offset": 0,
},
},
"type": "text",
"value": "Some text with ",
},
Object {
"children": Array [
Object {
"children": Array [],
"position": Position {
"end": Object {
"column": 23,
"line": 1,
"offset": 22,
},
"indent": Array [],
"start": Object {
"column": 17,
"line": 1,
"offset": 16,
},
},
"type": "text",
"value": "a link",
},
],
"position": Position {
"end": Object {
"column": 67,
"line": 1,
"offset": 66,
},
"indent": Array [],
"start": Object {
"column": 16,
"line": 1,
"offset": 15,
},
},
"title": null,
"type": "link",
"url": "https://netlify.com",
},
Object {
"children": Array [],
"position": Position {
"end": Object {
"column": 74,
"line": 1,
"offset": 73,
},
"indent": Array [],
"start": Object {
"column": 67,
"line": 1,
"offset": 66,
},
},
"type": "text",
"value": " in it.",
},
],
"position": Position {
"end": Object {
"column": 74,
"line": 1,
"offset": 73,
},
"indent": Array [],
"start": Object {
"column": 1,
"line": 1,
"offset": 0,
},
},
"type": "paragraph",
},
],
"position": Object {
"end": Object {
"column": 74,
"line": 1,
"offset": 73,
},
"start": Object {
"column": 1,
"line": 1,
"offset": 0,
},
},
"type": "root",
}
`);
});
it('should use remark serializer plugins when converting mdast to markdown', () => {
function withEscapedLessThanChar() {
if (this.Compiler) {
this.Compiler.prototype.visitors.text = node => {
return node.value.replace(/</g, '&lt;');
};
}
}
const plugins = [withEscapedLessThanChar];
const result = remarkToMarkdown(
{
type: 'root',
children: [
{
type: 'paragraph',
children: [
{
type: 'text',
value: '<3 Netlify',
},
],
},
],
},
plugins,
);
expect(result).toMatchInlineSnapshot(`"&lt;3 Netlify"`);
});
it('should use remark preset with settings when converting mdast to markdown', () => {
const settings = {
emphasis: '_',
bullet: '-',
};
const plugins = [{ settings }];
const result = remarkToMarkdown(
{
type: 'root',
children: [
{
type: 'paragraph',
children: [
{
type: 'text',
value: 'Some ',
},
{
type: 'emphasis',
children: [
{
type: 'text',
value: 'important',
},
],
},
{
type: 'text',
value: ' points:',
},
],
},
{
type: 'list',
ordered: false,
start: null,
spread: false,
children: [
{
type: 'listItem',
spread: false,
checked: null,
children: [
{
type: 'paragraph',
children: [
{
type: 'text',
value: 'One',
},
],
},
],
},
{
type: 'listItem',
spread: false,
checked: null,
children: [
{
type: 'paragraph',
children: [
{
type: 'text',
value: 'Two',
},
],
},
],
},
],
},
],
},
plugins,
);
expect(result).toMatchInlineSnapshot(`
"Some _important_ points:
- One
- Two"
`);
});
});

View File

@@ -0,0 +1,106 @@
import { Map, OrderedMap } from 'immutable';
import { remarkParseShortcodes, getLinesWithOffsets } from '../remarkShortcodes';
// Stub of Remark Parser
function process(value, plugins, processEat = () => {}) {
function eat() {
return processEat;
}
function Parser() {}
Parser.prototype.blockTokenizers = {};
Parser.prototype.blockMethods = [];
remarkParseShortcodes.call({ Parser }, { plugins });
Parser.prototype.blockTokenizers.shortcode(eat, value);
}
function EditorComponent({ id = 'foo', fromBlock = jest.fn(), pattern }) {
return {
id,
fromBlock,
pattern,
};
}
describe('remarkParseShortcodes', () => {
describe('pattern matching', () => {
it('should work', () => {
const editorComponent = EditorComponent({ pattern: /bar/ });
process('foo bar', Map({ [editorComponent.id]: editorComponent }));
expect(editorComponent.fromBlock).toHaveBeenCalledWith(expect.arrayContaining(['bar']));
});
it('should match value surrounded in newlines', () => {
const editorComponent = EditorComponent({ pattern: /^bar$/ });
process('foo\n\nbar\n', Map({ [editorComponent.id]: editorComponent }));
expect(editorComponent.fromBlock).toHaveBeenCalledWith(expect.arrayContaining(['bar']));
});
it('should match multiline shortcodes', () => {
const editorComponent = EditorComponent({ pattern: /^foo\nbar$/ });
process('foo\nbar', Map({ [editorComponent.id]: editorComponent }));
expect(editorComponent.fromBlock).toHaveBeenCalledWith(expect.arrayContaining(['foo\nbar']));
});
it('should match multiline shortcodes with empty lines', () => {
const editorComponent = EditorComponent({ pattern: /^foo\n\nbar$/ });
process('foo\n\nbar', Map({ [editorComponent.id]: editorComponent }));
expect(editorComponent.fromBlock).toHaveBeenCalledWith(
expect.arrayContaining(['foo\n\nbar']),
);
});
it('should match shortcodes based on order of occurrence in value', () => {
const fooEditorComponent = EditorComponent({ id: 'foo', pattern: /foo/ });
const barEditorComponent = EditorComponent({ id: 'bar', pattern: /bar/ });
process(
'foo\n\nbar',
OrderedMap([
[barEditorComponent.id, barEditorComponent],
[fooEditorComponent.id, fooEditorComponent],
]),
);
expect(fooEditorComponent.fromBlock).toHaveBeenCalledWith(expect.arrayContaining(['foo']));
});
it('should match shortcodes based on order of occurrence in value even when some use line anchors', () => {
const barEditorComponent = EditorComponent({ id: 'bar', pattern: /bar/ });
const bazEditorComponent = EditorComponent({ id: 'baz', pattern: /^baz$/ });
process(
'foo\n\nbar\n\nbaz',
OrderedMap([
[bazEditorComponent.id, bazEditorComponent],
[barEditorComponent.id, barEditorComponent],
]),
);
expect(barEditorComponent.fromBlock).toHaveBeenCalledWith(expect.arrayContaining(['bar']));
});
});
describe('output', () => {
it('should be a remark shortcode node', () => {
const processEat = jest.fn();
const shortcodeData = { bar: 'baz' };
const expectedNode = { type: 'shortcode', data: { shortcode: 'foo', shortcodeData } };
const editorComponent = EditorComponent({ pattern: /bar/, fromBlock: () => shortcodeData });
process('foo bar', Map({ [editorComponent.id]: editorComponent }), processEat);
expect(processEat).toHaveBeenCalledWith(expectedNode);
});
});
});
describe('getLinesWithOffsets', () => {
test('should split into lines', () => {
const value = ' line1\n\nline2 \n\n line3 \n\n';
const lines = getLinesWithOffsets(value);
expect(lines).toEqual([
{ line: ' line1', start: 0 },
{ line: 'line2', start: 8 },
{ line: ' line3', start: 16 },
{ line: '', start: 30 },
]);
});
test('should return single item on no match', () => {
const value = ' line1 ';
const lines = getLinesWithOffsets(value);
expect(lines).toEqual([{ line: ' line1', start: 0 }]);
});
});

View File

@@ -0,0 +1,67 @@
import { mergeAdjacentTexts } from '../remarkSlate';
describe('remarkSlate', () => {
describe('mergeAdjacentTexts', () => {
it('should handle empty array', () => {
const children = [];
expect(mergeAdjacentTexts(children)).toBe(children);
});
it('should merge adjacent texts with same marks', () => {
const children = [
{ text: '<a href="https://www.netlify.com" target="_blank">', marks: [] },
{ text: 'Netlify', marks: [] },
{ text: '</a>', marks: [] },
];
expect(mergeAdjacentTexts(children)).toEqual([
{
text: '<a href="https://www.netlify.com" target="_blank">Netlify</a>',
marks: [],
},
]);
});
it('should not merge adjacent texts with different marks', () => {
const children = [
{ text: '<a href="https://www.netlify.com" target="_blank">', marks: [] },
{ text: 'Netlify', marks: ['b'] },
{ text: '</a>', marks: [] },
];
expect(mergeAdjacentTexts(children)).toEqual(children);
});
it('should handle mixed children array', () => {
const children = [
{ object: 'inline' },
{ text: '<a href="https://www.netlify.com" target="_blank">', marks: [] },
{ text: 'Netlify', marks: [] },
{ text: '</a>', marks: [] },
{ object: 'inline' },
{ text: '<a href="https://www.netlify.com" target="_blank">', marks: [] },
{ text: 'Netlify', marks: ['b'] },
{ text: '</a>', marks: [] },
{ text: '<a href="https://www.netlify.com" target="_blank">', marks: [] },
{ object: 'inline' },
{ text: '</a>', marks: [] },
];
expect(mergeAdjacentTexts(children)).toEqual([
{ object: 'inline' },
{
text: '<a href="https://www.netlify.com" target="_blank">Netlify</a>',
marks: [],
},
{ object: 'inline' },
{ text: '<a href="https://www.netlify.com" target="_blank">', marks: [] },
{ text: 'Netlify', marks: ['b'] },
{
text: '</a><a href="https://www.netlify.com" target="_blank">',
marks: [],
},
{ object: 'inline' },
{ text: '</a>', marks: [] },
]);
});
});
});

View File

@@ -0,0 +1,23 @@
import unified from 'unified';
import u from 'unist-builder';
import remarkStripTrailingBreaks from '../remarkStripTrailingBreaks';
function process(children) {
const tree = u('root', children);
const strippedMdast = unified().use(remarkStripTrailingBreaks).runSync(tree);
return strippedMdast.children;
}
describe('remarkStripTrailingBreaks', () => {
it('should remove trailing breaks at the end of a block', () => {
expect(process([u('break')])).toEqual([]);
expect(process([u('break'), u('text', '\n \n')])).toEqual([u('text', '\n \n')]);
expect(process([u('text', 'a'), u('break')])).toEqual([u('text', 'a')]);
});
it('should not remove trailing breaks that are not at the end of a block', () => {
expect(process([u('break'), u('text', 'a')])).toEqual([u('break'), u('text', 'a')]);
});
});

View File

@@ -0,0 +1,300 @@
/** @jsx h */
import { flow } from 'lodash';
import h from '../../../test-helpers/h';
import { markdownToSlate, slateToMarkdown } from '../index';
const process = flow([markdownToSlate, slateToMarkdown]);
describe('slate', () => {
it('should not decode encoded html entities in inline code', () => {
expect(process('<element type="code">&lt;div&gt;</element>')).toEqual(
'<element type="code">&lt;div&gt;</element>',
);
});
it('should parse non-text children of mark nodes', () => {
expect(process('**a[b](c)d**')).toEqual('**a[b](c)d**');
expect(process('**[a](b)**')).toEqual('**[a](b)**');
expect(process('**![a](b)**')).toEqual('**![a](b)**');
expect(process('_`a`_')).toEqual('*`a`*');
});
it('should handle unstyled code nodes adjacent to styled code nodes', () => {
expect(process('`foo`***`bar`***')).toEqual('`foo`***`bar`***');
});
it('should handle styled code nodes adjacent to non-code text', () => {
expect(process('_`a`b_')).toEqual('*`a`b*');
expect(process('_`a`**b**_')).toEqual('*`a`**b***');
});
it('should condense adjacent, identically styled text and inline nodes', () => {
expect(process('**a ~~b~~~~c~~**')).toEqual('**a ~~bc~~**');
expect(process('**a ~~b~~~~[c](d)~~**')).toEqual('**a ~~b[c](d)~~**');
});
it('should handle nested markdown entities', () => {
expect(process('**a**b**c**')).toEqual('**a**b**c**');
expect(process('**a _b_ c**')).toEqual('**a *b* c**');
expect(process('*`a`*')).toEqual('*`a`*');
});
it('should parse inline images as images', () => {
expect(process('a ![b](c)')).toEqual('a ![b](c)');
});
it('should not escape markdown entities in html', () => {
expect(process('<span>*</span>')).toEqual('<span>*</span>');
});
it('should wrap break tags in surrounding marks', () => {
expect(process('*a \nb*')).toEqual('*a\\\nb*');
});
// slateAst no longer valid
it('should not output empty headers in markdown', () => {
// prettier-ignore
const slateAst = (
<editor>
<element type="heading-one"></element>
<element type="paragraph">foo</element>
<element type="heading-one"></element>
</editor>
);
expect(slateToMarkdown(slateAst.children)).toMatchInlineSnapshot(`"foo"`);
});
it('should not output empty marks in markdown', () => {
// prettier-ignore
const slateAst = (
<editor>
<element type="paragraph">
<text bold></text>
foo<text italic><text bold></text></text>bar
<text bold></text>baz<text italic></text>
</element>
</editor>
);
expect(slateToMarkdown(slateAst.children)).toMatchInlineSnapshot(`"foobarbaz"`);
});
it('should not produce invalid markdown when a styled block has trailing whitespace', () => {
// prettier-ignore
const slateAst = (
<editor>
<element type="paragraph">
<text bold>foo </text>bar <text bold>bim </text><text bold><text italic>bam</text></text>
</element>
</editor>
);
expect(slateToMarkdown(slateAst.children)).toMatchInlineSnapshot(`"**foo** bar **bim *bam***"`);
});
it('should not produce invalid markdown when a styled block has leading whitespace', () => {
// prettier-ignore
const slateAst = (
<editor>
<element type="paragraph">
foo<text bold> bar</text>
</element>
</editor>
);
expect(slateToMarkdown(slateAst.children)).toMatchInlineSnapshot(`"foo **bar**"`);
});
it('should group adjacent marks into a single mark when possible', () => {
// prettier-ignore
const slateAst = (
<editor>
<element type="paragraph">
<text bold>shared mark</text>
<element type="link" data={{ url: "link" }}>
<text bold><text italic>link</text></text>
</element>
{' '}
<text bold>not shared mark</text>
<element type="link" data={{ url: "link" }}>
<text italic>another </text>
<text bold><text italic>link</text></text>
</element>
</element>
</editor>
);
expect(slateToMarkdown(slateAst.children)).toMatchInlineSnapshot(
`"**shared mark*[link](link)*** **not shared mark***[another **link**](link)*"`,
);
});
describe('links', () => {
it('should handle inline code in link content', () => {
// prettier-ignore
const slateAst = (
<editor>
<element type="paragraph">
<element type="link" data={{ url: "link" }}>
<text code>foo</text>
</element>
</element>
</editor>
);
expect(slateToMarkdown(slateAst.children)).toMatchInlineSnapshot(`"[\`foo\`](link)"`);
});
});
describe('code marks', () => {
it('can contain other marks', () => {
// prettier-ignore
const slateAst = (
<editor>
<element type="paragraph">
<text code><text italic><text bold>foo</text></text></text>
</element>
</editor>
);
expect(slateToMarkdown(slateAst.children)).toMatchInlineSnapshot(`"***\`foo\`***"`);
});
it('can be condensed when no other marks are present', () => {
// prettier-ignore
const slateAst = (
<editor>
<element type="paragraph">
<text code>foo</text>
<text code>bar</text>
</element>
</editor>
);
expect(slateToMarkdown(slateAst.children)).toMatchInlineSnapshot(`"\`foo\`"`);
});
});
describe('with nested styles within a single word', () => {
it('should not produce invalid markdown when a bold word has italics applied to a smaller part', () => {
// prettier-ignore
const slateAst = (
<editor>
<element type="paragraph">
<text bold>h</text>
<text bold><text italic>e</text></text>
<text bold>y</text>
</element>
</editor>
);
expect(slateToMarkdown(slateAst.children)).toMatchInlineSnapshot(`"**h*e*y**"`);
});
it('should not produce invalid markdown when an italic word has bold applied to a smaller part', () => {
// prettier-ignore
const slateAst = (
<editor>
<element type="paragraph">
<text italic>h</text>
<text italic><text bold>e</text></text>
<text italic>y</text>
</element>
</editor>
);
expect(slateToMarkdown(slateAst.children)).toMatchInlineSnapshot(`"*h**e**y*"`);
});
it('should handle italics inside bold inside strikethrough', () => {
// prettier-ignore
const slateAst = (
<editor>
<element type="paragraph">
<text delete>h</text>
<text delete><text bold>e</text></text>
<text delete><text bold><text italic>l</text></text></text>
<text delete><text bold>l</text></text>
<text delete>o</text>
</element>
</editor>
);
expect(slateToMarkdown(slateAst.children)).toMatchInlineSnapshot(`"~~h**e*l*l**o~~"`);
});
it('should handle bold inside italics inside strikethrough', () => {
// prettier-ignore
const slateAst = (
<editor>
<element type="paragraph">
<text delete>h</text>
<text delete><text italic>e</text></text>
<text delete><text italic><text bold>l</text></text></text>
<text delete><text italic>l</text></text>
<text delete>o</text>
</element>
</editor>
);
expect(slateToMarkdown(slateAst.children)).toMatchInlineSnapshot(`"~~h*e**l**l*o~~"`);
});
it('should handle strikethrough inside italics inside bold', () => {
// prettier-ignore
const slateAst = (
<editor>
<element type="paragraph">
<text bold>h</text>
<text bold><text italic>e</text></text>
<text bold><text italic><text delete>l</text></text></text>
<text bold><text italic>l</text></text>
<text bold>o</text>
</element>
</editor>
);
expect(slateToMarkdown(slateAst.children)).toMatchInlineSnapshot(`"**h*e~~l~~l*o**"`);
});
it('should handle italics inside strikethrough inside bold', () => {
// prettier-ignore
const slateAst = (
<editor>
<element type="paragraph">
<text bold>h</text>
<text bold><text delete>e</text></text>
<text bold><text delete><text italic>l</text></text></text>
<text bold><text delete>l</text></text>
<text bold>o</text>
</element>
</editor>
);
expect(slateToMarkdown(slateAst.children)).toMatchInlineSnapshot(`"**h~~e*l*l~~o**"`);
});
it('should handle strikethrough inside bold inside italics', () => {
// prettier-ignore
const slateAst = (
<editor>
<element type="paragraph">
<text italic>h</text>
<text italic><text bold>e</text></text>
<text italic><text bold><text delete>l</text></text></text>
<text italic><text bold>l</text></text>
<text italic>o</text>
</element>
</editor>
);
expect(slateToMarkdown(slateAst.children)).toMatchInlineSnapshot(`"*h**e~~l~~l**o*"`);
});
it('should handle bold inside strikethrough inside italics', () => {
// prettier-ignore
const slateAst = (
<editor>
<element type="paragraph">
<text italic>h</text>
<text italic><text delete>e</text></text>
<text italic><text delete><text bold>l</text></text></text>
<text italic><text delete>l</text></text>
<text italic>o</text>
</element>
</editor>
);
expect(slateToMarkdown(slateAst.children)).toMatchInlineSnapshot(`"*h~~e**l**l~~o*"`);
});
});
});