Code blocks в Markdown представляют собой многострочные фрагменты кода, заключённые в тройные обратные кавычки (```). В контексте JavaScript и экосистемы Remark/Rehype их обработка требует понимания двух уровней: синтаксического анализа Markdown и трансформации AST в HTML.
Remark использует MDAST (Markdown Abstract Syntax
Tree). В MDAST code blocks представлены узлами типа
code. Основные свойства узла:
type: "code" — указывает на тип узла.lang: строка, указывающая язык (например,
"js", "python"), может быть
null.value: содержимое блока кода.meta: дополнительные данные, такие как подсветка или
названия файлов.Пример AST для блока кода:
{
"type": "code",
"lang": "js",
"meta": "highlight-line=2",
"value": "console.log('Hello World');"
}
Этот узел можно использовать для дальнейших трансформаций или подсветки синтаксиса.
Remark отвечает за парсинг Markdown, Rehype — за работу с HTML. Для обработки code blocks стандартная цепочка выглядит так:
import { unified } from 'unified';
import remarkParse from 'remark-parse';
import remarkRehype from 'remark-rehype';
import rehypeStringify from 'rehype-stringify';
const processor = unified()
.use(remarkParse)
.use(remarkRehype)
.use(rehypeStringify);
const markdown = `
\`\`\`js
console.log('Hello World');
\`\`\`
`;
const html = await processor.process(markdown);
console.log(String(html));
В результате получаем HTML:
<pre><code class="language-js">console.log('Hello World');</code></pre>
Ключевой момент — class="language-js", который
используется для интеграции с библиотеками подсветки синтаксиса,
например Prism или Highlight.js.
Для подсветки кода подключается rehype-highlight:
import rehypeHighlight from 'rehype-highlight';
const processor = unified()
.use(remarkParse)
.use(remarkRehype)
.use(rehypeHighlight)
.use(rehypeStringify);
rehype-highlight автоматически определяет язык по классу
language-* и применяет HTML-классы для подсветки.
Дополнительно можно передавать настройки:
.use(rehypeHighlight, { ignoreMissing: true });
ignoreMissing: true позволяет пропускать блоки без
указания языка, не генерируя ошибок.Remark поддерживает метаданные внутри тройных кавычек:
```js title="example.js" highlight-line=2
console.log('Hello World');
console.error('Error');
Узел MDAST:
```json
{
"type": "code",
"lang": "js",
"meta": "title=\"example.js\" highlight-line=2",
"value": "console.log('Hello World');\nconsole.error('Error');"
}
Метаданные можно парсить с помощью сторонних утилит, например
parse-meta или самостоятельно:
function parseMeta(meta) {
const result = {};
meta?.split(' ').forEach(item => {
const [key, value] = item.split('=');
result[key] = value?.replace(/"/g, '');
});
return result;
}
После этого можно добавить к HTML атрибуты, например
data-title или data-highlight.
Remark + Rehype позволяет полностью кастомизировать рендеринг блоков кода через rehype plugins. Пример создания плагина для добавления заголовка к каждому блоку:
function rehypeCodeTitle() {
return (tree) => {
visit(tree, 'element', (node) => {
if (node.tagName === 'pre' && node.children[0]?.tagName === 'code') {
const meta = node.children[0].properties?.meta;
if (meta) {
const titleNode = {
type: 'element',
tagName: 'div',
properties: { className: ['code-title'] },
children: [{ type: 'text', value: meta }]
};
node.children.unshift(titleNode);
}
}
});
};
}
Этот подход позволяет создавать визуальные улучшения для блоков кода без вмешательства в сам Markdown.
Помимо многострочных блоков, MDAST поддерживает inline
code (inlineCode):
type: "inlineCode".value: содержимое кода.<code>...</code>
без <pre>.Пример использования:
Используйте `console.log()` для отладки.
В HTML:
<p>Используйте <code>console.log()</code> для отладки.</p>
Подсветка обычно не применяется к inline-коду, но метаданные можно обрабатывать аналогично.
code и inlineCode в MDAST — основа
для работы с кодом в Markdown.remarkRehype преобразует AST в HTML с сохранением
семантики <pre><code>.rehype-highlight обеспечивает
автоматическую подсветку синтаксиса.Эта комбинация инструментов обеспечивает гибкую и мощную обработку code blocks, поддерживая как базовые сценарии, так и сложные визуальные требования.