Compare commits
1 Commits
master
...
dependabot
| Author | SHA1 | Date |
|---|---|---|
|
|
ba54fd4bee |
150
Dockerfile
150
Dockerfile
|
|
@ -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.20.1-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
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:
|
||||
```
|
||||
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.
|
||||
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
go 1.21
|
||||
go 1.15
|
||||
|
||||
require (
|
||||
github.com/tomwright/grace v0.1.2
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -9,6 +9,6 @@
|
|||
"author": "",
|
||||
"license": "ISC",
|
||||
"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