mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-12-10 06:24:16 +01:00
Compare commits
4 Commits
6587-class
...
gitgraph-m
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
256e81bcd2 | ||
|
|
513a3eef98 | ||
|
|
85a13da40f | ||
|
|
1269486124 |
5
.changeset/big-tools-do.md
Normal file
5
.changeset/big-tools-do.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'mermaid': patch
|
||||
---
|
||||
|
||||
fix: Handle master/main merges correctly in GitGraph diagrams
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'mermaid': patch
|
||||
---
|
||||
|
||||
fix: Added support for styling class diagram elements based on stereotype annotations
|
||||
@@ -1042,88 +1042,4 @@ class C13["With Città foreign language"]
|
||||
{ logLevel: 1, htmlLabels: true }
|
||||
);
|
||||
});
|
||||
it('should render a full class diagram using interface annotation', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
classDiagram
|
||||
Class01 <|-- AveryLongClass : Cool
|
||||
<<interface>> Class01
|
||||
Class03 "0" *-- "0..n" Class04
|
||||
Class05 "1" o-- "many" Class06
|
||||
Class07 .. Class08
|
||||
Class09 "many" --> "1" C2 : Where am i?
|
||||
Class09 "0" --* "1..n" C3
|
||||
Class09 --|> Class07
|
||||
Class07 : equals()
|
||||
Class07 : Object[] elementData
|
||||
Class01 : #size()
|
||||
Class01 : -int chimp
|
||||
Class01 : +int gorilla
|
||||
Class08 <--> C2: Cool label
|
||||
class Class10 {
|
||||
<<service>>
|
||||
int id
|
||||
size()
|
||||
}
|
||||
|
||||
`,
|
||||
{ logLevel: 1, htmlLabels: true }
|
||||
);
|
||||
});
|
||||
it('should render a full class diagram using abstract annotation', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
classDiagram
|
||||
Class01 <|-- AveryLongClass : Cool
|
||||
<<abstract>> Class01
|
||||
Class03 "0" *-- "0..n" Class04
|
||||
Class05 "1" o-- "many" Class06
|
||||
Class07 .. Class08
|
||||
Class09 "many" --> "1" C2 : Where am i?
|
||||
Class09 "0" --* "1..n" C3
|
||||
Class09 --|> Class07
|
||||
Class07 : equals()
|
||||
Class07 : Object[] elementData
|
||||
Class01 : #size()
|
||||
Class01 : -int chimp
|
||||
Class01 : +int gorilla
|
||||
Class08 <--> C2: Cool label
|
||||
class Class10 {
|
||||
<<service>>
|
||||
int id
|
||||
size()
|
||||
}
|
||||
|
||||
`,
|
||||
{ logLevel: 1, htmlLabels: true }
|
||||
);
|
||||
});
|
||||
it('should render a full class diagram using enumeration annotation', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
classDiagram
|
||||
Class01 <|-- AveryLongClass : Cool
|
||||
<<enumeration>> Class01
|
||||
Class03 "0" *-- "0..n" Class04
|
||||
Class05 "1" o-- "many" Class06
|
||||
Class07 .. Class08
|
||||
Class09 "many" --> "1" C2 : Where am i?
|
||||
Class09 "0" --* "1..n" C3
|
||||
Class09 --|> Class07
|
||||
Class07 : equals()
|
||||
Class07 : Object[] elementData
|
||||
Class01 : #size()
|
||||
Class01 : -int chimp
|
||||
Class01 : +int gorilla
|
||||
Class08 <--> C2: Cool label
|
||||
class Class10 {
|
||||
<<service>>
|
||||
int id
|
||||
size()
|
||||
}
|
||||
|
||||
`,
|
||||
{ logLevel: 1, htmlLabels: true }
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1569,4 +1569,14 @@ gitGraph TB:
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('77: should render a gitGraph merging main into a newly created branch', () => {
|
||||
imgSnapshotTest(
|
||||
`gitGraph
|
||||
commit
|
||||
branch stable
|
||||
checkout stable
|
||||
merge main`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,227 +2,227 @@
|
||||
"durations": [
|
||||
{
|
||||
"spec": "cypress/integration/other/configuration.spec.js",
|
||||
"duration": 5841
|
||||
"duration": 6099
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/other/external-diagrams.spec.js",
|
||||
"duration": 2138
|
||||
"duration": 2236
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/other/ghsa.spec.js",
|
||||
"duration": 3370
|
||||
"duration": 3405
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/other/iife.spec.js",
|
||||
"duration": 2052
|
||||
"duration": 2176
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/other/interaction.spec.js",
|
||||
"duration": 12243
|
||||
"duration": 12300
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/other/rerender.spec.js",
|
||||
"duration": 2065
|
||||
"duration": 2089
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/other/xss.spec.js",
|
||||
"duration": 31288
|
||||
"duration": 32033
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/appli.spec.js",
|
||||
"duration": 3421
|
||||
"duration": 3672
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/architecture.spec.ts",
|
||||
"duration": 97
|
||||
"duration": 103
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/block.spec.js",
|
||||
"duration": 18500
|
||||
"duration": 18135
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/c4.spec.js",
|
||||
"duration": 5793
|
||||
"duration": 5661
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/classDiagram-elk-v3.spec.js",
|
||||
"duration": 40966
|
||||
"duration": 41456
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/classDiagram-handDrawn-v3.spec.js",
|
||||
"duration": 39176
|
||||
"duration": 38910
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/classDiagram-v2.spec.js",
|
||||
"duration": 23468
|
||||
"duration": 24120
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/classDiagram-v3.spec.js",
|
||||
"duration": 38291
|
||||
"duration": 38454
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/classDiagram.spec.js",
|
||||
"duration": 16949
|
||||
"duration": 17099
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/conf-and-directives.spec.js",
|
||||
"duration": 9480
|
||||
"duration": 9844
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/current.spec.js",
|
||||
"duration": 2753
|
||||
"duration": 2951
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/erDiagram-unified.spec.js",
|
||||
"duration": 88028
|
||||
"duration": 90081
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/erDiagram.spec.js",
|
||||
"duration": 15615
|
||||
"duration": 19496
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/errorDiagram.spec.js",
|
||||
"duration": 3706
|
||||
"duration": 3829
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/flowchart-elk.spec.js",
|
||||
"duration": 43905
|
||||
"duration": 42517
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/flowchart-handDrawn.spec.js",
|
||||
"duration": 31217
|
||||
"duration": 31541
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/flowchart-icon.spec.js",
|
||||
"duration": 7531
|
||||
"duration": 7749
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/flowchart-shape-alias.spec.ts",
|
||||
"duration": 25423
|
||||
"duration": 25230
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/flowchart-v2.spec.js",
|
||||
"duration": 49664
|
||||
"duration": 49359
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/flowchart.spec.js",
|
||||
"duration": 32525
|
||||
"duration": 33028
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/gantt.spec.js",
|
||||
"duration": 20915
|
||||
"duration": 22271
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/gitGraph.spec.js",
|
||||
"duration": 53556
|
||||
"duration": 51837
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/iconShape.spec.ts",
|
||||
"duration": 283038
|
||||
"duration": 285060
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/imageShape.spec.ts",
|
||||
"duration": 59434
|
||||
"duration": 59517
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/info.spec.ts",
|
||||
"duration": 3101
|
||||
"duration": 3501
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/journey.spec.js",
|
||||
"duration": 7099
|
||||
"duration": 7405
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/kanban.spec.ts",
|
||||
"duration": 7567
|
||||
"duration": 7975
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/katex.spec.js",
|
||||
"duration": 3817
|
||||
"duration": 4312
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/marker_unique_id.spec.js",
|
||||
"duration": 2624
|
||||
"duration": 2630
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/mindmap-tidy-tree.spec.js",
|
||||
"duration": 4246
|
||||
"duration": 4541
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/mindmap.spec.ts",
|
||||
"duration": 11967
|
||||
"duration": 12134
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/newShapes.spec.ts",
|
||||
"duration": 151914
|
||||
"duration": 151160
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/oldShapes.spec.ts",
|
||||
"duration": 116698
|
||||
"duration": 118044
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/packet.spec.ts",
|
||||
"duration": 4967
|
||||
"duration": 5166
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/pie.spec.ts",
|
||||
"duration": 6700
|
||||
"duration": 7074
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/quadrantChart.spec.js",
|
||||
"duration": 8963
|
||||
"duration": 9518
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/radar.spec.js",
|
||||
"duration": 5540
|
||||
"duration": 5846
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/requirement.spec.js",
|
||||
"duration": 2782
|
||||
"duration": 3089
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/requirementDiagram-unified.spec.js",
|
||||
"duration": 54797
|
||||
"duration": 55361
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/sankey.spec.ts",
|
||||
"duration": 6914
|
||||
"duration": 7236
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/sequencediagram-v2.spec.js",
|
||||
"duration": 20481
|
||||
"duration": 26057
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/sequencediagram.spec.js",
|
||||
"duration": 38490
|
||||
"duration": 48401
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/stateDiagram-v2.spec.js",
|
||||
"duration": 30766
|
||||
"duration": 30364
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/stateDiagram.spec.js",
|
||||
"duration": 16705
|
||||
"duration": 16862
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/theme.spec.js",
|
||||
"duration": 30928
|
||||
"duration": 30553
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/timeline.spec.ts",
|
||||
"duration": 8424
|
||||
"duration": 8962
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/treemap.spec.ts",
|
||||
"duration": 12533
|
||||
"duration": 12486
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/xyChart.spec.js",
|
||||
"duration": 21197
|
||||
"duration": 21718
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/zenuml.spec.js",
|
||||
"duration": 3455
|
||||
"duration": 3882
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -36,46 +36,15 @@ export async function textHelper<T extends SVGGraphicsElement>(
|
||||
|
||||
annotationGroup = shapeSvg.insert('g').attr('class', 'annotation-group text');
|
||||
if (node.annotations.length > 0) {
|
||||
await addText(
|
||||
annotationGroup,
|
||||
{ text: `«${node.annotations[0]}»` } as unknown as ClassMember,
|
||||
0,
|
||||
[]
|
||||
);
|
||||
annotationGroup.style('opacity', '1');
|
||||
const annotation = node.annotations[0];
|
||||
await addText(annotationGroup, { text: `«${annotation}»` } as unknown as ClassMember, 0);
|
||||
|
||||
const annotationGroupBBox = annotationGroup.node()!.getBBox();
|
||||
annotationGroupHeight = annotationGroupBBox.height;
|
||||
}
|
||||
|
||||
labelGroup = shapeSvg.insert('g').attr('class', 'label-group text');
|
||||
|
||||
// Determine styling based on annotations
|
||||
let labelStyles = [''];
|
||||
let labelClass = '';
|
||||
if (node.annotations && node.annotations.length > 0) {
|
||||
const annotation = node.annotations[0].toLowerCase();
|
||||
switch (annotation) {
|
||||
case 'abstract':
|
||||
labelClass = 'abstract';
|
||||
labelStyles = [];
|
||||
break;
|
||||
case 'enumeration':
|
||||
labelClass = 'enumeration';
|
||||
labelStyles = [];
|
||||
break;
|
||||
case 'interface':
|
||||
labelClass = 'interface';
|
||||
labelStyles = [];
|
||||
break;
|
||||
default:
|
||||
labelClass = '';
|
||||
labelStyles = [];
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Apply the CSS class to the label group
|
||||
labelGroup.attr('class', `label-group text classTitle ${labelClass}`);
|
||||
|
||||
await addText(labelGroup, node, 0, labelStyles);
|
||||
await addText(labelGroup, node, 0, ['font-weight: bolder']);
|
||||
const labelGroupBBox = labelGroup.node()!.getBBox();
|
||||
labelGroupHeight = labelGroupBBox.height;
|
||||
|
||||
@@ -102,7 +71,7 @@ export async function textHelper<T extends SVGGraphicsElement>(
|
||||
// Center annotation
|
||||
if (annotationGroup !== null) {
|
||||
const annotationGroupBBox = annotationGroup.node()!.getBBox();
|
||||
annotationGroup.attr('transform', `translate(${-annotationGroupBBox.width / 2}, 0)`);
|
||||
annotationGroup.attr('transform', `translate(${-annotationGroupBBox.width / 2})`);
|
||||
}
|
||||
|
||||
// Adjust label
|
||||
|
||||
@@ -55,7 +55,7 @@ const getStyles = (options) =>
|
||||
}
|
||||
|
||||
.classTitle {
|
||||
font-weight: normal;
|
||||
font-weight: bolder;
|
||||
}
|
||||
.node rect,
|
||||
.node circle,
|
||||
@@ -172,20 +172,6 @@ g.classGroup line {
|
||||
stroke: ${options.lineColor} !important;
|
||||
stroke-width: 1;
|
||||
}
|
||||
|
||||
.classTitle.abstract {
|
||||
font-style: italic;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.classTitle.enumeration {
|
||||
text-decoration: underline;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.classTitle.interface {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.edgeTerminals {
|
||||
font-size: 11px;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { log } from '../../logger.js';
|
||||
import { db } from './gitGraphAst.js';
|
||||
import { parser } from './gitGraphParser.js';
|
||||
import { commitType } from './gitGraphTypes.js';
|
||||
|
||||
describe('when parsing a gitGraph', function () {
|
||||
beforeEach(function () {
|
||||
@@ -843,6 +844,39 @@ describe('when parsing a gitGraph', function () {
|
||||
expect(db.getBranchesAsObjArray()).toStrictEqual([{ name: 'main' }, { name: 'testBranch' }]);
|
||||
});
|
||||
|
||||
it('should handle merging the same branch multiple times', async () => {
|
||||
const str = `gitGraph:
|
||||
commit
|
||||
branch stable
|
||||
checkout stable
|
||||
merge main
|
||||
checkout main
|
||||
commit
|
||||
commit
|
||||
checkout stable
|
||||
merge main
|
||||
`;
|
||||
|
||||
await parser.parse(str);
|
||||
const commits = db.getCommits();
|
||||
expect(commits.size).toBe(5);
|
||||
expect(db.getCurrentBranch()).toBe('stable');
|
||||
expect(db.getDirection()).toBe('LR');
|
||||
expect(db.getBranches().size).toBe(2);
|
||||
|
||||
const commitsArray = db.getCommitsArray();
|
||||
expect(commitsArray[0].branch).toBe('main');
|
||||
expect(commitsArray[0].parents).toStrictEqual([]);
|
||||
expect(commitsArray[1].branch).toBe('stable');
|
||||
expect(commitsArray[1].type).toBe(commitType.MERGE);
|
||||
expect(commitsArray[1].parents.length).toBe(2);
|
||||
expect(commitsArray[2].branch).toBe('main');
|
||||
expect(commitsArray[3].branch).toBe('main');
|
||||
expect(commitsArray[4].branch).toBe('stable');
|
||||
expect(commitsArray[4].type).toBe(commitType.MERGE);
|
||||
expect(commitsArray[4].parents.length).toBe(2);
|
||||
});
|
||||
|
||||
it('should handle merge with custom ids, tags and type', async () => {
|
||||
const str = `gitGraph:
|
||||
commit
|
||||
@@ -1236,7 +1270,7 @@ describe('when parsing a gitGraph', function () {
|
||||
);
|
||||
}
|
||||
});
|
||||
it('should throw error when trying to merge branches having same heads', async () => {
|
||||
it('should allow merging branches having same heads', async () => {
|
||||
const str = `gitGraph
|
||||
commit
|
||||
branch testBranch
|
||||
@@ -1244,13 +1278,19 @@ describe('when parsing a gitGraph', function () {
|
||||
merge testBranch
|
||||
`;
|
||||
|
||||
try {
|
||||
await parser.parse(str);
|
||||
// Fail test if above expression doesn't throw anything.
|
||||
expect(true).toBe(false);
|
||||
} catch (e: any) {
|
||||
expect(e.message).toBe('Incorrect usage of "merge". Both branches have same head');
|
||||
}
|
||||
await parser.parse(str);
|
||||
const commits = db.getCommits();
|
||||
expect(commits.size).toBe(2);
|
||||
expect(db.getCurrentBranch()).toBe('main');
|
||||
|
||||
const commitsArray = db.getCommitsArray();
|
||||
expect(commitsArray[0].branch).toBe('main');
|
||||
expect(commitsArray[0].parents).toStrictEqual([]);
|
||||
expect(commitsArray[1].branch).toBe('main');
|
||||
expect(commitsArray[1].type).toBe(commitType.MERGE);
|
||||
expect(commitsArray[1].parents.length).toBe(2);
|
||||
expect(commitsArray[1].parents[0]).toBe(commitsArray[0].id);
|
||||
expect(commitsArray[1].parents[1]).toBe(commitsArray[0].id);
|
||||
});
|
||||
it('should throw error when trying to merge branch which has no commits', async () => {
|
||||
const str = `gitGraph
|
||||
|
||||
@@ -167,9 +167,6 @@ export const merge = (mergeDB: MergeDB): void => {
|
||||
const otherCommit: Commit | undefined = otherBranchCheck
|
||||
? state.records.commits.get(otherBranchCheck)
|
||||
: undefined;
|
||||
if (currentCommit && otherCommit && currentCommit.branch === otherBranch) {
|
||||
throw new Error(`Cannot merge branch '${otherBranch}' into itself.`);
|
||||
}
|
||||
if (state.records.currBranch === otherBranch) {
|
||||
const error: any = new Error('Incorrect usage of "merge". Cannot merge a branch to itself');
|
||||
error.hash = {
|
||||
@@ -212,15 +209,6 @@ export const merge = (mergeDB: MergeDB): void => {
|
||||
};
|
||||
throw error;
|
||||
}
|
||||
if (currentCommit === otherCommit) {
|
||||
const error: any = new Error('Incorrect usage of "merge". Both branches have same head');
|
||||
error.hash = {
|
||||
text: `merge ${otherBranch}`,
|
||||
token: `merge ${otherBranch}`,
|
||||
expected: ['branch abc'],
|
||||
};
|
||||
throw error;
|
||||
}
|
||||
if (customId && state.records.commits.has(customId)) {
|
||||
const error: any = new Error(
|
||||
'Incorrect usage of "merge". Commit with id:' +
|
||||
|
||||
Reference in New Issue
Block a user