feat(html): index repeated layout block ids
Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
c6bca226a9
commit
850dbdb0b6
4 changed files with 36 additions and 18 deletions
|
|
@ -366,7 +366,7 @@ func TestLayout_InvalidVariant_MixedValidInvalid(t *testing.T) {
|
|||
func TestLayout_DuplicateVariantChars(t *testing.T) {
|
||||
ctx := NewContext()
|
||||
|
||||
// "CCC" — C appears three times. Should render C slot content three times.
|
||||
// "CCC" — C appears three times. Each occurrence should get its own block index.
|
||||
layout := NewLayout("CCC").C(Raw("content"))
|
||||
got := layout.Render(ctx)
|
||||
|
||||
|
|
@ -374,6 +374,11 @@ func TestLayout_DuplicateVariantChars(t *testing.T) {
|
|||
if count != 3 {
|
||||
t.Errorf("CCC variant should render C slot 3 times, got %d occurrences in:\n%s", count, got)
|
||||
}
|
||||
for _, want := range []string{`data-block="C-0"`, `data-block="C-1"`, `data-block="C-2"`} {
|
||||
if !strings.Contains(got, want) {
|
||||
t.Errorf("CCC variant should contain %q in:\n%s", want, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLayout_EmptySlots(t *testing.T) {
|
||||
|
|
|
|||
12
layout.go
12
layout.go
|
|
@ -138,9 +138,10 @@ func (l *Layout) setAttr(key, value string) {
|
|||
l.attrs[key] = value
|
||||
}
|
||||
|
||||
// blockID returns the deterministic data-block attribute value for a slot.
|
||||
func (l *Layout) blockID(slot byte) string {
|
||||
return l.path + string(slot) + "-0"
|
||||
// blockID returns the deterministic data-block attribute value for a slot
|
||||
// occurrence within this layout variant.
|
||||
func (l *Layout) blockID(slot byte, index int) string {
|
||||
return l.path + string(slot) + "-" + strconv.Itoa(index)
|
||||
}
|
||||
|
||||
// layout.go: VariantError reports whether the layout variant string contained any invalid
|
||||
|
|
@ -171,6 +172,7 @@ func (l *Layout) Render(ctx *Context) string {
|
|||
|
||||
var b strings.Builder
|
||||
|
||||
slotCounts := make(map[byte]int)
|
||||
for i := range len(l.variant) {
|
||||
slot := l.variant[i]
|
||||
children := l.slots[slot]
|
||||
|
|
@ -180,7 +182,9 @@ func (l *Layout) Render(ctx *Context) string {
|
|||
continue
|
||||
}
|
||||
|
||||
bid := l.blockID(slot)
|
||||
index := slotCounts[slot]
|
||||
slotCounts[slot] = index + 1
|
||||
bid := l.blockID(slot, index)
|
||||
|
||||
b.WriteByte('<')
|
||||
b.WriteString(escapeHTML(meta.tag))
|
||||
|
|
|
|||
13
path.go
13
path.go
|
|
@ -10,7 +10,7 @@ func ParseBlockID(id string) []byte {
|
|||
}
|
||||
|
||||
// Split on "-" and require the exact structural pattern:
|
||||
// slot, 0, slot, 0, ...
|
||||
// slot, numeric index, slot, numeric index, ...
|
||||
var slots []byte
|
||||
i := 0
|
||||
for part := range strings.SplitSeq(id, "-") {
|
||||
|
|
@ -22,8 +22,15 @@ func ParseBlockID(id string) []byte {
|
|||
return nil
|
||||
}
|
||||
slots = append(slots, part[0])
|
||||
} else if part != "0" {
|
||||
return nil
|
||||
} else {
|
||||
if part == "" {
|
||||
return nil
|
||||
}
|
||||
for j := range len(part) {
|
||||
if part[j] < '0' || part[j] > '9' {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
i++
|
||||
}
|
||||
|
|
|
|||
22
path_test.go
22
path_test.go
|
|
@ -149,21 +149,22 @@ func TestNestedLayout_NilChild(t *testing.T) {
|
|||
|
||||
func TestBlockID(t *testing.T) {
|
||||
tests := []struct {
|
||||
path string
|
||||
slot byte
|
||||
want string
|
||||
path string
|
||||
slot byte
|
||||
index int
|
||||
want string
|
||||
}{
|
||||
{"", 'H', "H-0"},
|
||||
{"L-0-", 'C', "L-0-C-0"},
|
||||
{"C-0-C-0-", 'C', "C-0-C-0-C-0"},
|
||||
{"", 'F', "F-0"},
|
||||
{"", 'H', 0, "H-0"},
|
||||
{"L-0-", 'C', 0, "L-0-C-0"},
|
||||
{"C-0-C-0-", 'C', 0, "C-0-C-0-C-0"},
|
||||
{"", 'F', 2, "F-2"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
l := &Layout{path: tt.path}
|
||||
got := l.blockID(tt.slot)
|
||||
got := l.blockID(tt.slot, tt.index)
|
||||
if got != tt.want {
|
||||
t.Errorf("blockID(%q, %c) = %q, want %q", tt.path, tt.slot, got, tt.want)
|
||||
t.Errorf("blockID(%q, %c, %d) = %q, want %q", tt.path, tt.slot, tt.index, got, tt.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -174,10 +175,11 @@ func TestParseBlockID(t *testing.T) {
|
|||
want []byte
|
||||
}{
|
||||
{"L-0-C-0", []byte{'L', 'C'}},
|
||||
{"C-0-C-1", []byte{'C', 'C'}},
|
||||
{"H-0", []byte{'H'}},
|
||||
{"C-0-C-0-C-0", []byte{'C', 'C', 'C'}},
|
||||
{"", nil},
|
||||
{"L-1-C-0", nil},
|
||||
{"L-1-C-0", []byte{'L', 'C'}},
|
||||
{"L-0-C", nil},
|
||||
{"LL-0", nil},
|
||||
{"X-0", nil},
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue