mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-12-20 11:17:21 +01:00
Compare commits
4 Commits
renovate/t
...
flowchart-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
383f5b5bec | ||
|
|
efff583bb0 | ||
|
|
d435ac6fe1 | ||
|
|
09c60be450 |
2
.github/workflows/e2e-timings.yml
vendored
2
.github/workflows/e2e-timings.yml
vendored
@@ -58,7 +58,7 @@ jobs:
|
||||
echo "EOF" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Commit and create pull request
|
||||
uses: peter-evans/create-pull-request@84ae59a2cdc2258d6fa0732dd66352dddae2a412
|
||||
uses: peter-evans/create-pull-request@0979079bc20c05bbbb590a56c21c4e2b1d1f1bbe
|
||||
with:
|
||||
add-paths: |
|
||||
cypress/timings.json
|
||||
|
||||
2
.github/workflows/lint.yml
vendored
2
.github/workflows/lint.yml
vendored
@@ -89,7 +89,7 @@ jobs:
|
||||
continue-on-error: ${{ github.event_name == 'push' }}
|
||||
run: pnpm run docs:verify
|
||||
|
||||
- uses: testomatio/check-tests@8d7e741fd2c9e46c8e8a3b27207731b0658e0fbe # stable
|
||||
- uses: testomatio/check-tests@0ea638fcec1820cf2e7b9854fdbdd04128a55bd4 # stable
|
||||
with:
|
||||
framework: cypress
|
||||
tests: './cypress/e2e/**/**.spec.js'
|
||||
|
||||
@@ -1012,6 +1012,7 @@ You have to call mermaid.initialize.`
|
||||
const baseNode = {
|
||||
id: vertex.id,
|
||||
label: vertex.text,
|
||||
labelType: vertex.labelType,
|
||||
labelStyle: '',
|
||||
parentId,
|
||||
padding: config.flowchart?.padding || 8,
|
||||
@@ -1119,6 +1120,7 @@ You have to call mermaid.initialize.`
|
||||
end: rawEdge.end,
|
||||
type: rawEdge.type ?? 'normal',
|
||||
label: rawEdge.text,
|
||||
labelType: rawEdge.labelType,
|
||||
labelpos: 'c',
|
||||
thickness: rawEdge.stroke,
|
||||
minlen: rawEdge.length,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { markdownToLines, markdownToHTML } from './handle-markdown-text.js';
|
||||
import { markdownToLines, markdownToHTML, hasMarkdownSyntax } from './handle-markdown-text.js';
|
||||
import { test, expect } from 'vitest';
|
||||
|
||||
test('markdownToLines - Basic test', () => {
|
||||
@@ -311,3 +311,35 @@ test('markdownToHTML - auto wrapping', () => {
|
||||
)
|
||||
).toMatchInlineSnapshot('"<p>Hello, how do<br/>you do?</p>"');
|
||||
});
|
||||
|
||||
test('hasMarkdownSyntax - detects bold text', () => {
|
||||
expect(hasMarkdownSyntax('This is **bold** text')).toBe(true);
|
||||
expect(hasMarkdownSyntax('**Bold**')).toBe(true);
|
||||
expect(hasMarkdownSyntax('Text with **bold** in middle')).toBe(true);
|
||||
});
|
||||
|
||||
test('hasMarkdownSyntax - detects italic text', () => {
|
||||
expect(hasMarkdownSyntax('This is *italic* text')).toBe(true);
|
||||
expect(hasMarkdownSyntax('*Italic*')).toBe(true);
|
||||
expect(hasMarkdownSyntax('Text with *italic* in middle')).toBe(true);
|
||||
});
|
||||
|
||||
test('hasMarkdownSyntax - detects mixed formatting', () => {
|
||||
expect(hasMarkdownSyntax('*Italic* and **bold**')).toBe(true);
|
||||
expect(hasMarkdownSyntax('The dog in **the** hog')).toBe(true);
|
||||
});
|
||||
|
||||
test('hasMarkdownSyntax - returns false for plain text', () => {
|
||||
expect(hasMarkdownSyntax('This is plain text')).toBe(false);
|
||||
expect(hasMarkdownSyntax('The dog in the hog')).toBe(false);
|
||||
expect(hasMarkdownSyntax('Simple label')).toBe(false);
|
||||
expect(hasMarkdownSyntax('')).toBe(false);
|
||||
});
|
||||
|
||||
test('hasMarkdownSyntax - handles edge cases', () => {
|
||||
expect(hasMarkdownSyntax(null as any)).toBe(false);
|
||||
expect(hasMarkdownSyntax(undefined as any)).toBe(false);
|
||||
expect(hasMarkdownSyntax(' ')).toBe(false);
|
||||
expect(hasMarkdownSyntax('Text with asterisks * but not italic')).toBe(false);
|
||||
expect(hasMarkdownSyntax('Text with ** but not bold')).toBe(false);
|
||||
});
|
||||
|
||||
@@ -70,6 +70,42 @@ export function markdownToLines(markdown: string, config: MermaidConfig = {}): M
|
||||
return lines;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if text contains actual markdown syntax (bold, italic, etc.)
|
||||
* This helps validate that labels marked as 'markdown' actually contain markdown
|
||||
* @param text - text to check
|
||||
* @returns true if text contains markdown syntax, false otherwise
|
||||
*/
|
||||
export function hasMarkdownSyntax(text: string): boolean {
|
||||
if (!text || typeof text !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
const nodes = marked.lexer(text);
|
||||
|
||||
// Check if any node contains markdown formatting
|
||||
function hasMarkdownInNode(node: Token): boolean {
|
||||
if (node.type === 'strong' || node.type === 'em') {
|
||||
return true;
|
||||
}
|
||||
if (node.type === 'paragraph' && node.tokens) {
|
||||
return node.tokens.some(hasMarkdownInNode);
|
||||
}
|
||||
if ('tokens' in node && node.tokens) {
|
||||
return node.tokens.some(hasMarkdownInNode);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return nodes.some(hasMarkdownInNode);
|
||||
} catch (error) {
|
||||
// If parsing fails, assume it's not markdown
|
||||
log.debug('Failed to parse text as markdown:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function markdownToHTML(markdown: string, { markdownAutoWrap }: MermaidConfig = {}) {
|
||||
const nodes = marked.lexer(markdown);
|
||||
|
||||
|
||||
@@ -45,16 +45,29 @@ export const getLabelStyles = (styleArray) => {
|
||||
};
|
||||
|
||||
export const insertEdgeLabel = async (elem, edge) => {
|
||||
let useHtmlLabels = evaluate(getConfig().flowchart.htmlLabels);
|
||||
const config = getConfig();
|
||||
let useHtmlLabels = evaluate(config.flowchart.htmlLabels);
|
||||
|
||||
// Only process as markdown if labelType is explicitly 'markdown'
|
||||
// This ensures only labels properly delimited with ["`...`"] are processed as markdown
|
||||
// This validation is restricted to flowcharts only
|
||||
const isFlowchart = config.flowchart !== undefined;
|
||||
const shouldProcessAsMarkdown = isFlowchart && edge.labelType === 'markdown';
|
||||
|
||||
const { labelStyles } = styles2String(edge);
|
||||
edge.labelStyle = labelStyles;
|
||||
const labelElement = await createText(elem, edge.label, {
|
||||
style: edge.labelStyle,
|
||||
useHtmlLabels,
|
||||
addSvgBackground: true,
|
||||
isNode: false,
|
||||
});
|
||||
|
||||
let labelElement;
|
||||
if (shouldProcessAsMarkdown) {
|
||||
labelElement = await createText(elem, edge.label, {
|
||||
style: edge.labelStyle,
|
||||
useHtmlLabels,
|
||||
addSvgBackground: true,
|
||||
isNode: false,
|
||||
});
|
||||
} else {
|
||||
labelElement = await createLabel(edge.label, edge.labelStyle, undefined, false);
|
||||
}
|
||||
log.info('abc82', edge, edge.labelType);
|
||||
|
||||
// Create outer g, edgeLabel, this will be positioned after graph layout
|
||||
|
||||
@@ -6,6 +6,7 @@ import defaultConfig from '../../../defaultConfig.js';
|
||||
import { evaluate, sanitizeText } from '../../../diagrams/common/common.js';
|
||||
import { decodeEntities, handleUndefinedAttr, parseFontSize } from '../../../utils.js';
|
||||
import type { D3Selection, Point } from '../../../types.js';
|
||||
import createLabel from '../createLabel.js';
|
||||
|
||||
export const labelHelper = async <T extends SVGGraphicsElement>(
|
||||
parent: D3Selection<T>,
|
||||
@@ -40,14 +41,31 @@ export const labelHelper = async <T extends SVGGraphicsElement>(
|
||||
label = typeof node.label === 'string' ? node.label : node.label[0];
|
||||
}
|
||||
|
||||
const text = await createText(labelEl, sanitizeText(decodeEntities(label), getConfig()), {
|
||||
useHtmlLabels,
|
||||
width: node.width || getConfig().flowchart?.wrappingWidth,
|
||||
// @ts-expect-error -- This is currently not used. Should this be `classes` instead?
|
||||
cssClasses: 'markdown-node-label',
|
||||
style: node.labelStyle,
|
||||
addSvgBackground: !!node.icon || !!node.img,
|
||||
});
|
||||
// Only process as markdown if labelType is explicitly 'markdown'
|
||||
// This ensures only labels properly delimited with ["`...`"] are processed as markdown
|
||||
// This validation is restricted to flowcharts only
|
||||
const config = getConfig();
|
||||
const isFlowchart = config.flowchart !== undefined;
|
||||
const shouldProcessAsMarkdown = isFlowchart && node.labelType === 'markdown';
|
||||
let text;
|
||||
if (shouldProcessAsMarkdown) {
|
||||
text = await createText(labelEl, sanitizeText(decodeEntities(label), config), {
|
||||
useHtmlLabels,
|
||||
width: node.width || config.flowchart?.wrappingWidth,
|
||||
// @ts-expect-error -- This is currently not used. Should this be `classes` instead?
|
||||
cssClasses: 'markdown-node-label',
|
||||
style: node.labelStyle,
|
||||
addSvgBackground: !!node.icon || !!node.img,
|
||||
});
|
||||
} else {
|
||||
const labelElement = await createLabel(
|
||||
sanitizeText(decodeEntities(label), config),
|
||||
node.labelStyle,
|
||||
false,
|
||||
true
|
||||
);
|
||||
text = labelEl.node()?.appendChild(labelElement);
|
||||
}
|
||||
// Get the size of the label
|
||||
let bbox = text.getBBox();
|
||||
const halfPadding = (node?.padding ?? 0) / 2;
|
||||
|
||||
Reference in New Issue
Block a user