fix(html): improve layout variant diagnostics
Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
a029931f76
commit
957bc85c64
2 changed files with 48 additions and 8 deletions
47
layout.go
47
layout.go
|
|
@ -4,6 +4,7 @@ import (
|
|||
"errors"
|
||||
"maps"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
|
|
@ -57,18 +58,17 @@ func NewLayout(variant string) *Layout {
|
|||
// recognised slot characters.
|
||||
// Example: ValidateLayoutVariant("HCF").
|
||||
func ValidateLayoutVariant(variant string) error {
|
||||
var invalid bool
|
||||
var invalidSlots []byte
|
||||
for i := range len(variant) {
|
||||
if _, ok := slotRegistry[variant[i]]; ok {
|
||||
continue
|
||||
}
|
||||
invalid = true
|
||||
break
|
||||
invalidSlots = append(invalidSlots, variant[i])
|
||||
}
|
||||
if !invalid {
|
||||
if len(invalidSlots) == 0 {
|
||||
return nil
|
||||
}
|
||||
return &layoutVariantError{variant: variant}
|
||||
return &layoutVariantError{variant: variant, invalidSlots: invalidSlots}
|
||||
}
|
||||
|
||||
// H appends nodes to the Header slot.
|
||||
|
|
@ -182,13 +182,46 @@ func (l *Layout) Render(ctx *Context) string {
|
|||
}
|
||||
|
||||
type layoutVariantError struct {
|
||||
variant string
|
||||
variant string
|
||||
invalidSlots []byte
|
||||
}
|
||||
|
||||
func (e *layoutVariantError) Error() string {
|
||||
return "html: invalid layout variant " + e.variant
|
||||
if e == nil {
|
||||
return ErrInvalidLayoutVariant.Error()
|
||||
}
|
||||
|
||||
var b strings.Builder
|
||||
b.WriteString("html: invalid layout variant ")
|
||||
b.WriteString(e.variant)
|
||||
if len(e.invalidSlots) == 0 {
|
||||
return b.String()
|
||||
}
|
||||
|
||||
b.WriteString(" (invalid slot")
|
||||
if len(e.invalidSlots) > 1 {
|
||||
b.WriteString("s")
|
||||
}
|
||||
b.WriteString(": ")
|
||||
for i, slot := range e.invalidSlots {
|
||||
if i > 0 {
|
||||
b.WriteString(", ")
|
||||
}
|
||||
b.WriteString(strconv.QuoteRuneToASCII(rune(slot)))
|
||||
}
|
||||
b.WriteByte(')')
|
||||
return b.String()
|
||||
}
|
||||
|
||||
func (e *layoutVariantError) Unwrap() error {
|
||||
return ErrInvalidLayoutVariant
|
||||
}
|
||||
|
||||
// InvalidSlots returns a copy of the invalid slot characters that were present
|
||||
// in the original variant string.
|
||||
func (e *layoutVariantError) InvalidSlots() []byte {
|
||||
if e == nil || len(e.invalidSlots) == 0 {
|
||||
return nil
|
||||
}
|
||||
return append([]byte(nil), e.invalidSlots...)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -179,7 +179,7 @@ func TestLayout_VariantError(t *testing.T) {
|
|||
name: "mixed invalid variant",
|
||||
variant: "HXC",
|
||||
wantErr: true,
|
||||
wantErrString: "html: invalid layout variant HXC",
|
||||
wantErrString: "html: invalid layout variant HXC (invalid slot: 'X')",
|
||||
wantRender: `<header role="banner" data-block="H-0">header</header>` +
|
||||
`<main role="main" data-block="C-0">main</main>`,
|
||||
},
|
||||
|
|
@ -200,6 +200,13 @@ func TestLayout_VariantError(t *testing.T) {
|
|||
if got := layout.VariantError().Error(); got != tt.wantErrString {
|
||||
t.Fatalf("VariantError().Error() = %q, want %q", got, tt.wantErrString)
|
||||
}
|
||||
if err, ok := layout.VariantError().(*layoutVariantError); ok {
|
||||
if got := string(err.InvalidSlots()); got != "X" {
|
||||
t.Fatalf("InvalidSlots() = %q, want %q", got, "X")
|
||||
}
|
||||
} else {
|
||||
t.Fatalf("VariantError() has unexpected concrete type %T", layout.VariantError())
|
||||
}
|
||||
} else if layout.VariantError() != nil {
|
||||
t.Fatalf("VariantError() = %v, want nil", layout.VariantError())
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue