diff --git a/d2compiler/compile.go b/d2compiler/compile.go
index 4a542a974..be71308b8 100644
--- a/d2compiler/compile.go
+++ b/d2compiler/compile.go
@@ -59,6 +59,8 @@ func compileIR(ast *d2ast.Map, m *d2ir.Map) (*d2graph.Graph, error) {
}
func (c *compiler) compileBoard(g *d2graph.Graph, ir *d2ir.Map) *d2graph.Graph {
+ ir = ir.Copy(nil).(*d2ir.Map)
+ // c.preprocessSeqDiagrams(ir)
c.compileMap(g.Root, ir)
if len(c.err.Errors) == 0 {
c.validateKeys(g.Root, ir)
@@ -100,7 +102,8 @@ func (c *compiler) compileBoardsField(g *d2graph.Graph, ir *d2ir.Map, fieldName
}
type compiler struct {
- err d2parser.ParseError
+ inEdgeGroup bool
+ err d2parser.ParseError
}
func (c *compiler) errorf(n d2ast.Node, f string, v ...interface{}) {
@@ -658,3 +661,127 @@ func d2graphIDA(irIDA []string) (ida []string) {
}
return ida
}
+
+// Unused for now until shape: edge_group
+func (c *compiler) preprocessSeqDiagrams(m *d2ir.Map) {
+ for _, f := range m.Fields {
+ if f.Name == "shape" && f.Primary_.Value.ScalarString() == d2target.ShapeSequenceDiagram {
+ c.preprocessEdgeGroup(m, m)
+ return
+ }
+ if f.Map() != nil {
+ c.preprocessSeqDiagrams(f.Map())
+ }
+ }
+}
+
+func (c *compiler) preprocessEdgeGroup(seqDiagram, m *d2ir.Map) {
+ // Any child of a sequence diagram can be either an actor, edge group or a span.
+ // 1. Actors are shapes without edges inside them defined at the top level scope of a
+ // sequence diagram.
+ // 2. Spans are the children of actors. For our purposes we can ignore them.
+ // 3. Edge groups are defined as having at least one connection within them and also not
+ // being connected to anything. All direct children of an edge group are either edge
+ // groups or top level actors.
+
+ // Go through all the fields and hoist actors from edge groups while also processing
+ // the edge groups recursively.
+ for _, f := range m.Fields {
+ if isEdgeGroup(f) {
+ if f.Map() != nil {
+ c.preprocessEdgeGroup(seqDiagram, f.Map())
+ }
+ } else {
+ if m == seqDiagram {
+ // Ignore for root.
+ continue
+ }
+ hoistActor(seqDiagram, f)
+ }
+ }
+
+ // We need to adjust all edges recursively to point to actual actors instead.
+ for _, e := range m.Edges {
+ if isCrossEdgeGroupEdge(m, e) {
+ c.errorf(e.References[0].AST(), "illegal edge between edge groups")
+ continue
+ }
+
+ if m == seqDiagram {
+ // Root edges between actors directly do not require hoisting.
+ continue
+ }
+
+ srcParent := seqDiagram
+ for i, el := range e.ID.SrcPath {
+ f := srcParent.GetField(el)
+ if !isEdgeGroup(f) {
+ for j := 0; j < i+1; j++ {
+ e.ID.SrcPath = append([]string{"_"}, e.ID.SrcPath...)
+ e.ID.DstPath = append([]string{"_"}, e.ID.DstPath...)
+ }
+ break
+ }
+ srcParent = f.Map()
+ }
+ }
+}
+
+func hoistActor(seqDiagram *d2ir.Map, f *d2ir.Field) {
+ f2 := seqDiagram.GetField(f.Name)
+ if f2 == nil {
+ seqDiagram.Fields = append(seqDiagram.Fields, f.Copy(seqDiagram).(*d2ir.Field))
+ } else {
+ d2ir.OverlayField(f2, f)
+ d2ir.ParentMap(f).DeleteField(f.Name)
+ }
+}
+
+func isCrossEdgeGroupEdge(m *d2ir.Map, e *d2ir.Edge) bool {
+ srcParent := m
+ for _, el := range e.ID.SrcPath {
+ f := srcParent.GetField(el)
+ if f == nil {
+ // Hoisted already.
+ break
+ }
+ if isEdgeGroup(f) {
+ return true
+ }
+ srcParent = f.Map()
+ }
+
+ dstParent := m
+ for _, el := range e.ID.DstPath {
+ f := dstParent.GetField(el)
+ if f == nil {
+ // Hoisted already.
+ break
+ }
+ if isEdgeGroup(f) {
+ return true
+ }
+ dstParent = f.Map()
+ }
+
+ return false
+}
+
+func isEdgeGroup(n d2ir.Node) bool {
+ return n.Map().EdgeCountRecursive() > 0
+}
+
+func parentSeqDiagram(n d2ir.Node) *d2ir.Map {
+ for {
+ m := d2ir.ParentMap(n)
+ if m == nil {
+ return nil
+ }
+ for _, f := range m.Fields {
+ if f.Name == "shape" && f.Primary_.Value.ScalarString() == d2target.ShapeSequenceDiagram {
+ return m
+ }
+ }
+ n = m
+ }
+}
diff --git a/d2compiler/compile_test.go b/d2compiler/compile_test.go
index 67c66e8f4..37e68632c 100644
--- a/d2compiler/compile_test.go
+++ b/d2compiler/compile_test.go
@@ -1947,6 +1947,7 @@ func TestCompile2(t *testing.T) {
t.Parallel()
t.Run("boards", testBoards)
+ t.Run("seqdiagrams", testSeqDiagrams)
}
func testBoards(t *testing.T) {
@@ -2032,6 +2033,57 @@ steps: {
}
}
+func testSeqDiagrams(t *testing.T) {
+ t.Parallel()
+
+ t.Run("errs", func(t *testing.T) {
+ t.Parallel()
+
+ tca := []struct {
+ name string
+ skip bool
+ run func(t *testing.T)
+ }{
+ {
+ name: "sequence_diagram_edge_between_edge_groups",
+ // New sequence diagram scoping implementation is disabled.
+ skip: true,
+ run: func(t *testing.T) {
+ assertCompile(t, `
+Office chatter: {
+ shape: sequence_diagram
+ alice: Alice
+ bob: Bobby
+ awkward small talk: {
+ alice -> bob: uhm, hi
+ bob -> alice: oh, hello
+ icebreaker attempt: {
+ alice -> bob: what did you have for lunch?
+ }
+ unfortunate outcome: {
+ bob -> alice: that's personal
+ }
+ }
+ awkward small talk.icebreaker attempt.alice -> awkward small talk.unfortunate outcome.bob
+}
+`, "d2/testdata/d2compiler/TestCompile2/seqdiagrams/errs/sequence_diagram_edge_between_edge_groups.d2:16:3: edges between edge groups are not allowed")
+ },
+ },
+ }
+
+ for _, tc := range tca {
+ tc := tc
+ t.Run(tc.name, func(t *testing.T) {
+ t.Parallel()
+ if tc.skip {
+ t.SkipNow()
+ }
+ tc.run(t)
+ })
+ }
+ })
+}
+
func assertCompile(t *testing.T, text string, expErr string) *d2graph.Graph {
d2Path := fmt.Sprintf("d2/testdata/d2compiler/%v.d2", t.Name())
g, err := d2compiler.Compile(d2Path, strings.NewReader(text), nil)
diff --git a/d2graph/d2graph.go b/d2graph/d2graph.go
index 49ff3e211..11e2c179a 100644
--- a/d2graph/d2graph.go
+++ b/d2graph/d2graph.go
@@ -645,15 +645,16 @@ func (obj *Object) FindEdges(mk *d2ast.Key) ([]*Edge, bool) {
return ea, true
}
-func (obj *Object) ensureChildEdge(ids []string) *Object {
- for i := range ids {
+func (obj *Object) ensureChildEdge(ida []string) *Object {
+ for i := range ida {
switch obj.Attributes.Shape.Value {
case d2target.ShapeClass, d2target.ShapeSQLTable:
// This will only be called for connecting edges where we want to truncate to the
// container.
return obj
+ default:
+ obj = obj.EnsureChild(ida[i : i+1])
}
- obj = obj.EnsureChild(ids[i : i+1])
}
return obj
}
@@ -665,11 +666,22 @@ func (obj *Object) EnsureChild(ida []string) *Object {
if seq != nil {
for _, c := range seq.ChildrenArray {
if c.ID == ida[0] {
+ if obj.ID == ida[0] {
+ // In cases of a.a where EnsureChild is called on the parent a, the second a should
+ // be created as a child of a and not as a child of the diagram. This is super
+ // unfortunate code but alas.
+ break
+ }
obj = seq
break
}
}
}
+
+ if len(ida) == 0 {
+ return obj
+ }
+
_, is := ReservedKeywordHolders[ida[0]]
if len(ida) == 1 && !is {
_, ok := ReservedKeywords[ida[0]]
@@ -681,6 +693,10 @@ func (obj *Object) EnsureChild(ida []string) *Object {
id := ida[0]
ida = ida[1:]
+ if id == "_" {
+ return obj.Parent.EnsureChild(ida)
+ }
+
child, ok := obj.Children[strings.ToLower(id)]
if !ok {
child = obj.newObject(id)
diff --git a/d2graph/seqdiagram.go b/d2graph/seqdiagram.go
index b9cddac8d..c7497fa9a 100644
--- a/d2graph/seqdiagram.go
+++ b/d2graph/seqdiagram.go
@@ -33,7 +33,7 @@ func (obj *Object) IsSequenceDiagramGroup() bool {
return false
}
}
- return obj.ContainsAnyObject(obj.Graph.Objects) || obj.ContainsAnyEdge(obj.Graph.Edges)
+ return len(obj.ChildrenArray) > 0 || obj.ContainsAnyEdge(obj.Graph.Edges)
}
// notes are descendant of actors with no edges and no children
diff --git a/d2ir/compile.go b/d2ir/compile.go
index 70839d85c..03cc04b85 100644
--- a/d2ir/compile.go
+++ b/d2ir/compile.go
@@ -42,7 +42,8 @@ func (c *compiler) compileScenarios(m *Map) {
continue
}
base := m.CopyBase(sf)
- sf.Composite = Overlay(base, sf.Map())
+ OverlayMap(base, sf.Map())
+ sf.Composite = base
c.compileScenarios(sf.Map())
c.compileSteps(sf.Map())
}
@@ -67,7 +68,8 @@ func (c *compiler) compileSteps(m *Map) {
} else {
base = steps.Fields[i-1].Map().CopyBase(sf)
}
- sf.Composite = Overlay(base, sf.Map())
+ OverlayMap(base, sf.Map())
+ sf.Composite = base
c.compileScenarios(sf.Map())
c.compileSteps(sf.Map())
}
diff --git a/d2ir/d2ir.go b/d2ir/d2ir.go
index cddacba2f..1a90d8d5c 100644
--- a/d2ir/d2ir.go
+++ b/d2ir/d2ir.go
@@ -179,6 +179,9 @@ func (m *Map) Copy(newParent Node) Node {
for i := range m.Edges {
m.Edges[i] = m.Edges[i].Copy(m).(*Edge)
}
+ if m.parent == nil {
+ m.initRoot()
+ }
return m
}
diff --git a/d2ir/merge.go b/d2ir/merge.go
index 9d0834b4f..15ba2a9ec 100644
--- a/d2ir/merge.go
+++ b/d2ir/merge.go
@@ -1,25 +1,13 @@
package d2ir
-func Overlay(base, overlay *Map) *Map {
+func OverlayMap(base, overlay *Map) {
for _, of := range overlay.Fields {
bf := base.GetField(of.Name)
if bf == nil {
base.Fields = append(base.Fields, of.Copy(base).(*Field))
continue
}
- if of.Primary_ != nil {
- bf.Primary_ = of.Primary_.Copy(bf).(*Scalar)
- }
- switch ofc := of.Composite.(type) {
- case *Array:
- bf.Composite = ofc.Copy(bf).(*Map)
- case *Map:
- if bf.Map() != nil {
- bf.Composite = Overlay(bf.Map(), ofc)
- } else {
- bf.Composite = of.Composite.Copy(bf).(*Map)
- }
- }
+ OverlayField(bf, of)
}
for _, oe := range overlay.Edges {
@@ -29,17 +17,36 @@ func Overlay(base, overlay *Map) *Map {
continue
}
be := bea[0]
- if oe.Primary_ != nil {
- be.Primary_ = oe.Primary_.Copy(be).(*Scalar)
- }
- if oe.Map_ != nil {
- if be.Map_ != nil {
- be.Map_ = Overlay(be.Map(), oe.Map_)
- } else {
- be.Map_ = oe.Map_.Copy(be).(*Map)
- }
+ OverlayEdge(be, oe)
+ }
+}
+
+func OverlayField(bf, of *Field) {
+ if of.Primary_ != nil {
+ bf.Primary_ = of.Primary_.Copy(bf).(*Scalar)
+ }
+
+ if of.Composite != nil {
+ if bf.Map() != nil && of.Map() != nil {
+ OverlayMap(bf.Map(), of.Map())
+ } else {
+ bf.Composite = of.Composite.Copy(bf).(*Map)
}
}
- return base
+ bf.References = append(bf.References, of.References...)
+}
+
+func OverlayEdge(be, oe *Edge) {
+ if oe.Primary_ != nil {
+ be.Primary_ = oe.Primary_.Copy(be).(*Scalar)
+ }
+ if oe.Map_ != nil {
+ if be.Map_ != nil {
+ OverlayMap(be.Map(), oe.Map_)
+ } else {
+ be.Map_ = oe.Map_.Copy(be).(*Map)
+ }
+ }
+ be.References = append(be.References, oe.References...)
}
diff --git a/e2etests/regression_test.go b/e2etests/regression_test.go
index 02d82f9b5..b96ad0b77 100644
--- a/e2etests/regression_test.go
+++ b/e2etests/regression_test.go
@@ -444,6 +444,27 @@ group 11: {
}
b -> c
+`,
+ },
+ {
+ name: "sequence_diagram_ambiguous_edge_group",
+ script: `
+Office chatter: {
+ shape: sequence_diagram
+ alice: Alice
+ bob: Bobby
+ awkward small talk: {
+ awkward small talk.ok
+ alice -> bob: uhm, hi
+ bob -> alice: oh, hello
+ icebreaker attempt: {
+ alice -> bob: what did you have for lunch?
+ }
+ unfortunate outcome: {
+ bob -> alice: that's personal
+ }
+ }
+}
`,
},
}
diff --git a/e2etests/testdata/regression/sequence_diagram_ambiguous_edge_group/dagre/board.exp.json b/e2etests/testdata/regression/sequence_diagram_ambiguous_edge_group/dagre/board.exp.json
new file mode 100644
index 000000000..1b7df691c
--- /dev/null
+++ b/e2etests/testdata/regression/sequence_diagram_ambiguous_edge_group/dagre/board.exp.json
@@ -0,0 +1,606 @@
+{
+ "name": "",
+ "fontFamily": "SourceSansPro",
+ "shapes": [
+ {
+ "id": "Office chatter",
+ "type": "sequence_diagram",
+ "pos": {
+ "x": 0,
+ "y": 0
+ },
+ "width": 741,
+ "height": 1166,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 0,
+ "borderRadius": 0,
+ "fill": "#FFFFFF",
+ "stroke": "#0D32B2",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "Office chatter",
+ "fontSize": 28,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#0A0F25",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 164,
+ "labelHeight": 41,
+ "labelPosition": "INSIDE_TOP_CENTER",
+ "zIndex": 0,
+ "level": 1
+ },
+ {
+ "id": "Office chatter.alice",
+ "type": "rectangle",
+ "pos": {
+ "x": 24,
+ "y": 110
+ },
+ "width": 150,
+ "height": 126,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "#EDF0FD",
+ "stroke": "#0D32B2",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "Alice",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#0A0F25",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 38,
+ "labelHeight": 26,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 2
+ },
+ {
+ "id": "Office chatter.bob",
+ "type": "rectangle",
+ "pos": {
+ "x": 274,
+ "y": 110
+ },
+ "width": 150,
+ "height": 126,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "#EDF0FD",
+ "stroke": "#0D32B2",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "Bobby",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#0A0F25",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 48,
+ "labelHeight": 26,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 2
+ },
+ {
+ "id": "Office chatter.awkward small talk",
+ "type": "rectangle",
+ "pos": {
+ "x": 482,
+ "y": 110
+ },
+ "width": 235,
+ "height": 126,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "#EDF0FD",
+ "stroke": "#0D32B2",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "awkward small talk",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#0A0F25",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 135,
+ "labelHeight": 26,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 2
+ },
+ {
+ "id": "Office chatter.awkward small talk.awkward small talk",
+ "type": "rectangle",
+ "pos": {
+ "x": 593,
+ "y": 350
+ },
+ "width": 12,
+ "height": 158,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "#E3E9FD",
+ "stroke": "#0D32B2",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#0A0F25",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 135,
+ "labelHeight": 26,
+ "zIndex": 2,
+ "level": 3
+ },
+ {
+ "id": "Office chatter.awkward small talk.awkward small talk.ok",
+ "type": "page",
+ "pos": {
+ "x": 538,
+ "y": 366
+ },
+ "width": 122,
+ "height": 126,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "#FFFFFF",
+ "stroke": "#0D32B2",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "ok",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#0A0F25",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 22,
+ "labelHeight": 26,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 5,
+ "level": 4
+ },
+ {
+ "id": "Office chatter.awkward small talk.icebreaker attempt",
+ "type": "rectangle",
+ "pos": {
+ "x": 593,
+ "y": -9223372036854775808
+ },
+ "width": 12,
+ "height": 80,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 0,
+ "borderRadius": 0,
+ "fill": "#DEE1EB",
+ "stroke": "#0D32B2",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": true,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#0A0F25",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 134,
+ "labelHeight": 26,
+ "zIndex": 2,
+ "level": 3
+ },
+ {
+ "id": "Office chatter.awkward small talk.unfortunate outcome",
+ "type": "rectangle",
+ "pos": {
+ "x": 593,
+ "y": -9223372036854775808
+ },
+ "width": 12,
+ "height": 80,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 0,
+ "borderRadius": 0,
+ "fill": "#DEE1EB",
+ "stroke": "#0D32B2",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": true,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#0A0F25",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 148,
+ "labelHeight": 26,
+ "zIndex": 2,
+ "level": 3
+ }
+ ],
+ "connections": [
+ {
+ "id": "Office chatter.(alice -> bob)[1]",
+ "src": "Office chatter.alice",
+ "srcArrow": "none",
+ "srcLabel": "",
+ "dst": "Office chatter.bob",
+ "dstArrow": "triangle",
+ "dstLabel": "",
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "stroke": "#0D32B2",
+ "label": "uhm, hi",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#676C7E",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 50,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "labelPercentage": 0,
+ "route": [
+ {
+ "x": 99,
+ "y": 622
+ },
+ {
+ "x": 349,
+ "y": 622
+ }
+ ],
+ "animated": false,
+ "tooltip": "",
+ "icon": null,
+ "zIndex": 4
+ },
+ {
+ "id": "Office chatter.(bob -> alice)[1]",
+ "src": "Office chatter.bob",
+ "srcArrow": "none",
+ "srcLabel": "",
+ "dst": "Office chatter.alice",
+ "dstArrow": "triangle",
+ "dstLabel": "",
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "stroke": "#0D32B2",
+ "label": "oh, hello",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#676C7E",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 56,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "labelPercentage": 0,
+ "route": [
+ {
+ "x": 349,
+ "y": 752
+ },
+ {
+ "x": 99,
+ "y": 752
+ }
+ ],
+ "animated": false,
+ "tooltip": "",
+ "icon": null,
+ "zIndex": 4
+ },
+ {
+ "id": "Office chatter.(alice -> bob)[0]",
+ "src": "Office chatter.alice",
+ "srcArrow": "none",
+ "srcLabel": "",
+ "dst": "Office chatter.bob",
+ "dstArrow": "triangle",
+ "dstLabel": "",
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "stroke": "#0D32B2",
+ "label": "what did you have for lunch?",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#676C7E",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 187,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "labelPercentage": 0,
+ "route": [
+ {
+ "x": 99,
+ "y": 882
+ },
+ {
+ "x": 349,
+ "y": 882
+ }
+ ],
+ "animated": false,
+ "tooltip": "",
+ "icon": null,
+ "zIndex": 4
+ },
+ {
+ "id": "Office chatter.(bob -> alice)[0]",
+ "src": "Office chatter.bob",
+ "srcArrow": "none",
+ "srcLabel": "",
+ "dst": "Office chatter.alice",
+ "dstArrow": "triangle",
+ "dstLabel": "",
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "stroke": "#0D32B2",
+ "label": "that's personal",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#676C7E",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 99,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "labelPercentage": 0,
+ "route": [
+ {
+ "x": 349,
+ "y": 1012
+ },
+ {
+ "x": 99,
+ "y": 1012
+ }
+ ],
+ "animated": false,
+ "tooltip": "",
+ "icon": null,
+ "zIndex": 4
+ },
+ {
+ "id": "(Office chatter.alice -- )[0]",
+ "src": "Office chatter.alice",
+ "srcArrow": "none",
+ "srcLabel": "",
+ "dst": "alice-lifeline-end-3851299086",
+ "dstArrow": "none",
+ "dstLabel": "",
+ "opacity": 1,
+ "strokeDash": 6,
+ "strokeWidth": 2,
+ "stroke": "#0D32B2",
+ "label": "",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#676C7E",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 0,
+ "labelHeight": 0,
+ "labelPosition": "",
+ "labelPercentage": 0,
+ "route": [
+ {
+ "x": 99,
+ "y": 236
+ },
+ {
+ "x": 99,
+ "y": 1142
+ }
+ ],
+ "animated": false,
+ "tooltip": "",
+ "icon": null,
+ "zIndex": 1
+ },
+ {
+ "id": "(Office chatter.bob -- )[0]",
+ "src": "Office chatter.bob",
+ "srcArrow": "none",
+ "srcLabel": "",
+ "dst": "bob-lifeline-end-3036726343",
+ "dstArrow": "none",
+ "dstLabel": "",
+ "opacity": 1,
+ "strokeDash": 6,
+ "strokeWidth": 2,
+ "stroke": "#0D32B2",
+ "label": "",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#676C7E",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 0,
+ "labelHeight": 0,
+ "labelPosition": "",
+ "labelPercentage": 0,
+ "route": [
+ {
+ "x": 349,
+ "y": 236
+ },
+ {
+ "x": 349,
+ "y": 1142
+ }
+ ],
+ "animated": false,
+ "tooltip": "",
+ "icon": null,
+ "zIndex": 1
+ },
+ {
+ "id": "(Office chatter.awkward small talk -- )[0]",
+ "src": "Office chatter.awkward small talk",
+ "srcArrow": "none",
+ "srcLabel": "",
+ "dst": "awkward small talk-lifeline-end-861194358",
+ "dstArrow": "none",
+ "dstLabel": "",
+ "opacity": 1,
+ "strokeDash": 6,
+ "strokeWidth": 2,
+ "stroke": "#0D32B2",
+ "label": "",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#676C7E",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 0,
+ "labelHeight": 0,
+ "labelPosition": "",
+ "labelPercentage": 0,
+ "route": [
+ {
+ "x": 599.5,
+ "y": 236
+ },
+ {
+ "x": 599.5,
+ "y": 1142
+ }
+ ],
+ "animated": false,
+ "tooltip": "",
+ "icon": null,
+ "zIndex": 1
+ }
+ ]
+}
diff --git a/e2etests/testdata/regression/sequence_diagram_ambiguous_edge_group/dagre/sketch.exp.svg b/e2etests/testdata/regression/sequence_diagram_ambiguous_edge_group/dagre/sketch.exp.svg
new file mode 100644
index 000000000..dce56d71f
--- /dev/null
+++ b/e2etests/testdata/regression/sequence_diagram_ambiguous_edge_group/dagre/sketch.exp.svg
@@ -0,0 +1,62 @@
+
+
\ No newline at end of file
diff --git a/e2etests/testdata/regression/sequence_diagram_ambiguous_edge_group/elk/board.exp.json b/e2etests/testdata/regression/sequence_diagram_ambiguous_edge_group/elk/board.exp.json
new file mode 100644
index 000000000..42dba2171
--- /dev/null
+++ b/e2etests/testdata/regression/sequence_diagram_ambiguous_edge_group/elk/board.exp.json
@@ -0,0 +1,606 @@
+{
+ "name": "",
+ "fontFamily": "SourceSansPro",
+ "shapes": [
+ {
+ "id": "Office chatter",
+ "type": "sequence_diagram",
+ "pos": {
+ "x": 12,
+ "y": 12
+ },
+ "width": 741,
+ "height": 1166,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 0,
+ "borderRadius": 0,
+ "fill": "#FFFFFF",
+ "stroke": "#0D32B2",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "Office chatter",
+ "fontSize": 28,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#0A0F25",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 164,
+ "labelHeight": 41,
+ "labelPosition": "INSIDE_TOP_CENTER",
+ "zIndex": 0,
+ "level": 1
+ },
+ {
+ "id": "Office chatter.alice",
+ "type": "rectangle",
+ "pos": {
+ "x": 36,
+ "y": 122
+ },
+ "width": 150,
+ "height": 126,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "#EDF0FD",
+ "stroke": "#0D32B2",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "Alice",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#0A0F25",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 38,
+ "labelHeight": 26,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 2
+ },
+ {
+ "id": "Office chatter.bob",
+ "type": "rectangle",
+ "pos": {
+ "x": 286,
+ "y": 122
+ },
+ "width": 150,
+ "height": 126,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "#EDF0FD",
+ "stroke": "#0D32B2",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "Bobby",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#0A0F25",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 48,
+ "labelHeight": 26,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 2
+ },
+ {
+ "id": "Office chatter.awkward small talk",
+ "type": "rectangle",
+ "pos": {
+ "x": 494,
+ "y": 122
+ },
+ "width": 235,
+ "height": 126,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "#EDF0FD",
+ "stroke": "#0D32B2",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "awkward small talk",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#0A0F25",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 135,
+ "labelHeight": 26,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 2
+ },
+ {
+ "id": "Office chatter.awkward small talk.awkward small talk",
+ "type": "rectangle",
+ "pos": {
+ "x": 605,
+ "y": 362
+ },
+ "width": 12,
+ "height": 158,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "#E3E9FD",
+ "stroke": "#0D32B2",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#0A0F25",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 135,
+ "labelHeight": 26,
+ "zIndex": 2,
+ "level": 3
+ },
+ {
+ "id": "Office chatter.awkward small talk.awkward small talk.ok",
+ "type": "page",
+ "pos": {
+ "x": 550,
+ "y": 378
+ },
+ "width": 122,
+ "height": 126,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "#FFFFFF",
+ "stroke": "#0D32B2",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "ok",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#0A0F25",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 22,
+ "labelHeight": 26,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 5,
+ "level": 4
+ },
+ {
+ "id": "Office chatter.awkward small talk.icebreaker attempt",
+ "type": "rectangle",
+ "pos": {
+ "x": 605,
+ "y": -9223372036854775808
+ },
+ "width": 12,
+ "height": 80,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 0,
+ "borderRadius": 0,
+ "fill": "#DEE1EB",
+ "stroke": "#0D32B2",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": true,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#0A0F25",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 134,
+ "labelHeight": 26,
+ "zIndex": 2,
+ "level": 3
+ },
+ {
+ "id": "Office chatter.awkward small talk.unfortunate outcome",
+ "type": "rectangle",
+ "pos": {
+ "x": 605,
+ "y": -9223372036854775808
+ },
+ "width": 12,
+ "height": 80,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 0,
+ "borderRadius": 0,
+ "fill": "#DEE1EB",
+ "stroke": "#0D32B2",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": true,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#0A0F25",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 148,
+ "labelHeight": 26,
+ "zIndex": 2,
+ "level": 3
+ }
+ ],
+ "connections": [
+ {
+ "id": "Office chatter.(alice -> bob)[1]",
+ "src": "Office chatter.alice",
+ "srcArrow": "none",
+ "srcLabel": "",
+ "dst": "Office chatter.bob",
+ "dstArrow": "triangle",
+ "dstLabel": "",
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "stroke": "#0D32B2",
+ "label": "uhm, hi",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#676C7E",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 50,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "labelPercentage": 0,
+ "route": [
+ {
+ "x": 111,
+ "y": 634
+ },
+ {
+ "x": 361,
+ "y": 634
+ }
+ ],
+ "animated": false,
+ "tooltip": "",
+ "icon": null,
+ "zIndex": 4
+ },
+ {
+ "id": "Office chatter.(bob -> alice)[1]",
+ "src": "Office chatter.bob",
+ "srcArrow": "none",
+ "srcLabel": "",
+ "dst": "Office chatter.alice",
+ "dstArrow": "triangle",
+ "dstLabel": "",
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "stroke": "#0D32B2",
+ "label": "oh, hello",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#676C7E",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 56,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "labelPercentage": 0,
+ "route": [
+ {
+ "x": 361,
+ "y": 764
+ },
+ {
+ "x": 111,
+ "y": 764
+ }
+ ],
+ "animated": false,
+ "tooltip": "",
+ "icon": null,
+ "zIndex": 4
+ },
+ {
+ "id": "Office chatter.(alice -> bob)[0]",
+ "src": "Office chatter.alice",
+ "srcArrow": "none",
+ "srcLabel": "",
+ "dst": "Office chatter.bob",
+ "dstArrow": "triangle",
+ "dstLabel": "",
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "stroke": "#0D32B2",
+ "label": "what did you have for lunch?",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#676C7E",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 187,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "labelPercentage": 0,
+ "route": [
+ {
+ "x": 111,
+ "y": 894
+ },
+ {
+ "x": 361,
+ "y": 894
+ }
+ ],
+ "animated": false,
+ "tooltip": "",
+ "icon": null,
+ "zIndex": 4
+ },
+ {
+ "id": "Office chatter.(bob -> alice)[0]",
+ "src": "Office chatter.bob",
+ "srcArrow": "none",
+ "srcLabel": "",
+ "dst": "Office chatter.alice",
+ "dstArrow": "triangle",
+ "dstLabel": "",
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "stroke": "#0D32B2",
+ "label": "that's personal",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#676C7E",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 99,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "labelPercentage": 0,
+ "route": [
+ {
+ "x": 361,
+ "y": 1024
+ },
+ {
+ "x": 111,
+ "y": 1024
+ }
+ ],
+ "animated": false,
+ "tooltip": "",
+ "icon": null,
+ "zIndex": 4
+ },
+ {
+ "id": "(Office chatter.alice -- )[0]",
+ "src": "Office chatter.alice",
+ "srcArrow": "none",
+ "srcLabel": "",
+ "dst": "alice-lifeline-end-3851299086",
+ "dstArrow": "none",
+ "dstLabel": "",
+ "opacity": 1,
+ "strokeDash": 6,
+ "strokeWidth": 2,
+ "stroke": "#0D32B2",
+ "label": "",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#676C7E",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 0,
+ "labelHeight": 0,
+ "labelPosition": "",
+ "labelPercentage": 0,
+ "route": [
+ {
+ "x": 111,
+ "y": 248
+ },
+ {
+ "x": 111,
+ "y": 1154
+ }
+ ],
+ "animated": false,
+ "tooltip": "",
+ "icon": null,
+ "zIndex": 1
+ },
+ {
+ "id": "(Office chatter.bob -- )[0]",
+ "src": "Office chatter.bob",
+ "srcArrow": "none",
+ "srcLabel": "",
+ "dst": "bob-lifeline-end-3036726343",
+ "dstArrow": "none",
+ "dstLabel": "",
+ "opacity": 1,
+ "strokeDash": 6,
+ "strokeWidth": 2,
+ "stroke": "#0D32B2",
+ "label": "",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#676C7E",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 0,
+ "labelHeight": 0,
+ "labelPosition": "",
+ "labelPercentage": 0,
+ "route": [
+ {
+ "x": 361,
+ "y": 248
+ },
+ {
+ "x": 361,
+ "y": 1154
+ }
+ ],
+ "animated": false,
+ "tooltip": "",
+ "icon": null,
+ "zIndex": 1
+ },
+ {
+ "id": "(Office chatter.awkward small talk -- )[0]",
+ "src": "Office chatter.awkward small talk",
+ "srcArrow": "none",
+ "srcLabel": "",
+ "dst": "awkward small talk-lifeline-end-861194358",
+ "dstArrow": "none",
+ "dstLabel": "",
+ "opacity": 1,
+ "strokeDash": 6,
+ "strokeWidth": 2,
+ "stroke": "#0D32B2",
+ "label": "",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#676C7E",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 0,
+ "labelHeight": 0,
+ "labelPosition": "",
+ "labelPercentage": 0,
+ "route": [
+ {
+ "x": 611.5,
+ "y": 248
+ },
+ {
+ "x": 611.5,
+ "y": 1154
+ }
+ ],
+ "animated": false,
+ "tooltip": "",
+ "icon": null,
+ "zIndex": 1
+ }
+ ]
+}
diff --git a/e2etests/testdata/regression/sequence_diagram_ambiguous_edge_group/elk/sketch.exp.svg b/e2etests/testdata/regression/sequence_diagram_ambiguous_edge_group/elk/sketch.exp.svg
new file mode 100644
index 000000000..4f4934866
--- /dev/null
+++ b/e2etests/testdata/regression/sequence_diagram_ambiguous_edge_group/elk/sketch.exp.svg
@@ -0,0 +1,62 @@
+
+
\ No newline at end of file
diff --git a/e2etests/testdata/regression/sequence_diagram_self_edge_group_overlap/dagre/board.exp.json b/e2etests/testdata/regression/sequence_diagram_self_edge_group_overlap/dagre/board.exp.json
index 8e59a4826..3f9dcd83c 100644
--- a/e2etests/testdata/regression/sequence_diagram_self_edge_group_overlap/dagre/board.exp.json
+++ b/e2etests/testdata/regression/sequence_diagram_self_edge_group_overlap/dagre/board.exp.json
@@ -248,14 +248,54 @@
"zIndex": 3,
"level": 1
},
+ {
+ "id": "a.a",
+ "type": "rectangle",
+ "pos": {
+ "x": 93,
+ "y": 734
+ },
+ "width": 12,
+ "height": 162,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "#E3E9FD",
+ "stroke": "#0D32B2",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#0A0F25",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 12,
+ "labelHeight": 26,
+ "zIndex": 2,
+ "level": 2
+ },
{
"id": "group 4",
"type": "rectangle",
"pos": {
- "x": 49,
+ "x": 55,
"y": 840
},
- "width": 350,
+ "width": 344,
"height": 80,
"opacity": 1,
"strokeDash": 0,
@@ -665,11 +705,11 @@
"zIndex": 4
},
{
- "id": "(a -> a)[1]",
+ "id": "(a -> a.a)[0]",
"src": "a",
"srcArrow": "none",
"srcLabel": "",
- "dst": "a",
+ "dst": "a.a",
"dstArrow": "triangle",
"dstLabel": "",
"opacity": 1,
@@ -702,7 +742,7 @@
"y": 750
},
{
- "x": 99,
+ "x": 105,
"y": 750
}
],
@@ -712,8 +752,8 @@
"zIndex": 4
},
{
- "id": "(a -> b)[1]",
- "src": "a",
+ "id": "(a.a -> b)[0]",
+ "src": "a.a",
"srcArrow": "none",
"srcLabel": "",
"dst": "b",
@@ -737,7 +777,7 @@
"labelPercentage": 0,
"route": [
{
- "x": 99,
+ "x": 105,
"y": 880
},
{
@@ -883,6 +923,53 @@
"icon": null,
"zIndex": 4
},
+ {
+ "id": "(a -> a)[1]",
+ "src": "a",
+ "srcArrow": "none",
+ "srcLabel": "",
+ "dst": "a",
+ "dstArrow": "triangle",
+ "dstLabel": "",
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "stroke": "#0D32B2",
+ "label": "",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#676C7E",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 0,
+ "labelHeight": 0,
+ "labelPosition": "",
+ "labelPercentage": 0,
+ "route": [
+ {
+ "x": 99,
+ "y": 1480
+ },
+ {
+ "x": 199,
+ "y": 1480
+ },
+ {
+ "x": 199,
+ "y": 1560
+ },
+ {
+ "x": 99,
+ "y": 1560
+ }
+ ],
+ "animated": false,
+ "tooltip": "",
+ "icon": null,
+ "zIndex": 4
+ },
{
"id": "(a -> a)[2]",
"src": "a",
@@ -907,53 +994,6 @@
"labelHeight": 0,
"labelPosition": "",
"labelPercentage": 0,
- "route": [
- {
- "x": 99,
- "y": 1480
- },
- {
- "x": 199,
- "y": 1480
- },
- {
- "x": 199,
- "y": 1560
- },
- {
- "x": 99,
- "y": 1560
- }
- ],
- "animated": false,
- "tooltip": "",
- "icon": null,
- "zIndex": 4
- },
- {
- "id": "(a -> a)[3]",
- "src": "a",
- "srcArrow": "none",
- "srcLabel": "",
- "dst": "a",
- "dstArrow": "triangle",
- "dstLabel": "",
- "opacity": 1,
- "strokeDash": 0,
- "strokeWidth": 2,
- "stroke": "#0D32B2",
- "label": "",
- "fontSize": 16,
- "fontFamily": "DEFAULT",
- "language": "",
- "color": "#676C7E",
- "italic": true,
- "bold": false,
- "underline": false,
- "labelWidth": 0,
- "labelHeight": 0,
- "labelPosition": "",
- "labelPercentage": 0,
"route": [
{
"x": 99,
@@ -977,53 +1017,6 @@
"icon": null,
"zIndex": 4
},
- {
- "id": "(a -> a)[5]",
- "src": "a",
- "srcArrow": "none",
- "srcLabel": "",
- "dst": "a",
- "dstArrow": "triangle",
- "dstLabel": "",
- "opacity": 1,
- "strokeDash": 0,
- "strokeWidth": 2,
- "stroke": "#0D32B2",
- "label": "",
- "fontSize": 16,
- "fontFamily": "DEFAULT",
- "language": "",
- "color": "#676C7E",
- "italic": true,
- "bold": false,
- "underline": false,
- "labelWidth": 0,
- "labelHeight": 0,
- "labelPosition": "",
- "labelPercentage": 0,
- "route": [
- {
- "x": 99,
- "y": 1900
- },
- {
- "x": 199,
- "y": 1900
- },
- {
- "x": 199,
- "y": 1980
- },
- {
- "x": 99,
- "y": 1980
- }
- ],
- "animated": false,
- "tooltip": "",
- "icon": null,
- "zIndex": 4
- },
{
"id": "(a -> a)[4]",
"src": "a",
@@ -1048,6 +1041,53 @@
"labelHeight": 0,
"labelPosition": "",
"labelPercentage": 0,
+ "route": [
+ {
+ "x": 99,
+ "y": 1900
+ },
+ {
+ "x": 199,
+ "y": 1900
+ },
+ {
+ "x": 199,
+ "y": 1980
+ },
+ {
+ "x": 99,
+ "y": 1980
+ }
+ ],
+ "animated": false,
+ "tooltip": "",
+ "icon": null,
+ "zIndex": 4
+ },
+ {
+ "id": "(a -> a)[3]",
+ "src": "a",
+ "srcArrow": "none",
+ "srcLabel": "",
+ "dst": "a",
+ "dstArrow": "triangle",
+ "dstLabel": "",
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "stroke": "#0D32B2",
+ "label": "",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#676C7E",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 0,
+ "labelHeight": 0,
+ "labelPosition": "",
+ "labelPercentage": 0,
"route": [
{
"x": 99,
@@ -1072,7 +1112,7 @@
"zIndex": 4
},
{
- "id": "(a -> a)[6]",
+ "id": "(a -> a)[5]",
"src": "a",
"srcArrow": "none",
"srcLabel": "",
diff --git a/e2etests/testdata/regression/sequence_diagram_self_edge_group_overlap/dagre/sketch.exp.svg b/e2etests/testdata/regression/sequence_diagram_self_edge_group_overlap/dagre/sketch.exp.svg
index f2bfc06d5..b9a9742f1 100644
--- a/e2etests/testdata/regression/sequence_diagram_self_edge_group_overlap/dagre/sketch.exp.svg
+++ b/e2etests/testdata/regression/sequence_diagram_self_edge_group_overlap/dagre/sketch.exp.svg
@@ -39,12 +39,12 @@ width="927" height="3388" viewBox="-78 -28 927 3388">Office chatterAliceBobbyawkward small talkicebreaker attemptunfortunate outcome uhm, hioh, hellowhat did you have for lunch?that's personal
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/e2etests/testdata/todo/sequence_diagram_edge_group_span_field/elk/board.exp.json b/e2etests/testdata/todo/sequence_diagram_edge_group_span_field/elk/board.exp.json
new file mode 100644
index 000000000..4069e2c56
--- /dev/null
+++ b/e2etests/testdata/todo/sequence_diagram_edge_group_span_field/elk/board.exp.json
@@ -0,0 +1,568 @@
+{
+ "name": "",
+ "fontFamily": "SourceSansPro",
+ "shapes": [
+ {
+ "id": "Office chatter",
+ "type": "sequence_diagram",
+ "pos": {
+ "x": 12,
+ "y": 12
+ },
+ "width": 448,
+ "height": 910,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 0,
+ "borderRadius": 0,
+ "fill": "#FFFFFF",
+ "stroke": "#0D32B2",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "Office chatter",
+ "fontSize": 28,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#0A0F25",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 164,
+ "labelHeight": 41,
+ "labelPosition": "INSIDE_TOP_CENTER",
+ "zIndex": 0,
+ "level": 1
+ },
+ {
+ "id": "Office chatter.alice",
+ "type": "rectangle",
+ "pos": {
+ "x": 36,
+ "y": 122
+ },
+ "width": 150,
+ "height": 126,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "#EDF0FD",
+ "stroke": "#0D32B2",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "Alice",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#0A0F25",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 38,
+ "labelHeight": 26,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 2
+ },
+ {
+ "id": "Office chatter.alice.a",
+ "type": "rectangle",
+ "pos": {
+ "x": 105,
+ "y": 752
+ },
+ "width": 12,
+ "height": 80,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "#E3E9FD",
+ "stroke": "#0D32B2",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#0A0F25",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 12,
+ "labelHeight": 26,
+ "zIndex": 2,
+ "level": 3
+ },
+ {
+ "id": "Office chatter.bob",
+ "type": "rectangle",
+ "pos": {
+ "x": 286,
+ "y": 122
+ },
+ "width": 150,
+ "height": 126,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "#EDF0FD",
+ "stroke": "#0D32B2",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "Bobby",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#0A0F25",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 48,
+ "labelHeight": 26,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 2
+ },
+ {
+ "id": "Office chatter.awkward small talk",
+ "type": "rectangle",
+ "pos": {
+ "x": 37,
+ "y": 338
+ },
+ "width": 398,
+ "height": 494,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 0,
+ "borderRadius": 0,
+ "fill": "#DEE1EB",
+ "stroke": "#0D32B2",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": true,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "awkward small talk",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#0A0F25",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 135,
+ "labelHeight": 26,
+ "labelPosition": "INSIDE_TOP_LEFT",
+ "zIndex": 3,
+ "level": 2
+ },
+ {
+ "id": "Office chatter.awkward small talk.icebreaker attempt",
+ "type": "rectangle",
+ "pos": {
+ "x": 61,
+ "y": 598
+ },
+ "width": 350,
+ "height": 80,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 0,
+ "borderRadius": 0,
+ "fill": "#DEE1EB",
+ "stroke": "#0D32B2",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": true,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "icebreaker attempt",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#0A0F25",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 134,
+ "labelHeight": 26,
+ "labelPosition": "INSIDE_TOP_LEFT",
+ "zIndex": 3,
+ "level": 3
+ },
+ {
+ "id": "Office chatter.awkward small talk.unfortunate outcome",
+ "type": "rectangle",
+ "pos": {
+ "x": 67,
+ "y": 728
+ },
+ "width": 338,
+ "height": 80,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 0,
+ "borderRadius": 0,
+ "fill": "#DEE1EB",
+ "stroke": "#0D32B2",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": true,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "unfortunate outcome",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#0A0F25",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 148,
+ "labelHeight": 26,
+ "labelPosition": "INSIDE_TOP_LEFT",
+ "zIndex": 3,
+ "level": 3
+ },
+ {
+ "id": "Office chatter.bob.a",
+ "type": "rectangle",
+ "pos": {
+ "x": 355,
+ "y": 752
+ },
+ "width": 12,
+ "height": 80,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "#E3E9FD",
+ "stroke": "#0D32B2",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#0A0F25",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 12,
+ "labelHeight": 26,
+ "zIndex": 2,
+ "level": 3
+ }
+ ],
+ "connections": [
+ {
+ "id": "Office chatter.(alice -> bob)[1]",
+ "src": "Office chatter.alice",
+ "srcArrow": "none",
+ "srcLabel": "",
+ "dst": "Office chatter.bob",
+ "dstArrow": "triangle",
+ "dstLabel": "",
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "stroke": "#0D32B2",
+ "label": "uhm, hi",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#676C7E",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 50,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "labelPercentage": 0,
+ "route": [
+ {
+ "x": 111,
+ "y": 378
+ },
+ {
+ "x": 361,
+ "y": 378
+ }
+ ],
+ "animated": false,
+ "tooltip": "",
+ "icon": null,
+ "zIndex": 4
+ },
+ {
+ "id": "Office chatter.(bob -> alice)[0]",
+ "src": "Office chatter.bob",
+ "srcArrow": "none",
+ "srcLabel": "",
+ "dst": "Office chatter.alice",
+ "dstArrow": "triangle",
+ "dstLabel": "",
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "stroke": "#0D32B2",
+ "label": "oh, hello",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#676C7E",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 56,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "labelPercentage": 0,
+ "route": [
+ {
+ "x": 361,
+ "y": 508
+ },
+ {
+ "x": 111,
+ "y": 508
+ }
+ ],
+ "animated": false,
+ "tooltip": "",
+ "icon": null,
+ "zIndex": 4
+ },
+ {
+ "id": "Office chatter.(alice -> bob)[0]",
+ "src": "Office chatter.alice",
+ "srcArrow": "none",
+ "srcLabel": "",
+ "dst": "Office chatter.bob",
+ "dstArrow": "triangle",
+ "dstLabel": "",
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "stroke": "#0D32B2",
+ "label": "what did you have for lunch?",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#676C7E",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 187,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "labelPercentage": 0,
+ "route": [
+ {
+ "x": 111,
+ "y": 638
+ },
+ {
+ "x": 361,
+ "y": 638
+ }
+ ],
+ "animated": false,
+ "tooltip": "",
+ "icon": null,
+ "zIndex": 4
+ },
+ {
+ "id": "Office chatter.(bob.a -> alice.a)[0]",
+ "src": "Office chatter.bob.a",
+ "srcArrow": "none",
+ "srcLabel": "",
+ "dst": "Office chatter.alice.a",
+ "dstArrow": "triangle",
+ "dstLabel": "",
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "stroke": "#0D32B2",
+ "label": "that's personal",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#676C7E",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 99,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "labelPercentage": 0,
+ "route": [
+ {
+ "x": 355,
+ "y": 768
+ },
+ {
+ "x": 117,
+ "y": 768
+ }
+ ],
+ "animated": false,
+ "tooltip": "",
+ "icon": null,
+ "zIndex": 4
+ },
+ {
+ "id": "(Office chatter.alice -- )[0]",
+ "src": "Office chatter.alice",
+ "srcArrow": "none",
+ "srcLabel": "",
+ "dst": "alice-lifeline-end-3851299086",
+ "dstArrow": "none",
+ "dstLabel": "",
+ "opacity": 1,
+ "strokeDash": 6,
+ "strokeWidth": 2,
+ "stroke": "#0D32B2",
+ "label": "",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#676C7E",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 0,
+ "labelHeight": 0,
+ "labelPosition": "",
+ "labelPercentage": 0,
+ "route": [
+ {
+ "x": 111,
+ "y": 248
+ },
+ {
+ "x": 111,
+ "y": 898
+ }
+ ],
+ "animated": false,
+ "tooltip": "",
+ "icon": null,
+ "zIndex": 1
+ },
+ {
+ "id": "(Office chatter.bob -- )[0]",
+ "src": "Office chatter.bob",
+ "srcArrow": "none",
+ "srcLabel": "",
+ "dst": "bob-lifeline-end-3036726343",
+ "dstArrow": "none",
+ "dstLabel": "",
+ "opacity": 1,
+ "strokeDash": 6,
+ "strokeWidth": 2,
+ "stroke": "#0D32B2",
+ "label": "",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#676C7E",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 0,
+ "labelHeight": 0,
+ "labelPosition": "",
+ "labelPercentage": 0,
+ "route": [
+ {
+ "x": 361,
+ "y": 248
+ },
+ {
+ "x": 361,
+ "y": 898
+ }
+ ],
+ "animated": false,
+ "tooltip": "",
+ "icon": null,
+ "zIndex": 1
+ }
+ ]
+}
diff --git a/e2etests/testdata/todo/sequence_diagram_edge_group_span_field/elk/sketch.exp.svg b/e2etests/testdata/todo/sequence_diagram_edge_group_span_field/elk/sketch.exp.svg
new file mode 100644
index 000000000..f7cd08e57
--- /dev/null
+++ b/e2etests/testdata/todo/sequence_diagram_edge_group_span_field/elk/sketch.exp.svg
@@ -0,0 +1,65 @@
+
+
\ No newline at end of file
diff --git a/e2etests/todo_test.go b/e2etests/todo_test.go
index d70d98367..3fbf45e67 100644
--- a/e2etests/todo_test.go
+++ b/e2etests/todo_test.go
@@ -197,6 +197,28 @@ small code: |go
width: 4
height: 3
}
+`,
+ },
+ {
+ // issue https://github.com/terrastruct/d2/issues/748
+ name: "sequence_diagram_edge_group_span_field",
+ script: `
+Office chatter: {
+ shape: sequence_diagram
+ alice: Alice
+ bob: Bobby
+ alice.a
+ awkward small talk: {
+ alice -> bob: uhm, hi
+ bob -> alice: oh, hello
+ icebreaker attempt: {
+ alice -> bob: what did you have for lunch?
+ }
+ unfortunate outcome: {
+ bob.a -> alice.a: that's personal
+ }
+ }
+}
`,
},
}
diff --git a/testdata/d2compiler/TestCompile2/seqdiagrams/errs/sequence_diagram_edge_between_edge_groups.exp.json b/testdata/d2compiler/TestCompile2/seqdiagrams/errs/sequence_diagram_edge_between_edge_groups.exp.json
new file mode 100644
index 000000000..f828ca6c3
--- /dev/null
+++ b/testdata/d2compiler/TestCompile2/seqdiagrams/errs/sequence_diagram_edge_between_edge_groups.exp.json
@@ -0,0 +1,12 @@
+{
+ "graph": null,
+ "err": {
+ "ioerr": null,
+ "errs": [
+ {
+ "range": "d2/testdata/d2compiler/TestCompile2/seqdiagrams/errs/sequence_diagram_edge_between_edge_groups.d2,15:2:307-15:91:396",
+ "errmsg": "d2/testdata/d2compiler/TestCompile2/seqdiagrams/errs/sequence_diagram_edge_between_edge_groups.d2:16:3: edges between edge groups are not allowed"
+ }
+ ]
+ }
+}