Строчные элементы

Строчные элементы (inline elements) — это элементы, которые располагаются внутри блочных элементов и не создают новых блоков разметки. В контексте работы с Markdown через библиотеку Remark и его HTML-парсер Rehype понимание структуры и обработки строчных элементов критично для точного преобразования и модификации контента.


Основные типы строчных элементов

В Markdown и соответствующих AST (Abstract Syntax Tree) структурах Remark выделяются следующие ключевые строчные элементы:

  • Text (text) Наиболее простой тип узла, содержащий текст без форматирования.

    { type: 'text', value: 'Пример текста' }
  • Emphasis (emphasis) Представляет курсивное выделение текста, создается с помощью * или _.

    {
      type: 'emphasis',
      children: [{ type: 'text', value: 'курсив' }]
    }
  • Strong (strong) Жирное выделение текста через ** или __.

    {
      type: 'strong',
      children: [{ type: 'text', value: 'жирный текст' }]
    }
  • InlineCode (inlineCode) Код внутри строки, обрамленный обратными кавычками `.

    { type: 'inlineCode', value: 'console.log("Hello")' }
  • Link (link) Гиперссылки с текстом и URL.

    {
      type: 'link',
      url: 'https://example.com',
      title: 'Пример',
      children: [{ type: 'text', value: 'Перейти на сайт' }]
    }
  • Image (image) Встраиваемое изображение с альтернативным текстом и URL.

    {
      type: 'image',
      url: 'https://example.com/image.png',
      alt: 'Описание изображения'
    }
  • Break (break) Принудительный перенос строки. В AST представлен узлом типа break.


Структура AST для строчных элементов

AST в Remark строится иерархически: блочные элементы содержат массив children, внутри которого находятся строчные узлы. Пример для параграфа:

{
  type: 'paragraph',
  children: [
    { type: 'text', value: 'Это пример ' },
    { type: 'strong', children: [{ type: 'text', value: 'жирного текста' }] },
    { type: 'text', value: ' и ' },
    { type: 'emphasis', children: [{ type: 'text', value: 'курсива' }] },
    { type: 'text', value: '.' }
  ]
}

Каждый строчный элемент может содержать другие строчные элементы в качестве дочерних узлов. Это позволяет строить сложные структуры текста: ссылки внутри жирного текста, код внутри курсивного выделения и т. д.


Преобразования с помощью Rehype

Rehype используется для конвертации Markdown AST в HTML AST или для обхода HTML-структуры. Строчные элементы требуют внимательного маппинга:

Remark Type Rehype Element Примечание
text #text Прямое отображение текста
emphasis em Оборачивает дочерние узлы в тег <em>
strong strong Оборачивает дочерние узлы в тег <strong>
inlineCode code Тег <code> без блока
link a Атрибуты href и title передаются из AST
image img Атрибуты src и alt передаются напрямую

Работа с плагинами для строчных элементов

Remark предоставляет возможность создавать плагины для обработки и модификации AST. Для строчных элементов часто используют следующие подходы:

  • Поиск и замена текста Обход всех text узлов и изменение их значения.

    function remarkReplaceText() {
      return (tree) => {
        visit(tree, 'text', (node) => {
          node.value = node.value.replace(/важно/g, 'ВАЖНО');
        });
      };
    }
  • Оборачивание узлов в теги Пример: все слова важно оборачиваются в strong.

    function remarkWrapImportant() {
      return (tree) => {
        visit(tree, 'text', (node, index, parent) => {
          if (node.value.includes('важно')) {
            const parts = node.value.split(/(важно)/);
            const newNodes = parts.map((part) =>
              part === 'важно'
                ? { type: 'strong', children: [{ type: 'text', value: part }] }
                : { type: 'text', value: part }
            );
            parent.children.splice(index, 1, ...newNodes);
          }
        });
      };
    }
  • Конвертация в HTML После обработки AST с помощью плагинов можно использовать rehype для генерации HTML с корректными тегами для строчных элементов.


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

  1. Вложенность Все строчные элементы поддерживают рекурсивную вложенность, что важно учитывать при обходе AST.

  2. Порядок обхода Порядок обхода узлов может влиять на результаты обработки, особенно при модификации текста внутри strong и emphasis.

  3. Сочетание с блочными элементами Понимание того, что строчные элементы существуют внутри блочных элементов, помогает правильно строить плагины и трансформации Markdown в HTML.

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


Практический пример полной обработки

Пример плагина для Remark + Rehype, который:

  1. Находит все вхождения слова JavaScript.
  2. Оборачивает их в <strong>.
  3. Конвертирует в HTML.
import { unified } from 'unified';
import remarkParse from 'remark-parse';
import remarkRehype from 'remark-rehype';
import rehypeStringify from 'rehype-stringify';
import { visit } from 'unist-util-visit';

function wrapJavaScript() {
  return (tree) => {
    visit(tree, 'text', (node, index, parent) => {
      if (node.value.includes('JavaScript')) {
        const parts = node.value.split(/(JavaScript)/);
        const newNodes = parts.map((part) =>
          part === 'JavaScript'
            ? { type: 'strong', children: [{ type: 'text', value: part }] }
            : { type: 'text', value: part }
        );
        parent.children.splice(index, 1, ...newNodes);
      }
    });
  };
}

const processor = unified()
  .use(remarkParse)
  .use(wrapJavaScript)
  .use(remarkRehype)
  .use(rehypeStringify);

const markdown = 'Я изучаю JavaScript и хочу стать экспертом.';
processor.process(markdown).then((file) => console.log(String(file)));

Результат генерации HTML:

<p>Я изучаю <strong>JavaScript</strong> и хочу стать экспертом.</p>

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