-
Notifications
You must be signed in to change notification settings - Fork 10
/
doc.go
119 lines (98 loc) · 2.59 KB
/
doc.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
119
package bel
import (
"fmt"
"go/ast"
"go/doc"
"go/parser"
"go/token"
"os"
"reflect"
"strings"
)
// DocHandler provides documentation for types
type DocHandler interface {
// Type retrieves documentation for a type
Type(t reflect.Type) string
// Method retrieves documentation for an interface's method
Method(parent reflect.Type, method reflect.Method) string
}
type nullDocHandler string
func (*nullDocHandler) Type(t reflect.Type) string {
return ""
}
func (*nullDocHandler) Method(parent reflect.Type, method reflect.Method) string {
return ""
}
// ParsedSourceDocHandler provides Go doc documentation from
type ParsedSourceDocHandler struct {
pkgs map[string]*doc.Package
}
// NewParsedSourceDocHandler creates a new doc handler with a single pkg in its index
func NewParsedSourceDocHandler(srcdir, base string) (*ParsedSourceDocHandler, error) {
res := &ParsedSourceDocHandler{pkgs: make(map[string]*doc.Package)}
if err := res.AddToIndex(srcdir, base); err != nil {
return nil, err
}
return res, nil
}
// AddToIndex adds another package to the handler's index. src is the path to the Go src folder of the package, pkg is its import path
func (h *ParsedSourceDocHandler) AddToIndex(src, pkg string) error {
fset := token.NewFileSet()
ps, err := parser.ParseDir(fset, src, func(i os.FileInfo) bool { return true }, parser.ParseComments)
if err != nil {
return err
}
for n, p := range ps {
importPath := n
if pkg != "" {
importPath = fmt.Sprintf("%s/%s", strings.TrimRight(pkg, "/"), n)
}
h.pkgs[importPath] = doc.New(p, importPath, 0)
}
return nil
}
func (h *ParsedSourceDocHandler) findDoc(t reflect.Type) *doc.Type {
pkg, ok := h.pkgs[t.PkgPath()]
if !ok {
return nil
}
for _, doct := range pkg.Types {
if doct.Name == t.Name() {
return doct
}
}
return nil
}
// Type retrieves documentation for a type using the handler's index
func (h *ParsedSourceDocHandler) Type(t reflect.Type) string {
doct := h.findDoc(t)
if doct == nil {
return ""
}
return strings.TrimSpace(doct.Doc)
}
// Method retrieves documentation for a method using the handler's index
func (h *ParsedSourceDocHandler) Method(parent reflect.Type, method reflect.Method) string {
doct := h.findDoc(parent)
if doct == nil {
return ""
}
specs := doct.Decl.Specs
if len(specs) < 1 {
return ""
}
tspec, ok := specs[0].(*ast.TypeSpec)
if !ok {
return ""
}
ifspec, ok := tspec.Type.(*ast.InterfaceType)
if !ok {
return ""
}
for _, dm := range ifspec.Methods.List {
if len(dm.Names) > 0 && dm.Names[0].Name == method.Name {
return strings.TrimSpace(dm.Doc.Text())
}
}
return ""
}