From db3e4c21a76b2aaef20c87d483394a33c7a52716 Mon Sep 17 00:00:00 2001 From: Alexander Wang Date: Mon, 31 Mar 2025 11:49:07 -0600 Subject: [PATCH] implement --- d2compiler/compile_test.go | 8 +- d2ir/compile.go | 122 +++++++++++------- .../TestCompile2/globs/level-filter.exp.json | 16 ++- 3 files changed, 97 insertions(+), 49 deletions(-) diff --git a/d2compiler/compile_test.go b/d2compiler/compile_test.go index 591184f53..da5e686ba 100644 --- a/d2compiler/compile_test.go +++ b/d2compiler/compile_test.go @@ -5679,7 +5679,13 @@ a.1 -> x assert.Equal(t, (*d2graph.Scalar)(nil), g.Objects[2].Attributes.Style.Stroke) assert.Equal(t, "(x -> y)[0]", g.Edges[0].AbsID()) - assert.Equal(t, "blue", g.Edges[0].Attributes.Style.Stroke) + assert.Equal(t, "blue", g.Edges[0].Attributes.Style.Stroke.Value) + + assert.Equal(t, "a.(1 -> 2)[0]", g.Edges[1].AbsID()) + assert.Equal(t, (*d2graph.Scalar)(nil), g.Edges[1].Attributes.Style.Stroke) + + assert.Equal(t, "(a.1 -> x)[0]", g.Edges[2].AbsID()) + assert.Equal(t, (*d2graph.Scalar)(nil), g.Edges[2].Attributes.Style.Stroke) }, }, { diff --git a/d2ir/compile.go b/d2ir/compile.go index 47031ddfe..04754ce48 100644 --- a/d2ir/compile.go +++ b/d2ir/compile.go @@ -755,6 +755,13 @@ func (c *compiler) ampersandFilter(refctx *RefContext) bool { return false } + secondPart := keyPath.Path[1].Unbox().ScalarString() + value := refctx.Key.Value.ScalarBox().Unbox().ScalarString() + + if len(keyPath.Path) == 2 && c._ampersandPropertyFilter(secondPart, value, node, refctx.Key) { + return true + } + propKeyPath := &d2ast.KeyPath{ Path: keyPath.Path[1:], } @@ -840,53 +847,7 @@ func (c *compiler) ampersandFilter(refctx *RefContext) bool { }, } return c._ampersandFilter(f, refctx) - case "leaf": - raw := refctx.Key.Value.ScalarBox().Unbox().ScalarString() - boolVal, err := strconv.ParseBool(raw) - if err != nil { - c.errorf(refctx.Key, `&leaf must be "true" or "false", got %q`, raw) - return false - } - f := refctx.ScopeMap.Parent().(*Field) - isLeaf := f.Map() == nil || !f.Map().IsContainer() - return isLeaf == boolVal - case "level": - raw := refctx.Key.Value.ScalarBox().Unbox().ScalarString() - levelVal, err := strconv.Atoi(raw) - if err != nil { - c.errorf(refctx.Key, `&level must be a non-negative integer, got %q`, raw) - return false - } - if levelVal < 0 { - c.errorf(refctx.Key, `&level must be a non-negative integer, got %d`, levelVal) - return false - } - - f := refctx.ScopeMap.Parent().(*Field) - level := 0 - parent := ParentField(f) - for parent != nil && parent.Name.ScalarString() != "root" && NodeBoardKind(parent) == "" { - level++ - parent = ParentField(parent) - } - return level == levelVal - case "connected": - raw := refctx.Key.Value.ScalarBox().Unbox().ScalarString() - boolVal, err := strconv.ParseBool(raw) - if err != nil { - c.errorf(refctx.Key, `&connected must be "true" or "false", got %q`, raw) - return false - } - f := refctx.ScopeMap.Parent().(*Field) - isConnected := false - for _, r := range f.References { - if r.InEdge() { - isConnected = true - break - } - } - return isConnected == boolVal case "label": f := &Field{} n := refctx.ScopeMap.Parent() @@ -978,7 +939,10 @@ func (c *compiler) ampersandFilter(refctx *RefContext) bool { return dstPath == filterValue default: - return false + f := refctx.ScopeMap.Parent().(*Field) + propName := refctx.Key.Key.Last().ScalarString() + value := refctx.Key.Value.ScalarBox().Unbox().ScalarString() + return c._ampersandPropertyFilter(propName, value, f, refctx.Key) } } for _, f := range fa { @@ -990,6 +954,70 @@ func (c *compiler) ampersandFilter(refctx *RefContext) bool { return true } +// handles filters that are not based on fields +func (c *compiler) _ampersandPropertyFilter(propName string, value string, node *Field, key *d2ast.Key) bool { + switch propName { + case "level": + levelVal, err := strconv.Atoi(value) + if err != nil { + c.errorf(key, `&level must be a non-negative integer, got %q`, value) + return false + } + if levelVal < 0 { + c.errorf(key, `&level must be a non-negative integer, got %d`, levelVal) + return false + } + + level := 0 + parent := ParentField(node) + for parent != nil && parent.Name.ScalarString() != "root" && NodeBoardKind(parent) == "" { + level++ + parent = ParentField(parent) + } + return level == levelVal + case "leaf": + boolVal, err := strconv.ParseBool(value) + if err != nil { + c.errorf(key, `&leaf must be "true" or "false", got %q`, value) + return false + } + isLeaf := node.Map() == nil || !node.Map().IsContainer() + return isLeaf == boolVal + case "connected": + boolVal, err := strconv.ParseBool(value) + if err != nil { + c.errorf(key, `&connected must be "true" or "false", got %q`, value) + return false + } + isConnected := false + for _, r := range node.References { + if r.InEdge() { + isConnected = true + break + } + } + return isConnected == boolVal + case "label": + f := &Field{} + if node.Primary() == nil { + f.Primary_ = &Scalar{ + Value: node.Name, + } + } else { + f.Primary_ = node.Primary() + } + propKey := &d2ast.Key{ + Key: key.Key, + Value: key.Value, + } + propRefCtx := &RefContext{ + Key: propKey, + } + return c._ampersandFilter(f, propRefCtx) + } + return false +} + func (c *compiler) _ampersandFilter(f *Field, refctx *RefContext) bool { if refctx.Key.Value.ScalarBox().Unbox() == nil { c.errorf(refctx.Key, "glob filters cannot be composites") diff --git a/testdata/d2compiler/TestCompile2/globs/level-filter.exp.json b/testdata/d2compiler/TestCompile2/globs/level-filter.exp.json index 414d3eee0..acec6846c 100644 --- a/testdata/d2compiler/TestCompile2/globs/level-filter.exp.json +++ b/testdata/d2compiler/TestCompile2/globs/level-filter.exp.json @@ -670,6 +670,9 @@ "src_arrow": false, "dst_arrow": true, "references": [ + { + "map_key_edge_index": 0 + }, { "map_key_edge_index": 0 } @@ -682,7 +685,12 @@ "width": 0, "height": 0 }, - "style": {}, + "style": { + "stroke": { + "value": "blue" + } + }, + "iconStyle": {}, "near_key": null, "shape": { "value": "" @@ -713,6 +721,7 @@ "height": 0 }, "style": {}, + "iconStyle": {}, "near_key": null, "shape": { "value": "" @@ -743,6 +752,7 @@ "height": 0 }, "style": {}, + "iconStyle": {}, "near_key": null, "shape": { "value": "" @@ -1077,6 +1087,7 @@ "value": "red" } }, + "iconStyle": {}, "near_key": null, "shape": { "value": "rectangle" @@ -1126,6 +1137,7 @@ "value": "red" } }, + "iconStyle": {}, "near_key": null, "shape": { "value": "rectangle" @@ -1206,6 +1218,7 @@ "value": "yellow" } }, + "iconStyle": {}, "near_key": null, "shape": { "value": "rectangle" @@ -1255,6 +1268,7 @@ "value": "yellow" } }, + "iconStyle": {}, "near_key": null, "shape": { "value": "rectangle"