diff --git a/d2ast/d2ast.go b/d2ast/d2ast.go index 3d209be6a..282c3509f 100644 --- a/d2ast/d2ast.go +++ b/d2ast/d2ast.go @@ -3,23 +3,23 @@ // d2ast implements the d2 language's abstract syntax tree. // // Special characters to think about in parser: -// # -// """ -// ; -// [] -// {} -// | -// $ -// ' -// " -// \ -// : -// . -// -- -// <> -// * -// & -// () +// # +// """ +// ; +// [] +// {} +// | +// $ +// ' +// " +// \ +// : +// . +// -- +// <> +// * +// & +// () package d2ast import ( @@ -159,9 +159,9 @@ func (r Range) Before(r2 Range) bool { // // note: Line and Column are zero indexed. // note: Column and Byte are UTF-8 byte indexes unless byUTF16 was passed to Position.Advance in -// which they are UTF-16 code unit indexes. -// If intended for Javascript consumption like in the browser or via LSP, byUTF16 is -// set to true. +// . which they are UTF-16 code unit indexes. +// . If intended for Javascript consumption like in the browser or via LSP, byUTF16 is +// . set to true. type Position struct { Line int Column int @@ -650,9 +650,14 @@ func (mk1 *Key) Equals(mk2 *Key) bool { } if mk1.Value.Unbox() != nil { - if mk1.Value.ScalarBox().Unbox().ScalarString() != mk2.Value.ScalarBox().Unbox().ScalarString() { + if (mk1.Value.ScalarBox().Unbox() == nil) != (mk2.Value.ScalarBox().Unbox() == nil) { return false } + if mk1.Value.ScalarBox().Unbox() != nil { + if mk1.Value.ScalarBox().Unbox().ScalarString() != mk2.Value.ScalarBox().Unbox().ScalarString() { + return false + } + } } return true diff --git a/d2oracle/edit_test.go b/d2oracle/edit_test.go index 3f10dfe4a..0d1e27f36 100644 --- a/d2oracle/edit_test.go +++ b/d2oracle/edit_test.go @@ -1858,6 +1858,32 @@ func TestMove(t *testing.T) { assert.JSON(t, g.Objects[1].ID, "c") }, }, + { + name: "duplicate", + + text: `a: { + b: { + shape: cylinder + } +} + +a: { + b: { + shape: cylinder + } +} +`, + key: `a.b`, + newKey: `b`, + + exp: `a + +a +b: { + shape: cylinder +} +`, + }, { name: "rename_2", diff --git a/testdata/d2oracle/TestMove/duplicate.exp.json b/testdata/d2oracle/TestMove/duplicate.exp.json new file mode 100644 index 000000000..9364aa80e --- /dev/null +++ b/testdata/d2oracle/TestMove/duplicate.exp.json @@ -0,0 +1,262 @@ +{ + "graph": { + "name": "", + "isFolderOnly": false, + "ast": { + "range": "d2/testdata/d2oracle/TestMove/duplicate.d2,0:0:0-6:0:30", + "nodes": [ + { + "map_key": { + "range": "d2/testdata/d2oracle/TestMove/duplicate.d2,0:0:0-0:1:1", + "key": { + "range": "d2/testdata/d2oracle/TestMove/duplicate.d2,0:0:0-0:1:1", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2oracle/TestMove/duplicate.d2,0:0:0-0:1:1", + "value": [ + { + "string": "a", + "raw_string": "a" + } + ] + } + } + ] + }, + "primary": {}, + "value": {} + } + }, + { + "map_key": { + "range": "d2/testdata/d2oracle/TestMove/duplicate.d2,2:0:3-2:1:4", + "key": { + "range": "d2/testdata/d2oracle/TestMove/duplicate.d2,2:0:3-2:1:4", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2oracle/TestMove/duplicate.d2,2:0:3-2:1:4", + "value": [ + { + "string": "a", + "raw_string": "a" + } + ] + } + } + ] + }, + "primary": {}, + "value": {} + } + }, + { + "map_key": { + "range": "d2/testdata/d2oracle/TestMove/duplicate.d2,3:0:5-5:1:29", + "key": { + "range": "d2/testdata/d2oracle/TestMove/duplicate.d2,3:0:5-3:1:6", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2oracle/TestMove/duplicate.d2,3:0:5-3:1:6", + "value": [ + { + "string": "b", + "raw_string": "b" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "map": { + "range": "d2/testdata/d2oracle/TestMove/duplicate.d2,3:3:8-5:0:28", + "nodes": [ + { + "map_key": { + "range": "d2/testdata/d2oracle/TestMove/duplicate.d2,4:2:12-4:17:27", + "key": { + "range": "d2/testdata/d2oracle/TestMove/duplicate.d2,4:2:12-4:7:17", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2oracle/TestMove/duplicate.d2,4:2:12-4:7:17", + "value": [ + { + "string": "shape", + "raw_string": "shape" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "unquoted_string": { + "range": "d2/testdata/d2oracle/TestMove/duplicate.d2,4:9:19-4:17:27", + "value": [ + { + "string": "cylinder", + "raw_string": "cylinder" + } + ] + } + } + } + } + ] + } + } + } + } + ] + }, + "root": { + "id": "", + "id_val": "", + "label_dimensions": { + "width": 0, + "height": 0 + }, + "attributes": { + "label": { + "value": "" + }, + "style": {}, + "near_key": null, + "shape": { + "value": "" + }, + "direction": { + "value": "" + }, + "constraint": { + "value": "" + } + }, + "zIndex": 0 + }, + "edges": null, + "objects": [ + { + "id": "a", + "id_val": "a", + "label_dimensions": { + "width": 0, + "height": 0 + }, + "references": [ + { + "key": { + "range": "d2/testdata/d2oracle/TestMove/duplicate.d2,0:0:0-0:1:1", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2oracle/TestMove/duplicate.d2,0:0:0-0:1:1", + "value": [ + { + "string": "a", + "raw_string": "a" + } + ] + } + } + ] + }, + "key_path_index": 0, + "map_key_edge_index": -1 + }, + { + "key": { + "range": "d2/testdata/d2oracle/TestMove/duplicate.d2,2:0:3-2:1:4", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2oracle/TestMove/duplicate.d2,2:0:3-2:1:4", + "value": [ + { + "string": "a", + "raw_string": "a" + } + ] + } + } + ] + }, + "key_path_index": 0, + "map_key_edge_index": -1 + } + ], + "attributes": { + "label": { + "value": "a" + }, + "style": {}, + "near_key": null, + "shape": { + "value": "rectangle" + }, + "direction": { + "value": "" + }, + "constraint": { + "value": "" + } + }, + "zIndex": 0 + }, + { + "id": "b", + "id_val": "b", + "label_dimensions": { + "width": 0, + "height": 0 + }, + "references": [ + { + "key": { + "range": "d2/testdata/d2oracle/TestMove/duplicate.d2,3:0:5-3:1:6", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2oracle/TestMove/duplicate.d2,3:0:5-3:1:6", + "value": [ + { + "string": "b", + "raw_string": "b" + } + ] + } + } + ] + }, + "key_path_index": 0, + "map_key_edge_index": -1 + } + ], + "attributes": { + "label": { + "value": "b" + }, + "style": {}, + "near_key": null, + "shape": { + "value": "cylinder" + }, + "direction": { + "value": "" + }, + "constraint": { + "value": "" + } + }, + "zIndex": 0 + } + ] + }, + "err": "" +}