Библиотека Marked предоставляет гибкий механизм расширений, позволяющий изменять и дополнять стандартный процесс парсинга Markdown. Расширения включают три ключевых компонента: лексеры, парсеры и рендереры, каждый из которых можно кастомизировать для достижения специфических целей.
Лексер в Marked отвечает за разделение текста на токены. Каждый токен представляет собой отдельный элемент Markdown — заголовок, список, ссылку или блок кода.
Пример базового создания собственного лексера:
const marked = require('marked');
const lexerOptions = {
extensions: [
{
name: 'customLexer',
level: 'block', // уровень: block или inline
start(src) { return src.match(/^!!!/)?.index; }, // определение начала токена
tokenizer(src, tokens) {
const rule = /^!!!(.*)\n([\s\S]+?)\n!!!/;
const match = rule.exec(src);
if (match) {
return {
type: 'customBlock',
raw: match[0],
content: match[2].trim()
};
}
}
}
]
};
const lexer = new marked.Lexer(lexerOptions);
const tokens = lexer.lex('!!!warning\nВнимание! Это кастомный блок.\n!!!');
console.log(tokens);
Ключевой момент: метод tokenizer
позволяет определить структуру нового токена, а
start ускоряет обработку, указывая, где искать начало
токена.
После того как текст разделен на токены, парсер превращает их в HTML или другую форму вывода. В Marked можно полностью заменить стандартный парсер или добавить обработку новых типов токенов.
Пример расширения парсера:
const parserOptions = {
extensions: [
{
name: 'customParser',
renderer(token) {
if (token.type === 'customBlock') {
return `<div class="alert">${token.content}</div>`;
}
return false; // fallback на стандартный рендер
}
}
]
};
const parser = new marked.Parser(parserOptions);
const html = parser.parse(tokens);
console.log(html);
Важная особенность: метод renderer
получает токен и возвращает HTML. Если возвращается false,
используется стандартная обработка.
Рендерер в Marked отвечает за генерацию финального HTML. Можно создавать кастомные рендереры для отдельных элементов или глобально переопределять весь процесс.
Пример кастомного рендерера для ссылок:
const renderer = {
link(href, title, text) {
return `<a href="${href}" title="${title || ''}" target="_blank">${text}</a>`;
}
};
marked.use({ renderer });
const htmlLink = marked('[Google](https://google.com)');
console.log(htmlLink);
Особенности работы:
heading, list, code и др.).use.Marked поддерживает несколько расширений одновременно. Это позволяет комбинировать кастомные лексеры, парсеры и рендереры для сложных сценариев.
marked.use({
extensions: [customLexer, customParser],
renderer: customRenderer
});
Принцип работы: библиотека сначала применяет все лексеры, затем парсеры, и в конце рендереры, что обеспечивает гибкость и предсказуемость результатов.
Кроме стандартной системы расширений, Marked предоставляет хуки, которые позволяют вмешиваться в процесс парсинга на отдельных этапах:
walkTokens(token) — проход по всем токенам после
лексинга.renderer — настройка вывода HTML для каждого
токена.tokenizer — добавление новых правил распознавания
Markdown элементов.Пример использования walkTokens:
marked.use({
walkTokens(token) {
if (token.type === 'text') {
token.text = token.text.replace(/TODO:/g, '<strong>TODO:</strong>');
}
}
});
Расширения делятся на два уровня:
Разделение по уровням позволяет точечно управлять обработкой Markdown, не затрагивая лишние элементы.
start для ускорения работы лексера при
обработке больших документов.false в рендерере для токенов,
которые не обрабатываются кастомно, чтобы сохранить совместимость со
стандартным парсингом.marked.use для
модульного подхода к кастомизации.Система расширений Marked обеспечивает полный контроль над процессом преобразования Markdown, позволяя добавлять новые типы блоков, кастомизировать вывод и интегрировать библиотеку в сложные проекты с нестандартными требованиями к разметке.