@@ -32,9 +32,7 @@ import (
3232 "sigs.k8s.io/kube-api-linter/pkg/markers"
3333)
3434
35- const (
36- name = "enums"
37- )
35+ const name = "enums"
3836
3937type analyzer struct {
4038 config * Config
@@ -76,6 +74,7 @@ func (a *analyzer) checkField(pass *analysis.Pass, field *ast.Field, markersAcce
7674 if fieldName == "" {
7775 return
7876 }
77+
7978 // Get the underlying type, unwrapping pointers and arrays
8079 fieldType , isArray := unwrapTypeWithArrayTracking (field .Type )
8180
@@ -87,23 +86,17 @@ func (a *analyzer) checkField(pass *analysis.Pass, field *ast.Field, markersAcce
8786
8887 prefix := buildFieldPrefix (fieldName , isArray )
8988
89+ // Check if it's a plain string (basic type) vs. a type alias
9090 if ident .Name == "string" && utils .IsBasicType (pass , ident ) {
9191 a .checkPlainStringField (pass , field , markersAccess , prefix )
9292
9393 return
9494 }
9595
96+ // Check if it's a type alias that might be an enum
9697 a .checkTypeAliasField (pass , field , ident , markersAccess , prefix )
9798}
9899
99- func buildFieldPrefix (fieldName string , isArray bool ) string {
100- if isArray {
101- return fmt .Sprintf ("field %s array element" , fieldName )
102- }
103-
104- return fmt .Sprintf ("field %s" , fieldName )
105- }
106-
107100func (a * analyzer ) checkPlainStringField (pass * analysis.Pass , field * ast.Field , markersAccess markershelper.Markers , prefix string ) {
108101 if ! hasEnumMarker (markersAccess .FieldMarkers (field )) {
109102 pass .Reportf (field .Pos (),
@@ -216,6 +209,25 @@ func (a *analyzer) getEnumTypeSpec(pass *analysis.Pass, name *ast.Ident) *ast.Ty
216209 return typeSpec
217210}
218211
212+ func (a * analyzer ) isInAllowlist (value string ) bool {
213+ if a .config == nil {
214+ return false
215+ }
216+
217+ return slices .Contains (a .config .Allowlist , value )
218+ }
219+
220+ // Helper functions below this line.
221+
222+ // buildFieldPrefix constructs a human-readable prefix for error messages.
223+ func buildFieldPrefix (fieldName string , isArray bool ) string {
224+ if isArray {
225+ return fmt .Sprintf ("field %s array element" , fieldName )
226+ }
227+
228+ return fmt .Sprintf ("field %s" , fieldName )
229+ }
230+
219231// unwrapType removes pointer and array wrappers to get the underlying type.
220232func unwrapType (expr ast.Expr ) ast.Expr {
221233 switch t := expr .(type ) {
@@ -246,6 +258,7 @@ func unwrapTypeWithArrayTracking(expr ast.Expr) (ast.Expr, bool) {
246258 }
247259}
248260
261+ // isStringTypeAlias checks if a type spec is a string type alias.
249262func isStringTypeAlias (pass * analysis.Pass , typeSpec * ast.TypeSpec ) bool {
250263 underlyingType := unwrapType (typeSpec .Type )
251264
@@ -258,10 +271,12 @@ func isStringTypeAlias(pass *analysis.Pass, typeSpec *ast.TypeSpec) bool {
258271 return ident .Name == "string" && utils .IsBasicType (pass , ident )
259272}
260273
274+ // hasEnumMarker checks if a marker set contains enum markers.
261275func hasEnumMarker (markerSet markershelper.MarkerSet ) bool {
262276 return markerSet .Has (markers .KubebuilderEnumMarker ) || markerSet .Has (markers .K8sEnumMarker )
263277}
264278
279+ // hasEnumMarkerOnTypeSpec checks if a type spec has enum markers in its documentation.
265280func hasEnumMarkerOnTypeSpec (pass * analysis.Pass , typeSpec * ast.TypeSpec ) bool {
266281 for _ , file := range pass .Files {
267282 if genDecl := findGenDeclForSpec (file , typeSpec ); genDecl != nil {
@@ -272,6 +287,7 @@ func hasEnumMarkerOnTypeSpec(pass *analysis.Pass, typeSpec *ast.TypeSpec) bool {
272287 return false
273288}
274289
290+ // findGenDeclForSpec finds the GenDecl that contains a given TypeSpec.
275291func findGenDeclForSpec (file * ast.File , typeSpec * ast.TypeSpec ) * ast.GenDecl {
276292 for _ , decl := range file .Decls {
277293 genDecl , ok := decl .(* ast.GenDecl )
@@ -289,6 +305,7 @@ func findGenDeclForSpec(file *ast.File, typeSpec *ast.TypeSpec) *ast.GenDecl {
289305 return nil
290306}
291307
308+ // hasEnumMarkerInDoc checks if a comment group contains enum markers.
292309func hasEnumMarkerInDoc (doc * ast.CommentGroup ) bool {
293310 if doc == nil {
294311 return false
@@ -304,15 +321,7 @@ func hasEnumMarkerInDoc(doc *ast.CommentGroup) bool {
304321 return false
305322}
306323
307- // isInAllowlist checks if a value is in the configured allowlist.
308- func (a * analyzer ) isInAllowlist (value string ) bool {
309- if a .config == nil {
310- return false
311- }
312-
313- return slices .Contains (a .config .Allowlist , value )
314- }
315-
324+ // findTypeSpecByName finds a type spec by its name in the pass's files.
316325func findTypeSpecByName (pass * analysis.Pass , typeName string ) * ast.TypeSpec {
317326 for _ , file := range pass .Files {
318327 for _ , decl := range file .Decls {
@@ -337,6 +346,7 @@ func findTypeSpecByName(pass *analysis.Pass, typeName string) *ast.TypeSpec {
337346 return nil
338347}
339348
349+ // isPascalCase checks if a string follows PascalCase naming convention.
340350func isPascalCase (s string ) bool {
341351 if len (s ) == 0 {
342352 return false
0 commit comments