diff --git a/d2compiler/compile.go b/d2compiler/compile.go index 651238afe..c7030146b 100644 --- a/d2compiler/compile.go +++ b/d2compiler/compile.go @@ -208,55 +208,48 @@ func findFieldAST(ast *d2ast.Map, f *d2ir.Field) *d2ast.Map { curr = d2ir.ParentField(curr) } - currAST := ast - for len(path) > 0 { - head := path[0] - found := false - for _, n := range currAST.Nodes { - if n.MapKey == nil { - continue - } - if n.MapKey.Key == nil { - continue - } - if len(n.MapKey.Key.Path) != 1 { - continue - } - head2 := n.MapKey.Key.Path[0].Unbox().ScalarString() - if head == head2 { - currAST = n.MapKey.Value.Map - // The BaseAST is only used for making edits to the AST (through d2oracle) - // If there's no Map for a given board, either it's an empty layer or set to an import - // Either way, in order to make edits, it needs to be expanded into a Map to add lines to - if currAST == nil { - n.MapKey.Value.Map = &d2ast.Map{ - Range: d2ast.MakeRange(",1:0:0-1:0:0"), - } - if n.MapKey.Value.Import != nil { - imp := &d2ast.Import{ - Range: d2ast.MakeRange(",1:0:0-1:0:0"), - Spread: true, - Pre: n.MapKey.Value.Import.Pre, - Path: n.MapKey.Value.Import.Path, - } - n.MapKey.Value.Map.Nodes = append(n.MapKey.Value.Map.Nodes, d2ast.MapNodeBox{ - Import: imp, - }) + return _findFieldAST(ast, path) +} - } - currAST = n.MapKey.Value.Map - } - found = true - break - } - } - if !found { - return nil - } - path = path[1:] +func _findFieldAST(ast *d2ast.Map, path []string) *d2ast.Map { + if len(path) == 0 { + return ast } - return currAST + head := path[0] + remainingPath := path[1:] + + for i := range ast.Nodes { + if ast.Nodes[i].MapKey == nil || ast.Nodes[i].MapKey.Key == nil || len(ast.Nodes[i].MapKey.Key.Path) != 1 { + continue + } + + head2 := ast.Nodes[i].MapKey.Key.Path[0].Unbox().ScalarString() + if head == head2 { + if ast.Nodes[i].MapKey.Value.Map == nil { + ast.Nodes[i].MapKey.Value.Map = &d2ast.Map{ + Range: d2ast.MakeRange(",1:0:0-1:0:0"), + } + if ast.Nodes[i].MapKey.Value.Import != nil { + imp := &d2ast.Import{ + Range: d2ast.MakeRange(",1:0:0-1:0:0"), + Spread: true, + Pre: ast.Nodes[i].MapKey.Value.Import.Pre, + Path: ast.Nodes[i].MapKey.Value.Import.Path, + } + ast.Nodes[i].MapKey.Value.Map.Nodes = append(ast.Nodes[i].MapKey.Value.Map.Nodes, d2ast.MapNodeBox{ + Import: imp, + }) + } + } + + if result := _findFieldAST(ast.Nodes[i].MapKey.Value.Map, remainingPath); result != nil { + return result + } + } + } + + return nil } type compiler struct { diff --git a/d2oracle/edit_test.go b/d2oracle/edit_test.go index 9e6466568..94d103615 100644 --- a/d2oracle/edit_test.go +++ b/d2oracle/edit_test.go @@ -2775,6 +2775,40 @@ scenarios: { Metricbeat.style.stroke: red } } +`, + }, + { + name: "set-style-in-layer", + text: `hey + +layers: { + k: { + b: {style.stroke: "#969db4"} + } +} + +layers: { + x: { + y + } +} +`, + boardPath: []string{"x"}, + key: `y.style.fill`, + value: go2.Pointer(`#ff0000`), + exp: `hey + +layers: { + k: { + b: {style.stroke: "#969db4"} + } +} + +layers: { + x: { + y: {style.fill: "#ff0000"} + } +} `, }, } diff --git a/d2oracle/get.go b/d2oracle/get.go index c39e88469..15df0767a 100644 --- a/d2oracle/get.go +++ b/d2oracle/get.go @@ -48,51 +48,35 @@ func ReplaceBoardNode(ast, ast2 *d2ast.Map, boardPath []string) bool { return false } - findMap := func(root *d2ast.Map, name string) *d2ast.Map { - for _, n := range root.Nodes { - if n.MapKey != nil && n.MapKey.Key != nil && n.MapKey.Key.Path[0].Unbox().ScalarString() == name { - return n.MapKey.Value.Map - } - } - return nil - } + return replaceBoardNodeInMap(ast, ast2, boardPath, "layers") || + replaceBoardNodeInMap(ast, ast2, boardPath, "scenarios") || + replaceBoardNodeInMap(ast, ast2, boardPath, "steps") +} - layersMap := findMap(ast, "layers") - scenariosMap := findMap(ast, "scenarios") - stepsMap := findMap(ast, "steps") +func replaceBoardNodeInMap(ast, ast2 *d2ast.Map, boardPath []string, boardType string) bool { + var matches []*d2ast.Map - if layersMap != nil { - m := findMap(layersMap, boardPath[0]) - if m != nil { - if len(boardPath) > 1 { - return ReplaceBoardNode(m, ast2, boardPath[1:]) - } else { - m.Nodes = ast2.Nodes - return true - } + for _, n := range ast.Nodes { + if n.MapKey != nil && n.MapKey.Key != nil && + n.MapKey.Key.Path[0].Unbox().ScalarString() == boardType && + n.MapKey.Value.Map != nil { + matches = append(matches, n.MapKey.Value.Map) } } - if scenariosMap != nil { - m := findMap(scenariosMap, boardPath[0]) - if m != nil { - if len(boardPath) > 1 { - return ReplaceBoardNode(m, ast2, boardPath[1:]) - } else { - m.Nodes = ast2.Nodes - return true - } - } - } - - if stepsMap != nil { - m := findMap(stepsMap, boardPath[0]) - if m != nil { - if len(boardPath) > 1 { - return ReplaceBoardNode(m, ast2, boardPath[1:]) - } else { - m.Nodes = ast2.Nodes - return true + for _, boardMap := range matches { + for _, n := range boardMap.Nodes { + if n.MapKey != nil && n.MapKey.Key != nil && + n.MapKey.Key.Path[0].Unbox().ScalarString() == boardPath[0] && + n.MapKey.Value.Map != nil { + if len(boardPath) > 1 { + if ReplaceBoardNode(n.MapKey.Value.Map, ast2, boardPath[1:]) { + return true + } + } else { + n.MapKey.Value.Map.Nodes = ast2.Nodes + return true + } } } } diff --git a/testdata/d2oracle/TestSet/set-style-in-layer.exp.json b/testdata/d2oracle/TestSet/set-style-in-layer.exp.json new file mode 100644 index 000000000..73d98726c --- /dev/null +++ b/testdata/d2oracle/TestSet/set-style-in-layer.exp.json @@ -0,0 +1,726 @@ +{ + "graph": { + "name": "", + "isFolderOnly": false, + "ast": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,0:0:0-13:0:116", + "nodes": [ + { + "map_key": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,0:0:0-0:3:3", + "key": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,0:0:0-0:3:3", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,0:0:0-0:3:3", + "value": [ + { + "string": "hey", + "raw_string": "hey" + } + ] + } + } + ] + }, + "primary": {}, + "value": {} + } + }, + { + "map_key": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,2:0:5-6:1:60", + "key": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,2:0:5-2:6:11", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,2:0:5-2:6:11", + "value": [ + { + "string": "layers", + "raw_string": "layers" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "map": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,2:8:13-6:1:60", + "nodes": [ + { + "map_key": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,3:2:17-5:3:58", + "key": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,3:2:17-3:3:18", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,3:2:17-3:3:18", + "value": [ + { + "string": "k", + "raw_string": "k" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "map": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,3:5:20-5:3:58", + "nodes": [ + { + "map_key": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,4:4:26-4:32:54", + "key": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,4:4:26-4:5:27", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,4:4:26-4:5:27", + "value": [ + { + "string": "b", + "raw_string": "b" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "map": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,4:7:29-4:32:54", + "nodes": [ + { + "map_key": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,4:8:30-4:31:53", + "key": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,4:8:30-4:20:42", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,4:8:30-4:13:35", + "value": [ + { + "string": "style", + "raw_string": "style" + } + ] + } + }, + { + "unquoted_string": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,4:14:36-4:20:42", + "value": [ + { + "string": "stroke", + "raw_string": "stroke" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "double_quoted_string": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,4:22:44-4:31:53", + "value": [ + { + "string": "#969db4", + "raw_string": "#969db4" + } + ] + } + } + } + } + ] + } + } + } + } + ] + } + } + } + } + ] + } + } + } + }, + { + "map_key": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,8:0:62-12:1:115", + "key": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,8:0:62-8:6:68", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,8:0:62-8:6:68", + "value": [ + { + "string": "layers", + "raw_string": "layers" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "map": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,8:8:70-12:1:115", + "nodes": [ + { + "map_key": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,9:2:74-11:3:113", + "key": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,9:2:74-9:3:75", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,9:2:74-9:3:75", + "value": [ + { + "string": "x", + "raw_string": "x" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "map": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,9:5:77-11:3:113", + "nodes": [ + { + "map_key": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,10:4:83-10:30:109", + "key": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,10:4:83-10:5:84", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,10:4:83-10:5:84", + "value": [ + { + "string": "y", + "raw_string": "y" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "map": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,10:7:86-10:30:109", + "nodes": [ + { + "map_key": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,10:8:87-10:29:108", + "key": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,10:8:87-10:18:97", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,10:8:87-10:13:92", + "value": [ + { + "string": "style", + "raw_string": "style" + } + ] + } + }, + { + "unquoted_string": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,10:14:93-10:18:97", + "value": [ + { + "string": "fill", + "raw_string": "fill" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "double_quoted_string": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,10:20:99-10:29:108", + "value": [ + { + "string": "#ff0000", + "raw_string": "#ff0000" + } + ] + } + } + } + } + ] + } + } + } + } + ] + } + } + } + } + ] + } + } + } + } + ] + }, + "root": { + "id": "", + "id_val": "", + "attributes": { + "label": { + "value": "" + }, + "labelDimensions": { + "width": 0, + "height": 0 + }, + "style": {}, + "iconStyle": {}, + "near_key": null, + "shape": { + "value": "" + }, + "direction": { + "value": "" + }, + "constraint": null + }, + "zIndex": 0 + }, + "edges": null, + "objects": [ + { + "id": "hey", + "id_val": "hey", + "references": [ + { + "key": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,0:0:0-0:3:3", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.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": {}, + "iconStyle": {}, + "near_key": null, + "shape": { + "value": "rectangle" + }, + "direction": { + "value": "" + }, + "constraint": null + }, + "zIndex": 0 + } + ], + "layers": [ + { + "name": "k", + "isFolderOnly": false, + "ast": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,0:0:0-1:0:0", + "nodes": [ + { + "map_key": { + "range": ",0:0:0-0:0:0", + "key": { + "range": ",0:0:0-0:0:0", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,4:4:26-4:5:27", + "value": [ + { + "string": "b", + "raw_string": "b" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "map": { + "range": ",1:0:0-2:0:0", + "nodes": [ + { + "map_key": { + "range": ",0:0:0-0:0:0", + "key": { + "range": ",0:0:0-0:0:0", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,4:8:30-4:13:35", + "value": [ + { + "string": "style", + "raw_string": "style" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "map": { + "range": ",1:0:0-2:0:0", + "nodes": [ + { + "map_key": { + "range": ",0:0:0-0:0:0", + "key": { + "range": ",0:0:0-0:0:0", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,4:14:36-4:20:42", + "value": [ + { + "string": "stroke", + "raw_string": "stroke" + } + ] + } + } + ] + }, + "primary": { + "double_quoted_string": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,4:22:44-4:31:53", + "value": [ + { + "string": "#969db4", + "raw_string": "#969db4" + } + ] + } + }, + "value": {} + } + } + ] + } + } + } + } + ] + } + } + } + } + ] + }, + "root": { + "id": "", + "id_val": "", + "attributes": { + "label": { + "value": "" + }, + "labelDimensions": { + "width": 0, + "height": 0 + }, + "style": {}, + "iconStyle": {}, + "near_key": null, + "shape": { + "value": "" + }, + "direction": { + "value": "" + }, + "constraint": null + }, + "zIndex": 0 + }, + "edges": null, + "objects": [ + { + "id": "b", + "id_val": "b", + "references": [ + { + "key": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,4:4:26-4:5:27", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,4:4:26-4:5:27", + "value": [ + { + "string": "b", + "raw_string": "b" + } + ] + } + } + ] + }, + "key_path_index": 0, + "map_key_edge_index": -1 + } + ], + "attributes": { + "label": { + "value": "b" + }, + "labelDimensions": { + "width": 0, + "height": 0 + }, + "style": { + "stroke": { + "value": "#969db4" + } + }, + "iconStyle": {}, + "near_key": null, + "shape": { + "value": "rectangle" + }, + "direction": { + "value": "" + }, + "constraint": null + }, + "zIndex": 0 + } + ] + }, + { + "name": "x", + "isFolderOnly": false, + "ast": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,0:0:0-1:0:0", + "nodes": [ + { + "map_key": { + "range": ",0:0:0-0:0:0", + "key": { + "range": ",0:0:0-0:0:0", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,10:4:83-10:5:84", + "value": [ + { + "string": "y", + "raw_string": "y" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "map": { + "range": ",1:0:0-2:0:0", + "nodes": [ + { + "map_key": { + "range": ",0:0:0-0:0:0", + "key": { + "range": ",0:0:0-0:0:0", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,10:8:87-10:13:92", + "value": [ + { + "string": "style", + "raw_string": "style" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "map": { + "range": ",1:0:0-2:0:0", + "nodes": [ + { + "map_key": { + "range": ",0:0:0-0:0:0", + "key": { + "range": ",0:0:0-0:0:0", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,10:14:93-10:18:97", + "value": [ + { + "string": "fill", + "raw_string": "fill" + } + ] + } + } + ] + }, + "primary": { + "double_quoted_string": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,10:20:99-10:29:108", + "value": [ + { + "string": "#ff0000", + "raw_string": "#ff0000" + } + ] + } + }, + "value": {} + } + } + ] + } + } + } + } + ] + } + } + } + } + ] + }, + "root": { + "id": "", + "id_val": "", + "attributes": { + "label": { + "value": "" + }, + "labelDimensions": { + "width": 0, + "height": 0 + }, + "style": {}, + "iconStyle": {}, + "near_key": null, + "shape": { + "value": "" + }, + "direction": { + "value": "" + }, + "constraint": null + }, + "zIndex": 0 + }, + "edges": null, + "objects": [ + { + "id": "y", + "id_val": "y", + "references": [ + { + "key": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,10:4:83-10:5:84", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2oracle/TestSet/set-style-in-layer.d2,10:4:83-10:5:84", + "value": [ + { + "string": "y", + "raw_string": "y" + } + ] + } + } + ] + }, + "key_path_index": 0, + "map_key_edge_index": -1 + } + ], + "attributes": { + "label": { + "value": "y" + }, + "labelDimensions": { + "width": 0, + "height": 0 + }, + "style": { + "fill": { + "value": "#ff0000" + } + }, + "iconStyle": {}, + "near_key": null, + "shape": { + "value": "rectangle" + }, + "direction": { + "value": "" + }, + "constraint": null + }, + "zIndex": 0 + } + ] + } + ] + }, + "err": "" +}