Построение иерархической структуры

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


Структура узлов AST

Каждый узел AST описывается объектом с ключевыми свойствами:

  • type — тип узла (например, paragraph, heading, text, link).
  • children — массив дочерних узлов, позволяющий формировать иерархию.
  • value — содержимое узла (применимо для текстовых узлов).
  • data — дополнительные метаданные, которые могут быть использованы плагинами.

Пример узла Markdown-параграфа:

{
  type: 'paragraph',
  children: [
    {
      type: 'text',
      value: 'Это пример текста в параграфе.'
    }
  ]
}

В данном примере узел paragraph является родителем для текстового узла text. Именно эта вложенность формирует иерархическую структуру документа, которую Remark и Rehype используют для анализа и трансформации содержимого.


Построение дерева документа

Работа с Remark начинается с разбора Markdown-файла в AST:

import { unified } from 'unified';
import remarkParse from 'remark-parse';

const processor = unified().use(remarkParse);
const tree = processor.parse('# Заголовок\n\nТекст параграфа');

Результатом будет объект дерева, где:

  • root — корневой узел документа.
  • children — массив разделов и параграфов.
  • Вложенные элементы (heading, paragraph) могут содержать свои дочерние узлы (text, link и т.д.).

Такое дерево позволяет рекурсивно обходить все элементы документа, изменять их или добавлять новые узлы на любом уровне вложенности.


Манипуляции с узлами

Основные операции с деревом AST включают:

  1. Добавление узлов:
tree.children.push({
  type: 'paragraph',
  children: [{ type: 'text', value: 'Новый параграф' }]
});
  1. Удаление узлов:
tree.children = tree.children.filter(node => node.type !== 'heading');
  1. Изменение содержимого:
tree.children.forEach(node => {
  if (node.type === 'text') node.value = node.value.toUpperCase();
});

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


Преобразование Markdown в HTML с сохранением иерархии

Remark и Rehype можно объединять для трансформации Markdown в HTML. Важным моментом является сохранение структуры AST при конвертации:

import remarkRehype from 'remark-rehype';
import rehypeStringify from 'rehype-stringify';

const html = await unified()
  .use(remarkParse)
  .use(remarkRehype)
  .use(rehypeStringify)
  .process('# Заголовок\n\nТекст параграфа');

В этом процессе:

  • Remark создаёт Markdown AST.
  • remarkRehype преобразует его в HTML AST, сохраняя иерархию.
  • Rehype генерирует конечный HTML-код.

Рекурсивный обход дерева

Для сложных задач (например, поиск всех ссылок или заголовков) используется рекурсивный обход:

function visit(node, callback) {
  callback(node);
  if (node.children) {
    node.children.forEach(child => visit(child, callback));
  }
}

visit(tree, node => {
  if (node.type === 'link') {
    console.log('Найдена ссылка:', node.url);
  }
});

Этот подход позволяет работать с документом на любом уровне вложенности, добавляя или изменяя элементы без нарушения структуры.


Использование плагинов для расширения возможностей

Remark и Rehype построены на плагинах, которые работают с AST. Плагины могут:

  • Добавлять новые узлы (table, footnote).
  • Преобразовывать узлы (emoji в картинки, автогенерация якорей).
  • Анализировать структуру документа для линтинга или извлечения данных.

Пример плагина для замены всех заголовков на верхний регистр:

function uppercaseHeadings() {
  return tree => {
    visit(tree, node => {
      if (node.type === 'heading') {
        node.children.forEach(child => {
          if (child.type === 'text') child.value = child.value.toUpperCase();
        });
      }
    });
  };
}

Вывод

Иерархическая структура в Remark и Rehype — это ядро работы с Markdown и HTML. Правильное понимание:

  • как строится AST,
  • как добавлять и изменять узлы,
  • как преобразовывать дерево между форматами,

позволяет создавать сложные, динамические и расширяемые системы обработки документов в JavaScript.

Гибкость дерева AST обеспечивает мощный контроль над содержимым, поддерживая строгую и логичную иерархию на всех уровнях документа.