Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,35 @@ which help you to use the various OpenAPI 3 Authentication mechanism.
}
```

- `x-enum-varnames`: supplies other enum names for the corresponding values. (alias: `x-enumNames`)

```yaml
components:
schemas:
Object:
properties:
category:
type: integer
enum: [0, 1, 2]
x-enum-varnames:
- notice
- warning
- urgent
```

After code generation you will get this result:

```go
// Defines values for ObjectCategory.
const (
Notice ObjectCategory = 0
Urgent ObjectCategory = 2
Warning ObjectCategory = 1
)

// ObjectCategory defines model for Object.Category.
type ObjectCategory int
```

## Using `oapi-codegen`

Expand Down
5 changes: 5 additions & 0 deletions pkg/codegen/codegen_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,11 @@ type GetTestByNameResponse struct {
assert.Contains(t, code, "func (c *Client) GetTestByName(ctx context.Context, name string, params *GetTestByNameParams, reqEditors ...RequestEditorFn) (*http.Response, error) {")
assert.Contains(t, code, "func (c *ClientWithResponses) GetTestByNameWithResponse(ctx context.Context, name string, params *GetTestByNameParams, reqEditors ...RequestEditorFn) (*GetTestByNameResponse, error) {")
assert.Contains(t, code, "DeadSince *time.Time `json:\"dead_since,omitempty\" tag1:\"value1\" tag2:\"value2\"`")
assert.Contains(t, code, "type EnumTestNumerics int")
assert.Contains(t, code, "N2 EnumTestNumerics = 2")
assert.Contains(t, code, "type EnumTestEnumNames int")
assert.Contains(t, code, "Two EnumTestEnumNames = 2")
assert.Contains(t, code, "Double EnumTestEnumVarnames = 2")

// Make sure the generated code is valid:
checkLint(t, "test.gen.go", []byte(code))
Expand Down
14 changes: 14 additions & 0 deletions pkg/codegen/extension.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ const (
extPropGoJsonIgnore = "x-go-json-ignore"
extPropOmitEmpty = "x-omitempty"
extPropExtraTags = "x-oapi-codegen-extra-tags"
extEnumVarNames = "x-enum-varnames"
extEnumNames = "x-enumNames"
)

func extString(extPropValue interface{}) (string, error) {
Expand Down Expand Up @@ -78,3 +80,15 @@ func extParseGoJsonIgnore(extPropValue interface{}) (bool, error) {

return goJsonIgnore, nil
}

func extParseEnumVarNames(extPropValue interface{}) ([]string, error) {
raw, ok := extPropValue.(json.RawMessage)
if !ok {
return nil, fmt.Errorf("failed to convert type: %T", extPropValue)
}
var names []string
if err := json.Unmarshal(raw, &names); err != nil {
return nil, fmt.Errorf("failed to unmarshal json: %w", err)
}
return names, nil
}
12 changes: 11 additions & 1 deletion pkg/codegen/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,17 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) {
enumValues[i] = fmt.Sprintf("%v", enumValue)
}

sanitizedValues := SanitizeEnumNames(enumValues)
enumNames := enumValues
for _, key := range []string{extEnumVarNames, extEnumNames} {
if _, ok := schema.ExtensionProps.Extensions[key]; ok {
if extEnumNames, err := extParseEnumVarNames(schema.ExtensionProps.Extensions[key]); err == nil {
enumNames = extEnumNames
break
}
}
}

sanitizedValues := SanitizeEnumNames(enumNames, enumValues)
outSchema.EnumValues = make(map[string]string, len(sanitizedValues))

for k, v := range sanitizedValues {
Expand Down
41 changes: 41 additions & 0 deletions pkg/codegen/test_spec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,27 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/Error'
/enum:
get:
tags:
- enum
summary: References enum
operationId: getEnum
responses:
200:
description: Success
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/EnumTest'
default:
description: Error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'

components:
schemas:
Expand Down Expand Up @@ -136,3 +157,23 @@ components:
cause:
type: string
enum: [ car, dog, oldage ]

EnumTest:
properties:
numerics:
type: integer
enum: [0, 1, 2]
enumNames:
type: integer
enum: [0, 1, 2]
x-enumNames:
- zero
- one
- two
enumVarnames:
type: integer
enum: [0, 1, 2]
x-enum-varnames:
- na
- single
- double
23 changes: 14 additions & 9 deletions pkg/codegen/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -554,27 +554,32 @@ func SanitizeGoIdentity(str string) string {

// SanitizeEnumNames fixes illegal chars in the enum names
// and removes duplicates
func SanitizeEnumNames(enumNames []string) map[string]string {
dupCheck := make(map[string]int, len(enumNames))
deDup := make([]string, 0, len(enumNames))

for _, n := range enumNames {
func SanitizeEnumNames(enumNames, enumValues []string) map[string]string {
dupCheck := make(map[string]int, len(enumValues))
deDup := make([][]string, 0, len(enumValues))

for i, v := range enumValues {
n := v
if i < len(enumNames) {
n = enumNames[i]
}
if _, dup := dupCheck[n]; !dup {
deDup = append(deDup, n)
deDup = append(deDup, []string{n, v})
}
dupCheck[n] = 0
}

dupCheck = make(map[string]int, len(deDup))
sanitizedDeDup := make(map[string]string, len(deDup))

for _, n := range deDup {
for _, p := range deDup {
n, v := p[0], p[1]
sanitized := SanitizeGoIdentity(SchemaNameToTypeName(n))

if _, dup := dupCheck[sanitized]; !dup {
sanitizedDeDup[sanitized] = n
sanitizedDeDup[sanitized] = v
} else {
sanitizedDeDup[sanitized+strconv.Itoa(dupCheck[sanitized])] = n
sanitizedDeDup[sanitized+strconv.Itoa(dupCheck[sanitized])] = v
}
dupCheck[sanitized]++
}
Expand Down