Библиотека Markdown-it предоставляет мощный механизм для потоковой обработки Markdown, который позволяет управлять разбором и рендерингом на уровне токенов и событий. Потоковая обработка особенно полезна при работе с большими документами, динамическим контентом или интеграции с другими системами, где требуется постепенная генерация HTML без загрузки всего текста сразу.
Markdown-it разбивает исходный Markdown на последовательность токенов. Каждый токен представляет собой элемент структуры документа: заголовок, параграф, список, цитату, код-блок.
Структура токена включает ключевые поля:
type — тип токена (paragraph_open,
inline, heading_open и т.д.)tag — HTML-тег, соответствующий токену (p,
h1, ul)attrs — массив атрибутов
([['class', 'highlight']])map — диапазон строк в исходном Markdown
[startLine, endLine]nesting — уровень вложенности (1 — открытие, -1 —
закрытие, 0 — самостоятельный элемент)content — текст внутри токена (для
inline)children — вложенные токены для инлайн-содержимогоПример токенизации параграфа:
const md = require('markdown-it')();
const tokens = md.parse('Привет, **мир**!', {});
console.log(tokens);
Вывод покажет токены для параграфа, жирного текста и обычного текста, каждый с подробной информацией о позиции и вложенности.
Markdown-it поддерживает рекурсивный и итеративный рендеринг токенов. Для потоковой обработки создаётся объект renderer, который можно настроить:
const md = require('markdown-it')();
md.renderer.rules.paragraph_open = () => '<p class="custom">';
md.renderer.rules.paragraph_close = () => '</p>';
const result = md.render('Текст параграфа');
Потоковый рендеринг можно реализовать через итерацию по токенам:
const tokens = md.parse(markdownString, {});
for (const token of tokens) {
switch(token.type) {
case 'heading_open':
process.stdout.write(`<${token.tag}>`);
break;
case 'inline':
process.stdout.write(token.content);
break;
case 'heading_close':
process.stdout.write(`</${token.tag}>\n`);
break;
}
}
Такой подход позволяет выводить HTML по мере разбора Markdown без накопления всего документа в памяти.
При работе с очень большими файлами стандартный
md.render может потреблять значительное количество памяти,
так как Markdown сначала полностью токенизируется, а затем рендерится.
Для решения этой задачи применяются стратегии:
md.parseInline
— полезно для генерации контента из потоковых источников (например, из
сети).paragraph, heading, code_block)
обрабатывается как самостоятельный фрагмент.Пример построчной обработки:
const lines = largeMarkdown.split('\n');
for (const line of lines) {
const tokens = md.parseInline(line, {});
for (const token of tokens) {
process.stdout.write(token.content);
}
}
Markdown-it построен модульно и позволяет подключать плагины для потоковой модификации токенов:
markdown-it-anchor — добавление якорей к
заголовкам.markdown-it-footnote — обработка сносок.function myStreamPlugin(md) {
md.core.ruler.push('uppercase_tokens', state => {
state.tokens.forEach(token => {
if (token.type === 'inline') {
token.content = token.content.toUpperCase();
}
});
});
}
md.use(myStreamPlugin);
Такая архитектура позволяет интегрировать Markdown-поток в веб-сервер, потоковую обработку файлов и генерацию HTML на лету.
Инлайновые токены (em, strong,
link, code) обрабатываются отдельно и могут
иметь вложенные токены. Потоковый рендеринг инлайновых
токенов требует рекурсивной функции:
function renderInline(tokens) {
for (const token of tokens) {
if (token.type.endsWith('_open')) process.stdout.write(`<${token.tag}>`);
else if (token.type.endsWith('_close')) process.stdout.write(`</${token.tag}>`);
else if (token.type === 'text') process.stdout.write(token.content);
else if (token.children) renderInline(token.children);
}
}
Рекурсивный обход гарантирует корректное вложение HTML-тегов и минимизирует использование памяти при потоковой генерации.
Для больших потоков рекомендуется:
Markdown-it предоставляет гибкость на уровне токенов, что позволяет строить как классическую обработку Markdown, так и потоковую генерацию HTML для приложений с высокой нагрузкой или ограниченной памятью.
Потоковая обработка в Markdown-it делает библиотеку подходящей не только для рендеринга статических файлов, но и для динамических систем: редакторов, генераторов сайтов и серверных приложений, где важна эффективность и контроль над структурой HTML на лету.