goscript 0.0.47 → 0.0.49

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 (152) hide show
  1. package/cmd/goscript/deps.go +1 -4
  2. package/compiler/analysis.go +224 -63
  3. package/compiler/analysis_test.go +112 -0
  4. package/compiler/compiler.go +19 -87
  5. package/compiler/expr-call-type-conversion.go +148 -59
  6. package/compiler/expr-call.go +202 -10
  7. package/compiler/expr.go +5 -82
  8. package/compiler/gs_dependencies_test.go +60 -1
  9. package/compiler/spec-value.go +73 -51
  10. package/compiler/spec.go +293 -151
  11. package/compiler/stmt.go +192 -81
  12. package/dist/gs/builtin/builtin.d.ts +1 -5
  13. package/dist/gs/builtin/builtin.js +1 -34
  14. package/dist/gs/builtin/builtin.js.map +1 -1
  15. package/dist/gs/builtin/slice.js.map +1 -1
  16. package/dist/gs/fmt/fmt.js +20 -4
  17. package/dist/gs/fmt/fmt.js.map +1 -1
  18. package/dist/gs/io/fs/fs.d.ts +6 -12
  19. package/dist/gs/io/fs/fs.js +52 -67
  20. package/dist/gs/io/fs/fs.js.map +1 -1
  21. package/dist/gs/os/index.d.ts +2 -1
  22. package/dist/gs/os/index.js +1 -1
  23. package/dist/gs/os/index.js.map +1 -1
  24. package/dist/gs/os/types_js.gs.d.ts +7 -1
  25. package/dist/gs/os/types_js.gs.js +16 -1
  26. package/dist/gs/os/types_js.gs.js.map +1 -1
  27. package/dist/gs/os/types_unix.gs.js +2 -2
  28. package/dist/gs/os/types_unix.gs.js.map +1 -1
  29. package/dist/gs/reflect/index.d.ts +3 -3
  30. package/dist/gs/reflect/index.js +2 -2
  31. package/dist/gs/reflect/index.js.map +1 -1
  32. package/dist/gs/reflect/map.js +2 -2
  33. package/dist/gs/reflect/map.js.map +1 -1
  34. package/dist/gs/reflect/type.d.ts +8 -9
  35. package/dist/gs/reflect/type.js +101 -103
  36. package/dist/gs/reflect/type.js.map +1 -1
  37. package/dist/gs/reflect/types.d.ts +1 -10
  38. package/dist/gs/reflect/types.js +3 -26
  39. package/dist/gs/reflect/types.js.map +1 -1
  40. package/dist/gs/reflect/value.js +23 -23
  41. package/dist/gs/reflect/value.js.map +1 -1
  42. package/dist/gs/reflect/visiblefields.js +3 -3
  43. package/dist/gs/reflect/visiblefields.js.map +1 -1
  44. package/dist/gs/time/time.d.ts +11 -22
  45. package/dist/gs/time/time.js +29 -57
  46. package/dist/gs/time/time.js.map +1 -1
  47. package/gs/TODO.md +129 -0
  48. package/gs/builtin/builtin.ts +3 -41
  49. package/gs/builtin/slice.ts +1 -1
  50. package/gs/bytes/meta.json +10 -0
  51. package/gs/fmt/fmt.ts +18 -4
  52. package/gs/fmt/meta.json +5 -0
  53. package/gs/internal/meta.json +5 -0
  54. package/gs/io/fs/fs.ts +58 -73
  55. package/gs/io/meta.json +9 -0
  56. package/gs/maps/meta.json +6 -0
  57. package/gs/math/meta.json +5 -0
  58. package/gs/os/index.ts +8 -1
  59. package/gs/os/meta.json +15 -0
  60. package/gs/os/types_js.gs.ts +22 -1
  61. package/gs/os/types_unix.gs.ts +2 -2
  62. package/gs/path/meta.json +6 -0
  63. package/gs/reflect/function-types.test.ts +10 -10
  64. package/gs/reflect/index.ts +6 -6
  65. package/gs/reflect/map.ts +2 -2
  66. package/gs/reflect/meta.json +5 -0
  67. package/gs/reflect/type.ts +108 -103
  68. package/gs/reflect/types.ts +2 -28
  69. package/gs/reflect/value.ts +23 -23
  70. package/gs/reflect/visiblefields.ts +3 -3
  71. package/gs/strconv/meta.json +5 -0
  72. package/gs/strings/meta.json +9 -0
  73. package/gs/sync/meta.json +19 -0
  74. package/gs/time/time.ts +32 -65
  75. package/package.json +1 -1
  76. package/dist/gs/builtin/io.d.ts +0 -16
  77. package/dist/gs/builtin/io.js +0 -15
  78. package/dist/gs/builtin/io.js.map +0 -1
  79. package/dist/gs/internal/testlog/index.d.ts +0 -1
  80. package/dist/gs/internal/testlog/index.js +0 -5
  81. package/dist/gs/internal/testlog/index.js.map +0 -1
  82. package/dist/gs/maps/iter.gs.d.ts +0 -7
  83. package/dist/gs/maps/iter.gs.js +0 -65
  84. package/dist/gs/maps/iter.gs.js.map +0 -1
  85. package/dist/gs/maps/maps.gs.d.ts +0 -7
  86. package/dist/gs/maps/maps.gs.js +0 -79
  87. package/dist/gs/maps/maps.gs.js.map +0 -1
  88. package/dist/gs/reflect/abi.d.ts +0 -59
  89. package/dist/gs/reflect/abi.gs.d.ts +0 -59
  90. package/dist/gs/reflect/abi.gs.js +0 -79
  91. package/dist/gs/reflect/abi.gs.js.map +0 -1
  92. package/dist/gs/reflect/abi.js +0 -79
  93. package/dist/gs/reflect/abi.js.map +0 -1
  94. package/dist/gs/reflect/badlinkname.d.ts +0 -52
  95. package/dist/gs/reflect/badlinkname.gs.d.ts +0 -52
  96. package/dist/gs/reflect/badlinkname.gs.js +0 -72
  97. package/dist/gs/reflect/badlinkname.gs.js.map +0 -1
  98. package/dist/gs/reflect/badlinkname.js +0 -72
  99. package/dist/gs/reflect/badlinkname.js.map +0 -1
  100. package/dist/gs/reflect/deepequal.gs.d.ts +0 -25
  101. package/dist/gs/reflect/deepequal.gs.js +0 -308
  102. package/dist/gs/reflect/deepequal.gs.js.map +0 -1
  103. package/dist/gs/reflect/float32reg_generic.gs.d.ts +0 -2
  104. package/dist/gs/reflect/float32reg_generic.gs.js +0 -10
  105. package/dist/gs/reflect/float32reg_generic.gs.js.map +0 -1
  106. package/dist/gs/reflect/index.gs.d.ts +0 -1
  107. package/dist/gs/reflect/index.gs.js +0 -3
  108. package/dist/gs/reflect/index.gs.js.map +0 -1
  109. package/dist/gs/reflect/iter.gs.d.ts +0 -3
  110. package/dist/gs/reflect/iter.gs.js +0 -24
  111. package/dist/gs/reflect/iter.gs.js.map +0 -1
  112. package/dist/gs/reflect/makefunc.gs.d.ts +0 -34
  113. package/dist/gs/reflect/makefunc.gs.js +0 -288
  114. package/dist/gs/reflect/makefunc.gs.js.map +0 -1
  115. package/dist/gs/reflect/map_swiss.gs.d.ts +0 -14
  116. package/dist/gs/reflect/map_swiss.gs.js +0 -70
  117. package/dist/gs/reflect/map_swiss.gs.js.map +0 -1
  118. package/dist/gs/reflect/reflect.gs.d.ts +0 -132
  119. package/dist/gs/reflect/reflect.gs.js +0 -437
  120. package/dist/gs/reflect/reflect.gs.js.map +0 -1
  121. package/dist/gs/reflect/swapper.gs.d.ts +0 -1
  122. package/dist/gs/reflect/swapper.gs.js +0 -32
  123. package/dist/gs/reflect/swapper.gs.js.map +0 -1
  124. package/dist/gs/reflect/type.gs.d.ts +0 -4
  125. package/dist/gs/reflect/type.gs.js +0 -21
  126. package/dist/gs/reflect/type.gs.js.map +0 -1
  127. package/dist/gs/reflect/value.gs.d.ts +0 -4
  128. package/dist/gs/reflect/value.gs.js +0 -12
  129. package/dist/gs/reflect/value.gs.js.map +0 -1
  130. package/dist/gs/reflect/visiblefields.gs.d.ts +0 -3
  131. package/dist/gs/reflect/visiblefields.gs.js +0 -123
  132. package/dist/gs/reflect/visiblefields.gs.js.map +0 -1
  133. package/dist/gs/stringslite/index.d.ts +0 -1
  134. package/dist/gs/stringslite/index.js +0 -2
  135. package/dist/gs/stringslite/index.js.map +0 -1
  136. package/dist/gs/stringslite/strings.d.ts +0 -11
  137. package/dist/gs/stringslite/strings.js +0 -67
  138. package/dist/gs/stringslite/strings.js.map +0 -1
  139. package/gs/bytes/metadata.go +0 -12
  140. package/gs/fmt/metadata.go +0 -7
  141. package/gs/internal/metadata.go +0 -7
  142. package/gs/io/io.go +0 -75
  143. package/gs/io/metadata.go +0 -11
  144. package/gs/maps/metadata.go +0 -8
  145. package/gs/math/metadata.go +0 -7
  146. package/gs/os/metadata.go +0 -17
  147. package/gs/path/metadata.go +0 -8
  148. package/gs/reflect/metadata.go +0 -7
  149. package/gs/strconv/metadata.go +0 -7
  150. package/gs/strings/metadata.go +0 -11
  151. package/gs/sync/metadata.go +0 -7
  152. 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.IsWrapperType(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.IsWrapperType(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,115 @@ 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.IsWrapperType(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
+ fmt.Printf("DEBUG: Type conversion constructor for %s\n", funIdent.String())
292
+
293
+ // Use auto-wrapping for the constructor argument
294
+ // The constructor parameter type is the underlying type of the named type
295
+ // For MyMode (which is type MyMode os.FileMode), the constructor expects os.FileMode
296
+ constructorParamType := typeName.Type()
297
+ if namedType, ok := typeName.Type().(*types.Named); ok {
298
+ // For named types, the constructor expects the underlying type
299
+ constructorParamType = namedType.Underlying()
300
+ }
301
+
302
+ fmt.Printf("DEBUG: Constructor param type: %v\n", constructorParamType)
303
+
304
+ if err := c.writeAutoWrappedArgument(exp.Args[0], constructorParamType); err != nil {
260
305
  return true, fmt.Errorf("failed to write argument for type constructor: %w", err)
261
306
  }
262
307
  c.tsw.WriteLiterally(")")
263
308
  return true, nil
264
309
  } 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)
310
+ // Determine if this type should use constructor syntax
311
+ shouldUseConstructor := false
312
+
313
+ // Check if it's a type alias (like os.FileMode)
314
+ if alias, isAlias := typeName.Type().(*types.Alias); isAlias {
315
+ // For type aliases, check the underlying type
316
+ if _, isInterface := alias.Underlying().(*types.Interface); !isInterface {
317
+ if _, isStruct := alias.Underlying().(*types.Struct); !isStruct {
318
+ // For non-struct, non-interface type aliases, use constructor
319
+ shouldUseConstructor = true
320
+ }
321
+ }
322
+ } else if namedType, isNamed := typeName.Type().(*types.Named); isNamed {
323
+ // For named types, check if they have receiver methods in the current package
324
+ // or if they follow the pattern of non-struct, non-interface named types
325
+ if c.hasReceiverMethods(funIdent.String()) {
326
+ shouldUseConstructor = true
327
+ } else if _, isInterface := namedType.Underlying().(*types.Interface); !isInterface {
328
+ if _, isStruct := namedType.Underlying().(*types.Struct); !isStruct {
329
+ // For non-struct, non-interface named types, use constructor
330
+ shouldUseConstructor = true
331
+ }
332
+ }
269
333
  }
270
334
 
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
335
+ if shouldUseConstructor {
336
+ // For types that should use constructors, use class constructor
337
+ c.tsw.WriteLiterally("new ")
338
+ c.tsw.WriteLiterally(funIdent.String())
339
+ c.tsw.WriteLiterally("(")
340
+ if err := c.WriteValueExpr(exp.Args[0]); err != nil {
341
+ return true, fmt.Errorf("failed to write argument for type constructor: %w", err)
342
+ }
343
+ c.tsw.WriteLiterally(")")
344
+ return true, nil
345
+ } else {
346
+ // For types that don't need constructors, use the TypeScript "as" operator
347
+ c.tsw.WriteLiterally("(")
348
+ if err := c.WriteValueExpr(exp.Args[0]); err != nil {
349
+ return true, fmt.Errorf("failed to write argument for type cast: %w", err)
350
+ }
351
+
352
+ // Then use the TypeScript "as" operator with the mapped type name
353
+ c.tsw.WriteLiterally(" as ")
354
+ c.WriteGoType(typeName.Type(), GoTypeContextGeneral)
355
+ c.tsw.WriteLiterally(")")
356
+ return true, nil
357
+ }
276
358
  }
277
359
  }
278
360
  }
@@ -293,17 +375,15 @@ func (c *GoToTSCompiler) writeIntConversion(exp *ast.CallExpr) error {
293
375
  // Check if we're converting FROM a type with receiver methods TO int
294
376
  if argType := c.pkg.TypesInfo.TypeOf(arg); argType != nil {
295
377
  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) {
378
+ // Check if the argument type is a wrapper type
379
+ if c.analysis.IsWrapperType(namedArgType) {
299
380
  // Check if we're converting to int (the underlying type)
300
381
  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()
382
+ // This is a conversion from a wrapper type to int
383
+ // Since wrapper types are now type aliases, just write the value directly
303
384
  if err := c.WriteValueExpr(arg); err != nil {
304
- return fmt.Errorf("failed to write argument for valueOf conversion: %w", err)
385
+ return fmt.Errorf("failed to write argument for int conversion: %w", err)
305
386
  }
306
- c.tsw.WriteLiterally(".valueOf()")
307
387
  return nil
308
388
  }
309
389
  }
@@ -332,19 +412,17 @@ func (c *GoToTSCompiler) writeQualifiedTypeConversion(exp *ast.CallExpr, selecto
332
412
  // Check if we're converting FROM a type with receiver methods TO its underlying type
333
413
  if argType := c.pkg.TypesInfo.TypeOf(arg); argType != nil {
334
414
  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) {
415
+ // Check if the argument type is a wrapper type
416
+ if c.analysis.IsWrapperType(namedArgType) {
338
417
  // Check if we're converting to the underlying type
339
418
  targetType := typeName.Type()
340
419
  underlyingType := namedArgType.Underlying()
341
420
  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
421
+ // This is a conversion from a wrapper type to its underlying type
422
+ // Since wrapper types are now type aliases, just write the value directly
344
423
  if err := c.WriteValueExpr(arg); err != nil {
345
- return true, fmt.Errorf("failed to write argument for valueOf conversion: %w", err)
424
+ return true, fmt.Errorf("failed to write argument for type conversion: %w", err)
346
425
  }
347
- c.tsw.WriteLiterally(".valueOf()")
348
426
  return true, nil
349
427
  }
350
428
  }
@@ -365,33 +443,44 @@ func (c *GoToTSCompiler) writeQualifiedTypeConversion(exp *ast.CallExpr, selecto
365
443
  c.tsw.WriteLiterallyf(", { __goTypeName: '%s' })", selectorExpr.Sel.Name)
366
444
  return true, nil
367
445
  } 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
- }
446
+ // Check if this is a wrapper type
447
+ isWrapperType := c.analysis.IsWrapperType(typeName.Type())
448
+ if isWrapperType {
449
+ // For wrapper types, use type casting instead of constructor calls
450
+ c.tsw.WriteLiterally("(")
451
+ if err := c.WriteValueExpr(exp.Args[0]); err != nil {
452
+ return true, fmt.Errorf("failed to write argument for wrapper type cast: %w", err)
379
453
  }
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 {
454
+ c.tsw.WriteLiterally(" as ")
455
+ c.WriteGoType(typeName.Type(), GoTypeContextGeneral)
456
+ c.tsw.WriteLiterally(")")
457
+ return true, nil
458
+ }
459
+
460
+ // Check if this is a simple named type (no methods, not struct, not interface)
461
+ if namedType, ok := typeName.Type().(*types.Named); ok {
462
+ // Don't use constructors for simple named types without methods
463
+ if namedType.NumMethods() == 0 {
464
+ // Exclude struct and interface types - they should still use constructors
386
465
  if _, isStruct := namedType.Underlying().(*types.Struct); !isStruct {
387
- // For non-struct, non-interface named types, use constructor
388
- shouldUseConstructor = true
466
+ if _, isInterface := namedType.Underlying().(*types.Interface); !isInterface {
467
+ // Simple named type without methods - use type casting
468
+ c.tsw.WriteLiterally("(")
469
+ if err := c.WriteValueExpr(exp.Args[0]); err != nil {
470
+ return true, fmt.Errorf("failed to write argument for simple named type cast: %w", err)
471
+ }
472
+ c.tsw.WriteLiterally(" as ")
473
+ c.WriteGoType(typeName.Type(), GoTypeContextGeneral)
474
+ c.tsw.WriteLiterally(")")
475
+ return true, nil
476
+ }
389
477
  }
390
478
  }
391
479
  }
392
480
 
393
- if shouldUseConstructor {
394
- // For types that should use constructors, use class constructor
481
+ // Check if this type has receiver methods
482
+ if c.hasReceiverMethods(selectorExpr.Sel.Name) {
483
+ // For types with methods that are NOT wrapper types, still use class constructor
395
484
  c.tsw.WriteLiterally("new ")
396
485
  if err := c.WriteSelectorExpr(selectorExpr); err != nil {
397
486
  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`)
@@ -89,6 +90,11 @@ 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.)
@@ -123,27 +129,213 @@ 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.IsWrapperType(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
+ }
148
202
  return nil
149
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.IsWrapperType(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
+ }
262
+ return nil
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
275
+ if !c.analysis.IsWrapperType(baseType) {
276
+ return false, nil
277
+ }
278
+
279
+ // Get the type name for the function call
280
+ var typeName string
281
+ if namedType, ok := baseType.(*types.Named); ok {
282
+ if obj := namedType.Obj(); obj != nil {
283
+ if obj.Pkg() != nil && obj.Pkg() != c.pkg.Types {
284
+ // Imported type like os.FileMode
285
+ if importAlias := c.getImportAlias(obj.Pkg().Path()); importAlias != "" {
286
+ typeName = importAlias + "." + obj.Name()
287
+ } else {
288
+ typeName = obj.Name()
289
+ }
290
+ } else {
291
+ // Local type
292
+ typeName = obj.Name()
293
+ }
294
+ }
295
+ } else if aliasType, ok := baseType.(*types.Alias); ok {
296
+ if obj := aliasType.Obj(); obj != nil {
297
+ if obj.Pkg() != nil && obj.Pkg() != c.pkg.Types {
298
+ // Imported type alias
299
+ if importAlias := c.getImportAlias(obj.Pkg().Path()); importAlias != "" {
300
+ typeName = importAlias + "." + obj.Name()
301
+ } else {
302
+ typeName = obj.Name()
303
+ }
304
+ } else {
305
+ // Local type alias
306
+ typeName = obj.Name()
307
+ }
308
+ }
309
+ }
310
+
311
+ if typeName == "" {
312
+ return false, nil
313
+ }
314
+
315
+ // Write the function call: TypeName_MethodName(receiver, args...)
316
+ c.tsw.WriteLiterally(typeName)
317
+ c.tsw.WriteLiterally("_")
318
+ c.tsw.WriteLiterally(selectorExpr.Sel.Name)
319
+ c.tsw.WriteLiterally("(")
320
+
321
+ // First argument is the receiver
322
+ if err := c.WriteValueExpr(selectorExpr.X); err != nil {
323
+ return true, fmt.Errorf("failed to write wrapper type method receiver: %w", err)
324
+ }
325
+
326
+ // Add other arguments
327
+ if len(exp.Args) > 0 {
328
+ c.tsw.WriteLiterally(", ")
329
+ for i, arg := range exp.Args {
330
+ if i != 0 {
331
+ c.tsw.WriteLiterally(", ")
332
+ }
333
+ if err := c.WriteValueExpr(arg); err != nil {
334
+ return true, fmt.Errorf("failed to write wrapper type method argument %d: %w", i, err)
335
+ }
336
+ }
337
+ }
338
+
339
+ c.tsw.WriteLiterally(")")
340
+ return true, nil
341
+ }
package/compiler/expr.go CHANGED
@@ -294,70 +294,6 @@ func (c *GoToTSCompiler) isNamedNumericType(t types.Type) bool {
294
294
  return false
295
295
  }
296
296
 
297
- // isWrapperType checks if a type is implemented as a wrapper class with valueOf() method
298
- // This is true for named types that have methods defined on them
299
- func (c *GoToTSCompiler) isWrapperType(t types.Type) bool {
300
- if t == nil {
301
- return false
302
- }
303
-
304
- // Follow any type aliases to get to the actual named type
305
- namedType, ok := t.(*types.Named)
306
- if !ok {
307
- return false
308
- }
309
-
310
- // If the named type has methods, it's implemented as a class with valueOf()
311
- numMethods := namedType.NumMethods()
312
- return numMethods > 0
313
- }
314
-
315
- // needsValueOfForBitwiseOp checks if an operand in a bitwise operation needs .valueOf() to be called
316
- // This is needed for custom types (like FileMode) that have a valueOf() method and need to be treated as numbers
317
- func (c *GoToTSCompiler) needsValueOfForBitwiseOp(expr ast.Expr) bool {
318
- if c.pkg == nil || c.pkg.TypesInfo == nil {
319
- return false
320
- }
321
-
322
- exprType := c.pkg.TypesInfo.TypeOf(expr)
323
- if exprType == nil {
324
- return false
325
- }
326
-
327
- // Don't add valueOf() for basic literals (numeric, string, bool literals)
328
- switch expr.(type) {
329
- case *ast.BasicLit:
330
- return false
331
- }
332
-
333
- // Check if this is a compile-time constant of a primitive type
334
- if tv, ok := c.pkg.TypesInfo.Types[expr]; ok {
335
- if tv.Value != nil {
336
- // This is a constant expression - but only skip valueOf() if it's truly a primitive type
337
- // (not a named type with methods that happens to be constant)
338
- if _, isBasic := exprType.(*types.Basic); isBasic {
339
- // Primitive constant, don't add valueOf()
340
- return false
341
- }
342
- }
343
- }
344
-
345
- // Check if this type is implemented as a wrapper class with valueOf()
346
- return c.isWrapperType(exprType)
347
- }
348
-
349
- // writeBitwiseOperand writes an operand for a bitwise operation, adding .valueOf() if needed
350
- func (c *GoToTSCompiler) writeBitwiseOperand(expr ast.Expr) error {
351
- if c.needsValueOfForBitwiseOp(expr) {
352
- if err := c.WriteValueExpr(expr); err != nil {
353
- return err
354
- }
355
- c.tsw.WriteLiterally(".valueOf()")
356
- return nil
357
- }
358
- return c.WriteValueExpr(expr)
359
- }
360
-
361
297
  // WriteBinaryExpr translates a Go binary expression (`ast.BinaryExpr`) into its
362
298
  // TypeScript equivalent.
363
299
  // It handles several cases:
@@ -542,16 +478,10 @@ func (c *GoToTSCompiler) WriteBinaryExpr(exp *ast.BinaryExpr) error {
542
478
  c.tsw.WriteLiterally("(") // Add opening parenthesis for bitwise operations
543
479
  }
544
480
 
545
- // For bitwise operations, use special operand writing that adds .valueOf() when needed
546
- if isBitwise {
547
- if err := c.writeBitwiseOperand(exp.X); err != nil {
548
- return fmt.Errorf("failed to write binary expression left operand: %w", err)
549
- }
550
- } else {
551
- if err := c.WriteValueExpr(exp.X); err != nil {
552
- return fmt.Errorf("failed to write binary expression left operand: %w", err)
553
- }
481
+ if err := c.WriteValueExpr(exp.X); err != nil {
482
+ return fmt.Errorf("failed to write binary expression left operand: %w", err)
554
483
  }
484
+
555
485
  c.tsw.WriteLiterally(" ")
556
486
  tokStr, ok := TokenToTs(exp.Op)
557
487
  if !ok {
@@ -561,15 +491,8 @@ func (c *GoToTSCompiler) WriteBinaryExpr(exp *ast.BinaryExpr) error {
561
491
  c.tsw.WriteLiterally(tokStr)
562
492
  c.tsw.WriteLiterally(" ")
563
493
 
564
- // For bitwise operations, use special operand writing that adds .valueOf() when needed
565
- if isBitwise {
566
- if err := c.writeBitwiseOperand(exp.Y); err != nil {
567
- return fmt.Errorf("failed to write binary expression right operand: %w", err)
568
- }
569
- } else {
570
- if err := c.WriteValueExpr(exp.Y); err != nil {
571
- return fmt.Errorf("failed to write binary expression right operand: %w", err)
572
- }
494
+ if err := c.WriteValueExpr(exp.Y); err != nil {
495
+ return fmt.Errorf("failed to write binary expression right operand: %w", err)
573
496
  }
574
497
 
575
498
  if isBitwise {