Novolis Docs
novolis-governance / completed-plans/mermaid_rendering_package_f25717a3.plan.md

Novolis.Markup.Mermaid.Rendering

dotnetgovernancenovolis

name: Mermaid Rendering package overview: Add Novolis.Markup.Mermaid.Rendering in novolis-markup with IMermaidable extension methods for SVG (Mermaider) and PNG (Svg.Skia), then thin Avalonia.Mermaid to consume it instead of owning Mermaider. todos:

  • id: scaffold-pkg

content: Scaffold Novolis.Markup.Mermaid.Rendering csproj, packages.json, slnx, Directory.Packages.props (Mermaider + Svg.Skia) status: completed

  • id: svg-png-api

content: Implement MermaidSvgRenderer, MermaidPngRenderer, MermaidRenderTheme, IMermaidable extension methods status: completed

  • id: unit-tests

content: Add Markup.Unit Rendering tests for SVG/PNG/export/themes status: completed

  • id: docs-map

content: Package README + Generate-Platform-Slnx.ps1 regen status: completed

  • id: avalonia-thin

content: "After markup GPR: Avalonia.Mermaid wraps Rendering; drop direct Mermaider ref" status: completed isProject: false


Context

Package

ItemValue
PackageId`Novolis.Markup.Mermaid.Rendering`
Path[`d:\novolis\novolis-markup\src\Novolis.Markup.Mermaid.Rendering\`](d:\novolis\novolis-markup\src\Novolis.Markup.Mermaid.Rendering\)
Deps`Novolis.Markup.Mermaid` (ProjectReference), **Mermaider** `0.12.1`, **Svg.Skia** (pulls SkiaSharp for raster)
LayerOrthogonal Markup island — **no Avalonia**

Public API

Extensions on IMermaidable (and parallel string helpers for raw Mermaid source):

using Novolis.Markup.Mermaid;
using Novolis.Markup.Mermaid.Rendering;

var chart = new Flowchart(Direction.TopToBottom);
// ...
string? svg = chart.ToSvg();                    // Mermaider
byte[]? png = chart.ToPng(scale: 2f);           // Mermaider → Svg.Skia
chart.ExportSvg(@"d:\out\diagram.svg");
chart.ExportPng(@"d:\out\diagram.png");

Supporting types (moved/adapted from Avalonia):

  • MermaidRenderThemeStudioDark / GitHubLight (same palettes as current MermaidTheme)
  • MermaidSvgRenderer — static TryRenderSvg / theme→RenderOptions (core of today’s MermaidSvg)
  • MermaidPngRenderer — SVG string → PNG bytes via SKSvg
  • MermaidRenderExtensionsToSvg / ToPng / ExportSvg / ExportPng on IMermaidable
  • Soft-fail: Try* / To* return null on blank/invalid (match Avalonia); Export* return bool

HTML <img> / fallback <pre> stay in Avalonia (UI host concern), not this package.

flowchart LR
  builder[IMermaidable]
  text[Mermaid source string]
  mermaider[Mermaider RenderSvg]
  svg[SVG string]
  skia[Svg.Skia]
  png[PNG bytes]
  builder -->|GetMermaidString| text
  text --> mermaider --> svg
  svg --> skia --> png

Avalonia follow-up (same effort, after markup publish)

In `novolis-avalonia`:

  • Replace direct Mermaider PackageReference with Novolis.Markup.Mermaid.Rendering
  • Make MermaidSvg.TryRenderSvg / OptionsFor thin wrappers over MermaidSvgRenderer
  • Map MermaidThemeMermaidRenderTheme (keep Avalonia enum for API stability; Markdown preview mapping unchanged)
  • Update unit tests that assert theme options

Publish order: markup first (GPR), then Avalonia. Local ProjectRef via Novolis.Platform.slnx covers both before GPR.

Repo wiring (novolis-markup)

Tests

Under tests/Novolis.Markup.Unit/Mermaid/Rendering/:

  • Flowchart/sequence ToSvg contains <svg
  • Blank / invalid → null
  • ToPng non-empty, PNG signature 89 50 4E 47
  • Theme StudioDark vs GitHubLight changes background options
  • ExportSvg / ExportPng write files

Out of scope

  • Dogfooding demo app
  • Changing fluent Mermaid builders
  • Moving HTML image helpers into Markup
  • Touching Novolis.Rendering.* GPU stack