В библиотеке Marked инлайн-токенизация отвечает за
разбор содержимого строк Markdown на составляющие элементы, такие как
ссылки, изображения, эмфаза текста, коды и другие встроенные
конструкции. Основной объект для работы — Lexer с
методом inlineTokens, а также возможность создания
собственных токенов через расширения.
Инлайн-токен в Marked представлен объектом с определёнными ключами:
type — тип токена (text,
strong, em, link,
image, codespan и т. д.).raw — исходная строка, соответствующая этому
токену.text — текстовое содержимое токена (без
Markdown-разметки).href — ссылка для токенов link или
image.title — атрибут title для ссылок и
изображений.tokens — массив вложенных токенов для сложных
элементов, например, эмфазы внутри ссылки.Пример токена для ссылки:
{
"type": "link",
"raw": "[пример](https://example.com)",
"text": "пример",
"href": "https://example.com",
"title": null,
"tokens": [
{ "type": "text", "raw": "пример", "text": "пример" }
]
}
Базовый инлайн-лексер вызывается через метод
Lexer.lexInline или Lexer.lex. Для
примера:
import { Lexer } from 'marked';
const md = "Это **жирный** текст и [ссылка](https://example.com)";
const tokens = Lexer.lexInline(md);
console.log(tokens);
Результат — массив токенов, где emphasis, strong, link будут выделены как отдельные объекты.
Для расширения стандартного поведения Marked используется объект extensions, содержащий правила для новых токенов. Структура правила включает:
name — уникальное имя токена.level — inline или
block.start — функция или регулярное выражение, определяющее
возможное начало токена.tokenizer — функция, которая принимает строку и
возвращает токен.renderer — функция для преобразования токена в
HTML.Пример создания токена для кастомного тега
==highlight==:
import { marked } from 'marked';
const highlightExtension = {
name: 'highlight',
level: 'inline',
start: (src) => src.indexOf('=='),
tokenizer: (src) => {
const match = /^==(.+?)==/.exec(src);
if (match) {
return {
type: 'highlight',
raw: match[0],
text: match[1]
};
}
},
renderer: (token) => `<mark>${token.text}</mark>`
};
marked.use({ extensions: [highlightExtension] });
const html = marked.parse('Это ==важно==!');
console.log(html); // <p>Это <mark>важно</mark>!</p>
Инлайн-токен может содержать вложенные токены. Это необходимо для
правильного разбора Markdown внутри ссылок, эмфазы и других конструкций.
Метод Lexer.inlineTokens рекурсивно создаёт массив токенов
для вложенного содержимого. Пример:
const md = "Текст с *курсивом* внутри [ссылки *важно*](https://example.com)";
const tokens = Lexer.lexInline(md);
Внутри токена link появится массив tokens с
объектами text и em, что позволяет корректно
рендерить HTML с вложенной разметкой.
Marked позволяет переопределять существующие токены через расширения:
const strongOverride = {
name: 'strong',
level: 'inline',
tokenizer: (src) => {
const match = /^\*\*(.+?)\*\*/.exec(src);
if (match) {
return {
type: 'strong',
raw: match[0],
text: match[1],
tokens: Lexer.inlineTokens(match[1])
};
}
},
renderer: (token) => `<b>${token.text}</b>`
};
marked.use({ extensions: [strongOverride] });
Это полезно для добавления кастомного HTML или других атрибутов к стандартным токенам.
tokens: Lexer.inlineTokens(text), чтобы вложенные
Markdown-элементы были корректно разобраны.start функции критичны для производительности: они
позволяют Marked быстро пропускать части строки, которые точно не
содержат токен.tokenizer должны быть «ленивыми»
(+?), чтобы не поглощать лишний текст.Для визуализации структуры токенов удобно использовать
console.dir(tokens, { depth: null }). Это позволяет увидеть
полную вложенность токенов, включая все свойства raw,
text, tokens, href и
title.
Хотите, я могу дополнительно сделать подробный разбор реальных сложных примеров Markdown с несколькими вложенными инлайн-токенами, чтобы показать работу Marked «в бою»?