Markdown-it представляет собой высокопроизводительный парсер Markdown на JavaScript, который генерирует промежуточное представление документа в виде последовательности токенов. Каждый токен описывает элемент синтаксиса Markdown: заголовок, параграф, список, ссылку, изображение и так далее. Токены содержат ключевые поля:
paragraph_open, inline,
heading_open).p,
h1, ul и др.).[ключ, значение].[начальная, конечная].1 –
открывающий тег, -1 – закрывающий, 0 –
одиночный.inline.inline и некоторых других типов.Токены формируются во время стадии лексического анализа и могут быть изменены на этапе рендеринга, что позволяет гибко модифицировать вывод HTML без переписывания исходного Markdown.
Чтобы изменить поведение Markdown-it, используют метод
use для подключения плагинов. Основная
идея модификации заключается в обходе массива токенов и редактировании
их свойств. Пример базовой функции-плагина:
function customPlugin(md) {
md.core.ruler.push('modify_tokens', function(state) {
state.tokens.forEach(token => {
if (token.type === 'paragraph_open') {
token.attrs = token.attrs || [];
token.attrs.push(['class', 'custom-paragraph']);
}
});
});
}
const md = require('markdown-it')();
md.use(customPlugin);
В этом примере каждому параграфу добавляется CSS-класс
custom-paragraph. Важно, что модификация происходит
до рендеринга, что обеспечивает единообразие
HTML-кода.
Некоторые токены, например inline, содержат массив
children, где хранятся текстовые элементы и встроенные
объекты, такие как ссылки, эмодзи или код. Для изменения текста или
атрибутов внутри таких токенов требуется рекурсивный обход:
function modifyInlineTokens(tokens) {
tokens.forEach(token => {
if (token.type === 'inline' && token.children) {
token.children.forEach(child => {
if (child.type === 'text') {
child.content = child.content.replace(/важно/g, 'критично');
}
});
}
});
}
После такой обработки все вхождения слова “важно” в тексте будут заменены на “критично”. Рекурсивный подход необходим, если структура документа сложная, с вложенными списками, блоками цитат и таблицами.
Markdown-it позволяет не только изменять существующие токены, но и
создавать новые. Для этого используется конструктор
Token, доступный через
require('markdown-it/lib/token'):
const Token = require('markdown-it/lib/token');
function insertCustomToken(md) {
md.core.ruler.push('insert_token', function(state) {
const token = new Token('paragraph_open', 'p', 1);
token.attrs = [['class', 'inserted']];
state.tokens.push(token);
const inline = new Token('inline', '', 0);
inline.content = 'Вставленный абзац';
inline.children = [];
state.tokens.push(inline);
state.tokens.push(new Token('paragraph_close', 'p', -1));
});
}
md.use(insertCustomToken);
Этот метод позволяет добавлять произвольные элементы в любой точке документа, создавая динамические блоки Markdown, которые затем корректно рендерятся в HTML.
Еще один мощный способ управления выводом — переопределение рендер-функций для конкретных типов токенов:
md.renderer.rules.paragraph_open = (tokens, idx) => {
const token = tokens[idx];
return `<p style="color:red;">`;
};
Преимущество этого подхода в том, что структура токенов остается неизменной, а изменения применяются только при формировании HTML. Можно сочетать модификацию токенов и кастомный рендеринг для максимальной гибкости.
Токены поддерживают массив атрибутов
attrs, что позволяет добавлять CSS-классы, id,
data-* атрибуты. Также можно создавать собственные свойства
на токенах, которые используются внутри плагинов:
state.tokens.forEach(token => {
if (token.type === 'heading_open') {
token.customLevel = parseInt(token.tag[1]);
}
});
Эти свойства не влияют на стандартный рендеринг, но позволяют хранить вспомогательные данные для плагинов, анализа или генерации оглавления.
nesting и
tag, иначе HTML будет некорректным.Модификация токенов в Markdown-it открывает возможность создавать сложные кастомные расширения, динамические контенты и продвинутые рендереры, сохраняя при этом высокую производительность и структурированность документа.