goscript 0.0.48 → 0.0.50

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (159) hide show
  1. package/cmd/goscript/deps.go +1 -4
  2. package/compiler/analysis.go +1120 -513
  3. package/compiler/analysis_test.go +113 -4
  4. package/compiler/compiler.go +88 -124
  5. package/compiler/decl.go +22 -0
  6. package/compiler/expr-call-async.go +46 -52
  7. package/compiler/expr-call-type-conversion.go +144 -59
  8. package/compiler/expr-call.go +235 -12
  9. package/compiler/expr.go +5 -82
  10. package/compiler/gs_dependencies_test.go +60 -1
  11. package/compiler/spec-value.go +73 -51
  12. package/compiler/spec.go +337 -151
  13. package/compiler/stmt-assign.go +7 -4
  14. package/compiler/stmt.go +250 -81
  15. package/compiler/type.go +13 -0
  16. package/dist/gs/builtin/builtin.d.ts +1 -5
  17. package/dist/gs/builtin/builtin.js +1 -34
  18. package/dist/gs/builtin/builtin.js.map +1 -1
  19. package/dist/gs/builtin/slice.js.map +1 -1
  20. package/dist/gs/context/context.d.ts +16 -18
  21. package/dist/gs/context/context.js +23 -13
  22. package/dist/gs/context/context.js.map +1 -1
  23. package/dist/gs/fmt/fmt.js +22 -4
  24. package/dist/gs/fmt/fmt.js.map +1 -1
  25. package/dist/gs/io/fs/fs.d.ts +6 -12
  26. package/dist/gs/io/fs/fs.js +52 -67
  27. package/dist/gs/io/fs/fs.js.map +1 -1
  28. package/dist/gs/os/index.d.ts +2 -1
  29. package/dist/gs/os/index.js +1 -1
  30. package/dist/gs/os/index.js.map +1 -1
  31. package/dist/gs/os/types_js.gs.d.ts +7 -1
  32. package/dist/gs/os/types_js.gs.js +16 -1
  33. package/dist/gs/os/types_js.gs.js.map +1 -1
  34. package/dist/gs/os/types_unix.gs.js +2 -2
  35. package/dist/gs/os/types_unix.gs.js.map +1 -1
  36. package/dist/gs/reflect/index.d.ts +3 -3
  37. package/dist/gs/reflect/index.js +2 -2
  38. package/dist/gs/reflect/index.js.map +1 -1
  39. package/dist/gs/reflect/map.js +2 -2
  40. package/dist/gs/reflect/map.js.map +1 -1
  41. package/dist/gs/reflect/type.d.ts +8 -9
  42. package/dist/gs/reflect/type.js +98 -103
  43. package/dist/gs/reflect/type.js.map +1 -1
  44. package/dist/gs/reflect/types.d.ts +1 -10
  45. package/dist/gs/reflect/types.js +3 -26
  46. package/dist/gs/reflect/types.js.map +1 -1
  47. package/dist/gs/reflect/value.js +23 -23
  48. package/dist/gs/reflect/value.js.map +1 -1
  49. package/dist/gs/reflect/visiblefields.js +3 -3
  50. package/dist/gs/reflect/visiblefields.js.map +1 -1
  51. package/dist/gs/time/time.d.ts +13 -23
  52. package/dist/gs/time/time.js +57 -75
  53. package/dist/gs/time/time.js.map +1 -1
  54. package/gs/builtin/builtin.ts +3 -47
  55. package/gs/builtin/slice.ts +1 -1
  56. package/gs/bytes/meta.json +10 -0
  57. package/gs/context/context.ts +63 -45
  58. package/gs/fmt/fmt.ts +22 -4
  59. package/gs/fmt/meta.json +5 -0
  60. package/gs/internal/meta.json +5 -0
  61. package/gs/io/fs/fs.ts +58 -73
  62. package/gs/io/meta.json +9 -0
  63. package/gs/maps/meta.json +6 -0
  64. package/gs/math/meta.json +5 -0
  65. package/gs/os/index.ts +8 -1
  66. package/gs/os/meta.json +15 -0
  67. package/gs/os/types_js.gs.ts +22 -1
  68. package/gs/os/types_unix.gs.ts +2 -2
  69. package/gs/path/meta.json +6 -0
  70. package/gs/reflect/function-types.test.ts +10 -10
  71. package/gs/reflect/index.ts +6 -6
  72. package/gs/reflect/map.ts +2 -2
  73. package/gs/reflect/meta.json +5 -0
  74. package/gs/reflect/type.ts +105 -105
  75. package/gs/reflect/types.ts +2 -28
  76. package/gs/reflect/value.ts +23 -23
  77. package/gs/reflect/visiblefields.ts +3 -3
  78. package/gs/strconv/meta.json +5 -0
  79. package/gs/strings/meta.json +9 -0
  80. package/gs/sync/meta.json +19 -0
  81. package/gs/time/time.ts +65 -84
  82. package/package.json +2 -2
  83. package/dist/gs/builtin/io.d.ts +0 -16
  84. package/dist/gs/builtin/io.js +0 -15
  85. package/dist/gs/builtin/io.js.map +0 -1
  86. package/dist/gs/internal/testlog/index.d.ts +0 -1
  87. package/dist/gs/internal/testlog/index.js +0 -5
  88. package/dist/gs/internal/testlog/index.js.map +0 -1
  89. package/dist/gs/maps/iter.gs.d.ts +0 -7
  90. package/dist/gs/maps/iter.gs.js +0 -65
  91. package/dist/gs/maps/iter.gs.js.map +0 -1
  92. package/dist/gs/maps/maps.gs.d.ts +0 -7
  93. package/dist/gs/maps/maps.gs.js +0 -79
  94. package/dist/gs/maps/maps.gs.js.map +0 -1
  95. package/dist/gs/reflect/abi.d.ts +0 -59
  96. package/dist/gs/reflect/abi.gs.d.ts +0 -59
  97. package/dist/gs/reflect/abi.gs.js +0 -79
  98. package/dist/gs/reflect/abi.gs.js.map +0 -1
  99. package/dist/gs/reflect/abi.js +0 -79
  100. package/dist/gs/reflect/abi.js.map +0 -1
  101. package/dist/gs/reflect/badlinkname.d.ts +0 -52
  102. package/dist/gs/reflect/badlinkname.gs.d.ts +0 -52
  103. package/dist/gs/reflect/badlinkname.gs.js +0 -72
  104. package/dist/gs/reflect/badlinkname.gs.js.map +0 -1
  105. package/dist/gs/reflect/badlinkname.js +0 -72
  106. package/dist/gs/reflect/badlinkname.js.map +0 -1
  107. package/dist/gs/reflect/deepequal.gs.d.ts +0 -25
  108. package/dist/gs/reflect/deepequal.gs.js +0 -308
  109. package/dist/gs/reflect/deepequal.gs.js.map +0 -1
  110. package/dist/gs/reflect/float32reg_generic.gs.d.ts +0 -2
  111. package/dist/gs/reflect/float32reg_generic.gs.js +0 -10
  112. package/dist/gs/reflect/float32reg_generic.gs.js.map +0 -1
  113. package/dist/gs/reflect/index.gs.d.ts +0 -1
  114. package/dist/gs/reflect/index.gs.js +0 -3
  115. package/dist/gs/reflect/index.gs.js.map +0 -1
  116. package/dist/gs/reflect/iter.gs.d.ts +0 -3
  117. package/dist/gs/reflect/iter.gs.js +0 -24
  118. package/dist/gs/reflect/iter.gs.js.map +0 -1
  119. package/dist/gs/reflect/makefunc.gs.d.ts +0 -34
  120. package/dist/gs/reflect/makefunc.gs.js +0 -288
  121. package/dist/gs/reflect/makefunc.gs.js.map +0 -1
  122. package/dist/gs/reflect/map_swiss.gs.d.ts +0 -14
  123. package/dist/gs/reflect/map_swiss.gs.js +0 -70
  124. package/dist/gs/reflect/map_swiss.gs.js.map +0 -1
  125. package/dist/gs/reflect/reflect.gs.d.ts +0 -132
  126. package/dist/gs/reflect/reflect.gs.js +0 -437
  127. package/dist/gs/reflect/reflect.gs.js.map +0 -1
  128. package/dist/gs/reflect/swapper.gs.d.ts +0 -1
  129. package/dist/gs/reflect/swapper.gs.js +0 -32
  130. package/dist/gs/reflect/swapper.gs.js.map +0 -1
  131. package/dist/gs/reflect/type.gs.d.ts +0 -4
  132. package/dist/gs/reflect/type.gs.js +0 -21
  133. package/dist/gs/reflect/type.gs.js.map +0 -1
  134. package/dist/gs/reflect/value.gs.d.ts +0 -4
  135. package/dist/gs/reflect/value.gs.js +0 -12
  136. package/dist/gs/reflect/value.gs.js.map +0 -1
  137. package/dist/gs/reflect/visiblefields.gs.d.ts +0 -3
  138. package/dist/gs/reflect/visiblefields.gs.js +0 -123
  139. package/dist/gs/reflect/visiblefields.gs.js.map +0 -1
  140. package/dist/gs/stringslite/index.d.ts +0 -1
  141. package/dist/gs/stringslite/index.js +0 -2
  142. package/dist/gs/stringslite/index.js.map +0 -1
  143. package/dist/gs/stringslite/strings.d.ts +0 -11
  144. package/dist/gs/stringslite/strings.js +0 -67
  145. package/dist/gs/stringslite/strings.js.map +0 -1
  146. package/gs/bytes/metadata.go +0 -12
  147. package/gs/fmt/metadata.go +0 -7
  148. package/gs/internal/metadata.go +0 -7
  149. package/gs/io/io.go +0 -75
  150. package/gs/io/metadata.go +0 -11
  151. package/gs/maps/metadata.go +0 -8
  152. package/gs/math/metadata.go +0 -7
  153. package/gs/os/metadata.go +0 -17
  154. package/gs/path/metadata.go +0 -8
  155. package/gs/reflect/metadata.go +0 -7
  156. package/gs/strconv/metadata.go +0 -7
  157. package/gs/strings/metadata.go +0 -11
  158. package/gs/sync/metadata.go +0 -7
  159. package/gs/sync/sync.go +0 -64
@@ -80,9 +80,8 @@ func (c *GoToTSCompiler) writeArrayTypeConversion(exp *ast.CallExpr) (handled bo
80
80
  if argType := c.pkg.TypesInfo.TypeOf(arg); argType != nil {
81
81
  // Check if the argument is a named type with a slice underlying type
82
82
  if namedArgType, isNamed := argType.(*types.Named); isNamed {
83
- // Check if the named type has receiver methods (is a wrapper class)
84
- typeName := namedArgType.Obj().Name()
85
- if c.hasReceiverMethods(typeName) {
83
+ // Check if the named type has receiver methods (is a wrapper type)
84
+ if c.analysis.IsNamedBasicType(namedArgType) {
86
85
  // Check if the underlying type matches the target slice type
87
86
  if sliceUnderlying, isSlice := namedArgType.Underlying().(*types.Slice); isSlice {
88
87
  // Get the target slice type
@@ -90,12 +89,11 @@ func (c *GoToTSCompiler) writeArrayTypeConversion(exp *ast.CallExpr) (handled bo
90
89
  if targetSliceType, isTargetSlice := targetType.Underlying().(*types.Slice); isTargetSlice {
91
90
  // Check if element types are compatible
92
91
  if types.Identical(sliceUnderlying.Elem(), targetSliceType.Elem()) {
93
- // This is a conversion from NamedType to []T where NamedType has underlying []T
94
- // Use valueOf() to get the underlying slice
92
+ // This is a conversion from wrapper slice type to []T
93
+ // Since wrapper types are now type aliases, just write the value directly
95
94
  if err := c.WriteValueExpr(arg); err != nil {
96
95
  return true, fmt.Errorf("failed to write argument for slice type conversion: %w", err)
97
96
  }
98
- c.tsw.WriteLiterally(".valueOf()")
99
97
  return true, nil
100
98
  }
101
99
  }
@@ -217,19 +215,17 @@ func (c *GoToTSCompiler) writeTypeConversion(exp *ast.CallExpr, funIdent *ast.Id
217
215
  // Check if we're converting FROM a type with receiver methods TO its underlying type
218
216
  if argType := c.pkg.TypesInfo.TypeOf(arg); argType != nil {
219
217
  if namedArgType, isNamed := argType.(*types.Named); isNamed {
220
- argTypeName := namedArgType.Obj().Name()
221
- // Check if the argument type has receiver methods
222
- if c.hasReceiverMethods(argTypeName) {
218
+ // Check if the argument type is a wrapper type
219
+ if c.analysis.IsNamedBasicType(namedArgType) {
223
220
  // Check if we're converting to the underlying type
224
221
  targetType := typeName.Type()
225
222
  underlyingType := namedArgType.Underlying()
226
223
  if types.Identical(targetType, underlyingType) {
227
- // This is a conversion from a type with methods to its underlying type
228
- // Use valueOf() instead of TypeScript cast
224
+ // This is a conversion from a wrapper type to its underlying type
225
+ // Since wrapper types are now type aliases, just write the value directly
229
226
  if err := c.WriteValueExpr(arg); err != nil {
230
- return true, fmt.Errorf("failed to write argument for valueOf conversion: %w", err)
227
+ return true, fmt.Errorf("failed to write argument for type conversion: %w", err)
231
228
  }
232
- c.tsw.WriteLiterally(".valueOf()")
233
229
  return true, nil
234
230
  }
235
231
  }
@@ -250,29 +246,111 @@ func (c *GoToTSCompiler) writeTypeConversion(exp *ast.CallExpr, funIdent *ast.Id
250
246
  c.tsw.WriteLiterallyf(", { __goTypeName: '%s' })", funIdent.String())
251
247
  return true, nil
252
248
  } else {
249
+ // Check if this is a wrapper type
250
+ isWrapperType := c.analysis.IsNamedBasicType(typeName.Type())
251
+ if isWrapperType {
252
+ // For wrapper types, use type casting instead of constructor calls
253
+ c.tsw.WriteLiterally("(")
254
+ if err := c.WriteValueExpr(exp.Args[0]); err != nil {
255
+ return true, fmt.Errorf("failed to write argument for wrapper type cast: %w", err)
256
+ }
257
+ c.tsw.WriteLiterally(" as ")
258
+ c.WriteGoType(typeName.Type(), GoTypeContextGeneral)
259
+ c.tsw.WriteLiterally(")")
260
+ return true, nil
261
+ }
262
+
263
+ // Check if this is a simple named type (no methods, not struct, not interface)
264
+ if namedType, ok := typeName.Type().(*types.Named); ok {
265
+ // Don't use constructors for simple named types without methods
266
+ if namedType.NumMethods() == 0 {
267
+ // Exclude struct and interface types - they should still use constructors
268
+ if _, isStruct := namedType.Underlying().(*types.Struct); !isStruct {
269
+ if _, isInterface := namedType.Underlying().(*types.Interface); !isInterface {
270
+ // Simple named type without methods - use type casting
271
+ c.tsw.WriteLiterally("(")
272
+ if err := c.WriteValueExpr(exp.Args[0]); err != nil {
273
+ return true, fmt.Errorf("failed to write argument for simple named type cast: %w", err)
274
+ }
275
+ c.tsw.WriteLiterally(" as ")
276
+ c.WriteGoType(typeName.Type(), GoTypeContextGeneral)
277
+ c.tsw.WriteLiterally(")")
278
+ return true, nil
279
+ }
280
+ }
281
+ }
282
+ }
283
+
253
284
  // Check if this type has receiver methods
254
285
  if c.hasReceiverMethods(funIdent.String()) {
255
- // For types with methods, use class constructor
286
+ // For types with methods that are NOT wrapper types, still use class constructor
256
287
  c.tsw.WriteLiterally("new ")
257
288
  c.tsw.WriteLiterally(funIdent.String())
258
289
  c.tsw.WriteLiterally("(")
259
- if err := c.WriteValueExpr(exp.Args[0]); err != nil {
290
+
291
+ // Use auto-wrapping for the constructor argument
292
+ // The constructor parameter type is the underlying type of the named type
293
+ // For MyMode (which is type MyMode os.FileMode), the constructor expects os.FileMode
294
+ constructorParamType := typeName.Type()
295
+ if namedType, ok := typeName.Type().(*types.Named); ok {
296
+ // For named types, the constructor expects the underlying type
297
+ constructorParamType = namedType.Underlying()
298
+ }
299
+
300
+ if err := c.writeAutoWrappedArgument(exp.Args[0], constructorParamType); err != nil {
260
301
  return true, fmt.Errorf("failed to write argument for type constructor: %w", err)
261
302
  }
262
303
  c.tsw.WriteLiterally(")")
263
304
  return true, nil
264
305
  } else {
265
- // For non-function types without methods, use the TypeScript "as" operator
266
- c.tsw.WriteLiterally("(")
267
- if err := c.WriteValueExpr(exp.Args[0]); err != nil {
268
- return true, fmt.Errorf("failed to write argument for type cast: %w", err)
306
+ // Determine if this type should use constructor syntax
307
+ shouldUseConstructor := false
308
+
309
+ // Check if it's a type alias (like os.FileMode)
310
+ if alias, isAlias := typeName.Type().(*types.Alias); isAlias {
311
+ // For type aliases, check the underlying type
312
+ if _, isInterface := alias.Underlying().(*types.Interface); !isInterface {
313
+ if _, isStruct := alias.Underlying().(*types.Struct); !isStruct {
314
+ // For non-struct, non-interface type aliases, use constructor
315
+ shouldUseConstructor = true
316
+ }
317
+ }
318
+ } else if namedType, isNamed := typeName.Type().(*types.Named); isNamed {
319
+ // For named types, check if they have receiver methods in the current package
320
+ // or if they follow the pattern of non-struct, non-interface named types
321
+ if c.hasReceiverMethods(funIdent.String()) {
322
+ shouldUseConstructor = true
323
+ } else if _, isInterface := namedType.Underlying().(*types.Interface); !isInterface {
324
+ if _, isStruct := namedType.Underlying().(*types.Struct); !isStruct {
325
+ // For non-struct, non-interface named types, use constructor
326
+ shouldUseConstructor = true
327
+ }
328
+ }
269
329
  }
270
330
 
271
- // Then use the TypeScript "as" operator with the mapped type name
272
- c.tsw.WriteLiterally(" as ")
273
- c.WriteGoType(typeName.Type(), GoTypeContextGeneral)
274
- c.tsw.WriteLiterally(")")
275
- return true, nil
331
+ if shouldUseConstructor {
332
+ // For types that should use constructors, use class constructor
333
+ c.tsw.WriteLiterally("new ")
334
+ c.tsw.WriteLiterally(funIdent.String())
335
+ c.tsw.WriteLiterally("(")
336
+ if err := c.WriteValueExpr(exp.Args[0]); err != nil {
337
+ return true, fmt.Errorf("failed to write argument for type constructor: %w", err)
338
+ }
339
+ c.tsw.WriteLiterally(")")
340
+ return true, nil
341
+ } else {
342
+ // For types that don't need constructors, use the TypeScript "as" operator
343
+ c.tsw.WriteLiterally("(")
344
+ if err := c.WriteValueExpr(exp.Args[0]); err != nil {
345
+ return true, fmt.Errorf("failed to write argument for type cast: %w", err)
346
+ }
347
+
348
+ // Then use the TypeScript "as" operator with the mapped type name
349
+ c.tsw.WriteLiterally(" as ")
350
+ c.WriteGoType(typeName.Type(), GoTypeContextGeneral)
351
+ c.tsw.WriteLiterally(")")
352
+ return true, nil
353
+ }
276
354
  }
277
355
  }
278
356
  }
@@ -293,17 +371,15 @@ func (c *GoToTSCompiler) writeIntConversion(exp *ast.CallExpr) error {
293
371
  // Check if we're converting FROM a type with receiver methods TO int
294
372
  if argType := c.pkg.TypesInfo.TypeOf(arg); argType != nil {
295
373
  if namedArgType, isNamed := argType.(*types.Named); isNamed {
296
- argTypeName := namedArgType.Obj().Name()
297
- // Check if the argument type has receiver methods
298
- if c.hasReceiverMethods(argTypeName) {
374
+ // Check if the argument type is a wrapper type
375
+ if c.analysis.IsNamedBasicType(namedArgType) {
299
376
  // Check if we're converting to int (the underlying type)
300
377
  if types.Identical(types.Typ[types.Int], namedArgType.Underlying()) {
301
- // This is a conversion from a type with methods to int
302
- // Use valueOf() instead of $.int()
378
+ // This is a conversion from a wrapper type to int
379
+ // Since wrapper types are now type aliases, just write the value directly
303
380
  if err := c.WriteValueExpr(arg); err != nil {
304
- return fmt.Errorf("failed to write argument for valueOf conversion: %w", err)
381
+ return fmt.Errorf("failed to write argument for int conversion: %w", err)
305
382
  }
306
- c.tsw.WriteLiterally(".valueOf()")
307
383
  return nil
308
384
  }
309
385
  }
@@ -332,19 +408,17 @@ func (c *GoToTSCompiler) writeQualifiedTypeConversion(exp *ast.CallExpr, selecto
332
408
  // Check if we're converting FROM a type with receiver methods TO its underlying type
333
409
  if argType := c.pkg.TypesInfo.TypeOf(arg); argType != nil {
334
410
  if namedArgType, isNamed := argType.(*types.Named); isNamed {
335
- argTypeName := namedArgType.Obj().Name()
336
- // Check if the argument type has receiver methods
337
- if c.hasReceiverMethods(argTypeName) {
411
+ // Check if the argument type is a wrapper type
412
+ if c.analysis.IsNamedBasicType(namedArgType) {
338
413
  // Check if we're converting to the underlying type
339
414
  targetType := typeName.Type()
340
415
  underlyingType := namedArgType.Underlying()
341
416
  if types.Identical(targetType, underlyingType) {
342
- // This is a conversion from a type with methods to its underlying type
343
- // Use valueOf() instead of TypeScript cast
417
+ // This is a conversion from a wrapper type to its underlying type
418
+ // Since wrapper types are now type aliases, just write the value directly
344
419
  if err := c.WriteValueExpr(arg); err != nil {
345
- return true, fmt.Errorf("failed to write argument for valueOf conversion: %w", err)
420
+ return true, fmt.Errorf("failed to write argument for type conversion: %w", err)
346
421
  }
347
- c.tsw.WriteLiterally(".valueOf()")
348
422
  return true, nil
349
423
  }
350
424
  }
@@ -365,33 +439,44 @@ func (c *GoToTSCompiler) writeQualifiedTypeConversion(exp *ast.CallExpr, selecto
365
439
  c.tsw.WriteLiterallyf(", { __goTypeName: '%s' })", selectorExpr.Sel.Name)
366
440
  return true, nil
367
441
  } else {
368
- // Determine if this type should use constructor syntax
369
- shouldUseConstructor := false
370
-
371
- // Check if it's a type alias (like os.FileMode)
372
- if alias, isAlias := typeName.Type().(*types.Alias); isAlias {
373
- // For type aliases, check the underlying type
374
- if _, isInterface := alias.Underlying().(*types.Interface); !isInterface {
375
- if _, isStruct := alias.Underlying().(*types.Struct); !isStruct {
376
- // For non-struct, non-interface type aliases, use constructor
377
- shouldUseConstructor = true
378
- }
442
+ // Check if this is a wrapper type
443
+ isWrapperType := c.analysis.IsNamedBasicType(typeName.Type())
444
+ if isWrapperType {
445
+ // For wrapper types, use type casting instead of constructor calls
446
+ c.tsw.WriteLiterally("(")
447
+ if err := c.WriteValueExpr(exp.Args[0]); err != nil {
448
+ return true, fmt.Errorf("failed to write argument for wrapper type cast: %w", err)
379
449
  }
380
- } else if namedType, isNamed := typeName.Type().(*types.Named); isNamed {
381
- // For named types, check if they have receiver methods in the current package
382
- // or if they follow the pattern of non-struct, non-interface named types
383
- if c.hasReceiverMethods(selectorExpr.Sel.Name) {
384
- shouldUseConstructor = true
385
- } else if _, isInterface := namedType.Underlying().(*types.Interface); !isInterface {
450
+ c.tsw.WriteLiterally(" as ")
451
+ c.WriteGoType(typeName.Type(), GoTypeContextGeneral)
452
+ c.tsw.WriteLiterally(")")
453
+ return true, nil
454
+ }
455
+
456
+ // Check if this is a simple named type (no methods, not struct, not interface)
457
+ if namedType, ok := typeName.Type().(*types.Named); ok {
458
+ // Don't use constructors for simple named types without methods
459
+ if namedType.NumMethods() == 0 {
460
+ // Exclude struct and interface types - they should still use constructors
386
461
  if _, isStruct := namedType.Underlying().(*types.Struct); !isStruct {
387
- // For non-struct, non-interface named types, use constructor
388
- shouldUseConstructor = true
462
+ if _, isInterface := namedType.Underlying().(*types.Interface); !isInterface {
463
+ // Simple named type without methods - use type casting
464
+ c.tsw.WriteLiterally("(")
465
+ if err := c.WriteValueExpr(exp.Args[0]); err != nil {
466
+ return true, fmt.Errorf("failed to write argument for simple named type cast: %w", err)
467
+ }
468
+ c.tsw.WriteLiterally(" as ")
469
+ c.WriteGoType(typeName.Type(), GoTypeContextGeneral)
470
+ c.tsw.WriteLiterally(")")
471
+ return true, nil
472
+ }
389
473
  }
390
474
  }
391
475
  }
392
476
 
393
- if shouldUseConstructor {
394
- // For types that should use constructors, use class constructor
477
+ // Check if this type has receiver methods
478
+ if c.hasReceiverMethods(selectorExpr.Sel.Name) {
479
+ // For types with methods that are NOT wrapper types, still use class constructor
395
480
  c.tsw.WriteLiterally("new ")
396
481
  if err := c.WriteSelectorExpr(selectorExpr); err != nil {
397
482
  return true, fmt.Errorf("failed to write qualified type name: %w", err)
@@ -5,6 +5,7 @@ import (
5
5
  "go/ast"
6
6
  "go/token"
7
7
  "go/types"
8
+ "strings"
8
9
  )
9
10
 
10
11
  // WriteCallExpr translates a Go function call expression (`ast.CallExpr`)
@@ -73,7 +74,7 @@ func (c *GoToTSCompiler) WriteCallExpr(exp *ast.CallExpr) error {
73
74
  }
74
75
 
75
76
  // Check if this is an async function call
76
- _ = c.writeAsyncCall(exp, funIdent)
77
+ c.writeAsyncCallIfNeeded(exp)
77
78
 
78
79
  // Not a special built-in, treat as a regular function call
79
80
  if err := c.WriteValueExpr(expFun); err != nil {
@@ -89,11 +90,16 @@ func (c *GoToTSCompiler) WriteCallExpr(exp *ast.CallExpr) error {
89
90
  if handled, err := c.writeQualifiedTypeConversion(exp, selectorExpr); handled {
90
91
  return err
91
92
  }
93
+
94
+ // Handle wrapper type method calls: obj.Method() -> TypeName_Method(obj, ...)
95
+ if handled, err := c.writeWrapperTypeMethodCall(exp, selectorExpr); handled {
96
+ return err
97
+ }
92
98
  }
93
99
 
94
100
  // Handle non-identifier function expressions (method calls, function literals, etc.)
95
101
  // Check if this is an async method call (e.g., mu.Lock())
96
- _ = c.writeAsyncMethodCall(exp)
102
+ c.writeAsyncCallIfNeeded(exp)
97
103
 
98
104
  // If expFun is a function literal, it needs to be wrapped in parentheses for IIFE syntax
99
105
  if _, isFuncLit := expFun.(*ast.FuncLit); isFuncLit {
@@ -123,27 +129,244 @@ func (c *GoToTSCompiler) WriteCallExpr(exp *ast.CallExpr) error {
123
129
  // writeCallArguments writes the argument list for a function call
124
130
  func (c *GoToTSCompiler) writeCallArguments(exp *ast.CallExpr) error {
125
131
  c.tsw.WriteLiterally("(")
132
+
133
+ // Get function signature for parameter type checking
134
+ var funcSig *types.Signature
135
+ if c.pkg != nil && c.pkg.TypesInfo != nil {
136
+ if funcType := c.pkg.TypesInfo.TypeOf(exp.Fun); funcType != nil {
137
+ if sig, ok := funcType.(*types.Signature); ok {
138
+ funcSig = sig
139
+ }
140
+ }
141
+ }
142
+
126
143
  for i, arg := range exp.Args {
127
144
  if i != 0 {
128
145
  c.tsw.WriteLiterally(", ")
129
146
  }
130
147
  // Check if this is the last argument and we have ellipsis (variadic call)
131
148
  if exp.Ellipsis != token.NoPos && i == len(exp.Args)-1 {
132
- c.tsw.WriteLiterally("...")
149
+ c.tsw.WriteLiterally("...(")
150
+ // Write the argument
151
+ if err := c.writeArgumentWithTypeHandling(arg, funcSig, i); err != nil {
152
+ return err
153
+ }
154
+ // Add null coalescing for slice spread to prevent TypeScript errors
155
+ c.tsw.WriteLiterally(" ?? [])")
156
+ continue
133
157
  }
134
- if err := c.WriteValueExpr(arg); err != nil {
135
- return fmt.Errorf("failed to write argument %d in call: %w", i, err)
158
+
159
+ if err := c.writeArgumentWithTypeHandling(arg, funcSig, i); err != nil {
160
+ return err
136
161
  }
137
- // Add non-null assertion for spread arguments that might be null
138
- if exp.Ellipsis != token.NoPos && i == len(exp.Args)-1 {
139
- // Check if the argument type is potentially nullable (slice)
140
- if argType := c.pkg.TypesInfo.TypeOf(arg); argType != nil {
141
- if _, isSlice := argType.Underlying().(*types.Slice); isSlice {
142
- c.tsw.WriteLiterally("!")
162
+ }
163
+
164
+ c.tsw.WriteLiterally(")")
165
+ return nil
166
+ }
167
+
168
+ // writeArgumentWithTypeHandling writes a single argument with proper type handling
169
+ func (c *GoToTSCompiler) writeArgumentWithTypeHandling(arg ast.Expr, funcSig *types.Signature, argIndex int) error {
170
+ if funcSig != nil && argIndex < funcSig.Params().Len() {
171
+ paramType := funcSig.Params().At(argIndex).Type()
172
+ isWrapper := c.analysis.IsNamedBasicType(paramType)
173
+
174
+ if isWrapper {
175
+ // For wrapper types (now type aliases), no auto-wrapping is needed
176
+ // Just use type casting if the types don't match exactly
177
+ argType := c.pkg.TypesInfo.TypeOf(arg)
178
+
179
+ // Only add type casting if needed
180
+ if argType != nil && !types.Identical(argType, paramType) {
181
+ c.tsw.WriteLiterally("(")
182
+ if err := c.WriteValueExpr(arg); err != nil {
183
+ return fmt.Errorf("failed to write argument for type cast: %w", err)
184
+ }
185
+ c.tsw.WriteLiterally(" as ")
186
+ c.WriteGoType(paramType, GoTypeContextGeneral)
187
+ c.tsw.WriteLiterally(")")
188
+ } else {
189
+ // Types match, just write the argument directly
190
+ if err := c.WriteValueExpr(arg); err != nil {
191
+ return fmt.Errorf("failed to write argument: %w", err)
143
192
  }
144
193
  }
194
+ return nil
145
195
  }
146
196
  }
147
- c.tsw.WriteLiterally(")")
197
+
198
+ // For non-wrapper types, normal argument writing
199
+ if err := c.WriteValueExpr(arg); err != nil {
200
+ return fmt.Errorf("failed to write argument: %w", err)
201
+ }
202
+ return nil
203
+ }
204
+
205
+ // getImportAlias returns the import alias for a given package path
206
+ func (c *GoToTSCompiler) getImportAlias(pkgPath string) string {
207
+ if c.analysis == nil {
208
+ return ""
209
+ }
210
+
211
+ // First try to find by exact package path
212
+ for importAlias := range c.analysis.Imports {
213
+ if importInfo := c.analysis.Imports[importAlias]; importInfo != nil {
214
+ if importInfo.importPath == pkgPath {
215
+ return importAlias
216
+ }
217
+ }
218
+ }
219
+
220
+ // Fallback: try to match by package name extracted from path
221
+ parts := strings.Split(pkgPath, "/")
222
+ defaultPkgName := parts[len(parts)-1]
223
+
224
+ for importAlias := range c.analysis.Imports {
225
+ if importAlias == defaultPkgName {
226
+ return importAlias
227
+ }
228
+ }
229
+
230
+ return ""
231
+ }
232
+
233
+ // writeAutoWrappedArgument writes an argument, auto-wrapping it if needed based on the expected parameter type
234
+ func (c *GoToTSCompiler) writeAutoWrappedArgument(arg ast.Expr, expectedType types.Type) error {
235
+ // For wrapper types (now type aliases), no auto-wrapping is needed
236
+ // Just use type casting if the types don't match exactly
237
+ if c.analysis.IsNamedBasicType(expectedType) {
238
+ argType := c.pkg.TypesInfo.TypeOf(arg)
239
+
240
+ // Only add type casting if needed
241
+ if argType != nil && !types.Identical(argType, expectedType) {
242
+ c.tsw.WriteLiterally("(")
243
+ if err := c.WriteValueExpr(arg); err != nil {
244
+ return fmt.Errorf("failed to write argument for wrapper type cast: %w", err)
245
+ }
246
+ c.tsw.WriteLiterally(" as ")
247
+ c.WriteGoType(expectedType, GoTypeContextGeneral)
248
+ c.tsw.WriteLiterally(")")
249
+ } else {
250
+ // Types match, just write the argument directly
251
+ if err := c.WriteValueExpr(arg); err != nil {
252
+ return fmt.Errorf("failed to write argument: %w", err)
253
+ }
254
+ }
255
+ return nil
256
+ }
257
+
258
+ // For non-wrapper types, normal argument writing
259
+ if err := c.WriteValueExpr(arg); err != nil {
260
+ return fmt.Errorf("failed to write argument: %w", err)
261
+ }
148
262
  return nil
149
263
  }
264
+
265
+ // writeWrapperTypeMethodCall handles method calls on wrapper types by converting them to function calls
266
+ // obj.Method(args) -> TypeName_Method(obj, args)
267
+ func (c *GoToTSCompiler) writeWrapperTypeMethodCall(exp *ast.CallExpr, selectorExpr *ast.SelectorExpr) (handled bool, err error) {
268
+ // Get the type of the base expression (the receiver)
269
+ baseType := c.pkg.TypesInfo.TypeOf(selectorExpr.X)
270
+ if baseType == nil {
271
+ return false, nil
272
+ }
273
+
274
+ // Check if this is a wrapper type using the analysis
275
+ isWrapperType := c.analysis.IsNamedBasicType(baseType)
276
+
277
+ // Special handling for type aliases to basic types that might have wrapper functions
278
+ // Even if IsNamedBasicType returns false, we should check for known wrapper type patterns
279
+ var typeName string
280
+ if !isWrapperType {
281
+ // Check if this is a type alias to a basic type that might have wrapper methods
282
+ if aliasType, ok := baseType.(*types.Alias); ok {
283
+ if aliasType.Obj() != nil && aliasType.Obj().Pkg() != nil {
284
+ // Check if the underlying type is a basic type
285
+ underlying := aliasType.Underlying()
286
+ if _, isBasic := underlying.(*types.Basic); isBasic {
287
+ // This is a type alias to a basic type - treat it as a potential wrapper type
288
+ isWrapperType = true
289
+ if aliasType.Obj().Pkg() != c.pkg.Types {
290
+ // Imported type alias like os.FileMode
291
+ if importAlias := c.getImportAlias(aliasType.Obj().Pkg().Path()); importAlias != "" {
292
+ typeName = importAlias + "." + aliasType.Obj().Name()
293
+ } else {
294
+ typeName = aliasType.Obj().Name()
295
+ }
296
+ } else {
297
+ // Local type alias
298
+ typeName = aliasType.Obj().Name()
299
+ }
300
+ }
301
+ }
302
+ }
303
+ }
304
+
305
+ if !isWrapperType {
306
+ return false, nil
307
+ }
308
+
309
+ // Get the type name for the function call if not already set
310
+ if typeName == "" {
311
+ if namedType, ok := baseType.(*types.Named); ok {
312
+ if obj := namedType.Obj(); obj != nil {
313
+ if obj.Pkg() != nil && obj.Pkg() != c.pkg.Types {
314
+ // Imported type like os.FileMode
315
+ if importAlias := c.getImportAlias(obj.Pkg().Path()); importAlias != "" {
316
+ typeName = importAlias + "." + obj.Name()
317
+ } else {
318
+ typeName = obj.Name()
319
+ }
320
+ } else {
321
+ // Local type
322
+ typeName = obj.Name()
323
+ }
324
+ }
325
+ } else if aliasType, ok := baseType.(*types.Alias); ok {
326
+ if obj := aliasType.Obj(); obj != nil {
327
+ if obj.Pkg() != nil && obj.Pkg() != c.pkg.Types {
328
+ // Imported type alias
329
+ if importAlias := c.getImportAlias(obj.Pkg().Path()); importAlias != "" {
330
+ typeName = importAlias + "." + obj.Name()
331
+ } else {
332
+ typeName = obj.Name()
333
+ }
334
+ } else {
335
+ // Local type alias
336
+ typeName = obj.Name()
337
+ }
338
+ }
339
+ }
340
+ }
341
+
342
+ if typeName == "" {
343
+ return false, nil
344
+ }
345
+
346
+ // Write the function call: TypeName_MethodName(receiver, args...)
347
+ c.tsw.WriteLiterally(typeName)
348
+ c.tsw.WriteLiterally("_")
349
+ c.tsw.WriteLiterally(selectorExpr.Sel.Name)
350
+ c.tsw.WriteLiterally("(")
351
+
352
+ // First argument is the receiver
353
+ if err := c.WriteValueExpr(selectorExpr.X); err != nil {
354
+ return true, fmt.Errorf("failed to write wrapper type method receiver: %w", err)
355
+ }
356
+
357
+ // Add other arguments
358
+ if len(exp.Args) > 0 {
359
+ c.tsw.WriteLiterally(", ")
360
+ for i, arg := range exp.Args {
361
+ if i != 0 {
362
+ c.tsw.WriteLiterally(", ")
363
+ }
364
+ if err := c.WriteValueExpr(arg); err != nil {
365
+ return true, fmt.Errorf("failed to write wrapper type method argument %d: %w", i, err)
366
+ }
367
+ }
368
+ }
369
+
370
+ c.tsw.WriteLiterally(")")
371
+ return true, nil
372
+ }