Структура объекта расширения

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

Основные компоненты объекта расширения

Объект расширения в Marked представляет собой JavaScript-объект с определёнными свойствами, которые позволяют контролировать поведение парсера. Основные свойства включают:

  1. name – строковое имя расширения. Используется для идентификации расширения в списке подключённых. Например:

    const myExtension = {
        name: 'customLink'
    };
  2. level – определяет уровень обработки: block или inline.

    • block – расширение применяется к блочным элементам Markdown, таким как параграфы, заголовки, списки.
    • inline – расширение применяется к содержимому внутри блочных элементов, например, к ссылкам, эмодзи или выделенному тексту.
    level: 'inline'
  3. start – необязательная функция или массив индексов для оптимизации. Используется для повышения производительности парсинга, предоставляя парсеру информацию о том, с каких символов стоит начинать проверку для данного расширения.

    start(src) {
        return src.indexOf('@@');
    }
  4. tokenizer – функция, которая выполняет разбор входного текста и возвращает объект токена. Токен описывает распознанный элемент Markdown. Структура токена:

    {
        type: 'custom',       // тип токена
        raw: '@@example@@',   // исходный текст
        text: 'example'       // содержимое без маркеров
    }

    Пример tokenizer для нестандартного синтаксиса:

    tokenizer(src) {
        const match = /^@@(\w+)@@/.exec(src);
        if (match) {
            return {
                type: 'custom',
                raw: match[0],
                text: match[1]
            };
        }
    }
  5. renderer – функция, которая преобразует токен в HTML. Принимает токен, возвращает строку с HTML-разметкой:

    renderer(token) {
        return `<span class="highlight">${token.text}</span>`;
    }
  6. childTokens – массив дочерних токенов, если элемент имеет вложенную структуру. Полезно для блочных элементов, содержащих внутренние инлайн-элементы.

    const token = {
        type: 'customBlock',
        raw: '::alert This is important::',
        text: 'This is important',
        childTokens: []
    };

Особенности и расширенные возможности

  • Множественные расширения: можно подключать массив объектов расширений. Парсер будет последовательно применять их, начиная с первого.
  • Совместимость с встроенными правилами: расширения не удаляют стандартный функционал Marked, а дополняют его.
  • Асинхронные расширения: начиная с версии 5.x, tokenizer может быть асинхронным, возвращая Promise, что удобно при интеграции с внешними источниками данных.

Пример комплексного расширения

const alertExtension = {
    name: 'alertBlock',
    level: 'block',
    start(src) {
        return src.indexOf('::alert');
    },
    tokenizer(src) {
        const rule = /^::alert\s+([\s\S]+?)::/;
        const match = rule.exec(src);
        if (match) {
            return {
                type: 'alert',
                raw: match[0],
                text: match[1].trim()
            };
        }
    },
    renderer(token) {
        return `<div class="alert">${token.text}</div>`;
    }
};

Это расширение создаёт блоки предупреждений в Markdown, которые будут рендериться в HTML с обёрткой <div class="alert">.

Рекомендации по организации объектов расширения

  • Единообразие свойств: все расширения должны иметь name, level и хотя бы один из методов tokenizer или renderer.
  • Минимизация пересечений: уникальные имена и уникальные правила регулярных выражений предотвращают конфликты с другими расширениями.
  • Оптимизация производительности: использование свойства start уменьшает количество проверок текста и ускоряет обработку больших документов.
  • Вложенные токены: для блоков с внутренними элементами рекомендуется использовать childTokens и соответствующие правила рендеринга, чтобы сохранить структуру документа.

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