05a447ef02
AppInfo.WithAddress fills the catalog placeholder (<label>.DOMAIN -> the effective subdomain + customer domain, bare DOMAIN -> the domain) on a copy; appDetailHandler applies it. Pinned per catalog template (both languages) and on the rendered page. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
52 lines
1.8 KiB
Go
52 lines
1.8 KiB
Go
package stacks
|
|
|
|
import "regexp"
|
|
|
|
// reDomainPlaceholder matches the catalog's address placeholder in app copy: a bare `DOMAIN` or a
|
|
// `<label>.DOMAIN` (wiki.DOMAIN, https://paste.DOMAIN/…). `\b` keeps SUBDOMAIN and MAIL_DOMAIN out —
|
|
// the letter or underscore before them is a word character, so no boundary falls inside them.
|
|
var reDomainPlaceholder = regexp.MustCompile(`(?:([a-z0-9-]+)\.)?\bDOMAIN\b`)
|
|
|
|
// WithAddress returns a copy of the app copy with the catalog's `DOMAIN` placeholder filled in
|
|
// (R-498): `<label>.DOMAIN` becomes `<subdomain>.<domain>` — the app's EFFECTIVE subdomain (the one
|
|
// the household chose at install), or the catalog label when none is known — and a bare `DOMAIN`
|
|
// becomes `<domain>`. With no domain configured the copy is returned unchanged: a placeholder is
|
|
// better than an address that is wrong. The receiver is not modified (slices are copied), because the
|
|
// stack's metadata is shared with every other page. Pinned by TestR498_* (stacks and web).
|
|
func (ai AppInfo) WithAddress(subdomain, domain string) AppInfo {
|
|
if domain == "" {
|
|
return ai
|
|
}
|
|
fill := func(s string) string {
|
|
return reDomainPlaceholder.ReplaceAllStringFunc(s, func(m string) string {
|
|
sub := reDomainPlaceholder.FindStringSubmatch(m)
|
|
if sub[1] == "" {
|
|
return domain
|
|
}
|
|
label := sub[1]
|
|
if subdomain != "" {
|
|
label = subdomain
|
|
}
|
|
return label + "." + domain
|
|
})
|
|
}
|
|
list := func(in []string) []string {
|
|
if in == nil {
|
|
return nil
|
|
}
|
|
out := make([]string, len(in))
|
|
for i, s := range in {
|
|
out[i] = fill(s)
|
|
}
|
|
return out
|
|
}
|
|
out := ai
|
|
out.Tagline = fill(ai.Tagline)
|
|
out.UseCases = list(ai.UseCases)
|
|
out.FirstSteps = list(ai.FirstSteps)
|
|
out.Prerequisites = list(ai.Prerequisites)
|
|
out.DefaultCreds = fill(ai.DefaultCreds)
|
|
out.AddPeople = fill(ai.AddPeople)
|
|
return out
|
|
}
|