Markdown-it — это современный парсер Markdown на JavaScript, который преобразует текст в структуру токенов, а затем рендерит её в HTML. Токены — это основные строительные блоки внутреннего представления документа, которые позволяют анализировать структуру Markdown на низком уровне. Понимание токенов критично для расширений, плагинов и глубокой настройки рендеринга.
Каждый токен в Markdown-it представляет собой объект с набором свойств:
paragraph_open, inline, text,
heading_open и т.д.).p, h1, li и т.д.).[ключ, значение] (например, для ссылок или
изображений).[startLine, endLine].1, 0
или -1, указывающее на открывающий, одиночный или
закрывающий токен.inline).Пример базового токена:
{
type: 'paragraph_open',
tag: 'p',
attrs: null,
map: [0, 1],
nesting: 1,
level: 0,
children: null
}
Markdown-it позволяет получить токены с помощью метода
parse. Вызов выглядит так:
const MarkdownIt = require('markdown-it');
const md = new MarkdownIt();
const src = `# Заголовок 1
Это пример текста с **жирным** выделением.`;
const tokens = md.parse(src, {});
console.log(tokens);
tokens — массив объектов, где каждый объект описывает
отдельный элемент Markdown: заголовок, параграф, текст, форматирование.
Важно, что inline токены содержат свои дочерние токены в
children, что позволяет детально разбирать внутренние
элементы текста.
Для анализа документа часто используют рекурсивное или итеративное прохождение по массиву токенов. Основные методы работы:
tokens.forEach(token => {
console.log(token.type, token.tag, token.nesting);
});
tokens.forEach(token => {
if (token.type === 'inline' && token.children) {
token.children.forEach(child => {
console.log(child.type, child.content);
});
}
});
const textTokens = tokens.filter(t => t.type === 'text');
textTokens.forEach(t => console.log(t.content));
tokens.forEach(token => {
if (token.type === 'inline' && token.children) {
token.children.forEach(child => {
if (child.type === 'link_open') {
const href = child.attrs.find(attr => attr[0] === 'href')[1];
console.log('Ссылка:', href);
}
});
}
});
const headings = tokens.filter(t => t.type === 'heading_open');
headings.forEach(h => console.log(h.tag));
let plainText = '';
tokens.forEach(token => {
if (token.type === 'inline' && token.children) {
token.children.forEach(child => {
if (child.type === 'text') plainText += child.content + ' ';
});
}
});
console.log(plainText.trim());
Markdown-it предоставляет возможность перехватывать и
изменять токены перед рендерингом. Для этого используют метод
core.ruler.push:
md.core.ruler.push('uppercase_text', state => {
state.tokens.forEach(token => {
if (token.type === 'inline' && token.children) {
token.children.forEach(child => {
if (child.type === 'text') {
child.content = child.content.toUpperCase();
}
});
}
});
});
Этот подход позволяет внедрять кастомную обработку Markdown, например, автоматическую замену определенных слов, изменение структуры документа или добавление атрибутов к HTML-элементам.
level токена отражает глубину вложенности, начиная с 0.
Это особенно важно для списков, блоков кода и вложенных элементов.
Пример:
tokens.forEach(token => {
console.log('Уровень:', token.level, 'Тип:', token.type, 'Тег:', token.tag);
});
Использование level помогает различать, например,
параграф внутри списка и параграф на верхнем уровне документа.
type для быстрого фильтрования нужных
элементов.children у
inline токенов.map помогает сопоставлять токены с исходными строками
Markdown, что полезно для подсветки синтаксиса или линтинга
документа.Эти методы позволяют полностью контролировать процесс разборки Markdown, создавая расширенные функциональные возможности поверх Markdown-it и обеспечивая точный анализ структуры текста на уровне токенов.