syntax-highlighting.test.js 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. import { parseHTML } from 'linkedom';
  2. import Markdoc from '@markdoc/markdoc';
  3. import shiki from '../dist/extensions/shiki.js';
  4. import prism from '../dist/extensions/prism.js';
  5. import { setupConfig } from '../dist/runtime.js';
  6. import { isHTMLString } from 'astro/runtime/server/index.js';
  7. import assert from 'node:assert/strict';
  8. import { describe, it } from 'node:test';
  9. const entry = `
  10. \`\`\`ts
  11. const highlighting = true;
  12. \`\`\`
  13. \`\`\`css
  14. .highlighting {
  15. color: red;
  16. }
  17. \`\`\`
  18. `;
  19. describe('Markdoc - syntax highlighting', () => {
  20. describe('shiki', () => {
  21. it('transforms with defaults', async () => {
  22. const ast = Markdoc.parse(entry);
  23. const content = Markdoc.transform(ast, await getConfigExtendingShiki());
  24. assert.equal(content.children.length, 2);
  25. for (const codeBlock of content.children) {
  26. assert.equal(isHTMLString(codeBlock), true);
  27. const pre = parsePreTag(codeBlock);
  28. assert.equal(pre.classList.contains('astro-code'), true);
  29. assert.equal(pre.classList.contains('github-dark'), true);
  30. }
  31. });
  32. it('transforms with `theme` property', async () => {
  33. const ast = Markdoc.parse(entry);
  34. const content = Markdoc.transform(
  35. ast,
  36. await getConfigExtendingShiki({
  37. theme: 'dracula',
  38. })
  39. );
  40. assert.equal(content.children.length, 2);
  41. for (const codeBlock of content.children) {
  42. assert.equal(isHTMLString(codeBlock), true);
  43. const pre = parsePreTag(codeBlock);
  44. assert.equal(pre.classList.contains('astro-code'), true);
  45. assert.equal(pre.classList.contains('dracula'), true);
  46. }
  47. });
  48. it('transforms with `wrap` property', async () => {
  49. const ast = Markdoc.parse(entry);
  50. const content = Markdoc.transform(
  51. ast,
  52. await getConfigExtendingShiki({
  53. wrap: true,
  54. })
  55. );
  56. assert.equal(content.children.length, 2);
  57. for (const codeBlock of content.children) {
  58. assert.equal(isHTMLString(codeBlock), true);
  59. const pre = parsePreTag(codeBlock);
  60. assert.equal(pre.getAttribute('style').includes('white-space: pre-wrap'), true);
  61. assert.equal(pre.getAttribute('style').includes('word-wrap: break-word'), true);
  62. }
  63. });
  64. });
  65. describe('prism', () => {
  66. it('transforms', async () => {
  67. const ast = Markdoc.parse(entry);
  68. const config = await setupConfig({
  69. extends: [prism()],
  70. });
  71. const content = Markdoc.transform(ast, config);
  72. assert.equal(content.children.length, 2);
  73. const [tsBlock, cssBlock] = content.children;
  74. assert.equal(isHTMLString(tsBlock), true);
  75. assert.equal(isHTMLString(cssBlock), true);
  76. const preTs = parsePreTag(tsBlock);
  77. assert.equal(preTs.classList.contains('language-ts'), true);
  78. const preCss = parsePreTag(cssBlock);
  79. assert.equal(preCss.classList.contains('language-css'), true);
  80. });
  81. });
  82. });
  83. /**
  84. * @param {import('astro').ShikiConfig} config
  85. * @returns {import('../src/config.js').AstroMarkdocConfig}
  86. */
  87. async function getConfigExtendingShiki(config) {
  88. return await setupConfig({
  89. extends: [shiki(config)],
  90. });
  91. }
  92. /**
  93. * @param {string} html
  94. * @returns {HTMLPreElement}
  95. */
  96. function parsePreTag(html) {
  97. const { document } = parseHTML(html);
  98. const pre = document.querySelector('pre');
  99. assert.ok(pre);
  100. return pre;
  101. }