MDAST: спецификация дерева Markdown

MDAST (Markdown Abstract Syntax Tree) — это абстрактное синтаксическое дерево, которое используется библиотеками Remark и Rehype для представления содержимого Markdown в структурированном виде. Оно позволяет анализировать, трансформировать и генерировать Markdown-приложения программным способом. Каждое дерево MDAST состоит из узлов, которые отражают элементы Markdown, такие как заголовки, параграфы, списки, ссылки и другие.

Каждый узел MDAST имеет тип и свойства. Основное свойство узла — type, определяющее его категорию. Например, узел с типом "paragraph" соответствует параграфу текста, а "heading" — заголовку.

{
  type: 'paragraph',
  children: [
    { type: 'text', value: 'Пример параграфа.' }
  ]
}

Ключевые характеристики узлов MDAST:

  • type: строка, описывающая тип узла.
  • children: массив дочерних узлов (используется для вложенных структур).
  • value: строка текста (для листовых узлов, таких как "text").
  • depth: уровень заголовка (для узлов типа "heading").
  • ordered и start: свойства списков, определяющие нумерацию и начальное значение.

Типы узлов MDAST

Листовые узлы (Leaf Nodes) Листовые узлы содержат только текстовое значение и не имеют дочерних элементов.

  • text — простой текст внутри параграфа или заголовка.
  • inlineCode — фрагменты кода внутри текста.
  • break — перенос строки.
  • thematicBreak — горизонтальная линия.

Композитные узлы (Parent Nodes) Композитные узлы содержат массив дочерних узлов в свойстве children.

  • paragraph — параграф текста.
  • heading — заголовок, с атрибутом depth (уровень 1–6).
  • list — список, упорядоченный или нет, с массивом children элементов списка.
  • listItem — элемент списка.
  • blockquote — цитата, содержащая дочерние узлы.

Пример сложного MDAST

{
  type: 'root',
  children: [
    {
      type: 'heading',
      depth: 2,
      children: [{ type: 'text', value: 'Пример заголовка' }]
    },
    {
      type: 'paragraph',
      children: [{ type: 'text', value: 'Это пример параграфа с ' },
                 { type: 'strong', children: [{ type: 'text', value: 'жирным текстом' }] }]
    },
    {
      type: 'list',
      ordered: true,
      start: 1,
      children: [
        { type: 'listItem', children: [{ type: 'paragraph', children: [{ type: 'text', value: 'Первый элемент' }] }] },
        { type: 'listItem', children: [{ type: 'paragraph', children: [{ type: 'text', value: 'Второй элемент' }] }] }
      ]
    }
  ]
}

Особенности работы с MDAST

  1. Парсинг Markdown Remark предоставляет функцию remark().parse(markdown), которая конвертирует текст в дерево MDAST. Каждый узел в дереве отражает отдельный синтаксический элемент Markdown.

  2. Трансформации дерева Узлы можно модифицировать, добавлять или удалять с помощью плагинов. Плагины работают рекурсивно с узлами, что позволяет выполнять сложные операции, например, автоматическое добавление якорей к заголовкам или обогащение ссылок дополнительными атрибутами.

  3. Генерация Markdown После изменения дерева MDAST его можно обратно конвертировать в Markdown с помощью remark().stringify(tree). Структура дерева гарантирует, что все вложенные элементы сохранят правильное форматирование.

  4. Интеграция с Rehype Для работы с HTML используется библиотека Rehype. MDAST легко преобразуется в HAST (HTML AST) через плагин remark-rehype. Это позволяет использовать один и тот же Markdown-код как источник для HTML и других форматов.

Важные свойства и соглашения

  • position — свойство, указывающее диапазон строк и столбцов исходного Markdown. Оно важно для линтеров, подсветки синтаксиса и инструментов анализа.
  • data — объект для хранения пользовательских метаданных в узлах.
  • Узлы без дочерних элементов считаются листовыми.
  • Все дочерние элементы должны быть корректными узлами MDAST для поддержания совместимости с плагинами Remark.

Принципы построения дерева

  • Корневой узел всегда имеет type: 'root'.
  • Все текстовые элементы находятся внутри листовых узлов text.
  • Композитные узлы могут содержать другие композитные узлы, создавая иерархию.
  • Узлы могут содержать дополнительные свойства, специфичные для конкретного типа (например, alt и url для изображений).

Применение MDAST в проектах

MDAST используется для:

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

Строгая спецификация MDAST обеспечивает предсказуемое поведение парсеров и плагинов, что делает его основой для всех задач обработки Markdown в экосистеме Remark и Rehype.