В экосистеме 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",
что важно для безопасности при открытии внешних сайтов.
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.
properties для всех
атрибутов. Это единый стандарт для Rehype.className.undefined.Эти правила обеспечивают консистентность при работе с AST и упрощают интеграцию с другими инструментами обработки Markdown и HTML.