Remark и Rehype представляют собой две мощные библиотеки экосистемы unified, предназначенные для работы с текстовыми и HTML-данными. Remark ориентирован на работу с Markdown, преобразуя его в абстрактное синтаксическое дерево (AST), тогда как Rehype работает с HTML. Основной концепцией обеих библиотек является построение цепочек обработки данных, позволяющих последовательно применять плагины для трансформации, анализа и генерации контента.
Цепочка обработки данных в unified строится по следующему принципу:
Каждый этап может быть дополнен различными плагинами, обеспечивающими фильтрацию, модификацию или анализ данных.
import { unified } from 'unified';
import remarkParse from 'remark-parse';
import remarkStringify from 'remark-stringify';
const processor = unified()
.use(remarkParse)
.use(remarkStringify);
const markdown = '# Заголовок\n\nТекст параграфа';
const result = processor.processSync(markdown).toString();
В данном примере Markdown сначала парсится в дерево узлов с помощью
remark-parse, затем обратно преобразуется в текст с помощью
remark-stringify. Между этими шагами могут быть добавлены
любые плагины, изменяющие структуру документа.
Плагины являются ядром цепочки. Они могут быть двух типов:
import remarkEmoji from 'remark-emoji';
const processor = unified()
.use(remarkParse)
.use(remarkEmoji)
.use(remarkStringify);
Здесь remark-emoji добавляет поддержку эмодзи в
Markdown, заменяя текстовые коды на соответствующие символы Unicode.
Цепочка позволяет применять плагины в строгой
последовательности, что критично для предсказуемого результата:
сначала парсинг, затем модификации, потом генерация.
AST (Abstract Syntax Tree) является промежуточным представлением документа. Каждый узел дерева имеет следующие ключевые поля:
type — тип узла (например, heading,
paragraph, text).children — массив дочерних узлов.value — текстовое значение, если узел является
листовым.data — дополнительные метаданные, используемые
плагинами.Пример обхода AST для модификации текста:
import { visit } from 'unist-util-visit';
function uppercaseText() {
return (tree) => {
visit(tree, 'text', (node) => {
node.value = node.value.toUpperCase();
});
};
}
const processor = unified()
.use(remarkParse)
.use(uppercaseText)
.use(remarkStringify);
Функция visit из unist-util-visit позволяет
рекурсивно обходить дерево и применять трансформации только к узлам
определённого типа. Это фундаментальный механизм при построении цепочек
обработки данных.
Для генерации HTML используется связка Remark → Rehype. Remark
сначала парсит Markdown, затем через плагин remark-rehype
AST преобразуется в HTML-дерево, которое может быть дополнительно
обработано Rehype.
import remarkRehype from 'remark-rehype';
import rehypeStringify from 'rehype-stringify';
const processor = unified()
.use(remarkParse)
.use(remarkRehype)
.use(rehypeStringify);
const html = processor.processSync('# Заголовок').toString();
Таким образом можно строить сквозные цепочки, где Markdown преобразуется в AST, модифицируется, затем конвертируется в HTML и получает финальную генерацию.
Многие плагины работают асинхронно, поэтому метод
process возвращает промис:
async function processMarkdown(markdown) {
const result = await unified()
.use(remarkParse)
.use(async (tree) => {
// асинхронная модификация
})
.use(remarkStringify)
.process(markdown);
return result.toString();
}
Асинхронные цепочки позволяют интегрировать сетевые вызовы, загрузку данных из базы или проверку ссылок без нарушения архитектуры цепочки.
Порядок применения плагинов критичен. Например, если сначала выполнить генерацию строки, а потом попытаться модифицировать AST, это приведёт к ошибкам. Следует придерживаться принципа:
Для сложных цепочек часто используют разделение на этапы: pre-processing, main transformations, post-processing.
Цепочки Remark/Rehype позволяют встроить анализатор данных на любом этапе. Например, подсчёт количества заголовков:
import { visit } from 'unist-util-visit';
function countHeadings() {
return (tree) => {
let count = 0;
visit(tree, 'heading', () => count++);
console.log('Количество заголовков:', count);
};
}
unified()
.use(remarkParse)
.use(countHeadings)
.use(remarkStringify)
.processSync('# H1\n## H2\nТекст');
Это позволяет не только модифицировать контент, но и собирать метрики, проверять структуру документа и строить автоматические отчёты.
Эти принципы делают Remark и Rehype универсальными инструментами для построения сложных конвейеров обработки текстовых и HTML-данных.