Изменение атрибутов

Remark и Rehype — это мощные инструменты для работы с Markdown и HTML в экосистеме JavaScript. Один из ключевых сценариев их использования — манипуляция атрибутами элементов, будь то HTML-теги, встроенные изображения или ссылки в Markdown. Атрибуты позволяют контролировать поведение и оформление контента, поэтому умение их изменять является важным навыком при построении парсеров и трансформаций.


Работа с атрибутами в Rehype

Rehype оперирует деревом AST (Abstract Syntax Tree) для HTML, где каждый узел представляет собой элемент, текст или комментарий. Атрибуты элемента хранятся в объекте properties. Для изменения атрибутов используется обход дерева через плагины или функции трансформации.

Пример базового обхода узлов с модификацией атрибутов:

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

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

Ключевые моменты:

  • visit(tree, 'element', callback) — стандартный способ обхода элементов.
  • node.tagName определяет тип HTML-тега.
  • node.properties — объект, где ключи соответствуют атрибутам HTML, а значения — их значения.
  • С помощью спред-оператора ...node.properties сохраняются существующие атрибуты.

Добавление и удаление атрибутов

Для добавления нового атрибута достаточно назначить его в объекте properties:

node.properties.id = 'unique-id';
node.properties.className = ['highlighted', 'active'];

Для удаления атрибута используется delete:

delete node.properties.style;

Особенности работы с классами и стилями:

  • className всегда массив строк.
  • style хранится как объект {property: value} и может быть преобразован в строку при необходимости.

Использование плагинов для Rehype

Существуют готовые плагины, облегчающие изменение атрибутов:

  1. rehype-add-attributes — позволяет автоматически добавлять атрибуты по селекторам:
import rehypeAddAttributes from 'rehype-add-attributes';

const processor = unified()
  .use(rehypeParse)
  .use(rehypeAddAttributes, { 
    selector: 'img',
    attributes: { loading: 'lazy', className: 'responsive' }
  })
  .use(rehypeStringify);
  1. rehype-remove-attributes — удаляет атрибуты по имени или селектору.

Плагины особенно удобны при работе с большим деревом или при повторяющихся правилах изменения атрибутов.


Работа с атрибутами в Remark

Remark работает с Markdown и не оперирует HTML напрямую, но поддерживает расширения через MDX или remark-directive. Для встроенного HTML и ссылок используется узлы типа link, image или html.

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

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

function modifyLinkAttributes() {
  return (tree) => {
    visit(tree, 'link', (node) => {
      node.data = node.data || {};
      node.data.hProperties = {
        ...node.data.hProperties,
        target: '_blank',
        rel: 'noopener noreferrer'
      };
    });
  };
}

Важные детали:

  • node.data.hProperties используется для передачи атрибутов HTML в процессе конвертации Markdown → HTML.
  • Markdown-узлы не имеют properties напрямую, поэтому изменения проводятся через hProperties.

Комбинированная трансформация Markdown → HTML → модификация атрибутов

В типичном пайплайне Remark → Rehype атрибуты можно изменять на двух уровнях:

  1. На уровне Markdown — изменение ссылок, изображений через remark плагины.
  2. На уровне HTML — более гибкое добавление атрибутов к любым тегам через 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)
  .use(modifyAttributes)  // Rehype plugin
  .use(rehypeStringify);

const html = processor.processSync(markdownContent).toString();

Рекомендации при работе с атрибутами

  • Проверять существующие атрибуты перед их перезаписью.
  • Для классов использовать массивы, чтобы избежать ошибок при объединении стилей.
  • Использовать unist-util-visit для обхода и модификации только нужных узлов.
  • При больших документах эффективнее применять плагины, чем писать сложные рекурсивные обходы вручную.

Изменение атрибутов в Remark и Rehype предоставляет полный контроль над HTML, генерируемым из Markdown. Гибкость AST позволяет как простое добавление target="_blank" для ссылок, так и сложные трансформации стилей, классов и других пользовательских атрибутов, что делает эти библиотеки незаменимыми в современной веб-разработке.