diff --git a/d2compiler/compile.go b/d2compiler/compile.go index 66940ce56..0236a9ce2 100644 --- a/d2compiler/compile.go +++ b/d2compiler/compile.go @@ -73,6 +73,7 @@ func (c *compiler) compileBoard(g *d2graph.Graph, ir *d2ir.Map) *d2graph.Graph { c.validateKeys(g.Root, ir) } c.validateNear(g) + c.validateEdges(g) c.compileBoardsField(g, ir, "layers") c.compileBoardsField(g, ir, "scenarios") @@ -787,6 +788,19 @@ func (c *compiler) validateNear(g *d2graph.Graph) { } } +func (c *compiler) validateEdges(g *d2graph.Graph) { + for _, edge := range g.Edges { + if grid := edge.Src.ClosestGrid(); grid != nil { + c.errorf(edge.GetAstEdge(), "edge %#v cannot enter grid %#v", d2format.Format(edge.GetAstEdge()), grid.AbsID()) + continue + } + if grid := edge.Dst.ClosestGrid(); grid != nil { + c.errorf(edge.GetAstEdge(), "edge %#v cannot enter grid %#v", d2format.Format(edge.GetAstEdge()), grid.AbsID()) + continue + } + } +} + func (c *compiler) validateBoardLinks(g *d2graph.Graph) { for _, obj := range g.Objects { if obj.Attributes.Link == nil { diff --git a/d2compiler/compile_test.go b/d2compiler/compile_test.go index 2d6e63a95..4afc52fbf 100644 --- a/d2compiler/compile_test.go +++ b/d2compiler/compile_test.go @@ -2288,6 +2288,21 @@ obj { `, expErr: `d2/testdata/d2compiler/TestCompile/grid_negative.d2:3:11: columns must be a positive integer: "-200"`, }, + { + name: "grid_edge", + text: `hey: { + rows: 1 + a -> b +} + c -> hey.b + hey.a -> c + + hey -> c: ok +`, + expErr: `d2/testdata/d2compiler/TestCompile/grid_edge.d2:3:2: edge "a -> b" cannot enter grid "hey" +d2/testdata/d2compiler/TestCompile/grid_edge.d2:5:2: edge "c -> hey.b" cannot enter grid "hey" +d2/testdata/d2compiler/TestCompile/grid_edge.d2:6:2: edge "hey.a -> c" cannot enter grid "hey"`, + }, } for _, tc := range testCases { diff --git a/d2graph/d2graph.go b/d2graph/d2graph.go index 42f42977a..d9ae9a89d 100644 --- a/d2graph/d2graph.go +++ b/d2graph/d2graph.go @@ -1013,6 +1013,10 @@ type EdgeReference struct { ScopeObj *Object `json:"-"` } +func (e *Edge) GetAstEdge() *d2ast.Edge { + return e.References[0].Edge +} + func (e *Edge) GetStroke(dashGapSize interface{}) string { if dashGapSize != 0.0 { return color.B2 diff --git a/d2graph/grid.go b/d2graph/grid.go index 1ff029bba..0315fe60b 100644 --- a/d2graph/grid.go +++ b/d2graph/grid.go @@ -4,3 +4,13 @@ func (obj *Object) IsGrid() bool { return obj != nil && obj.Attributes != nil && (obj.Attributes.Rows != nil || obj.Attributes.Columns != nil) } + +func (obj *Object) ClosestGrid() *Object { + if obj.Parent == nil { + return nil + } + if obj.Parent.IsGrid() { + return obj.Parent + } + return obj.Parent.ClosestGrid() +} diff --git a/testdata/d2compiler/TestCompile/grid_edge.exp.json b/testdata/d2compiler/TestCompile/grid_edge.exp.json new file mode 100644 index 000000000..1d6c84181 --- /dev/null +++ b/testdata/d2compiler/TestCompile/grid_edge.exp.json @@ -0,0 +1,20 @@ +{ + "graph": null, + "err": { + "ioerr": null, + "errs": [ + { + "range": "d2/testdata/d2compiler/TestCompile/grid_edge.d2,2:1:17-2:7:23", + "errmsg": "d2/testdata/d2compiler/TestCompile/grid_edge.d2:3:2: edge \"a -> b\" cannot enter grid \"hey\"" + }, + { + "range": "d2/testdata/d2compiler/TestCompile/grid_edge.d2,4:1:27-4:11:37", + "errmsg": "d2/testdata/d2compiler/TestCompile/grid_edge.d2:5:2: edge \"c -> hey.b\" cannot enter grid \"hey\"" + }, + { + "range": "d2/testdata/d2compiler/TestCompile/grid_edge.d2,5:1:39-5:11:49", + "errmsg": "d2/testdata/d2compiler/TestCompile/grid_edge.d2:6:2: edge \"hey.a -> c\" cannot enter grid \"hey\"" + } + ] + } +}