better-mermaid
Version:
Markdown-ish syntax for generating flowcharts, mindmaps, sequence diagrams, class diagrams, gantt charts, git graphs and more.
4 lines • 268 kB
Source Map (JSON)
{
"version": 3,
"sources": ["../src/mermaid.ts", "../src/mermaidAPI.ts", "../src/diagrams/c4/c4Detector.ts", "../src/diagrams/flowchart/flowDetector.ts", "../src/diagrams/flowchart/flowDetector-v2.ts", "../src/diagrams/er/erDetector.ts", "../src/diagrams/git/gitGraphDetector.ts", "../src/diagrams/gantt/ganttDetector.ts", "../src/diagrams/info/infoDetector.ts", "../src/diagrams/pie/pieDetector.ts", "../src/diagrams/quadrant-chart/quadrantDetector.ts", "../src/diagrams/xychart/xychartDetector.ts", "../src/diagrams/requirement/requirementDetector.ts", "../src/diagrams/sequence/sequenceDetector.ts", "../src/diagrams/class/classDetector.ts", "../src/diagrams/class/classDetector-V2.ts", "../src/diagrams/state/stateDetector.ts", "../src/diagrams/state/stateDetector-V2.ts", "../src/diagrams/user-journey/journeyDetector.ts", "../src/diagrams/error/errorRenderer.ts", "../src/diagrams/error/errorDiagram.ts", "../src/diagrams/flowchart/elk/detector.ts", "../src/diagrams/timeline/detector.ts", "../src/diagrams/mindmap/detector.ts", "../src/diagrams/sankey/sankeyDetector.ts", "../src/diagrams/packet/detector.ts", "../src/diagrams/block/blockDetector.ts", "../src/diagram-api/diagram-orchestration.ts", "../src/Diagram.ts", "../src/interactionDb.ts", "../src/accessibility.ts", "../src/diagram-api/comments.ts", "../../../node_modules/.pnpm/js-yaml@4.1.0/node_modules/js-yaml/dist/js-yaml.mjs", "../src/diagram-api/frontmatter.ts", "../src/preprocess.ts", "../src/diagram-api/loadDiagram.ts"],
"sourcesContent": ["/**\n * Web page integration module for the mermaid framework. It uses the mermaidAPI for mermaid\n * functionality and to render the diagrams to svg code!\n */\nimport { dedent } from 'ts-dedent';\nimport type { MermaidConfig } from './config.type.js';\nimport { log } from './logger.js';\nimport utils from './utils.js';\nimport type { ParseOptions, ParseResult, RenderResult } from './mermaidAPI.js';\nimport { mermaidAPI } from './mermaidAPI.js';\nimport { registerLazyLoadedDiagrams, detectType } from './diagram-api/detectType.js';\nimport { loadRegisteredDiagrams } from './diagram-api/loadDiagram.js';\nimport type { ParseErrorFunction } from './Diagram.js';\nimport { isDetailedError } from './utils.js';\nimport type { DetailedError } from './utils.js';\nimport type { ExternalDiagramDefinition } from './diagram-api/types.js';\nimport type { UnknownDiagramError } from './errors.js';\nimport { addDiagrams } from './diagram-api/diagram-orchestration.js';\n\nexport type {\n MermaidConfig,\n DetailedError,\n ExternalDiagramDefinition,\n ParseErrorFunction,\n RenderResult,\n ParseOptions,\n ParseResult,\n UnknownDiagramError,\n};\n\nexport interface RunOptions {\n /**\n * The query selector to use when finding elements to render. Default: `\".mermaid\"`.\n */\n querySelector?: string;\n /**\n * The nodes to render. If this is set, `querySelector` will be ignored.\n */\n nodes?: ArrayLike<HTMLElement>;\n /**\n * A callback to call after each diagram is rendered.\n */\n postRenderCallback?: (id: string) => unknown;\n /**\n * If `true`, errors will be logged to the console, but not thrown. Default: `false`\n */\n suppressErrors?: boolean;\n}\n\nconst handleError = (error: unknown, errors: DetailedError[], parseError?: ParseErrorFunction) => {\n log.warn(error);\n if (isDetailedError(error)) {\n // handle case where error string and hash were\n // wrapped in object like`const error = { str, hash };`\n if (parseError) {\n parseError(error.str, error.hash);\n }\n errors.push({ ...error, message: error.str, error });\n } else {\n // assume it is just error string and pass it on\n if (parseError) {\n parseError(error);\n }\n if (error instanceof Error) {\n errors.push({\n str: error.message,\n message: error.message,\n hash: error.name,\n error,\n });\n }\n }\n};\n\n/**\n * ## run\n *\n * Function that goes through the document to find the chart definitions in there and render them.\n *\n * The function tags the processed attributes with the attribute data-processed and ignores found\n * elements with the attribute already set. This way the init function can be triggered several\n * times.\n *\n * ```mermaid\n * graph LR;\n * a(Find elements)-->b{Processed}\n * b-->|Yes|c(Leave element)\n * b-->|No |d(Transform)\n * ```\n *\n * Renders the mermaid diagrams\n *\n * @param options - Optional runtime configs\n */\nconst run = async function (\n options: RunOptions = {\n querySelector: '.mermaid',\n }\n) {\n try {\n await runThrowsErrors(options);\n } catch (e) {\n if (isDetailedError(e)) {\n log.error(e.str);\n }\n if (mermaid.parseError) {\n mermaid.parseError(e as string);\n }\n if (!options.suppressErrors) {\n log.error('Use the suppressErrors option to suppress these errors');\n throw e;\n }\n }\n};\n\nconst runThrowsErrors = async function (\n { postRenderCallback, querySelector, nodes }: Omit<RunOptions, 'suppressErrors'> = {\n querySelector: '.mermaid',\n }\n) {\n const conf = mermaidAPI.getConfig();\n\n log.debug(`${!postRenderCallback ? 'No ' : ''}Callback function found`);\n\n let nodesToProcess: ArrayLike<HTMLElement>;\n if (nodes) {\n nodesToProcess = nodes;\n } else if (querySelector) {\n nodesToProcess = document.querySelectorAll(querySelector);\n } else {\n throw new Error('Nodes and querySelector are both undefined');\n }\n\n log.debug(`Found ${nodesToProcess.length} diagrams`);\n if (conf?.startOnLoad !== undefined) {\n log.debug('Start On Load: ' + conf?.startOnLoad);\n mermaidAPI.updateSiteConfig({ startOnLoad: conf?.startOnLoad });\n }\n\n // generate the id of the diagram\n const idGenerator = new utils.InitIDGenerator(conf.deterministicIds, conf.deterministicIDSeed);\n\n let txt: string;\n const errors: DetailedError[] = [];\n\n // element is the current div with mermaid class\n // eslint-disable-next-line unicorn/prefer-spread\n for (const element of Array.from(nodesToProcess)) {\n log.info('Rendering diagram: ' + element.id);\n /*! Check if previously processed */\n if (element.getAttribute('data-processed')) {\n continue;\n }\n element.setAttribute('data-processed', 'true');\n\n const id = `mermaid-${idGenerator.next()}`;\n\n // Fetch the graph definition including tags\n txt = element.innerHTML;\n\n // transforms the html to pure text\n txt = dedent(utils.entityDecode(txt)) // removes indentation, required for YAML parsing\n .trim()\n .replace(/<br\\s*\\/?>/gi, '<br/>');\n\n const init = utils.detectInit(txt);\n if (init) {\n log.debug('Detected early reinit: ', init);\n }\n try {\n const { svg, bindFunctions } = await render(id, txt, element);\n element.innerHTML = svg;\n if (postRenderCallback) {\n await postRenderCallback(id);\n }\n if (bindFunctions) {\n bindFunctions(element);\n }\n } catch (error) {\n handleError(error, errors, mermaid.parseError);\n }\n }\n if (errors.length > 0) {\n // TODO: We should be throwing an error object.\n throw errors[0];\n }\n};\n\n/**\n * Used to set configurations for mermaid.\n * This function should be called before the run function.\n * @param config - Configuration object for mermaid.\n */\n\nconst initialize = function (config: MermaidConfig) {\n mermaidAPI.initialize(config);\n};\n\n/**\n * ## init\n *\n * @deprecated Use {@link initialize} and {@link run} instead.\n *\n * Renders the mermaid diagrams\n *\n * @param config - **Deprecated**, please set configuration in {@link initialize}.\n * @param nodes - **Default**: `.mermaid`. One of the following:\n * - A DOM Node\n * - An array of DOM nodes (as would come from a jQuery selector)\n * - A W3C selector, a la `.mermaid`\n * @param callback - Called once for each rendered diagram's id.\n */\nconst init = async function (\n config?: MermaidConfig,\n nodes?: string | HTMLElement | NodeListOf<HTMLElement>,\n callback?: (id: string) => unknown\n) {\n log.warn('mermaid.init is deprecated. Please use run instead.');\n if (config) {\n initialize(config);\n }\n const runOptions: RunOptions = { postRenderCallback: callback, querySelector: '.mermaid' };\n if (typeof nodes === 'string') {\n runOptions.querySelector = nodes;\n } else if (nodes) {\n if (nodes instanceof HTMLElement) {\n runOptions.nodes = [nodes];\n } else {\n runOptions.nodes = nodes;\n }\n }\n await run(runOptions);\n};\n\n/**\n * Used to register external diagram types.\n * @param diagrams - Array of {@link ExternalDiagramDefinition}.\n * @param opts - If opts.lazyLoad is false, the diagrams will be loaded immediately.\n */\nconst registerExternalDiagrams = async (\n diagrams: ExternalDiagramDefinition[],\n {\n lazyLoad = true,\n }: {\n lazyLoad?: boolean;\n } = {}\n) => {\n addDiagrams();\n registerLazyLoadedDiagrams(...diagrams);\n if (lazyLoad === false) {\n await loadRegisteredDiagrams();\n }\n};\n\n/**\n * ##contentLoaded Callback function that is called when page is loaded. This functions fetches\n * configuration for mermaid rendering and calls init for rendering the mermaid diagrams on the\n * page.\n */\nconst contentLoaded = function () {\n if (mermaid.startOnLoad) {\n const { startOnLoad } = mermaidAPI.getConfig();\n if (startOnLoad) {\n mermaid.run().catch((err) => log.error('Mermaid failed to initialize', err));\n }\n }\n};\n\nif (typeof document !== 'undefined') {\n /*!\n * Wait for document loaded before starting the execution\n */\n window.addEventListener('load', contentLoaded, false);\n}\n\n/**\n * ## setParseErrorHandler Alternative to directly setting parseError using:\n *\n * ```js\n * mermaid.parseError = function(err,hash){=\n * forExampleDisplayErrorInGui(err); // do something with the error\n * };\n * ```\n *\n * This is provided for environments where the mermaid object can't directly have a new member added\n * to it (eg. dart interop wrapper). (Initially there is no parseError member of mermaid).\n *\n * @param parseErrorHandler - New parseError() callback.\n */\nconst setParseErrorHandler = function (parseErrorHandler: (err: any, hash: any) => void) {\n mermaid.parseError = parseErrorHandler;\n};\n\nconst executionQueue: (() => Promise<unknown>)[] = [];\nlet executionQueueRunning = false;\nconst executeQueue = async () => {\n if (executionQueueRunning) {\n return;\n }\n executionQueueRunning = true;\n while (executionQueue.length > 0) {\n const f = executionQueue.shift();\n if (f) {\n try {\n await f();\n } catch (e) {\n log.error('Error executing queue', e);\n }\n }\n }\n executionQueueRunning = false;\n};\n\n/**\n * Parse the text and validate the syntax.\n * @param text - The mermaid diagram definition.\n * @param parseOptions - Options for parsing. @see {@link ParseOptions}\n * @returns If valid, {@link ParseResult} otherwise `false` if parseOptions.suppressErrors is `true`.\n * @throws Error if the diagram is invalid and parseOptions.suppressErrors is false or not set.\n *\n * @example\n * ```js\n * console.log(await mermaid.parse('flowchart \\n a --> b'));\n * // { diagramType: 'flowchart-v2' }\n * console.log(await mermaid.parse('wrong \\n a --> b', { suppressErrors: true }));\n * // false\n * console.log(await mermaid.parse('wrong \\n a --> b', { suppressErrors: false }));\n * // throws Error\n * console.log(await mermaid.parse('wrong \\n a --> b'));\n * // throws Error\n * ```\n */\nconst parse: typeof mermaidAPI.parse = async (text, parseOptions) => {\n return new Promise((resolve, reject) => {\n // This promise will resolve when the render call is done.\n // It will be queued first and will be executed when it is first in line\n const performCall = () =>\n new Promise((res, rej) => {\n mermaidAPI.parse(text, parseOptions).then(\n (r) => {\n // This resolves for the promise for the queue handling\n res(r);\n // This fulfills the promise sent to the value back to the original caller\n resolve(r);\n },\n (e) => {\n log.error('Error parsing', e);\n mermaid.parseError?.(e);\n rej(e);\n reject(e);\n }\n );\n });\n executionQueue.push(performCall);\n executeQueue().catch(reject);\n });\n};\n\n/**\n * Function that renders an svg with a graph from a chart definition. Usage example below.\n *\n * ```javascript\n * element = document.querySelector('#graphDiv');\n * const graphDefinition = 'graph TB\\na-->b';\n * const { svg, bindFunctions } = await mermaid.render('graphDiv', graphDefinition);\n * element.innerHTML = svg;\n * bindFunctions?.(element);\n * ```\n *\n * @remarks\n * Multiple calls to this function will be enqueued to run serially.\n *\n * @param id - The id for the SVG element (the element to be rendered)\n * @param text - The text for the graph definition\n * @param container - HTML element where the svg will be inserted. (Is usually element with the .mermaid class)\n * If no svgContainingElement is provided then the SVG element will be appended to the body.\n * Selector to element in which a div with the graph temporarily will be\n * inserted. If one is provided a hidden div will be inserted in the body of the page instead. The\n * element will be removed when rendering is completed.\n * @returns Returns the SVG Definition and BindFunctions.\n */\nconst render: typeof mermaidAPI.render = (id, text, container) => {\n return new Promise((resolve, reject) => {\n // This promise will resolve when the mermaidAPI.render call is done.\n // It will be queued first and will be executed when it is first in line\n const performCall = () =>\n new Promise((res, rej) => {\n mermaidAPI.render(id, text, container).then(\n (r) => {\n // This resolves for the promise for the queue handling\n res(r);\n // This fulfills the promise sent to the value back to the original caller\n resolve(r);\n },\n (e) => {\n log.error('Error parsing', e);\n mermaid.parseError?.(e);\n rej(e);\n reject(e);\n }\n );\n });\n executionQueue.push(performCall);\n executeQueue().catch(reject);\n });\n};\n\nexport interface Mermaid {\n startOnLoad: boolean;\n parseError?: ParseErrorFunction;\n mermaidAPI: typeof mermaidAPI;\n parse: typeof parse;\n render: typeof render;\n init: typeof init;\n run: typeof run;\n registerExternalDiagrams: typeof registerExternalDiagrams;\n initialize: typeof initialize;\n contentLoaded: typeof contentLoaded;\n setParseErrorHandler: typeof setParseErrorHandler;\n detectType: typeof detectType;\n}\n\nconst mermaid: Mermaid = {\n startOnLoad: true,\n mermaidAPI,\n parse,\n render,\n init,\n run,\n registerExternalDiagrams,\n initialize,\n parseError: undefined,\n contentLoaded,\n setParseErrorHandler,\n detectType,\n};\n\nexport default mermaid;\n", "/**\n * This is the API to be used when optionally handling the integration with the web page, instead of\n * using the default integration provided by mermaid.js.\n *\n * The core of this api is the [**render**](Setup.md?id=render) function which, given a graph\n * definition as text, renders the graph/diagram and returns an svg element for the graph.\n *\n * It is then up to the user of the API to make use of the svg, either insert it somewhere in the\n * page or do something completely different.\n *\n * In addition to the render function, a number of behavioral configuration options are available.\n */\n// @ts-ignore TODO: Investigate D3 issue\nimport { select } from 'd3';\nimport { compile, serialize, stringify } from 'stylis';\n// @ts-ignore: TODO Fix ts errors\nimport { version } from '../package.json';\nimport * as configApi from './config.js';\nimport { addDiagrams } from './diagram-api/diagram-orchestration.js';\nimport { Diagram } from './Diagram.js';\nimport errorRenderer from './diagrams/error/errorRenderer.js';\nimport { attachFunctions } from './interactionDb.js';\nimport { log, setLogLevel } from './logger.js';\nimport getStyles from './styles.js';\nimport theme from './themes/index.js';\nimport DOMPurify from 'dompurify';\nimport type { MermaidConfig } from './config.type.js';\nimport { evaluate } from './diagrams/common/common.js';\nimport isEmpty from 'lodash-es/isEmpty.js';\nimport { setA11yDiagramInfo, addSVGa11yTitleDescription } from './accessibility.js';\nimport type { DiagramMetadata, DiagramStyleClassDef } from './diagram-api/types.js';\nimport { preprocessDiagram } from './preprocess.js';\nimport { decodeEntities } from './utils.js';\n\nconst MAX_TEXTLENGTH = 50_000;\nconst MAX_TEXTLENGTH_EXCEEDED_MSG =\n 'graph TB;a[Maximum text size in diagram exceeded];style a fill:#faa';\n\nconst SECURITY_LVL_SANDBOX = 'sandbox';\nconst SECURITY_LVL_LOOSE = 'loose';\n\nconst XMLNS_SVG_STD = 'http://www.w3.org/2000/svg';\nconst XMLNS_XLINK_STD = 'http://www.w3.org/1999/xlink';\nconst XMLNS_XHTML_STD = 'http://www.w3.org/1999/xhtml';\n\n// ------------------------------\n// iFrame\nconst IFRAME_WIDTH = '100%';\nconst IFRAME_HEIGHT = '100%';\nconst IFRAME_STYLES = 'border:0;margin:0;';\nconst IFRAME_BODY_STYLE = 'margin:0';\nconst IFRAME_SANDBOX_OPTS = 'allow-top-navigation-by-user-activation allow-popups';\nconst IFRAME_NOT_SUPPORTED_MSG = 'The \"iframe\" tag is not supported by your browser.';\n\n// DOMPurify settings for svgCode\nconst DOMPURIFY_TAGS = ['foreignobject'];\nconst DOMPURIFY_ATTR = ['dominant-baseline'];\n\nexport interface ParseOptions {\n /**\n * If `true`, parse will return `false` instead of throwing error when the diagram is invalid.\n * The `parseError` function will not be called.\n */\n suppressErrors?: boolean;\n}\n\nexport interface ParseResult {\n /**\n * The diagram type, e.g. 'flowchart', 'sequence', etc.\n */\n diagramType: string;\n}\n// This makes it clear that we're working with a d3 selected element of some kind, even though it's hard to specify the exact type.\nexport type D3Element = any;\n\nexport interface RenderResult {\n /**\n * The svg code for the rendered graph.\n */\n svg: string;\n /**\n * The diagram type, e.g. 'flowchart', 'sequence', etc.\n */\n diagramType: string;\n /**\n * Bind function to be called after the svg has been inserted into the DOM.\n * This is necessary for adding event listeners to the elements in the svg.\n * ```js\n * const { svg, bindFunctions } = mermaidAPI.render('id1', 'graph TD;A-->B');\n * div.innerHTML = svg;\n * bindFunctions?.(div); // To call bindFunctions only if it's present.\n * ```\n */\n bindFunctions?: (element: Element) => void;\n data: any;\n}\n\nfunction processAndSetConfigs(text: string) {\n const processed = preprocessDiagram(text);\n configApi.reset();\n configApi.addDirective(processed.config ?? {});\n return processed;\n}\n\n/**\n * Parse the text and validate the syntax.\n * @param text - The mermaid diagram definition.\n * @param parseOptions - Options for parsing. @see {@link ParseOptions}\n * @returns An object with the `diagramType` set to type of the diagram if valid. Otherwise `false` if parseOptions.suppressErrors is `true`.\n * @throws Error if the diagram is invalid and parseOptions.suppressErrors is false or not set.\n */\nasync function parse(\n text: string,\n parseOptions: ParseOptions & { suppressErrors: true }\n): Promise<ParseResult | false>;\nasync function parse(text: string, parseOptions?: ParseOptions): Promise<ParseResult>;\nasync function parse(text: string, parseOptions?: ParseOptions): Promise<ParseResult | false> {\n addDiagrams();\n try {\n const { code } = processAndSetConfigs(text);\n const diagram = await getDiagramFromText(code);\n return { diagramType: diagram.type };\n } catch (error) {\n if (parseOptions?.suppressErrors) {\n return false;\n }\n throw error;\n }\n}\n\n/**\n * Create a CSS style that starts with the given class name, then the element,\n * with an enclosing block that has each of the cssClasses followed by !important;\n * @param cssClass - CSS class name\n * @param element - CSS element\n * @param cssClasses - list of CSS styles to append after the element\n * @returns - the constructed string\n */\nexport const cssImportantStyles = (\n cssClass: string,\n element: string,\n cssClasses: string[] = []\n): string => {\n return `\\n.${cssClass} ${element} { ${cssClasses.join(' !important; ')} !important; }`;\n};\n\n/**\n * Create the user styles\n * @internal\n * @param config - configuration that has style and theme settings to use\n * @param classDefs - the classDefs in the diagram text. Might be null if none were defined. Usually is the result of a call to getClasses(...)\n * @returns the string with all the user styles\n */\nexport const createCssStyles = (\n config: MermaidConfig,\n classDefs: Map<string, DiagramStyleClassDef> | null | undefined = new Map()\n): string => {\n let cssStyles = '';\n\n // user provided theme CSS info\n // If you add more configuration driven data into the user styles make sure that the value is\n // sanitized by the sanitize CSS function TODO where is this method? what should be used to replace it? refactor so that it's always sanitized\n if (config.themeCSS !== undefined) {\n cssStyles += `\\n${config.themeCSS}`;\n }\n\n if (config.fontFamily !== undefined) {\n cssStyles += `\\n:root { --mermaid-font-family: ${config.fontFamily}}`;\n }\n if (config.altFontFamily !== undefined) {\n cssStyles += `\\n:root { --mermaid-alt-font-family: ${config.altFontFamily}}`;\n }\n\n // classDefs defined in the diagram text\n if (classDefs instanceof Map) {\n const htmlLabels = config.htmlLabels || config.flowchart?.htmlLabels; // TODO why specifically check the Flowchart diagram config?\n\n const cssHtmlElements = ['> *', 'span']; // TODO make a constant\n const cssShapeElements = ['rect', 'polygon', 'ellipse', 'circle', 'path']; // TODO make a constant\n\n const cssElements = htmlLabels ? cssHtmlElements : cssShapeElements;\n\n // create the CSS styles needed for each styleClass definition and css element\n classDefs.forEach((styleClassDef) => {\n // create the css styles for each cssElement and the styles (only if there are styles)\n if (!isEmpty(styleClassDef.styles)) {\n cssElements.forEach((cssElement) => {\n cssStyles += cssImportantStyles(styleClassDef.id, cssElement, styleClassDef.styles);\n });\n }\n // create the css styles for the tspan element and the text styles (only if there are textStyles)\n if (!isEmpty(styleClassDef.textStyles)) {\n cssStyles += cssImportantStyles(styleClassDef.id, 'tspan', styleClassDef.textStyles);\n }\n });\n }\n return cssStyles;\n};\n\nexport const createUserStyles = (\n config: MermaidConfig,\n graphType: string,\n classDefs: Map<string, DiagramStyleClassDef> | undefined,\n svgId: string\n): string => {\n const userCSSstyles = createCssStyles(config, classDefs);\n const allStyles = getStyles(graphType, userCSSstyles, config.themeVariables);\n\n // Now turn all of the styles into a (compiled) string that starts with the id\n // use the stylis library to compile the css, turn the results into a valid CSS string (serialize(...., stringify))\n // @see https://github.com/thysultan/stylis\n return serialize(compile(`${svgId}{${allStyles}}`), stringify);\n};\n\n/**\n * Clean up svgCode. Do replacements needed\n *\n * @param svgCode - the code to clean up\n * @param inSandboxMode - security level\n * @param useArrowMarkerUrls - should arrow marker's use full urls? (vs. just the anchors)\n * @returns the cleaned up svgCode\n */\nexport const cleanUpSvgCode = (\n svgCode = '',\n inSandboxMode: boolean,\n useArrowMarkerUrls: boolean\n): string => {\n let cleanedUpSvg = svgCode;\n\n // Replace marker-end urls with just the # anchor (remove the preceding part of the URL)\n if (!useArrowMarkerUrls && !inSandboxMode) {\n cleanedUpSvg = cleanedUpSvg.replace(\n /marker-end=\"url\\([\\d+./:=?A-Za-z-]*?#/g,\n 'marker-end=\"url(#'\n );\n }\n\n cleanedUpSvg = decodeEntities(cleanedUpSvg);\n\n // replace old br tags with newer style\n cleanedUpSvg = cleanedUpSvg.replace(/<br>/g, '<br/>');\n\n return cleanedUpSvg;\n};\n\n/**\n * Put the svgCode into an iFrame. Return the iFrame code\n *\n * @param svgCode - the svg code to put inside the iFrame\n * @param svgElement - the d3 node that has the current svgElement so we can get the height from it\n * @returns - the code with the iFrame that now contains the svgCode\n * TODO replace btoa(). Replace with buf.toString('base64')?\n */\nexport const putIntoIFrame = (svgCode = '', svgElement?: D3Element): string => {\n const height = svgElement?.viewBox?.baseVal?.height\n ? svgElement.viewBox.baseVal.height + 'px'\n : IFRAME_HEIGHT;\n const base64encodedSrc = btoa('<body style=\"' + IFRAME_BODY_STYLE + '\">' + svgCode + '</body>');\n return `<iframe style=\"width:${IFRAME_WIDTH};height:${height};${IFRAME_STYLES}\" src=\"data:text/html;base64,${base64encodedSrc}\" sandbox=\"${IFRAME_SANDBOX_OPTS}\">\n ${IFRAME_NOT_SUPPORTED_MSG}\n</iframe>`;\n};\n\n/**\n * Append an enclosing div, then svg, then g (group) to the d3 parentRoot. Set attributes.\n * Only set the style attribute on the enclosing div if divStyle is given.\n * Only set the xmlns:xlink attribute on svg if svgXlink is given.\n * Return the last node appended\n *\n * @param parentRoot - the d3 node to append things to\n * @param id - the value to set the id attr to\n * @param enclosingDivId - the id to set the enclosing div to\n * @param divStyle - if given, the style to set the enclosing div to\n * @param svgXlink - if given, the link to set the new svg element to\n * @returns - returns the parentRoot that had nodes appended\n */\nexport const appendDivSvgG = (\n parentRoot: D3Element,\n id: string,\n enclosingDivId: string,\n divStyle?: string,\n svgXlink?: string\n): D3Element => {\n const enclosingDiv = parentRoot.append('div');\n enclosingDiv.attr('id', enclosingDivId);\n if (divStyle) {\n enclosingDiv.attr('style', divStyle);\n }\n\n const svgNode = enclosingDiv\n .append('svg')\n .attr('id', id)\n .attr('width', '100%')\n .attr('xmlns', XMLNS_SVG_STD);\n if (svgXlink) {\n svgNode.attr('xmlns:xlink', svgXlink);\n }\n\n svgNode.append('g');\n return parentRoot;\n};\n\n/**\n * Append an iFrame node to the given parentNode and set the id, style, and 'sandbox' attributes\n * Return the appended iframe d3 node\n *\n * @param parentNode - the d3 node to append the iFrame node to\n * @param iFrameId - id to use for the iFrame\n * @returns the appended iframe d3 node\n */\nfunction sandboxedIframe(parentNode: D3Element, iFrameId: string): D3Element {\n return parentNode\n .append('iframe')\n .attr('id', iFrameId)\n .attr('style', 'width: 100%; height: 100%;')\n .attr('sandbox', '');\n}\n\n/**\n * Remove any existing elements from the given document\n *\n * @param doc - the document to removed elements from\n * @param id - id for any existing SVG element\n * @param divSelector - selector for any existing enclosing div element\n * @param iFrameSelector - selector for any existing iFrame element\n */\nexport const removeExistingElements = (\n doc: Document,\n id: string,\n divId: string,\n iFrameId: string\n) => {\n // Remove existing SVG element if it exists\n doc.getElementById(id)?.remove();\n // Remove previous temporary element if it exists\n // Both div and iframe needs to be cleared in case there is a config change happening between renders.\n doc.getElementById(divId)?.remove();\n doc.getElementById(iFrameId)?.remove();\n};\n\n/**\n * @deprecated - use the `mermaid.render` function instead of `mermaid.mermaidAPI.render`\n *\n * Deprecated for external use.\n */\n\nconst render = async function (\n id: string,\n text: string,\n svgContainingElement?: Element\n): Promise<RenderResult> {\n addDiagrams();\n\n const processed = processAndSetConfigs(text);\n text = processed.code;\n\n const config = configApi.getConfig();\n log.debug(config);\n\n // Check the maximum allowed text size\n if (text.length > (config?.maxTextSize ?? MAX_TEXTLENGTH)) {\n text = MAX_TEXTLENGTH_EXCEEDED_MSG;\n }\n\n const idSelector = '#' + id;\n const iFrameID = 'i' + id;\n const iFrameID_selector = '#' + iFrameID;\n const enclosingDivID = 'd' + id;\n const enclosingDivID_selector = '#' + enclosingDivID;\n\n const removeTempElements = () => {\n // -------------------------------------------------------------------------------\n // Remove the temporary HTML element if appropriate\n const tmpElementSelector = isSandboxed ? iFrameID_selector : enclosingDivID_selector;\n const node = select(tmpElementSelector).node();\n if (node && 'remove' in node) {\n node.remove();\n }\n };\n\n let root: any = select('body');\n\n const isSandboxed = config.securityLevel === SECURITY_LVL_SANDBOX;\n const isLooseSecurityLevel = config.securityLevel === SECURITY_LVL_LOOSE;\n\n const fontFamily = config.fontFamily;\n\n // -------------------------------------------------------------------------------\n // Define the root d3 node\n // In regular execution the svgContainingElement will be the element with a mermaid class\n\n if (svgContainingElement !== undefined) {\n if (svgContainingElement) {\n svgContainingElement.innerHTML = '';\n }\n\n if (isSandboxed) {\n // If we are in sandboxed mode, we do everything mermaid related in a (sandboxed )iFrame\n const iframe = sandboxedIframe(select(svgContainingElement), iFrameID);\n root = select(iframe.nodes()[0]!.contentDocument!.body);\n root.node().style.margin = 0;\n } else {\n root = select(svgContainingElement);\n }\n appendDivSvgG(root, id, enclosingDivID, `font-family: ${fontFamily}`, XMLNS_XLINK_STD);\n } else {\n // No svgContainingElement was provided\n\n // If there is an existing element with the id, we remove it. This likely a previously rendered diagram\n removeExistingElements(document, id, enclosingDivID, iFrameID);\n\n // Add the temporary div used for rendering with the enclosingDivID.\n // This temporary div will contain a svg with the id == id\n\n if (isSandboxed) {\n // If we are in sandboxed mode, we do everything mermaid related in a (sandboxed) iFrame\n const iframe = sandboxedIframe(select('body'), iFrameID);\n root = select(iframe.nodes()[0]!.contentDocument!.body);\n root.node().style.margin = 0;\n } else {\n root = select('body');\n }\n\n appendDivSvgG(root, id, enclosingDivID);\n }\n\n // -------------------------------------------------------------------------------\n // Create the diagram\n\n // Important that we do not create the diagram until after the directives have been included\n let diag: Diagram;\n let parseEncounteredException;\n\n try {\n diag = await Diagram.fromText(text, { title: processed.title });\n } catch (error) {\n if (config.suppressErrorRendering) {\n removeTempElements();\n throw error;\n }\n diag = await Diagram.fromText('error');\n parseEncounteredException = error;\n }\n\n // Get the temporary div element containing the svg\n const element = root.select(enclosingDivID_selector).node();\n const diagramType = diag.type;\n\n // -------------------------------------------------------------------------------\n // Create and insert the styles (user styles, theme styles, config styles)\n\n // Insert an element into svg. This is where we put the styles\n const svg = element.firstChild;\n const firstChild = svg.firstChild;\n const diagramClassDefs = diag.renderer.getClasses?.(text, diag);\n\n const rules = createUserStyles(config, diagramType, diagramClassDefs, idSelector);\n\n const style1 = document.createElement('style');\n style1.innerHTML = rules;\n svg.insertBefore(style1, firstChild);\n\n // -------------------------------------------------------------------------------\n // Draw the diagram with the renderer\n let data = null;\n try {\n data = await diag.renderer.draw(text, id, version, diag);\n } catch (e) {\n if (config.suppressErrorRendering) {\n removeTempElements();\n } else {\n errorRenderer.draw(text, id, version);\n }\n throw e;\n }\n\n // This is the d3 node for the svg element\n const svgNode = root.select(`${enclosingDivID_selector} svg`);\n const a11yTitle: string | undefined = diag.db.getAccTitle?.();\n const a11yDescr: string | undefined = diag.db.getAccDescription?.();\n addA11yInfo(diagramType, svgNode, a11yTitle, a11yDescr);\n // -------------------------------------------------------------------------------\n // Clean up SVG code\n root.select(`[id=\"${id}\"]`).selectAll('foreignobject > *').attr('xmlns', XMLNS_XHTML_STD);\n\n // Fix for when the base tag is used\n let svgCode: string = root.select(enclosingDivID_selector).node().innerHTML;\n\n log.debug('config.arrowMarkerAbsolute', config.arrowMarkerAbsolute);\n svgCode = cleanUpSvgCode(svgCode, isSandboxed, evaluate(config.arrowMarkerAbsolute));\n\n if (isSandboxed) {\n const svgEl = root.select(enclosingDivID_selector + ' svg').node();\n svgCode = putIntoIFrame(svgCode, svgEl);\n } else if (!isLooseSecurityLevel) {\n // Sanitize the svgCode using DOMPurify\n svgCode = DOMPurify.sanitize(svgCode, {\n ADD_TAGS: DOMPURIFY_TAGS,\n ADD_ATTR: DOMPURIFY_ATTR,\n });\n }\n\n attachFunctions();\n\n if (parseEncounteredException) {\n throw parseEncounteredException;\n }\n\n removeTempElements();\n\n return {\n diagramType,\n svg: svgCode,\n bindFunctions: diag.db.bindFunctions,\n data,\n };\n};\n\n/**\n * @param options - Initial Mermaid options\n */\nfunction initialize(options: MermaidConfig = {}) {\n // Handle legacy location of font-family configuration\n if (options?.fontFamily && !options.themeVariables?.fontFamily) {\n if (!options.themeVariables) {\n options.themeVariables = {};\n }\n options.themeVariables.fontFamily = options.fontFamily;\n }\n\n // Set default options\n configApi.saveConfigFromInitialize(options);\n\n if (options?.theme && options.theme in theme) {\n // Todo merge with user options\n options.themeVariables = theme[options.theme as keyof typeof theme].getThemeVariables(\n options.themeVariables\n );\n } else if (options) {\n options.themeVariables = theme.default.getThemeVariables(options.themeVariables);\n }\n\n const config =\n typeof options === 'object' ? configApi.setSiteConfig(options) : configApi.getSiteConfig();\n\n setLogLevel(config.logLevel);\n addDiagrams();\n}\n\nconst getDiagramFromText = (text: string, metadata: Pick<DiagramMetadata, 'title'> = {}) => {\n const { code } = preprocessDiagram(text);\n return Diagram.fromText(code, metadata);\n};\n\n/**\n * Add accessibility (a11y) information to the diagram.\n *\n * @param diagramType - diagram type\n * @param svgNode - d3 node to insert the a11y title and desc info\n * @param a11yTitle - a11y title\n * @param a11yDescr - a11y description\n */\nfunction addA11yInfo(\n diagramType: string,\n svgNode: D3Element,\n a11yTitle?: string,\n a11yDescr?: string\n): void {\n setA11yDiagramInfo(svgNode, diagramType);\n addSVGa11yTitleDescription(svgNode, a11yTitle, a11yDescr, svgNode.attr('id'));\n}\n\n/**\n * ## mermaidAPI configuration defaults\n *\n * ```ts\n * const config = {\n * theme: 'default',\n * logLevel: 'fatal',\n * securityLevel: 'strict',\n * startOnLoad: true,\n * arrowMarkerAbsolute: false,\n * suppressErrorRendering: false,\n *\n * er: {\n * diagramPadding: 20,\n * layoutDirection: 'TB',\n * minEntityWidth: 100,\n * minEntityHeight: 75,\n * entityPadding: 15,\n * stroke: 'gray',\n * fill: 'honeydew',\n * fontSize: 12,\n * useMaxWidth: true,\n * },\n * flowchart: {\n * diagramPadding: 8,\n * htmlLabels: true,\n * curve: 'basis',\n * },\n * sequence: {\n * diagramMarginX: 50,\n * diagramMarginY: 10,\n * actorMargin: 50,\n * width: 150,\n * height: 65,\n * boxMargin: 10,\n * boxTextMargin: 5,\n * noteMargin: 10,\n * messageMargin: 35,\n * messageAlign: 'center',\n * mirrorActors: true,\n * bottomMarginAdj: 1,\n * useMaxWidth: true,\n * rightAngles: false,\n * showSequenceNumbers: false,\n * },\n * gantt: {\n * titleTopMargin: 25,\n * barHeight: 20,\n * barGap: 4,\n * topPadding: 50,\n * leftPadding: 75,\n * gridLineStartPadding: 35,\n * fontSize: 11,\n * fontFamily: '\"Open Sans\", sans-serif',\n * numberSectionStyles: 4,\n * axisFormat: '%Y-%m-%d',\n * topAxis: false,\n * displayMode: '',\n * },\n * };\n * mermaid.initialize(config);\n * ```\n */\n\nexport const mermaidAPI = Object.freeze({\n render,\n parse,\n getDiagramFromText,\n initialize,\n getConfig: configApi.getConfig,\n setConfig: configApi.setConfig,\n getSiteConfig: configApi.getSiteConfig,\n updateSiteConfig: configApi.updateSiteConfig,\n reset: () => {\n configApi.reset();\n },\n globalReset: () => {\n configApi.reset(configApi.defaultConfig);\n },\n defaultConfig: configApi.defaultConfig,\n});\n\nsetLogLevel(configApi.getConfig().logLevel);\nconfigApi.reset(configApi.getConfig());\nexport default mermaidAPI;\n", "import type {\n DiagramDetector,\n DiagramLoader,\n ExternalDiagramDefinition,\n} from '../../diagram-api/types.js';\n\nconst id = 'c4';\n\nconst detector: DiagramDetector = (txt) => {\n return /^\\s*C4Context|C4Container|C4Component|C4Dynamic|C4Deployment/.test(txt);\n};\n\nconst loader: DiagramLoader = async () => {\n const { diagram } = await import('./c4Diagram.js');\n return { id, diagram };\n};\n\nconst plugin: ExternalDiagramDefinition = {\n id,\n detector,\n loader,\n};\n\nexport default plugin;\n", "import type {\n DiagramDetector,\n DiagramLoader,\n ExternalDiagramDefinition,\n} from '../../diagram-api/types.js';\n\nconst id = 'flowchart';\n\nconst detector: DiagramDetector = (txt, config) => {\n // If we have conferred to only use new flow charts this function should always return false\n // as in not signalling true for a legacy flowchart\n if (\n config?.flowchart?.defaultRenderer === 'dagre-wrapper' ||\n config?.flowchart?.defaultRenderer === 'elk'\n ) {\n return false;\n }\n return /^\\s*graph/.test(txt);\n};\n\nconst loader: DiagramLoader = async () => {\n const { diagram } = await import('./flowDiagram.js');\n return { id, diagram };\n};\n\nconst plugin: ExternalDiagramDefinition = {\n id,\n detector,\n loader,\n};\n\nexport default plugin;\n", "import type { DiagramDetector, DiagramLoader } from '../../diagram-api/types.js';\nimport type { ExternalDiagramDefinition } from '../../diagram-api/types.js';\n\nconst id = 'flowchart-v2';\n\nconst detector: DiagramDetector = (txt, config) => {\n if (\n config?.flowchart?.defaultRenderer === 'dagre-d3' ||\n config?.flowchart?.defaultRenderer === 'elk'\n ) {\n return false;\n }\n\n // If we have configured to use dagre-wrapper then we should return true in this function for graph code thus making it use the new flowchart diagram\n if (/^\\s*graph/.test(txt) && config?.flowchart?.defaultRenderer === 'dagre-wrapper') {\n return true;\n }\n return /^\\s*flowchart/.test(txt);\n};\n\nconst loader: DiagramLoader = async () => {\n const { diagram } = await import('./flowDiagram-v2.js');\n return { id, diagram };\n};\n\nconst plugin: ExternalDiagramDefinition = {\n id,\n detector,\n loader,\n};\n\nexport default plugin;\n", "import type {\n DiagramDetector,\n DiagramLoader,\n ExternalDiagramDefinition,\n} from '../../diagram-api/types.js';\n\nconst id = 'er';\n\nconst detector: DiagramDetector = (txt) => {\n return /^\\s*erDiagram/.test(txt);\n};\n\nconst loader: DiagramLoader = async () => {\n const { diagram } = await import('./erDiagram.js');\n return { id, diagram };\n};\n\nconst plugin: ExternalDiagramDefinition = {\n id,\n detector,\n loader,\n};\n\nexport default plugin;\n", "import type { DiagramDetector, DiagramLoader } from '../../diagram-api/types.js';\nimport type { ExternalDiagramDefinition } from '../../diagram-api/types.js';\n\nconst id = 'gitGraph';\n\nconst detector: DiagramDetector = (txt) => {\n return /^\\s*gitGraph/.test(txt);\n};\n\nconst loader: DiagramLoader = async () => {\n const { diagram } = await import('./gitGraphDiagram.js');\n return { id, diagram };\n};\n\nconst plugin: ExternalDiagramDefinition = {\n id,\n detector,\n loader,\n};\n\nexport default plugin;\n", "import type {\n DiagramDetector,\n DiagramLoader,\n ExternalDiagramDefinition,\n} from '../../diagram-api/types.js';\n\nconst id = 'gantt';\n\nconst detector: DiagramDetector = (txt) => {\n return /^\\s*gantt/.test(txt);\n};\n\nconst loader: DiagramLoader = async () => {\n const { diagram } = await import('./ganttDiagram.js');\n return { id, diagram };\n};\n\nconst plugin: ExternalDiagramDefinition = {\n id,\n detector,\n loader,\n};\n\nexport default plugin;\n", "import type {\n DiagramDetector,\n DiagramLoader,\n ExternalDiagramDefinition,\n} from '../../diagram-api/types.js';\n\nconst id = 'info';\n\nconst detector: DiagramDetector = (txt) => {\n return /^\\s*info/.test(txt);\n};\n\nconst loader: DiagramLoader = async () => {\n const { diagram } = await import('./infoDiagram.js');\n return { id, diagram };\n};\n\nexport const info: ExternalDiagramDefinition = {\n id,\n detector,\n loader,\n};\n", "import type {\n DiagramDetector,\n DiagramLoader,\n ExternalDiagramDefinition,\n} from '../../diagram-api/types.js';\n\nconst id = 'pie';\n\nconst detector: DiagramDetector = (txt) => {\n return /^\\s*pie/.test(txt);\n};\n\nconst loader: DiagramLoader = async () => {\n const { diagram } = await import('./pieDiagram.js');\n return { id, diagram };\n};\n\nexport const pie: ExternalDiagramDefinition = {\n id,\n detector,\n loader,\n};\n", "import type {\n DiagramDetector,\n DiagramLoader,\n ExternalDiagramDefinition,\n} from '../../diagram-api/types.js';\n\nconst id = 'quadrantChart';\n\nconst detector: DiagramDetector = (txt) => {\n return /^\\s*quadrantChart/.test(txt);\n};\n\nconst loader: DiagramLoader = async () => {\n const { diagram } = await import('./quadrantDiagram.js');\n return { id, diagram };\n};\n\nconst plugin: ExternalDiagramDefinition = {\n id,\n detector,\n loader,\n};\n\nexport default plugin;\n", "import type {\n DiagramDetector,\n DiagramLoader,\n ExternalDiagramDefinition,\n} from '../../diagram-api/types.js';\n\nconst id = 'xychart';\n\nconst detector: DiagramDetector = (txt) => {\n return /^\\s*xychart-beta/.test(txt);\n};\n\nconst loader: DiagramLoader = async () => {\n const { diagram } = await import('./xychartDiagram.js');\n return { id, diagram };\n};\n\nconst plugin: ExternalDiagramDefinition = {\n id,\n detector,\n loader,\n};\n\nexport default plugin;\n", "import type {\n DiagramDetector,\n DiagramLoader,\n ExternalDiagramDefinition,\n} from '../../diagram-api/types.js';\n\nconst id = 'requirement';\n\nconst detector: DiagramDetector = (txt) => {\n return /^\\s*requirement(Diagram)?/.test(txt);\n};\n\nconst loader: DiagramLoader = async () => {\n const { diagram } = await import('./requirementDiagram.js');\n return { id, diagram };\n};\n\nconst plugin: ExternalDiagramDefinition = {\n id,\n detector,\n loader,\n};\n\nexport default plugin;\n", "import type {\n DiagramDetector,\n DiagramLoader,\n ExternalDiagramDefinition,\n} from '../../diagram-api/types.js';\n\nconst id = 'sequence';\n\nconst detector: DiagramDetector = (txt) => {\n return /^\\s*sequenceDiagram/.test(txt);\n};\n\nconst loader: DiagramLoader = async () => {\n const { diagram } = await import('./sequenceDiagram.js');\n return { id, diagram };\n};\n\nconst plugin: ExternalDiagramDefinition = {\n id,\n detector,\n loader,\n};\n\nexport default plugin;\n", "import type {\n DiagramDetector,\n DiagramLoader,\n ExternalDiagramDefinition,\n} from '../../diagram-api/types.js';\n\nconst id = 'class';\n\nconst detector: DiagramDetector = (txt, config) => {\n // If we have configured to use dagre-wrapper then we should never return true in this function\n if (config?.class?.defaultRenderer === 'dagre-wrapper') {\n return false;\n }\n // We have not opted to use the new renderer so we should return true if we detect a class diagram\n return /^\\s*classDiagram/.test(txt);\n};\n\nconst loader: DiagramLoader = async () => {\n const { diagram } = await import('./classDiagram.js');\n return { id, diagram };\n};\n\nconst plugin: ExternalDiagramDefinition = {\n id,\n detector,\n loader,\n};\n\nexport default plugin;\n", "import type {\n DiagramDetector,\n DiagramLoader,\n ExternalDiagramDefinition,\n} from '../../diagram-api/types.js';\n\nconst id = 'classDiagram';\n\nconst detector: DiagramDetector = (txt, config) => {\n // If we have configured to use dagre-wrapper then we should return true in this function for classDiagram code thus making it use the new class diagram\n if (/^\\s*classDiagram/.test(txt) && config?.class?.defaultRenderer === 'dagre-wrapper') {\n return true;\n }\n // We have not opted to use the new renderer so we should return true if we detect a class diagram\n return /^\\s*classDiagram-v2/.test(txt);\n};\n\nconst loader: DiagramLoader = async () => {\n const { diagram } = await import('./classDiagram-v2.js');\n return { id, diagram };\n};\n\nconst plugin: ExternalDiagramDefinition = {\n id,\n detector,\n loader,\n};\n\nexport default plugin;\n", "import type {\n DiagramDetector,\n DiagramLoader,\n ExternalDiagramDefinition,\n} from '../../diagram-api/types.js';\n\nconst id = 'state';\n\nconst detector: DiagramDetector = (txt, config) => {\n // If we have confirmed to only use new state diagrams this function should always return false\n // as in not signalling true for a legacy state diagram\n if (config?.state?.defaultRenderer === 'dagre-wrapper') {\n return false;\n }\n return /^\\s*stateDiagram/.test(txt);\n};\n\nconst loader: DiagramLoader = async () => {\n const { diagram } = await import('./stateDiagram.js');\n return { id, diagram };\n};\n\nconst plugin: ExternalDiagramDefinition = {\n id,\n detector,\n loader,\n};\n\nexport default plugin;\n", "import type {\n DiagramDetector,\n DiagramLoader,\n ExternalDiagramDefinition,\n} from '../../diagram-api/types.js';\n\nconst id = 'stateDiagram';\n\nconst detector: DiagramDetector = (txt, config) => {\n if (/^\\s*stateDiagram-v2/.test(txt)) {\n return true;\n }\n if (/^\\s*stateDiagram/.test(txt) && config?.state?.defaultRenderer === 'dagre-wrapper') {\n return true;\n }\n return false;\n};\n\nconst loader: DiagramLoader = async () => {\n const { diagram } = await import('./stateDiagram-v2.js');\n return { id, diagram };\n};\n\nconst plugin: ExternalDiagramDefinition = {\n id,\n detector,\n loader,\n};\n\nexport default plugin;\n", "import type {\n DiagramDetector,\n DiagramLoader,\n ExternalDiagramDefinition,\n} from '../../diagram-api/types.js';\n\nconst id = 'journey';\n\nconst detector: DiagramDetector = (txt) => {\n return /^\\s*journey/.test(txt);\n};\n\nconst loader: DiagramLoader = async () => {\n const { diagram } = await import('./journeyDiagram.js');\n return { id, diagram };\n};\n\nconst plugin: ExternalDiagramDefinition = {\n id,\n detector,\n loader,\n};\n\nexport default plugin;\n", "import { log } from '../../logger.js';\nimport type { Group, SVG } from '../../diagram-api/types.js';\nimport { selectSvgElement } from '../../rendering-util/selectSvgElement.js';\nimport { configureSvgSize } from '../../setupGraphViewbox.js';\n\n/**\n * Draws an info picture in the tag with id: id based on the graph definition in text.\n *\n * @param _text - Mermaid graph definition.\n * @param id - The text for the error\n * @param version - The version\n */\nexport const draw = (_text: string, id: string, version: string) => {\n log.debug('rendering svg for syntax error\\n');\n const svg: SVG = selectSvgElement(id);\n const g: Group = svg.append('g');\n\n svg.attr('viewBox', '0 0 2412 512');\n configureSvgSize(svg, 100, 512, true);\n\n g.append('path')\n .attr('class', 'error-icon')\n .attr(\n 'd',\n 'm411.313,123.313c6.25-6.25 6.25-16.375 0-22.625s-16.375-6.25-22.625,0l-32,32-9.375,9.375-20.688-20.688c-12.484-12.5-32.766-12.5-45.25,0l-16,16c-1.261,1.261-2.304,2.648-3.31,4.051-21.739-8.561-45.324-13.426-70.065-13.426-105.867,0-192,86.133-192,192s86.133,192 192,192 192-86.133 192-192c0-24.741-4.864-48.327-13.426-70.065 1.402-1.007 2.79-2.049 4.051-3.31l16-16c12.5-12.492 12.5-32.758 0-45.25l-20.688-20.688 9.375-9.375 32.001-31.999zm-219.313,100.687c-52.938,0-96,43.063-96,96 0,8.836-7.164,16-16,16s-16-7.164-16-16c0-70.578 57.422-128 128-128 8.836,0 16,7.164 16,16s-7.164,16-16,16z'\n );\n\n g.append('path')\n .attr('class', 'error-icon')\n .attr(\n 'd',\n 'm459.02,148.98c-6.25-6.25-16.375-6.25-22.625,0s-6.25,16.375 0,22.625l16,16c3.125,3.125 7.219,4.688 11.313,4.688 4.094,0 8.188-1.563 11.313-4.688 6.25-6.25 6.25-16.375 0-22.625l-16.001-16z'\n );\n\n g.append('path')\n .attr('class', 'error-icon')\n .attr(\n 'd',\n 'm340.395,75.605c3.125,3.125 7.219,4.