Skip to content

Commit cf45a35

Browse files
committed
Updated the code to include nested namespaces for class diagrams
1 parent dd03043 commit cf45a35

File tree

5 files changed

+185
-40
lines changed

5 files changed

+185
-40
lines changed

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
./packages/mermaid/src/docs/community/contributing.md
1+
./packages/mermaid/src/docs/community/contributing.md

cypress/downloads/downloads.htm

1.4 MB
Binary file not shown.

demos/classchart.html

Lines changed: 75 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -159,30 +159,89 @@ <h1>Class diagram demos</h1>
159159
class People List~List~Person~~
160160
</pre>
161161
<hr />
162-
163162
<pre class="mermaid">
164-
classDiagram
165-
A1 --> B1
166-
namespace A {
167-
class A1 {
168-
+foo : string
163+
classDiagram
164+
namespace Company.Project.Module {
165+
class GenericClass~T~ {
166+
+addItem(item: T)
167+
+getItem() T
168+
}
169+
}
170+
</pre>
171+
<hr />
172+
<pre class="mermaid">
173+
classDiagram
174+
namespace Company.Project.Module.SubModule {
175+
class Report {
176+
+generatePDF(data: List)
177+
+generateCSV(data: List)
178+
}
169179
}
170-
class A2 {
171-
+bar : int
180+
namespace Company.Project.Module {
181+
class Admin {
182+
+generateReport()
183+
}
172184
}
173-
}
174-
namespace B {
175-
class B1 {
176-
+foo : bool
185+
Admin --> Report : generates
186+
</pre>
187+
<pre class="mermaid">
188+
classDiagram
189+
namespace Company.Project.Module {
190+
class User {
191+
+login(username: String, password: String)
192+
+logout()
193+
}
194+
class Admin {
195+
+addUser(user: User)
196+
+removeUser(user: User)
197+
+generateReport()
177198
}
178-
class B2 {
179-
+bar : float
199+
class Report {
200+
+generatePDF(reportData: List)
201+
+generateCSV(reportData: List)
180202
}
203+
181204
}
182-
A2 --> B2
205+
Admin --> User : manages
206+
Admin --> Report : generates
183207
</pre>
184208
<hr />
185-
209+
<pre class="mermaid">
210+
classDiagram
211+
namespace Shapes {
212+
class Shape {
213+
+calculateArea() double
214+
}
215+
class Circle {
216+
+double radius
217+
}
218+
class Square {
219+
+double side
220+
}
221+
}
222+
223+
Shape <|-- Circle
224+
Shape <|-- Square
225+
226+
namespace Vehicles {
227+
class Vehicle {
228+
+String brand
229+
}
230+
class Car {
231+
+int horsepower
232+
}
233+
class Bike {
234+
+boolean hasGears
235+
}
236+
}
237+
238+
Vehicle <|-- Car
239+
Vehicle <|-- Bike
240+
241+
Car --> Circle : "Logo Shape"
242+
Bike --> Square : "Logo Shape"
243+
244+
</pre>
186245
<script type="module">
187246
import mermaid from './mermaid.esm.mjs';
188247
mermaid.initialize({

packages/mermaid/src/diagrams/class/classDiagram.spec.ts

Lines changed: 104 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,78 @@ describe('given a basic class diagram, ', function () {
1414
classDb.clear();
1515
parser.yy = classDb;
1616
});
17+
it('should handle classes within namespaces', () => {
18+
const str = `classDiagram
19+
namespace Company.Project {
20+
class User {
21+
+login(username: String, password: String)
22+
+logout()
23+
}
24+
}
25+
namespace Company.Project.Module {
26+
class Admin {
27+
+addUser(user: User)
28+
+removeUser(user: User)
29+
}
30+
}`;
31+
32+
parser.parse(str);
33+
34+
const user = classDb.getClass('User');
35+
const admin = classDb.getClass('Admin');
36+
37+
// Check if the classes are correctly registered under their respective namespaces
38+
expect(user.parent).toBe('Company.Project');
39+
expect(admin.parent).toBe('Company.Project.Module');
40+
expect(user.methods.length).toBe(2);
41+
expect(admin.methods.length).toBe(2);
42+
});
43+
44+
it('should handle generic classes within namespaces', () => {
45+
const str = `classDiagram
46+
namespace Company.Project.Module {
47+
class GenericClass~T~ {
48+
+addItem(item: T)
49+
+getItem() T
50+
}
51+
}`;
52+
53+
parser.parse(str);
54+
55+
const genericClass = classDb.getClass('GenericClass');
56+
expect(genericClass.type).toBe('T');
57+
expect(genericClass.methods[0].getDisplayDetails().displayText).toBe('+addItem(item: T)');
58+
expect(genericClass.methods[1].getDisplayDetails().displayText).toBe('+getItem() : T');
59+
});
60+
61+
it('should handle nested namespaces and relationships', () => {
62+
const str = ` classDiagram
63+
namespace Company.Project.Module.SubModule {
64+
class Report {
65+
+generatePDF(data: List)
66+
+generateCSV(data: List)
67+
}
68+
}
69+
namespace Company.Project.Module {
70+
class Admin {
71+
+generateReport()
72+
}
73+
}
74+
Admin --> Report : generates`;
75+
76+
parser.parse(str);
77+
78+
const report = classDb.getClass('Report');
79+
const admin = classDb.getClass('Admin');
80+
const relations = classDb.getRelations();
81+
82+
expect(report.parent).toBe('Company.Project.Module.SubModule');
83+
expect(admin.parent).toBe('Company.Project.Module');
84+
expect(relations[0].id1).toBe('Admin');
85+
expect(relations[0].id2).toBe('Report');
86+
expect(relations[0].title).toBe('generates');
87+
});
88+
1789
it('should handle accTitle and accDescr', function () {
1890
const str = `classDiagram
1991
accTitle: My Title
@@ -48,6 +120,22 @@ describe('given a basic class diagram, ', function () {
48120
}
49121
});
50122

123+
it('should handle fully qualified class names in relationships', () => {
124+
const str = `classDiagram
125+
namespace Company.Project.Module {
126+
class User
127+
class Admin
128+
}
129+
Admin --> User : manages`;
130+
131+
parser.parse(str);
132+
133+
const relations = classDb.getRelations();
134+
expect(relations[0].id1).toBe('Admin');
135+
expect(relations[0].id2).toBe('User');
136+
expect(relations[0].title).toBe('manages');
137+
});
138+
51139
it('should handle backquoted class names', function () {
52140
const str = 'classDiagram\n' + 'class `Car`';
53141

@@ -393,27 +481,23 @@ class C13["With Città foreign language"]
393481
Student "1" --o "1" IdCard : carries
394482
Student "1" --o "1" Bike : rides`);
395483

484+
const studentClass = classDb.getClasses().get('Student');
485+
// Check that the important properties match, but ignore the domId
486+
expect(studentClass).toMatchObject({
487+
id: 'Student',
488+
label: 'Student',
489+
members: [
490+
expect.objectContaining({
491+
id: 'idCard : IdCard',
492+
visibility: '-',
493+
}),
494+
],
495+
methods: [],
496+
annotations: [],
497+
cssClasses: [],
498+
});
499+
396500
expect(classDb.getClasses().size).toBe(3);
397-
expect(classDb.getClasses().get('Student')).toMatchInlineSnapshot(`
398-
{
399-
"annotations": [],
400-
"cssClasses": [],
401-
"domId": "classId-Student-134",
402-
"id": "Student",
403-
"label": "Student",
404-
"members": [
405-
ClassMember {
406-
"classifier": "",
407-
"id": "idCard : IdCard",
408-
"memberType": "attribute",
409-
"visibility": "-",
410-
},
411-
],
412-
"methods": [],
413-
"styles": [],
414-
"type": "",
415-
}
416-
`);
417501
expect(classDb.getRelations().length).toBe(2);
418502
expect(classDb.getRelations()).toMatchInlineSnapshot(`
419503
[

packages/mermaid/src/diagrams/class/parser/classDiagram.jison

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -241,11 +241,13 @@ classLabel
241241

242242
namespaceName
243243
: alphaNumToken { $$=$1; }
244+
| alphaNumToken DOT namespaceName { $$=$1+'.'+$3; }
244245
| alphaNumToken namespaceName { $$=$1+$2; }
245246
;
246247

247248
className
248249
: alphaNumToken { $$=$1; }
250+
| alphaNumToken DOT className { $$=$1+'.'+$3; } // Allow class names with dots
249251
| classLiteralName { $$=$1; }
250252
| alphaNumToken className { $$=$1+$2; }
251253
| alphaNumToken GENERICTYPE { $$=$1+'~'+$2+'~'; }
@@ -270,12 +272,12 @@ statement
270272
;
271273

272274
namespaceStatement
273-
: namespaceIdentifier STRUCT_START classStatements STRUCT_STOP {yy.addClassesToNamespace($1, $3);}
274-
| namespaceIdentifier STRUCT_START NEWLINE classStatements STRUCT_STOP {yy.addClassesToNamespace($1, $4);}
275+
: namespaceIdentifier STRUCT_START classStatements STRUCT_STOP { yy.addClassesToNamespace($1, $3); }
276+
| namespaceIdentifier STRUCT_START NEWLINE classStatements STRUCT_STOP { yy.addClassesToNamespace($1, $4); }
275277
;
276278

277279
namespaceIdentifier
278-
: NAMESPACE namespaceName {$$=$2; yy.addNamespace($2);}
280+
: NAMESPACE namespaceName { $$=$2; yy.addNamespace($2); }
279281
;
280282

281283
classStatements

0 commit comments

Comments
 (0)