goscript 0.0.22 → 0.0.24
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/README.md +1 -1
- package/cmd/goscript/cmd_compile.go +3 -3
- package/compiler/analysis.go +302 -182
- package/compiler/analysis_test.go +220 -0
- package/compiler/assignment.go +42 -43
- package/compiler/builtin_test.go +102 -0
- package/compiler/compiler.go +117 -29
- package/compiler/compiler_test.go +36 -8
- package/compiler/composite-lit.go +133 -53
- package/compiler/config.go +7 -3
- package/compiler/config_test.go +6 -33
- package/compiler/decl.go +36 -0
- package/compiler/expr-call.go +116 -60
- package/compiler/expr-selector.go +88 -43
- package/compiler/expr-star.go +57 -65
- package/compiler/expr-type.go +132 -5
- package/compiler/expr-value.go +8 -38
- package/compiler/expr.go +326 -30
- package/compiler/field.go +3 -3
- package/compiler/lit.go +34 -2
- package/compiler/primitive.go +19 -12
- package/compiler/spec-struct.go +140 -9
- package/compiler/spec-value.go +119 -41
- package/compiler/spec.go +21 -6
- package/compiler/stmt-assign.go +65 -3
- package/compiler/stmt-for.go +11 -0
- package/compiler/stmt-range.go +119 -11
- package/compiler/stmt-select.go +211 -0
- package/compiler/stmt-type-switch.go +147 -0
- package/compiler/stmt.go +175 -238
- package/compiler/type-assert.go +125 -379
- package/compiler/type.go +216 -129
- package/dist/gs/builtin/builtin.js +37 -0
- package/dist/gs/builtin/builtin.js.map +1 -0
- package/dist/gs/builtin/channel.js +471 -0
- package/dist/gs/builtin/channel.js.map +1 -0
- package/dist/gs/builtin/defer.js +54 -0
- package/dist/gs/builtin/defer.js.map +1 -0
- package/dist/gs/builtin/io.js +15 -0
- package/dist/gs/builtin/io.js.map +1 -0
- package/dist/gs/builtin/map.js +44 -0
- package/dist/gs/builtin/map.js.map +1 -0
- package/dist/gs/builtin/slice.js +799 -0
- package/dist/gs/builtin/slice.js.map +1 -0
- package/dist/gs/builtin/type.js +745 -0
- package/dist/gs/builtin/type.js.map +1 -0
- package/dist/gs/builtin/varRef.js +14 -0
- package/dist/gs/builtin/varRef.js.map +1 -0
- package/dist/gs/context/context.js +55 -0
- package/dist/gs/context/context.js.map +1 -0
- package/dist/gs/context/index.js +2 -0
- package/dist/gs/context/index.js.map +1 -0
- package/dist/gs/runtime/index.js +2 -0
- package/dist/gs/runtime/index.js.map +1 -0
- package/dist/gs/runtime/runtime.js +158 -0
- package/dist/gs/runtime/runtime.js.map +1 -0
- package/dist/gs/time/index.js +2 -0
- package/dist/gs/time/index.js.map +1 -0
- package/dist/gs/time/time.js +115 -0
- package/dist/gs/time/time.js.map +1 -0
- package/package.json +7 -6
- 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
|
+
// `$.VarRef<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 `$.VarRef<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, context)
|
|
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 `$.VarRef<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 varRefing
|
|
97
|
+
c.tsw.WriteLiterally("$.VarRef<")
|
|
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,37 +202,81 @@ 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
|
|
|
154
229
|
// WritePointerType translates a Go pointer type (*T) to its TypeScript equivalent.
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
230
|
+
func (c *GoToTSCompiler) WritePointerType(t *types.Pointer, context GoTypeContext) {
|
|
231
|
+
elemGoType := t.Elem()
|
|
232
|
+
underlyingElemGoType := elemGoType.Underlying()
|
|
233
|
+
|
|
234
|
+
// Handle pointers to functions: *func(...) -> func(...) | null
|
|
235
|
+
if _, isSignature := underlyingElemGoType.(*types.Signature); isSignature {
|
|
236
|
+
c.WriteGoType(elemGoType, context) // Write the function signature itself, pass context
|
|
237
|
+
c.tsw.WriteLiterally(" | null") // Function pointers are nullable
|
|
238
|
+
return
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Handle pointers to structs or interfaces: *MyStruct -> MyStruct | null
|
|
242
|
+
_, isStruct := underlyingElemGoType.(*types.Struct)
|
|
243
|
+
_, isInterface := underlyingElemGoType.(*types.Interface)
|
|
244
|
+
|
|
245
|
+
if isStruct || isInterface {
|
|
246
|
+
// For pointers to structs or interfaces, the TS type is StructName | null or InterfaceName | null.
|
|
247
|
+
// This aligns with VAR_REFS.md and JS/TS object reference semantics.
|
|
248
|
+
// TODO If the target variable is boxed, we have to wrap with VarRef as well?
|
|
249
|
+
c.WriteGoType(elemGoType, context) // Write the struct/interface type directly, pass context
|
|
250
|
+
c.tsw.WriteLiterally(" | null")
|
|
251
|
+
} else {
|
|
252
|
+
// For pointers to other types (primitives, slices, maps, other pointers like **MyStruct),
|
|
253
|
+
// they are generally represented as $.VarRef<T_ts> | null.
|
|
254
|
+
// Example: *int -> $.VarRef<number> | null
|
|
255
|
+
// Example: **MyStruct -> $.VarRef<MyStruct | null> | null (recursive call handles inner part)
|
|
256
|
+
c.tsw.WriteLiterally("$.VarRef<")
|
|
257
|
+
c.WriteGoType(elemGoType, context) // Translate element type, pass context
|
|
258
|
+
c.tsw.WriteLiterally("> | null") // Pointers are always nullable
|
|
259
|
+
}
|
|
160
260
|
}
|
|
161
261
|
|
|
162
262
|
// WriteSliceType translates a Go slice type ([]T) to its TypeScript equivalent.
|
|
163
263
|
// It generates $.Slice<T_ts>, where T_ts is the translated element type.
|
|
264
|
+
// For []byte, it generates Uint8Array.
|
|
164
265
|
func (c *GoToTSCompiler) WriteSliceType(t *types.Slice) {
|
|
266
|
+
// Check if it's a []byte slice
|
|
267
|
+
if elem, ok := t.Elem().(*types.Basic); ok && elem.Kind() == types.Uint8 {
|
|
268
|
+
c.tsw.WriteLiterally("Uint8Array")
|
|
269
|
+
return
|
|
270
|
+
}
|
|
165
271
|
c.tsw.WriteLiterally("$.Slice<")
|
|
166
|
-
c.WriteGoType(t.Elem())
|
|
272
|
+
c.WriteGoType(t.Elem(), GoTypeContextGeneral)
|
|
167
273
|
c.tsw.WriteLiterally(">")
|
|
168
274
|
}
|
|
169
275
|
|
|
170
276
|
// WriteArrayType translates a Go array type ([N]T) to its TypeScript equivalent.
|
|
171
277
|
// It generates T_ts[], where T_ts is the translated element type.
|
|
172
278
|
func (c *GoToTSCompiler) WriteArrayType(t *types.Array) {
|
|
173
|
-
c.WriteGoType(t.Elem())
|
|
279
|
+
c.WriteGoType(t.Elem(), GoTypeContextGeneral)
|
|
174
280
|
c.tsw.WriteLiterally("[]") // Arrays cannot be nil
|
|
175
281
|
}
|
|
176
282
|
|
|
@@ -179,18 +285,19 @@ func (c *GoToTSCompiler) WriteArrayType(t *types.Array) {
|
|
|
179
285
|
// and element types respectively.
|
|
180
286
|
func (c *GoToTSCompiler) WriteMapType(t *types.Map) {
|
|
181
287
|
c.tsw.WriteLiterally("Map<")
|
|
182
|
-
c.WriteGoType(t.Key())
|
|
288
|
+
c.WriteGoType(t.Key(), GoTypeContextGeneral)
|
|
183
289
|
c.tsw.WriteLiterally(", ")
|
|
184
|
-
c.WriteGoType(t.Elem())
|
|
290
|
+
c.WriteGoType(t.Elem(), GoTypeContextGeneral)
|
|
185
291
|
c.tsw.WriteLiterally(">")
|
|
186
292
|
}
|
|
187
293
|
|
|
188
294
|
// WriteChannelType translates a Go channel type (chan T) to its TypeScript equivalent.
|
|
189
|
-
// It generates $.Channel<T_ts
|
|
295
|
+
// It generates $.Channel<T_ts> | null, where T_ts is the translated element type.
|
|
296
|
+
// Channels are nilable in Go, so they are represented as nullable types in TypeScript.
|
|
190
297
|
func (c *GoToTSCompiler) WriteChannelType(t *types.Chan) {
|
|
191
298
|
c.tsw.WriteLiterally("$.Channel<")
|
|
192
|
-
c.WriteGoType(t.Elem())
|
|
193
|
-
c.tsw.WriteLiterally(">")
|
|
299
|
+
c.WriteGoType(t.Elem(), GoTypeContextGeneral)
|
|
300
|
+
c.tsw.WriteLiterally("> | null")
|
|
194
301
|
}
|
|
195
302
|
|
|
196
303
|
// WriteFuncType translates a Go function type (`ast.FuncType`) into a TypeScript
|
|
@@ -217,7 +324,7 @@ func (c *GoToTSCompiler) WriteFuncType(exp *ast.FuncType, isAsync bool) {
|
|
|
217
324
|
if len(exp.Results.List) == 1 && len(exp.Results.List[0].Names) == 0 {
|
|
218
325
|
// Single unnamed return type
|
|
219
326
|
typ := c.pkg.TypesInfo.TypeOf(exp.Results.List[0].Type)
|
|
220
|
-
c.WriteGoType(typ)
|
|
327
|
+
c.WriteGoType(typ, GoTypeContextFunctionReturn)
|
|
221
328
|
} else {
|
|
222
329
|
// Multiple or named return types -> tuple
|
|
223
330
|
c.tsw.WriteLiterally("[")
|
|
@@ -226,7 +333,7 @@ func (c *GoToTSCompiler) WriteFuncType(exp *ast.FuncType, isAsync bool) {
|
|
|
226
333
|
c.tsw.WriteLiterally(", ")
|
|
227
334
|
}
|
|
228
335
|
typ := c.pkg.TypesInfo.TypeOf(field.Type)
|
|
229
|
-
c.WriteGoType(typ)
|
|
336
|
+
c.WriteGoType(typ, GoTypeContextFunctionReturn)
|
|
230
337
|
}
|
|
231
338
|
c.tsw.WriteLiterally("]")
|
|
232
339
|
}
|
|
@@ -288,10 +395,10 @@ func (c *GoToTSCompiler) WriteSignatureType(t *types.Signature) {
|
|
|
288
395
|
c.tsw.WriteLiterally(": ")
|
|
289
396
|
|
|
290
397
|
if paramVariadic && paramIsSlice {
|
|
291
|
-
c.WriteGoType(paramSlice.Elem())
|
|
398
|
+
c.WriteGoType(paramSlice.Elem(), GoTypeContextGeneral)
|
|
292
399
|
c.tsw.WriteLiterally("[]")
|
|
293
400
|
} else {
|
|
294
|
-
c.WriteGoType(param.Type())
|
|
401
|
+
c.WriteGoType(param.Type(), GoTypeContextGeneral)
|
|
295
402
|
}
|
|
296
403
|
}
|
|
297
404
|
c.tsw.WriteLiterally(")")
|
|
@@ -302,7 +409,7 @@ func (c *GoToTSCompiler) WriteSignatureType(t *types.Signature) {
|
|
|
302
409
|
if results.Len() == 0 {
|
|
303
410
|
c.tsw.WriteLiterally("void")
|
|
304
411
|
} else if results.Len() == 1 {
|
|
305
|
-
c.WriteGoType(results.At(0).Type())
|
|
412
|
+
c.WriteGoType(results.At(0).Type(), GoTypeContextFunctionReturn)
|
|
306
413
|
} else {
|
|
307
414
|
// Multiple return values -> tuple
|
|
308
415
|
c.tsw.WriteLiterally("[")
|
|
@@ -310,7 +417,7 @@ func (c *GoToTSCompiler) WriteSignatureType(t *types.Signature) {
|
|
|
310
417
|
if i > 0 {
|
|
311
418
|
c.tsw.WriteLiterally(", ")
|
|
312
419
|
}
|
|
313
|
-
c.WriteGoType(results.At(i).Type())
|
|
420
|
+
c.WriteGoType(results.At(i).Type(), GoTypeContextFunctionReturn)
|
|
314
421
|
}
|
|
315
422
|
c.tsw.WriteLiterally("]")
|
|
316
423
|
}
|
|
@@ -378,7 +485,7 @@ func (c *GoToTSCompiler) writeInterfaceStructure(iface *types.Interface, astNode
|
|
|
378
485
|
}
|
|
379
486
|
c.tsw.WriteLiterally(paramName)
|
|
380
487
|
c.tsw.WriteLiterally(": ")
|
|
381
|
-
c.WriteGoType(paramVar.Type()) // Recursive call for param type
|
|
488
|
+
c.WriteGoType(paramVar.Type(), GoTypeContextGeneral) // Recursive call for param type
|
|
382
489
|
}
|
|
383
490
|
c.tsw.WriteLiterally(")") // End params
|
|
384
491
|
|
|
@@ -388,14 +495,14 @@ func (c *GoToTSCompiler) writeInterfaceStructure(iface *types.Interface, astNode
|
|
|
388
495
|
if results.Len() == 0 {
|
|
389
496
|
c.tsw.WriteLiterally("void")
|
|
390
497
|
} else if results.Len() == 1 {
|
|
391
|
-
c.WriteGoType(results.At(0).Type()) // Recursive call for result type
|
|
498
|
+
c.WriteGoType(results.At(0).Type(), GoTypeContextFunctionReturn) // Recursive call for result type
|
|
392
499
|
} else {
|
|
393
500
|
c.tsw.WriteLiterally("[")
|
|
394
501
|
for j := 0; j < results.Len(); j++ {
|
|
395
502
|
if j > 0 {
|
|
396
503
|
c.tsw.WriteLiterally(", ")
|
|
397
504
|
}
|
|
398
|
-
c.WriteGoType(results.At(j).Type()) // Recursive call for result type
|
|
505
|
+
c.WriteGoType(results.At(j).Type(), GoTypeContextFunctionReturn) // Recursive call for result type
|
|
399
506
|
}
|
|
400
507
|
c.tsw.WriteLiterally("]")
|
|
401
508
|
}
|
|
@@ -419,7 +526,7 @@ func (c *GoToTSCompiler) writeInterfaceStructure(iface *types.Interface, astNode
|
|
|
419
526
|
// When WriteGoType encounters an interface, it will call WriteInterfaceType
|
|
420
527
|
// which will pass nil for astNode, so comments for deeply embedded interface literals
|
|
421
528
|
// might not be available unless they are named types.
|
|
422
|
-
c.WriteGoType(embeddedType)
|
|
529
|
+
c.WriteGoType(embeddedType, GoTypeContextGeneral)
|
|
423
530
|
}
|
|
424
531
|
}
|
|
425
532
|
}
|
|
@@ -433,107 +540,10 @@ func (c *GoToTSCompiler) getTypeString(goType types.Type) string {
|
|
|
433
540
|
var typeStr strings.Builder
|
|
434
541
|
writer := NewTSCodeWriter(&typeStr)
|
|
435
542
|
tempCompiler := NewGoToTSCompiler(writer, c.pkg, c.analysis)
|
|
436
|
-
tempCompiler.WriteGoType(goType)
|
|
543
|
+
tempCompiler.WriteGoType(goType, GoTypeContextGeneral)
|
|
437
544
|
return typeStr.String()
|
|
438
545
|
}
|
|
439
546
|
|
|
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
547
|
// WriteStructType translates a Go struct type definition (`ast.StructType`)
|
|
538
548
|
// into a TypeScript anonymous object type (e.g., `{ Field1: Type1; Field2: Type2 }`).
|
|
539
549
|
// If the struct has no fields, it writes `{}`. Otherwise, it delegates to
|
|
@@ -550,7 +560,84 @@ func (c *GoToTSCompiler) WriteStructType(t *types.Struct) {
|
|
|
550
560
|
c.tsw.WriteLiterally("; ")
|
|
551
561
|
}
|
|
552
562
|
c.tsw.WriteLiterally(field.Name() + "?: ")
|
|
553
|
-
c.WriteGoType(field.Type())
|
|
563
|
+
c.WriteGoType(field.Type(), GoTypeContextGeneral)
|
|
554
564
|
}
|
|
555
565
|
c.tsw.WriteLiterally(" }")
|
|
556
566
|
}
|
|
567
|
+
|
|
568
|
+
// WriteTypeParameters translates Go type parameters to TypeScript generic parameters.
|
|
569
|
+
// It handles the TypeParams field of ast.FuncDecl and ast.TypeSpec to generate
|
|
570
|
+
// TypeScript generic parameter lists like <T extends SomeConstraint, U extends OtherConstraint>.
|
|
571
|
+
func (c *GoToTSCompiler) WriteTypeParameters(typeParams *ast.FieldList) {
|
|
572
|
+
if typeParams == nil || len(typeParams.List) == 0 {
|
|
573
|
+
return
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
c.tsw.WriteLiterally("<")
|
|
577
|
+
for i, field := range typeParams.List {
|
|
578
|
+
if i > 0 {
|
|
579
|
+
c.tsw.WriteLiterally(", ")
|
|
580
|
+
}
|
|
581
|
+
// Write each type parameter name and constraint
|
|
582
|
+
for j, name := range field.Names {
|
|
583
|
+
if j > 0 {
|
|
584
|
+
c.tsw.WriteLiterally(", ")
|
|
585
|
+
}
|
|
586
|
+
c.tsw.WriteLiterally(name.Name)
|
|
587
|
+
|
|
588
|
+
// Write constraint if present
|
|
589
|
+
if field.Type != nil {
|
|
590
|
+
c.tsw.WriteLiterally(" extends ")
|
|
591
|
+
c.WriteTypeConstraint(field.Type)
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
c.tsw.WriteLiterally(">")
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
// WriteTypeConstraint translates Go type constraints to TypeScript constraint expressions.
|
|
599
|
+
// It handles different constraint types including:
|
|
600
|
+
// - Union types: []byte | string -> string | Uint8Array
|
|
601
|
+
// - Interface types: interface{Method()} -> {Method(): void}
|
|
602
|
+
// - Basic types: any -> any, comparable -> $.Comparable
|
|
603
|
+
func (c *GoToTSCompiler) WriteTypeConstraint(constraint ast.Expr) {
|
|
604
|
+
switch t := constraint.(type) {
|
|
605
|
+
case *ast.Ident:
|
|
606
|
+
// Handle predeclared constraints
|
|
607
|
+
switch t.Name {
|
|
608
|
+
case "any":
|
|
609
|
+
c.tsw.WriteLiterally("any")
|
|
610
|
+
case "comparable":
|
|
611
|
+
c.tsw.WriteLiterally("$.Comparable")
|
|
612
|
+
default:
|
|
613
|
+
// Use the type directly
|
|
614
|
+
c.WriteTypeExpr(t)
|
|
615
|
+
}
|
|
616
|
+
case *ast.BinaryExpr:
|
|
617
|
+
// Handle union types like []byte | string
|
|
618
|
+
if t.Op.String() == "|" {
|
|
619
|
+
c.WriteTypeConstraint(t.X)
|
|
620
|
+
c.tsw.WriteLiterally(" | ")
|
|
621
|
+
c.WriteTypeConstraint(t.Y)
|
|
622
|
+
} else {
|
|
623
|
+
// Fallback for other binary expressions
|
|
624
|
+
c.WriteTypeExpr(constraint)
|
|
625
|
+
}
|
|
626
|
+
case *ast.InterfaceType:
|
|
627
|
+
// Handle interface constraints
|
|
628
|
+
c.WriteTypeExpr(constraint)
|
|
629
|
+
case *ast.ArrayType:
|
|
630
|
+
// Handle []byte specifically
|
|
631
|
+
if ident, ok := t.Elt.(*ast.Ident); ok && ident.Name == "byte" {
|
|
632
|
+
c.tsw.WriteLiterally("Uint8Array")
|
|
633
|
+
} else {
|
|
634
|
+
c.WriteTypeExpr(constraint)
|
|
635
|
+
}
|
|
636
|
+
case *ast.SliceExpr:
|
|
637
|
+
// Handle slice types in constraints
|
|
638
|
+
c.WriteTypeExpr(constraint)
|
|
639
|
+
default:
|
|
640
|
+
// Fallback: use the standard type expression writer
|
|
641
|
+
c.WriteTypeExpr(constraint)
|
|
642
|
+
}
|
|
643
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export * from './varRef.js';
|
|
2
|
+
export * from './channel.js';
|
|
3
|
+
export * from './defer.js';
|
|
4
|
+
export * from './io.js';
|
|
5
|
+
export * from './map.js';
|
|
6
|
+
export * from './slice.js';
|
|
7
|
+
export * from './type.js';
|
|
8
|
+
// Duration multiplication helper for time package operations
|
|
9
|
+
// Handles expressions like time.Hour * 24
|
|
10
|
+
export function multiplyDuration(duration, multiplier) {
|
|
11
|
+
// Check if duration has a multiply method (like our Duration class)
|
|
12
|
+
if (duration && typeof duration.multiply === 'function') {
|
|
13
|
+
return duration.multiply(multiplier);
|
|
14
|
+
}
|
|
15
|
+
// Check if duration has a valueOf method for numeric operations
|
|
16
|
+
if (duration && typeof duration.valueOf === 'function') {
|
|
17
|
+
const numValue = duration.valueOf();
|
|
18
|
+
// Return an object with the same structure but multiplied value
|
|
19
|
+
if (typeof numValue === 'number') {
|
|
20
|
+
// Try to create a new instance of the same type
|
|
21
|
+
if (duration.constructor) {
|
|
22
|
+
return new duration.constructor(numValue * multiplier);
|
|
23
|
+
}
|
|
24
|
+
// Fallback: return a simple object with valueOf
|
|
25
|
+
return {
|
|
26
|
+
valueOf: () => numValue * multiplier,
|
|
27
|
+
toString: () => (numValue * multiplier).toString() + "ns"
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
// Fallback for simple numeric values
|
|
32
|
+
if (typeof duration === 'number') {
|
|
33
|
+
return duration * multiplier;
|
|
34
|
+
}
|
|
35
|
+
throw new Error(`Cannot multiply duration of type ${typeof duration}`);
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=builtin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"builtin.js","sourceRoot":"","sources":["../../../gs/builtin/builtin.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAA;AAC3B,cAAc,cAAc,CAAA;AAC5B,cAAc,YAAY,CAAA;AAC1B,cAAc,SAAS,CAAA;AACvB,cAAc,UAAU,CAAA;AACxB,cAAc,YAAY,CAAA;AAC1B,cAAc,WAAW,CAAA;AAEzB,6DAA6D;AAC7D,0CAA0C;AAC1C,MAAM,UAAU,gBAAgB,CAAC,QAAa,EAAE,UAAkB,EAAO;IACvE,oEAAoE;IACpE,IAAI,QAAQ,IAAI,OAAO,QAAQ,CAAC,QAAQ,KAAK,UAAU,EAAE,CAAC;QACxD,OAAO,QAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;IACvC,CAAC;IAED,gEAAgE;IAChE,IAAI,QAAQ,IAAI,OAAO,QAAQ,CAAC,OAAO,KAAK,UAAU,EAAE,CAAC;QACvD,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO,EAAE,CAAC;QACpC,gEAAgE;QAChE,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;YACjC,gDAAgD;YAChD,IAAI,QAAQ,CAAC,WAAW,EAAE,CAAC;gBACzB,OAAO,IAAI,QAAQ,CAAC,WAAW,CAAC,QAAQ,GAAG,UAAU,CAAC,CAAC;YACzD,CAAC;YACD,gDAAgD;YAChD,OAAO;gBACL,OAAO,EAAE,GAAG,EAAE,CAAC,QAAQ,GAAG,UAAU;gBACpC,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC,QAAQ,GAAG,UAAU,CAAC,CAAC,QAAQ,EAAE,GAAG,IAAI;aAC1D,CAAC;QACJ,CAAC;IACH,CAAC;IAED,qCAAqC;IACrC,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACjC,OAAO,QAAQ,GAAG,UAAU,CAAC;IAC/B,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,oCAAoC,OAAO,QAAQ,EAAE,CAAC,CAAC;AAAA,CACxE"}
|