From 9ea0101dbd32eb18da933ef95573a91cb6563b32 Mon Sep 17 00:00:00 2001 From: Alexander Wang Date: Thu, 3 Apr 2025 18:39:42 -0600 Subject: [PATCH 1/3] add test --- d2compiler/compile_test.go | 19 ++ .../TestCompile/import-nested-var.exp.json | 191 ++++++++++++++++++ 2 files changed, 210 insertions(+) create mode 100644 testdata/d2compiler/TestCompile/import-nested-var.exp.json diff --git a/d2compiler/compile_test.go b/d2compiler/compile_test.go index da5e686ba..f077c5abe 100644 --- a/d2compiler/compile_test.go +++ b/d2compiler/compile_test.go @@ -1714,6 +1714,25 @@ steps: { assert.Equal(t, 1, len(g.Layers[0].Steps)) }, }, + { + name: "import-nested-var", + + text: `...@models.environment +`, + files: map[string]string{ + "models.d2": ` +vars: { + c: { + k + } +} + +environment: { + ...${c} +} +`, + }, + }, { name: "import-connections", diff --git a/testdata/d2compiler/TestCompile/import-nested-var.exp.json b/testdata/d2compiler/TestCompile/import-nested-var.exp.json new file mode 100644 index 000000000..243379fb6 --- /dev/null +++ b/testdata/d2compiler/TestCompile/import-nested-var.exp.json @@ -0,0 +1,191 @@ +{ + "graph": { + "name": "", + "isFolderOnly": false, + "ast": { + "range": "d2/testdata/d2compiler/TestCompile/import-nested-var.d2,0:0:0-3:0:42", + "nodes": [ + { + "map_key": { + "range": "d2/testdata/d2compiler/TestCompile/import-nested-var.d2,0:0:0-2:1:41", + "key": { + "range": "d2/testdata/d2compiler/TestCompile/import-nested-var.d2,0:0:0-0:11:11", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/import-nested-var.d2,0:0:0-0:11:11", + "value": [ + { + "string": "development", + "raw_string": "development" + } + ] + } + } + ] + }, + "primary": {}, + "value": { + "map": { + "range": "d2/testdata/d2compiler/TestCompile/import-nested-var.d2,0:13:13-2:1:41", + "nodes": [ + { + "import": { + "range": "d2/testdata/d2compiler/TestCompile/import-nested-var.d2,1:2:17-1:24:39", + "spread": true, + "pre": "", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/import-nested-var.d2,1:6:21-1:12:27", + "value": [ + { + "string": "models", + "raw_string": "models" + } + ] + } + }, + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/import-nested-var.d2,1:13:28-1:24:39", + "value": [ + { + "string": "environment", + "raw_string": "environment" + } + ] + } + } + ] + } + } + ] + } + } + } + } + ] + }, + "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": "development", + "id_val": "development", + "references": [ + { + "key": { + "range": "d2/testdata/d2compiler/TestCompile/import-nested-var.d2,0:0:0-0:11:11", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/import-nested-var.d2,0:0:0-0:11:11", + "value": [ + { + "string": "development", + "raw_string": "development" + } + ] + } + } + ] + }, + "key_path_index": 0, + "map_key_edge_index": -1 + } + ], + "attributes": { + "label": { + "value": "development" + }, + "labelDimensions": { + "width": 0, + "height": 0 + }, + "style": {}, + "iconStyle": {}, + "near_key": null, + "shape": { + "value": "rectangle" + }, + "direction": { + "value": "" + }, + "constraint": null + }, + "zIndex": 0 + }, + { + "id": "k", + "id_val": "k", + "references": [ + { + "key": { + "range": "d2/testdata/d2compiler/TestCompile/models.d2,8:2:56-8:3:57", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/models.d2,8:2:56-8:3:57", + "value": [ + { + "string": "k", + "raw_string": "k" + } + ] + } + } + ] + }, + "key_path_index": 0, + "map_key_edge_index": -1 + } + ], + "attributes": { + "label": { + "value": "k" + }, + "labelDimensions": { + "width": 0, + "height": 0 + }, + "style": {}, + "iconStyle": {}, + "near_key": null, + "shape": { + "value": "rectangle" + }, + "direction": { + "value": "" + }, + "constraint": null + }, + "zIndex": 0 + } + ] + }, + "err": null +} From 1acd6ef34ab1556743752a62c94c1b4122623e3e Mon Sep 17 00:00:00 2001 From: Alexander Wang Date: Thu, 3 Apr 2025 19:52:41 -0600 Subject: [PATCH 2/3] fix --- d2compiler/compile_test.go | 4 + d2ir/import.go | 8 ++ .../TestCompile/import-nested-var.exp.json | 133 ++++-------------- 3 files changed, 41 insertions(+), 104 deletions(-) diff --git a/d2compiler/compile_test.go b/d2compiler/compile_test.go index f077c5abe..44c4d1bb2 100644 --- a/d2compiler/compile_test.go +++ b/d2compiler/compile_test.go @@ -1732,6 +1732,10 @@ environment: { } `, }, + assertions: func(t *testing.T, g *d2graph.Graph) { + assert.Equal(t, 1, len(g.Objects)) + assert.Equal(t, "k", g.Objects[0].AbsID()) + }, }, { name: "import-connections", diff --git a/d2ir/import.go b/d2ir/import.go index 6f593c5c7..2d6630203 100644 --- a/d2ir/import.go +++ b/d2ir/import.go @@ -111,6 +111,14 @@ func (c *compiler) __import(imp *d2ast.Import) (*Map, bool) { c.compileMap(ir, ast, ast) + // We attempt to resolve variables in the imported file scope first + // But ignore errors, in case the variable is meant to be resolved at the + // importer + savedErrors := make([]d2ast.Error, len(c.err.Errors)) + copy(savedErrors, c.err.Errors) + c.compileSubstitutions(ir, nil) + c.err.Errors = savedErrors + c.seenImports[impPath] = struct{}{} return ir, true diff --git a/testdata/d2compiler/TestCompile/import-nested-var.exp.json b/testdata/d2compiler/TestCompile/import-nested-var.exp.json index 243379fb6..a2ec401d7 100644 --- a/testdata/d2compiler/TestCompile/import-nested-var.exp.json +++ b/testdata/d2compiler/TestCompile/import-nested-var.exp.json @@ -3,66 +3,37 @@ "name": "", "isFolderOnly": false, "ast": { - "range": "d2/testdata/d2compiler/TestCompile/import-nested-var.d2,0:0:0-3:0:42", + "range": "d2/testdata/d2compiler/TestCompile/import-nested-var.d2,0:0:0-1:0:23", "nodes": [ { - "map_key": { - "range": "d2/testdata/d2compiler/TestCompile/import-nested-var.d2,0:0:0-2:1:41", - "key": { - "range": "d2/testdata/d2compiler/TestCompile/import-nested-var.d2,0:0:0-0:11:11", - "path": [ - { - "unquoted_string": { - "range": "d2/testdata/d2compiler/TestCompile/import-nested-var.d2,0:0:0-0:11:11", - "value": [ - { - "string": "development", - "raw_string": "development" - } - ] - } - } - ] - }, - "primary": {}, - "value": { - "map": { - "range": "d2/testdata/d2compiler/TestCompile/import-nested-var.d2,0:13:13-2:1:41", - "nodes": [ - { - "import": { - "range": "d2/testdata/d2compiler/TestCompile/import-nested-var.d2,1:2:17-1:24:39", - "spread": true, - "pre": "", - "path": [ - { - "unquoted_string": { - "range": "d2/testdata/d2compiler/TestCompile/import-nested-var.d2,1:6:21-1:12:27", - "value": [ - { - "string": "models", - "raw_string": "models" - } - ] - } - }, - { - "unquoted_string": { - "range": "d2/testdata/d2compiler/TestCompile/import-nested-var.d2,1:13:28-1:24:39", - "value": [ - { - "string": "environment", - "raw_string": "environment" - } - ] - } - } - ] + "import": { + "range": "d2/testdata/d2compiler/TestCompile/import-nested-var.d2,0:0:0-0:22:22", + "spread": true, + "pre": "", + "path": [ + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/import-nested-var.d2,0:4:4-0:10:10", + "value": [ + { + "string": "models", + "raw_string": "models" } - } - ] + ] + } + }, + { + "unquoted_string": { + "range": "d2/testdata/d2compiler/TestCompile/import-nested-var.d2,0:11:11-0:22:22", + "value": [ + { + "string": "environment", + "raw_string": "environment" + } + ] + } } - } + ] } } ] @@ -93,63 +64,17 @@ }, "edges": null, "objects": [ - { - "id": "development", - "id_val": "development", - "references": [ - { - "key": { - "range": "d2/testdata/d2compiler/TestCompile/import-nested-var.d2,0:0:0-0:11:11", - "path": [ - { - "unquoted_string": { - "range": "d2/testdata/d2compiler/TestCompile/import-nested-var.d2,0:0:0-0:11:11", - "value": [ - { - "string": "development", - "raw_string": "development" - } - ] - } - } - ] - }, - "key_path_index": 0, - "map_key_edge_index": -1 - } - ], - "attributes": { - "label": { - "value": "development" - }, - "labelDimensions": { - "width": 0, - "height": 0 - }, - "style": {}, - "iconStyle": {}, - "near_key": null, - "shape": { - "value": "rectangle" - }, - "direction": { - "value": "" - }, - "constraint": null - }, - "zIndex": 0 - }, { "id": "k", "id_val": "k", "references": [ { "key": { - "range": "d2/testdata/d2compiler/TestCompile/models.d2,8:2:56-8:3:57", + "range": "d2/testdata/d2compiler/TestCompile/models.d2,3:4:20-3:5:21", "path": [ { "unquoted_string": { - "range": "d2/testdata/d2compiler/TestCompile/models.d2,8:2:56-8:3:57", + "range": "d2/testdata/d2compiler/TestCompile/models.d2,3:4:20-3:5:21", "value": [ { "string": "k", From a829683431501f9d4a94f036012d9af6dce090c8 Mon Sep 17 00:00:00 2001 From: Alexander Wang Date: Thu, 3 Apr 2025 19:54:25 -0600 Subject: [PATCH 3/3] next --- ci/release/changelogs/next.md | 1 + 1 file changed, 1 insertion(+) diff --git a/ci/release/changelogs/next.md b/ci/release/changelogs/next.md index 092a1ff80..8f68152a0 100644 --- a/ci/release/changelogs/next.md +++ b/ci/release/changelogs/next.md @@ -18,6 +18,7 @@ - Watch mode ignores backup files (e.g. files created by certain editors like Helix). [#2131](https://github.com/terrastruct/d2/issues/2131) - Compiler: - `link`s can be set to root path, e.g. `/xyz`. [#2357](https://github.com/terrastruct/d2/issues/2357) + - When importing a file, attempt resolving substitutions at the imported file scope first [#2482](https://github.com/terrastruct/d2/pull/2482) - Parser: - impose max key length. It's almost certainly a mistake if an ID gets too long, e.g. missing quotes [#2465](https://github.com/terrastruct/d2/pull/2465) - Render: