github.com/profzone/eden-framework@v1.0.10/internal/generator/scanner/enum_scanner.go (about) 1 package scanner 2 3 import ( 4 "fmt" 5 "github.com/profzone/eden-framework/pkg/enumeration" 6 "github.com/profzone/eden-framework/pkg/packagex" 7 str "github.com/profzone/eden-framework/pkg/strings" 8 "go/ast" 9 "go/types" 10 "sort" 11 "strconv" 12 "strings" 13 ) 14 15 func NewEnumScanner(pkg *packagex.Package) *EnumScanner { 16 return &EnumScanner{ 17 pkg: pkg, 18 } 19 } 20 21 type EnumScanner struct { 22 pkg *packagex.Package 23 EnumSet map[*types.TypeName][]enumeration.EnumOption 24 } 25 26 func sortEnumOptions(enumOptions []enumeration.EnumOption) []enumeration.EnumOption { 27 sort.Slice(enumOptions, func(i, j int) bool { 28 return enumOptions[i].Val > enumOptions[j].Val 29 }) 30 return enumOptions 31 } 32 33 func (scanner *EnumScanner) Enum(typeName *types.TypeName) []enumeration.EnumOption { 34 if typeName == nil { 35 return nil 36 } 37 38 if enumOptions, ok := scanner.EnumSet[typeName]; ok { 39 return sortEnumOptions(enumOptions) 40 } 41 42 if !strings.Contains(typeName.Type().Underlying().String(), "int") { 43 panic(fmt.Errorf("enumeration type underlying must be an int or uint, but got %s", typeName.String())) 44 } 45 46 pkgInfo := scanner.pkg.Pkg(typeName.Pkg().Path()) 47 if pkgInfo == nil { 48 return nil 49 } 50 51 typeNameString := typeName.Name() 52 53 for ident, def := range pkgInfo.TypesInfo.Defs { 54 typeConst, ok := def.(*types.Const) 55 if !ok { 56 continue 57 } 58 if typeConst.Type() != typeName.Type() { 59 continue 60 } 61 name := typeConst.Name() 62 63 if strings.HasPrefix(name, "_") { 64 continue 65 } 66 67 val := typeConst.Val() 68 label := strings.TrimSpace(ident.Obj.Decl.(*ast.ValueSpec).Comment.Text()) 69 70 if strings.HasPrefix(name, str.ToUpperSnakeCase(typeNameString)) { 71 var values = strings.SplitN(name, "__", 2) 72 if len(values) == 2 { 73 firstChar := values[1][0] 74 if '0' <= firstChar && firstChar <= '9' { 75 panic(fmt.Errorf("not support enum key starts with number, please fix `%s`", name)) 76 } 77 intVal, _ := strconv.ParseInt(val.String(), 10, 64) 78 scanner.addEnum(typeName, int(intVal), values[1], label) 79 } 80 } 81 } 82 83 return sortEnumOptions(scanner.EnumSet[typeName]) 84 } 85 86 func (scanner *EnumScanner) addEnum(typeName *types.TypeName, constValue int, value string, label string) { 87 if scanner.EnumSet == nil { 88 scanner.EnumSet = map[*types.TypeName][]enumeration.EnumOption{} 89 } 90 91 if label == "" { 92 label = value 93 } 94 95 scanner.EnumSet[typeName] = append(scanner.EnumSet[typeName], enumeration.EnumOption{ 96 Val: constValue, 97 Value: value, 98 Label: label, 99 }) 100 } 101 102 func (scanner *EnumScanner) HasOffset(typeName *types.TypeName) bool { 103 pkgInfo := scanner.pkg.PkgInfoOf(typeName) 104 if pkgInfo == nil { 105 return false 106 } 107 for _, def := range pkgInfo.Defs { 108 if typeConst, ok := def.(*types.Const); ok { 109 if typeConst.Name() == str.ToUpperSnakeCase(typeName.Name())+"_OFFSET" { 110 return true 111 } 112 } 113 } 114 return false 115 }