Типы узлов HAST

HAST (Hypertext Abstract Syntax Tree) — это абстрактное представление HTML-документа в виде дерева, где каждый элемент структуры HTML представлен узлом с определённым типом и набором свойств. Работа с HAST в экосистеме Rehype позволяет анализировать, модифицировать и генерировать HTML на программном уровне, обеспечивая гибкость и безопасность при обработке разметки.

Основные типы узлов HAST

В HAST различают несколько ключевых типов узлов, каждый из которых отражает определённый аспект HTML-документа. Понимание этих типов необходимо для корректного обхода дерева и трансформации контента.

  1. Element (Элемент)

    • Представляет стандартный HTML-тег, такой как <div>, <p> или <a>.

    • Основные свойства:

      • tagName — строка с названием тега.
      • properties — объект с атрибутами элемента (например, class, id, href).
      • children — массив дочерних узлов, которые могут быть другими элементами или текстовыми узлами.
    • Пример структуры:

      {
        type: 'element',
        tagName: 'p',
        properties: { className: ['intro'] },
        children: [
          { type: 'text', value: 'Пример текста.' }
        ]
      }
  2. Text (Текстовый узел)

    • Содержит текст внутри элемента HTML.

    • Основное свойство:

      • value — строка с текстом.
    • Текстовые узлы не имеют дочерних элементов.

    • Пример:

      { type: 'text', value: 'Здесь находится текст.' }
  3. Comment (Комментарий)

    • Представляет HTML-комментарий.

    • Свойства:

      • value — содержимое комментария без <!-- и -->.
    • Пример:

      { type: 'comment', value: 'Это комментарий' }
  4. Doctype (Тип документа)

    • Используется для указания типа документа (<!DOCTYPE html>).

    • Свойства:

      • name — имя типа документа.
      • public — публичная идентификация DTD (при наличии).
      • system — системная идентификация DTD (при наличии).
    • Пример:

      { type: 'doctype', name: 'html' }
  5. Raw (Необработанный контент)

    • Содержит HTML, который не должен быть преобразован Rehype.

    • Применяется редко, в основном при генерации кода без изменений.

    • Пример:

      { type: 'raw', value: '<script>alert("Hello")</script>' }

Специфика работы с элементами HAST

Дочерние узлы элементов могут быть любого типа, что позволяет строить сложные вложенные структуры. Например, элемент <ul> может содержать несколько <li>, а каждый <li> — текстовый узел или даже вложенный <ul>.

Атрибуты и свойства элементов в HAST представлены объектом properties. Некоторые HTML-атрибуты, такие как class, преобразуются в массивы (className: ['example']), что облегчает их обработку программно. Специальное внимание стоит уделять boolean-атрибутам (checked, disabled), которые в HAST хранятся как true или false.

Примеры обхода HAST

Для обхода дерева HAST часто используют рекурсивные функции или утилиты вроде unist-util-visit. Основные приёмы включают:

  • Поиск всех элементов определённого типа

    import { visit } from 'unist-util-visit';
    
    visit(tree, 'element', node => {
      if (node.tagName === 'a') {
        console.log(node.properties.href);
      }
    });
  • Изменение текстового содержимого

    visit(tree, 'text', node => {
      node.value = node.value.toUpperCase();
    });
  • Удаление комментариев

    visit(tree, 'comment', (node, index, parent) => {
      parent.children.splice(index, 1);
    });

Практические рекомендации

  • Всегда проверять type узла перед доступом к его свойствам, чтобы избежать ошибок при обходе дерева.
  • Для элементов с атрибутами использовать properties вместо прямого доступа к HTML-атрибутам.
  • Текстовые узлы можно безопасно модифицировать напрямую, так как они не содержат дочерних элементов.
  • Комментарии и doctype можно игнорировать при генерации контента, если не требуется их сохранение.

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