Remark и Rehype — это мощные инструменты для анализа, трансформации и генерации Markdown и HTML в экосистеме JavaScript. Remark специализируется на Markdown, предоставляя удобные способы чтения, изменения и генерации документов. Rehype фокусируется на HTML, обеспечивая работу с деревом узлов HTML (AST) аналогично тому, как Remark работает с Markdown.
Обе библиотеки используют концепцию Abstract Syntax Tree (AST). AST представляет собой древовидную структуру, где каждый узел описывает элемент документа:
type — тип узла (heading,
paragraph, link, text и
т.д.).children — массив дочерних узлов, если элемент содержит
вложенные структуры.value — текстовое содержание узла (для текстовых
узлов).Пример простого Markdown:
# Заголовок 1
Текст абзаца с [ссылкой](https://example.com)
AST через Remark будет выглядеть как:
{
"type": "root",
"children": [
{
"type": "heading",
"depth": 1,
"children": [
{ "type": "text", "value": "Заголовок 1" }
]
},
{
"type": "paragraph",
"children": [
{ "type": "text", "value": "Текст абзаца с " },
{
"type": "link",
"url": "https://example.com",
"children": [{ "type": "text", "value": "ссылкой" }]
}
]
}
]
}
AST позволяет извлекать информацию и изменять документ программно. Основные методы навигации:
Рекурсивный обход дерева
function traverse(node) {
console.log(node.type);
if (node.children) {
node.children.forEach(traverse);
}
}
traverse(ast);
Рекурсивная функция обходит каждый узел, печатая его тип.
Использование unist-util-visit
Библиотека unist-util-visit упрощает поиск узлов нужного
типа:
import { visit } from 'unist-util-visit';
visit(ast, 'heading', node => {
console.log(node.depth, node.children[0].value);
});Remark и Rehype позволяют искать узлы по типу, значению или атрибутам.
Поиск по типу:
visit(ast, 'link', node => console.log(node.url));Фильтрация с условием:
const externalLinks = [];
visit(ast, 'link', node => {
if (node.url.startsWith('http')) {
externalLinks.push(node.url);
}
});Извлечение текста заголовков:
const headings = [];
visit(ast, 'heading', node => {
const text = node.children.map(child => child.value).join('');
headings.push({ depth: node.depth, text });
});Добавление узлов:
ast.children.push({
type: 'paragraph',
children: [{ type: 'text', value: 'Новый абзац добавлен программно' }]
});
Замена узлов:
visit(ast, 'heading', node => {
if (node.depth === 2) {
node.children = [{ type: 'text', value: 'Обновленный заголовок' }];
}
});
Удаление узлов через
unist-util-remove:
import { remove } from 'unist-util-remove';
remove(ast, node => node.type === 'link' && node.url.includes('spam'));
После обработки Markdown через Remark можно преобразовать AST в HTML с помощью remark-rehype:
import { unified } from 'unified';
import remarkParse from 'remark-parse';
import remarkRehype from 'remark-rehype';
import rehypeStringify from 'rehype-stringify';
const html = await unified()
.use(remarkParse)
.use(remarkRehype)
.use(rehypeStringify)
.process('# Заголовок и [ссылка](https://example.com)');
console.log(html.toString());
AST Rehype похож на DOM, что позволяет поиск и навигацию по HTML-узлам:
tagName — имя HTML-тега.properties — атрибуты (className,
href, id).children — вложенные элементы.Пример поиска всех ссылок в Rehype:
visit(ast, 'element', node => {
if (node.tagName === 'a') {
console.log(node.properties.href);
}
});
С помощью Rehype можно выполнять массовое обновление атрибутов:
visit(ast, 'element', node => {
if (node.tagName === 'img') {
node.properties.loading = 'lazy';
}
});
Это полезно для оптимизации веб-страниц и добавления SEO-атрибутов.
AST позволяет создавать оглавления и карту документа:
const toc = [];
visit(ast, 'heading', node => {
const text = node.children.map(c => c.value).join('');
const id = text.toLowerCase().replace(/\s+/g, '-');
toc.push({ id, text, depth: node.depth });
});
Результат можно использовать для генерации боковой панели или внутренней навигации.
unist-util-visit для целенаправленного
обхода вместо ручной рекурсии.unist-util-visit-parents, чтобы иметь доступ к родительским
узлам.Remark и Rehype образуют мощный тандем для анализa, модификации и генерации контента, обеспечивая гибкую навигацию и поиск по документам, будь то Markdown или HTML.