diff --git a/ci/release/changelogs/next.md b/ci/release/changelogs/next.md index 9c2df2e84..c2b7dc711 100644 --- a/ci/release/changelogs/next.md +++ b/ci/release/changelogs/next.md @@ -9,3 +9,4 @@ - Fixes a bug calculating grid height with only grid-rows and different horizontal-gap and vertical-gap values. [#1646](https://github.com/terrastruct/d2/pull/1646) - Grid layout now accounts for each cell's outside labels and icons [#1624](https://github.com/terrastruct/d2/pull/1624) +- Fixes a panic with a spread substitution in a glob map [#1643](https://github.com/terrastruct/d2/pull/1643) diff --git a/d2ast/d2ast.go b/d2ast/d2ast.go index 87b0921f6..85a530c88 100644 --- a/d2ast/d2ast.go +++ b/d2ast/d2ast.go @@ -651,6 +651,12 @@ type Key struct { } func (mk1 *Key) D2OracleEquals(mk2 *Key) bool { + if mk1 == nil && mk2 == nil { + return true + } + if (mk1 == nil) || (mk2 == nil) { + return false + } if mk1.Ampersand != mk2.Ampersand { return false } @@ -724,6 +730,12 @@ func (mk1 *Key) D2OracleEquals(mk2 *Key) bool { } func (mk1 *Key) Equals(mk2 *Key) bool { + if mk1 == nil && mk2 == nil { + return true + } + if (mk1 == nil) || (mk2 == nil) { + return false + } if mk1.Ampersand != mk2.Ampersand { return false } diff --git a/d2compiler/compile_test.go b/d2compiler/compile_test.go index 5bd130eca..836922aae 100644 --- a/d2compiler/compile_test.go +++ b/d2compiler/compile_test.go @@ -2684,6 +2684,28 @@ a -> b: { class: [association; one target] } tassert.Equal(t, "arrow", g.Edges[1].DstArrowhead.Shape.Value) }, }, + { + name: "var_in_glob", + text: `vars: { + v: { + ok + } +} + +x1 -> x2 + +x*: { + ...${v} +} +`, + assertions: func(t *testing.T, g *d2graph.Graph) { + tassert.Equal(t, 4, len(g.Objects)) + tassert.Equal(t, "x1.ok", g.Objects[0].AbsID()) + tassert.Equal(t, "x2.ok", g.Objects[1].AbsID()) + tassert.Equal(t, "x1", g.Objects[2].AbsID()) + tassert.Equal(t, "x2", g.Objects[3].AbsID()) + }, + }, { name: "class-shape-class", text: `classes: { diff --git a/testdata/d2compiler/TestCompile/var_in_glob.exp.json b/testdata/d2compiler/TestCompile/var_in_glob.exp.json new file mode 100644 index 000000000..1ac428dc9 --- /dev/null +++ b/testdata/d2compiler/TestCompile/var_in_glob.exp.json @@ -0,0 +1,428 @@ +{ + "graph": { + "name": "", + "isFolderOnly": false, + "ast": { + "range": "d2/testdata/d2compiler/TestCompile/var_in_glob.d2,0:0:0-11:0:57", + "nodes": [ + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile/var_in_glob.d2,0:0:0-4:1:27", + "key": { + "range": "d2/testdata/d2compiler/TestCompile/var_in_glob.d2,0:0:0-0:4:4", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/var_in_glob.d2,0:0:0-0:4:4", + "value": [ + { + "string": "vars", + "raw_string": "vars" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "map": { + "range": "d2/testdata/d2compiler/TestCompile/var_in_glob.d2,0:6:6-4:1:27", + "nodes": [ + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile/var_in_glob.d2,1:2:10-3:3:25", + "key": { + "range": "d2/testdata/d2compiler/TestCompile/var_in_glob.d2,1:2:10-1:3:11", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/var_in_glob.d2,1:2:10-1:3:11", + "value": [ + { + "string": "v", + "raw_string": "v" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "map": { + "range": "d2/testdata/d2compiler/TestCompile/var_in_glob.d2,1:5:13-3:3:25", + "nodes": [ + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile/var_in_glob.d2,2:4:19-2:6:21", + "key": { + "range": "d2/testdata/d2compiler/TestCompile/var_in_glob.d2,2:4:19-2:6:21", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/var_in_glob.d2,2:4:19-2:6:21", + "value": [ + { + "string": "ok", + "raw_string": "ok" + } + ] + } + } + ] + }, + "primary": {}, + "value": {} + } + } + ] + } + } + } + } + ] + } + } + } + }, + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile/var_in_glob.d2,6:0:29-6:8:37", + "edges": [ + { + "range": "d2/testdata/d2compiler/TestCompile/var_in_glob.d2,6:0:29-6:8:37", + "src": { + "range": "d2/testdata/d2compiler/TestCompile/var_in_glob.d2,6:0:29-6:2:31", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/var_in_glob.d2,6:0:29-6:2:31", + "value": [ + { + "string": "x1", + "raw_string": "x1" + } + ] + } + } + ] + }, + "src_arrow": "", + "dst": { + "range": "d2/testdata/d2compiler/TestCompile/var_in_glob.d2,6:6:35-6:8:37", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/var_in_glob.d2,6:6:35-6:8:37", + "value": [ + { + "string": "x2", + "raw_string": "x2" + } + ] + } + } + ] + }, + "dst_arrow": ">" + } + ], + "primary": {}, + "value": {} + } + }, + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile/var_in_glob.d2,8:0:39-10:1:56", + "key": { + "range": "d2/testdata/d2compiler/TestCompile/var_in_glob.d2,8:0:39-8:2:41", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/var_in_glob.d2,8:0:39-8:2:41", + "value": [ + { + "string": "x*", + "raw_string": "x*" + } + ], + "pattern": [ + "x", + "*" + ] + } + } + ] + }, + "primary": {}, + "value": { + "map": { + "range": "d2/testdata/d2compiler/TestCompile/var_in_glob.d2,8:4:43-10:1:56", + "nodes": [ + { + "substitution": { + "range": "d2/testdata/d2compiler/TestCompile/var_in_glob.d2,9:2:47-9:9:54", + "spread": true, + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/var_in_glob.d2,9:7:52-9:8:53", + "value": [ + { + "string": "v", + "raw_string": "v" + } + ] + } + } + ] + } + } + ] + } + } + } + } + ] + }, + "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 + } + ], + "attributes": { + "label": { + "value": "" + }, + "labelDimensions": { + "width": 0, + "height": 0 + }, + "style": {}, + "near_key": null, + "shape": { + "value": "" + }, + "direction": { + "value": "" + }, + "constraint": null + }, + "zIndex": 0 + } + ], + "objects": [ + { + "id": "ok", + "id_val": "ok", + "references": [ + { + "key": { + "range": "d2/testdata/d2compiler/TestCompile/var_in_glob.d2,2:4:19-2:6:21", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/var_in_glob.d2,2:4:19-2:6:21", + "value": [ + { + "string": "ok", + "raw_string": "ok" + } + ] + } + } + ] + }, + "key_path_index": 0, + "map_key_edge_index": -1 + } + ], + "attributes": { + "label": { + "value": "ok" + }, + "labelDimensions": { + "width": 0, + "height": 0 + }, + "style": {}, + "near_key": null, + "shape": { + "value": "rectangle" + }, + "direction": { + "value": "" + }, + "constraint": null + }, + "zIndex": 0 + }, + { + "id": "ok", + "id_val": "ok", + "references": [ + { + "key": { + "range": "d2/testdata/d2compiler/TestCompile/var_in_glob.d2,2:4:19-2:6:21", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/var_in_glob.d2,2:4:19-2:6:21", + "value": [ + { + "string": "ok", + "raw_string": "ok" + } + ] + } + } + ] + }, + "key_path_index": 0, + "map_key_edge_index": -1 + } + ], + "attributes": { + "label": { + "value": "ok" + }, + "labelDimensions": { + "width": 0, + "height": 0 + }, + "style": {}, + "near_key": null, + "shape": { + "value": "rectangle" + }, + "direction": { + "value": "" + }, + "constraint": null + }, + "zIndex": 0 + }, + { + "id": "x1", + "id_val": "x1", + "references": [ + { + "key": { + "range": "d2/testdata/d2compiler/TestCompile/var_in_glob.d2,6:0:29-6:2:31", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/var_in_glob.d2,6:0:29-6:2:31", + "value": [ + { + "string": "x1", + "raw_string": "x1" + } + ] + } + } + ] + }, + "key_path_index": 0, + "map_key_edge_index": 0 + } + ], + "attributes": { + "label": { + "value": "x1" + }, + "labelDimensions": { + "width": 0, + "height": 0 + }, + "style": {}, + "near_key": null, + "shape": { + "value": "rectangle" + }, + "direction": { + "value": "" + }, + "constraint": null + }, + "zIndex": 0 + }, + { + "id": "x2", + "id_val": "x2", + "references": [ + { + "key": { + "range": "d2/testdata/d2compiler/TestCompile/var_in_glob.d2,6:6:35-6:8:37", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/var_in_glob.d2,6:6:35-6:8:37", + "value": [ + { + "string": "x2", + "raw_string": "x2" + } + ] + } + } + ] + }, + "key_path_index": 0, + "map_key_edge_index": 0 + } + ], + "attributes": { + "label": { + "value": "x2" + }, + "labelDimensions": { + "width": 0, + "height": 0 + }, + "style": {}, + "near_key": null, + "shape": { + "value": "rectangle" + }, + "direction": { + "value": "" + }, + "constraint": null + }, + "zIndex": 0 + } + ] + }, + "err": null +}