github.com/profzone/eden-framework@v1.0.10/internal/generator/scanner/status_err_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  	"go/ast"
     8  	"go/types"
     9  	"sort"
    10  	"strings"
    11  )
    12  
    13  func NewStatusErrScanner(pkg *packagex.Package) *StatusErrScanner {
    14  	statusErrorScanner := &StatusErrScanner{
    15  		pkg:              pkg,
    16  		statusErrorTypes: map[*types.Named][]*status_error.StatusError{},
    17  		errorsUsed:       map[*types.Func][]*status_error.StatusError{},
    18  	}
    19  
    20  	statusErrorScanner.init()
    21  
    22  	return statusErrorScanner
    23  }
    24  
    25  type StatusErrScanner struct {
    26  	StatusErrType    *types.Named
    27  	pkg              *packagex.Package
    28  	statusErrorTypes map[*types.Named][]*status_error.StatusError
    29  	errorsUsed       map[*types.Func][]*status_error.StatusError
    30  }
    31  
    32  func (scanner *StatusErrScanner) StatusErrorsInFunc(typeFunc *types.Func) []*status_error.StatusError {
    33  	if typeFunc == nil {
    34  		return nil
    35  	}
    36  
    37  	if statusErrList, ok := scanner.errorsUsed[typeFunc]; ok {
    38  		return statusErrList
    39  	}
    40  
    41  	scanner.errorsUsed[typeFunc] = []*status_error.StatusError{}
    42  
    43  	pkg := packagex.NewPackage(scanner.pkg.Pkg(typeFunc.Pkg().Path()))
    44  
    45  	funcDecl := pkg.FuncDeclOf(typeFunc)
    46  
    47  	if funcDecl != nil {
    48  		ast.Inspect(funcDecl, func(node ast.Node) bool {
    49  			switch node.(type) {
    50  			case *ast.CallExpr:
    51  				identList := packagex.GetIdentChainOfCallFunc(node.(*ast.CallExpr).Fun)
    52  				if len(identList) > 0 {
    53  					callIdent := identList[len(identList)-1]
    54  					obj := pkg.TypesInfo.ObjectOf(callIdent)
    55  
    56  					if obj != nil && obj.Pkg() != nil && obj.Pkg().Path() == scanner.StatusErrType.Obj().Pkg().Path() {
    57  						for i := range identList {
    58  							scanner.mayAddStateErrorByObject(typeFunc, pkg.TypesInfo.ObjectOf(identList[i]))
    59  						}
    60  						return false
    61  					}
    62  					if nextTypeFunc, ok := obj.(*types.Func); ok && nextTypeFunc != typeFunc && nextTypeFunc.Pkg() != nil {
    63  						scanner.appendStateErrs(typeFunc, scanner.StatusErrorsInFunc(nextTypeFunc)...)
    64  					}
    65  				}
    66  			case *ast.Ident:
    67  				scanner.mayAddStateErrorByObject(typeFunc, pkg.TypesInfo.ObjectOf(node.(*ast.Ident)))
    68  			}
    69  			return true
    70  		})
    71  
    72  		doc := packagex.StringifyCommentGroup(funcDecl.Doc)
    73  		scanner.appendStateErrs(typeFunc, pickStatusErrorsFromDoc(doc)...)
    74  	}
    75  
    76  	return scanner.errorsUsed[typeFunc]
    77  }
    78  
    79  func (scanner *StatusErrScanner) mayAddStateErrorByObject(typeFunc *types.Func, obj types.Object) {
    80  	if obj == nil {
    81  		return
    82  	}
    83  	if typeConst, ok := obj.(*types.Const); ok {
    84  		if named, ok := typeConst.Type().(*types.Named); ok {
    85  			if errs, ok := scanner.statusErrorTypes[named]; ok {
    86  				for i := range errs {
    87  					if errs[i].Key == typeConst.Name() {
    88  						scanner.appendStateErrs(typeFunc, errs[i])
    89  					}
    90  				}
    91  			}
    92  		}
    93  	}
    94  }
    95  
    96  func (scanner *StatusErrScanner) appendStateErrs(typeFunc *types.Func, statusErrs ...*status_error.StatusError) {
    97  	m := map[string]*status_error.StatusError{}
    98  
    99  	errs := append(scanner.errorsUsed[typeFunc], statusErrs...)
   100  	for i := range errs {
   101  		s := errs[i]
   102  		m[fmt.Sprintf("%s%d", s.Key, s.Code)] = s
   103  	}
   104  
   105  	next := make([]*status_error.StatusError, 0)
   106  	for k := range m {
   107  		next = append(next, m[k])
   108  	}
   109  
   110  	sort.Slice(next, func(i, j int) bool {
   111  		return next[i].Code < next[j].Code
   112  	})
   113  
   114  	scanner.errorsUsed[typeFunc] = next
   115  }
   116  
   117  func (scanner *StatusErrScanner) init() {
   118  	pkg := scanner.pkg.Pkg("github.com/profzone/eden-framework/pkg/courier/status_error")
   119  	if pkg == nil {
   120  		return
   121  	}
   122  
   123  	scanner.StatusErrType = packagex.NewPackage(pkg).TypeName("StatusError").Type().(*types.Named)
   124  	//ttypeStatusError := packagex.NewPackage(pkg).TypeName("StatusError").Type().Underlying().(*types.Interface)
   125  	//
   126  	//isStatusError := func(typ *types.TypeName) bool {
   127  	//	return types.Implements(typ.Type(), ttypeStatusError)
   128  	//}
   129  
   130  	//s := NewStatusErrorScanner(scanner.pkg)
   131  
   132  	for _, pkgInfo := range scanner.pkg.AllPackages {
   133  		for _, obj := range pkgInfo.TypesInfo.Defs {
   134  			if _, ok := obj.(*types.TypeName); ok {
   135  				//if isStatusError(typName) {
   136  				//	scanner.statusErrorTypes[typName.Type().(*types.Named)] = s.StatusError(typName)
   137  				//}
   138  			}
   139  		}
   140  	}
   141  }
   142  
   143  func pickStatusErrorsFromDoc(doc string) []*status_error.StatusError {
   144  	statusErrorList := make([]*status_error.StatusError, 0)
   145  
   146  	lines := strings.Split(doc, "\n")
   147  
   148  	for _, line := range lines {
   149  		if line != "" {
   150  			if statusErr := status_error.ParseString(line); statusErr != nil {
   151  				statusErrorList = append(statusErrorList, statusErr)
   152  			}
   153  		}
   154  	}
   155  
   156  	return statusErrorList
   157  }