fix(core): harden layout and responsive nil chains
Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
c6fd135239
commit
911071d2b0
4 changed files with 70 additions and 5 deletions
35
layout.go
35
layout.go
|
|
@ -37,38 +37,63 @@ func NewLayout(variant string) *Layout {
|
|||
}
|
||||
}
|
||||
|
||||
func (l *Layout) slotsForSlot(slot byte) []Node {
|
||||
if l == nil {
|
||||
return nil
|
||||
}
|
||||
if l.slots == nil {
|
||||
l.slots = make(map[byte][]Node)
|
||||
}
|
||||
return l.slots[slot]
|
||||
}
|
||||
|
||||
// H appends nodes to the Header slot.
|
||||
// Usage example: NewLayout("HCF").H(Text("title"))
|
||||
func (l *Layout) H(nodes ...Node) *Layout {
|
||||
l.slots['H'] = append(l.slots['H'], nodes...)
|
||||
if l == nil {
|
||||
return nil
|
||||
}
|
||||
l.slots['H'] = append(l.slotsForSlot('H'), nodes...)
|
||||
return l
|
||||
}
|
||||
|
||||
// L appends nodes to the Left aside slot.
|
||||
// Usage example: NewLayout("LC").L(Text("nav"))
|
||||
func (l *Layout) L(nodes ...Node) *Layout {
|
||||
l.slots['L'] = append(l.slots['L'], nodes...)
|
||||
if l == nil {
|
||||
return nil
|
||||
}
|
||||
l.slots['L'] = append(l.slotsForSlot('L'), nodes...)
|
||||
return l
|
||||
}
|
||||
|
||||
// C appends nodes to the Content (main) slot.
|
||||
// Usage example: NewLayout("C").C(Text("body"))
|
||||
func (l *Layout) C(nodes ...Node) *Layout {
|
||||
l.slots['C'] = append(l.slots['C'], nodes...)
|
||||
if l == nil {
|
||||
return nil
|
||||
}
|
||||
l.slots['C'] = append(l.slotsForSlot('C'), nodes...)
|
||||
return l
|
||||
}
|
||||
|
||||
// R appends nodes to the Right aside slot.
|
||||
// Usage example: NewLayout("CR").R(Text("ads"))
|
||||
func (l *Layout) R(nodes ...Node) *Layout {
|
||||
l.slots['R'] = append(l.slots['R'], nodes...)
|
||||
if l == nil {
|
||||
return nil
|
||||
}
|
||||
l.slots['R'] = append(l.slotsForSlot('R'), nodes...)
|
||||
return l
|
||||
}
|
||||
|
||||
// F appends nodes to the Footer slot.
|
||||
// Usage example: NewLayout("CF").F(Text("footer"))
|
||||
func (l *Layout) F(nodes ...Node) *Layout {
|
||||
l.slots['F'] = append(l.slots['F'], nodes...)
|
||||
if l == nil {
|
||||
return nil
|
||||
}
|
||||
l.slots['F'] = append(l.slotsForSlot('F'), nodes...)
|
||||
return l
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -113,3 +113,27 @@ func TestLayout_IgnoresInvalidSlots_Good(t *testing.T) {
|
|||
t.Errorf("C variant should ignore R slot content, got:\n%s", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLayout_Methods_NilLayout_Ugly(t *testing.T) {
|
||||
var layout *Layout
|
||||
|
||||
if layout.H(Raw("h")) != nil {
|
||||
t.Fatal("expected nil layout from H on nil receiver")
|
||||
}
|
||||
if layout.L(Raw("l")) != nil {
|
||||
t.Fatal("expected nil layout from L on nil receiver")
|
||||
}
|
||||
if layout.C(Raw("c")) != nil {
|
||||
t.Fatal("expected nil layout from C on nil receiver")
|
||||
}
|
||||
if layout.R(Raw("r")) != nil {
|
||||
t.Fatal("expected nil layout from R on nil receiver")
|
||||
}
|
||||
if layout.F(Raw("f")) != nil {
|
||||
t.Fatal("expected nil layout from F on nil receiver")
|
||||
}
|
||||
|
||||
if got := layout.Render(NewContext()); got != "" {
|
||||
t.Fatalf("nil layout render should be empty, got %q", got)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,9 @@ func NewResponsive() *Responsive {
|
|||
// Usage example: NewResponsive().Variant("desktop", NewLayout("HLCRF"))
|
||||
// Variants render in insertion order.
|
||||
func (r *Responsive) Variant(name string, layout *Layout) *Responsive {
|
||||
if r == nil {
|
||||
r = NewResponsive()
|
||||
}
|
||||
r.variants = append(r.variants, responsiveVariant{name: name, layout: layout})
|
||||
return r
|
||||
}
|
||||
|
|
|
|||
|
|
@ -86,3 +86,16 @@ func TestResponsive_VariantsIndependent_Good(t *testing.T) {
|
|||
func TestResponsive_ImplementsNode_Ugly(t *testing.T) {
|
||||
var _ Node = NewResponsive()
|
||||
}
|
||||
|
||||
func TestResponsive_Variant_NilResponsive_Ugly(t *testing.T) {
|
||||
var r *Responsive
|
||||
|
||||
got := r.Variant("mobile", NewLayout("C").C(Raw("content")))
|
||||
if got == nil {
|
||||
t.Fatal("expected non-nil responsive from Variant on nil receiver")
|
||||
}
|
||||
|
||||
if output := got.Render(NewContext()); output != `<div data-variant="mobile"><main data-block="C-0">content</main></div>` {
|
||||
t.Fatalf("unexpected output from nil receiver Variant path: %q", output)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue