Skip to content

Instantly share code, notes, and snippets.

@SoMaCoSF
Created March 2, 2025 23:21
Show Gist options
  • Save SoMaCoSF/12292c34627b7baa4897be3d4f04fc1d to your computer and use it in GitHub Desktop.
Save SoMaCoSF/12292c34627b7baa4897be3d4f04fc1d to your computer and use it in GitHub Desktop.
mermaid to svg script, run within terminal in Composer/vscode (mcp next)
# Mermaid to SVG Converter
A PowerShell-based utility to convert Mermaid diagram code to SVG files with a text-based user interface.
## Overview
This tool allows you to create, edit, and convert Mermaid diagram code to SVG files without leaving the terminal. It provides a simple text-based UI for managing and converting your diagrams.
![Mermaid Converter Workflow](https://raw.githubusercontent.com/username/mermaid-to-svg/main/workflow.svg)
## Features
- Interactive text-based UI with navigable menus
- Create and edit Mermaid diagrams directly in the terminal
- Load existing Mermaid code from files
- Convert Mermaid code to SVG using:
- Local Mermaid CLI (if installed)
- Web-based API fallback (requires internet connection)
- Customize output directory
- Built-in dependency checker
- Simple SVG preview screen
## Prerequisites
For optimal experience with local rendering:
- [Node.js](https://nodejs.org/)
- [Mermaid CLI](https://github.com/mermaid-js/mermaid-cli): Install with `npm install -g @mermaid-js/mermaid-cli`
The script will automatically fall back to using the Mermaid.ink web API if local dependencies are not available (requires internet connection).
## Installation
1. Download the `mermaid_to_svg.ps1` script
2. Ensure PowerShell execution policy allows running the script
```powershell
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
```
## Usage
### Basic Usage
```powershell
.\mermaid_to_svg.ps1
```
### Specify Output Directory
```powershell
.\mermaid_to_svg.ps1 -OutputPath "C:\Diagrams"
```
## How to Use
1. Run the script using one of the commands above
2. Navigate through the main menu using keyboard input:
- **1** - Create a new diagram
- **2** - Load Mermaid code from a file
- **3** - Change the output directory
- **4** - Check for dependencies
- **5** - Exit
### Creating/Editing Diagrams
1. Select option **1** or **2** from the main menu
2. In the editor screen:
- Press **E** to enter edit mode
- Type or paste your Mermaid code
- Type **END** on a new line when finished
- Navigate buttons with arrow keys
- Press **Enter** to select a button
### Example Diagram Code
```
flowchart TD
A[Start] --> B{Is it working?}
B -->|Yes| C[Great!]
B -->|No| D[Debug]
D --> B
```
## Limitations
- The SVG viewer is text-based and does not show the actual SVG content
- Some complex Mermaid diagrams may not render correctly with the web API fallback
## Troubleshooting
If you encounter issues:
1. Run the dependency checker (option 4) to verify your setup
2. Ensure you have an internet connection if using the web API fallback
3. Check that your Mermaid code syntax is valid
## License
MIT
## Acknowledgements
- [Mermaid.js](https://mermaid.js.org/) - JavaScript based diagramming and charting tool
- [Mermaid CLI](https://github.com/mermaid-js/mermaid-cli) - Command line interface for Mermaid
- [Mermaid.ink](https://mermaid.ink/) - Web service for rendering Mermaid diagrams
<#
.SYNOPSIS
Converts Mermaid diagram code to SVG with a text-based UI
.DESCRIPTION
This PowerShell script provides a menu-driven interface to convert Mermaid diagram code to SVG files
using either the Mermaid CLI (if installed) or the Mermaid Live Editor API.
.PARAMETER OutputPath
Path to save the SVG file (default: current directory)
.EXAMPLE
.\mermaid_to_svg.ps1
.\mermaid_to_svg.ps1 -OutputPath "C:\Diagrams"
#>
param(
[string]$OutputPath = ""
)
# Initialize default values
if ([string]::IsNullOrEmpty($OutputPath)) { $OutputPath = (Get-Location).Path }
# Function to check if Node.js and Mermaid CLI are installed
function Test-MermaidCLI {
try {
$nodeVersion = node --version
$mmdcVersion = mmdc --version 2>$null
return $true
}
catch {
return $false
}
}
# Function to convert Mermaid to SVG using Mermaid CLI
function Convert-MermaidToSVG-CLI {
param(
[string]$MermaidCode,
[string]$OutputFile
)
$tempFile = Join-Path $env:TEMP "temp_mermaid.mmd"
$MermaidCode | Out-File -FilePath $tempFile -Encoding utf8
try {
mmdc -i $tempFile -o $OutputFile
return $true
}
catch {
Write-Host "Error using Mermaid CLI: $_" -ForegroundColor Red
return $false
}
finally {
if (Test-Path $tempFile) {
Remove-Item $tempFile -Force
}
}
}
# Function to convert Mermaid to SVG using web API
function Convert-MermaidToSVG-API {
param(
[string]$MermaidCode,
[string]$OutputFile
)
try {
# Encode the Mermaid code for URL
$encodedMermaid = [System.Web.HttpUtility]::UrlEncode($MermaidCode)
# Use mermaid.ink service
$url = "https://mermaid.ink/svg/$encodedMermaid"
# Download the SVG
Invoke-WebRequest -Uri $url -OutFile $OutputFile
return $true
}
catch {
Write-Host "Error using Mermaid web API: $_" -ForegroundColor Red
return $false
}
}
# Function to display ASCII button
function Show-Button {
param(
[string]$Text,
[bool]$Selected = $false
)
if ($Selected) {
Write-Host " [" -NoNewline
Write-Host $Text -NoNewline -ForegroundColor Black -BackgroundColor White
Write-Host "] " -NoNewline
}
else {
Write-Host " [ " -NoNewline
Write-Host $Text -NoNewline
Write-Host " ] " -NoNewline
}
}
# Function to display a simple ASCII viewer for SVG
function Show-SVGViewer {
param(
[string]$SVGPath
)
$width = 60
$height = 15
Clear-Host
# Draw top border
Write-Host "╔" -NoNewline
Write-Host ("═" * ($width - 2)) -NoNewline
Write-Host "╗"
# Draw title
$title = " SVG Viewer: $(Split-Path $SVGPath -Leaf) "
$padding = [Math]::Floor(($width - $title.Length) / 2)
Write-Host "║" -NoNewline
Write-Host (" " * $padding) -NoNewline
Write-Host $title -NoNewline -ForegroundColor Cyan
Write-Host (" " * ($width - $padding - $title.Length - 2)) -NoNewline
Write-Host "║"
# Draw separator
Write-Host "╠" -NoNewline
Write-Host ("═" * ($width - 2)) -NoNewline
Write-Host "╣"
# Draw content area
for ($i = 0; $i -lt $height; $i++) {
Write-Host "║" -NoNewline
if ($i -eq [Math]::Floor($height / 2)) {
$message = " SVG created successfully! "
$padding = [Math]::Floor(($width - $message.Length) / 2)
Write-Host (" " * $padding) -NoNewline
Write-Host $message -NoNewline -ForegroundColor Green
Write-Host (" " * ($width - $padding - $message.Length - 2)) -NoNewline
}
elseif ($i -eq [Math]::Floor($height / 2) + 2) {
$message = " Opening in default viewer... "
$padding = [Math]::Floor(($width - $message.Length) / 2)
Write-Host (" " * $padding) -NoNewline
Write-Host $message -NoNewline -ForegroundColor Yellow
Write-Host (" " * ($width - $padding - $message.Length - 2)) -NoNewline
}
else {
Write-Host (" " * ($width - 2)) -NoNewline
}
Write-Host "║"
}
# Draw bottom border
Write-Host "╚" -NoNewline
Write-Host ("═" * ($width - 2)) -NoNewline
Write-Host "╝"
Write-Host
Write-Host "Press any key to continue..." -ForegroundColor DarkGray
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
}
# Function to display the main menu
function Show-MainMenu {
Clear-Host
Write-Host "╔════════════════════════════════════════════════════════╗" -ForegroundColor Cyan
Write-Host "║ MERMAID TO SVG CONVERTER ║" -ForegroundColor Cyan
Write-Host "╚════════════════════════════════════════════════════════╝" -ForegroundColor Cyan
Write-Host
Write-Host "Current Settings:" -ForegroundColor Yellow
Write-Host " Output Path: $OutputPath"
Write-Host
Write-Host "1. Create New Diagram"
Write-Host "2. Load Mermaid Code from File"
Write-Host "3. Change Output Path"
Write-Host "4. Check Dependencies"
Write-Host "5. Exit"
Write-Host
$choice = Read-Host "Enter your choice (1-5)"
return $choice
}
# Function to display the editor interface
function Show-MermaidEditor {
param(
[string[]]$InitialCode = @()
)
$mermaidCode = $InitialCode
$selectedButton = 0 # 0 = Submit, 1 = Clear, 2 = Cancel
$buttons = @("Submit", "Clear", "Cancel")
$editing = $true
while ($editing) {
Clear-Host
Write-Host "╔════════════════════════════════════════════════════════╗" -ForegroundColor Cyan
Write-Host "║ MERMAID CODE EDITOR ║" -ForegroundColor Cyan
Write-Host "╚════════════════════════════════════════════════════════╝" -ForegroundColor Cyan
Write-Host
Write-Host "Enter your Mermaid diagram code below:" -ForegroundColor Yellow
Write-Host "Use the arrow keys to navigate and Enter to submit." -ForegroundColor Yellow
Write-Host
# Display the code box
Write-Host "┌" + ("─" * 58) + "┐"
if ($mermaidCode.Count -eq 0) {
Write-Host "│" -NoNewline
Write-Host " <Enter your Mermaid code here> " -NoNewline -ForegroundColor DarkGray
Write-Host (" " * 28) -NoNewline
Write-Host "│"
}
else {
foreach ($line in $mermaidCode) {
$displayLine = if ($line.Length -gt 56) { $line.Substring(0, 53) + "..." } else { $line }
$padding = 58 - $displayLine.Length
Write-Host "│ " -NoNewline
Write-Host $displayLine -NoNewline
Write-Host (" " * $padding) -NoNewline
Write-Host "│"
}
}
Write-Host "└" + ("─" * 58) + "┘"
Write-Host
# Display buttons
Write-Host " " -NoNewline
for ($i = 0; $i -lt $buttons.Length; $i++) {
Show-Button -Text $buttons[$i] -Selected ($i -eq $selectedButton)
Write-Host " " -NoNewline
}
Write-Host
Write-Host
Write-Host "Press 'E' to edit, arrow keys to navigate, Enter to select" -ForegroundColor DarkGray
# Get key input
$key = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
switch ($key.VirtualKeyCode) {
37 {
# Left arrow
$selectedButton = ($selectedButton - 1) % $buttons.Length
if ($selectedButton -lt 0) { $selectedButton = $buttons.Length - 1 }
}
39 {
# Right arrow
$selectedButton = ($selectedButton + 1) % $buttons.Length
}
69 {
# E key
# Edit mode
Clear-Host
Write-Host "Enter/paste your Mermaid code below." -ForegroundColor Yellow
Write-Host "Type 'END' on a new line when finished." -ForegroundColor Yellow
Write-Host
$newCode = @()
$line = ""
do {
$line = Read-Host
if ($line -ne "END") {
$newCode += $line
}
} while ($line -ne "END")
if ($newCode.Count -gt 0) {
$mermaidCode = $newCode
}
}
13 {
# Enter key
switch ($selectedButton) {
0 {
# Submit
if ($mermaidCode.Count -gt 0) {
$editing = $false
return $mermaidCode
}
else {
Write-Host "Please enter some Mermaid code first." -ForegroundColor Red
Start-Sleep -Seconds 2
}
}
1 {
# Clear
$mermaidCode = @()
}
2 {
# Cancel
return $null
}
}
}
}
}
return $mermaidCode
}
# Function to load Mermaid code from file
function Load-MermaidFromFile {
$filePath = Read-Host "Enter path to Mermaid file (.mmd, .txt)"
if (-not (Test-Path $filePath)) {
Write-Host "File not found: $filePath" -ForegroundColor Red
Start-Sleep -Seconds 2
return $null
}
try {
$content = Get-Content -Path $filePath -Raw
return $content -split "`n"
}
catch {
Write-Host "Error reading file: $_" -ForegroundColor Red
Start-Sleep -Seconds 2
return $null
}
}
# Function to change output path
function Set-OutputDirectory {
$newPath = Read-Host "Enter new output path (current: $OutputPath)"
if ([string]::IsNullOrEmpty($newPath)) {
return $OutputPath
}
if (Test-Path $newPath -PathType Container) {
return $newPath
}
else {
$createDir = Read-Host "Directory doesn't exist. Create it? (y/n)"
if ($createDir -eq "y") {
try {
New-Item -ItemType Directory -Path $newPath -Force | Out-Null
return $newPath
}
catch {
Write-Host "Error creating directory: $_" -ForegroundColor Red
Start-Sleep -Seconds 2
return $OutputPath
}
}
else {
return $OutputPath
}
}
}
# Function to check dependencies
function Check-Dependencies {
Clear-Host
Write-Host "╔════════════════════════════════════════════════════════╗" -ForegroundColor Cyan
Write-Host "║ DEPENDENCY CHECKER ║" -ForegroundColor Cyan
Write-Host "╚════════════════════════════════════════════════════════╝" -ForegroundColor Cyan
Write-Host
# Check for Node.js
Write-Host "Checking for Node.js..." -NoNewline
try {
$nodeVersion = node --version
Write-Host " FOUND" -ForegroundColor Green
Write-Host " Version: $nodeVersion"
}
catch {
Write-Host " NOT FOUND" -ForegroundColor Red
Write-Host " Node.js is required for local rendering. Install from https://nodejs.org/"
}
# Check for Mermaid CLI
Write-Host "Checking for Mermaid CLI..." -NoNewline
try {
$mmdcVersion = mmdc --version 2>$null
Write-Host " FOUND" -ForegroundColor Green
Write-Host " Version: $mmdcVersion"
}
catch {
Write-Host " NOT FOUND" -ForegroundColor Red
Write-Host " Install with: npm install -g @mermaid-js/mermaid-cli"
}
# Check for internet connection (for API fallback)
Write-Host "Checking internet connection..." -NoNewline
try {
$webRequest = Invoke-WebRequest -Uri "https://mermaid.ink" -UseBasicParsing -TimeoutSec 5
Write-Host " CONNECTED" -ForegroundColor Green
}
catch {
Write-Host " NOT CONNECTED" -ForegroundColor Yellow
Write-Host " Internet connection required for API fallback if CLI is not available."
}
Write-Host
Write-Host "Press any key to continue..." -ForegroundColor DarkGray
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
}
# Main function
function Start-MermaidConverter {
$exit = $false
while (-not $exit) {
$choice = Show-MainMenu
switch ($choice) {
"1" {
# Create New Diagram
$mermaidCode = Show-MermaidEditor
if ($null -ne $mermaidCode -and $mermaidCode.Count -gt 0) {
# Join the lines
$mermaidCodeText = $mermaidCode -join "`n"
# Get output filename
$defaultFilename = "mermaid_diagram_$(Get-Date -Format 'yyyyMMdd_HHmmss').svg"
$outputFilename = Read-Host "Enter output filename (default: $defaultFilename)"
if ([string]::IsNullOrEmpty($outputFilename)) {
$outputFilename = $defaultFilename
}
if (-not $outputFilename.EndsWith(".svg")) {
$outputFilename += ".svg"
}
$outputFile = Join-Path $OutputPath $outputFilename
# Ensure output directory exists
$outputDir = Split-Path -Path $outputFile -Parent
if (-not (Test-Path $outputDir)) {
New-Item -ItemType Directory -Path $outputDir | Out-Null
}
# Try to convert using available methods
Write-Host "Converting Mermaid code to SVG..." -ForegroundColor Cyan
$success = $false
# First try using Mermaid CLI if available
if (Test-MermaidCLI) {
Write-Host "Using Mermaid CLI..." -ForegroundColor Green
$success = Convert-MermaidToSVG-CLI -MermaidCode $mermaidCodeText -OutputFile $outputFile
}
# If CLI failed or not available, try web API
if (-not $success) {
Write-Host "Using Mermaid web API..." -ForegroundColor Yellow
# Load HttpUtility for URL encoding
Add-Type -AssemblyName System.Web
$success = Convert-MermaidToSVG-API -MermaidCode $mermaidCodeText -OutputFile $outputFile
}
if ($success) {
# Show the SVG viewer
Show-SVGViewer -SVGPath $outputFile
# Open the file
Invoke-Item $outputFile
}
else {
Write-Host "Failed to convert Mermaid code to SVG." -ForegroundColor Red
Start-Sleep -Seconds 2
}
}
}
"2" {
# Load Mermaid Code from File
$loadedCode = Load-MermaidFromFile
if ($null -ne $loadedCode) {
$mermaidCode = Show-MermaidEditor -InitialCode $loadedCode
if ($null -ne $mermaidCode -and $mermaidCode.Count -gt 0) {
# Process the same as option 1
# (Code duplicated for clarity, could be refactored)
$mermaidCodeText = $mermaidCode -join "`n"
$defaultFilename = "mermaid_diagram_$(Get-Date -Format 'yyyyMMdd_HHmmss').svg"
$outputFilename = Read-Host "Enter output filename (default: $defaultFilename)"
if ([string]::IsNullOrEmpty($outputFilename)) {
$outputFilename = $defaultFilename
}
if (-not $outputFilename.EndsWith(".svg")) {
$outputFilename += ".svg"
}
$outputFile = Join-Path $OutputPath $outputFilename
if (-not (Test-Path (Split-Path -Path $outputFile -Parent))) {
New-Item -ItemType Directory -Path (Split-Path -Path $outputFile -Parent) | Out-Null
}
$success = $false
if (Test-MermaidCLI) {
$success = Convert-MermaidToSVG-CLI -MermaidCode $mermaidCodeText -OutputFile $outputFile
}
if (-not $success) {
Add-Type -AssemblyName System.Web
$success = Convert-MermaidToSVG-API -MermaidCode $mermaidCodeText -OutputFile $outputFile
}
if ($success) {
Show-SVGViewer -SVGPath $outputFile
Invoke-Item $outputFile
}
else {
Write-Host "Failed to convert Mermaid code to SVG." -ForegroundColor Red
Start-Sleep -Seconds 2
}
}
}
}
"3" {
# Change Output Path
$OutputPath = Set-OutputDirectory
}
"4" {
# Check Dependencies
Check-Dependencies
}
"5" {
# Exit
$exit = $true
}
default {
Write-Host "Invalid choice. Please try again." -ForegroundColor Red
Start-Sleep -Seconds 1
}
}
}
}
# Start the application
Start-MermaidConverter
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment