github.com/profzone/eden-framework@v1.0.10/internal/generator/scanner/status_error_scanner.go (about) 1 package scanner 2 3 import ( 4 "fmt" 5 "github.com/profzone/eden-framework/pkg/courier/status_error" 6 "github.com/profzone/eden-framework/pkg/packagex" 7 "github.com/profzone/eden-framework/pkg/reflectx" 8 "go/ast" 9 "go/types" 10 "sort" 11 "strconv" 12 "strings" 13 ) 14 15 func NewStatusErrorScanner(pkg *packagex.Package) *StatusErrorScanner { 16 return &StatusErrorScanner{ 17 pkg: pkg, 18 } 19 } 20 21 type StatusErrorScanner struct { 22 pkg *packagex.Package 23 StatusErrors map[*types.TypeName][]*status_error.StatusError 24 } 25 26 func sortedStatusErrList(list []*status_error.StatusError) []*status_error.StatusError { 27 sort.Slice(list, func(i, j int) bool { 28 return list[i].Code < list[j].Code 29 }) 30 return list 31 } 32 33 func (scanner *StatusErrorScanner) StatusError(typeName *types.TypeName) []*status_error.StatusError { 34 if typeName == nil { 35 return nil 36 } 37 38 if statusErrs, ok := scanner.StatusErrors[typeName]; ok { 39 return sortedStatusErrList(statusErrs) 40 } 41 42 if !strings.Contains(typeName.Type().Underlying().String(), "int") { 43 panic(fmt.Errorf("status error 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 var serviceCode int64 = 0 52 53 method, ok := reflectx.FromTType(typeName.Type()).MethodByName("ServiceCode") 54 if ok { 55 results, n := scanner.pkg.FuncResultsOf(method.(*reflectx.TMethod).Func) 56 if n == 1 { 57 ret := results[0][0] 58 if ret.IsValue() { 59 if i, err := strconv.ParseInt(ret.Value.String(), 10, 64); err == nil { 60 serviceCode = i 61 } 62 } 63 } 64 } 65 66 for ident, def := range pkgInfo.TypesInfo.Defs { 67 typeConst, ok := def.(*types.Const) 68 if !ok { 69 continue 70 } 71 if typeConst.Type() != typeName.Type() { 72 continue 73 } 74 75 key := typeConst.Name() 76 code, _ := strconv.ParseInt(typeConst.Val().String(), 10, 64) 77 78 msg, canBeTalkError := ParseStatusErrMsg(ident.Obj.Decl.(*ast.ValueSpec).Doc.Text()) 79 80 scanner.addStatusError(typeName, key, code+serviceCode, msg, canBeTalkError) 81 } 82 83 return sortedStatusErrList(scanner.StatusErrors[typeName]) 84 } 85 86 func ParseStatusErrMsg(s string) (string, bool) { 87 firstLine := strings.Split(strings.TrimSpace(s), "\n")[0] 88 89 prefix := "@errTalk " 90 if strings.HasPrefix(firstLine, prefix) { 91 return firstLine[len(prefix):], true 92 } 93 return firstLine, false 94 } 95 96 func (scanner *StatusErrorScanner) addStatusError( 97 typeName *types.TypeName, 98 key string, code int64, msg string, canBeTalkError bool, 99 ) { 100 if scanner.StatusErrors == nil { 101 scanner.StatusErrors = map[*types.TypeName][]*status_error.StatusError{} 102 } 103 104 statusErr := status_error.NewStatusError(key, code, msg) 105 if canBeTalkError { 106 statusErr = statusErr.WithErrTalk() 107 } 108 scanner.StatusErrors[typeName] = append(scanner.StatusErrors[typeName], statusErr) 109 }