mermaid
Version:
Markdown-ish syntax for generating flowcharts, mindmaps, sequence diagrams, class diagrams, gantt charts, git graphs and more.
8 lines • 53 kB
Source Map (JSON)
{
"version": 3,
"sources": ["../../../src/profiler.ts", "../../../src/rendering-util/fastdom.ts", "../../../src/rendering-util/createText.ts", "../../../src/rendering-util/handle-markdown-text.ts", "../../../src/rendering-util/splitText.ts"],
"sourcesContent": ["/* eslint-disable no-console */\n\n/**\n * Lightweight, hierarchical render profiler.\n *\n * ## Zero production cost\n * Every call site is guarded by `injected.profiling`, a compile-time constant\n * that esbuild replaces with the literal `false` for normal builds. The guard\n * then folds away (`if (false) { \u2026 }`), every reference to {@link profiler}\n * disappears, and this whole module is tree-shaken out \u2014 zero bytes, zero\n * runtime cost. Dev and dedicated profiling builds set it to `true`.\n *\n * ## Two gates (hybrid)\n * 1. Build-time (`injected.profiling`): present only in dev/profiling builds.\n * 2. Runtime ({@link Profiler.enabled}): off by default even when compiled in,\n * so a profiling build pays only a single boolean check until you opt in\n * with `profiler.enable()` (or `__mermaidProfiler.enable()` in the console).\n *\n * ## Output\n * When enabled, each measured phase emits:\n * 1. A User Timing entry (`performance.measure`) so phases show up in the\n * Chrome DevTools Performance panel \"Timings\" track \u2014 standard\n * instrumentation, free visualization.\n * 2. A node in an in-memory tree ({@link ProfileSpan}) used for the structured\n * console summary and for programmatic access via {@link Profiler.report}.\n */\n\nexport interface ProfileSpan {\n name: string;\n /** High-res start timestamp (`performance.now()`), relative to the time origin. */\n start: number;\n /** Wall-clock duration in milliseconds. `-1` until the span ends. */\n duration: number;\n children: ProfileSpan[];\n}\n\nconst hasPerformance = typeof performance !== 'undefined' && typeof performance.now === 'function';\n\nconst now = (): number => (hasPerformance ? performance.now() : 0);\n\n/** DevTools timeline prefix so mermaid marks/measures are easy to spot and filter. */\nconst MEASURE_PREFIX = '\uD83E\uDDDC ';\n\n/**\n * DevTools custom-track config (Chrome 130+). Phases render as labeled, colored\n * bars in a dedicated \"Mermaid render\" track instead of being lost among the\n * generic Timings entries. Requires \"Show custom tracks\" in the Performance\n * panel's capture settings. Unknown fields are ignored on older Chrome, where\n * the entry just falls back to the Timings track.\n */\nconst DEVTOOLS_TRACK = 'Mermaid render';\nconst DEVTOOLS_TRACK_GROUP = 'Mermaid';\n\n/** DevTools palette colour per phase, for at-a-glance separation. */\nconst PHASE_COLORS: Record<string, string> = {\n parse: 'tertiary',\n prepare: 'secondary',\n measure: 'primary',\n layout: 'primary-dark',\n layoutCore: 'error',\n draw: 'primary-light',\n paint: 'secondary-dark',\n serialize: 'tertiary-dark',\n render: 'primary-light',\n};\n\nexport interface ProfileRecord {\n /** Label for this render (e.g. the layout name when comparing layouts). */\n label: string;\n /** The completed phase tree for the render. */\n tree: ProfileSpan;\n /**\n * Flat accumulators summed across the render \u2014 for sub-operations that run too\n * many times to be tree spans (e.g. per-node `getBBox`). See {@link Profiler.tickSync}.\n */\n buckets: Record<string, number>;\n}\n\nclass Profiler {\n /** Runtime toggle. Off by default even in profiling builds. */\n public enabled = false;\n /** Log a summary to the console automatically when each root span closes. */\n public autoPrint = true;\n /**\n * Optional label applied to the next completed render's {@link ProfileRecord}.\n * A harness (e.g. the Dev Explorer's Profile tab) sets this before each\n * render to tag the resulting tree, e.g. with the layout name. Consumed and\n * cleared on {@link stop}.\n */\n public runLabel?: string;\n /** Completed render trees, oldest first, capped at {@link maxRecords}. */\n public readonly records: ProfileRecord[] = [];\n\n private readonly maxRecords = 200;\n private roots: ProfileSpan[] = [];\n private stack: ProfileSpan[] = [];\n private buckets: Record<string, number> = {};\n\n public enable(): this {\n this.enabled = true;\n return this;\n }\n\n public disable(): this {\n this.enabled = false;\n return this;\n }\n\n /** Begin a new top-level measurement (one per diagram render). */\n public start(label: string): void {\n if (!this.enabled) {\n return;\n }\n this.roots = [];\n this.stack = [];\n this.buckets = {};\n this.begin(label);\n }\n\n /**\n * Accumulate the wall-clock of a synchronous sub-operation into a named bucket,\n * summed over every call within the render \u2014 for hot operations that run too\n * often to be individual tree spans (e.g. per-node `getBBox`). Returns the\n * function's result. No-op (just calls `fn`) unless enabled.\n */\n public tickSync<T>(name: string, fn: () => T): T {\n if (!this.enabled) {\n return fn();\n }\n const t0 = now();\n try {\n return fn();\n } finally {\n this.buckets[name] = (this.buckets[name] ?? 0) + (now() - t0);\n }\n }\n\n /**\n * Async variant of {@link tickSync}. WARNING: only meaningful for operations\n * that run one-at-a-time. Do NOT use it for calls awaited concurrently (e.g.\n * `Promise.all(nodes.map(...))`) \u2014 their wall-clocks overlap and the summed\n * bucket balloons far past the real elapsed time. For concurrent CPU\n * attribution use a DevTools CPU profile instead.\n */\n public async tick<T>(name: string, fn: () => T | Promise<T>): Promise<T> {\n if (!this.enabled) {\n return fn();\n }\n const t0 = now();\n try {\n return await fn();\n } finally {\n this.buckets[name] = (this.buckets[name] ?? 0) + (now() - t0);\n }\n }\n\n /** End the current top-level measurement and optionally print a summary. */\n public stop(): ProfileSpan | undefined {\n if (!this.enabled) {\n return undefined;\n }\n // Defensive: close any spans a thrown phase may have left open.\n while (this.stack.length > 0) {\n this.end();\n }\n const root = this.roots.at(-1);\n const label = this.runLabel ?? root?.name;\n if (root) {\n this.records.push({ label: label ?? root.name, tree: root, buckets: { ...this.buckets } });\n if (this.records.length > this.maxRecords) {\n this.records.splice(0, this.records.length - this.maxRecords);\n }\n if (this.autoPrint) {\n this.printSummary(root, label);\n }\n }\n this.runLabel = undefined;\n return root;\n }\n\n /** Open a child span. Pair with {@link end}. No-op unless enabled. */\n public begin(name: string): void {\n if (!this.enabled) {\n return;\n }\n const span: ProfileSpan = { name, start: now(), duration: -1, children: [] };\n const parent = this.stack.at(-1);\n if (parent) {\n parent.children.push(span);\n } else {\n this.roots.push(span);\n }\n this.stack.push(span);\n // DevTools: a labeled point marker at the phase start (Timings track).\n if (hasPerformance && typeof performance.mark === 'function') {\n try {\n performance.mark(`${MEASURE_PREFIX}${name} \u25B6`);\n } catch {\n // Never let instrumentation break a render.\n }\n }\n }\n\n /** Close the most recently opened span. No-op unless enabled. */\n public end(): void {\n if (!this.enabled) {\n return;\n }\n const span = this.stack.pop();\n if (!span) {\n return;\n }\n const end = now();\n span.duration = end - span.start;\n if (hasPerformance && typeof performance.measure === 'function') {\n try {\n performance.measure(`${MEASURE_PREFIX}${span.name}`, {\n start: span.start,\n end,\n detail: {\n devtools: {\n dataType: 'track-entry',\n track: DEVTOOLS_TRACK,\n trackGroup: DEVTOOLS_TRACK_GROUP,\n color: PHASE_COLORS[span.name] ?? 'primary',\n tooltipText: `${span.name} \u2014 ${span.duration.toFixed(1)} ms`,\n },\n },\n });\n } catch {\n // Some environments reject the options form; never let timing break a render.\n }\n }\n }\n\n /**\n * Measure an async phase. Returns the wrapped function's result and rethrows\n * any error after closing the span, so instrumentation never swallows\n * failures or leaks an open span. No measurement overhead unless enabled.\n */\n public async span<T>(name: string, fn: () => T | Promise<T>): Promise<T> {\n if (!this.enabled) {\n return fn();\n }\n this.begin(name);\n try {\n return await fn();\n } finally {\n this.end();\n }\n }\n\n /** The most recent completed render tree, or `undefined`. */\n public report(): ProfileSpan | undefined {\n return this.records.at(-1)?.tree ?? this.roots.at(-1);\n }\n\n /** Drop all collected records and any in-progress spans. */\n public clear(): void {\n this.records.length = 0;\n this.roots = [];\n this.stack = [];\n this.runLabel = undefined;\n }\n\n public reset(): void {\n this.roots = [];\n this.stack = [];\n }\n\n public printSummary(root = this.report(), label?: string): void {\n if (!root) {\n return;\n }\n const total = root.duration;\n const heading = label && label !== root.name ? `${root.name} [${label}]` : root.name;\n const lines: string[] = ['ms % phase'];\n const walk = (span: ProfileSpan, depth: number): void => {\n const indent = ' '.repeat(depth);\n const ms = span.duration.toFixed(1).padStart(8);\n const pct = total > 0 ? `${((span.duration / total) * 100).toFixed(0).padStart(3)}%` : ' -';\n lines.push(`${ms} ${pct} ${indent}${span.name}`);\n for (const child of span.children) {\n walk(child, depth + 1);\n }\n // Surface unaccounted self-time when children don't add up to the parent.\n if (span.children.length > 0) {\n const childTotal = span.children.reduce((sum, c) => sum + c.duration, 0);\n const self = span.duration - childTotal;\n if (self > 0.5) {\n const selfMs = self.toFixed(1).padStart(8);\n lines.push(`${selfMs} ${indent} (self)`);\n }\n }\n };\n walk(root, 0);\n const bucketNames = Object.keys(this.buckets);\n if (bucketNames.length > 0) {\n lines.push('\u2014\u2014 buckets (summed) \u2014\u2014');\n for (const name of bucketNames) {\n lines.push(`${this.buckets[name].toFixed(1).padStart(8)} ${name}`);\n }\n }\n console.log(`${MEASURE_PREFIX}mermaid render profile \u00B7 ${heading}\\n${lines.join('\\n')}`);\n }\n}\n\ntype GlobalWithProfiler = typeof globalThis & {\n __mermaidProfiler?: Profiler;\n injected?: { includeLargeFeatures: boolean; profiling: boolean; version: string };\n};\n\n// `injected.*` are build-time constants that esbuild's `define` replaces with\n// literals. In runtimes that execute the source *without* that define \u2014 e.g. the\n// docs generator running modules through tsx \u2014 `injected` is undefined and the\n// guarded reads below would throw `ReferenceError: injected is not defined`. Seed a\n// production-equivalent default. Bundled builds replace `injected.profiling` with a\n// literal and never read this object, so it has no effect there.\n(globalThis as GlobalWithProfiler).injected ??= {\n includeLargeFeatures: true,\n profiling: false,\n version: '0.0.0',\n};\n\n// A SINGLE profiler instance shared across every mermaid bundle on the page.\n//\n// External layout packages (e.g. @mermaid-js/layout-elk) are built as separate\n// bundles that inline their own copy of mermaid's rendering pipeline \u2014 including\n// this module and the phase spans inside createCommonLayoutRenderer. Without\n// sharing, each bundle gets its own Profiler, so the elk layout's phase spans\n// would land in a different instance than the one the rest of the render\n// (parse/serialize/start/stop) and the Dev Explorer use \u2014 and silently vanish.\n// Resolving the instance from globalThis collapses them into one, so spans from\n// every bundle nest into the same tree.\n//\n// It also doubles as the console/Dev-Explorer handle: `__mermaidProfiler.enable()`.\n//\n// In production `injected.profiling` is `false`, so this folds to a plain,\n// unused (pure) instance that tree-shakes away with no global side effect.\nexport const profiler: Profiler = injected.profiling\n ? ((globalThis as GlobalWithProfiler).__mermaidProfiler ??= new Profiler())\n : /* @__PURE__ */ new Profiler();\n", "// eslint-disable-next-line @typescript-eslint/no-restricted-imports -- Only allowed to import `fastdom` in this file\nimport fastdomModule from 'fastdom';\nimport fastdomPromised from 'fastdom/extensions/fastdom-promised.js';\n\n/**\n * Promisified version of {@link fastdom} that uses `queueMicrotask` instead of `requestAnimationFrame` for faster execution.\n *\n * @example\n * ```\n * const bbox = await fastdom.measure(() => div.node()!.getBoundingClientRect());\n * ```\n */\nconst fastdom = // @ts-expect-error -- fastdom types aren't yet ESM-compatible, we need this hack\n (fastdomModule as typeof fastdomModule.default)\n .extend({\n /**\n * `requestAnimationFrame` is too slow compared to `queueMicrotask`.\n */\n raf(cb: () => void) {\n if (typeof queueMicrotask === 'function') {\n queueMicrotask(cb);\n } else {\n setTimeout(cb, 0);\n }\n },\n })\n .extend(fastdomPromised);\n\nexport default fastdom;\n", "import { select } from 'd3';\nimport type { MermaidConfig } from '../config.type.js';\nimport type { SVGGroup } from '../diagram-api/types.js';\nimport common, { hasKatex, renderKatexSanitized, sanitizeText } from '../diagrams/common/common.js';\nimport type { D3TSpanElement, D3TextElement } from '../diagrams/common/commonTypes.js';\nimport { log } from '../logger.js';\nimport { profiler } from '../profiler.js';\nimport {\n markdownToHTML,\n markdownToLines,\n nonMarkdownToHTML,\n nonMarkdownToLines,\n} from '../rendering-util/handle-markdown-text.js';\nimport { decodeEntities } from '../utils.js';\nimport fastdom from './fastdom.js';\nimport { getIconSVG, isIconAvailable } from './icons.js';\nimport { splitLineToFitWidth } from './splitText.js';\nimport type { MarkdownLine, MarkdownWord } from './types.js';\nimport { getConfig } from '../config.js';\nimport type { D3Selection } from '../types.js';\n\nfunction applyStyle<T extends Element>(\n dom: d3.Selection<T, unknown, Element | null, unknown>,\n styleFn?: Parameters<typeof dom.attr>[1]\n) {\n if (styleFn) {\n dom.attr('style', styleFn);\n }\n}\n\n// We assume that nobody will want to create labels larger than 16384 pixels wide\nconst maxSafeSizeForWidth = 16384;\n\nasync function addHtmlSpan(\n element: D3Selection<SVGGElement>,\n node: { label: string; labelStyle: string; isNode: boolean },\n width: number,\n classes: string,\n addBackground = false,\n // TODO: Make config mandatory\n config: MermaidConfig = getConfig()\n) {\n const fo = element.append('foreignObject');\n // This is not the final width but used in order to make sure the foreign\n // object in firefox gets a width at all. The final width is fetched from the div\n fo.attr('width', `${Math.min(10 * width, maxSafeSizeForWidth)}px`);\n fo.attr('height', `${Math.min(10 * width, maxSafeSizeForWidth)}px`);\n\n const div = fo.append<HTMLDivElement>('xhtml:div');\n const sanitizedLabel = hasKatex(node.label)\n ? await renderKatexSanitized(node.label.replace(common.lineBreakRegex, '\\n'), config)\n : sanitizeText(node.label, config);\n const labelClass = node.isNode ? 'nodeLabel' : 'edgeLabel';\n const span = div.append('span');\n span.html(sanitizedLabel);\n applyStyle(span, node.labelStyle);\n span.attr('class', `${labelClass} ${classes}`);\n\n applyStyle(div, node.labelStyle);\n div.style('display', 'table-cell');\n div.style('white-space', 'nowrap');\n div.style('line-height', '1.5');\n if (width !== Number.POSITIVE_INFINITY) {\n div.style('max-width', width + 'px');\n div.style('text-align', 'center');\n }\n div.attr('xmlns', 'http://www.w3.org/1999/xhtml');\n if (addBackground) {\n div.attr('class', 'labelBkg');\n }\n\n const bbox = await fastdom.measure(() => div.node()!.getBoundingClientRect());\n if (bbox.width === width) {\n div.style('display', 'table');\n div.style('white-space', 'break-spaces');\n div.style('width', width + 'px');\n }\n\n return fo.node()!;\n}\n\n/**\n * Creates a tspan element with the specified attributes for text positioning.\n *\n * @param textElement - The parent text element to append the tspan element.\n * @param lineIndex - The index of the current line in the structuredText array.\n * @param lineHeight - The line height value for the text.\n * @param centerText - The flag to determine if the text should be centered.\n * @returns The created tspan element.\n */\nfunction createTspan(\n textElement: D3Selection<SVGTextElement>,\n lineIndex: number,\n lineHeight: number,\n centerText = false\n) {\n const tspan = textElement\n .append('tspan')\n .attr('class', 'text-outer-tspan')\n .attr('x', 0)\n .attr('y', lineIndex * lineHeight - 0.1 + 'em')\n .attr('dy', lineHeight + 'em');\n if (centerText) {\n tspan.attr('text-anchor', 'middle');\n }\n return tspan;\n}\n\nfunction computeWidthOfText(\n parentNode: D3Selection<SVGGElement>,\n lineHeight: number,\n line: MarkdownLine\n): number {\n const testElement = parentNode.append('text');\n const testSpan = createTspan(testElement, 1, lineHeight);\n updateTextContentAndStyles(testSpan, line);\n const textLength = testSpan.node()!.getComputedTextLength();\n testElement.remove();\n return textLength;\n}\n\nexport function computeDimensionOfText(\n parentNode: SVGGroup,\n lineHeight: number,\n text: string\n): DOMRect | undefined {\n const testElement: D3TextElement = parentNode.append('text');\n const testSpan: D3TSpanElement = createTspan(testElement, 1, lineHeight);\n updateTextContentAndStyles(testSpan, [{ content: text, type: 'normal' }]);\n const textDimension: DOMRect | undefined = testSpan.node()?.getBoundingClientRect();\n if (textDimension) {\n testElement.remove();\n }\n return textDimension;\n}\n\n/**\n * Creates a formatted text element by breaking lines and applying styles based on\n * the given structuredText.\n *\n * @param width - The maximum allowed width of the text.\n * @param g - The parent group element to append the formatted text.\n * @param structuredText - The structured text data to format.\n * @param addBackground - Whether to add a background to the text.\n * @param centerText - The flag to determine if the text should be centered.\n */\nfunction createFormattedText(\n width: number,\n g: D3Selection<SVGGElement>,\n structuredText: MarkdownWord[][],\n addBackground = false,\n centerText = false\n) {\n const lineHeight = 1.1;\n const labelGroup = g.append('g');\n const bkg = labelGroup.insert('rect').attr('class', 'background').attr('style', 'stroke: none');\n const textElement = labelGroup.append('text').attr('y', '-10.1');\n if (centerText) {\n textElement.attr('text-anchor', 'middle');\n }\n let lineIndex = 0;\n for (const line of structuredText) {\n /**\n * Preprocess raw string content of line data\n * Creating an array of strings pre-split to satisfy width limit\n */\n const checkWidth = (line: MarkdownLine) =>\n computeWidthOfText(labelGroup, lineHeight, line) <= width;\n const linesUnderWidth = checkWidth(line) ? [line] : splitLineToFitWidth(line, checkWidth);\n /** Add each prepared line as a tspan to the parent node */\n for (const preparedLine of linesUnderWidth) {\n const tspan = createTspan(textElement, lineIndex, lineHeight, centerText);\n updateTextContentAndStyles(tspan, preparedLine);\n lineIndex++;\n }\n }\n if (addBackground) {\n // The `&& profiler.tickSync` guard tolerates an older shared profiler instance\n // (from a different mermaid version sharing the page's `__mermaidProfiler`) that\n // predates `tickSync` \u2014 fall back to a plain read. In production the whole\n // `injected.profiling` ternary folds away to just the direct `getBBox()`.\n const bbox =\n injected.profiling && profiler.tickSync\n ? profiler.tickSync('getBBox', () => textElement.node()!.getBBox())\n : textElement.node()!.getBBox();\n const padding = 2;\n bkg\n .attr('x', bbox.x - padding)\n .attr('y', bbox.y - padding)\n .attr('width', bbox.width + 2 * padding)\n .attr('height', bbox.height + 2 * padding);\n\n return labelGroup.node()!;\n } else {\n return textElement.node()!;\n }\n}\n\n/**\n * Our HTML code uses `.innerHTML` to apply the text,\n * however our plain text SVG code uses `.textContent` to apply the text,\n * which means that HTML entities are not decoded in SVG text.\n *\n * This means that we need to decode any HTML entities that `sanitizeText` encodes.\n *\n * TODO: If we're using `.textContent`, we can probably skip sanitization entirely.\n */\nfunction decodeHTMLEntities(text: string): string {\n // We only need to decode the few entries that `sanitizeText` encodes.\n const regex = /&(amp|lt|gt);/g;\n return text.replace(regex, (match, entity) => {\n switch (entity) {\n case 'amp':\n return '&';\n case 'lt':\n return '<';\n case 'gt':\n return '>';\n default:\n return match;\n }\n });\n}\n\n/**\n * Updates the text content and styles of the given tspan element based on the\n * provided wrappedLine data.\n *\n * @param tspan - The tspan element to update.\n * @param wrappedLine - The line data to apply to the tspan element.\n */\nfunction updateTextContentAndStyles(\n tspan: D3Selection<SVGTSpanElement>,\n wrappedLine: MarkdownWord[]\n) {\n tspan.text('');\n\n wrappedLine.forEach((word, index) => {\n const innerTspan = tspan\n .append('tspan')\n .attr('font-style', word.type === 'em' ? 'italic' : 'normal')\n .attr('class', 'text-inner-tspan')\n .attr('font-weight', word.type === 'strong' ? 'bold' : 'normal');\n if (index === 0) {\n innerTspan.text(decodeHTMLEntities(word.content));\n } else {\n // TODO: check what joiner to use.\n innerTspan.text(' ' + decodeHTMLEntities(word.content));\n }\n });\n}\n\n/**\n * Convert fontawesome labels into fontawesome icons by using a regex pattern\n * @param text - The raw string to convert\n * @param config - Mermaid config\n * @returns string with fontawesome icons as svg if the icon is registered otherwise as i tags\n */\nexport async function replaceIconSubstring(\n text: string,\n // TODO: Make config mandatory\n config: MermaidConfig = {}\n): Promise<string> {\n const pendingReplacements: Promise<string>[] = [];\n // cspell: disable-next-line\n text.replace(/(fa[bklrs]?):fa-([\\w-]+)/g, (fullMatch, prefix, iconName) => {\n pendingReplacements.push(\n (async () => {\n const registeredIconName = `${prefix}:${iconName}`;\n if (await isIconAvailable(registeredIconName)) {\n return await getIconSVG(registeredIconName, undefined, { class: 'label-icon' });\n } else {\n return `<i class='${sanitizeText(fullMatch, config).replace(':', ' ')}'></i>`;\n }\n })()\n );\n return fullMatch;\n });\n\n const replacements = await Promise.all(pendingReplacements);\n // cspell: disable-next-line\n return text.replace(/(fa[bklrs]?):fa-([\\w-]+)/g, () => replacements.shift() ?? '');\n}\n\n// Note when using from flowcharts converting the API isNode means classes should be set accordingly. When using htmlLabels => to set classes to 'nodeLabel' when isNode=true otherwise 'edgeLabel'\n// When not using htmlLabels => to set classes to 'title-row' when isTitle=true otherwise 'title-row'\n/**\n * Creates a text element within the given SVG group element.\n *\n * If `markdown` is `true`, basic markdown syntax will be processed.\n * Otherwise, if:\n * - `useHtmlLabels` is `true`, the text will be sanitized and set in `<foreignObject>` as HTML.\n * - `useHtmlLabels` is `false`, the text will be added as a `<text>` element using `.text`\n *\n * @param el - The parent SVG `<g>` element to append the text element to.\n * @param text - The text content to be displayed.\n * @param options - Optional options\n * @param config - Mermaid configuration object\n * @returns The created text element, either a `<foreignObject>` or a `<text>` element depending on the options.\n */\nexport const createText = async (\n el: D3Selection<SVGGElement>,\n text = '',\n {\n style = '',\n isTitle = false,\n classes = '',\n useHtmlLabels = true,\n markdown = true,\n isNode = true,\n /**\n * The width to wrap the text within. Set to `Number.POSITIVE_INFINITY` for no wrapping.\n */\n width = 200,\n addSvgBackground = false,\n } = {},\n config?: MermaidConfig\n) => {\n log.debug(\n 'XYZ createText',\n text,\n style,\n isTitle,\n classes,\n useHtmlLabels,\n isNode,\n 'addSvgBackground: ',\n addSvgBackground\n );\n if (useHtmlLabels) {\n // TODO: addHtmlLabel accepts a labelStyle. Do we possibly have that?\n\n const htmlText = markdown ? markdownToHTML(text, config) : nonMarkdownToHTML(text);\n const decodedReplacedText = await replaceIconSubstring(decodeEntities(htmlText), config);\n\n //for Katex the text could contain escaped characters, \\\\relax that should be transformed to \\relax\n const inputForKatex = text.replace(/\\\\\\\\/g, '\\\\');\n\n const node = {\n isNode,\n label: hasKatex(text) ? inputForKatex : decodedReplacedText,\n labelStyle: style.replace('fill:', 'color:'),\n };\n const vertexNode = await addHtmlSpan(el, node, width, classes, addSvgBackground, config);\n return vertexNode;\n } else {\n //sometimes the user might add br tags with 1 or more spaces in between, so we need to replace them with <br/>\n const sanitizeBR = decodeEntities(text.replace(/<br\\s*\\/?>/g, '<br/>'));\n const structuredText = markdown\n ? markdownToLines(sanitizeBR.replace('<br>', '<br/>'), config)\n : nonMarkdownToLines(sanitizeBR);\n const svgLabel = createFormattedText(\n width,\n el,\n structuredText,\n text ? addSvgBackground : false,\n !isNode\n );\n if (isNode) {\n if (/stroke:/.exec(style)) {\n style = style.replace('stroke:', 'lineColor:');\n }\n\n const nodeLabelTextStyle = style\n .replace(/stroke:[^;]+;?/g, '')\n .replace(/stroke-width:[^;]+;?/g, '')\n .replace(/fill:[^;]+;?/g, '')\n .replace(/color:/g, 'fill:');\n select(svgLabel).attr('style', nodeLabelTextStyle);\n // svgLabel.setAttribute('style', style);\n } else {\n //On style, assume `stroke`, `stroke-width` are used for edge path, so remove them\n // remove `fill`\n // use `background` as `fill` for label rect,\n\n const edgeLabelRectStyle = style\n .replace(/stroke:[^;]+;?/g, '')\n .replace(/stroke-width:[^;]+;?/g, '')\n .replace(/fill:[^;]+;?/g, '')\n .replace(/background:/g, 'fill:');\n select(svgLabel)\n .select('rect')\n .attr('style', edgeLabelRectStyle.replace(/background:/g, 'fill:'));\n\n // for text, update fill color with `color`\n const edgeLabelTextStyle = style\n .replace(/stroke:[^;]+;?/g, '')\n .replace(/stroke-width:[^;]+;?/g, '')\n .replace(/fill:[^;]+;?/g, '')\n .replace(/color:/g, 'fill:');\n select(svgLabel).select('text').attr('style', edgeLabelTextStyle);\n }\n if (isTitle) {\n // I can't actually see the title-row/row class being used anywhere, but keeping it for backward compatibility\n select(svgLabel).selectAll('tspan.text-outer-tspan').classed('title-row', true);\n } else {\n select(svgLabel).selectAll('tspan.text-outer-tspan').classed('row', true);\n }\n return svgLabel;\n }\n};\n", "import type { MarkedToken, Token } from 'marked';\nimport { marked } from 'marked';\nimport { dedent } from 'ts-dedent';\nimport type { MarkdownLine, MarkdownWordType } from './types.js';\nimport type { MermaidConfig } from '../config.type.js';\nimport { log } from '../logger.js';\n\n/**\n * @param markdown - markdown to process\n * @returns processed markdown\n */\nfunction preprocessMarkdown(markdown: string, { markdownAutoWrap }: MermaidConfig): string {\n //Replace <br/>with \\n\n const withoutBR = markdown.replace(/<br\\/>/g, '\\n');\n // Replace multiple newlines with a single newline\n const withoutMultipleNewlines = withoutBR.replace(/\\n{2,}/g, '\\n');\n // Remove extra spaces at the beginning of each line\n const withoutExtraSpaces = dedent(withoutMultipleNewlines);\n if (markdownAutoWrap === false) {\n // TODO: Disabling `markdownAutoWrap` is currently broken for `htmlLabels: false`,\n // since the code calls `splitWordToFitWidth` to split words even we can't\n // break on spaces.\n // return withoutExtraSpaces.replace(/ /g, '\\u00A0');\n }\n return withoutExtraSpaces;\n}\n\n/**\n * @param nonMarkdownText - Non-markdown text to split into plain-text formatted lines.\n * This treats new lines, `\\n`, and `<br/>` as line breaks, and splits on spaces for words.\n * SVG tags are preserved as separate words to maintain proper formatting.\n */\nexport function nonMarkdownToLines(nonMarkdownText: string): MarkdownLine[] {\n return nonMarkdownText.split(/\\\\n|\\n|<br\\s*\\/?>/gi).map(\n (line) =>\n line\n .trim()\n .match(/<[^>]+>|[^\\s<>]+/g) // keeps SVG tags intact and preserves space between tags and text\n ?.map((word) => ({ content: word, type: 'normal' })) ?? []\n );\n}\n\n/**\n * @param markdown - markdown to split into lines\n */\nexport function markdownToLines(markdown: string, config: MermaidConfig = {}): MarkdownLine[] {\n const preprocessedMarkdown = preprocessMarkdown(markdown, config);\n const nodes = marked.lexer(preprocessedMarkdown);\n const lines: MarkdownLine[] = [[]];\n let currentLine = 0;\n\n function processNode(node: MarkedToken, parentType: MarkdownWordType = 'normal') {\n if (node.type === 'text') {\n const textLines = node.text.split('\\n');\n textLines.forEach((textLine, index) => {\n if (index !== 0) {\n currentLine++;\n lines.push([]);\n }\n textLine.split(' ').forEach((word) => {\n word = word.replace(/'/g, `'`);\n if (word) {\n lines[currentLine].push({ content: word, type: parentType });\n }\n });\n });\n } else if (node.type === 'strong' || node.type === 'em') {\n node.tokens.forEach((contentNode) => {\n processNode(contentNode as MarkedToken, node.type);\n });\n } else if (node.type === 'html') {\n lines[currentLine].push({ content: node.text, type: 'normal' });\n }\n }\n\n nodes.forEach((treeNode) => {\n if (treeNode.type === 'paragraph') {\n treeNode.tokens?.forEach((contentNode) => {\n processNode(contentNode as MarkedToken);\n });\n } else if (treeNode.type === 'html') {\n lines[currentLine].push({ content: treeNode.text, type: 'normal' });\n } else {\n lines[currentLine].push({ content: treeNode.raw, type: 'normal' });\n }\n });\n\n return lines;\n}\n\n/**\n * Counterpart to {@link markdownToHTML} for non-markdown text.\n *\n * Non-markdown text is not wrapped normally, and users can use an explicit `\\n`\n * sequence to add a line break.\n *\n * @param text - Non-markdown text to convert to HTML.\n */\nexport function nonMarkdownToHTML(text: string) {\n if (!text) {\n return '';\n }\n /*\n * Edge labels may have double backgrounds if `addBackground` is `true`.\n * This `<p>` wrapper aligns with how {@link markdownToHTML} wraps its output, and\n * ensures both backgrounds are the same size.\n *\n * We can't set it for empty labels, otherwise it causes rendering changes.\n */\n return `<p>${\n /**\n * Replace new lines with <br /> tags.\n *\n * Unlike in markdown text, `\\n` sequences are treated as line breaks here.\n */\n text.replace(/\\\\n|\\n/g, '<br />')\n }</p>`;\n}\n\nexport function markdownToHTML(markdown: string, { markdownAutoWrap }: MermaidConfig = {}) {\n const nodes = marked.lexer(markdown);\n\n function output(node: Token): string {\n if (node.type === 'text') {\n if (markdownAutoWrap === false) {\n return node.text.replace(/\\n */g, '<br/>').replace(/ /g, ' ');\n }\n return node.text.replace(/\\n */g, '<br/>');\n } else if (node.type === 'strong') {\n return `<strong>${node.tokens?.map(output).join('')}</strong>`;\n } else if (node.type === 'em') {\n return `<em>${node.tokens?.map(output).join('')}</em>`;\n } else if (node.type === 'paragraph') {\n return `<p>${node.tokens?.map(output).join('')}</p>`;\n } else if (node.type === 'space') {\n return '';\n } else if (node.type === 'html') {\n return `${node.text}`;\n } else if (node.type === 'escape') {\n return node.text;\n }\n log.warn(`Unsupported markdown: ${node.type}`);\n return node.raw;\n }\n\n return nodes.map(output).join('');\n}\n", "import type { CheckFitFunction, MarkdownLine, MarkdownWord, MarkdownWordType } from './types.js';\n\n/**\n * Splits a string into graphemes if available, otherwise characters.\n */\nexport function splitTextToChars(text: string): string[] {\n if (Intl.Segmenter) {\n return [...new Intl.Segmenter().segment(text)].map((s) => s.segment);\n }\n return [...text];\n}\n\n/**\n * Splits a string into words by using `Intl.Segmenter` if available, or splitting by ' '.\n * `Intl.Segmenter` uses the default locale, which might be different across browsers.\n */\nexport function splitLineToWords(text: string): string[] {\n if (Intl.Segmenter) {\n return [...new Intl.Segmenter(undefined, { granularity: 'word' }).segment(text)].map(\n (s) => s.segment\n );\n }\n // Split by ' ' removes the ' 's from the result.\n const words = text.split(' ');\n // Add the ' 's back to the result.\n const wordsWithSpaces = words.flatMap((s) => [s, ' ']).filter((s) => s);\n // Remove last space.\n wordsWithSpaces.pop();\n return wordsWithSpaces;\n}\n\n/**\n * Splits a word into two parts, the first part fits the width and the remaining part.\n * @param checkFit - Function to check if word fits\n * @param word - Word to split\n * @returns [first part of word that fits, rest of word]\n */\nexport function splitWordToFitWidth(\n checkFit: CheckFitFunction,\n word: MarkdownWord\n): [MarkdownWord, MarkdownWord] {\n const characters = splitTextToChars(word.content);\n return splitWordToFitWidthRecursion(checkFit, [], characters, word.type);\n}\n\nfunction splitWordToFitWidthRecursion(\n checkFit: CheckFitFunction,\n usedChars: string[],\n remainingChars: string[],\n type: MarkdownWordType\n): [MarkdownWord, MarkdownWord] {\n if (remainingChars.length === 0) {\n return [\n { content: usedChars.join(''), type },\n { content: '', type },\n ];\n }\n const [nextChar, ...rest] = remainingChars;\n const newWord = [...usedChars, nextChar];\n if (checkFit([{ content: newWord.join(''), type }])) {\n return splitWordToFitWidthRecursion(checkFit, newWord, rest, type);\n }\n if (usedChars.length === 0 && nextChar) {\n // If the first character does not fit, split it anyway\n usedChars.push(nextChar);\n remainingChars.shift();\n }\n return [\n { content: usedChars.join(''), type },\n { content: remainingChars.join(''), type },\n ];\n}\n\n/**\n * Splits a line into multiple lines that satisfy the checkFit function.\n * @param line - Line to split\n * @param checkFit - Function to check if line fits\n * @returns Array of lines that fit\n */\nexport function splitLineToFitWidth(\n line: MarkdownLine,\n checkFit: CheckFitFunction\n): MarkdownLine[] {\n if (line.some(({ content }) => content.includes('\\n'))) {\n throw new Error('splitLineToFitWidth does not support newlines in the line');\n }\n return splitLineToFitWidthRecursion(line, checkFit);\n}\n\nfunction splitLineToFitWidthRecursion(\n words: MarkdownWord[],\n checkFit: CheckFitFunction,\n lines: MarkdownLine[] = [],\n newLine: MarkdownLine = []\n): MarkdownLine[] {\n // Return if there is nothing left to split\n if (words.length === 0) {\n // If there is a new line, add it to the lines\n if (newLine.length > 0) {\n lines.push(newLine);\n }\n return lines.length > 0 ? lines : [];\n }\n let joiner = '';\n if (words[0].content === ' ') {\n joiner = ' ';\n words.shift();\n }\n const nextWord: MarkdownWord = words.shift() ?? { content: ' ', type: 'normal' };\n const lineWithNextWord: MarkdownLine = [...newLine];\n if (joiner !== '') {\n lineWithNextWord.push({ content: joiner, type: 'normal' });\n }\n lineWithNextWord.push(nextWord);\n\n if (checkFit(lineWithNextWord)) {\n // nextWord fits, so we can add it to the new line and continue\n return splitLineToFitWidthRecursion(words, checkFit, lines, lineWithNextWord);\n }\n\n // nextWord doesn't fit, so we need to split it\n if (newLine.length > 0) {\n // There was text in newLine, so add it to lines and push nextWord back into words.\n lines.push(newLine);\n words.unshift(nextWord);\n } else if (nextWord.content) {\n // There was no text in newLine, so we need to split nextWord\n const [line, rest] = splitWordToFitWidth(checkFit, nextWord);\n lines.push([line]);\n if (rest.content) {\n words.unshift(rest);\n }\n }\n return splitLineToFitWidthRecursion(words, checkFit, lines);\n}\n"],
"mappings": "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",
"names": ["line", "profiler"]
}