import { marked } from "marked";
// Расширение для спойлеров
const spoilerExtension = {
name: "spoiler",
level: "inline" as const,
start(src: string) {
return src.match(/\|\|/)?.index;
},
tokenizer(src: string) {
const rule = /^\|\|(.*?)\|\|/;
const match = rule.exec(src);
if (match) {
return {
type: "spoiler",
raw: match[0],
text: match[1].trim(),
};
}
},
renderer(token: any) {
return `${token.text}`;
},
};
// Функция для рендеринга вложенных токенов
function renderTokens(tokens: any[], renderer: any): string {
return tokens
.map((token) => {
// Используем кастомный renderer если он есть
if (renderer[token.type]) {
return renderer[token.type](token);
}
// Fallback для встроенных типов токенов
if (token.type === "text") {
return token.text || "";
}
if (token.type === "strong") {
return `${renderTokens(token.tokens || [], renderer)}`;
}
if (token.type === "em") {
return `${renderTokens(token.tokens || [], renderer)}`;
}
if (token.type === "codespan") {
return `${token.text || ""}`;
}
if (token.type === "del") {
return `${renderTokens(token.tokens || [], renderer)}`;
}
if (token.type === "link") {
// Для ссылок используем кастомный renderer если доступен
if (renderer.link) {
return renderer.link(token);
}
// Fallback для встроенных ссылок
const href = token.href || "";
const title = token.title ? ` title="${token.title}"` : "";
const text =
token.tokens && token.tokens.length > 0
? renderTokens(token.tokens, renderer)
: token.text || "";
return `${text}`;
}
if (token.type === "spoiler") {
// Для спойлеров используем кастомный renderer если доступен
if (renderer.spoiler) {
return renderer.spoiler(token);
}
return `${
token.text || ""
}`;
}
return token.text || "";
})
.join("");
}
// Кастомный renderer для внешних ссылок и чекбоксов
const renderer: any = {
link(token: any) {
const href = token.href;
const title = token.title;
// Правильно обрабатываем вложенные токены для форматирования внутри ссылок
let text = "";
if (token.tokens && token.tokens.length > 0) {
text = renderTokens(token.tokens, this);
} else if (token.text) {
text = token.text;
}
try {
const url = new URL(href, window.location.href);
const isExternal = url.origin !== window.location.origin;
if (isExternal) {
return `${text}`;
}
} catch {}
return `${text}`;
},
// Кастомный renderer для элементов списка с чекбоксами
listitem(token: any) {
const task = token.task;
const checked = token.checked;
// Правильно обрабатываем вложенные токены для форматирования
let content = "";
if (token.tokens && token.tokens.length > 0) {
// Рендерим вложенные токены используя наш renderer
content = renderTokens(token.tokens, this);
} else if (token.text) {
// Если токенов нет, используем текст (для обратной совместимости)
content = token.text;
}
if (task) {
const checkbox = ``;
return `