Remark и Rehype — это мощные инструменты для работы с текстом в формате Markdown и HTML, основанные на концепции абстрактного синтаксического дерева (AST, Abstract Syntax Tree). AST представляет собой иерархическую структуру, где каждый узел соответствует элементу документа: заголовку, параграфу, ссылке, изображению и так далее. Понимание структуры AST критически важно для визуализации и трансформации документов.
В Remark узлы AST имеют тип MDAST (Markdown AST), а в
Rehype — HAST (HTML AST). Типичный узел включает следующие
свойства:
type — тип узла (например, paragraph,
heading, link).children — массив дочерних узлов (для вложенных
структур).value — содержимое текстового узла (только для узлов
типа text).position — информация о позиции в исходном документе
(начало, конец, линия).Пример структуры MDAST для заголовка:
{
"type": "heading",
"depth": 2,
"children": [
{
"type": "text",
"value": "Пример заголовка"
}
]
}
Эта структура позволяет строить визуальные представления дерева с полной информацией о типе узла и его содержимом.
unist-util-visit для обхода дереваДля визуализации синтаксических деревьев необходимо обойти все узлы
AST. Для этого применяют библиотеку
unist-util-visit, которая обеспечивает
рекурсивный проход по дереву:
import { visit } from 'unist-util-visit';
visit(tree, (node) => {
console.log(`${node.type}: ${node.value || ''}`);
});
Ключевые моменты:
visit(tree, type, callback) позволяет фильтровать узлы
по типу.callback получает каждый узел и его индекс, что
удобно для построения иерархической визуализации.Для визуализации дерева Markdown сначала преобразуют текст в AST:
import { unified } from 'unified';
import remarkParse from 'remark-parse';
const markdown = `# Заголовок\n\nПараграф текста.`;
const tree = unified()
.use(remarkParse)
.parse(markdown);
console.log(JSON.stringify(tree, null, 2));
Особенности:
parse возвращает MDAST, который можно
визуализировать как дерево.depth или рекурсивный обход.После работы с Markdown часто требуется преобразовать AST в HTML, где HAST представляет собой структуру аналогичную MDAST, но с HTML-тегами. Пример:
import rehype from 'rehype';
import rehypeStringify from 'rehype-stringify';
import remarkRehype from 'remark-rehype';
const html = await unified()
.use(remarkParse)
.use(remarkRehype)
.use(rehypeStringify)
.process(markdown);
console.log(String(html));
Ключевые моменты:
remarkRehype выполняет конвертацию MDAST → HAST.rehypeStringify сериализует HAST в HTML.element, text,
comment, и свойства tagName и
children.Для наглядного представления AST можно использовать графические библиотеки, такие как D3.js или Cytoscape. Основная задача — преобразовать AST в формат узлы + связи:
function buildGraph(node, parentId = null, nodes = [], edges = []) {
const nodeId = nodes.length;
nodes.push({ id: nodeId, label: node.type });
if (parentId !== null) edges.push({ from: parentId, to: nodeId });
if (node.children) {
node.children.forEach(child => buildGraph(child, nodeId, nodes, edges));
}
return { nodes, edges };
}
Особенности:
id и
label.Для визуального анализа полезно добавлять к узлам:
Пример добавления цвета узлу:
const nodeColor = (type) => {
switch(type) {
case 'heading': return 'blue';
case 'paragraph': return 'green';
case 'link': return 'orange';
default: return 'gray';
}
};
nodes.forEach(n => n.color = nodeColor(n.label));
При визуализации больших AST:
Remark и Rehype позволяют строить интерактивные редакторы Markdown/HTML, где AST используется для:
Использование AST как промежуточного слоя обеспечивает гибкость: можно динамически изменять контент, визуализировать структуру и сразу видеть результат в браузере.