mermaid-it-markdown
Version:
一个markdown-it的插件,用于支持mermaid语法的渲染
110 lines (109 loc) • 3.97 kB
JavaScript
import mermaid from "mermaid";
let getRandomValues;
const rnds8 = new Uint8Array(16);
function rng() {
if (!getRandomValues) {
getRandomValues = typeof crypto !== "undefined" && crypto.getRandomValues && crypto.getRandomValues.bind(crypto);
if (!getRandomValues) {
throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");
}
}
return getRandomValues(rnds8);
}
const byteToHex = [];
for (let i = 0; i < 256; ++i) {
byteToHex.push((i + 256).toString(16).slice(1));
}
function unsafeStringify(arr, offset = 0) {
return byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]];
}
const randomUUID = typeof crypto !== "undefined" && crypto.randomUUID && crypto.randomUUID.bind(crypto);
const native = {
randomUUID
};
function v4(options, buf, offset) {
if (native.randomUUID && !buf && !options) {
return native.randomUUID();
}
options = options || {};
const rnds = options.random || (options.rng || rng)();
rnds[6] = rnds[6] & 15 | 64;
rnds[8] = rnds[8] & 63 | 128;
if (buf) {
offset = offset || 0;
for (let i = 0; i < 16; ++i) {
buf[offset + i] = rnds[i];
}
return buf;
}
return unsafeStringify(rnds);
}
const genUid = (split = "") => {
return v4().split("-").join(split);
};
const hashCode = (str) => {
let hash = 0;
if (str.length === 0)
return hash;
for (let i = 0; i < str.length; i++) {
const char = str.charCodeAt(i);
hash = (hash << 5) - hash + char;
hash = hash & hash;
}
return Math.abs(hash);
};
const mermaidCache = /* @__PURE__ */ new Map();
const MAX_CACHE_SIZE = 200;
const mermaidCacheCount = /* @__PURE__ */ new Map();
let count = 0;
const clearCache = () => {
if (mermaidCache.size <= MAX_CACHE_SIZE)
return;
const entries = Array.from(mermaidCacheCount.entries());
entries.sort((a, b) => a[1] - b[1]);
const deleteCount = Math.floor(entries.length / 2);
for (let i = 0; i < deleteCount; i++) {
const key = entries[i][0];
mermaidCache.delete(key);
mermaidCacheCount.delete(key);
}
};
const renderMermaid = async (code, targetId) => {
const container = document.getElementById(targetId);
if (!container)
return;
try {
const { svg } = await mermaid.render("mermaid-svg-" + genUid(), code);
container.innerHTML = svg;
mermaidCache.set(targetId, svg);
mermaidCacheCount.set(targetId, count);
} catch (e) {
console.error("Mermaid rendering error:", e);
container.innerHTML = `<div style="color: red; padding: 10px; border: 1px solid red;">Mermaid Error: ${e.message || "Invalid syntax"}</div>`;
}
};
const MermaidIt = function(md) {
mermaid.initialize({ startOnLoad: false });
const defaultRenderer = md.renderer.rules.fence.bind(md.renderer.rules);
md.renderer.rules.fence = (tokens, idx, options, env, self) => {
count++;
clearCache();
const token = tokens[idx];
const info = token.info.trim();
if (info === "mermaid") {
const containerId = "mermaid-container-" + hashCode(token.content);
const cachedSvg = mermaidCache.get(containerId);
if (cachedSvg) {
mermaidCacheCount.set(containerId, count);
return `<div id="${containerId}">${cachedSvg}</div>`;
} else {
setTimeout(() => renderMermaid(token.content, containerId), 0);
return `<div id="${containerId}">Loading mermaid...</div>`;
}
}
return defaultRenderer(tokens, idx, options, env, self);
};
};
export {
MermaidIt as default
};