/
parse.go
123 lines (111 loc) · 2.35 KB
/
parse.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
package main
import (
"go/ast"
"go/parser"
"go/token"
"os"
"reflect"
"strings"
)
type Category struct {
Type string
Fields []Field
}
type Field struct {
Name string
Type string
Comment string
DefaultFrom string
DefaultFromMany string
}
func ParseCategories() ([]Category, error) {
b, err := os.ReadFile(flags.file)
if err != nil {
return nil, err
}
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, "theme.go", b, parser.ParseComments)
if err != nil {
return nil, err
}
categories := make([]Category, 0, len(f.Decls))
for _, decl := range f.Decls {
genDecl, ok := decl.(*ast.GenDecl)
if !ok {
continue
}
category, ok := visitGenDecl(genDecl)
if !ok {
continue
}
categories = append(categories, category)
}
return categories, nil
}
func visitGenDecl(decl *ast.GenDecl) (Category, bool) {
typeSpec := getTypeSpec(decl)
if typeSpec == nil {
return Category{}, false
}
if !strings.HasPrefix(typeSpec.Name.Name, "Theme") {
return Category{}, false
}
structType, ok := typeSpec.Type.(*ast.StructType)
if !ok {
return Category{}, false
}
category := Category{
Type: typeSpec.Name.Name,
}
for _, field := range structType.Fields.List {
if len(field.Names) != 1 {
continue
}
name := field.Names[0].Name
typ, ok := field.Type.(*ast.Ident)
if !ok {
continue
}
var comments []string
if field.Comment != nil {
for _, c := range field.Comment.List {
comments = append(comments, trimComment(c.Text))
}
}
var tag reflect.StructTag
if field.Tag != nil {
tag = reflect.StructTag(strings.Trim(field.Tag.Value, "`"))
}
category.Fields = append(category.Fields, Field{
Name: name,
Type: typ.Name,
Comment: strings.Join(comments, "\n"),
DefaultFrom: tag.Get("defaultFrom"),
DefaultFromMany: tag.Get("defaultFromMany"),
})
}
return category, true
}
func trimComment(s string) string {
if after, ok := strings.CutPrefix(s, "//"); ok {
return strings.TrimSpace(after)
}
if after, ok := strings.CutPrefix(s, "/*"); ok {
inBetween, _ := strings.CutSuffix(after, "*/")
return strings.TrimSpace(inBetween)
}
return s
}
func getTypeSpec(decl *ast.GenDecl) *ast.TypeSpec {
if decl.Tok.String() != "type" {
return nil
}
if len(decl.Specs) != 1 {
return nil
}
spec, ok := decl.Specs[0].(*ast.TypeSpec)
if !ok {
return nil
}
return spec
}