fix(config): handle struct defaults with child keys in migration check
- commit
- 3fc796d46f336e1bf42ecaeb36c64418145449d2
- author
- bnema · · 2025-12-27 18:56 UTC
- parent
- 2ac17d0
- signature
- GPG Unverified
2B82207D370127A0The key is unknown
2 files · +22 -5
M internal/infrastructure/config/migrate.go +16 -5
| @@ -212,8 +212,8 @@ func (m *Migrator) findMissingKeys(defaultKeys []string, userKeys map[string]boo | |||
| 212 | 212 | missing := make([]string, 0) | |
| 213 | 213 | ||
| 214 | 214 | for _, key := range defaultKeys { | |
| 215 | - | // Check if key or any parent key exists in user config | |
| 216 | - | if m.keyOrParentExists(key, userKeys) { | |
| 215 | + | // Check if key or any related key exists in user config | |
| 216 | + | if m.keyOrRelatedExists(key, userKeys) { | |
| 217 | 217 | continue | |
| 218 | 218 | } | |
| 219 | 219 | missing = append(missing, key) | |
| @@ -224,9 +224,11 @@ func (m *Migrator) findMissingKeys(defaultKeys []string, userKeys map[string]boo | |||
| 224 | 224 | return missing | |
| 225 | 225 | } | |
| 226 | 226 | ||
| 227 | - | // keyOrParentExists checks if a key or any of its parent keys exist in the map. | |
| 228 | - | // This handles cases where a user has defined a parent section but not all children. | |
| 229 | - | func (*Migrator) keyOrParentExists(key string, keys map[string]bool) bool { | |
| 227 | + | // keyOrRelatedExists checks if a key, any parent, or any child keys exist in the map. | |
| 228 | + | // This handles cases where: | |
| 229 | + | // - User has defined a parent section but not all children | |
| 230 | + | // - Default is a struct key but user has individual sub-keys (e.g., palettes) | |
| 231 | + | func (*Migrator) keyOrRelatedExists(key string, keys map[string]bool) bool { | |
| 230 | 232 | if keys[key] { | |
| 231 | 233 | return true | |
| 232 | 234 | } | |
| @@ -242,6 +244,15 @@ func (*Migrator) keyOrParentExists(key string, keys map[string]bool) bool { | |||
| 242 | 244 | } | |
| 243 | 245 | } | |
| 244 | 246 | ||
| 247 | + | // Check if any child keys exist (e.g., default is "appearance.dark_palette" | |
| 248 | + | // but user has "appearance.dark_palette.background") | |
| 249 | + | keyPrefix := key + "." | |
| 250 | + | for userKey := range keys { | |
| 251 | + | if strings.HasPrefix(userKey, keyPrefix) { | |
| 252 | + | return true | |
| 253 | + | } | |
| 254 | + | } | |
| 255 | + | ||
| 245 | 256 | return false | |
| 246 | 257 | } | |
| 247 | 258 | ||
| @@ -212,8 +212,8 @@ func (m *Migrator) findMissingKeys(defaultKeys []string, userKeys map[string]boo | |||||
| 212 | missing := make([]string, 0) | 212 | missing := make([]string, 0) | ||
| 213 | 213 | ||||
| 214 | for _, key := range defaultKeys { | 214 | for _, key := range defaultKeys { | ||
| 215 | - | // Check if key or any parent key exists in user config | 215 | + | // Check if key or any related key exists in user config |
| 216 | - | if m.keyOrParentExists(key, userKeys) { | 216 | + | if m.keyOrRelatedExists(key, userKeys) { |
| 217 | continue | 217 | continue | ||
| 218 | } | 218 | } | ||
| 219 | missing = append(missing, key) | 219 | missing = append(missing, key) | ||
| @@ -224,9 +224,11 @@ func (m *Migrator) findMissingKeys(defaultKeys []string, userKeys map[string]boo | |||||
| 224 | return missing | 224 | return missing | ||
| 225 | } | 225 | } | ||
| 226 | 226 | ||||
| 227 | - | // keyOrParentExists checks if a key or any of its parent keys exist in the map. | 227 | + | // keyOrRelatedExists checks if a key, any parent, or any child keys exist in the map. |
| 228 | - | // This handles cases where a user has defined a parent section but not all children. | 228 | + | // This handles cases where: |
| 229 | - | func (*Migrator) keyOrParentExists(key string, keys map[string]bool) bool { | 229 | + | // - User has defined a parent section but not all children |
| 230 | + | // - Default is a struct key but user has individual sub-keys (e.g., palettes) | |||
| 231 | + | func (*Migrator) keyOrRelatedExists(key string, keys map[string]bool) bool { | |||
| 230 | if keys[key] { | 232 | if keys[key] { | ||
| 231 | return true | 233 | return true | ||
| 232 | } | 234 | } | ||
| @@ -242,6 +244,15 @@ func (*Migrator) keyOrParentExists(key string, keys map[string]bool) bool { | |||||
| 242 | } | 244 | } | ||
| 243 | } | 245 | } | ||
| 244 | 246 | ||||
| 247 | + | // Check if any child keys exist (e.g., default is "appearance.dark_palette" | |||
| 248 | + | // but user has "appearance.dark_palette.background") | |||
| 249 | + | keyPrefix := key + "." | |||
| 250 | + | for userKey := range keys { | |||
| 251 | + | if strings.HasPrefix(userKey, keyPrefix) { | |||
| 252 | + | return true | |||
| 253 | + | } | |||
| 254 | + | } | |||
| 255 | + | ||||
| 245 | return false | 256 | return false | ||
| 246 | } | 257 | } | ||
| 247 | 258 | ||||
M internal/infrastructure/config/migrate_test.go +6 -0
| @@ -229,6 +229,12 @@ func TestMigrator_FindMissingKeys(t *testing.T) { | |||
| 229 | 229 | userKeys: map[string]bool{"parent": true}, | |
| 230 | 230 | expected: []string{}, // Parent covers children | |
| 231 | 231 | }, | |
| 232 | + | { | |
| 233 | + | name: "child keys cover parent (struct defaults like palettes)", | |
| 234 | + | defaultKeys: []string{"appearance.dark_palette"}, | |
| 235 | + | userKeys: map[string]bool{"appearance.dark_palette.background": true, "appearance.dark_palette.accent": true}, | |
| 236 | + | expected: []string{}, // Child keys mean parent is defined | |
| 237 | + | }, | |
| 232 | 238 | } | |
| 233 | 239 | ||
| 234 | 240 | for _, tt := range tests { | |
| @@ -229,6 +229,12 @@ func TestMigrator_FindMissingKeys(t *testing.T) { | |||||
| 229 | userKeys: map[string]bool{"parent": true}, | 229 | userKeys: map[string]bool{"parent": true}, | ||
| 230 | expected: []string{}, // Parent covers children | 230 | expected: []string{}, // Parent covers children | ||
| 231 | }, | 231 | }, | ||
| 232 | + | { | |||
| 233 | + | name: "child keys cover parent (struct defaults like palettes)", | |||
| 234 | + | defaultKeys: []string{"appearance.dark_palette"}, | |||
| 235 | + | userKeys: map[string]bool{"appearance.dark_palette.background": true, "appearance.dark_palette.accent": true}, | |||
| 236 | + | expected: []string{}, // Child keys mean parent is defined | |||
| 237 | + | }, | |||
| 232 | } | 238 | } | ||
| 233 | 239 | ||||
| 234 | for _, tt := range tests { | 240 | for _, tt := range tests { | ||