diff --git a/layout.go b/layout.go
index 0fb6b11..c3008e2 100644
--- a/layout.go
+++ b/layout.go
@@ -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()
diff --git a/layout_test.go b/layout_test.go
index b1d6926..1db057a 100644
--- a/layout_test.go
+++ b/layout_test.go
@@ -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: `` +
`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 {