Текстовые узлы

В экосистеме Remark и Rehype текстовые узлы (text nodes) играют ключевую роль в представлении содержимого документа. Они представляют собой «атомарные» единицы текста в дереве синтаксического анализа (AST — Abstract Syntax Tree) и используются для хранения всех строковых данных между тегами или разметкой.

Структура текстового узла

В Markdown и HTML деревьях текстовые узлы имеют простую структуру. В случае Remark для Markdown узел текста имеет тип text:

{
  type: 'text',
  value: 'Пример текста'
}
  • type — всегда 'text' для текстовых узлов.
  • value — строка, содержащая фактический текст.

В Rehype для HTML аналогичная структура:

{
  type: 'text',
  value: 'Содержимое текстового узла'
}

Несмотря на схожесть, в Rehype узлы могут включать дополнительные свойства при необходимости, например позиционные данные (position), которые используются для точной привязки к исходному коду.

Роль текстовых узлов в дереве

Текстовые узлы всегда являются листьями дерева AST. Они не могут содержать дочерних элементов, в отличие от узлов типа paragraph, heading или element. Это делает их ключевыми для анализа, трансформации и генерации текста.

Примеры узлов с текстовыми детьми:

{
  type: 'paragraph',
  children: [
    { type: 'text', value: 'Это простой текст внутри абзаца.' }
  ]
}

В данном случае paragraph является контейнером, а текстовый узел хранит непосредственно содержимое.

Обработка текстовых узлов

Текстовые узлы часто подвергаются трансформации для следующих задач:

  1. Фильтрация и поиск: можно обходить дерево AST и извлекать все текстовые значения.
  2. Замена текста: изменение содержания текста без изменения структуры документа.
  3. Анализ лексем и токенизация: при необходимости разбить текст на слова, предложения или символы.

Пример обхода дерева с использованием unist-util-visit:

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

visit(tree, 'text', (node) => {
  node.value = node.value.toUpperCase();
});

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

Конкатенация и нормализация текста

Часто текст может быть разбит на несколько узлов из-за особенностей парсера. Для обработки целостного текста применяются методы конкатенации узлов:

const paragraphNode = {
  type: 'paragraph',
  children: [
    { type: 'text', value: 'Первое ' },
    { type: 'text', value: 'слово' },
    { type: 'text', value: ' в абзаце.' }
  ]
};

const fullText = paragraphNode.children.map(node => node.value).join('');
// 'Первое слово в абзаце.'

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

Особенности обработки символов и пробелов

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

{ type: 'text', value: 'Символ & должен быть экранирован' }

При рендеринге парсер автоматически преобразует & в &, сохраняя корректность HTML.

Использование текстовых узлов для плагинов

Текстовые узлы часто являются объектом внимания при разработке плагинов для Remark и Rehype:

  • Добавление ссылок или стилей: текстовые узлы могут быть заменены на элементы с вложенными текстовыми узлами.
  • Лемматизация и анализ текста: узлы используются для поиска и модификации словоформ.
  • Автоматическое исправление опечаток и замена символов: текстовый узел можно менять без затрагивания структуры документа.

Пример преобразования текста в Markdown, добавление эмфазы к ключевым словам:

visit(tree, 'text', (node, index, parent) => {
  if (node.value.includes('важно')) {
    parent.children[index] = {
      type: 'emphasis',
      children: [{ type: 'text', value: node.value }]
    };
  }
});

Связь с другими типами узлов

Текстовые узлы тесно связаны с inline-элементами (например, emphasis, strong, link). Внутри таких элементов текст всегда представлен отдельными текстовыми узлами, что обеспечивает унифицированную обработку документа:

{
  type: 'strong',
  children: [
    { type: 'text', value: 'Сильный текст' }
  ]
}

Это позволяет гибко применять трансформации к любой части текста независимо от её окружения.

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

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

Текстовые узлы представляют собой основу всех текстовых операций в Remark и Rehype. Глубокое понимание их структуры и правил обработки позволяет создавать эффективные плагины, выполнять анализ контента и точно контролировать вывод Markdown или HTML.