// Copyright 2020-2026 Project Capsule Authors // SPDX-License-Identifier: Apache-2.0 package utils import ( "fmt" "reflect" "k8s.io/apimachinery/pkg/runtime" ) func MapMergeNoOverrite(dst, src map[string]string) { if len(src) == 0 { return } for k, v := range src { if _, exists := dst[k]; !exists { dst[k] = v } } } func MapEqual(a, b map[string]string) bool { if len(a) != len(b) { return false } for k, v := range a { if bv, ok := b[k]; !ok || bv != v { return false } } return true } func ToUnstructuredMap(obj any) (map[string]any, error) { m, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj) if err != nil { return nil, err } return m, nil } func Mapify(data any) map[string]any { result := make(map[string]any) v := reflect.ValueOf(data) // If the provided data is a pointer, resolve to the underlying value if v.Kind() == reflect.Pointer { if v.IsNil() { return result // Return empty map for nil pointers } v = v.Elem() } // Ensure we're working with a struct if v.Kind() == reflect.Struct { for i := range v.NumField() { field := v.Type().Field(i) // Skip unexported fields if field.PkgPath != "" { continue } value := v.Field(i) // Handle different types with recursive or base handling //nolint:exhaustive switch value.Kind() { case reflect.Pointer: if !value.IsNil() { result[field.Name] = Mapify(value.Interface()) } case reflect.Struct: result[field.Name] = Mapify(value.Interface()) case reflect.Slice: var slice []any for j := range value.Len() { item := value.Index(j) if item.Kind() == reflect.Struct { slice = append(slice, Mapify(item.Interface())) } else { slice = append(slice, item.Interface()) } } result[field.Name] = slice case reflect.Map: mapResult := make(map[string]any) for _, key := range value.MapKeys() { mapResult[fmt.Sprint(key)] = value.MapIndex(key).Interface() } result[field.Name] = mapResult default: result[field.Name] = value.Interface() } } } return result }