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  }