Концепция рендереров в Marked

Основы рендеринга Markdown

В библиотеке Marked рендерер отвечает за преобразование элементов Markdown в HTML. При парсинге Markdown строки библиотека разбивает текст на токены, которые представляют различные элементы: заголовки, списки, ссылки, изображения, код и так далее. Каждый тип токена обрабатывается с помощью соответствующего метода рендерера. По умолчанию используется встроенный рендерер marked.Renderer, который реализует стандартное HTML-преобразование.

Ключевые моменты:

  • Токенизация и рендеринг разделены: сначала происходит разбор Markdown в токены, затем каждый токен рендерится в HTML.
  • Рендерер можно заменить или расширить, создавая кастомные методы для любых токенов.

Создание собственного рендерера

Чтобы изменить стандартное поведение, создается объект, наследующий от marked.Renderer или просто объект с необходимыми методами. Каждый метод соответствует определенному типу Markdown-элемента.

Пример структуры метода рендерера:

const customRenderer = {
  heading(text, level, raw, slugger) {
    return `<h${level} class="custom-heading">${text}</h${level}>`;
  },
  link(href, title, text) {
    return `<a href="${href}" title="${title || ''}" target="_blank">${text}</a>`;
  },
  list(body, ordered) {
    const tag = ordered ? 'ol' : 'ul';
    return `<${tag} class="custom-list">${body}</${tag}>`;
  }
};

Особенности:

  • Параметр text — уже обработанный текст, который может содержать вложенные элементы.
  • level для заголовков указывает уровень (1–6).
  • Методы должны возвращать строку HTML.

Интеграция кастомного рендерера

После определения рендерера его нужно передать в опции Marked при вызове функции:

marked.use({ renderer: customRenderer });

const markdownText = `
# Заголовок первого уровня
- Элемент списка
[Ссылка](https://example.com)
`;

const html = marked.parse(markdownText);
console.log(html);

Результат будет соответствовать кастомным правилам рендерера, а не стандартному HTML.

Методы рендерера и их параметры

  1. heading(text, level, raw, slugger)

    • text — содержимое заголовка с уже обработанными вложенными элементами.
    • level — уровень заголовка.
    • raw — исходный текст Markdown без обработки.
    • slugger — объект для генерации уникальных идентификаторов.
  2. paragraph(text)

    • text — текст абзаца. Возвращает HTML-строку <p>...</p>.
  3. link(href, title, text)

    • href — адрес ссылки.
    • title — атрибут title.
    • text — текст ссылки.
  4. list(body, ordered, start)

    • body — HTML-содержимое списка.
    • orderedtrue, если это нумерованный список.
    • start — начальное число для нумерованного списка.
  5. listitem(text, task, checked)

    • text — содержимое элемента.
    • tasktrue, если элемент — чекбокс.
    • checkedtrue, если чекбокс отмечен.
  6. code(code, language, isEscaped)

    • code — текст кода.
    • language — указанная язык разметки.
    • isEscaped — указывает, было ли экранирование HTML.
  7. image(href, title, text)

    • href — путь к изображению.
    • title — атрибут title.
    • text — alt-текст изображения.

Расширение рендерера через классы

Можно создать класс, наследующий от marked.Renderer, чтобы переопределять только нужные методы, сохраняя остальные стандартные:

class MyRenderer extends marked.Renderer {
  heading(text, level) {
    return `<h${level} class="my-heading">${text}</h${level}>`;
  }
}

marked.use({ renderer: new MyRenderer() });

Это удобно, когда нужно изменить поведение нескольких элементов без полной копии стандартного рендерера.

Контекст использования рендереров

  • Темизация и стилизация: позволяет задавать классы, атрибуты или даже полностью изменять структуру HTML.
  • Обработка безопасности: можно фильтровать HTML-теги, добавлять rel="nofollow" к ссылкам, предотвращать XSS.
  • Расширение синтаксиса Markdown: добавлять специальные блоки или элементы, которых нет в стандартном Markdown, просто создавая методы для новых токенов.

Комбинирование рендереров с другими функциями Marked

Рендереры тесно интегрируются с опциями highlight и walkTokens:

  • highlight(code, lang) — подсветка кода, может использоваться внутри метода code.
  • walkTokens(token) — позволяет изменять токены перед рендерингом, что особенно полезно для внедрения кастомных атрибутов и обработки нестандартных элементов.
marked.use({
  renderer: customRenderer,
  highlight: (code, lang) => Prism.highlight(code, Prism.languages[lang] || Prism.languages.javascript, lang),
  walkTokens: token => {
    if (token.type === 'link') {
      token.href = token.href.replace('http:', 'https:');
    }
  }
});

Заключение о концепции

Рендерер в Marked — это централизованный механизм контроля вывода HTML из Markdown. Он отделяет парсинг от визуального представления, обеспечивает гибкость и безопасность, а также позволяет легко внедрять кастомные правила и расширения. При правильном проектировании рендереры делают Markdown мощным инструментом для динамических веб-приложений и статических сайтов.