104 lines
3.2 KiB
TypeScript
104 lines
3.2 KiB
TypeScript
import { Marked, type MarkedExtension } from "marked";
|
|
import { createDirectives, presetDirectiveConfigs } from "marked-directive";
|
|
import markedAlert from "marked-alert";
|
|
import markedMermaid from "./mermaid";
|
|
import markedTable from "./table";
|
|
import { gfmHeadingId } from "marked-gfm-heading-id";
|
|
import markedColumns from "./columns";
|
|
import markedCodeBlockYamlTag from "./code-block-yaml-tag";
|
|
|
|
let globalIconPrefix: string | undefined = undefined;
|
|
function overrideIconPrefix(path?: string) {
|
|
globalIconPrefix = path;
|
|
return {
|
|
[Symbol.dispose]() {
|
|
globalIconPrefix = undefined;
|
|
},
|
|
};
|
|
}
|
|
|
|
// 使用 marked-directive 来支持指令语法
|
|
const marked = new Marked()
|
|
.use(gfmHeadingId())
|
|
.use(markedAlert())
|
|
.use(markedMermaid())
|
|
.use(markedTable())
|
|
.use(markedCodeBlockYamlTag())
|
|
.use(
|
|
createDirectives([
|
|
...presetDirectiveConfigs,
|
|
{
|
|
marker: "::::",
|
|
level: "container",
|
|
},
|
|
{
|
|
marker: ":::::",
|
|
level: "container",
|
|
},
|
|
{
|
|
level: "inline",
|
|
marker: ":",
|
|
// :[icon] 或 :[icon.ext] 语法
|
|
// 支持的扩展名: .svg, .png, .gif, .jpg, .jpeg, .webp
|
|
// 如果不指定扩展名,默认为 .png
|
|
renderer(token) {
|
|
if (!token.meta.name) {
|
|
const iconText = token.text || "";
|
|
|
|
// 已知支持的图片扩展名
|
|
const supportedExtensions = [
|
|
"svg",
|
|
"png",
|
|
"gif",
|
|
"jpg",
|
|
"jpeg",
|
|
"webp",
|
|
];
|
|
|
|
// 检查是否包含扩展名(查找最后一个点)
|
|
let iconName = iconText;
|
|
let extension = "png"; // 默认扩展名
|
|
|
|
const lastDotIndex = iconName.lastIndexOf(".");
|
|
if (lastDotIndex > 0) {
|
|
const potentialExt = iconName
|
|
.slice(lastDotIndex + 1)
|
|
.toLowerCase();
|
|
if (supportedExtensions.includes(potentialExt)) {
|
|
extension = potentialExt;
|
|
iconName = iconName.slice(0, lastDotIndex);
|
|
}
|
|
}
|
|
|
|
const label = token.attrs?.label as string | undefined;
|
|
const inner = label
|
|
? `<span class="icon-label-stroke">${label}</span><span class="icon-label">${label}</span>`
|
|
: "";
|
|
const style = globalIconPrefix
|
|
? `style="--icon-src: url('${globalIconPrefix}/${iconName}.${extension}')"`
|
|
: "";
|
|
const iconHtml = `<icon ${style} class="icon-${iconName} ${token.attrs?.class || ""}">${inner}</icon>`;
|
|
|
|
const repeat = parseInt(`${token.attrs?.repeat || ""}`);
|
|
const join = token.attrs?.join || "";
|
|
const separator = join ? `<${join}></${join}>` : "";
|
|
if (isNaN(repeat) || repeat < 1) return iconHtml;
|
|
|
|
return Array(repeat).fill(iconHtml).join(separator);
|
|
}
|
|
return false;
|
|
},
|
|
},
|
|
]),
|
|
{
|
|
extensions: [...markedColumns()],
|
|
},
|
|
);
|
|
|
|
export function parseMarkdown(content: string, iconPrefix?: string): string {
|
|
using prefix = overrideIconPrefix(iconPrefix);
|
|
return marked.parse(content.trimStart()) as string;
|
|
}
|
|
|
|
export { marked };
|