Переход от Remark к Rehype

Remark — это мощная библиотека для парсинга, анализа и трансформации Markdown-документов в AST (Abstract Syntax Tree). Она предоставляет средства для работы с содержимым Markdown, включая создание плагинов, обработку синтаксиса и генерацию новых структур данных. Rehype, в свою очередь, предназначен для работы с HTML-документами и AST, который соответствует HTML-дереву. Переход от Remark к Rehype позволяет преобразовывать Markdown в HTML и применять к нему расширенные трансформации.

Архитектура Remark

Remark разбивает процесс работы с Markdown на несколько ключевых этапов:

  1. Парсинг — Markdown преобразуется в AST формата MDAST (Markdown Abstract Syntax Tree). Каждая структура документа, будь то заголовок, параграф, список или ссылка, становится отдельным узлом дерева.
  2. Трансформация — на этом этапе можно применять плагины, которые изменяют структуру AST, добавляют новые узлы, изменяют текст или атрибуты.
  3. Генерация — преобразованное дерево может быть возвращено обратно в Markdown, в HTML (через Rehype) или в другой формат.

Ключевой особенностью Remark является модульность: каждый плагин работает с AST и может быть добавлен или удалён без изменения основного потока обработки документа.

Переход от MDAST к HAST

HAST (Hypertext Abstract Syntax Tree) — это формат AST, используемый Rehype для HTML. Чтобы конвертировать Markdown в HTML через промежуточное AST, используется утилита remark-rehype.

Пример конверсии:

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) // преобразует MDAST в HAST
  .use(rehypeStringify); // преобразует HAST в HTML

const markdown = '# Заголовок\n\nТекст параграфа.';
processor.process(markdown).then(file => {
  console.log(String(file));
});

В этом примере:

  • remarkParse создает MDAST из Markdown.
  • remarkRehype преобразует MDAST в HAST.
  • rehypeStringify превращает HAST в готовый HTML.

Работа с плагинами

Remark и Rehype поддерживают плагины для расширенной обработки узлов AST.

Примеры возможностей:

  • Добавление классов к элементам HTML.
  • Преобразование ссылок для SEO.
  • Вставка кастомного содержимого (например, подсветка кода).
  • Фильтрация или удаление определённых узлов.

Пример плагина для добавления класса к заголовкам:

import rehypeVisit from 'unist-util-visit';

function addHeadingClass() {
  return (tree) => {
    rehypeVisit(tree, 'element', node => {
      if (node.tagName === 'h1') {
        node.properties = node.properties || {};
        node.properties.className = ['main-heading'];
      }
    });
  };
}

const processor = unified()
  .use(remarkParse)
  .use(remarkRehype)
  .use(addHeadingClass)
  .use(rehypeStringify);

Преобразования и цепочки обработки

Remark и Rehype поддерживают каскадные цепочки трансформаций:

  1. Сначала анализ Markdown в MDAST.
  2. Затем преобразование MDAST в HAST.
  3. Далее любые изменения в HAST с помощью Rehype-плагинов.
  4. И, наконец, генерация HTML или другой целевой разметки.

Это позволяет комбинировать мощь обеих библиотек и создавать гибкие пайплайны. Например, Markdown-документ можно анализировать с помощью Remark, затем обогащать HTML-атрибутами и классами с помощью Rehype, а затем превращать в статический HTML для сайта.

Практические советы по миграции

  • Минимизировать повторное создание узлов: преобразование MDAST → HAST не должно создавать лишние вложенности.
  • Использовать встроенные утилиты для обхода дерева: unist-util-visit и unist-util-map упрощают модификацию AST.
  • Разделять ответственность плагинов: Remark-плагины должны работать с Markdown-содержимым, а Rehype-плагины — с HTML-структурой.
  • Следить за совместимостью типов узлов: MDAST и HAST имеют разные схемы, поэтому важно проверять, какой тип узла ожидается плагином.

Настройка генерации HTML

Rehype позволяет полностью контролировать итоговый HTML:

  • Управление атрибутами тегов.
  • Поддержка вложенных элементов и блоков.
  • Оптимизация HTML для SEO или статического рендеринга.
  • Поддержка синтаксиса React или JSX через rehype-react.

Пример интеграции с React:

import rehypeReact from 'rehype-react';
import { createElement } from 'react';

const processor = unified()
  .use(remarkParse)
  .use(remarkRehype)
  .use(rehypeReact, { createElement });

const reactElements = processor.processSync(markdown).result;

Этот подход позволяет использовать Markdown как источник контента и динамически рендерить его в компоненты React.

Итоговые ключевые моменты

  • Remark работает с Markdown, Rehype — с HTML.
  • remark-rehype соединяет две библиотеки через конвертацию AST.
  • Плагины позволяют гибко модифицировать дерево на любом этапе.
  • Разделение задач между MDAST и HAST обеспечивает чистую архитектуру обработки.
  • Возможности интеграции с React или другими платформами расширяют сферу применения.

Такой подход обеспечивает мощный, модульный и расширяемый пайплайн для преобразования, анализа и генерации веб-контента из Markdown.