You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1319 lines
38 KiB

7 months ago
  1. // CodeMirror, copyright (c) by Marijn Haverbeke and others
  2. // Distributed under an MIT license: https://codemirror.net/5/LICENSE
  3. (function() {
  4. var config = {tabSize: 4, indentUnit: 2}
  5. var mode = CodeMirror.getMode(config, "markdown");
  6. function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); }
  7. var modeHighlightFormatting = CodeMirror.getMode(config, {name: "markdown", highlightFormatting: true});
  8. function FT(name) { test.mode(name, modeHighlightFormatting, Array.prototype.slice.call(arguments, 1)); }
  9. var modeMT_noXml = CodeMirror.getMode(config, {name: "markdown", xml: false});
  10. function MT_noXml(name) { test.mode(name, modeMT_noXml, Array.prototype.slice.call(arguments, 1)); }
  11. var modeMT_noFencedHighlight = CodeMirror.getMode(config, {name: "markdown", fencedCodeBlockHighlighting: false});
  12. function MT_noFencedHighlight(name) { test.mode(name, modeMT_noFencedHighlight, Array.prototype.slice.call(arguments, 1)); }
  13. var modeAtxNoSpace = CodeMirror.getMode(config, {name: "markdown", allowAtxHeaderWithoutSpace: true});
  14. function AtxNoSpaceTest(name) { test.mode(name, modeAtxNoSpace, Array.prototype.slice.call(arguments, 1)); }
  15. var modeOverrideClasses = CodeMirror.getMode(config, {
  16. name: "markdown",
  17. strikethrough: true,
  18. emoji: true,
  19. tokenTypeOverrides: {
  20. "header" : "override-header",
  21. "code" : "override-code",
  22. "quote" : "override-quote",
  23. "list1" : "override-list1",
  24. "list2" : "override-list2",
  25. "list3" : "override-list3",
  26. "hr" : "override-hr",
  27. "image" : "override-image",
  28. "imageAltText": "override-image-alt-text",
  29. "imageMarker": "override-image-marker",
  30. "linkInline" : "override-link-inline",
  31. "linkEmail" : "override-link-email",
  32. "linkText" : "override-link-text",
  33. "linkHref" : "override-link-href",
  34. "em" : "override-em",
  35. "strong" : "override-strong",
  36. "strikethrough" : "override-strikethrough",
  37. "emoji" : "override-emoji"
  38. }});
  39. function TokenTypeOverrideTest(name) { test.mode(name, modeOverrideClasses, Array.prototype.slice.call(arguments, 1)); }
  40. var modeFormattingOverride = CodeMirror.getMode(config, {
  41. name: "markdown",
  42. highlightFormatting: true,
  43. tokenTypeOverrides: {
  44. "formatting" : "override-formatting"
  45. }});
  46. function FormatTokenTypeOverrideTest(name) { test.mode(name, modeFormattingOverride, Array.prototype.slice.call(arguments, 1)); }
  47. var modeET = CodeMirror.getMode(config, {name: "markdown", emoji: true});
  48. function ET(name) { test.mode(name, modeET, Array.prototype.slice.call(arguments, 1)); }
  49. FT("formatting_emAsterisk",
  50. "[em&formatting&formatting-em *][em foo][em&formatting&formatting-em *]");
  51. FT("formatting_emUnderscore",
  52. "[em&formatting&formatting-em _][em foo][em&formatting&formatting-em _]");
  53. FT("formatting_strongAsterisk",
  54. "[strong&formatting&formatting-strong **][strong foo][strong&formatting&formatting-strong **]");
  55. FT("formatting_strongUnderscore",
  56. "[strong&formatting&formatting-strong __][strong foo][strong&formatting&formatting-strong __]");
  57. FT("formatting_codeBackticks",
  58. "[comment&formatting&formatting-code `][comment foo][comment&formatting&formatting-code `]");
  59. FT("formatting_doubleBackticks",
  60. "[comment&formatting&formatting-code ``][comment foo ` bar][comment&formatting&formatting-code ``]");
  61. FT("formatting_atxHeader",
  62. "[header&header-1&formatting&formatting-header&formatting-header-1 # ][header&header-1 foo # bar ][header&header-1&formatting&formatting-header&formatting-header-1 #]");
  63. FT("formatting_setextHeader",
  64. "[header&header-1 foo]",
  65. "[header&header-1&formatting&formatting-header&formatting-header-1 =]");
  66. FT("formatting_blockquote",
  67. "[quote&quote-1&formatting&formatting-quote&formatting-quote-1 > ][quote&quote-1 foo]");
  68. FT("formatting_list",
  69. "[variable-2&formatting&formatting-list&formatting-list-ul - ][variable-2 foo]");
  70. FT("formatting_list",
  71. "[variable-2&formatting&formatting-list&formatting-list-ol 1. ][variable-2 foo]");
  72. FT("formatting_link",
  73. "[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 )]");
  74. FT("formatting_linkReference",
  75. "[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 ]]]",
  76. "[link&formatting&formatting-link [][link bar][link&formatting&formatting-link ]]:] [string&url http://example.com/]");
  77. FT("formatting_linkWeb",
  78. "[link&formatting&formatting-link <][link http://example.com/][link&formatting&formatting-link >]");
  79. FT("formatting_linkEmail",
  80. "[link&formatting&formatting-link <][link user@example.com][link&formatting&formatting-link >]");
  81. FT("formatting_escape",
  82. "[formatting-escape \\*]");
  83. FT("formatting_image",
  84. "[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 )]");
  85. FT("codeBlock",
  86. "[comment&formatting&formatting-code-block ```css]",
  87. "[tag foo]",
  88. "[comment&formatting&formatting-code-block ```]");
  89. MT("plainText",
  90. "foo");
  91. // Don't style single trailing space
  92. MT("trailingSpace1",
  93. "foo ");
  94. // Two or more trailing spaces should be styled with line break character
  95. MT("trailingSpace2",
  96. "foo[trailing-space-a ][trailing-space-new-line ]");
  97. MT("trailingSpace3",
  98. "foo[trailing-space-a ][trailing-space-b ][trailing-space-new-line ]");
  99. MT("trailingSpace4",
  100. "foo[trailing-space-a ][trailing-space-b ][trailing-space-a ][trailing-space-new-line ]");
  101. // Code blocks using 4 spaces (regardless of CodeMirror.tabSize value)
  102. MT("codeBlocksUsing4Spaces",
  103. " [comment foo]");
  104. // Code blocks using 4 spaces with internal indentation
  105. MT("codeBlocksUsing4SpacesIndentation",
  106. " [comment bar]",
  107. " [comment hello]",
  108. " [comment world]",
  109. " [comment foo]",
  110. "bar");
  111. // Code blocks should end even after extra indented lines
  112. MT("codeBlocksWithTrailingIndentedLine",
  113. " [comment foo]",
  114. " [comment bar]",
  115. " [comment baz]",
  116. " ",
  117. "hello");
  118. // Code blocks using 1 tab (regardless of CodeMirror.indentWithTabs value)
  119. MT("codeBlocksUsing1Tab",
  120. "\t[comment foo]");
  121. // No code blocks directly after paragraph
  122. // http://spec.commonmark.org/0.19/#example-65
  123. MT("noCodeBlocksAfterParagraph",
  124. "Foo",
  125. " Bar");
  126. MT("codeBlocksAfterATX",
  127. "[header&header-1 # foo]",
  128. " [comment code]");
  129. MT("codeBlocksAfterSetext",
  130. "[header&header-2 foo]",
  131. "[header&header-2 ---]",
  132. " [comment code]");
  133. MT("codeBlocksAfterFencedCode",
  134. "[comment ```]",
  135. "[comment foo]",
  136. "[comment ```]",
  137. " [comment code]");
  138. // Inline code using backticks
  139. MT("inlineCodeUsingBackticks",
  140. "foo [comment `bar`]");
  141. // Block code using single backtick (shouldn't work)
  142. MT("blockCodeSingleBacktick",
  143. "[comment `]",
  144. "[comment foo]",
  145. "[comment `]");
  146. // Unclosed backticks
  147. // Instead of simply marking as CODE, it would be nice to have an
  148. // incomplete flag for CODE, that is styled slightly different.
  149. MT("unclosedBackticks",
  150. "foo [comment `bar]");
  151. // Per documentation: "To include a literal backtick character within a
  152. // code span, you can use multiple backticks as the opening and closing
  153. // delimiters"
  154. MT("doubleBackticks",
  155. "[comment ``foo ` bar``]");
  156. // Tests based on Dingus
  157. // http://daringfireball.net/projects/markdown/dingus
  158. //
  159. // Multiple backticks within an inline code block
  160. MT("consecutiveBackticks",
  161. "[comment `foo```bar`]");
  162. // Multiple backticks within an inline code block with a second code block
  163. MT("consecutiveBackticks",
  164. "[comment `foo```bar`] hello [comment `world`]");
  165. // Unclosed with several different groups of backticks
  166. MT("unclosedBackticks",
  167. "[comment ``foo ``` bar` hello]");
  168. // Closed with several different groups of backticks
  169. MT("closedBackticks",
  170. "[comment ``foo ``` bar` hello``] world");
  171. // info string cannot contain backtick, thus should result in inline code
  172. MT("closingFencedMarksOnSameLine",
  173. "[comment ``` code ```] foo");
  174. // atx headers
  175. // http://daringfireball.net/projects/markdown/syntax#header
  176. MT("atxH1",
  177. "[header&header-1 # foo]");
  178. MT("atxH2",
  179. "[header&header-2 ## foo]");
  180. MT("atxH3",
  181. "[header&header-3 ### foo]");
  182. MT("atxH4",
  183. "[header&header-4 #### foo]");
  184. MT("atxH5",
  185. "[header&header-5 ##### foo]");
  186. MT("atxH6",
  187. "[header&header-6 ###### foo]");
  188. // http://spec.commonmark.org/0.19/#example-24
  189. MT("noAtxH7",
  190. "####### foo");
  191. // http://spec.commonmark.org/0.19/#example-25
  192. MT("noAtxH1WithoutSpace",
  193. "#5 bolt");
  194. // CommonMark requires a space after # but most parsers don't
  195. AtxNoSpaceTest("atxNoSpaceAllowed_H1NoSpace",
  196. "[header&header-1 #foo]");
  197. AtxNoSpaceTest("atxNoSpaceAllowed_H4NoSpace",
  198. "[header&header-4 ####foo]");
  199. AtxNoSpaceTest("atxNoSpaceAllowed_H1Space",
  200. "[header&header-1 # foo]");
  201. // Inline styles should be parsed inside headers
  202. MT("atxH1inline",
  203. "[header&header-1 # foo ][header&header-1&em *bar*]");
  204. MT("atxIndentedTooMuch",
  205. "[header&header-1 # foo]",
  206. " [comment # bar]");
  207. // disable atx inside blockquote until we implement proper blockquote inner mode
  208. // TODO: fix to be CommonMark-compliant
  209. MT("atxNestedInsideBlockquote",
  210. "[quote&quote-1 > # foo]");
  211. MT("atxAfterBlockquote",
  212. "[quote&quote-1 > foo]",
  213. "[header&header-1 # bar]");
  214. // Setext headers - H1, H2
  215. // Per documentation, "Any number of underlining =’s or -’s will work."
  216. // http://daringfireball.net/projects/markdown/syntax#header
  217. // Ideally, the text would be marked as `header` as well, but this is
  218. // not really feasible at the moment. So, instead, we're testing against
  219. // what works today, to avoid any regressions.
  220. //
  221. // Check if single underlining = works
  222. MT("setextH1",
  223. "[header&header-1 foo]",
  224. "[header&header-1 =]");
  225. // Check if 3+ ='s work
  226. MT("setextH1",
  227. "[header&header-1 foo]",
  228. "[header&header-1 ===]");
  229. // Check if single underlining - should not be interpreted
  230. // as it might lead to an empty list:
  231. // https://spec.commonmark.org/0.28/#setext-heading-underline
  232. MT("setextH2Single",
  233. "foo",
  234. "-");
  235. // Check if 3+ -'s work
  236. MT("setextH2",
  237. "[header&header-2 foo]",
  238. "[header&header-2 ---]");
  239. // http://spec.commonmark.org/0.19/#example-45
  240. MT("setextH2AllowSpaces",
  241. "[header&header-2 foo]",
  242. " [header&header-2 ---- ]");
  243. // http://spec.commonmark.org/0.19/#example-44
  244. MT("noSetextAfterIndentedCodeBlock",
  245. " [comment foo]",
  246. "[hr ---]");
  247. MT("setextAfterFencedCode",
  248. "[comment ```]",
  249. "[comment foo]",
  250. "[comment ```]",
  251. "[header&header-2 bar]",
  252. "[header&header-2 ---]");
  253. MT("setextAfterATX",
  254. "[header&header-1 # foo]",
  255. "[header&header-2 bar]",
  256. "[header&header-2 ---]");
  257. // http://spec.commonmark.org/0.19/#example-51
  258. MT("noSetextAfterQuote",
  259. "[quote&quote-1 > foo]",
  260. "[hr ---]",
  261. "",
  262. "[quote&quote-1 > foo]",
  263. "[quote&quote-1 bar]",
  264. "[hr ---]");
  265. MT("noSetextAfterList",
  266. "[variable-2 - foo]",
  267. "[hr ---]");
  268. MT("noSetextAfterList_listContinuation",
  269. "[variable-2 - foo]",
  270. "bar",
  271. "[hr ---]");
  272. MT("setextAfterList_afterIndentedCode",
  273. "[variable-2 - foo]",
  274. "",
  275. " [comment bar]",
  276. "[header&header-2 baz]",
  277. "[header&header-2 ---]");
  278. MT("setextAfterList_afterFencedCodeBlocks",
  279. "[variable-2 - foo]",
  280. "",
  281. " [comment ```]",
  282. " [comment bar]",
  283. " [comment ```]",
  284. "[header&header-2 baz]",
  285. "[header&header-2 ---]");
  286. MT("setextAfterList_afterHeader",
  287. "[variable-2 - foo]",
  288. " [variable-2&header&header-1 # bar]",
  289. "[header&header-2 baz]",
  290. "[header&header-2 ---]");
  291. MT("setextAfterList_afterHr",
  292. "[variable-2 - foo]",
  293. "",
  294. " [hr ---]",
  295. "[header&header-2 bar]",
  296. "[header&header-2 ---]");
  297. MT("setext_nestedInlineMarkup",
  298. "[header&header-1 foo ][em&header&header-1 *bar*]",
  299. "[header&header-1 =]");
  300. MT("setext_linkDef",
  301. "[link [[aaa]]:] [string&url http://google.com 'title']",
  302. "[hr ---]");
  303. // currently, looks max one line ahead, thus won't catch valid CommonMark
  304. // markup
  305. MT("setext_oneLineLookahead",
  306. "foo",
  307. "[header&header-1 bar]",
  308. "[header&header-1 =]");
  309. // ensure we regard space after a single dash as a list
  310. MT("setext_emptyList",
  311. "foo",
  312. "[variable-2 - ]",
  313. "foo");
  314. // Single-line blockquote with trailing space
  315. MT("blockquoteSpace",
  316. "[quote&quote-1 > foo]");
  317. // Single-line blockquote
  318. MT("blockquoteNoSpace",
  319. "[quote&quote-1 >foo]");
  320. // No blank line before blockquote
  321. MT("blockquoteNoBlankLine",
  322. "foo",
  323. "[quote&quote-1 > bar]");
  324. MT("blockquoteNested",
  325. "[quote&quote-1 > foo]",
  326. "[quote&quote-1 >][quote&quote-2 > foo]",
  327. "[quote&quote-1 >][quote&quote-2 >][quote&quote-3 > foo]");
  328. // ensure quote-level is inferred correctly even if indented
  329. MT("blockquoteNestedIndented",
  330. " [quote&quote-1 > foo]",
  331. " [quote&quote-1 >][quote&quote-2 > foo]",
  332. " [quote&quote-1 >][quote&quote-2 >][quote&quote-3 > foo]");
  333. // ensure quote-level is inferred correctly even if indented
  334. MT("blockquoteIndentedTooMuch",
  335. "foo",
  336. " > bar");
  337. // Single-line blockquote followed by normal paragraph
  338. MT("blockquoteThenParagraph",
  339. "[quote&quote-1 >foo]",
  340. "",
  341. "bar");
  342. // Multi-line blockquote (lazy mode)
  343. MT("multiBlockquoteLazy",
  344. "[quote&quote-1 >foo]",
  345. "[quote&quote-1 bar]");
  346. // Multi-line blockquote followed by normal paragraph (lazy mode)
  347. MT("multiBlockquoteLazyThenParagraph",
  348. "[quote&quote-1 >foo]",
  349. "[quote&quote-1 bar]",
  350. "",
  351. "hello");
  352. // Multi-line blockquote (non-lazy mode)
  353. MT("multiBlockquote",
  354. "[quote&quote-1 >foo]",
  355. "[quote&quote-1 >bar]");
  356. // Multi-line blockquote followed by normal paragraph (non-lazy mode)
  357. MT("multiBlockquoteThenParagraph",
  358. "[quote&quote-1 >foo]",
  359. "[quote&quote-1 >bar]",
  360. "",
  361. "hello");
  362. // disallow lists inside blockquote for now because it causes problems outside blockquote
  363. // TODO: fix to be CommonMark-compliant
  364. MT("listNestedInBlockquote",
  365. "[quote&quote-1 > - foo]");
  366. // disallow fenced blocks inside blockquote because it causes problems outside blockquote
  367. // TODO: fix to be CommonMark-compliant
  368. MT("fencedBlockNestedInBlockquote",
  369. "[quote&quote-1 > ```]",
  370. "[quote&quote-1 > code]",
  371. "[quote&quote-1 > ```]",
  372. // ensure we still allow inline code
  373. "[quote&quote-1 > ][quote&quote-1&comment `code`]");
  374. // Header with leading space after continued blockquote (#3287, negative indentation)
  375. MT("headerAfterContinuedBlockquote",
  376. "[quote&quote-1 > foo]",
  377. "[quote&quote-1 bar]",
  378. "",
  379. " [header&header-1 # hello]");
  380. // Check list types
  381. MT("listAsterisk",
  382. "foo",
  383. "bar",
  384. "",
  385. "[variable-2 * foo]",
  386. "[variable-2 * bar]");
  387. MT("listPlus",
  388. "foo",
  389. "bar",
  390. "",
  391. "[variable-2 + foo]",
  392. "[variable-2 + bar]");
  393. MT("listDash",
  394. "foo",
  395. "bar",
  396. "",
  397. "[variable-2 - foo]",
  398. "[variable-2 - bar]");
  399. MT("listNumber",
  400. "foo",
  401. "bar",
  402. "",
  403. "[variable-2 1. foo]",
  404. "[variable-2 2. bar]");
  405. MT("listFromParagraph",
  406. "foo",
  407. "[variable-2 1. bar]",
  408. "[variable-2 2. hello]");
  409. // List after hr
  410. MT("listAfterHr",
  411. "[hr ---]",
  412. "[variable-2 - bar]");
  413. // List after header
  414. MT("listAfterHeader",
  415. "[header&header-1 # foo]",
  416. "[variable-2 - bar]");
  417. // hr after list
  418. MT("hrAfterList",
  419. "[variable-2 - foo]",
  420. "[hr -----]");
  421. MT("hrAfterFencedCode",
  422. "[comment ```]",
  423. "[comment code]",
  424. "[comment ```]",
  425. "[hr ---]");
  426. // allow hr inside lists
  427. // (require prev line to be empty or hr, TODO: non-CommonMark-compliant)
  428. MT("hrInsideList",
  429. "[variable-2 - foo]",
  430. "",
  431. " [hr ---]",
  432. " [hr ---]",
  433. "",
  434. " [comment ---]");
  435. MT("consecutiveHr",
  436. "[hr ---]",
  437. "[hr ---]",
  438. "[hr ---]");
  439. // Formatting in lists (*)
  440. MT("listAsteriskFormatting",
  441. "[variable-2 * ][variable-2&em *foo*][variable-2 bar]",
  442. "[variable-2 * ][variable-2&strong **foo**][variable-2 bar]",
  443. "[variable-2 * ][variable-2&em&strong ***foo***][variable-2 bar]",
  444. "[variable-2 * ][variable-2&comment `foo`][variable-2 bar]");
  445. // Formatting in lists (+)
  446. MT("listPlusFormatting",
  447. "[variable-2 + ][variable-2&em *foo*][variable-2 bar]",
  448. "[variable-2 + ][variable-2&strong **foo**][variable-2 bar]",
  449. "[variable-2 + ][variable-2&em&strong ***foo***][variable-2 bar]",
  450. "[variable-2 + ][variable-2&comment `foo`][variable-2 bar]");
  451. // Formatting in lists (-)
  452. MT("listDashFormatting",
  453. "[variable-2 - ][variable-2&em *foo*][variable-2 bar]",
  454. "[variable-2 - ][variable-2&strong **foo**][variable-2 bar]",
  455. "[variable-2 - ][variable-2&em&strong ***foo***][variable-2 bar]",
  456. "[variable-2 - ][variable-2&comment `foo`][variable-2 bar]");
  457. // Formatting in lists (1.)
  458. MT("listNumberFormatting",
  459. "[variable-2 1. ][variable-2&em *foo*][variable-2 bar]",
  460. "[variable-2 2. ][variable-2&strong **foo**][variable-2 bar]",
  461. "[variable-2 3. ][variable-2&em&strong ***foo***][variable-2 bar]",
  462. "[variable-2 4. ][variable-2&comment `foo`][variable-2 bar]");
  463. // Paragraph lists
  464. MT("listParagraph",
  465. "[variable-2 * foo]",
  466. "",
  467. "[variable-2 * bar]");
  468. // Multi-paragraph lists
  469. //
  470. // 4 spaces
  471. MT("listMultiParagraph",
  472. "[variable-2 * foo]",
  473. "",
  474. "[variable-2 * bar]",
  475. "",
  476. " [variable-2 hello]");
  477. // 4 spaces, extra blank lines (should still be list, per Dingus)
  478. MT("listMultiParagraphExtra",
  479. "[variable-2 * foo]",
  480. "",
  481. "[variable-2 * bar]",
  482. "",
  483. "",
  484. " [variable-2 hello]");
  485. // 4 spaces, plus 1 space (should still be list, per Dingus)
  486. MT("listMultiParagraphExtraSpace",
  487. "[variable-2 * foo]",
  488. "",
  489. "[variable-2 * bar]",
  490. "",
  491. " [variable-2 hello]",
  492. "",
  493. " [variable-2 world]");
  494. // 1 tab
  495. MT("listTab",
  496. "[variable-2 * foo]",
  497. "",
  498. "[variable-2 * bar]",
  499. "",
  500. "\t[variable-2 hello]");
  501. // No indent
  502. MT("listNoIndent",
  503. "[variable-2 * foo]",
  504. "",
  505. "[variable-2 * bar]",
  506. "",
  507. "hello");
  508. MT("listCommonMarkIndentationCode",
  509. "[variable-2 * Code blocks also affect]",
  510. " [variable-3 * The next level starts where the contents start.]",
  511. " [variable-3 * Anything less than that will keep the item on the same level.]",
  512. " [variable-3 * Each list item can indent the first level further and further.]",
  513. " [variable-3 * For the most part, this makes sense while writing a list.]",
  514. " [keyword * This means two items with same indentation can be different levels.]",
  515. " [keyword * Each level has an indent requirement that can change between items.]",
  516. " [keyword * A list item that meets this will be part of the next level.]",
  517. " [variable-3 * Otherwise, it will be part of the level where it does meet this.]",
  518. " [variable-2 * World]");
  519. // should handle nested and un-nested lists
  520. MT("listCommonMark_MixedIndents",
  521. "[variable-2 * list1]",
  522. " [variable-2 list1]",
  523. " [variable-2&header&header-1 # heading still part of list1]",
  524. " [variable-2 text after heading still part of list1]",
  525. "",
  526. " [comment indented codeblock]",
  527. " [variable-2 list1 after code block]",
  528. " [variable-3 * list2]",
  529. // amount of spaces on empty lines between lists doesn't matter
  530. " ",
  531. // extra empty lines irrelevant
  532. "",
  533. "",
  534. " [variable-3 indented text part of list2]",
  535. " [keyword * list3]",
  536. "",
  537. " [variable-3 text at level of list2]",
  538. "",
  539. " [variable-2 de-indented text part of list1 again]",
  540. "",
  541. " [variable-2&comment ```]",
  542. " [comment code]",
  543. " [variable-2&comment ```]",
  544. "",
  545. " [variable-2 text after fenced code]");
  546. // should correctly parse numbered list content indentation
  547. MT("listCommonMark_NumberedListIndent",
  548. "[variable-2 1000. list with base indent of 6]",
  549. "",
  550. " [variable-2 text must be indented 6 spaces at minimum]",
  551. "",
  552. " [variable-2 9-spaces indented text still part of list]",
  553. "",
  554. " [comment indented codeblock starts at 10 spaces]",
  555. "",
  556. " [comment text indented by 5 spaces no longer belong to list]");
  557. // should consider tab as 4 spaces
  558. MT("listCommonMark_TabIndented",
  559. "[variable-2 * list]",
  560. "\t[variable-3 * list2]",
  561. "",
  562. "\t\t[variable-3 part of list2]");
  563. MT("listAfterBlockquote",
  564. "[quote&quote-1 > foo]",
  565. "[variable-2 - bar]");
  566. // shouldn't create sublist if it's indented more than allowed
  567. MT("nestedListIndentedTooMuch",
  568. "[variable-2 - foo]",
  569. " [variable-2 - bar]");
  570. MT("listIndentedTooMuchAfterParagraph",
  571. "foo",
  572. " - bar");
  573. // Blockquote
  574. MT("blockquote",
  575. "[variable-2 * foo]",
  576. "",
  577. "[variable-2 * bar]",
  578. "",
  579. " [variable-2&quote&quote-1 > hello]");
  580. // Code block
  581. MT("blockquoteCode",
  582. "[variable-2 * foo]",
  583. "",
  584. "[variable-2 * bar]",
  585. "",
  586. " [comment > hello]",
  587. "",
  588. " [variable-2 world]");
  589. // Code block followed by text
  590. MT("blockquoteCodeText",
  591. "[variable-2 * foo]",
  592. "",
  593. " [variable-2 bar]",
  594. "",
  595. " [comment hello]",
  596. "",
  597. " [variable-2 world]");
  598. // Nested list
  599. MT("listAsteriskNested",
  600. "[variable-2 * foo]",
  601. "",
  602. " [variable-3 * bar]");
  603. MT("listPlusNested",
  604. "[variable-2 + foo]",
  605. "",
  606. " [variable-3 + bar]");
  607. MT("listDashNested",
  608. "[variable-2 - foo]",
  609. "",
  610. " [variable-3 - bar]");
  611. MT("listNumberNested",
  612. "[variable-2 1. foo]",
  613. "",
  614. " [variable-3 2. bar]");
  615. MT("listMixed",
  616. "[variable-2 * foo]",
  617. "",
  618. " [variable-3 + bar]",
  619. "",
  620. " [keyword - hello]",
  621. "",
  622. " [variable-2 1. world]");
  623. MT("listBlockquote",
  624. "[variable-2 * foo]",
  625. "",
  626. " [variable-3 + bar]",
  627. "",
  628. " [quote&quote-1&variable-3 > hello]");
  629. MT("listCode",
  630. "[variable-2 * foo]",
  631. "",
  632. " [variable-3 + bar]",
  633. "",
  634. " [comment hello]");
  635. // Code with internal indentation
  636. MT("listCodeIndentation",
  637. "[variable-2 * foo]",
  638. "",
  639. " [comment bar]",
  640. " [comment hello]",
  641. " [comment world]",
  642. " [comment foo]",
  643. " [variable-2 bar]");
  644. // List nesting edge cases
  645. MT("listNested",
  646. "[variable-2 * foo]",
  647. "",
  648. " [variable-3 * bar]",
  649. "",
  650. " [variable-3 hello]"
  651. );
  652. MT("listNested",
  653. "[variable-2 * foo]",
  654. "",
  655. " [variable-3 * bar]",
  656. "",
  657. " [keyword * foo]"
  658. );
  659. // Code followed by text
  660. MT("listCodeText",
  661. "[variable-2 * foo]",
  662. "",
  663. " [comment bar]",
  664. "",
  665. "hello");
  666. // Following tests directly from official Markdown documentation
  667. // http://daringfireball.net/projects/markdown/syntax#hr
  668. MT("hrSpace",
  669. "[hr * * *]");
  670. MT("hr",
  671. "[hr ***]");
  672. MT("hrLong",
  673. "[hr *****]");
  674. MT("hrSpaceDash",
  675. "[hr - - -]");
  676. MT("hrDashLong",
  677. "[hr ---------------------------------------]");
  678. //Images
  679. MT("Images",
  680. "[image&image-marker !][image&image-alt-text&link [[alt text]]][string&url (http://link.to/image.jpg)]")
  681. //Images with highlight alt text
  682. MT("imageEm",
  683. "[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)]");
  684. MT("imageStrong",
  685. "[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)]");
  686. MT("imageEmStrong",
  687. "[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)]");
  688. // Inline link with title
  689. MT("linkTitle",
  690. "[link [[foo]]][string&url (http://example.com/ \"bar\")] hello");
  691. // Inline link without title
  692. MT("linkNoTitle",
  693. "[link [[foo]]][string&url (http://example.com/)] bar");
  694. // Inline link with image
  695. MT("linkImage",
  696. "[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");
  697. // Inline link with Em
  698. MT("linkEm",
  699. "[link [[][link&em *foo*][link ]]][string&url (http://example.com/)] bar");
  700. // Inline link with Strong
  701. MT("linkStrong",
  702. "[link [[][link&strong **foo**][link ]]][string&url (http://example.com/)] bar");
  703. // Inline link with EmStrong
  704. MT("linkEmStrong",
  705. "[link [[][link&em&strong ***foo***][link ]]][string&url (http://example.com/)] bar");
  706. MT("multilineLink",
  707. "[link [[foo]",
  708. "[link bar]]][string&url (https://foo#_a)]",
  709. "should not be italics")
  710. // Image with title
  711. MT("imageTitle",
  712. "[image&image-marker !][image&image-alt-text&link [[alt text]]][string&url (http://example.com/ \"bar\")] hello");
  713. // Image without title
  714. MT("imageNoTitle",
  715. "[image&image-marker !][image&image-alt-text&link [[alt text]]][string&url (http://example.com/)] bar");
  716. // Image with asterisks
  717. MT("imageAsterisks",
  718. "[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");
  719. // Not a link. Should be normal text due to square brackets being used
  720. // regularly in text, especially in quoted material, and no space is allowed
  721. // between square brackets and parentheses (per Dingus).
  722. MT("notALink",
  723. "[link [[foo]]] (bar)");
  724. // Reference-style links
  725. MT("linkReference",
  726. "[link [[foo]]][string&url [[bar]]] hello");
  727. // Reference-style links with Em
  728. MT("linkReferenceEm",
  729. "[link [[][link&em *foo*][link ]]][string&url [[bar]]] hello");
  730. // Reference-style links with Strong
  731. MT("linkReferenceStrong",
  732. "[link [[][link&strong **foo**][link ]]][string&url [[bar]]] hello");
  733. // Reference-style links with EmStrong
  734. MT("linkReferenceEmStrong",
  735. "[link [[][link&em&strong ***foo***][link ]]][string&url [[bar]]] hello");
  736. // Reference-style links with optional space separator (per documentation)
  737. // "You can optionally use a space to separate the sets of brackets"
  738. MT("linkReferenceSpace",
  739. "[link [[foo]]] [string&url [[bar]]] hello");
  740. // Should only allow a single space ("...use *a* space...")
  741. MT("linkReferenceDoubleSpace",
  742. "[link [[foo]]] [link [[bar]]] hello");
  743. // Reference-style links with implicit link name
  744. MT("linkImplicit",
  745. "[link [[foo]]][string&url [[]]] hello");
  746. // @todo It would be nice if, at some point, the document was actually
  747. // checked to see if the referenced link exists
  748. // Link label, for reference-style links (taken from documentation)
  749. MT("labelNoTitle",
  750. "[link [[foo]]:] [string&url http://example.com/]");
  751. MT("labelIndented",
  752. " [link [[foo]]:] [string&url http://example.com/]");
  753. MT("labelSpaceTitle",
  754. "[link [[foo bar]]:] [string&url http://example.com/ \"hello\"]");
  755. MT("labelDoubleTitle",
  756. "[link [[foo bar]]:] [string&url http://example.com/ \"hello\"] \"world\"");
  757. MT("labelTitleDoubleQuotes",
  758. "[link [[foo]]:] [string&url http://example.com/ \"bar\"]");
  759. MT("labelTitleSingleQuotes",
  760. "[link [[foo]]:] [string&url http://example.com/ 'bar']");
  761. MT("labelTitleParentheses",
  762. "[link [[foo]]:] [string&url http://example.com/ (bar)]");
  763. MT("labelTitleInvalid",
  764. "[link [[foo]]:] [string&url http://example.com/] bar");
  765. MT("labelLinkAngleBrackets",
  766. "[link [[foo]]:] [string&url <http://example.com/> \"bar\"]");
  767. MT("labelTitleNextDoubleQuotes",
  768. "[link [[foo]]:] [string&url http://example.com/]",
  769. "[string \"bar\"] hello");
  770. MT("labelTitleNextSingleQuotes",
  771. "[link [[foo]]:] [string&url http://example.com/]",
  772. "[string 'bar'] hello");
  773. MT("labelTitleNextParentheses",
  774. "[link [[foo]]:] [string&url http://example.com/]",
  775. "[string (bar)] hello");
  776. MT("labelTitleNextMixed",
  777. "[link [[foo]]:] [string&url http://example.com/]",
  778. "(bar\" hello");
  779. MT("labelEscape",
  780. "[link [[foo \\]] ]]:] [string&url http://example.com/]");
  781. MT("labelEscapeColon",
  782. "[link [[foo \\]]: bar]]:] [string&url http://example.com/]");
  783. MT("labelEscapeEnd",
  784. "\\[[foo\\]]: http://example.com/");
  785. MT("linkWeb",
  786. "[link <http://example.com/>] foo");
  787. MT("linkWebDouble",
  788. "[link <http://example.com/>] foo [link <http://example.com/>]");
  789. MT("linkEmail",
  790. "[link <user@example.com>] foo");
  791. MT("linkEmailDouble",
  792. "[link <user@example.com>] foo [link <user@example.com>]");
  793. MT("emAsterisk",
  794. "[em *foo*] bar");
  795. MT("emUnderscore",
  796. "[em _foo_] bar");
  797. MT("emInWordAsterisk",
  798. "foo[em *bar*]hello");
  799. MT("emInWordUnderscore",
  800. "foo_bar_hello");
  801. // Per documentation: "...surround an * or _ with spaces, it’ll be
  802. // treated as a literal asterisk or underscore."
  803. MT("emEscapedBySpaceIn",
  804. "foo [em _bar _ hello_] world");
  805. MT("emEscapedBySpaceOut",
  806. "foo _ bar [em _hello_] world");
  807. MT("emEscapedByNewline",
  808. "foo",
  809. "_ bar [em _hello_] world");
  810. // Unclosed emphasis characters
  811. // Instead of simply marking as EM / STRONG, it would be nice to have an
  812. // incomplete flag for EM and STRONG, that is styled slightly different.
  813. MT("emIncompleteAsterisk",
  814. "foo [em *bar]");
  815. MT("emIncompleteUnderscore",
  816. "foo [em _bar]");
  817. MT("strongAsterisk",
  818. "[strong **foo**] bar");
  819. MT("strongUnderscore",
  820. "[strong __foo__] bar");
  821. MT("emStrongAsterisk",
  822. "[em *foo][em&strong **bar*][strong hello**] world");
  823. MT("emStrongUnderscore",
  824. "[em _foo ][em&strong __bar_][strong hello__] world");
  825. // "...same character must be used to open and close an emphasis span.""
  826. MT("emStrongMixed",
  827. "[em _foo][em&strong **bar*hello__ world]");
  828. MT("emStrongMixed",
  829. "[em *foo ][em&strong __bar_hello** world]");
  830. MT("linkWithNestedParens",
  831. "[link [[foo]]][string&url (bar(baz))]")
  832. // These characters should be escaped:
  833. // \ backslash
  834. // ` backtick
  835. // * asterisk
  836. // _ underscore
  837. // {} curly braces
  838. // [] square brackets
  839. // () parentheses
  840. // # hash mark
  841. // + plus sign
  842. // - minus sign (hyphen)
  843. // . dot
  844. // ! exclamation mark
  845. MT("escapeBacktick",
  846. "foo \\`bar\\`");
  847. MT("doubleEscapeBacktick",
  848. "foo \\\\[comment `bar\\\\`]");
  849. MT("escapeAsterisk",
  850. "foo \\*bar\\*");
  851. MT("doubleEscapeAsterisk",
  852. "foo \\\\[em *bar\\\\*]");
  853. MT("escapeUnderscore",
  854. "foo \\_bar\\_");
  855. MT("doubleEscapeUnderscore",
  856. "foo \\\\[em _bar\\\\_]");
  857. MT("escapeHash",
  858. "\\# foo");
  859. MT("doubleEscapeHash",
  860. "\\\\# foo");
  861. MT("escapeNewline",
  862. "\\",
  863. "[em *foo*]");
  864. // Class override tests
  865. TokenTypeOverrideTest("overrideHeader1",
  866. "[override-header&override-header-1 # Foo]");
  867. TokenTypeOverrideTest("overrideHeader2",
  868. "[override-header&override-header-2 ## Foo]");
  869. TokenTypeOverrideTest("overrideHeader3",
  870. "[override-header&override-header-3 ### Foo]");
  871. TokenTypeOverrideTest("overrideHeader4",
  872. "[override-header&override-header-4 #### Foo]");
  873. TokenTypeOverrideTest("overrideHeader5",
  874. "[override-header&override-header-5 ##### Foo]");
  875. TokenTypeOverrideTest("overrideHeader6",
  876. "[override-header&override-header-6 ###### Foo]");
  877. TokenTypeOverrideTest("overrideCode",
  878. "[override-code `foo`]");
  879. TokenTypeOverrideTest("overrideCodeBlock",
  880. "[override-code ```]",
  881. "[override-code foo]",
  882. "[override-code ```]");
  883. TokenTypeOverrideTest("overrideQuote",
  884. "[override-quote&override-quote-1 > foo]",
  885. "[override-quote&override-quote-1 > bar]");
  886. TokenTypeOverrideTest("overrideQuoteNested",
  887. "[override-quote&override-quote-1 > foo]",
  888. "[override-quote&override-quote-1 >][override-quote&override-quote-2 > bar]",
  889. "[override-quote&override-quote-1 >][override-quote&override-quote-2 >][override-quote&override-quote-3 > baz]");
  890. TokenTypeOverrideTest("overrideLists",
  891. "[override-list1 - foo]",
  892. "",
  893. " [override-list2 + bar]",
  894. "",
  895. " [override-list3 * baz]",
  896. "",
  897. " [override-list1 1. qux]",
  898. "",
  899. " [override-list2 - quux]");
  900. TokenTypeOverrideTest("overrideHr",
  901. "[override-hr * * *]");
  902. TokenTypeOverrideTest("overrideImage",
  903. "[override-image&override-image-marker !][override-image&override-image-alt-text&link [[alt text]]][override-link-href&url (http://link.to/image.jpg)]");
  904. TokenTypeOverrideTest("overrideLinkText",
  905. "[override-link-text [[foo]]][override-link-href&url (http://example.com)]");
  906. TokenTypeOverrideTest("overrideLinkEmailAndInline",
  907. "[override-link-email <][override-link-inline foo@example.com>]");
  908. TokenTypeOverrideTest("overrideEm",
  909. "[override-em *foo*]");
  910. TokenTypeOverrideTest("overrideStrong",
  911. "[override-strong **foo**]");
  912. TokenTypeOverrideTest("overrideStrikethrough",
  913. "[override-strikethrough ~~foo~~]");
  914. TokenTypeOverrideTest("overrideEmoji",
  915. "[override-emoji :foo:]");
  916. FormatTokenTypeOverrideTest("overrideFormatting",
  917. "[override-formatting-escape \\*]");
  918. // Tests to make sure GFM-specific things aren't getting through
  919. MT("taskList",
  920. "[variable-2 * ][link&variable-2 [[ ]]][variable-2 bar]");
  921. MT("fencedCodeBlocks",
  922. "[comment ```]",
  923. "[comment foo]",
  924. "",
  925. "[comment bar]",
  926. "[comment ```]",
  927. "baz");
  928. MT("fencedCodeBlocks_invalidClosingFence_trailingText",
  929. "[comment ```]",
  930. "[comment foo]",
  931. "[comment ``` must not have trailing text]",
  932. "[comment baz]");
  933. MT("fencedCodeBlocks_invalidClosingFence_trailingTabs",
  934. "[comment ```]",
  935. "[comment foo]",
  936. "[comment ```\t]",
  937. "[comment baz]");
  938. MT("fencedCodeBlocks_validClosingFence",
  939. "[comment ```]",
  940. "[comment foo]",
  941. // may have trailing spaces
  942. "[comment ``` ]",
  943. "baz");
  944. MT("fencedCodeBlocksInList_closingFenceIndented",
  945. "[variable-2 - list]",
  946. " [variable-2&comment ```]",
  947. " [comment foo]",
  948. " [variable-2&comment ```]",
  949. " [variable-2 baz]");
  950. MT("fencedCodeBlocksInList_closingFenceIndentedTooMuch",
  951. "[variable-2 - list]",
  952. " [variable-2&comment ```]",
  953. " [comment foo]",
  954. " [comment ```]",
  955. " [comment baz]");
  956. MT("fencedCodeBlockModeSwitching",
  957. "[comment ```javascript]",
  958. "[variable foo]",
  959. "",
  960. "[comment ```]",
  961. "bar");
  962. MT_noFencedHighlight("fencedCodeBlock_noHighlight",
  963. "[comment ```javascript]",
  964. "[comment foo]",
  965. "[comment ```]");
  966. MT("fencedCodeBlockModeSwitchingObjc",
  967. "[comment ```objective-c]",
  968. "[keyword @property] [variable NSString] [operator *] [variable foo];",
  969. "[comment ```]",
  970. "bar");
  971. MT("fencedCodeBlocksMultipleChars",
  972. "[comment `````]",
  973. "[comment foo]",
  974. "[comment ```]",
  975. "[comment foo]",
  976. "[comment `````]",
  977. "bar");
  978. MT("fencedCodeBlocksTildes",
  979. "[comment ~~~]",
  980. "[comment foo]",
  981. "[comment ~~~]",
  982. "bar");
  983. MT("fencedCodeBlocksTildesMultipleChars",
  984. "[comment ~~~~~]",
  985. "[comment ~~~]",
  986. "[comment foo]",
  987. "[comment ~~~~~]",
  988. "bar");
  989. MT("fencedCodeBlocksMultipleChars",
  990. "[comment `````]",
  991. "[comment foo]",
  992. "[comment ```]",
  993. "[comment foo]",
  994. "[comment `````]",
  995. "bar");
  996. MT("fencedCodeBlocksMixed",
  997. "[comment ~~~]",
  998. "[comment ```]",
  999. "[comment foo]",
  1000. "[comment ~~~]",
  1001. "bar");
  1002. MT("fencedCodeBlocksAfterBlockquote",
  1003. "[quote&quote-1 > foo]",
  1004. "[comment ```]",
  1005. "[comment bar]",
  1006. "[comment ```]");
  1007. // fencedCode indented too much should act as simple indentedCode
  1008. // (hence has no highlight formatting)
  1009. FT("tooMuchIndentedFencedCode",
  1010. " [comment ```]",
  1011. " [comment code]",
  1012. " [comment ```]");
  1013. MT("autoTerminateFencedCodeWhenLeavingList",
  1014. "[variable-2 - list1]",
  1015. " [variable-3 - list2]",
  1016. " [variable-3&comment ```]",
  1017. " [comment code]",
  1018. " [variable-3 - list2]",
  1019. " [variable-2&comment ```]",
  1020. " [comment code]",
  1021. "[quote&quote-1 > foo]");
  1022. // Tests that require XML mode
  1023. MT("xmlMode",
  1024. "[tag&bracket <][tag div][tag&bracket >]",
  1025. " *foo*",
  1026. " [tag&bracket <][tag http://github.com][tag&bracket />]",
  1027. "[tag&bracket </][tag div][tag&bracket >]",
  1028. "[link <http://github.com/>]");
  1029. MT("xmlModeWithMarkdownInside",
  1030. "[tag&bracket <][tag div] [attribute markdown]=[string 1][tag&bracket >]",
  1031. "[em *foo*]",
  1032. "[link <http://github.com/>]",
  1033. "[tag </div>]",
  1034. "[link <http://github.com/>]",
  1035. "[tag&bracket <][tag div][tag&bracket >]",
  1036. "[tag&bracket </][tag div][tag&bracket >]");
  1037. MT("xmlModeLineBreakInTags",
  1038. "[tag&bracket <][tag div] [attribute id]=[string \"1\"]",
  1039. " [attribute class]=[string \"sth\"][tag&bracket >]xxx",
  1040. "[tag&bracket </][tag div][tag&bracket >]");
  1041. MT("xmlModeCommentWithBlankLine",
  1042. "[comment <!-- Hello]",
  1043. "",
  1044. "[comment World -->]");
  1045. MT("xmlModeCDATA",
  1046. "[atom <![CDATA[ Hello]",
  1047. "",
  1048. "[atom FooBar]",
  1049. "[atom Test ]]]]>]");
  1050. MT("xmlModePreprocessor",
  1051. "[meta <?php] [meta echo '1234'; ?>]");
  1052. MT_noXml("xmlHighlightDisabled",
  1053. "<div>foo</div>");
  1054. // Tests Emojis
  1055. ET("emojiDefault",
  1056. "[builtin :foobar:]");
  1057. ET("emojiTable",
  1058. " :--:");
  1059. })();