Commit 40993056bc

40993056bcc352d584fb86acb080fe6eb1daf6c6

parent: 4228201736

Verified · cmc

cmc <hello@cleberg.net> · 2026-09-17 06:22 UTC

web: class coverage test skips composed class tokens

Template actions are replaced with a \x00 marker before the class="..."
regex runs; any token still carrying the marker (chip-{{.State}},
l{{.Level}}) is a class composed at render time and is skipped, since
style.css has rules for the concrete values, not the bare prefix.

Fails today, listing classes with no rule in style.css:
  activity (owner.html)
  authorlink (layout.html)
  chroma (layout.html)
  compareform (refs.html)
  feedline (dashboard.html)
  msmain (milestones.html, orgmilestones.html)
  signupform (register.html)

Ref #218
internal/web/classes_test.go +7 −5
@@ -9,10 +9,9 @@ import (
99)
1010
1111// TestEveryTemplateClassHasARule fails on a class a template uses that
12// no selector in style.css mentions. Template actions are removed before
13// matching, so a class composed at render time (chip-{{.State}})
14// contributes only its literal part; the rules for the concrete values
15// cover the rest.
12// no selector in style.css mentions. Template actions are replaced by a
13// marker and any class token carrying one (chip-{{.State}}, l{{.Level}})
14// is skipped; the rules for the concrete values cover those.
1615func TestEveryTemplateClassHasARule(t *testing.T) {
1716 css := string(StyleCSS)
1817 // Every ".name" that appears in a selector position: outside braces.
@@ -73,9 +72,12 @@ func TestEveryTemplateClassHasARule(t *testing.T) {
7372 if err != nil {
7473 t.Fatal(err)
7574 }
76 clean := actionRe.ReplaceAllString(string(src), " ")
75 clean := actionRe.ReplaceAllString(string(src), "\x00")
7776 for _, m := range attrRe.FindAllStringSubmatch(clean, -1) {
7877 for _, c := range strings.Fields(m[1]) {
78 if strings.Contains(c, "\x00") {
79 continue // composed at render time; the concrete values have rules
80 }
7981 if !styled[c] {
8082 missing[c] = append(missing[c], e.Name())
8183 }