Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support NSRouter and multi-level namespace #587

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
187 changes: 113 additions & 74 deletions generate/swaggergen/g_docs.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,16 @@ var stdlibObject = map[string]string{
"&{json RawMessage}": "json.RawMessage",
}

var httpMethods = map[string]bool{
"GET": true,
"POST": true,
"PUT": true,
"PATCH": true,
"DELETE": true,
"HEAD": true,
"OPTIONS": true,
}

func init() {
pkgCache = make(map[string]struct{})
controllerComments = make(map[string]string)
Expand Down Expand Up @@ -278,41 +288,7 @@ func GenerateDocs(curpath string) {
if !selOK || selExpr.Sel.Name != "NewNamespace" {
continue
}
version, params := analyseNewNamespace(v)
if rootapi.BasePath == "" && version != "" {
rootapi.BasePath = version
}
for _, p := range params {
switch pp := p.(type) {
case *ast.CallExpr:
var controllerName string
if selname := pp.Fun.(*ast.SelectorExpr).Sel.String(); selname == "NSNamespace" {
s, params := analyseNewNamespace(pp)
for _, sp := range params {
switch pp := sp.(type) {
case *ast.CallExpr:
if pp.Fun.(*ast.SelectorExpr).Sel.String() == "NSInclude" {
controllerName = analyseNSInclude(s, pp)
if v, ok := controllerComments[controllerName]; ok {
rootapi.Tags = append(rootapi.Tags, swagger.Tag{
Name: strings.Trim(s, "/"),
Description: v,
})
}
}
}
}
} else if selname == "NSInclude" {
controllerName = analyseNSInclude("", pp)
if v, ok := controllerComments[controllerName]; ok {
rootapi.Tags = append(rootapi.Tags, swagger.Tag{
Name: controllerName, // if the NSInclude has no prefix, we use the controllername as the tag
Description: v,
})
}
}
}
}
traverseNameSpace("", v)
}

}
Expand Down Expand Up @@ -343,6 +319,41 @@ func GenerateDocs(curpath string) {
}
}

func traverseNameSpace(baseURL string, pp *ast.CallExpr) {
s, params := analyseNewNamespace(pp)
if rootapi.BasePath == "" && baseURL == "" {
rootapi.BasePath = s // version
s = ""
}
for _, sp := range params {
switch pp := sp.(type) {
case *ast.CallExpr:
selname := pp.Fun.(*ast.SelectorExpr).Sel.String()
switch selname {
case "NSNamespace":
traverseNameSpace(baseURL+s, pp)
case "NSRouter":
rootpath := strings.Trim(pp.Args[0].(*ast.BasicLit).Value, "\"")
controllerName := analyseNSRouter(baseURL+s, rootpath, pp)
if v, ok := controllerComments[controllerName]; ok {
rootapi.Tags = append(rootapi.Tags, swagger.Tag{
Name: strings.Trim(s, "/"),
Description: v,
})
}
case "NSInclude":
controllerName := analyseNSInclude(baseURL+s, pp)
if v, ok := controllerComments[controllerName]; ok {
rootapi.Tags = append(rootapi.Tags, swagger.Tag{
Name: strings.Trim(s, "/"),
Description: v,
})
}
}
}
}
}

// analyseNewNamespace returns version and the others params
func analyseNewNamespace(ce *ast.CallExpr) (first string, others []ast.Expr) {
for i, p := range ce.Args {
Expand All @@ -358,6 +369,66 @@ func analyseNewNamespace(ce *ast.CallExpr) (first string, others []ast.Expr) {
return
}

func appendController(pkgname, cname, baseurl, routeurl string) string {
if v, ok := importlist[pkgname]; ok {
cname = v + cname
}
if apis, ok := controllerList[cname]; ok {
for rt, item := range apis {
if routeurl != "" {
if rt != "" {
continue
}
rt = routeurl // routers without '@router' annotation
}
tag := cname
if baseurl != "" {
rt = baseurl + rt
tag = strings.Trim(baseurl, "/")
}
if item.Get != nil {
item.Get.Tags = []string{tag}
}
if item.Post != nil {
item.Post.Tags = []string{tag}
}
if item.Put != nil {
item.Put.Tags = []string{tag}
}
if item.Patch != nil {
item.Patch.Tags = []string{tag}
}
if item.Head != nil {
item.Head.Tags = []string{tag}
}
if item.Delete != nil {
item.Delete.Tags = []string{tag}
}
if item.Options != nil {
item.Options.Tags = []string{tag}
}
if len(rootapi.Paths) == 0 {
rootapi.Paths = make(map[string]*swagger.Item)
}
rt = urlReplace(rt)
rootapi.Paths[rt] = item
}
}
return cname
}

func analyseNSRouter(baseurl, routeurl string, ce *ast.CallExpr) string {
var x *ast.SelectorExpr
var p interface{} = ce.Args[1]

if _, ok := p.(*ast.UnaryExpr); ok {
x = p.(*ast.UnaryExpr).X.(*ast.CompositeLit).Type.(*ast.SelectorExpr)
} else {
beeLogger.Log.Warnf("Couldn't determine type\n")
}
return appendController(fmt.Sprint(x.X), x.Sel.Name, baseurl, routeurl)
}

func analyseNSInclude(baseurl string, ce *ast.CallExpr) string {
cname := ""
for _, p := range ce.Args {
Expand All @@ -376,44 +447,8 @@ func analyseNSInclude(baseurl string, ce *ast.CallExpr) string {
beeLogger.Log.Warnf("Couldn't determine type\n")
continue
}
if v, ok := importlist[fmt.Sprint(x.X)]; ok {
cname = v + x.Sel.Name
}
if apis, ok := controllerList[cname]; ok {
for rt, item := range apis {
tag := cname
if baseurl != "" {
rt = baseurl + rt
tag = strings.Trim(baseurl, "/")
}
if item.Get != nil {
item.Get.Tags = []string{tag}
}
if item.Post != nil {
item.Post.Tags = []string{tag}
}
if item.Put != nil {
item.Put.Tags = []string{tag}
}
if item.Patch != nil {
item.Patch.Tags = []string{tag}
}
if item.Head != nil {
item.Head.Tags = []string{tag}
}
if item.Delete != nil {
item.Delete.Tags = []string{tag}
}
if item.Options != nil {
item.Options.Tags = []string{tag}
}
if len(rootapi.Paths) == 0 {
rootapi.Paths = make(map[string]*swagger.Item)
}
rt = urlReplace(rt)
rootapi.Paths[rt] = item
}
}

cname = appendController(fmt.Sprint(x.X), x.Sel.Name, baseurl, "")
}
return cname
}
Expand Down Expand Up @@ -538,6 +573,10 @@ func parserComments(f *ast.FuncDecl, controllerName, pkgpath string) error {
funcName := f.Name.String()
comments := f.Doc
funcParamMap := buildParamMap(f.Type.Params)

if fn := strings.ToUpper(funcName); httpMethods[fn] {
HTTPMethod = fn
}
//TODO: resultMap := buildParamMap(f.Type.Results)
if comments != nil && comments.List != nil {
for _, c := range comments.List {
Expand Down Expand Up @@ -731,7 +770,7 @@ func parserComments(f *ast.FuncDecl, controllerName, pkgpath string) error {
}
}

if routerPath != "" {
if HTTPMethod != "" {
//Go over function parameters which were not mapped and create swagger params for them
for name, typ := range funcParamMap {
para := swagger.Parameter{}
Expand Down