github.com/profzone/eden-framework@v1.0.10/internal/generator/scanner/router_scanner.go (about) 1 package scanner 2 3 import ( 4 "bytes" 5 "github.com/julienschmidt/httprouter" 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 type RouterScanner struct { 16 pkg *packagex.Package 17 routers map[*types.Var]*Router 18 operatorScanner *OperatorScanner 19 } 20 21 func NewRouterScanner(pkg *packagex.Package) *RouterScanner { 22 routerScanner := &RouterScanner{ 23 pkg: pkg, 24 routers: make(map[*types.Var]*Router), 25 operatorScanner: NewOperatorScanner(pkg), 26 } 27 28 routerScanner.init() 29 return routerScanner 30 } 31 32 func (scanner *RouterScanner) OperatorScanner() *OperatorScanner { 33 return scanner.operatorScanner 34 } 35 36 func (scanner *RouterScanner) init() { 37 for _, pkg := range scanner.pkg.AllPackages { 38 for ident, obj := range pkg.TypesInfo.Defs { 39 if typeVar, ok := obj.(*types.Var); ok { 40 if typeVar != nil && !strings.HasSuffix(typeVar.Pkg().Path(), pkgImportPathCourier) { 41 if isRouterType(typeVar.Type()) { 42 router := NewRouter(typeVar) 43 44 ast.Inspect(ident.Obj.Decl.(ast.Node), func(node ast.Node) bool { 45 switch node.(type) { 46 case *ast.CallExpr: 47 callExpr := node.(*ast.CallExpr) 48 router.AppendOperators(scanner.OperatorTypeNamesFromArgs(packagex.NewPackage(pkg), callExpr.Args...)...) 49 return false 50 } 51 return true 52 }) 53 54 scanner.routers[typeVar] = router 55 } 56 } 57 } 58 } 59 } 60 61 for _, pkg := range scanner.pkg.AllPackages { 62 for selectExpr, selection := range pkg.TypesInfo.Selections { 63 if selection.Obj() != nil { 64 if typeFunc, ok := selection.Obj().(*types.Func); ok { 65 recv := typeFunc.Type().(*types.Signature).Recv() 66 if recv != nil && isRouterType(recv.Type()) { 67 for typeVar, router := range scanner.routers { 68 switch selectExpr.Sel.Name { 69 case "Register": 70 if typeVar == pkg.TypesInfo.ObjectOf(packagex.GetIdentChainOfCallFunc(selectExpr)[0]) { 71 file := scanner.pkg.FileOf(selectExpr) 72 ast.Inspect(file, func(node ast.Node) bool { 73 switch node.(type) { 74 case *ast.CallExpr: 75 callExpr := node.(*ast.CallExpr) 76 if callExpr.Fun == selectExpr { 77 routerIdent := callExpr.Args[0] 78 switch routerIdent.(type) { 79 case *ast.Ident: 80 argTypeVar := pkg.TypesInfo.ObjectOf(routerIdent.(*ast.Ident)).(*types.Var) 81 if r, ok := scanner.routers[argTypeVar]; ok { 82 router.Register(r) 83 } 84 case *ast.SelectorExpr: 85 argTypeVar := pkg.TypesInfo.ObjectOf(routerIdent.(*ast.SelectorExpr).Sel).(*types.Var) 86 if r, ok := scanner.routers[argTypeVar]; ok { 87 router.Register(r) 88 } 89 case *ast.CallExpr: 90 callExprForRegister := routerIdent.(*ast.CallExpr) 91 router.With(scanner.OperatorTypeNamesFromArgs(packagex.NewPackage(pkg), callExprForRegister.Args...)...) 92 } 93 return false 94 } 95 } 96 return true 97 }) 98 } 99 } 100 } 101 } 102 } 103 } 104 } 105 } 106 } 107 108 func (scanner *RouterScanner) Router(typeName *types.Var) *Router { 109 return scanner.routers[typeName] 110 } 111 112 func (scanner *RouterScanner) OperatorTypeNamesFromArgs(pkg *packagex.Package, args ...ast.Expr) []*OperatorWithTypeName { 113 opTypeNames := make([]*OperatorWithTypeName, 0) 114 115 for _, arg := range args { 116 opTypeName := scanner.OperatorTypeNameFromType(pkg.TypesInfo.TypeOf(arg)) 117 118 if opTypeName == nil { 119 continue 120 } 121 122 if callExpr, ok := arg.(*ast.CallExpr); ok { 123 if selectorExpr, ok := callExpr.Fun.(*ast.SelectorExpr); ok { 124 if isFromHttpTransport(pkg.TypesInfo.ObjectOf(selectorExpr.Sel).Type()) { 125 switch selectorExpr.Sel.Name { 126 case "BasePath": 127 switch v := callExpr.Args[0].(type) { 128 case *ast.BasicLit: 129 opTypeName.BasePath, _ = strconv.Unquote(v.Value) 130 } 131 case "Group": 132 switch v := callExpr.Args[0].(type) { 133 case *ast.BasicLit: 134 opTypeName.Path, _ = strconv.Unquote(v.Value) 135 } 136 } 137 } 138 } 139 } 140 141 if opTypeName.TypeName != nil { 142 // handle interface WithMiddleOperators 143 method, ok := reflectx.FromTType(opTypeName.TypeName.Type()).MethodByName("MiddleOperators") 144 if ok { 145 results, n := scanner.pkg.FuncResultsOf(method.(*reflectx.TMethod).Func) 146 if n == 1 { 147 for _, v := range results[0] { 148 if compositeLit, ok := v.Expr.(*ast.CompositeLit); ok { 149 ops := scanner.OperatorTypeNamesFromArgs(pkg, compositeLit.Elts...) 150 opTypeNames = append(opTypeNames, ops...) 151 } 152 153 } 154 } 155 } 156 } 157 158 opTypeNames = append(opTypeNames, opTypeName) 159 } 160 161 return opTypeNames 162 } 163 164 func (scanner *RouterScanner) OperatorTypeNameFromType(typ types.Type) *OperatorWithTypeName { 165 switch t := typ.(type) { 166 case *types.Pointer: 167 return scanner.OperatorTypeNameFromType(t.Elem()) 168 case *types.Named: 169 typeName := t.Obj() 170 171 if operator := scanner.operatorScanner.Operator(typeName); operator != nil { 172 return &OperatorWithTypeName{ 173 Operator: operator, 174 TypeName: typeName, 175 } 176 } 177 178 return nil 179 default: 180 return nil 181 } 182 } 183 184 type Router struct { 185 typeVar *types.Var 186 parent *Router 187 operators []*OperatorWithTypeName 188 children map[*Router]bool 189 } 190 191 func NewRouter(typeVar *types.Var, operators ...*OperatorWithTypeName) *Router { 192 return &Router{ 193 typeVar: typeVar, 194 operators: operators, 195 } 196 } 197 198 func (router *Router) Name() string { 199 if router.typeVar == nil { 200 return "Anonymous" 201 } 202 return router.typeVar.Pkg().Name() + "." + router.typeVar.Name() 203 } 204 205 func (router *Router) String() string { 206 buf := bytes.NewBufferString(router.Name()) 207 208 buf.WriteString("<") 209 for i := range router.operators { 210 o := router.operators[i] 211 if i != 0 { 212 buf.WriteByte(',') 213 } 214 buf.WriteString(o.String()) 215 } 216 buf.WriteString(">") 217 218 buf.WriteString("[") 219 220 i := 0 221 for sub := range router.children { 222 if i != 0 { 223 buf.WriteByte(',') 224 } 225 buf.WriteString(sub.Name()) 226 i++ 227 } 228 buf.WriteString("]") 229 230 return buf.String() 231 } 232 233 func (router *Router) AppendOperators(operators ...*OperatorWithTypeName) { 234 router.operators = append(router.operators, operators...) 235 } 236 237 func (router *Router) With(operators ...*OperatorWithTypeName) { 238 router.Register(NewRouter(nil, operators...)) 239 } 240 241 func (router *Router) Register(r *Router) { 242 if router.children == nil { 243 router.children = map[*Router]bool{} 244 } 245 r.parent = router 246 router.children[r] = true 247 } 248 249 func (router *Router) Route() *Route { 250 parent := router.parent 251 operators := router.operators 252 253 for parent != nil { 254 operators = append(parent.operators, operators...) 255 parent = parent.parent 256 } 257 258 route := Route{ 259 last: router.children == nil, 260 Operators: operators, 261 } 262 263 return &route 264 } 265 266 func (router *Router) Routes() (routes []*Route) { 267 for child := range router.children { 268 route := child.Route() 269 270 if route.last { 271 routes = append(routes, route) 272 } 273 274 if child.children != nil { 275 routes = append(routes, child.Routes()...) 276 } 277 } 278 279 sort.Slice(routes, func(i, j int) bool { 280 return routes[i].String() < routes[j].String() 281 }) 282 283 return routes 284 } 285 286 type Route struct { 287 Operators []*OperatorWithTypeName 288 last bool 289 } 290 291 func (route *Route) String() string { 292 buf := bytes.NewBufferString(route.Method()) 293 buf.WriteString(" ") 294 buf.WriteString(route.Path()) 295 296 for i := range route.Operators { 297 buf.WriteString(" ") 298 buf.WriteString(route.Operators[i].String()) 299 } 300 301 return buf.String() 302 } 303 304 func (route *Route) Method() string { 305 method := "" 306 for _, m := range route.Operators { 307 if m.Method != "" { 308 method = m.Method 309 } 310 } 311 return method 312 } 313 314 func (route *Route) Path() string { 315 basePath := "/" 316 fullPath := "" 317 318 for _, operator := range route.Operators { 319 if operator.BasePath != "" { 320 basePath = operator.BasePath 321 } 322 if operator.Path != "" { 323 fullPath += operator.Path 324 } 325 } 326 327 return httprouter.CleanPath(basePath + fullPath) 328 } 329 330 type OperatorWithTypeName struct { 331 *Operator 332 TypeName *types.TypeName 333 } 334 335 func (operator *OperatorWithTypeName) String() string { 336 return operator.TypeName.Pkg().Name() + "." + operator.TypeName.Name() 337 }