-
Notifications
You must be signed in to change notification settings - Fork 4
/
util.go
149 lines (138 loc) · 4.12 KB
/
util.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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
package astra
import (
"fmt"
"go/ast"
astparser "go/parser"
"go/token"
"io/ioutil"
"os"
"path/filepath"
"strings"
"github.com/vetcher/go-astra/types"
)
// Opens and parses file by name and return information about it.
func ParseFile(filename string, options ...Option) (*types.File, error) {
path, err := filepath.Abs(filename)
if err != nil {
return nil, fmt.Errorf("can not filepath.Abs: %v", err)
}
fset := token.NewFileSet()
tree, err := astparser.ParseFile(fset, path, nil, astparser.ParseComments)
if err != nil {
return nil, fmt.Errorf("error when parse file: %v", err)
}
info, err := ParseAstFile(tree, options...)
if err != nil {
return nil, fmt.Errorf("error when parsing info from file: %v", err)
}
return info, nil
}
// Merges parsed files to one. Helpful, when you need full information about package.
func MergeFiles(files []*types.File) (*types.File, error) {
targetFile := &types.File{}
for _, file := range files {
if file == nil {
continue
}
// do not merge documentation.
targetFile.Base.Name = file.Base.Name
targetFile.Imports = mergeImports(targetFile.Imports, file.Imports)
targetFile.Constants = append(targetFile.Constants, file.Constants...)
targetFile.Vars = append(targetFile.Vars, file.Vars...)
targetFile.Interfaces = append(targetFile.Interfaces, file.Interfaces...)
targetFile.Structures = append(targetFile.Structures, file.Structures...)
targetFile.Methods = append(targetFile.Methods, file.Methods...)
targetFile.Types = append(targetFile.Types, file.Types...)
targetFile.Functions = append(targetFile.Functions, file.Functions...)
}
err := linkMethodsToStructs(targetFile)
if err != nil {
return nil, err
}
return targetFile, nil
}
// Parses all .go files from directory.
// Deprecated: use GetPackage instead
func ParsePackage(path string, options ...Option) ([]*types.File, error) {
p, err := filepath.Abs(path)
if err != nil {
return nil, fmt.Errorf("can not filepath.Abs: %v", err)
}
files, err := ioutil.ReadDir(p)
if err != nil {
return nil, fmt.Errorf("can not read dir: %v", err)
}
var parsedFiles []*types.File
for _, file := range files {
if file.IsDir() {
continue
}
if !strings.HasSuffix(file.Name(), ".go") {
continue
}
f, err := ParseFile(p+"/"+file.Name(), options...)
if err != nil {
return nil, fmt.Errorf("can not parse %s: %v", file.Name(), err)
}
parsedFiles = append(parsedFiles, f)
}
return parsedFiles, nil
}
func GetPackage(path string, options ...Option) (*types.File, error) {
p, err := filepath.Abs(path)
if err != nil {
return nil, fmt.Errorf("can not filepath.Abs: %v", err)
}
fset := token.NewFileSet()
pkgs, err := astparser.ParseDir(fset, p, nil, astparser.ParseComments)
if err != nil {
return nil, fmt.Errorf("can not parse dir: %v", err)
}
if len(pkgs) > 1 {
return nil, fmt.Errorf("unexpected number of packages: expect 1, found %d", len(pkgs))
}
for _, pkg := range pkgs {
f := ast.MergePackageFiles(pkg, ast.FilterUnassociatedComments|ast.FilterFuncDuplicates|ast.FilterImportDuplicates)
return ParseAstFile(f, options...)
}
return nil, fmt.Errorf("unexpected number of packages: expect 1, found 0")
}
func ResolvePackagePath(outPath string) (string, error) {
gopath := os.Getenv("GOPATH")
if gopath == "" {
return "", ErrGoPathIsEmpty
}
absOutPath, err := filepath.Abs(filepath.Dir(outPath))
if err != nil {
return "", err
}
for _, path := range strings.Split(gopath, ":") {
gopathSrc := filepath.Join(path, "src")
if !strings.HasPrefix(absOutPath, gopathSrc) {
continue
}
return absOutPath[len(gopathSrc)+1:], nil
}
return "", ErrNotInGoPath
}
func namesOfIdents(idents []*ast.Ident) (res []string) {
for i := range idents {
if idents[i] != nil {
res = append(res, idents[i].Name)
}
}
return
}
func mergeStringSlices(slices ...[]string) []string {
if len(slices) == 0 {
return nil
}
return append(slices[0], mergeStringSlices(slices[1:]...)...)
}
func parseCommentFromSources(opt Option, groups ...*ast.CommentGroup) []string {
temp := make([][]string, len(groups))
for i := range groups {
temp[i] = parseComments(groups[i], opt)
}
return mergeStringSlices(temp...)
}