Методы работы с токенами

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


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

Каждый токен в Markdown-it имеет следующие основные свойства:

  • type — строка, определяющая тип токена, например: paragraph_open, inline, heading_open.

  • tag — HTML-тег, соответствующий токену (p, h1, ul и т.д.).

  • attrs — массив атрибутов [ [имя, значение], ... ].

  • map — массив [startLine, endLine], определяющий диапазон строк в исходном Markdown.

  • nesting — числовой флаг, определяющий вложенность:

    • 1 — открывающий тег,
    • 0 — самозакрывающийся,
    • -1 — закрывающий тег.
  • level — текущий уровень вложенности токена.

  • children — массив вложенных токенов (для токенов типа inline).

  • content — текстовое содержимое, актуально для текстовых и inline-токенов.

  • markup — символы разметки, которые использовались (*, **, # и т.д.).

  • info — дополнительная информация, например, для блоков кода это имя языка.

Пример токена для параграфа:

{
  type: 'paragraph_open',
  tag: 'p',
  attrs: null,
  map: [0, 1],
  nesting: 1,
  level: 0,
  children: null,
  content: '',
  markup: '',
  info: ''
}

Итерация по токенам

После парсинга Markdown с помощью метода md.parse(markdownString, env) получается массив токенов. Работа с токенами обычно включает итерирование по массиву, обработку children и применение пользовательской логики.

const MarkdownIt = require('markdown-it');
const md = new MarkdownIt();

const tokens = md.parse('# Заголовок\n\nПараграф текста.', {});
tokens.forEach(token => {
  console.log(token.type, token.tag, token.level);
});

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


Модификация токенов

Токены можно изменять для кастомизации вывода:

  • Изменение HTML-тега:
tokens.forEach(token => {
  if (token.type === 'heading_open') {
    token.tag = 'h2';
  }
});
  • Добавление атрибутов:
tokens.forEach(token => {
  if (token.type === 'paragraph_open') {
    token.attrs = token.attrs || [];
    token.attrs.push(['class', 'custom-paragraph']);
  }
});
  • Изменение текстового содержимого для inline-токенов:
tokens.forEach(token => {
  if (token.type === 'inline' && token.children) {
    token.children.forEach(child => {
      if (child.type === 'text') {
        child.content = child.content.toUpperCase();
      }
    });
  }
});

Работа с children токенов

Inline-токены содержат массив children, которые описывают текстовые и форматирующие элементы. Основные типы children:

  • text — обычный текст.
  • strong_open / strong_close — выделение жирным.
  • em_open / em_close — курсив.
  • link_open / link_close — ссылки.
  • code_inline — встроенный код.

Пример обхода inline-токенов:

tokens.forEach(token => {
  if (token.type === 'inline') {
    token.children.forEach(child => {
      if (child.type === 'code_inline') {
        child.content = `Processed: ${child.content}`;
      }
    });
  }
});

Фильтрация токенов

Часто требуется извлечь токены определенного типа. Для этого удобно использовать filter:

const headings = tokens.filter(t => t.type.endsWith('_open') && t.tag.startsWith('h'));
headings.forEach(h => console.log(h.tag, h.content));

Так можно получить список всех заголовков документа или любых других элементов.


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

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

const token = new md.Token('custom_block', 'div', 1);
token.attrs = [['class', 'highlight']];
token.content = 'Содержимое кастомного блока';
tokens.push(token);

// Добавление закрывающего токена
const closingToken = new md.Token('custom_block', 'div', -1);
tokens.push(closingToken);

Эта возможность открывает доступ к расширению Markdown без изменения исходного синтаксиса.


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

Плагины Markdown-it часто работают напрямую с токенами, чтобы:

  • Реализовать новые синтаксические конструкции.
  • Модифицировать существующие элементы (добавлять атрибуты, классы, стили).
  • Создавать полностью кастомный HTML на основе Markdown.

Пример простого плагина, который добавляет класс всем ссылкам:

function addLinkClass(md) {
  md.core.ruler.push('link_class', state => {
    state.tokens.forEach(token => {
      if (token.type === 'link_open') {
        token.attrs = token.attrs || [];
        token.attrs.push(['class', 'external-link']);
      }
    });
  });
}

md.use(addLinkClass);

Здесь используется state.tokens — основной массив токенов, который можно изменять на любом этапе парсинга.


Работа с уровнями вложенности

Свойство level токена отражает глубину вложенности элементов. Например:

  • Уровень 0 — корневой блок документа.
  • Уровень 1 — параграф внутри документа.
  • Уровень 2 — текст внутри параграфа.

Уровни вложенности помогают при генерации дерева HTML, при вставке новых блоков и при контроле структуры документа.


Заключение по методам работы с токенами

Методы работы с токенами в Markdown-it предоставляют полный контроль над процессом рендеринга. Понимание структуры токенов, их свойств и вложенности позволяет:

  • Модифицировать стандартный вывод HTML.
  • Добавлять собственные блоки и разметку.
  • Создавать плагины и расширять функциональность Markdown.

Использование токенов — это мощный инструмент, открывающий доступ к глубокой кастомизации Markdown-парсинга и рендеринга в JavaScript.