mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-08-21 17:26:45 +02:00
Updated the code to include nested namespaces for class diagrams
This commit is contained in:
BIN
cypress/downloads/downloads.htm
Normal file
BIN
cypress/downloads/downloads.htm
Normal file
Binary file not shown.
@@ -159,30 +159,89 @@
|
|||||||
class People List~List~Person~~
|
class People List~List~Person~~
|
||||||
</pre>
|
</pre>
|
||||||
<hr />
|
<hr />
|
||||||
|
|
||||||
<pre class="mermaid">
|
<pre class="mermaid">
|
||||||
classDiagram
|
classDiagram
|
||||||
A1 --> B1
|
namespace Company.Project.Module {
|
||||||
namespace A {
|
class GenericClass~T~ {
|
||||||
class A1 {
|
+addItem(item: T)
|
||||||
+foo : string
|
+getItem() T
|
||||||
}
|
|
||||||
class A2 {
|
|
||||||
+bar : int
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
namespace B {
|
|
||||||
class B1 {
|
|
||||||
+foo : bool
|
|
||||||
}
|
|
||||||
class B2 {
|
|
||||||
+bar : float
|
|
||||||
}
|
|
||||||
}
|
|
||||||
A2 --> B2
|
|
||||||
</pre>
|
</pre>
|
||||||
<hr />
|
<hr />
|
||||||
|
<pre class="mermaid">
|
||||||
|
classDiagram
|
||||||
|
namespace Company.Project.Module.SubModule {
|
||||||
|
class Report {
|
||||||
|
+generatePDF(data: List)
|
||||||
|
+generateCSV(data: List)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
namespace Company.Project.Module {
|
||||||
|
class Admin {
|
||||||
|
+generateReport()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Admin --> Report : generates
|
||||||
|
</pre>
|
||||||
|
<pre class="mermaid">
|
||||||
|
classDiagram
|
||||||
|
namespace Company.Project.Module {
|
||||||
|
class User {
|
||||||
|
+login(username: String, password: String)
|
||||||
|
+logout()
|
||||||
|
}
|
||||||
|
class Admin {
|
||||||
|
+addUser(user: User)
|
||||||
|
+removeUser(user: User)
|
||||||
|
+generateReport()
|
||||||
|
}
|
||||||
|
class Report {
|
||||||
|
+generatePDF(reportData: List)
|
||||||
|
+generateCSV(reportData: List)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
Admin --> User : manages
|
||||||
|
Admin --> Report : generates
|
||||||
|
</pre>
|
||||||
|
<hr />
|
||||||
|
<pre class="mermaid">
|
||||||
|
classDiagram
|
||||||
|
namespace Shapes {
|
||||||
|
class Shape {
|
||||||
|
+calculateArea() double
|
||||||
|
}
|
||||||
|
class Circle {
|
||||||
|
+double radius
|
||||||
|
}
|
||||||
|
class Square {
|
||||||
|
+double side
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Shape <|-- Circle
|
||||||
|
Shape <|-- Square
|
||||||
|
|
||||||
|
namespace Vehicles {
|
||||||
|
class Vehicle {
|
||||||
|
+String brand
|
||||||
|
}
|
||||||
|
class Car {
|
||||||
|
+int horsepower
|
||||||
|
}
|
||||||
|
class Bike {
|
||||||
|
+boolean hasGears
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Vehicle <|-- Car
|
||||||
|
Vehicle <|-- Bike
|
||||||
|
|
||||||
|
Car --> Circle : "Logo Shape"
|
||||||
|
Bike --> Square : "Logo Shape"
|
||||||
|
|
||||||
|
</pre>
|
||||||
<script type="module">
|
<script type="module">
|
||||||
import mermaid from './mermaid.esm.mjs';
|
import mermaid from './mermaid.esm.mjs';
|
||||||
mermaid.initialize({
|
mermaid.initialize({
|
||||||
|
@@ -14,6 +14,78 @@ describe('given a basic class diagram, ', function () {
|
|||||||
classDb.clear();
|
classDb.clear();
|
||||||
parser.yy = classDb;
|
parser.yy = classDb;
|
||||||
});
|
});
|
||||||
|
it('should handle classes within namespaces', () => {
|
||||||
|
const str = `classDiagram
|
||||||
|
namespace Company.Project {
|
||||||
|
class User {
|
||||||
|
+login(username: String, password: String)
|
||||||
|
+logout()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
namespace Company.Project.Module {
|
||||||
|
class Admin {
|
||||||
|
+addUser(user: User)
|
||||||
|
+removeUser(user: User)
|
||||||
|
}
|
||||||
|
}`;
|
||||||
|
|
||||||
|
parser.parse(str);
|
||||||
|
|
||||||
|
const user = classDb.getClass('User');
|
||||||
|
const admin = classDb.getClass('Admin');
|
||||||
|
|
||||||
|
// Check if the classes are correctly registered under their respective namespaces
|
||||||
|
expect(user.parent).toBe('Company.Project');
|
||||||
|
expect(admin.parent).toBe('Company.Project.Module');
|
||||||
|
expect(user.methods.length).toBe(2);
|
||||||
|
expect(admin.methods.length).toBe(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle generic classes within namespaces', () => {
|
||||||
|
const str = `classDiagram
|
||||||
|
namespace Company.Project.Module {
|
||||||
|
class GenericClass~T~ {
|
||||||
|
+addItem(item: T)
|
||||||
|
+getItem() T
|
||||||
|
}
|
||||||
|
}`;
|
||||||
|
|
||||||
|
parser.parse(str);
|
||||||
|
|
||||||
|
const genericClass = classDb.getClass('GenericClass');
|
||||||
|
expect(genericClass.type).toBe('T');
|
||||||
|
expect(genericClass.methods[0].getDisplayDetails().displayText).toBe('+addItem(item: T)');
|
||||||
|
expect(genericClass.methods[1].getDisplayDetails().displayText).toBe('+getItem() : T');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle nested namespaces and relationships', () => {
|
||||||
|
const str = ` classDiagram
|
||||||
|
namespace Company.Project.Module.SubModule {
|
||||||
|
class Report {
|
||||||
|
+generatePDF(data: List)
|
||||||
|
+generateCSV(data: List)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
namespace Company.Project.Module {
|
||||||
|
class Admin {
|
||||||
|
+generateReport()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Admin --> Report : generates`;
|
||||||
|
|
||||||
|
parser.parse(str);
|
||||||
|
|
||||||
|
const report = classDb.getClass('Report');
|
||||||
|
const admin = classDb.getClass('Admin');
|
||||||
|
const relations = classDb.getRelations();
|
||||||
|
|
||||||
|
expect(report.parent).toBe('Company.Project.Module.SubModule');
|
||||||
|
expect(admin.parent).toBe('Company.Project.Module');
|
||||||
|
expect(relations[0].id1).toBe('Admin');
|
||||||
|
expect(relations[0].id2).toBe('Report');
|
||||||
|
expect(relations[0].title).toBe('generates');
|
||||||
|
});
|
||||||
|
|
||||||
it('should handle accTitle and accDescr', function () {
|
it('should handle accTitle and accDescr', function () {
|
||||||
const str = `classDiagram
|
const str = `classDiagram
|
||||||
accTitle: My Title
|
accTitle: My Title
|
||||||
@@ -48,6 +120,22 @@ describe('given a basic class diagram, ', function () {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should handle fully qualified class names in relationships', () => {
|
||||||
|
const str = `classDiagram
|
||||||
|
namespace Company.Project.Module {
|
||||||
|
class User
|
||||||
|
class Admin
|
||||||
|
}
|
||||||
|
Admin --> User : manages`;
|
||||||
|
|
||||||
|
parser.parse(str);
|
||||||
|
|
||||||
|
const relations = classDb.getRelations();
|
||||||
|
expect(relations[0].id1).toBe('Admin');
|
||||||
|
expect(relations[0].id2).toBe('User');
|
||||||
|
expect(relations[0].title).toBe('manages');
|
||||||
|
});
|
||||||
|
|
||||||
it('should handle backquoted class names', function () {
|
it('should handle backquoted class names', function () {
|
||||||
const str = 'classDiagram\n' + 'class `Car`';
|
const str = 'classDiagram\n' + 'class `Car`';
|
||||||
|
|
||||||
@@ -393,27 +481,23 @@ class C13["With Città foreign language"]
|
|||||||
Student "1" --o "1" IdCard : carries
|
Student "1" --o "1" IdCard : carries
|
||||||
Student "1" --o "1" Bike : rides`);
|
Student "1" --o "1" Bike : rides`);
|
||||||
|
|
||||||
expect(classDb.getClasses().size).toBe(3);
|
const studentClass = classDb.getClasses().get('Student');
|
||||||
expect(classDb.getClasses().get('Student')).toMatchInlineSnapshot(`
|
// Check that the important properties match, but ignore the domId
|
||||||
{
|
expect(studentClass).toMatchObject({
|
||||||
"annotations": [],
|
id: 'Student',
|
||||||
"cssClasses": [],
|
label: 'Student',
|
||||||
"domId": "classId-Student-134",
|
members: [
|
||||||
"id": "Student",
|
expect.objectContaining({
|
||||||
"label": "Student",
|
id: 'idCard : IdCard',
|
||||||
"members": [
|
visibility: '-',
|
||||||
ClassMember {
|
}),
|
||||||
"classifier": "",
|
|
||||||
"id": "idCard : IdCard",
|
|
||||||
"memberType": "attribute",
|
|
||||||
"visibility": "-",
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
"methods": [],
|
methods: [],
|
||||||
"styles": [],
|
annotations: [],
|
||||||
"type": "",
|
cssClasses: [],
|
||||||
}
|
});
|
||||||
`);
|
|
||||||
|
expect(classDb.getClasses().size).toBe(3);
|
||||||
expect(classDb.getRelations().length).toBe(2);
|
expect(classDb.getRelations().length).toBe(2);
|
||||||
expect(classDb.getRelations()).toMatchInlineSnapshot(`
|
expect(classDb.getRelations()).toMatchInlineSnapshot(`
|
||||||
[
|
[
|
||||||
|
@@ -241,11 +241,13 @@ classLabel
|
|||||||
|
|
||||||
namespaceName
|
namespaceName
|
||||||
: alphaNumToken { $$=$1; }
|
: alphaNumToken { $$=$1; }
|
||||||
|
| alphaNumToken DOT namespaceName { $$=$1+'.'+$3; }
|
||||||
| alphaNumToken namespaceName { $$=$1+$2; }
|
| alphaNumToken namespaceName { $$=$1+$2; }
|
||||||
;
|
;
|
||||||
|
|
||||||
className
|
className
|
||||||
: alphaNumToken { $$=$1; }
|
: alphaNumToken { $$=$1; }
|
||||||
|
| alphaNumToken DOT className { $$=$1+'.'+$3; } // Allow class names with dots
|
||||||
| classLiteralName { $$=$1; }
|
| classLiteralName { $$=$1; }
|
||||||
| alphaNumToken className { $$=$1+$2; }
|
| alphaNumToken className { $$=$1+$2; }
|
||||||
| alphaNumToken GENERICTYPE { $$=$1+'~'+$2+'~'; }
|
| alphaNumToken GENERICTYPE { $$=$1+'~'+$2+'~'; }
|
||||||
@@ -270,12 +272,12 @@ statement
|
|||||||
;
|
;
|
||||||
|
|
||||||
namespaceStatement
|
namespaceStatement
|
||||||
: namespaceIdentifier STRUCT_START classStatements STRUCT_STOP {yy.addClassesToNamespace($1, $3);}
|
: namespaceIdentifier STRUCT_START classStatements STRUCT_STOP { yy.addClassesToNamespace($1, $3); }
|
||||||
| namespaceIdentifier STRUCT_START NEWLINE classStatements STRUCT_STOP {yy.addClassesToNamespace($1, $4);}
|
| namespaceIdentifier STRUCT_START NEWLINE classStatements STRUCT_STOP { yy.addClassesToNamespace($1, $4); }
|
||||||
;
|
;
|
||||||
|
|
||||||
namespaceIdentifier
|
namespaceIdentifier
|
||||||
: NAMESPACE namespaceName {$$=$2; yy.addNamespace($2);}
|
: NAMESPACE namespaceName { $$=$2; yy.addNamespace($2); }
|
||||||
;
|
;
|
||||||
|
|
||||||
classStatements
|
classStatements
|
||||||
|
Reference in New Issue
Block a user