| 
                        123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243 | 
                        - export function cleanUpSvgCode(svgCode: string): string {
 -   return svgCode.replaceAll('<br>', '<br/>')
 - }
 - 
 - /**
 -  * Preprocesses mermaid code to fix common syntax issues
 -  */
 - export function preprocessMermaidCode(code: string): string {
 -   if (!code || typeof code !== 'string')
 -     return ''
 - 
 -   // First check if this is a gantt chart
 -   if (code.trim().startsWith('gantt')) {
 -     // For gantt charts, we need to ensure each task is on its own line
 -     // Split the code into lines and process each line separately
 -     const lines = code.split('\n').map(line => line.trim())
 -     return lines.join('\n')
 -   }
 - 
 -   return code
 -     // Replace English colons with Chinese colons in section nodes to avoid parsing issues
 -     .replace(/section\s+([^:]+):/g, (match, sectionName) => `section ${sectionName}:`)
 -     // Fix common syntax issues
 -     .replace(/fifopacket/g, 'rect')
 -     // Ensure graph has direction
 -     .replace(/^graph\s+((?:TB|BT|RL|LR)*)/, (match, direction) => {
 -       return direction ? match : 'graph TD'
 -     })
 -     // Clean up empty lines and extra spaces
 -     .trim()
 - }
 - 
 - /**
 -  * Prepares mermaid code based on selected style
 -  */
 - export function prepareMermaidCode(code: string, style: 'classic' | 'handDrawn'): string {
 -   let finalCode = preprocessMermaidCode(code)
 - 
 -   // Special handling for gantt charts and mindmaps
 -   if (finalCode.trim().startsWith('gantt') || finalCode.trim().startsWith('mindmap')) {
 -     // For gantt charts and mindmaps, preserve the structure exactly as is
 -     return finalCode
 -   }
 - 
 -   if (style === 'handDrawn') {
 -     finalCode = finalCode
 -       // Remove style definitions that interfere with hand-drawn style
 -       .replace(/style\s+[^\n]+/g, '')
 -       .replace(/linkStyle\s+[^\n]+/g, '')
 -       .replace(/^flowchart/, 'graph')
 -       // Remove any styles that might interfere with hand-drawn style
 -       .replace(/class="[^"]*"/g, '')
 -       .replace(/fill="[^"]*"/g, '')
 -       .replace(/stroke="[^"]*"/g, '')
 - 
 -     // Ensure hand-drawn style charts always start with graph
 -     if (!finalCode.startsWith('graph') && !finalCode.startsWith('flowchart'))
 -       finalCode = `graph TD\n${finalCode}`
 -   }
 - 
 -   return finalCode
 - }
 - 
 - /**
 -  * Converts SVG to base64 string for image rendering
 -  */
 - export function svgToBase64(svgGraph: string): Promise<string> {
 -   if (!svgGraph)
 -     return Promise.resolve('')
 - 
 -   try {
 -     // Ensure SVG has correct XML declaration
 -     if (!svgGraph.includes('<?xml'))
 -       svgGraph = `<?xml version="1.0" encoding="UTF-8"?>${svgGraph}`
 - 
 -     const blob = new Blob([new TextEncoder().encode(svgGraph)], { type: 'image/svg+xml;charset=utf-8' })
 -     return new Promise((resolve, reject) => {
 -       const reader = new FileReader()
 -       reader.onloadend = () => resolve(reader.result as string)
 -       reader.onerror = reject
 -       reader.readAsDataURL(blob)
 -     })
 -   }
 -   catch (error) {
 -     console.error('Error converting SVG to base64:', error)
 -     return Promise.resolve('')
 -   }
 - }
 - 
 - /**
 -  * Processes SVG for theme styling
 -  */
 - export function processSvgForTheme(
 -   svg: string,
 -   isDark: boolean,
 -   isHandDrawn: boolean,
 -   themes: {
 -     light: any
 -     dark: any
 -   },
 - ): string {
 -   let processedSvg = svg
 - 
 -   if (isDark) {
 -     processedSvg = processedSvg
 -       .replace(/style="fill: ?#000000"/g, 'style="fill: #e2e8f0"')
 -       .replace(/style="stroke: ?#000000"/g, 'style="stroke: #94a3b8"')
 -       .replace(/<rect [^>]*fill="#ffffff"/g, '<rect $& fill="#1e293b"')
 - 
 -     if (isHandDrawn) {
 -       processedSvg = processedSvg
 -         .replace(/fill="#[a-fA-F0-9]{6}"/g, `fill="${themes.dark.nodeColors[0].bg}"`)
 -         .replace(/stroke="#[a-fA-F0-9]{6}"/g, `stroke="${themes.dark.connectionColor}"`)
 -         .replace(/stroke-width="1"/g, 'stroke-width="1.5"')
 -     }
 -     else {
 -       let i = 0
 -       themes.dark.nodeColors.forEach(() => {
 -         const regex = /fill="#[a-fA-F0-9]{6}"[^>]*class="node-[^"]*"/g
 -         processedSvg = processedSvg.replace(regex, (match: string) => {
 -           const colorIndex = i % themes.dark.nodeColors.length
 -           i++
 -           return match.replace(/fill="#[a-fA-F0-9]{6}"/, `fill="${themes.dark.nodeColors[colorIndex].bg}"`)
 -         })
 -       })
 - 
 -       processedSvg = processedSvg
 -         .replace(/<path [^>]*stroke="#[a-fA-F0-9]{6}"/g,
 -           `<path stroke="${themes.dark.connectionColor}" stroke-width="1.5"`)
 -         .replace(/<(line|polyline) [^>]*stroke="#[a-fA-F0-9]{6}"/g,
 -           `<$1 stroke="${themes.dark.connectionColor}" stroke-width="1.5"`)
 -     }
 -   }
 -   else {
 -     if (isHandDrawn) {
 -       processedSvg = processedSvg
 -         .replace(/fill="#[a-fA-F0-9]{6}"/g, `fill="${themes.light.nodeColors[0].bg}"`)
 -         .replace(/stroke="#[a-fA-F0-9]{6}"/g, `stroke="${themes.light.connectionColor}"`)
 -         .replace(/stroke-width="1"/g, 'stroke-width="1.5"')
 -     }
 -     else {
 -       themes.light.nodeColors.forEach(() => {
 -         const regex = /fill="#[a-fA-F0-9]{6}"[^>]*class="node-[^"]*"/g
 -         let i = 0
 -         processedSvg = processedSvg.replace(regex, (match: string) => {
 -           const colorIndex = i % themes.light.nodeColors.length
 -           i++
 -           return match.replace(/fill="#[a-fA-F0-9]{6}"/, `fill="${themes.light.nodeColors[colorIndex].bg}"`)
 -         })
 -       })
 - 
 -       processedSvg = processedSvg
 -         .replace(/<path [^>]*stroke="#[a-fA-F0-9]{6}"/g,
 -           `<path stroke="${themes.light.connectionColor}"`)
 -         .replace(/<(line|polyline) [^>]*stroke="#[a-fA-F0-9]{6}"/g,
 -           `<$1 stroke="${themes.light.connectionColor}"`)
 -     }
 -   }
 - 
 -   return processedSvg
 - }
 - 
 - /**
 -  * Checks if mermaid code is complete and valid
 -  */
 - export function isMermaidCodeComplete(code: string): boolean {
 -   if (!code || code.trim().length === 0)
 -     return false
 - 
 -   try {
 -     const trimmedCode = code.trim()
 - 
 -     // Special handling for gantt charts
 -     if (trimmedCode.startsWith('gantt')) {
 -       // For gantt charts, check if it has at least a title and one task
 -       const lines = trimmedCode.split('\n').filter(line => line.trim().length > 0)
 -       return lines.length >= 3
 -     }
 - 
 -     // Special handling for mindmaps
 -     if (trimmedCode.startsWith('mindmap')) {
 -       // For mindmaps, check if it has at least a root node
 -       const lines = trimmedCode.split('\n').filter(line => line.trim().length > 0)
 -       return lines.length >= 2
 -     }
 - 
 -     // Check for basic syntax structure
 -     const hasValidStart = /^(graph|flowchart|sequenceDiagram|classDiagram|classDef|class|stateDiagram|gantt|pie|er|journey|requirementDiagram|mindmap)/.test(trimmedCode)
 - 
 -     // Check for balanced brackets and parentheses
 -     const isBalanced = (() => {
 -       const stack = []
 -       const pairs = { '{': '}', '[': ']', '(': ')' }
 - 
 -       for (const char of trimmedCode) {
 -         if (char in pairs) {
 -           stack.push(char)
 -         }
 -         else if (Object.values(pairs).includes(char)) {
 -           const last = stack.pop()
 -           if (pairs[last as keyof typeof pairs] !== char)
 -             return false
 -         }
 -       }
 - 
 -       return stack.length === 0
 -     })()
 - 
 -     // Check for common syntax errors
 -     const hasNoSyntaxErrors = !trimmedCode.includes('undefined')
 -                            && !trimmedCode.includes('[object Object]')
 -                            && trimmedCode.split('\n').every(line =>
 -                              !(line.includes('-->') && !line.match(/\S+\s*-->\s*\S+/)))
 - 
 -     return hasValidStart && isBalanced && hasNoSyntaxErrors
 -   }
 -   catch (error) {
 -     console.debug('Mermaid code validation error:', error)
 -     return false
 -   }
 - }
 - 
 - /**
 -  * Helper to wait for DOM element with retry mechanism
 -  */
 - export function waitForDOMElement(callback: () => Promise<any>, maxAttempts = 3, delay = 100): Promise<any> {
 -   return new Promise((resolve, reject) => {
 -     let attempts = 0
 -     const tryRender = async () => {
 -       try {
 -         resolve(await callback())
 -       }
 -       catch (error) {
 -         attempts++
 -         if (attempts < maxAttempts)
 -           setTimeout(tryRender, delay)
 -         else
 -           reject(error)
 -       }
 -     }
 -     tryRender()
 -   })
 - }
 
 
  |