micromark-extension-growi-plugin.test.js 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092
  1. /**
  2. * @typedef {import('../src/micromark-extension-growi-plugin/index.js').HtmlOptions} HtmlOptions
  3. * @typedef {import('../src/micromark-extension-growi-plugin/index.js').Handle} Handle
  4. */
  5. import { htmlVoidElements } from 'html-void-elements';
  6. import { micromark } from 'micromark';
  7. import test from 'tape';
  8. import { DirectiveType } from '../src/mdast-util-growi-plugin/consts.js';
  9. import { directive as syntax, directiveHtml as html } from '../src/micromark-extension-growi-plugin/index.js';
  10. const own = {}.hasOwnProperty;
  11. test('micromark-extension-directive (syntax)', (t) => {
  12. t.test('text', (t) => {
  13. t.equal(
  14. micromark('\\$a', options()),
  15. '<p>$a</p>',
  16. 'should support an escaped colon which would otherwise be a directive',
  17. );
  18. t.equal(
  19. micromark('\\$$a', options()),
  20. '<p>$</p>',
  21. 'should support a directive after an escaped colon',
  22. );
  23. // t.equal(
  24. // micromark('a :$b', options()),
  25. // '<p>a :$b</p>',
  26. // 'should not support a directive after a colon',
  27. // );
  28. t.equal(
  29. micromark('$', options()),
  30. '<p>$</p>',
  31. 'should not support a colon not followed by an alpha',
  32. );
  33. t.equal(
  34. micromark('a $a', options()),
  35. '<p>a </p>',
  36. 'should support a colon followed by an alpha',
  37. );
  38. t.equal(
  39. micromark('$9', options()),
  40. '<p>$9</p>',
  41. 'should not support a colon followed by a digit',
  42. );
  43. t.equal(
  44. micromark('$-', options()),
  45. '<p>$-</p>',
  46. 'should not support a colon followed by a dash',
  47. );
  48. t.equal(
  49. micromark('$_', options()),
  50. '<p>$_</p>',
  51. 'should not support a colon followed by an underscore',
  52. );
  53. t.equal(
  54. micromark('a $a9', options()),
  55. '<p>a </p>',
  56. 'should support a digit in a name',
  57. );
  58. t.equal(
  59. micromark('a $a-b', options()),
  60. '<p>a </p>',
  61. 'should support a dash in a name',
  62. );
  63. t.equal(
  64. micromark('$a-', options()),
  65. '<p>$a-</p>',
  66. 'should *not* support a dash at the end of a name',
  67. );
  68. t.equal(
  69. micromark('a $a_b', options()),
  70. '<p>a </p>',
  71. 'should support an underscore in a name',
  72. );
  73. t.equal(
  74. micromark('$a_', options()),
  75. '<p>$a_</p>',
  76. 'should *not* support an underscore at the end of a name',
  77. );
  78. t.equal(
  79. micromark('$a$', options()),
  80. '<p>$a$</p>',
  81. 'should *not* support a colon right after a name',
  82. );
  83. t.equal(
  84. micromark('_$directive_', options()),
  85. '<p><em>$directive</em></p>',
  86. 'should not interfere w/ emphasis (`_`)',
  87. );
  88. t.equal(
  89. micromark('$a[', options()),
  90. '<p>[</p>',
  91. 'should support a name followed by an unclosed `[`',
  92. );
  93. t.equal(
  94. micromark('$a(', options()),
  95. '<p>(</p>',
  96. 'should support a name followed by an unclosed `{`',
  97. );
  98. t.equal(
  99. micromark('$a[b', options()),
  100. '<p>[b</p>',
  101. 'should support a name followed by an unclosed `[` w/ content',
  102. );
  103. t.equal(
  104. micromark('$a(b', options()),
  105. '<p>(b</p>',
  106. 'should support a name followed by an unclosed `{` w/ content',
  107. );
  108. t.equal(
  109. micromark('a $a[]', options()),
  110. '<p>a </p>',
  111. 'should support an empty label',
  112. );
  113. t.equal(
  114. micromark('a $a[ \t]', options()),
  115. '<p>a </p>',
  116. 'should support a whitespace only label',
  117. );
  118. t.equal(
  119. micromark('$a[\n]', options()),
  120. '<p></p>',
  121. 'should support an eol in an label',
  122. );
  123. t.equal(
  124. micromark('$a[a b c]asd', options()),
  125. '<p>asd</p>',
  126. 'should support content in an label',
  127. );
  128. t.equal(
  129. micromark('$a[a *b* c]asd', options()),
  130. '<p>asd</p>',
  131. 'should support markdown in an label',
  132. );
  133. t.equal(
  134. micromark('a $b[c :d[e] f] g', options()),
  135. '<p>a g</p>',
  136. 'should support a directive in an label',
  137. );
  138. t.equal(
  139. micromark('$a[]asd', options()),
  140. '<p>asd</p>',
  141. 'should support content after a label',
  142. );
  143. t.equal(
  144. micromark('a $a()', options()),
  145. '<p>a </p>',
  146. 'should support empty attributes',
  147. );
  148. t.equal(
  149. micromark('a $a( \t)', options()),
  150. '<p>a </p>',
  151. 'should support whitespace only attributes',
  152. );
  153. t.equal(
  154. micromark('$a(\n)', options()),
  155. '<p></p>',
  156. 'should support an eol in attributes',
  157. );
  158. t.equal(
  159. micromark('a $a(a b c)', options()),
  160. '<p>a </p>',
  161. 'should support attributes w/o values',
  162. );
  163. t.equal(
  164. micromark('a $a(a=b c=d)', options()),
  165. '<p>a </p>',
  166. 'should support attributes w/ unquoted values',
  167. );
  168. t.equal(
  169. micromark('a $a(.a .b)', options()),
  170. '<p>a </p>',
  171. 'should support attributes w/ class shortcut',
  172. );
  173. t.equal(
  174. micromark('a $a(.a.b)', options()),
  175. '<p>a </p>',
  176. 'should support attributes w/ class shortcut w/o whitespace between',
  177. );
  178. t.equal(
  179. micromark('a $a(#a #b)', options()),
  180. '<p>a </p>',
  181. 'should support attributes w/ id shortcut',
  182. );
  183. t.equal(
  184. micromark('a $a(#a#b)', options()),
  185. '<p>a </p>',
  186. 'should support attributes w/ id shortcut w/o whitespace between',
  187. );
  188. t.equal(
  189. micromark('a $a(#a.b.c#d e f=g #h.i.j)', options()),
  190. '<p>a </p>',
  191. 'should support attributes w/ shortcuts combined w/ other attributes',
  192. );
  193. t.equal(
  194. micromark('$a(..b)', options()),
  195. '<p>(..b)</p>',
  196. 'should not support an empty shortcut (`.`)',
  197. );
  198. t.equal(
  199. micromark('$a(.#b)', options()),
  200. '<p>(.#b)</p>',
  201. 'should not support an empty shortcut (`#`)',
  202. );
  203. t.equal(
  204. micromark('$a(.)', options()),
  205. '<p>(.)</p>',
  206. 'should not support an empty shortcut (`}`)',
  207. );
  208. t.equal(
  209. micromark('$a(.a=b)', options()),
  210. '<p>(.a=b)</p>',
  211. 'should not support certain characters in shortcuts (`=`)',
  212. );
  213. t.equal(
  214. micromark('$a(.a"b)', options()),
  215. '<p>(.a&quot;b)</p>',
  216. 'should not support certain characters in shortcuts (`"`)',
  217. );
  218. t.equal(
  219. micromark('$a(.a<b)', options()),
  220. '<p>(.a&lt;b)</p>',
  221. 'should not support certain characters in shortcuts (`<`)',
  222. );
  223. t.equal(
  224. micromark('a $a(.a💚b)', options()),
  225. '<p>a </p>',
  226. 'should support most characters in shortcuts',
  227. );
  228. t.equal(
  229. micromark('a $a(_)', options()),
  230. '<p>a </p>',
  231. 'should support an underscore in attribute names',
  232. );
  233. t.equal(
  234. micromark('a $a(xml:lang)', options()),
  235. '<p>a </p>',
  236. 'should support a colon in attribute names',
  237. );
  238. t.equal(
  239. micromark('a $a(a="b" c="d e f")', options()),
  240. '<p>a </p>',
  241. 'should support double quoted attributes',
  242. );
  243. t.equal(
  244. micromark("a $a(a='b' c='d e f')", options()),
  245. '<p>a </p>',
  246. 'should support single quoted attributes',
  247. );
  248. t.equal(
  249. micromark('a $a(a = b c\t=\t\'d\' f =\r"g")', options()),
  250. '<p>a </p>',
  251. 'should support whitespace around initializers',
  252. );
  253. t.equal(
  254. micromark('$a(b==)', options()),
  255. '<p>(b==)</p>',
  256. 'should not support `=` to start an unquoted attribute value',
  257. );
  258. t.equal(
  259. micromark('$a(b=)', options()),
  260. '<p>(b=)</p>',
  261. 'should not support a missing attribute value after `=`',
  262. );
  263. t.equal(
  264. micromark("$a(b=c')", options()),
  265. "<p>(b=c')</p>",
  266. 'should not support an apostrophe in an unquoted attribute value',
  267. );
  268. t.equal(
  269. micromark('$a(b=c`)', options()),
  270. '<p>(b=c`)</p>',
  271. 'should not support a grave accent in an unquoted attribute value',
  272. );
  273. t.equal(
  274. micromark('a $a(b=a💚b)', options()),
  275. '<p>a </p>',
  276. 'should support most other characters in unquoted attribute values',
  277. );
  278. t.equal(
  279. micromark('$a(b="c', options()),
  280. '<p>(b=&quot;c</p>',
  281. 'should not support an EOF in a quoted attribute value',
  282. );
  283. t.equal(
  284. micromark('a $a(b="a💚b")', options()),
  285. '<p>a </p>',
  286. 'should support most other characters in quoted attribute values',
  287. );
  288. t.equal(
  289. micromark('$a(b="\nc\r d")', options()),
  290. '<p></p>',
  291. 'should support EOLs in quoted attribute values',
  292. );
  293. t.equal(
  294. micromark('$a(b="c"', options()),
  295. '<p>(b=&quot;c&quot;</p>',
  296. 'should not support an EOF after a quoted attribute value',
  297. );
  298. t.end();
  299. });
  300. t.test('leaf', (t) => {
  301. t.equal(micromark('$b', options()), '', 'should support a directive');
  302. t.equal(
  303. micromark(':', options()),
  304. '<p>:</p>',
  305. 'should not support one colon',
  306. );
  307. t.equal(
  308. micromark('::', options()),
  309. '<p>::</p>',
  310. 'should not support two colons not followed by an alpha',
  311. );
  312. t.equal(
  313. micromark('$a', options()),
  314. '',
  315. 'should support two colons followed by an alpha',
  316. );
  317. t.equal(
  318. micromark('$9', options()),
  319. '<p>$9</p>',
  320. 'should not support two colons followed by a digit',
  321. );
  322. t.equal(
  323. micromark('$-', options()),
  324. '<p>$-</p>',
  325. 'should not support two colons followed by a dash',
  326. );
  327. t.equal(
  328. micromark('$a9', options()),
  329. '',
  330. 'should support a digit in a name',
  331. );
  332. t.equal(
  333. micromark('$a-b', options()),
  334. '',
  335. 'should support a dash in a name',
  336. );
  337. // == Resolved as text directive
  338. // t.equal(
  339. // micromark('$a[', options()),
  340. // '<p>$a[</p>',
  341. // 'should not support a name followed by an unclosed `[`',
  342. // );
  343. // == Resolved as text directive
  344. // t.equal(
  345. // micromark('$a{', options()),
  346. // '<p>$a{</p>',
  347. // 'should not support a name followed by an unclosed `{`',
  348. // );
  349. // == Resolved as text directive
  350. // t.equal(
  351. // micromark('$a[b', options()),
  352. // '<p>$a[b</p>',
  353. // 'should not support a name followed by an unclosed `[` w/ content',
  354. // );
  355. // == Resolved as text directive
  356. // t.equal(
  357. // micromark('$a{b', options()),
  358. // '<p>$a{b</p>',
  359. // 'should not support a name followed by an unclosed `{` w/ content',
  360. // );
  361. t.equal(micromark('$a[]', options()), '', 'should support an empty label');
  362. t.equal(
  363. micromark('$a[ \t]', options()),
  364. '',
  365. 'should support a whitespace only label',
  366. );
  367. // == Resolved as text directive
  368. // t.equal(
  369. // micromark('$a[\n]', options()),
  370. // '<p>$a[\n]</p>',
  371. // 'should not support an eol in an label',
  372. // );
  373. t.equal(
  374. micromark('$a[a b c]', options()),
  375. '',
  376. 'should support content in an label',
  377. );
  378. t.equal(
  379. micromark('$a[a *b* c]', options()),
  380. '',
  381. 'should support markdown in an label',
  382. );
  383. // == Resolved as text directive
  384. // t.equal(
  385. // micromark('$a[]asd', options()),
  386. // '<p>$a[]asd</p>',
  387. // 'should not support content after a label',
  388. // );
  389. t.equal(
  390. micromark('$a()', options()),
  391. '',
  392. 'should support empty attributes',
  393. );
  394. t.equal(
  395. micromark('$a( \t)', options()),
  396. '',
  397. 'should support whitespace only attributes',
  398. );
  399. // == Resolved as text directive
  400. // t.equal(
  401. // micromark('$a(\n)', options()),
  402. // '<p>$a(\n)</p>',
  403. // 'should not support an eol in attributes',
  404. // );
  405. t.equal(
  406. micromark('$a(a b c)', options()),
  407. '',
  408. 'should support attributes w/o values',
  409. );
  410. t.equal(
  411. micromark('$a(a=b c=d)', options()),
  412. '',
  413. 'should support attributes w/ unquoted values',
  414. );
  415. t.equal(
  416. micromark('$a(.a .b)', options()),
  417. '',
  418. 'should support attributes w/ class shortcut',
  419. );
  420. t.equal(
  421. micromark('$a(#a #b)', options()),
  422. '',
  423. 'should support attributes w/ id shortcut',
  424. );
  425. t.equal(
  426. micromark('$a(.a💚b)', options()),
  427. '',
  428. 'should support most characters in shortcuts',
  429. );
  430. t.equal(
  431. micromark('$a(a="b" c="d e f")', options()),
  432. '',
  433. 'should support double quoted attributes',
  434. );
  435. t.equal(
  436. micromark("$a(a='b' c='d e f')", options()),
  437. '',
  438. 'should support single quoted attributes',
  439. );
  440. t.equal(
  441. micromark("$a(a = b c\t=\t'd')", options()),
  442. '',
  443. 'should support whitespace around initializers',
  444. );
  445. // == Resolved as text directive
  446. // t.equal(
  447. // micromark('$a(f =\rg)', options()),
  448. // '<p>$a(f =\rg)</p>',
  449. // 'should not support EOLs around initializers',
  450. // );
  451. // == Resolved as text directive
  452. // t.equal(
  453. // micromark('$a(b==)', options()),
  454. // '<p>$a(b==)</p>',
  455. // 'should not support `=` to start an unquoted attribute value',
  456. // );
  457. t.equal(
  458. micromark('$a(b=a💚b)', options()),
  459. '',
  460. 'should support most other characters in unquoted attribute values',
  461. );
  462. // == Resolved as text directive
  463. // t.equal(
  464. // micromark('$a(b="c', options()),
  465. // '<p>$a(b=&quot;c</p>',
  466. // 'should not support an EOF in a quoted attribute value',
  467. // );
  468. t.equal(
  469. micromark('$a(b="a💚b")', options()),
  470. '',
  471. 'should support most other characters in quoted attribute values',
  472. );
  473. // == Resolved as text directive
  474. // t.equal(
  475. // micromark('$a(b="\nc\r d")', options()),
  476. // '<p>$a(b=&quot;\nc\rd&quot;)</p>',
  477. // 'should not support EOLs in quoted attribute values',
  478. // );
  479. // t.equal(
  480. // micromark('$a(b="c"', options()),
  481. // '<p>$a(b=&quot;c&quot;</p>',
  482. // 'should not support an EOF after a quoted attribute value',
  483. // );
  484. t.equal(
  485. micromark('$a(b=c) \t ', options()),
  486. '',
  487. 'should support whitespace after directives',
  488. );
  489. t.equal(
  490. micromark('$a(b=c)\n>a', options()),
  491. '<blockquote>\n<p>a</p>\n</blockquote>',
  492. 'should support a block quote after a leaf',
  493. );
  494. t.equal(
  495. micromark('$a(b=c)\n```js\na', options()),
  496. '<pre><code class="language-js">a\n</code></pre>\n',
  497. 'should support code (fenced) after a leaf',
  498. );
  499. t.equal(
  500. micromark('$a(b=c)\n a', options()),
  501. '<pre><code>a\n</code></pre>',
  502. 'should support code (indented) after a leaf',
  503. );
  504. t.equal(
  505. micromark('$a(b=c)\n[a]: b', options()),
  506. '',
  507. 'should support a definition after a leaf',
  508. );
  509. t.equal(
  510. micromark('$a(b=c)\n# a', options()),
  511. '<h1>a</h1>',
  512. 'should support a heading (atx) after a leaf',
  513. );
  514. t.equal(
  515. micromark('$a(b=c)\na\n=', options()),
  516. '<h1>a</h1>',
  517. 'should support a heading (setext) after a leaf',
  518. );
  519. t.equal(
  520. micromark('$a(b=c)\n<!-->', options()),
  521. '<!-->',
  522. 'should support html after a leaf',
  523. );
  524. t.equal(
  525. micromark('$a(b=c)\n* a', options()),
  526. '<ul>\n<li>a</li>\n</ul>',
  527. 'should support a list after a leaf',
  528. );
  529. t.equal(
  530. micromark('$a(b=c)\na', options()),
  531. '<p>a</p>',
  532. 'should support a paragraph after a leaf',
  533. );
  534. t.equal(
  535. micromark('$a(b=c)\n***', options()),
  536. '<hr />',
  537. 'should support a thematic break after a leaf',
  538. );
  539. t.equal(
  540. micromark('>a\n$a(b=c)', options()),
  541. '<blockquote>\n<p>a</p>\n</blockquote>\n',
  542. 'should support a block quote before a leaf',
  543. );
  544. t.equal(
  545. micromark('```js\na\n```\n$a(b=c)', options()),
  546. '<pre><code class="language-js">a\n</code></pre>\n',
  547. 'should support code (fenced) before a leaf',
  548. );
  549. t.equal(
  550. micromark(' a\n$a(b=c)', options()),
  551. '<pre><code>a\n</code></pre>\n',
  552. 'should support code (indented) before a leaf',
  553. );
  554. t.equal(
  555. micromark('[a]: b\n$a(b=c)', options()),
  556. '',
  557. 'should support a definition before a leaf',
  558. );
  559. t.equal(
  560. micromark('# a\n$a(b=c)', options()),
  561. '<h1>a</h1>\n',
  562. 'should support a heading (atx) before a leaf',
  563. );
  564. t.equal(
  565. micromark('a\n=\n$a(b=c)', options()),
  566. '<h1>a</h1>\n',
  567. 'should support a heading (setext) before a leaf',
  568. );
  569. t.equal(
  570. micromark('<!-->\n$a(b=c)', options()),
  571. '<!-->\n',
  572. 'should support html before a leaf',
  573. );
  574. t.equal(
  575. micromark('* a\n$a(b=c)', options()),
  576. '<ul>\n<li>a</li>\n</ul>\n',
  577. 'should support a list before a leaf',
  578. );
  579. t.equal(
  580. micromark('a\n$a(b=c)', options()),
  581. '<p>a</p>\n',
  582. 'should support a paragraph before a leaf',
  583. );
  584. t.equal(
  585. micromark('***\n$a(b=c)', options()),
  586. '<hr />\n',
  587. 'should support a thematic break before a leaf',
  588. );
  589. t.equal(
  590. micromark('> $a\nb', options({ '*': h })),
  591. '<blockquote><a></a>\n</blockquote>\n<p>b</p>',
  592. 'should not support lazyness (1)',
  593. );
  594. t.equal(
  595. micromark('> a\n$b', options({ '*': h })),
  596. '<blockquote>\n<p>a</p>\n</blockquote>\n<b></b>',
  597. 'should not support lazyness (2)',
  598. );
  599. t.end();
  600. });
  601. t.end();
  602. });
  603. test('micromark-extension-directive (compile)', (t) => {
  604. t.equal(
  605. micromark(
  606. [
  607. 'a $abbr',
  608. 'a $abbr[HTML]',
  609. 'a $abbr(title="HyperText Markup Language")',
  610. 'a $abbr[HTML](title="HyperText Markup Language")',
  611. ].join('\n\n'),
  612. options({ abbr }),
  613. ),
  614. [
  615. '<p>a <abbr></abbr></p>',
  616. '<p>a <abbr>HTML</abbr></p>',
  617. '<p>a <abbr title="HyperText Markup Language"></abbr></p>',
  618. '<p>a <abbr title="HyperText Markup Language">HTML</abbr></p>',
  619. ].join('\n'),
  620. 'should support a directives (abbr)',
  621. );
  622. t.equal(
  623. micromark(
  624. [
  625. 'Text:',
  626. 'a $youtube',
  627. 'a $youtube[Cat in a box a]',
  628. 'a $youtube(v=1)',
  629. 'a $youtube[Cat in a box b](v=2)',
  630. 'Leaf:',
  631. '$youtube',
  632. '$youtube[Cat in a box c]',
  633. '$youtube(v=3)',
  634. '$youtube[Cat in a box d](v=4)',
  635. ].join('\n\n'),
  636. options({ youtube }),
  637. ),
  638. [
  639. '<p>Text:</p>',
  640. '<p>a </p>',
  641. '<p>a </p>',
  642. '<p>a <iframe src="https://www.youtube.com/embed/1" allowfullscreen></iframe></p>',
  643. '<p>a <iframe src="https://www.youtube.com/embed/2" allowfullscreen title="Cat in a box b"></iframe></p>',
  644. '<p>Leaf:</p>',
  645. '<iframe src="https://www.youtube.com/embed/3" allowfullscreen></iframe>',
  646. '<iframe src="https://www.youtube.com/embed/4" allowfullscreen title="Cat in a box d"></iframe>',
  647. ].join('\n'),
  648. 'should support directives (youtube)',
  649. );
  650. t.equal(
  651. micromark('a $youtube[Cat in a box]\n$br a', options({ youtube, '*': h })),
  652. '<p>a <youtube>Cat in a box</youtube>\n<br> a</p>',
  653. 'should support fall through directives (`*`)',
  654. );
  655. t.equal(
  656. micromark('a $a[$img(src="x" alt=y)](href="z")', options({ '*': h })),
  657. '<p>a <a href="z"><img src="x" alt="y"></a></p>',
  658. 'should support fall through directives (`*`)',
  659. );
  660. t.end();
  661. });
  662. test('content', (t) => {
  663. t.equal(
  664. micromark('a $abbr[x\\&y&amp;z]', options({ abbr })),
  665. '<p>a <abbr>x&amp;y&amp;z</abbr></p>',
  666. 'should support character escapes and character references in label',
  667. );
  668. t.equal(
  669. micromark('a $abbr[x\\[y\\]z]', options({ abbr })),
  670. '<p>a <abbr>x[y]z</abbr></p>',
  671. 'should support escaped brackets in a label',
  672. );
  673. t.equal(
  674. micromark('a $abbr[x[y]z]', options({ abbr })),
  675. '<p>a <abbr>x[y]z</abbr></p>',
  676. 'should support balanced brackets in a label',
  677. );
  678. t.equal(
  679. micromark(
  680. 'a $abbr[1[2[3[4[5[6[7[8[9[10[11[12[13[14[15[16[17[18[19[20[21[22[23[24[25[26[27[28[29[30[31[32[x]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]',
  681. options({ abbr }),
  682. ),
  683. '<p>a <abbr>1[2[3[4[5[6[7[8[9[10[11[12[13[14[15[16[17[18[19[20[21[22[23[24[25[26[27[28[29[30[31[32[x]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]</abbr></p>',
  684. 'should support balanced brackets in a label, 32 levels deep',
  685. );
  686. t.equal(
  687. micromark(
  688. '$abbr[1[2[3[4[5[6[7[8[9[10[11[12[13[14[15[16[17[18[19[20[21[22[23[24[25[26[27[28[29[30[31[32[33[x]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]',
  689. options({ abbr }),
  690. ),
  691. '<p><abbr></abbr>[1[2[3[4[5[6[7[8[9[10[11[12[13[14[15[16[17[18[19[20[21[22[23[24[25[26[27[28[29[30[31[32[33[x]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]</p>',
  692. 'should *not* support balanced brackets in a label, 33 levels deep',
  693. );
  694. t.equal(
  695. micromark('$abbr[a\nb\rc]', options({ abbr })),
  696. '<p><abbr>a\nb\rc</abbr></p>',
  697. 'should support EOLs in a label',
  698. );
  699. t.equal(
  700. micromark('$abbr[\na\r]', options({ abbr })),
  701. '<p><abbr>\na\r</abbr></p>',
  702. 'should support EOLs at the edges of a label (1)',
  703. );
  704. t.equal(
  705. micromark('$abbr[\n]', options({ abbr })),
  706. '<p><abbr>\n</abbr></p>',
  707. 'should support EOLs at the edges of a label (2)',
  708. );
  709. // == does not work but I don't know why.. -- 2022.08.12 Yuki Takei
  710. // t.equal(
  711. // micromark('$abbr[a\n$abbr[b]\nc]', options({ abbr })),
  712. // '<p>a <abbr>a\n<abbr>b</abbr>\nc</abbr> a</p>',
  713. // 'should support EOLs around nested directives',
  714. // );
  715. t.equal(
  716. micromark('$abbr[$abbr[\n]]', options({ abbr })),
  717. '<p><abbr><abbr>\n</abbr></abbr></p>',
  718. 'should support EOLs inside nested directives (1)',
  719. );
  720. t.equal(
  721. micromark('$abbr[$abbr[a\nb]]', options({ abbr })),
  722. '<p><abbr><abbr>a\nb</abbr></abbr></p>',
  723. 'should support EOLs inside nested directives (2)',
  724. );
  725. t.equal(
  726. micromark('$abbr[$abbr[\nb\n]]', options({ abbr })),
  727. '<p><abbr><abbr>\nb\n</abbr></abbr></p>',
  728. 'should support EOLs inside nested directives (3)',
  729. );
  730. t.equal(
  731. micromark('$abbr[$abbr[\\\n]]', options({ abbr })),
  732. '<p><abbr><abbr><br />\n</abbr></abbr></p>',
  733. 'should support EOLs inside nested directives (4)',
  734. );
  735. t.equal(
  736. micromark('a $abbr[a *b* **c** d]', options({ abbr })),
  737. '<p>a <abbr>a <em>b</em> <strong>c</strong> d</abbr></p>',
  738. 'should support markdown in a label',
  739. );
  740. t.equal(
  741. micromark('a $abbr(title=a&apos;b)', options({ abbr })),
  742. '<p>a <abbr title="a\'b"></abbr></p>',
  743. 'should support character references in unquoted attribute values',
  744. );
  745. t.equal(
  746. micromark('a $abbr(title="a&apos;b")', options({ abbr })),
  747. '<p>a <abbr title="a\'b"></abbr></p>',
  748. 'should support character references in double attribute values',
  749. );
  750. t.equal(
  751. micromark("a $abbr(title='a&apos;b')", options({ abbr })),
  752. '<p>a <abbr title="a\'b"></abbr></p>',
  753. 'should support character references in single attribute values',
  754. );
  755. t.equal(
  756. micromark('a $abbr(title="a&somethingelse;b")', options({ abbr })),
  757. '<p>a <abbr title="a&amp;somethingelse;b"></abbr></p>',
  758. 'should support unknown character references in attribute values',
  759. );
  760. t.equal(
  761. micromark('$span(a\nb)', options({ '*': h })),
  762. '<p><span a="" b=""></span></p>',
  763. 'should support EOLs between attributes',
  764. );
  765. t.equal(
  766. micromark('$span(\na\n)', options({ '*': h })),
  767. '<p><span a=""></span></p>',
  768. 'should support EOLs at the edges of attributes',
  769. );
  770. t.equal(
  771. micromark('$span(a\r= b)', options({ '*': h })),
  772. '<p><span a="b"></span></p>',
  773. 'should support EOLs before initializer',
  774. );
  775. t.equal(
  776. micromark('$span(a=\r\nb)', options({ '*': h })),
  777. '<p><span a="b"></span></p>',
  778. 'should support EOLs after initializer',
  779. );
  780. t.equal(
  781. micromark('$span(a=b\nc)', options({ '*': h })),
  782. '<p><span a="b" c=""></span></p>',
  783. 'should support EOLs between an unquoted attribute value and a next attribute name',
  784. );
  785. t.equal(
  786. micromark('$span(a="b\nc")', options({ '*': h })),
  787. '<p><span a="b\nc"></span></p>',
  788. 'should support EOLs in a double quoted attribute value',
  789. );
  790. t.equal(
  791. micromark("$span(a='b\nc')", options({ '*': h })),
  792. '<p><span a="b\nc"></span></p>',
  793. 'should support EOLs in a single quoted attribute value',
  794. );
  795. t.equal(
  796. micromark('a $span(#a#b)', options({ '*': h })),
  797. '<p>a <span id="b"></span></p>',
  798. 'should support `id` shortcuts',
  799. );
  800. t.equal(
  801. micromark('a $span(id=a id="b" #c#d)', options({ '*': h })),
  802. '<p>a <span id="d"></span></p>',
  803. 'should support `id` shortcuts after `id` attributes',
  804. );
  805. t.equal(
  806. micromark('a $span(.a.b)', options({ '*': h })),
  807. '<p>a <span class="a b"></span></p>',
  808. 'should support `class` shortcuts',
  809. );
  810. t.equal(
  811. micromark('a $span(class=a class="b c" .d.e)', options({ '*': h })),
  812. '<p>a <span class="a b c d e"></span></p>',
  813. 'should support `class` shortcuts after `class` attributes',
  814. );
  815. t.test('spec for growi plugin', (t) => {
  816. t.equal(
  817. micromark('a $lsx(/Sandbox)', options()),
  818. '<p>a </p>',
  819. 'should support name with slash',
  820. );
  821. t.equal(
  822. micromark('a $lsx(key=value, reverse)', options()),
  823. '<p>a </p>',
  824. 'should support name=value and an attribute w/o value',
  825. );
  826. t.equal(
  827. micromark('a $lsx(key=value, reverse, reverse2)', options()),
  828. '<p>a </p>',
  829. 'should support consecutive attributes w/o value',
  830. );
  831. t.equal(
  832. micromark('a $lsx(/Sandbox, key=value, reverse)', options()),
  833. '<p>a </p>',
  834. 'should support name=value after an empty value attribute',
  835. );
  836. t.end();
  837. });
  838. t.end();
  839. });
  840. /** @type {Handle} */
  841. function abbr(d) {
  842. if (d.type !== DirectiveType.Text) return false;
  843. this.tag('<abbr');
  844. if (d.attributes && 'title' in d.attributes) {
  845. this.tag(` title="${this.encode(d.attributes.title)}"`);
  846. }
  847. this.tag('>');
  848. this.raw(d.label || '');
  849. this.tag('</abbr>');
  850. }
  851. /** @type {Handle} */
  852. function youtube(d) {
  853. const attrs = d.attributes || {};
  854. const v = attrs.v;
  855. /** @type {string} */
  856. let prop;
  857. if (!v) return false;
  858. const list = [
  859. `src="https://www.youtube.com/embed/${this.encode(v)}"`,
  860. 'allowfullscreen',
  861. ];
  862. if (d.label) {
  863. list.push(`title="${this.encode(d.label)}"`);
  864. }
  865. // eslint-disable-next-line no-restricted-syntax
  866. for (prop in attrs) {
  867. if (prop !== 'v') {
  868. list.push(`${this.encode(prop)}="${this.encode(attrs[prop])}"`);
  869. }
  870. }
  871. this.tag(`<iframe ${list.join(' ')}>`);
  872. if (d.content) {
  873. this.lineEndingIfNeeded();
  874. this.raw(d.content);
  875. this.lineEndingIfNeeded();
  876. }
  877. this.tag('</iframe>');
  878. }
  879. /** @type {Handle} */
  880. function h(d) {
  881. const content = d.content || d.label;
  882. const attrs = d.attributes || {};
  883. /** @type {Array.<string>} */
  884. const list = [];
  885. /** @type {string} */
  886. let prop;
  887. // eslint-disable-next-line no-restricted-syntax
  888. for (prop in attrs) {
  889. if (own.call(attrs, prop)) {
  890. list.push(`${this.encode(prop)}="${this.encode(attrs[prop])}"`);
  891. }
  892. }
  893. this.tag(`<${d.name}`);
  894. if (list.length > 0) this.tag(` ${list.join(' ')}`);
  895. this.tag('>');
  896. if (content) {
  897. if (d.type === 'containerGrowiPluginDirective') this.lineEndingIfNeeded();
  898. this.raw(content);
  899. if (d.type === 'containerGrowiPluginDirective') this.lineEndingIfNeeded();
  900. }
  901. if (!htmlVoidElements.includes(d.name)) this.tag(`</${d.name}>`);
  902. }
  903. /**
  904. * @param {HtmlOptions} [options]
  905. */
  906. function options(options) {
  907. return {
  908. allowDangerousHtml: true,
  909. extensions: [syntax()],
  910. htmlExtensions: [html(options)],
  911. };
  912. }