diff --git a/ci/release/changelogs/next.md b/ci/release/changelogs/next.md index bc2ea0d5c..c25f0d95a 100644 --- a/ci/release/changelogs/next.md +++ b/ci/release/changelogs/next.md @@ -25,6 +25,7 @@ - fixes panic when comment lines appear in arrays [#2378](https://github.com/terrastruct/d2/pull/2378) - fixes inconsistencies when objects were double quoted [#2390](https://github.com/terrastruct/d2/pull/2390) - fixes globs not applying to spread substitutions [#2426](https://github.com/terrastruct/d2/issues/2426) + - fixes panic when classes were mixed with layers incorrectly [#2448](https://github.com/terrastruct/d2/pull/2448) - CLI: fetch and render remote images of mimetype octet-stream correctly [#2370](https://github.com/terrastruct/d2/pull/2370) - d2js: handle unicode characters [#2393](https://github.com/terrastruct/d2/pull/2393) diff --git a/d2compiler/compile_test.go b/d2compiler/compile_test.go index ccd042fad..5135be5a8 100644 --- a/d2compiler/compile_test.go +++ b/d2compiler/compile_test.go @@ -328,7 +328,7 @@ containers: { Steps } `, - expErr: `d2/testdata/d2compiler/TestCompile/image_children_Steps.d2:4:3: steps is only allowed at a board root`, + expErr: `d2/testdata/d2compiler/TestCompile/image_children_Steps.d2:4:3: steps must be declared at a board root scope`, }, { name: "name-with-dot-underscore", @@ -1714,6 +1714,40 @@ steps: { assert.Equal(t, 1, len(g.Layers[0].Steps)) }, }, + { + name: "import-classes-boards", + + text: `classes: { + a: { + label: hi + } +} + +layers: { + asdf: { + qwer: { + layers: { + ok: { + bok + } + } + } + } + wert: { + classes: @classes + } +} + +`, + files: map[string]string{ + "classes.d2": ` +c: { + label: bye +} +`, + }, + expErr: `d2/testdata/d2compiler/TestCompile/import-classes-boards.d2:10:7: layers must be declared at a board root scope`, + }, { name: "import_url_link", diff --git a/d2ir/compile.go b/d2ir/compile.go index 19a77c037..68e19b6da 100644 --- a/d2ir/compile.go +++ b/d2ir/compile.go @@ -113,7 +113,7 @@ func (c *compiler) overlayClasses(m *Map) { if lClasses == nil { lClasses = classes.Copy(l).(*Field) l.Fields = append(l.Fields, lClasses) - } else { + } else if lClasses.Map() != nil { base := classes.Copy(l).(*Field) OverlayMap(base.Map(), lClasses.Map()) l.DeleteField("classes") diff --git a/d2ir/compile_test.go b/d2ir/compile_test.go index c0ac8f4c4..da3a74aaa 100644 --- a/d2ir/compile_test.go +++ b/d2ir/compile_test.go @@ -593,7 +593,7 @@ classes: { } } `) - assert.ErrorString(t, err, `TestCompile/classes/nonroot.d2:2:3: classes is only allowed at a board root`) + assert.ErrorString(t, err, `TestCompile/classes/nonroot.d2:2:3: classes must be declared at a board root scope`) }, }, { diff --git a/d2ir/d2ir.go b/d2ir/d2ir.go index e41edbb83..290e679de 100644 --- a/d2ir/d2ir.go +++ b/d2ir/d2ir.go @@ -942,11 +942,11 @@ func (m *Map) ensureField(i int, kp *d2ast.KeyPath, refctx *RefContext, create b } if headString == "classes" && head.IsUnquoted() && NodeBoardKind(m) == "" { - return d2parser.Errorf(kp.Path[i].Unbox(), "%s is only allowed at a board root", headString) + return d2parser.Errorf(kp.Path[i].Unbox(), "%s must be declared at a board root scope", headString) } if findBoardKeyword(head) != -1 && head.IsUnquoted() && NodeBoardKind(m) == "" { - return d2parser.Errorf(kp.Path[i].Unbox(), "%s is only allowed at a board root", headString) + return d2parser.Errorf(kp.Path[i].Unbox(), "%s must be declared at a board root scope", headString) } for _, f := range m.Fields { diff --git a/testdata/d2compiler/TestCompile/image_children_Steps.exp.json b/testdata/d2compiler/TestCompile/image_children_Steps.exp.json index b9b6f483f..647584533 100644 --- a/testdata/d2compiler/TestCompile/image_children_Steps.exp.json +++ b/testdata/d2compiler/TestCompile/image_children_Steps.exp.json @@ -4,7 +4,7 @@ "errs": [ { "range": "d2/testdata/d2compiler/TestCompile/image_children_Steps.d2,3:2:115-3:7:120", - "errmsg": "d2/testdata/d2compiler/TestCompile/image_children_Steps.d2:4:3: steps is only allowed at a board root" + "errmsg": "d2/testdata/d2compiler/TestCompile/image_children_Steps.d2:4:3: steps must be declared at a board root scope" } ] } diff --git a/testdata/d2compiler/TestCompile/import-classes-boards.exp.json b/testdata/d2compiler/TestCompile/import-classes-boards.exp.json new file mode 100644 index 000000000..50d98e426 --- /dev/null +++ b/testdata/d2compiler/TestCompile/import-classes-boards.exp.json @@ -0,0 +1,11 @@ +{ + "graph": null, + "err": { + "errs": [ + { + "range": "d2/testdata/d2compiler/TestCompile/import-classes-boards.d2,9:6:75-9:12:81", + "errmsg": "d2/testdata/d2compiler/TestCompile/import-classes-boards.d2:10:7: layers must be declared at a board root scope" + } + ] + } +}