package sandbox import ( "fmt" "go.starlark.net/starlark" ) // GoToStarlark converts a Go value (typically from JSON unmarshal) to a // starlark.Value. Handles nil, bool, int, int64, float64, string, // map[string]any, []any, and their interface{} equivalents. Unknown // types are stringified. func GoToStarlark(v any) starlark.Value { switch val := v.(type) { case nil: return starlark.None case bool: return starlark.Bool(val) case int: return starlark.MakeInt(val) case int64: return starlark.MakeInt64(val) case float64: if val == float64(int64(val)) { return starlark.MakeInt64(int64(val)) } return starlark.Float(val) case string: return starlark.String(val) case map[string]any: return MapToDict(val) case []any: elems := make([]starlark.Value, len(val)) for i, e := range val { elems[i] = GoToStarlark(e) } return starlark.NewList(elems) default: return starlark.String(fmt.Sprintf("%v", val)) } } // StarlarkToGo converts a starlark.Value to a Go value suitable for // JSON serialization. Handles None, Bool, Int, Float, String, List, // Dict, and Tuple. func StarlarkToGo(v starlark.Value) any { switch val := v.(type) { case starlark.NoneType: return nil case starlark.Bool: return bool(val) case starlark.Int: if i, ok := val.Int64(); ok { return i } return val.String() case starlark.Float: return float64(val) case starlark.String: return string(val) case *starlark.List: result := make([]any, val.Len()) for i := 0; i < val.Len(); i++ { result[i] = StarlarkToGo(val.Index(i)) } return result case *starlark.Dict: return DictToMap(val) case starlark.Tuple: result := make([]any, len(val)) for i, e := range val { result[i] = StarlarkToGo(e) } return result default: return v.String() } } // DictToMap converts a *starlark.Dict to map[string]any. // Non-string keys are silently skipped. func DictToMap(d *starlark.Dict) map[string]any { result := make(map[string]any, d.Len()) for _, item := range d.Items() { k, ok := starlark.AsString(item[0]) if !ok { continue } result[k] = StarlarkToGo(item[1]) } return result } // MapToDict converts a map[string]any to *starlark.Dict. func MapToDict(m map[string]any) *starlark.Dict { d := starlark.NewDict(len(m)) for k, v := range m { _ = d.SetKey(starlark.String(k), GoToStarlark(v)) } return d }