-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
type.go
108 lines (96 loc) · 4.1 KB
/
type.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
package gadget
import (
"go/ast"
"strings"
"github.com/wilhelm-murdoch/go-collection"
)
const (
KIND_INTERFACE = "interface" // Used if the type is an interface with methods.
KIND_STRUCT = "struct" // Used if the type is a struct with fields.
KIND_ARRAY = "array" // Used for array types.
KIND_FUNC = "function" // Use function types.
KIND_CHAN = "channel" // Used for channel types.
KIND_MAP = "map" // Used for map types.
)
// Type represents a golang type definition.
type Type struct {
Name string `json:"name"` // The name of the struct.
Kind string `json:"kind"` // Determines the kind of type, eg; interface or struct.
LineStart int `json:"line_start"` // The line number in the associated source file where this struct is initially defined.
LineEnd int `json:"line_end"` // The line number in the associated source file where the definition block ends.
LineCount int `json:"line_count"` // The total number of lines, including body, the struct occupies.
Comment string `json:"comment,omitempty"` // Any inline comments associated with the struct.
Doc string `json:"doc,omitempty"` // The comment block directly above this struct's definition.
Signature string `json:"signature"` // The full definition of the struct itself.
Body string `json:"body,omitempty"` // The full body of the struct sourced directly from the associated file; comments included.
Fields *collection.Collection[*Field] `json:"fields,omitempty"` // A collection of fields and their associated metadata.
astSpec *ast.TypeSpec
parent *File
}
// NewType returns an struct instance and attempts to populate all associated
// fields with meaningful values.
func NewType(ts *ast.TypeSpec, parent *File) *Type {
return (&Type{
Name: ts.Name.Name,
Fields: collection.New[*Field](),
Doc: ts.Doc.Text(),
astSpec: ts,
parent: parent,
}).Parse()
}
// Parse is responsible for browsing through f.astSpec, f.astType, f.parent to
// populate the current struct's fields. ( Chainable )
func (t *Type) Parse() *Type {
t.parseLines()
t.parseBody()
t.parseSignature()
t.parseFields()
return t
}
// parseLines determines the current struct's opening and closing line
// positions.
func (t *Type) parseLines() {
t.LineStart = t.parent.tokenSet.File(t.astSpec.Pos()).Line(t.astSpec.Pos())
t.LineEnd = t.parent.tokenSet.Position(t.astSpec.End()).Line
t.LineCount = (t.LineEnd + 1) - t.LineStart
}
// parseBody attempts to make a few adjustments to the *ast.BlockStmt which
// represents the current struct's body. We remove the opening and closing
// braces as well as the first occurrent `\t` sequence on each line.
func (t *Type) parseBody() {
t.Body = AdjustSource(string(GetLinesFromFile(t.parent.Path, t.LineStart+1, t.LineEnd-1)), false)
}
// parseSignature attempts to determine the current structs's type and assigns
// it to the Signature field of struct Function.
func (t *Type) parseSignature() {
line := strings.TrimSpace(string(GetLinesFromFile(t.parent.Path, t.LineStart, t.LineStart)))
t.Signature = strings.TrimSpace(line[:len(line)-1])
}
// parseFields iterates through the struct's list of defined methods to
// populate the Fields collection.
func (t *Type) parseFields() {
switch tp := t.astSpec.Type.(type) {
case *ast.StructType:
t.Kind = KIND_STRUCT
for _, field := range tp.Fields.List {
t.Fields.Push(NewField(field, t.parent))
}
case *ast.InterfaceType:
t.Kind = KIND_INTERFACE
for _, method := range tp.Methods.List {
t.Fields.Push(NewField(method, t.parent))
}
case *ast.ArrayType:
t.Kind = KIND_ARRAY
case *ast.FuncType:
t.Kind = KIND_FUNC
case *ast.ChanType:
t.Kind = KIND_CHAN
case *ast.MapType:
t.Kind = KIND_MAP
}
}
// String implements the Stringer struct and returns the current package's name.
func (t *Type) String() string {
return t.Name
}