1
0

test.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. import { test } from 'uvu'
  2. import * as assert from 'uvu/assert'
  3. import { visit } from 'unist-util-visit'
  4. import rehype from 'rehype'
  5. import dedent from 'dedent'
  6. import rehypePrism from './index.js'
  7. /**
  8. * Mock meta in code block
  9. */
  10. const addMeta = (metastring) => {
  11. if (!metastring) return
  12. return (tree) => {
  13. visit(tree, 'element', (node, index, parent) => {
  14. if (node.tagName === 'code') {
  15. node.data = { meta: metastring }
  16. }
  17. })
  18. }
  19. }
  20. const processHtml = (html, options, metastring) => {
  21. return rehype()
  22. .data('settings', { fragment: true })
  23. .use(addMeta, metastring)
  24. .use(rehypePrism, options)
  25. .processSync(html)
  26. .toString()
  27. }
  28. test('copies the language- class to pre tag', () => {
  29. const result = processHtml(dedent`
  30. <pre><code class="language-py"></code></pre>
  31. `)
  32. const expected = dedent`<pre class="language-py"><code class="language-py"></code></pre>`
  33. assert.is(result, expected)
  34. })
  35. test('add div with class code line for each line', () => {
  36. const result = processHtml(dedent`
  37. <pre><code>x = 6</code></pre>
  38. `)
  39. const expected = dedent`<pre><code><div class="code-line">x = 6</div></code></pre>`
  40. assert.is(result, expected)
  41. })
  42. test('finds code and highlights', () => {
  43. const result = processHtml(dedent`
  44. <div>
  45. <p>foo</p>
  46. <pre><code class="language-py">x = 6</code></pre>
  47. </div>
  48. `).trim()
  49. const expected = dedent`
  50. <div>
  51. <p>foo</p>
  52. <pre class="language-py"><code class="language-py"><div class="code-line">x <span class="token operator">=</span> <span class="token number">6</span></div></code></pre>
  53. </div>
  54. `
  55. assert.is(result, expected)
  56. })
  57. test('handles uppercase correctly', () => {
  58. const result = processHtml(dedent`
  59. <div>
  60. <p>foo</p>
  61. <pre><code class="language-PY">x = 6</code></pre>
  62. </div>
  63. `).trim()
  64. const expected = dedent`
  65. <div>
  66. <p>foo</p>
  67. <pre class="language-py"><code class="language-PY"><div class="code-line">x <span class="token operator">=</span> <span class="token number">6</span></div></code></pre>
  68. </div>
  69. `
  70. assert.is(result, expected)
  71. })
  72. test('each line of code should be a separate div', async () => {
  73. const result = processHtml(dedent`
  74. <div>
  75. <p>foo</p>
  76. <pre>
  77. <code class="language-py">x = 6
  78. y = 7
  79. </code>
  80. </pre>
  81. </div>
  82. `).trim()
  83. const codeLineCount = (result.match(/<div class="code-line">/g) || []).length
  84. assert.is(codeLineCount, 2)
  85. })
  86. test('should highlight line', async () => {
  87. const meta = '{1}'
  88. const result = processHtml(
  89. dedent`
  90. <div>
  91. <pre>
  92. <code class="language-py">x = 6
  93. y = 7
  94. </code>
  95. </pre>
  96. </div>
  97. `,
  98. {},
  99. meta
  100. ).trim()
  101. const codeHighlightCount = (result.match(/<div class="code-line highlight-line">/g) || []).length
  102. assert.is(codeHighlightCount, 1)
  103. })
  104. test('should highlight comma separated lines', async () => {
  105. const meta = '{1,3}'
  106. const result = processHtml(
  107. dedent`
  108. <div>
  109. <pre>
  110. <code class="language-py">x = 6
  111. y = 7
  112. z = 10
  113. </code>
  114. </pre>
  115. </div>
  116. `,
  117. {},
  118. meta
  119. ).trim()
  120. const codeHighlightCount = (result.match(/<div class="code-line highlight-line">/g) || []).length
  121. assert.is(codeHighlightCount, 2)
  122. })
  123. test('should highlight range separated lines', async () => {
  124. const meta = '{1-3}'
  125. const result = processHtml(
  126. dedent`
  127. <div>
  128. <pre>
  129. <code class="language-py">x = 6
  130. y = 7
  131. z = 10
  132. </code>
  133. </pre>
  134. </div>
  135. `,
  136. {},
  137. meta
  138. ).trim()
  139. const codeHighlightCount = (result.match(/<div class="code-line highlight-line">/g) || []).length
  140. assert.is(codeHighlightCount, 3)
  141. })
  142. test('showLineNumbers option add line numbers', async () => {
  143. const result = processHtml(
  144. dedent`
  145. <div>
  146. <pre>
  147. <code class="language-py">x = 6
  148. y = 7
  149. </code>
  150. </pre>
  151. </div>
  152. `,
  153. { showLineNumbers: true }
  154. ).trim()
  155. assert.ok(result.match(/line="1"/g))
  156. assert.ok(result.match(/line="2"/g))
  157. assert.not(result.match(/line="3"/g))
  158. })
  159. test('showLineNumbers property works in meta field', async () => {
  160. const meta = 'showLineNumbers'
  161. const result = processHtml(
  162. dedent`
  163. <div>
  164. <pre>
  165. <code class="language-py">x = 6
  166. y = 7
  167. </code>
  168. </pre>
  169. </div>
  170. `,
  171. {},
  172. meta
  173. ).trim()
  174. assert.ok(result.match(/line="1"/g))
  175. assert.ok(result.match(/line="2"/g))
  176. assert.not(result.match(/line="3"/g))
  177. })
  178. test('should support both highlighting and add line number', async () => {
  179. const meta = '{1} showLineNumbers'
  180. const result = processHtml(
  181. dedent`
  182. <div>
  183. <pre>
  184. <code class="language-py">x = 6
  185. y = 7
  186. z = 10
  187. </code>
  188. </pre>
  189. </div>
  190. `,
  191. {},
  192. meta
  193. ).trim()
  194. const codeHighlightCount = (result.match(/highlight-line/g) || []).length
  195. assert.is(codeHighlightCount, 1)
  196. assert.ok(result.match(/line="1"/g))
  197. assert.ok(result.match(/line="2"/g))
  198. })
  199. test('throw error with fake language- class', () => {
  200. assert.throws(
  201. () =>
  202. processHtml(dedent`
  203. <pre><code class="language-thisisnotalanguage">x = 6</code></pre>
  204. `),
  205. /Unknown language/
  206. )
  207. })
  208. test('with options.ignoreMissing, does nothing to code block with fake language- class', () => {
  209. const result = processHtml(
  210. dedent`
  211. <pre><code class="language-thisisnotalanguage">x = 6</code></pre>
  212. `,
  213. { ignoreMissing: true }
  214. )
  215. const expected = dedent`<pre class="language-thisisnotalanguage"><code class="language-thisisnotalanguage"><div class="code-line">x = 6</div></code></pre>`
  216. assert.is(result, expected)
  217. })
  218. test.run()