goscript 0.0.16 → 0.0.18

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.
@@ -303,24 +303,11 @@ func (c *GoToTSCompiler) WriteGoType(typ types.Type) {
303
303
  case *types.Signature:
304
304
  c.WriteSignatureType(t)
305
305
  case *types.Struct:
306
- // Generate an interface with the struct's fields
307
- c.tsw.WriteLiterally("{ ")
308
- // Add field properties to the interface
309
- if t.NumFields() > 0 {
310
- for i := 0; i < t.NumFields(); i++ {
311
- field := t.Field(i)
312
- if i > 0 {
313
- c.tsw.WriteLiterally("; ")
314
- }
315
- c.tsw.WriteLiterally(field.Name() + "?: ")
316
- c.WriteGoType(field.Type())
317
- }
318
- }
319
- c.tsw.WriteLiterally(" }")
306
+ c.WriteStructType(t)
320
307
  default:
321
308
  // For other types, just write "any" and add a comment
322
309
  c.tsw.WriteLiterally("any")
323
- c.tsw.WriteCommentInline(fmt.Sprintf("unhandled type: %T", typ))
310
+ c.tsw.WriteCommentInlinef("unhandled type: %T", typ)
324
311
  }
325
312
  }
326
313
 
@@ -452,7 +439,7 @@ func (c *GoToTSCompiler) WriteSignatureType(t *types.Signature) {
452
439
  if param.Name() != "" {
453
440
  c.tsw.WriteLiterally(param.Name())
454
441
  } else {
455
- c.tsw.WriteLiterally(fmt.Sprintf("p%d", i))
442
+ c.tsw.WriteLiterallyf("p%d", i)
456
443
  }
457
444
  c.tsw.WriteLiterally(": ")
458
445
 
@@ -752,6 +739,20 @@ func (c *GoToTSCompiler) WriteValueExpr(a ast.Expr) error {
752
739
  c.tsw.WriteLiterally(")")
753
740
  return nil
754
741
  case *ast.ParenExpr:
742
+ // Check if this is a nil pointer to struct type cast: (*struct{})(nil)
743
+ if starExpr, isStarExpr := exp.X.(*ast.StarExpr); isStarExpr {
744
+ if _, isStructType := starExpr.X.(*ast.StructType); isStructType {
745
+ c.tsw.WriteLiterally("null")
746
+ return nil
747
+ }
748
+ }
749
+
750
+ // Check if this is a type cast with nil: (SomeType)(nil)
751
+ if ident, isIdent := exp.X.(*ast.Ident); isIdent && ident.Name == "nil" {
752
+ c.tsw.WriteLiterally("null")
753
+ return nil
754
+ }
755
+
755
756
  // Translate (X) to (X)
756
757
  // If we haven't written anything in this statement yet, prepend ;
757
758
  c.tsw.WriteLiterally("(")
@@ -763,7 +764,7 @@ func (c *GoToTSCompiler) WriteValueExpr(a ast.Expr) error {
763
764
  case *ast.FuncLit:
764
765
  return c.WriteFuncLitValue(exp)
765
766
  default:
766
- c.tsw.WriteCommentLine(fmt.Sprintf("unhandled value expr: %T", exp))
767
+ c.tsw.WriteCommentLinef("unhandled value expr: %T", exp)
767
768
  return nil
768
769
  }
769
770
  }
@@ -774,19 +775,19 @@ func (c *GoToTSCompiler) WriteIndexExpr(exp *ast.IndexExpr) error {
774
775
  if tv, ok := c.pkg.TypesInfo.Types[exp.X]; ok {
775
776
  // Check if it's a map type
776
777
  if mapType, isMap := tv.Type.Underlying().(*types.Map); isMap {
778
+ c.tsw.WriteLiterally("$.mapGet(")
777
779
  if err := c.WriteValueExpr(exp.X); err != nil {
778
780
  return err
779
781
  }
780
- c.tsw.WriteLiterally(".get(")
782
+ c.tsw.WriteLiterally(", ")
781
783
  if err := c.WriteValueExpr(exp.Index); err != nil {
782
784
  return err
783
785
  }
784
- // Map.get() returns undefined when key not found, but Go returns zero value
785
- // Add nullish coalescing with the appropriate zero value for the map's value type
786
- c.tsw.WriteLiterally(") ?? ")
786
+ c.tsw.WriteLiterally(", ")
787
787
 
788
- // Generate the zero value based on the map's value type
788
+ // Generate the zero value as the default value for mapGet
789
789
  c.WriteZeroValueForType(mapType.Elem())
790
+ c.tsw.WriteLiterally(")")
790
791
  return nil
791
792
  }
792
793
  }
@@ -810,9 +811,6 @@ func (c *GoToTSCompiler) WriteIndexExpr(exp *ast.IndexExpr) error {
810
811
  // context, we expect the asserted value directly. The `TypeName` string is used
811
812
  // by the runtime for error messages.
812
813
  func (c *GoToTSCompiler) WriteTypeAssertExpr(exp *ast.TypeAssertExpr) error {
813
- // Get the type name string for the asserted type
814
- typeName := c.getTypeNameString(exp.Type)
815
-
816
814
  // Generate a call to $.typeAssert
817
815
  c.tsw.WriteLiterally("$.typeAssert<")
818
816
  c.WriteTypeExpr(exp.Type) // Write the asserted type for the generic
@@ -821,8 +819,23 @@ func (c *GoToTSCompiler) WriteTypeAssertExpr(exp *ast.TypeAssertExpr) error {
821
819
  return fmt.Errorf("failed to write interface expression in type assertion expression: %w", err)
822
820
  }
823
821
  c.tsw.WriteLiterally(", ")
824
- c.tsw.WriteLiterally(fmt.Sprintf("'%s'", typeName))
825
- c.tsw.WriteLiterally(").value") // Access the value field directly in expression context
822
+
823
+ // Write the type description instead of just the type name
824
+ // This ensures we generate proper type info objects for all types
825
+
826
+ // Unwrap parenthesized expressions to handle cases like r.((<-chan T))
827
+ typeExpr := exp.Type
828
+ for {
829
+ if parenExpr, ok := typeExpr.(*ast.ParenExpr); ok {
830
+ typeExpr = parenExpr.X
831
+ } else {
832
+ break
833
+ }
834
+ }
835
+
836
+ c.writeTypeDescription(typeExpr)
837
+
838
+ c.tsw.WriteLiterally(")") // Just close the parenthesis, don't access .value directly
826
839
  return nil
827
840
  }
828
841
 
@@ -1087,17 +1100,19 @@ func (c *GoToTSCompiler) WriteStarExpr(exp *ast.StarExpr) error {
1087
1100
  // `WriteFieldList` to generate the list of field definitions.
1088
1101
  // Note: This is for anonymous struct type literals. Named struct types are usually
1089
1102
  // handled as classes via `WriteTypeSpec`.
1090
- func (c *GoToTSCompiler) WriteStructType(exp *ast.StructType) {
1091
- if typ := c.pkg.TypesInfo.TypeOf(exp); typ != nil {
1092
- c.WriteGoType(typ)
1093
- return
1094
- }
1095
-
1096
- if exp.Fields == nil || exp.Fields.NumFields() == 0 {
1097
- c.tsw.WriteLiterally("{}")
1098
- return
1103
+ func (c *GoToTSCompiler) WriteStructType(t *types.Struct) {
1104
+ // Generate an interface with the struct's fields
1105
+ c.tsw.WriteLiterally("{ ")
1106
+ // Add field properties to the interface
1107
+ for i := range t.NumFields() {
1108
+ field := t.Field(i)
1109
+ if i > 0 {
1110
+ c.tsw.WriteLiterally("; ")
1111
+ }
1112
+ c.tsw.WriteLiterally(field.Name() + "?: ")
1113
+ c.WriteGoType(field.Type())
1099
1114
  }
1100
- c.WriteFieldList(exp.Fields, false) // false = not arguments
1115
+ c.tsw.WriteLiterally(" }")
1101
1116
  }
1102
1117
 
1103
1118
  // WriteFuncType translates a Go function type (`ast.FuncType`) into a TypeScript
@@ -1175,6 +1190,22 @@ func (c *GoToTSCompiler) WriteFuncType(exp *ast.FuncType, isAsync bool) {
1175
1190
  func (c *GoToTSCompiler) WriteCallExpr(exp *ast.CallExpr) error {
1176
1191
  expFun := exp.Fun
1177
1192
 
1193
+ // Handle any type conversion with nil argument
1194
+ if len(exp.Args) == 1 {
1195
+ if nilIdent, isIdent := exp.Args[0].(*ast.Ident); isIdent && nilIdent.Name == "nil" {
1196
+ // Handle nil pointer to struct type conversions: (*struct{})(nil)
1197
+ if starExpr, isStarExpr := expFun.(*ast.StarExpr); isStarExpr {
1198
+ if _, isStructType := starExpr.X.(*ast.StructType); isStructType {
1199
+ c.tsw.WriteLiterally("null")
1200
+ return nil
1201
+ }
1202
+ }
1203
+
1204
+ c.tsw.WriteLiterally("null")
1205
+ return nil
1206
+ }
1207
+ }
1208
+
1178
1209
  // Handle array type conversions like []rune(string)
1179
1210
  if arrayType, isArrayType := expFun.(*ast.ArrayType); isArrayType {
1180
1211
  // Check if it's a []rune type
@@ -1270,7 +1301,26 @@ func (c *GoToTSCompiler) WriteCallExpr(exp *ast.CallExpr) error {
1270
1301
  c.tsw.WriteLiterally(", ") // Add comma for zero value argument
1271
1302
 
1272
1303
  // Write the zero value for the channel's element type
1273
- c.WriteZeroValueForType(chanType.Elem())
1304
+ if chanType.Elem().String() == "struct{}" {
1305
+ c.tsw.WriteLiterally("{}")
1306
+ } else {
1307
+ c.WriteZeroValueForType(chanType.Elem())
1308
+ }
1309
+
1310
+ // Add direction parameter
1311
+ c.tsw.WriteLiterally(", ")
1312
+
1313
+ // Determine channel direction
1314
+ switch chanType.Dir() {
1315
+ case types.SendRecv:
1316
+ c.tsw.WriteLiterally("'both'")
1317
+ case types.SendOnly:
1318
+ c.tsw.WriteLiterally("'send'")
1319
+ case types.RecvOnly:
1320
+ c.tsw.WriteLiterally("'receive'")
1321
+ default:
1322
+ c.tsw.WriteLiterally("'both'") // Default to bidirectional
1323
+ }
1274
1324
 
1275
1325
  c.tsw.WriteLiterally(")")
1276
1326
  return nil // Handled make for channel
@@ -1431,6 +1481,42 @@ func (c *GoToTSCompiler) WriteCallExpr(exp *ast.CallExpr) error {
1431
1481
  }
1432
1482
  return errors.New("unhandled byte call with incorrect number of arguments")
1433
1483
  default:
1484
+ // Check if this is a type conversion to a function type
1485
+ if funIdent != nil {
1486
+ if obj := c.pkg.TypesInfo.Uses[funIdent]; obj != nil {
1487
+ // Check if the object is a type name
1488
+ if typeName, isType := obj.(*types.TypeName); isType {
1489
+ // Make sure we have exactly one argument
1490
+ if len(exp.Args) == 1 {
1491
+ // Check if this is a function type
1492
+ if _, isFuncType := typeName.Type().Underlying().(*types.Signature); isFuncType {
1493
+ // For function types, we need to add a __goTypeName property
1494
+ c.tsw.WriteLiterally("Object.assign(")
1495
+
1496
+ // Write the argument first
1497
+ if err := c.WriteValueExpr(exp.Args[0]); err != nil {
1498
+ return fmt.Errorf("failed to write argument for function type cast: %w", err)
1499
+ }
1500
+
1501
+ // Add the __goTypeName property with the function type name
1502
+ c.tsw.WriteLiterallyf(", { __goTypeName: '%s' })", funIdent.String())
1503
+ return nil // Handled function type cast
1504
+ } else {
1505
+ // For non-function types, use the TypeScript "as" operator
1506
+ c.tsw.WriteLiterally("(")
1507
+ if err := c.WriteValueExpr(exp.Args[0]); err != nil {
1508
+ return fmt.Errorf("failed to write argument for type cast: %w", err)
1509
+ }
1510
+
1511
+ // Then use the TypeScript "as" operator with the type name
1512
+ c.tsw.WriteLiterallyf(" as %s)", funIdent.String())
1513
+ return nil // Handled non-function type cast
1514
+ }
1515
+ }
1516
+ }
1517
+ }
1518
+ }
1519
+
1434
1520
  // Check if this is an async function call
1435
1521
  if funIdent != nil {
1436
1522
  // Get the object for this function identifier
@@ -1444,6 +1530,15 @@ func (c *GoToTSCompiler) WriteCallExpr(exp *ast.CallExpr) error {
1444
1530
  if err := c.WriteValueExpr(expFun); err != nil {
1445
1531
  return fmt.Errorf("failed to write function expression in call: %w", err)
1446
1532
  }
1533
+
1534
+ if funType := c.pkg.TypesInfo.TypeOf(expFun); funType != nil {
1535
+ if _, ok := funType.Underlying().(*types.Signature); ok {
1536
+ if _, isNamed := funType.(*types.Named); isNamed {
1537
+ c.tsw.WriteLiterally("!")
1538
+ }
1539
+ }
1540
+ }
1541
+
1447
1542
  c.tsw.WriteLiterally("(")
1448
1543
  for i, arg := range exp.Args {
1449
1544
  if i != 0 {
@@ -1461,6 +1556,14 @@ func (c *GoToTSCompiler) WriteCallExpr(exp *ast.CallExpr) error {
1461
1556
  if err := c.WriteValueExpr(expFun); err != nil {
1462
1557
  return fmt.Errorf("failed to write method expression in call: %w", err)
1463
1558
  }
1559
+
1560
+ if funType := c.pkg.TypesInfo.TypeOf(expFun); funType != nil {
1561
+ if _, ok := funType.Underlying().(*types.Signature); ok {
1562
+ if _, isNamed := funType.(*types.Named); isNamed {
1563
+ c.tsw.WriteLiterally("!")
1564
+ }
1565
+ }
1566
+ }
1464
1567
  }
1465
1568
  c.tsw.WriteLiterally("(")
1466
1569
  for i, arg := range exp.Args {
@@ -1709,10 +1812,10 @@ func (c *GoToTSCompiler) WriteBasicLit(exp *ast.BasicLit) {
1709
1812
  // Use strconv.UnquoteChar to handle escape sequences correctly.
1710
1813
  val, _, _, err := strconv.UnquoteChar(exp.Value[1:len(exp.Value)-1], '\'')
1711
1814
  if err != nil {
1712
- c.tsw.WriteCommentInline(fmt.Sprintf("error parsing char literal %s: %v", exp.Value, err))
1815
+ c.tsw.WriteCommentInlinef("error parsing char literal %s: %v", exp.Value, err)
1713
1816
  c.tsw.WriteLiterally("0") // Default to 0 on error
1714
1817
  } else {
1715
- c.tsw.WriteLiterally(fmt.Sprintf("%d", val))
1818
+ c.tsw.WriteLiterallyf("%d", val)
1716
1819
  }
1717
1820
  } else {
1718
1821
  // Other literals (INT, FLOAT, STRING, IMAG)
@@ -2362,7 +2465,7 @@ func (c *GoToTSCompiler) collectMethodNames(structName string) string {
2362
2465
  // Check if the receiver identifier name matches the struct name
2363
2466
  if ident, ok := recvType.(*ast.Ident); ok && ident.Name == structName {
2364
2467
  // Found a method for this struct
2365
- methodNames = append(methodNames, fmt.Sprintf("'%s'", funcDecl.Name.Name))
2468
+ methodNames = append(methodNames, strconv.Quote(funcDecl.Name.Name))
2366
2469
  }
2367
2470
  }
2368
2471
  }
@@ -2744,6 +2847,21 @@ func (c *GoToTSCompiler) WriteValueSpec(a *ast.ValueSpec) error {
2744
2847
  var initializerExpr ast.Expr
2745
2848
  if hasInitializer {
2746
2849
  initializerExpr = a.Values[0]
2850
+
2851
+ // Special case for nil pointer to struct type: (*struct{})(nil)
2852
+ if callExpr, isCallExpr := initializerExpr.(*ast.CallExpr); isCallExpr {
2853
+ if starExpr, isStarExpr := callExpr.Fun.(*ast.StarExpr); isStarExpr {
2854
+ if _, isStructType := starExpr.X.(*ast.StructType); isStructType {
2855
+ // Check if the argument is nil
2856
+ if len(callExpr.Args) == 1 {
2857
+ if nilIdent, isIdent := callExpr.Args[0].(*ast.Ident); isIdent && nilIdent.Name == "nil" {
2858
+ c.tsw.WriteLiterally("null")
2859
+ return nil
2860
+ }
2861
+ }
2862
+ }
2863
+ }
2864
+ }
2747
2865
  }
2748
2866
 
2749
2867
  if needsBox {
@@ -3017,10 +3135,17 @@ func (c *GoToTSCompiler) WriteFieldList(a *ast.FieldList, isArguments bool) {
3017
3135
  if i > 0 {
3018
3136
  c.tsw.WriteLiterally(", ")
3019
3137
  }
3020
- c.WriteField(field, true)
3021
- c.tsw.WriteLiterally(": ")
3022
- typ := c.pkg.TypesInfo.TypeOf(field.Type)
3023
- c.WriteGoType(typ)
3138
+
3139
+ // Handle multiple parameter names for the same type
3140
+ for j, name := range field.Names {
3141
+ if j > 0 {
3142
+ c.tsw.WriteLiterally(", ")
3143
+ }
3144
+ c.tsw.WriteLiterally(name.Name)
3145
+ c.tsw.WriteLiterally(": ")
3146
+ typ := c.pkg.TypesInfo.TypeOf(field.Type)
3147
+ c.WriteGoType(typ)
3148
+ }
3024
3149
  }
3025
3150
 
3026
3151
  // Handle the variadic parameter
@@ -3050,11 +3175,16 @@ func (c *GoToTSCompiler) WriteFieldList(a *ast.FieldList, isArguments bool) {
3050
3175
  }
3051
3176
 
3052
3177
  if isArguments {
3053
- // For function parameters, write "name: type"
3054
- c.WriteField(field, true)
3055
- c.tsw.WriteLiterally(": ")
3056
- typ := c.pkg.TypesInfo.TypeOf(field.Type)
3057
- c.WriteGoType(typ) // Use WriteGoType for parameter type
3178
+ // For function parameters with multiple names, write each with its type
3179
+ for j, name := range field.Names {
3180
+ if j > 0 {
3181
+ c.tsw.WriteLiterally(", ")
3182
+ }
3183
+ c.tsw.WriteLiterally(name.Name)
3184
+ c.tsw.WriteLiterally(": ")
3185
+ typ := c.pkg.TypesInfo.TypeOf(field.Type)
3186
+ c.WriteGoType(typ) // Use WriteGoType for parameter type
3187
+ }
3058
3188
  } else {
3059
3189
  // For struct fields and other non-argument fields
3060
3190
  c.WriteField(field, false)
@@ -3100,7 +3230,11 @@ func (c *GoToTSCompiler) WriteField(field *ast.Field, isArguments bool) {
3100
3230
  return
3101
3231
  }
3102
3232
 
3103
- for _, name := range field.Names {
3233
+ for i, name := range field.Names {
3234
+ if i > 0 && isArguments {
3235
+ c.tsw.WriteLiterally(", ")
3236
+ }
3237
+
3104
3238
  // argument names: keep original casing, no access modifier
3105
3239
  if isArguments {
3106
3240
  c.tsw.WriteLiterally(name.Name)
@@ -3120,7 +3254,7 @@ func (c *GoToTSCompiler) WriteField(field *ast.Field, isArguments bool) {
3120
3254
  if !isArguments {
3121
3255
  // write tag comment if any for struct fields
3122
3256
  if field.Tag != nil {
3123
- c.tsw.WriteCommentLine(fmt.Sprintf(" // tag: %s", field.Tag.Value))
3257
+ c.tsw.WriteCommentLinef("tag: %s", field.Tag.Value)
3124
3258
  } else {
3125
3259
  c.tsw.WriteLine("") // No semicolon
3126
3260
  }
@@ -3198,8 +3332,12 @@ func (c *GoToTSCompiler) WriteStmt(a ast.Stmt) error {
3198
3332
  if err := c.WriteValueSpec(valueSpec); err != nil {
3199
3333
  return fmt.Errorf("failed to write value spec in declaration statement: %w", err)
3200
3334
  }
3335
+ } else if typeSpec, ok := spec.(*ast.TypeSpec); ok {
3336
+ if err := c.WriteTypeSpec(typeSpec); err != nil {
3337
+ return fmt.Errorf("failed to write type spec in declaration statement: %w", err)
3338
+ }
3201
3339
  } else {
3202
- c.tsw.WriteCommentLine(fmt.Sprintf("unhandled spec in DeclStmt: %T", spec))
3340
+ c.tsw.WriteCommentLinef("unhandled spec in DeclStmt: %T", spec)
3203
3341
  }
3204
3342
  }
3205
3343
  } else {
@@ -3278,7 +3416,7 @@ func (c *GoToTSCompiler) WriteStmt(a ast.Stmt) error {
3278
3416
  case token.CONTINUE:
3279
3417
  c.tsw.WriteLine("continue") // No semicolon needed
3280
3418
  default:
3281
- c.tsw.WriteCommentLine(fmt.Sprintf("unhandled branch statement token: %s", exp.Tok.String()))
3419
+ c.tsw.WriteCommentLinef("unhandled branch statement token: %s", exp.Tok.String())
3282
3420
  }
3283
3421
  default:
3284
3422
  return errors.Errorf("unknown statement: %s\n", a)
@@ -3316,7 +3454,7 @@ func (c *GoToTSCompiler) WriteStmtDefer(exp *ast.DeferStmt) error {
3316
3454
 
3317
3455
  // Set stack variable based on whether we are in an async function
3318
3456
  stackVar := "__defer"
3319
- c.tsw.WriteLiterally(fmt.Sprintf("%s.defer(%s() => {", stackVar, asyncPrefix))
3457
+ c.tsw.WriteLiterallyf("%s.defer(%s() => {", stackVar, asyncPrefix)
3320
3458
  c.tsw.Indent(1)
3321
3459
  c.tsw.WriteLine("")
3322
3460
 
@@ -3418,7 +3556,7 @@ func (c *GoToTSCompiler) WriteStmtSelect(exp *ast.SelectStmt) error {
3418
3556
  c.tsw.WriteLiterally("{") // Start object literal
3419
3557
  c.tsw.Indent(1)
3420
3558
  c.tsw.WriteLine("")
3421
- c.tsw.WriteLiterally(fmt.Sprintf("id: %d,", caseID))
3559
+ c.tsw.WriteLiterallyf("id: %d,", caseID)
3422
3560
  c.tsw.WriteLine("")
3423
3561
 
3424
3562
  // Handle different types of comm statements
@@ -3437,10 +3575,10 @@ func (c *GoToTSCompiler) WriteStmtSelect(exp *ast.SelectStmt) error {
3437
3575
  c.tsw.WriteLiterally(",")
3438
3576
  c.tsw.WriteLine("")
3439
3577
  } else {
3440
- c.tsw.WriteCommentLine(fmt.Sprintf("unhandled RHS in select assignment case: %T", comm.Rhs[0]))
3578
+ c.tsw.WriteCommentLinef("unhandled RHS in select assignment case: %T", comm.Rhs[0])
3441
3579
  }
3442
3580
  } else {
3443
- c.tsw.WriteCommentLine(fmt.Sprintf("unhandled RHS count in select assignment case: %d", len(comm.Rhs)))
3581
+ c.tsw.WriteCommentLinef("unhandled RHS count in select assignment case: %d", len(comm.Rhs))
3444
3582
  }
3445
3583
  case *ast.ExprStmt:
3446
3584
  // This is a simple receive: case <-ch:
@@ -3454,7 +3592,7 @@ func (c *GoToTSCompiler) WriteStmtSelect(exp *ast.SelectStmt) error {
3454
3592
  c.tsw.WriteLiterally(",")
3455
3593
  c.tsw.WriteLine("")
3456
3594
  } else {
3457
- c.tsw.WriteCommentLine(fmt.Sprintf("unhandled expression in select case: %T", comm.X))
3595
+ c.tsw.WriteCommentLinef("unhandled expression in select case: %T", comm.X)
3458
3596
  }
3459
3597
  case *ast.SendStmt:
3460
3598
  // This is a send operation: case ch <- v:
@@ -3473,7 +3611,7 @@ func (c *GoToTSCompiler) WriteStmtSelect(exp *ast.SelectStmt) error {
3473
3611
  c.tsw.WriteLiterally(",")
3474
3612
  c.tsw.WriteLine("")
3475
3613
  default:
3476
- c.tsw.WriteCommentLine(fmt.Sprintf("unhandled comm statement in select case: %T", comm))
3614
+ c.tsw.WriteCommentLinef("unhandled comm statement in select case: %T", comm)
3477
3615
  }
3478
3616
 
3479
3617
  // Add the onSelected handler to execute the case body after the select resolves
@@ -3530,14 +3668,14 @@ func (c *GoToTSCompiler) WriteStmtSelect(exp *ast.SelectStmt) error {
3530
3668
  c.tsw.WriteLine("")
3531
3669
 
3532
3670
  } else {
3533
- c.tsw.WriteCommentLine(fmt.Sprintf("unknown statement in select body: %T", stmt))
3671
+ c.tsw.WriteCommentLinef("unknown statement in select body: %T", stmt)
3534
3672
  }
3535
3673
  }
3536
3674
 
3537
3675
  // Close the array literal and the selectStatement call
3538
3676
  c.tsw.Indent(-1)
3539
3677
  c.tsw.WriteLiterally("], ")
3540
- c.tsw.WriteLiterally(fmt.Sprintf("%t", hasDefault))
3678
+ c.tsw.WriteLiterallyf("%t", hasDefault)
3541
3679
  c.tsw.WriteLiterally(")")
3542
3680
  c.tsw.WriteLine("")
3543
3681
 
@@ -3591,7 +3729,7 @@ func (c *GoToTSCompiler) WriteStmtSwitch(exp *ast.SwitchStmt) error {
3591
3729
  return fmt.Errorf("failed to write case clause in switch statement: %w", err)
3592
3730
  }
3593
3731
  } else {
3594
- c.tsw.WriteCommentLine(fmt.Sprintf("unhandled statement in switch body: %T", stmt))
3732
+ c.tsw.WriteCommentLinef("unhandled statement in switch body: %T", stmt)
3595
3733
  }
3596
3734
  }
3597
3735
 
@@ -4547,10 +4685,11 @@ func (c *GoToTSCompiler) WriteStmtAssign(exp *ast.AssignStmt) error {
4547
4685
  if !existsIsBlank {
4548
4686
  c.tsw.WriteLiterally(existsName)
4549
4687
  c.tsw.WriteLiterally(" = ")
4688
+ c.tsw.WriteLiterally("$.mapHas(")
4550
4689
  if err := c.WriteValueExpr(indexExpr.X); err != nil { // Map
4551
4690
  return err
4552
4691
  }
4553
- c.tsw.WriteLiterally(".has(")
4692
+ c.tsw.WriteLiterally(", ")
4554
4693
  if err := c.WriteValueExpr(indexExpr.Index); err != nil { // Key
4555
4694
  return err
4556
4695
  }
@@ -4562,14 +4701,15 @@ func (c *GoToTSCompiler) WriteStmtAssign(exp *ast.AssignStmt) error {
4562
4701
  if !valueIsBlank {
4563
4702
  c.tsw.WriteLiterally(valueName)
4564
4703
  c.tsw.WriteLiterally(" = ")
4704
+ c.tsw.WriteLiterally("$.mapGet(")
4565
4705
  if err := c.WriteValueExpr(indexExpr.X); err != nil { // Map
4566
4706
  return err
4567
4707
  }
4568
- c.tsw.WriteLiterally(".get(")
4708
+ c.tsw.WriteLiterally(", ")
4569
4709
  if err := c.WriteValueExpr(indexExpr.Index); err != nil { // Key
4570
4710
  return err
4571
4711
  }
4572
- c.tsw.WriteLiterally(") ?? ")
4712
+ c.tsw.WriteLiterally(", ")
4573
4713
  // Write the zero value for the map's value type
4574
4714
  if tv, ok := c.pkg.TypesInfo.Types[indexExpr.X]; ok {
4575
4715
  if mapType, isMap := tv.Type.Underlying().(*types.Map); isMap {
@@ -4581,27 +4721,30 @@ func (c *GoToTSCompiler) WriteStmtAssign(exp *ast.AssignStmt) error {
4581
4721
  } else {
4582
4722
  c.tsw.WriteLiterally("null")
4583
4723
  }
4724
+ c.tsw.WriteLiterally(")")
4584
4725
  c.tsw.WriteLine("")
4585
4726
  } else if existsIsBlank {
4586
4727
  // If both are blank, still evaluate for side effects (though .has/.get are usually pure)
4587
4728
  // We add a ; otherwise TypeScript thinks we are invoking a function.
4588
- c.tsw.WriteLiterally(";(") // Wrap in parens to make it an expression statement
4729
+ c.tsw.WriteLiterally(";(") // Wrap in parens to make it an expression statement
4730
+ c.tsw.WriteLiterally("$.mapHas(")
4589
4731
  if err := c.WriteValueExpr(indexExpr.X); err != nil { // Map
4590
4732
  return err
4591
4733
  }
4592
- c.tsw.WriteLiterally(".has(")
4734
+ c.tsw.WriteLiterally(", ")
4593
4735
  if err := c.WriteValueExpr(indexExpr.Index); err != nil { // Key
4594
4736
  return err
4595
4737
  }
4596
- c.tsw.WriteLiterally("), ") // Evaluate .has
4738
+ c.tsw.WriteLiterally("), ") // Evaluate .has
4739
+ c.tsw.WriteLiterally("$.mapGet(")
4597
4740
  if err := c.WriteValueExpr(indexExpr.X); err != nil { // Map
4598
4741
  return err
4599
4742
  }
4600
- c.tsw.WriteLiterally(".get(")
4743
+ c.tsw.WriteLiterally(", ")
4601
4744
  if err := c.WriteValueExpr(indexExpr.Index); err != nil { // Key
4602
4745
  return err
4603
4746
  }
4604
- c.tsw.WriteLiterally("))") // Evaluate .get
4747
+ c.tsw.WriteLiterally(", null))") // Evaluate .get with null as default
4605
4748
  c.tsw.WriteLine("")
4606
4749
  }
4607
4750
 
@@ -5072,7 +5215,7 @@ func (c *GoToTSCompiler) WriteStmtRange(exp *ast.RangeStmt) error {
5072
5215
  indexVarName = keyIdent.Name
5073
5216
  }
5074
5217
  }
5075
- c.tsw.WriteLiterally(fmt.Sprintf("for (let %s = 0; %s < _runes.length; %s++) {", indexVarName, indexVarName, indexVarName))
5218
+ c.tsw.WriteLiterallyf("for (let %s = 0; %s < _runes.length; %s++) {", indexVarName, indexVarName, indexVarName)
5076
5219
  c.tsw.Indent(1)
5077
5220
  c.tsw.WriteLine("")
5078
5221
  // Declare value if provided and not blank
@@ -5104,11 +5247,11 @@ func (c *GoToTSCompiler) WriteStmtRange(exp *ast.RangeStmt) error {
5104
5247
  }
5105
5248
  }
5106
5249
 
5107
- c.tsw.WriteLiterally(fmt.Sprintf("for (let %s = 0; %s < ", indexVarName, indexVarName))
5250
+ c.tsw.WriteLiterallyf("for (let %s = 0; %s < ", indexVarName, indexVarName)
5108
5251
  if err := c.WriteValueExpr(exp.X); err != nil { // This is N
5109
5252
  return fmt.Errorf("failed to write range loop integer expression: %w", err)
5110
5253
  }
5111
- c.tsw.WriteLiterally(fmt.Sprintf("; %s++) {", indexVarName))
5254
+ c.tsw.WriteLiterallyf("; %s++) {", indexVarName)
5112
5255
  c.tsw.Indent(1)
5113
5256
  c.tsw.WriteLine("")
5114
5257
 
@@ -5139,11 +5282,11 @@ func (c *GoToTSCompiler) WriteStmtRange(exp *ast.RangeStmt) error {
5139
5282
  }
5140
5283
  // If both key and value are provided, use an index loop and assign both
5141
5284
  if exp.Key != nil && exp.Value != nil {
5142
- c.tsw.WriteLiterally(fmt.Sprintf("for (let %s = 0; %s < ", indexVarName, indexVarName))
5285
+ c.tsw.WriteLiterallyf("for (let %s = 0; %s < $.len(", indexVarName, indexVarName)
5143
5286
  if err := c.WriteValueExpr(exp.X); err != nil { // Write the expression for the iterable
5144
5287
  return fmt.Errorf("failed to write range loop array/slice expression (key and value): %w", err)
5145
5288
  }
5146
- c.tsw.WriteLiterally(fmt.Sprintf(".length; %s++) {", indexVarName))
5289
+ c.tsw.WriteLiterallyf("); %s++) {", indexVarName)
5147
5290
  c.tsw.Indent(1)
5148
5291
  c.tsw.WriteLine("")
5149
5292
  // Declare value if not blank
@@ -5154,7 +5297,7 @@ func (c *GoToTSCompiler) WriteStmtRange(exp *ast.RangeStmt) error {
5154
5297
  if err := c.WriteValueExpr(exp.X); err != nil {
5155
5298
  return fmt.Errorf("failed to write range loop array/slice value expression: %w", err)
5156
5299
  }
5157
- c.tsw.WriteLiterally(fmt.Sprintf("[%s]", indexVarName)) // Use indexVarName
5300
+ c.tsw.WriteLiterallyf("![%s]", indexVarName) // Use indexVarName with not-null assert
5158
5301
  c.tsw.WriteLine("")
5159
5302
  }
5160
5303
  if err := c.WriteStmt(exp.Body); err != nil {
@@ -5164,12 +5307,12 @@ func (c *GoToTSCompiler) WriteStmtRange(exp *ast.RangeStmt) error {
5164
5307
  c.tsw.WriteLine("}")
5165
5308
  return nil
5166
5309
  } else if exp.Key != nil && exp.Value == nil { // Only key provided
5167
- c.tsw.WriteLiterally(fmt.Sprintf("for (let %s = 0; %s < ", indexVarName, indexVarName))
5310
+ c.tsw.WriteLiterallyf("for (let %s = 0; %s < $.len(", indexVarName, indexVarName)
5168
5311
  // Write the expression for the iterable
5169
5312
  if err := c.WriteValueExpr(exp.X); err != nil {
5170
5313
  return fmt.Errorf("failed to write expression for the iterable: %w", err)
5171
5314
  }
5172
- c.tsw.WriteLiterally(fmt.Sprintf(".length; %s++) {", indexVarName))
5315
+ c.tsw.WriteLiterallyf("); %s++) {", indexVarName)
5173
5316
  c.tsw.Indent(1)
5174
5317
  c.tsw.WriteLine("")
5175
5318
  if err := c.WriteStmtBlock(exp.Body, false); err != nil {
@@ -5184,11 +5327,11 @@ func (c *GoToTSCompiler) WriteStmtRange(exp *ast.RangeStmt) error {
5184
5327
  } else {
5185
5328
  // Fallback: simple index loop without declaring range variables, use _i
5186
5329
  indexVarName := "_i"
5187
- c.tsw.WriteLiterally(fmt.Sprintf("for (let %s = 0; %s < ", indexVarName, indexVarName))
5330
+ c.tsw.WriteLiterallyf("for (let %s = 0; %s < $.len(", indexVarName, indexVarName)
5188
5331
  if err := c.WriteValueExpr(exp.X); err != nil {
5189
5332
  return fmt.Errorf("failed to write range loop array/slice length expression (fallback): %w", err)
5190
5333
  }
5191
- c.tsw.WriteLiterally(fmt.Sprintf(".length; %s++) {", indexVarName))
5334
+ c.tsw.WriteLiterallyf("); %s++) {", indexVarName)
5192
5335
  c.tsw.Indent(1)
5193
5336
  c.tsw.WriteLine("")
5194
5337
  if err := c.WriteStmtBlock(exp.Body, false); err != nil {
@@ -5249,6 +5392,15 @@ func (c *GoToTSCompiler) writeTypeAssertion(lhs []ast.Expr, typeAssertExpr *ast.
5249
5392
  interfaceExpr := typeAssertExpr.X
5250
5393
  assertedType := typeAssertExpr.Type
5251
5394
 
5395
+ // Unwrap parenthesized expressions to handle cases like r.((<-chan T))
5396
+ for {
5397
+ if parenExpr, ok := assertedType.(*ast.ParenExpr); ok {
5398
+ assertedType = parenExpr.X
5399
+ } else {
5400
+ break
5401
+ }
5402
+ }
5403
+
5252
5404
  // Ensure LHS has exactly two expressions (value and ok)
5253
5405
  if len(lhs) != 2 {
5254
5406
  return fmt.Errorf("type assertion assignment requires exactly 2 variables on LHS, got %d", len(lhs))
@@ -5259,32 +5411,93 @@ func (c *GoToTSCompiler) writeTypeAssertion(lhs []ast.Expr, typeAssertExpr *ast.
5259
5411
  okIsBlank := false
5260
5412
  var valueName string
5261
5413
  var okName string
5414
+ var valueIdent *ast.Ident
5415
+ var okIdent *ast.Ident
5262
5416
 
5263
- if valIdent, ok := lhs[0].(*ast.Ident); ok {
5264
- if valIdent.Name == "_" {
5417
+ if valId, ok := lhs[0].(*ast.Ident); ok {
5418
+ valueIdent = valId
5419
+ if valId.Name == "_" {
5265
5420
  valueIsBlank = true
5266
5421
  } else {
5267
- valueName = valIdent.Name
5422
+ valueName = valId.Name
5268
5423
  }
5269
5424
  } else {
5270
5425
  return fmt.Errorf("unhandled LHS expression type for value in type assertion: %T", lhs[0])
5271
5426
  }
5272
5427
 
5273
- if okIdent, ok := lhs[1].(*ast.Ident); ok {
5274
- if okIdent.Name == "_" {
5428
+ if okId, ok := lhs[1].(*ast.Ident); ok {
5429
+ okIdent = okId
5430
+ if okId.Name == "_" {
5275
5431
  okIsBlank = true
5276
5432
  } else {
5277
- okName = okIdent.Name
5433
+ okName = okId.Name
5278
5434
  }
5279
5435
  } else {
5280
5436
  return fmt.Errorf("unhandled LHS expression type for ok in type assertion: %T", lhs[1])
5281
5437
  }
5282
5438
 
5283
- // Generate the destructuring assignment
5439
+ // For token.DEFINE (:=), we need to check if any of the variables are already declared
5440
+ // In Go, := can be used for redeclaration if at least one variable is new
5441
+ writeEndParen := false
5284
5442
  if tok == token.DEFINE {
5285
- c.tsw.WriteLiterally("let ")
5443
+ // Identify which variables are new vs existing
5444
+ valueIsNew := true
5445
+ okIsNew := true
5446
+ anyNewVars := false
5447
+ allNewVars := true
5448
+
5449
+ // Check if variables are already in scope
5450
+ if !valueIsBlank {
5451
+ if obj := c.pkg.TypesInfo.Uses[valueIdent]; obj != nil {
5452
+ // If it's in Uses, it's referenced elsewhere, so it exists
5453
+ valueIsNew = false
5454
+ allNewVars = false
5455
+ }
5456
+ if valueIsNew {
5457
+ anyNewVars = true
5458
+ }
5459
+ }
5460
+
5461
+ if !okIsBlank {
5462
+ if obj := c.pkg.TypesInfo.Uses[okIdent]; obj != nil {
5463
+ // If it's in Uses, it's referenced elsewhere, so it exists
5464
+ okIsNew = false
5465
+ allNewVars = false
5466
+ }
5467
+ if okIsNew {
5468
+ anyNewVars = true
5469
+ }
5470
+ }
5471
+
5472
+ if allNewVars && anyNewVars {
5473
+ c.tsw.WriteLiterally("let ")
5474
+ } else if anyNewVars {
5475
+ // If only some variables are new, declare them separately
5476
+ if !valueIsBlank && valueIsNew {
5477
+ c.tsw.WriteLiterally("let ")
5478
+ c.tsw.WriteLiterally(valueName)
5479
+ // Add type annotation if possible
5480
+ if tv, ok := c.pkg.TypesInfo.Types[assertedType]; ok {
5481
+ c.tsw.WriteLiterally(": ")
5482
+ c.WriteGoType(tv.Type)
5483
+ }
5484
+ c.tsw.WriteLine("")
5485
+ }
5486
+ if !okIsBlank && okIsNew {
5487
+ c.tsw.WriteLiterally("let ")
5488
+ c.tsw.WriteLiterally(okName)
5489
+ c.tsw.WriteLiterally(": boolean") // ok is always boolean
5490
+ c.tsw.WriteLine("")
5491
+ }
5492
+ // Use parenthesized destructuring assignment for existing variables
5493
+ c.tsw.WriteLiterally(";(")
5494
+ writeEndParen = true
5495
+ } else {
5496
+ // All variables exist, use parenthesized destructuring assignment
5497
+ c.tsw.WriteLiterally(";(")
5498
+ writeEndParen = true
5499
+ }
5286
5500
  } else {
5287
- // We must wrap in parenthesis.
5288
5501
  c.tsw.WriteLiterally("(")
5289
5502
  }
5290
5503
 
@@ -5319,9 +5532,9 @@ func (c *GoToTSCompiler) writeTypeAssertion(lhs []ast.Expr, typeAssertExpr *ast.
5319
5532
  c.tsw.WriteLiterally("keyType: ")
5320
5533
  if ident, ok := typeExpr.Key.(*ast.Ident); ok && isPrimitiveType(ident.Name) {
5321
5534
  if tsType, ok := GoBuiltinToTypescript(ident.Name); ok {
5322
- c.tsw.WriteLiterally(fmt.Sprintf("'%s'", tsType))
5535
+ c.tsw.WriteLiterallyf("'%s'", tsType)
5323
5536
  } else {
5324
- c.tsw.WriteLiterally(fmt.Sprintf("'%s'", ident.Name)) // Fallback
5537
+ c.tsw.WriteLiterallyf("'%s'", ident.Name) // Fallback
5325
5538
  }
5326
5539
  } else {
5327
5540
  c.writeTypeDescription(typeExpr.Key)
@@ -5333,9 +5546,9 @@ func (c *GoToTSCompiler) writeTypeAssertion(lhs []ast.Expr, typeAssertExpr *ast.
5333
5546
  c.tsw.WriteLiterally("elemType: ")
5334
5547
  if ident, ok := typeExpr.Value.(*ast.Ident); ok && isPrimitiveType(ident.Name) {
5335
5548
  if tsType, ok := GoBuiltinToTypescript(ident.Name); ok {
5336
- c.tsw.WriteLiterally(fmt.Sprintf("'%s'", tsType))
5549
+ c.tsw.WriteLiterallyf("'%s'", tsType)
5337
5550
  } else {
5338
- c.tsw.WriteLiterally(fmt.Sprintf("'%s'", ident.Name)) // Fallback
5551
+ c.tsw.WriteLiterallyf("'%s'", ident.Name) // Fallback
5339
5552
  }
5340
5553
  } else {
5341
5554
  c.writeTypeDescription(typeExpr.Value)
@@ -5351,15 +5564,15 @@ func (c *GoToTSCompiler) writeTypeAssertion(lhs []ast.Expr, typeAssertExpr *ast.
5351
5564
 
5352
5565
  // Create a type descriptor object
5353
5566
  c.tsw.WriteLiterally("{")
5354
- c.tsw.WriteLiterally(fmt.Sprintf("kind: %s, ", typeKind))
5567
+ c.tsw.WriteLiterallyf("kind: %s, ", typeKind)
5355
5568
 
5356
5569
  // Add element type
5357
5570
  c.tsw.WriteLiterally("elemType: ")
5358
5571
  if ident, ok := typeExpr.Elt.(*ast.Ident); ok && isPrimitiveType(ident.Name) {
5359
5572
  if tsType, ok := GoBuiltinToTypescript(ident.Name); ok {
5360
- c.tsw.WriteLiterally(fmt.Sprintf("'%s'", tsType))
5573
+ c.tsw.WriteLiterallyf("'%s'", tsType)
5361
5574
  } else {
5362
- c.tsw.WriteLiterally(fmt.Sprintf("'%s'", ident.Name)) // Fallback
5575
+ c.tsw.WriteLiterallyf("'%s'", ident.Name) // Fallback
5363
5576
  }
5364
5577
  } else {
5365
5578
  c.writeTypeDescription(typeExpr.Elt)
@@ -5374,21 +5587,30 @@ func (c *GoToTSCompiler) writeTypeAssertion(lhs []ast.Expr, typeAssertExpr *ast.
5374
5587
  // Get the type name if available
5375
5588
  typeName := c.getTypeNameString(assertedType)
5376
5589
  if typeName != "unknown" {
5377
- c.tsw.WriteLiterally(fmt.Sprintf(", name: '%s'", typeName))
5590
+ c.tsw.WriteLiterallyf(", name: '%s'", typeName)
5378
5591
  }
5379
5592
 
5380
5593
  if typeExpr.Fields != nil && typeExpr.Fields.List != nil {
5381
- c.tsw.WriteLiterally(", fields: new Set([")
5594
+ // Add fields property to provide type information
5595
+ c.tsw.WriteLiterally(", fields: {")
5382
5596
 
5383
- fields := []string{}
5597
+ hasFields := false
5384
5598
  for _, field := range typeExpr.Fields.List {
5385
- for _, name := range field.Names {
5386
- fields = append(fields, fmt.Sprintf("'%s'", name.Name))
5599
+ if len(field.Names) > 0 {
5600
+ for _, name := range field.Names {
5601
+ if hasFields {
5602
+ c.tsw.WriteLiterally(", ")
5603
+ }
5604
+ c.tsw.WriteLiterally(fmt.Sprintf("'%s': ", name.Name))
5605
+ c.writeTypeDescription(field.Type)
5606
+ hasFields = true
5607
+ }
5387
5608
  }
5388
5609
  }
5389
5610
 
5390
- c.tsw.WriteLiterally(strings.Join(fields, ", "))
5391
- c.tsw.WriteLiterally("])")
5611
+ c.tsw.WriteLiterally("}")
5612
+ } else {
5613
+ c.tsw.WriteLiterally(", fields: {}")
5392
5614
  }
5393
5615
 
5394
5616
  // Add empty methods set to satisfy StructTypeInfo interface
@@ -5402,7 +5624,7 @@ func (c *GoToTSCompiler) writeTypeAssertion(lhs []ast.Expr, typeAssertExpr *ast.
5402
5624
  // Get the type name if available
5403
5625
  typeName := c.getTypeNameString(assertedType)
5404
5626
  if typeName != "unknown" {
5405
- c.tsw.WriteLiterally(fmt.Sprintf(", name: '%s'", typeName))
5627
+ c.tsw.WriteLiterallyf(", name: '%s'", typeName)
5406
5628
  }
5407
5629
 
5408
5630
  // Add methods if available
@@ -5425,9 +5647,12 @@ func (c *GoToTSCompiler) writeTypeAssertion(lhs []ast.Expr, typeAssertExpr *ast.
5425
5647
  c.tsw.WriteLiterally("{")
5426
5648
  c.tsw.WriteLiterally("kind: $.TypeKind.Pointer")
5427
5649
 
5428
- // Add element type if it's a named type
5429
- if ident, ok := typeExpr.X.(*ast.Ident); ok {
5430
- c.tsw.WriteLiterally(fmt.Sprintf(", elemType: '%s'", ident.Name))
5650
+ // Add element type if it's a struct type or named type
5651
+ if structType, ok := typeExpr.X.(*ast.StructType); ok {
5652
+ c.tsw.WriteLiterally(", elemType: ")
5653
+ c.writeTypeDescription(structType)
5654
+ } else if ident, ok := typeExpr.X.(*ast.Ident); ok {
5655
+ c.tsw.WriteLiterallyf(", elemType: '%s'", ident.Name)
5431
5656
  }
5432
5657
 
5433
5658
  c.tsw.WriteLiterally("}")
@@ -5439,19 +5664,64 @@ func (c *GoToTSCompiler) writeTypeAssertion(lhs []ast.Expr, typeAssertExpr *ast.
5439
5664
  c.tsw.WriteLiterally(", elemType: ")
5440
5665
  if ident, ok := typeExpr.Value.(*ast.Ident); ok && isPrimitiveType(ident.Name) {
5441
5666
  if tsType, ok := GoBuiltinToTypescript(ident.Name); ok {
5442
- c.tsw.WriteLiterally(fmt.Sprintf("'%s'", tsType))
5667
+ c.tsw.WriteLiterallyf("'%s'", tsType)
5443
5668
  } else {
5444
- c.tsw.WriteLiterally(fmt.Sprintf("'%s'", ident.Name)) // Fallback
5669
+ c.tsw.WriteLiterallyf("'%s'", ident.Name) // Fallback
5445
5670
  }
5446
5671
  } else {
5447
5672
  c.writeTypeDescription(typeExpr.Value)
5448
5673
  }
5449
5674
 
5675
+ c.tsw.WriteLiterally(", direction: ")
5676
+ switch typeExpr.Dir {
5677
+ case ast.SEND:
5678
+ c.tsw.WriteLiterally("'send'")
5679
+ case ast.RECV:
5680
+ c.tsw.WriteLiterally("'receive'")
5681
+ case ast.SEND | ast.RECV: // bidirectional
5682
+ c.tsw.WriteLiterally("'both'")
5683
+ default:
5684
+ // This should not happen, but just in case
5685
+ c.tsw.WriteLiterally("'both'")
5686
+ }
5687
+
5450
5688
  c.tsw.WriteLiterally("}")
5451
5689
  case *ast.FuncType:
5452
- // For function types, create a type descriptor object
5690
+ // For function types, create a type descriptor object with params and results
5453
5691
  c.tsw.WriteLiterally("{")
5454
5692
  c.tsw.WriteLiterally("kind: $.TypeKind.Function")
5693
+
5694
+ // Add name if this is a named function type
5695
+ if namedType := c.pkg.TypesInfo.TypeOf(typeExpr); namedType != nil {
5696
+ if named, ok := namedType.(*types.Named); ok {
5697
+ c.tsw.WriteLiterallyf(", name: '%s'", named.Obj().Name())
5698
+ }
5699
+ }
5700
+
5701
+ // Add params if present
5702
+ if typeExpr.Params != nil && len(typeExpr.Params.List) > 0 {
5703
+ c.tsw.WriteLiterally(", params: [")
5704
+ for i, param := range typeExpr.Params.List {
5705
+ if i > 0 {
5706
+ c.tsw.WriteLiterally(", ")
5707
+ }
5708
+ c.writeTypeDescription(param.Type)
5709
+ }
5710
+ c.tsw.WriteLiterally("]")
5711
+ }
5712
+
5713
+ // Add results if present
5714
+ if typeExpr.Results != nil && len(typeExpr.Results.List) > 0 {
5715
+ c.tsw.WriteLiterally(", results: [")
5716
+ for i, result := range typeExpr.Results.List {
5717
+ if i > 0 {
5718
+ c.tsw.WriteLiterally(", ")
5719
+ }
5720
+ c.writeTypeDescription(result.Type)
5721
+ }
5722
+ c.tsw.WriteLiterally("]")
5723
+ }
5724
+
5455
5725
  c.tsw.WriteLiterally("}")
5456
5726
  case *ast.Ident:
5457
5727
  if isPrimitiveType(typeExpr.Name) {
@@ -5460,31 +5730,102 @@ func (c *GoToTSCompiler) writeTypeAssertion(lhs []ast.Expr, typeAssertExpr *ast.
5460
5730
 
5461
5731
  // Use TypeScript equivalent if available
5462
5732
  if tsType, ok := GoBuiltinToTypescript(typeExpr.Name); ok {
5463
- c.tsw.WriteLiterally(fmt.Sprintf("name: '%s'", tsType))
5733
+ c.tsw.WriteLiterallyf("name: '%s'", tsType) // TODO: use %q?
5464
5734
  } else {
5465
- c.tsw.WriteLiterally(fmt.Sprintf("name: '%s'", typeExpr.Name))
5735
+ c.tsw.WriteLiterallyf("name: '%s'", typeExpr.Name)
5466
5736
  }
5467
5737
 
5468
5738
  c.tsw.WriteLiterally("}")
5469
5739
  } else {
5470
- c.tsw.WriteLiterally(fmt.Sprintf("'%s'", typeExpr.Name))
5740
+ // Check if this is a named function type
5741
+ isFunctionType := false
5742
+ if namedType := c.pkg.TypesInfo.TypeOf(typeExpr); namedType != nil {
5743
+ if named, ok := namedType.(*types.Named); ok {
5744
+ if _, ok := named.Underlying().(*types.Signature); ok {
5745
+ // This is a named function type, generate a FunctionTypeInfo
5746
+ isFunctionType = true
5747
+ c.tsw.WriteLiterally("{")
5748
+ c.tsw.WriteLiterally("kind: $.TypeKind.Function")
5749
+ c.tsw.WriteLiterallyf(", name: '%s'", typeExpr.Name)
5750
+
5751
+ // Get the underlying signature
5752
+ signature := named.Underlying().(*types.Signature)
5753
+
5754
+ // Add params if present
5755
+ params := signature.Params()
5756
+ if params != nil && params.Len() > 0 {
5757
+ c.tsw.WriteLiterally(", params: [")
5758
+ for i := 0; i < params.Len(); i++ {
5759
+ if i > 0 {
5760
+ c.tsw.WriteLiterally(", ")
5761
+ }
5762
+ // Use basic type info for parameters
5763
+ param := params.At(i)
5764
+ c.tsw.WriteLiterally("{")
5765
+ c.tsw.WriteLiterally("kind: $.TypeKind.Basic, ")
5766
+
5767
+ typeName := param.Type().String()
5768
+ if tsType, ok := GoBuiltinToTypescript(typeName); ok {
5769
+ c.tsw.WriteLiterallyf("name: '%s'", tsType)
5770
+ } else {
5771
+ c.tsw.WriteLiterallyf("name: '%s'", typeName)
5772
+ }
5773
+
5774
+ c.tsw.WriteLiterally("}")
5775
+ }
5776
+ c.tsw.WriteLiterally("]")
5777
+ }
5778
+
5779
+ // Add results if present
5780
+ results := signature.Results()
5781
+ if results != nil && results.Len() > 0 {
5782
+ c.tsw.WriteLiterally(", results: [")
5783
+ for i := 0; i < results.Len(); i++ {
5784
+ if i > 0 {
5785
+ c.tsw.WriteLiterally(", ")
5786
+ }
5787
+ result := results.At(i)
5788
+ c.tsw.WriteLiterally("{")
5789
+ c.tsw.WriteLiterally("kind: $.TypeKind.Basic, ")
5790
+
5791
+ typeName := result.Type().String()
5792
+ if tsType, ok := GoBuiltinToTypescript(typeName); ok {
5793
+ c.tsw.WriteLiterallyf("name: '%s'", tsType)
5794
+ } else {
5795
+ c.tsw.WriteLiterallyf("name: '%s'", typeName)
5796
+ }
5797
+
5798
+ c.tsw.WriteLiterally("}")
5799
+ }
5800
+ c.tsw.WriteLiterally("]")
5801
+ }
5802
+
5803
+ c.tsw.WriteLiterally("}")
5804
+ }
5805
+ }
5806
+ }
5807
+
5808
+ // Default case for non-function named types
5809
+ if !isFunctionType {
5810
+ c.tsw.WriteLiterallyf("'%s'", typeExpr.Name)
5811
+ }
5471
5812
  }
5472
5813
  case *ast.SelectorExpr:
5473
5814
  // For imported types like pkg.Type
5474
5815
  if ident, ok := typeExpr.X.(*ast.Ident); ok {
5475
- c.tsw.WriteLiterally(fmt.Sprintf("'%s.%s'", ident.Name, typeExpr.Sel.Name))
5816
+ c.tsw.WriteLiterallyf("'%s.%s'", ident.Name, typeExpr.Sel.Name)
5476
5817
  } else {
5477
- c.tsw.WriteLiterally(fmt.Sprintf("'%s'", c.getTypeNameString(assertedType)))
5818
+ c.tsw.WriteLiterallyf("'%s'", c.getTypeNameString(assertedType))
5478
5819
  }
5479
5820
  default:
5480
5821
  // For other types, use the string name as before
5481
5822
  typeName := c.getTypeNameString(assertedType)
5482
- c.tsw.WriteLiterally(fmt.Sprintf("'%s'", typeName))
5823
+ c.tsw.WriteLiterallyf("'%s'", typeName)
5483
5824
  }
5484
5825
 
5485
5826
  c.tsw.WriteLiterally(")")
5486
5827
 
5487
- if tok != token.DEFINE {
5828
+ if tok != token.DEFINE || writeEndParen {
5488
5829
  c.tsw.WriteLiterally(")")
5489
5830
  }
5490
5831
 
@@ -5506,22 +5847,22 @@ func (c *GoToTSCompiler) writeTypeDescription(typeExpr ast.Expr) {
5506
5847
  if tsType, ok := GoBuiltinToTypescript(t.Name); ok {
5507
5848
  c.tsw.WriteLiterally("{")
5508
5849
  c.tsw.WriteLiterally("kind: $.TypeKind.Basic, ")
5509
- c.tsw.WriteLiterally(fmt.Sprintf("name: '%s'", tsType))
5850
+ c.tsw.WriteLiterallyf("name: '%s'", tsType)
5510
5851
  c.tsw.WriteLiterally("}")
5511
5852
  } else {
5512
5853
  // Fallback for other primitive types
5513
5854
  c.tsw.WriteLiterally("{")
5514
5855
  c.tsw.WriteLiterally("kind: $.TypeKind.Basic, ")
5515
- c.tsw.WriteLiterally(fmt.Sprintf("name: '%s'", t.Name))
5856
+ c.tsw.WriteLiterallyf("name: '%s'", t.Name)
5516
5857
  c.tsw.WriteLiterally("}")
5517
5858
  }
5518
5859
  } else {
5519
5860
  // For named types, just use the name string
5520
- c.tsw.WriteLiterally(fmt.Sprintf("'%s'", t.Name))
5861
+ c.tsw.WriteLiterallyf("'%s'", t.Name)
5521
5862
  }
5522
5863
  case *ast.SelectorExpr:
5523
5864
  if ident, ok := t.X.(*ast.Ident); ok {
5524
- c.tsw.WriteLiterally(fmt.Sprintf("'%s.%s'", ident.Name, t.Sel.Name))
5865
+ c.tsw.WriteLiterallyf("'%s.%s'", ident.Name, t.Sel.Name)
5525
5866
  }
5526
5867
  case *ast.ArrayType:
5527
5868
  typeKind := "$.TypeKind.Slice"
@@ -5530,7 +5871,7 @@ func (c *GoToTSCompiler) writeTypeDescription(typeExpr ast.Expr) {
5530
5871
  }
5531
5872
 
5532
5873
  c.tsw.WriteLiterally("{")
5533
- c.tsw.WriteLiterally(fmt.Sprintf("kind: %s, ", typeKind))
5874
+ c.tsw.WriteLiterallyf("kind: %s, ", typeKind)
5534
5875
  c.tsw.WriteLiterally("elemType: ")
5535
5876
  c.writeTypeDescription(t.Elt)
5536
5877
  c.tsw.WriteLiterally("}")
@@ -5540,20 +5881,7 @@ func (c *GoToTSCompiler) writeTypeDescription(typeExpr ast.Expr) {
5540
5881
 
5541
5882
  // Add field names and types to the struct type info
5542
5883
  if t.Fields != nil && t.Fields.List != nil {
5543
- c.tsw.WriteLiterally("fields: new Set([")
5544
-
5545
- fields := []string{}
5546
- for _, field := range t.Fields.List {
5547
- for _, name := range field.Names {
5548
- fields = append(fields, fmt.Sprintf("'%s'", name.Name))
5549
- }
5550
- }
5551
-
5552
- c.tsw.WriteLiterally(strings.Join(fields, ", "))
5553
- c.tsw.WriteLiterally("]), ")
5554
-
5555
- // Add fieldTypes property to provide type information
5556
- c.tsw.WriteLiterally("fieldTypes: {")
5884
+ c.tsw.WriteLiterally("fields: {")
5557
5885
 
5558
5886
  hasFields := false
5559
5887
  for _, field := range t.Fields.List {
@@ -5562,7 +5890,7 @@ func (c *GoToTSCompiler) writeTypeDescription(typeExpr ast.Expr) {
5562
5890
  if hasFields {
5563
5891
  c.tsw.WriteLiterally(", ")
5564
5892
  }
5565
- c.tsw.WriteLiterally(fmt.Sprintf("'%s': ", name.Name))
5893
+ c.tsw.WriteLiterallyf("'%s': ", name.Name)
5566
5894
  c.writeTypeDescription(field.Type)
5567
5895
  hasFields = true
5568
5896
  }
@@ -5571,7 +5899,7 @@ func (c *GoToTSCompiler) writeTypeDescription(typeExpr ast.Expr) {
5571
5899
 
5572
5900
  c.tsw.WriteLiterally("}, ")
5573
5901
  } else {
5574
- c.tsw.WriteLiterally("fields: new Set(), ")
5902
+ c.tsw.WriteLiterally("fields: {}, ")
5575
5903
  }
5576
5904
 
5577
5905
  c.tsw.WriteLiterally("methods: new Set()")
@@ -5591,10 +5919,79 @@ func (c *GoToTSCompiler) writeTypeDescription(typeExpr ast.Expr) {
5591
5919
  c.tsw.WriteLiterally("kind: $.TypeKind.Pointer, ")
5592
5920
  c.tsw.WriteLiterally("elemType: ")
5593
5921
  c.writeTypeDescription(t.X)
5922
+ c.tsw.WriteLiterally("}")
5923
+ case *ast.FuncType:
5924
+ // For function types, create a type descriptor object with params and results
5925
+ c.tsw.WriteLiterally("{")
5926
+ c.tsw.WriteLiterally("kind: $.TypeKind.Function")
5927
+
5928
+ // Add name if this is a named function type
5929
+ if namedType := c.pkg.TypesInfo.TypeOf(typeExpr); namedType != nil {
5930
+ if named, ok := namedType.(*types.Named); ok {
5931
+ c.tsw.WriteLiterallyf(", name: '%s'", named.Obj().Name())
5932
+ }
5933
+ }
5934
+
5935
+ // Add params if present
5936
+ if t.Params != nil && len(t.Params.List) > 0 {
5937
+ c.tsw.WriteLiterally(", params: [")
5938
+ for i, param := range t.Params.List {
5939
+ if i > 0 {
5940
+ c.tsw.WriteLiterally(", ")
5941
+ }
5942
+ c.writeTypeDescription(param.Type)
5943
+ }
5944
+ c.tsw.WriteLiterally("]")
5945
+ }
5946
+
5947
+ // Add results if present
5948
+ if t.Results != nil && len(t.Results.List) > 0 {
5949
+ c.tsw.WriteLiterally(", results: [")
5950
+ for i, result := range t.Results.List {
5951
+ if i > 0 {
5952
+ c.tsw.WriteLiterally(", ")
5953
+ }
5954
+ c.writeTypeDescription(result.Type)
5955
+ }
5956
+ c.tsw.WriteLiterally("]")
5957
+ }
5958
+
5959
+ c.tsw.WriteLiterally("}")
5960
+ return
5961
+ case *ast.ChanType:
5962
+ c.tsw.WriteLiterally("{")
5963
+ c.tsw.WriteLiterally("kind: $.TypeKind.Channel, ")
5964
+ c.tsw.WriteLiterally("elemType: ")
5965
+
5966
+ // Add element type
5967
+ if ident, ok := t.Value.(*ast.Ident); ok && isPrimitiveType(ident.Name) {
5968
+ if tsType, ok := GoBuiltinToTypescript(ident.Name); ok {
5969
+ c.tsw.WriteLiterallyf("'%s'", tsType)
5970
+ } else {
5971
+ c.tsw.WriteLiterallyf("'%s'", ident.Name) // Fallback
5972
+ }
5973
+ } else {
5974
+ c.writeTypeDescription(t.Value)
5975
+ }
5976
+
5977
+ // Add direction
5978
+ c.tsw.WriteLiterally(", direction: ")
5979
+ switch t.Dir {
5980
+ case ast.SEND:
5981
+ c.tsw.WriteLiterally("'send'")
5982
+ case ast.RECV:
5983
+ c.tsw.WriteLiterally("'receive'")
5984
+ case ast.SEND | ast.RECV: // bidirectional
5985
+ c.tsw.WriteLiterally("'both'")
5986
+ default:
5987
+ // This should not happen, but just in case
5988
+ c.tsw.WriteLiterally("'both'")
5989
+ }
5990
+
5594
5991
  c.tsw.WriteLiterally("}")
5595
5992
  default:
5596
5993
  // For other types, use the string representation
5597
- c.tsw.WriteLiterally(fmt.Sprintf("'%s'", c.getTypeNameString(typeExpr)))
5994
+ c.tsw.WriteLiterallyf("'%s'", c.getTypeNameString(typeExpr))
5598
5995
  }
5599
5996
  }
5600
5997