Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: getMessageAPI so it considers entity codes #5002

Merged
merged 8 commits into from
Nov 7, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion packages/mermaid/src/Diagram.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { log } from './logger.js';
import { getDiagram, registerDiagram } from './diagram-api/diagramAPI.js';
import { detectType, getDiagramLoader } from './diagram-api/detectType.js';
import { UnknownDiagramError } from './errors.js';
import type { DetailedError } from './utils.js';
import { encodeEntities, type DetailedError } from './utils.js';
import type { DiagramDefinition, DiagramMetadata } from './diagram-api/types.js';

export type ParseErrorFunction = (err: string | DetailedError | unknown, hash?: any) => void;
Expand Down Expand Up @@ -81,6 +81,8 @@ export const getDiagramFromText = async (
text: string,
metadata: Pick<DiagramMetadata, 'title'> = {}
): Promise<Diagram> => {
text = encodeEntities(text);

ad1992 marked this conversation as resolved.
Show resolved Hide resolved
const type = detectType(text, configApi.getConfig());
try {
// Trying to find the diagram
Expand Down
14 changes: 14 additions & 0 deletions packages/mermaid/src/diagram.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,18 @@ Expecting 'TXT', got 'NEWLINE'"
'"No diagram type detected matching given configuration for text: thor TD; A-->B"'
);
});

test('should consider entity codes when present in diagram defination', async () => {
const diagram = await getDiagramFromText(`sequenceDiagram
A->>B: I #9829; you!
B->>A: I #9829; you #infin; times more!`);
//@ts-ignore
const messages = diagram.db?.getMessages?.();
if (!messages) {
throw new Error('Messages not found!');
}

expect(messages[0].message).toBe('I fl°°9829¶ß you!');
expect(messages[1].message).toBe('I fl°°9829¶ß you fl°infin¶ß times more!');
});
});
3 changes: 1 addition & 2 deletions packages/mermaid/src/mermaidAPI.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@ import type { MermaidConfig } from './config.type.js';

import mermaidAPI, { removeExistingElements } from './mermaidAPI.js';
import {
encodeEntities,
decodeEntities,
createCssStyles,
createUserStyles,
appendDivSvgG,
Expand Down Expand Up @@ -68,6 +66,7 @@ vi.mock('stylis', () => {
};
});
import { compile, serialize } from 'stylis';
import { decodeEntities, encodeEntities } from './utils.js';

/**
* @see https://vitest.dev/guide/mocking.html Mock part of a module
Expand Down
40 changes: 1 addition & 39 deletions packages/mermaid/src/mermaidAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import isEmpty from 'lodash-es/isEmpty.js';
import { setA11yDiagramInfo, addSVGa11yTitleDescription } from './accessibility.js';
import type { DiagramStyleClassDef } from './diagram-api/types.js';
import { preprocessDiagram } from './preprocess.js';
import { decodeEntities } from './utils.js';

const MAX_TEXTLENGTH = 50_000;
const MAX_TEXTLENGTH_EXCEEDED_MSG =
Expand Down Expand Up @@ -110,43 +111,6 @@ async function parse(text: string, parseOptions?: ParseOptions): Promise<boolean
return true;
}

/**
* @param text - text to be encoded
* @returns
*/
export const encodeEntities = function (text: string): string {
let txt = text;

txt = txt.replace(/style.*:\S*#.*;/g, function (s): string {
return s.substring(0, s.length - 1);
});
txt = txt.replace(/classDef.*:\S*#.*;/g, function (s): string {
return s.substring(0, s.length - 1);
});

txt = txt.replace(/#\w+;/g, function (s) {
const innerTxt = s.substring(1, s.length - 1);

const isInt = /^\+?\d+$/.test(innerTxt);
if (isInt) {
return 'fl°°' + innerTxt + '¶ß';
} else {
return 'fl°' + innerTxt + '¶ß';
}
});

return txt;
};

/**
*
* @param text - text to be decoded
* @returns
*/
export const decodeEntities = function (text: string): string {
return text.replace(/fl°°/g, '&#').replace(/fl°/g, '&').replace(/¶ß/g, ';');
};

// append !important; to each cssClass followed by a final !important, all enclosed in { }
//
/**
Expand Down Expand Up @@ -436,8 +400,6 @@ const render = async function (
appendDivSvgG(root, id, enclosingDivID);
}

text = encodeEntities(text);

// -------------------------------------------------------------------------------
// Create the diagram

Expand Down
37 changes: 37 additions & 0 deletions packages/mermaid/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -888,3 +888,40 @@
parseFontSize,
InitIDGenerator,
};

/**
* @param text - text to be encoded
* @returns
*/
export const encodeEntities = function (text: string): string {
let txt = text;

txt = txt.replace(/style.*:\S*#.*;/g, function (s): string {
return s.substring(0, s.length - 1);
});
Comment on lines +899 to +901

Check failure

Code scanning / CodeQL

Polynomial regular expression used on uncontrolled data High

This
regular expression
that depends on
library input
may run slow on strings starting with 'style' and with many repetitions of 'style'.
This
regular expression
that depends on
library input
may run slow on strings starting with 'style:' and with many repetitions of ':'.
This
regular expression
that depends on
library input
may run slow on strings starting with 'style:#' and with many repetitions of '#'.
txt = txt.replace(/classDef.*:\S*#.*;/g, function (s): string {
return s.substring(0, s.length - 1);
});

txt = txt.replace(/#\w+;/g, function (s) {
const innerTxt = s.substring(1, s.length - 1);

const isInt = /^\+?\d+$/.test(innerTxt);
if (isInt) {
return 'fl°°' + innerTxt + '¶ß';
} else {
return 'fl°' + innerTxt + '¶ß';
}
});

return txt;
};

/**
*
* @param text - text to be decoded
* @returns
*/
export const decodeEntities = function (text: string): string {
return text.replace(/fl°°/g, '&#').replace(/fl°/g, '&').replace(/¶ß/g, ';');
};
Loading