| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146 |
- // Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
- //
- // This Source Code Form is subject to the terms of the MIT License.
- // If a copy of the MIT was not distributed with this file,
- // You can obtain one at https://github.com/gogf/gf.
- package genenums
- import (
- "go/constant"
- "go/types"
- "golang.org/x/tools/go/packages"
- "github.com/gogf/gf/v2/encoding/gjson"
- "github.com/gogf/gf/v2/text/gstr"
- "github.com/gogf/gf/v2/util/gconv"
- )
- const pkgLoadMode = 0xffffff
- type EnumsParser struct {
- enums []EnumItem
- parsedPkg map[string]struct{}
- prefixes []string
- }
- type EnumItem struct {
- Name string
- Value string
- Kind constant.Kind // String/Int/Bool/Float/Complex/Unknown
- Type string // Pkg.ID + TypeName
- }
- var standardPackages = make(map[string]struct{})
- func init() {
- stdPackages, err := packages.Load(nil, "std")
- if err != nil {
- panic(err)
- }
- for _, p := range stdPackages {
- standardPackages[p.ID] = struct{}{}
- }
- }
- func NewEnumsParser(prefixes []string) *EnumsParser {
- return &EnumsParser{
- enums: make([]EnumItem, 0),
- parsedPkg: make(map[string]struct{}),
- prefixes: prefixes,
- }
- }
- func (p *EnumsParser) ParsePackages(pkgs []*packages.Package) {
- for _, pkg := range pkgs {
- p.ParsePackage(pkg)
- }
- }
- func (p *EnumsParser) ParsePackage(pkg *packages.Package) {
- // Ignore std packages.
- if _, ok := standardPackages[pkg.ID]; ok {
- return
- }
- // Ignore pared packages.
- if _, ok := p.parsedPkg[pkg.ID]; ok {
- return
- }
- p.parsedPkg[pkg.ID] = struct{}{}
- // Only parse specified prefixes.
- if len(p.prefixes) > 0 {
- var hasPrefix bool
- for _, prefix := range p.prefixes {
- if hasPrefix = gstr.HasPrefix(pkg.ID, prefix); hasPrefix {
- break
- }
- }
- if !hasPrefix {
- return
- }
- }
- var (
- scope = pkg.Types.Scope()
- names = scope.Names()
- )
- for _, name := range names {
- con, ok := scope.Lookup(name).(*types.Const)
- if !ok {
- // Only constants can be enums.
- continue
- }
- if !con.Exported() {
- // Ignore unexported values.
- continue
- }
- var enumType = con.Type().String()
- if !gstr.Contains(enumType, "/") {
- // Ignore std types.
- continue
- }
- var (
- enumName = con.Name()
- enumValue = con.Val().ExactString()
- enumKind = con.Val().Kind()
- )
- if con.Val().Kind() == constant.String {
- enumValue = constant.StringVal(con.Val())
- }
- p.enums = append(p.enums, EnumItem{
- Name: enumName,
- Value: enumValue,
- Type: enumType,
- Kind: enumKind,
- })
- }
- for _, im := range pkg.Imports {
- p.ParsePackage(im)
- }
- }
- func (p *EnumsParser) Export() string {
- var typeEnumMap = make(map[string][]interface{})
- for _, enum := range p.enums {
- if typeEnumMap[enum.Type] == nil {
- typeEnumMap[enum.Type] = make([]interface{}, 0)
- }
- var value interface{}
- switch enum.Kind {
- case constant.Int:
- value = gconv.Int64(enum.Value)
- case constant.String:
- value = enum.Value
- case constant.Float:
- value = gconv.Float64(enum.Value)
- case constant.Bool:
- value = gconv.Bool(enum.Value)
- default:
- value = enum.Value
- }
- typeEnumMap[enum.Type] = append(typeEnumMap[enum.Type], value)
- }
- return gjson.MustEncodeString(typeEnumMap)
- }
|