cli/internal/generators/csharp/csharp.go

145 lines
3.1 KiB
Go

package csharp
import (
_ "embed"
"fmt"
"maps"
"slices"
"strings"
"text/template"
"github.com/open-feature/cli/internal/flagset"
"github.com/open-feature/cli/internal/generators"
)
type CsharpGenerator struct {
generators.CommonGenerator
}
type Params struct {
// Add C# specific parameters here if needed
Namespace string
}
//go:embed csharp.tmpl
var csharpTmpl string
func openFeatureType(t flagset.FlagType) string {
switch t {
case flagset.IntType:
return "int"
case flagset.FloatType:
return "double" // .NET uses double, not float
case flagset.BoolType:
return "bool"
case flagset.StringType:
return "string"
case flagset.ObjectType:
return "object"
default:
return ""
}
}
func formatDefaultValue(flag flagset.Flag) string {
switch flag.Type {
case flagset.StringType:
return fmt.Sprintf("\"%s\"", flag.DefaultValue)
case flagset.BoolType:
if flag.DefaultValue == true {
return "true"
}
return "false"
default:
return fmt.Sprintf("%v", flag.DefaultValue)
}
}
func toCSharpDict(value any) string {
assertedMap, ok := value.(map[string]any)
if !ok {
return "null"
}
keys := slices.Sorted(maps.Keys(assertedMap))
var builder strings.Builder
builder.WriteString("new Value(Structure.Builder()")
for _, key := range keys {
val := assertedMap[key]
builder.WriteString(fmt.Sprintf(".Set(%q, %s)", key, formatNestedValue(val)))
}
builder.WriteString(".Build())")
return builder.String()
}
func formatNestedValue(value any) string {
switch val := value.(type) {
case string:
flag := flagset.Flag{
Type: flagset.StringType,
DefaultValue: val,
}
return formatDefaultValue(flag)
case bool:
flag := flagset.Flag{
Type: flagset.BoolType,
DefaultValue: val,
}
return formatDefaultValue(flag)
case int, int64:
flag := flagset.Flag{
Type: flagset.IntType,
DefaultValue: val,
}
return formatDefaultValue(flag)
case float64:
flag := flagset.Flag{
Type: flagset.FloatType,
DefaultValue: val,
}
return formatDefaultValue(flag)
case map[string]any:
return toCSharpDict(val)
case []any:
var sliceBuilder strings.Builder
sliceBuilder.WriteString("new Value(new List<Value>{")
for index, elem := range val {
if index > 0 {
sliceBuilder.WriteString(", ")
}
sliceBuilder.WriteString(formatNestedValue(elem))
}
sliceBuilder.WriteString("})")
return sliceBuilder.String()
default:
return fmt.Sprintf("new Value(%s)", val)
}
}
func (g *CsharpGenerator) Generate(params *generators.Params[Params]) error {
funcs := template.FuncMap{
"OpenFeatureType": openFeatureType,
"FormatDefaultValue": formatDefaultValue,
"ToCSharpDict": toCSharpDict,
}
newParams := &generators.Params[any]{
OutputPath: params.OutputPath,
Custom: params.Custom,
}
return g.GenerateFile(funcs, csharpTmpl, newParams, "OpenFeature.g.cs")
}
// NewGenerator creates a generator for C#.
func NewGenerator(fs *flagset.Flagset) *CsharpGenerator {
return &CsharpGenerator{
CommonGenerator: *generators.NewGenerator(fs, map[flagset.FlagType]bool{}),
}
}