Skip to content

Commit b08431b

Browse files
authored
Merge pull request #1256 from alixander/class-array
implement arrays for classes
2 parents 2224366 + 7c401a4 commit b08431b

File tree

9 files changed

+1368
-10
lines changed

9 files changed

+1368
-10
lines changed

ci/release/changelogs/next.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#### Features 🚀
22

3+
- `class` field now accepts arrays. See [docs](TODO). [#1256](https://github.com/terrastruct/d2/pull/1256)
34
- Pill shape is implemented with rectangles of large border radius. Thanks @Poivey ! [#1006](https://github.com/terrastruct/d2/pull/1006)
45

56
#### Improvements 🧹

d2compiler/compile.go

+48-10
Original file line numberDiff line numberDiff line change
@@ -126,11 +126,25 @@ func (c *compiler) errorf(n d2ast.Node, f string, v ...interface{}) {
126126
func (c *compiler) compileMap(obj *d2graph.Object, m *d2ir.Map) {
127127
class := m.GetField("class")
128128
if class != nil {
129-
className := class.Primary()
130-
if className == nil {
131-
c.errorf(class.LastRef().AST(), "class missing value")
129+
var classNames []string
130+
if class.Primary() != nil {
131+
classNames = append(classNames, class.Primary().String())
132+
} else if class.Composite != nil {
133+
if arr, ok := class.Composite.(*d2ir.Array); ok {
134+
for _, class := range arr.Values {
135+
if scalar, ok := class.(*d2ir.Scalar); ok {
136+
classNames = append(classNames, scalar.Value.ScalarString())
137+
} else {
138+
c.errorf(class.LastPrimaryKey(), "invalid value in array")
139+
}
140+
}
141+
}
132142
} else {
133-
classMap := m.GetClassMap(className.String())
143+
c.errorf(class.LastRef().AST(), "class missing value")
144+
}
145+
146+
for _, className := range classNames {
147+
classMap := m.GetClassMap(className)
134148
if classMap != nil {
135149
c.compileMap(obj, classMap)
136150
}
@@ -293,7 +307,7 @@ func (c *compiler) compileLabel(attrs *d2graph.Attributes, f d2ir.Node) {
293307

294308
func (c *compiler) compileReserved(attrs *d2graph.Attributes, f *d2ir.Field) {
295309
if f.Primary() == nil {
296-
if f.Composite != nil {
310+
if f.Composite != nil && !strings.EqualFold(f.Name, "class") {
297311
c.errorf(f.LastPrimaryKey(), "reserved field %v does not accept composite", f.Name)
298312
}
299313
return
@@ -463,7 +477,17 @@ func (c *compiler) compileReserved(attrs *d2graph.Attributes, f *d2ir.Field) {
463477
attrs.HorizontalGap.Value = scalar.ScalarString()
464478
attrs.HorizontalGap.MapKey = f.LastPrimaryKey()
465479
case "class":
466-
attrs.Classes = append(attrs.Classes, scalar.ScalarString())
480+
if f.Primary() != nil {
481+
attrs.Classes = append(attrs.Classes, scalar.ScalarString())
482+
} else if f.Composite != nil {
483+
if arr, ok := f.Composite.(*d2ir.Array); ok {
484+
for _, class := range arr.Values {
485+
if scalar, ok := class.(*d2ir.Scalar); ok {
486+
attrs.Classes = append(attrs.Classes, scalar.Value.ScalarString())
487+
}
488+
}
489+
}
490+
}
467491
case "classes":
468492
}
469493

@@ -582,11 +606,25 @@ func (c *compiler) compileEdge(obj *d2graph.Object, e *d2ir.Edge) {
582606
func (c *compiler) compileEdgeMap(edge *d2graph.Edge, m *d2ir.Map) {
583607
class := m.GetField("class")
584608
if class != nil {
585-
className := class.Primary()
586-
if className == nil {
587-
c.errorf(class.LastRef().AST(), "class missing value")
609+
var classNames []string
610+
if class.Primary() != nil {
611+
classNames = append(classNames, class.Primary().String())
612+
} else if class.Composite != nil {
613+
if arr, ok := class.Composite.(*d2ir.Array); ok {
614+
for _, class := range arr.Values {
615+
if scalar, ok := class.(*d2ir.Scalar); ok {
616+
classNames = append(classNames, scalar.Value.ScalarString())
617+
} else {
618+
c.errorf(class.LastPrimaryKey(), "invalid value in array")
619+
}
620+
}
621+
}
588622
} else {
589-
classMap := m.GetClassMap(className.String())
623+
c.errorf(class.LastRef().AST(), "class missing value")
624+
}
625+
626+
for _, className := range classNames {
627+
classMap := m.GetClassMap(className)
590628
if classMap != nil {
591629
c.compileEdgeMap(edge, classMap)
592630
}

d2compiler/compile_test.go

+29
Original file line numberDiff line numberDiff line change
@@ -2400,6 +2400,35 @@ nostar -> 1star: { class: path }
24002400
tassert.Equal(t, "then", g.Edges[0].Label.Value)
24012401
},
24022402
},
2403+
{
2404+
name: "array-classes",
2405+
text: `classes: {
2406+
dragon_ball: {
2407+
label: ""
2408+
shape: circle
2409+
style.fill: orange
2410+
}
2411+
path: {
2412+
label: "then"
2413+
style.stroke-width: 4
2414+
}
2415+
path2: {
2416+
style.stroke-width: 2
2417+
}
2418+
}
2419+
nostar: { class: [dragon_ball; path] }
2420+
1star: { class: [path; dragon_ball] }
2421+
2422+
nostar -> 1star: { class: [path; path2] }
2423+
`,
2424+
assertions: func(t *testing.T, g *d2graph.Graph) {
2425+
tassert.Equal(t, "then", g.Objects[0].Label.Value)
2426+
tassert.Equal(t, "", g.Objects[1].Label.Value)
2427+
tassert.Equal(t, "circle", g.Objects[0].Shape.Value)
2428+
tassert.Equal(t, "circle", g.Objects[1].Shape.Value)
2429+
tassert.Equal(t, "2", g.Edges[0].Style.StrokeWidth.Value)
2430+
},
2431+
},
24032432
{
24042433
name: "reordered-classes",
24052434
text: `classes: {

e2etests/stable_test.go

+18
Original file line numberDiff line numberDiff line change
@@ -2422,6 +2422,24 @@ nostar: { class: dragon_ball }
24222422
24232423
nostar -> 1star: { class: path }
24242424
1star -> 2star: { class: path }
2425+
`,
2426+
},
2427+
{
2428+
name: "array-classes",
2429+
script: `classes: {
2430+
button: {
2431+
style.border-radius: 999
2432+
style.stroke: black
2433+
}
2434+
success: {
2435+
style.fill: "#90EE90"
2436+
}
2437+
error: {
2438+
style.fill: "#EA9999"
2439+
}
2440+
}
2441+
yay: Successful { class: [button; success] }
2442+
nay: Failure { class: [button; error] }
24252443
`,
24262444
},
24272445
{

e2etests/testdata/stable/array-classes/dagre/board.exp.json

+130
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Loading

0 commit comments

Comments
 (0)