Создание токенов в плагине

В Markdown-it любой процесс обработки текста начинается с лексического анализа, который превращает входной Markdown в последовательность токенов. Токены — это структуры, описывающие блоки или inline-элементы разметки, включая их тип, содержимое и дополнительные атрибуты. Понимание и создание токенов является ключевым для разработки собственных плагинов и расширений.

Структура токена

Токен в Markdown-it представляет собой объект с определёнными полями:

  • type — строка, обозначающая тип токена, например paragraph_open, inline, text.
  • tag — HTML-тег, соответствующий токену (p, strong, em и т.д.).
  • attrs — массив атрибутов, например [["class", "highlight"]].
  • map — массив с начальной и конечной строкой исходного текста [startLine, endLine].
  • nesting — целое число: 1 для открывающего тега, -1 для закрывающего, 0 для самостоятельного.
  • level — глубина вложенности в дереве документа.
  • children — массив вложенных токенов (для inline элементов).
  • content — строка с текстом (для текстовых токенов).

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

const token = new state.Token('text', '', 0);
token.content = 'Пример текста';

Создание блоковых токенов

Для добавления нового блокового элемента создаётся открывающий токен, затем при необходимости вложенные токены, и закрывающий токен. Например, для создания блока с пользовательским тегом note:

const openToken = new state.Token('note_open', 'div', 1);
openToken.attrs = [['class', 'note']];
openToken.map = [startLine, endLine];

const contentToken = new state.Token('inline', '', 0);
contentToken.content = 'Содержимое блока note';
contentToken.children = [];

const closeToken = new state.Token('note_close', 'div', -1);

state.tokens.push(openToken, contentToken, closeToken);

Ключевой момент: правильная установка поля nesting. Оно определяет, как Markdown-it будет интерпретировать токен при генерации HTML. Ошибка в nesting может привести к некорректному рендерингу или пропуску содержимого.

Встроенные токены (inline)

Inline-токены отвечают за форматирование внутри строки: жирный, курсив, ссылки, изображения. Их создают внутри inline токена через поле children.

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

const inlineToken = new state.Token('inline', '', 0);

const strongOpen = new state.Token('strong_open', 'strong', 1);
const text = new state.Token('text', '', 0);
text.content = 'Выделенный текст';
const strongClose = new state.Token('strong_close', 'strong', -1);

inlineToken.children = [strongOpen, text, strongClose];
state.tokens.push(inlineToken);

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

Каждый токен может содержать массив атрибутов. Атрибуты хранятся в виде массивов [имя, значение]. Для добавления или изменения атрибута:

token.attrs = token.attrs || [];
token.attrs.push(['id', 'custom-id']);

Для поиска и модификации существующего атрибута:

const index = token.attrs.findIndex(attr => attr[0] === 'class');
if (index >= 0) {
    token.attrs[index][1] += ' additional-class';
}

Создание токенов в плагине

При разработке плагина создаются новые правила для блоков или inline-элементов. Для блоков добавляют правило в md.block.ruler, для inline — в md.inline.ruler. Правило — это функция с сигнатурой:

function myBlockRule(state, startLine, endLine, silent) {
    // 1. Проверка условия
    // 2. Создание открывающего токена
    // 3. Создание контентных токенов
    // 4. Создание закрывающего токена
    return true; // если блок успешно обработан
}

Пример добавления правила:

md.block.ruler.before('paragraph', 'note_block', myBlockRule);

Внутри функции state.tokens.push(...) добавляются все необходимые токены, а state.line обновляется для перехода к следующей необработанной строке.

Полезные методы и свойства

  • state.push(type, tag, nesting) — создает и добавляет токен в текущий массив state.tokens.
  • state.md.renderer.render(tokens, options, env) — позволяет рендерить массив токенов в HTML.
  • state.src.slice(start, end) — извлекает подстроку исходного Markdown.
  • state.bMarks и state.eMarks — массивы с индексами начала и конца строк для точной навигации по тексту.

Советы при создании токенов

  • Всегда указывать nesting корректно: 1 открывающий, -1 закрывающий, 0 самостоятельный.
  • Для inline-токенов обязательно формировать children.
  • Проверять map, чтобы корректно работали редакторы и подсветка синтаксиса.
  • Использовать уникальные type, чтобы не конфликтовать с внутренними правилами Markdown-it.

Создание токенов — это фундамент расширений Markdown-it. Понимание их структуры и правильное использование открывает возможности для создания сложных кастомных блоков и элементов, полностью интегрированных с системой рендеринга.