From c1df62638d1b1a158f74dc6285f03d59dcb2d6f8 Mon Sep 17 00:00:00 2001 From: Kazuki Tsunemi Date: Thu, 9 Mar 2023 21:14:30 +0900 Subject: [PATCH 1/8] class body grammer apply to class stetement only --- .../diagrams/class/parser/classDiagram.jison | 123 ++++++++++-------- 1 file changed, 66 insertions(+), 57 deletions(-) diff --git a/packages/mermaid/src/diagrams/class/parser/classDiagram.jison b/packages/mermaid/src/diagrams/class/parser/classDiagram.jison index 0c9ad2f2a..4e68372f3 100644 --- a/packages/mermaid/src/diagrams/class/parser/classDiagram.jison +++ b/packages/mermaid/src/diagrams/class/parser/classDiagram.jison @@ -19,6 +19,8 @@ %x acc_title %x acc_descr %x acc_descr_multiline +%x class +%x class-body %% \%\%\{ { this.begin('open_directive'); return 'open_directive'; } .*direction\s+TB[^\n]* return 'direction_tb'; @@ -41,35 +43,30 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multili \s*(\r?\n)+ return 'NEWLINE'; \s+ /* skip whitespace */ + "classDiagram-v2" return 'CLASS_DIAGRAM'; "classDiagram" return 'CLASS_DIAGRAM'; -[{] { this.begin("struct"); /*console.log('Starting struct');*/ return 'STRUCT_START';} -"[*]" { /*console.log('EDGE_STATE=',yytext);*/ return 'EDGE_STATE';} -<> return "EOF_IN_STRUCT"; -[{] return "OPEN_IN_STRUCT"; -[}] { /*console.log('Ending struct');*/this.popState(); return 'STRUCT_STOP';}} -[\n] /* nothing */ -[^{}\n]* { /*console.log('lex-member: ' + yytext);*/ return "MEMBER";} +"[*]" return 'EDGE_STATE'; -"class" return 'CLASS'; -"cssClass" return 'CSSCLASS'; -"callback" return 'CALLBACK'; -"link" return 'LINK'; -"click" return 'CLICK'; -"note for" return 'NOTE_FOR'; -"note" return 'NOTE'; -"<<" return 'ANNOTATION_START'; -">>" return 'ANNOTATION_END'; -[~] this.begin("generic"); -[~] this.popState(); -[^~]* return "GENERICTYPE"; -["] this.begin("string"); -["] this.popState(); -[^"]* return "STR"; +"class" { this.begin('class'); return 'CLASS';} +\s*(\r?\n)+ { this.popState(); return 'NEWLINE'; } +\s+ /* skip whitespace */ +[{] { this.begin("class-body"); return 'STRUCT_START';} +[}] { this.popState(); return 'STRUCT_STOP'; } +<> return "EOF_IN_STRUCT"; +"[*]" { return 'EDGE_STATE';} +[{] return "OPEN_IN_STRUCT"; +[\n] /* nothing */ +[^{}\n]* { return "MEMBER";} -[`] this.begin("bqstring"); -[`] this.popState(); -[^`]+ return "BQUOTE_STR"; +<*>"cssClass" return 'CSSCLASS'; +<*>"callback" return 'CALLBACK'; +<*>"link" return 'LINK'; +<*>"click" return 'CLICK'; +<*>"note for" return 'NOTE_FOR'; +<*>"note" return 'NOTE'; +<*>"<<" return 'ANNOTATION_START'; +<*>">>" return 'ANNOTATION_END'; /* ---interactivity command--- @@ -77,7 +74,7 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multili line was introduced with 'click'. 'href ""' attaches the specified link to the node that was specified by 'click'. */ -"href"[\s]+["] this.begin("href"); +<*>"href"[\s]+["] this.begin("href"); ["] this.popState(); [^"]* return 'HREF'; @@ -89,41 +86,53 @@ the line was introduced with 'click'. arguments to the node that was specified by 'click'. Function arguments are optional: 'call ()' simply executes 'callback_name' without any arguments. */ -"call"[\s]+ this.begin("callback_name"); +<*>"call"[\s]+ this.begin("callback_name"); \([\s]*\) this.popState(); \( this.popState(); this.begin("callback_args"); [^(]* return 'CALLBACK_NAME'; \) this.popState(); [^)]* return 'CALLBACK_ARGS'; -"_self" return 'LINK_TARGET'; -"_blank" return 'LINK_TARGET'; -"_parent" return 'LINK_TARGET'; -"_top" return 'LINK_TARGET'; +[~] this.popState(); +[^~]* return "GENERICTYPE"; +<*>[~] this.begin("generic"); -\s*\<\| return 'EXTENSION'; -\s*\|\> return 'EXTENSION'; -\s*\> return 'DEPENDENCY'; -\s*\< return 'DEPENDENCY'; -\s*\* return 'COMPOSITION'; -\s*o return 'AGGREGATION'; -\s*\(\) return 'LOLLIPOP'; -\-\- return 'LINE'; -\.\. return 'DOTTED_LINE'; -":"{1}[^:\n;]+ return 'LABEL'; -":"{3} return 'STYLE_SEPARATOR'; -\- return 'MINUS'; -"." return 'DOT'; -\+ return 'PLUS'; -\% return 'PCT'; -"=" return 'EQUALS'; -\= return 'EQUALS'; -\w+ return 'ALPHA'; -"[" return 'SQS'; -"]" return 'SQE'; -[!"#$%&'*+,-.`?\\/] return 'PUNCTUATION'; -[0-9]+ return 'NUM'; -[\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6]| +["] this.popState(); +[^"]* return "STR"; +<*>["] this.begin("string"); + +[`] this.popState(); +[^`]+ return "BQUOTE_STR"; +<*>[`] this.begin("bqstring"); + +<*>"_self" return 'LINK_TARGET'; +<*>"_blank" return 'LINK_TARGET'; +<*>"_parent" return 'LINK_TARGET'; +<*>"_top" return 'LINK_TARGET'; + +<*>\s*\<\| return 'EXTENSION'; +<*>\s*\|\> return 'EXTENSION'; +<*>\s*\> return 'DEPENDENCY'; +<*>\s*\< return 'DEPENDENCY'; +<*>\s*\* return 'COMPOSITION'; +<*>\s*o return 'AGGREGATION'; +<*>\s*\(\) return 'LOLLIPOP'; +<*>\-\- return 'LINE'; +<*>\.\. return 'DOTTED_LINE'; +<*>":"{1}[^:\n;]+ return 'LABEL'; +<*>":"{3} return 'STYLE_SEPARATOR'; +<*>\- return 'MINUS'; +<*>"." return 'DOT'; +<*>\+ return 'PLUS'; +<*>\% return 'PCT'; +<*>"=" return 'EQUALS'; +<*>\= return 'EQUALS'; +<*>\w+ return 'ALPHA'; +<*>"[" return 'SQS'; +<*>"]" return 'SQE'; +<*>[!"#$%&'*+,-.`?\\/] return 'PUNCTUATION'; +<*>[0-9]+ return 'NUM'; +<*>[\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6]| [\u00F8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377]| [\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5]| [\u03F7-\u0481\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA]| @@ -184,9 +193,9 @@ Function arguments are optional: 'call ()' simply executes 'callb [\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC]| [\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF]| [\uFFD2-\uFFD7\uFFDA-\uFFDC] - return 'UNICODE_TEXT'; -\s return 'SPACE'; -<> return 'EOF'; + return 'UNICODE_TEXT'; +<*>\s return 'SPACE'; +<*><> return 'EOF'; /lex From 4017bb3c49d26c50ec87e3afcb9bf2b0b8cd1593 Mon Sep 17 00:00:00 2001 From: Kazuki Tsunemi Date: Thu, 9 Mar 2023 17:42:38 +0900 Subject: [PATCH 2/8] Implement namespace parser --- .../mermaid/src/diagrams/class/classDb.ts | 25 +++++++++++++ .../src/diagrams/class/classDiagram.spec.ts | 31 ++++++++++++++++ .../diagrams/class/parser/classDiagram.jison | 36 ++++++++++++++++++- 3 files changed, 91 insertions(+), 1 deletion(-) diff --git a/packages/mermaid/src/diagrams/class/classDb.ts b/packages/mermaid/src/diagrams/class/classDb.ts index 48ef7ccbe..851353477 100644 --- a/packages/mermaid/src/diagrams/class/classDb.ts +++ b/packages/mermaid/src/diagrams/class/classDb.ts @@ -392,6 +392,29 @@ const setDirection = (dir: string) => { direction = dir; }; +/** + * Function called by parser when a namespace keyword has been found. + * + * @param id - Id of the namespace to add + * @public + */ +// eslint-disable-next-line @typescript-eslint/no-unused-vars +export const addNamespace = function (id: string) { + // TODO: Implement here +}; + +/** + * Function called by parser when a namespace definition has been found. + * + * @param id - Id of the namespace to add + * @param classNames - Ids of the class to add + * @public + */ +// eslint-disable-next-line @typescript-eslint/no-unused-vars +export const addClassesToNamespace = function (id: string, classNames: string[]) { + // TODO: Implement here +}; + export default { parseDirective, setAccTitle, @@ -425,4 +448,6 @@ export default { setDiagramTitle, getDiagramTitle, setClassLabel, + addNamespace, + addClassesToNamespace, }; diff --git a/packages/mermaid/src/diagrams/class/classDiagram.spec.ts b/packages/mermaid/src/diagrams/class/classDiagram.spec.ts index 24fbc41ea..11b556179 100644 --- a/packages/mermaid/src/diagrams/class/classDiagram.spec.ts +++ b/packages/mermaid/src/diagrams/class/classDiagram.spec.ts @@ -571,6 +571,37 @@ foo() const str = 'classDiagram\n' + 'note "test"\n'; parser.parse(str); }); + + it('should handle "namespace"', function () { + const str = `classDiagram +namespace Namespace1 { class Class1 } +namespace Namespace2 { class Class1 +} +namespace Namespace3 { +class Class1 { +int : test +string : foo +test() +foo() +} +} +namespace Namespace4 { +class Class1 { +int : test +string : foo +test() +foo() +} +class Class2 { +int : test +string : foo +test() +foo() +} +} +`; + parser.parse(str); + }); }); describe('when fetching data from a classDiagram it', function () { diff --git a/packages/mermaid/src/diagrams/class/parser/classDiagram.jison b/packages/mermaid/src/diagrams/class/parser/classDiagram.jison index 4e68372f3..1c0ccdbbe 100644 --- a/packages/mermaid/src/diagrams/class/parser/classDiagram.jison +++ b/packages/mermaid/src/diagrams/class/parser/classDiagram.jison @@ -21,6 +21,8 @@ %x acc_descr_multiline %x class %x class-body +%x namespace +%x namespace-body %% \%\%\{ { this.begin('open_directive'); return 'open_directive'; } .*direction\s+TB[^\n]* return 'direction_tb'; @@ -48,9 +50,20 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multili "classDiagram" return 'CLASS_DIAGRAM'; "[*]" return 'EDGE_STATE'; -"class" { this.begin('class'); return 'CLASS';} +"namespace" { this.begin('namespace'); return 'NAMESPACE'; } +\s*(\r?\n)+ { this.popState(); return 'NEWLINE'; } +\s+ /* skip whitespace */ +[{] { this.begin("namespace-body"); return 'STRUCT_START';} +[}] { this.popState(); return 'STRUCT_STOP'; } +<> return "EOF_IN_STRUCT"; +\s*(\r?\n)+ return 'NEWLINE'; +\s+ /* skip whitespace */ +"[*]" return 'EDGE_STATE'; + +"class" { this.begin('class'); return 'CLASS';} \s*(\r?\n)+ { this.popState(); return 'NEWLINE'; } \s+ /* skip whitespace */ +[}] { this.popState(); this.popState(); return 'STRUCT_STOP';} [{] { this.begin("class-body"); return 'STRUCT_START';} [}] { this.popState(); return 'STRUCT_STOP'; } <> return "EOF_IN_STRUCT"; @@ -264,6 +277,11 @@ classLabel : SQS STR SQE { $$=$2; } ; +namespaceName + : alphaNumToken { $$=$1; } + | alphaNumToken namespaceName { $$=$1+$2; } + ; + className : alphaNumToken { $$=$1; } | classLiteralName { $$=$1; } @@ -275,6 +293,7 @@ className statement : relationStatement { yy.addRelation($1); } | relationStatement LABEL { $1.title = yy.cleanupLabel($2); yy.addRelation($1); } + | namespaceStatement | classStatement | methodStatement | annotationStatement @@ -288,6 +307,21 @@ statement | acc_descr_multiline_value { $$=$1.trim();yy.setAccDescription($$); } ; +namespaceStatement + : namespaceIdentifier STRUCT_START classStatements STRUCT_STOP {yy.addClassesToNamespace($1, $3);} + | namespaceIdentifier STRUCT_START NEWLINE classStatements STRUCT_STOP {yy.addClassesToNamespace($1, $4);} + ; + +namespaceIdentifier + : NAMESPACE namespaceName {$$=$2; yy.addNamespace($2);} + ; + +classStatements + : classStatement {$$=[$1]} + | classStatement NEWLINE {$$=[$1]} + | classStatement NEWLINE classStatements {$3.unshift($1); $$=$3} + ; + classStatement : classIdentifier | classIdentifier STYLE_SEPARATOR alphaNumToken {yy.setCssClass($1, $3);} From 75502d076e843d3eb932c86027849347df737e08 Mon Sep 17 00:00:00 2001 From: Kazuki Tsunemi Date: Fri, 10 Mar 2023 19:37:54 +0900 Subject: [PATCH 3/8] Implement database for namespace data --- .../mermaid/src/diagrams/class/classDb.ts | 46 ++++++++++++++++--- .../src/diagrams/class/classDiagram.spec.ts | 19 ++++++++ .../mermaid/src/diagrams/class/classTypes.ts | 9 ++++ 3 files changed, 67 insertions(+), 7 deletions(-) diff --git a/packages/mermaid/src/diagrams/class/classDb.ts b/packages/mermaid/src/diagrams/class/classDb.ts index 851353477..18e218244 100644 --- a/packages/mermaid/src/diagrams/class/classDb.ts +++ b/packages/mermaid/src/diagrams/class/classDb.ts @@ -14,7 +14,14 @@ import { setDiagramTitle, getDiagramTitle, } from '../../commonDb'; -import { ClassRelation, ClassNode, ClassNote, ClassMap } from './classTypes'; +import { + ClassRelation, + ClassNode, + ClassNote, + ClassMap, + NamespaceMap, + NamespaceNode, +} from './classTypes'; const MERMAID_DOM_ID_PREFIX = 'classId-'; @@ -22,6 +29,8 @@ let relations: ClassRelation[] = []; let classes: ClassMap = {}; let notes: ClassNote[] = []; let classCounter = 0; +let namespaces: NamespaceMap = {}; +let namespaceCounter = 0; let functions: any[] = []; @@ -100,6 +109,8 @@ export const clear = function () { notes = []; functions = []; functions.push(setupToolTips); + namespaces = {}; + namespaceCounter = 0; commonClear(); }; @@ -393,14 +404,28 @@ const setDirection = (dir: string) => { }; /** - * Function called by parser when a namespace keyword has been found. + * Function called by parser when a namespace definition has been found. * * @param id - Id of the namespace to add * @public */ -// eslint-disable-next-line @typescript-eslint/no-unused-vars -export const addNamespace = function (id: string) { - // TODO: Implement here +export const addNamespace = function (name: string) { + namespaces[name] = { + id: name, + domId: MERMAID_DOM_ID_PREFIX + name + '-' + namespaceCounter, + classes: {}, + children: {}, + }; + + namespaceCounter++; +}; + +const getNamespace = function (name: string): NamespaceNode { + return namespaces[name]; +}; + +const getNamespaces = function (): NamespaceMap { + return namespaces; }; /** @@ -410,9 +435,14 @@ export const addNamespace = function (id: string) { * @param classNames - Ids of the class to add * @public */ -// eslint-disable-next-line @typescript-eslint/no-unused-vars export const addClassesToNamespace = function (id: string, classNames: string[]) { - // TODO: Implement here + if (namespaces[id] !== undefined) { + classNames.map((className) => { + namespaces[id].classes[className] = classes[className]; + delete classes[className]; + classCounter--; + }); + } }; export default { @@ -450,4 +480,6 @@ export default { setClassLabel, addNamespace, addClassesToNamespace, + getNamespace, + getNamespaces, }; diff --git a/packages/mermaid/src/diagrams/class/classDiagram.spec.ts b/packages/mermaid/src/diagrams/class/classDiagram.spec.ts index 11b556179..48d7ca64d 100644 --- a/packages/mermaid/src/diagrams/class/classDiagram.spec.ts +++ b/packages/mermaid/src/diagrams/class/classDiagram.spec.ts @@ -1008,6 +1008,25 @@ foo() expect(classDb.setClickEvent).toHaveBeenCalledWith('Class1', 'functionCall'); expect(classDb.setTooltip).toHaveBeenCalledWith('Class1', 'A tooltip'); }); + + it('should add classes namespaces', function () { + const str = `classDiagram +namespace Namespace1 { +class Class1 { +int : test +string : foo +test() +foo() +} +class Class2 +}`; + parser.parse(str); + + const testNamespace = parser.yy.getNamespace('Namespace1'); + expect(Object.keys(testNamespace.classes).length).toBe(2); + expect(Object.keys(testNamespace.children).length).toBe(0); + expect(testNamespace.classes['Class1'].id).toBe('Class1'); + }); }); describe('when parsing classDiagram with text labels', () => { diff --git a/packages/mermaid/src/diagrams/class/classTypes.ts b/packages/mermaid/src/diagrams/class/classTypes.ts index 4cacad3db..cf6f20f0b 100644 --- a/packages/mermaid/src/diagrams/class/classTypes.ts +++ b/packages/mermaid/src/diagrams/class/classTypes.ts @@ -52,4 +52,13 @@ export type ClassRelation = { lineType: number; }; }; + +export interface NamespaceNode { + id: string; + domId: string; + classes: ClassMap; + children: NamespaceMap; +} + export type ClassMap = Record; +export type NamespaceMap = Record; From 434961b44a5705a9f198047a76712bd97b982f91 Mon Sep 17 00:00:00 2001 From: Kazuki Tsunemi Date: Fri, 10 Mar 2023 18:04:05 +0900 Subject: [PATCH 4/8] Implement rendering logic --- .../rendering/classDiagram-v2.spec.js | 14 ++++ .../mermaid/src/diagrams/class/classDb.ts | 20 ++++-- .../src/diagrams/class/classRenderer-v2.ts | 67 ++++++++++++++++++- 3 files changed, 92 insertions(+), 9 deletions(-) diff --git a/cypress/integration/rendering/classDiagram-v2.spec.js b/cypress/integration/rendering/classDiagram-v2.spec.js index 71810cfa4..90ad677ea 100644 --- a/cypress/integration/rendering/classDiagram-v2.spec.js +++ b/cypress/integration/rendering/classDiagram-v2.spec.js @@ -548,4 +548,18 @@ class C13["With Città foreign language"] ` ); }); + it('should add classes namespaces', function () { + imgSnapshotTest( + ` + classDiagram + namespace Namespace1 { + class C1 + class C2 + } + C1 --> C2 + class C3 + class C4 + ` + ); + }); }); diff --git a/packages/mermaid/src/diagrams/class/classDb.ts b/packages/mermaid/src/diagrams/class/classDb.ts index 18e218244..6468b5e8c 100644 --- a/packages/mermaid/src/diagrams/class/classDb.ts +++ b/packages/mermaid/src/diagrams/class/classDb.ts @@ -245,7 +245,11 @@ const setTooltip = function (ids: string, tooltip?: string) { } }); }; -export const getTooltip = function (id: string) { +export const getTooltip = function (id: string, namespace?: string) { + if (namespace) { + return namespaces[namespace].classes[id].tooltip; + } + return classes[id].tooltip; }; /** @@ -409,13 +413,17 @@ const setDirection = (dir: string) => { * @param id - Id of the namespace to add * @public */ -export const addNamespace = function (name: string) { - namespaces[name] = { - id: name, - domId: MERMAID_DOM_ID_PREFIX + name + '-' + namespaceCounter, +export const addNamespace = function (id: string) { + if (namespaces[id] !== undefined) { + return; + } + + namespaces[id] = { + id: id, classes: {}, children: {}, - }; + domId: MERMAID_DOM_ID_PREFIX + id + '-' + namespaceCounter, + } as NamespaceNode; namespaceCounter++; }; diff --git a/packages/mermaid/src/diagrams/class/classRenderer-v2.ts b/packages/mermaid/src/diagrams/class/classRenderer-v2.ts index e308990c6..e9b221141 100644 --- a/packages/mermaid/src/diagrams/class/classRenderer-v2.ts +++ b/packages/mermaid/src/diagrams/class/classRenderer-v2.ts @@ -8,7 +8,7 @@ import utils from '../../utils'; import { interpolateToCurve, getStylesFromArray } from '../../utils'; import { setupGraphViewbox } from '../../setupGraphViewbox'; import common from '../common/common'; -import { ClassRelation, ClassNote, ClassMap, EdgeData } from './classTypes'; +import { ClassRelation, ClassNote, ClassMap, EdgeData, NamespaceMap } from './classTypes'; const sanitizeText = (txt: string) => common.sanitizeText(txt, getConfig()); @@ -19,6 +19,58 @@ let conf = { curve: undefined, }; +interface RectParameters { + id: string; + shape: 'rect'; + labelStyle: string; + domId: string; + labelText: string; + padding: number | undefined; + style?: string; +} + +/** + * Function that adds the vertices found during parsing to the graph to be rendered. + * + * @param namespaces - Object containing the vertices. + * @param g - The graph that is to be drawn. + * @param _id - id of the graph + * @param diagObj - The diagram object + */ +export const addNamespaces = function ( + namespaces: NamespaceMap, + g: graphlib.Graph, + _id: string, + diagObj: any +) { + const keys = Object.keys(namespaces); + log.info('keys:', keys); + log.info(namespaces); + + // Iterate through each item in the vertex object (containing all the vertices found) in the graph definition + keys.forEach(function (id) { + const vertex = namespaces[id]; + + // parent node must be one of [rect, roundedWithTitle, noteGroup, divider] + const shape = 'rect'; + + const node: RectParameters = { + shape: shape, + id: vertex.id, + domId: vertex.domId, + labelText: sanitizeText(vertex.id), + labelStyle: '', + // TODO V10: Flowchart ? Keeping flowchart for backwards compatibility. Remove in next major release + padding: getConfig().flowchart?.padding ?? getConfig().class?.padding, + }; + + g.setNode(vertex.id, node); + addClasses(vertex.classes, g, _id, diagObj, vertex.id); + + log.info('setNode', node); + }); +}; + /** * Function that adds the vertices found during parsing to the graph to be rendered. * @@ -31,7 +83,8 @@ export const addClasses = function ( classes: ClassMap, g: graphlib.Graph, _id: string, - diagObj: any + diagObj: any, + parent?: string ) { const keys = Object.keys(classes); log.info('keys:', keys); @@ -55,6 +108,7 @@ export const addClasses = function ( const vertexText = vertex.label ?? vertex.id; const radius = 0; const shape = 'class_box'; + // Add the node const node = { labelStyle: styles.labelStyle, @@ -67,7 +121,7 @@ export const addClasses = function ( style: styles.style, id: vertex.id, domId: vertex.domId, - tooltip: diagObj.db.getTooltip(vertex.id) || '', + tooltip: diagObj.db.getTooltip(vertex.id, parent) || '', haveCallback: vertex.haveCallback, link: vertex.link, width: vertex.type === 'group' ? 500 : undefined, @@ -76,6 +130,11 @@ export const addClasses = function ( padding: getConfig().flowchart?.padding ?? getConfig().class?.padding, }; g.setNode(vertex.id, node); + + if (parent) { + g.setParent(vertex.id, parent); + } + log.info('setNode', node); }); }; @@ -275,10 +334,12 @@ export const draw = function (text: string, id: string, _version: string, diagOb }); // Fetch the vertices/nodes and edges/links from the parsed graph definition + const namespaces: NamespaceMap = diagObj.db.getNamespaces(); const classes: ClassMap = diagObj.db.getClasses(); const relations: ClassRelation[] = diagObj.db.getRelations(); const notes: ClassNote[] = diagObj.db.getNotes(); log.info(relations); + addNamespaces(namespaces, g, id, diagObj); addClasses(classes, g, id, diagObj); addRelations(relations, g); addNotes(notes, g, relations.length + 1, classes); From b51b2c7b04fab4135044b984dcb94a4a4edd6c41 Mon Sep 17 00:00:00 2001 From: Kazuki Tsunemi Date: Fri, 17 Mar 2023 14:21:31 +0900 Subject: [PATCH 5/8] Add namespace sample to README --- README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/README.md b/README.md index d42e2f7e1..d8e06b62f 100644 --- a/README.md +++ b/README.md @@ -165,6 +165,13 @@ class Class10 { int id size() } +namespace Namespace01 { + class Class11 + class Class12 { + int id + size() + } +} ``` ```mermaid @@ -184,6 +191,13 @@ class Class10 { int id size() } +namespace Namespace01 { + class Class11 + class Class12 { + int id + size() + } +} ``` ### State diagram [docs - live editor] From b725b69fda5641904a5ec89ef75533093439a874 Mon Sep 17 00:00:00 2001 From: Kazuki Tsunemi Date: Fri, 17 Mar 2023 14:47:32 +0900 Subject: [PATCH 6/8] Add package of class diagrams to doc --- docs/syntax/classDiagram.md | 28 +++++++++++++++++++ .../mermaid/src/docs/syntax/classDiagram.md | 17 +++++++++++ 2 files changed, 45 insertions(+) diff --git a/docs/syntax/classDiagram.md b/docs/syntax/classDiagram.md index 69144ef39..bc44a4c48 100644 --- a/docs/syntax/classDiagram.md +++ b/docs/syntax/classDiagram.md @@ -421,6 +421,34 @@ And `Link` can be one of: | -- | Solid | | .. | Dashed | +## Define Namespace + +A namespace groups classes. + +Code: + +```mermaid-example +classDiagram +namespace BaseShapes { + class Triangle + class Rectangle { + double width + double height + } +} +``` + +```mermaid +classDiagram +namespace BaseShapes { + class Triangle + class Rectangle { + double width + double height + } +} +``` + ## Cardinality / Multiplicity on relations Multiplicity or cardinality in class diagrams indicates the number of instances of one class that can be linked to an instance of the other class. For example, each company will have one or more employees (not zero), and each employee currently works for zero or one companies. diff --git a/packages/mermaid/src/docs/syntax/classDiagram.md b/packages/mermaid/src/docs/syntax/classDiagram.md index 9d3766590..588aff874 100644 --- a/packages/mermaid/src/docs/syntax/classDiagram.md +++ b/packages/mermaid/src/docs/syntax/classDiagram.md @@ -277,6 +277,23 @@ And `Link` can be one of: | -- | Solid | | .. | Dashed | +## Define Namespace + +A namespace groups classes. + +Code: + +```mermaid-example +classDiagram +namespace BaseShapes { + class Triangle + class Rectangle { + double width + double height + } +} +``` + ## Cardinality / Multiplicity on relations Multiplicity or cardinality in class diagrams indicates the number of instances of one class that can be linked to an instance of the other class. For example, each company will have one or more employees (not zero), and each employee currently works for zero or one companies. From 70a52da3932da47d8ffc8288d74576f54dfd1dc9 Mon Sep 17 00:00:00 2001 From: Kazuki Tsunemi Date: Mon, 1 May 2023 19:06:46 +0900 Subject: [PATCH 7/8] namespace rect is not filled --- packages/mermaid/src/diagrams/class/classRenderer-v2.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/mermaid/src/diagrams/class/classRenderer-v2.ts b/packages/mermaid/src/diagrams/class/classRenderer-v2.ts index f31cf8890..40fad703e 100644 --- a/packages/mermaid/src/diagrams/class/classRenderer-v2.ts +++ b/packages/mermaid/src/diagrams/class/classRenderer-v2.ts @@ -60,6 +60,7 @@ export const addNamespaces = function ( domId: vertex.domId, labelText: sanitizeText(vertex.id), labelStyle: '', + style: 'fill: none; stroke: black', // TODO V10: Flowchart ? Keeping flowchart for backwards compatibility. Remove in next major release padding: getConfig().flowchart?.padding ?? getConfig().class?.padding, }; From 0d373f3a6ab7c8f858b243bfc76677f70b93ade6 Mon Sep 17 00:00:00 2001 From: Kazuki Tsunemi Date: Mon, 1 May 2023 19:12:39 +0900 Subject: [PATCH 8/8] Modify jsdoc of addClasses --- packages/mermaid/src/diagrams/class/classRenderer-v2.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/mermaid/src/diagrams/class/classRenderer-v2.ts b/packages/mermaid/src/diagrams/class/classRenderer-v2.ts index 40fad703e..352002242 100644 --- a/packages/mermaid/src/diagrams/class/classRenderer-v2.ts +++ b/packages/mermaid/src/diagrams/class/classRenderer-v2.ts @@ -79,6 +79,7 @@ export const addNamespaces = function ( * @param g - The graph that is to be drawn. * @param _id - id of the graph * @param diagObj - The diagram object + * @param parent - id of the parent namespace, if it exists */ export const addClasses = function ( classes: ClassMap,