links.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. /**
  2. * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md.
  4. */
  5. import MarkdownDataProcessor from '/ckeditor5/markdown-gfm/gfmdataprocessor.js';
  6. import { stringify } from '/tests/engine/_utils/view.js';
  7. describe( 'GFMDataProcessor', () => {
  8. let dataProcessor;
  9. beforeEach( () => {
  10. dataProcessor = new MarkdownDataProcessor();
  11. } );
  12. describe( 'links', () => {
  13. describe( 'toView', () => {
  14. it( 'should autolink', () => {
  15. const viewFragment = dataProcessor.toView( 'Link: <http://example.com/>.' );
  16. expect( stringify( viewFragment ) ).to.equal( '<p>Link: <a href="http://example.com/">http://example.com/</a>.</p>' );
  17. } );
  18. it( 'should autolink #2', () => {
  19. const viewFragment = dataProcessor.toView( 'Link: http://example.com/.' );
  20. expect( stringify( viewFragment ) ).to.equal( '<p>Link: <a href="http://example.com/">http://example.com/</a>.</p>' );
  21. } );
  22. it( 'should autolink with params', () => {
  23. const viewFragment = dataProcessor.toView( 'Link: <http://example.com/?foo=1&bar=2>.' );
  24. expect( stringify( viewFragment ) ).to.equal(
  25. '<p>Link: <a href="http://example.com/?foo=1&bar=2">http://example.com/?foo=1&bar=2</a>.</p>'
  26. );
  27. } );
  28. it( 'should autolink inside list', () => {
  29. const viewFragment = dataProcessor.toView( '* <http://example.com/>' );
  30. expect( stringify( viewFragment ) ).to.equal(
  31. '<ul>' +
  32. '<li><a href="http://example.com/">http://example.com/</a></li>' +
  33. '</ul>'
  34. );
  35. } );
  36. it( 'should autolink inside blockquote', () => {
  37. const viewFragment = dataProcessor.toView( '> Blockquoted: <http://example.com/>' );
  38. expect( stringify( viewFragment ) ).to.equal(
  39. '<blockquote>' +
  40. '<p>Blockquoted: <a href="http://example.com/">http://example.com/</a></p>' +
  41. '</blockquote>'
  42. );
  43. } );
  44. it( 'should not autolink inside inline code', () => {
  45. const viewFragment = dataProcessor.toView( '`<http://example.com/>`' );
  46. expect( stringify( viewFragment ) ).to.equal( '<p><code><http://example.com/></code></p>' );
  47. } );
  48. it( 'should not autolink inside code block', () => {
  49. const viewFragment = dataProcessor.toView( ' <http://example.com/>' );
  50. expect( stringify( viewFragment ) ).to.equal( '<pre><code><http://example.com/></code></pre>' );
  51. } );
  52. it( 'should not process already linked #1', () => {
  53. const viewFragment = dataProcessor.toView( 'Already linked: <a href="http://example.com/">http://example.com/</a>' );
  54. expect( stringify( viewFragment ) ).to.equal( '<p>Already linked: <a href="http://example.com/">http://example.com/</a></p>' );
  55. } );
  56. it( 'should not process already linked #2', () => {
  57. const viewFragment = dataProcessor.toView( 'Already linked: [http://example.com/](http://example.com/)' );
  58. expect( stringify( viewFragment ) ).to.equal( '<p>Already linked: <a href="http://example.com/">http://example.com/</a></p>' );
  59. } );
  60. it( 'should not process already linked #3', () => {
  61. const viewFragment = dataProcessor.toView( 'Already linked: <a href="http://example.com/">**http://example.com/**</a>' );
  62. expect( stringify( viewFragment ) ).to.equal(
  63. '<p>Already linked: <a href="http://example.com/"><strong>http://example.com/</strong></a></p>'
  64. );
  65. } );
  66. it( 'should process inline links', () => {
  67. const viewFragment = dataProcessor.toView( '[URL](/url/)' );
  68. expect( stringify( viewFragment ) ).to.equal( '<p><a href="/url/">URL</a></p>' );
  69. } );
  70. it( 'should process inline links with title', () => {
  71. const viewFragment = dataProcessor.toView( '[URL and title](/url/ "title")' );
  72. expect( stringify( viewFragment ) ).to.equal( '<p><a href="/url/" title="title">URL and title</a></p>' );
  73. } );
  74. it( 'should process inline links with title preceded by two spaces', () => {
  75. const viewFragment = dataProcessor.toView( '[URL and title](/url/ "title preceded by two spaces")' );
  76. expect( stringify( viewFragment ) ).to.equal( '<p><a href="/url/" title="title preceded by two spaces">URL and title</a></p>' );
  77. } );
  78. it( 'should process inline links with title preceded by tab', () => {
  79. const viewFragment = dataProcessor.toView( '[URL and title](/url/ "title preceded by tab")' );
  80. expect( stringify( viewFragment ) ).to.equal( '<p><a href="/url/" title="title preceded by tab">URL and title</a></p>' );
  81. } );
  82. it( 'should process inline links with title that has spaces afterwards', () => {
  83. const viewFragment = dataProcessor.toView( '[URL and title](/url/ "title has spaces afterward" )' );
  84. expect( stringify( viewFragment ) ).to.equal( '<p><a href="/url/" title="title has spaces afterward">URL and title</a></p>' );
  85. } );
  86. it( 'should process inline links with spaces in URL', () => {
  87. const viewFragment = dataProcessor.toView( '[URL and title]( /url/has space )' );
  88. expect( stringify( viewFragment ) ).to.equal( '<p><a href="/url/has space">URL and title</a></p>' );
  89. } );
  90. it( 'should process inline links with titles and spaces in URL', () => {
  91. const viewFragment = dataProcessor.toView( '[URL and title]( /url/has space/ "url has space and title")' );
  92. expect( stringify( viewFragment ) ).to.equal( '<p><a href="/url/has space/" title="url has space and title">URL and title</a></p>' );
  93. } );
  94. it( 'should process empty link', () => {
  95. const viewFragment = dataProcessor.toView( '[Empty]()' );
  96. expect( stringify( viewFragment ) ).to.equal( '<p><a href="">Empty</a></p>' );
  97. } );
  98. it( 'should process reference links', () => {
  99. const viewFragment = dataProcessor.toView(
  100. 'Foo [bar] [1].\n' +
  101. '[1]: /url/ "Title"'
  102. );
  103. expect( stringify( viewFragment ) ).to.equal( '<p>Foo <a href="/url/" title="Title">bar</a>.</p>' );
  104. } );
  105. it( 'should process reference links - without space', () => {
  106. const viewFragment = dataProcessor.toView(
  107. 'Foo [bar][1].\n' +
  108. '[1]: /url/ "Title"'
  109. );
  110. expect( stringify( viewFragment ) ).to.equal( '<p>Foo <a href="/url/" title="Title">bar</a>.</p>' );
  111. } );
  112. it( 'should process reference links - with newline', () => {
  113. const viewFragment = dataProcessor.toView(
  114. 'Foo [bar]\n[1].\n' +
  115. '[1]: /url/ "Title"'
  116. );
  117. expect( stringify( viewFragment ) ).to.equal( '<p>Foo <a href="/url/" title="Title">bar</a>.</p>' );
  118. } );
  119. it( 'should process reference links - with embedded brackets', () => {
  120. const viewFragment = dataProcessor.toView(
  121. 'With [embedded [brackets]] [b].\n' +
  122. '[b]: /url/'
  123. );
  124. expect( stringify( viewFragment ) ).to.equal( '<p>With <a href="/url/">embedded [brackets]</a>.</p>' );
  125. } );
  126. it( 'should process reference links - with reference indented once', () => {
  127. const viewFragment = dataProcessor.toView(
  128. 'Indented [once][].\n' +
  129. ' [once]: /url'
  130. );
  131. expect( stringify( viewFragment ) ).to.equal( '<p>Indented <a href="/url">once</a>.</p>' );
  132. } );
  133. it( 'should process reference links - with reference indented twice', () => {
  134. const viewFragment = dataProcessor.toView(
  135. 'Indented [twice][].\n' +
  136. ' [twice]: /url'
  137. );
  138. expect( stringify( viewFragment ) ).to.equal( '<p>Indented <a href="/url">twice</a>.</p>' );
  139. } );
  140. it( 'should process reference links - with reference indented trice', () => {
  141. const viewFragment = dataProcessor.toView(
  142. 'Indented [trice][].\n' +
  143. ' [trice]: /url'
  144. );
  145. expect( stringify( viewFragment ) ).to.equal( '<p>Indented <a href="/url">trice</a>.</p>' );
  146. } );
  147. it( 'should NOT process reference links - with reference indented four times', () => {
  148. const viewFragment = dataProcessor.toView(
  149. 'Indented [four][] times.\n' +
  150. ' [four]: /url'
  151. );
  152. // GitHub renders it as:
  153. // <p>Indented [four][] times.<br>[four]: /url</p>
  154. expect( stringify( viewFragment ) ).to.equal( '<p>Indented [four][] times.</p><pre><code>[four]: /url</code></pre>' );
  155. } );
  156. it( 'should process reference links when title and reference are same #1', () => {
  157. const viewFragment = dataProcessor.toView(
  158. '[this] [this]\n' +
  159. '[this]: foo'
  160. );
  161. expect( stringify( viewFragment ) ).to.equal( '<p><a href="foo">this</a></p>' );
  162. } );
  163. it( 'should process reference links when title and reference are same #2', () => {
  164. const viewFragment = dataProcessor.toView(
  165. '[this][this]\n' +
  166. '[this]: foo'
  167. );
  168. expect( stringify( viewFragment ) ).to.equal( '<p><a href="foo">this</a></p>' );
  169. } );
  170. it( 'should process reference links when only title is provided and is same as reference #1', () => {
  171. const viewFragment = dataProcessor.toView(
  172. '[this] []\n' +
  173. '[this]: foo'
  174. );
  175. expect( stringify( viewFragment ) ).to.equal( '<p><a href="foo">this</a></p>' );
  176. } );
  177. it( 'should process reference links when only title is provided and is same as reference #2', () => {
  178. const viewFragment = dataProcessor.toView(
  179. '[this][]\n' +
  180. '[this]: foo'
  181. );
  182. expect( stringify( viewFragment ) ).to.equal( '<p><a href="foo">this</a></p>' );
  183. } );
  184. it( 'should process reference links when only title is provided and is same as reference #3', () => {
  185. const viewFragment = dataProcessor.toView(
  186. '[this]\n' +
  187. '[this]: foo'
  188. );
  189. expect( stringify( viewFragment ) ).to.equal( '<p><a href="foo">this</a></p>' );
  190. } );
  191. it( 'should not process reference links when reference is not found #1', () => {
  192. const viewFragment = dataProcessor.toView(
  193. '[this] []'
  194. );
  195. expect( stringify( viewFragment ) ).to.equal( '<p>[this] []</p>' );
  196. } );
  197. it( 'should not process reference links when reference is not found #2', () => {
  198. const viewFragment = dataProcessor.toView(
  199. '[this][]'
  200. );
  201. expect( stringify( viewFragment ) ).to.equal( '<p>[this][]</p>' );
  202. } );
  203. it( 'should not process reference links when reference is not found #2', () => {
  204. const viewFragment = dataProcessor.toView(
  205. '[this]'
  206. );
  207. expect( stringify( viewFragment ) ).to.equal( '<p>[this]</p>' );
  208. } );
  209. it( 'should process reference links nested in brackets #1', () => {
  210. const viewFragment = dataProcessor.toView(
  211. '[a reference inside [this][]]\n' +
  212. '[this]: foo'
  213. );
  214. expect( stringify( viewFragment ) ).to.equal( '<p>[a reference inside <a href="foo">this</a>]</p>' );
  215. } );
  216. it( 'should process reference links nested in brackets #2', () => {
  217. const viewFragment = dataProcessor.toView(
  218. '[a reference inside [this]]\n' +
  219. '[this]: foo'
  220. );
  221. expect( stringify( viewFragment ) ).to.equal( '<p>[a reference inside <a href="foo">this</a>]</p>' );
  222. } );
  223. it( 'should not process reference links when title is same as reference but reference is different', () => {
  224. const viewFragment = dataProcessor.toView(
  225. '[this](/something/else/)\n' +
  226. '[this]: foo'
  227. );
  228. expect( stringify( viewFragment ) ).to.equal( '<p><a href="/something/else/">this</a></p>' );
  229. } );
  230. it( 'should not process reference links suppressed by backslashes', () => {
  231. const viewFragment = dataProcessor.toView(
  232. 'Suppress \\[this] and [this\\].\n' +
  233. '[this]: foo'
  234. );
  235. expect( stringify( viewFragment ) ).to.equal( '<p>Suppress [this] and [this].</p>' );
  236. } );
  237. it( 'should process reference links when used across multiple lines #1', () => {
  238. const viewFragment = dataProcessor.toView(
  239. 'This is [multiline\nreference]\n' +
  240. '[multiline reference]: foo'
  241. );
  242. expect( stringify( viewFragment ) ).to.equal( '<p>This is <a href="foo">multiline<br></br>reference</a></p>' );
  243. } );
  244. it( 'should process reference links when used across multiple lines #2', () => {
  245. const viewFragment = dataProcessor.toView(
  246. 'This is [multiline \nreference]\n' +
  247. '[multiline reference]: foo'
  248. );
  249. expect( stringify( viewFragment ) ).to.equal( '<p>This is <a href="foo">multiline<br></br>reference</a></p>' );
  250. } );
  251. } );
  252. } );
  253. } );