mermaid diagrams are rendered as image tags with link to mermaid server rendering; uses pako for compression as expected

This commit is contained in:
Adam Teichert
2025-12-10 17:44:02 -07:00
parent f6b2427749
commit a203dc6e46
4 changed files with 45 additions and 3 deletions

View File

@@ -0,0 +1,22 @@
import { describe, it, expect } from 'vitest';
import { markdownToHtmlNoImages } from './htmlMarkdownUtils';
describe('markdownToHtmlNoImages', () => {
it('renders mermaid diagrams correctly using pako compression', () => {
const markdown = `
\`\`\`mermaid
graph TD;
A-->B;
A-->C;
B-->D;
C-->D;
\`\`\`
`;
const html = markdownToHtmlNoImages(markdown);
// The expected URL part for the graph above when compressed with pako
const expectedUrlPart = "pako:eNqrVkrOT0lVslJKL0osyFAIcbGOyVMAAkddXTsnJLYzlO0EZMPUOIPZSjpKualFuYmZKUpW1UolGam5IONSUtMSS3NKlGprAQJ0Gx4";
expect(html).toContain(`https://mermaid.ink/img/${expectedUrlPart}`);
});
});

View File

@@ -2,6 +2,7 @@
import { marked } from "marked";
import DOMPurify from "isomorphic-dompurify";
import markedKatex from "marked-katex-extension";
import pako from "pako";
import { LocalCourseSettings } from "@/features/local/course/localCourseSettings";
const mermaidExtension = {
@@ -22,9 +23,17 @@ const mermaidExtension = {
}
},
renderer(token: { text: string }) {
const base64 = btoa(token.text);
const url = `https://mermaid.ink/img/${base64}?type=svg`;
console.log(token.text, url);
const data = JSON.stringify({
code: token.text,
mermaid: { theme: "default" },
});
const compressed = pako.deflate(data, { level: 9 });
const binaryString = Array.from(compressed, (byte) =>
String.fromCharCode(byte)
).join("");
const base64 = btoa(binaryString).replace(/\+/g, "-").replace(/\//g, "_");
const url = `https://mermaid.ink/img/pako:${base64}?type=svg`;
// console.log(token.text, url);
return `<img src="${url}" alt="Mermaid diagram" />`;
},
};
@@ -63,6 +72,8 @@ export function convertImagesToCanvasImages(
}, {} as { [key: string]: string });
for (const imageSrc of imageSources) {
if (imageSrc.startsWith("http://") || imageSrc.startsWith("https://"))
continue;
const destinationUrl = imageLookup[imageSrc];
if (typeof destinationUrl === "undefined") {
console.log(