diff --git a/d2compiler/compile_test.go b/d2compiler/compile_test.go index 457b442a7..15ed52962 100644 --- a/d2compiler/compile_test.go +++ b/d2compiler/compile_test.go @@ -3696,6 +3696,22 @@ 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 f4f0e7d4c..f4fc7775b 100644 --- a/d2ir/compile.go +++ b/d2ir/compile.go @@ -143,6 +143,11 @@ func (c *compiler) resolveSubstitutions(varsStack []*Map, node Node) { for _, vars := range varsStack { resolvedField = c.resolveSubstitution(vars, box.Substitution) if resolvedField != nil { + if resolvedField.Primary() != nil { + if _, ok := resolvedField.Primary().Value.(*d2ast.Null); ok { + resolvedField = nil + } + } break } } @@ -257,6 +262,7 @@ func (c *compiler) resolveSubstitution(vars *Map, substitution *d2ast.Substituti if f == nil { return nil } + if i == len(substitution.Path)-1 { return f } @@ -351,8 +357,12 @@ func (c *compiler) compileKey(refctx *RefContext) { 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 { - dst.DeleteField(kp.IDA()...) - return + // 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" { + dst.DeleteField(kp.IDA()...) + return + } } f, err := dst.EnsureField(kp, refctx) if err != nil { diff --git a/testdata/d2compiler/TestCompile2/vars/boards/null.exp.json b/testdata/d2compiler/TestCompile2/vars/boards/null.exp.json new file mode 100644 index 000000000..b96afe0dd --- /dev/null +++ b/testdata/d2compiler/TestCompile2/vars/boards/null.exp.json @@ -0,0 +1,11 @@ +{ + "graph": null, + "err": { + "errs": [ + { + "range": "d2/testdata/d2compiler/TestCompile2/vars/boards/null.d2,8:2:64-8:4:66", + "errmsg": "d2/testdata/d2compiler/TestCompile2/vars/boards/null.d2:9:3: could not resolve variable \"surname\"" + } + ] + } +}