/
walker_comments.go
118 lines (94 loc) · 2.92 KB
/
walker_comments.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
package main
import (
"github.com/jackmanlabs/errors"
"go/ast"
"go/build"
"go/parser"
"go/token"
"log"
"strings"
)
func getCommentBlocks(pkgPath string) ([]string, error) {
bpkg, err := build.Import(pkgPath, srcPath, 0)
if err != nil {
return []string{}, nil
}
fset := token.NewFileSet()
pkgs, err := parser.ParseDir(fset, bpkg.Dir, nil, parser.AllErrors|parser.ParseComments)
if err != nil {
return nil, errors.Stack(err)
}
commentVisitor := &CommentVisitor{
Fset: fset,
Comments: make([]string, 0),
}
for _, pkg := range pkgs {
//log.Print("Package name: ", pkg.Name)
ast.Walk(commentVisitor, pkg)
}
return commentVisitor.Comments, nil
}
/*
We're using a map for the imports so we don't have to worry about duplicates.
*/
type CommentVisitor struct {
Fset *token.FileSet
Comments []string
}
func (this *CommentVisitor) Visit(node ast.Node) (w ast.Visitor) {
if this.Fset == nil {
log.Println("fset is nil.")
return nil
}
switch t := node.(type) {
//case *ast.CommentGroup:
// this.Comments = append(this.Comments, t.Text())
//
// return nil
case *ast.File:
// For some reason, file-level docs don't get detected with the CommentGroup filter.
//if t.Name.Name == "rest" {
// ast.Fprint(os.Stderr, this.Fset, t, ast.NotNilFilter)
//}
for _, commentGroup := range t.Comments {
s := commentGroup.Text()
// We don't need all the comments, so let's save some memory/CPU.
if strings.Contains(s, "OpenAPI") {
this.Comments = append(this.Comments, s)
}
}
return nil
case nil:
default:
//log.Printf("unexpected type %T\n", t) // %T prints whatever type t has
}
return this
}
// This is used to detect blocks with 'OpenAPI Path:'. A comment block that describes a path/operation is useless if it
// fails to describe the path. Therefore, this is a good indicator.
func detectOperationComments(commentBlocks []string) []string {
return detectComments(commentBlocks, "OpenAPI Path:")
}
// This detects comments blocks with 'OpenAPI API Title:'. The API Title is a required member of the Swagger definition,
// so it must be present.
func detectApiCommentBlocks(commentBlocks []string) []string {
return detectComments(commentBlocks, "OpenAPI API Title:")
}
// This detects comment blocks with 'OpenAPI Tag:'. There is no garantee that these tags declarations will be a part of
// any other comment block.
func detectTagComments(commentBlocks []string) []string {
return detectComments(commentBlocks, "OpenAPI Tags:")
}
// Comment detection is case-insensitive.
// Any comment blocks that prove to have the test string will be returned.
func detectComments(commentBlocks []string, keyword string) []string {
keyword = strings.ToLower(keyword)
detectedBlocks := make([]string, 0)
for _, comment := range commentBlocks {
comment_ := strings.ToLower(comment)
if strings.Contains(comment_, keyword) {
detectedBlocks = append(detectedBlocks, comment)
}
}
return detectedBlocks
}