Отладка расширений

Для начала работы с библиотекой Marked необходимо установить её через npm:

npm install marked

Импорт в проект JavaScript осуществляется следующим образом:

import { marked } from 'marked';

Базовое использование заключается в преобразовании Markdown в HTML:

const markdown = "# Заголовок\n\nТекст с **жирным** выделением.";
const html = marked(markdown);
console.log(html);

Результатом будет:

<h1>Заголовок</h1>
<p>Текст с <strong>жирным</strong> выделением.</p>

Настройка токенизатора и рендерера

Marked позволяет глубоко кастомизировать процесс парсинга Markdown через Lexer, Parser и собственные рендереры.

Пользовательский рендерер

Создание собственного рендерера позволяет изменять поведение стандартного HTML-вывода:

const renderer = {
  heading(text, level) {
    return `<h${level} class="custom-heading">${text}</h${level}>`;
  },
  link(href, title, text) {
    return `<a href="${href}" title="${title || ''}" target="_blank">${text}</a>`;
  }
};

marked.use({ renderer });

Теперь все заголовки будут иметь класс custom-heading, а ссылки открываться в новом окне.


Отладка кастомных расширений

Расширения в Marked — это объектные конфигурации, которые позволяют добавлять новые правила токенизации, парсинга или рендеринга. Для их отладки важно понимать последовательность этапов обработки Markdown:

  1. Лексинг (Lexing) – преобразование текста в токены.
  2. Парсинг (Parsing) – преобразование токенов в HTML.
  3. Рендеринг (Rendering) – финальное формирование HTML.

Создание расширения

Простейшее расширение может добавлять поддержку нестандартного синтаксиса:

const highlightExtension = {
  name: 'highlight',
  level: 'inline',
  start(src) { return src.indexOf('=='); },
  tokenizer(src) {
    const match = src.match(/^==(.+?)==/);
    if (match) return { type: 'highlight', raw: match[0], text: match[1] };
  },
  renderer(token) {
    return `<mark>${token.text}</mark>`;
  }
};

marked.use({ extensions: [highlightExtension] });

Теперь текст ==важное== будет преобразован в <mark>важное</mark>.


Логирование токенов

Для отладки расширений часто полезно увидеть, какие токены создаются на этапе лексинга:

const tokens = marked.lexer("Текст с ==выделением==");
console.log(tokens);

Вывод покажет массив объектов токенов, включая созданный тип highlight, что облегчает поиск ошибок.


Использование обработчиков ошибок

Расширения могут генерировать некорректные токены или падать при парсинге. Marked предоставляет возможность безопасной обработки ошибок через try/catch и кастомные функции рендеринга ошибок:

const safeRenderer = {
  highlight(token) {
    try {
      if (!token.text) throw new Error("Пустой токен");
      return `<mark>${token.text}</mark>`;
    } catch (err) {
      console.error(err);
      return `<span class="error">Ошибка выделения</span>`;
    }
  }
};

marked.use({ renderer: safeRenderer });

Инструменты и методы для отладки

  1. Lexer – используется для проверки правильности токенизации:
console.log(marked.lexer("## Тест"));
  1. Parser – можно отдельно вызвать парсинг токенов:
const tokens = marked.lexer("Тестовый текст");
const html = marked.parser(tokens);
console.log(html);
  1. Hooks – позволяют внедряться в этапы обработки Markdown:
marked.use({
  walkTokens(token) {
    console.log("Обрабатывается токен:", token);
  }
});

Советы по отладке

  • Всегда проверять токены перед передачей их в парсер.
  • Использовать walkTokens для логирования всех промежуточных токенов.
  • Разделять кастомные рендереры и токенизаторы на модули для изоляции ошибок.
  • В случае сложных расширений писать юнит-тесты, имитируя различные входные Markdown-строки.
  • Обращать внимание на level: 'inline' и level: 'block' при создании расширений, иначе токены могут не распознаваться.

Пример комплексной отладки

Добавление пользовательского блока заметки с логированием:

const noteExtension = {
  name: 'note',
  level: 'block',
  start(src) { return src.indexOf(':::note'); },
  tokenizer(src) {
    const match = src.match(/^:::note\n([\s\S]+?)\n:::/);
    if (match) return { type: 'note', raw: match[0], text: match[1] };
  },
  renderer(token) {
    console.log("Рендеринг токена заметки:", token);
    return `<div class="note">${token.text}</div>`;
  }
};

marked.use({ extensions: [noteExtension] });

console.log(marked(":::note\nСодержимое заметки\n:::"));

Консоль покажет все этапы обработки токена, а результат будет корректно обёрнут в HTML <div>.


Эти методы позволяют детально контролировать работу Marked, выявлять ошибки на любом этапе обработки Markdown и безопасно разрабатывать сложные пользовательские расширения.