goscript 0.0.24 → 0.0.25

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 (65) hide show
  1. package/README.md +1 -1
  2. package/cmd/goscript/cmd_compile.go +17 -1
  3. package/compiler/analysis.go +1 -1
  4. package/compiler/builtin_test.go +2 -14
  5. package/compiler/compiler.go +231 -11
  6. package/compiler/decl.go +7 -1
  7. package/compiler/expr-call.go +212 -2
  8. package/compiler/expr.go +46 -2
  9. package/compiler/field.go +4 -4
  10. package/compiler/stmt-range.go +204 -1
  11. package/compiler/type.go +47 -4
  12. package/dist/gs/builtin/builtin.d.ts +9 -0
  13. package/dist/gs/builtin/builtin.js +9 -0
  14. package/dist/gs/builtin/builtin.js.map +1 -1
  15. package/dist/gs/builtin/channel.d.ts +193 -0
  16. package/dist/gs/builtin/channel.js.map +1 -1
  17. package/dist/gs/builtin/defer.d.ts +38 -0
  18. package/dist/gs/builtin/defer.js.map +1 -1
  19. package/dist/gs/builtin/index.d.ts +1 -0
  20. package/dist/gs/builtin/index.js +2 -0
  21. package/dist/gs/builtin/index.js.map +1 -0
  22. package/dist/gs/builtin/io.d.ts +16 -0
  23. package/dist/gs/builtin/io.js.map +1 -1
  24. package/dist/gs/builtin/map.d.ts +33 -0
  25. package/dist/gs/builtin/map.js.map +1 -1
  26. package/dist/gs/builtin/slice.d.ts +173 -0
  27. package/dist/gs/builtin/slice.js.map +1 -1
  28. package/dist/gs/builtin/type.d.ts +203 -0
  29. package/dist/gs/builtin/type.js +1 -2
  30. package/dist/gs/builtin/type.js.map +1 -1
  31. package/dist/gs/builtin/varRef.d.ts +14 -0
  32. package/dist/gs/builtin/varRef.js.map +1 -1
  33. package/dist/gs/cmp/index.d.ts +4 -0
  34. package/dist/gs/cmp/index.js +27 -0
  35. package/dist/gs/cmp/index.js.map +1 -0
  36. package/dist/gs/context/context.d.ts +26 -0
  37. package/dist/gs/context/context.js +287 -37
  38. package/dist/gs/context/context.js.map +1 -1
  39. package/dist/gs/context/index.d.ts +1 -0
  40. package/dist/gs/internal/goarch/index.d.ts +6 -0
  41. package/dist/gs/internal/goarch/index.js +14 -0
  42. package/dist/gs/internal/goarch/index.js.map +1 -0
  43. package/dist/gs/iter/index.d.ts +1 -0
  44. package/dist/gs/iter/index.js +2 -0
  45. package/dist/gs/iter/index.js.map +1 -0
  46. package/dist/gs/iter/iter.d.ts +4 -0
  47. package/dist/gs/iter/iter.js +91 -0
  48. package/dist/gs/iter/iter.js.map +1 -0
  49. package/dist/gs/math/bits/index.d.ts +47 -0
  50. package/dist/gs/math/bits/index.js +298 -0
  51. package/dist/gs/math/bits/index.js.map +1 -0
  52. package/dist/gs/runtime/index.d.ts +1 -0
  53. package/dist/gs/runtime/runtime.d.ts +41 -0
  54. package/dist/gs/runtime/runtime.js.map +1 -1
  55. package/dist/gs/slices/index.d.ts +1 -0
  56. package/dist/gs/slices/index.js +2 -0
  57. package/dist/gs/slices/index.js.map +1 -0
  58. package/dist/gs/slices/slices.d.ts +8 -0
  59. package/dist/gs/slices/slices.js +20 -0
  60. package/dist/gs/slices/slices.js.map +1 -0
  61. package/dist/gs/time/index.d.ts +1 -0
  62. package/dist/gs/time/time.d.ts +57 -0
  63. package/dist/gs/time/time.js +103 -10
  64. package/dist/gs/time/time.js.map +1 -1
  65. package/package.json +1 -1
@@ -111,6 +111,15 @@ func (c *GoToTSCompiler) WriteCallExpr(exp *ast.CallExpr) error {
111
111
  return errors.Errorf("unhandled cap call with incorrect number of arguments: %d != 1", len(exp.Args))
112
112
  }
113
113
  c.tsw.WriteLiterally("$.cap")
114
+ case "new":
115
+ // Translate new(T) to new T_ts()
116
+ if len(exp.Args) != 1 {
117
+ return errors.Errorf("unhandled new call with incorrect number of arguments: %d != 1", len(exp.Args))
118
+ }
119
+ c.tsw.WriteLiterally("new ")
120
+ c.WriteTypeExpr(exp.Args[0]) // This should write the TypeScript type T_ts
121
+ c.tsw.WriteLiterally("()")
122
+ return nil // Prevent falling through to generic argument handling
114
123
  case "delete":
115
124
  // Translate delete(map, key) to $.deleteMapEntry(map, key)
116
125
  if len(exp.Args) != 2 {
@@ -205,6 +214,33 @@ func (c *GoToTSCompiler) WriteCallExpr(exp *ast.CallExpr) error {
205
214
  return nil // Handled make for []byte
206
215
  }
207
216
 
217
+ // Check if the element type is a generic type parameter
218
+ if _, isTypeParam := goElemType.(*types.TypeParam); isTypeParam {
219
+ // This is make([]E, n) where E is a type parameter
220
+ c.tsw.WriteLiterally("$.makeSlice<")
221
+ c.WriteGoType(goElemType, GoTypeContextGeneral) // Write the element type parameter
222
+ c.tsw.WriteLiterally(">(")
223
+
224
+ if len(exp.Args) >= 2 {
225
+ if err := c.WriteValueExpr(exp.Args[1]); err != nil { // Length
226
+ return err
227
+ }
228
+ if len(exp.Args) == 3 {
229
+ c.tsw.WriteLiterally(", ")
230
+ if err := c.WriteValueExpr(exp.Args[2]); err != nil { // Capacity
231
+ return err
232
+ }
233
+ } else if len(exp.Args) > 3 {
234
+ return errors.New("makeSlice expects 2 or 3 arguments")
235
+ }
236
+ } else {
237
+ // If no length is provided, default to 0
238
+ c.tsw.WriteLiterally("0")
239
+ }
240
+ c.tsw.WriteLiterally(")")
241
+ return nil // Handled make for []E where E is type parameter
242
+ }
243
+
208
244
  c.tsw.WriteLiterally("$.makeSlice<")
209
245
  c.WriteGoType(goElemType, GoTypeContextGeneral) // Write the element type
210
246
  c.tsw.WriteLiterally(">(")
@@ -228,6 +264,71 @@ func (c *GoToTSCompiler) WriteCallExpr(exp *ast.CallExpr) error {
228
264
  c.tsw.WriteLiterally(")")
229
265
  return nil // Handled make for slice
230
266
  }
267
+
268
+ // Handle generic type parameter make calls: make(S, len, cap) where S ~[]E
269
+ if ident, ok := exp.Args[0].(*ast.Ident); ok {
270
+ // Check if this identifier refers to a type parameter
271
+ if obj := c.pkg.TypesInfo.Uses[ident]; obj != nil {
272
+ if typeName, isTypeName := obj.(*types.TypeName); isTypeName {
273
+ if typeParam, isTypeParam := typeName.Type().(*types.TypeParam); isTypeParam {
274
+ // Check if the type parameter is constrained to slice types
275
+ constraint := typeParam.Constraint()
276
+ if constraint != nil {
277
+ underlying := constraint.Underlying()
278
+ if iface, isInterface := underlying.(*types.Interface); isInterface {
279
+ // Check if the constraint includes slice types
280
+ // For constraints like ~[]E, we need to look at the type terms
281
+ if hasSliceConstraint(iface) {
282
+ // This is a generic slice type parameter
283
+ // We need to determine the element type from the constraint
284
+ elemType := getSliceElementTypeFromConstraint(iface)
285
+ if elemType != nil {
286
+ // Check if it's make(S, ...) where S constrains to []byte
287
+ if basicElem, isBasic := elemType.(*types.Basic); isBasic && basicElem.Kind() == types.Uint8 {
288
+ c.tsw.WriteLiterally("new Uint8Array(")
289
+ if len(exp.Args) >= 2 {
290
+ if err := c.WriteValueExpr(exp.Args[1]); err != nil { // Length
291
+ return err
292
+ }
293
+ // Capacity argument for make([]byte, len, cap) is ignored for new Uint8Array(len)
294
+ } else {
295
+ // If no length is provided, default to 0
296
+ c.tsw.WriteLiterally("0")
297
+ }
298
+ c.tsw.WriteLiterally(")")
299
+ return nil // Handled make for generic []byte
300
+ }
301
+
302
+ c.tsw.WriteLiterally("$.makeSlice<")
303
+ c.WriteGoType(elemType, GoTypeContextGeneral) // Write the element type
304
+ c.tsw.WriteLiterally(">(")
305
+
306
+ if len(exp.Args) >= 2 {
307
+ if err := c.WriteValueExpr(exp.Args[1]); err != nil { // Length
308
+ return err
309
+ }
310
+ if len(exp.Args) == 3 {
311
+ c.tsw.WriteLiterally(", ")
312
+ if err := c.WriteValueExpr(exp.Args[2]); err != nil { // Capacity
313
+ return err
314
+ }
315
+ } else if len(exp.Args) > 3 {
316
+ return errors.New("makeSlice expects 2 or 3 arguments")
317
+ }
318
+ } else {
319
+ // If no length is provided, default to 0
320
+ c.tsw.WriteLiterally("0")
321
+ }
322
+ c.tsw.WriteLiterally(")")
323
+ return nil // Handled make for generic slice
324
+ }
325
+ }
326
+ }
327
+ }
328
+ }
329
+ }
330
+ }
331
+ }
231
332
  }
232
333
  // Fallthrough for unhandled make calls (e.g., channels)
233
334
  return errors.New("unhandled make call")
@@ -424,7 +525,17 @@ func (c *GoToTSCompiler) WriteCallExpr(exp *ast.CallExpr) error {
424
525
 
425
526
  if funType := c.pkg.TypesInfo.TypeOf(expFun); funType != nil {
426
527
  if _, ok := funType.Underlying().(*types.Signature); ok {
427
- if _, isNamed := funType.(*types.Named); isNamed {
528
+ // Check if this is a function parameter identifier that needs not-null assertion
529
+ if ident, isIdent := expFun.(*ast.Ident); isIdent {
530
+ // Check if this identifier is a function parameter
531
+ if obj := c.pkg.TypesInfo.Uses[ident]; obj != nil {
532
+ if _, isVar := obj.(*types.Var); isVar {
533
+ // This is a variable (including function parameters)
534
+ // Function parameters that are function types need ! assertion
535
+ c.tsw.WriteLiterally("!")
536
+ }
537
+ }
538
+ } else if _, isNamed := funType.(*types.Named); isNamed {
428
539
  c.tsw.WriteLiterally("!")
429
540
  }
430
541
  }
@@ -458,7 +569,17 @@ func (c *GoToTSCompiler) WriteCallExpr(exp *ast.CallExpr) error {
458
569
 
459
570
  if funType := c.pkg.TypesInfo.TypeOf(expFun); funType != nil {
460
571
  if _, ok := funType.Underlying().(*types.Signature); ok {
461
- if _, isNamed := funType.(*types.Named); isNamed {
572
+ // Check if this is a function parameter identifier that needs not-null assertion
573
+ if ident, isIdent := expFun.(*ast.Ident); isIdent {
574
+ // Check if this identifier is a function parameter
575
+ if obj := c.pkg.TypesInfo.Uses[ident]; obj != nil {
576
+ if _, isVar := obj.(*types.Var); isVar {
577
+ // This is a variable (including function parameters)
578
+ // Function parameters that are function types need ! assertion
579
+ c.tsw.WriteLiterally("!")
580
+ }
581
+ }
582
+ } else if _, isNamed := funType.(*types.Named); isNamed {
462
583
  c.tsw.WriteLiterally("!")
463
584
  }
464
585
  }
@@ -477,3 +598,92 @@ func (c *GoToTSCompiler) WriteCallExpr(exp *ast.CallExpr) error {
477
598
  c.tsw.WriteLiterally(")")
478
599
  return nil
479
600
  }
601
+
602
+ // hasSliceConstraint checks if an interface constraint includes slice types
603
+ // For constraints like ~[]E, this returns true
604
+ func hasSliceConstraint(iface *types.Interface) bool {
605
+ // Check if the interface has type terms that include slice types
606
+ for i := 0; i < iface.NumEmbeddeds(); i++ {
607
+ embedded := iface.EmbeddedType(i)
608
+ if union, ok := embedded.(*types.Union); ok {
609
+ for j := 0; j < union.Len(); j++ {
610
+ term := union.Term(j)
611
+ if _, isSlice := term.Type().Underlying().(*types.Slice); isSlice {
612
+ return true
613
+ }
614
+ }
615
+ } else if _, isSlice := embedded.Underlying().(*types.Slice); isSlice {
616
+ return true
617
+ }
618
+ }
619
+ return false
620
+ }
621
+
622
+ // getSliceElementTypeFromConstraint extracts the element type from a slice constraint
623
+ // For constraints like ~[]E, this returns E
624
+ func getSliceElementTypeFromConstraint(iface *types.Interface) types.Type {
625
+ // Check if the interface has type terms that include slice types
626
+ for i := 0; i < iface.NumEmbeddeds(); i++ {
627
+ embedded := iface.EmbeddedType(i)
628
+ if union, ok := embedded.(*types.Union); ok {
629
+ for j := 0; j < union.Len(); j++ {
630
+ term := union.Term(j)
631
+ if sliceType, isSlice := term.Type().Underlying().(*types.Slice); isSlice {
632
+ return sliceType.Elem()
633
+ }
634
+ }
635
+ } else if sliceType, isSlice := embedded.Underlying().(*types.Slice); isSlice {
636
+ return sliceType.Elem()
637
+ }
638
+ }
639
+ return nil
640
+ }
641
+
642
+ // hasMixedStringByteConstraint checks if an interface constraint includes both string and []byte types
643
+ // For constraints like string | []byte, this returns true
644
+ // For pure slice constraints like ~[]E, this returns false
645
+ func hasMixedStringByteConstraint(iface *types.Interface) bool {
646
+ hasString := false
647
+ hasByteSlice := false
648
+
649
+ // Check if the interface has type terms that include both string and []byte
650
+ for i := 0; i < iface.NumEmbeddeds(); i++ {
651
+ embedded := iface.EmbeddedType(i)
652
+ if union, ok := embedded.(*types.Union); ok {
653
+ for j := 0; j < union.Len(); j++ {
654
+ term := union.Term(j)
655
+ termType := term.Type().Underlying()
656
+
657
+ // Check for string type
658
+ if basicType, isBasic := termType.(*types.Basic); isBasic && (basicType.Info()&types.IsString) != 0 {
659
+ hasString = true
660
+ }
661
+
662
+ // Check for []byte type
663
+ if sliceType, isSlice := termType.(*types.Slice); isSlice {
664
+ if elemType, isBasic := sliceType.Elem().(*types.Basic); isBasic && elemType.Kind() == types.Uint8 {
665
+ hasByteSlice = true
666
+ }
667
+ }
668
+ }
669
+ } else {
670
+ // Handle non-union embedded types
671
+ termType := embedded.Underlying()
672
+
673
+ // Check for string type
674
+ if basicType, isBasic := termType.(*types.Basic); isBasic && (basicType.Info()&types.IsString) != 0 {
675
+ hasString = true
676
+ }
677
+
678
+ // Check for []byte type
679
+ if sliceType, isSlice := termType.(*types.Slice); isSlice {
680
+ if elemType, isBasic := sliceType.Elem().(*types.Basic); isBasic && elemType.Kind() == types.Uint8 {
681
+ hasByteSlice = true
682
+ }
683
+ }
684
+ }
685
+ }
686
+
687
+ // Return true only if we have both string and []byte in the constraint
688
+ return hasString && hasByteSlice
689
+ }
package/compiler/expr.go CHANGED
@@ -71,8 +71,44 @@ func (c *GoToTSCompiler) WriteIndexExpr(exp *ast.IndexExpr) error {
71
71
  }
72
72
 
73
73
  // Check if it's a type parameter with a union constraint (e.g., string | []byte)
74
- if _, isTypeParam := tv.Type.(*types.TypeParam); isTypeParam {
75
- // For type parameters with string | []byte constraint, use specialized function
74
+ if typeParam, isTypeParam := tv.Type.(*types.TypeParam); isTypeParam {
75
+ // Check if the type parameter is constrained to slice types
76
+ constraint := typeParam.Constraint()
77
+ if constraint != nil {
78
+ underlying := constraint.Underlying()
79
+ if iface, isInterface := underlying.(*types.Interface); isInterface {
80
+ // Check if this is a mixed string/byte constraint (like string | []byte)
81
+ if hasMixedStringByteConstraint(iface) {
82
+ // For mixed constraints, use specialized function that returns number (byte value)
83
+ c.tsw.WriteLiterally("$.indexStringOrBytes(")
84
+ if err := c.WriteValueExpr(exp.X); err != nil {
85
+ return err
86
+ }
87
+ c.tsw.WriteLiterally(", ")
88
+ if err := c.WriteValueExpr(exp.Index); err != nil {
89
+ return err
90
+ }
91
+ c.tsw.WriteLiterally(")")
92
+ return nil
93
+ }
94
+
95
+ // Check if the constraint includes only slice types (pure slice constraint)
96
+ if hasSliceConstraint(iface) {
97
+ // This is a pure slice type parameter, use regular slice indexing
98
+ if err := c.WriteValueExpr(exp.X); err != nil {
99
+ return err
100
+ }
101
+ c.tsw.WriteLiterally("![") // non-null assertion
102
+ if err := c.WriteValueExpr(exp.Index); err != nil {
103
+ return err
104
+ }
105
+ c.tsw.WriteLiterally("]")
106
+ return nil
107
+ }
108
+ }
109
+ }
110
+
111
+ // For other type parameters, use specialized function as fallback
76
112
  // that returns number (byte value) for better TypeScript typing
77
113
  c.tsw.WriteLiterally("$.indexStringOrBytes(")
78
114
  if err := c.WriteValueExpr(exp.X); err != nil {
@@ -377,6 +413,7 @@ func (c *GoToTSCompiler) WriteBinaryExpr(exp *ast.BinaryExpr) error {
377
413
  if !ok {
378
414
  return errors.Errorf("unhandled binary op: %s", exp.Op.String())
379
415
  }
416
+
380
417
  c.tsw.WriteLiterally(tokStr)
381
418
  c.tsw.WriteLiterally(" ")
382
419
  if err := c.WriteValueExpr(exp.Y); err != nil {
@@ -452,6 +489,13 @@ func (c *GoToTSCompiler) WriteUnaryExpr(exp *ast.UnaryExpr) error {
452
489
  if !ok {
453
490
  return errors.Errorf("unhandled unary op: %s", exp.Op.String())
454
491
  }
492
+
493
+ // Special case: In Go, ^ is bitwise NOT when used as unary operator
494
+ // In TypeScript, bitwise NOT is ~, not ^
495
+ if exp.Op == token.XOR {
496
+ tokStr = "~"
497
+ }
498
+
455
499
  c.tsw.WriteLiterally(tokStr)
456
500
 
457
501
  // Add space if operator is not postfix (e.g., !)
package/compiler/field.go CHANGED
@@ -47,7 +47,7 @@ func (c *GoToTSCompiler) WriteFieldList(a *ast.FieldList, isArguments bool) {
47
47
  if j > 0 {
48
48
  c.tsw.WriteLiterally(", ")
49
49
  }
50
- c.tsw.WriteLiterally(name.Name)
50
+ c.tsw.WriteLiterally(c.sanitizeIdentifier(name.Name))
51
51
  c.tsw.WriteLiterally(": ")
52
52
  typ := c.pkg.TypesInfo.TypeOf(field.Type)
53
53
  c.WriteGoType(typ, GoTypeContextGeneral)
@@ -65,7 +65,7 @@ func (c *GoToTSCompiler) WriteFieldList(a *ast.FieldList, isArguments bool) {
65
65
  c.tsw.WriteLiterally(", ")
66
66
  }
67
67
  c.tsw.WriteLiterally("...")
68
- c.tsw.WriteLiterally(name.Name)
68
+ c.tsw.WriteLiterally(c.sanitizeIdentifier(name.Name))
69
69
  }
70
70
 
71
71
  c.tsw.WriteLiterally(": ")
@@ -86,7 +86,7 @@ func (c *GoToTSCompiler) WriteFieldList(a *ast.FieldList, isArguments bool) {
86
86
  if j > 0 {
87
87
  c.tsw.WriteLiterally(", ")
88
88
  }
89
- c.tsw.WriteLiterally(name.Name)
89
+ c.tsw.WriteLiterally(c.sanitizeIdentifier(name.Name))
90
90
  c.tsw.WriteLiterally(": ")
91
91
  typ := c.pkg.TypesInfo.TypeOf(field.Type)
92
92
  c.WriteGoType(typ, GoTypeContextGeneral) // Use WriteGoType for parameter type
@@ -143,7 +143,7 @@ func (c *GoToTSCompiler) WriteField(field *ast.Field, isArguments bool) {
143
143
 
144
144
  // argument names: keep original casing, no access modifier
145
145
  if isArguments {
146
- c.tsw.WriteLiterally(name.Name)
146
+ c.tsw.WriteLiterally(c.sanitizeIdentifier(name.Name))
147
147
  // Argument type is handled in WriteFieldList, so continue
148
148
  continue
149
149
  } else {
@@ -146,13 +146,15 @@ func (c *GoToTSCompiler) WriteStmtRange(exp *ast.RangeStmt) error {
146
146
  if err := c.WriteValueExpr(exp.X); err != nil { // This is N
147
147
  return fmt.Errorf("failed to write range loop integer expression: %w", err)
148
148
  }
149
- c.tsw.WriteLiterallyf("; %s++) ", indexVarName)
149
+ c.tsw.WriteLiterallyf("; %s++) {", indexVarName)
150
150
 
151
151
  // write body
152
152
  if err := c.WriteStmtBlock(exp.Body, false); err != nil {
153
153
  return fmt.Errorf("failed to write range loop integer body: %w", err)
154
154
  }
155
155
 
156
+ c.tsw.Indent(-1)
157
+ c.tsw.WriteLine("}")
156
158
  return nil
157
159
  }
158
160
  }
@@ -341,5 +343,206 @@ func (c *GoToTSCompiler) WriteStmtRange(exp *ast.RangeStmt) error {
341
343
  }
342
344
  }
343
345
 
346
+ // Handle iterator function signatures
347
+ if sig, ok := underlying.(*types.Signature); ok {
348
+ // Check if this is an iterator function signature
349
+ // Iterator functions have the form: func(yield func(...) bool)
350
+ params := sig.Params()
351
+ if params.Len() == 1 {
352
+ yieldParam := params.At(0).Type()
353
+ if yieldSig, ok := yieldParam.Underlying().(*types.Signature); ok {
354
+ yieldParams := yieldSig.Params()
355
+ yieldResults := yieldSig.Results()
356
+
357
+ // Verify the yield function returns bool
358
+ if yieldResults.Len() == 1 {
359
+ if basic, ok := yieldResults.At(0).Type().Underlying().(*types.Basic); ok && basic.Kind() == types.Bool {
360
+ // This is an iterator function
361
+ // Generate TypeScript code that calls the iterator with a yield function
362
+
363
+ if yieldParams.Len() == 0 {
364
+ // func(func() bool) - iterator with no values
365
+ c.tsw.WriteLiterally(";(() => {")
366
+ c.tsw.Indent(1)
367
+ c.tsw.WriteLine("")
368
+ c.tsw.WriteLiterally("let shouldContinue = true")
369
+ c.tsw.WriteLine("")
370
+ if err := c.WriteValueExpr(exp.X); err != nil {
371
+ return fmt.Errorf("failed to write iterator expression: %w", err)
372
+ }
373
+ c.tsw.WriteLiterally("(() => {")
374
+ c.tsw.Indent(1)
375
+ c.tsw.WriteLine("")
376
+ if err := c.WriteStmtBlock(exp.Body, false); err != nil {
377
+ return fmt.Errorf("failed to write iterator body: %w", err)
378
+ }
379
+ c.tsw.WriteLiterally("return shouldContinue")
380
+ c.tsw.WriteLine("")
381
+ c.tsw.Indent(-1)
382
+ c.tsw.WriteLiterally("})")
383
+ c.tsw.WriteLine("")
384
+ c.tsw.Indent(-1)
385
+ c.tsw.WriteLine("})()")
386
+ return nil
387
+ } else if yieldParams.Len() == 1 {
388
+ // func(func(V) bool) - iterator with one value
389
+ c.tsw.WriteLiterally(";(() => {")
390
+ c.tsw.Indent(1)
391
+ c.tsw.WriteLine("")
392
+ c.tsw.WriteLiterally("let shouldContinue = true")
393
+ c.tsw.WriteLine("")
394
+ if err := c.WriteValueExpr(exp.X); err != nil {
395
+ return fmt.Errorf("failed to write iterator expression: %w", err)
396
+ }
397
+ c.tsw.WriteLiterally("((")
398
+ if exp.Value != nil {
399
+ if ident, ok := exp.Value.(*ast.Ident); ok && ident.Name != "_" {
400
+ c.WriteIdent(ident, false)
401
+ } else {
402
+ c.tsw.WriteLiterally("v")
403
+ }
404
+ } else {
405
+ c.tsw.WriteLiterally("v")
406
+ }
407
+ c.tsw.WriteLiterally(") => {")
408
+ c.tsw.Indent(1)
409
+ c.tsw.WriteLine("")
410
+ if err := c.WriteStmtBlock(exp.Body, false); err != nil {
411
+ return fmt.Errorf("failed to write iterator body: %w", err)
412
+ }
413
+ c.tsw.WriteLiterally("return shouldContinue")
414
+ c.tsw.WriteLine("")
415
+ c.tsw.Indent(-1)
416
+ c.tsw.WriteLiterally("})")
417
+ c.tsw.WriteLine("")
418
+ c.tsw.Indent(-1)
419
+ c.tsw.WriteLine("})()")
420
+ return nil
421
+ } else if yieldParams.Len() == 2 {
422
+ // func(func(K, V) bool) - iterator with key-value pairs
423
+ c.tsw.WriteLiterally(";(() => {")
424
+ c.tsw.Indent(1)
425
+ c.tsw.WriteLine("")
426
+ c.tsw.WriteLiterally("let shouldContinue = true")
427
+ c.tsw.WriteLine("")
428
+ if err := c.WriteValueExpr(exp.X); err != nil {
429
+ return fmt.Errorf("failed to write iterator expression: %w", err)
430
+ }
431
+ c.tsw.WriteLiterally("((")
432
+ if exp.Key != nil {
433
+ if ident, ok := exp.Key.(*ast.Ident); ok && ident.Name != "_" {
434
+ c.WriteIdent(ident, false)
435
+ } else {
436
+ c.tsw.WriteLiterally("k")
437
+ }
438
+ } else {
439
+ c.tsw.WriteLiterally("k")
440
+ }
441
+ c.tsw.WriteLiterally(", ")
442
+ if exp.Value != nil {
443
+ if ident, ok := exp.Value.(*ast.Ident); ok && ident.Name != "_" {
444
+ c.WriteIdent(ident, false)
445
+ } else {
446
+ c.tsw.WriteLiterally("v")
447
+ }
448
+ } else {
449
+ c.tsw.WriteLiterally("v")
450
+ }
451
+ c.tsw.WriteLiterally(") => {")
452
+ c.tsw.Indent(1)
453
+ c.tsw.WriteLine("")
454
+ if err := c.WriteStmtBlock(exp.Body, false); err != nil {
455
+ return fmt.Errorf("failed to write iterator body: %w", err)
456
+ }
457
+ c.tsw.WriteLiterally("return shouldContinue")
458
+ c.tsw.WriteLine("")
459
+ c.tsw.Indent(-1)
460
+ c.tsw.WriteLiterally("})")
461
+ c.tsw.WriteLine("")
462
+ c.tsw.Indent(-1)
463
+ c.tsw.WriteLine("})()")
464
+ return nil
465
+ }
466
+ }
467
+ }
468
+ }
469
+ }
470
+ }
471
+
472
+ // Handle interface types that may represent iterators
473
+ if _, ok := underlying.(*types.Interface); ok {
474
+ // For interface types, we need to treat them as potential iterators
475
+ // In Go 1.23+, interfaces can represent iterator functions
476
+ // We'll attempt to call them as iterator functions with a yield callback
477
+
478
+ // Try to determine the iterator pattern based on context or assume key-value pairs
479
+ // Since we can't easily determine the exact signature from just the interface,
480
+ // we'll generate a generic iterator call pattern
481
+
482
+ c.tsw.WriteLiterally(";(() => {")
483
+ c.tsw.Indent(1)
484
+ c.tsw.WriteLine("")
485
+ c.tsw.WriteLiterally("let shouldContinue = true")
486
+ c.tsw.WriteLine("")
487
+
488
+ // Call the interface as an iterator function
489
+ if err := c.WriteValueExpr(exp.X); err != nil {
490
+ return fmt.Errorf("failed to write interface iterator expression: %w", err)
491
+ }
492
+
493
+ // Generate the appropriate yield function based on the range variables
494
+ if exp.Key != nil && exp.Value != nil {
495
+ // Key-value iterator
496
+ c.tsw.WriteLiterally("((")
497
+ if ident, ok := exp.Key.(*ast.Ident); ok && ident.Name != "_" {
498
+ c.WriteIdent(ident, false)
499
+ } else {
500
+ c.tsw.WriteLiterally("k")
501
+ }
502
+ c.tsw.WriteLiterally(", ")
503
+ if ident, ok := exp.Value.(*ast.Ident); ok && ident.Name != "_" {
504
+ c.WriteIdent(ident, false)
505
+ } else {
506
+ c.tsw.WriteLiterally("v")
507
+ }
508
+ c.tsw.WriteLiterally(") => {")
509
+ } else if exp.Value != nil {
510
+ // Value-only iterator
511
+ c.tsw.WriteLiterally("((")
512
+ if ident, ok := exp.Value.(*ast.Ident); ok && ident.Name != "_" {
513
+ c.WriteIdent(ident, false)
514
+ } else {
515
+ c.tsw.WriteLiterally("v")
516
+ }
517
+ c.tsw.WriteLiterally(") => {")
518
+ } else if exp.Key != nil {
519
+ // Key-only iterator (treating it as value for single-param iterator)
520
+ c.tsw.WriteLiterally("((")
521
+ if ident, ok := exp.Key.(*ast.Ident); ok && ident.Name != "_" {
522
+ c.WriteIdent(ident, false)
523
+ } else {
524
+ c.tsw.WriteLiterally("k")
525
+ }
526
+ c.tsw.WriteLiterally(") => {")
527
+ } else {
528
+ // No variables iterator
529
+ c.tsw.WriteLiterally("(() => {")
530
+ }
531
+
532
+ c.tsw.Indent(1)
533
+ c.tsw.WriteLine("")
534
+ if err := c.WriteStmtBlock(exp.Body, false); err != nil {
535
+ return fmt.Errorf("failed to write interface iterator body: %w", err)
536
+ }
537
+ c.tsw.WriteLiterally("return shouldContinue")
538
+ c.tsw.WriteLine("")
539
+ c.tsw.Indent(-1)
540
+ c.tsw.WriteLiterally("})")
541
+ c.tsw.WriteLine("")
542
+ c.tsw.Indent(-1)
543
+ c.tsw.WriteLine("})()")
544
+ return nil
545
+ }
546
+
344
547
  return errors.Errorf("unsupported range loop type: %T for expression %v", underlying, exp)
345
548
  }
package/compiler/type.go CHANGED
@@ -68,6 +68,15 @@ func (c *GoToTSCompiler) WriteGoType(typ types.Type, context GoTypeContext) {
68
68
  case *types.TypeParam:
69
69
  // For type parameters, write the type parameter name (e.g., "T", "K", etc.)
70
70
  c.tsw.WriteLiterally(t.Obj().Name())
71
+ case *types.Union:
72
+ // Handle union types (e.g., string | []byte)
73
+ for i := 0; i < t.Len(); i++ {
74
+ if i > 0 {
75
+ c.tsw.WriteLiterally(" | ")
76
+ }
77
+ term := t.Term(i)
78
+ c.WriteGoType(term.Type(), context)
79
+ }
71
80
  default:
72
81
  // For other types, just write "any" and add a comment
73
82
  c.tsw.WriteLiterally("any")
@@ -202,7 +211,8 @@ func (c *GoToTSCompiler) WriteBasicType(t *types.Basic) {
202
211
 
203
212
  // WriteNamedType translates a Go named type to its TypeScript equivalent.
204
213
  // It specially handles the error interface as $.GoError, and uses the original
205
- // type name for other named types. For generic types, it includes type arguments.
214
+ // type name for other named types. For imported types, it writes the qualified
215
+ // name using the import alias found from the analysis imports. For generic types, it includes type arguments.
206
216
  func (c *GoToTSCompiler) WriteNamedType(t *types.Named) {
207
217
  // Check if the named type is the error interface
208
218
  if iface, ok := t.Underlying().(*types.Interface); ok && iface.String() == "interface{Error() string}" {
@@ -210,7 +220,40 @@ func (c *GoToTSCompiler) WriteNamedType(t *types.Named) {
210
220
  return
211
221
  }
212
222
 
213
- // Use Obj().Name() for the original defined name
223
+ // Check if this type is from an imported package
224
+ typePkg := t.Obj().Pkg()
225
+ if typePkg != nil && typePkg != c.pkg.Types {
226
+ // This type is from an imported package, find the import alias
227
+ typePkgPath := typePkg.Path()
228
+
229
+ // Try to find the import alias by matching the package path
230
+ for importAlias, _ := range c.analysis.Imports {
231
+ // The importAlias could be either the explicit alias or the default package name
232
+ // If it's the default package name, it should match the last segment of the path
233
+ defaultPkgName := packageNameFromGoPath(typePkgPath)
234
+ if importAlias == defaultPkgName || importAlias == typePkgPath {
235
+ // Write the qualified name: importAlias.TypeName
236
+ c.tsw.WriteLiterally(importAlias)
237
+ c.tsw.WriteLiterally(".")
238
+ c.tsw.WriteLiterally(t.Obj().Name())
239
+
240
+ // For generic types, include type arguments
241
+ if t.TypeArgs() != nil && t.TypeArgs().Len() > 0 {
242
+ c.tsw.WriteLiterally("<")
243
+ for i := 0; i < t.TypeArgs().Len(); i++ {
244
+ if i > 0 {
245
+ c.tsw.WriteLiterally(", ")
246
+ }
247
+ c.WriteGoType(t.TypeArgs().At(i), GoTypeContextGeneral)
248
+ }
249
+ c.tsw.WriteLiterally(">")
250
+ }
251
+ return
252
+ }
253
+ }
254
+ }
255
+
256
+ // Use Obj().Name() for the original defined name (local types or unmatched imports)
214
257
  c.tsw.WriteLiterally(t.Obj().Name())
215
258
 
216
259
  // For generic types, include type arguments
@@ -388,7 +431,7 @@ func (c *GoToTSCompiler) WriteSignatureType(t *types.Signature) {
388
431
 
389
432
  // Use parameter name if available, otherwise use p0, p1, etc.
390
433
  if param.Name() != "" {
391
- c.tsw.WriteLiterally(param.Name())
434
+ c.tsw.WriteLiterally(c.sanitizeIdentifier(param.Name()))
392
435
  } else {
393
436
  c.tsw.WriteLiterallyf("p%d", i)
394
437
  }
@@ -483,7 +526,7 @@ func (c *GoToTSCompiler) writeInterfaceStructure(iface *types.Interface, astNode
483
526
  if paramName == "" || paramName == "_" {
484
527
  paramName = fmt.Sprintf("_p%d", j)
485
528
  }
486
- c.tsw.WriteLiterally(paramName)
529
+ c.tsw.WriteLiterally(c.sanitizeIdentifier(paramName))
487
530
  c.tsw.WriteLiterally(": ")
488
531
  c.WriteGoType(paramVar.Type(), GoTypeContextGeneral) // Recursive call for param type
489
532
  }
@@ -0,0 +1,9 @@
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
+ export declare function copy<T>(dst: T[], src: T[]): number;
9
+ export declare function multiplyDuration(duration: any, multiplier: number): any;
@@ -5,6 +5,15 @@ export * from './io.js';
5
5
  export * from './map.js';
6
6
  export * from './slice.js';
7
7
  export * from './type.js';
8
+ // Copy is the Go builtin function that copies the contents of one slice to another.
9
+ // It returns the number of elements copied.
10
+ export function copy(dst, src) {
11
+ const n = Math.min(dst.length, src.length);
12
+ for (let i = 0; i < n; i++) {
13
+ dst[i] = src[i];
14
+ }
15
+ return n;
16
+ }
8
17
  // Duration multiplication helper for time package operations
9
18
  // Handles expressions like time.Hour * 24
10
19
  export function multiplyDuration(duration, multiplier) {