feat: support mermaid charts in markdown renderer#1889
Conversation
Greptile SummaryAdds Mermaid diagram rendering support to the existing markdown renderer by intercepting
Confidence Score: 4/5Safe to merge with awareness of the SVG injection surface and the mermaid global-state reset on every render. The core rendering pipeline is well-structured: the promise queue correctly serializes mermaid renders, cancellation prevents stale setState calls, and the pre-wrapper stripping logic works for the react-markdown output shape. The two areas that warrant a second look are the dangerouslySetInnerHTML path (SVG from AI-generated diagram content bypasses React's XSS protection and trusts mermaid's internal DOMPurify entirely) and mermaid.initialize being called on every queued render rather than only on theme changes, which resets mermaid's full global state unnecessarily and could interact poorly with future mermaid updates. mermaid-renderer.ts and mermaid-diagram.tsx deserve the most attention — the initialize-on-every-render pattern and the dangerouslySetInnerHTML injection are both concentrated there.
|
| Filename | Overview |
|---|---|
| src/renderer/lib/ui/mermaid-renderer.ts | New module: serialized mermaid render queue; calls mermaid.initialize on every render which resets global state unnecessarily. |
| src/renderer/lib/ui/mermaid-diagram.tsx | New React component wrapping mermaid rendering with loading/error states; uses dangerouslySetInnerHTML for SVG output and has a duplicate error message in the fallback path. |
| src/renderer/lib/ui/markdown-renderer.tsx | Intercepts mermaid code blocks in both full and compact variants, strips the pre wrapper around MermaidDiagram, and threads isDark into useCompactComponents correctly. |
| package.json | Adds mermaid ^11.12.2 as a production dependency. |
| pnpm-lock.yaml | Lockfile updated to pin mermaid 11.12.2. |
Sequence Diagram
sequenceDiagram
participant MD as MarkdownRenderer
participant CC as code component
participant MD2 as MermaidDiagram
participant MR as mermaid-renderer (queue)
participant LIB as mermaid lib
MD->>CC: render code block (className="language-mermaid")
CC->>CC: renderMermaidCodeBlock()
CC-->>MD2: <MermaidDiagram chart=... isDark=... />
MD->>pre: render pre (children = <MermaidDiagram/>)
pre->>pre: isOnlyMermaidDiagramChild() → true
pre-->>MD: <>{children}</> (wrapper stripped)
MD2->>MR: renderMermaidDiagram({ id, chart, theme })
Note over MR: chains onto renderQueue promise
MR->>LIB: mermaid.initialize(config)
MR->>LIB: mermaid.render(id, chart)
LIB-->>MR: { svg }
MR-->>MD2: svg string
MD2->>MD2: setState({ kind: 'rendered', svg })
MD2-->>MD: <div dangerouslySetInnerHTML={svg} />
Prompt To Fix All With AI
Fix the following 3 code review issues. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 3
src/renderer/lib/ui/mermaid-renderer.ts:23-35
**`mermaid.initialize` called on every render, resetting global state**
`mermaid.initialize(config)` is called inside `render` on every invocation of `renderMermaidDiagram`, even when the theme hasn't changed. Mermaid's `initialize` resets its entire internal state (clearing layout caches, re-registering diagram types, etc.), which is both wasteful and fragile. If mermaid is ever updated to schedule async work inside `initialize`, it would escape the render queue's serialization. The last-used theme should be tracked at module scope so `initialize` is only called when the theme actually changes.
### Issue 2 of 3
src/renderer/lib/ui/mermaid-diagram.tsx:82-85
**`dangerouslySetInnerHTML` bypasses React's XSS protection for mermaid SVG output**
The SVG string from `mermaid.render` is injected directly into the DOM. While `securityLevel: 'strict'` instructs mermaid to run DOMPurify over the output, this relies entirely on mermaid's internal sanitizer being correct and up-to-date. In this app, diagram content originates from AI model output, which can include crafted mermaid syntax. If a mermaid parser bug or a DOMPurify bypass is ever found, arbitrary SVG/script content would execute in the renderer process. Consider running the returned SVG through an independent sanitization step (e.g. DOMPurify directly in this file) before injecting it.
### Issue 3 of 3
src/renderer/lib/ui/mermaid-diagram.tsx:51-58
**Duplicate "Unable to render Mermaid diagram." message in error fallback path**
The error UI always shows `"Unable to render Mermaid diagram."` as a bold title, then renders `visibleState.message` below it. `errorMessage()` returns the same string `'Unable to render Mermaid diagram.'` as a fallback when the thrown value is not an `Error` or has an empty message — so when that path is taken, the same sentence appears twice in the error box. The mermaid-specific error text (e.g. a parse error string) should be shown in the `message` slot only when it differs from the generic title, or the title should be omitted in the generic fallback.
Reviews (1): Last reviewed commit: "feat(renderer): render mermaid code fenc..." | Re-trigger Greptile
No description provided.