diff --git a/packages/mermaid/src/diagrams/flowchart/flowDb.ts b/packages/mermaid/src/diagrams/flowchart/flowDb.ts
index d07ea0a18..fdc187bff 100644
--- a/packages/mermaid/src/diagrams/flowchart/flowDb.ts
+++ b/packages/mermaid/src/diagrams/flowchart/flowDb.ts
@@ -120,6 +120,7 @@ export class FlowDB implements DiagramDB {
// Extract the metadata from the shapeData, the syntax for adding metadata for nodes and edges is the same
// so at this point we don't know if it's a node or an edge, but we can still extract the metadata
let doc;
+ let originalYamlData = '';
if (metadata !== undefined) {
let yamlData;
// detect if shapeData contains a newline character
@@ -128,6 +129,7 @@ export class FlowDB implements DiagramDB {
} else {
yamlData = metadata + '\n';
}
+ originalYamlData = yamlData; // Store original for multiline detection
doc = yaml.load(yamlData, { schema: yaml.JSON_SCHEMA }) as NodeMetaData;
}
@@ -211,15 +213,35 @@ export class FlowDB implements DiagramDB {
if (doc?.label) {
// Convert newlines to
tags for HTML rendering (except for YAML pipe syntax which preserves \n)
let labelText = doc.label;
- if (
- typeof labelText === 'string' &&
- labelText.includes('\n') &&
- !labelText.endsWith('\n')
- ) {
- // This is a quoted multiline string, convert \n to
- labelText = labelText.replace(/\n/g, '
');
+
+ // Check if the original YAML had a quoted multiline string pattern
+ const quotedMultilinePattern = /label:\s*"[^"]*\n[^"]*"/;
+ const isQuotedMultiline = quotedMultilinePattern.test(originalYamlData);
+
+ if (typeof labelText === 'string' && labelText.includes('\n')) {
+ // Check if this is a YAML block scalar (ends with \n) vs quoted multiline string
+ if (labelText.endsWith('\n')) {
+ // YAML block scalar (label: |) - preserve as-is with \n
+ vertex.text = labelText;
+ } else {
+ // Quoted multiline string (label: "text\nmore text") - convert \n to
+ labelText = labelText.replace(/\n/g, '
');
+ vertex.text = labelText;
+ }
+ } else if (isQuotedMultiline && typeof labelText === 'string') {
+ // YAML parsed away the newlines, but original had quoted multiline - add
+ // Find where the line break should be by analyzing the original YAML
+ const match = originalYamlData.match(/label:\s*"([^"]*)\n\s*([^"]*)"/);
+ if (match) {
+ const part1 = match[1].trim();
+ const part2 = match[2].trim();
+ vertex.text = `${part1}
${part2}`;
+ } else {
+ vertex.text = labelText;
+ }
+ } else {
+ vertex.text = labelText;
}
- vertex.text = labelText;
}
if (doc?.icon) {
vertex.icon = doc?.icon;
diff --git a/packages/mermaid/src/diagrams/flowchart/parser/antlr/FlowchartParserCore.ts b/packages/mermaid/src/diagrams/flowchart/parser/antlr/FlowchartParserCore.ts
index 381d6822b..49305eae8 100644
--- a/packages/mermaid/src/diagrams/flowchart/parser/antlr/FlowchartParserCore.ts
+++ b/packages/mermaid/src/diagrams/flowchart/parser/antlr/FlowchartParserCore.ts
@@ -885,16 +885,31 @@ export class FlowchartParserCore {
// Remove the { and } wrapper
if (yamlContent.startsWith('{') && yamlContent.endsWith('}')) {
- yamlContent = yamlContent.substring(1, yamlContent.length - 1).trim();
+ yamlContent = yamlContent.substring(1, yamlContent.length - 1);
}
- // Normalize the YAML content
+ // Normalize YAML indentation while preserving structure
const lines = yamlContent.split('\n');
- const normalizedLines = lines
- .map((line: string) => line.trim())
- .filter((line: string) => line.length > 0);
- return normalizedLines.join('\n');
+ // Find the minimum indentation (excluding empty lines)
+ let minIndent = Infinity;
+ for (const line of lines) {
+ if (line.trim().length > 0) {
+ const indent = line.length - line.trimStart().length;
+ minIndent = Math.min(minIndent, indent);
+ }
+ }
+
+ // Remove the common indentation from all lines
+ if (minIndent !== Infinity && minIndent > 0) {
+ const normalizedLines = lines.map((line) => {
+ if (line.trim().length === 0) return '';
+ return line.substring(minIndent);
+ });
+ return normalizedLines.join('\n').trim();
+ }
+
+ return yamlContent.trim();
}
// Style processing methods