Repository navigation
Expand file tree
/
Copy pathmake_structures.go
More file actions
233 lines (204 loc) · 5.71 KB
/
Copy pathmake_structures.go
File metadata and controls
233 lines (204 loc) · 5.71 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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
package gen
import (
"fmt"
"strings"
"github.com/go-faster/errors"
"github.com/gotd/getdoc"
)
// structDef represents go structure definition.
type structDef struct {
// Name of struct, just like that: `type Name struct {`.
Name string
// Comment for struct, in one line.
Comment string
// Receiver name. E.g. "m" for Message.
Receiver string
// HexID is hex-encoded id, like 29bacabb.
HexID string
// BufArg is name of Encode and Decode argument of bin.Buffer type
// that is used in those functions.
//
// Should not equal to Name.
BufArg string
// RawType is type name from TL schema, like authPassword#29bacabb.
RawType string
// RawName is type name from TL schema without HexID (CRC code), like authPassword.
RawName string
// Interface refers to interface of generic type.
Interface string
InterfaceFunc string
// Method name if function definition.
Method string
// Result type name.
Result string
// ResultSingular denotes whether Result is singular type an can be used
// directly.
ResultSingular bool
// ResultBaseName is BaseName of result interface.
ResultBaseName string
ResultFunc string
ResultVector bool
UnpackParameters bool
Vector bool
// Fields of structure.
Fields []fieldDef
// Tuples of Conditional fields.
ConditionalTuples [32][]fieldDef
// Namespace for file structure generation.
Namespace []string
// BaseName for file structure generation.
BaseName string
// URL to documentation.
// Like https://core.telegram.org/method/account.getPrivacy
// Or https://core.telegram.org/constructor/account.privacyRules
URL string
// Docs is comments from documentation.
Docs []string
// Links from documentation
Links []string
// BotCanUse denotes whether method can be used by bots.
BotCanUse bool
// Errors is list of possible errors.
Errors []getdoc.Error
}
func (s *structDef) fillFromClass(class classBinding) {
s.Result = class.Name
s.ResultSingular = class.Singular
s.ResultBaseName = class.BaseName
s.ResultFunc = class.Func
s.ResultVector = class.Vector
}
type bindingDef struct {
HexID string // id in hex
Raw string // raw tl type
Name string // go type
}
func (g *Generator) docStruct(k string) getdoc.Constructor {
if g.doc == nil {
return getdoc.Constructor{}
}
return g.doc.Constructors[k]
}
func (g *Generator) docMethod(k string) getdoc.Method {
if g.doc == nil {
return getdoc.Method{}
}
return g.doc.Methods[k]
}
// makeStructures generates go structure definition representations.
//
// nolint:gocognit,gocyclo // TODO(ernado): simplify
func (g *Generator) makeStructures() error {
for _, sd := range g.schema.Definitions {
var (
d = sd.Definition
typeKey = definitionType(d)
docStruct = g.docStruct(typeKey)
docMethod = g.docMethod(typeKey)
)
t, ok := g.types[typeKey]
if !ok {
return errors.Errorf("find type binding for %q", typeKey)
}
s := structDef{
Namespace: t.Namespace,
Name: t.Name,
BaseName: d.Name,
HexID: fmt.Sprintf("%x", d.ID),
BufArg: "b",
RawType: fmt.Sprintf("%s#%x", typeKey, d.ID),
RawName: typeKey,
Interface: t.Interface,
InterfaceFunc: t.InterfaceFunc,
Method: t.Method,
Docs: docStruct.Description,
Links: docStruct.Links,
}
if t.Method != "" {
s.Docs = docMethod.Description
s.Links = docMethod.Links
s.BotCanUse = docMethod.BotCanUse
for _, e := range docMethod.Errors {
if strings.Contains(e.Type, ",") {
// HACK(ernado): fix in getdoc
continue
}
s.Errors = append(s.Errors, e)
}
}
if g.docBase != nil {
// Assuming constructor by default.
s.URL = g.docURL("constructor", typeKey)
}
s.Docs = splitLines(s.Docs, g.docLineLimit)
// Selecting receiver based on non-namespaced type.
s.Receiver = strings.ToLower(d.Name[:1])
if s.Receiver == "b" {
// bin.Buffer argument collides with receiver.
s.BufArg = "buf"
}
if strings.TrimSpace(s.Comment) == "" {
// TODO(ernado): multi-line comments.
s.Comment = fmt.Sprintf("%s represents TL type `%s`.", s.Name, s.RawType)
}
allFieldRequired := true
for _, param := range d.Params {
f, err := g.makeField(param, sd.Annotations)
if err != nil {
return errors.Wrapf(err, "make field %s", param.Name)
}
f.Links = docStruct.Fields[param.Name].Links
if t.Method != "" {
f.Links = docMethod.Parameters[param.Name].Links
}
if f.Conditional {
if f.ConditionalIndex >= 32 || f.ConditionalIndex < 0 {
return errors.Errorf("invalid conditional index %d", f.ConditionalIndex)
}
s.ConditionalTuples[f.ConditionalIndex] = append(s.ConditionalTuples[f.ConditionalIndex], f)
allFieldRequired = false
}
if len(f.Comment) < 1 || f.Comment[0] == "" {
comment := docMethod.Parameters[param.Name].Description
if strings.TrimSpace(comment) == "" {
comment = docStruct.Fields[param.Name].Description
}
if strings.TrimSpace(comment) == "" {
comment = fmt.Sprintf("%s field of %s.", f.Name, s.Name)
}
f.Comment = []string{comment}
}
f.Comment = splitLines(f.Comment, g.docLineLimit)
s.Fields = append(s.Fields, f)
}
if allFieldRequired && len(d.Params) < 2 {
s.UnpackParameters = true
}
if s.Method != "" && t.Class != "Ok" {
// RPC call.
class, ok := g.classes[t.Class]
switch {
case !ok && strings.HasPrefix(t.Class, "Vector<"):
var err error
class, err = g.makeVector(t.Class)
if err != nil {
return err
}
fallthrough
case ok:
s.fillFromClass(class)
s.URL = g.docURL("method", typeKey)
default:
// Not implemented.
s.Method = ""
}
}
g.structs = append(g.structs, s)
g.registry = append(g.registry, bindingDef{
HexID: s.HexID,
Raw: s.RawType,
Name: s.Name,
})
}
return nil
}