From 0002817b0a9621741195d49dc4661acbfb9baf05 Mon Sep 17 00:00:00 2001 From: Anmol Sethi Date: Sat, 29 Jul 2023 15:09:29 -0700 Subject: [PATCH] d2ir: Implement ampersand filters --- d2ast/d2ast.go | 2 +- d2ir/compile.go | 25 + d2ir/compile_test.go | 1 + d2ir/filter_test.go | 36 + .../d2ir/TestCompile/filters/escaped.exp.json | 637 ++++++++++++++++++ 5 files changed, 700 insertions(+), 1 deletion(-) create mode 100644 d2ir/filter_test.go create mode 100644 testdata/d2ir/TestCompile/filters/escaped.exp.json diff --git a/d2ast/d2ast.go b/d2ast/d2ast.go index 6b6f47389..102429b7a 100644 --- a/d2ast/d2ast.go +++ b/d2ast/d2ast.go @@ -610,7 +610,7 @@ func (m *Map) IsFileMap() bool { type Key struct { Range Range `json:"range"` - // Indicates this MapKey is an override selector. + // Indicates this MapKey is a filter selector. Ampersand bool `json:"ampersand,omitempty"` // At least one of Key and Edges will be set but all four can also be set. diff --git a/d2ir/compile.go b/d2ir/compile.go index 43763139d..c422eaa79 100644 --- a/d2ir/compile.go +++ b/d2ir/compile.go @@ -408,6 +408,31 @@ func (c *compiler) compileField(dst *Map, kp *d2ast.KeyPath, refctx *RefContext) } func (c *compiler) _compileField(f *Field, refctx *RefContext) { + if refctx.Key.Ampersand { + f2 := ParentMap(f).Map().GetField(refctx.Key.Key.IDA()...) + if f2 == nil { + return + } + if refctx.Key.Primary.Unbox() != nil { + if f2.Primary_ == nil { + return + } + if refctx.Key.Primary.Unbox().ScalarString() != f2.Primary_.Value.ScalarString() { + return + } + } + if refctx.Key.Value.ScalarBox().Unbox() != nil { + if f2.Primary_ == nil { + return + } + if refctx.Key.Value.ScalarBox().Unbox().ScalarString() != f2.Primary_.Value.ScalarString() { + println(refctx.Key.Value.ScalarBox().Unbox().ScalarString()) + println(f2.Primary_.Value.ScalarString()) + return + } + } + } + if len(refctx.Key.Edges) == 0 && refctx.Key.Value.Null != nil { // For vars, if we delete the field, it may just resolve to an outer scope var of the same name // Instead we keep it around, so that resolveSubstitutions can find it diff --git a/d2ir/compile_test.go b/d2ir/compile_test.go index 64d16ad8d..9fc96b228 100644 --- a/d2ir/compile_test.go +++ b/d2ir/compile_test.go @@ -27,6 +27,7 @@ func TestCompile(t *testing.T) { t.Run("steps", testCompileSteps) t.Run("imports", testCompileImports) t.Run("patterns", testCompilePatterns) + t.Run("filters", testCompileFilters) } type testCase struct { diff --git a/d2ir/filter_test.go b/d2ir/filter_test.go new file mode 100644 index 000000000..9ba4c3559 --- /dev/null +++ b/d2ir/filter_test.go @@ -0,0 +1,36 @@ +package d2ir_test + +import ( + "testing" + + "oss.terrastruct.com/util-go/assert" +) + +func testCompileFilters(t *testing.T) { + t.Parallel() + + tca := []testCase{ + { + name: "escaped", + run: func(t testing.TB) { + m, err := compile(t, `jacob: { + shape: circle +} +jeremy: { + shape: rectangle +} +*: { + &shape: rectangle + label: I'm a rectangle +}`) + assert.Success(t, err) + t.Log(m.String()) + assertQuery(t, m, 1, 0, nil, "jacob") + assertQuery(t, m, 2, 0, "", "jeremy") + assertQuery(t, m, 0, 0, "I'm a rectangle", "jeremy.label") + }, + }, + } + + runa(t, tca) +} diff --git a/testdata/d2ir/TestCompile/filters/escaped.exp.json b/testdata/d2ir/TestCompile/filters/escaped.exp.json new file mode 100644 index 000000000..6553327a5 --- /dev/null +++ b/testdata/d2ir/TestCompile/filters/escaped.exp.json @@ -0,0 +1,637 @@ +{ + "fields": [ + { + "name": "jacob", + "composite": { + "fields": [ + { + "name": "shape", + "primary": { + "value": { + "range": "TestCompile/filters/escaped.d2,1:8:17-1:14:23", + "value": [ + { + "string": "circle", + "raw_string": "circle" + } + ] + } + }, + "references": [ + { + "string": { + "range": "TestCompile/filters/escaped.d2,1:1:10-1:6:15", + "value": [ + { + "string": "shape", + "raw_string": "shape" + } + ] + }, + "key_path": { + "range": "TestCompile/filters/escaped.d2,1:1:10-1:6:15", + "path": [ + { + "unquoted_string": { + "range": "TestCompile/filters/escaped.d2,1:1:10-1:6:15", + "value": [ + { + "string": "shape", + "raw_string": "shape" + } + ] + } + } + ] + }, + "context": { + "edge": null, + "key": { + "range": "TestCompile/filters/escaped.d2,1:1:10-1:14:23", + "key": { + "range": "TestCompile/filters/escaped.d2,1:1:10-1:6:15", + "path": [ + { + "unquoted_string": { + "range": "TestCompile/filters/escaped.d2,1:1:10-1:6:15", + "value": [ + { + "string": "shape", + "raw_string": "shape" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "unquoted_string": { + "range": "TestCompile/filters/escaped.d2,1:8:17-1:14:23", + "value": [ + { + "string": "circle", + "raw_string": "circle" + } + ] + } + } + } + } + }, + { + "string": { + "range": "TestCompile/filters/escaped.d2,7:2:63-7:7:68", + "value": [ + { + "string": "shape", + "raw_string": "shape" + } + ] + }, + "key_path": { + "range": "TestCompile/filters/escaped.d2,7:2:63-7:7:68", + "path": [ + { + "unquoted_string": { + "range": "TestCompile/filters/escaped.d2,7:2:63-7:7:68", + "value": [ + { + "string": "shape", + "raw_string": "shape" + } + ] + } + } + ] + }, + "context": { + "edge": null, + "key": { + "range": "TestCompile/filters/escaped.d2,7:1:62-7:18:79", + "ampersand": true, + "key": { + "range": "TestCompile/filters/escaped.d2,7:2:63-7:7:68", + "path": [ + { + "unquoted_string": { + "range": "TestCompile/filters/escaped.d2,7:2:63-7:7:68", + "value": [ + { + "string": "shape", + "raw_string": "shape" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "unquoted_string": { + "range": "TestCompile/filters/escaped.d2,7:9:70-7:18:79", + "value": [ + { + "string": "rectangle", + "raw_string": "rectangle" + } + ] + } + } + } + } + } + ] + }, + { + "name": "label", + "primary": { + "value": { + "range": "TestCompile/filters/escaped.d2,8:8:88-8:23:103", + "value": [ + { + "string": "I'm a rectangle", + "raw_string": "I'm a rectangle" + } + ] + } + }, + "references": [ + { + "string": { + "range": "TestCompile/filters/escaped.d2,8:1:81-8:6:86", + "value": [ + { + "string": "label", + "raw_string": "label" + } + ] + }, + "key_path": { + "range": "TestCompile/filters/escaped.d2,8:1:81-8:6:86", + "path": [ + { + "unquoted_string": { + "range": "TestCompile/filters/escaped.d2,8:1:81-8:6:86", + "value": [ + { + "string": "label", + "raw_string": "label" + } + ] + } + } + ] + }, + "context": { + "edge": null, + "key": { + "range": "TestCompile/filters/escaped.d2,8:1:81-8:23:103", + "key": { + "range": "TestCompile/filters/escaped.d2,8:1:81-8:6:86", + "path": [ + { + "unquoted_string": { + "range": "TestCompile/filters/escaped.d2,8:1:81-8:6:86", + "value": [ + { + "string": "label", + "raw_string": "label" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "unquoted_string": { + "range": "TestCompile/filters/escaped.d2,8:8:88-8:23:103", + "value": [ + { + "string": "I'm a rectangle", + "raw_string": "I'm a rectangle" + } + ] + } + } + } + } + } + ] + } + ], + "edges": null + }, + "references": [ + { + "string": { + "range": "TestCompile/filters/escaped.d2,0:0:0-0:5:5", + "value": [ + { + "string": "jacob", + "raw_string": "jacob" + } + ] + }, + "key_path": { + "range": "TestCompile/filters/escaped.d2,0:0:0-0:5:5", + "path": [ + { + "unquoted_string": { + "range": "TestCompile/filters/escaped.d2,0:0:0-0:5:5", + "value": [ + { + "string": "jacob", + "raw_string": "jacob" + } + ] + } + } + ] + }, + "context": { + "edge": null, + "key": { + "range": "TestCompile/filters/escaped.d2,0:0:0-2:1:25", + "key": { + "range": "TestCompile/filters/escaped.d2,0:0:0-0:5:5", + "path": [ + { + "unquoted_string": { + "range": "TestCompile/filters/escaped.d2,0:0:0-0:5:5", + "value": [ + { + "string": "jacob", + "raw_string": "jacob" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "map": { + "range": "TestCompile/filters/escaped.d2,0:7:7-2:1:25", + "nodes": [ + { + "map_key": { + "range": "TestCompile/filters/escaped.d2,1:1:10-1:14:23", + "key": { + "range": "TestCompile/filters/escaped.d2,1:1:10-1:6:15", + "path": [ + { + "unquoted_string": { + "range": "TestCompile/filters/escaped.d2,1:1:10-1:6:15", + "value": [ + { + "string": "shape", + "raw_string": "shape" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "unquoted_string": { + "range": "TestCompile/filters/escaped.d2,1:8:17-1:14:23", + "value": [ + { + "string": "circle", + "raw_string": "circle" + } + ] + } + } + } + } + ] + } + } + } + } + } + ] + }, + { + "name": "jeremy", + "composite": { + "fields": [ + { + "name": "shape", + "primary": { + "value": { + "range": "TestCompile/filters/escaped.d2,7:9:70-7:18:79", + "value": [ + { + "string": "rectangle", + "raw_string": "rectangle" + } + ] + } + }, + "references": [ + { + "string": { + "range": "TestCompile/filters/escaped.d2,4:1:37-4:6:42", + "value": [ + { + "string": "shape", + "raw_string": "shape" + } + ] + }, + "key_path": { + "range": "TestCompile/filters/escaped.d2,4:1:37-4:6:42", + "path": [ + { + "unquoted_string": { + "range": "TestCompile/filters/escaped.d2,4:1:37-4:6:42", + "value": [ + { + "string": "shape", + "raw_string": "shape" + } + ] + } + } + ] + }, + "context": { + "edge": null, + "key": { + "range": "TestCompile/filters/escaped.d2,4:1:37-4:17:53", + "key": { + "range": "TestCompile/filters/escaped.d2,4:1:37-4:6:42", + "path": [ + { + "unquoted_string": { + "range": "TestCompile/filters/escaped.d2,4:1:37-4:6:42", + "value": [ + { + "string": "shape", + "raw_string": "shape" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "unquoted_string": { + "range": "TestCompile/filters/escaped.d2,4:8:44-4:17:53", + "value": [ + { + "string": "rectangle", + "raw_string": "rectangle" + } + ] + } + } + } + } + }, + { + "string": { + "range": "TestCompile/filters/escaped.d2,7:2:63-7:7:68", + "value": [ + { + "string": "shape", + "raw_string": "shape" + } + ] + }, + "key_path": { + "range": "TestCompile/filters/escaped.d2,7:2:63-7:7:68", + "path": [ + { + "unquoted_string": { + "range": "TestCompile/filters/escaped.d2,7:2:63-7:7:68", + "value": [ + { + "string": "shape", + "raw_string": "shape" + } + ] + } + } + ] + }, + "context": { + "edge": null, + "key": { + "range": "TestCompile/filters/escaped.d2,7:1:62-7:18:79", + "ampersand": true, + "key": { + "range": "TestCompile/filters/escaped.d2,7:2:63-7:7:68", + "path": [ + { + "unquoted_string": { + "range": "TestCompile/filters/escaped.d2,7:2:63-7:7:68", + "value": [ + { + "string": "shape", + "raw_string": "shape" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "unquoted_string": { + "range": "TestCompile/filters/escaped.d2,7:9:70-7:18:79", + "value": [ + { + "string": "rectangle", + "raw_string": "rectangle" + } + ] + } + } + } + } + } + ] + }, + { + "name": "label", + "primary": { + "value": { + "range": "TestCompile/filters/escaped.d2,8:8:88-8:23:103", + "value": [ + { + "string": "I'm a rectangle", + "raw_string": "I'm a rectangle" + } + ] + } + }, + "references": [ + { + "string": { + "range": "TestCompile/filters/escaped.d2,8:1:81-8:6:86", + "value": [ + { + "string": "label", + "raw_string": "label" + } + ] + }, + "key_path": { + "range": "TestCompile/filters/escaped.d2,8:1:81-8:6:86", + "path": [ + { + "unquoted_string": { + "range": "TestCompile/filters/escaped.d2,8:1:81-8:6:86", + "value": [ + { + "string": "label", + "raw_string": "label" + } + ] + } + } + ] + }, + "context": { + "edge": null, + "key": { + "range": "TestCompile/filters/escaped.d2,8:1:81-8:23:103", + "key": { + "range": "TestCompile/filters/escaped.d2,8:1:81-8:6:86", + "path": [ + { + "unquoted_string": { + "range": "TestCompile/filters/escaped.d2,8:1:81-8:6:86", + "value": [ + { + "string": "label", + "raw_string": "label" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "unquoted_string": { + "range": "TestCompile/filters/escaped.d2,8:8:88-8:23:103", + "value": [ + { + "string": "I'm a rectangle", + "raw_string": "I'm a rectangle" + } + ] + } + } + } + } + } + ] + } + ], + "edges": null + }, + "references": [ + { + "string": { + "range": "TestCompile/filters/escaped.d2,3:0:26-3:6:32", + "value": [ + { + "string": "jeremy", + "raw_string": "jeremy" + } + ] + }, + "key_path": { + "range": "TestCompile/filters/escaped.d2,3:0:26-3:6:32", + "path": [ + { + "unquoted_string": { + "range": "TestCompile/filters/escaped.d2,3:0:26-3:6:32", + "value": [ + { + "string": "jeremy", + "raw_string": "jeremy" + } + ] + } + } + ] + }, + "context": { + "edge": null, + "key": { + "range": "TestCompile/filters/escaped.d2,3:0:26-5:1:55", + "key": { + "range": "TestCompile/filters/escaped.d2,3:0:26-3:6:32", + "path": [ + { + "unquoted_string": { + "range": "TestCompile/filters/escaped.d2,3:0:26-3:6:32", + "value": [ + { + "string": "jeremy", + "raw_string": "jeremy" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "map": { + "range": "TestCompile/filters/escaped.d2,3:8:34-5:1:55", + "nodes": [ + { + "map_key": { + "range": "TestCompile/filters/escaped.d2,4:1:37-4:17:53", + "key": { + "range": "TestCompile/filters/escaped.d2,4:1:37-4:6:42", + "path": [ + { + "unquoted_string": { + "range": "TestCompile/filters/escaped.d2,4:1:37-4:6:42", + "value": [ + { + "string": "shape", + "raw_string": "shape" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "unquoted_string": { + "range": "TestCompile/filters/escaped.d2,4:8:44-4:17:53", + "value": [ + { + "string": "rectangle", + "raw_string": "rectangle" + } + ] + } + } + } + } + ] + } + } + } + } + } + ] + } + ], + "edges": null +}