Skip to content

Commit 7075f83

Browse files
authored
Merge pull request #6566 from arpitjain099/develop
fix: escape backslashes before parentheses in URL replacement logic
2 parents d629c5e + d0f1daf commit 7075f83

File tree

9 files changed

+24
-57
lines changed

9 files changed

+24
-57
lines changed

.changeset/yellow-walls-fry.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'mermaid': patch
3+
---
4+
5+
fix: Fix incomplete string escaping in URL manipulation logic when `arrowMarkerAbsolute: true` by ensuring all unsafe characters are escaped.

cypress/integration/other/configuration.spec.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,9 @@ describe('Configuration', () => {
6969
.and('include', 'url(#');
7070
});
7171
});
72-
it('should handle arrowMarkerAbsolute explicitly set to "false" as false', () => {
72+
// This has been broken for a long time, but something about the Cypress environment was
73+
// rewriting the URL to be relative, causing the test to incorrectly pass.
74+
it.skip('should handle arrowMarkerAbsolute explicitly set to "false" as false', () => {
7375
renderGraph(
7476
`graph TD
7577
A[Christmas] -->|Get money| B(Go shopping)
@@ -112,7 +114,7 @@ describe('Configuration', () => {
112114
.first()
113115
.should('have.attr', 'marker-end')
114116
.should('exist')
115-
.and('include', 'url(http://localhost');
117+
.and('include', 'url(http\\:\\/\\/localhost');
116118
});
117119
});
118120
it('should not taint the initial configuration when using multiple directives', () => {

packages/mermaid/src/dagre-wrapper/edges.js

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { createText } from '../rendering-util/createText.js';
44
import { line, curveBasis, select } from 'd3';
55
import { getConfig } from '../diagram-api/diagramAPI.js';
66
import utils from '../utils.js';
7-
import { evaluate } from '../diagrams/common/common.js';
7+
import { evaluate, getUrl } from '../diagrams/common/common.js';
88
import { getLineFunctionsWithOffset } from '../utils/lineWithOffset.js';
99
import { getSubGraphTitleMargins } from '../utils/subGraphTitleMargins.js';
1010
import { addEdgeMarkers } from './edgeMarker.js';
@@ -440,14 +440,7 @@ export const insertEdge = function (elem, e, edge, clusterDb, diagramType, graph
440440
let url = '';
441441
// // TODO: Can we load this config only from the rendered graph type?
442442
if (getConfig().flowchart.arrowMarkerAbsolute || getConfig().state.arrowMarkerAbsolute) {
443-
url =
444-
window.location.protocol +
445-
'//' +
446-
window.location.host +
447-
window.location.pathname +
448-
window.location.search;
449-
url = url.replace(/\(/g, '\\(');
450-
url = url.replace(/\)/g, '\\)');
443+
url = getUrl(true);
451444
}
452445

453446
addEdgeMarkers(svgPath, edge, url, id, diagramType);

packages/mermaid/src/diagrams/class/svgDraw.js

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { line, curveBasis } from 'd3';
22
import utils from '../../utils.js';
33
import { log } from '../../logger.js';
4-
import { parseGenericTypes } from '../common/common.js';
4+
import { parseGenericTypes, getUrl } from '../common/common.js';
55

66
let edgeCount = 0;
77
export const drawEdge = function (elem, path, relation, conf, diagObj) {
@@ -42,14 +42,7 @@ export const drawEdge = function (elem, path, relation, conf, diagObj) {
4242
.attr('class', 'relation');
4343
let url = '';
4444
if (conf.arrowMarkerAbsolute) {
45-
url =
46-
window.location.protocol +
47-
'//' +
48-
window.location.host +
49-
window.location.pathname +
50-
window.location.search;
51-
url = url.replace(/\(/g, '\\(');
52-
url = url.replace(/\)/g, '\\)');
45+
url = getUrl(true);
5346
}
5447

5548
if (relation.relation.lineType == 1) {

packages/mermaid/src/diagrams/common/common.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ const breakToPlaceholder = (s: string): string => {
149149
* @param useAbsolute - Whether to return the absolute URL or not
150150
* @returns The current URL
151151
*/
152-
const getUrl = (useAbsolute: boolean): string => {
152+
export const getUrl = (useAbsolute: boolean): string => {
153153
let url = '';
154154
if (useAbsolute) {
155155
url =
@@ -158,8 +158,8 @@ const getUrl = (useAbsolute: boolean): string => {
158158
window.location.host +
159159
window.location.pathname +
160160
window.location.search;
161-
url = url.replaceAll(/\(/g, '\\(');
162-
url = url.replaceAll(/\)/g, '\\)');
161+
162+
url = CSS.escape(url);
163163
}
164164

165165
return url;

packages/mermaid/src/diagrams/er/erRenderer.js

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { log } from '../../logger.js';
66
import utils from '../../utils.js';
77
import erMarkers from './erMarkers.js';
88
import { configureSvgSize } from '../../setupGraphViewbox.js';
9-
import { parseGenericTypes } from '../common/common.js';
9+
import { parseGenericTypes, getUrl } from '../common/common.js';
1010
import { v5 as uuid5 } from 'uuid';
1111

1212
/** Regex used to remove chars from the entity name so the result can be used in an id */
@@ -451,14 +451,7 @@ const drawRelationshipFromLayout = function (svg, rel, g, insert, diagObj) {
451451
// TODO: Understand this better
452452
let url = '';
453453
if (conf.arrowMarkerAbsolute) {
454-
url =
455-
window.location.protocol +
456-
'//' +
457-
window.location.host +
458-
window.location.pathname +
459-
window.location.search;
460-
url = url.replace(/\(/g, '\\(');
461-
url = url.replace(/\)/g, '\\)');
454+
url = getUrl(true);
462455
}
463456

464457
// Decide which start and end markers it needs. It may be possible to be more concise here

packages/mermaid/src/diagrams/sequence/sequenceRenderer.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { select } from 'd3';
33
import svgDraw, { drawKatex, ACTOR_TYPE_WIDTH, drawText, fixLifeLineHeights } from './svgDraw.js';
44
import { log } from '../../logger.js';
55
import common, { calculateMathMLDimensions, hasKatex } from '../common/common.js';
6+
import { getUrl } from '../common/common.js';
67
import * as svgDrawCommon from '../common/svgDrawCommon.js';
78
import { getConfig } from '../../diagram-api/diagramAPI.js';
89
import assignWithDepth from '../../assignWithDepth.js';
@@ -449,14 +450,7 @@ const drawMessage = async function (diagram, msgModel, lineStartY: number, diagO
449450

450451
let url = '';
451452
if (conf.arrowMarkerAbsolute) {
452-
url =
453-
window.location.protocol +
454-
'//' +
455-
window.location.host +
456-
window.location.pathname +
457-
window.location.search;
458-
url = url.replace(/\(/g, '\\(');
459-
url = url.replace(/\)/g, '\\)');
453+
url = getUrl(true);
460454
}
461455

462456
line.attr('stroke-width', 2);

packages/mermaid/src/diagrams/state/shapes.js

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { line, curveBasis } from 'd3';
22
import { StateDB } from './stateDb.js';
33
import utils from '../../utils.js';
4-
import common from '../common/common.js';
4+
import common, { getUrl } from '../common/common.js';
55
import { getConfig } from '../../diagram-api/diagramAPI.js';
66
import { log } from '../../logger.js';
77

@@ -444,14 +444,7 @@ export const drawEdge = function (elem, path, relation) {
444444
.attr('class', 'transition');
445445
let url = '';
446446
if (getConfig().state.arrowMarkerAbsolute) {
447-
url =
448-
window.location.protocol +
449-
'//' +
450-
window.location.host +
451-
window.location.pathname +
452-
window.location.search;
453-
url = url.replace(/\(/g, '\\(');
454-
url = url.replace(/\)/g, '\\)');
447+
url = getUrl(true);
455448
}
456449

457450
svgPath.attr(

packages/mermaid/src/rendering-util/rendering-elements/edges.js

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { getConfig } from '../../diagram-api/diagramAPI.js';
2-
import { evaluate } from '../../diagrams/common/common.js';
2+
import { evaluate, getUrl } from '../../diagrams/common/common.js';
33
import { log } from '../../logger.js';
44
import { createText } from '../createText.js';
55
import utils from '../../utils.js';
@@ -631,13 +631,7 @@ export const insertEdge = function (elem, edge, clusterDb, diagramType, startNod
631631

632632
let url = '';
633633
if (getConfig().flowchart.arrowMarkerAbsolute || getConfig().state.arrowMarkerAbsolute) {
634-
url =
635-
window.location.protocol +
636-
'//' +
637-
window.location.host +
638-
window.location.pathname +
639-
window.location.search;
640-
url = url.replace(/\(/g, '\\(').replace(/\)/g, '\\)');
634+
url = getUrl(true);
641635
}
642636
log.info('arrowTypeStart', edge.arrowTypeStart);
643637
log.info('arrowTypeEnd', edge.arrowTypeEnd);

0 commit comments

Comments
 (0)