-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathparse.go
More file actions
153 lines (135 loc) · 3.79 KB
/
parse.go
File metadata and controls
153 lines (135 loc) · 3.79 KB
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
150
151
152
153
package main
import (
"fmt"
"go/ast"
"go/parser"
"go/token"
"log"
"os"
"strings"
)
type ParsedField struct {
Name string // name of the argument
Type string // type of the argument
}
type ParsedGeneric struct {
Name string // name of the generic type
Constraint string // type of the generic type
}
type ParsedData struct {
Name string // name of the struct
Fields []ParsedField // fields of the struct
Generics []ParsedGeneric // generics of the struct
}
type ParsedFile struct {
PackageName string
Imports []string
Data map[string][]ParsedData
}
func parseFile(flags Flags) (ParsedFile, error) {
fset := token.NewFileSet()
node, err := parser.ParseFile(fset, flags.inputFile, nil, parser.ParseComments)
if err != nil {
return ParsedFile{}, err
}
src, err := os.ReadFile(flags.inputFile)
if err != nil {
log.Fatal(err)
}
var parsedFile ParsedFile
parsedFile.PackageName = node.Name.Name // Extracting the package name
parsedFile.Data = make(map[string][]ParsedData)
for _, imp := range node.Imports {
// Extracting the import paths
path := strings.Trim(imp.Path.Value, `"`)
if imp.Name != nil {
parsedFile.Imports = append(parsedFile.Imports, imp.Name.Name+" "+path)
} else {
parsedFile.Imports = append(parsedFile.Imports, path)
}
}
for _, f := range node.Decls {
// Check if the declaration is a general declaration (var, const, type, or func)
genDecl, ok := f.(*ast.GenDecl)
if !ok {
continue
}
for _, spec := range genDecl.Specs {
// Check if the spec is a type specification (type name Type = ...)
typeSpec, ok := spec.(*ast.TypeSpec)
if !ok || !strings.HasSuffix(typeSpec.Name.Name, flags.structSuffix) {
continue
}
parsedFile.Data[typeSpec.Name.Name] = []ParsedData{}
var parsedGeneric []ParsedGeneric
// Add this block to handle type parameters
if typeSpec.TypeParams != nil {
for _, param := range typeSpec.TypeParams.List {
for _, name := range param.Names {
start := fset.Position(param.Type.Pos()).Offset
end := fset.Position(param.Type.End()).Offset
parsedGeneric = append(parsedGeneric, ParsedGeneric{
Name: name.Name,
Constraint: string(src[start:end]),
})
}
}
}
structType, ok := typeSpec.Type.(*ast.StructType)
if !ok {
continue
}
for _, field := range structType.Fields.List {
funcType, ok := field.Type.(*ast.FuncType)
if !ok {
continue
}
var fields []ParsedField
if funcType.Params != nil {
for i, param := range funcType.Params.List {
// Handle different types of fields
fieldType := exprToString(param.Type)
for _, paramName := range param.Names {
fields = append(fields, ParsedField{
Name: paramName.Name,
Type: fieldType,
})
}
if len(param.Names) == 0 {
fields = append(fields, ParsedField{
Name: fmt.Sprintf("arg%d", i),
Type: fieldType,
})
}
}
}
for _, fieldName := range field.Names {
parsedFile.Data[typeSpec.Name.Name] = append(parsedFile.Data[typeSpec.Name.Name], ParsedData{
Name: fieldName.Name,
Fields: fields,
Generics: parsedGeneric,
})
}
}
}
}
return parsedFile, nil
}
// exprToString converts an ast.Expr to a string representation of the type
func exprToString(expr ast.Expr) string {
switch t := expr.(type) {
case *ast.Ident:
return t.Name
case *ast.SelectorExpr:
return exprToString(t.X) + "." + t.Sel.Name
case *ast.StarExpr:
return "*" + exprToString(t.X)
case *ast.ArrayType:
return "[]" + exprToString(t.Elt)
case *ast.IndexExpr:
return exprToString(t.X) + "[" + exprToString(t.Index) + "]"
// Add more cases as needed for other types
default:
return fmt.Sprintf("exprToString failed: %#v", expr)
}
}