Обработка ошибок парсинга

Библиотека Marked — это высокопроизводительный парсер Markdown в JavaScript, который позволяет конвертировать текстовый Markdown в HTML. Несмотря на простоту использования, важно учитывать особенности обработки ошибок при парсинге, чтобы избежать некорректного вывода и потенциальных уязвимостей.


Встроенная система обработки ошибок

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

Примеры потенциальных ошибок:

  • Незакрытые теги разметки: **жирный текст
  • Некорректная ссылка: [текст](url
  • Ошибки в списках: неправильная нумерация или смешение типов списков

Marked не выдаёт исключений по умолчанию на такие ошибки, но предоставляет возможности ловить и обрабатывать исключительные ситуации при парсинге.


Использование try/catch для безопасного парсинга

Для предотвращения сбоев приложения при неожиданных входных данных можно обернуть вызов парсера в конструкцию try/catch:

const marked = require('marked');

const markdownText = '**Незакрытый текст';

try {
  const html = marked.parse(markdownText);
  console.log(html);
} catch (error) {
  console.error('Ошибка при парсинге Markdown:', error.message);
}

В большинстве случаев marked.parse не выбросит исключение, но данная конструкция полезна при работе с пользовательским контентом или кастомными токенами, где вероятность ошибки выше.


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

Marked разбивает процесс обработки Markdown на два этапа: лексический разбор (лексер) и рендеринг (парсер). Лексер превращает исходный текст в токены, а парсер преобразует их в HTML.

const lexer = new marked.Lexer();
const tokens = lexer.lex(markdownText);

Ключевой момент: ошибки на этапе лексического анализа могут быть обнаружены при использовании кастомного токенизатора. Например, можно добавить проверку специфических конструкций:

class SafeLexer extends marked.Lexer {
  constructor(options) {
    super(options);
  }

  code(src, lang) {
    if (!lang) {
      console.warn('Языковая подсветка не указана для блока кода');
    }
    return super.code(src, lang);
  }
}

Это позволяет контролировать обработку нестандартных блоков и выводить предупреждения вместо полной остановки процесса.


Обработка ошибок в пользовательских рендерах

Marked поддерживает кастомные рендереры, что открывает возможность тонкой настройки HTML-выхода. Ошибки могут возникать при преобразовании токенов в HTML, особенно если в рендерере предполагается строгое соответствие типам токенов:

const renderer = {
  heading(text, level) {
    if (!text) {
      console.error(`Пустой заголовок уровня ${level}`);
      return `<h${level}>Ошибка заголовка</h${level}>`;
    }
    return `<h${level}>${text}</h${level}>`;
  }
};

marked.use({ renderer });

Использование кастомного рендерера позволяет предотвратить некорректный вывод и логировать проблемы на этапе рендеринга.


Валидация ссылок и изображений

Частая категория ошибок — некорректные URL в ссылках и изображениях. Для их обработки можно использовать колбэк walkTokens:

marked.use({
  walkTokens(token) {
    if (token.type === 'link' || token.type === 'image') {
      try {
        new URL(token.href);
      } catch {
        console.warn(`Неверный URL: ${token.href}`);
        token.href = '#';
      }
    }
  }
});

walkTokens позволяет проверять каждый токен перед рендерингом, предотвращая генерацию HTML с некорректными ссылками.


Логирование и предупреждения

Для масштабных приложений рекомендуется использовать систему логирования предупреждений вместо остановки процесса. Это особенно важно при работе с Markdown, который поступает от пользователей:

  • Несоответствие заголовков уровня
  • Пустые параграфы
  • Незакрытые или дублирующиеся теги

Использование console.warn или интеграция с системами логирования (например, winston или pino) позволяет отслеживать ошибки без прерывания парсинга.


Защита от XSS и потенциальных уязвимостей

Ошибки парсинга иногда могут использоваться злоумышленниками для внедрения скриптов в HTML. Marked предлагает опцию sanitize, которая фильтрует потенциально опасный контент:

marked.setOptions({
  sanitizer: (html) => {
    // Простейшая фильтрация тегов <script>
    return html.replace(/<script.*?>.*?<\/script>/gi, '');
  }
});

Это не заменяет полноценную библиотеку для защиты от XSS, но помогает минимизировать риск внедрения опасного HTML при обработке некорректного Markdown.


Советы по устойчивой обработке ошибок

  • Всегда использовать try/catch при обработке внешнего контента.
  • Для критичных приложений создавать кастомный рендерер с проверками.
  • Применять walkTokens для валидации ссылок, изображений и других элементов.
  • Логировать предупреждения, не останавливая процесс парсинга.
  • При необходимости фильтровать HTML через sanitizer или внешние библиотеки.

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