diff --git a/d2compiler/compile_test.go b/d2compiler/compile_test.go index 009e7885e..b9df3323a 100644 --- a/d2compiler/compile_test.go +++ b/d2compiler/compile_test.go @@ -5648,6 +5648,24 @@ a -> b assert.Equal(t, 0, len(g.Edges)) }, }, + { + name: "unsuspend-edge-child", + run: func(t *testing.T) { + g, _ := assertCompile(t, ` +a: { + b -> c +} + +**: suspend +(** -> **)[*]: suspend +(** -> **)[*]: unsuspend { + &dst: a.c +} +`, ``) + assert.Equal(t, 3, len(g.Objects)) + assert.Equal(t, 1, len(g.Edges)) + }, + }, { name: "unsuspend-shape-label", run: func(t *testing.T) { diff --git a/d2ir/compile.go b/d2ir/compile.go index 5799b2ae5..71e8d7c7e 100644 --- a/d2ir/compile.go +++ b/d2ir/compile.go @@ -869,6 +869,22 @@ func (c *compiler) ampersandFilter(refctx *RefContext) bool { for _, part := range edge.ID.SrcPath { srcParts = append(srcParts, part.ScalarString()) } + + container := ParentField(edge) + if container != nil && container.Name.ScalarString() != "root" { + containerPath := []string{} + curr := container + for curr != nil && curr.Name.ScalarString() != "root" { + containerPath = append([]string{curr.Name.ScalarString()}, containerPath...) + curr = ParentField(curr) + } + + srcStart := srcParts[0] + if !strings.EqualFold(srcStart, containerPath[0]) { + srcParts = append(containerPath, srcParts...) + } + } + srcPath := strings.Join(srcParts, ".") return srcPath == filterValue @@ -889,6 +905,23 @@ func (c *compiler) ampersandFilter(refctx *RefContext) bool { for _, part := range edge.ID.DstPath { dstParts = append(dstParts, part.ScalarString()) } + + // Find the container that holds this edge + // Build the absolute path by prepending the container's path + container := ParentField(edge) + if container != nil && container.Name.ScalarString() != "root" { + containerPath := []string{} + curr := container + for curr != nil && curr.Name.ScalarString() != "root" { + containerPath = append([]string{curr.Name.ScalarString()}, containerPath...) + curr = ParentField(curr) + } + + dstStart := dstParts[0] + if !strings.EqualFold(dstStart, containerPath[0]) { + dstParts = append(containerPath, dstParts...) + } + } dstPath := strings.Join(dstParts, ".") return dstPath == filterValue @@ -1298,16 +1331,48 @@ func (c *compiler) _compileEdges(refctx *RefContext) { e.suspended = suspensionValue // If we're unsuspending an edge, we should also unsuspend its src and dst objects + // And their ancestors if !suspensionValue { srcPath, dstPath := e.ID.SrcPath, e.ID.DstPath - srcObj := refctx.ScopeMap.GetField(srcPath...) - dstObj := refctx.ScopeMap.GetField(dstPath...) + container := ParentField(e) + if container != nil && container.Name.ScalarString() != "root" { + containerPath := []d2ast.String{} + curr := container + for curr != nil && curr.Name.ScalarString() != "root" { + containerPath = append([]d2ast.String{curr.Name}, containerPath...) + curr = ParentField(curr) + } + + if len(srcPath) > 0 && !strings.EqualFold(srcPath[0].ScalarString(), containerPath[0].ScalarString()) { + absSrcPath := append([]d2ast.String{}, containerPath...) + srcPath = append(absSrcPath, srcPath...) + } + + if len(dstPath) > 0 && !strings.EqualFold(dstPath[0].ScalarString(), containerPath[0].ScalarString()) { + absDstPath := append([]d2ast.String{}, containerPath...) + dstPath = append(absDstPath, dstPath...) + } + } + + rootMap := RootMap(refctx.ScopeMap) + srcObj := rootMap.GetField(srcPath...) + dstObj := rootMap.GetField(dstPath...) if srcObj != nil { srcObj.suspended = false + parent := ParentField(srcObj) + for parent != nil && parent.Name.ScalarString() != "root" { + parent.suspended = false + parent = ParentField(parent) + } } if dstObj != nil { dstObj.suspended = false + parent := ParentField(srcObj) + for parent != nil && parent.Name.ScalarString() != "root" { + parent.suspended = false + parent = ParentField(parent) + } } } } diff --git a/testdata/d2compiler/TestCompile2/globs/unsuspend-edge-child.exp.json b/testdata/d2compiler/TestCompile2/globs/unsuspend-edge-child.exp.json new file mode 100644 index 000000000..0cc431588 --- /dev/null +++ b/testdata/d2compiler/TestCompile2/globs/unsuspend-edge-child.exp.json @@ -0,0 +1,490 @@ +{ + "graph": { + "name": "", + "isFolderOnly": false, + "ast": { + "range": "d2/testdata/d2compiler/TestCompile2/globs/unsuspend-edge-child.d2,0:0:0-10:0:94", + "nodes": [ + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile2/globs/unsuspend-edge-child.d2,1:0:1-3:1:16", + "key": { + "range": "d2/testdata/d2compiler/TestCompile2/globs/unsuspend-edge-child.d2,1:0:1-1:1:2", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile2/globs/unsuspend-edge-child.d2,1:0:1-1:1:2", + "value": [ + { + "string": "a", + "raw_string": "a" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "map": { + "range": "d2/testdata/d2compiler/TestCompile2/globs/unsuspend-edge-child.d2,1:3:4-3:1:16", + "nodes": [ + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile2/globs/unsuspend-edge-child.d2,2:2:8-2:8:14", + "edges": [ + { + "range": "d2/testdata/d2compiler/TestCompile2/globs/unsuspend-edge-child.d2,2:2:8-2:8:14", + "src": { + "range": "d2/testdata/d2compiler/TestCompile2/globs/unsuspend-edge-child.d2,2:2:8-2:3:9", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile2/globs/unsuspend-edge-child.d2,2:2:8-2:3:9", + "value": [ + { + "string": "b", + "raw_string": "b" + } + ] + } + } + ] + }, + "src_arrow": "", + "dst": { + "range": "d2/testdata/d2compiler/TestCompile2/globs/unsuspend-edge-child.d2,2:7:13-2:8:14", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile2/globs/unsuspend-edge-child.d2,2:7:13-2:8:14", + "value": [ + { + "string": "c", + "raw_string": "c" + } + ] + } + } + ] + }, + "dst_arrow": ">" + } + ], + "primary": {}, + "value": {} + } + } + ] + } + } + } + }, + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile2/globs/unsuspend-edge-child.d2,5:0:18-5:11:29", + "key": { + "range": "d2/testdata/d2compiler/TestCompile2/globs/unsuspend-edge-child.d2,5:0:18-5:2:20", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile2/globs/unsuspend-edge-child.d2,5:0:18-5:2:20", + "value": [ + { + "string": "**", + "raw_string": "**" + } + ], + "pattern": [ + "*", + "", + "*" + ] + } + } + ] + }, + "primary": {}, + "value": { + "suspension": { + "range": "d2/testdata/d2compiler/TestCompile2/globs/unsuspend-edge-child.d2,5:4:22-5:11:29", + "value": true + } + } + } + }, + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile2/globs/unsuspend-edge-child.d2,6:0:30-6:22:52", + "edges": [ + { + "range": "d2/testdata/d2compiler/TestCompile2/globs/unsuspend-edge-child.d2,6:1:31-6:9:39", + "src": { + "range": "d2/testdata/d2compiler/TestCompile2/globs/unsuspend-edge-child.d2,6:1:31-6:3:33", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile2/globs/unsuspend-edge-child.d2,6:1:31-6:3:33", + "value": [ + { + "string": "**", + "raw_string": "**" + } + ], + "pattern": [ + "*", + "", + "*" + ] + } + } + ] + }, + "src_arrow": "", + "dst": { + "range": "d2/testdata/d2compiler/TestCompile2/globs/unsuspend-edge-child.d2,6:7:37-6:9:39", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile2/globs/unsuspend-edge-child.d2,6:7:37-6:9:39", + "value": [ + { + "string": "**", + "raw_string": "**" + } + ], + "pattern": [ + "*", + "", + "*" + ] + } + } + ] + }, + "dst_arrow": ">" + } + ], + "edge_index": { + "range": "d2/testdata/d2compiler/TestCompile2/globs/unsuspend-edge-child.d2,6:10:40-6:13:43", + "int": null, + "glob": true + }, + "primary": {}, + "value": { + "suspension": { + "range": "d2/testdata/d2compiler/TestCompile2/globs/unsuspend-edge-child.d2,6:15:45-6:22:52", + "value": true + } + } + } + }, + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile2/globs/unsuspend-edge-child.d2,7:0:53-9:1:93", + "edges": [ + { + "range": "d2/testdata/d2compiler/TestCompile2/globs/unsuspend-edge-child.d2,7:1:54-7:9:62", + "src": { + "range": "d2/testdata/d2compiler/TestCompile2/globs/unsuspend-edge-child.d2,7:1:54-7:3:56", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile2/globs/unsuspend-edge-child.d2,7:1:54-7:3:56", + "value": [ + { + "string": "**", + "raw_string": "**" + } + ], + "pattern": [ + "*", + "", + "*" + ] + } + } + ] + }, + "src_arrow": "", + "dst": { + "range": "d2/testdata/d2compiler/TestCompile2/globs/unsuspend-edge-child.d2,7:7:60-7:9:62", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile2/globs/unsuspend-edge-child.d2,7:7:60-7:9:62", + "value": [ + { + "string": "**", + "raw_string": "**" + } + ], + "pattern": [ + "*", + "", + "*" + ] + } + } + ] + }, + "dst_arrow": ">" + } + ], + "edge_index": { + "range": "d2/testdata/d2compiler/TestCompile2/globs/unsuspend-edge-child.d2,7:10:63-7:13:66", + "int": null, + "glob": true + }, + "primary": { + "suspension": { + "range": "d2/testdata/d2compiler/TestCompile2/globs/unsuspend-edge-child.d2,7:15:68-7:24:77", + "value": false + } + }, + "value": { + "map": { + "range": "d2/testdata/d2compiler/TestCompile2/globs/unsuspend-edge-child.d2,7:25:78-9:1:93", + "nodes": [ + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile2/globs/unsuspend-edge-child.d2,8:2:82-8:11:91", + "ampersand": true, + "key": { + "range": "d2/testdata/d2compiler/TestCompile2/globs/unsuspend-edge-child.d2,8:3:83-8:6:86", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile2/globs/unsuspend-edge-child.d2,8:3:83-8:6:86", + "value": [ + { + "string": "dst", + "raw_string": "dst" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile2/globs/unsuspend-edge-child.d2,8:8:88-8:11:91", + "value": [ + { + "string": "a.c", + "raw_string": "a.c" + } + ] + } + } + } + } + ] + } + } + } + } + ] + }, + "root": { + "id": "", + "id_val": "", + "attributes": { + "label": { + "value": "" + }, + "labelDimensions": { + "width": 0, + "height": 0 + }, + "style": {}, + "near_key": null, + "shape": { + "value": "" + }, + "direction": { + "value": "" + }, + "constraint": null + }, + "zIndex": 0 + }, + "edges": [ + { + "index": 0, + "isCurve": false, + "src_arrow": false, + "dst_arrow": true, + "references": [ + { + "map_key_edge_index": 0 + }, + { + "map_key_edge_index": 0 + }, + { + "map_key_edge_index": 0 + } + ], + "attributes": { + "label": { + "value": "" + }, + "labelDimensions": { + "width": 0, + "height": 0 + }, + "style": {}, + "near_key": null, + "shape": { + "value": "" + }, + "direction": { + "value": "" + }, + "constraint": null + }, + "zIndex": 0 + } + ], + "objects": [ + { + "id": "a", + "id_val": "a", + "references": [ + { + "key": { + "range": "d2/testdata/d2compiler/TestCompile2/globs/unsuspend-edge-child.d2,1:0:1-1:1:2", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile2/globs/unsuspend-edge-child.d2,1:0:1-1:1:2", + "value": [ + { + "string": "a", + "raw_string": "a" + } + ] + } + } + ] + }, + "key_path_index": 0, + "map_key_edge_index": -1 + } + ], + "attributes": { + "label": { + "value": "a" + }, + "labelDimensions": { + "width": 0, + "height": 0 + }, + "style": {}, + "near_key": null, + "shape": { + "value": "rectangle" + }, + "direction": { + "value": "" + }, + "constraint": null + }, + "zIndex": 0 + }, + { + "id": "b", + "id_val": "b", + "references": [ + { + "key": { + "range": "d2/testdata/d2compiler/TestCompile2/globs/unsuspend-edge-child.d2,2:2:8-2:3:9", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile2/globs/unsuspend-edge-child.d2,2:2:8-2:3:9", + "value": [ + { + "string": "b", + "raw_string": "b" + } + ] + } + } + ] + }, + "key_path_index": 0, + "map_key_edge_index": 0 + } + ], + "attributes": { + "label": { + "value": "b" + }, + "labelDimensions": { + "width": 0, + "height": 0 + }, + "style": {}, + "near_key": null, + "shape": { + "value": "rectangle" + }, + "direction": { + "value": "" + }, + "constraint": null + }, + "zIndex": 0 + }, + { + "id": "c", + "id_val": "c", + "references": [ + { + "key": { + "range": "d2/testdata/d2compiler/TestCompile2/globs/unsuspend-edge-child.d2,2:7:13-2:8:14", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile2/globs/unsuspend-edge-child.d2,2:7:13-2:8:14", + "value": [ + { + "string": "c", + "raw_string": "c" + } + ] + } + } + ] + }, + "key_path_index": 0, + "map_key_edge_index": 0 + } + ], + "attributes": { + "label": { + "value": "c" + }, + "labelDimensions": { + "width": 0, + "height": 0 + }, + "style": {}, + "near_key": null, + "shape": { + "value": "rectangle" + }, + "direction": { + "value": "" + }, + "constraint": null + }, + "zIndex": 0 + } + ] + }, + "err": null +}