diff --git a/d2compiler/compile_test.go b/d2compiler/compile_test.go index a283166be..f0dbaa1bb 100644 --- a/d2compiler/compile_test.go +++ b/d2compiler/compile_test.go @@ -3079,6 +3079,19 @@ y: null assert.Equal(t, 0, len(g.Edges)) }, }, + { + name: "delete-multiple-connections", + run: func(t *testing.T) { + g := assertCompile(t, ` +x -> y +z -> y +y -> a +y: null +`, "") + assert.Equal(t, 3, len(g.Objects)) + assert.Equal(t, 0, len(g.Edges)) + }, + }, { name: "no-delete-connection", run: func(t *testing.T) { diff --git a/d2ir/d2ir.go b/d2ir/d2ir.go index dc239975a..65ed636b5 100644 --- a/d2ir/d2ir.go +++ b/d2ir/d2ir.go @@ -766,11 +766,10 @@ func (m *Map) DeleteField(ida ...string) *Field { } if len(rest) == 0 { for _, fr := range f.References { - for i, e := range m.Edges { + for _, e := range m.Edges { for _, er := range e.References { if er.Context == fr.Context { m.DeleteEdge(e.ID) - i-- break } } @@ -781,12 +780,12 @@ func (m *Map) DeleteField(ida ...string) *Field { // If a field was deleted from a keyword-holder keyword and that holder is empty, // then that holder becomes meaningless and should be deleted too parent := ParentField(f) - for keyword := range d2graph.ReservedKeywordHolders { - if parent != nil && parent.Name == keyword && len(parent.Map().Fields) == 0 { - styleParentMap := ParentMap(parent) - for i, f := range styleParentMap.Fields { - if f.Name == keyword { - styleParentMap.Fields = append(styleParentMap.Fields[:i], styleParentMap.Fields[i+1:]...) + for keywordHolder := range d2graph.ReservedKeywordHolders { + if parent != nil && parent.Name == keywordHolder && len(parent.Map().Fields) == 0 { + keywordHolderParentMap := ParentMap(parent) + for i, f := range keywordHolderParentMap.Fields { + if f.Name == keywordHolder { + keywordHolderParentMap.Fields = append(keywordHolderParentMap.Fields[:i], keywordHolderParentMap.Fields[i+1:]...) break } } diff --git a/testdata/d2compiler/TestCompile2/nulls/implicit/delete-multiple-connections.exp.json b/testdata/d2compiler/TestCompile2/nulls/implicit/delete-multiple-connections.exp.json new file mode 100644 index 000000000..7a9d1b326 --- /dev/null +++ b/testdata/d2compiler/TestCompile2/nulls/implicit/delete-multiple-connections.exp.json @@ -0,0 +1,338 @@ +{ + "graph": { + "name": "", + "isFolderOnly": false, + "ast": { + "range": "d2/testdata/d2compiler/TestCompile2/nulls/implicit/delete-multiple-connections.d2,0:0:0-5:0:30", + "nodes": [ + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile2/nulls/implicit/delete-multiple-connections.d2,1:0:1-1:6:7", + "edges": [ + { + "range": "d2/testdata/d2compiler/TestCompile2/nulls/implicit/delete-multiple-connections.d2,1:0:1-1:6:7", + "src": { + "range": "d2/testdata/d2compiler/TestCompile2/nulls/implicit/delete-multiple-connections.d2,1:0:1-1:1:2", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile2/nulls/implicit/delete-multiple-connections.d2,1:0:1-1:1:2", + "value": [ + { + "string": "x", + "raw_string": "x" + } + ] + } + } + ] + }, + "src_arrow": "", + "dst": { + "range": "d2/testdata/d2compiler/TestCompile2/nulls/implicit/delete-multiple-connections.d2,1:5:6-1:6:7", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile2/nulls/implicit/delete-multiple-connections.d2,1:5:6-1:6:7", + "value": [ + { + "string": "y", + "raw_string": "y" + } + ] + } + } + ] + }, + "dst_arrow": ">" + } + ], + "primary": {}, + "value": {} + } + }, + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile2/nulls/implicit/delete-multiple-connections.d2,2:0:8-2:6:14", + "edges": [ + { + "range": "d2/testdata/d2compiler/TestCompile2/nulls/implicit/delete-multiple-connections.d2,2:0:8-2:6:14", + "src": { + "range": "d2/testdata/d2compiler/TestCompile2/nulls/implicit/delete-multiple-connections.d2,2:0:8-2:1:9", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile2/nulls/implicit/delete-multiple-connections.d2,2:0:8-2:1:9", + "value": [ + { + "string": "z", + "raw_string": "z" + } + ] + } + } + ] + }, + "src_arrow": "", + "dst": { + "range": "d2/testdata/d2compiler/TestCompile2/nulls/implicit/delete-multiple-connections.d2,2:5:13-2:6:14", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile2/nulls/implicit/delete-multiple-connections.d2,2:5:13-2:6:14", + "value": [ + { + "string": "y", + "raw_string": "y" + } + ] + } + } + ] + }, + "dst_arrow": ">" + } + ], + "primary": {}, + "value": {} + } + }, + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile2/nulls/implicit/delete-multiple-connections.d2,3:0:15-3:6:21", + "edges": [ + { + "range": "d2/testdata/d2compiler/TestCompile2/nulls/implicit/delete-multiple-connections.d2,3:0:15-3:6:21", + "src": { + "range": "d2/testdata/d2compiler/TestCompile2/nulls/implicit/delete-multiple-connections.d2,3:0:15-3:1:16", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile2/nulls/implicit/delete-multiple-connections.d2,3:0:15-3:1:16", + "value": [ + { + "string": "y", + "raw_string": "y" + } + ] + } + } + ] + }, + "src_arrow": "", + "dst": { + "range": "d2/testdata/d2compiler/TestCompile2/nulls/implicit/delete-multiple-connections.d2,3:5:20-3:6:21", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile2/nulls/implicit/delete-multiple-connections.d2,3:5:20-3:6:21", + "value": [ + { + "string": "a", + "raw_string": "a" + } + ] + } + } + ] + }, + "dst_arrow": ">" + } + ], + "primary": {}, + "value": {} + } + }, + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile2/nulls/implicit/delete-multiple-connections.d2,4:0:22-4:7:29", + "key": { + "range": "d2/testdata/d2compiler/TestCompile2/nulls/implicit/delete-multiple-connections.d2,4:0:22-4:1:23", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile2/nulls/implicit/delete-multiple-connections.d2,4:0:22-4:1:23", + "value": [ + { + "string": "y", + "raw_string": "y" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "null": { + "range": "d2/testdata/d2compiler/TestCompile2/nulls/implicit/delete-multiple-connections.d2,4:3:25-4:7:29" + } + } + } + } + ] + }, + "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": null, + "objects": [ + { + "id": "x", + "id_val": "x", + "references": [ + { + "key": { + "range": "d2/testdata/d2compiler/TestCompile2/nulls/implicit/delete-multiple-connections.d2,1:0:1-1:1:2", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile2/nulls/implicit/delete-multiple-connections.d2,1:0:1-1:1:2", + "value": [ + { + "string": "x", + "raw_string": "x" + } + ] + } + } + ] + }, + "key_path_index": 0, + "map_key_edge_index": 0 + } + ], + "attributes": { + "label": { + "value": "x" + }, + "labelDimensions": { + "width": 0, + "height": 0 + }, + "style": {}, + "near_key": null, + "shape": { + "value": "rectangle" + }, + "direction": { + "value": "" + }, + "constraint": null + }, + "zIndex": 0 + }, + { + "id": "z", + "id_val": "z", + "references": [ + { + "key": { + "range": "d2/testdata/d2compiler/TestCompile2/nulls/implicit/delete-multiple-connections.d2,2:0:8-2:1:9", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile2/nulls/implicit/delete-multiple-connections.d2,2:0:8-2:1:9", + "value": [ + { + "string": "z", + "raw_string": "z" + } + ] + } + } + ] + }, + "key_path_index": 0, + "map_key_edge_index": 0 + } + ], + "attributes": { + "label": { + "value": "z" + }, + "labelDimensions": { + "width": 0, + "height": 0 + }, + "style": {}, + "near_key": null, + "shape": { + "value": "rectangle" + }, + "direction": { + "value": "" + }, + "constraint": null + }, + "zIndex": 0 + }, + { + "id": "a", + "id_val": "a", + "references": [ + { + "key": { + "range": "d2/testdata/d2compiler/TestCompile2/nulls/implicit/delete-multiple-connections.d2,3:5:20-3:6:21", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile2/nulls/implicit/delete-multiple-connections.d2,3:5:20-3:6:21", + "value": [ + { + "string": "a", + "raw_string": "a" + } + ] + } + } + ] + }, + "key_path_index": 0, + "map_key_edge_index": 0 + } + ], + "attributes": { + "label": { + "value": "a" + }, + "labelDimensions": { + "width": 0, + "height": 0 + }, + "style": {}, + "near_key": null, + "shape": { + "value": "rectangle" + }, + "direction": { + "value": "" + }, + "constraint": null + }, + "zIndex": 0 + } + ] + }, + "err": null +}