Обработка пользовательского контента

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

Структура AST в Remark

Remark строит дерево синтаксического анализа Markdown. Каждый узел дерева имеет тип и свойства. Типы узлов включают:

  • root — корневой узел документа.
  • paragraph — абзац текста.
  • heading — заголовок (depth указывает уровень).
  • text — текстовая нода.
  • link — ссылка с атрибутами url и title.
  • image — изображение с url и alt.

Пример AST для Markdown # Заголовок\nТекст абзаца выглядит так:

{
  "type": "root",
  "children": [
    {
      "type": "heading",
      "depth": 1,
      "children": [{ "type": "text", "value": "Заголовок" }]
    },
    {
      "type": "paragraph",
      "children": [{ "type": "text", "value": "Текст абзаца" }]
    }
  ]
}

Подключение и базовая настройка

Установка библиотек через npm:

npm install remark remark-html rehype rehype-stringify

Простейший пример преобразования Markdown в HTML:

import { remark } from 'remark';
import remarkHtml from 'remark-html';

const markdown = '# Заголовок\nТекст абзаца';

remark()
  .use(remarkHtml)
  .process(markdown)
  .then(file => {
    console.log(String(file));
  });

Здесь remarkHtml превращает Markdown AST в HTML через промежуточное дерево.

Плагины Remark и Rehype

Плагины позволяют расширять функциональность:

  • remark-parse — парсер Markdown.
  • remark-stringify — генератор Markdown из AST.
  • remark-gfm — поддержка GitHub Flavored Markdown (таблицы, чекбоксы, автоссылки).
  • rehype-parse — парсер HTML.
  • rehype-stringify — генератор HTML из AST.
  • rehype-sanitize — безопасная обработка HTML (удаление потенциально вредоносного контента).

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

import { remark } from 'remark';
import remarkGfm from 'remark-gfm';
import remarkHtml from 'remark-html';

const markdown = '## Список задач\n- [x] Выполнено\n- [ ] В процессе';

remark()
  .use(remarkGfm)
  .use(remarkHtml)
  .process(markdown)
  .then(file => console.log(String(file)));

Трансформация AST

Remark и Rehype предоставляют возможности для изменения контента на уровне AST. Например, для добавления CSS-класса к заголовкам можно использовать собственный плагин:

function addClassToHeadings() {
  return (tree) => {
    visit(tree, 'heading', (node) => {
      if (!node.data) node.data = {};
      if (!node.data.hProperties) node.data.hProperties = {};
      node.data.hProperties.className = 'custom-heading';
    });
  };
}

remark()
  .use(addClassToHeadings)
  .use(remarkHtml)
  .process('# Заголовок')
  .then(file => console.log(String(file)));

visit — утилита из пакета unist-util-visit, которая позволяет обходить AST и модифицировать узлы по типу.

Интеграция Remark и Rehype

Часто Markdown нужно превратить в безопасный HTML с дальнейшей обработкой. Для этого Remark и Rehype можно комбинировать через unified:

import { unified } from 'unified';
import remarkParse from 'remark-parse';
import remarkRehype from 'remark-rehype';
import rehypeStringify from 'rehype-stringify';
import rehypeSanitize from 'rehype-sanitize';

const markdown = '# Заголовок\n<p>HTML внутри Markdown</p>';

unified()
  .use(remarkParse)
  .use(remarkRehype, { allowDangerousHtml: true })
  .use(rehypeSanitize)
  .use(rehypeStringify)
  .process(markdown)
  .then(file => console.log(String(file)));

Опция allowDangerousHtml разрешает встроенный HTML, а rehype-sanitize удаляет потенциально опасные теги и атрибуты, что критично для пользовательского контента.

Обработка пользовательского контента

При работе с пользовательским Markdown и HTML важно:

  • Санитизация HTML: удаление скриптов, iframe и встроенных стилей.
  • Валидация Markdown: проверка длины текста, отсутствие запрещённых элементов.
  • Расширение функционала через плагины: чекбоксы, эмодзи, таблицы.

Преобразование Markdown → AST → Rehype AST → безопасный HTML — стандартный рабочий поток для безопасной обработки контента в приложениях типа блогов или форумов.

Советы по оптимизации и расширению

  • Использовать кеширование AST при многократной обработке одинакового контента.
  • Разделять плагины по назначению: одни для парсинга, другие для визуальной трансформации.
  • Для больших документов применять асинхронную обработку и промисы, чтобы не блокировать event loop.
  • При комбинировании с React удобно использовать rehype-react для генерации React-компонентов из AST.

Ключевые методы и утилиты

  • unified().use(parser).use(transformer).process(content) — основной поток обработки.
  • visit(tree, type, callback) — обход узлов AST.
  • toString(node) — получение текстового содержимого узла.
  • Плагины Remark/Rehype могут быть как синхронными, так и асинхронными, что важно учитывать при построении пайплайна.

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