Markdown-it предоставляет мощный механизм расширения синтаксиса через пользовательские правила парсинга. Эти правила позволяют обрабатывать нестандартные конструкции Markdown, модифицировать токены или внедрять новую логику в процесс преобразования текста в HTML.
В основе Markdown-it лежит система токенов, которые
формируются в процессе лексического анализа. Каждое правило парсинга
получает текстовый поток и токены, которые оно может создавать, изменять
или удалять. Для добавления нового правила используется метод
md.inline.ruler для инлайновых токенов или
md.block.ruler для блочных элементов.
Пример создания правила для инлайнового синтаксиса:
const md = require('markdown-it')();
function insertCustomToken(state, silent) {
const start = state.pos;
if (state.src.charCodeAt(start) !== 0x40) { // проверка на символ "@"
return false;
}
let match = state.src.slice(start).match(/^@(\w+)/);
if (!match) return false;
if (!silent) {
const token = state.push('custom_mention', '', 0);
token.content = match[1];
}
state.pos += match[0].length;
return true;
}
md.inline.ruler.before('emphasis', 'mention', insertCustomToken);
md.renderer.rules.custom_mention = function(tokens, idx) {
return `<span class="mention">@${tokens[idx].content}</span>`;
};
console.log(md.render('Привет, @user!'));
В этом примере создается инлайновое правило, которое ищет упоминания
в формате @username и преобразует их в HTML-элемент с
классом mention.
Блочные правила работают с целыми абзацами или строками Markdown и чаще всего применяются для расширения синтаксиса заголовков, списков или специальных блоков.
Пример правила для блока “alert”:
function alertBlock(state, startLine, endLine, silent) {
const start = state.bMarks[startLine] + state.tShift[startLine];
const max = state.eMarks[startLine];
if (state.src.slice(start, start + 6) !== '!!!alert') {
return false;
}
let nextLine = startLine + 1;
while (nextLine < endLine && state.src.slice(state.bMarks[nextLine], state.eMarks[nextLine]).trim() !== '') {
nextLine++;
}
if (!silent) {
const token = state.push('alert_open', 'div', 1);
token.attrs = [['class', 'alert']];
token.map = [startLine, nextLine];
const contentToken = state.push('inline', '', 0);
contentToken.content = state.getLines(startLine + 1, nextLine, state.tShift[startLine + 1], true);
contentToken.map = [startLine + 1, nextLine];
state.push('alert_close', 'div', -1);
}
state.line = nextLine;
return true;
}
md.block.ruler.before('paragraph', 'alert', alertBlock);
md.renderer.rules.alert_open = () => '<div class="alert">';
md.renderer.rules.alert_close = () => '</div>';
Это правило позволяет использовать конструкцию:
!!!alert
Это сообщение об ошибке или предупреждении.
и преобразует её в HTML-блок
<div class="alert">.
Markdown-it обрабатывает правила в том порядке, в котором они зарегистрированы. Для точного контроля доступны методы:
before(name, ruleName, ruleFunc) — вставляет новое
правило перед существующим.after(name, ruleName, ruleFunc) — вставляет правило
после указанного.push(name, ruleFunc) — добавляет правило в конец
списка.Понимание порядка критично, когда новые правила могут пересекаться с существующими синтаксическими конструкциями.
Каждое правило получает объект state, который
содержит:
src — исходный текст.pos — текущая позиция при обработке инлайнов.bMarks и eMarks — массивы с границами
строк.tShift — массив с количеством пробелов до текста.push(type, tag, nesting) — метод создания токена.getLines(start, end, indent, keepLastLF) — извлечение
текста из нескольких строк.Грамотная работа с этим объектом позволяет создавать сложные конструкции, такие как вложенные блоки, кастомные списки и таблицы.
После того как токен создан, его визуальное представление управляется
через renderer.rules. Каждый тип токена можно преобразовать
в HTML по собственным правилам:
md.renderer.rules.my_token_type = function(tokens, idx, options, env, self) {
return `<span class="my-class">${tokens[idx].content}</span>`;
};
Если правило не указано, Markdown-it использует default renderer, который выводит содержимое без изменений.
:emoji:.Все эти расширения строятся на комбинации:
Эта система делает Markdown-it гибкой платформой для любых задач преобразования Markdown в HTML, сохраняя при этом высокую скорость работы и предсказуемое поведение при обработке стандартного синтаксиса.
Если требуется, могу подготовить следующую секцию с пошаговой инструкцией создания комплексного расширения Markdown, включая вложенные токены и динамический рендеринг. Это будет очень полезно для учебника.