From 274053ce7aad940af455f430a5e59fd8ced07454 Mon Sep 17 00:00:00 2001 From: Justin Greywolf Date: Sat, 11 Oct 2025 14:33:47 -0700 Subject: [PATCH] fix: Support multiple stereotypes on class diagrams (#6680) - Modified JISON grammar to support consecutive annotations like <><> - Updated addAnnotation method to create classes if they don't exist - Added comprehensive tests for multiple annotation scenarios - Maintains backward compatibility with existing single annotation syntax Fixes #6680 --- .../mermaid/src/diagrams/class/classDb.ts | 1 + .../src/diagrams/class/classDiagram.spec.ts | 22 +++++++++++++++++++ .../diagrams/class/parser/classDiagram.jison | 7 +++++- 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/packages/mermaid/src/diagrams/class/classDb.ts b/packages/mermaid/src/diagrams/class/classDb.ts index e3d4e0bcf..5deb383f7 100644 --- a/packages/mermaid/src/diagrams/class/classDb.ts +++ b/packages/mermaid/src/diagrams/class/classDb.ts @@ -237,6 +237,7 @@ export class ClassDB implements DiagramDB { * @public */ public addAnnotation(className: string, annotation: string) { + this.addClass(className); const validatedClassName = this.splitClassNameAndType(className).className; this.classes.get(validatedClassName)!.annotations.push(annotation); } diff --git a/packages/mermaid/src/diagrams/class/classDiagram.spec.ts b/packages/mermaid/src/diagrams/class/classDiagram.spec.ts index aa5e514e0..544a25a46 100644 --- a/packages/mermaid/src/diagrams/class/classDiagram.spec.ts +++ b/packages/mermaid/src/diagrams/class/classDiagram.spec.ts @@ -922,6 +922,28 @@ foo() expect(actual.methods.length).toBe(1); expect(actual.annotations[0]).toBe('interface'); }); + + it('should handle multiple consecutive annotations on a single class', function () { + const str = 'classDiagram\n' + '<><> Class1'; + + parser.parse(str); + + const actual = parser.yy.getClass('Class1'); + expect(actual.annotations.length).toBe(2); + expect(actual.annotations).toContain('interface'); + expect(actual.annotations).toContain('injected'); + }); + + it('should handle multiple separate annotations on a single class', function () { + const str = 'classDiagram\n' + '<> Class1\n' + '<> Class1'; + + parser.parse(str); + + const actual = parser.yy.getClass('Class1'); + expect(actual.annotations.length).toBe(2); + expect(actual.annotations).toContain('interface'); + expect(actual.annotations).toContain('injected'); + }); }); }); diff --git a/packages/mermaid/src/diagrams/class/parser/classDiagram.jison b/packages/mermaid/src/diagrams/class/parser/classDiagram.jison index 9a1f991a7..ad3670582 100644 --- a/packages/mermaid/src/diagrams/class/parser/classDiagram.jison +++ b/packages/mermaid/src/diagrams/class/parser/classDiagram.jison @@ -310,7 +310,12 @@ emptyBody ; annotationStatement - : ANNOTATION_START alphaNumToken ANNOTATION_END className { yy.addAnnotation($4,$2); } + : annotationList className { for(const annotation of $1) { yy.addAnnotation($2, annotation); } } + ; + +annotationList + : ANNOTATION_START alphaNumToken ANNOTATION_END { $$ = [$2]; } + | annotationList ANNOTATION_START alphaNumToken ANNOTATION_END { $1.push($3); $$ = $1; } ; members