goscript 0.0.17 → 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,20 +303,7 @@ 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")
@@ -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("(")
@@ -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.WriteLiterallyf("'%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 {
@@ -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)
@@ -3198,6 +3332,10 @@ 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
3340
  c.tsw.WriteCommentLinef("unhandled spec in DeclStmt: %T", spec)
3203
3341
  }
@@ -5254,6 +5392,15 @@ func (c *GoToTSCompiler) writeTypeAssertion(lhs []ast.Expr, typeAssertExpr *ast.
5254
5392
  interfaceExpr := typeAssertExpr.X
5255
5393
  assertedType := typeAssertExpr.Type
5256
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
+
5257
5404
  // Ensure LHS has exactly two expressions (value and ok)
5258
5405
  if len(lhs) != 2 {
5259
5406
  return fmt.Errorf("type assertion assignment requires exactly 2 variables on LHS, got %d", len(lhs))
@@ -5264,32 +5411,93 @@ func (c *GoToTSCompiler) writeTypeAssertion(lhs []ast.Expr, typeAssertExpr *ast.
5264
5411
  okIsBlank := false
5265
5412
  var valueName string
5266
5413
  var okName string
5414
+ var valueIdent *ast.Ident
5415
+ var okIdent *ast.Ident
5267
5416
 
5268
- if valIdent, ok := lhs[0].(*ast.Ident); ok {
5269
- if valIdent.Name == "_" {
5417
+ if valId, ok := lhs[0].(*ast.Ident); ok {
5418
+ valueIdent = valId
5419
+ if valId.Name == "_" {
5270
5420
  valueIsBlank = true
5271
5421
  } else {
5272
- valueName = valIdent.Name
5422
+ valueName = valId.Name
5273
5423
  }
5274
5424
  } else {
5275
5425
  return fmt.Errorf("unhandled LHS expression type for value in type assertion: %T", lhs[0])
5276
5426
  }
5277
5427
 
5278
- if okIdent, ok := lhs[1].(*ast.Ident); ok {
5279
- if okIdent.Name == "_" {
5428
+ if okId, ok := lhs[1].(*ast.Ident); ok {
5429
+ okIdent = okId
5430
+ if okId.Name == "_" {
5280
5431
  okIsBlank = true
5281
5432
  } else {
5282
- okName = okIdent.Name
5433
+ okName = okId.Name
5283
5434
  }
5284
5435
  } else {
5285
5436
  return fmt.Errorf("unhandled LHS expression type for ok in type assertion: %T", lhs[1])
5286
5437
  }
5287
5438
 
5288
- // 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
5289
5442
  if tok == token.DEFINE {
5290
- 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
+ }
5291
5500
  } else {
5292
- // We must wrap in parenthesis.
5293
5501
  c.tsw.WriteLiterally("(")
5294
5502
  }
5295
5503
 
@@ -5383,17 +5591,26 @@ func (c *GoToTSCompiler) writeTypeAssertion(lhs []ast.Expr, typeAssertExpr *ast.
5383
5591
  }
5384
5592
 
5385
5593
  if typeExpr.Fields != nil && typeExpr.Fields.List != nil {
5386
- c.tsw.WriteLiterally(", fields: new Set([")
5594
+ // Add fields property to provide type information
5595
+ c.tsw.WriteLiterally(", fields: {")
5387
5596
 
5388
- fields := []string{}
5597
+ hasFields := false
5389
5598
  for _, field := range typeExpr.Fields.List {
5390
- for _, name := range field.Names {
5391
- 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
+ }
5392
5608
  }
5393
5609
  }
5394
5610
 
5395
- c.tsw.WriteLiterally(strings.Join(fields, ", "))
5396
- c.tsw.WriteLiterally("])")
5611
+ c.tsw.WriteLiterally("}")
5612
+ } else {
5613
+ c.tsw.WriteLiterally(", fields: {}")
5397
5614
  }
5398
5615
 
5399
5616
  // Add empty methods set to satisfy StructTypeInfo interface
@@ -5430,8 +5647,11 @@ func (c *GoToTSCompiler) writeTypeAssertion(lhs []ast.Expr, typeAssertExpr *ast.
5430
5647
  c.tsw.WriteLiterally("{")
5431
5648
  c.tsw.WriteLiterally("kind: $.TypeKind.Pointer")
5432
5649
 
5433
- // Add element type if it's a named type
5434
- if ident, ok := typeExpr.X.(*ast.Ident); ok {
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 {
5435
5655
  c.tsw.WriteLiterallyf(", elemType: '%s'", ident.Name)
5436
5656
  }
5437
5657
 
@@ -5452,11 +5672,56 @@ func (c *GoToTSCompiler) writeTypeAssertion(lhs []ast.Expr, typeAssertExpr *ast.
5452
5672
  c.writeTypeDescription(typeExpr.Value)
5453
5673
  }
5454
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
+
5455
5688
  c.tsw.WriteLiterally("}")
5456
5689
  case *ast.FuncType:
5457
- // For function types, create a type descriptor object
5690
+ // For function types, create a type descriptor object with params and results
5458
5691
  c.tsw.WriteLiterally("{")
5459
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
+
5460
5725
  c.tsw.WriteLiterally("}")
5461
5726
  case *ast.Ident:
5462
5727
  if isPrimitiveType(typeExpr.Name) {
@@ -5472,7 +5737,78 @@ func (c *GoToTSCompiler) writeTypeAssertion(lhs []ast.Expr, typeAssertExpr *ast.
5472
5737
 
5473
5738
  c.tsw.WriteLiterally("}")
5474
5739
  } else {
5475
- c.tsw.WriteLiterallyf("'%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
+ }
5476
5812
  }
5477
5813
  case *ast.SelectorExpr:
5478
5814
  // For imported types like pkg.Type
@@ -5489,7 +5825,7 @@ func (c *GoToTSCompiler) writeTypeAssertion(lhs []ast.Expr, typeAssertExpr *ast.
5489
5825
 
5490
5826
  c.tsw.WriteLiterally(")")
5491
5827
 
5492
- if tok != token.DEFINE {
5828
+ if tok != token.DEFINE || writeEndParen {
5493
5829
  c.tsw.WriteLiterally(")")
5494
5830
  }
5495
5831
 
@@ -5545,20 +5881,7 @@ func (c *GoToTSCompiler) writeTypeDescription(typeExpr ast.Expr) {
5545
5881
 
5546
5882
  // Add field names and types to the struct type info
5547
5883
  if t.Fields != nil && t.Fields.List != nil {
5548
- c.tsw.WriteLiterally("fields: new Set([")
5549
-
5550
- fields := []string{}
5551
- for _, field := range t.Fields.List {
5552
- for _, name := range field.Names {
5553
- fields = append(fields, fmt.Sprintf("'%s'", name.Name))
5554
- }
5555
- }
5556
-
5557
- c.tsw.WriteLiterally(strings.Join(fields, ", "))
5558
- c.tsw.WriteLiterally("]), ")
5559
-
5560
- // Add fieldTypes property to provide type information
5561
- c.tsw.WriteLiterally("fieldTypes: {")
5884
+ c.tsw.WriteLiterally("fields: {")
5562
5885
 
5563
5886
  hasFields := false
5564
5887
  for _, field := range t.Fields.List {
@@ -5576,7 +5899,7 @@ func (c *GoToTSCompiler) writeTypeDescription(typeExpr ast.Expr) {
5576
5899
 
5577
5900
  c.tsw.WriteLiterally("}, ")
5578
5901
  } else {
5579
- c.tsw.WriteLiterally("fields: new Set(), ")
5902
+ c.tsw.WriteLiterally("fields: {}, ")
5580
5903
  }
5581
5904
 
5582
5905
  c.tsw.WriteLiterally("methods: new Set()")
@@ -5596,6 +5919,75 @@ func (c *GoToTSCompiler) writeTypeDescription(typeExpr ast.Expr) {
5596
5919
  c.tsw.WriteLiterally("kind: $.TypeKind.Pointer, ")
5597
5920
  c.tsw.WriteLiterally("elemType: ")
5598
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
+
5599
5991
  c.tsw.WriteLiterally("}")
5600
5992
  default:
5601
5993
  // For other types, use the string representation