micromark-extension-growi-directive.test.js 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161
  1. /**
  2. * @typedef {import('../src/micromark-extension-growi-directive/index.js').HtmlOptions} HtmlOptions
  3. * @typedef {import('../src/micromark-extension-growi-directive/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-directive/consts.js';
  9. import { directive as syntax, directiveHtml as html } from '../src/micromark-extension-growi-directive/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 $a(..b)', options()),
  195. '<p>a </p>',
  196. 'should support attrs which starts w/ continuous dots',
  197. );
  198. t.equal(
  199. micromark('a $a(.#b)', options()),
  200. '<p>a </p>',
  201. 'should support attrs which start w/ `#`',
  202. );
  203. t.equal(
  204. micromark('a $a(.)', options()),
  205. '<p>a </p>',
  206. 'should support attrs w/ (`.`)',
  207. );
  208. t.equal(
  209. micromark('a $a(.a=b)', options()),
  210. '<p>a </p>',
  211. 'should support with the attr `(.a=b)`',
  212. );
  213. t.equal(
  214. micromark('a $a(.a"b)', options()),
  215. '<p>a </p>',
  216. 'should support with the attr `(.a"b)`',
  217. );
  218. t.equal(
  219. micromark('a $a(.a<b)', options()),
  220. '<p>a </p>',
  221. 'should support with the attr `(.a<b)`',
  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 attribute keys',
  277. );
  278. t.equal(
  279. micromark('a $a(b=a💚b)', options()),
  280. '<p>a </p>',
  281. 'should support most other characters in unquoted attribute values',
  282. );
  283. t.equal(
  284. micromark('$a(b="c', options()),
  285. '<p>(b=&quot;c</p>',
  286. 'should not support an EOF in a quoted attribute value',
  287. );
  288. t.equal(
  289. micromark('a $a(b="a💚b")', options()),
  290. '<p>a </p>',
  291. 'should support most other characters in quoted attribute values',
  292. );
  293. t.equal(
  294. micromark('$a(b="\nc\r d")', options()),
  295. '<p></p>',
  296. 'should support EOLs in quoted attribute values',
  297. );
  298. t.equal(
  299. micromark('$a(b="c"', options()),
  300. '<p>(b=&quot;c&quot;</p>',
  301. 'should not support an EOF after a quoted attribute value',
  302. );
  303. t.end();
  304. });
  305. t.test('leaf', (t) => {
  306. t.equal(micromark('$b', options()), '', 'should support a directive');
  307. t.equal(
  308. micromark(':', options()),
  309. '<p>:</p>',
  310. 'should not support one colon',
  311. );
  312. t.equal(
  313. micromark('::', options()),
  314. '<p>::</p>',
  315. 'should not support two colons not followed by an alpha',
  316. );
  317. t.equal(
  318. micromark('$a', options()),
  319. '',
  320. 'should support two colons followed by an alpha',
  321. );
  322. t.equal(
  323. micromark('$9', options()),
  324. '<p>$9</p>',
  325. 'should not support two colons followed by a digit',
  326. );
  327. t.equal(
  328. micromark('$-', options()),
  329. '<p>$-</p>',
  330. 'should not support two colons followed by a dash',
  331. );
  332. t.equal(
  333. micromark('$a9', options()),
  334. '',
  335. 'should support a digit in a name',
  336. );
  337. t.equal(
  338. micromark('$a-b', options()),
  339. '',
  340. 'should support a dash in a name',
  341. );
  342. // == Resolved as text directive
  343. // t.equal(
  344. // micromark('$a[', options()),
  345. // '<p>$a[</p>',
  346. // 'should not support a name followed by an unclosed `[`',
  347. // );
  348. // == Resolved as text directive
  349. // t.equal(
  350. // micromark('$a{', options()),
  351. // '<p>$a{</p>',
  352. // 'should not support a name followed by an unclosed `{`',
  353. // );
  354. // == Resolved as text directive
  355. // t.equal(
  356. // micromark('$a[b', options()),
  357. // '<p>$a[b</p>',
  358. // 'should not support a name followed by an unclosed `[` w/ content',
  359. // );
  360. // == Resolved as text directive
  361. // t.equal(
  362. // micromark('$a{b', options()),
  363. // '<p>$a{b</p>',
  364. // 'should not support a name followed by an unclosed `{` w/ content',
  365. // );
  366. t.equal(micromark('$a[]', options()), '', 'should support an empty label');
  367. t.equal(
  368. micromark('$a[ \t]', options()),
  369. '',
  370. 'should support a whitespace only label',
  371. );
  372. // == Resolved as text directive
  373. // t.equal(
  374. // micromark('$a[\n]', options()),
  375. // '<p>$a[\n]</p>',
  376. // 'should not support an eol in an label',
  377. // );
  378. t.equal(
  379. micromark('$a[a b c]', options()),
  380. '',
  381. 'should support content in an label',
  382. );
  383. t.equal(
  384. micromark('$a[a *b* c]', options()),
  385. '',
  386. 'should support markdown in an label',
  387. );
  388. // == Resolved as text directive
  389. // t.equal(
  390. // micromark('$a[]asd', options()),
  391. // '<p>$a[]asd</p>',
  392. // 'should not support content after a label',
  393. // );
  394. t.equal(
  395. micromark('$a()', options()),
  396. '',
  397. 'should support empty attributes',
  398. );
  399. t.equal(
  400. micromark('$a( \t)', options()),
  401. '',
  402. 'should support whitespace only attributes',
  403. );
  404. // == Resolved as text directive
  405. // t.equal(
  406. // micromark('$a(\n)', options()),
  407. // '<p>$a(\n)</p>',
  408. // 'should not support an eol in attributes',
  409. // );
  410. t.equal(
  411. micromark('$a(a b c)', options()),
  412. '',
  413. 'should support attributes w/o values',
  414. );
  415. t.equal(
  416. micromark('$a(a=b c=d)', options()),
  417. '',
  418. 'should support attributes w/ unquoted values',
  419. );
  420. t.equal(
  421. micromark('$a(.a .b)', options()),
  422. '',
  423. 'should support attributes w/ class shortcut',
  424. );
  425. t.equal(
  426. micromark('$a(#a #b)', options()),
  427. '',
  428. 'should support attributes w/ id shortcut',
  429. );
  430. t.equal(
  431. micromark('$a(.a💚b)', options()),
  432. '',
  433. 'should support most characters in shortcuts',
  434. );
  435. t.equal(
  436. micromark('$a(a="b" c="d e f")', options()),
  437. '',
  438. 'should support double quoted attributes',
  439. );
  440. t.equal(
  441. micromark("$a(a='b' c='d e f')", options()),
  442. '',
  443. 'should support single quoted attributes',
  444. );
  445. t.equal(
  446. micromark("$a(a = b c\t=\t'd')", options()),
  447. '',
  448. 'should support whitespace around initializers',
  449. );
  450. // == Resolved as text directive
  451. // t.equal(
  452. // micromark('$a(f =\rg)', options()),
  453. // '<p>$a(f =\rg)</p>',
  454. // 'should not support EOLs around initializers',
  455. // );
  456. // == Resolved as text directive
  457. // t.equal(
  458. // micromark('$a(b==)', options()),
  459. // '<p>$a(b==)</p>',
  460. // 'should not support `=` to start an unquoted attribute value',
  461. // );
  462. t.equal(
  463. micromark('$a(b💚=a💚b)', options()),
  464. '',
  465. 'should support most other characters in attribute keys',
  466. );
  467. t.equal(
  468. micromark('$a(b=a💚b)', options()),
  469. '',
  470. 'should support most other characters in unquoted attribute values',
  471. );
  472. // == Resolved as text directive
  473. // t.equal(
  474. // micromark('$a(b="c', options()),
  475. // '<p>$a(b=&quot;c</p>',
  476. // 'should not support an EOF in a quoted attribute value',
  477. // );
  478. t.equal(
  479. micromark('$a(b="a💚b")', options()),
  480. '',
  481. 'should support most other characters in quoted attribute values',
  482. );
  483. // == Resolved as text directive
  484. // t.equal(
  485. // micromark('$a(b="\nc\r d")', options()),
  486. // '<p>$a(b=&quot;\nc\rd&quot;)</p>',
  487. // 'should not support EOLs in quoted attribute values',
  488. // );
  489. // t.equal(
  490. // micromark('$a(b="c"', options()),
  491. // '<p>$a(b=&quot;c&quot;</p>',
  492. // 'should not support an EOF after a quoted attribute value',
  493. // );
  494. t.equal(
  495. micromark('$a(b=c) \t ', options()),
  496. '',
  497. 'should support whitespace after directives',
  498. );
  499. t.equal(
  500. micromark('$a(b=c)\n>a', options()),
  501. '<blockquote>\n<p>a</p>\n</blockquote>',
  502. 'should support a block quote after a leaf',
  503. );
  504. t.equal(
  505. micromark('$a(b=c)\n```js\na', options()),
  506. '<pre><code class="language-js">a\n</code></pre>\n',
  507. 'should support code (fenced) after a leaf',
  508. );
  509. t.equal(
  510. micromark('$a(b=c)\n a', options()),
  511. '<pre><code>a\n</code></pre>',
  512. 'should support code (indented) after a leaf',
  513. );
  514. t.equal(
  515. micromark('$a(b=c)\n[a]: b', options()),
  516. '',
  517. 'should support a definition after a leaf',
  518. );
  519. t.equal(
  520. micromark('$a(b=c)\n# a', options()),
  521. '<h1>a</h1>',
  522. 'should support a heading (atx) after a leaf',
  523. );
  524. t.equal(
  525. micromark('$a(b=c)\na\n=', options()),
  526. '<h1>a</h1>',
  527. 'should support a heading (setext) after a leaf',
  528. );
  529. t.equal(
  530. micromark('$a(b=c)\n<!-->', options()),
  531. '<!-->',
  532. 'should support html after a leaf',
  533. );
  534. t.equal(
  535. micromark('$a(b=c)\n* a', options()),
  536. '<ul>\n<li>a</li>\n</ul>',
  537. 'should support a list after a leaf',
  538. );
  539. t.equal(
  540. micromark('$a(b=c)\na', options()),
  541. '<p>a</p>',
  542. 'should support a paragraph after a leaf',
  543. );
  544. t.equal(
  545. micromark('$a(b=c)\n***', options()),
  546. '<hr />',
  547. 'should support a thematic break after a leaf',
  548. );
  549. t.equal(
  550. micromark('>a\n$a(b=c)', options()),
  551. '<blockquote>\n<p>a</p>\n</blockquote>\n',
  552. 'should support a block quote before a leaf',
  553. );
  554. t.equal(
  555. micromark('```js\na\n```\n$a(b=c)', options()),
  556. '<pre><code class="language-js">a\n</code></pre>\n',
  557. 'should support code (fenced) before a leaf',
  558. );
  559. t.equal(
  560. micromark(' a\n$a(b=c)', options()),
  561. '<pre><code>a\n</code></pre>\n',
  562. 'should support code (indented) before a leaf',
  563. );
  564. t.equal(
  565. micromark('[a]: b\n$a(b=c)', options()),
  566. '',
  567. 'should support a definition before a leaf',
  568. );
  569. t.equal(
  570. micromark('# a\n$a(b=c)', options()),
  571. '<h1>a</h1>\n',
  572. 'should support a heading (atx) before a leaf',
  573. );
  574. t.equal(
  575. micromark('a\n=\n$a(b=c)', options()),
  576. '<h1>a</h1>\n',
  577. 'should support a heading (setext) before a leaf',
  578. );
  579. t.equal(
  580. micromark('<!-->\n$a(b=c)', options()),
  581. '<!-->\n',
  582. 'should support html before a leaf',
  583. );
  584. t.equal(
  585. micromark('* a\n$a(b=c)', options()),
  586. '<ul>\n<li>a</li>\n</ul>\n',
  587. 'should support a list before a leaf',
  588. );
  589. t.equal(
  590. micromark('a\n$a(b=c)', options()),
  591. '<p>a</p>\n',
  592. 'should support a paragraph before a leaf',
  593. );
  594. t.equal(
  595. micromark('***\n$a(b=c)', options()),
  596. '<hr />\n',
  597. 'should support a thematic break before a leaf',
  598. );
  599. t.equal(
  600. micromark('> $a\nb', options({ '*': h })),
  601. '<blockquote><a></a>\n</blockquote>\n<p>b</p>',
  602. 'should not support lazyness (1)',
  603. );
  604. t.equal(
  605. micromark('> a\n$b', options({ '*': h })),
  606. '<blockquote>\n<p>a</p>\n</blockquote>\n<b></b>',
  607. 'should not support lazyness (2)',
  608. );
  609. t.end();
  610. });
  611. t.end();
  612. });
  613. test('micromark-extension-directive (compile)', (t) => {
  614. t.equal(
  615. micromark(
  616. [
  617. 'a $abbr',
  618. 'a $abbr[HTML]',
  619. 'a $abbr(title="HyperText Markup Language")',
  620. 'a $abbr[HTML](title="HyperText Markup Language")',
  621. ].join('\n\n'),
  622. options({ abbr }),
  623. ),
  624. [
  625. '<p>a <abbr></abbr></p>',
  626. '<p>a <abbr>HTML</abbr></p>',
  627. '<p>a <abbr title="HyperText Markup Language"></abbr></p>',
  628. '<p>a <abbr title="HyperText Markup Language">HTML</abbr></p>',
  629. ].join('\n'),
  630. 'should support a directives (abbr)',
  631. );
  632. t.equal(
  633. micromark(
  634. [
  635. 'Text:',
  636. 'a $youtube',
  637. 'a $youtube[Cat in a box a]',
  638. 'a $youtube(v=1)',
  639. 'a $youtube[Cat in a box b](v=2)',
  640. 'Leaf:',
  641. '$youtube',
  642. '$youtube[Cat in a box c]',
  643. '$youtube(v=3)',
  644. '$youtube[Cat in a box d](v=4)',
  645. ].join('\n\n'),
  646. options({ youtube }),
  647. ),
  648. [
  649. '<p>Text:</p>',
  650. '<p>a </p>',
  651. '<p>a </p>',
  652. '<p>a <iframe src="https://www.youtube.com/embed/1" allowfullscreen></iframe></p>',
  653. '<p>a <iframe src="https://www.youtube.com/embed/2" allowfullscreen title="Cat in a box b"></iframe></p>',
  654. '<p>Leaf:</p>',
  655. '<iframe src="https://www.youtube.com/embed/3" allowfullscreen></iframe>',
  656. '<iframe src="https://www.youtube.com/embed/4" allowfullscreen title="Cat in a box d"></iframe>',
  657. ].join('\n'),
  658. 'should support directives (youtube)',
  659. );
  660. t.equal(
  661. micromark(
  662. [
  663. 'Text:',
  664. 'a $lsx',
  665. 'a $lsx()',
  666. 'a $lsx(num=1)',
  667. 'a $lsx(/)',
  668. 'a $lsx(/,num=5,depth=1)',
  669. 'a $lsx(/, num=5, depth=1)',
  670. 'a $lsx(💚)',
  671. 'Leaf:',
  672. '$lsx',
  673. '$lsx()',
  674. '$lsx(num=1)',
  675. '$lsx(/)',
  676. '$lsx(/,num=5,depth=1)',
  677. '$lsx(/, num=5, depth=1)',
  678. '$lsx(💚)',
  679. ].join('\n\n'),
  680. options({ lsx }),
  681. ),
  682. [
  683. '<p>Text:</p>',
  684. '<p>a <lsx ></lsx></p>',
  685. '<p>a <lsx ></lsx></p>',
  686. '<p>a <lsx num="1"></lsx></p>',
  687. '<p>a <lsx prefix="/"></lsx></p>',
  688. '<p>a <lsx prefix="/" num="5" depth="1"></lsx></p>',
  689. '<p>a <lsx prefix="/" num="5" depth="1"></lsx></p>',
  690. '<p>a <lsx prefix="💚"></lsx></p>',
  691. '<p>Leaf:</p>',
  692. '<lsx ></lsx>',
  693. '<lsx ></lsx>',
  694. '<lsx num="1"></lsx>',
  695. '<lsx prefix="/"></lsx>',
  696. '<lsx prefix="/" num="5" depth="1"></lsx>',
  697. '<lsx prefix="/" num="5" depth="1"></lsx>',
  698. '<lsx prefix="💚"></lsx>',
  699. ].join('\n'),
  700. 'should support directives (lsx)',
  701. );
  702. t.equal(
  703. micromark('a $youtube[Cat in a box]\n$br a', options({ youtube, '*': h })),
  704. '<p>a <youtube>Cat in a box</youtube>\n<br> a</p>',
  705. 'should support fall through directives (`*`)',
  706. );
  707. t.equal(
  708. micromark('a $a[$img(src="x" alt=y)](href="z")', options({ '*': h })),
  709. '<p>a <a href="z"><img src="x" alt="y"></a></p>',
  710. 'should support fall through directives (`*`)',
  711. );
  712. t.end();
  713. });
  714. test('content', (t) => {
  715. t.equal(
  716. micromark('a $abbr[x\\&y&amp;z]', options({ abbr })),
  717. '<p>a <abbr>x&amp;y&amp;z</abbr></p>',
  718. 'should support character escapes and character references in label',
  719. );
  720. t.equal(
  721. micromark('a $abbr[x\\[y\\]z]', options({ abbr })),
  722. '<p>a <abbr>x[y]z</abbr></p>',
  723. 'should support escaped brackets in a label',
  724. );
  725. t.equal(
  726. micromark('a $abbr[x[y]z]', options({ abbr })),
  727. '<p>a <abbr>x[y]z</abbr></p>',
  728. 'should support balanced brackets in a label',
  729. );
  730. t.equal(
  731. micromark(
  732. '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]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]',
  733. options({ abbr }),
  734. ),
  735. '<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>',
  736. 'should support balanced brackets in a label, 32 levels deep',
  737. );
  738. t.equal(
  739. micromark(
  740. '$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]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]',
  741. options({ abbr }),
  742. ),
  743. '<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>',
  744. 'should *not* support balanced brackets in a label, 33 levels deep',
  745. );
  746. t.equal(
  747. micromark('$abbr[a\nb\rc]', options({ abbr })),
  748. '<p><abbr>a\nb\rc</abbr></p>',
  749. 'should support EOLs in a label',
  750. );
  751. t.equal(
  752. micromark('$abbr[\na\r]', options({ abbr })),
  753. '<p><abbr>\na\r</abbr></p>',
  754. 'should support EOLs at the edges of a label (1)',
  755. );
  756. t.equal(
  757. micromark('$abbr[\n]', options({ abbr })),
  758. '<p><abbr>\n</abbr></p>',
  759. 'should support EOLs at the edges of a label (2)',
  760. );
  761. // == does not work but I don't know why.. -- 2022.08.12 Yuki Takei
  762. // t.equal(
  763. // micromark('$abbr[a\n$abbr[b]\nc]', options({ abbr })),
  764. // '<p>a <abbr>a\n<abbr>b</abbr>\nc</abbr> a</p>',
  765. // 'should support EOLs around nested directives',
  766. // );
  767. t.equal(
  768. micromark('$abbr[$abbr[\n]]', options({ abbr })),
  769. '<p><abbr><abbr>\n</abbr></abbr></p>',
  770. 'should support EOLs inside nested directives (1)',
  771. );
  772. t.equal(
  773. micromark('$abbr[$abbr[a\nb]]', options({ abbr })),
  774. '<p><abbr><abbr>a\nb</abbr></abbr></p>',
  775. 'should support EOLs inside nested directives (2)',
  776. );
  777. t.equal(
  778. micromark('$abbr[$abbr[\nb\n]]', options({ abbr })),
  779. '<p><abbr><abbr>\nb\n</abbr></abbr></p>',
  780. 'should support EOLs inside nested directives (3)',
  781. );
  782. t.equal(
  783. micromark('$abbr[$abbr[\\\n]]', options({ abbr })),
  784. '<p><abbr><abbr><br />\n</abbr></abbr></p>',
  785. 'should support EOLs inside nested directives (4)',
  786. );
  787. t.equal(
  788. micromark('a $abbr[a *b* **c** d]', options({ abbr })),
  789. '<p>a <abbr>a <em>b</em> <strong>c</strong> d</abbr></p>',
  790. 'should support markdown in a label',
  791. );
  792. t.equal(
  793. micromark('a $abbr(title=a&apos;b)', options({ abbr })),
  794. '<p>a <abbr title="a\'b"></abbr></p>',
  795. 'should support character references in unquoted attribute values',
  796. );
  797. t.equal(
  798. micromark('a $abbr(title="a&apos;b")', options({ abbr })),
  799. '<p>a <abbr title="a\'b"></abbr></p>',
  800. 'should support character references in double attribute values',
  801. );
  802. t.equal(
  803. micromark("a $abbr(title='a&apos;b')", options({ abbr })),
  804. '<p>a <abbr title="a\'b"></abbr></p>',
  805. 'should support character references in single attribute values',
  806. );
  807. t.equal(
  808. micromark('a $abbr(title="a&somethingelse;b")', options({ abbr })),
  809. '<p>a <abbr title="a&amp;somethingelse;b"></abbr></p>',
  810. 'should support unknown character references in attribute values',
  811. );
  812. t.equal(
  813. micromark('$span(a\nb)', options({ '*': h })),
  814. '<p><span a="" b=""></span></p>',
  815. 'should support EOLs between attributes',
  816. );
  817. t.equal(
  818. micromark('$span(\na\n)', options({ '*': h })),
  819. '<p><span a=""></span></p>',
  820. 'should support EOLs at the edges of attributes',
  821. );
  822. t.equal(
  823. micromark('$span(a\r= b)', options({ '*': h })),
  824. '<p><span a="b"></span></p>',
  825. 'should support EOLs before initializer',
  826. );
  827. t.equal(
  828. micromark('$span(a=\r\nb)', options({ '*': h })),
  829. '<p><span a="b"></span></p>',
  830. 'should support EOLs after initializer',
  831. );
  832. t.equal(
  833. micromark('$span(a=b\nc)', options({ '*': h })),
  834. '<p><span a="b" c=""></span></p>',
  835. 'should support EOLs between an unquoted attribute value and a next attribute name',
  836. );
  837. t.equal(
  838. micromark('$span(a="b\nc")', options({ '*': h })),
  839. '<p><span a="b\nc"></span></p>',
  840. 'should support EOLs in a double quoted attribute value',
  841. );
  842. t.equal(
  843. micromark("$span(a='b\nc')", options({ '*': h })),
  844. '<p><span a="b\nc"></span></p>',
  845. 'should support EOLs in a single quoted attribute value',
  846. );
  847. t.equal(
  848. micromark('a $span(#a#b)', options({ '*': h })),
  849. '<p>a <span #a#b=""></span></p>',
  850. 'should support attrs which contains `#` (1)',
  851. );
  852. t.equal(
  853. micromark('a $span(id=a id="b" #c#d)', options({ '*': h })),
  854. '<p>a <span id="b" #c#d=""></span></p>',
  855. 'should support attrs which contains `#` (2)',
  856. );
  857. t.equal(
  858. micromark('a $span(.a.b)', options({ '*': h })),
  859. '<p>a <span .a.b=""></span></p>',
  860. 'should support attrs with dot notation',
  861. );
  862. t.test('spec for growi plugin', (t) => {
  863. t.equal(
  864. micromark('a $lsx(/Sandbox)', options()),
  865. '<p>a </p>',
  866. 'should support name with slash',
  867. );
  868. t.equal(
  869. micromark('a $lsx(key=value, reverse)', options()),
  870. '<p>a </p>',
  871. 'should support name=value and an attribute w/o value',
  872. );
  873. t.equal(
  874. micromark('a $lsx(key=value, reverse, reverse2)', options()),
  875. '<p>a </p>',
  876. 'should support consecutive attributes w/o value',
  877. );
  878. t.equal(
  879. micromark('a $lsx(/Sandbox, key=value, reverse)', options()),
  880. '<p>a </p>',
  881. 'should support name=value after an empty value attribute',
  882. );
  883. t.end();
  884. });
  885. t.end();
  886. });
  887. /** @type {Handle} */
  888. function abbr(d) {
  889. if (d.type !== DirectiveType.Text) return false;
  890. this.tag('<abbr');
  891. if (d.attributes && 'title' in d.attributes) {
  892. this.tag(` title="${this.encode(d.attributes.title)}"`);
  893. }
  894. this.tag('>');
  895. this.raw(d.label || '');
  896. this.tag('</abbr>');
  897. }
  898. /** @type {Handle} */
  899. function youtube(d) {
  900. const attrs = d.attributes || {};
  901. const v = attrs.v;
  902. /** @type {string} */
  903. let prop;
  904. if (!v) return false;
  905. const list = [
  906. `src="https://www.youtube.com/embed/${this.encode(v)}"`,
  907. 'allowfullscreen',
  908. ];
  909. if (d.label) {
  910. list.push(`title="${this.encode(d.label)}"`);
  911. }
  912. // eslint-disable-next-line no-restricted-syntax
  913. for (prop in attrs) {
  914. if (prop !== 'v') {
  915. list.push(`${this.encode(prop)}="${this.encode(attrs[prop])}"`);
  916. }
  917. }
  918. this.tag(`<iframe ${list.join(' ')}>`);
  919. if (d.content) {
  920. this.lineEndingIfNeeded();
  921. this.raw(d.content);
  922. this.lineEndingIfNeeded();
  923. }
  924. this.tag('</iframe>');
  925. }
  926. /** @type {Handle} */
  927. function lsx(d) {
  928. const attrs = d.attributes || {};
  929. const props = [];
  930. // eslint-disable-next-line no-restricted-syntax
  931. for (const key in attrs) {
  932. if (attrs[key].length === 0) {
  933. props.push(`prefix="${key}"`);
  934. }
  935. else {
  936. props.push(`${key}="${attrs[key]}"`);
  937. }
  938. }
  939. this.tag(`<lsx ${props.join(' ')}>`);
  940. this.tag('</lsx>');
  941. }
  942. /** @type {Handle} */
  943. function h(d) {
  944. const content = d.content || d.label;
  945. const attrs = d.attributes || {};
  946. /** @type {Array.<string>} */
  947. const list = [];
  948. /** @type {string} */
  949. let prop;
  950. // eslint-disable-next-line no-restricted-syntax
  951. for (prop in attrs) {
  952. if (own.call(attrs, prop)) {
  953. list.push(`${this.encode(prop)}="${this.encode(attrs[prop])}"`);
  954. }
  955. }
  956. this.tag(`<${d.name}`);
  957. if (list.length > 0) this.tag(` ${list.join(' ')}`);
  958. this.tag('>');
  959. if (content) {
  960. if (d.type === 'containerGrowiPluginDirective') this.lineEndingIfNeeded();
  961. this.raw(content);
  962. if (d.type === 'containerGrowiPluginDirective') this.lineEndingIfNeeded();
  963. }
  964. if (!htmlVoidElements.includes(d.name)) this.tag(`</${d.name}>`);
  965. }
  966. /**
  967. * @param {HtmlOptions} [options]
  968. */
  969. function options(options) {
  970. return {
  971. allowDangerousHtml: true,
  972. extensions: [syntax()],
  973. htmlExtensions: [html(options)],
  974. };
  975. }