diff --git a/d2format/format.go b/d2format/format.go index 09a932e46..e72800e68 100644 --- a/d2format/format.go +++ b/d2format/format.go @@ -339,12 +339,14 @@ func (p *printer) _map(m *d2ast.Map) { n := boards[i].Unbox() // if this board is the very first line of the file, don't add an extra newline if n.GetRange().Start.Line != 0 { - p.newline() + p.sb.WriteByte('\n') } // if scope only has boards, don't newline the first board if i != 0 || len(m.Nodes) > len(boards) { - p.newline() + p.sb.WriteByte('\n') } + + p.sb.WriteString(p.indentStr) p.node(n) prev = n } diff --git a/d2oracle/edit.go b/d2oracle/edit.go index 0bbdc9400..41660b174 100644 --- a/d2oracle/edit.go +++ b/d2oracle/edit.go @@ -411,6 +411,47 @@ func _set(g *d2graph.Graph, baseAST *d2ast.Map, key string, tag, value *string) } } + if mk.Key != nil && len(mk.Key.Path) == 2 { + boardType := mk.Key.Path[0].Unbox().ScalarString() + if boardType == "layers" || boardType == "scenarios" || boardType == "steps" { + // Force map structure + var containerMap *d2ast.Map + for _, n := range scope.Nodes { + if n.MapKey != nil && n.MapKey.Key != nil && len(n.MapKey.Key.Path) == 1 && + n.MapKey.Key.Path[0].Unbox().ScalarString() == boardType { + containerMap = n.MapKey.Value.Map + break + } + } + + if containerMap == nil { + containerMap = &d2ast.Map{ + Range: d2ast.MakeRange(",1:0:0-1:0:0"), + } + containerMK := &d2ast.Key{ + Key: &d2ast.KeyPath{ + Path: []*d2ast.StringBox{ + d2ast.MakeValueBox(d2ast.RawString(boardType, true)).StringBox(), + }, + }, + Value: d2ast.MakeValueBox(containerMap), + } + appendMapKey(scope, containerMK) + } + + itemMK := &d2ast.Key{ + Key: &d2ast.KeyPath{ + Path: []*d2ast.StringBox{ + d2ast.MakeValueBox(d2ast.RawString(mk.Key.Path[1].Unbox().ScalarString(), true)).StringBox(), + }, + }, + Value: mk.Value, + } + appendMapKey(containerMap, itemMK) + return nil + } + } + writeableLabelMK := true var objK *d2ast.Key if baseAST != g.AST || imported { diff --git a/d2oracle/edit_test.go b/d2oracle/edit_test.go index bbab7f2e8..794c5c44d 100644 --- a/d2oracle/edit_test.go +++ b/d2oracle/edit_test.go @@ -482,6 +482,67 @@ layers: { b } } +`, + }, + { + name: "add_layer/1", + text: `b`, + key: `layers.c`, + + expKey: `layers.c`, + exp: `b + +layers: { + c +} +`, + }, + { + name: "add_layer/2", + text: `b +layers: { + c: { + x + } +}`, + key: `layers.b`, + + expKey: `layers.b`, + exp: `b + +layers: { + c: { + x + } + b +} +`, + }, + { + name: "add_layer/3", + text: `b + +layers: { + c: { + d + } +} +`, + key: `layers.c`, + + boardPath: []string{"c"}, + expKey: `layers.c`, + exp: `b + +layers: { + c: { + d + + layers: { + c + } + } +} `, }, { diff --git a/testdata/d2oracle/TestCreate/add_layer/1.exp.json b/testdata/d2oracle/TestCreate/add_layer/1.exp.json new file mode 100644 index 000000000..26fe0e14f --- /dev/null +++ b/testdata/d2oracle/TestCreate/add_layer/1.exp.json @@ -0,0 +1,158 @@ +{ + "graph": { + "name": "", + "isFolderOnly": false, + "ast": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/1.d2,0:0:0-4:0:18", + "nodes": [ + { + "map_key": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/1.d2,0:0:0-0:1:1", + "key": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/1.d2,0:0:0-0:1:1", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/1.d2,0:0:0-0:1:1", + "value": [ + { + "string": "b", + "raw_string": "b" + } + ] + } + } + ] + }, + "primary": {}, + "value": {} + } + }, + { + "map_key": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/1.d2,1:0:2-3:1:17", + "key": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/1.d2,1:0:2-1:6:8", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/1.d2,1:0:2-1:6:8", + "value": [ + { + "string": "layers", + "raw_string": "layers" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "map": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/1.d2,1:8:10-3:1:17", + "nodes": [ + { + "map_key": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/1.d2,2:2:14-2:3:15", + "key": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/1.d2,2:2:14-2:3:15", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/1.d2,2:2:14-2:3:15", + "value": [ + { + "string": "c", + "raw_string": "c" + } + ] + } + } + ] + }, + "primary": {}, + "value": {} + } + } + ] + } + } + } + } + ] + }, + "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": "b", + "id_val": "b", + "references": [ + { + "key": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/1.d2,0:0:0-0:1:1", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/1.d2,0:0:0-0:1:1", + "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": {}, + "near_key": null, + "shape": { + "value": "rectangle" + }, + "direction": { + "value": "" + }, + "constraint": null + }, + "zIndex": 0 + } + ] + }, + "err": "" +} diff --git a/testdata/d2oracle/TestCreate/add_layer/2.exp.json b/testdata/d2oracle/TestCreate/add_layer/2.exp.json new file mode 100644 index 000000000..9f0976167 --- /dev/null +++ b/testdata/d2oracle/TestCreate/add_layer/2.exp.json @@ -0,0 +1,314 @@ +{ + "graph": { + "name": "", + "isFolderOnly": false, + "ast": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/2.d2,0:0:0-8:0:36", + "nodes": [ + { + "map_key": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/2.d2,0:0:0-0:1:1", + "key": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/2.d2,0:0:0-0:1:1", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/2.d2,0:0:0-0:1:1", + "value": [ + { + "string": "b", + "raw_string": "b" + } + ] + } + } + ] + }, + "primary": {}, + "value": {} + } + }, + { + "map_key": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/2.d2,2:0:3-7:1:35", + "key": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/2.d2,2:0:3-2:6:9", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/2.d2,2:0:3-2:6:9", + "value": [ + { + "string": "layers", + "raw_string": "layers" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "map": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/2.d2,2:8:11-7:1:35", + "nodes": [ + { + "map_key": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/2.d2,3:2:15-5:3:29", + "key": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/2.d2,3:2:15-3:3:16", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/2.d2,3:2:15-3:3:16", + "value": [ + { + "string": "c", + "raw_string": "c" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "map": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/2.d2,3:5:18-5:3:29", + "nodes": [ + { + "map_key": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/2.d2,4:4:24-4:5:25", + "key": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/2.d2,4:4:24-4:5:25", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/2.d2,4:4:24-4:5:25", + "value": [ + { + "string": "x", + "raw_string": "x" + } + ] + } + } + ] + }, + "primary": {}, + "value": {} + } + } + ] + } + } + } + }, + { + "map_key": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/2.d2,6:2:32-6:3:33", + "key": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/2.d2,6:2:32-6:3:33", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/2.d2,6:2:32-6:3:33", + "value": [ + { + "string": "b", + "raw_string": "b" + } + ] + } + } + ] + }, + "primary": {}, + "value": {} + } + } + ] + } + } + } + } + ] + }, + "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": "b", + "id_val": "b", + "references": [ + { + "key": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/2.d2,0:0:0-0:1:1", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/2.d2,0:0:0-0:1:1", + "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": {}, + "near_key": null, + "shape": { + "value": "rectangle" + }, + "direction": { + "value": "" + }, + "constraint": null + }, + "zIndex": 0 + } + ], + "layers": [ + { + "name": "c", + "isFolderOnly": false, + "ast": { + "range": ",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": ",0:0:0-0:0:0", + "value": [ + { + "string": "x" + } + ] + } + } + ] + }, + "primary": {}, + "value": {} + } + } + ] + }, + "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": "x", + "id_val": "x", + "references": [ + { + "key": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/2.d2,4:4:24-4:5:25", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/2.d2,4:4:24-4:5:25", + "value": [ + { + "string": "x", + "raw_string": "x" + } + ] + } + } + ] + }, + "key_path_index": 0, + "map_key_edge_index": -1 + } + ], + "attributes": { + "label": { + "value": "x" + }, + "labelDimensions": { + "width": 0, + "height": 0 + }, + "style": {}, + "near_key": null, + "shape": { + "value": "rectangle" + }, + "direction": { + "value": "" + }, + "constraint": null + }, + "zIndex": 0 + } + ] + } + ] + }, + "err": "" +} diff --git a/testdata/d2oracle/TestCreate/add_layer/3.exp.json b/testdata/d2oracle/TestCreate/add_layer/3.exp.json new file mode 100644 index 000000000..8f8c523b2 --- /dev/null +++ b/testdata/d2oracle/TestCreate/add_layer/3.exp.json @@ -0,0 +1,393 @@ +{ + "graph": { + "name": "", + "isFolderOnly": false, + "ast": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/3.d2,0:0:0-10:0:60", + "nodes": [ + { + "map_key": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/3.d2,0:0:0-0:1:1", + "key": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/3.d2,0:0:0-0:1:1", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/3.d2,0:0:0-0:1:1", + "value": [ + { + "string": "b", + "raw_string": "b" + } + ] + } + } + ] + }, + "primary": {}, + "value": {} + } + }, + { + "map_key": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/3.d2,2:0:3-9:1:59", + "key": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/3.d2,2:0:3-2:6:9", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/3.d2,2:0:3-2:6:9", + "value": [ + { + "string": "layers", + "raw_string": "layers" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "map": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/3.d2,2:8:11-9:1:59", + "nodes": [ + { + "map_key": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/3.d2,3:2:15-8:3:57", + "key": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/3.d2,3:2:15-3:3:16", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/3.d2,3:2:15-3:3:16", + "value": [ + { + "string": "c", + "raw_string": "c" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "map": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/3.d2,3:5:18-8:3:57", + "nodes": [ + { + "map_key": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/3.d2,4:4:24-4:5:25", + "key": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/3.d2,4:4:24-4:5:25", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/3.d2,4:4:24-4:5:25", + "value": [ + { + "string": "d", + "raw_string": "d" + } + ] + } + } + ] + }, + "primary": {}, + "value": {} + } + }, + { + "map_key": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/3.d2,5:4:30-7:5:53", + "key": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/3.d2,5:4:30-5:10:36", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/3.d2,5:4:30-5:10:36", + "value": [ + { + "string": "layers", + "raw_string": "layers" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "map": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/3.d2,5:12:38-7:5:53", + "nodes": [ + { + "map_key": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/3.d2,6:6:46-6:7:47", + "key": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/3.d2,6:6:46-6:7:47", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/3.d2,6:6:46-6:7:47", + "value": [ + { + "string": "c", + "raw_string": "c" + } + ] + } + } + ] + }, + "primary": {}, + "value": {} + } + } + ] + } + } + } + } + ] + } + } + } + } + ] + } + } + } + } + ] + }, + "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": "b", + "id_val": "b", + "references": [ + { + "key": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/3.d2,0:0:0-0:1:1", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/3.d2,0:0:0-0:1:1", + "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": {}, + "near_key": null, + "shape": { + "value": "rectangle" + }, + "direction": { + "value": "" + }, + "constraint": null + }, + "zIndex": 0 + } + ], + "layers": [ + { + "name": "c", + "isFolderOnly": false, + "ast": { + "range": ",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": ",0:0:0-0:0:0", + "value": [ + { + "string": "d" + } + ] + } + } + ] + }, + "primary": {}, + "value": {} + } + }, + { + "map_key": { + "range": ",0:0:0-0:0:0", + "key": { + "range": ",0:0:0-0:0:0", + "path": [ + { + "unquoted_string": { + "range": ",0:0:0-0:0:0", + "value": [ + { + "string": "layers" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "map": { + "range": ",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": ",0:0:0-0:0:0", + "value": [ + { + "string": "c" + } + ] + } + } + ] + }, + "primary": {}, + "value": {} + } + } + ] + } + } + } + } + ] + }, + "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": "d", + "id_val": "d", + "references": [ + { + "key": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/3.d2,4:4:24-4:5:25", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2oracle/TestCreate/add_layer/3.d2,4:4:24-4:5:25", + "value": [ + { + "string": "d", + "raw_string": "d" + } + ] + } + } + ] + }, + "key_path_index": 0, + "map_key_edge_index": -1 + } + ], + "attributes": { + "label": { + "value": "d" + }, + "labelDimensions": { + "width": 0, + "height": 0 + }, + "style": {}, + "near_key": null, + "shape": { + "value": "rectangle" + }, + "direction": { + "value": "" + }, + "constraint": null + }, + "zIndex": 0 + } + ] + } + ] + }, + "err": "" +}