test.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636
  1. (function() {
  2. var mode = CodeMirror.getMode({tabSize: 4}, "markdown");
  3. function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); }
  4. MT("plainText",
  5. "foo");
  6. // Code blocks using 4 spaces (regardless of CodeMirror.tabSize value)
  7. MT("codeBlocksUsing4Spaces",
  8. " [comment foo]");
  9. // Code blocks using 4 spaces with internal indentation
  10. MT("codeBlocksUsing4SpacesIndentation",
  11. " [comment bar]",
  12. " [comment hello]",
  13. " [comment world]",
  14. " [comment foo]",
  15. "bar");
  16. // Code blocks using 4 spaces with internal indentation
  17. MT("codeBlocksUsing4SpacesIndentation",
  18. " foo",
  19. " [comment bar]",
  20. " [comment hello]",
  21. " [comment world]");
  22. // Code blocks using 1 tab (regardless of CodeMirror.indentWithTabs value)
  23. MT("codeBlocksUsing1Tab",
  24. "\t[comment foo]");
  25. // Inline code using backticks
  26. MT("inlineCodeUsingBackticks",
  27. "foo [comment `bar`]");
  28. // Block code using single backtick (shouldn't work)
  29. MT("blockCodeSingleBacktick",
  30. "[comment `]",
  31. "foo",
  32. "[comment `]");
  33. // Unclosed backticks
  34. // Instead of simply marking as CODE, it would be nice to have an
  35. // incomplete flag for CODE, that is styled slightly different.
  36. MT("unclosedBackticks",
  37. "foo [comment `bar]");
  38. // Per documentation: "To include a literal backtick character within a
  39. // code span, you can use multiple backticks as the opening and closing
  40. // delimiters"
  41. MT("doubleBackticks",
  42. "[comment ``foo ` bar``]");
  43. // Tests based on Dingus
  44. // http://daringfireball.net/projects/markdown/dingus
  45. //
  46. // Multiple backticks within an inline code block
  47. MT("consecutiveBackticks",
  48. "[comment `foo```bar`]");
  49. // Multiple backticks within an inline code block with a second code block
  50. MT("consecutiveBackticks",
  51. "[comment `foo```bar`] hello [comment `world`]");
  52. // Unclosed with several different groups of backticks
  53. MT("unclosedBackticks",
  54. "[comment ``foo ``` bar` hello]");
  55. // Closed with several different groups of backticks
  56. MT("closedBackticks",
  57. "[comment ``foo ``` bar` hello``] world");
  58. // atx headers
  59. // http://daringfireball.net/projects/markdown/syntax#header
  60. MT("atxH1",
  61. "[header # foo]");
  62. MT("atxH2",
  63. "[header ## foo]");
  64. MT("atxH3",
  65. "[header ### foo]");
  66. MT("atxH4",
  67. "[header #### foo]");
  68. MT("atxH5",
  69. "[header ##### foo]");
  70. MT("atxH6",
  71. "[header ###### foo]");
  72. // H6 - 7x '#' should still be H6, per Dingus
  73. // http://daringfireball.net/projects/markdown/dingus
  74. MT("atxH6NotH7",
  75. "[header ####### foo]");
  76. // Setext headers - H1, H2
  77. // Per documentation, "Any number of underlining =’s or -’s will work."
  78. // http://daringfireball.net/projects/markdown/syntax#header
  79. // Ideally, the text would be marked as `header` as well, but this is
  80. // not really feasible at the moment. So, instead, we're testing against
  81. // what works today, to avoid any regressions.
  82. //
  83. // Check if single underlining = works
  84. MT("setextH1",
  85. "foo",
  86. "[header =]");
  87. // Check if 3+ ='s work
  88. MT("setextH1",
  89. "foo",
  90. "[header ===]");
  91. // Check if single underlining - works
  92. MT("setextH2",
  93. "foo",
  94. "[header -]");
  95. // Check if 3+ -'s work
  96. MT("setextH2",
  97. "foo",
  98. "[header ---]");
  99. // Single-line blockquote with trailing space
  100. MT("blockquoteSpace",
  101. "[atom > foo]");
  102. // Single-line blockquote
  103. MT("blockquoteNoSpace",
  104. "[atom >foo]");
  105. // No blank line before blockquote
  106. MT("blockquoteNoBlankLine",
  107. "foo",
  108. "[atom > bar]");
  109. // Nested blockquote
  110. MT("blockquoteSpace",
  111. "[atom > foo]",
  112. "[number > > foo]",
  113. "[atom > > > foo]");
  114. // Single-line blockquote followed by normal paragraph
  115. MT("blockquoteThenParagraph",
  116. "[atom >foo]",
  117. "",
  118. "bar");
  119. // Multi-line blockquote (lazy mode)
  120. MT("multiBlockquoteLazy",
  121. "[atom >foo]",
  122. "[atom bar]");
  123. // Multi-line blockquote followed by normal paragraph (lazy mode)
  124. MT("multiBlockquoteLazyThenParagraph",
  125. "[atom >foo]",
  126. "[atom bar]",
  127. "",
  128. "hello");
  129. // Multi-line blockquote (non-lazy mode)
  130. MT("multiBlockquote",
  131. "[atom >foo]",
  132. "[atom >bar]");
  133. // Multi-line blockquote followed by normal paragraph (non-lazy mode)
  134. MT("multiBlockquoteThenParagraph",
  135. "[atom >foo]",
  136. "[atom >bar]",
  137. "",
  138. "hello");
  139. // Check list types
  140. MT("listAsterisk",
  141. "foo",
  142. "bar",
  143. "",
  144. "[variable-2 * foo]",
  145. "[variable-2 * bar]");
  146. MT("listPlus",
  147. "foo",
  148. "bar",
  149. "",
  150. "[variable-2 + foo]",
  151. "[variable-2 + bar]");
  152. MT("listDash",
  153. "foo",
  154. "bar",
  155. "",
  156. "[variable-2 - foo]",
  157. "[variable-2 - bar]");
  158. MT("listNumber",
  159. "foo",
  160. "bar",
  161. "",
  162. "[variable-2 1. foo]",
  163. "[variable-2 2. bar]");
  164. // Lists require a preceding blank line (per Dingus)
  165. MT("listBogus",
  166. "foo",
  167. "1. bar",
  168. "2. hello");
  169. // Formatting in lists (*)
  170. MT("listAsteriskFormatting",
  171. "[variable-2 * ][variable-2&em *foo*][variable-2 bar]",
  172. "[variable-2 * ][variable-2&strong **foo**][variable-2 bar]",
  173. "[variable-2 * ][variable-2&strong **][variable-2&em&strong *foo**][variable-2&em *][variable-2 bar]",
  174. "[variable-2 * ][variable-2&comment `foo`][variable-2 bar]");
  175. // Formatting in lists (+)
  176. MT("listPlusFormatting",
  177. "[variable-2 + ][variable-2&em *foo*][variable-2 bar]",
  178. "[variable-2 + ][variable-2&strong **foo**][variable-2 bar]",
  179. "[variable-2 + ][variable-2&strong **][variable-2&em&strong *foo**][variable-2&em *][variable-2 bar]",
  180. "[variable-2 + ][variable-2&comment `foo`][variable-2 bar]");
  181. // Formatting in lists (-)
  182. MT("listDashFormatting",
  183. "[variable-2 - ][variable-2&em *foo*][variable-2 bar]",
  184. "[variable-2 - ][variable-2&strong **foo**][variable-2 bar]",
  185. "[variable-2 - ][variable-2&strong **][variable-2&em&strong *foo**][variable-2&em *][variable-2 bar]",
  186. "[variable-2 - ][variable-2&comment `foo`][variable-2 bar]");
  187. // Formatting in lists (1.)
  188. MT("listNumberFormatting",
  189. "[variable-2 1. ][variable-2&em *foo*][variable-2 bar]",
  190. "[variable-2 2. ][variable-2&strong **foo**][variable-2 bar]",
  191. "[variable-2 3. ][variable-2&strong **][variable-2&em&strong *foo**][variable-2&em *][variable-2 bar]",
  192. "[variable-2 4. ][variable-2&comment `foo`][variable-2 bar]");
  193. // Paragraph lists
  194. MT("listParagraph",
  195. "[variable-2 * foo]",
  196. "",
  197. "[variable-2 * bar]");
  198. // Multi-paragraph lists
  199. //
  200. // 4 spaces
  201. MT("listMultiParagraph",
  202. "[variable-2 * foo]",
  203. "",
  204. "[variable-2 * bar]",
  205. "",
  206. " [variable-2 hello]");
  207. // 4 spaces, extra blank lines (should still be list, per Dingus)
  208. MT("listMultiParagraphExtra",
  209. "[variable-2 * foo]",
  210. "",
  211. "[variable-2 * bar]",
  212. "",
  213. "",
  214. " [variable-2 hello]");
  215. // 4 spaces, plus 1 space (should still be list, per Dingus)
  216. MT("listMultiParagraphExtraSpace",
  217. "[variable-2 * foo]",
  218. "",
  219. "[variable-2 * bar]",
  220. "",
  221. " [variable-2 hello]",
  222. "",
  223. " [variable-2 world]");
  224. // 1 tab
  225. MT("listTab",
  226. "[variable-2 * foo]",
  227. "",
  228. "[variable-2 * bar]",
  229. "",
  230. "\t[variable-2 hello]");
  231. // No indent
  232. MT("listNoIndent",
  233. "[variable-2 * foo]",
  234. "",
  235. "[variable-2 * bar]",
  236. "",
  237. "hello");
  238. // Blockquote
  239. MT("blockquote",
  240. "[variable-2 * foo]",
  241. "",
  242. "[variable-2 * bar]",
  243. "",
  244. " [variable-2&atom > hello]");
  245. // Code block
  246. MT("blockquoteCode",
  247. "[variable-2 * foo]",
  248. "",
  249. "[variable-2 * bar]",
  250. "",
  251. " [comment > hello]",
  252. "",
  253. " [variable-2 world]");
  254. // Code block followed by text
  255. MT("blockquoteCodeText",
  256. "[variable-2 * foo]",
  257. "",
  258. " [variable-2 bar]",
  259. "",
  260. " [comment hello]",
  261. "",
  262. " [variable-2 world]");
  263. // Nested list
  264. MT("listAsteriskNested",
  265. "[variable-2 * foo]",
  266. "",
  267. " [variable-3 * bar]");
  268. MT("listPlusNested",
  269. "[variable-2 + foo]",
  270. "",
  271. " [variable-3 + bar]");
  272. MT("listDashNested",
  273. "[variable-2 - foo]",
  274. "",
  275. " [variable-3 - bar]");
  276. MT("listNumberNested",
  277. "[variable-2 1. foo]",
  278. "",
  279. " [variable-3 2. bar]");
  280. MT("listMixed",
  281. "[variable-2 * foo]",
  282. "",
  283. " [variable-3 + bar]",
  284. "",
  285. " [keyword - hello]",
  286. "",
  287. " [variable-2 1. world]");
  288. MT("listBlockquote",
  289. "[variable-2 * foo]",
  290. "",
  291. " [variable-3 + bar]",
  292. "",
  293. " [atom&variable-3 > hello]");
  294. MT("listCode",
  295. "[variable-2 * foo]",
  296. "",
  297. " [variable-3 + bar]",
  298. "",
  299. " [comment hello]");
  300. // Code with internal indentation
  301. MT("listCodeIndentation",
  302. "[variable-2 * foo]",
  303. "",
  304. " [comment bar]",
  305. " [comment hello]",
  306. " [comment world]",
  307. " [comment foo]",
  308. " [variable-2 bar]");
  309. // List nesting edge cases
  310. MT("listNested",
  311. "[variable-2 * foo]",
  312. "",
  313. " [variable-3 * bar]",
  314. "",
  315. " [variable-2 hello]"
  316. );
  317. MT("listNested",
  318. "[variable-2 * foo]",
  319. "",
  320. " [variable-3 * bar]",
  321. "",
  322. " [variable-3 * foo]"
  323. );
  324. // Code followed by text
  325. MT("listCodeText",
  326. "[variable-2 * foo]",
  327. "",
  328. " [comment bar]",
  329. "",
  330. "hello");
  331. // Following tests directly from official Markdown documentation
  332. // http://daringfireball.net/projects/markdown/syntax#hr
  333. MT("hrSpace",
  334. "[hr * * *]");
  335. MT("hr",
  336. "[hr ***]");
  337. MT("hrLong",
  338. "[hr *****]");
  339. MT("hrSpaceDash",
  340. "[hr - - -]");
  341. MT("hrDashLong",
  342. "[hr ---------------------------------------]");
  343. // Inline link with title
  344. MT("linkTitle",
  345. "[link [[foo]]][string (http://example.com/ \"bar\")] hello");
  346. // Inline link without title
  347. MT("linkNoTitle",
  348. "[link [[foo]]][string (http://example.com/)] bar");
  349. // Inline link with image
  350. MT("linkImage",
  351. "[link [[][tag ![[foo]]][string (http://example.com/)][link ]]][string (http://example.com/)] bar");
  352. // Inline link with Em
  353. MT("linkEm",
  354. "[link [[][link&em *foo*][link ]]][string (http://example.com/)] bar");
  355. // Inline link with Strong
  356. MT("linkStrong",
  357. "[link [[][link&strong **foo**][link ]]][string (http://example.com/)] bar");
  358. // Inline link with EmStrong
  359. MT("linkEmStrong",
  360. "[link [[][link&strong **][link&em&strong *foo**][link&em *][link ]]][string (http://example.com/)] bar");
  361. // Image with title
  362. MT("imageTitle",
  363. "[tag ![[foo]]][string (http://example.com/ \"bar\")] hello");
  364. // Image without title
  365. MT("imageNoTitle",
  366. "[tag ![[foo]]][string (http://example.com/)] bar");
  367. // Image with asterisks
  368. MT("imageAsterisks",
  369. "[tag ![[*foo*]]][string (http://example.com/)] bar");
  370. // Not a link. Should be normal text due to square brackets being used
  371. // regularly in text, especially in quoted material, and no space is allowed
  372. // between square brackets and parentheses (per Dingus).
  373. MT("notALink",
  374. "[[foo]] (bar)");
  375. // Reference-style links
  376. MT("linkReference",
  377. "[link [[foo]]][string [[bar]]] hello");
  378. // Reference-style links with Em
  379. MT("linkReferenceEm",
  380. "[link [[][link&em *foo*][link ]]][string [[bar]]] hello");
  381. // Reference-style links with Strong
  382. MT("linkReferenceStrong",
  383. "[link [[][link&strong **foo**][link ]]][string [[bar]]] hello");
  384. // Reference-style links with EmStrong
  385. MT("linkReferenceEmStrong",
  386. "[link [[][link&strong **][link&em&strong *foo**][link&em *][link ]]][string [[bar]]] hello");
  387. // Reference-style links with optional space separator (per docuentation)
  388. // "You can optionally use a space to separate the sets of brackets"
  389. MT("linkReferenceSpace",
  390. "[link [[foo]]] [string [[bar]]] hello");
  391. // Should only allow a single space ("...use *a* space...")
  392. MT("linkReferenceDoubleSpace",
  393. "[[foo]] [[bar]] hello");
  394. // Reference-style links with implicit link name
  395. MT("linkImplicit",
  396. "[link [[foo]]][string [[]]] hello");
  397. // @todo It would be nice if, at some point, the document was actually
  398. // checked to see if the referenced link exists
  399. // Link label, for reference-style links (taken from documentation)
  400. MT("labelNoTitle",
  401. "[link [[foo]]:] [string http://example.com/]");
  402. MT("labelIndented",
  403. " [link [[foo]]:] [string http://example.com/]");
  404. MT("labelSpaceTitle",
  405. "[link [[foo bar]]:] [string http://example.com/ \"hello\"]");
  406. MT("labelDoubleTitle",
  407. "[link [[foo bar]]:] [string http://example.com/ \"hello\"] \"world\"");
  408. MT("labelTitleDoubleQuotes",
  409. "[link [[foo]]:] [string http://example.com/ \"bar\"]");
  410. MT("labelTitleSingleQuotes",
  411. "[link [[foo]]:] [string http://example.com/ 'bar']");
  412. MT("labelTitleParenthese",
  413. "[link [[foo]]:] [string http://example.com/ (bar)]");
  414. MT("labelTitleInvalid",
  415. "[link [[foo]]:] [string http://example.com/] bar");
  416. MT("labelLinkAngleBrackets",
  417. "[link [[foo]]:] [string <http://example.com/> \"bar\"]");
  418. MT("labelTitleNextDoubleQuotes",
  419. "[link [[foo]]:] [string http://example.com/]",
  420. "[string \"bar\"] hello");
  421. MT("labelTitleNextSingleQuotes",
  422. "[link [[foo]]:] [string http://example.com/]",
  423. "[string 'bar'] hello");
  424. MT("labelTitleNextParenthese",
  425. "[link [[foo]]:] [string http://example.com/]",
  426. "[string (bar)] hello");
  427. MT("labelTitleNextMixed",
  428. "[link [[foo]]:] [string http://example.com/]",
  429. "(bar\" hello");
  430. MT("linkWeb",
  431. "[link <http://example.com/>] foo");
  432. MT("linkEmail",
  433. "[link <user@example.com>] foo");
  434. MT("emAsterisk",
  435. "[em *foo*] bar");
  436. MT("emUnderscore",
  437. "[em _foo_] bar");
  438. MT("emInWordAsterisk",
  439. "foo[em *bar*]hello");
  440. MT("emInWordUnderscore",
  441. "foo[em _bar_]hello");
  442. // Per documentation: "...surround an * or _ with spaces, it’ll be
  443. // treated as a literal asterisk or underscore."
  444. MT("emEscapedBySpaceIn",
  445. "foo [em _bar _ hello_] world");
  446. MT("emEscapedBySpaceOut",
  447. "foo _ bar[em _hello_]world");
  448. // Unclosed emphasis characters
  449. // Instead of simply marking as EM / STRONG, it would be nice to have an
  450. // incomplete flag for EM and STRONG, that is styled slightly different.
  451. MT("emIncompleteAsterisk",
  452. "foo [em *bar]");
  453. MT("emIncompleteUnderscore",
  454. "foo [em _bar]");
  455. MT("strongAsterisk",
  456. "[strong **foo**] bar");
  457. MT("strongUnderscore",
  458. "[strong __foo__] bar");
  459. MT("emStrongAsterisk",
  460. "[em *foo][em&strong **bar*][strong hello**] world");
  461. MT("emStrongUnderscore",
  462. "[em _foo][em&strong __bar_][strong hello__] world");
  463. // "...same character must be used to open and close an emphasis span.""
  464. MT("emStrongMixed",
  465. "[em _foo][em&strong **bar*hello__ world]");
  466. MT("emStrongMixed",
  467. "[em *foo][em&strong __bar_hello** world]");
  468. // These characters should be escaped:
  469. // \ backslash
  470. // ` backtick
  471. // * asterisk
  472. // _ underscore
  473. // {} curly braces
  474. // [] square brackets
  475. // () parentheses
  476. // # hash mark
  477. // + plus sign
  478. // - minus sign (hyphen)
  479. // . dot
  480. // ! exclamation mark
  481. MT("escapeBacktick",
  482. "foo \\`bar\\`");
  483. MT("doubleEscapeBacktick",
  484. "foo \\\\[comment `bar\\\\`]");
  485. MT("escapeAsterisk",
  486. "foo \\*bar\\*");
  487. MT("doubleEscapeAsterisk",
  488. "foo \\\\[em *bar\\\\*]");
  489. MT("escapeUnderscore",
  490. "foo \\_bar\\_");
  491. MT("doubleEscapeUnderscore",
  492. "foo \\\\[em _bar\\\\_]");
  493. MT("escapeHash",
  494. "\\# foo");
  495. MT("doubleEscapeHash",
  496. "\\\\# foo");
  497. // Tests to make sure GFM-specific things aren't getting through
  498. MT("taskList",
  499. "[variable-2 * [ ]] bar]");
  500. MT("fencedCodeBlocks",
  501. "[comment ```]",
  502. "foo",
  503. "[comment ```]");
  504. })();