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.
Files changed (66) hide show
  1. package/README.md +1 -1
  2. package/cmd/goscript/cmd_compile.go +3 -3
  3. package/compiler/analysis.go +302 -182
  4. package/compiler/analysis_test.go +220 -0
  5. package/compiler/assignment.go +42 -43
  6. package/compiler/builtin_test.go +102 -0
  7. package/compiler/compiler.go +117 -29
  8. package/compiler/compiler_test.go +36 -8
  9. package/compiler/composite-lit.go +133 -53
  10. package/compiler/config.go +7 -3
  11. package/compiler/config_test.go +6 -33
  12. package/compiler/decl.go +36 -0
  13. package/compiler/expr-call.go +116 -60
  14. package/compiler/expr-selector.go +88 -43
  15. package/compiler/expr-star.go +57 -65
  16. package/compiler/expr-type.go +132 -5
  17. package/compiler/expr-value.go +8 -38
  18. package/compiler/expr.go +326 -30
  19. package/compiler/field.go +3 -3
  20. package/compiler/lit.go +34 -2
  21. package/compiler/primitive.go +19 -12
  22. package/compiler/spec-struct.go +140 -9
  23. package/compiler/spec-value.go +119 -41
  24. package/compiler/spec.go +21 -6
  25. package/compiler/stmt-assign.go +65 -3
  26. package/compiler/stmt-for.go +11 -0
  27. package/compiler/stmt-range.go +119 -11
  28. package/compiler/stmt-select.go +211 -0
  29. package/compiler/stmt-type-switch.go +147 -0
  30. package/compiler/stmt.go +175 -238
  31. package/compiler/type-assert.go +125 -379
  32. package/compiler/type.go +216 -129
  33. package/dist/gs/builtin/builtin.js +37 -0
  34. package/dist/gs/builtin/builtin.js.map +1 -0
  35. package/dist/gs/builtin/channel.js +471 -0
  36. package/dist/gs/builtin/channel.js.map +1 -0
  37. package/dist/gs/builtin/defer.js +54 -0
  38. package/dist/gs/builtin/defer.js.map +1 -0
  39. package/dist/gs/builtin/io.js +15 -0
  40. package/dist/gs/builtin/io.js.map +1 -0
  41. package/dist/gs/builtin/map.js +44 -0
  42. package/dist/gs/builtin/map.js.map +1 -0
  43. package/dist/gs/builtin/slice.js +799 -0
  44. package/dist/gs/builtin/slice.js.map +1 -0
  45. package/dist/gs/builtin/type.js +745 -0
  46. package/dist/gs/builtin/type.js.map +1 -0
  47. package/dist/gs/builtin/varRef.js +14 -0
  48. package/dist/gs/builtin/varRef.js.map +1 -0
  49. package/dist/gs/context/context.js +55 -0
  50. package/dist/gs/context/context.js.map +1 -0
  51. package/dist/gs/context/index.js +2 -0
  52. package/dist/gs/context/index.js.map +1 -0
  53. package/dist/gs/runtime/index.js +2 -0
  54. package/dist/gs/runtime/index.js.map +1 -0
  55. package/dist/gs/runtime/runtime.js +158 -0
  56. package/dist/gs/runtime/runtime.js.map +1 -0
  57. package/dist/gs/time/index.js +2 -0
  58. package/dist/gs/time/index.js.map +1 -0
  59. package/dist/gs/time/time.js +115 -0
  60. package/dist/gs/time/time.js.map +1 -0
  61. package/package.json +7 -6
  62. package/builtin/builtin.go +0 -11
  63. package/builtin/builtin.ts +0 -2379
  64. package/dist/builtin/builtin.d.ts +0 -513
  65. package/dist/builtin/builtin.js +0 -1686
  66. 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
- c.WritePointerType(t)
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
- } else {
149
- // Use Obj().Name() for the original defined name
150
- c.tsw.WriteLiterally(t.Obj().Name())
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
- // It generates $.Box<T_ts> | null, where T_ts is the translated element type.
156
- func (c *GoToTSCompiler) WritePointerType(t *types.Pointer) {
157
- c.tsw.WriteLiterally("$.Box<")
158
- c.WriteGoType(t.Elem())
159
- c.tsw.WriteLiterally("> | null") // Pointers are always nullable
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>, where T_ts is the translated element type.
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"}