Mercurial
diff .cms/lib/codemirror/mode/markdown/test.js @ 0:78edf6b517a0 draft
24.10
author | Coffee CMS <info@coffee-cms.ru> |
---|---|
date | Fri, 11 Oct 2024 22:40:23 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.cms/lib/codemirror/mode/markdown/test.js Fri Oct 11 22:40:23 2024 +0000 @@ -0,0 +1,1319 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/5/LICENSE + +(function() { + var config = {tabSize: 4, indentUnit: 2} + var mode = CodeMirror.getMode(config, "markdown"); + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } + var modeHighlightFormatting = CodeMirror.getMode(config, {name: "markdown", highlightFormatting: true}); + function FT(name) { test.mode(name, modeHighlightFormatting, Array.prototype.slice.call(arguments, 1)); } + var modeMT_noXml = CodeMirror.getMode(config, {name: "markdown", xml: false}); + function MT_noXml(name) { test.mode(name, modeMT_noXml, Array.prototype.slice.call(arguments, 1)); } + var modeMT_noFencedHighlight = CodeMirror.getMode(config, {name: "markdown", fencedCodeBlockHighlighting: false}); + function MT_noFencedHighlight(name) { test.mode(name, modeMT_noFencedHighlight, Array.prototype.slice.call(arguments, 1)); } + var modeAtxNoSpace = CodeMirror.getMode(config, {name: "markdown", allowAtxHeaderWithoutSpace: true}); + function AtxNoSpaceTest(name) { test.mode(name, modeAtxNoSpace, Array.prototype.slice.call(arguments, 1)); } + var modeOverrideClasses = CodeMirror.getMode(config, { + name: "markdown", + strikethrough: true, + emoji: true, + tokenTypeOverrides: { + "header" : "override-header", + "code" : "override-code", + "quote" : "override-quote", + "list1" : "override-list1", + "list2" : "override-list2", + "list3" : "override-list3", + "hr" : "override-hr", + "image" : "override-image", + "imageAltText": "override-image-alt-text", + "imageMarker": "override-image-marker", + "linkInline" : "override-link-inline", + "linkEmail" : "override-link-email", + "linkText" : "override-link-text", + "linkHref" : "override-link-href", + "em" : "override-em", + "strong" : "override-strong", + "strikethrough" : "override-strikethrough", + "emoji" : "override-emoji" + }}); + function TokenTypeOverrideTest(name) { test.mode(name, modeOverrideClasses, Array.prototype.slice.call(arguments, 1)); } + var modeFormattingOverride = CodeMirror.getMode(config, { + name: "markdown", + highlightFormatting: true, + tokenTypeOverrides: { + "formatting" : "override-formatting" + }}); + function FormatTokenTypeOverrideTest(name) { test.mode(name, modeFormattingOverride, Array.prototype.slice.call(arguments, 1)); } + var modeET = CodeMirror.getMode(config, {name: "markdown", emoji: true}); + function ET(name) { test.mode(name, modeET, Array.prototype.slice.call(arguments, 1)); } + + + FT("formatting_emAsterisk", + "[em&formatting&formatting-em *][em foo][em&formatting&formatting-em *]"); + + FT("formatting_emUnderscore", + "[em&formatting&formatting-em _][em foo][em&formatting&formatting-em _]"); + + FT("formatting_strongAsterisk", + "[strong&formatting&formatting-strong **][strong foo][strong&formatting&formatting-strong **]"); + + FT("formatting_strongUnderscore", + "[strong&formatting&formatting-strong __][strong foo][strong&formatting&formatting-strong __]"); + + FT("formatting_codeBackticks", + "[comment&formatting&formatting-code `][comment foo][comment&formatting&formatting-code `]"); + + FT("formatting_doubleBackticks", + "[comment&formatting&formatting-code ``][comment foo ` bar][comment&formatting&formatting-code ``]"); + + FT("formatting_atxHeader", + "[header&header-1&formatting&formatting-header&formatting-header-1 # ][header&header-1 foo # bar ][header&header-1&formatting&formatting-header&formatting-header-1 #]"); + + FT("formatting_setextHeader", + "[header&header-1 foo]", + "[header&header-1&formatting&formatting-header&formatting-header-1 =]"); + + FT("formatting_blockquote", + "[quote"e-1&formatting&formatting-quote&formatting-quote-1 > ][quote"e-1 foo]"); + + FT("formatting_list", + "[variable-2&formatting&formatting-list&formatting-list-ul - ][variable-2 foo]"); + FT("formatting_list", + "[variable-2&formatting&formatting-list&formatting-list-ol 1. ][variable-2 foo]"); + + FT("formatting_link", + "[link&formatting&formatting-link [][link foo][link&formatting&formatting-link ]]][string&formatting&formatting-link-string&url (][string&url http://example.com/][string&formatting&formatting-link-string&url )]"); + + FT("formatting_linkReference", + "[link&formatting&formatting-link [][link foo][link&formatting&formatting-link ]]][string&formatting&formatting-link-string&url [][string&url bar][string&formatting&formatting-link-string&url ]]]", + "[link&formatting&formatting-link [][link bar][link&formatting&formatting-link ]]:] [string&url http://example.com/]"); + + FT("formatting_linkWeb", + "[link&formatting&formatting-link <][link http://example.com/][link&formatting&formatting-link >]"); + + FT("formatting_linkEmail", + "[link&formatting&formatting-link <][link user@example.com][link&formatting&formatting-link >]"); + + FT("formatting_escape", + "[formatting-escape \\*]"); + + FT("formatting_image", + "[formatting&formatting-image&image&image-marker !][formatting&formatting-image&image&image-alt-text&link [[][image&image-alt-text&link alt text][formatting&formatting-image&image&image-alt-text&link ]]][formatting&formatting-link-string&string&url (][url&string http://link.to/image.jpg][formatting&formatting-link-string&string&url )]"); + + FT("codeBlock", + "[comment&formatting&formatting-code-block ```css]", + "[tag foo]", + "[comment&formatting&formatting-code-block ```]"); + + MT("plainText", + "foo"); + + // Don't style single trailing space + MT("trailingSpace1", + "foo "); + + // Two or more trailing spaces should be styled with line break character + MT("trailingSpace2", + "foo[trailing-space-a ][trailing-space-new-line ]"); + + MT("trailingSpace3", + "foo[trailing-space-a ][trailing-space-b ][trailing-space-new-line ]"); + + MT("trailingSpace4", + "foo[trailing-space-a ][trailing-space-b ][trailing-space-a ][trailing-space-new-line ]"); + + // Code blocks using 4 spaces (regardless of CodeMirror.tabSize value) + MT("codeBlocksUsing4Spaces", + " [comment foo]"); + + // Code blocks using 4 spaces with internal indentation + MT("codeBlocksUsing4SpacesIndentation", + " [comment bar]", + " [comment hello]", + " [comment world]", + " [comment foo]", + "bar"); + + // Code blocks should end even after extra indented lines + MT("codeBlocksWithTrailingIndentedLine", + " [comment foo]", + " [comment bar]", + " [comment baz]", + " ", + "hello"); + + // Code blocks using 1 tab (regardless of CodeMirror.indentWithTabs value) + MT("codeBlocksUsing1Tab", + "\t[comment foo]"); + + // No code blocks directly after paragraph + // http://spec.commonmark.org/0.19/#example-65 + MT("noCodeBlocksAfterParagraph", + "Foo", + " Bar"); + + MT("codeBlocksAfterATX", + "[header&header-1 # foo]", + " [comment code]"); + + MT("codeBlocksAfterSetext", + "[header&header-2 foo]", + "[header&header-2 ---]", + " [comment code]"); + + MT("codeBlocksAfterFencedCode", + "[comment ```]", + "[comment foo]", + "[comment ```]", + " [comment code]"); + + // Inline code using backticks + MT("inlineCodeUsingBackticks", + "foo [comment `bar`]"); + + // Block code using single backtick (shouldn't work) + MT("blockCodeSingleBacktick", + "[comment `]", + "[comment foo]", + "[comment `]"); + + // Unclosed backticks + // Instead of simply marking as CODE, it would be nice to have an + // incomplete flag for CODE, that is styled slightly different. + MT("unclosedBackticks", + "foo [comment `bar]"); + + // Per documentation: "To include a literal backtick character within a + // code span, you can use multiple backticks as the opening and closing + // delimiters" + MT("doubleBackticks", + "[comment ``foo ` bar``]"); + + // Tests based on Dingus + // http://daringfireball.net/projects/markdown/dingus + // + // Multiple backticks within an inline code block + MT("consecutiveBackticks", + "[comment `foo```bar`]"); + + // Multiple backticks within an inline code block with a second code block + MT("consecutiveBackticks", + "[comment `foo```bar`] hello [comment `world`]"); + + // Unclosed with several different groups of backticks + MT("unclosedBackticks", + "[comment ``foo ``` bar` hello]"); + + // Closed with several different groups of backticks + MT("closedBackticks", + "[comment ``foo ``` bar` hello``] world"); + + // info string cannot contain backtick, thus should result in inline code + MT("closingFencedMarksOnSameLine", + "[comment ``` code ```] foo"); + + // atx headers + // http://daringfireball.net/projects/markdown/syntax#header + + MT("atxH1", + "[header&header-1 # foo]"); + + MT("atxH2", + "[header&header-2 ## foo]"); + + MT("atxH3", + "[header&header-3 ### foo]"); + + MT("atxH4", + "[header&header-4 #### foo]"); + + MT("atxH5", + "[header&header-5 ##### foo]"); + + MT("atxH6", + "[header&header-6 ###### foo]"); + + // http://spec.commonmark.org/0.19/#example-24 + MT("noAtxH7", + "####### foo"); + + // http://spec.commonmark.org/0.19/#example-25 + MT("noAtxH1WithoutSpace", + "#5 bolt"); + + // CommonMark requires a space after # but most parsers don't + AtxNoSpaceTest("atxNoSpaceAllowed_H1NoSpace", + "[header&header-1 #foo]"); + + AtxNoSpaceTest("atxNoSpaceAllowed_H4NoSpace", + "[header&header-4 ####foo]"); + + AtxNoSpaceTest("atxNoSpaceAllowed_H1Space", + "[header&header-1 # foo]"); + + // Inline styles should be parsed inside headers + MT("atxH1inline", + "[header&header-1 # foo ][header&header-1&em *bar*]"); + + MT("atxIndentedTooMuch", + "[header&header-1 # foo]", + " [comment # bar]"); + + // disable atx inside blockquote until we implement proper blockquote inner mode + // TODO: fix to be CommonMark-compliant + MT("atxNestedInsideBlockquote", + "[quote"e-1 > # foo]"); + + MT("atxAfterBlockquote", + "[quote"e-1 > foo]", + "[header&header-1 # bar]"); + + // Setext headers - H1, H2 + // Per documentation, "Any number of underlining =’s or -’s will work." + // http://daringfireball.net/projects/markdown/syntax#header + // Ideally, the text would be marked as `header` as well, but this is + // not really feasible at the moment. So, instead, we're testing against + // what works today, to avoid any regressions. + // + // Check if single underlining = works + MT("setextH1", + "[header&header-1 foo]", + "[header&header-1 =]"); + + // Check if 3+ ='s work + MT("setextH1", + "[header&header-1 foo]", + "[header&header-1 ===]"); + + // Check if single underlining - should not be interpreted + // as it might lead to an empty list: + // https://spec.commonmark.org/0.28/#setext-heading-underline + MT("setextH2Single", + "foo", + "-"); + + // Check if 3+ -'s work + MT("setextH2", + "[header&header-2 foo]", + "[header&header-2 ---]"); + + // http://spec.commonmark.org/0.19/#example-45 + MT("setextH2AllowSpaces", + "[header&header-2 foo]", + " [header&header-2 ---- ]"); + + // http://spec.commonmark.org/0.19/#example-44 + MT("noSetextAfterIndentedCodeBlock", + " [comment foo]", + "[hr ---]"); + + MT("setextAfterFencedCode", + "[comment ```]", + "[comment foo]", + "[comment ```]", + "[header&header-2 bar]", + "[header&header-2 ---]"); + + MT("setextAfterATX", + "[header&header-1 # foo]", + "[header&header-2 bar]", + "[header&header-2 ---]"); + + // http://spec.commonmark.org/0.19/#example-51 + MT("noSetextAfterQuote", + "[quote"e-1 > foo]", + "[hr ---]", + "", + "[quote"e-1 > foo]", + "[quote"e-1 bar]", + "[hr ---]"); + + MT("noSetextAfterList", + "[variable-2 - foo]", + "[hr ---]"); + + MT("noSetextAfterList_listContinuation", + "[variable-2 - foo]", + "bar", + "[hr ---]"); + + MT("setextAfterList_afterIndentedCode", + "[variable-2 - foo]", + "", + " [comment bar]", + "[header&header-2 baz]", + "[header&header-2 ---]"); + + MT("setextAfterList_afterFencedCodeBlocks", + "[variable-2 - foo]", + "", + " [comment ```]", + " [comment bar]", + " [comment ```]", + "[header&header-2 baz]", + "[header&header-2 ---]"); + + MT("setextAfterList_afterHeader", + "[variable-2 - foo]", + " [variable-2&header&header-1 # bar]", + "[header&header-2 baz]", + "[header&header-2 ---]"); + + MT("setextAfterList_afterHr", + "[variable-2 - foo]", + "", + " [hr ---]", + "[header&header-2 bar]", + "[header&header-2 ---]"); + + MT("setext_nestedInlineMarkup", + "[header&header-1 foo ][em&header&header-1 *bar*]", + "[header&header-1 =]"); + + MT("setext_linkDef", + "[link [[aaa]]:] [string&url http://google.com 'title']", + "[hr ---]"); + + // currently, looks max one line ahead, thus won't catch valid CommonMark + // markup + MT("setext_oneLineLookahead", + "foo", + "[header&header-1 bar]", + "[header&header-1 =]"); + + // ensure we regard space after a single dash as a list + MT("setext_emptyList", + "foo", + "[variable-2 - ]", + "foo"); + + // Single-line blockquote with trailing space + MT("blockquoteSpace", + "[quote"e-1 > foo]"); + + // Single-line blockquote + MT("blockquoteNoSpace", + "[quote"e-1 >foo]"); + + // No blank line before blockquote + MT("blockquoteNoBlankLine", + "foo", + "[quote"e-1 > bar]"); + + MT("blockquoteNested", + "[quote"e-1 > foo]", + "[quote"e-1 >][quote"e-2 > foo]", + "[quote"e-1 >][quote"e-2 >][quote"e-3 > foo]"); + + // ensure quote-level is inferred correctly even if indented + MT("blockquoteNestedIndented", + " [quote"e-1 > foo]", + " [quote"e-1 >][quote"e-2 > foo]", + " [quote"e-1 >][quote"e-2 >][quote"e-3 > foo]"); + + // ensure quote-level is inferred correctly even if indented + MT("blockquoteIndentedTooMuch", + "foo", + " > bar"); + + // Single-line blockquote followed by normal paragraph + MT("blockquoteThenParagraph", + "[quote"e-1 >foo]", + "", + "bar"); + + // Multi-line blockquote (lazy mode) + MT("multiBlockquoteLazy", + "[quote"e-1 >foo]", + "[quote"e-1 bar]"); + + // Multi-line blockquote followed by normal paragraph (lazy mode) + MT("multiBlockquoteLazyThenParagraph", + "[quote"e-1 >foo]", + "[quote"e-1 bar]", + "", + "hello"); + + // Multi-line blockquote (non-lazy mode) + MT("multiBlockquote", + "[quote"e-1 >foo]", + "[quote"e-1 >bar]"); + + // Multi-line blockquote followed by normal paragraph (non-lazy mode) + MT("multiBlockquoteThenParagraph", + "[quote"e-1 >foo]", + "[quote"e-1 >bar]", + "", + "hello"); + + // disallow lists inside blockquote for now because it causes problems outside blockquote + // TODO: fix to be CommonMark-compliant + MT("listNestedInBlockquote", + "[quote"e-1 > - foo]"); + + // disallow fenced blocks inside blockquote because it causes problems outside blockquote + // TODO: fix to be CommonMark-compliant + MT("fencedBlockNestedInBlockquote", + "[quote"e-1 > ```]", + "[quote"e-1 > code]", + "[quote"e-1 > ```]", + // ensure we still allow inline code + "[quote"e-1 > ][quote"e-1&comment `code`]"); + + // Header with leading space after continued blockquote (#3287, negative indentation) + MT("headerAfterContinuedBlockquote", + "[quote"e-1 > foo]", + "[quote"e-1 bar]", + "", + " [header&header-1 # hello]"); + + // Check list types + + MT("listAsterisk", + "foo", + "bar", + "", + "[variable-2 * foo]", + "[variable-2 * bar]"); + + MT("listPlus", + "foo", + "bar", + "", + "[variable-2 + foo]", + "[variable-2 + bar]"); + + MT("listDash", + "foo", + "bar", + "", + "[variable-2 - foo]", + "[variable-2 - bar]"); + + MT("listNumber", + "foo", + "bar", + "", + "[variable-2 1. foo]", + "[variable-2 2. bar]"); + + MT("listFromParagraph", + "foo", + "[variable-2 1. bar]", + "[variable-2 2. hello]"); + + // List after hr + MT("listAfterHr", + "[hr ---]", + "[variable-2 - bar]"); + + // List after header + MT("listAfterHeader", + "[header&header-1 # foo]", + "[variable-2 - bar]"); + + // hr after list + MT("hrAfterList", + "[variable-2 - foo]", + "[hr -----]"); + + MT("hrAfterFencedCode", + "[comment ```]", + "[comment code]", + "[comment ```]", + "[hr ---]"); + + // allow hr inside lists + // (require prev line to be empty or hr, TODO: non-CommonMark-compliant) + MT("hrInsideList", + "[variable-2 - foo]", + "", + " [hr ---]", + " [hr ---]", + "", + " [comment ---]"); + + MT("consecutiveHr", + "[hr ---]", + "[hr ---]", + "[hr ---]"); + + // Formatting in lists (*) + MT("listAsteriskFormatting", + "[variable-2 * ][variable-2&em *foo*][variable-2 bar]", + "[variable-2 * ][variable-2&strong **foo**][variable-2 bar]", + "[variable-2 * ][variable-2&em&strong ***foo***][variable-2 bar]", + "[variable-2 * ][variable-2&comment `foo`][variable-2 bar]"); + + // Formatting in lists (+) + MT("listPlusFormatting", + "[variable-2 + ][variable-2&em *foo*][variable-2 bar]", + "[variable-2 + ][variable-2&strong **foo**][variable-2 bar]", + "[variable-2 + ][variable-2&em&strong ***foo***][variable-2 bar]", + "[variable-2 + ][variable-2&comment `foo`][variable-2 bar]"); + + // Formatting in lists (-) + MT("listDashFormatting", + "[variable-2 - ][variable-2&em *foo*][variable-2 bar]", + "[variable-2 - ][variable-2&strong **foo**][variable-2 bar]", + "[variable-2 - ][variable-2&em&strong ***foo***][variable-2 bar]", + "[variable-2 - ][variable-2&comment `foo`][variable-2 bar]"); + + // Formatting in lists (1.) + MT("listNumberFormatting", + "[variable-2 1. ][variable-2&em *foo*][variable-2 bar]", + "[variable-2 2. ][variable-2&strong **foo**][variable-2 bar]", + "[variable-2 3. ][variable-2&em&strong ***foo***][variable-2 bar]", + "[variable-2 4. ][variable-2&comment `foo`][variable-2 bar]"); + + // Paragraph lists + MT("listParagraph", + "[variable-2 * foo]", + "", + "[variable-2 * bar]"); + + // Multi-paragraph lists + // + // 4 spaces + MT("listMultiParagraph", + "[variable-2 * foo]", + "", + "[variable-2 * bar]", + "", + " [variable-2 hello]"); + + // 4 spaces, extra blank lines (should still be list, per Dingus) + MT("listMultiParagraphExtra", + "[variable-2 * foo]", + "", + "[variable-2 * bar]", + "", + "", + " [variable-2 hello]"); + + // 4 spaces, plus 1 space (should still be list, per Dingus) + MT("listMultiParagraphExtraSpace", + "[variable-2 * foo]", + "", + "[variable-2 * bar]", + "", + " [variable-2 hello]", + "", + " [variable-2 world]"); + + // 1 tab + MT("listTab", + "[variable-2 * foo]", + "", + "[variable-2 * bar]", + "", + "\t[variable-2 hello]"); + + // No indent + MT("listNoIndent", + "[variable-2 * foo]", + "", + "[variable-2 * bar]", + "", + "hello"); + + MT("listCommonMarkIndentationCode", + "[variable-2 * Code blocks also affect]", + " [variable-3 * The next level starts where the contents start.]", + " [variable-3 * Anything less than that will keep the item on the same level.]", + " [variable-3 * Each list item can indent the first level further and further.]", + " [variable-3 * For the most part, this makes sense while writing a list.]", + " [keyword * This means two items with same indentation can be different levels.]", + " [keyword * Each level has an indent requirement that can change between items.]", + " [keyword * A list item that meets this will be part of the next level.]", + " [variable-3 * Otherwise, it will be part of the level where it does meet this.]", + " [variable-2 * World]"); + + // should handle nested and un-nested lists + MT("listCommonMark_MixedIndents", + "[variable-2 * list1]", + " [variable-2 list1]", + " [variable-2&header&header-1 # heading still part of list1]", + " [variable-2 text after heading still part of list1]", + "", + " [comment indented codeblock]", + " [variable-2 list1 after code block]", + " [variable-3 * list2]", + // amount of spaces on empty lines between lists doesn't matter + " ", + // extra empty lines irrelevant + "", + "", + " [variable-3 indented text part of list2]", + " [keyword * list3]", + "", + " [variable-3 text at level of list2]", + "", + " [variable-2 de-indented text part of list1 again]", + "", + " [variable-2&comment ```]", + " [comment code]", + " [variable-2&comment ```]", + "", + " [variable-2 text after fenced code]"); + + // should correctly parse numbered list content indentation + MT("listCommonMark_NumberedListIndent", + "[variable-2 1000. list with base indent of 6]", + "", + " [variable-2 text must be indented 6 spaces at minimum]", + "", + " [variable-2 9-spaces indented text still part of list]", + "", + " [comment indented codeblock starts at 10 spaces]", + "", + " [comment text indented by 5 spaces no longer belong to list]"); + + // should consider tab as 4 spaces + MT("listCommonMark_TabIndented", + "[variable-2 * list]", + "\t[variable-3 * list2]", + "", + "\t\t[variable-3 part of list2]"); + + MT("listAfterBlockquote", + "[quote"e-1 > foo]", + "[variable-2 - bar]"); + + // shouldn't create sublist if it's indented more than allowed + MT("nestedListIndentedTooMuch", + "[variable-2 - foo]", + " [variable-2 - bar]"); + + MT("listIndentedTooMuchAfterParagraph", + "foo", + " - bar"); + + // Blockquote + MT("blockquote", + "[variable-2 * foo]", + "", + "[variable-2 * bar]", + "", + " [variable-2"e"e-1 > hello]"); + + // Code block + MT("blockquoteCode", + "[variable-2 * foo]", + "", + "[variable-2 * bar]", + "", + " [comment > hello]", + "", + " [variable-2 world]"); + + // Code block followed by text + MT("blockquoteCodeText", + "[variable-2 * foo]", + "", + " [variable-2 bar]", + "", + " [comment hello]", + "", + " [variable-2 world]"); + + // Nested list + + MT("listAsteriskNested", + "[variable-2 * foo]", + "", + " [variable-3 * bar]"); + + MT("listPlusNested", + "[variable-2 + foo]", + "", + " [variable-3 + bar]"); + + MT("listDashNested", + "[variable-2 - foo]", + "", + " [variable-3 - bar]"); + + MT("listNumberNested", + "[variable-2 1. foo]", + "", + " [variable-3 2. bar]"); + + MT("listMixed", + "[variable-2 * foo]", + "", + " [variable-3 + bar]", + "", + " [keyword - hello]", + "", + " [variable-2 1. world]"); + + MT("listBlockquote", + "[variable-2 * foo]", + "", + " [variable-3 + bar]", + "", + " [quote"e-1&variable-3 > hello]"); + + MT("listCode", + "[variable-2 * foo]", + "", + " [variable-3 + bar]", + "", + " [comment hello]"); + + // Code with internal indentation + MT("listCodeIndentation", + "[variable-2 * foo]", + "", + " [comment bar]", + " [comment hello]", + " [comment world]", + " [comment foo]", + " [variable-2 bar]"); + + // List nesting edge cases + MT("listNested", + "[variable-2 * foo]", + "", + " [variable-3 * bar]", + "", + " [variable-3 hello]" + ); + MT("listNested", + "[variable-2 * foo]", + "", + " [variable-3 * bar]", + "", + " [keyword * foo]" + ); + + // Code followed by text + MT("listCodeText", + "[variable-2 * foo]", + "", + " [comment bar]", + "", + "hello"); + + // Following tests directly from official Markdown documentation + // http://daringfireball.net/projects/markdown/syntax#hr + + MT("hrSpace", + "[hr * * *]"); + + MT("hr", + "[hr ***]"); + + MT("hrLong", + "[hr *****]"); + + MT("hrSpaceDash", + "[hr - - -]"); + + MT("hrDashLong", + "[hr ---------------------------------------]"); + + //Images + MT("Images", + "[image&image-marker !][image&image-alt-text&link [[alt text]]][string&url (http://link.to/image.jpg)]") + + //Images with highlight alt text + MT("imageEm", + "[image&image-marker !][image&image-alt-text&link [[][image-alt-text&em&image&link *alt text*][image&image-alt-text&link ]]][string&url (http://link.to/image.jpg)]"); + + MT("imageStrong", + "[image&image-marker !][image&image-alt-text&link [[][image-alt-text&strong&image&link **alt text**][image&image-alt-text&link ]]][string&url (http://link.to/image.jpg)]"); + + MT("imageEmStrong", + "[image&image-marker !][image&image-alt-text&link [[][image&image-alt-text&em&strong&link ***alt text***][image&image-alt-text&link ]]][string&url (http://link.to/image.jpg)]"); + + // Inline link with title + MT("linkTitle", + "[link [[foo]]][string&url (http://example.com/ \"bar\")] hello"); + + // Inline link without title + MT("linkNoTitle", + "[link [[foo]]][string&url (http://example.com/)] bar"); + + // Inline link with image + MT("linkImage", + "[link [[][link&image&image-marker !][link&image&image-alt-text&link [[alt text]]][string&url (http://link.to/image.jpg)][link ]]][string&url (http://example.com/)] bar"); + + // Inline link with Em + MT("linkEm", + "[link [[][link&em *foo*][link ]]][string&url (http://example.com/)] bar"); + + // Inline link with Strong + MT("linkStrong", + "[link [[][link&strong **foo**][link ]]][string&url (http://example.com/)] bar"); + + // Inline link with EmStrong + MT("linkEmStrong", + "[link [[][link&em&strong ***foo***][link ]]][string&url (http://example.com/)] bar"); + + MT("multilineLink", + "[link [[foo]", + "[link bar]]][string&url (https://foo#_a)]", + "should not be italics") + + // Image with title + MT("imageTitle", + "[image&image-marker !][image&image-alt-text&link [[alt text]]][string&url (http://example.com/ \"bar\")] hello"); + + // Image without title + MT("imageNoTitle", + "[image&image-marker !][image&image-alt-text&link [[alt text]]][string&url (http://example.com/)] bar"); + + // Image with asterisks + MT("imageAsterisks", + "[image&image-marker !][image&image-alt-text&link [[ ][image&image-alt-text&em&link *alt text*][image&image-alt-text&link ]]][string&url (http://link.to/image.jpg)] bar"); + + // Not a link. Should be normal text due to square brackets being used + // regularly in text, especially in quoted material, and no space is allowed + // between square brackets and parentheses (per Dingus). + MT("notALink", + "[link [[foo]]] (bar)"); + + // Reference-style links + MT("linkReference", + "[link [[foo]]][string&url [[bar]]] hello"); + + // Reference-style links with Em + MT("linkReferenceEm", + "[link [[][link&em *foo*][link ]]][string&url [[bar]]] hello"); + + // Reference-style links with Strong + MT("linkReferenceStrong", + "[link [[][link&strong **foo**][link ]]][string&url [[bar]]] hello"); + + // Reference-style links with EmStrong + MT("linkReferenceEmStrong", + "[link [[][link&em&strong ***foo***][link ]]][string&url [[bar]]] hello"); + + // Reference-style links with optional space separator (per documentation) + // "You can optionally use a space to separate the sets of brackets" + MT("linkReferenceSpace", + "[link [[foo]]] [string&url [[bar]]] hello"); + + // Should only allow a single space ("...use *a* space...") + MT("linkReferenceDoubleSpace", + "[link [[foo]]] [link [[bar]]] hello"); + + // Reference-style links with implicit link name + MT("linkImplicit", + "[link [[foo]]][string&url [[]]] hello"); + + // @todo It would be nice if, at some point, the document was actually + // checked to see if the referenced link exists + + // Link label, for reference-style links (taken from documentation) + + MT("labelNoTitle", + "[link [[foo]]:] [string&url http://example.com/]"); + + MT("labelIndented", + " [link [[foo]]:] [string&url http://example.com/]"); + + MT("labelSpaceTitle", + "[link [[foo bar]]:] [string&url http://example.com/ \"hello\"]"); + + MT("labelDoubleTitle", + "[link [[foo bar]]:] [string&url http://example.com/ \"hello\"] \"world\""); + + MT("labelTitleDoubleQuotes", + "[link [[foo]]:] [string&url http://example.com/ \"bar\"]"); + + MT("labelTitleSingleQuotes", + "[link [[foo]]:] [string&url http://example.com/ 'bar']"); + + MT("labelTitleParentheses", + "[link [[foo]]:] [string&url http://example.com/ (bar)]"); + + MT("labelTitleInvalid", + "[link [[foo]]:] [string&url http://example.com/] bar"); + + MT("labelLinkAngleBrackets", + "[link [[foo]]:] [string&url <http://example.com/> \"bar\"]"); + + MT("labelTitleNextDoubleQuotes", + "[link [[foo]]:] [string&url http://example.com/]", + "[string \"bar\"] hello"); + + MT("labelTitleNextSingleQuotes", + "[link [[foo]]:] [string&url http://example.com/]", + "[string 'bar'] hello"); + + MT("labelTitleNextParentheses", + "[link [[foo]]:] [string&url http://example.com/]", + "[string (bar)] hello"); + + MT("labelTitleNextMixed", + "[link [[foo]]:] [string&url http://example.com/]", + "(bar\" hello"); + + MT("labelEscape", + "[link [[foo \\]] ]]:] [string&url http://example.com/]"); + + MT("labelEscapeColon", + "[link [[foo \\]]: bar]]:] [string&url http://example.com/]"); + + MT("labelEscapeEnd", + "\\[[foo\\]]: http://example.com/"); + + MT("linkWeb", + "[link <http://example.com/>] foo"); + + MT("linkWebDouble", + "[link <http://example.com/>] foo [link <http://example.com/>]"); + + MT("linkEmail", + "[link <user@example.com>] foo"); + + MT("linkEmailDouble", + "[link <user@example.com>] foo [link <user@example.com>]"); + + MT("emAsterisk", + "[em *foo*] bar"); + + MT("emUnderscore", + "[em _foo_] bar"); + + MT("emInWordAsterisk", + "foo[em *bar*]hello"); + + MT("emInWordUnderscore", + "foo_bar_hello"); + + // Per documentation: "...surround an * or _ with spaces, it’ll be + // treated as a literal asterisk or underscore." + + MT("emEscapedBySpaceIn", + "foo [em _bar _ hello_] world"); + + MT("emEscapedBySpaceOut", + "foo _ bar [em _hello_] world"); + + MT("emEscapedByNewline", + "foo", + "_ bar [em _hello_] world"); + + // Unclosed emphasis characters + // Instead of simply marking as EM / STRONG, it would be nice to have an + // incomplete flag for EM and STRONG, that is styled slightly different. + MT("emIncompleteAsterisk", + "foo [em *bar]"); + + MT("emIncompleteUnderscore", + "foo [em _bar]"); + + MT("strongAsterisk", + "[strong **foo**] bar"); + + MT("strongUnderscore", + "[strong __foo__] bar"); + + MT("emStrongAsterisk", + "[em *foo][em&strong **bar*][strong hello**] world"); + + MT("emStrongUnderscore", + "[em _foo ][em&strong __bar_][strong hello__] world"); + + // "...same character must be used to open and close an emphasis span."" + MT("emStrongMixed", + "[em _foo][em&strong **bar*hello__ world]"); + + MT("emStrongMixed", + "[em *foo ][em&strong __bar_hello** world]"); + + MT("linkWithNestedParens", + "[link [[foo]]][string&url (bar(baz))]") + + // These characters should be escaped: + // \ backslash + // ` backtick + // * asterisk + // _ underscore + // {} curly braces + // [] square brackets + // () parentheses + // # hash mark + // + plus sign + // - minus sign (hyphen) + // . dot + // ! exclamation mark + + MT("escapeBacktick", + "foo \\`bar\\`"); + + MT("doubleEscapeBacktick", + "foo \\\\[comment `bar\\\\`]"); + + MT("escapeAsterisk", + "foo \\*bar\\*"); + + MT("doubleEscapeAsterisk", + "foo \\\\[em *bar\\\\*]"); + + MT("escapeUnderscore", + "foo \\_bar\\_"); + + MT("doubleEscapeUnderscore", + "foo \\\\[em _bar\\\\_]"); + + MT("escapeHash", + "\\# foo"); + + MT("doubleEscapeHash", + "\\\\# foo"); + + MT("escapeNewline", + "\\", + "[em *foo*]"); + + // Class override tests + TokenTypeOverrideTest("overrideHeader1", + "[override-header&override-header-1 # Foo]"); + + TokenTypeOverrideTest("overrideHeader2", + "[override-header&override-header-2 ## Foo]"); + + TokenTypeOverrideTest("overrideHeader3", + "[override-header&override-header-3 ### Foo]"); + + TokenTypeOverrideTest("overrideHeader4", + "[override-header&override-header-4 #### Foo]"); + + TokenTypeOverrideTest("overrideHeader5", + "[override-header&override-header-5 ##### Foo]"); + + TokenTypeOverrideTest("overrideHeader6", + "[override-header&override-header-6 ###### Foo]"); + + TokenTypeOverrideTest("overrideCode", + "[override-code `foo`]"); + + TokenTypeOverrideTest("overrideCodeBlock", + "[override-code ```]", + "[override-code foo]", + "[override-code ```]"); + + TokenTypeOverrideTest("overrideQuote", + "[override-quote&override-quote-1 > foo]", + "[override-quote&override-quote-1 > bar]"); + + TokenTypeOverrideTest("overrideQuoteNested", + "[override-quote&override-quote-1 > foo]", + "[override-quote&override-quote-1 >][override-quote&override-quote-2 > bar]", + "[override-quote&override-quote-1 >][override-quote&override-quote-2 >][override-quote&override-quote-3 > baz]"); + + TokenTypeOverrideTest("overrideLists", + "[override-list1 - foo]", + "", + " [override-list2 + bar]", + "", + " [override-list3 * baz]", + "", + " [override-list1 1. qux]", + "", + " [override-list2 - quux]"); + + TokenTypeOverrideTest("overrideHr", + "[override-hr * * *]"); + + TokenTypeOverrideTest("overrideImage", + "[override-image&override-image-marker !][override-image&override-image-alt-text&link [[alt text]]][override-link-href&url (http://link.to/image.jpg)]"); + + TokenTypeOverrideTest("overrideLinkText", + "[override-link-text [[foo]]][override-link-href&url (http://example.com)]"); + + TokenTypeOverrideTest("overrideLinkEmailAndInline", + "[override-link-email <][override-link-inline foo@example.com>]"); + + TokenTypeOverrideTest("overrideEm", + "[override-em *foo*]"); + + TokenTypeOverrideTest("overrideStrong", + "[override-strong **foo**]"); + + TokenTypeOverrideTest("overrideStrikethrough", + "[override-strikethrough ~~foo~~]"); + + TokenTypeOverrideTest("overrideEmoji", + "[override-emoji :foo:]"); + + FormatTokenTypeOverrideTest("overrideFormatting", + "[override-formatting-escape \\*]"); + + // Tests to make sure GFM-specific things aren't getting through + + MT("taskList", + "[variable-2 * ][link&variable-2 [[ ]]][variable-2 bar]"); + + MT("fencedCodeBlocks", + "[comment ```]", + "[comment foo]", + "", + "[comment bar]", + "[comment ```]", + "baz"); + + MT("fencedCodeBlocks_invalidClosingFence_trailingText", + "[comment ```]", + "[comment foo]", + "[comment ``` must not have trailing text]", + "[comment baz]"); + + MT("fencedCodeBlocks_invalidClosingFence_trailingTabs", + "[comment ```]", + "[comment foo]", + "[comment ```\t]", + "[comment baz]"); + + MT("fencedCodeBlocks_validClosingFence", + "[comment ```]", + "[comment foo]", + // may have trailing spaces + "[comment ``` ]", + "baz"); + + MT("fencedCodeBlocksInList_closingFenceIndented", + "[variable-2 - list]", + " [variable-2&comment ```]", + " [comment foo]", + " [variable-2&comment ```]", + " [variable-2 baz]"); + + MT("fencedCodeBlocksInList_closingFenceIndentedTooMuch", + "[variable-2 - list]", + " [variable-2&comment ```]", + " [comment foo]", + " [comment ```]", + " [comment baz]"); + + MT("fencedCodeBlockModeSwitching", + "[comment ```javascript]", + "[variable foo]", + "", + "[comment ```]", + "bar"); + + MT_noFencedHighlight("fencedCodeBlock_noHighlight", + "[comment ```javascript]", + "[comment foo]", + "[comment ```]"); + + MT("fencedCodeBlockModeSwitchingObjc", + "[comment ```objective-c]", + "[keyword @property] [variable NSString] [operator *] [variable foo];", + "[comment ```]", + "bar"); + + MT("fencedCodeBlocksMultipleChars", + "[comment `````]", + "[comment foo]", + "[comment ```]", + "[comment foo]", + "[comment `````]", + "bar"); + + MT("fencedCodeBlocksTildes", + "[comment ~~~]", + "[comment foo]", + "[comment ~~~]", + "bar"); + + MT("fencedCodeBlocksTildesMultipleChars", + "[comment ~~~~~]", + "[comment ~~~]", + "[comment foo]", + "[comment ~~~~~]", + "bar"); + + MT("fencedCodeBlocksMultipleChars", + "[comment `````]", + "[comment foo]", + "[comment ```]", + "[comment foo]", + "[comment `````]", + "bar"); + + MT("fencedCodeBlocksMixed", + "[comment ~~~]", + "[comment ```]", + "[comment foo]", + "[comment ~~~]", + "bar"); + + MT("fencedCodeBlocksAfterBlockquote", + "[quote"e-1 > foo]", + "[comment ```]", + "[comment bar]", + "[comment ```]"); + + // fencedCode indented too much should act as simple indentedCode + // (hence has no highlight formatting) + FT("tooMuchIndentedFencedCode", + " [comment ```]", + " [comment code]", + " [comment ```]"); + + MT("autoTerminateFencedCodeWhenLeavingList", + "[variable-2 - list1]", + " [variable-3 - list2]", + " [variable-3&comment ```]", + " [comment code]", + " [variable-3 - list2]", + " [variable-2&comment ```]", + " [comment code]", + "[quote"e-1 > foo]"); + + // Tests that require XML mode + + MT("xmlMode", + "[tag&bracket <][tag div][tag&bracket >]", + " *foo*", + " [tag&bracket <][tag http://github.com][tag&bracket />]", + "[tag&bracket </][tag div][tag&bracket >]", + "[link <http://github.com/>]"); + + MT("xmlModeWithMarkdownInside", + "[tag&bracket <][tag div] [attribute markdown]=[string 1][tag&bracket >]", + "[em *foo*]", + "[link <http://github.com/>]", + "[tag </div>]", + "[link <http://github.com/>]", + "[tag&bracket <][tag div][tag&bracket >]", + "[tag&bracket </][tag div][tag&bracket >]"); + + MT("xmlModeLineBreakInTags", + "[tag&bracket <][tag div] [attribute id]=[string \"1\"]", + " [attribute class]=[string \"sth\"][tag&bracket >]xxx", + "[tag&bracket </][tag div][tag&bracket >]"); + + MT("xmlModeCommentWithBlankLine", + "[comment <!-- Hello]", + "", + "[comment World -->]"); + + MT("xmlModeCDATA", + "[atom <![CDATA[ Hello]", + "", + "[atom FooBar]", + "[atom Test ]]]]>]"); + + MT("xmlModePreprocessor", + "[meta <?php] [meta echo '1234'; ?>]"); + + MT_noXml("xmlHighlightDisabled", + "<div>foo</div>"); + + // Tests Emojis + + ET("emojiDefault", + "[builtin :foobar:]"); + + ET("emojiTable", + " :--:"); +})();