feat(html): add cloneable context data helpers
Some checks are pending
Security Scan / security (push) Waiting to run
Test / test (push) Waiting to run

Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
Virgil 2026-04-04 00:20:41 +00:00
parent 9a90819aaf
commit c56924d95c
2 changed files with 75 additions and 0 deletions

View file

@ -21,6 +21,23 @@ type Context struct {
service Translator
}
// Clone returns a shallow copy of the context with an independent Data map.
// Example: next := ctx.Clone().SetData("theme", "dark").
func (ctx *Context) Clone() *Context {
if ctx == nil {
return nil
}
clone := *ctx
if ctx.Data != nil {
clone.Data = make(map[string]any, len(ctx.Data))
for key, value := range ctx.Data {
clone.Data[key] = value
}
}
return &clone
}
func applyLocaleToService(svc Translator, locale string) {
if svc == nil || locale == "" {
return
@ -127,6 +144,17 @@ func (ctx *Context) SetData(key string, value any) *Context {
return ctx
}
// WithData returns a cloned context with one additional data value set.
// Example: next := ctx.WithData("theme", "dark").
func (ctx *Context) WithData(key string, value any) *Context {
clone := ctx.Clone()
if clone == nil {
return nil
}
clone.SetData(key, value)
return clone
}
// SetLocale updates the context locale and reapplies it to the active
// translator.
// Example: ctx.SetLocale("en-US").

View file

@ -134,6 +134,53 @@ func TestContext_SetData_InitialisesNilMap(t *testing.T) {
}
}
func TestContext_CloneCopiesDataWithoutSharingMap(t *testing.T) {
svc := &localeTranslator{}
ctx := NewContextWithService(svc, "en-GB")
ctx.SetIdentity("user-123")
ctx.SetData("theme", "dark")
clone := ctx.Clone()
if clone == ctx {
t.Fatal("Clone should return a distinct context instance")
}
if clone.service != ctx.service {
t.Fatal("Clone should preserve the active translator")
}
if clone.Locale != ctx.Locale {
t.Fatalf("Clone should preserve locale, got %q want %q", clone.Locale, ctx.Locale)
}
if clone.Identity != ctx.Identity {
t.Fatalf("Clone should preserve identity, got %q want %q", clone.Identity, ctx.Identity)
}
clone.SetData("theme", "light")
if got := ctx.Data["theme"]; got != "dark" {
t.Fatalf("Clone should not share Data map with original, got %v", got)
}
}
func TestContext_WithDataReturnsClonedContext(t *testing.T) {
ctx := NewContext()
ctx.SetData("theme", "dark")
next := ctx.WithData("locale", "fr-FR")
if next == ctx {
t.Fatal("WithData should return a cloned context")
}
if got := ctx.Data["locale"]; got != nil {
t.Fatalf("WithData should not mutate the original context, got %v", got)
}
if got := next.Data["locale"]; got != "fr-FR" {
t.Fatalf("WithData should set the requested value on the clone, got %v", got)
}
if got := next.Data["theme"]; got != "dark" {
t.Fatalf("WithData should preserve existing data on the clone, got %v", got)
}
}
func TestContext_Setters_NilReceiver(t *testing.T) {
var ctx *Context