goscript 0.0.17 → 0.0.19

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")
@@ -641,6 +628,18 @@ func (c *GoToTSCompiler) WriteZeroValueForType(typ any) {
641
628
  default:
642
629
  c.tsw.WriteLiterally("0")
643
630
  }
631
+ case *types.Named:
632
+ // Handle named types, especially struct types
633
+ if _, isStruct := t.Underlying().(*types.Struct); isStruct {
634
+ // Initialize struct types with a new instance
635
+ c.tsw.WriteLiterallyf("new %s()", t.Obj().Name())
636
+ return
637
+ }
638
+ // For other named types, use the zero value of the underlying type
639
+ c.WriteZeroValueForType(t.Underlying())
640
+ case *types.Struct:
641
+ // For anonymous struct types, initialize with {}
642
+ c.tsw.WriteLiterally("{}")
644
643
  default:
645
644
  c.tsw.WriteLiterally("null")
646
645
  }
@@ -752,6 +751,20 @@ func (c *GoToTSCompiler) WriteValueExpr(a ast.Expr) error {
752
751
  c.tsw.WriteLiterally(")")
753
752
  return nil
754
753
  case *ast.ParenExpr:
754
+ // Check if this is a nil pointer to struct type cast: (*struct{})(nil)
755
+ if starExpr, isStarExpr := exp.X.(*ast.StarExpr); isStarExpr {
756
+ if _, isStructType := starExpr.X.(*ast.StructType); isStructType {
757
+ c.tsw.WriteLiterally("null")
758
+ return nil
759
+ }
760
+ }
761
+
762
+ // Check if this is a type cast with nil: (SomeType)(nil)
763
+ if ident, isIdent := exp.X.(*ast.Ident); isIdent && ident.Name == "nil" {
764
+ c.tsw.WriteLiterally("null")
765
+ return nil
766
+ }
767
+
755
768
  // Translate (X) to (X)
756
769
  // If we haven't written anything in this statement yet, prepend ;
757
770
  c.tsw.WriteLiterally("(")
@@ -810,9 +823,6 @@ func (c *GoToTSCompiler) WriteIndexExpr(exp *ast.IndexExpr) error {
810
823
  // context, we expect the asserted value directly. The `TypeName` string is used
811
824
  // by the runtime for error messages.
812
825
  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
826
  // Generate a call to $.typeAssert
817
827
  c.tsw.WriteLiterally("$.typeAssert<")
818
828
  c.WriteTypeExpr(exp.Type) // Write the asserted type for the generic
@@ -821,8 +831,23 @@ func (c *GoToTSCompiler) WriteTypeAssertExpr(exp *ast.TypeAssertExpr) error {
821
831
  return fmt.Errorf("failed to write interface expression in type assertion expression: %w", err)
822
832
  }
823
833
  c.tsw.WriteLiterally(", ")
824
- c.tsw.WriteLiterallyf("'%s'", typeName)
825
- c.tsw.WriteLiterally(").value") // Access the value field directly in expression context
834
+
835
+ // Write the type description instead of just the type name
836
+ // This ensures we generate proper type info objects for all types
837
+
838
+ // Unwrap parenthesized expressions to handle cases like r.((<-chan T))
839
+ typeExpr := exp.Type
840
+ for {
841
+ if parenExpr, ok := typeExpr.(*ast.ParenExpr); ok {
842
+ typeExpr = parenExpr.X
843
+ } else {
844
+ break
845
+ }
846
+ }
847
+
848
+ c.writeTypeDescription(typeExpr)
849
+
850
+ c.tsw.WriteLiterally(")") // Just close the parenthesis, don't access .value directly
826
851
  return nil
827
852
  }
828
853
 
@@ -1087,17 +1112,19 @@ func (c *GoToTSCompiler) WriteStarExpr(exp *ast.StarExpr) error {
1087
1112
  // `WriteFieldList` to generate the list of field definitions.
1088
1113
  // Note: This is for anonymous struct type literals. Named struct types are usually
1089
1114
  // 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
1115
+ func (c *GoToTSCompiler) WriteStructType(t *types.Struct) {
1116
+ // Generate an interface with the struct's fields
1117
+ c.tsw.WriteLiterally("{ ")
1118
+ // Add field properties to the interface
1119
+ for i := range t.NumFields() {
1120
+ field := t.Field(i)
1121
+ if i > 0 {
1122
+ c.tsw.WriteLiterally("; ")
1123
+ }
1124
+ c.tsw.WriteLiterally(field.Name() + "?: ")
1125
+ c.WriteGoType(field.Type())
1099
1126
  }
1100
- c.WriteFieldList(exp.Fields, false) // false = not arguments
1127
+ c.tsw.WriteLiterally(" }")
1101
1128
  }
1102
1129
 
1103
1130
  // WriteFuncType translates a Go function type (`ast.FuncType`) into a TypeScript
@@ -1175,6 +1202,22 @@ func (c *GoToTSCompiler) WriteFuncType(exp *ast.FuncType, isAsync bool) {
1175
1202
  func (c *GoToTSCompiler) WriteCallExpr(exp *ast.CallExpr) error {
1176
1203
  expFun := exp.Fun
1177
1204
 
1205
+ // Handle any type conversion with nil argument
1206
+ if len(exp.Args) == 1 {
1207
+ if nilIdent, isIdent := exp.Args[0].(*ast.Ident); isIdent && nilIdent.Name == "nil" {
1208
+ // Handle nil pointer to struct type conversions: (*struct{})(nil)
1209
+ if starExpr, isStarExpr := expFun.(*ast.StarExpr); isStarExpr {
1210
+ if _, isStructType := starExpr.X.(*ast.StructType); isStructType {
1211
+ c.tsw.WriteLiterally("null")
1212
+ return nil
1213
+ }
1214
+ }
1215
+
1216
+ c.tsw.WriteLiterally("null")
1217
+ return nil
1218
+ }
1219
+ }
1220
+
1178
1221
  // Handle array type conversions like []rune(string)
1179
1222
  if arrayType, isArrayType := expFun.(*ast.ArrayType); isArrayType {
1180
1223
  // Check if it's a []rune type
@@ -1270,7 +1313,26 @@ func (c *GoToTSCompiler) WriteCallExpr(exp *ast.CallExpr) error {
1270
1313
  c.tsw.WriteLiterally(", ") // Add comma for zero value argument
1271
1314
 
1272
1315
  // Write the zero value for the channel's element type
1273
- c.WriteZeroValueForType(chanType.Elem())
1316
+ if chanType.Elem().String() == "struct{}" {
1317
+ c.tsw.WriteLiterally("{}")
1318
+ } else {
1319
+ c.WriteZeroValueForType(chanType.Elem())
1320
+ }
1321
+
1322
+ // Add direction parameter
1323
+ c.tsw.WriteLiterally(", ")
1324
+
1325
+ // Determine channel direction
1326
+ switch chanType.Dir() {
1327
+ case types.SendRecv:
1328
+ c.tsw.WriteLiterally("'both'")
1329
+ case types.SendOnly:
1330
+ c.tsw.WriteLiterally("'send'")
1331
+ case types.RecvOnly:
1332
+ c.tsw.WriteLiterally("'receive'")
1333
+ default:
1334
+ c.tsw.WriteLiterally("'both'") // Default to bidirectional
1335
+ }
1274
1336
 
1275
1337
  c.tsw.WriteLiterally(")")
1276
1338
  return nil // Handled make for channel
@@ -1431,6 +1493,42 @@ func (c *GoToTSCompiler) WriteCallExpr(exp *ast.CallExpr) error {
1431
1493
  }
1432
1494
  return errors.New("unhandled byte call with incorrect number of arguments")
1433
1495
  default:
1496
+ // Check if this is a type conversion to a function type
1497
+ if funIdent != nil {
1498
+ if obj := c.pkg.TypesInfo.Uses[funIdent]; obj != nil {
1499
+ // Check if the object is a type name
1500
+ if typeName, isType := obj.(*types.TypeName); isType {
1501
+ // Make sure we have exactly one argument
1502
+ if len(exp.Args) == 1 {
1503
+ // Check if this is a function type
1504
+ if _, isFuncType := typeName.Type().Underlying().(*types.Signature); isFuncType {
1505
+ // For function types, we need to add a __goTypeName property
1506
+ c.tsw.WriteLiterally("Object.assign(")
1507
+
1508
+ // Write the argument first
1509
+ if err := c.WriteValueExpr(exp.Args[0]); err != nil {
1510
+ return fmt.Errorf("failed to write argument for function type cast: %w", err)
1511
+ }
1512
+
1513
+ // Add the __goTypeName property with the function type name
1514
+ c.tsw.WriteLiterallyf(", { __goTypeName: '%s' })", funIdent.String())
1515
+ return nil // Handled function type cast
1516
+ } else {
1517
+ // For non-function types, use the TypeScript "as" operator
1518
+ c.tsw.WriteLiterally("(")
1519
+ if err := c.WriteValueExpr(exp.Args[0]); err != nil {
1520
+ return fmt.Errorf("failed to write argument for type cast: %w", err)
1521
+ }
1522
+
1523
+ // Then use the TypeScript "as" operator with the type name
1524
+ c.tsw.WriteLiterallyf(" as %s)", funIdent.String())
1525
+ return nil // Handled non-function type cast
1526
+ }
1527
+ }
1528
+ }
1529
+ }
1530
+ }
1531
+
1434
1532
  // Check if this is an async function call
1435
1533
  if funIdent != nil {
1436
1534
  // Get the object for this function identifier
@@ -1444,6 +1542,15 @@ func (c *GoToTSCompiler) WriteCallExpr(exp *ast.CallExpr) error {
1444
1542
  if err := c.WriteValueExpr(expFun); err != nil {
1445
1543
  return fmt.Errorf("failed to write function expression in call: %w", err)
1446
1544
  }
1545
+
1546
+ if funType := c.pkg.TypesInfo.TypeOf(expFun); funType != nil {
1547
+ if _, ok := funType.Underlying().(*types.Signature); ok {
1548
+ if _, isNamed := funType.(*types.Named); isNamed {
1549
+ c.tsw.WriteLiterally("!")
1550
+ }
1551
+ }
1552
+ }
1553
+
1447
1554
  c.tsw.WriteLiterally("(")
1448
1555
  for i, arg := range exp.Args {
1449
1556
  if i != 0 {
@@ -1461,6 +1568,14 @@ func (c *GoToTSCompiler) WriteCallExpr(exp *ast.CallExpr) error {
1461
1568
  if err := c.WriteValueExpr(expFun); err != nil {
1462
1569
  return fmt.Errorf("failed to write method expression in call: %w", err)
1463
1570
  }
1571
+
1572
+ if funType := c.pkg.TypesInfo.TypeOf(expFun); funType != nil {
1573
+ if _, ok := funType.Underlying().(*types.Signature); ok {
1574
+ if _, isNamed := funType.(*types.Named); isNamed {
1575
+ c.tsw.WriteLiterally("!")
1576
+ }
1577
+ }
1578
+ }
1464
1579
  }
1465
1580
  c.tsw.WriteLiterally("(")
1466
1581
  for i, arg := range exp.Args {
@@ -2744,6 +2859,21 @@ func (c *GoToTSCompiler) WriteValueSpec(a *ast.ValueSpec) error {
2744
2859
  var initializerExpr ast.Expr
2745
2860
  if hasInitializer {
2746
2861
  initializerExpr = a.Values[0]
2862
+
2863
+ // Special case for nil pointer to struct type: (*struct{})(nil)
2864
+ if callExpr, isCallExpr := initializerExpr.(*ast.CallExpr); isCallExpr {
2865
+ if starExpr, isStarExpr := callExpr.Fun.(*ast.StarExpr); isStarExpr {
2866
+ if _, isStructType := starExpr.X.(*ast.StructType); isStructType {
2867
+ // Check if the argument is nil
2868
+ if len(callExpr.Args) == 1 {
2869
+ if nilIdent, isIdent := callExpr.Args[0].(*ast.Ident); isIdent && nilIdent.Name == "nil" {
2870
+ c.tsw.WriteLiterally("null")
2871
+ return nil
2872
+ }
2873
+ }
2874
+ }
2875
+ }
2876
+ }
2747
2877
  }
2748
2878
 
2749
2879
  if needsBox {
@@ -3017,10 +3147,17 @@ func (c *GoToTSCompiler) WriteFieldList(a *ast.FieldList, isArguments bool) {
3017
3147
  if i > 0 {
3018
3148
  c.tsw.WriteLiterally(", ")
3019
3149
  }
3020
- c.WriteField(field, true)
3021
- c.tsw.WriteLiterally(": ")
3022
- typ := c.pkg.TypesInfo.TypeOf(field.Type)
3023
- c.WriteGoType(typ)
3150
+
3151
+ // Handle multiple parameter names for the same type
3152
+ for j, name := range field.Names {
3153
+ if j > 0 {
3154
+ c.tsw.WriteLiterally(", ")
3155
+ }
3156
+ c.tsw.WriteLiterally(name.Name)
3157
+ c.tsw.WriteLiterally(": ")
3158
+ typ := c.pkg.TypesInfo.TypeOf(field.Type)
3159
+ c.WriteGoType(typ)
3160
+ }
3024
3161
  }
3025
3162
 
3026
3163
  // Handle the variadic parameter
@@ -3050,11 +3187,16 @@ func (c *GoToTSCompiler) WriteFieldList(a *ast.FieldList, isArguments bool) {
3050
3187
  }
3051
3188
 
3052
3189
  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
3190
+ // For function parameters with multiple names, write each with its type
3191
+ for j, name := range field.Names {
3192
+ if j > 0 {
3193
+ c.tsw.WriteLiterally(", ")
3194
+ }
3195
+ c.tsw.WriteLiterally(name.Name)
3196
+ c.tsw.WriteLiterally(": ")
3197
+ typ := c.pkg.TypesInfo.TypeOf(field.Type)
3198
+ c.WriteGoType(typ) // Use WriteGoType for parameter type
3199
+ }
3058
3200
  } else {
3059
3201
  // For struct fields and other non-argument fields
3060
3202
  c.WriteField(field, false)
@@ -3100,7 +3242,11 @@ func (c *GoToTSCompiler) WriteField(field *ast.Field, isArguments bool) {
3100
3242
  return
3101
3243
  }
3102
3244
 
3103
- for _, name := range field.Names {
3245
+ for i, name := range field.Names {
3246
+ if i > 0 && isArguments {
3247
+ c.tsw.WriteLiterally(", ")
3248
+ }
3249
+
3104
3250
  // argument names: keep original casing, no access modifier
3105
3251
  if isArguments {
3106
3252
  c.tsw.WriteLiterally(name.Name)
@@ -3198,6 +3344,10 @@ func (c *GoToTSCompiler) WriteStmt(a ast.Stmt) error {
3198
3344
  if err := c.WriteValueSpec(valueSpec); err != nil {
3199
3345
  return fmt.Errorf("failed to write value spec in declaration statement: %w", err)
3200
3346
  }
3347
+ } else if typeSpec, ok := spec.(*ast.TypeSpec); ok {
3348
+ if err := c.WriteTypeSpec(typeSpec); err != nil {
3349
+ return fmt.Errorf("failed to write type spec in declaration statement: %w", err)
3350
+ }
3201
3351
  } else {
3202
3352
  c.tsw.WriteCommentLinef("unhandled spec in DeclStmt: %T", spec)
3203
3353
  }
@@ -4462,8 +4612,61 @@ func (c *GoToTSCompiler) WriteStmtAssign(exp *ast.AssignStmt) error {
4462
4612
  }
4463
4613
  }
4464
4614
 
4465
- // Write the left-hand side as a destructuring pattern
4466
- // For token.DEFINE, we've already declared any new variables above
4615
+
4616
+ // First, collect all the selector expressions to identify variables that need to be initialized
4617
+ hasSelectors := false
4618
+ for _, lhsExpr := range lhs {
4619
+ if _, ok := lhsExpr.(*ast.SelectorExpr); ok {
4620
+ hasSelectors = true
4621
+ break
4622
+ }
4623
+ }
4624
+
4625
+ // If we have selector expressions, we need to ensure variables are initialized
4626
+ // before the destructuring assignment
4627
+ if hasSelectors {
4628
+ c.tsw.WriteLiterally("{")
4629
+ c.tsw.WriteLine("")
4630
+
4631
+ // Write a temporary variable to hold the function call result
4632
+ c.tsw.WriteLiterally(" const _tmp = ")
4633
+ if err := c.WriteValueExpr(callExpr); err != nil {
4634
+ return fmt.Errorf("failed to write RHS call expression in assignment: %w", err)
4635
+ }
4636
+ c.tsw.WriteLine("")
4637
+
4638
+ for i, lhsExpr := range lhs {
4639
+ // Skip underscore variables
4640
+ if ident, ok := lhsExpr.(*ast.Ident); ok && ident.Name == "_" {
4641
+ continue
4642
+ }
4643
+
4644
+ // Write the LHS with indentation
4645
+ c.tsw.WriteLiterally(" ")
4646
+ if ident, ok := lhsExpr.(*ast.Ident); ok {
4647
+ c.WriteIdent(ident, false)
4648
+ } else if selectorExpr, ok := lhsExpr.(*ast.SelectorExpr); ok {
4649
+ if err := c.WriteValueExpr(selectorExpr); err != nil {
4650
+ return fmt.Errorf("failed to write selector expression in LHS: %w", err)
4651
+ }
4652
+ } else {
4653
+ return errors.Errorf("unhandled LHS expression in assignment: %T", lhsExpr)
4654
+ }
4655
+
4656
+ // Write the assignment
4657
+ c.tsw.WriteLiterallyf(" = _tmp[%d]", i)
4658
+ // Always add a newline after each assignment
4659
+ c.tsw.WriteLine("")
4660
+ }
4661
+
4662
+ // Close the block scope
4663
+ c.tsw.WriteLiterally("}")
4664
+ c.tsw.WriteLine("")
4665
+
4666
+ return nil
4667
+ }
4668
+
4669
+ // For simple cases without selector expressions, use array destructuring
4467
4670
  c.tsw.WriteLiterally("[")
4468
4671
 
4469
4672
  for i, lhsExpr := range lhs {
@@ -4472,11 +4675,15 @@ func (c *GoToTSCompiler) WriteStmtAssign(exp *ast.AssignStmt) error {
4472
4675
  }
4473
4676
 
4474
4677
  if ident, ok := lhsExpr.(*ast.Ident); ok {
4475
- if ident.Name == "_" {
4476
- // For underscore variables, use empty slots in destructuring pattern
4477
- } else {
4678
+ // For underscore variables, use empty slots in destructuring pattern
4679
+ if ident.Name != "_" {
4478
4680
  c.WriteIdent(ident, false)
4479
4681
  }
4682
+ } else if selectorExpr, ok := lhsExpr.(*ast.SelectorExpr); ok {
4683
+ // Handle selector expressions (e.g., a.b) by using WriteValueExpr
4684
+ if err := c.WriteValueExpr(selectorExpr); err != nil {
4685
+ return fmt.Errorf("failed to write selector expression in LHS: %w", err)
4686
+ }
4480
4687
  } else {
4481
4688
  // Should not happen for valid Go code in this context, but handle defensively
4482
4689
  return errors.Errorf("unhandled LHS expression in destructuring: %T", lhsExpr)
@@ -5254,6 +5461,15 @@ func (c *GoToTSCompiler) writeTypeAssertion(lhs []ast.Expr, typeAssertExpr *ast.
5254
5461
  interfaceExpr := typeAssertExpr.X
5255
5462
  assertedType := typeAssertExpr.Type
5256
5463
 
5464
+ // Unwrap parenthesized expressions to handle cases like r.((<-chan T))
5465
+ for {
5466
+ if parenExpr, ok := assertedType.(*ast.ParenExpr); ok {
5467
+ assertedType = parenExpr.X
5468
+ } else {
5469
+ break
5470
+ }
5471
+ }
5472
+
5257
5473
  // Ensure LHS has exactly two expressions (value and ok)
5258
5474
  if len(lhs) != 2 {
5259
5475
  return fmt.Errorf("type assertion assignment requires exactly 2 variables on LHS, got %d", len(lhs))
@@ -5264,32 +5480,93 @@ func (c *GoToTSCompiler) writeTypeAssertion(lhs []ast.Expr, typeAssertExpr *ast.
5264
5480
  okIsBlank := false
5265
5481
  var valueName string
5266
5482
  var okName string
5483
+ var valueIdent *ast.Ident
5484
+ var okIdent *ast.Ident
5267
5485
 
5268
- if valIdent, ok := lhs[0].(*ast.Ident); ok {
5269
- if valIdent.Name == "_" {
5486
+ if valId, ok := lhs[0].(*ast.Ident); ok {
5487
+ valueIdent = valId
5488
+ if valId.Name == "_" {
5270
5489
  valueIsBlank = true
5271
5490
  } else {
5272
- valueName = valIdent.Name
5491
+ valueName = valId.Name
5273
5492
  }
5274
5493
  } else {
5275
5494
  return fmt.Errorf("unhandled LHS expression type for value in type assertion: %T", lhs[0])
5276
5495
  }
5277
5496
 
5278
- if okIdent, ok := lhs[1].(*ast.Ident); ok {
5279
- if okIdent.Name == "_" {
5497
+ if okId, ok := lhs[1].(*ast.Ident); ok {
5498
+ okIdent = okId
5499
+ if okId.Name == "_" {
5280
5500
  okIsBlank = true
5281
5501
  } else {
5282
- okName = okIdent.Name
5502
+ okName = okId.Name
5283
5503
  }
5284
5504
  } else {
5285
5505
  return fmt.Errorf("unhandled LHS expression type for ok in type assertion: %T", lhs[1])
5286
5506
  }
5287
5507
 
5288
- // Generate the destructuring assignment
5508
+ // For token.DEFINE (:=), we need to check if any of the variables are already declared
5509
+ // In Go, := can be used for redeclaration if at least one variable is new
5510
+ writeEndParen := false
5289
5511
  if tok == token.DEFINE {
5290
- c.tsw.WriteLiterally("let ")
5512
+ // Identify which variables are new vs existing
5513
+ valueIsNew := true
5514
+ okIsNew := true
5515
+ anyNewVars := false
5516
+ allNewVars := true
5517
+
5518
+ // Check if variables are already in scope
5519
+ if !valueIsBlank {
5520
+ if obj := c.pkg.TypesInfo.Uses[valueIdent]; obj != nil {
5521
+ // If it's in Uses, it's referenced elsewhere, so it exists
5522
+ valueIsNew = false
5523
+ allNewVars = false
5524
+ }
5525
+ if valueIsNew {
5526
+ anyNewVars = true
5527
+ }
5528
+ }
5529
+
5530
+ if !okIsBlank {
5531
+ if obj := c.pkg.TypesInfo.Uses[okIdent]; obj != nil {
5532
+ // If it's in Uses, it's referenced elsewhere, so it exists
5533
+ okIsNew = false
5534
+ allNewVars = false
5535
+ }
5536
+ if okIsNew {
5537
+ anyNewVars = true
5538
+ }
5539
+ }
5540
+
5541
+ if allNewVars && anyNewVars {
5542
+ c.tsw.WriteLiterally("let ")
5543
+ } else if anyNewVars {
5544
+ // If only some variables are new, declare them separately
5545
+ if !valueIsBlank && valueIsNew {
5546
+ c.tsw.WriteLiterally("let ")
5547
+ c.tsw.WriteLiterally(valueName)
5548
+ // Add type annotation if possible
5549
+ if tv, ok := c.pkg.TypesInfo.Types[assertedType]; ok {
5550
+ c.tsw.WriteLiterally(": ")
5551
+ c.WriteGoType(tv.Type)
5552
+ }
5553
+ c.tsw.WriteLine("")
5554
+ }
5555
+ if !okIsBlank && okIsNew {
5556
+ c.tsw.WriteLiterally("let ")
5557
+ c.tsw.WriteLiterally(okName)
5558
+ c.tsw.WriteLiterally(": boolean") // ok is always boolean
5559
+ c.tsw.WriteLine("")
5560
+ }
5561
+ // Use parenthesized destructuring assignment for existing variables
5562
+ c.tsw.WriteLiterally(";(")
5563
+ writeEndParen = true
5564
+ } else {
5565
+ // All variables exist, use parenthesized destructuring assignment
5566
+ c.tsw.WriteLiterally(";(")
5567
+ writeEndParen = true
5568
+ }
5291
5569
  } else {
5292
- // We must wrap in parenthesis.
5293
5570
  c.tsw.WriteLiterally("(")
5294
5571
  }
5295
5572
 
@@ -5383,17 +5660,26 @@ func (c *GoToTSCompiler) writeTypeAssertion(lhs []ast.Expr, typeAssertExpr *ast.
5383
5660
  }
5384
5661
 
5385
5662
  if typeExpr.Fields != nil && typeExpr.Fields.List != nil {
5386
- c.tsw.WriteLiterally(", fields: new Set([")
5663
+ // Add fields property to provide type information
5664
+ c.tsw.WriteLiterally(", fields: {")
5387
5665
 
5388
- fields := []string{}
5666
+ hasFields := false
5389
5667
  for _, field := range typeExpr.Fields.List {
5390
- for _, name := range field.Names {
5391
- fields = append(fields, fmt.Sprintf("'%s'", name.Name))
5668
+ if len(field.Names) > 0 {
5669
+ for _, name := range field.Names {
5670
+ if hasFields {
5671
+ c.tsw.WriteLiterally(", ")
5672
+ }
5673
+ c.tsw.WriteLiterally(fmt.Sprintf("'%s': ", name.Name))
5674
+ c.writeTypeDescription(field.Type)
5675
+ hasFields = true
5676
+ }
5392
5677
  }
5393
5678
  }
5394
5679
 
5395
- c.tsw.WriteLiterally(strings.Join(fields, ", "))
5396
- c.tsw.WriteLiterally("])")
5680
+ c.tsw.WriteLiterally("}")
5681
+ } else {
5682
+ c.tsw.WriteLiterally(", fields: {}")
5397
5683
  }
5398
5684
 
5399
5685
  // Add empty methods set to satisfy StructTypeInfo interface
@@ -5430,8 +5716,11 @@ func (c *GoToTSCompiler) writeTypeAssertion(lhs []ast.Expr, typeAssertExpr *ast.
5430
5716
  c.tsw.WriteLiterally("{")
5431
5717
  c.tsw.WriteLiterally("kind: $.TypeKind.Pointer")
5432
5718
 
5433
- // Add element type if it's a named type
5434
- if ident, ok := typeExpr.X.(*ast.Ident); ok {
5719
+ // Add element type if it's a struct type or named type
5720
+ if structType, ok := typeExpr.X.(*ast.StructType); ok {
5721
+ c.tsw.WriteLiterally(", elemType: ")
5722
+ c.writeTypeDescription(structType)
5723
+ } else if ident, ok := typeExpr.X.(*ast.Ident); ok {
5435
5724
  c.tsw.WriteLiterallyf(", elemType: '%s'", ident.Name)
5436
5725
  }
5437
5726
 
@@ -5452,11 +5741,56 @@ func (c *GoToTSCompiler) writeTypeAssertion(lhs []ast.Expr, typeAssertExpr *ast.
5452
5741
  c.writeTypeDescription(typeExpr.Value)
5453
5742
  }
5454
5743
 
5744
+ c.tsw.WriteLiterally(", direction: ")
5745
+ switch typeExpr.Dir {
5746
+ case ast.SEND:
5747
+ c.tsw.WriteLiterally("'send'")
5748
+ case ast.RECV:
5749
+ c.tsw.WriteLiterally("'receive'")
5750
+ case ast.SEND | ast.RECV: // bidirectional
5751
+ c.tsw.WriteLiterally("'both'")
5752
+ default:
5753
+ // This should not happen, but just in case
5754
+ c.tsw.WriteLiterally("'both'")
5755
+ }
5756
+
5455
5757
  c.tsw.WriteLiterally("}")
5456
5758
  case *ast.FuncType:
5457
- // For function types, create a type descriptor object
5759
+ // For function types, create a type descriptor object with params and results
5458
5760
  c.tsw.WriteLiterally("{")
5459
5761
  c.tsw.WriteLiterally("kind: $.TypeKind.Function")
5762
+
5763
+ // Add name if this is a named function type
5764
+ if namedType := c.pkg.TypesInfo.TypeOf(typeExpr); namedType != nil {
5765
+ if named, ok := namedType.(*types.Named); ok {
5766
+ c.tsw.WriteLiterallyf(", name: '%s'", named.Obj().Name())
5767
+ }
5768
+ }
5769
+
5770
+ // Add params if present
5771
+ if typeExpr.Params != nil && len(typeExpr.Params.List) > 0 {
5772
+ c.tsw.WriteLiterally(", params: [")
5773
+ for i, param := range typeExpr.Params.List {
5774
+ if i > 0 {
5775
+ c.tsw.WriteLiterally(", ")
5776
+ }
5777
+ c.writeTypeDescription(param.Type)
5778
+ }
5779
+ c.tsw.WriteLiterally("]")
5780
+ }
5781
+
5782
+ // Add results if present
5783
+ if typeExpr.Results != nil && len(typeExpr.Results.List) > 0 {
5784
+ c.tsw.WriteLiterally(", results: [")
5785
+ for i, result := range typeExpr.Results.List {
5786
+ if i > 0 {
5787
+ c.tsw.WriteLiterally(", ")
5788
+ }
5789
+ c.writeTypeDescription(result.Type)
5790
+ }
5791
+ c.tsw.WriteLiterally("]")
5792
+ }
5793
+
5460
5794
  c.tsw.WriteLiterally("}")
5461
5795
  case *ast.Ident:
5462
5796
  if isPrimitiveType(typeExpr.Name) {
@@ -5472,7 +5806,78 @@ func (c *GoToTSCompiler) writeTypeAssertion(lhs []ast.Expr, typeAssertExpr *ast.
5472
5806
 
5473
5807
  c.tsw.WriteLiterally("}")
5474
5808
  } else {
5475
- c.tsw.WriteLiterallyf("'%s'", typeExpr.Name)
5809
+ // Check if this is a named function type
5810
+ isFunctionType := false
5811
+ if namedType := c.pkg.TypesInfo.TypeOf(typeExpr); namedType != nil {
5812
+ if named, ok := namedType.(*types.Named); ok {
5813
+ if _, ok := named.Underlying().(*types.Signature); ok {
5814
+ // This is a named function type, generate a FunctionTypeInfo
5815
+ isFunctionType = true
5816
+ c.tsw.WriteLiterally("{")
5817
+ c.tsw.WriteLiterally("kind: $.TypeKind.Function")
5818
+ c.tsw.WriteLiterallyf(", name: '%s'", typeExpr.Name)
5819
+
5820
+ // Get the underlying signature
5821
+ signature := named.Underlying().(*types.Signature)
5822
+
5823
+ // Add params if present
5824
+ params := signature.Params()
5825
+ if params != nil && params.Len() > 0 {
5826
+ c.tsw.WriteLiterally(", params: [")
5827
+ for i := 0; i < params.Len(); i++ {
5828
+ if i > 0 {
5829
+ c.tsw.WriteLiterally(", ")
5830
+ }
5831
+ // Use basic type info for parameters
5832
+ param := params.At(i)
5833
+ c.tsw.WriteLiterally("{")
5834
+ c.tsw.WriteLiterally("kind: $.TypeKind.Basic, ")
5835
+
5836
+ typeName := param.Type().String()
5837
+ if tsType, ok := GoBuiltinToTypescript(typeName); ok {
5838
+ c.tsw.WriteLiterallyf("name: '%s'", tsType)
5839
+ } else {
5840
+ c.tsw.WriteLiterallyf("name: '%s'", typeName)
5841
+ }
5842
+
5843
+ c.tsw.WriteLiterally("}")
5844
+ }
5845
+ c.tsw.WriteLiterally("]")
5846
+ }
5847
+
5848
+ // Add results if present
5849
+ results := signature.Results()
5850
+ if results != nil && results.Len() > 0 {
5851
+ c.tsw.WriteLiterally(", results: [")
5852
+ for i := 0; i < results.Len(); i++ {
5853
+ if i > 0 {
5854
+ c.tsw.WriteLiterally(", ")
5855
+ }
5856
+ result := results.At(i)
5857
+ c.tsw.WriteLiterally("{")
5858
+ c.tsw.WriteLiterally("kind: $.TypeKind.Basic, ")
5859
+
5860
+ typeName := result.Type().String()
5861
+ if tsType, ok := GoBuiltinToTypescript(typeName); ok {
5862
+ c.tsw.WriteLiterallyf("name: '%s'", tsType)
5863
+ } else {
5864
+ c.tsw.WriteLiterallyf("name: '%s'", typeName)
5865
+ }
5866
+
5867
+ c.tsw.WriteLiterally("}")
5868
+ }
5869
+ c.tsw.WriteLiterally("]")
5870
+ }
5871
+
5872
+ c.tsw.WriteLiterally("}")
5873
+ }
5874
+ }
5875
+ }
5876
+
5877
+ // Default case for non-function named types
5878
+ if !isFunctionType {
5879
+ c.tsw.WriteLiterallyf("'%s'", typeExpr.Name)
5880
+ }
5476
5881
  }
5477
5882
  case *ast.SelectorExpr:
5478
5883
  // For imported types like pkg.Type
@@ -5489,7 +5894,7 @@ func (c *GoToTSCompiler) writeTypeAssertion(lhs []ast.Expr, typeAssertExpr *ast.
5489
5894
 
5490
5895
  c.tsw.WriteLiterally(")")
5491
5896
 
5492
- if tok != token.DEFINE {
5897
+ if tok != token.DEFINE || writeEndParen {
5493
5898
  c.tsw.WriteLiterally(")")
5494
5899
  }
5495
5900
 
@@ -5545,20 +5950,7 @@ func (c *GoToTSCompiler) writeTypeDescription(typeExpr ast.Expr) {
5545
5950
 
5546
5951
  // Add field names and types to the struct type info
5547
5952
  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: {")
5953
+ c.tsw.WriteLiterally("fields: {")
5562
5954
 
5563
5955
  hasFields := false
5564
5956
  for _, field := range t.Fields.List {
@@ -5576,7 +5968,7 @@ func (c *GoToTSCompiler) writeTypeDescription(typeExpr ast.Expr) {
5576
5968
 
5577
5969
  c.tsw.WriteLiterally("}, ")
5578
5970
  } else {
5579
- c.tsw.WriteLiterally("fields: new Set(), ")
5971
+ c.tsw.WriteLiterally("fields: {}, ")
5580
5972
  }
5581
5973
 
5582
5974
  c.tsw.WriteLiterally("methods: new Set()")
@@ -5596,6 +5988,75 @@ func (c *GoToTSCompiler) writeTypeDescription(typeExpr ast.Expr) {
5596
5988
  c.tsw.WriteLiterally("kind: $.TypeKind.Pointer, ")
5597
5989
  c.tsw.WriteLiterally("elemType: ")
5598
5990
  c.writeTypeDescription(t.X)
5991
+ c.tsw.WriteLiterally("}")
5992
+ case *ast.FuncType:
5993
+ // For function types, create a type descriptor object with params and results
5994
+ c.tsw.WriteLiterally("{")
5995
+ c.tsw.WriteLiterally("kind: $.TypeKind.Function")
5996
+
5997
+ // Add name if this is a named function type
5998
+ if namedType := c.pkg.TypesInfo.TypeOf(typeExpr); namedType != nil {
5999
+ if named, ok := namedType.(*types.Named); ok {
6000
+ c.tsw.WriteLiterallyf(", name: '%s'", named.Obj().Name())
6001
+ }
6002
+ }
6003
+
6004
+ // Add params if present
6005
+ if t.Params != nil && len(t.Params.List) > 0 {
6006
+ c.tsw.WriteLiterally(", params: [")
6007
+ for i, param := range t.Params.List {
6008
+ if i > 0 {
6009
+ c.tsw.WriteLiterally(", ")
6010
+ }
6011
+ c.writeTypeDescription(param.Type)
6012
+ }
6013
+ c.tsw.WriteLiterally("]")
6014
+ }
6015
+
6016
+ // Add results if present
6017
+ if t.Results != nil && len(t.Results.List) > 0 {
6018
+ c.tsw.WriteLiterally(", results: [")
6019
+ for i, result := range t.Results.List {
6020
+ if i > 0 {
6021
+ c.tsw.WriteLiterally(", ")
6022
+ }
6023
+ c.writeTypeDescription(result.Type)
6024
+ }
6025
+ c.tsw.WriteLiterally("]")
6026
+ }
6027
+
6028
+ c.tsw.WriteLiterally("}")
6029
+ return
6030
+ case *ast.ChanType:
6031
+ c.tsw.WriteLiterally("{")
6032
+ c.tsw.WriteLiterally("kind: $.TypeKind.Channel, ")
6033
+ c.tsw.WriteLiterally("elemType: ")
6034
+
6035
+ // Add element type
6036
+ if ident, ok := t.Value.(*ast.Ident); ok && isPrimitiveType(ident.Name) {
6037
+ if tsType, ok := GoBuiltinToTypescript(ident.Name); ok {
6038
+ c.tsw.WriteLiterallyf("'%s'", tsType)
6039
+ } else {
6040
+ c.tsw.WriteLiterallyf("'%s'", ident.Name) // Fallback
6041
+ }
6042
+ } else {
6043
+ c.writeTypeDescription(t.Value)
6044
+ }
6045
+
6046
+ // Add direction
6047
+ c.tsw.WriteLiterally(", direction: ")
6048
+ switch t.Dir {
6049
+ case ast.SEND:
6050
+ c.tsw.WriteLiterally("'send'")
6051
+ case ast.RECV:
6052
+ c.tsw.WriteLiterally("'receive'")
6053
+ case ast.SEND | ast.RECV: // bidirectional
6054
+ c.tsw.WriteLiterally("'both'")
6055
+ default:
6056
+ // This should not happen, but just in case
6057
+ c.tsw.WriteLiterally("'both'")
6058
+ }
6059
+
5599
6060
  c.tsw.WriteLiterally("}")
5600
6061
  default:
5601
6062
  // For other types, use the string representation