test.js 16 KB

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