Compare commits

..

1 Commits

Author SHA1 Message Date
dependabot[bot] d39e3412e0
Bump @mermaid-js/mermaid-cli from 9.1.7 to 10.0.0 in /mermaidcli
Bumps [@mermaid-js/mermaid-cli](https://github.com/mermaid-js/mermaid-cli) from 9.1.7 to 10.0.0.
- [Release notes](https://github.com/mermaid-js/mermaid-cli/releases)
- [Commits](https://github.com/mermaid-js/mermaid-cli/compare/9.1.7...10.0.0)

---
updated-dependencies:
- dependency-name: "@mermaid-js/mermaid-cli"
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-06 07:56:50 +00:00
29 changed files with 605 additions and 5633 deletions

View File

@ -1,94 +1,78 @@
# Multi-stage build
# Stage 1: Build the Go executable
FROM golang:1.21-bookworm as go-builder
# This stage builds the go executable.
FROM golang:1.19.3-buster as go
WORKDIR /root
COPY go.mod go.sum ./
RUN go mod download
COPY ./ ./
COPY cmd/ ./cmd/
COPY internal/ ./internal/
RUN go build -o bin/app cmd/app/main.go
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o bin/app cmd/app/main.go
# Stage 2: Setup Node.js environment with mermaid CLI and Chrome
FROM node:20-bookworm-slim
# Final stage that will be pushed.
FROM debian:buster-slim
FROM node:18.10.0-buster-slim as node
WORKDIR /root
# copy the mermaidcli node package into the container and install
COPY ./mermaidcli/* ./
RUN npm install && npm cache clean --force;
# Install system dependencies for Chrome/Puppeteer
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y \
ca-certificates \
fonts-liberation \
libappindicator3-1 \
libasound2 \
libatk-bridge2.0-0 \
libatk1.0-0 \
libc6 \
libcairo2 \
libcups2 \
libdbus-1-3 \
libexpat1 \
libfontconfig1 \
libgbm1 \
libgcc1 \
libglib2.0-0 \
libgtk-3-0 \
libnspr4 \
libnss3 \
libpango-1.0-0 \
libpangocairo-1.0-0 \
libstdc++6 \
libx11-6 \
libx11-xcb1 \
libxcb1 \
libxcomposite1 \
libxcursor1 \
libxdamage1 \
libxext6 \
libxfixes3 \
libxi6 \
libxrandr2 \
libxrender1 \
libxss1 \
libxtst6 \
libxshmfence1 \
libdrm2 \
libxkbcommon0 \
libatspi2.0-0 \
lsb-release \
wget \
xdg-utils \
--no-install-recommends && \
rm -rf /var/lib/apt/lists/*
RUN apt-get update 2>/dev/null && \
apt-get install -y --no-install-recommends \
ca-certificates \
gconf-service \
libasound2 \
libatk1.0-0 \
libatk-bridge2.0-0 \
libc6 \
libcairo2 \
libcups2 \
libdbus-1-3 \
libexpat1 \
libfontconfig1 \
libgcc1 \
libgconf-2-4 \
libgdk-pixbuf2.0-0 \
libglib2.0-0 \
libgtk-3-0 \
libnspr4 \
libpango-1.0-0 \
libpangocairo-1.0-0 \
libstdc++6 \
libx11-6 \
libx11-xcb1 \
libxcb1 \
libxcomposite1 \
libxcursor1 \
libxdamage1 \
libxext6 \
libxfixes3 \
libxi6 \
libxrandr2 \
libxrender1 \
libxss1 \
libxtst6 \
libxcb-dri3-0 \
libgbm1 \
ca-certificates \
fonts-liberation \
libappindicator1 \
libnss3 \
lsb-release \
xdg-utils \
wget \
libxshmfence1 \
2>/dev/null && rm -rf /var/lib/apt/lists/*;
WORKDIR /root
COPY --from=go /root/bin/app ./app
# Copy Go executable
COPY --from=go-builder /root/bin/app ./app
RUN mkdir -p ./in
RUN mkdir -p ./out
RUN chmod 0777 ./in
RUN chmod 0777 ./out
# Copy mermaid CLI package files
COPY ./mermaidcli/package*.json ./
COPY ./mermaidcli/puppeteer-config.json ./
CMD ["./app", "--mermaid=./node_modules/.bin/mmdc", "--in=./in", "--out=./out", "--puppeteer=./puppeteer-config.json", "--allow-all-origins=true"]
# Install Node dependencies and Chrome in single layer
RUN npm ci --only=production && \
npx puppeteer browsers install chrome-headless-shell && \
npm cache clean --force
# Set environment variables - let Puppeteer find Chrome automatically
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=false
# Create directories for input/output
RUN mkdir -p ./in ./out && \
chmod 0777 ./in ./out
# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:80/health || exit 1
# Expose port
EXPOSE 80
# Run the application directly
CMD ["./app", "--allow-all-origins=true", "--mermaid=./node_modules/.bin/mmdc", "--in=./in", "--out=./out", "--puppeteer=./puppeteer-config.json"]

21
LICENSE
View File

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2020 Tom Wright
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -10,7 +10,7 @@ While this currently serves the diagrams via HTTP, it could easily be manipulate
Run the container:
```
docker run -d --name mermaid-server -p 80:80 tomwright/mermaid-server:latest
docker run -d --name mermaid-server -p 80:80 tomwright/mermaid-server:latest --allow-all-origins=true
```
### Manually as a go command
@ -51,4 +51,4 @@ curl --location --request GET 'http://localhost:80/generate?data=graph%20LR%0A%0
### Caching
All generated diagram input and output will be cached for 1 hour. The cache time is reset whenever a cached diagram is accessed.

View File

@ -1,41 +0,0 @@
// Alternative API call using GET with URL encoding (like the healthcheck)
export const code = async (inputs) => {
const { diagram, format } = inputs;
if (!diagram || !diagram.trim()) {
throw new Error("No Mermaid input provided");
}
// Normalize line endings
const normalizedDiagram = diagram
.replace(/\r\n/g, '\n') // Convert Windows line endings
.replace(/\r/g, '\n') // Convert old Mac line endings
.trim(); // Remove leading/trailing whitespace
// URL encode the diagram (this preserves newlines as %0A)
const encodedDiagram = encodeURIComponent(normalizedDiagram);
// Log for debugging
console.log("Original diagram:");
console.log(JSON.stringify(normalizedDiagram));
console.log("URL encoded diagram:");
console.log(encodedDiagram);
// Use GET with data parameter (like the healthcheck does)
const url = `https://diagrams.starbit.cloud/generate?type=${encodeURIComponent(format)}&data=${encodedDiagram}`;
const resp = await fetch(url, {
method: "GET",
});
if (!resp.ok) {
const txt = await resp.text();
throw new Error(`Mermaid-server error ${resp.status}: ${txt}`);
}
const buffer = Buffer.from(await resp.arrayBuffer());
const mime = format === "png" ? "image/png" : "image/svg+xml";
const file = `data:${mime};base64,${buffer.toString("base64")}`;
return { file };
};

View File

@ -1,2 +0,0 @@
graph TD
A --> B

View File

@ -1,65 +0,0 @@
// Debug script to test different approaches for quadrant charts
export const code = async (inputs) => {
const raw = String(inputs.diagram || "").trim();
if (!raw) throw new Error("No Mermaid input provided");
// Normalize line endings first
let normalizedDiagram = raw
.replace(/\r\n/g, '\n') // Convert Windows line endings
.replace(/\r/g, '\n'); // Convert old Mac line endings
console.log("Original diagram:");
console.log(normalizedDiagram);
// Check if it's already single line
if (!normalizedDiagram.includes('\n')) {
console.log("Already single line, returning as-is");
return { rawDsl: normalizedDiagram };
}
// For quadrant charts, try different encoding methods
const firstWord = normalizedDiagram.split(/\s+/)[0];
if (firstWord === 'quadrantChart') {
console.log("Quadrant chart detected - trying special encoding methods");
// Method 1: Try different newline encoding
const method1 = normalizedDiagram.replace(/\n/g, '\\n');
console.log("Method 1 (\\n encoding):", method1);
// Method 2: Try different marker
const method2 = normalizedDiagram.replace(/\n/g, ' | ');
console.log("Method 2 (pipe separator):", method2);
// Method 3: Try preserving original with different content-type hint
const method3 = `PRESERVE_NEWLINES:${normalizedDiagram}`;
console.log("Method 3 (preserve hint):", method3);
// Let's try method 2 first (pipe separator)
return { rawDsl: method2 };
}
// Convert other types to single line with semicolons
const convertibleTypes = ['graph', 'flowchart', 'sequenceDiagram', 'pie', 'gitGraph'];
if (convertibleTypes.some(type => firstWord.startsWith(type))) {
const lines = normalizedDiagram.split('\n');
const firstLine = lines[0];
const remainingLines = lines.slice(1)
.filter(line => line.trim())
.map(line => line.trim());
const singleLine = firstLine + '; ' + remainingLines.join('; ');
console.log("Converted to single line:");
console.log(singleLine);
return { rawDsl: singleLine };
}
// For other non-convertible types, use NEWLINE encoding
const encodedDiagram = normalizedDiagram.replace(/\n/g, ' NEWLINE ');
console.log("Using NEWLINE encoding:");
console.log(encodedDiagram);
return { rawDsl: encodedDiagram };
};

View File

@ -1,35 +0,0 @@
// Debug script to test what the server actually receives
const diagram = `graph TD
A[Test] --> B[Node]
A --> C[Another]`;
console.log("Original diagram:");
console.log(JSON.stringify(diagram));
console.log("\nDiagram visualization:");
console.log(diagram);
// Test with both your current format and a simple test
const testCases = [
{
name: "Simple test",
diagram: "graph TD\n A --> B"
},
{
name: "Your format",
diagram: diagram
},
{
name: "Minimal",
diagram: "graph TD\nA-->B"
}
];
testCases.forEach((testCase, i) => {
console.log(`\n=== Test Case ${i+1}: ${testCase.name} ===`);
console.log("JSON representation:", JSON.stringify(testCase.diagram));
console.log("Actual content:");
console.log(testCase.diagram);
console.log("Length:", testCase.diagram.length);
console.log("Contains newlines:", testCase.diagram.includes('\n'));
console.log("Newline positions:", [...testCase.diagram].map((char, idx) => char === '\n' ? idx : null).filter(x => x !== null));
});

View File

@ -1,20 +0,0 @@
version: "3.8"
services:
mermaid-server:
build: .
container_name: mermaid-server
ports:
- "7000:80" # Map host port 7000 to container port 80
volumes:
- ./in:/root/in # optional: persist input for caching
- ./out:/root/out # optional: persist output for debugging
environment:
ALLOW_ALL_ORIGINS: "true"
restart: unless-stopped
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:80/generate?data=graph%20TD%0A%20%20%20%20A%5BTest%5D"]
interval: 30s
timeout: 10s
start_period: 5s
retries: 3

View File

@ -1,23 +0,0 @@
// Enhanced mermaid conversion script that preserves newlines for all chart types
export const code = async (inputs) => {
const raw = String(inputs.diagram || "").trim();
if (!raw) throw new Error("No Mermaid input provided");
// Normalize line endings first
const normalizedDiagram = raw
.replace(/\r\n/g, '\n') // Convert Windows line endings
.replace(/\r/g, '\n'); // Convert old Mac line endings
// Base64 encode to preserve exact content including newlines
const base64Encoded = Buffer.from(normalizedDiagram, 'utf8').toString('base64');
// Create a wrapper that tells the server this is base64 encoded
const wrappedDiagram = `%%{init: {"base64": true}}%%\n${base64Encoded}`;
console.log("Original diagram length:", normalizedDiagram.length);
console.log("Original has newlines:", normalizedDiagram.includes('\n'));
console.log("Base64 encoded length:", base64Encoded.length);
console.log("Wrapped diagram:", wrappedDiagram);
return { rawDsl: wrappedDiagram };
};

View File

@ -1,47 +0,0 @@
// Final fixed API call - handles URL encoding edge cases properly
export const code = async (inputs) => {
const { diagram, format } = inputs;
if (!diagram || !diagram.trim()) {
throw new Error("No Mermaid input provided");
}
// Normalize line endings
const normalizedDiagram = diagram
.replace(/\r\n/g, '\n') // Convert Windows line endings
.replace(/\r/g, '\n') // Convert old Mac line endings
.trim(); // Remove leading/trailing whitespace
// Use URLSearchParams for proper encoding of complex content
const params = new URLSearchParams();
params.set('type', format);
params.set('data', normalizedDiagram);
// Log for debugging
console.log("Original diagram:");
console.log(JSON.stringify(normalizedDiagram));
console.log("URL params:");
console.log(params.toString());
// Build URL manually to avoid double encoding issues
const url = `https://diagrams.starbit.cloud/generate?${params.toString()}`;
const resp = await fetch(url, {
method: "GET",
headers: {
'Accept': 'image/svg+xml, image/png, */*',
'User-Agent': 'Mermaid-Client/1.0'
}
});
if (!resp.ok) {
const txt = await resp.text();
throw new Error(`Mermaid-server error ${resp.status}: ${txt}`);
}
const buffer = Buffer.from(await resp.arrayBuffer());
const mime = format === "png" ? "image/png" : "image/svg+xml";
const file = `data:${mime};base64,${buffer.toString("base64")}`;
return { file };
};

View File

@ -1,39 +0,0 @@
// Fixed API call script for your workflow
export const code = async (inputs) => {
const { diagram, format } = inputs;
// diagram is now your exact multiline DSL (including any %%init%% lines)
if (!diagram || !diagram.trim()) {
throw new Error("No Mermaid input provided");
}
// Ensure proper newlines are preserved and normalize line endings
const normalizedDiagram = diagram
.replace(/\r\n/g, '\n') // Convert Windows line endings
.replace(/\r/g, '\n') // Convert old Mac line endings
.trim(); // Remove leading/trailing whitespace
// Log for debugging
console.log("Sending diagram:");
console.log(JSON.stringify(normalizedDiagram));
const url = `https://diagrams.starbit.cloud/generate?type=${encodeURIComponent(format)}`;
const resp = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "text/plain; charset=utf-8" // Explicit charset
},
body: normalizedDiagram, // <-- send the normalized, multi-line DSL
});
if (!resp.ok) {
const txt = await resp.text();
throw new Error(`Mermaid-server error ${resp.status}: ${txt}`);
}
const buffer = Buffer.from(await resp.arrayBuffer());
const mime = format === "png" ? "image/png" : "image/svg+xml";
const file = `data:${mime};base64,${buffer.toString("base64")}`;
return { file };
};

2
go.mod
View File

@ -1,6 +1,6 @@
module github.com/tomwright/mermaid-server
go 1.21
go 1.15
require (
github.com/tomwright/grace v0.1.2

View File

@ -4,7 +4,6 @@ import (
"crypto/md5"
"encoding/base64"
"encoding/hex"
"fmt"
"strings"
"sync"
"time"
@ -12,31 +11,8 @@ import (
// NewDiagram returns a new diagram.
func NewDiagram(description []byte, imgType string) *Diagram {
// Debug: Log what we received
fmt.Printf("DEBUG: Received %d bytes\n", len(description))
fmt.Printf("DEBUG: Raw bytes: %q\n", string(description))
fmt.Printf("DEBUG: Contains newlines: %t\n", strings.Contains(string(description), "\n"))
trimmed := strings.TrimSpace(string(description))
fmt.Printf("DEBUG: After TrimSpace: %q\n", trimmed)
fmt.Printf("DEBUG: Still contains newlines: %t\n", strings.Contains(trimmed, "\n"))
// Decode NEWLINE markers back to actual newlines for complex diagrams
if strings.Contains(trimmed, " NEWLINE ") {
trimmed = strings.ReplaceAll(trimmed, " NEWLINE ", "\n")
fmt.Printf("DEBUG: After NEWLINE decoding: %q\n", trimmed)
fmt.Printf("DEBUG: Now contains newlines: %t\n", strings.Contains(trimmed, "\n"))
}
// Decode pipe separators back to newlines for quadrant charts
if strings.Contains(trimmed, " | ") {
trimmed = strings.ReplaceAll(trimmed, " | ", "\n")
fmt.Printf("DEBUG: After pipe decoding: %q\n", trimmed)
fmt.Printf("DEBUG: Now contains newlines: %t\n", strings.Contains(trimmed, "\n"))
}
return &Diagram{
description: []byte(trimmed),
description: []byte(strings.TrimSpace(string(description))),
lastTouched: time.Now(),
mu: &sync.RWMutex{},
imgType: imgType,

File diff suppressed because it is too large Load Diff

View File

@ -9,6 +9,6 @@
"author": "",
"license": "ISC",
"dependencies": {
"@mermaid-js/mermaid-cli": "^11.4.2"
"@mermaid-js/mermaid-cli": "^10.0.0"
}
}

View File

@ -1,69 +0,0 @@
# Quadrant Chart Examples (Fixed)
These examples should work correctly with the updated conversion script that treats quadrant charts as convertible types:
## 1. Simple Business Priority Matrix
```
quadrantChart
title Business Priorities
x-axis Low Effort --> High Effort
y-axis Low Impact --> High Impact
quadrant-1 Do First
quadrant-2 Schedule
quadrant-3 Delegate
quadrant-4 Eliminate
Task A: [0.3, 0.9]
Task B: [0.7, 0.7]
Task C: [0.2, 0.3]
Task D: [0.8, 0.2]
```
## 2. Product Analysis
```
quadrantChart
title Product Analysis
x-axis Low Cost --> High Cost
y-axis Low Value --> High Value
quadrant-1 Quick Wins
quadrant-2 Strategic
quadrant-3 Fill-ins
quadrant-4 Questionable
Product A: [0.2, 0.8]
Product B: [0.8, 0.9]
Product C: [0.3, 0.2]
Product D: [0.7, 0.3]
```
## 3. Technology Assessment
```
quadrantChart
title Technology Stack
x-axis Low Complexity --> High Complexity
y-axis Low ROI --> High ROI
quadrant-1 Adopt
quadrant-2 Trial
quadrant-3 Assess
quadrant-4 Hold
React: [0.3, 0.8]
Vue: [0.2, 0.7]
Angular: [0.8, 0.6]
jQuery: [0.1, 0.2]
```
## How This Will Convert:
**Input (multiline):**
```
quadrantChart
title Business Priorities
x-axis Low Effort --> High Effort
y-axis Low Impact --> High Impact
quadrant-1 Do First
```
**Output (single line with semicolons):**
```
quadrantChart; title Business Priorities; x-axis Low Effort --> High Effort; y-axis Low Impact --> High Impact; quadrant-1 Do First
```
This should fix the text rendering issue where quadrant labels were getting concatenated!

View File

@ -1,36 +0,0 @@
// Simple POST fix - back to basics with proper headers
export const code = async (inputs) => {
const { diagram, format } = inputs;
if (!diagram || !diagram.trim()) {
throw new Error("No Mermaid input provided");
}
// Ensure proper line endings (just normalize, don't over-process)
const cleanDiagram = diagram.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
console.log("Sending diagram (length: " + cleanDiagram.length + "):");
console.log(JSON.stringify(cleanDiagram));
const url = `https://diagrams.starbit.cloud/generate?type=${format}`;
const resp = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "text/plain",
"Content-Length": cleanDiagram.length.toString()
},
body: cleanDiagram
});
if (!resp.ok) {
const txt = await resp.text();
throw new Error(`Mermaid-server error ${resp.status}: ${txt}`);
}
const buffer = Buffer.from(await resp.arrayBuffer());
const mime = format === "png" ? "image/png" : "image/svg+xml";
const file = `data:${mime};base64,${buffer.toString("base64")}`;
return { file };
};

View File

@ -1,10 +0,0 @@
graph TD
A[Website Analytics] --> B[Traffic: 1.2M visitors]
A --> C[Revenue: $450K]
A --> D[Growth: +25%]
B --> E[Desktop: 60%]
B --> F[Mobile: 40%]
C --> G[Q1: $95K]
C --> H[Q2: $115K]
C --> I[Q3: $125K]
C --> J[Q4: $115K]

View File

@ -1,50 +0,0 @@
# Single Line Mermaid Examples
## Basic Flowchart (Single Line)
```
graph TD; A[Analytics]-->B[Traffic]; A-->C[Revenue]; B-->D[Desktop]; B-->E[Mobile]
```
## Simple Analytics Dashboard
```
graph LR; A[Website]-->B[Users: 1.2M]; A-->C[Revenue: $450K]; A-->D[Growth: +25%]
```
## Process Flow
```
graph TD; Start[Start]-->Process[Process Data]-->Decision{Valid?}-->|Yes|End[Complete]; Decision-->|No|Error[Error]
```
## Network Diagram
```
graph LR; Client[Client]-->LB[Load Balancer]-->Server1[Server 1]; LB-->Server2[Server 2]; Server1-->DB[(Database)]; Server2-->DB
```
## Sequence Diagram (Single Line)
```
sequenceDiagram; participant A as User; participant B as System; A->>B: Request; B-->>A: Response
```
## Pie Chart (Single Line)
```
pie title Traffic Sources; "Direct": 40; "Search": 35; "Social": 15; "Referral": 10
```
## Git Flow
```
gitGraph; commit; commit; branch develop; commit; commit; checkout main; merge develop
```
## Simple Class Diagram
```
classDiagram; class User { +name: string +email: string +login() }; class Admin { +permissions: array +manage() }; User <|-- Admin
```
## State Diagram
```
stateDiagram-v2; [*]-->Idle; Idle-->Processing: start; Processing-->Complete: finish; Complete-->[*]
```
## Journey Map
```
journey; title User Shopping Journey; section Discovery; Search: 5: User; Compare: 3: User; section Purchase; Add to Cart: 4: User; Checkout: 2: User

View File

@ -1,52 +0,0 @@
// Smart mermaid conversion script that converts multiline to single-line format
export const code = async (inputs) => {
const raw = String(inputs.diagram || "").trim();
if (!raw) throw new Error("No Mermaid input provided");
// Normalize line endings first
let normalizedDiagram = raw
.replace(/\r\n/g, '\n') // Convert Windows line endings
.replace(/\r/g, '\n'); // Convert old Mac line endings
console.log("Original diagram:");
console.log(normalizedDiagram);
// Check if it's already single line
if (!normalizedDiagram.includes('\n')) {
console.log("Already single line, returning as-is");
return { rawDsl: normalizedDiagram };
}
// Convert multiline to single line with semicolons
// This works for: graph, flowchart, sequenceDiagram, pie, gitGraph
const convertibleTypes = ['graph', 'flowchart', 'sequenceDiagram', 'pie', 'gitGraph'];
const firstWord = normalizedDiagram.split(/\s+/)[0];
if (convertibleTypes.some(type => firstWord.startsWith(type))) {
// Convert newlines to semicolons, preserving the first line structure
const lines = normalizedDiagram.split('\n');
const firstLine = lines[0];
const remainingLines = lines.slice(1)
.filter(line => line.trim()) // Remove empty lines
.map(line => line.trim()); // Remove indentation
const singleLine = firstLine + '; ' + remainingLines.join('; ');
console.log("Converted to single line:");
console.log(singleLine);
return { rawDsl: singleLine };
}
// For non-convertible types (journey, stateDiagram, classDiagram),
// try replacing newlines with specific delimiters that might work
console.log("Non-convertible type detected, using special encoding");
// Try using a special marker that we can detect and replace on server side
const encodedDiagram = normalizedDiagram.replace(/\n/g, ' NEWLINE ');
console.log("Encoded diagram:");
console.log(encodedDiagram);
return { rawDsl: encodedDiagram };
};

View File

@ -1,10 +0,0 @@
%%{init: {"theme": "base", "themeVariables": {"primaryColor": "#ff6b6b", "primaryTextColor": "#fff", "primaryBorderColor": "#ff4757", "lineColor": "#5f27cd", "secondaryColor": "#00d2d3", "tertiaryColor": "#ff9ff3"}}}%%
xychart-beta
title "Monthly Website Performance Metrics - 2024"
x-axis [Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec]
y-axis "Metrics Count" 0 --> 120000
bar "Unique Visitors" [45000, 52000, 48000, 67000, 72000, 85000, 91000, 88000, 95000, 102000, 108000, 115000]
bar "Page Views" [89000, 104000, 96000, 134000, 144000, 170000, 182000, 176000, 190000, 204000, 216000, 230000]
bar "Sessions" [38000, 44000, 41000, 58000, 62000, 73000, 78000, 75000, 82000, 88000, 93000, 99000]
bar "Bounce Rate %" [45, 42, 48, 38, 35, 32, 30, 33, 29, 27, 25, 23]

View File

@ -1,47 +0,0 @@
// Test different mermaid syntaxes to see which ones work
const testDiagrams = [
{
name: "Minimal flowchart",
diagram: "flowchart TD\nA-->B"
},
{
name: "Graph syntax",
diagram: "graph TD\nA-->B"
},
{
name: "Sequence diagram",
diagram: "sequenceDiagram\nAlice->>Bob: Hello"
},
{
name: "Pie chart",
diagram: 'pie title NETFLIX\n"Time spent looking for movie" : 90\n"Time spent watching it" : 10'
},
{
name: "Single line flowchart",
diagram: "graph LR; A-->B-->C"
},
{
name: "Semicolon separated",
diagram: "graph TD; A[Start]-->B[End]"
}
];
testDiagrams.forEach((test, i) => {
console.log(`\n=== Test ${i+1}: ${test.name} ===`);
console.log("Raw:", JSON.stringify(test.diagram));
console.log("Display:");
console.log(test.diagram);
console.log("Has newlines:", test.diagram.includes('\n'));
});
// Test if semicolons can replace newlines
console.log("\n=== Semicolon replacement test ===");
const original = `graph TD
A[Analytics] --> B[Traffic]
A --> C[Revenue]`;
const semicolonVersion = original.replace(/\n\s*/g, '; ');
console.log("Original:", JSON.stringify(original));
console.log("Semicolon version:", JSON.stringify(semicolonVersion));
console.log("Display semicolon version:");
console.log(semicolonVersion);

View File

@ -1,30 +0,0 @@
// Test URL encoding to see if this preserves newlines properly
const diagram = `graph TD
A[Website Analytics] --> B[Traffic]
A --> C[Revenue]`;
console.log("Original diagram:");
console.log(JSON.stringify(diagram));
console.log("\nURL encoded:");
const encoded = encodeURIComponent(diagram);
console.log(encoded);
console.log("\nDecoded back:");
const decoded = decodeURIComponent(encoded);
console.log(JSON.stringify(decoded));
console.log("\nAre they equal?", diagram === decoded);
// Show what the healthcheck URL looks like
const healthcheckDiagram = "graph TD\n A[Test]";
const healthcheckEncoded = encodeURIComponent(healthcheckDiagram);
console.log("\nHealthcheck diagram encoded:");
console.log(healthcheckEncoded);
// Test the exact healthcheck URL from docker-compose
const dockerHealthcheck = "graph%20TD%0A%20%20%20%20A%5BTest%5D";
console.log("\nDocker healthcheck URL param:");
console.log(dockerHealthcheck);
console.log("Decoded:");
console.log(decodeURIComponent(dockerHealthcheck));

View File

@ -1,35 +0,0 @@
// Test URLSearchParams encoding vs manual encoding
const diagram = `graph TD
A[Website Analytics] --> B[Traffic]
A --> C[Revenue]`;
console.log("=== Manual encodeURIComponent ===");
const manualEncoded = encodeURIComponent(diagram);
console.log("Manual:", manualEncoded);
console.log("\n=== URLSearchParams ===");
const params = new URLSearchParams();
params.set('data', diagram);
params.set('type', 'svg');
console.log("URLSearchParams:", params.toString());
console.log("\n=== Decoded comparison ===");
const manualDecoded = decodeURIComponent(manualEncoded);
const paramsDecoded = decodeURIComponent(params.get('data'));
console.log("Manual decoded:", JSON.stringify(manualDecoded));
console.log("Params decoded:", JSON.stringify(paramsDecoded));
console.log("Are equal:", manualDecoded === paramsDecoded);
// Test with problematic characters
console.log("\n=== Testing problematic chars ===");
const problematic = `graph TD
A[Test] --> B[End]`;
const problemParams = new URLSearchParams();
problemParams.set('data', problematic);
console.log("Problematic encoded:", problemParams.toString());
// Show exact URL that would be generated
console.log("\n=== Full URL ===");
const fullUrl = `https://diagrams.starbit.cloud/generate?${params.toString()}`;
console.log("URL length:", fullUrl.length);
console.log("URL:", fullUrl);

View File

@ -1,42 +0,0 @@
// Test script that mimics your workflow exactly
const diagram = `graph TD
A[Website Analytics] --> B[Traffic]
A --> C[Revenue]
B --> D[Desktop]
B --> E[Mobile]`;
console.log("Raw diagram string:");
console.log(JSON.stringify(diagram));
console.log("\nDiagram content:");
console.log(diagram);
console.log("\nLength:", diagram.length);
// Test the conversion step
const convertMermaidBlock = (inputs) => {
const raw = String(inputs.diagram || "").trim();
if (!raw) throw new Error("No Mermaid input provided");
return { rawDsl: raw };
};
// Test the API call step
const makeApiCall = async (inputs) => {
const { diagram, format } = inputs;
if (!diagram || !diagram.trim()) {
throw new Error("No Mermaid input provided");
}
console.log("Sending to API:");
console.log("URL: https://diagrams.starbit.cloud/generate?type=" + encodeURIComponent(format));
console.log("Content-Type: text/plain");
console.log("Body:", JSON.stringify(diagram));
return { success: true };
};
// Run the test
const result1 = convertMermaidBlock({ diagram });
console.log("\nStep 1 result:", result1);
const result2 = makeApiCall({ diagram: result1.rawDsl, format: "svg" });
console.log("\nStep 2 result:", result2);

View File

@ -1,52 +0,0 @@
// Updated smart mermaid conversion script with quadrantChart fix
export const code = async (inputs) => {
const raw = String(inputs.diagram || "").trim();
if (!raw) throw new Error("No Mermaid input provided");
// Normalize line endings first
let normalizedDiagram = raw
.replace(/\r\n/g, '\n') // Convert Windows line endings
.replace(/\r/g, '\n'); // Convert old Mac line endings
console.log("Original diagram:");
console.log(normalizedDiagram);
// Check if it's already single line
if (!normalizedDiagram.includes('\n')) {
console.log("Already single line, returning as-is");
return { rawDsl: normalizedDiagram };
}
// Convert multiline to single line with semicolons
// Added quadrantChart to convertible types to fix the text rendering issue
const convertibleTypes = ['graph', 'flowchart', 'sequenceDiagram', 'pie', 'gitGraph', 'quadrantChart'];
const firstWord = normalizedDiagram.split(/\s+/)[0];
if (convertibleTypes.some(type => firstWord.startsWith(type))) {
// Convert newlines to semicolons, preserving the first line structure
const lines = normalizedDiagram.split('\n');
const firstLine = lines[0];
const remainingLines = lines.slice(1)
.filter(line => line.trim()) // Remove empty lines
.map(line => line.trim()); // Remove indentation
const singleLine = firstLine + '; ' + remainingLines.join('; ');
console.log("Converted to single line:");
console.log(singleLine);
return { rawDsl: singleLine };
}
// For non-convertible types (journey, stateDiagram, classDiagram),
// try replacing newlines with specific delimiters that might work
console.log("Non-convertible type detected, using special encoding");
// Try using a special marker that we can detect and replace on server side
const encodedDiagram = normalizedDiagram.replace(/\n/g, ' NEWLINE ');
console.log("Encoded diagram:");
console.log(encodedDiagram);
return { rawDsl: encodedDiagram };
};

View File

@ -1,23 +0,0 @@
%%{init: {"theme": "base", "themeVariables": {"primaryColor": "#1f77b4", "primaryTextColor": "#fff", "primaryBorderColor": "#ff7f0e", "lineColor": "#2ca02c"}}}%%
flowchart TD
A["📊 Website Analytics Dashboard<br/>2024 Performance"] --> B["👥 Traffic Metrics"]
A --> C["📈 Growth Analysis"]
A --> D["🎯 Conversion Data"]
B --> E["Unique Visitors: 1.2M<br/>↗️ +25% from 2023"]
B --> F["Page Views: 2.8M<br/>↗️ +32% from 2023"]
B --> G["Sessions: 950K<br/>↗️ +18% from 2023"]
C --> H["Q1: 285K visitors<br/>Growth: +15%"]
C --> I["Q2: 312K visitors<br/>Growth: +22%"]
C --> J["Q3: 335K visitors<br/>Growth: +28%"]
C --> K["Q4: 268K visitors<br/>Growth: +35%"]
D --> L["Conversion Rate: 3.2%<br/>↗️ +0.8% improvement"]
D --> M["Revenue: $450K<br/>↗️ +42% increase"]
D --> N["AOV: $125<br/>↗️ +12% increase"]
style A fill:#e1f5fe,stroke:#01579b,stroke-width:3px
style B fill:#f3e5f5,stroke:#4a148c,stroke-width:2px
style C fill:#e8f5e8,stroke:#1b5e20,stroke-width:2px
style D fill:#fff3e0,stroke:#e65100,stroke-width:2px

View File

@ -1,8 +0,0 @@
%%{init: {"theme": "base", "themeVariables": {"primaryColor": "#ff6b6b", "primaryTextColor": "#fff", "primaryBorderColor": "#ff4757"}}}%%
gitGraph
commit id: "Jan: 45K visitors"
commit id: "Feb: 52K visitors"
commit id: "Mar: 48K visitors"
commit id: "Apr: 67K visitors"
commit id: "May: 72K visitors"
commit id: "Jun: 85K visitors"

View File

@ -1,66 +0,0 @@
# ✅ Working Single Line Mermaid Examples
These are **confirmed working** single-line mermaid diagrams that bypass the newline issue:
## 📊 Analytics Dashboard
```
graph LR; A[Website]-->B[Users: 1.2M]; A-->C[Revenue: $450K]; A-->D[Growth: +25%]
```
## 🔄 Basic Flowchart
```
graph TD; A[Analytics]-->B[Traffic]; A-->C[Revenue]; B-->D[Desktop]; B-->E[Mobile]
```
## ⚡ Process Flow
```
graph TD; Start[Start]-->Process[Process Data]-->Decision{Valid?}-->|Yes|End[Complete]; Decision-->|No|Error[Error]
```
## 🏗️ Network Architecture
```
graph LR; Client[Client]-->LB[Load Balancer]-->Server1[Server 1]; LB-->Server2[Server 2]; Server1-->DB[(Database)]; Server2-->DB
```
## 💬 API Sequence
```
sequenceDiagram; participant A as User; participant B as System; A->>B: Request; B-->>A: Response
```
## 📈 Traffic Sources (Pie Chart)
```
pie title Traffic Sources; "Direct": 40; "Search": 35; "Social": 15; "Referral": 10
```
## 🔀 Git Flow
```
gitGraph; commit; commit; branch develop; commit; commit; checkout main; merge develop
```
## 🎯 **Test These First:**
**Ultra Simple Test:**
```
graph TD; A[Test]-->B[Success]
```
**Basic Analytics:**
```
graph LR; A[Dashboard]-->B[Users]; A-->C[Sales]; A-->D[Traffic]
```
---
## ❌ **Don't Use These (They Require Newlines):**
- Journey diagrams
- State diagrams
- Class diagrams
- Complex entity relationship diagrams
---
## 💡 **Pro Tips:**
1. **Always use semicolons (`;`)** to separate statements
2. **Keep everything on one line**
3. **Test simple versions first** before adding complexity
4. **Flowcharts and sequence diagrams work best** in single-line format