Элементы и их атрибуты

Основы работы с элементами

В экосистеме Remark и Rehype основным строительным блоком являются узлы (nodes), которые представляют отдельные элементы документа. В Remark это обычно Markdown-узлы, в Rehype — HTML-узлы. Каждый узел имеет тип, который определяет его роль: paragraph, heading, text, link, image и т.д.

Узлы могут содержать дочерние узлы в свойстве children и атрибуты в зависимости от типа. В HTML-узлах, используемых Rehype, атрибуты хранятся в объекте properties, где ключ — это имя атрибута, а значение — его содержимое.

Пример структуры HTML-узла для изображения:

const imageNode = {
  type: 'element',
  tagName: 'img',
  properties: {
    src: 'image.png',
    alt: 'Пример изображения',
    width: 400,
  },
  children: [],
};

Здесь type: 'element' указывает на HTML-элемент, tagName — название тега, properties — объект с атрибутами, children — массив дочерних узлов (для <img> он пустой, так как это самозакрывающийся тег).


Атрибуты элементов

Атрибуты элементов в Rehype обрабатываются через объект properties. Поддерживаются как стандартные HTML-атрибуты (id, className, src, alt, href и т.д.), так и кастомные пользовательские атрибуты. Ключевой момент — использование className вместо class, поскольку class является зарезервированным словом в JavaScript.

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

const paragraphNode = {
  type: 'element',
  tagName: 'p',
  properties: {
    className: ['highlighted', 'intro'],
    style: 'color: red; font-weight: bold;',
  },
  children: [
    { type: 'text', value: 'Текст параграфа с классами и стилями.' },
  ],
};

Здесь className принимает массив классов, а style — строку с CSS-свойствами.


Вложенные элементы

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

const listNode = {
  type: 'element',
  tagName: 'ul',
  children: [
    {
      type: 'element',
      tagName: 'li',
      children: [
        {
          type: 'element',
          tagName: 'a',
          properties: { href: 'https://example.com' },
          children: [{ type: 'text', value: 'Ссылка внутри списка' }],
        },
      ],
    },
  ],
};

Каждый уровень вложенности представлен отдельным узлом с типом element. Атрибуты всегда хранятся в properties, а содержимое текста — в children через узлы text.


Обработка атрибутов и модификация узлов

Для изменения атрибутов используется обход дерева узлов и изменение объектов properties. С помощью unist-util-visit можно найти нужные элементы и корректировать их атрибуты:

import { visit } from 'unist-util-visit';

visit(tree, 'element', (node) => {
  if (node.tagName === 'a') {
    node.properties.target = '_blank';
    node.properties.rel = 'noopener noreferrer';
  }
});

В этом примере все ссылки получают атрибуты target="_blank" и rel="noopener noreferrer", что важно для безопасности при открытии внешних сайтов.


Специальные атрибуты для Markdown

Remark преобразует Markdown в AST (Abstract Syntax Tree), где текстовые и структурные элементы не имеют HTML-атрибутов по умолчанию. Чтобы добавить атрибуты, используется плагин remark-directive или remark-attr:

:::note class="important"
Это важная заметка
:::

После обработки через соответствующий плагин узел div будет иметь:

{
  type: 'element',
  tagName: 'div',
  properties: { className: ['note', 'important'] },
  children: [{ type: 'text', value: 'Это важная заметка' }],
}

Атрибуты пользовательских элементов

Для расширяемых компонентов (custom components) в Rehype или при интеграции с React через rehype-react атрибуты передаются напрямую как свойства:

const customNode = {
  type: 'element',
  tagName: 'MyComponent',
  properties: {
    title: 'Пример компонента',
    isActive: true,
  },
  children: [
    { type: 'text', value: 'Содержимое компонента' },
  ],
};

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


Атрибуты и их типы

  • Строковыеalt, title, href, src.
  • Булевыchecked, disabled, readonly.
  • МассивыclassName, списки токенов.
  • Объектыstyle может быть как строкой, так и объектом CSS-свойств при интеграции с React.

Поддержка типов атрибутов важна для корректного рендеринга и совместимости с инструментами анализа AST.


Рекомендации по организации атрибутов

  1. Использовать properties для всех атрибутов. Это единый стандарт для Rehype.
  2. Приводить классы к массиву строк через className.
  3. Стиль писать как строку CSS, либо как объект для JSX.
  4. Булевы атрибуты устанавливать явно, чтобы избежать неожиданных значений undefined.
  5. Модифицировать дерево через обход узлов, избегая прямого изменения исходных данных Markdown.

Эти правила обеспечивают консистентность при работе с AST и упрощают интеграцию с другими инструментами обработки Markdown и HTML.