Markdown-it предоставляет мощный и гибкий механизм для
переопределения рендеринга элементов Markdown. Центральным понятием
здесь является рендерер (Renderer),
который отвечает за преобразование токенов, полученных парсером, в HTML.
Каждый тип токена имеет соответствующий метод рендерера, который можно
модифицировать или полностью заменить.
В объекте рендерера (md.renderer.rules) хранится словарь
правил для различных токенов. Ключи словаря соответствуют типам токенов,
а значения — функциям, выполняющим генерацию HTML:
const md = require('markdown-it')();
md.renderer.rules.fence = function(tokens, idx, options, env, self) {
const token = tokens[idx];
return `<pre class="custom">${md.utils.escapeHtml(token.content)}</pre>`;
};
В этом примере переопределяется рендеринг блока кода
(fence). Используется метод
md.utils.escapeHtml для безопасного отображения содержимого
кода.
Markdown-it позволяет изменять рендеринг встроенных элементов, таких как ссылки, эмфазы и изображения:
md.renderer.rules.link_open = function(tokens, idx) {
const hrefIndex = tokens[idx].attrIndex('href');
if (hrefIndex >= 0) {
tokens[idx].attrs[hrefIndex][1] = 'https://example.com';
}
return self.renderToken(tokens, idx, options);
};
В данном случае все ссылки получают фиксированный href.
Можно добавлять классы, атрибуты target="_blank" или любые
другие модификации.
Markdown-it поддерживает создание кастомных токенов
через плагины или через API core и block. Это
позволяет обрабатывать нестандартный синтаксис или добавлять новые
элементы:
md.core.ruler.push('custom_token', function(state) {
state.tokens.push({
type: 'custom_block',
content: 'Это мой кастомный блок',
level: 0
});
});
md.renderer.rules.custom_block = function(tokens, idx) {
return `<div class="custom-block">${tokens[idx].content}</div>`;
};
Токен добавляется на этапе core, а его рендеринг
определяется в renderer.rules.
Иногда необходимо учитывать контекст соседних токенов. Методы
рендерера получают массив tokens и индекс idx,
что позволяет:
Пример объединения нескольких параграфов в один контейнер:
md.renderer.rules.paragraph_open = function(tokens, idx) {
if (idx > 0 && tokens[idx - 1].type === 'paragraph_close') {
return ''; // объединяем блоки
}
return '<p class="merged">';
};
md.renderer.rules.paragraph_close = function(tokens, idx) {
if (idx < tokens.length - 1 && tokens[idx + 1].type === 'paragraph_open') {
return '';
}
return '</p>';
};
self.renderTokenПри переопределении рендеринга рекомендуется сохранять базовую
обработку через self.renderToken(tokens, idx, options). Это
обеспечивает корректную генерацию стандартных атрибутов, классов и
вложенных элементов.
Любой токен содержит массив attrs, где хранятся пары
[имя, значение]. Изменение атрибутов позволяет динамически
влиять на HTML:
md.renderer.rules.image = function(tokens, idx, options, env, self) {
tokens[idx].attrPush(['loading', 'lazy']);
return self.renderToken(tokens, idx, options);
};
Так можно добавлять оптимизацию загрузки изображений или классы для CSS-стилизации.
Для глобального контроля рендеринга можно использовать метод
md.renderer.render с кастомной функцией обработки
токенов:
const result = md.renderer.render(tokens, md.options, env);
При необходимости можно пройтись по всем токенам и модифицировать их содержимое перед финальной генерацией HTML.
escapeHtml
предотвращает XSS и ошибки в разметке.Правильное использование renderer.rules,
self.renderToken и работы с атрибутами делает Markdown-it
мощным инструментом для любых задач по генерации HTML из Markdown.