diff --git a/d2compiler/compile_test.go b/d2compiler/compile_test.go index b99b1a8c9..767cc9ac0 100644 --- a/d2compiler/compile_test.go +++ b/d2compiler/compile_test.go @@ -3572,6 +3572,42 @@ hi: { assert.Equal(t, "a-b", g.Objects[1].Label.Value) }, }, + { + name: "null", + run: func(t *testing.T) { + assertCompile(t, ` +vars: { + surname: Smith +} +a: { + vars: { + surname: null + } + hi: John ${surname} +} +`, `d2/testdata/d2compiler/TestCompile2/vars/override/null.d2:9:3: could not resolve variable "surname"`) + }, + }, + { + name: "nested-null", + run: func(t *testing.T) { + assertCompile(t, ` +vars: { + surnames: { + john: smith + } +} +a: { + vars: { + surnames: { + john: null + } + } + hi: John ${surname} +} +`, `d2/testdata/d2compiler/TestCompile2/vars/override/nested-null.d2:13:3: could not resolve variable "surname"`) + }, + }, } for _, tc := range tca { @@ -3711,22 +3747,6 @@ scenarios: { assert.Equal(t, "im replaced x var", g.Scenarios[0].Objects[0].Label.Value) }, }, - { - name: "null", - run: func(t *testing.T) { - assertCompile(t, ` -vars: { - surname: Smith -} -a: { - vars: { - surname: null - } - hi: John ${surname} -} -`, `d2/testdata/d2compiler/TestCompile2/vars/boards/null.d2:9:3: could not resolve variable "surname"`) - }, - }, } for _, tc := range tca { diff --git a/d2ir/compile.go b/d2ir/compile.go index 3efd94dd8..ef88d95a9 100644 --- a/d2ir/compile.go +++ b/d2ir/compile.go @@ -331,7 +331,7 @@ func (c *compiler) compileField(dst *Map, kp *d2ast.KeyPath, refctx *RefContext) if refctx.Key != nil && len(refctx.Key.Edges) == 0 && refctx.Key.Value.Null != nil { // For vars, if we delete the field, it may just resolve to an outer scope var of the same name // Instead we keep it around, so that resolveSubstitutions can find it - if ParentField(dst) == nil || ParentField(dst).Name != "vars" { + if !IsVar(dst) { dst.DeleteField(kp.IDA()...) return } diff --git a/d2ir/d2ir.go b/d2ir/d2ir.go index 65ed636b5..1160021f4 100644 --- a/d2ir/d2ir.go +++ b/d2ir/d2ir.go @@ -1026,6 +1026,21 @@ func ParentField(n Node) *Field { } } +func IsVar(n Node) bool { + for { + if n == nil { + return false + } + if NodeBoardKind(n) != "" { + return false + } + if f, ok := n.(*Field); ok && f.Name == "vars" { + return true + } + n = n.Parent() + } +} + func ParentBoard(n Node) Node { for { n = n.Parent() diff --git a/testdata/d2compiler/TestCompile2/vars/override/nested-null.exp.json b/testdata/d2compiler/TestCompile2/vars/override/nested-null.exp.json new file mode 100644 index 000000000..e73ae9f61 --- /dev/null +++ b/testdata/d2compiler/TestCompile2/vars/override/nested-null.exp.json @@ -0,0 +1,11 @@ +{ + "graph": null, + "err": { + "errs": [ + { + "range": "d2/testdata/d2compiler/TestCompile2/vars/override/nested-null.d2,12:2:102-12:4:104", + "errmsg": "d2/testdata/d2compiler/TestCompile2/vars/override/nested-null.d2:13:3: could not resolve variable \"surname\"" + } + ] + } +} diff --git a/testdata/d2compiler/TestCompile2/vars/override/null.exp.json b/testdata/d2compiler/TestCompile2/vars/override/null.exp.json new file mode 100644 index 000000000..84df5d0e5 --- /dev/null +++ b/testdata/d2compiler/TestCompile2/vars/override/null.exp.json @@ -0,0 +1,11 @@ +{ + "graph": null, + "err": { + "errs": [ + { + "range": "d2/testdata/d2compiler/TestCompile2/vars/override/null.d2,8:2:64-8:4:66", + "errmsg": "d2/testdata/d2compiler/TestCompile2/vars/override/null.d2:9:3: could not resolve variable \"surname\"" + } + ] + } +}