mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-01-14 06:43:25 +08:00
Picked state diagram as a sample for sankey
This commit is contained in:
parent
c2417de5f1
commit
6b40b394c8
13
__mocks__/sankeyRenderer.js
Normal file
13
__mocks__/sankeyRenderer.js
Normal file
@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Mocked Sankey diagram renderer
|
||||
*/
|
||||
|
||||
import { vi } from 'vitest';
|
||||
|
||||
export const draw = vi.fn().mockImplementation(() => {
|
||||
return '';
|
||||
});
|
||||
|
||||
export default {
|
||||
draw,
|
||||
};
|
@ -18,7 +18,7 @@ import errorDiagram from '../diagrams/error/errorDiagram.js';
|
||||
import flowchartElk from '../diagrams/flowchart/elk/detector.js';
|
||||
import timeline from '../diagrams/timeline/detector.js';
|
||||
import mindmap from '../diagrams/mindmap/detector.js';
|
||||
import sankey from '../diagrams/sankey/detector.js';
|
||||
import sankey from '../diagrams/sankey/sankeyDetector.js';
|
||||
import { registerLazyLoadedDiagrams } from './detectType.js';
|
||||
import { registerDiagram } from './diagramAPI.js';
|
||||
|
||||
|
@ -1,13 +1,350 @@
|
||||
/** mermaid
|
||||
* https://mermaidjs.github.io/
|
||||
* (c) 2014-2015 Knut Sveidqvist
|
||||
* MIT license.
|
||||
*
|
||||
* Based on js sequence diagrams jison grammr
|
||||
* https://bramp.github.io/js-sequence-diagrams/
|
||||
* (c) 2012-2013 Andrew Brampton (bramp.net)
|
||||
* Simplified BSD license.
|
||||
*/
|
||||
%lex
|
||||
|
||||
%options case-insensitive
|
||||
|
||||
// Special states for recognizing aliases
|
||||
// A special state for grabbing text up to the first comment/newline
|
||||
%x ID ALIAS LINE
|
||||
|
||||
// Directive states
|
||||
%x open_directive type_directive arg_directive
|
||||
%x acc_title
|
||||
%x acc_descr
|
||||
%x acc_descr_multiline
|
||||
%%
|
||||
|
||||
\%\%\{ { this.begin('open_directive'); return 'open_directive'; }
|
||||
<open_directive>((?:(?!\}\%\%)[^:.])*) { this.begin('type_directive'); return 'type_directive'; }
|
||||
<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]+ return 'NEWLINE';
|
||||
\s+ /* skip all whitespace */
|
||||
<ID,ALIAS,LINE>((?!\n)\s)+ /* skip same-line whitespace */
|
||||
<INITIAL,ID,ALIAS,LINE,arg_directive,type_directive,open_directive>\#[^\n]* /* skip comments */
|
||||
\%%(?!\{)[^\n]* /* skip comments */
|
||||
[^\}]\%\%[^\n]* /* skip comments */
|
||||
[0-9]+(?=[ \n]+) return 'NUM';
|
||||
"box" { this.begin('LINE'); return 'box'; }
|
||||
"participant" { this.begin('ID'); return 'participant'; }
|
||||
"actor" { this.begin('ID'); return 'participant_actor'; }
|
||||
<ID>[^\->:\n,;]+?([\-]*[^\->:\n,;]+?)*?(?=((?!\n)\s)+"as"(?!\n)\s|[#\n;]|$) { yytext = yytext.trim(); this.begin('ALIAS'); return 'ACTOR'; }
|
||||
<ALIAS>"as" { this.popState(); this.popState(); this.begin('LINE'); return 'AS'; }
|
||||
<ALIAS>(?:) { this.popState(); this.popState(); return 'NEWLINE'; }
|
||||
"loop" { this.begin('LINE'); return 'loop'; }
|
||||
"rect" { this.begin('LINE'); return 'rect'; }
|
||||
"opt" { this.begin('LINE'); return 'opt'; }
|
||||
"alt" { this.begin('LINE'); return 'alt'; }
|
||||
"else" { this.begin('LINE'); return 'else'; }
|
||||
"par" { this.begin('LINE'); return 'par'; }
|
||||
"par_over" { this.begin('LINE'); return 'par_over'; }
|
||||
"and" { this.begin('LINE'); return 'and'; }
|
||||
"critical" { this.begin('LINE'); return 'critical'; }
|
||||
"option" { this.begin('LINE'); return 'option'; }
|
||||
"break" { this.begin('LINE'); return 'break'; }
|
||||
<LINE>(?:[:]?(?:no)?wrap:)?[^#\n;]* { this.popState(); return 'restOfLine'; }
|
||||
"end" return 'end';
|
||||
"left of" return 'left_of';
|
||||
"right of" return 'right_of';
|
||||
"links" return 'links';
|
||||
"link" return 'link';
|
||||
"properties" return 'properties';
|
||||
"details" return 'details';
|
||||
"over" return 'over';
|
||||
"note" return 'note';
|
||||
"activate" { this.begin('ID'); return 'activate'; }
|
||||
"deactivate" { this.begin('ID'); return 'deactivate'; }
|
||||
"title"\s[^#\n;]+ return 'title';
|
||||
"title:"\s[^#\n;]+ return 'legacy_title';
|
||||
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'; }
|
||||
<acc_descr>(?!\n|;|#)*[^\n]* { this.popState(); return "acc_descr_value"; }
|
||||
accDescr\s*"{"\s* { this.begin("acc_descr_multiline");}
|
||||
<acc_descr_multiline>[\}] { this.popState(); }
|
||||
<acc_descr_multiline>[^\}]* return "acc_descr_multiline_value";
|
||||
"sequenceDiagram" return 'SD';
|
||||
"autonumber" return 'autonumber';
|
||||
"off" return 'off';
|
||||
"," return ',';
|
||||
";" return 'NEWLINE';
|
||||
[^\+\->:\n,;]+((?!(\-x|\-\-x|\-\)|\-\-\)))[\-]*[^\+\->:\n,;]+)* { yytext = yytext.trim(); return 'ACTOR'; }
|
||||
"->>" return 'SOLID_ARROW';
|
||||
"-->>" return 'DOTTED_ARROW';
|
||||
"->" return 'SOLID_OPEN_ARROW';
|
||||
"-->" return 'DOTTED_OPEN_ARROW';
|
||||
\-[x] return 'SOLID_CROSS';
|
||||
\-\-[x] return 'DOTTED_CROSS';
|
||||
\-[\)] return 'SOLID_POINT';
|
||||
\-\-[\)] return 'DOTTED_POINT';
|
||||
":"(?:(?:no)?wrap:)?[^#\n;]+ return 'TXT';
|
||||
"+" return '+';
|
||||
"-" return '-';
|
||||
<<EOF>> return 'NEWLINE';
|
||||
. return 'INVALID';
|
||||
|
||||
/lex
|
||||
|
||||
%start graph
|
||||
%left '^'
|
||||
|
||||
%start start
|
||||
|
||||
%% /* language grammar */
|
||||
|
||||
start
|
||||
: SPACE start
|
||||
| NEWLINE start
|
||||
| directive start
|
||||
| SD document { yy.apply($2);return $2; }
|
||||
;
|
||||
|
||||
document
|
||||
: /* empty */ { $$ = [] }
|
||||
| document line {$1.push($2);$$ = $1}
|
||||
;
|
||||
|
||||
line
|
||||
: SPACE statement { $$ = $2 }
|
||||
| statement { $$ = $1 }
|
||||
| NEWLINE { $$=[]; }
|
||||
;
|
||||
|
||||
box_section
|
||||
: /* empty */ { $$ = [] }
|
||||
| box_section box_line {$1.push($2);$$ = $1}
|
||||
;
|
||||
|
||||
box_line
|
||||
: SPACE participant_statement { $$ = $2 }
|
||||
| participant_statement { $$ = $1 }
|
||||
| NEWLINE { $$=[]; }
|
||||
;
|
||||
|
||||
|
||||
directive
|
||||
: openDirective typeDirective closeDirective 'NEWLINE'
|
||||
| openDirective typeDirective ':' argDirective closeDirective 'NEWLINE'
|
||||
;
|
||||
|
||||
statement
|
||||
: participant_statement
|
||||
| 'box' restOfLine box_section end
|
||||
{
|
||||
$3.unshift({type: 'boxStart', boxData:yy.parseBoxData($2) });
|
||||
$3.push({type: 'boxEnd', boxText:$2});
|
||||
$$=$3;}
|
||||
| signal 'NEWLINE'
|
||||
| autonumber NUM NUM 'NEWLINE' { $$= {type:'sequenceIndex',sequenceIndex: Number($2), sequenceIndexStep:Number($3), sequenceVisible:true, signalType:yy.LINETYPE.AUTONUMBER};}
|
||||
| autonumber NUM 'NEWLINE' { $$ = {type:'sequenceIndex',sequenceIndex: Number($2), sequenceIndexStep:1, sequenceVisible:true, signalType:yy.LINETYPE.AUTONUMBER};}
|
||||
| autonumber off 'NEWLINE' { $$ = {type:'sequenceIndex', sequenceVisible:false, signalType:yy.LINETYPE.AUTONUMBER};}
|
||||
| autonumber 'NEWLINE' {$$ = {type:'sequenceIndex', sequenceVisible:true, signalType:yy.LINETYPE.AUTONUMBER}; }
|
||||
| 'activate' actor 'NEWLINE' {$$={type: 'activeStart', signalType: yy.LINETYPE.ACTIVE_START, actor: $2};}
|
||||
| 'deactivate' actor 'NEWLINE' {$$={type: 'activeEnd', signalType: yy.LINETYPE.ACTIVE_END, actor: $2};}
|
||||
| note_statement 'NEWLINE'
|
||||
| links_statement 'NEWLINE'
|
||||
| link_statement 'NEWLINE'
|
||||
| properties_statement 'NEWLINE'
|
||||
| details_statement 'NEWLINE'
|
||||
| title {yy.setDiagramTitle($1.substring(6));$$=$1.substring(6);}
|
||||
| legacy_title {yy.setDiagramTitle($1.substring(7));$$=$1.substring(7);}
|
||||
| acc_title acc_title_value { $$=$2.trim();yy.setAccTitle($$); }
|
||||
| acc_descr acc_descr_value { $$=$2.trim();yy.setAccDescription($$); }
|
||||
| acc_descr_multiline_value { $$=$1.trim();yy.setAccDescription($$); }
|
||||
| 'loop' restOfLine document end
|
||||
{
|
||||
$3.unshift({type: 'loopStart', loopText:yy.parseMessage($2), signalType: yy.LINETYPE.LOOP_START});
|
||||
$3.push({type: 'loopEnd', loopText:$2, signalType: yy.LINETYPE.LOOP_END});
|
||||
$$=$3;}
|
||||
| 'rect' restOfLine document end
|
||||
{
|
||||
$3.unshift({type: 'rectStart', color:yy.parseMessage($2), signalType: yy.LINETYPE.RECT_START });
|
||||
$3.push({type: 'rectEnd', color:yy.parseMessage($2), signalType: yy.LINETYPE.RECT_END });
|
||||
$$=$3;}
|
||||
| opt restOfLine document end
|
||||
{
|
||||
$3.unshift({type: 'optStart', optText:yy.parseMessage($2), signalType: yy.LINETYPE.OPT_START});
|
||||
$3.push({type: 'optEnd', optText:yy.parseMessage($2), signalType: yy.LINETYPE.OPT_END});
|
||||
$$=$3;}
|
||||
| alt restOfLine else_sections end
|
||||
{
|
||||
// Alt start
|
||||
$3.unshift({type: 'altStart', altText:yy.parseMessage($2), signalType: yy.LINETYPE.ALT_START});
|
||||
// Content in alt is already in $3
|
||||
// End
|
||||
$3.push({type: 'altEnd', signalType: yy.LINETYPE.ALT_END});
|
||||
$$=$3;}
|
||||
| par restOfLine par_sections end
|
||||
{
|
||||
// Parallel start
|
||||
$3.unshift({type: 'parStart', parText:yy.parseMessage($2), signalType: yy.LINETYPE.PAR_START});
|
||||
// Content in par is already in $3
|
||||
// End
|
||||
$3.push({type: 'parEnd', signalType: yy.LINETYPE.PAR_END});
|
||||
$$=$3;}
|
||||
| par_over restOfLine par_sections end
|
||||
{
|
||||
// Parallel (overlapped) start
|
||||
$3.unshift({type: 'parStart', parText:yy.parseMessage($2), signalType: yy.LINETYPE.PAR_OVER_START});
|
||||
// Content in par is already in $3
|
||||
// End
|
||||
$3.push({type: 'parEnd', signalType: yy.LINETYPE.PAR_END});
|
||||
$$=$3;}
|
||||
| critical restOfLine option_sections end
|
||||
{
|
||||
// critical start
|
||||
$3.unshift({type: 'criticalStart', criticalText:yy.parseMessage($2), signalType: yy.LINETYPE.CRITICAL_START});
|
||||
// Content in critical is already in $3
|
||||
// critical end
|
||||
$3.push({type: 'criticalEnd', signalType: yy.LINETYPE.CRITICAL_END});
|
||||
$$=$3;}
|
||||
| break restOfLine document end
|
||||
{
|
||||
$3.unshift({type: 'breakStart', breakText:yy.parseMessage($2), signalType: yy.LINETYPE.BREAK_START});
|
||||
$3.push({type: 'breakEnd', optText:yy.parseMessage($2), signalType: yy.LINETYPE.BREAK_END});
|
||||
$$=$3;}
|
||||
| directive
|
||||
;
|
||||
|
||||
option_sections
|
||||
: document
|
||||
| document option restOfLine option_sections
|
||||
{ $$ = $1.concat([{type: 'option', optionText:yy.parseMessage($3), signalType: yy.LINETYPE.CRITICAL_OPTION}, $4]); }
|
||||
;
|
||||
|
||||
par_sections
|
||||
: document
|
||||
| document and restOfLine par_sections
|
||||
{ $$ = $1.concat([{type: 'and', parText:yy.parseMessage($3), signalType: yy.LINETYPE.PAR_AND}, $4]); }
|
||||
;
|
||||
|
||||
else_sections
|
||||
: document
|
||||
| document else restOfLine else_sections
|
||||
{ $$ = $1.concat([{type: 'else', altText:yy.parseMessage($3), signalType: yy.LINETYPE.ALT_ELSE}, $4]); }
|
||||
;
|
||||
|
||||
participant_statement
|
||||
: 'participant' actor 'AS' restOfLine 'NEWLINE' {$2.type='addParticipant';$2.description=yy.parseMessage($4); $$=$2;}
|
||||
| 'participant' actor 'NEWLINE' {$2.type='addParticipant';$$=$2;}
|
||||
| 'participant_actor' actor 'AS' restOfLine 'NEWLINE' {$2.type='addActor';$2.description=yy.parseMessage($4); $$=$2;}
|
||||
| 'participant_actor' actor 'NEWLINE' {$2.type='addActor'; $$=$2;}
|
||||
;
|
||||
|
||||
note_statement
|
||||
: 'note' placement actor text2
|
||||
{
|
||||
$$ = [$3, {type:'addNote', placement:$2, actor:$3.actor, text:$4}];}
|
||||
| 'note' 'over' actor_pair text2
|
||||
{
|
||||
// Coerce actor_pair into a [to, from, ...] array
|
||||
$2 = [].concat($3, $3).slice(0, 2);
|
||||
$2[0] = $2[0].actor;
|
||||
$2[1] = $2[1].actor;
|
||||
$$ = [$3, {type:'addNote', placement:yy.PLACEMENT.OVER, actor:$2.slice(0, 2), text:$4}];}
|
||||
;
|
||||
|
||||
links_statement
|
||||
: 'links' actor text2
|
||||
{
|
||||
$$ = [$2, {type:'addLinks', actor:$2.actor, text:$3}];
|
||||
}
|
||||
;
|
||||
|
||||
link_statement
|
||||
: 'link' actor text2
|
||||
{
|
||||
$$ = [$2, {type:'addALink', actor:$2.actor, text:$3}];
|
||||
}
|
||||
;
|
||||
|
||||
properties_statement
|
||||
: 'properties' actor text2
|
||||
{
|
||||
$$ = [$2, {type:'addProperties', actor:$2.actor, text:$3}];
|
||||
}
|
||||
;
|
||||
|
||||
details_statement
|
||||
: 'details' actor text2
|
||||
{
|
||||
$$ = [$2, {type:'addDetails', actor:$2.actor, text:$3}];
|
||||
}
|
||||
;
|
||||
|
||||
spaceList
|
||||
: SPACE spaceList
|
||||
| SPACE
|
||||
;
|
||||
actor_pair
|
||||
: actor ',' actor { $$ = [$1, $3]; }
|
||||
| actor { $$ = $1; }
|
||||
;
|
||||
|
||||
placement
|
||||
: 'left_of' { $$ = yy.PLACEMENT.LEFTOF; }
|
||||
| 'right_of' { $$ = yy.PLACEMENT.RIGHTOF; }
|
||||
;
|
||||
|
||||
signal
|
||||
: actor signaltype '+' actor text2
|
||||
{ $$ = [$1,$4,{type: 'addMessage', from:$1.actor, to:$4.actor, signalType:$2, msg:$5},
|
||||
{type: 'activeStart', signalType: yy.LINETYPE.ACTIVE_START, actor: $4}
|
||||
]}
|
||||
| actor signaltype '-' actor text2
|
||||
{ $$ = [$1,$4,{type: 'addMessage', from:$1.actor, to:$4.actor, signalType:$2, msg:$5},
|
||||
{type: 'activeEnd', signalType: yy.LINETYPE.ACTIVE_END, actor: $1}
|
||||
]}
|
||||
| actor signaltype actor text2
|
||||
{ $$ = [$1,$3,{type: 'addMessage', from:$1.actor, to:$3.actor, signalType:$2, msg:$4}]}
|
||||
;
|
||||
|
||||
// actor
|
||||
// : actor_participant
|
||||
// | actor_actor
|
||||
// ;
|
||||
|
||||
actor: ACTOR {$$={ type: 'addParticipant', actor:$1}};
|
||||
// actor_actor: ACTOR {$$={type: 'addActor', actor:$1}};
|
||||
|
||||
signaltype
|
||||
: SOLID_OPEN_ARROW { $$ = yy.LINETYPE.SOLID_OPEN; }
|
||||
| DOTTED_OPEN_ARROW { $$ = yy.LINETYPE.DOTTED_OPEN; }
|
||||
| SOLID_ARROW { $$ = yy.LINETYPE.SOLID; }
|
||||
| DOTTED_ARROW { $$ = yy.LINETYPE.DOTTED; }
|
||||
| SOLID_CROSS { $$ = yy.LINETYPE.SOLID_CROSS; }
|
||||
| DOTTED_CROSS { $$ = yy.LINETYPE.DOTTED_CROSS; }
|
||||
| SOLID_POINT { $$ = yy.LINETYPE.SOLID_POINT; }
|
||||
| DOTTED_POINT { $$ = yy.LINETYPE.DOTTED_POINT; }
|
||||
;
|
||||
|
||||
text2
|
||||
: TXT {$$ = yy.parseMessage($1.trim().substring(1)) }
|
||||
;
|
||||
|
||||
openDirective
|
||||
: open_directive { yy.parseDirective('%%{', 'open_directive'); }
|
||||
;
|
||||
|
||||
typeDirective
|
||||
: type_directive { yy.parseDirective($1, 'type_directive'); }
|
||||
;
|
||||
|
||||
argDirective
|
||||
: arg_directive { $1 = $1.trim().replace(/'/g, '"'); yy.parseDirective($1, 'arg_directive'); }
|
||||
;
|
||||
|
||||
closeDirective
|
||||
: close_directive { yy.parseDirective('}%%', 'close_directive', 'sequence'); }
|
||||
;
|
||||
|
||||
%%
|
||||
|
||||
graph
|
||||
: node ->
|
@ -1,27 +0,0 @@
|
||||
// import { select, scaleOrdinal, pie as d3pie, arc } from 'd3';
|
||||
|
||||
// import { select, selectAll } from 'd3';
|
||||
// import { log } from '../../logger.js';
|
||||
// import common from '../common/common.js';
|
||||
// import * as svgDrawCommon from '../common/svgDrawCommon';
|
||||
import * as configApi from '../../config.js';
|
||||
// import assignWithDepth from '../../assignWithDepth.js';
|
||||
// import utils from '../../utils.js';
|
||||
// import { configureSvgSize } from '../../setupGraphViewbox.js';
|
||||
import { Diagram } from '../../Diagram.js';
|
||||
|
||||
// import { parseFontSize } from '../../utils.js';
|
||||
|
||||
const conf = configApi.getConfig();
|
||||
|
||||
/**
|
||||
* Draws a Sankey Diagram with the data given in text.
|
||||
*
|
||||
* @param text
|
||||
* @param id
|
||||
*/
|
||||
export const draw = function (_text: string, id: string, _version: string, _diagObj: Diagram) {}
|
||||
|
||||
export default {
|
||||
draw,
|
||||
};
|
24
packages/mermaid/src/diagrams/sankey/sankeyDiagram.spec.js
Normal file
24
packages/mermaid/src/diagrams/sankey/sankeyDiagram.spec.js
Normal file
@ -0,0 +1,24 @@
|
||||
import diagram from './parser/sankey.jison';
|
||||
import { parser } from './parser/sankey.jison';
|
||||
import db from './sankeyDB.js';
|
||||
|
||||
describe('state diagram V2, ', function () {
|
||||
// TODO - these examples should be put into ./parser/stateDiagram.spec.js
|
||||
describe('when parsing an info graph it', function () {
|
||||
beforeEach(function () {
|
||||
parser.yy = stateDb;
|
||||
diagram.parser.yy = db;
|
||||
diagram.parser.yy.clear();
|
||||
});
|
||||
|
||||
it('super simple', function () {
|
||||
const str = `
|
||||
stateDiagram-v2
|
||||
[*] --> State1
|
||||
State1 --> [*]
|
||||
`;
|
||||
|
||||
parser.parse(str);
|
||||
});
|
||||
});
|
||||
});
|
@ -1,9 +1,9 @@
|
||||
import { DiagramDefinition } from '../../diagram-api/types.js';
|
||||
// @ts-ignore: TODO Fix ts errors
|
||||
import parser from './parser/sankey.jison';
|
||||
import db from './db.js';
|
||||
import db from './sankeyDB.js';
|
||||
import styles from './styles.js';
|
||||
import renderer from './renderer.js';
|
||||
import renderer from './sankeyRenderer.js';
|
||||
|
||||
export const diagram: DiagramDefinition = {
|
||||
parser,
|
||||
|
1446
packages/mermaid/src/diagrams/sankey/sankeyRenderer.ts
Normal file
1446
packages/mermaid/src/diagrams/sankey/sankeyRenderer.ts
Normal file
File diff suppressed because it is too large
Load Diff
@ -29,6 +29,7 @@ import state from './diagrams/state/styles.js';
|
||||
import journey from './diagrams/user-journey/styles.js';
|
||||
import timeline from './diagrams/timeline/styles.js';
|
||||
import mindmap from './diagrams/mindmap/styles.js';
|
||||
import sankey from './diagrams/sankey/styles.js';
|
||||
import themes from './themes/index.js';
|
||||
|
||||
async function checkValidStylisCSSStyleSheet(stylisString: string) {
|
||||
@ -98,6 +99,7 @@ describe('styles', () => {
|
||||
sequence,
|
||||
state,
|
||||
timeline,
|
||||
sankey,
|
||||
})) {
|
||||
test(`should return a valid style for diagram ${diagramId} and theme ${themeId}`, async () => {
|
||||
const { default: getStyles, addStylesForDiagram } = await import('./styles.js');
|
||||
|
Loading…
x
Reference in New Issue
Block a user