test.js 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990
  1. // CodeMirror, copyright (c) by Marijn Haverbeke and others
  2. // Distributed under an MIT license: http://codemirror.net/LICENSE
  3. (function() {
  4. var mode = CodeMirror.getMode({tabSize: 4}, "markdown");
  5. function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); }
  6. var modeHighlightFormatting = CodeMirror.getMode({tabSize: 4}, {name: "markdown", highlightFormatting: true});
  7. function FT(name) { test.mode(name, modeHighlightFormatting, Array.prototype.slice.call(arguments, 1)); }
  8. var modeAtxNoSpace = CodeMirror.getMode({tabSize: 4}, {name: "markdown", allowAtxHeaderWithoutSpace: true});
  9. function AtxNoSpaceTest(name) { test.mode(name, modeAtxNoSpace, Array.prototype.slice.call(arguments, 1)); }
  10. var modeFenced = CodeMirror.getMode({tabSize: 4}, {name: "markdown", fencedCodeBlocks: true});
  11. function FencedTest(name) { test.mode(name, modeFenced, Array.prototype.slice.call(arguments, 1)); }
  12. var modeOverrideClasses = CodeMirror.getMode({tabsize: 4}, {
  13. name: "markdown",
  14. strikethrough: true,
  15. tokenTypeOverrides: {
  16. "header" : "override-header",
  17. "code" : "override-code",
  18. "quote" : "override-quote",
  19. "list1" : "override-list1",
  20. "list2" : "override-list2",
  21. "list3" : "override-list3",
  22. "hr" : "override-hr",
  23. "image" : "override-image",
  24. "imageAltText": "override-image-alt-text",
  25. "imageMarker": "override-image-marker",
  26. "linkInline" : "override-link-inline",
  27. "linkEmail" : "override-link-email",
  28. "linkText" : "override-link-text",
  29. "linkHref" : "override-link-href",
  30. "em" : "override-em",
  31. "strong" : "override-strong",
  32. "strikethrough" : "override-strikethrough"
  33. }});
  34. function TokenTypeOverrideTest(name) { test.mode(name, modeOverrideClasses, Array.prototype.slice.call(arguments, 1)); }
  35. var modeFormattingOverride = CodeMirror.getMode({tabsize: 4}, {
  36. name: "markdown",
  37. highlightFormatting: true,
  38. tokenTypeOverrides: {
  39. "formatting" : "override-formatting"
  40. }});
  41. function FormatTokenTypeOverrideTest(name) { test.mode(name, modeFormattingOverride, Array.prototype.slice.call(arguments, 1)); }
  42. FT("formatting_emAsterisk",
  43. "[em&formatting&formatting-em *][em foo][em&formatting&formatting-em *]");
  44. FT("formatting_emUnderscore",
  45. "[em&formatting&formatting-em _][em foo][em&formatting&formatting-em _]");
  46. FT("formatting_strongAsterisk",
  47. "[strong&formatting&formatting-strong **][strong foo][strong&formatting&formatting-strong **]");
  48. FT("formatting_strongUnderscore",
  49. "[strong&formatting&formatting-strong __][strong foo][strong&formatting&formatting-strong __]");
  50. FT("formatting_codeBackticks",
  51. "[comment&formatting&formatting-code `][comment foo][comment&formatting&formatting-code `]");
  52. FT("formatting_doubleBackticks",
  53. "[comment&formatting&formatting-code ``][comment foo ` bar][comment&formatting&formatting-code ``]");
  54. FT("formatting_atxHeader",
  55. "[header&header-1&formatting&formatting-header&formatting-header-1 # ][header&header-1 foo # bar ][header&header-1&formatting&formatting-header&formatting-header-1 #]");
  56. FT("formatting_setextHeader",
  57. "foo",
  58. "[header&header-1&formatting&formatting-header&formatting-header-1 =]");
  59. FT("formatting_blockquote",
  60. "[quote&quote-1&formatting&formatting-quote&formatting-quote-1 > ][quote&quote-1 foo]");
  61. FT("formatting_list",
  62. "[variable-2&formatting&formatting-list&formatting-list-ul - ][variable-2 foo]");
  63. FT("formatting_list",
  64. "[variable-2&formatting&formatting-list&formatting-list-ol 1. ][variable-2 foo]");
  65. FT("formatting_link",
  66. "[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 )]");
  67. FT("formatting_linkReference",
  68. "[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 ]]]",
  69. "[link&formatting&formatting-link [][link bar][link&formatting&formatting-link ]]:] [string&url http://example.com/]");
  70. FT("formatting_linkWeb",
  71. "[link&formatting&formatting-link <][link http://example.com/][link&formatting&formatting-link >]");
  72. FT("formatting_linkEmail",
  73. "[link&formatting&formatting-link <][link user@example.com][link&formatting&formatting-link >]");
  74. FT("formatting_escape",
  75. "[formatting-escape \\*]");
  76. FT("formatting_image",
  77. "[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 )]");
  78. MT("plainText",
  79. "foo");
  80. // Don't style single trailing space
  81. MT("trailingSpace1",
  82. "foo ");
  83. // Two or more trailing spaces should be styled with line break character
  84. MT("trailingSpace2",
  85. "foo[trailing-space-a ][trailing-space-new-line ]");
  86. MT("trailingSpace3",
  87. "foo[trailing-space-a ][trailing-space-b ][trailing-space-new-line ]");
  88. MT("trailingSpace4",
  89. "foo[trailing-space-a ][trailing-space-b ][trailing-space-a ][trailing-space-new-line ]");
  90. // Code blocks using 4 spaces (regardless of CodeMirror.tabSize value)
  91. MT("codeBlocksUsing4Spaces",
  92. " [comment foo]");
  93. // Code blocks using 4 spaces with internal indentation
  94. MT("codeBlocksUsing4SpacesIndentation",
  95. " [comment bar]",
  96. " [comment hello]",
  97. " [comment world]",
  98. " [comment foo]",
  99. "bar");
  100. // Code blocks should end even after extra indented lines
  101. MT("codeBlocksWithTrailingIndentedLine",
  102. " [comment foo]",
  103. " [comment bar]",
  104. " [comment baz]",
  105. " ",
  106. "hello");
  107. // Code blocks using 1 tab (regardless of CodeMirror.indentWithTabs value)
  108. MT("codeBlocksUsing1Tab",
  109. "\t[comment foo]");
  110. // No code blocks directly after paragraph
  111. // http://spec.commonmark.org/0.19/#example-65
  112. MT("noCodeBlocksAfterParagraph",
  113. "Foo",
  114. " Bar");
  115. // Inline code using backticks
  116. MT("inlineCodeUsingBackticks",
  117. "foo [comment `bar`]");
  118. // Block code using single backtick (shouldn't work)
  119. MT("blockCodeSingleBacktick",
  120. "[comment `]",
  121. "[comment foo]",
  122. "[comment `]");
  123. // Unclosed backticks
  124. // Instead of simply marking as CODE, it would be nice to have an
  125. // incomplete flag for CODE, that is styled slightly different.
  126. MT("unclosedBackticks",
  127. "foo [comment `bar]");
  128. // Per documentation: "To include a literal backtick character within a
  129. // code span, you can use multiple backticks as the opening and closing
  130. // delimiters"
  131. MT("doubleBackticks",
  132. "[comment ``foo ` bar``]");
  133. // Tests based on Dingus
  134. // http://daringfireball.net/projects/markdown/dingus
  135. //
  136. // Multiple backticks within an inline code block
  137. MT("consecutiveBackticks",
  138. "[comment `foo```bar`]");
  139. // Multiple backticks within an inline code block with a second code block
  140. MT("consecutiveBackticks",
  141. "[comment `foo```bar`] hello [comment `world`]");
  142. // Unclosed with several different groups of backticks
  143. MT("unclosedBackticks",
  144. "[comment ``foo ``` bar` hello]");
  145. // Closed with several different groups of backticks
  146. MT("closedBackticks",
  147. "[comment ``foo ``` bar` hello``] world");
  148. // atx headers
  149. // http://daringfireball.net/projects/markdown/syntax#header
  150. MT("atxH1",
  151. "[header&header-1 # foo]");
  152. MT("atxH2",
  153. "[header&header-2 ## foo]");
  154. MT("atxH3",
  155. "[header&header-3 ### foo]");
  156. MT("atxH4",
  157. "[header&header-4 #### foo]");
  158. MT("atxH5",
  159. "[header&header-5 ##### foo]");
  160. MT("atxH6",
  161. "[header&header-6 ###### foo]");
  162. // http://spec.commonmark.org/0.19/#example-24
  163. MT("noAtxH7",
  164. "####### foo");
  165. // http://spec.commonmark.org/0.19/#example-25
  166. MT("noAtxH1WithoutSpace",
  167. "#5 bolt");
  168. // CommonMark requires a space after # but most parsers don't
  169. AtxNoSpaceTest("atxNoSpaceAllowed_H1NoSpace",
  170. "[header&header-1 #foo]");
  171. AtxNoSpaceTest("atxNoSpaceAllowed_H4NoSpace",
  172. "[header&header-4 ####foo]");
  173. AtxNoSpaceTest("atxNoSpaceAllowed_H1Space",
  174. "[header&header-1 # foo]");
  175. // Inline styles should be parsed inside headers
  176. MT("atxH1inline",
  177. "[header&header-1 # foo ][header&header-1&em *bar*]");
  178. // Setext headers - H1, H2
  179. // Per documentation, "Any number of underlining =’s or -’s will work."
  180. // http://daringfireball.net/projects/markdown/syntax#header
  181. // Ideally, the text would be marked as `header` as well, but this is
  182. // not really feasible at the moment. So, instead, we're testing against
  183. // what works today, to avoid any regressions.
  184. //
  185. // Check if single underlining = works
  186. MT("setextH1",
  187. "foo",
  188. "[header&header-1 =]");
  189. // Check if 3+ ='s work
  190. MT("setextH1",
  191. "foo",
  192. "[header&header-1 ===]");
  193. // Check if single underlining - works
  194. MT("setextH2",
  195. "foo",
  196. "[header&header-2 -]");
  197. // Check if 3+ -'s work
  198. MT("setextH2",
  199. "foo",
  200. "[header&header-2 ---]");
  201. // http://spec.commonmark.org/0.19/#example-45
  202. MT("setextH2AllowSpaces",
  203. "foo",
  204. " [header&header-2 ---- ]");
  205. // http://spec.commonmark.org/0.19/#example-44
  206. MT("noSetextAfterIndentedCodeBlock",
  207. " [comment foo]",
  208. "[hr ---]");
  209. // http://spec.commonmark.org/0.19/#example-51
  210. MT("noSetextAfterQuote",
  211. "[quote&quote-1 > foo]",
  212. "[hr ---]");
  213. MT("noSetextAfterList",
  214. "[variable-2 - foo]",
  215. "[hr ---]");
  216. // Single-line blockquote with trailing space
  217. MT("blockquoteSpace",
  218. "[quote&quote-1 > foo]");
  219. // Single-line blockquote
  220. MT("blockquoteNoSpace",
  221. "[quote&quote-1 >foo]");
  222. // No blank line before blockquote
  223. MT("blockquoteNoBlankLine",
  224. "foo",
  225. "[quote&quote-1 > bar]");
  226. // Nested blockquote
  227. MT("blockquoteSpace",
  228. "[quote&quote-1 > foo]",
  229. "[quote&quote-1 >][quote&quote-2 > foo]",
  230. "[quote&quote-1 >][quote&quote-2 >][quote&quote-3 > foo]");
  231. // Single-line blockquote followed by normal paragraph
  232. MT("blockquoteThenParagraph",
  233. "[quote&quote-1 >foo]",
  234. "",
  235. "bar");
  236. // Multi-line blockquote (lazy mode)
  237. MT("multiBlockquoteLazy",
  238. "[quote&quote-1 >foo]",
  239. "[quote&quote-1 bar]");
  240. // Multi-line blockquote followed by normal paragraph (lazy mode)
  241. MT("multiBlockquoteLazyThenParagraph",
  242. "[quote&quote-1 >foo]",
  243. "[quote&quote-1 bar]",
  244. "",
  245. "hello");
  246. // Multi-line blockquote (non-lazy mode)
  247. MT("multiBlockquote",
  248. "[quote&quote-1 >foo]",
  249. "[quote&quote-1 >bar]");
  250. // Multi-line blockquote followed by normal paragraph (non-lazy mode)
  251. MT("multiBlockquoteThenParagraph",
  252. "[quote&quote-1 >foo]",
  253. "[quote&quote-1 >bar]",
  254. "",
  255. "hello");
  256. // Header with leading space after continued blockquote (#3287, negative indentation)
  257. MT("headerAfterContinuedBlockquote",
  258. "[quote&quote-1 > foo]",
  259. "[quote&quote-1 bar]",
  260. "",
  261. " [header&header-1 # hello]");
  262. // Check list types
  263. MT("listAsterisk",
  264. "foo",
  265. "bar",
  266. "",
  267. "[variable-2 * foo]",
  268. "[variable-2 * bar]");
  269. MT("listPlus",
  270. "foo",
  271. "bar",
  272. "",
  273. "[variable-2 + foo]",
  274. "[variable-2 + bar]");
  275. MT("listDash",
  276. "foo",
  277. "bar",
  278. "",
  279. "[variable-2 - foo]",
  280. "[variable-2 - bar]");
  281. MT("listNumber",
  282. "foo",
  283. "bar",
  284. "",
  285. "[variable-2 1. foo]",
  286. "[variable-2 2. bar]");
  287. // Lists require a preceding blank line (per Dingus)
  288. MT("listBogus",
  289. "foo",
  290. "1. bar",
  291. "2. hello");
  292. // List after hr
  293. MT("listAfterHr",
  294. "[hr ---]",
  295. "[variable-2 - bar]");
  296. // List after header
  297. MT("listAfterHeader",
  298. "[header&header-1 # foo]",
  299. "[variable-2 - bar]");
  300. // hr after list
  301. MT("hrAfterList",
  302. "[variable-2 - foo]",
  303. "[hr -----]");
  304. // Formatting in lists (*)
  305. MT("listAsteriskFormatting",
  306. "[variable-2 * ][variable-2&em *foo*][variable-2 bar]",
  307. "[variable-2 * ][variable-2&strong **foo**][variable-2 bar]",
  308. "[variable-2 * ][variable-2&strong **][variable-2&em&strong *foo**][variable-2&em *][variable-2 bar]",
  309. "[variable-2 * ][variable-2&comment `foo`][variable-2 bar]");
  310. // Formatting in lists (+)
  311. MT("listPlusFormatting",
  312. "[variable-2 + ][variable-2&em *foo*][variable-2 bar]",
  313. "[variable-2 + ][variable-2&strong **foo**][variable-2 bar]",
  314. "[variable-2 + ][variable-2&strong **][variable-2&em&strong *foo**][variable-2&em *][variable-2 bar]",
  315. "[variable-2 + ][variable-2&comment `foo`][variable-2 bar]");
  316. // Formatting in lists (-)
  317. MT("listDashFormatting",
  318. "[variable-2 - ][variable-2&em *foo*][variable-2 bar]",
  319. "[variable-2 - ][variable-2&strong **foo**][variable-2 bar]",
  320. "[variable-2 - ][variable-2&strong **][variable-2&em&strong *foo**][variable-2&em *][variable-2 bar]",
  321. "[variable-2 - ][variable-2&comment `foo`][variable-2 bar]");
  322. // Formatting in lists (1.)
  323. MT("listNumberFormatting",
  324. "[variable-2 1. ][variable-2&em *foo*][variable-2 bar]",
  325. "[variable-2 2. ][variable-2&strong **foo**][variable-2 bar]",
  326. "[variable-2 3. ][variable-2&strong **][variable-2&em&strong *foo**][variable-2&em *][variable-2 bar]",
  327. "[variable-2 4. ][variable-2&comment `foo`][variable-2 bar]");
  328. // Paragraph lists
  329. MT("listParagraph",
  330. "[variable-2 * foo]",
  331. "",
  332. "[variable-2 * bar]");
  333. // Multi-paragraph lists
  334. //
  335. // 4 spaces
  336. MT("listMultiParagraph",
  337. "[variable-2 * foo]",
  338. "",
  339. "[variable-2 * bar]",
  340. "",
  341. " [variable-2 hello]");
  342. // 4 spaces, extra blank lines (should still be list, per Dingus)
  343. MT("listMultiParagraphExtra",
  344. "[variable-2 * foo]",
  345. "",
  346. "[variable-2 * bar]",
  347. "",
  348. "",
  349. " [variable-2 hello]");
  350. // 4 spaces, plus 1 space (should still be list, per Dingus)
  351. MT("listMultiParagraphExtraSpace",
  352. "[variable-2 * foo]",
  353. "",
  354. "[variable-2 * bar]",
  355. "",
  356. " [variable-2 hello]",
  357. "",
  358. " [variable-2 world]");
  359. // 1 tab
  360. MT("listTab",
  361. "[variable-2 * foo]",
  362. "",
  363. "[variable-2 * bar]",
  364. "",
  365. "\t[variable-2 hello]");
  366. // No indent
  367. MT("listNoIndent",
  368. "[variable-2 * foo]",
  369. "",
  370. "[variable-2 * bar]",
  371. "",
  372. "hello");
  373. MT("listCommonMarkIndentationCode",
  374. "[variable-2 * Code blocks also affect]",
  375. " [variable-3 * The next level starts where the contents start.]",
  376. " [variable-3 * Anything less than that will keep the item on the same level.]",
  377. " [variable-3 * Each list item can indent the first level further and further.]",
  378. " [variable-3 * For the most part, this makes sense while writing a list.]",
  379. " [keyword * This means two items with same indentation can be different levels.]",
  380. " [keyword * Each level has an indent requirement that can change between items.]",
  381. " [keyword * A list item that meets this will be part of the next level.]",
  382. " [variable-3 * Otherwise, it will be part of the level where it does meet this.]",
  383. " [variable-2 * World]");
  384. // Blockquote
  385. MT("blockquote",
  386. "[variable-2 * foo]",
  387. "",
  388. "[variable-2 * bar]",
  389. "",
  390. " [variable-2&quote&quote-1 > hello]");
  391. // Code block
  392. MT("blockquoteCode",
  393. "[variable-2 * foo]",
  394. "",
  395. "[variable-2 * bar]",
  396. "",
  397. " [comment > hello]",
  398. "",
  399. " [variable-2 world]");
  400. // Code block followed by text
  401. MT("blockquoteCodeText",
  402. "[variable-2 * foo]",
  403. "",
  404. " [variable-2 bar]",
  405. "",
  406. " [comment hello]",
  407. "",
  408. " [variable-2 world]");
  409. // Nested list
  410. MT("listAsteriskNested",
  411. "[variable-2 * foo]",
  412. "",
  413. " [variable-3 * bar]");
  414. MT("listPlusNested",
  415. "[variable-2 + foo]",
  416. "",
  417. " [variable-3 + bar]");
  418. MT("listDashNested",
  419. "[variable-2 - foo]",
  420. "",
  421. " [variable-3 - bar]");
  422. MT("listNumberNested",
  423. "[variable-2 1. foo]",
  424. "",
  425. " [variable-3 2. bar]");
  426. MT("listMixed",
  427. "[variable-2 * foo]",
  428. "",
  429. " [variable-3 + bar]",
  430. "",
  431. " [keyword - hello]",
  432. "",
  433. " [variable-2 1. world]");
  434. MT("listBlockquote",
  435. "[variable-2 * foo]",
  436. "",
  437. " [variable-3 + bar]",
  438. "",
  439. " [quote&quote-1&variable-3 > hello]");
  440. MT("listCode",
  441. "[variable-2 * foo]",
  442. "",
  443. " [variable-3 + bar]",
  444. "",
  445. " [comment hello]");
  446. // Code with internal indentation
  447. MT("listCodeIndentation",
  448. "[variable-2 * foo]",
  449. "",
  450. " [comment bar]",
  451. " [comment hello]",
  452. " [comment world]",
  453. " [comment foo]",
  454. " [variable-2 bar]");
  455. // List nesting edge cases
  456. MT("listNested",
  457. "[variable-2 * foo]",
  458. "",
  459. " [variable-3 * bar]",
  460. "",
  461. " [variable-3 hello]"
  462. );
  463. MT("listNested",
  464. "[variable-2 * foo]",
  465. "",
  466. " [variable-3 * bar]",
  467. "",
  468. " [keyword * foo]"
  469. );
  470. // Code followed by text
  471. MT("listCodeText",
  472. "[variable-2 * foo]",
  473. "",
  474. " [comment bar]",
  475. "",
  476. "hello");
  477. // Following tests directly from official Markdown documentation
  478. // http://daringfireball.net/projects/markdown/syntax#hr
  479. MT("hrSpace",
  480. "[hr * * *]");
  481. MT("hr",
  482. "[hr ***]");
  483. MT("hrLong",
  484. "[hr *****]");
  485. MT("hrSpaceDash",
  486. "[hr - - -]");
  487. MT("hrDashLong",
  488. "[hr ---------------------------------------]");
  489. //Images
  490. MT("Images",
  491. "[image&image-marker !][image&image-alt-text&link [[alt text]]][string&url (http://link.to/image.jpg)]")
  492. //Images with highlight alt text
  493. MT("imageEm",
  494. "[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)]");
  495. MT("imageStrong",
  496. "[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)]");
  497. MT("imageEmStrong",
  498. "[image&image-marker !][image&image-alt-text&link [[][image-alt-text&image&strong&link **][image&image-alt-text&em&strong&link *alt text**][image&image-alt-text&em&link *][image&image-alt-text&link ]]][string&url (http://link.to/image.jpg)]");
  499. // Inline link with title
  500. MT("linkTitle",
  501. "[link [[foo]]][string&url (http://example.com/ \"bar\")] hello");
  502. // Inline link without title
  503. MT("linkNoTitle",
  504. "[link [[foo]]][string&url (http://example.com/)] bar");
  505. // Inline link with image
  506. MT("linkImage",
  507. "[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");
  508. // Inline link with Em
  509. MT("linkEm",
  510. "[link [[][link&em *foo*][link ]]][string&url (http://example.com/)] bar");
  511. // Inline link with Strong
  512. MT("linkStrong",
  513. "[link [[][link&strong **foo**][link ]]][string&url (http://example.com/)] bar");
  514. // Inline link with EmStrong
  515. MT("linkEmStrong",
  516. "[link [[][link&strong **][link&em&strong *foo**][link&em *][link ]]][string&url (http://example.com/)] bar");
  517. // Image with title
  518. MT("imageTitle",
  519. "[image&image-marker !][image&image-alt-text&link [[alt text]]][string&url (http://example.com/ \"bar\")] hello");
  520. // Image without title
  521. MT("imageNoTitle",
  522. "[image&image-marker !][image&image-alt-text&link [[alt text]]][string&url (http://example.com/)] bar");
  523. // Image with asterisks
  524. MT("imageAsterisks",
  525. "[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");
  526. // Not a link. Should be normal text due to square brackets being used
  527. // regularly in text, especially in quoted material, and no space is allowed
  528. // between square brackets and parentheses (per Dingus).
  529. MT("notALink",
  530. "[[foo]] (bar)");
  531. // Reference-style links
  532. MT("linkReference",
  533. "[link [[foo]]][string&url [[bar]]] hello");
  534. // Reference-style links with Em
  535. MT("linkReferenceEm",
  536. "[link [[][link&em *foo*][link ]]][string&url [[bar]]] hello");
  537. // Reference-style links with Strong
  538. MT("linkReferenceStrong",
  539. "[link [[][link&strong **foo**][link ]]][string&url [[bar]]] hello");
  540. // Reference-style links with EmStrong
  541. MT("linkReferenceEmStrong",
  542. "[link [[][link&strong **][link&em&strong *foo**][link&em *][link ]]][string&url [[bar]]] hello");
  543. // Reference-style links with optional space separator (per documentation)
  544. // "You can optionally use a space to separate the sets of brackets"
  545. MT("linkReferenceSpace",
  546. "[link [[foo]]] [string&url [[bar]]] hello");
  547. // Should only allow a single space ("...use *a* space...")
  548. MT("linkReferenceDoubleSpace",
  549. "[[foo]] [[bar]] hello");
  550. // Reference-style links with implicit link name
  551. MT("linkImplicit",
  552. "[link [[foo]]][string&url [[]]] hello");
  553. // @todo It would be nice if, at some point, the document was actually
  554. // checked to see if the referenced link exists
  555. // Link label, for reference-style links (taken from documentation)
  556. MT("labelNoTitle",
  557. "[link [[foo]]:] [string&url http://example.com/]");
  558. MT("labelIndented",
  559. " [link [[foo]]:] [string&url http://example.com/]");
  560. MT("labelSpaceTitle",
  561. "[link [[foo bar]]:] [string&url http://example.com/ \"hello\"]");
  562. MT("labelDoubleTitle",
  563. "[link [[foo bar]]:] [string&url http://example.com/ \"hello\"] \"world\"");
  564. MT("labelTitleDoubleQuotes",
  565. "[link [[foo]]:] [string&url http://example.com/ \"bar\"]");
  566. MT("labelTitleSingleQuotes",
  567. "[link [[foo]]:] [string&url http://example.com/ 'bar']");
  568. MT("labelTitleParentheses",
  569. "[link [[foo]]:] [string&url http://example.com/ (bar)]");
  570. MT("labelTitleInvalid",
  571. "[link [[foo]]:] [string&url http://example.com/] bar");
  572. MT("labelLinkAngleBrackets",
  573. "[link [[foo]]:] [string&url <http://example.com/> \"bar\"]");
  574. MT("labelTitleNextDoubleQuotes",
  575. "[link [[foo]]:] [string&url http://example.com/]",
  576. "[string \"bar\"] hello");
  577. MT("labelTitleNextSingleQuotes",
  578. "[link [[foo]]:] [string&url http://example.com/]",
  579. "[string 'bar'] hello");
  580. MT("labelTitleNextParentheses",
  581. "[link [[foo]]:] [string&url http://example.com/]",
  582. "[string (bar)] hello");
  583. MT("labelTitleNextMixed",
  584. "[link [[foo]]:] [string&url http://example.com/]",
  585. "(bar\" hello");
  586. MT("labelEscape",
  587. "[link [[foo \\]] ]]:] [string&url http://example.com/]");
  588. MT("labelEscapeColon",
  589. "[link [[foo \\]]: bar]]:] [string&url http://example.com/]");
  590. MT("labelEscapeEnd",
  591. "[[foo\\]]: http://example.com/");
  592. MT("linkWeb",
  593. "[link <http://example.com/>] foo");
  594. MT("linkWebDouble",
  595. "[link <http://example.com/>] foo [link <http://example.com/>]");
  596. MT("linkEmail",
  597. "[link <user@example.com>] foo");
  598. MT("linkEmailDouble",
  599. "[link <user@example.com>] foo [link <user@example.com>]");
  600. MT("emAsterisk",
  601. "[em *foo*] bar");
  602. MT("emUnderscore",
  603. "[em _foo_] bar");
  604. MT("emInWordAsterisk",
  605. "foo[em *bar*]hello");
  606. MT("emInWordUnderscore",
  607. "foo[em _bar_]hello");
  608. // Per documentation: "...surround an * or _ with spaces, it’ll be
  609. // treated as a literal asterisk or underscore."
  610. MT("emEscapedBySpaceIn",
  611. "foo [em _bar _ hello_] world");
  612. MT("emEscapedBySpaceOut",
  613. "foo _ bar[em _hello_]world");
  614. MT("emEscapedByNewline",
  615. "foo",
  616. "_ bar[em _hello_]world");
  617. // Unclosed emphasis characters
  618. // Instead of simply marking as EM / STRONG, it would be nice to have an
  619. // incomplete flag for EM and STRONG, that is styled slightly different.
  620. MT("emIncompleteAsterisk",
  621. "foo [em *bar]");
  622. MT("emIncompleteUnderscore",
  623. "foo [em _bar]");
  624. MT("strongAsterisk",
  625. "[strong **foo**] bar");
  626. MT("strongUnderscore",
  627. "[strong __foo__] bar");
  628. MT("emStrongAsterisk",
  629. "[em *foo][em&strong **bar*][strong hello**] world");
  630. MT("emStrongUnderscore",
  631. "[em _foo][em&strong __bar_][strong hello__] world");
  632. // "...same character must be used to open and close an emphasis span.""
  633. MT("emStrongMixed",
  634. "[em _foo][em&strong **bar*hello__ world]");
  635. MT("emStrongMixed",
  636. "[em *foo][em&strong __bar_hello** world]");
  637. MT("linkWithNestedParens",
  638. "[link [[foo]]][string&url (bar(baz))]")
  639. // These characters should be escaped:
  640. // \ backslash
  641. // ` backtick
  642. // * asterisk
  643. // _ underscore
  644. // {} curly braces
  645. // [] square brackets
  646. // () parentheses
  647. // # hash mark
  648. // + plus sign
  649. // - minus sign (hyphen)
  650. // . dot
  651. // ! exclamation mark
  652. MT("escapeBacktick",
  653. "foo \\`bar\\`");
  654. MT("doubleEscapeBacktick",
  655. "foo \\\\[comment `bar\\\\`]");
  656. MT("escapeAsterisk",
  657. "foo \\*bar\\*");
  658. MT("doubleEscapeAsterisk",
  659. "foo \\\\[em *bar\\\\*]");
  660. MT("escapeUnderscore",
  661. "foo \\_bar\\_");
  662. MT("doubleEscapeUnderscore",
  663. "foo \\\\[em _bar\\\\_]");
  664. MT("escapeHash",
  665. "\\# foo");
  666. MT("doubleEscapeHash",
  667. "\\\\# foo");
  668. MT("escapeNewline",
  669. "\\",
  670. "[em *foo*]");
  671. // Class override tests
  672. TokenTypeOverrideTest("overrideHeader1",
  673. "[override-header&override-header-1 # Foo]");
  674. TokenTypeOverrideTest("overrideHeader2",
  675. "[override-header&override-header-2 ## Foo]");
  676. TokenTypeOverrideTest("overrideHeader3",
  677. "[override-header&override-header-3 ### Foo]");
  678. TokenTypeOverrideTest("overrideHeader4",
  679. "[override-header&override-header-4 #### Foo]");
  680. TokenTypeOverrideTest("overrideHeader5",
  681. "[override-header&override-header-5 ##### Foo]");
  682. TokenTypeOverrideTest("overrideHeader6",
  683. "[override-header&override-header-6 ###### Foo]");
  684. TokenTypeOverrideTest("overrideCode",
  685. "[override-code `foo`]");
  686. TokenTypeOverrideTest("overrideCodeBlock",
  687. "[override-code ```]",
  688. "[override-code foo]",
  689. "[override-code ```]");
  690. TokenTypeOverrideTest("overrideQuote",
  691. "[override-quote&override-quote-1 > foo]",
  692. "[override-quote&override-quote-1 > bar]");
  693. TokenTypeOverrideTest("overrideQuoteNested",
  694. "[override-quote&override-quote-1 > foo]",
  695. "[override-quote&override-quote-1 >][override-quote&override-quote-2 > bar]",
  696. "[override-quote&override-quote-1 >][override-quote&override-quote-2 >][override-quote&override-quote-3 > baz]");
  697. TokenTypeOverrideTest("overrideLists",
  698. "[override-list1 - foo]",
  699. "",
  700. " [override-list2 + bar]",
  701. "",
  702. " [override-list3 * baz]",
  703. "",
  704. " [override-list1 1. qux]",
  705. "",
  706. " [override-list2 - quux]");
  707. TokenTypeOverrideTest("overrideHr",
  708. "[override-hr * * *]");
  709. TokenTypeOverrideTest("overrideImage",
  710. "[override-image&override-image-marker !][override-image&override-image-alt-text&link [[alt text]]][override-link-href&url (http://link.to/image.jpg)]");
  711. TokenTypeOverrideTest("overrideLinkText",
  712. "[override-link-text [[foo]]][override-link-href&url (http://example.com)]");
  713. TokenTypeOverrideTest("overrideLinkEmailAndInline",
  714. "[override-link-email <][override-link-inline foo@example.com>]");
  715. TokenTypeOverrideTest("overrideEm",
  716. "[override-em *foo*]");
  717. TokenTypeOverrideTest("overrideStrong",
  718. "[override-strong **foo**]");
  719. TokenTypeOverrideTest("overrideStrikethrough",
  720. "[override-strikethrough ~~foo~~]");
  721. FormatTokenTypeOverrideTest("overrideFormatting",
  722. "[override-formatting-escape \\*]");
  723. // Tests to make sure GFM-specific things aren't getting through
  724. MT("taskList",
  725. "[variable-2 * [ ]] bar]");
  726. MT("noFencedCodeBlocks",
  727. "~~~",
  728. "foo",
  729. "~~~");
  730. FencedTest("fencedCodeBlocks",
  731. "[comment ```]",
  732. "[comment foo]",
  733. "[comment ```]",
  734. "bar");
  735. FencedTest("fencedCodeBlocksMultipleChars",
  736. "[comment `````]",
  737. "[comment foo]",
  738. "[comment ```]",
  739. "[comment foo]",
  740. "[comment `````]",
  741. "bar");
  742. FencedTest("fencedCodeBlocksTildes",
  743. "[comment ~~~]",
  744. "[comment foo]",
  745. "[comment ~~~]",
  746. "bar");
  747. FencedTest("fencedCodeBlocksTildesMultipleChars",
  748. "[comment ~~~~~]",
  749. "[comment ~~~]",
  750. "[comment foo]",
  751. "[comment ~~~~~]",
  752. "bar");
  753. FencedTest("fencedCodeBlocksMultipleChars",
  754. "[comment `````]",
  755. "[comment foo]",
  756. "[comment ```]",
  757. "[comment foo]",
  758. "[comment `````]",
  759. "bar");
  760. FencedTest("fencedCodeBlocksMixed",
  761. "[comment ~~~]",
  762. "[comment ```]",
  763. "[comment foo]",
  764. "[comment ~~~]",
  765. "bar");
  766. // Tests that require XML mode
  767. MT("xmlMode",
  768. "[tag&bracket <][tag div][tag&bracket >]",
  769. "*foo*",
  770. "[tag&bracket <][tag http://github.com][tag&bracket />]",
  771. "[tag&bracket </][tag div][tag&bracket >]",
  772. "[link <http://github.com/>]");
  773. MT("xmlModeWithMarkdownInside",
  774. "[tag&bracket <][tag div] [attribute markdown]=[string 1][tag&bracket >]",
  775. "[em *foo*]",
  776. "[link <http://github.com/>]",
  777. "[tag </div>]",
  778. "[link <http://github.com/>]",
  779. "[tag&bracket <][tag div][tag&bracket >]",
  780. "[tag&bracket </][tag div][tag&bracket >]");
  781. })();