Skip to content

Commit

Permalink
Paramgen support for maps and wildcards (#119)
Browse files Browse the repository at this point in the history
* add support for maps and wildcards to paramgen

* change test to use time.Duration
  • Loading branch information
lovromazgon authored Apr 16, 2024
1 parent 08c13f9 commit b2aac11
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 17 deletions.
41 changes: 41 additions & 0 deletions cmd/paramgen/internal/paramgen.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,8 @@ func (p *parameterParser) parseTypeSpec(ts *ast.TypeSpec, f *ast.Field) (params
return p.parseSelectorExpr(v, f)
case *ast.Ident:
return p.parseIdent(v, f)
case *ast.MapType:
return p.parseMapType(v, f)
default:
return nil, fmt.Errorf("unexpected type: %T", ts.Type)
}
Expand Down Expand Up @@ -297,6 +299,8 @@ func (p *parameterParser) parseField(f *ast.Field) (params map[string]sdk.Parame
return p.parseStructType(v, f)
case *ast.SelectorExpr:
return p.parseSelectorExpr(v, f)
case *ast.MapType:
return p.parseMapType(v, f)
case *ast.ArrayType:
strType := fmt.Sprintf("%s", v.Elt)
if !p.isBuiltinType(strType) && !strings.Contains(strType, "time Duration") {
Expand All @@ -313,6 +317,43 @@ func (p *parameterParser) parseField(f *ast.Field) (params map[string]sdk.Parame
}
}

func (p *parameterParser) parseMapType(mt *ast.MapType, f *ast.Field) (params map[string]sdk.Parameter, err error) {
if fmt.Sprintf("%s", mt.Key) != "string" {
return nil, fmt.Errorf("unsupported map key type: %s", mt.Key)
}

// parse map value as if it was a field
var tmpParams map[string]sdk.Parameter
switch val := mt.Value.(type) {
case *ast.Ident:
// identifier (builtin type or type in same package)
tmpParams, err = p.parseIdent(val, f)
case *ast.StructType:
// nested type
tmpParams, err = p.parseStructType(val, f)
case *ast.SelectorExpr:
tmpParams, err = p.parseSelectorExpr(val, f)
}
if err != nil {
return nil, err
}

// inject wildcard
params = make(map[string]sdk.Parameter, len(tmpParams))
for k, p := range tmpParams {
index := strings.Index(k, ".")
if index == -1 {
index = len(k)
}
name := k[:index] + ".*"
if index < len(k) {
name += k[index:]
}
params[name] = p
}
return params, nil
}

func (p *parameterParser) parseSelectorExpr(se *ast.SelectorExpr, f *ast.Field) (params map[string]sdk.Parameter, err error) {
defer func() {
if err != nil {
Expand Down
51 changes: 34 additions & 17 deletions cmd/paramgen/internal/paramgen_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,23 +58,26 @@ func TestParseSpecificationSuccess(t *testing.T) {
},
},
},
"myUint": {Type: sdk.ParameterTypeInt},
"myInt8": {Type: sdk.ParameterTypeInt},
"myUint8": {Type: sdk.ParameterTypeInt},
"myInt16": {Type: sdk.ParameterTypeInt},
"myUint16": {Type: sdk.ParameterTypeInt},
"myInt32": {Type: sdk.ParameterTypeInt},
"myUint32": {Type: sdk.ParameterTypeInt},
"myInt64": {Type: sdk.ParameterTypeInt},
"myUint64": {Type: sdk.ParameterTypeInt},
"myByte": {Type: sdk.ParameterTypeString},
"myRune": {Type: sdk.ParameterTypeInt},
"myFloat32": {Type: sdk.ParameterTypeFloat},
"myFloat64": {Type: sdk.ParameterTypeFloat},
"myDuration": {Type: sdk.ParameterTypeDuration},
"myIntSlice": {Type: sdk.ParameterTypeString},
"myFloatSlice": {Type: sdk.ParameterTypeString},
"myDurSlice": {Type: sdk.ParameterTypeString},
"myUint": {Type: sdk.ParameterTypeInt},
"myInt8": {Type: sdk.ParameterTypeInt},
"myUint8": {Type: sdk.ParameterTypeInt},
"myInt16": {Type: sdk.ParameterTypeInt},
"myUint16": {Type: sdk.ParameterTypeInt},
"myInt32": {Type: sdk.ParameterTypeInt},
"myUint32": {Type: sdk.ParameterTypeInt},
"myInt64": {Type: sdk.ParameterTypeInt},
"myUint64": {Type: sdk.ParameterTypeInt},
"myByte": {Type: sdk.ParameterTypeString},
"myRune": {Type: sdk.ParameterTypeInt},
"myFloat32": {Type: sdk.ParameterTypeFloat},
"myFloat64": {Type: sdk.ParameterTypeFloat},
"myDuration": {Type: sdk.ParameterTypeDuration},
"myIntSlice": {Type: sdk.ParameterTypeString},
"myFloatSlice": {Type: sdk.ParameterTypeString},
"myDurSlice": {Type: sdk.ParameterTypeString},
"myStringMap.*": {Type: sdk.ParameterTypeString},
"myStructMap.*.myInt": {Type: sdk.ParameterTypeInt},
"myStructMap.*.myString": {Type: sdk.ParameterTypeString},
},
},
{
Expand All @@ -87,6 +90,20 @@ func TestParseSpecificationSuccess(t *testing.T) {
Description: "duration does not have a name so the type name is used.",
Type: sdk.ParameterTypeDuration,
},
"global.wildcardStrings.*": {
Default: "foo",
Type: sdk.ParameterTypeString,
Validations: []sdk.Validation{
sdk.ValidationRequired{},
},
},
"global.renamed.*": {
Default: "1s",
Type: sdk.ParameterTypeDuration,
},
"global.wildcardStructs.*.name": {
Type: sdk.ParameterTypeString,
},
"nestMeHere.anotherNested": {
Type: sdk.ParameterTypeInt,
Description: "nestMeHere.anotherNested is also nested under nestMeHere. This is a block comment.",
Expand Down
8 changes: 8 additions & 0 deletions cmd/paramgen/internal/testdata/basic/specs.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,14 @@ type SourceConfig struct {
MyFloatSlice []float32
MyDurSlice []time.Duration

MyStringMap map[string]string
MyStructMap map[string]structMapVal

// this field is ignored because it is not exported
ignoreThis http.Client
}

type structMapVal struct {
MyString string
MyInt int
}
8 changes: 8 additions & 0 deletions cmd/paramgen/internal/testdata/complex/internal/global.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,12 @@ import "time"
type GlobalConfig struct {
// Duration does not have a name so the type name is used.
time.Duration `default:"1s"` // line comments on fields with doc comments are ignored

WildcardStrings map[string]string `default:"foo" validate:"required"`
WildcardInts map[string]time.Duration `json:"renamed" default:"1s"`
WildcardStructs WildcardStruct
}

type WildcardStruct map[string]struct {
Name string
}

0 comments on commit b2aac11

Please sign in to comment.