goscript 0.0.22 → 0.0.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cmd/goscript/cmd_compile.go +2 -2
- package/compiler/analysis.go +229 -51
- package/compiler/assignment.go +6 -1
- package/compiler/compiler.go +41 -18
- package/compiler/compiler_test.go +36 -8
- package/compiler/composite-lit.go +25 -10
- package/compiler/decl.go +36 -0
- package/compiler/expr-call.go +116 -60
- package/compiler/expr-selector.go +22 -2
- package/compiler/expr-type.go +131 -4
- package/compiler/expr-value.go +7 -37
- package/compiler/expr.go +247 -12
- package/compiler/field.go +3 -3
- package/compiler/lit.go +34 -2
- package/compiler/primitive.go +8 -2
- package/compiler/spec-struct.go +137 -6
- package/compiler/spec-value.go +50 -18
- package/compiler/spec.go +12 -3
- package/compiler/stmt-assign.go +29 -1
- package/compiler/stmt-range.go +9 -11
- package/compiler/stmt-select.go +211 -0
- package/compiler/stmt-type-switch.go +147 -0
- package/compiler/stmt.go +129 -244
- package/compiler/type-assert.go +125 -379
- package/compiler/type.go +187 -125
- package/package.json +5 -5
- package/builtin/builtin.go +0 -11
- package/builtin/builtin.ts +0 -2379
- package/dist/builtin/builtin.d.ts +0 -513
- package/dist/builtin/builtin.js +0 -1686
- package/dist/builtin/builtin.js.map +0 -1
package/compiler/type.go
CHANGED
|
@@ -4,17 +4,34 @@ import (
|
|
|
4
4
|
"fmt"
|
|
5
5
|
"go/ast"
|
|
6
6
|
"go/types"
|
|
7
|
-
"sort"
|
|
8
7
|
"strings"
|
|
9
8
|
)
|
|
10
9
|
|
|
10
|
+
// GoTypeContext specifies the context in which a Go type is being translated to TypeScript.
|
|
11
|
+
// This affects how certain types (especially pointers) are handled.
|
|
12
|
+
type GoTypeContext int
|
|
13
|
+
|
|
14
|
+
const (
|
|
15
|
+
// GoTypeContextGeneral is used for general type translation
|
|
16
|
+
GoTypeContextGeneral GoTypeContext = iota
|
|
17
|
+
// GoTypeContextFunctionReturn is used when translating types for function return values.
|
|
18
|
+
// In this context, pointer-to-struct types become `ClassName | null` instead of
|
|
19
|
+
// `$.Box<ClassName> | null` because function return values cannot be addressed.
|
|
20
|
+
GoTypeContextFunctionReturn
|
|
21
|
+
)
|
|
22
|
+
|
|
11
23
|
// WriteGoType is the main dispatcher for translating Go types to their TypeScript
|
|
12
24
|
// equivalents. It examines the type and delegates to more specialized type writer
|
|
13
25
|
// functions based on the specific Go type encountered.
|
|
14
26
|
//
|
|
27
|
+
// The context parameter controls how certain types (especially pointers) are handled:
|
|
28
|
+
// - GoTypeContextGeneral: Standard type translation
|
|
29
|
+
// - GoTypeContextFunctionReturn: Special handling for function return types where
|
|
30
|
+
// pointer-to-struct types become `ClassName | null` instead of `$.Box<ClassName> | null`
|
|
31
|
+
//
|
|
15
32
|
// It handles nil types as 'any' with a comment, and dispatches to appropriate
|
|
16
33
|
// type-specific writers for all other recognized Go types.
|
|
17
|
-
func (c *GoToTSCompiler) WriteGoType(typ types.Type) {
|
|
34
|
+
func (c *GoToTSCompiler) WriteGoType(typ types.Type, context GoTypeContext) {
|
|
18
35
|
if typ == nil {
|
|
19
36
|
c.tsw.WriteLiterally("any")
|
|
20
37
|
c.tsw.WriteCommentInline("nil type")
|
|
@@ -27,7 +44,11 @@ func (c *GoToTSCompiler) WriteGoType(typ types.Type) {
|
|
|
27
44
|
case *types.Named:
|
|
28
45
|
c.WriteNamedType(t)
|
|
29
46
|
case *types.Pointer:
|
|
30
|
-
|
|
47
|
+
if context == GoTypeContextFunctionReturn {
|
|
48
|
+
c.writePointerTypeForFunctionReturn(t)
|
|
49
|
+
} else {
|
|
50
|
+
c.WritePointerType(t)
|
|
51
|
+
}
|
|
31
52
|
case *types.Slice:
|
|
32
53
|
c.WriteSliceType(t)
|
|
33
54
|
case *types.Array:
|
|
@@ -43,7 +64,10 @@ func (c *GoToTSCompiler) WriteGoType(typ types.Type) {
|
|
|
43
64
|
case *types.Struct:
|
|
44
65
|
c.WriteStructType(t)
|
|
45
66
|
case *types.Alias:
|
|
46
|
-
c.WriteGoType(t.Underlying())
|
|
67
|
+
c.WriteGoType(t.Underlying(), context)
|
|
68
|
+
case *types.TypeParam:
|
|
69
|
+
// For type parameters, write the type parameter name (e.g., "T", "K", etc.)
|
|
70
|
+
c.tsw.WriteLiterally(t.Obj().Name())
|
|
47
71
|
default:
|
|
48
72
|
// For other types, just write "any" and add a comment
|
|
49
73
|
c.tsw.WriteLiterally("any")
|
|
@@ -51,12 +75,38 @@ func (c *GoToTSCompiler) WriteGoType(typ types.Type) {
|
|
|
51
75
|
}
|
|
52
76
|
}
|
|
53
77
|
|
|
78
|
+
// writePointerTypeForFunctionReturn translates a Go pointer type (*T) to its TypeScript
|
|
79
|
+
// equivalent for function return types. Unlike WritePointerType, this function
|
|
80
|
+
// handles pointer-to-struct types specially: they become `ClassName | null` instead
|
|
81
|
+
// of `$.Box<ClassName> | null` because function return values cannot be addressed.
|
|
82
|
+
func (c *GoToTSCompiler) writePointerTypeForFunctionReturn(t *types.Pointer) {
|
|
83
|
+
elemType := t.Elem()
|
|
84
|
+
|
|
85
|
+
// Check if the element type is a struct (directly or via a named type)
|
|
86
|
+
isStructType := false
|
|
87
|
+
if _, ok := elemType.Underlying().(*types.Struct); ok {
|
|
88
|
+
isStructType = true
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if isStructType {
|
|
92
|
+
// For pointer-to-struct in function returns, generate ClassName | null
|
|
93
|
+
c.WriteGoType(elemType, GoTypeContextFunctionReturn)
|
|
94
|
+
c.tsw.WriteLiterally(" | null")
|
|
95
|
+
} else {
|
|
96
|
+
// For pointer-to-primitive in function returns, still use boxing
|
|
97
|
+
c.tsw.WriteLiterally("$.Box<")
|
|
98
|
+
c.WriteGoType(elemType, GoTypeContextFunctionReturn)
|
|
99
|
+
c.tsw.WriteLiterally("> | null")
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
54
103
|
// WriteZeroValueForType writes the TypeScript representation of the zero value
|
|
55
104
|
// for a given Go type.
|
|
56
105
|
// It handles `types.Array` by recursively writing zero values for each element
|
|
57
106
|
// to form a TypeScript array literal (e.g., `[0, 0, 0]`).
|
|
58
107
|
// For `types.Basic` (like `bool`, `string`, numeric types), it writes the
|
|
59
108
|
// corresponding TypeScript zero value (`false`, `""`, `0`).
|
|
109
|
+
// For `[]byte`, it writes `new Uint8Array(0)`.
|
|
60
110
|
// Other types default to `null`. This function is primarily used for initializing
|
|
61
111
|
// arrays and variables where an explicit initializer is absent.
|
|
62
112
|
func (c *GoToTSCompiler) WriteZeroValueForType(typ any) {
|
|
@@ -97,9 +147,21 @@ func (c *GoToTSCompiler) WriteZeroValueForType(typ any) {
|
|
|
97
147
|
}
|
|
98
148
|
// For other named types, use the zero value of the underlying type
|
|
99
149
|
c.WriteZeroValueForType(t.Underlying())
|
|
150
|
+
case *types.Slice:
|
|
151
|
+
// Check if it's a []byte slice
|
|
152
|
+
if elem, ok := t.Elem().(*types.Basic); ok && elem.Kind() == types.Uint8 {
|
|
153
|
+
c.tsw.WriteLiterally("new Uint8Array(0)")
|
|
154
|
+
return
|
|
155
|
+
}
|
|
156
|
+
// For other slice types, default to null
|
|
157
|
+
c.tsw.WriteLiterally("null")
|
|
100
158
|
case *types.Struct:
|
|
101
159
|
// For anonymous struct types, initialize with {}
|
|
102
160
|
c.tsw.WriteLiterally("{}")
|
|
161
|
+
case *types.TypeParam:
|
|
162
|
+
// For type parameters, use null! (non-null assertion) to avoid TypeScript
|
|
163
|
+
// casting errors with union types like string | Uint8Array
|
|
164
|
+
c.tsw.WriteLiterally("null!")
|
|
103
165
|
default:
|
|
104
166
|
c.tsw.WriteLiterally("null")
|
|
105
167
|
}
|
|
@@ -140,14 +202,27 @@ func (c *GoToTSCompiler) WriteBasicType(t *types.Basic) {
|
|
|
140
202
|
|
|
141
203
|
// WriteNamedType translates a Go named type to its TypeScript equivalent.
|
|
142
204
|
// It specially handles the error interface as $.GoError, and uses the original
|
|
143
|
-
// type name for other named types.
|
|
205
|
+
// type name for other named types. For generic types, it includes type arguments.
|
|
144
206
|
func (c *GoToTSCompiler) WriteNamedType(t *types.Named) {
|
|
145
207
|
// Check if the named type is the error interface
|
|
146
208
|
if iface, ok := t.Underlying().(*types.Interface); ok && iface.String() == "interface{Error() string}" {
|
|
147
209
|
c.tsw.WriteLiterally("$.GoError")
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
210
|
+
return
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Use Obj().Name() for the original defined name
|
|
214
|
+
c.tsw.WriteLiterally(t.Obj().Name())
|
|
215
|
+
|
|
216
|
+
// For generic types, include type arguments
|
|
217
|
+
if t.TypeArgs() != nil && t.TypeArgs().Len() > 0 {
|
|
218
|
+
c.tsw.WriteLiterally("<")
|
|
219
|
+
for i := 0; i < t.TypeArgs().Len(); i++ {
|
|
220
|
+
if i > 0 {
|
|
221
|
+
c.tsw.WriteLiterally(", ")
|
|
222
|
+
}
|
|
223
|
+
c.WriteGoType(t.TypeArgs().At(i), GoTypeContextGeneral)
|
|
224
|
+
}
|
|
225
|
+
c.tsw.WriteLiterally(">")
|
|
151
226
|
}
|
|
152
227
|
}
|
|
153
228
|
|
|
@@ -155,22 +230,28 @@ func (c *GoToTSCompiler) WriteNamedType(t *types.Named) {
|
|
|
155
230
|
// It generates $.Box<T_ts> | null, where T_ts is the translated element type.
|
|
156
231
|
func (c *GoToTSCompiler) WritePointerType(t *types.Pointer) {
|
|
157
232
|
c.tsw.WriteLiterally("$.Box<")
|
|
158
|
-
c.WriteGoType(t.Elem())
|
|
233
|
+
c.WriteGoType(t.Elem(), GoTypeContextGeneral)
|
|
159
234
|
c.tsw.WriteLiterally("> | null") // Pointers are always nullable
|
|
160
235
|
}
|
|
161
236
|
|
|
162
237
|
// WriteSliceType translates a Go slice type ([]T) to its TypeScript equivalent.
|
|
163
238
|
// It generates $.Slice<T_ts>, where T_ts is the translated element type.
|
|
239
|
+
// For []byte, it generates Uint8Array.
|
|
164
240
|
func (c *GoToTSCompiler) WriteSliceType(t *types.Slice) {
|
|
241
|
+
// Check if it's a []byte slice
|
|
242
|
+
if elem, ok := t.Elem().(*types.Basic); ok && elem.Kind() == types.Uint8 {
|
|
243
|
+
c.tsw.WriteLiterally("Uint8Array")
|
|
244
|
+
return
|
|
245
|
+
}
|
|
165
246
|
c.tsw.WriteLiterally("$.Slice<")
|
|
166
|
-
c.WriteGoType(t.Elem())
|
|
247
|
+
c.WriteGoType(t.Elem(), GoTypeContextGeneral)
|
|
167
248
|
c.tsw.WriteLiterally(">")
|
|
168
249
|
}
|
|
169
250
|
|
|
170
251
|
// WriteArrayType translates a Go array type ([N]T) to its TypeScript equivalent.
|
|
171
252
|
// It generates T_ts[], where T_ts is the translated element type.
|
|
172
253
|
func (c *GoToTSCompiler) WriteArrayType(t *types.Array) {
|
|
173
|
-
c.WriteGoType(t.Elem())
|
|
254
|
+
c.WriteGoType(t.Elem(), GoTypeContextGeneral)
|
|
174
255
|
c.tsw.WriteLiterally("[]") // Arrays cannot be nil
|
|
175
256
|
}
|
|
176
257
|
|
|
@@ -179,18 +260,19 @@ func (c *GoToTSCompiler) WriteArrayType(t *types.Array) {
|
|
|
179
260
|
// and element types respectively.
|
|
180
261
|
func (c *GoToTSCompiler) WriteMapType(t *types.Map) {
|
|
181
262
|
c.tsw.WriteLiterally("Map<")
|
|
182
|
-
c.WriteGoType(t.Key())
|
|
263
|
+
c.WriteGoType(t.Key(), GoTypeContextGeneral)
|
|
183
264
|
c.tsw.WriteLiterally(", ")
|
|
184
|
-
c.WriteGoType(t.Elem())
|
|
265
|
+
c.WriteGoType(t.Elem(), GoTypeContextGeneral)
|
|
185
266
|
c.tsw.WriteLiterally(">")
|
|
186
267
|
}
|
|
187
268
|
|
|
188
269
|
// WriteChannelType translates a Go channel type (chan T) to its TypeScript equivalent.
|
|
189
|
-
// It generates $.Channel<T_ts
|
|
270
|
+
// It generates $.Channel<T_ts> | null, where T_ts is the translated element type.
|
|
271
|
+
// Channels are nilable in Go, so they are represented as nullable types in TypeScript.
|
|
190
272
|
func (c *GoToTSCompiler) WriteChannelType(t *types.Chan) {
|
|
191
273
|
c.tsw.WriteLiterally("$.Channel<")
|
|
192
|
-
c.WriteGoType(t.Elem())
|
|
193
|
-
c.tsw.WriteLiterally(">")
|
|
274
|
+
c.WriteGoType(t.Elem(), GoTypeContextGeneral)
|
|
275
|
+
c.tsw.WriteLiterally("> | null")
|
|
194
276
|
}
|
|
195
277
|
|
|
196
278
|
// WriteFuncType translates a Go function type (`ast.FuncType`) into a TypeScript
|
|
@@ -217,7 +299,7 @@ func (c *GoToTSCompiler) WriteFuncType(exp *ast.FuncType, isAsync bool) {
|
|
|
217
299
|
if len(exp.Results.List) == 1 && len(exp.Results.List[0].Names) == 0 {
|
|
218
300
|
// Single unnamed return type
|
|
219
301
|
typ := c.pkg.TypesInfo.TypeOf(exp.Results.List[0].Type)
|
|
220
|
-
c.WriteGoType(typ)
|
|
302
|
+
c.WriteGoType(typ, GoTypeContextFunctionReturn)
|
|
221
303
|
} else {
|
|
222
304
|
// Multiple or named return types -> tuple
|
|
223
305
|
c.tsw.WriteLiterally("[")
|
|
@@ -226,7 +308,7 @@ func (c *GoToTSCompiler) WriteFuncType(exp *ast.FuncType, isAsync bool) {
|
|
|
226
308
|
c.tsw.WriteLiterally(", ")
|
|
227
309
|
}
|
|
228
310
|
typ := c.pkg.TypesInfo.TypeOf(field.Type)
|
|
229
|
-
c.WriteGoType(typ)
|
|
311
|
+
c.WriteGoType(typ, GoTypeContextFunctionReturn)
|
|
230
312
|
}
|
|
231
313
|
c.tsw.WriteLiterally("]")
|
|
232
314
|
}
|
|
@@ -288,10 +370,10 @@ func (c *GoToTSCompiler) WriteSignatureType(t *types.Signature) {
|
|
|
288
370
|
c.tsw.WriteLiterally(": ")
|
|
289
371
|
|
|
290
372
|
if paramVariadic && paramIsSlice {
|
|
291
|
-
c.WriteGoType(paramSlice.Elem())
|
|
373
|
+
c.WriteGoType(paramSlice.Elem(), GoTypeContextGeneral)
|
|
292
374
|
c.tsw.WriteLiterally("[]")
|
|
293
375
|
} else {
|
|
294
|
-
c.WriteGoType(param.Type())
|
|
376
|
+
c.WriteGoType(param.Type(), GoTypeContextGeneral)
|
|
295
377
|
}
|
|
296
378
|
}
|
|
297
379
|
c.tsw.WriteLiterally(")")
|
|
@@ -302,7 +384,7 @@ func (c *GoToTSCompiler) WriteSignatureType(t *types.Signature) {
|
|
|
302
384
|
if results.Len() == 0 {
|
|
303
385
|
c.tsw.WriteLiterally("void")
|
|
304
386
|
} else if results.Len() == 1 {
|
|
305
|
-
c.WriteGoType(results.At(0).Type())
|
|
387
|
+
c.WriteGoType(results.At(0).Type(), GoTypeContextFunctionReturn)
|
|
306
388
|
} else {
|
|
307
389
|
// Multiple return values -> tuple
|
|
308
390
|
c.tsw.WriteLiterally("[")
|
|
@@ -310,7 +392,7 @@ func (c *GoToTSCompiler) WriteSignatureType(t *types.Signature) {
|
|
|
310
392
|
if i > 0 {
|
|
311
393
|
c.tsw.WriteLiterally(", ")
|
|
312
394
|
}
|
|
313
|
-
c.WriteGoType(results.At(i).Type())
|
|
395
|
+
c.WriteGoType(results.At(i).Type(), GoTypeContextFunctionReturn)
|
|
314
396
|
}
|
|
315
397
|
c.tsw.WriteLiterally("]")
|
|
316
398
|
}
|
|
@@ -378,7 +460,7 @@ func (c *GoToTSCompiler) writeInterfaceStructure(iface *types.Interface, astNode
|
|
|
378
460
|
}
|
|
379
461
|
c.tsw.WriteLiterally(paramName)
|
|
380
462
|
c.tsw.WriteLiterally(": ")
|
|
381
|
-
c.WriteGoType(paramVar.Type()) // Recursive call for param type
|
|
463
|
+
c.WriteGoType(paramVar.Type(), GoTypeContextGeneral) // Recursive call for param type
|
|
382
464
|
}
|
|
383
465
|
c.tsw.WriteLiterally(")") // End params
|
|
384
466
|
|
|
@@ -388,14 +470,14 @@ func (c *GoToTSCompiler) writeInterfaceStructure(iface *types.Interface, astNode
|
|
|
388
470
|
if results.Len() == 0 {
|
|
389
471
|
c.tsw.WriteLiterally("void")
|
|
390
472
|
} else if results.Len() == 1 {
|
|
391
|
-
c.WriteGoType(results.At(0).Type()) // Recursive call for result type
|
|
473
|
+
c.WriteGoType(results.At(0).Type(), GoTypeContextFunctionReturn) // Recursive call for result type
|
|
392
474
|
} else {
|
|
393
475
|
c.tsw.WriteLiterally("[")
|
|
394
476
|
for j := 0; j < results.Len(); j++ {
|
|
395
477
|
if j > 0 {
|
|
396
478
|
c.tsw.WriteLiterally(", ")
|
|
397
479
|
}
|
|
398
|
-
c.WriteGoType(results.At(j).Type()) // Recursive call for result type
|
|
480
|
+
c.WriteGoType(results.At(j).Type(), GoTypeContextFunctionReturn) // Recursive call for result type
|
|
399
481
|
}
|
|
400
482
|
c.tsw.WriteLiterally("]")
|
|
401
483
|
}
|
|
@@ -419,7 +501,7 @@ func (c *GoToTSCompiler) writeInterfaceStructure(iface *types.Interface, astNode
|
|
|
419
501
|
// When WriteGoType encounters an interface, it will call WriteInterfaceType
|
|
420
502
|
// which will pass nil for astNode, so comments for deeply embedded interface literals
|
|
421
503
|
// might not be available unless they are named types.
|
|
422
|
-
c.WriteGoType(embeddedType)
|
|
504
|
+
c.WriteGoType(embeddedType, GoTypeContextGeneral)
|
|
423
505
|
}
|
|
424
506
|
}
|
|
425
507
|
}
|
|
@@ -433,107 +515,10 @@ func (c *GoToTSCompiler) getTypeString(goType types.Type) string {
|
|
|
433
515
|
var typeStr strings.Builder
|
|
434
516
|
writer := NewTSCodeWriter(&typeStr)
|
|
435
517
|
tempCompiler := NewGoToTSCompiler(writer, c.pkg, c.analysis)
|
|
436
|
-
tempCompiler.WriteGoType(goType)
|
|
518
|
+
tempCompiler.WriteGoType(goType, GoTypeContextGeneral)
|
|
437
519
|
return typeStr.String()
|
|
438
520
|
}
|
|
439
521
|
|
|
440
|
-
// generateFlattenedInitTypeString generates a TypeScript type string for the
|
|
441
|
-
// initialization object passed to a Go struct's constructor (`_init` method in TypeScript).
|
|
442
|
-
// The generated type is a `Partial`-like structure, `"{ Field1?: Type1, Field2?: Type2, ... }"`,
|
|
443
|
-
// including all direct and promoted fields of the `structType`.
|
|
444
|
-
// - It iterates through the direct fields of the `structType`. Exported fields
|
|
445
|
-
// are included with their TypeScript types (obtained via `WriteGoType`).
|
|
446
|
-
// - For anonymous (embedded) fields, it generates a type like `EmbeddedName?: ConstructorParameters<typeof EmbeddedName>[0]`,
|
|
447
|
-
// allowing initialization of the embedded struct's fields directly within the outer struct's initializer.
|
|
448
|
-
// - It then uses `types.NewMethodSet` and checks for `types.Var` objects that are fields
|
|
449
|
-
// to find promoted fields from embedded structs, adding them to the type string if not already present.
|
|
450
|
-
//
|
|
451
|
-
// The resulting string is sorted by field name for deterministic output and represents
|
|
452
|
-
// the shape of the object expected by the struct's TypeScript constructor.
|
|
453
|
-
func (c *GoToTSCompiler) generateFlattenedInitTypeString(structType *types.Named) string {
|
|
454
|
-
if structType == nil {
|
|
455
|
-
return "{}"
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
// Use a map to collect unique field names and their types
|
|
459
|
-
fieldMap := make(map[string]string)
|
|
460
|
-
embeddedTypeMap := make(map[string]string) // Stores TS type string for embedded struct initializers
|
|
461
|
-
|
|
462
|
-
underlying, ok := structType.Underlying().(*types.Struct)
|
|
463
|
-
if !ok {
|
|
464
|
-
return "{}"
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
// First add the direct fields and track embedded types
|
|
468
|
-
for i := 0; i < underlying.NumFields(); i++ {
|
|
469
|
-
field := underlying.Field(i)
|
|
470
|
-
fieldName := field.Name()
|
|
471
|
-
|
|
472
|
-
if !field.Exported() && field.Pkg() != c.pkg.Types {
|
|
473
|
-
continue
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
if field.Anonymous() {
|
|
477
|
-
fieldType := field.Type()
|
|
478
|
-
isPtr := false
|
|
479
|
-
if ptr, ok := fieldType.(*types.Pointer); ok {
|
|
480
|
-
fieldType = ptr.Elem()
|
|
481
|
-
isPtr = true
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
if named, ok := fieldType.(*types.Named); ok {
|
|
485
|
-
embeddedName := named.Obj().Name()
|
|
486
|
-
// For embedded structs, the init type should allow providing fields of the embedded struct,
|
|
487
|
-
// or the embedded struct itself.
|
|
488
|
-
// We generate Partial<EmbeddedStructFields> | EmbeddedStructType
|
|
489
|
-
// This is complex. For now, let's use ConstructorParameters as before for simplicity,
|
|
490
|
-
// or allow the embedded struct type itself.
|
|
491
|
-
// The example `Person?: ConstructorParameters<typeof Person>[0]` is for the fields.
|
|
492
|
-
// Let's try to generate a type that allows either the embedded struct instance or its fields.
|
|
493
|
-
// This might be: `Partial<FlattenedInitType<EmbeddedName>> | EmbeddedName`
|
|
494
|
-
// For now, stick to the simpler `ConstructorParameters<typeof %s>[0]` which implies field-based init.
|
|
495
|
-
// Or, more simply, the type of the embedded struct itself if it's a pointer.
|
|
496
|
-
if isPtr {
|
|
497
|
-
embeddedTypeMap[c.getEmbeddedFieldKeyName(field.Type())] = c.getTypeString(field.Type()) // MyEmbeddedType | null
|
|
498
|
-
} else {
|
|
499
|
-
// For value-type embedded structs, allow initializing with its fields.
|
|
500
|
-
// This requires getting the flattened init type for the embedded struct.
|
|
501
|
-
// This could lead to recursion if not handled carefully.
|
|
502
|
-
// A simpler approach for now: use the embedded struct's own type.
|
|
503
|
-
// embeddedTypeMap[c.getEmbeddedFieldKeyName(field.Type())] = c.getTypeString(field.Type())
|
|
504
|
-
// Or, using ConstructorParameters to allow field-based initialization:
|
|
505
|
-
embeddedTypeMap[c.getEmbeddedFieldKeyName(field.Type())] = fmt.Sprintf("Partial<ConstructorParameters<typeof %s>[0]>", embeddedName)
|
|
506
|
-
}
|
|
507
|
-
}
|
|
508
|
-
continue
|
|
509
|
-
}
|
|
510
|
-
fieldMap[fieldName] = c.getTypeString(field.Type())
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
// Promoted fields (handled by Go's embedding, init should use direct/embedded names)
|
|
514
|
-
// The current logic for `generateFlattenedInitTypeString` seems to focus on top-level
|
|
515
|
-
// settable properties in the constructor. Promoted fields are accessed via `this.promotedField`,
|
|
516
|
-
// not typically set directly in `init?` unless the embedded struct itself is named in `init?`.
|
|
517
|
-
|
|
518
|
-
// Add embedded types to the field map (these are the names of the embedded structs themselves)
|
|
519
|
-
for embeddedName, embeddedTSType := range embeddedTypeMap {
|
|
520
|
-
fieldMap[embeddedName] = embeddedTSType
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
var fieldNames []string
|
|
524
|
-
for name := range fieldMap {
|
|
525
|
-
fieldNames = append(fieldNames, name)
|
|
526
|
-
}
|
|
527
|
-
sort.Strings(fieldNames)
|
|
528
|
-
|
|
529
|
-
var fieldDefs []string
|
|
530
|
-
for _, fieldName := range fieldNames {
|
|
531
|
-
fieldDefs = append(fieldDefs, fmt.Sprintf("%s?: %s", fieldName, fieldMap[fieldName]))
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
return "{" + strings.Join(fieldDefs, ", ") + "}"
|
|
535
|
-
}
|
|
536
|
-
|
|
537
522
|
// WriteStructType translates a Go struct type definition (`ast.StructType`)
|
|
538
523
|
// into a TypeScript anonymous object type (e.g., `{ Field1: Type1; Field2: Type2 }`).
|
|
539
524
|
// If the struct has no fields, it writes `{}`. Otherwise, it delegates to
|
|
@@ -550,7 +535,84 @@ func (c *GoToTSCompiler) WriteStructType(t *types.Struct) {
|
|
|
550
535
|
c.tsw.WriteLiterally("; ")
|
|
551
536
|
}
|
|
552
537
|
c.tsw.WriteLiterally(field.Name() + "?: ")
|
|
553
|
-
c.WriteGoType(field.Type())
|
|
538
|
+
c.WriteGoType(field.Type(), GoTypeContextGeneral)
|
|
554
539
|
}
|
|
555
540
|
c.tsw.WriteLiterally(" }")
|
|
556
541
|
}
|
|
542
|
+
|
|
543
|
+
// WriteTypeParameters translates Go type parameters to TypeScript generic parameters.
|
|
544
|
+
// It handles the TypeParams field of ast.FuncDecl and ast.TypeSpec to generate
|
|
545
|
+
// TypeScript generic parameter lists like <T extends SomeConstraint, U extends OtherConstraint>.
|
|
546
|
+
func (c *GoToTSCompiler) WriteTypeParameters(typeParams *ast.FieldList) {
|
|
547
|
+
if typeParams == nil || len(typeParams.List) == 0 {
|
|
548
|
+
return
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
c.tsw.WriteLiterally("<")
|
|
552
|
+
for i, field := range typeParams.List {
|
|
553
|
+
if i > 0 {
|
|
554
|
+
c.tsw.WriteLiterally(", ")
|
|
555
|
+
}
|
|
556
|
+
// Write each type parameter name and constraint
|
|
557
|
+
for j, name := range field.Names {
|
|
558
|
+
if j > 0 {
|
|
559
|
+
c.tsw.WriteLiterally(", ")
|
|
560
|
+
}
|
|
561
|
+
c.tsw.WriteLiterally(name.Name)
|
|
562
|
+
|
|
563
|
+
// Write constraint if present
|
|
564
|
+
if field.Type != nil {
|
|
565
|
+
c.tsw.WriteLiterally(" extends ")
|
|
566
|
+
c.WriteTypeConstraint(field.Type)
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
c.tsw.WriteLiterally(">")
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
// WriteTypeConstraint translates Go type constraints to TypeScript constraint expressions.
|
|
574
|
+
// It handles different constraint types including:
|
|
575
|
+
// - Union types: []byte | string -> string | Uint8Array
|
|
576
|
+
// - Interface types: interface{Method()} -> {Method(): void}
|
|
577
|
+
// - Basic types: any -> any, comparable -> $.Comparable
|
|
578
|
+
func (c *GoToTSCompiler) WriteTypeConstraint(constraint ast.Expr) {
|
|
579
|
+
switch t := constraint.(type) {
|
|
580
|
+
case *ast.Ident:
|
|
581
|
+
// Handle predeclared constraints
|
|
582
|
+
switch t.Name {
|
|
583
|
+
case "any":
|
|
584
|
+
c.tsw.WriteLiterally("any")
|
|
585
|
+
case "comparable":
|
|
586
|
+
c.tsw.WriteLiterally("$.Comparable")
|
|
587
|
+
default:
|
|
588
|
+
// Use the type directly
|
|
589
|
+
c.WriteTypeExpr(t)
|
|
590
|
+
}
|
|
591
|
+
case *ast.BinaryExpr:
|
|
592
|
+
// Handle union types like []byte | string
|
|
593
|
+
if t.Op.String() == "|" {
|
|
594
|
+
c.WriteTypeConstraint(t.X)
|
|
595
|
+
c.tsw.WriteLiterally(" | ")
|
|
596
|
+
c.WriteTypeConstraint(t.Y)
|
|
597
|
+
} else {
|
|
598
|
+
// Fallback for other binary expressions
|
|
599
|
+
c.WriteTypeExpr(constraint)
|
|
600
|
+
}
|
|
601
|
+
case *ast.InterfaceType:
|
|
602
|
+
// Handle interface constraints
|
|
603
|
+
c.WriteTypeExpr(constraint)
|
|
604
|
+
case *ast.ArrayType:
|
|
605
|
+
// Handle []byte specifically
|
|
606
|
+
if ident, ok := t.Elt.(*ast.Ident); ok && ident.Name == "byte" {
|
|
607
|
+
c.tsw.WriteLiterally("Uint8Array")
|
|
608
|
+
} else {
|
|
609
|
+
c.WriteTypeExpr(constraint)
|
|
610
|
+
}
|
|
611
|
+
case *ast.SliceExpr:
|
|
612
|
+
// Handle slice types in constraints
|
|
613
|
+
c.WriteTypeExpr(constraint)
|
|
614
|
+
default:
|
|
615
|
+
// Fallback: use the standard type expression writer
|
|
616
|
+
c.WriteTypeExpr(constraint)
|
|
617
|
+
}
|
|
618
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "goscript",
|
|
3
3
|
"description": "Go to TypeScript transpiler",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.23",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Aperture Robotics LLC.",
|
|
7
7
|
"email": "support@aperture.us",
|
|
@@ -34,10 +34,10 @@
|
|
|
34
34
|
"default": "./dist/compiler/index.js"
|
|
35
35
|
}
|
|
36
36
|
},
|
|
37
|
-
"./builtin": {
|
|
37
|
+
"./gs/builtin": {
|
|
38
38
|
"import": {
|
|
39
|
-
"types": "./dist/builtin/builtin.d.ts",
|
|
40
|
-
"default": "./dist/builtin/builtin.js"
|
|
39
|
+
"types": "./dist/gs/builtin/builtin.d.ts",
|
|
40
|
+
"default": "./dist/gs/builtin/builtin.js"
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
43
|
},
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"format": "npm run format:go && npm run format:js && npm run format:config",
|
|
53
53
|
"format:config": "prettier --write tsconfig.json package.json",
|
|
54
54
|
"format:go": "gofumpt -w .",
|
|
55
|
-
"format:js": "prettier --write './{src,
|
|
55
|
+
"format:js": "prettier --write './{src,gs,example}/**/(*.ts|*.tsx|*.html|*.css|*.scss)'",
|
|
56
56
|
"release": "npm run release:version && npm run release:commit",
|
|
57
57
|
"release:minor": "npm run release:version:minor && npm run release:commit",
|
|
58
58
|
"release:version": "npm version patch -m \"release: v%s\" --no-git-tag-version",
|
package/builtin/builtin.go
DELETED