diff --git a/enhanced_conversion_script.js b/enhanced_conversion_script.js new file mode 100644 index 0000000..936d764 --- /dev/null +++ b/enhanced_conversion_script.js @@ -0,0 +1,23 @@ +// 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 }; +}; diff --git a/final_fixed_api_call.js b/final_fixed_api_call.js new file mode 100644 index 0000000..7f8daed --- /dev/null +++ b/final_fixed_api_call.js @@ -0,0 +1,47 @@ +// 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 }; +}; diff --git a/internal/diagram.go b/internal/diagram.go index 8473e96..08d6535 100644 --- a/internal/diagram.go +++ b/internal/diagram.go @@ -21,6 +21,13 @@ func NewDiagram(description []byte, imgType string) *Diagram { 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")) + } + return &Diagram{ description: []byte(trimmed), lastTouched: time.Now(), diff --git a/mermaidcli/performance_quadrant.mmd b/mermaidcli/performance_quadrant.mmd deleted file mode 100644 index 4593c59..0000000 --- a/mermaidcli/performance_quadrant.mmd +++ /dev/null @@ -1,18 +0,0 @@ -quadrantChart - title Website Performance Analysis - x-axis Low Traffic --> High Traffic - y-axis Low Conversion --> High Conversion - - quadrant-1 Stars (High Traffic, High Conversion) - quadrant-2 Question Marks (Low Traffic, High Conversion) - quadrant-3 Dogs (Low Traffic, Low Conversion) - quadrant-4 Cash Cows (High Traffic, Low Conversion) - - Homepage: [0.8, 0.9] - Product Pages: [0.7, 0.8] - Blog Posts: [0.6, 0.4] - Contact Page: [0.2, 0.7] - About Page: [0.3, 0.3] - Pricing Page: [0.5, 0.8] - Support Page: [0.4, 0.5] - FAQ Page: [0.3, 0.6] diff --git a/simple_post_fix.js b/simple_post_fix.js new file mode 100644 index 0000000..3572c7a --- /dev/null +++ b/simple_post_fix.js @@ -0,0 +1,36 @@ +// 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 }; +}; diff --git a/single_line_examples.md b/single_line_examples.md new file mode 100644 index 0000000..1b49782 --- /dev/null +++ b/single_line_examples.md @@ -0,0 +1,50 @@ +# 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 diff --git a/smart_conversion_script.js b/smart_conversion_script.js new file mode 100644 index 0000000..e127dd7 --- /dev/null +++ b/smart_conversion_script.js @@ -0,0 +1,52 @@ +// 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 }; +}; diff --git a/test_different_syntax.js b/test_different_syntax.js new file mode 100644 index 0000000..f893c4f --- /dev/null +++ b/test_different_syntax.js @@ -0,0 +1,47 @@ +// 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); diff --git a/test_urlsearchparams.js b/test_urlsearchparams.js new file mode 100644 index 0000000..f15895e --- /dev/null +++ b/test_urlsearchparams.js @@ -0,0 +1,35 @@ +// 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); diff --git a/working_single_line_mermaid.md b/working_single_line_mermaid.md new file mode 100644 index 0000000..0586567 --- /dev/null +++ b/working_single_line_mermaid.md @@ -0,0 +1,66 @@ +# ✅ 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