@@ -39,8 +39,9 @@ func main() {
39
39
// TypescriptTypes holds all the code blocks created.
40
40
type TypescriptTypes struct {
41
41
// Each entry is the type name, and it's typescript code block.
42
- Types map [string ]string
43
- Enums map [string ]string
42
+ Types map [string ]string
43
+ Enums map [string ]string
44
+ Generics map [string ]string
44
45
}
45
46
46
47
// String just combines all the codeblocks.
@@ -50,16 +51,21 @@ func (t TypescriptTypes) String() string {
50
51
51
52
sortedTypes := make ([]string , 0 , len (t .Types ))
52
53
sortedEnums := make ([]string , 0 , len (t .Enums ))
54
+ sortedGenerics := make ([]string , 0 , len (t .Generics ))
53
55
54
56
for k := range t .Types {
55
57
sortedTypes = append (sortedTypes , k )
56
58
}
57
59
for k := range t .Enums {
58
60
sortedEnums = append (sortedEnums , k )
59
61
}
62
+ for k := range t .Generics {
63
+ sortedGenerics = append (sortedGenerics , k )
64
+ }
60
65
61
66
sort .Strings (sortedTypes )
62
67
sort .Strings (sortedEnums )
68
+ sort .Strings (sortedGenerics )
63
69
64
70
for _ , k := range sortedTypes {
65
71
v := t .Types [k ]
@@ -73,6 +79,12 @@ func (t TypescriptTypes) String() string {
73
79
_ , _ = s .WriteRune ('\n' )
74
80
}
75
81
82
+ for _ , k := range sortedGenerics {
83
+ v := t .Generics [k ]
84
+ _ , _ = s .WriteString (v )
85
+ _ , _ = s .WriteRune ('\n' )
86
+ }
87
+
76
88
return strings .TrimRight (s .String (), "\n " )
77
89
}
78
90
@@ -129,6 +141,7 @@ func (g *Generator) parsePackage(ctx context.Context, patterns ...string) error
129
141
// generateAll will generate for all types found in the pkg
130
142
func (g * Generator ) generateAll () (* TypescriptTypes , error ) {
131
143
structs := make (map [string ]string )
144
+ generics := make (map [string ]string )
132
145
enums := make (map [string ]types.Object )
133
146
enumConsts := make (map [string ][]* types.Const )
134
147
@@ -170,12 +183,11 @@ func (g *Generator) generateAll() (*TypescriptTypes, error) {
170
183
if ! ok {
171
184
panic ("all typename should be named types" )
172
185
}
173
- switch named .Underlying ().(type ) {
186
+ switch underNamed := named .Underlying ().(type ) {
174
187
case * types.Struct :
175
188
// type <Name> struct
176
189
// Structs are obvious.
177
- st , _ := obj .Type ().Underlying ().(* types.Struct )
178
- codeBlock , err := g .buildStruct (obj , st )
190
+ codeBlock , err := g .buildStruct (obj , underNamed )
179
191
if err != nil {
180
192
return nil , xerrors .Errorf ("generate %q: %w" , obj .Name (), err )
181
193
}
@@ -205,7 +217,35 @@ func (g *Generator) generateAll() (*TypescriptTypes, error) {
205
217
str .WriteString (fmt .Sprintf ("export type %s = %s\n " , obj .Name (), ts .ValueType ))
206
218
structs [obj .Name ()] = str .String ()
207
219
case * types.Array , * types.Slice :
208
- // TODO: @emyrk if you need this, follow the same design as "*types.Map" case.
220
+ // TODO: @emyrk if you need this, follow the same design as "*types.Map" case.
221
+ case * types.Interface :
222
+ // Interfaces are used as generics. Non-generic interfaces are
223
+ // not supported.
224
+ if underNamed .NumEmbeddeds () == 1 {
225
+ union , ok := underNamed .EmbeddedType (0 ).(* types.Union )
226
+ if ! ok {
227
+ // If the underlying is not a union, but has 1 type. It's
228
+ // just that one type.
229
+ union = types .NewUnion ([]* types.Term {
230
+ // Set the tilde to true to support underlying.
231
+ // Doesn't actually affect our generation.
232
+ types .NewTerm (true , underNamed .EmbeddedType (0 )),
233
+ })
234
+ }
235
+
236
+ block , err := g .buildUnion (obj , union )
237
+ if err != nil {
238
+ return nil , xerrors .Errorf ("generate union %q: %w" , obj .Name (), err )
239
+ }
240
+ generics [obj .Name ()] = block
241
+ }
242
+ case * types.Signature :
243
+ // Ignore named functions.
244
+ default :
245
+ // If you hit this error, you added a new unsupported named type.
246
+ // The easiest way to solve this is add a new case above with
247
+ // your type and a TODO to implement it.
248
+ return nil , xerrors .Errorf ("unsupported named type %q" , underNamed .String ())
209
249
}
210
250
case * types.Var :
211
251
// TODO: Are any enums var declarations? This is also codersdk.Me.
@@ -242,8 +282,9 @@ func (g *Generator) generateAll() (*TypescriptTypes, error) {
242
282
}
243
283
244
284
return & TypescriptTypes {
245
- Types : structs ,
246
- Enums : enumCodeBlocks ,
285
+ Types : structs ,
286
+ Enums : enumCodeBlocks ,
287
+ Generics : generics ,
247
288
}, nil
248
289
}
249
290
@@ -252,6 +293,33 @@ func (g *Generator) posLine(obj types.Object) string {
252
293
return fmt .Sprintf ("// From %s\n " , filepath .Join ("codersdk" , filepath .Base (file .Name ())))
253
294
}
254
295
296
+ // buildStruct just prints the typescript def for a type.
297
+ func (g * Generator ) buildUnion (obj types.Object , st * types.Union ) (string , error ) {
298
+ var s strings.Builder
299
+ _ , _ = s .WriteString (g .posLine (obj ))
300
+
301
+ allTypes := make ([]string , 0 , st .Len ())
302
+ var optional bool
303
+ for i := 0 ; i < st .Len (); i ++ {
304
+ term := st .Term (i )
305
+ scriptType , err := g .typescriptType (term .Type ())
306
+ if err != nil {
307
+ return "" , xerrors .Errorf ("union %q for %q failed to get type: %w" , st .String (), obj .Name (), err )
308
+ }
309
+ allTypes = append (allTypes , scriptType .ValueType )
310
+ optional = optional || scriptType .Optional
311
+ }
312
+
313
+ qMark := ""
314
+ if optional {
315
+ qMark = "?"
316
+ }
317
+
318
+ s .WriteString (fmt .Sprintf ("export type %s%s = %s\n " , obj .Name (), qMark , strings .Join (allTypes , " | " )))
319
+
320
+ return s .String (), nil
321
+ }
322
+
255
323
// buildStruct just prints the typescript def for a type.
256
324
func (g * Generator ) buildStruct (obj types.Object , st * types.Struct ) (string , error ) {
257
325
var s strings.Builder
0 commit comments