diff --git a/.changeset/nine-bugs-drop.md b/.changeset/nine-bugs-drop.md new file mode 100644 index 00000000000..1a01ed5b311 --- /dev/null +++ b/.changeset/nine-bugs-drop.md @@ -0,0 +1,5 @@ +--- +'mermaid': patch +--- + +fix(er): recognize '1' cardinality alias before relationship operators diff --git a/cypress/integration/rendering/erDiagram.spec.js b/cypress/integration/rendering/erDiagram.spec.js index 542de9f24a9..ad811f02aae 100644 --- a/cypress/integration/rendering/erDiagram.spec.js +++ b/cypress/integration/rendering/erDiagram.spec.js @@ -471,4 +471,30 @@ ORDER ||--|{ LINE-ITEM : contains { logLevel: 1, flowchart: { htmlLabels: false } } ); }); + + it('should render ER diagram with "1" cardinality alias before relationship operators', () => { + imgSnapshotTest( + ` + erDiagram + CUSTOMER 1--1 ORDER : "exactly one" + ORDER 1--o{ LINE-ITEM : "one to many" + PRODUCT 1--|{ CATEGORY : "one or more" + USER 1..1 PROFILE : "exactly one optional" + `, + { logLevel: 1 } + ); + }); + + it('should render ER diagram with "1" cardinality using all 4 relationship operator styles', () => { + imgSnapshotTest( + ` + erDiagram + A 1--1 B : "solid-solid" + C 1..1 D : "dotted-dotted" + E 1.-1 F : "dotted-solid" + G 1-.1 H : "solid-dotted" + `, + { logLevel: 1 } + ); + }); }); diff --git a/packages/mermaid/src/diagrams/er/parser/erDiagram.jison b/packages/mermaid/src/diagrams/er/parser/erDiagram.jison index f581c6777fa..89a797b50a6 100644 --- a/packages/mermaid/src/diagrams/er/parser/erDiagram.jison +++ b/packages/mermaid/src/diagrams/er/parser/erDiagram.jison @@ -68,6 +68,7 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multili "only one" return 'ONLY_ONE'; [0-9]+\.[0-9]+ return 'DECIMAL_NUM'; "1"(?=\s+[A-Za-z_"']) return 'ONLY_ONE'; +"1"(?=(\-\-|\.\.|\.\-|\-\.)) return 'ONLY_ONE'; "1" return 'ENTITY_ONE'; [0-9]+ return 'NUM'; \|\| return 'ONLY_ONE'; diff --git a/packages/mermaid/src/diagrams/er/parser/erDiagram.spec.js b/packages/mermaid/src/diagrams/er/parser/erDiagram.spec.js index 05948988d92..39a042e526d 100644 --- a/packages/mermaid/src/diagrams/er/parser/erDiagram.spec.js +++ b/packages/mermaid/src/diagrams/er/parser/erDiagram.spec.js @@ -734,6 +734,52 @@ describe('when parsing ER diagram it...', function () { expect(rels[0].relSpec.cardB).toBe(erDb.Cardinality.ZERO_OR_MORE); }); + it('should handle "1" alias directly followed by identifying relationship operator "--"', function () { + erDiagram.parser.parse('erDiagram\nCUSTOMER 1--one or more DELIVERY-ADDRESS : has'); + const rels = erDb.getRelationships(); + + expect(erDb.getEntities().size).toBe(2); + expect(rels.length).toBe(1); + expect(rels[0].relSpec.cardA).toBe(erDb.Cardinality.ONE_OR_MORE); + expect(rels[0].relSpec.cardB).toBe(erDb.Cardinality.ONLY_ONE); + expect(rels[0].relSpec.relType).toBe(erDb.Identification.IDENTIFYING); + }); + + it('should handle "1" alias directly followed by non-identifying relationship operator ".."', function () { + erDiagram.parser.parse('erDiagram\nCUSTOMER 1..one or more DELIVERY-ADDRESS : has'); + const rels = erDb.getRelationships(); + + expect(erDb.getEntities().size).toBe(2); + expect(rels.length).toBe(1); + expect(rels[0].relSpec.cardA).toBe(erDb.Cardinality.ONE_OR_MORE); + expect(rels[0].relSpec.cardB).toBe(erDb.Cardinality.ONLY_ONE); + expect(rels[0].relSpec.relType).toBe(erDb.Identification.NON_IDENTIFYING); + }); + + it('should handle "1" alias directly followed by mixed relationship operator ".-"', function () { + erDiagram.parser.parse('erDiagram\nCUSTOMER 1.-one or more DELIVERY-ADDRESS : has'); + const rels = erDb.getRelationships(); + + expect(erDb.getEntities().size).toBe(2); + expect(rels.length).toBe(1); + expect(rels[0].relSpec.cardA).toBe(erDb.Cardinality.ONE_OR_MORE); + expect(rels[0].relSpec.cardB).toBe(erDb.Cardinality.ONLY_ONE); + // ".-" is dotted-to-solid, which is NON_IDENTIFYING on the left side + expect(rels[0].relSpec.relType).toBe(erDb.Identification.NON_IDENTIFYING); + }); + + it('should handle "1" alias directly followed by mixed relationship operator "-."', function () { + erDiagram.parser.parse('erDiagram\nCUSTOMER 1-.one or more DELIVERY-ADDRESS : has'); + const rels = erDb.getRelationships(); + + expect(erDb.getEntities().size).toBe(2); + expect(rels.length).toBe(1); + expect(rels[0].relSpec.cardA).toBe(erDb.Cardinality.ONE_OR_MORE); + expect(rels[0].relSpec.cardB).toBe(erDb.Cardinality.ONLY_ONE); + // "-." is solid-to-dotted, which is NON_IDENTIFYING per the grammar + expect(rels[0].relSpec.relType).toBe(erDb.Identification.NON_IDENTIFYING); + }); + it('should represent identifying relationships properly', function () { erDiagram.parser.parse('erDiagram\nHOUSE ||--|{ ROOM : contains'); const rels = erDb.getRelationships();