Библиотека Markdown-it реализует Markdown через модульную архитектуру с набором правил, которые обрабатывают текст последовательно. Каждый блок и inline-элемент проходит через цепочку рендеринга, и понимание приоритета и порядка выполнения правил критически важно для точной настройки или расширения парсера.
Markdown-it разделяет обработку текста на два уровня:
Каждый уровень использует систему токенов: текст преобразуется в последовательность токенов, которые затем рендерятся в HTML. Понимание последовательности генерации токенов помогает управлять приоритетом правил.
Правила в Markdown-it определяются как функции, выполняющие определённое преобразование текста в токены. Они делятся на три основных типа:
Порядок выполнения блоков важен: Markdown-it проходит список правил, и первый совпавший паттерн запускается до следующих. Это позволяет отменять стандартное поведение, добавляя кастомные правила с нужным приоритетом.
Каждое правило имеет определённую позицию в массиве
parser.rules. Для управления приоритетом можно использовать
методы:
ruler.before(name, newRuleName, ruleFunc) – добавляет
правило перед существующим.ruler.after(name, newRuleName, ruleFunc) – добавляет
правило после указанного.ruler.push(newRuleName, ruleFunc) – добавляет правило в
конец цепочки.Пример:
const md = require('markdown-it')();
md.inline.ruler.before('emphasis', 'custom_bold', function(state, silent) {
// логика собственного правила
return false;
});
В этом примере правило custom_bold будет применяться
перед стандартным обработчиком выделения текста.
Core rules обрабатываются до всех block и inline правил. Ключевые моменты:
normalize – преобразует строки в стандартный
формат.block – отвечает за разбиение на блоки и установку типа
токена.inline – запускает inline-парсер на содержимом блочного
токена.Именно последовательность этих правил обеспечивает правильное распознавание вложенных элементов. Изменение порядка core rules может нарушить обработку Markdown.
Inline rules используют стек и позицию курсора для поиска совпадений. Конфликты происходят, если несколько правил совпадают на одном участке текста. Markdown-it решает их по позиции в массиве правил, поэтому:
md.inline.ruler.before('emphasis', 'ignore_dollar', function(state, silent) {
let pos = state.pos;
if (state.src[pos] === '$') {
state.pos += 1;
return true;
}
return false;
});
md.inline.ruler.after('link', 'custom_link', function(state, silent) {
const pos = state.pos;
// логика поиска и генерации токена custom_link
return false;
});
md.block.ruler.before('paragraph', 'custom_block', function(state, startLine, endLine, silent) {
const lineText = state.getLines(startLine, startLine + 1, 0, false);
if (lineText.startsWith('%%')) {
if (!silent) {
const token = state.push('custom_block', 'div', 0);
token.content = lineText.slice(2).trim();
}
return true;
}
return false;
});
Порядок выполнения правил напрямую влияет на производительность:
После генерации токенов Markdown-it строит дерево рендеринга. Токены хранят поля:
type – тип элемента (paragraph_open,
strong_open, text).tag – HTML-тег для рендера.children – вложенные токены для inline-обработки.level – глубина вложенности, определяет правильное
закрытие блоков.Понимание этих полей позволяет тонко управлять порядком вставки токенов и их рендерингом.