/** * Sanitization utilities for Mermaid diagrams * @module Mermaid/builders/core/sanitize */ /** * Characters that need to be escaped or removed in Mermaid labels */ const UNSAFE_CHARS = /["\n\r\\<>{}|]/g; /** * Mermaid reserved keywords that cannot be used as node IDs */ const RESERVED_WORDS = new Set([ 'end', 'graph', 'subgraph', 'direction', 'click', 'style', 'class', 'classDef', 'linkStyle', 'callback', ]); /** * Sanitize a label for use in Mermaid diagrams * Removes or escapes characters that could break the diagram syntax */ export function sanitizeLabel(label: string): string { return label .replace(UNSAFE_CHARS, '') .replace(/&/g, '&') .replace(/'/g, "'") .trim(); } /** * Convert an ID to a valid Mermaid node ID * - Removes special characters * - Adds optional prefix to ensure uniqueness * - Ensures ID starts with a letter * - Escapes reserved Mermaid keywords */ export function toNodeId(id: string, prefix = ''): string { // Remove special characters and spaces const cleanId = id.replace(/[^a-zA-Z0-9_]/g, '_'); // Ensure starts with letter let safeId = /^[a-zA-Z]/.test(cleanId) ? cleanId : `n${cleanId}`; // Escape reserved words by adding underscore suffix if (RESERVED_WORDS.has(safeId.toLowerCase())) { safeId = `${safeId}_`; } return prefix ? `${prefix}_${safeId}` : safeId; } /** * Escape a string for use in quoted Mermaid labels */ export function escapeQuoted(str: string): string { return str .replace(/\\/g, '\\\\') .replace(/"/g, '\\"') .replace(/\n/g, '
'); } /** * Format a label with optional subtitle using HTML-like syntax */ export function formatLabel(main: string, subtitle?: string): string { const sanitized = sanitizeLabel(main); if (!subtitle) return sanitized; return `${sanitized}
${sanitizeLabel(subtitle)}`; }