Логирование правил

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

Структура правил в Markdown-it

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

  • type — тип токена (например, paragraph_open, inline, text).
  • tag — HTML-тег, соответствующий токену.
  • attrs — массив атрибутов HTML-тега.
  • content — текстовое содержимое токена.
  • children — вложенные токены (для составных элементов, таких как inline-токены внутри параграфа).

Правила применяются на двух уровнях:

  1. Block rules — обрабатывают блочные элементы, такие как параграфы, списки, заголовки.
  2. Inline rules — обрабатывают содержимое блоков, включая ссылки, выделения, эмодзи, изображения.

Встроенные средства логирования

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-правила применяются после блочного разбора. Для логирования 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.

Лучшие практики логирования

  • Логировать только необходимые токены или строки для снижения объёма данных.
  • Использовать уровни логирования (info, debug, warning) при интеграции в сложные приложения.
  • Сохранять лог в структуру данных для последующего анализа, а не только выводить в консоль.
  • Для больших документов применять рекурсивное логирование children, чтобы видеть полное дерево элементов.

Логирование правил Markdown-it является мощным инструментом отладки, анализа и понимания работы парсера, позволяя разработчикам точно видеть, как каждый блок и inline-элемент преобразуется в токены и HTML.