mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-01-28 07:03:17 +08:00
fix(#4137): Cleanup comments before parsing
This commit is contained in:
parent
e4a2c74b1b
commit
48d267c6dc
@ -95,7 +95,7 @@ mermaid.initialize(config);
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:662](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L662)
|
||||
[mermaidAPI.ts:659](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L659)
|
||||
|
||||
## Functions
|
||||
|
||||
|
@ -5,6 +5,7 @@ import { detectType, getDiagramLoader } from './diagram-api/detectType';
|
||||
import { extractFrontMatter } from './diagram-api/frontmatter';
|
||||
import { UnknownDiagramError } from './errors';
|
||||
import { DetailedError } from './utils';
|
||||
import { cleanupComments } from './diagram-api/comments';
|
||||
|
||||
export type ParseErrorFunction = (err: string | DetailedError | unknown, hash?: any) => void;
|
||||
|
||||
@ -43,7 +44,8 @@ export class Diagram {
|
||||
// Similarly, we can't do this in getDiagramFromText() because some code
|
||||
// calls diagram.db.clear(), which would reset anything set by
|
||||
// extractFrontMatter().
|
||||
this.parser.parse = (text: string) => originalParse(extractFrontMatter(text, this.db));
|
||||
this.parser.parse = (text: string) =>
|
||||
originalParse(cleanupComments(extractFrontMatter(text, this.db)));
|
||||
this.parser.parser.yy = this.db;
|
||||
if (diagram.init) {
|
||||
diagram.init(cnf);
|
||||
|
70
packages/mermaid/src/diagram-api/comments.spec.ts
Normal file
70
packages/mermaid/src/diagram-api/comments.spec.ts
Normal file
@ -0,0 +1,70 @@
|
||||
// tests to check that comments are removed
|
||||
|
||||
import { cleanupComments } from './comments';
|
||||
import { describe, it, expect } from 'vitest';
|
||||
|
||||
describe('comments', () => {
|
||||
it('should remove comments', () => {
|
||||
const text = `
|
||||
|
||||
%% This is a comment
|
||||
%% This is another comment
|
||||
graph TD
|
||||
A-->B
|
||||
%% This is a comment
|
||||
`;
|
||||
expect(cleanupComments(text)).toMatchInlineSnapshot(`
|
||||
"
|
||||
|
||||
graph TD
|
||||
A-->B
|
||||
|
||||
"
|
||||
`);
|
||||
});
|
||||
|
||||
it('should keep init statements when removing comments', () => {
|
||||
const text = `
|
||||
%% This is a comment
|
||||
|
||||
%% This is another comment
|
||||
%%{init: {'theme': 'forest'}}%%
|
||||
%%{init: {'theme': 'space after ending'}}%%
|
||||
graph TD
|
||||
A-->B
|
||||
|
||||
B-->C
|
||||
%% This is a comment
|
||||
`;
|
||||
expect(cleanupComments(text)).toMatchInlineSnapshot(`
|
||||
"
|
||||
|
||||
%%{init: {'theme': 'forest'}}%%
|
||||
%%{init: {'theme': 'space after ending'}}%%
|
||||
graph TD
|
||||
A-->B
|
||||
|
||||
B-->C
|
||||
|
||||
"
|
||||
`);
|
||||
});
|
||||
|
||||
it('should remove indented comments', () => {
|
||||
const text = `
|
||||
%% This is a comment
|
||||
graph TD
|
||||
A-->B
|
||||
%% This is a comment
|
||||
C-->D
|
||||
`;
|
||||
expect(cleanupComments(text)).toMatchInlineSnapshot(`
|
||||
"
|
||||
graph TD
|
||||
A-->B
|
||||
|
||||
C-->D
|
||||
"
|
||||
`);
|
||||
});
|
||||
});
|
8
packages/mermaid/src/diagram-api/comments.ts
Normal file
8
packages/mermaid/src/diagram-api/comments.ts
Normal file
@ -0,0 +1,8 @@
|
||||
/**
|
||||
* Remove all lines starting with `%%` from the text that don't contain a `%%{`
|
||||
* @param text - The text to remove comments from
|
||||
* @returns cleaned text
|
||||
*/
|
||||
export const cleanupComments = (text: string): string => {
|
||||
return text.replace(/^\s*%%(?!{)[^\n]+/gm, '');
|
||||
};
|
@ -19,8 +19,6 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multili
|
||||
<type_directive>":" { this.popState(); this.begin('arg_directive'); return ':'; }
|
||||
<type_directive,arg_directive>\}\%\% { this.popState(); this.popState(); return 'close_directive'; }
|
||||
<arg_directive>((?:(?!\}\%\%).|\n)*) return 'arg_directive';
|
||||
\%%(?!\{)[^\n]* /* skip comments */
|
||||
[^\}]\%\%[^\n]* /* skip comments */
|
||||
[\n]+ return 'NEWLINE';
|
||||
\s+ /* skip whitespace */
|
||||
[\s]+ return 'SPACE';
|
||||
@ -35,8 +33,6 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multili
|
||||
<block>[A-Za-z_][A-Za-z0-9\-_\[\]\(\)]* return 'ATTRIBUTE_WORD'
|
||||
<block>\"[^"]*\" return 'COMMENT';
|
||||
<block>[\n]+ /* nothing */
|
||||
<block>\%%(?!\{)[^\n]* /* skip comments in attribute block */
|
||||
<block>[^\}]\%\%[^\n]* /* skip comments in attribute block */
|
||||
<block>"}" { this.popState(); return 'BLOCK_STOP'; }
|
||||
<block>. return yytext[0];
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
import flowDb from '../flowDb';
|
||||
import flow from './flow';
|
||||
import { setConfig } from '../../../config';
|
||||
import { cleanupComments } from '../../../diagram-api/comments';
|
||||
|
||||
setConfig({
|
||||
securityLevel: 'strict',
|
||||
@ -13,7 +14,7 @@ describe('[Comments] when parsing', () => {
|
||||
});
|
||||
|
||||
it('should handle comments', function () {
|
||||
const res = flow.parser.parse('graph TD;\n%% Comment\n A-->B;');
|
||||
const res = flow.parser.parse(cleanupComments('graph TD;\n%% Comment\n A-->B;'));
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
@ -28,7 +29,7 @@ describe('[Comments] when parsing', () => {
|
||||
});
|
||||
|
||||
it('should handle comments at the start', function () {
|
||||
const res = flow.parser.parse('%% Comment\ngraph TD;\n A-->B;');
|
||||
const res = flow.parser.parse(cleanupComments('%% Comment\ngraph TD;\n A-->B;'));
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
@ -43,7 +44,7 @@ describe('[Comments] when parsing', () => {
|
||||
});
|
||||
|
||||
it('should handle comments at the end', function () {
|
||||
const res = flow.parser.parse('graph TD;\n A-->B\n %% Comment at the end\n');
|
||||
const res = flow.parser.parse(cleanupComments('graph TD;\n A-->B\n %% Comment at the end\n'));
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
@ -58,7 +59,7 @@ describe('[Comments] when parsing', () => {
|
||||
});
|
||||
|
||||
it('should handle comments at the end no trailing newline', function () {
|
||||
const res = flow.parser.parse('graph TD;\n A-->B\n%% Comment');
|
||||
const res = flow.parser.parse(cleanupComments('graph TD;\n A-->B\n%% Comment'));
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
@ -73,7 +74,7 @@ describe('[Comments] when parsing', () => {
|
||||
});
|
||||
|
||||
it('should handle comments at the end many trailing newlines', function () {
|
||||
const res = flow.parser.parse('graph TD;\n A-->B\n%% Comment\n\n\n');
|
||||
const res = flow.parser.parse(cleanupComments('graph TD;\n A-->B\n%% Comment\n\n\n'));
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
@ -88,7 +89,7 @@ describe('[Comments] when parsing', () => {
|
||||
});
|
||||
|
||||
it('should handle no trailing newlines', function () {
|
||||
const res = flow.parser.parse('graph TD;\n A-->B');
|
||||
const res = flow.parser.parse(cleanupComments('graph TD;\n A-->B'));
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
@ -103,7 +104,7 @@ describe('[Comments] when parsing', () => {
|
||||
});
|
||||
|
||||
it('should handle many trailing newlines', function () {
|
||||
const res = flow.parser.parse('graph TD;\n A-->B\n\n');
|
||||
const res = flow.parser.parse(cleanupComments('graph TD;\n A-->B\n\n'));
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
@ -118,7 +119,7 @@ describe('[Comments] when parsing', () => {
|
||||
});
|
||||
|
||||
it('should handle a comment with blank rows in-between', function () {
|
||||
const res = flow.parser.parse('graph TD;\n\n\n %% Comment\n A-->B;');
|
||||
const res = flow.parser.parse(cleanupComments('graph TD;\n\n\n %% Comment\n A-->B;'));
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
@ -134,7 +135,9 @@ describe('[Comments] when parsing', () => {
|
||||
|
||||
it('should handle a comment with mermaid flowchart code in them', function () {
|
||||
const res = flow.parser.parse(
|
||||
'graph TD;\n\n\n %% Test od>Odd shape]-->|Two line<br>edge comment|ro;\n A-->B;'
|
||||
cleanupComments(
|
||||
'graph TD;\n\n\n %% Test od>Odd shape]-->|Two line<br>edge comment|ro;\n A-->B;'
|
||||
)
|
||||
);
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
|
@ -27,8 +27,6 @@
|
||||
<type_directive>":" { this.popState(); this.begin('arg_directive'); return ':'; }
|
||||
<type_directive,arg_directive>\}\%\% { this.popState(); this.popState(); return 'close_directive'; }
|
||||
<arg_directive>((?:(?!\}\%\%).|\n)*) return 'arg_directive';
|
||||
\%\%(?!\{)[^\n]* /* skip comments */
|
||||
[^\}]\%\%[^\n]* /* skip comments */
|
||||
accTitle\s*":"\s* { this.begin("acc_title");return 'acc_title'; }
|
||||
<acc_title>(?!\n|;|#)*[^\n]* { this.popState(); return "acc_title_value"; }
|
||||
accDescr\s*":"\s* { this.begin("acc_descr");return 'acc_descr'; }
|
||||
|
@ -1,6 +1,7 @@
|
||||
import flowDb from '../flowDb';
|
||||
import flow from './flow';
|
||||
import { setConfig } from '../../../config';
|
||||
import { cleanupComments } from '../../../diagram-api/comments';
|
||||
|
||||
setConfig({
|
||||
securityLevel: 'strict',
|
||||
@ -13,7 +14,7 @@ describe('parsing a flow chart', function () {
|
||||
});
|
||||
|
||||
it('should handle a trailing whitespaces after statements', function () {
|
||||
const res = flow.parser.parse('graph TD;\n\n\n %% Comment\n A-->B; \n B-->C;');
|
||||
const res = flow.parser.parse(cleanupComments('graph TD;\n\n\n %% Comment\n A-->B; \n B-->C;'));
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
const edges = flow.parser.yy.getEdges();
|
||||
|
@ -399,9 +399,6 @@ const render = async function (
|
||||
// clean up text CRLFs
|
||||
text = text.replace(/\r\n?/g, '\n'); // parser problems on CRLF ignore all CR and leave LF;;
|
||||
|
||||
// eslint-disable-next-line unicorn/better-regex
|
||||
text = text.replace(/\s*%%[^{\ninit].*\n/gm, '\n'); // remove comments from text to avoid issues with parser
|
||||
|
||||
const idSelector = '#' + id;
|
||||
const iFrameID = 'i' + id;
|
||||
const iFrameID_selector = '#' + iFrameID;
|
||||
|
Loading…
x
Reference in New Issue
Block a user