Skip to content

Commit 4dafa86

Browse files
authored
Merge pull request #2419 from alixander/unsuspend-dst
fix edge glob ampersand filters
2 parents 3bf7b49 + d01a0ea commit 4dafa86

File tree

11 files changed

+3034
-2291
lines changed

11 files changed

+3034
-2291
lines changed

d2compiler/compile_test.go

+54
Original file line numberDiff line numberDiff line change
@@ -5633,6 +5633,60 @@ c
56335633
assert.Equal(t, "hello", g.Edges[0].Label.Value)
56345634
},
56355635
},
5636+
{
5637+
name: "unsuspend-edge-filter",
5638+
run: func(t *testing.T) {
5639+
g, _ := assertCompile(t, `
5640+
a -> b
5641+
**: suspend
5642+
(** -> **)[*]: suspend
5643+
(* -> *)[*]: unsuspend {
5644+
&dst: a
5645+
}
5646+
`, ``)
5647+
assert.Equal(t, 0, len(g.Objects))
5648+
assert.Equal(t, 0, len(g.Edges))
5649+
},
5650+
},
5651+
{
5652+
name: "unsuspend-edge-child",
5653+
run: func(t *testing.T) {
5654+
g, _ := assertCompile(t, `
5655+
a: {
5656+
b -> c
5657+
}
5658+
5659+
**: suspend
5660+
(** -> **)[*]: suspend
5661+
(** -> **)[*]: unsuspend {
5662+
&dst: a.c
5663+
}
5664+
`, ``)
5665+
assert.Equal(t, 3, len(g.Objects))
5666+
assert.Equal(t, 1, len(g.Edges))
5667+
},
5668+
},
5669+
{
5670+
name: "unsuspend-cross-container-edge-label",
5671+
run: func(t *testing.T) {
5672+
g, _ := assertCompile(t, `
5673+
a: {
5674+
b
5675+
}
5676+
c: {
5677+
d
5678+
}
5679+
a.b -> c.d: likes
5680+
**: suspend
5681+
(** -> **)[*]: suspend
5682+
(** -> **)[*]: unsuspend {
5683+
&label: likes
5684+
}
5685+
`, ``)
5686+
assert.Equal(t, 4, len(g.Objects))
5687+
assert.Equal(t, 1, len(g.Edges))
5688+
},
5689+
},
56365690
{
56375691
name: "unsuspend-shape-label",
56385692
run: func(t *testing.T) {

d2ir/compile.go

+101-2
Original file line numberDiff line numberDiff line change
@@ -869,6 +869,22 @@ func (c *compiler) ampersandFilter(refctx *RefContext) bool {
869869
for _, part := range edge.ID.SrcPath {
870870
srcParts = append(srcParts, part.ScalarString())
871871
}
872+
873+
container := ParentField(edge)
874+
if container != nil && container.Name.ScalarString() != "root" {
875+
containerPath := []string{}
876+
curr := container
877+
for curr != nil && curr.Name.ScalarString() != "root" {
878+
containerPath = append([]string{curr.Name.ScalarString()}, containerPath...)
879+
curr = ParentField(curr)
880+
}
881+
882+
srcStart := srcParts[0]
883+
if !strings.EqualFold(srcStart, containerPath[0]) {
884+
srcParts = append(containerPath, srcParts...)
885+
}
886+
}
887+
872888
srcPath := strings.Join(srcParts, ".")
873889

874890
return srcPath == filterValue
@@ -889,6 +905,23 @@ func (c *compiler) ampersandFilter(refctx *RefContext) bool {
889905
for _, part := range edge.ID.DstPath {
890906
dstParts = append(dstParts, part.ScalarString())
891907
}
908+
909+
// Find the container that holds this edge
910+
// Build the absolute path by prepending the container's path
911+
container := ParentField(edge)
912+
if container != nil && container.Name.ScalarString() != "root" {
913+
containerPath := []string{}
914+
curr := container
915+
for curr != nil && curr.Name.ScalarString() != "root" {
916+
containerPath = append([]string{curr.Name.ScalarString()}, containerPath...)
917+
curr = ParentField(curr)
918+
}
919+
920+
dstStart := dstParts[0]
921+
if !strings.EqualFold(dstStart, containerPath[0]) {
922+
dstParts = append(containerPath, dstParts...)
923+
}
924+
}
892925
dstPath := strings.Join(dstParts, ".")
893926

894927
return dstPath == filterValue
@@ -1273,8 +1306,37 @@ func (c *compiler) _compileEdges(refctx *RefContext) {
12731306
continue
12741307
}
12751308

1309+
if refctx.Key.Value.Map != nil && refctx.Key.Value.Map.HasFilter() {
1310+
if e.Map_ == nil {
1311+
e.Map_ = &Map{
1312+
parent: e,
1313+
}
1314+
}
1315+
c.mapRefContextStack = append(c.mapRefContextStack, refctx)
1316+
ok := c.ampersandFilterMap(e.Map_, refctx.Key.Value.Map, refctx.ScopeAST)
1317+
c.mapRefContextStack = c.mapRefContextStack[:len(c.mapRefContextStack)-1]
1318+
if !ok {
1319+
continue
1320+
}
1321+
}
1322+
12761323
if refctx.Key.Primary.Suspension != nil || refctx.Key.Value.Suspension != nil {
12771324
if !c.lazyGlobBeingApplied {
1325+
// Check if edge passes filter before applying suspension
1326+
if refctx.Key.Value.Map != nil && refctx.Key.Value.Map.HasFilter() {
1327+
if e.Map_ == nil {
1328+
e.Map_ = &Map{
1329+
parent: e,
1330+
}
1331+
}
1332+
c.mapRefContextStack = append(c.mapRefContextStack, refctx)
1333+
ok := c.ampersandFilterMap(e.Map_, refctx.Key.Value.Map, refctx.ScopeAST)
1334+
c.mapRefContextStack = c.mapRefContextStack[:len(c.mapRefContextStack)-1]
1335+
if !ok {
1336+
continue
1337+
}
1338+
}
1339+
12781340
var suspensionValue bool
12791341
if refctx.Key.Primary.Suspension != nil {
12801342
suspensionValue = refctx.Key.Primary.Suspension.Value
@@ -1284,16 +1346,53 @@ func (c *compiler) _compileEdges(refctx *RefContext) {
12841346
e.suspended = suspensionValue
12851347

12861348
// If we're unsuspending an edge, we should also unsuspend its src and dst objects
1349+
// And their ancestors
12871350
if !suspensionValue {
12881351
srcPath, dstPath := e.ID.SrcPath, e.ID.DstPath
1289-
srcObj := refctx.ScopeMap.GetField(srcPath...)
1290-
dstObj := refctx.ScopeMap.GetField(dstPath...)
12911352

1353+
// Make paths absolute if they're relative
1354+
container := ParentField(e)
1355+
if container != nil && container.Name.ScalarString() != "root" {
1356+
containerPath := []d2ast.String{}
1357+
curr := container
1358+
for curr != nil && curr.Name.ScalarString() != "root" {
1359+
containerPath = append([]d2ast.String{curr.Name}, containerPath...)
1360+
curr = ParentField(curr)
1361+
}
1362+
1363+
if len(srcPath) > 0 && !strings.EqualFold(srcPath[0].ScalarString(), containerPath[0].ScalarString()) {
1364+
absSrcPath := append([]d2ast.String{}, containerPath...)
1365+
srcPath = append(absSrcPath, srcPath...)
1366+
}
1367+
1368+
if len(dstPath) > 0 && !strings.EqualFold(dstPath[0].ScalarString(), containerPath[0].ScalarString()) {
1369+
absDstPath := append([]d2ast.String{}, containerPath...)
1370+
dstPath = append(absDstPath, dstPath...)
1371+
}
1372+
}
1373+
1374+
rootMap := RootMap(refctx.ScopeMap)
1375+
srcObj := rootMap.GetField(srcPath...)
1376+
dstObj := rootMap.GetField(dstPath...)
1377+
1378+
// Unsuspend source node and all its ancestors
12921379
if srcObj != nil {
12931380
srcObj.suspended = false
1381+
parent := ParentField(srcObj)
1382+
for parent != nil && parent.Name.ScalarString() != "root" {
1383+
parent.suspended = false
1384+
parent = ParentField(parent)
1385+
}
12941386
}
1387+
1388+
// Unsuspend destination node and all its ancestors
12951389
if dstObj != nil {
12961390
dstObj.suspended = false
1391+
parent := ParentField(dstObj)
1392+
for parent != nil && parent.Name.ScalarString() != "root" {
1393+
parent.suspended = false
1394+
parent = ParentField(parent)
1395+
}
12971396
}
12981397
}
12991398
}

testdata/d2compiler/TestCompile2/globs/edge-glob-ampersand-filter/1.exp.json

-144
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)