diff --git a/packages/mermaid/src/diagrams/common/common.ts b/packages/mermaid/src/diagrams/common/common.ts index 04be2a5f4..60f8bc439 100644 --- a/packages/mermaid/src/diagrams/common/common.ts +++ b/packages/mermaid/src/diagrams/common/common.ts @@ -311,9 +311,8 @@ export const hasKatex = (text: string): boolean => (text.match(katexRegex)?.leng * @returns Object containing \{width, height\} */ export const calculateMathMLDimensions = async (text: string, config: MermaidConfig) => { - text = await renderKatex(text, config); const divElem = document.createElement('div'); - divElem.innerHTML = text; + divElem.innerHTML = await renderKatexSanitized(text, config); divElem.id = 'katex-temp'; divElem.style.visibility = 'hidden'; divElem.style.position = 'absolute'; @@ -325,14 +324,7 @@ export const calculateMathMLDimensions = async (text: string, config: MermaidCon return dim; }; -/** - * Attempts to render and return the KaTeX portion of a string with MathML - * - * @param text - The text to test - * @param config - Configuration for Mermaid - * @returns String containing MathML if KaTeX is supported, or an error message if it is not and stylesheets aren't present - */ -export const renderKatex = async (text: string, config: MermaidConfig): Promise => { +const renderKatexUnsanitized = async (text: string, config: MermaidConfig): Promise => { if (!hasKatex(text)) { return text; } @@ -366,6 +358,20 @@ export const renderKatex = async (text: string, config: MermaidConfig): Promise< ); }; +/** + * Attempts to render and return the KaTeX portion of a string with MathML + * + * @param text - The text to test + * @param config - Configuration for Mermaid + * @returns String containing MathML if KaTeX is supported, or an error message if it is not and stylesheets aren't present + */ +export const renderKatexSanitized = async ( + text: string, + config: MermaidConfig +): Promise => { + return sanitizeText(await renderKatexUnsanitized(text, config), config); +}; + export default { getRows, sanitizeText, diff --git a/packages/mermaid/src/diagrams/flowchart/flowRenderer-v2.js b/packages/mermaid/src/diagrams/flowchart/flowRenderer-v2.js index f27d8e353..e63e0e241 100644 --- a/packages/mermaid/src/diagrams/flowchart/flowRenderer-v2.js +++ b/packages/mermaid/src/diagrams/flowchart/flowRenderer-v2.js @@ -1,13 +1,12 @@ -import * as graphlib from 'dagre-d3-es/src/graphlib/index.js'; -import { select, curveLinear, selectAll } from 'd3'; -import { getConfig } from '../../diagram-api/diagramAPI.js'; -import utils from '../../utils.js'; -import { render } from '../../dagre-wrapper/index.js'; +import { curveLinear, select, selectAll } from 'd3'; import { addHtmlLabel } from 'dagre-d3-es/src/dagre-js/label/add-html-label.js'; +import * as graphlib from 'dagre-d3-es/src/graphlib/index.js'; +import { render } from '../../dagre-wrapper/index.js'; +import { getConfig } from '../../diagram-api/diagramAPI.js'; import { log } from '../../logger.js'; -import common, { evaluate, renderKatex } from '../common/common.js'; -import { interpolateToCurve, getStylesFromArray } from '../../utils.js'; import { setupGraphViewbox } from '../../setupGraphViewbox.js'; +import utils, { getStylesFromArray, interpolateToCurve } from '../../utils.js'; +import common, { evaluate, renderKatexSanitized } from '../common/common.js'; const conf = {}; export const setConf = function (cnf) { @@ -140,7 +139,7 @@ export const addVertices = async function (vert, g, svgId, root, doc, diagObj) { default: _shape = 'rect'; } - const labelText = await renderKatex(vertexText, getConfig()); + const labelText = await renderKatexSanitized(vertexText, getConfig()); // Add the node g.setNode(vertex.id, { @@ -315,7 +314,10 @@ export const addEdges = async function (edges, g, diagObj) { edgeData.labelpos = 'c'; } edgeData.labelType = edge.labelType; - edgeData.label = await renderKatex(edge.text.replace(common.lineBreakRegex, '\n'), getConfig()); + edgeData.label = await renderKatexSanitized( + edge.text.replace(common.lineBreakRegex, '\n'), + getConfig() + ); if (edge.style === undefined) { edgeData.style = edgeData.style || 'stroke: #333; stroke-width: 1.5px;fill:none;'; diff --git a/packages/mermaid/src/diagrams/flowchart/flowRenderer.js b/packages/mermaid/src/diagrams/flowchart/flowRenderer.js index c9e152012..e0f25f17a 100644 --- a/packages/mermaid/src/diagrams/flowchart/flowRenderer.js +++ b/packages/mermaid/src/diagrams/flowchart/flowRenderer.js @@ -1,13 +1,13 @@ -import * as graphlib from 'dagre-d3-es/src/graphlib/index.js'; -import { select, curveLinear, selectAll } from 'd3'; -import { getConfig } from '../../diagram-api/diagramAPI.js'; +import { curveLinear, select, selectAll } from 'd3'; import { render as Render } from 'dagre-d3-es'; -import { applyStyle } from 'dagre-d3-es/src/dagre-js/util.js'; import { addHtmlLabel } from 'dagre-d3-es/src/dagre-js/label/add-html-label.js'; +import { applyStyle } from 'dagre-d3-es/src/dagre-js/util.js'; +import * as graphlib from 'dagre-d3-es/src/graphlib/index.js'; +import { getConfig } from '../../diagram-api/diagramAPI.js'; import { log } from '../../logger.js'; -import common, { evaluate, renderKatex } from '../common/common.js'; -import { interpolateToCurve, getStylesFromArray } from '../../utils.js'; import { setupGraphViewbox } from '../../setupGraphViewbox.js'; +import { getStylesFromArray, interpolateToCurve } from '../../utils.js'; +import common, { evaluate, renderKatexSanitized } from '../common/common.js'; import flowChartShapes from './flowChartShapes.js'; const conf = {}; @@ -57,7 +57,7 @@ export const addVertices = async function (vert, g, svgId, root, _doc, diagObj) if (evaluate(getConfig().flowchart.htmlLabels)) { // TODO: addHtmlLabel accepts a labelStyle. Do we possibly have that? const node = { - label: await renderKatex( + label: await renderKatexSanitized( vertexText.replace( /fa[blrs]?:fa-[\w-]+/g, // cspell:disable-line (s) => `` @@ -242,7 +242,7 @@ export const addEdges = async function (edges, g, diagObj) { edgeData.labelType = 'html'; edgeData.label = `${await renderKatex( + }">${await renderKatexSanitized( edge.text.replace( /fa[blrs]?:fa-[\w-]+/g, // cspell:disable-line (s) => `` diff --git a/packages/mermaid/src/diagrams/sequence/svgDraw.js b/packages/mermaid/src/diagrams/sequence/svgDraw.js index 17842b092..72467c0cb 100644 --- a/packages/mermaid/src/diagrams/sequence/svgDraw.js +++ b/packages/mermaid/src/diagrams/sequence/svgDraw.js @@ -1,9 +1,12 @@ -import common, { calculateMathMLDimensions, hasKatex, renderKatex } from '../common/common.js'; -import * as svgDrawCommon from '../common/svgDrawCommon.js'; -import { addFunction } from '../../interactionDb.js'; -import { ZERO_WIDTH_SPACE, parseFontSize } from '../../utils.js'; import { sanitizeUrl } from '@braintree/sanitize-url'; import * as configApi from '../../config.js'; +import { ZERO_WIDTH_SPACE, parseFontSize } from '../../utils.js'; +import common, { + calculateMathMLDimensions, + hasKatex, + renderKatexSanitized, +} from '../common/common.js'; +import * as svgDrawCommon from '../common/svgDrawCommon.js'; export const ACTOR_TYPE_WIDTH = 18 * 2; const TOP_ACTOR_CLASS = 'actor-top'; @@ -86,13 +89,13 @@ const popupMenuToggle = function (popId) { export const drawKatex = async function (elem, textData, msgModel = null) { let textElem = elem.append('foreignObject'); - const lines = await renderKatex(textData.text, configApi.getConfig()); + const linesSanitized = await renderKatexSanitized(textData.text, configApi.getConfig()); const divElem = textElem .append('xhtml:div') .attr('style', 'width: fit-content;') .attr('xmlns', 'http://www.w3.org/1999/xhtml') - .html(lines); + .html(linesSanitized); const dim = divElem.node().getBoundingClientRect(); textElem.attr('height', Math.round(dim.height)).attr('width', Math.round(dim.width)); @@ -963,7 +966,7 @@ const _drawTextCandidateFunc = (function () { .append('div') .style('text-align', 'center') .style('vertical-align', 'middle') - .html(await renderKatex(content, configApi.getConfig())); + .html(await renderKatexSanitized(content, configApi.getConfig())); byTspan(content, s, x, y, width, height, textAttrs, conf); _setTextAttrs(text, textAttrs); diff --git a/packages/mermaid/src/rendering-util/createText.ts b/packages/mermaid/src/rendering-util/createText.ts index 20efc2f74..a965e6aa7 100644 --- a/packages/mermaid/src/rendering-util/createText.ts +++ b/packages/mermaid/src/rendering-util/createText.ts @@ -1,6 +1,8 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ // @ts-nocheck TODO: Fix types +import { getConfig } from '../config.js'; import type { Group } from '../diagram-api/types.js'; +import { sanitizeText } from '../diagrams/common/common.js'; import type { D3TSpanElement, D3TextElement } from '../diagrams/common/commonTypes.js'; import { log } from '../logger.js'; import { markdownToHTML, markdownToLines } from '../rendering-util/handle-markdown-text.js'; @@ -21,12 +23,15 @@ function addHtmlSpan(element, node, width, classes, addBackground = false) { const label = node.label; const labelClass = node.isNode ? 'nodeLabel' : 'edgeLabel'; div.html( - ` + sanitizeText( + ` ' + - label + - '' + (node.labelStyle ? 'style="' + node.labelStyle + '"' : '') + + '>' + + label + + '', + getConfig() + ) ); applyStyle(div, node.labelStyle);