UNPKG

@makolabs/ripple

Version:

Simple Svelte 5 powered component library ✨

154 lines (153 loc) 4.84 kB
/** * Content detection utilities for AI chat messages */ /** * Detects if content contains Mermaid diagram syntax */ export function detectMermaidDiagrams(content) { const mermaidBlocks = []; // Pattern to match mermaid code blocks // Handles various Mermaid diagram types and whitespace scenarios const mermaidRegex = /```(?:mermaid|graph|flowchart|sequenceDiagram|classDiagram|stateDiagram|stateDiagram-v2|erDiagram|journey|gantt|pie|gitgraph|mindmap)\s*\r?\n([\s\S]*?)\r?\n```/gi; let match; while ((match = mermaidRegex.exec(content)) !== null) { mermaidBlocks.push({ diagram: match[1].trim(), startIndex: match.index, endIndex: match.index + match[0].length }); } return mermaidBlocks; } /** * Detects code blocks in content */ export function detectCodeBlocks(content) { const codeBlocks = []; // Pattern to match code blocks with language specification // Handles: ```language, ```, and various whitespace scenarios const codeRegex = /```(\w+)?\s*\r?\n([\s\S]*?)\r?\n```/gi; let match; while ((match = codeRegex.exec(content)) !== null) { const language = match[1] || 'text'; const code = match[2].trim(); // Skip empty code blocks if (!code) { continue; } // Skip if it's a mermaid diagram (handled separately) if (!isMermaidLanguage(language)) { codeBlocks.push({ language, code, startIndex: match.index, endIndex: match.index + match[0].length }); } } return codeBlocks; } /** * Checks if a language identifier is for Mermaid diagrams */ function isMermaidLanguage(language) { const mermaidLanguages = [ 'mermaid', 'graph', 'flowchart', 'sequenceDiagram', 'classDiagram', 'stateDiagram', 'stateDiagram-v2', 'erDiagram', 'journey', 'gantt', 'pie', 'gitgraph', 'mindmap' ]; return mermaidLanguages.includes(language.toLowerCase()); } /** * Parses content into segments (text, code, mermaid) */ export function parseContentSegments(content) { console.log('parseContentSegments', content); const segments = []; const mermaidBlocks = detectMermaidDiagrams(content); const codeBlocks = detectCodeBlocks(content); // Combine all blocks and sort by position const allBlocks = [ ...mermaidBlocks.map((block) => ({ ...block, type: 'mermaid' })), ...codeBlocks.map((block) => ({ ...block, type: 'code' })) ].sort((a, b) => a.startIndex - b.startIndex); let currentIndex = 0; for (const block of allBlocks) { // Add text segment before this block if (currentIndex < block.startIndex) { const textContent = content.slice(currentIndex, block.startIndex).trim(); if (textContent) { segments.push({ type: 'text', content: textContent, startIndex: currentIndex, endIndex: block.startIndex }); } } // Add the block segment if (block.type === 'mermaid') { segments.push({ type: 'mermaid', content: block.diagram, startIndex: block.startIndex, endIndex: block.endIndex }); } else { const codeBlock = block; segments.push({ type: 'code', content: codeBlock.code, language: codeBlock.language, startIndex: block.startIndex, endIndex: block.endIndex }); } currentIndex = block.endIndex; } // Add remaining text after last block if (currentIndex < content.length) { const textContent = content.slice(currentIndex).trim(); if (textContent) { segments.push({ type: 'text', content: textContent, startIndex: currentIndex, endIndex: content.length }); } } // If no blocks found, return entire content as text if (segments.length === 0) { segments.push({ type: 'text', content: content, startIndex: 0, endIndex: content.length }); } return segments; } /** * Simple check if content contains any Mermaid diagrams */ export function hasMermaidDiagrams(content) { return detectMermaidDiagrams(content).length > 0; } /** * Simple check if content contains any code blocks */ export function hasCodeBlocks(content) { return detectCodeBlocks(content).length > 0; }