From c6120442d00709271d24278f8ea9633c84311aa7 Mon Sep 17 00:00:00 2001 From: Kai Gritun Date: Tue, 3 Feb 2026 20:23:13 -0500 Subject: [PATCH 1/5] fix(er): recognize '1' cardinality alias before relationship operators The '1' alias for 'only one' cardinality was not recognized when directly followed by relationship operators like '--' or '..'. This occurred because the lexer rule only matched '1' when followed by whitespace and then a letter. This fix adds a new lexer rule to also recognize '1' when directly followed by the relationship operators (--, .., .-, -.). Fixes #7351 --- .../src/diagrams/er/parser/erDiagram.jison | 1 + .../src/diagrams/er/parser/erDiagram.spec.js | 22 +++++++++++++++++++ 2 files changed, 23 insertions(+) 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..44ad0b6474c 100644 --- a/packages/mermaid/src/diagrams/er/parser/erDiagram.spec.js +++ b/packages/mermaid/src/diagrams/er/parser/erDiagram.spec.js @@ -734,6 +734,28 @@ 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 represent identifying relationships properly', function () { erDiagram.parser.parse('erDiagram\nHOUSE ||--|{ ROOM : contains'); const rels = erDb.getRelationships(); From 21c6b21400489e4ccefeffaec81682733f7bc59a Mon Sep 17 00:00:00 2001 From: Kai Gritun Date: Thu, 5 Feb 2026 06:08:31 -0500 Subject: [PATCH 2/5] test: add visual rendering test for '1' cardinality alias --- cypress/integration/rendering/erDiagram.spec.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/cypress/integration/rendering/erDiagram.spec.js b/cypress/integration/rendering/erDiagram.spec.js index 542de9f24a9..52c082f0ac5 100644 --- a/cypress/integration/rendering/erDiagram.spec.js +++ b/cypress/integration/rendering/erDiagram.spec.js @@ -471,4 +471,17 @@ 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 } + ); + }); }); From 9d0669a8c04281c3e96b96f285d4dd5d9e0088d7 Mon Sep 17 00:00:00 2001 From: Kai Gritun Date: Thu, 5 Feb 2026 10:11:21 -0500 Subject: [PATCH 3/5] test: add unit tests for 1.- and 1-. operators, add changeset --- .changeset/nine-bugs-drop.md | 5 ++++ .../integration/rendering/erDiagram.spec.js | 13 ++++++++++ .../src/diagrams/er/parser/erDiagram.spec.js | 24 +++++++++++++++++++ 3 files changed, 42 insertions(+) create mode 100644 .changeset/nine-bugs-drop.md diff --git a/.changeset/nine-bugs-drop.md b/.changeset/nine-bugs-drop.md new file mode 100644 index 00000000000..619de3ab934 --- /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 52c082f0ac5..ad811f02aae 100644 --- a/cypress/integration/rendering/erDiagram.spec.js +++ b/cypress/integration/rendering/erDiagram.spec.js @@ -484,4 +484,17 @@ ORDER ||--|{ LINE-ITEM : contains { 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.spec.js b/packages/mermaid/src/diagrams/er/parser/erDiagram.spec.js index 44ad0b6474c..5f5d6a6f716 100644 --- a/packages/mermaid/src/diagrams/er/parser/erDiagram.spec.js +++ b/packages/mermaid/src/diagrams/er/parser/erDiagram.spec.js @@ -756,6 +756,30 @@ describe('when parsing ER diagram it...', function () { 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 IDENTIFYING on the left side + expect(rels[0].relSpec.relType).toBe(erDb.Identification.IDENTIFYING); + }); + it('should represent identifying relationships properly', function () { erDiagram.parser.parse('erDiagram\nHOUSE ||--|{ ROOM : contains'); const rels = erDb.getRelationships(); From 144060b623e2f02ff8fae1cc5fc9d8065f8102bc Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Fri, 6 Feb 2026 06:37:49 +0000 Subject: [PATCH 4/5] [autofix.ci] apply automated fixes --- .changeset/nine-bugs-drop.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/nine-bugs-drop.md b/.changeset/nine-bugs-drop.md index 619de3ab934..1a01ed5b311 100644 --- a/.changeset/nine-bugs-drop.md +++ b/.changeset/nine-bugs-drop.md @@ -1,5 +1,5 @@ --- -"mermaid": patch +'mermaid': patch --- fix(er): recognize '1' cardinality alias before relationship operators From f41f3f46bad6f5217cc70ea5d2f71307ba4ed760 Mon Sep 17 00:00:00 2001 From: Kai Gritun Date: Sat, 7 Feb 2026 15:07:00 -0500 Subject: [PATCH 5/5] fix: correct test expectation for -. operator (NON_IDENTIFYING, not IDENTIFYING) Per the jison grammar, -. (solid-to-dotted) returns NON_IDENTIFYING. The test comment and expectation were incorrect. --- packages/mermaid/src/diagrams/er/parser/erDiagram.spec.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/mermaid/src/diagrams/er/parser/erDiagram.spec.js b/packages/mermaid/src/diagrams/er/parser/erDiagram.spec.js index 5f5d6a6f716..39a042e526d 100644 --- a/packages/mermaid/src/diagrams/er/parser/erDiagram.spec.js +++ b/packages/mermaid/src/diagrams/er/parser/erDiagram.spec.js @@ -776,8 +776,8 @@ describe('when parsing ER diagram it...', function () { 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 IDENTIFYING on the left side - expect(rels[0].relSpec.relType).toBe(erDb.Identification.IDENTIFYING); + // "-." 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 () {