Remark и Rehype работают с текстовыми данными через концепцию AST (Abstract Syntax Tree). В Remark исходным форматом является Markdown, а в Rehype — HTML. Парсинг — это первый этап обработки, на котором исходный текст превращается в дерево узлов.
remark-parse для
преобразования Markdown в дерево типа mdast (Markdown AST).
Узлы дерева имеют структуру
{ type, children, value, data }.rehype-parse для
создания hast (HTML AST). Узлы имеют аналогичную структуру
{ type, tagName, properties, children }.Парсер осуществляет лексический и синтаксический анализ. На лексическом уровне текст разбивается на токены (заголовки, списки, параграфы), на синтаксическом — строится иерархия узлов.
Пример структуры узла mdast для заголовка:
{
type: 'heading',
depth: 2,
children: [
{ type: 'text', value: 'Пример заголовка' }
]
}
Эта структура позволяет применять универсальные алгоритмы трансформации, независимо от исходного формата.
После парсинга следует трансформация AST. Этот этап является ключевым для обработки Markdown и HTML. Он включает:
Remark и Rehype предоставляют систему плагинов, которые принимают AST и возвращают изменённое дерево. Плагины могут быть:
remark-autolink-headings или
rehype-highlight)Пример синхронной трансформации Markdown:
import { visit } from 'unist-util-visit';
function capitalizeHeadings() {
return (tree) => {
visit(tree, 'heading', (node) => {
node.children.forEach(child => {
if (child.type === 'text') {
child.value = child.value.toUpperCase();
}
});
});
};
}
visit позволяет рекурсивно обходить все узлы и применять
изменения в реальном времени.
На последнем этапе происходит сериализация AST обратно в текстовый формат:
remark-stringify для
генерации Markdown.rehype-stringify для
генерации HTML.Сериализация учитывает иерархию узлов и их свойства. Важные моменты:
Пример сериализации:
import { unified } from 'unified';
import remarkParse from 'remark-parse';
import remarkStringify from 'remark-stringify';
const processor = unified()
.use(remarkParse)
.use(capitalizeHeadings)
.use(remarkStringify);
const markdown = '# пример заголовка';
const result = processor.processSync(markdown).toString();
// Результат: '# ПРИМЕР ЗАГОЛОВКА'
Remark и Rehype строят конвейер обработки данных, где результат одной фазы становится входом для следующей:
Такой подход позволяет:
| Фаза | Remark (Markdown) | Rehype (HTML) |
|---|---|---|
| Парсинг | remark-parse → mdast |
rehype-parse → hast |
| Трансформация | Плагины remark-* |
Плагины rehype-* |
| Сериализация | remark-stringify |
rehype-stringify |
| Основной тип узлов | Заголовки, параграфы, списки | Теги, атрибуты, текст |
Эта таблица отражает фундаментальное различие: Remark ориентирован на структурирование текста, Rehype — на работу с документами HTML.
mdast → hast.Каждая из фаз критически важна для построения надежного и гибкого пайплайна обработки контента. Их понимание позволяет создавать сложные системы генерации, парсинга и редактирования текстов и веб-документов.