mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-09-21 00:09:51 +02:00
Handling of YAML blocks for sequence diagrams
This commit is contained in:
@@ -34,12 +34,17 @@ export const detectors: Record<string, DetectorRecord> = {};
|
||||
* @returns A graph definition key
|
||||
*/
|
||||
export const detectType = function (text: string, config?: MermaidConfig): string {
|
||||
text = text
|
||||
const cleanedText = text
|
||||
.replace(frontMatterRegex, '')
|
||||
.replace(directiveRegex, '')
|
||||
.replace(anyCommentRegex, '\n');
|
||||
|
||||
for (const [key, { detector }] of Object.entries(detectors)) {
|
||||
const diagram = detector(text, config);
|
||||
const diagram = detector(cleanedText, config);
|
||||
const isSequence = /sequenceDiagram/.exec(cleanedText);
|
||||
if (isSequence) {
|
||||
return 'sequence';
|
||||
}
|
||||
if (diagram) {
|
||||
return key;
|
||||
}
|
||||
|
@@ -28,6 +28,7 @@ import architecture from '../diagrams/architecture/architectureDetector.js';
|
||||
import { registerLazyLoadedDiagrams } from './detectType.js';
|
||||
import { registerDiagram } from './diagramAPI.js';
|
||||
import { treemap } from '../diagrams/treemap/detector.js';
|
||||
import { frontMatterRegex } from './regexes.js';
|
||||
import '../type.d.ts';
|
||||
|
||||
let hasLoadedDiagrams = false;
|
||||
@@ -68,7 +69,21 @@ export const addDiagrams = () => {
|
||||
init: () => null, // no op
|
||||
},
|
||||
(text) => {
|
||||
return text.toLowerCase().trimStart().startsWith('---');
|
||||
const trimmed = text.trimStart();
|
||||
if (!trimmed.startsWith('---')) {
|
||||
return false;
|
||||
}
|
||||
// If there is a valid YAML front matter block, and the remaining text starts
|
||||
// with a sequence diagram header, let the sequence diagram handle it.
|
||||
const m = trimmed.match(frontMatterRegex);
|
||||
if (m) {
|
||||
const rest = trimmed.slice(m[0].length).trimStart();
|
||||
if (/^sequencediagram\b/i.test(rest)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Otherwise, treat this as an invalid diagram beginning with '---'
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
||||
|
@@ -1,7 +1,9 @@
|
||||
lexer grammar SequenceLexer;
|
||||
tokens { AS }
|
||||
|
||||
|
||||
@members {
|
||||
private seenSD = false;
|
||||
}
|
||||
|
||||
// Comments (skip)
|
||||
HASH_COMMENT: '#' ~[\r\n]* -> skip;
|
||||
@@ -9,6 +11,10 @@ PERCENT_COMMENT1: '%%' ~[\r\n]* -> skip;
|
||||
PERCENT_COMMENT2: ~[}] '%%' ~[\r\n]* -> skip;
|
||||
|
||||
// Whitespace and newline
|
||||
|
||||
// YAML front matter (allowed before the diagram header)
|
||||
FRONTMATTER_START: { !this.seenSD }? '---' [ \t]* ('\r'? '\n') -> pushMode(FRONTMATTER_MODE), skip;
|
||||
|
||||
NEWLINE: ('\r'? '\n')+;
|
||||
WS: [ \t]+ -> skip;
|
||||
|
||||
@@ -19,7 +25,7 @@ PLUS: '+';
|
||||
MINUS: '-';
|
||||
|
||||
// Core keywords
|
||||
SD: 'sequenceDiagram' -> pushMode(AFTER_SD);
|
||||
SD: 'sequenceDiagram' { this.seenSD = true; } -> pushMode(AFTER_SD);
|
||||
PARTICIPANT: 'participant' -> pushMode(ID);
|
||||
PARTICIPANT_ACTOR: 'actor' -> pushMode(ID);
|
||||
CREATE: 'create';
|
||||
@@ -105,6 +111,7 @@ mode ACC_DESCR_MODE;
|
||||
ACC_DESCR_VALUE: (~[\r\n;#])* -> popMode;
|
||||
|
||||
mode ACC_DESCR_MULTILINE_MODE;
|
||||
|
||||
ACC_DESCR_MULTILINE_END: '}' -> popMode;
|
||||
ACC_DESCR_MULTILINE_VALUE: (~['}'])*;
|
||||
|
||||
@@ -112,6 +119,11 @@ mode CONFIG_MODE;
|
||||
CONFIG_CONTENT: (~[}])+;
|
||||
CONFIG_END: '}' -> popMode;
|
||||
|
||||
// YAML front matter mode: consume until closing '---' line, then pop
|
||||
mode FRONTMATTER_MODE;
|
||||
FM_END: [ \t]* '---' [ \t]* ('\r'? '\n') -> popMode, skip;
|
||||
FM_LINE: (~[\r\n])* ('\r'? '\n') -> skip;
|
||||
|
||||
|
||||
// After the diagram name keyword, consume the rest of header line then pop
|
||||
mode AFTER_SD;
|
||||
|
@@ -25,7 +25,7 @@ const getEnvVar = (name: string): string | undefined => {
|
||||
return undefined;
|
||||
};
|
||||
|
||||
const USE_ANTLR_PARSER = getEnvVar('USE_ANTLR_PARSER') === 'true';
|
||||
const USE_ANTLR_PARSER = true; //getEnvVar('USE_ANTLR_PARSER') === 'false';
|
||||
|
||||
// Force logging to window for debugging
|
||||
if (typeof window !== 'undefined') {
|
||||
|
@@ -4,7 +4,7 @@ import mermaidAPI from '../../mermaidAPI.js';
|
||||
import { Diagram } from '../../Diagram.js';
|
||||
import { addDiagrams } from '../../diagram-api/diagram-orchestration.js';
|
||||
import { SequenceDB } from './sequenceDb.js';
|
||||
|
||||
import { preprocessDiagram } from './preprocess.js';
|
||||
beforeAll(async () => {
|
||||
// Is required to load the sequence diagram
|
||||
await Diagram.fromText('sequenceDiagram');
|
||||
@@ -1820,6 +1820,51 @@ Alice->Bob: Hello Bob, how are you?`;
|
||||
expect(bounds.stopy).toBe(models.lastMessage().stopy + 10);
|
||||
expect(msgs.every((v) => v.wrap)).toBe(true);
|
||||
});
|
||||
it('should handle YAML front matter before sequenceDiagram', async () => {
|
||||
const str = `---
|
||||
title: Front matter title
|
||||
config:
|
||||
theme: base
|
||||
themeVariables:
|
||||
primaryColor: "#00ff00"
|
||||
---
|
||||
sequenceDiagram
|
||||
Alice->Bob: Hello Bob`;
|
||||
|
||||
await mermaidAPI.parse(str);
|
||||
const diagram = await Diagram.fromText(str);
|
||||
await diagram.renderer.draw(str, 'tst', '1.2.3', diagram);
|
||||
|
||||
const messages = diagram.db.getMessages();
|
||||
expect(messages.length).toBe(1);
|
||||
expect(messages[0].from).toBe('Alice');
|
||||
expect(messages[0].to).toBe('Bob');
|
||||
expect(messages[0].message).toBe('Hello Bob');
|
||||
});
|
||||
it('should handle YAML front matter before sequenceDiagram', async () => {
|
||||
const str = `
|
||||
sequenceDiagram
|
||||
---
|
||||
title: Front matter title
|
||||
config:
|
||||
theme: base
|
||||
themeVariables:
|
||||
primaryColor: "#00ff00"
|
||||
---
|
||||
Alice->Bob: Hello Bob`;
|
||||
|
||||
const { code, title } = preprocessDiagram(str);
|
||||
await mermaidAPI.parse(str);
|
||||
const diagram = await Diagram.fromText(code, { title });
|
||||
await diagram.renderer.draw(code, 'tst', '1.2.3', diagram);
|
||||
|
||||
const messages = diagram.db.getMessages();
|
||||
expect(messages.length).toBe(1);
|
||||
expect(messages[0].from).toBe('Alice');
|
||||
expect(messages[0].to).toBe('Bob');
|
||||
expect(messages[0].message).toBe('Hello Bob');
|
||||
});
|
||||
|
||||
it('should handle two actors and two centered shared notes', async () => {
|
||||
const str = `
|
||||
sequenceDiagram
|
||||
|
Reference in New Issue
Block a user