Markdown-it предоставляет гибкий механизм парсинга Markdown и генерации HTML. Одной из мощных возможностей библиотеки является расширяемость через плагины и правила, а также возможность логирования процесса обработки, что особенно важно при отладке сложных Markdown-сценариев.
Markdown-it использует токенизацию как основу обработки Markdown. Каждый элемент документа, будь то заголовок, список или ссылка, преобразуется в токен с определёнными свойствами:
type — тип токена (например,
paragraph_open, inline,
text).tag — HTML-тег, соответствующий токену.attrs — массив атрибутов HTML-тега.content — текстовое содержимое токена.children — вложенные токены (для составных элементов,
таких как inline-токены внутри параграфа).Правила применяются на двух уровнях:
Markdown-it не предоставляет встроенный графический логгер, но процесс обработки можно отслеживать через переопределение правил и вывод информации о токенах.
Пример создания логирующего правила для блочного уровня:
const MarkdownIt = require('markdown-it');
const md = new MarkdownIt();
function logBlockTokens(state, startLine, endLine, silent) {
for (let line = startLine; line < endLine; line++) {
console.log(`Обрабатывается строка ${line}: ${state.src.split('\n')[line]}`);
}
return false; // возвращаем false, чтобы не мешать стандартной обработке
}
// Вставляем правило в начало цепочки блочных правил
md.block.ruler.before('paragraph', 'log_block', logBlockTokens);
В этом примере каждое блочное правило, проходящее через
log_block, выводит исходный текст строки, что позволяет
отслеживать работу парсера в реальном времени.
Для детального анализа Markdown-документа полезно логировать токены после парсинга:
const tokens = md.parse('# Заголовок\n\nТекст параграфа', {});
tokens.forEach((token, index) => {
console.log(`Токен ${index}:`);
console.log(` type: ${token.type}`);
console.log(` tag: ${token.tag}`);
console.log(` content: ${token.content}`);
console.log(` nesting: ${token.nesting}`);
});
Ключевые моменты:
nesting — уровень вложенности токена:
1 для открытия тега, 0 для текстового
содержимого, -1 для закрытия тега.children — вложенные токены, которые
тоже можно рекурсивно логировать для анализа inline-содержимого.Inline-правила применяются после блочного разбора. Для логирования
inline-токенов используют md.inline.ruler:
function logInlineTokens(state, silent) {
state.tokens.forEach(token => {
if (token.type === 'inline') {
token.children.forEach(child => {
console.log(`Inline токен: type=${child.type}, content='${child.content}'`);
});
}
});
return false;
}
md.inline.ruler.before('emphasis', 'log_inline', logInlineTokens);
Этот подход позволяет отслеживать, как парсер обрабатывает ссылки, выделения, кодовые фрагменты и другие inline-элементы.
Для масштабных документов полезно создать глобальный логгер, который:
block,
inline).Пример рекурсивной функции для детального логирования:
function logTokens(tokens, level = 0) {
tokens.forEach(token => {
const indent = ' '.repeat(level);
console.log(`${indent}${token.type} (${token.tag}): ${token.content}`);
if (token.children && token.children.length > 0) {
logTokens(token.children, level + 1);
}
});
}
Использование:
const parsed = md.parse('# Заголовок\nТекст', {});
logTokens(parsed);
Этот метод позволяет визуально представить структуру документа, включая вложенные inline-элементы.
Плагины Markdown-it часто создают новые правила или модифицируют существующие. Логирование помогает убедиться, что плагин корректно работает на различных типах Markdown-содержимого.
Пример добавления плагина с логированием:
function customPlugin(md) {
md.core.ruler.push('log_core', function(state) {
console.log('=== Лог состояния core ===');
state.tokens.forEach(token => {
console.log(`type=${token.type}, content='${token.content}'`);
});
});
}
md.use(customPlugin);
Использование core.ruler позволяет логировать документ
после применения всех блоковых и inline-правил, что
идеально для анализа итоговой структуры токенов перед генерацией
HTML.
children, чтобы видеть полное дерево элементов.Логирование правил Markdown-it является мощным инструментом отладки, анализа и понимания работы парсера, позволяя разработчикам точно видеть, как каждый блок и inline-элемент преобразуется в токены и HTML.