Compare commits
1 Commits
master
...
dependabot
| Author | SHA1 | Date |
|---|---|---|
|
|
be79485b32 |
|
|
@ -14,7 +14,7 @@ jobs:
|
||||||
go-version: ${{ matrix.go-version }}
|
go-version: ${{ matrix.go-version }}
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
- uses: actions/cache@v3.0.10
|
- uses: actions/cache@v3.2.6
|
||||||
with:
|
with:
|
||||||
path: ~/go/pkg/mod
|
path: ~/go/pkg/mod
|
||||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||||
|
|
|
||||||
150
Dockerfile
150
Dockerfile
|
|
@ -1,94 +1,78 @@
|
||||||
# Multi-stage build
|
# This stage builds the go executable.
|
||||||
|
FROM golang:1.19.3-buster as go
|
||||||
# Stage 1: Build the Go executable
|
|
||||||
FROM golang:1.21-bookworm as go-builder
|
|
||||||
|
|
||||||
WORKDIR /root
|
WORKDIR /root
|
||||||
COPY go.mod go.sum ./
|
COPY ./ ./
|
||||||
RUN go mod download
|
|
||||||
|
|
||||||
COPY cmd/ ./cmd/
|
RUN go build -o bin/app cmd/app/main.go
|
||||||
COPY internal/ ./internal/
|
|
||||||
|
|
||||||
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
|
# Final stage that will be pushed.
|
||||||
FROM node:20-bookworm-slim
|
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
|
ENV DEBIAN_FRONTEND=noninteractive
|
||||||
RUN apt-get update && apt-get install -y \
|
RUN apt-get update 2>/dev/null && \
|
||||||
ca-certificates \
|
apt-get install -y --no-install-recommends \
|
||||||
fonts-liberation \
|
ca-certificates \
|
||||||
libappindicator3-1 \
|
gconf-service \
|
||||||
libasound2 \
|
libasound2 \
|
||||||
libatk-bridge2.0-0 \
|
libatk1.0-0 \
|
||||||
libatk1.0-0 \
|
libatk-bridge2.0-0 \
|
||||||
libc6 \
|
libc6 \
|
||||||
libcairo2 \
|
libcairo2 \
|
||||||
libcups2 \
|
libcups2 \
|
||||||
libdbus-1-3 \
|
libdbus-1-3 \
|
||||||
libexpat1 \
|
libexpat1 \
|
||||||
libfontconfig1 \
|
libfontconfig1 \
|
||||||
libgbm1 \
|
libgcc1 \
|
||||||
libgcc1 \
|
libgconf-2-4 \
|
||||||
libglib2.0-0 \
|
libgdk-pixbuf2.0-0 \
|
||||||
libgtk-3-0 \
|
libglib2.0-0 \
|
||||||
libnspr4 \
|
libgtk-3-0 \
|
||||||
libnss3 \
|
libnspr4 \
|
||||||
libpango-1.0-0 \
|
libpango-1.0-0 \
|
||||||
libpangocairo-1.0-0 \
|
libpangocairo-1.0-0 \
|
||||||
libstdc++6 \
|
libstdc++6 \
|
||||||
libx11-6 \
|
libx11-6 \
|
||||||
libx11-xcb1 \
|
libx11-xcb1 \
|
||||||
libxcb1 \
|
libxcb1 \
|
||||||
libxcomposite1 \
|
libxcomposite1 \
|
||||||
libxcursor1 \
|
libxcursor1 \
|
||||||
libxdamage1 \
|
libxdamage1 \
|
||||||
libxext6 \
|
libxext6 \
|
||||||
libxfixes3 \
|
libxfixes3 \
|
||||||
libxi6 \
|
libxi6 \
|
||||||
libxrandr2 \
|
libxrandr2 \
|
||||||
libxrender1 \
|
libxrender1 \
|
||||||
libxss1 \
|
libxss1 \
|
||||||
libxtst6 \
|
libxtst6 \
|
||||||
libxshmfence1 \
|
libxcb-dri3-0 \
|
||||||
libdrm2 \
|
libgbm1 \
|
||||||
libxkbcommon0 \
|
ca-certificates \
|
||||||
libatspi2.0-0 \
|
fonts-liberation \
|
||||||
lsb-release \
|
libappindicator1 \
|
||||||
wget \
|
libnss3 \
|
||||||
xdg-utils \
|
lsb-release \
|
||||||
--no-install-recommends && \
|
xdg-utils \
|
||||||
rm -rf /var/lib/apt/lists/*
|
wget \
|
||||||
|
libxshmfence1 \
|
||||||
|
2>/dev/null && rm -rf /var/lib/apt/lists/*;
|
||||||
|
|
||||||
WORKDIR /root
|
COPY --from=go /root/bin/app ./app
|
||||||
|
|
||||||
# Copy Go executable
|
RUN mkdir -p ./in
|
||||||
COPY --from=go-builder /root/bin/app ./app
|
RUN mkdir -p ./out
|
||||||
|
RUN chmod 0777 ./in
|
||||||
|
RUN chmod 0777 ./out
|
||||||
|
|
||||||
# Copy mermaid CLI package files
|
CMD ["./app", "--mermaid=./node_modules/.bin/mmdc", "--in=./in", "--out=./out", "--puppeteer=./puppeteer-config.json", "--allow-all-origins=true"]
|
||||||
COPY ./mermaidcli/package*.json ./
|
|
||||||
COPY ./mermaidcli/puppeteer-config.json ./
|
|
||||||
|
|
||||||
# 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
21
LICENSE
|
|
@ -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.
|
|
||||||
|
|
@ -10,7 +10,7 @@ While this currently serves the diagrams via HTTP, it could easily be manipulate
|
||||||
|
|
||||||
Run the container:
|
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
|
### Manually as a go command
|
||||||
|
|
@ -51,4 +51,4 @@ curl --location --request GET 'http://localhost:80/generate?data=graph%20LR%0A%0
|
||||||
### Caching
|
### Caching
|
||||||
|
|
||||||
All generated diagram input and output will be cached for 1 hour. The cache time is reset whenever a cached diagram is accessed.
|
All generated diagram input and output will be cached for 1 hour. The cache time is reset whenever a cached diagram is accessed.
|
||||||
|
|
||||||
|
|
@ -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 };
|
|
||||||
};
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
graph TD
|
|
||||||
A --> B
|
|
||||||
|
|
@ -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 };
|
|
||||||
};
|
|
||||||
|
|
@ -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));
|
|
||||||
});
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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 };
|
|
||||||
};
|
|
||||||
|
|
@ -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 };
|
|
||||||
};
|
|
||||||
|
|
@ -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
2
go.mod
|
|
@ -1,6 +1,6 @@
|
||||||
module github.com/tomwright/mermaid-server
|
module github.com/tomwright/mermaid-server
|
||||||
|
|
||||||
go 1.21
|
go 1.15
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/tomwright/grace v0.1.2
|
github.com/tomwright/grace v0.1.2
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -12,31 +11,8 @@ import (
|
||||||
|
|
||||||
// NewDiagram returns a new diagram.
|
// NewDiagram returns a new diagram.
|
||||||
func NewDiagram(description []byte, imgType string) *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{
|
return &Diagram{
|
||||||
description: []byte(trimmed),
|
description: []byte(strings.TrimSpace(string(description))),
|
||||||
lastTouched: time.Now(),
|
lastTouched: time.Now(),
|
||||||
mu: &sync.RWMutex{},
|
mu: &sync.RWMutex{},
|
||||||
imgType: imgType,
|
imgType: imgType,
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -9,6 +9,6 @@
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mermaid-js/mermaid-cli": "^11.4.2"
|
"@mermaid-js/mermaid-cli": "^9.1.7"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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!
|
|
||||||
|
|
@ -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 };
|
|
||||||
};
|
|
||||||
|
|
@ -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]
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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 };
|
|
||||||
};
|
|
||||||
|
|
@ -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]
|
|
||||||
|
|
@ -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);
|
|
||||||
|
|
@ -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));
|
|
||||||
|
|
@ -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);
|
|
||||||
|
|
@ -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);
|
|
||||||
|
|
@ -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 };
|
|
||||||
};
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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"
|
|
||||||
|
|
@ -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
|
|
||||||
Loading…
Reference in New Issue