diff --git a/cmd/mktp/config.yaml b/cmd/mktp/config.yaml index ff60b01c..a99701a3 100644 --- a/cmd/mktp/config.yaml +++ b/cmd/mktp/config.yaml @@ -2,6 +2,12 @@ output: go_sdk: "../generated/pango" terraform_provider: "../generated/terraform-provider-panos" assets: +# generic_package: +# source: "assets/generic" +# target: +# go_sdk: true +# terraform_provider: false +# destination: "generic" # util_package: # source: "assets/util" # target: diff --git a/pkg/generate/generator.go b/pkg/generate/generator.go index 9d923931..58aac891 100644 --- a/pkg/generate/generator.go +++ b/pkg/generate/generator.go @@ -75,12 +75,16 @@ func (c *Creator) generateOutputFileFromTemplate(tmpl *template.Template, output func (c *Creator) parseTemplate(templateName string) (*template.Template, error) { templatePath := fmt.Sprintf("%s/%s", c.TemplatesDir, templateName) funcMap := template.FuncMap{ - "packageName": translate.PackageName, - "locationType": translate.LocationType, - "omitEmpty": translate.OmitEmpty, + "packageName": translate.PackageName, + "locationType": translate.LocationType, + "specParamType": translate.SpecParamType, + "omitEmpty": translate.OmitEmpty, "contains": func(full, part string) bool { return strings.Contains(full, part) }, + "subtract": func(a, b int) int { + return a - b + }, "asEntryXpath": translate.AsEntryXpath, } tmpl, err := template.New(templateName).Funcs(funcMap).ParseFiles(templatePath) diff --git a/pkg/naming/names_test.go b/pkg/naming/names_test.go new file mode 100644 index 00000000..e4537915 --- /dev/null +++ b/pkg/naming/names_test.go @@ -0,0 +1,16 @@ +package naming + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestCamelCase(t *testing.T) { + assert.Equal(t, "CamelCase", CamelCase("", "camel_case", "", true)) + assert.Equal(t, "camelCase", CamelCase("", "camel_case", "", false)) +} + +func TestAlphaNumeric(t *testing.T) { + assert.Equal(t, "alphanumeric", AlphaNumeric("alpha_numeric")) + assert.Equal(t, "AlphaNumeric", AlphaNumeric("Alpha_Numeric")) +} diff --git a/pkg/properties/normalized.go b/pkg/properties/normalized.go index c2861620..23290be1 100644 --- a/pkg/properties/normalized.go +++ b/pkg/properties/normalized.go @@ -72,8 +72,10 @@ type Spec struct { } type SpecParam struct { + Name *NameVariant Description string `json:"description" yaml:"description"` Type string `json:"type" yaml:"type"` + Required bool `json:"required" yaml:"required"` Length *SpecParamLength `json:"length" yaml:"length,omitempty"` Count *SpecParamCount `json:"count" yaml:"count,omitempty"` Items *SpecParamItems `json:"items" yaml:"items,omitempty"` @@ -140,12 +142,14 @@ func ParseSpec(input []byte) (*Normalization, error) { err := content.Unmarshal(input, &spec) - err = spec.AddNameVariants() + err = spec.AddNameVariantsForLocation() + err = spec.AddNameVariantsForParams() + err = spec.AddDefaultTypesForParams() return &spec, err } -func (spec *Normalization) AddNameVariants() error { +func (spec *Normalization) AddNameVariantsForLocation() error { for key, location := range spec.Locations { location.Name = &NameVariant{ Underscore: key, @@ -163,6 +167,62 @@ func (spec *Normalization) AddNameVariants() error { return nil } +func AddNameVariantsForParams(name string, param *SpecParam) error { + param.Name = &NameVariant{ + Underscore: name, + CamelCase: naming.CamelCase("", name, "", true), + } + if param.Spec != nil { + for key, childParam := range param.Spec.Params { + if err := AddNameVariantsForParams(key, childParam); err != nil { + return err + } + } + for key, childParam := range param.Spec.OneOf { + if err := AddNameVariantsForParams(key, childParam); err != nil { + return err + } + } + } + return nil +} + +func (spec *Normalization) AddNameVariantsForParams() error { + if spec.Spec != nil { + for key, param := range spec.Spec.Params { + if err := AddNameVariantsForParams(key, param); err != nil { + return err + } + } + for key, param := range spec.Spec.OneOf { + if err := AddNameVariantsForParams(key, param); err != nil { + return err + } + } + } + return nil +} + +func (spec *Normalization) AddDefaultTypesForParams() error { + if spec.Spec != nil { + if spec.Spec.Params != nil { + for _, param := range spec.Spec.Params { + if param.Type == "" { + param.Type = "string" + } + } + } + if spec.Spec.OneOf != nil { + for _, param := range spec.Spec.OneOf { + if param.Type == "" { + param.Type = "string" + } + } + } + } + return nil +} + func (spec *Normalization) Sanity() error { if spec.Name == "" { return errors.New("name is required") diff --git a/pkg/properties/normalized_test.go b/pkg/properties/normalized_test.go index 7d3a8b72..37401379 100644 --- a/pkg/properties/normalized_test.go +++ b/pkg/properties/normalized_test.go @@ -253,8 +253,12 @@ version: 10.1.0 spec: params: description: + name: + underscore: description + camelcase: Description description: The description. type: string + required: false length: min: 0 max: 1023 @@ -263,8 +267,12 @@ spec: - description spec: null tags: + name: + underscore: tags + camelcase: Tags description: The administrative tags. type: list + required: false count: min: null max: 64 @@ -280,8 +288,12 @@ spec: spec: null one_of: fqdn: + name: + underscore: fqdn + camelcase: Fqdn description: The FQDN value. - type: "" + type: string + required: false length: min: 1 max: 255 @@ -291,22 +303,34 @@ spec: - fqdn spec: null ip_netmask: + name: + underscore: ip_netmask + camelcase: IpNetmask description: The IP netmask value. - type: "" + type: string + required: false profiles: - xpath: - ip-netmask spec: null ip_range: + name: + underscore: ip_range + camelcase: IpRange description: The IP range value. - type: "" + type: string + required: false profiles: - xpath: - ip-range spec: null ip_wildcard: + name: + underscore: ip_wildcard + camelcase: IpWildcard description: The IP wildcard value. - type: "" + type: string + required: false profiles: - xpath: - ip-wildcard diff --git a/pkg/translate/structs.go b/pkg/translate/structs.go index 33e21fb4..67c808ba 100644 --- a/pkg/translate/structs.go +++ b/pkg/translate/structs.go @@ -16,6 +16,25 @@ func LocationType(location *properties.Location, pointer bool) string { } } +func SpecParamType(param *properties.SpecParam) string { + prefix := "" + if !param.Required { + prefix = "*" + } + if param.Type == "list" { + prefix = "[]" + } + + calculatedType := "" + if param.Type == "list" && param.Items != nil { + calculatedType = param.Items.Type + } else { + calculatedType = param.Type + } + + return prefix + calculatedType +} + func OmitEmpty(location *properties.Location) string { if location.Vars != nil { return ",omitempty" diff --git a/pkg/translate/structs_test.go b/pkg/translate/structs_test.go index 6bd61b31..13e140d9 100644 --- a/pkg/translate/structs_test.go +++ b/pkg/translate/structs_test.go @@ -67,6 +67,34 @@ func TestLocationType(t *testing.T) { assert.Contains(t, locationTypes, "bool") } +func TestSpecParamType(t *testing.T) { + // given + paramTypeRequiredString := properties.SpecParam{ + Type: "string", + Required: true, + } + itemsForParam := properties.SpecParamItems{ + Type: "string", + } + paramTypeListString := properties.SpecParam{ + Type: "list", + Items: &itemsForParam, + } + paramTypeOptionalString := properties.SpecParam{ + Type: "string", + } + + // when + calculatedTypeRequiredString := SpecParamType(¶mTypeRequiredString) + calculatedTypeListString := SpecParamType(¶mTypeListString) + calculatedTypeOptionalString := SpecParamType(¶mTypeOptionalString) + + // then + assert.Equal(t, "string", calculatedTypeRequiredString) + assert.Equal(t, "[]string", calculatedTypeListString) + assert.Equal(t, "*string", calculatedTypeOptionalString) +} + func TestOmitEmpty(t *testing.T) { // given yamlParsedData, _ := properties.ParseSpec([]byte(sampleSpec)) diff --git a/templates/sdk/entry.tmpl b/templates/sdk/entry.tmpl index 3b3d1518..281aa840 100644 --- a/templates/sdk/entry.tmpl +++ b/templates/sdk/entry.tmpl @@ -1 +1,69 @@ -package {{packageName .GoSdkPath}} \ No newline at end of file +package {{packageName .GoSdkPath}} + +import ( + "encoding/xml" + "fmt" + + "github.com/PaloAltoNetworks/pango/filtering" + "github.com/PaloAltoNetworks/pango/generic" + "github.com/PaloAltoNetworks/pango/util" + "github.com/PaloAltoNetworks/pango/version" +) + +var ( + _ filtering.Fielder = &Entry{} +) + +var ( + Suffix = []string{ + {{- $length := subtract (len .XpathSuffix) 1 }} + {{- range $index, $suffix := .XpathSuffix}}" + {{- $suffix}}"{{- if lt $index $length}},{{- end}} + {{- end}}} +) + +type Entry struct { + {{- if .Entry}} + Name string + {{- end}} + {{- range $_, $param := .Spec.Params}} + {{$param.Name.CamelCase}} {{specParamType $param}} + {{- end}} + {{- range $_, $param := .Spec.OneOf}} + {{$param.Name.CamelCase}} {{specParamType $param}} + {{- end}} + + Misc map[string][]generic.Xml +} + +func (e *Entry) CopyMiscFrom(v *Entry) { + if v == nil || len(v.Misc) == 0 { + return + } + + e.Misc = make(map[string][]generic.Xml) + for key := range v.Misc { + e.Misc[key] = append([]generic.Xml(nil), v.Misc[key]...) + } +} + +func (e *Entry) Field(v string) (any, error) { + {{- if .Entry}} + if v == "name" || v == "Name" { + return e.Name, nil + } + {{- end}} + + {{- range $_, $param := .Spec.Params}} + if v == "{{$param.Name.Underscore}}" || v == "{{$param.Name.CamelCase}}" { + return e.{{$param.Name.CamelCase}}, nil + } + {{- end}} + {{- range $_, $param := .Spec.OneOf}} + if v == "{{$param.Name.Underscore}}" || v == "{{$param.Name.CamelCase}}" { + return e.{{$param.Name.CamelCase}}, nil + } + {{- end}} + + return nil, fmt.Errorf("unknown field") +} \ No newline at end of file