diff --git a/d2compiler/compile.go b/d2compiler/compile.go index d99f7994c..df750cc7a 100644 --- a/d2compiler/compile.go +++ b/d2compiler/compile.go @@ -382,6 +382,47 @@ func (c *compiler) compileLabel(attrs *d2graph.Attributes, f d2ir.Node) { attrs.Label.MapKey = f.LastPrimaryKey() } +func (c *compiler) compilePosition(attrs *d2graph.Attributes, f *d2ir.Field) { + name := f.Name + if f.Map() != nil { + for _, f := range f.Map().Fields { + if f.Name == "near" { + if f.Primary() == nil { + c.errorf(f.LastPrimaryKey(), `invalid "near" field`) + } else { + scalar := f.Primary().Value + switch scalar := scalar.(type) { + case *d2ast.Null: + attrs.LabelPosition = nil + default: + if _, ok := d2graph.LabelPositions[scalar.ScalarString()]; !ok { + c.errorf(f.LastPrimaryKey(), `invalid "near" field`) + } else { + switch name { + case "label": + attrs.LabelPosition = &d2graph.Scalar{} + attrs.LabelPosition.Value = scalar.ScalarString() + attrs.LabelPosition.MapKey = f.LastPrimaryKey() + case "icon": + attrs.IconPosition = &d2graph.Scalar{} + attrs.IconPosition.Value = scalar.ScalarString() + attrs.IconPosition.MapKey = f.LastPrimaryKey() + } + } + } + } + } else { + if f.LastPrimaryKey() != nil { + c.errorf(f.LastPrimaryKey(), `unexpected field %s`, f.Name) + } + } + } + if len(f.Map().Edges) > 0 { + c.errorf(f.LastPrimaryKey(), "unexpected edges in map") + } + } +} + func (c *compiler) compileReserved(attrs *d2graph.Attributes, f *d2ir.Field) { if f.Primary() == nil { if f.Composite != nil { @@ -402,6 +443,8 @@ func (c *compiler) compileReserved(attrs *d2graph.Attributes, f *d2ir.Field) { } } } + case "label", "icon": + c.compilePosition(attrs, f) default: c.errorf(f.LastPrimaryKey(), "reserved field %v does not accept composite", f.Name) } @@ -412,6 +455,7 @@ func (c *compiler) compileReserved(attrs *d2graph.Attributes, f *d2ir.Field) { switch f.Name { case "label": c.compileLabel(attrs, f) + c.compilePosition(attrs, f) case "shape": in := d2target.IsShape(scalar.ScalarString()) _, isArrowhead := d2target.Arrowheads[scalar.ScalarString()] @@ -432,6 +476,7 @@ func (c *compiler) compileReserved(attrs *d2graph.Attributes, f *d2ir.Field) { return } attrs.Icon = iconURL + c.compilePosition(attrs, f) case "near": nearKey, err := d2parser.ParseKey(scalar.ScalarString()) if err != nil { diff --git a/d2compiler/compile_test.go b/d2compiler/compile_test.go index efa7ec146..c6cea1b2f 100644 --- a/d2compiler/compile_test.go +++ b/d2compiler/compile_test.go @@ -2371,6 +2371,77 @@ obj { `, expErr: `d2/testdata/d2compiler/TestCompile/near_near_const.d2:7:8: near keys cannot be set to an object with a constant near key`, }, + { + name: "label-near-parent", + text: `hey: sushi { + label.near: outside-top-left +} +`, + assertions: func(t *testing.T, g *d2graph.Graph) { + tassert.Equal(t, "sushi", g.Objects[0].Attributes.Label.Value) + tassert.Equal(t, "outside-top-left", g.Objects[0].Attributes.LabelPosition.Value) + }, + }, + { + name: "label-near-composite-separate", + text: `hey: { + label: sushi + label.near: outside-top-left +} +`, + assertions: func(t *testing.T, g *d2graph.Graph) { + tassert.Equal(t, "sushi", g.Objects[0].Attributes.Label.Value) + tassert.Equal(t, "outside-top-left", g.Objects[0].Attributes.LabelPosition.Value) + }, + }, + { + name: "label-near-composite-together", + text: `hey: { + label: sushi { + near: outside-top-left + } +} +`, + assertions: func(t *testing.T, g *d2graph.Graph) { + tassert.Equal(t, "sushi", g.Objects[0].Attributes.Label.Value) + tassert.Equal(t, "outside-top-left", g.Objects[0].Attributes.LabelPosition.Value) + }, + }, + { + name: "icon-near-composite-together", + text: `hey: { + icon: https://asdf.com { + near: outside-top-left + } +} +`, + assertions: func(t *testing.T, g *d2graph.Graph) { + tassert.Equal(t, "asdf.com", g.Objects[0].Attributes.Icon.Host) + tassert.Equal(t, "outside-top-left", g.Objects[0].Attributes.IconPosition.Value) + }, + }, + { + name: "label-near-invalid-edge", + text: `hey: { + label: sushi { + near: outside-top-left + a -> b + } +} +`, + expErr: `d2/testdata/d2compiler/TestCompile/label-near-invalid-edge.d2:2:3: unexpected edges in map`, + }, + { + name: "label-near-invalid-field", + text: `hey: { + label: sushi { + near: outside-top-left + a + } +} +`, + expErr: `d2/testdata/d2compiler/TestCompile/label-near-invalid-field.d2:4:3: unexpected field a`, + }, { name: "grid", text: `hey: { diff --git a/d2graph/d2graph.go b/d2graph/d2graph.go index d3afb199f..b65270ffe 100644 --- a/d2graph/d2graph.go +++ b/d2graph/d2graph.go @@ -143,6 +143,9 @@ type Attributes struct { VerticalGap *Scalar `json:"verticalGap,omitempty"` HorizontalGap *Scalar `json:"horizontalGap,omitempty"` + LabelPosition *Scalar `json:"labelPosition,omitempty"` + IconPosition *Scalar `json:"iconPosition,omitempty"` + // These names are attached to the rendered elements in SVG // so that users can target them however they like outside of D2 Classes []string `json:"classes,omitempty"` @@ -1645,7 +1648,10 @@ var ReservedKeywordHolders = map[string]struct{}{ // CompositeReservedKeywords are reserved keywords that can hold composites var CompositeReservedKeywords = map[string]struct{}{ - "classes": {}, + "classes": {}, + "constraint": {}, + "label": {}, + "icon": {}, } // StyleKeywords are reserved keywords which cannot exist outside of the "style" keyword @@ -1696,6 +1702,38 @@ var NearConstantsArray = []string{ } var NearConstants map[string]struct{} +// LabelPositionsArray are the values that labels and icons can set `near` to +var LabelPositionsArray = []string{ + "top-left", + "top-center", + "top-right", + + "center-left", + "center-center", + "center-right", + + "bottom-left", + "bottom-center", + "bottom-right", + + "outside-top-left", + "outside-top-center", + "outside-top-right", + + "outside-left-top", + "outside-left-center", + "outside-left-bottom", + + "outside-right-top", + "outside-right-center", + "outside-right-bottom", + + "outside-bottom-left", + "outside-bottom-center", + "outside-bottom-right", +} +var LabelPositions map[string]struct{} + var FillPatterns = []string{ "dots", "lines", @@ -1734,6 +1772,11 @@ func init() { for _, k := range NearConstantsArray { NearConstants[k] = struct{}{} } + + LabelPositions = make(map[string]struct{}, len(LabelPositionsArray)) + for _, k := range LabelPositionsArray { + LabelPositions[k] = struct{}{} + } } func (g *Graph) GetBoard(name string) *Graph { diff --git a/testdata/d2compiler/TestCompile/icon-near-composite-together.exp.json b/testdata/d2compiler/TestCompile/icon-near-composite-together.exp.json new file mode 100644 index 000000000..1d0b6974e --- /dev/null +++ b/testdata/d2compiler/TestCompile/icon-near-composite-together.exp.json @@ -0,0 +1,200 @@ +{ + "graph": { + "name": "", + "isFolderOnly": false, + "ast": { + "range": "d2/testdata/d2compiler/TestCompile/icon-near-composite-together.d2,0:0:0-5:0:64", + "nodes": [ + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile/icon-near-composite-together.d2,0:0:0-4:1:63", + "key": { + "range": "d2/testdata/d2compiler/TestCompile/icon-near-composite-together.d2,0:0:0-0:3:3", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/icon-near-composite-together.d2,0:0:0-0:3:3", + "value": [ + { + "string": "hey", + "raw_string": "hey" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "map": { + "range": "d2/testdata/d2compiler/TestCompile/icon-near-composite-together.d2,0:5:5-4:1:63", + "nodes": [ + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile/icon-near-composite-together.d2,1:1:8-3:3:61", + "key": { + "range": "d2/testdata/d2compiler/TestCompile/icon-near-composite-together.d2,1:1:8-1:5:12", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/icon-near-composite-together.d2,1:1:8-1:5:12", + "value": [ + { + "string": "icon", + "raw_string": "icon" + } + ] + } + } + ] + }, + "primary": { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/icon-near-composite-together.d2,1:7:14-1:23:30", + "value": [ + { + "string": "https://asdf.com", + "raw_string": "https://asdf.com" + } + ] + } + }, + "value": { + "map": { + "range": "d2/testdata/d2compiler/TestCompile/icon-near-composite-together.d2,1:24:31-3:3:61", + "nodes": [ + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile/icon-near-composite-together.d2,2:2:35-2:24:57", + "key": { + "range": "d2/testdata/d2compiler/TestCompile/icon-near-composite-together.d2,2:2:35-2:6:39", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/icon-near-composite-together.d2,2:2:35-2:6:39", + "value": [ + { + "string": "near", + "raw_string": "near" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/icon-near-composite-together.d2,2:8:41-2:24:57", + "value": [ + { + "string": "outside-top-left", + "raw_string": "outside-top-left" + } + ] + } + } + } + } + ] + } + } + } + } + ] + } + } + } + } + ] + }, + "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": "hey", + "id_val": "hey", + "references": [ + { + "key": { + "range": "d2/testdata/d2compiler/TestCompile/icon-near-composite-together.d2,0:0:0-0:3:3", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/icon-near-composite-together.d2,0:0:0-0:3:3", + "value": [ + { + "string": "hey", + "raw_string": "hey" + } + ] + } + } + ] + }, + "key_path_index": 0, + "map_key_edge_index": -1 + } + ], + "attributes": { + "label": { + "value": "hey" + }, + "labelDimensions": { + "width": 0, + "height": 0 + }, + "style": {}, + "icon": { + "Scheme": "https", + "Opaque": "", + "User": null, + "Host": "asdf.com", + "Path": "", + "RawPath": "", + "OmitHost": false, + "ForceQuery": false, + "RawQuery": "", + "Fragment": "", + "RawFragment": "" + }, + "near_key": null, + "shape": { + "value": "rectangle" + }, + "direction": { + "value": "" + }, + "constraint": null, + "iconPosition": { + "value": "outside-top-left" + } + }, + "zIndex": 0 + } + ] + }, + "err": null +} diff --git a/testdata/d2compiler/TestCompile/label-near-composite-separate.exp.json b/testdata/d2compiler/TestCompile/label-near-composite-separate.exp.json new file mode 100644 index 000000000..b73200e7a --- /dev/null +++ b/testdata/d2compiler/TestCompile/label-near-composite-separate.exp.json @@ -0,0 +1,192 @@ +{ + "graph": { + "name": "", + "isFolderOnly": false, + "ast": { + "range": "d2/testdata/d2compiler/TestCompile/label-near-composite-separate.d2,0:0:0-4:0:53", + "nodes": [ + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile/label-near-composite-separate.d2,0:0:0-3:1:52", + "key": { + "range": "d2/testdata/d2compiler/TestCompile/label-near-composite-separate.d2,0:0:0-0:3:3", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/label-near-composite-separate.d2,0:0:0-0:3:3", + "value": [ + { + "string": "hey", + "raw_string": "hey" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "map": { + "range": "d2/testdata/d2compiler/TestCompile/label-near-composite-separate.d2,0:5:5-3:1:52", + "nodes": [ + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile/label-near-composite-separate.d2,1:1:8-1:13:20", + "key": { + "range": "d2/testdata/d2compiler/TestCompile/label-near-composite-separate.d2,1:1:8-1:6:13", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/label-near-composite-separate.d2,1:1:8-1:6:13", + "value": [ + { + "string": "label", + "raw_string": "label" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/label-near-composite-separate.d2,1:8:15-1:13:20", + "value": [ + { + "string": "sushi", + "raw_string": "sushi" + } + ] + } + } + } + }, + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile/label-near-composite-separate.d2,2:1:22-2:29:50", + "key": { + "range": "d2/testdata/d2compiler/TestCompile/label-near-composite-separate.d2,2:1:22-2:11:32", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/label-near-composite-separate.d2,2:1:22-2:6:27", + "value": [ + { + "string": "label", + "raw_string": "label" + } + ] + } + }, + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/label-near-composite-separate.d2,2:7:28-2:11:32", + "value": [ + { + "string": "near", + "raw_string": "near" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/label-near-composite-separate.d2,2:13:34-2:29:50", + "value": [ + { + "string": "outside-top-left", + "raw_string": "outside-top-left" + } + ] + } + } + } + } + ] + } + } + } + } + ] + }, + "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": "hey", + "id_val": "hey", + "references": [ + { + "key": { + "range": "d2/testdata/d2compiler/TestCompile/label-near-composite-separate.d2,0:0:0-0:3:3", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/label-near-composite-separate.d2,0:0:0-0:3:3", + "value": [ + { + "string": "hey", + "raw_string": "hey" + } + ] + } + } + ] + }, + "key_path_index": 0, + "map_key_edge_index": -1 + } + ], + "attributes": { + "label": { + "value": "sushi" + }, + "labelDimensions": { + "width": 0, + "height": 0 + }, + "style": {}, + "near_key": null, + "shape": { + "value": "rectangle" + }, + "direction": { + "value": "" + }, + "constraint": null, + "labelPosition": { + "value": "outside-top-left" + } + }, + "zIndex": 0 + } + ] + }, + "err": null +} diff --git a/testdata/d2compiler/TestCompile/label-near-composite-together.exp.json b/testdata/d2compiler/TestCompile/label-near-composite-together.exp.json new file mode 100644 index 000000000..ee68c9863 --- /dev/null +++ b/testdata/d2compiler/TestCompile/label-near-composite-together.exp.json @@ -0,0 +1,187 @@ +{ + "graph": { + "name": "", + "isFolderOnly": false, + "ast": { + "range": "d2/testdata/d2compiler/TestCompile/label-near-composite-together.d2,0:0:0-5:0:55", + "nodes": [ + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile/label-near-composite-together.d2,0:0:0-4:1:54", + "key": { + "range": "d2/testdata/d2compiler/TestCompile/label-near-composite-together.d2,0:0:0-0:3:3", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/label-near-composite-together.d2,0:0:0-0:3:3", + "value": [ + { + "string": "hey", + "raw_string": "hey" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "map": { + "range": "d2/testdata/d2compiler/TestCompile/label-near-composite-together.d2,0:5:5-4:1:54", + "nodes": [ + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile/label-near-composite-together.d2,1:2:9-3:3:52", + "key": { + "range": "d2/testdata/d2compiler/TestCompile/label-near-composite-together.d2,1:2:9-1:7:14", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/label-near-composite-together.d2,1:2:9-1:7:14", + "value": [ + { + "string": "label", + "raw_string": "label" + } + ] + } + } + ] + }, + "primary": { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/label-near-composite-together.d2,1:9:16-1:14:21", + "value": [ + { + "string": "sushi", + "raw_string": "sushi" + } + ] + } + }, + "value": { + "map": { + "range": "d2/testdata/d2compiler/TestCompile/label-near-composite-together.d2,1:15:22-3:3:52", + "nodes": [ + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile/label-near-composite-together.d2,2:2:26-2:24:48", + "key": { + "range": "d2/testdata/d2compiler/TestCompile/label-near-composite-together.d2,2:2:26-2:6:30", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/label-near-composite-together.d2,2:2:26-2:6:30", + "value": [ + { + "string": "near", + "raw_string": "near" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/label-near-composite-together.d2,2:8:32-2:24:48", + "value": [ + { + "string": "outside-top-left", + "raw_string": "outside-top-left" + } + ] + } + } + } + } + ] + } + } + } + } + ] + } + } + } + } + ] + }, + "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": "hey", + "id_val": "hey", + "references": [ + { + "key": { + "range": "d2/testdata/d2compiler/TestCompile/label-near-composite-together.d2,0:0:0-0:3:3", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/label-near-composite-together.d2,0:0:0-0:3:3", + "value": [ + { + "string": "hey", + "raw_string": "hey" + } + ] + } + } + ] + }, + "key_path_index": 0, + "map_key_edge_index": -1 + } + ], + "attributes": { + "label": { + "value": "sushi" + }, + "labelDimensions": { + "width": 0, + "height": 0 + }, + "style": {}, + "near_key": null, + "shape": { + "value": "rectangle" + }, + "direction": { + "value": "" + }, + "constraint": null, + "labelPosition": { + "value": "outside-top-left" + } + }, + "zIndex": 0 + } + ] + }, + "err": null +} diff --git a/testdata/d2compiler/TestCompile/label-near-invalid-edge.exp.json b/testdata/d2compiler/TestCompile/label-near-invalid-edge.exp.json new file mode 100644 index 000000000..a0055eba2 --- /dev/null +++ b/testdata/d2compiler/TestCompile/label-near-invalid-edge.exp.json @@ -0,0 +1,11 @@ +{ + "graph": null, + "err": { + "errs": [ + { + "range": "d2/testdata/d2compiler/TestCompile/label-near-invalid-edge.d2,1:2:9-4:3:61", + "errmsg": "d2/testdata/d2compiler/TestCompile/label-near-invalid-edge.d2:2:3: unexpected edges in map" + } + ] + } +} diff --git a/testdata/d2compiler/TestCompile/label-near-invalid-field.exp.json b/testdata/d2compiler/TestCompile/label-near-invalid-field.exp.json new file mode 100644 index 000000000..ba96ec738 --- /dev/null +++ b/testdata/d2compiler/TestCompile/label-near-invalid-field.exp.json @@ -0,0 +1,11 @@ +{ + "graph": null, + "err": { + "errs": [ + { + "range": "d2/testdata/d2compiler/TestCompile/label-near-invalid-field.d2,3:2:51-3:3:52", + "errmsg": "d2/testdata/d2compiler/TestCompile/label-near-invalid-field.d2:4:3: unexpected field a" + } + ] + } +} diff --git a/testdata/d2compiler/TestCompile/label-near-parent.exp.json b/testdata/d2compiler/TestCompile/label-near-parent.exp.json new file mode 100644 index 000000000..192949f56 --- /dev/null +++ b/testdata/d2compiler/TestCompile/label-near-parent.exp.json @@ -0,0 +1,169 @@ +{ + "graph": { + "name": "", + "isFolderOnly": false, + "ast": { + "range": "d2/testdata/d2compiler/TestCompile/label-near-parent.d2,0:0:0-3:0:45", + "nodes": [ + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile/label-near-parent.d2,0:0:0-2:1:44", + "key": { + "range": "d2/testdata/d2compiler/TestCompile/label-near-parent.d2,0:0:0-0:3:3", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/label-near-parent.d2,0:0:0-0:3:3", + "value": [ + { + "string": "hey", + "raw_string": "hey" + } + ] + } + } + ] + }, + "primary": { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/label-near-parent.d2,0:5:5-0:10:10", + "value": [ + { + "string": "sushi", + "raw_string": "sushi" + } + ] + } + }, + "value": { + "map": { + "range": "d2/testdata/d2compiler/TestCompile/label-near-parent.d2,0:11:11-2:1:44", + "nodes": [ + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile/label-near-parent.d2,1:1:14-1:29:42", + "key": { + "range": "d2/testdata/d2compiler/TestCompile/label-near-parent.d2,1:1:14-1:11:24", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/label-near-parent.d2,1:1:14-1:6:19", + "value": [ + { + "string": "label", + "raw_string": "label" + } + ] + } + }, + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/label-near-parent.d2,1:7:20-1:11:24", + "value": [ + { + "string": "near", + "raw_string": "near" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/label-near-parent.d2,1:13:26-1:29:42", + "value": [ + { + "string": "outside-top-left", + "raw_string": "outside-top-left" + } + ] + } + } + } + } + ] + } + } + } + } + ] + }, + "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": "hey", + "id_val": "hey", + "references": [ + { + "key": { + "range": "d2/testdata/d2compiler/TestCompile/label-near-parent.d2,0:0:0-0:3:3", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/label-near-parent.d2,0:0:0-0:3:3", + "value": [ + { + "string": "hey", + "raw_string": "hey" + } + ] + } + } + ] + }, + "key_path_index": 0, + "map_key_edge_index": -1 + } + ], + "attributes": { + "label": { + "value": "sushi" + }, + "labelDimensions": { + "width": 0, + "height": 0 + }, + "style": {}, + "near_key": null, + "shape": { + "value": "rectangle" + }, + "direction": { + "value": "" + }, + "constraint": null, + "labelPosition": { + "value": "outside-top-left" + } + }, + "zIndex": 0 + } + ] + }, + "err": null +}