В библиотеке Marked вложенный разбор позволяет корректно обрабатывать структуры Markdown, которые содержат друг в друге элементы разметки. Это особенно важно для сложных случаев, таких как списки с кодовыми блоками, цитаты внутри списков или комбинированные форматирования текста.
1. Токенизация и поток токенов
Marked работает в два этапа: лексический анализ (tokenization) и парсинг (parsing). При обработке Markdown библиотека сначала разбивает текст на токены — объекты, представляющие отдельные элементы Markdown (заголовки, списки, цитаты, ссылки, текст).
Вложенный разбор реализуется через рекурсивное прохождение токенов: если токен содержит другой Markdown-контент, он передаётся на повторную обработку. Например, внутри цитаты может быть список, а внутри списка — параграф с выделением.
const marked = require('marked');
const markdown = `
> Список внутри цитаты:
> - Пункт 1
> - Пункт 2 с **жирным текстом**
`;
console.log(marked.parse(markdown));
В этом примере токен цитаты содержит токены списка, которые в свою очередь содержат токены текста с выделением. Marked автоматически обрабатывает все уровни вложенности.
Для контроля рендеринга вложенных структур можно использовать собственный объект Renderer. Каждый метод Renderer получает на вход HTML или токенизированный объект и возвращает строку HTML.
Пример кастомного рендеринга списков внутри цитат:
const renderer = {
blockquote(quote) {
return `<blockquote class="custom-quote">${quote}</blockquote>`;
},
list(body, ordered) {
const type = ordered ? 'ol' : 'ul';
return `<${type} class="custom-list">${body}</${type}>`;
}
};
const options = {
renderer,
breaks: true
};
console.log(marked.parse(markdown, options));
Ключевой момент: методы Renderer вызываются рекурсивно, что позволяет создавать кастомные стили и контролировать обработку вложенных элементов без изменения исходного Markdown.
- Пункт 1
- Подпункт 1.1
- Подпункт 1.2
- Пункт 2
Результат:
<ul>
<li>Пункт 1
<ul>
<li>Подпункт 1.1</li>
<li>Подпункт 1.2</li>
</ul>
</li>
<li>Пункт 2</li>
</ul>
> Это цитата
>
> - Список 1
> - Список 2
Marked корректно обработает пустые строки внутри цитат, что позволяет создавать сложные иерархии элементов.
> - Пункт с кодом
>
> ```js
> console.log("Hello, Marked!");
> ```
Внутри списка Marked создаёт отдельный блок
<pre><code> и правильно сохраняет
форматирование кода.
Для продвинутого контроля можно использовать API токенизации:
const tokens = marked.lexer(markdown);
console.log(tokens);
Токены имеют свойства:
type — тип элемента (paragraph, list, list_item,
blockquote и т.д.)text — содержимое текстаtokens — массив вложенных токеновТакой подход позволяет программно обходить дерево Markdown и применять кастомную обработку на любом уровне вложенности.
marked.lexer, чтобы понимать, как библиотека
интерпретирует сложные структуры.Вложенный разбор в Marked делает библиотеку мощным инструментом для преобразования сложного Markdown в корректный HTML. Он объединяет лексическую точность и гибкость рендеринга, обеспечивая правильную обработку любых уровней вложенности.