From 2615c6ef718487464dd337dd1339c8b9880de2c4 Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Mon, 16 Feb 2026 21:38:38 -0800 Subject: [PATCH 1/2] feat: add Valid() method to generated enum types Generate a Valid() bool method on each enum type that returns true when the receiver matches one of the defined enum constants and false otherwise. This lets callers validate enum values at runtime with a simple method call instead of hand-writing switch statements. This is default-on because it only adds a new method to an already generated type -- existing code that does not call Valid() is completely unaffected, so this should be very unlikely to break anything. Co-Authored-By: Claude Opus 4.6 --- internal/test/components/components.gen.go | 162 ++++++++++++++++++ .../externalref/petstore/externalref.gen.go | 42 +++++ .../test/issues/issue-1189/issue1189.gen.go | 36 ++++ .../test/issues/issue-1397/issue1397.gen.go | 12 ++ internal/test/issues/issue-832/issue.gen.go | 16 ++ .../issue-illegal_enum_names/issue.gen.go | 28 +++ internal/test/parameters/parameters.gen.go | 12 ++ internal/test/schemas/schemas.gen.go | 12 ++ internal/test/server/server.gen.go | 12 ++ pkg/codegen/schema.go | 12 ++ pkg/codegen/templates/constants.tmpl | 10 ++ 11 files changed, 354 insertions(+) diff --git a/internal/test/components/components.gen.go b/internal/test/components/components.gen.go index 95257707b1..0bfc1747e6 100644 --- a/internal/test/components/components.gen.go +++ b/internal/test/components/components.gen.go @@ -18,6 +18,20 @@ const ( Enum1Two Enum1 = "Two" ) +// Valid indicates whether the value is a known member of the Enum1 enum. +func (e Enum1) Valid() bool { + switch e { + case Enum1One: + return true + case Enum1Three: + return true + case Enum1Two: + return true + default: + return false + } +} + // Defines values for Enum2. const ( Enum2Four Enum2 = "Four" @@ -25,6 +39,20 @@ const ( Enum2Two Enum2 = "Two" ) +// Valid indicates whether the value is a known member of the Enum2 enum. +func (e Enum2) Valid() bool { + switch e { + case Enum2Four: + return true + case Enum2Three: + return true + case Enum2Two: + return true + default: + return false + } +} + // Defines values for Enum3. const ( Enum3Bar Enum3 = "Bar" @@ -32,6 +60,20 @@ const ( Enum3Foo Enum3 = "Foo" ) +// Valid indicates whether the value is a known member of the Enum3 enum. +func (e Enum3) Valid() bool { + switch e { + case Enum3Bar: + return true + case Enum3Enum1One: + return true + case Enum3Foo: + return true + default: + return false + } +} + // Defines values for Enum4. const ( Cat Enum4 = "Cat" @@ -39,6 +81,20 @@ const ( Mouse Enum4 = "Mouse" ) +// Valid indicates whether the value is a known member of the Enum4 enum. +func (e Enum4) Valid() bool { + switch e { + case Cat: + return true + case Dog: + return true + case Mouse: + return true + default: + return false + } +} + // Defines values for Enum5. const ( Enum5N5 Enum5 = 5 @@ -46,6 +102,20 @@ const ( Enum5N7 Enum5 = 7 ) +// Valid indicates whether the value is a known member of the Enum5 enum. +func (e Enum5) Valid() bool { + switch e { + case Enum5N5: + return true + case Enum5N6: + return true + case Enum5N7: + return true + default: + return false + } +} + // Defines values for EnumUnion. const ( EnumUnionFour EnumUnion = "Four" @@ -54,6 +124,22 @@ const ( EnumUnionTwo EnumUnion = "Two" ) +// Valid indicates whether the value is a known member of the EnumUnion enum. +func (e EnumUnion) Valid() bool { + switch e { + case EnumUnionFour: + return true + case EnumUnionOne: + return true + case EnumUnionThree: + return true + case EnumUnionTwo: + return true + default: + return false + } +} + // Defines values for EnumUnion2. const ( EnumUnion2One EnumUnion2 = "One" @@ -62,6 +148,22 @@ const ( EnumUnion2Two EnumUnion2 = "Two" ) +// Valid indicates whether the value is a known member of the EnumUnion2 enum. +func (e EnumUnion2) Valid() bool { + switch e { + case EnumUnion2One: + return true + case EnumUnion2Seven: + return true + case EnumUnion2Three: + return true + case EnumUnion2Two: + return true + default: + return false + } +} + // Defines values for FunnyValues. const ( FunnyValuesAnd FunnyValues = "&" @@ -71,6 +173,24 @@ const ( FunnyValuesPercent FunnyValues = "%" ) +// Valid indicates whether the value is a known member of the FunnyValues enum. +func (e FunnyValues) Valid() bool { + switch e { + case FunnyValuesAnd: + return true + case FunnyValuesAsterisk: + return true + case FunnyValuesEmpty: + return true + case FunnyValuesN5: + return true + case FunnyValuesPercent: + return true + default: + return false + } +} + // Defines values for EnumParam1. const ( EnumParam1Both EnumParam1 = "both" @@ -78,6 +198,20 @@ const ( EnumParam1On EnumParam1 = "on" ) +// Valid indicates whether the value is a known member of the EnumParam1 enum. +func (e EnumParam1) Valid() bool { + switch e { + case EnumParam1Both: + return true + case EnumParam1Off: + return true + case EnumParam1On: + return true + default: + return false + } +} + // Defines values for EnumParam2. const ( EnumParam2Both EnumParam2 = "both" @@ -85,6 +219,20 @@ const ( EnumParam2On EnumParam2 = "on" ) +// Valid indicates whether the value is a known member of the EnumParam2 enum. +func (e EnumParam2) Valid() bool { + switch e { + case EnumParam2Both: + return true + case EnumParam2Off: + return true + case EnumParam2On: + return true + default: + return false + } +} + // Defines values for EnumParam3. const ( Alice EnumParam3 = "alice" @@ -92,6 +240,20 @@ const ( Eve EnumParam3 = "eve" ) +// Valid indicates whether the value is a known member of the EnumParam3 enum. +func (e EnumParam3) Valid() bool { + switch e { + case Alice: + return true + case Bob: + return true + case Eve: + return true + default: + return false + } +} + // AdditionalPropertiesObject1 Has additional properties of type int type AdditionalPropertiesObject1 struct { Id int `json:"id"` diff --git a/internal/test/externalref/petstore/externalref.gen.go b/internal/test/externalref/petstore/externalref.gen.go index 33852217e1..e8102f0d28 100644 --- a/internal/test/externalref/petstore/externalref.gen.go +++ b/internal/test/externalref/petstore/externalref.gen.go @@ -29,6 +29,20 @@ const ( Placed OrderStatus = "placed" ) +// Valid indicates whether the value is a known member of the OrderStatus enum. +func (e OrderStatus) Valid() bool { + switch e { + case Approved: + return true + case Delivered: + return true + case Placed: + return true + default: + return false + } +} + // Defines values for PetStatus. const ( PetStatusAvailable PetStatus = "available" @@ -36,6 +50,20 @@ const ( PetStatusSold PetStatus = "sold" ) +// Valid indicates whether the value is a known member of the PetStatus enum. +func (e PetStatus) Valid() bool { + switch e { + case PetStatusAvailable: + return true + case PetStatusPending: + return true + case PetStatusSold: + return true + default: + return false + } +} + // Defines values for FindPetsByStatusParamsStatus. const ( FindPetsByStatusParamsStatusAvailable FindPetsByStatusParamsStatus = "available" @@ -43,6 +71,20 @@ const ( FindPetsByStatusParamsStatusSold FindPetsByStatusParamsStatus = "sold" ) +// Valid indicates whether the value is a known member of the FindPetsByStatusParamsStatus enum. +func (e FindPetsByStatusParamsStatus) Valid() bool { + switch e { + case FindPetsByStatusParamsStatusAvailable: + return true + case FindPetsByStatusParamsStatusPending: + return true + case FindPetsByStatusParamsStatusSold: + return true + default: + return false + } +} + // Address defines model for Address. type Address struct { City *string `json:"city,omitempty"` diff --git a/internal/test/issues/issue-1189/issue1189.gen.go b/internal/test/issues/issue-1189/issue1189.gen.go index c1a869ad98..c6e0579fd5 100644 --- a/internal/test/issues/issue-1189/issue1189.gen.go +++ b/internal/test/issues/issue-1189/issue1189.gen.go @@ -27,18 +27,54 @@ const ( TestFieldA1Foo TestFieldA1 = "foo" ) +// Valid indicates whether the value is a known member of the TestFieldA1 enum. +func (e TestFieldA1) Valid() bool { + switch e { + case TestFieldA1Bar: + return true + case TestFieldA1Foo: + return true + default: + return false + } +} + // Defines values for TestFieldB. const ( TestFieldBBar TestFieldB = "bar" TestFieldBFoo TestFieldB = "foo" ) +// Valid indicates whether the value is a known member of the TestFieldB enum. +func (e TestFieldB) Valid() bool { + switch e { + case TestFieldBBar: + return true + case TestFieldBFoo: + return true + default: + return false + } +} + // Defines values for TestFieldC1. const ( Bar TestFieldC1 = "bar" Foo TestFieldC1 = "foo" ) +// Valid indicates whether the value is a known member of the TestFieldC1 enum. +func (e TestFieldC1) Valid() bool { + switch e { + case Bar: + return true + case Foo: + return true + default: + return false + } +} + // Test defines model for test. type Test struct { FieldA *Test_FieldA `json:"fieldA,omitempty"` diff --git a/internal/test/issues/issue-1397/issue1397.gen.go b/internal/test/issues/issue-1397/issue1397.gen.go index 2463641eb1..11bc883db2 100644 --- a/internal/test/issues/issue-1397/issue1397.gen.go +++ b/internal/test/issues/issue-1397/issue1397.gen.go @@ -26,6 +26,18 @@ const ( Option2 TestField1 = "option2" ) +// Valid indicates whether the value is a known member of the TestField1 enum. +func (e TestField1) Valid() bool { + switch e { + case Option1: + return true + case Option2: + return true + default: + return false + } +} + // Test defines model for Test. type Test = MyTestRequest diff --git a/internal/test/issues/issue-832/issue.gen.go b/internal/test/issues/issue-832/issue.gen.go index 0aa74f232e..4a5aa56a3d 100644 --- a/internal/test/issues/issue-832/issue.gen.go +++ b/internal/test/issues/issue-832/issue.gen.go @@ -23,6 +23,22 @@ const ( Two Document_Status = "two" ) +// Valid indicates whether the value is a known member of the Document_Status enum. +func (e Document_Status) Valid() bool { + switch e { + case Four: + return true + case One: + return true + case Three: + return true + case Two: + return true + default: + return false + } +} + // Document defines model for Document. type Document struct { Name *string `json:"name,omitempty"` diff --git a/internal/test/issues/issue-illegal_enum_names/issue.gen.go b/internal/test/issues/issue-illegal_enum_names/issue.gen.go index 8f907486cf..0c29ab71eb 100644 --- a/internal/test/issues/issue-illegal_enum_names/issue.gen.go +++ b/internal/test/issues/issue-illegal_enum_names/issue.gen.go @@ -34,6 +34,34 @@ const ( BarUnderscoreFoo Bar = "_Foo_" ) +// Valid indicates whether the value is a known member of the Bar enum. +func (e Bar) Valid() bool { + switch e { + case BarBar: + return true + case BarEmpty: + return true + case BarFoo: + return true + case BarFoo1: + return true + case BarFoo2: + return true + case BarFooBar: + return true + case BarFooBar1: + return true + case BarN1: + return true + case BarN1Foo: + return true + case BarUnderscoreFoo: + return true + default: + return false + } +} + // Bar defines model for Bar. type Bar string diff --git a/internal/test/parameters/parameters.gen.go b/internal/test/parameters/parameters.gen.go index 630770731a..47c98a774e 100644 --- a/internal/test/parameters/parameters.gen.go +++ b/internal/test/parameters/parameters.gen.go @@ -27,6 +27,18 @@ const ( N200 EnumParamsParamsEnumPathParam = 200 ) +// Valid indicates whether the value is a known member of the EnumParamsParamsEnumPathParam enum. +func (e EnumParamsParamsEnumPathParam) Valid() bool { + switch e { + case N100: + return true + case N200: + return true + default: + return false + } +} + // ComplexObject defines model for ComplexObject. type ComplexObject struct { Id int `json:"Id"` diff --git a/internal/test/schemas/schemas.gen.go b/internal/test/schemas/schemas.gen.go index 1a7f9e61b7..c46358f7f6 100644 --- a/internal/test/schemas/schemas.gen.go +++ b/internal/test/schemas/schemas.gen.go @@ -34,6 +34,18 @@ const ( Second EnumInObjInArrayVal = "second" ) +// Valid indicates whether the value is a known member of the EnumInObjInArrayVal enum. +func (e EnumInObjInArrayVal) Valid() bool { + switch e { + case First: + return true + case Second: + return true + default: + return false + } +} + // N5StartsWithNumber This schema name starts with a number type N5StartsWithNumber = map[string]interface{} diff --git a/internal/test/server/server.gen.go b/internal/test/server/server.gen.go index e360916b3a..b2468c75b4 100644 --- a/internal/test/server/server.gen.go +++ b/internal/test/server/server.gen.go @@ -19,6 +19,18 @@ const ( Text GetWithContentTypeParamsContentType = "text" ) +// Valid indicates whether the value is a known member of the GetWithContentTypeParamsContentType enum. +func (e GetWithContentTypeParamsContentType) Valid() bool { + switch e { + case Json: + return true + case Text: + return true + default: + return false + } +} + // EveryTypeOptional defines model for EveryTypeOptional. type EveryTypeOptional struct { ArrayInlineField *[]int `json:"array_inline_field,omitempty"` diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go index 25f34de38a..1d16810316 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -3,6 +3,7 @@ package codegen import ( "errors" "fmt" + "sort" "strings" "github.com/getkin/kin-openapi/openapi3" @@ -197,6 +198,17 @@ func (e *EnumDefinition) GetValues() map[string]string { return newValues } +// GetValueNames returns a sorted list of constant names for this enum. +func (e *EnumDefinition) GetValueNames() []string { + values := e.GetValues() + names := make([]string, 0, len(values)) + for k := range values { + names = append(names, k) + } + sort.Strings(names) + return names +} + type Constants struct { // SecuritySchemeProviderNames holds all provider names for security schemes. SecuritySchemeProviderNames []string diff --git a/pkg/codegen/templates/constants.tmpl b/pkg/codegen/templates/constants.tmpl index 8fad8764c4..e21c21fd38 100644 --- a/pkg/codegen/templates/constants.tmpl +++ b/pkg/codegen/templates/constants.tmpl @@ -12,4 +12,14 @@ const ( {{$name}} {{$Enum.TypeName}} = {{$Enum.ValueWrapper}}{{$value}}{{$Enum.ValueWrapper -}} {{end}} ) + +// Valid indicates whether the value is a known member of the {{$Enum.TypeName}} enum. +func (e {{$Enum.TypeName}}) Valid() bool { + switch e { + {{range $Enum.GetValueNames}}case {{.}}: + return true + {{end}}default: + return false + } +} {{end}} From d74f61ef03dc1f0c3becaa9623ba95cf8b11cce7 Mon Sep 17 00:00:00 2001 From: Marcin Romaszewicz Date: Tue, 17 Feb 2026 07:03:06 -0800 Subject: [PATCH 2/2] Reduce complexity in enum validation It turns out we don't need a sorted map of names, since we have the same thing already present on the template context in a different way. Co-Authored-By: Claude Opus 4.6 --- pkg/codegen/schema.go | 12 ------------ pkg/codegen/templates/constants.tmpl | 2 +- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go index 1d16810316..25f34de38a 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -3,7 +3,6 @@ package codegen import ( "errors" "fmt" - "sort" "strings" "github.com/getkin/kin-openapi/openapi3" @@ -198,17 +197,6 @@ func (e *EnumDefinition) GetValues() map[string]string { return newValues } -// GetValueNames returns a sorted list of constant names for this enum. -func (e *EnumDefinition) GetValueNames() []string { - values := e.GetValues() - names := make([]string, 0, len(values)) - for k := range values { - names = append(names, k) - } - sort.Strings(names) - return names -} - type Constants struct { // SecuritySchemeProviderNames holds all provider names for security schemes. SecuritySchemeProviderNames []string diff --git a/pkg/codegen/templates/constants.tmpl b/pkg/codegen/templates/constants.tmpl index e21c21fd38..1c8cbd4922 100644 --- a/pkg/codegen/templates/constants.tmpl +++ b/pkg/codegen/templates/constants.tmpl @@ -16,7 +16,7 @@ const ( // Valid indicates whether the value is a known member of the {{$Enum.TypeName}} enum. func (e {{$Enum.TypeName}}) Valid() bool { switch e { - {{range $Enum.GetValueNames}}case {{.}}: + {{range $name, $value := $Enum.GetValues}}case {{$name}}: return true {{end}}default: return false