feat(layout): add variant validity helper
Some checks are pending
Security Scan / security (push) Waiting to run
Test / test (push) Waiting to run

Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
Virgil 2026-04-03 19:18:02 +00:00
parent 669163fcd6
commit d74b65913a
2 changed files with 25 additions and 4 deletions

View file

@ -59,16 +59,22 @@ func NewLayout(variant string) *Layout {
// Example: ValidateLayoutVariant("HCF").
func ValidateLayoutVariant(variant string) error {
var invalidSlots []byte
var invalidPositions []int
for i := range len(variant) {
if _, ok := slotRegistry[variant[i]]; ok {
continue
}
invalidSlots = append(invalidSlots, variant[i])
invalidPositions = append(invalidPositions, i)
}
if len(invalidSlots) == 0 {
return nil
}
return &layoutVariantError{variant: variant, invalidSlots: invalidSlots}
return &layoutVariantError{
variant: variant,
invalidSlots: invalidSlots,
invalidPositions: invalidPositions,
}
}
// layout.go: H appends nodes to the Header slot.
@ -131,6 +137,13 @@ func (l *Layout) VariantError() error {
return l.variantErr
}
// layout.go: VariantValid reports whether the layout variant string contains
// only recognised slot characters.
// Example: NewLayout("HCF").VariantValid().
func (l *Layout) VariantValid() bool {
return l == nil || l.variantErr == nil
}
// layout.go: Render produces the semantic HTML for this layout.
// Example: NewLayout("C").C(Raw("body")).Render(NewContext()).
// Only slots present in the variant string are rendered.
@ -188,8 +201,9 @@ func (l *Layout) Render(ctx *Context) string {
}
type layoutVariantError struct {
variant string
invalidSlots []byte
variant string
invalidSlots []byte
invalidPositions []int
}
func (e *layoutVariantError) Error() string {
@ -214,6 +228,10 @@ func (e *layoutVariantError) Error() string {
b.WriteString(", ")
}
b.WriteString(strconv.QuoteRuneToASCII(rune(slot)))
if i < len(e.invalidPositions) {
b.WriteString(" at position ")
b.WriteString(strconv.Itoa(e.invalidPositions[i] + 1))
}
}
b.WriteByte(')')
return b.String()

View file

@ -179,7 +179,7 @@ func TestLayout_VariantError(t *testing.T) {
name: "mixed invalid variant",
variant: "HXC",
wantErr: true,
wantErrString: "html: invalid layout variant HXC (invalid slot: 'X')",
wantErrString: "html: invalid layout variant HXC (invalid slot: 'X' at position 2)",
wantRender: `<header role="banner" data-block="H-0">header</header>` +
`<main role="main" data-block="C-0">main</main>`,
},
@ -210,6 +210,9 @@ func TestLayout_VariantError(t *testing.T) {
} else if layout.VariantError() != nil {
t.Fatalf("VariantError() = %v, want nil", layout.VariantError())
}
if got := layout.VariantValid(); got != !tt.wantErr {
t.Fatalf("VariantValid() = %v, want %v", got, !tt.wantErr)
}
got := layout.Render(NewContext())
if got != tt.wantRender {