goscript 0.0.60 → 0.0.62

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 (87) hide show
  1. package/README.md +9 -0
  2. package/compiler/analysis.go +974 -369
  3. package/compiler/assignment.go +72 -0
  4. package/compiler/compiler.go +74 -15
  5. package/compiler/composite-lit.go +29 -8
  6. package/compiler/decl.go +67 -98
  7. package/compiler/expr-call-async.go +26 -1
  8. package/compiler/expr-call-builtins.go +60 -4
  9. package/compiler/expr-call-helpers.go +182 -0
  10. package/compiler/expr-call-type-conversion.go +37 -5
  11. package/compiler/expr-call.go +25 -33
  12. package/compiler/expr-selector.go +71 -1
  13. package/compiler/expr-type.go +49 -3
  14. package/compiler/expr.go +37 -28
  15. package/compiler/index.test.ts +3 -1
  16. package/compiler/lit.go +13 -4
  17. package/compiler/spec-struct.go +42 -9
  18. package/compiler/spec-value.go +2 -2
  19. package/compiler/spec.go +42 -5
  20. package/compiler/stmt-assign.go +71 -0
  21. package/compiler/stmt-range.go +2 -2
  22. package/compiler/stmt.go +130 -10
  23. package/compiler/type-utils.go +40 -16
  24. package/compiler/type.go +50 -12
  25. package/dist/gs/builtin/builtin.d.ts +8 -1
  26. package/dist/gs/builtin/builtin.js +26 -1
  27. package/dist/gs/builtin/builtin.js.map +1 -1
  28. package/dist/gs/builtin/errors.d.ts +1 -0
  29. package/dist/gs/builtin/errors.js +8 -0
  30. package/dist/gs/builtin/errors.js.map +1 -1
  31. package/dist/gs/builtin/slice.d.ts +5 -4
  32. package/dist/gs/builtin/slice.js +51 -21
  33. package/dist/gs/builtin/slice.js.map +1 -1
  34. package/dist/gs/builtin/type.d.ts +28 -2
  35. package/dist/gs/builtin/type.js +132 -0
  36. package/dist/gs/builtin/type.js.map +1 -1
  37. package/dist/gs/bytes/reader.gs.d.ts +1 -1
  38. package/dist/gs/bytes/reader.gs.js +1 -1
  39. package/dist/gs/bytes/reader.gs.js.map +1 -1
  40. package/dist/gs/internal/byteorder/index.d.ts +6 -0
  41. package/dist/gs/internal/byteorder/index.js +34 -0
  42. package/dist/gs/internal/byteorder/index.js.map +1 -1
  43. package/dist/gs/reflect/index.d.ts +3 -3
  44. package/dist/gs/reflect/index.js +2 -2
  45. package/dist/gs/reflect/index.js.map +1 -1
  46. package/dist/gs/reflect/map.d.ts +3 -2
  47. package/dist/gs/reflect/map.js +37 -3
  48. package/dist/gs/reflect/map.js.map +1 -1
  49. package/dist/gs/reflect/type.d.ts +55 -8
  50. package/dist/gs/reflect/type.js +889 -23
  51. package/dist/gs/reflect/type.js.map +1 -1
  52. package/dist/gs/reflect/types.d.ts +11 -12
  53. package/dist/gs/reflect/types.js +26 -15
  54. package/dist/gs/reflect/types.js.map +1 -1
  55. package/dist/gs/reflect/value.d.ts +4 -4
  56. package/dist/gs/reflect/value.js +8 -2
  57. package/dist/gs/reflect/value.js.map +1 -1
  58. package/dist/gs/slices/slices.d.ts +32 -0
  59. package/dist/gs/slices/slices.js +81 -0
  60. package/dist/gs/slices/slices.js.map +1 -1
  61. package/dist/gs/sync/atomic/type.gs.d.ts +2 -2
  62. package/dist/gs/sync/atomic/type.gs.js +12 -2
  63. package/dist/gs/sync/atomic/type.gs.js.map +1 -1
  64. package/dist/gs/unicode/utf8/utf8.d.ts +2 -2
  65. package/dist/gs/unicode/utf8/utf8.js +10 -6
  66. package/dist/gs/unicode/utf8/utf8.js.map +1 -1
  67. package/go.mod +4 -4
  68. package/go.sum +8 -16
  69. package/gs/builtin/builtin.ts +27 -2
  70. package/gs/builtin/errors.ts +12 -0
  71. package/gs/builtin/slice.ts +77 -14
  72. package/gs/builtin/type.ts +167 -2
  73. package/gs/bytes/reader.gs.ts +2 -2
  74. package/gs/internal/byteorder/index.ts +40 -0
  75. package/gs/math/hypot.gs.test.ts +3 -1
  76. package/gs/math/pow10.gs.test.ts +5 -4
  77. package/gs/reflect/index.ts +6 -3
  78. package/gs/reflect/map.test.ts +7 -6
  79. package/gs/reflect/map.ts +49 -7
  80. package/gs/reflect/type.ts +1139 -43
  81. package/gs/reflect/types.ts +34 -21
  82. package/gs/reflect/value.ts +12 -6
  83. package/gs/slices/slices.ts +92 -0
  84. package/gs/sync/atomic/type.gs.ts +14 -5
  85. package/gs/sync/meta.json +1 -1
  86. package/gs/unicode/utf8/utf8.ts +12 -8
  87. package/package.json +13 -13
@@ -25,6 +25,9 @@ var builtinFunctions = map[string]bool{
25
25
  "recover": true,
26
26
  "print": true,
27
27
  "println": true,
28
+ "min": true,
29
+ "max": true,
30
+ "clear": true,
28
31
  }
29
32
 
30
33
  // writeBuiltinFunction handles built-in Go functions
@@ -34,7 +37,7 @@ func (c *GoToTSCompiler) writeBuiltinFunction(exp *ast.CallExpr, funName string)
34
37
  c.tsw.WriteLiterally("$.panic")
35
38
  return true, nil
36
39
  case "println":
37
- c.tsw.WriteLiterally("console.log")
40
+ c.tsw.WriteLiterally("$.println")
38
41
  return true, nil
39
42
  case "len":
40
43
  if len(exp.Args) != 1 {
@@ -89,6 +92,46 @@ func (c *GoToTSCompiler) writeBuiltinFunction(exp *ast.CallExpr, funName string)
89
92
  return true, nil
90
93
  case "append":
91
94
  return true, c.writeAppendCall(exp)
95
+ case "min":
96
+ if len(exp.Args) < 1 {
97
+ return true, errors.New("unhandled min call with no arguments")
98
+ }
99
+ c.tsw.WriteLiterally("Math.min(")
100
+ for i, arg := range exp.Args {
101
+ if i > 0 {
102
+ c.tsw.WriteLiterally(", ")
103
+ }
104
+ if err := c.WriteValueExpr(arg); err != nil {
105
+ return true, fmt.Errorf("failed to write argument %d in min call: %w", i, err)
106
+ }
107
+ }
108
+ c.tsw.WriteLiterally(")")
109
+ return true, nil
110
+ case "max":
111
+ if len(exp.Args) < 1 {
112
+ return true, errors.New("unhandled max call with no arguments")
113
+ }
114
+ c.tsw.WriteLiterally("Math.max(")
115
+ for i, arg := range exp.Args {
116
+ if i > 0 {
117
+ c.tsw.WriteLiterally(", ")
118
+ }
119
+ if err := c.WriteValueExpr(arg); err != nil {
120
+ return true, fmt.Errorf("failed to write argument %d in max call: %w", i, err)
121
+ }
122
+ }
123
+ c.tsw.WriteLiterally(")")
124
+ return true, nil
125
+ case "clear":
126
+ if len(exp.Args) != 1 {
127
+ return true, errors.Errorf("unhandled clear call with incorrect number of arguments: %d != 1", len(exp.Args))
128
+ }
129
+ c.tsw.WriteLiterally("$.clear(")
130
+ if err := c.WriteValueExpr(exp.Args[0]); err != nil {
131
+ return true, fmt.Errorf("failed to write argument in clear call: %w", err)
132
+ }
133
+ c.tsw.WriteLiterally(")")
134
+ return true, nil
92
135
  case "byte":
93
136
  if len(exp.Args) != 1 {
94
137
  return true, errors.Errorf("unhandled byte call with incorrect number of arguments: %d != 1", len(exp.Args))
@@ -119,13 +162,16 @@ func (c *GoToTSCompiler) writeAppendCall(exp *ast.CallExpr) error {
119
162
  }
120
163
 
121
164
  // The remaining arguments are the elements to append
122
- for i, arg := range exp.Args[1:] {
165
+ elemsToAppend := exp.Args[1:]
166
+ for i, arg := range elemsToAppend {
123
167
  if i > 0 || len(exp.Args) > 1 {
124
168
  c.tsw.WriteLiterally(", ")
125
169
  }
126
170
 
127
- // Special case: append([]byte, string...) should convert string to bytes
128
- if exp.Ellipsis != token.NoPos && i == 0 { // This is the first element after slice and has ellipsis
171
+ // Handle ellipsis (spread) for the last argument: append(slice, elems...)
172
+ // The ellipsis can only appear on the last argument, so check if this is the last element
173
+ isLastElement := i == len(elemsToAppend)-1
174
+ if exp.Ellipsis != token.NoPos && isLastElement {
129
175
  // Check if the slice is []byte and the argument is a string
130
176
  sliceType := c.pkg.TypesInfo.TypeOf(exp.Args[0])
131
177
  argType := c.pkg.TypesInfo.TypeOf(arg)
@@ -141,6 +187,16 @@ func (c *GoToTSCompiler) writeAppendCall(exp *ast.CallExpr) error {
141
187
  continue
142
188
  }
143
189
  }
190
+
191
+ // For other slice types with ellipsis, use spread operator
192
+ // append(slice, anotherSlice...) -> $.append(slice, ...(anotherSlice || []))
193
+ // The || [] handles the case where anotherSlice is null (nil in Go)
194
+ c.tsw.WriteLiterally("...(")
195
+ if err := c.WriteValueExpr(arg); err != nil {
196
+ return fmt.Errorf("failed to write spread argument in append call: %w", err)
197
+ }
198
+ c.tsw.WriteLiterally(" || [])")
199
+ continue
144
200
  }
145
201
 
146
202
  if err := c.WriteValueExpr(arg); err != nil {
@@ -108,3 +108,185 @@ func (c *GoToTSCompiler) writeExprOrDefault(expr interface{}, defaultValue strin
108
108
  return errors.Errorf("unsupported expression type in writeExprOrDefault: %T", e)
109
109
  }
110
110
  }
111
+
112
+ // writeReflectTypeFor handles reflect.TypeFor[T]() calls by generating appropriate TypeScript
113
+ func (c *GoToTSCompiler) writeReflectTypeFor(exp *ast.CallExpr, selectorExpr *ast.SelectorExpr) (handled bool, err error) {
114
+ // Check if this is reflect.TypeFor
115
+ if selectorExpr.Sel.Name != "TypeFor" {
116
+ return false, nil
117
+ }
118
+
119
+ // Check if X is an identifier referring to the reflect package
120
+ xIdent, ok := selectorExpr.X.(*ast.Ident)
121
+ if !ok {
122
+ return false, nil
123
+ }
124
+
125
+ obj := c.objectOfIdent(xIdent)
126
+ if obj == nil {
127
+ return false, nil
128
+ }
129
+
130
+ pkgName, ok := obj.(*types.PkgName)
131
+ if !ok || pkgName.Imported().Path() != "reflect" {
132
+ return false, nil
133
+ }
134
+
135
+ // DEBUG: We found reflect.TypeFor
136
+ // fmt.Printf("DEBUG: Found reflect.TypeFor call\n")
137
+
138
+ // This is reflect.TypeFor - now get the type argument
139
+ if c.pkg.TypesInfo.Instances == nil {
140
+ return false, errors.New("reflect.TypeFor called but no type instances available")
141
+ }
142
+
143
+ instance, hasInstance := c.pkg.TypesInfo.Instances[selectorExpr.Sel]
144
+ if !hasInstance || instance.TypeArgs == nil || instance.TypeArgs.Len() == 0 {
145
+ return false, errors.New("reflect.TypeFor called without type arguments")
146
+ }
147
+
148
+ // Get the first type argument
149
+ typeArg := instance.TypeArgs.At(0)
150
+ // fmt.Printf("DEBUG: Type argument: %v\n", typeArg)
151
+
152
+ // Generate TypeScript code to create a Type for this type
153
+ if err := c.writeTypeForTypeArg(typeArg); err != nil {
154
+ return true, err
155
+ }
156
+
157
+ return true, nil
158
+ }
159
+
160
+ // writeTypeForTypeArg generates TypeScript code to create a reflect.Type for the given Go type
161
+ func (c *GoToTSCompiler) writeTypeForTypeArg(t types.Type) error {
162
+ // Handle basic types
163
+ switch underlying := t.Underlying().(type) {
164
+ case *types.Basic:
165
+ return c.writeBasicTypeFor(underlying)
166
+ case *types.Named:
167
+ // For named types, use TypeOf with a zero value
168
+ return c.writeNamedTypeFor(t)
169
+ case *types.Pointer:
170
+ // For pointer types, use PointerTo
171
+ c.tsw.WriteLiterally("reflect.PointerTo(")
172
+ if err := c.writeTypeForTypeArg(underlying.Elem()); err != nil {
173
+ return err
174
+ }
175
+ c.tsw.WriteLiterally(")")
176
+ return nil
177
+ case *types.Slice:
178
+ // For slice types, use TypeOf with an empty slice
179
+ c.tsw.WriteLiterally("reflect.TypeOf([])")
180
+ return nil
181
+ case *types.Array:
182
+ // For array types, use TypeOf with an empty array
183
+ c.tsw.WriteLiterally("reflect.TypeOf([])")
184
+ return nil
185
+ case *types.Struct:
186
+ // For struct types, use TypeOf with zero value
187
+ return c.writeNamedTypeFor(t)
188
+ case *types.Interface:
189
+ // For interface types, use TypeOf with null
190
+ return c.writeNamedTypeFor(t)
191
+ default:
192
+ return errors.Errorf("unsupported type for reflect.TypeFor: %T", underlying)
193
+ }
194
+ }
195
+
196
+ // writeBasicTypeFor generates code for basic types
197
+ func (c *GoToTSCompiler) writeBasicTypeFor(basic *types.Basic) error {
198
+ // Map basic types to their reflect constructors or TypeOf calls
199
+ // Note: We don't pass type parameters to TypeOf - it infers from the value
200
+ switch basic.Kind() {
201
+ case types.Bool:
202
+ c.tsw.WriteLiterally("reflect.TypeOf(false)")
203
+ case types.Int:
204
+ c.tsw.WriteLiterally("reflect.TypeOf(0)")
205
+ case types.Int8:
206
+ c.tsw.WriteLiterally("reflect.TypeOf(0)")
207
+ case types.Int16:
208
+ c.tsw.WriteLiterally("reflect.TypeOf(0)")
209
+ case types.Int32:
210
+ c.tsw.WriteLiterally("reflect.TypeOf(0)")
211
+ case types.Int64:
212
+ c.tsw.WriteLiterally("reflect.TypeOf(0n)")
213
+ case types.Uint:
214
+ c.tsw.WriteLiterally("reflect.TypeOf(0)")
215
+ case types.Uint8:
216
+ c.tsw.WriteLiterally("reflect.TypeOf(0)")
217
+ case types.Uint16:
218
+ c.tsw.WriteLiterally("reflect.TypeOf(0)")
219
+ case types.Uint32:
220
+ c.tsw.WriteLiterally("reflect.TypeOf(0)")
221
+ case types.Uint64:
222
+ c.tsw.WriteLiterally("reflect.TypeOf(0n)")
223
+ case types.Uintptr:
224
+ c.tsw.WriteLiterally("reflect.TypeOf(0)")
225
+ case types.Float32:
226
+ c.tsw.WriteLiterally("reflect.TypeOf(0)")
227
+ case types.Float64:
228
+ c.tsw.WriteLiterally("reflect.TypeOf(0)")
229
+ case types.Complex64:
230
+ c.tsw.WriteLiterally("reflect.TypeOf([0, 0])")
231
+ case types.Complex128:
232
+ c.tsw.WriteLiterally("reflect.TypeOf([0, 0])")
233
+ case types.String:
234
+ c.tsw.WriteLiterally("reflect.TypeOf(\"\")")
235
+ case types.UnsafePointer:
236
+ c.tsw.WriteLiterally("reflect.TypeOf(null)")
237
+ default:
238
+ return errors.Errorf("unsupported basic type for reflect.TypeFor: %v", basic)
239
+ }
240
+ return nil
241
+ }
242
+
243
+ // writeNamedTypeFor generates code for named types (structs, interfaces, etc.)
244
+ func (c *GoToTSCompiler) writeNamedTypeFor(t types.Type) error {
245
+ // For interface types, we need special handling since null doesn't carry type info
246
+ if _, ok := t.Underlying().(*types.Interface); ok {
247
+ if named, ok := t.(*types.Named); ok {
248
+ obj := named.Obj()
249
+ pkgPath := ""
250
+ if pkg := obj.Pkg(); pkg != nil {
251
+ if pkg.Name() == "main" {
252
+ pkgPath = "main."
253
+ } else if pkg.Path() != "" {
254
+ pkgPath = pkg.Path() + "."
255
+ }
256
+ }
257
+ typeName := pkgPath + obj.Name()
258
+ c.tsw.WriteLiterally("reflect.getInterfaceTypeByName(\"" + typeName + "\")")
259
+ return nil
260
+ }
261
+ // For anonymous interfaces, use TypeOf(null)
262
+ c.tsw.WriteLiterally("reflect.TypeOf(null)")
263
+ return nil
264
+ }
265
+
266
+ // For named types, we need to create a zero value and call TypeOf
267
+ // Note: We don't pass a type parameter to TypeOf - it infers the type from the value
268
+ c.tsw.WriteLiterally("reflect.TypeOf(")
269
+
270
+ // Generate a zero value for this type
271
+ switch underlying := t.Underlying().(type) {
272
+ case *types.Struct:
273
+ // For struct types: new MyStruct()
274
+ // Check if this is a named type
275
+ if _, ok := t.(*types.Named); ok {
276
+ c.tsw.WriteLiterally("new ")
277
+ c.WriteGoType(t, GoTypeContextGeneral)
278
+ c.tsw.WriteLiterally("()")
279
+ } else {
280
+ // Anonymous struct
281
+ c.tsw.WriteLiterally("{}")
282
+ }
283
+ case *types.Basic:
284
+ // For basic types wrapped in named types
285
+ return c.writeBasicTypeFor(underlying)
286
+ default:
287
+ return errors.Errorf("unsupported named type underlying for reflect.TypeFor: %T", underlying)
288
+ }
289
+
290
+ c.tsw.WriteLiterally(")")
291
+ return nil
292
+ }
@@ -18,14 +18,33 @@ func (c *GoToTSCompiler) writeNilConversion(exp *ast.CallExpr) (handled bool, er
18
18
  return false, nil
19
19
  }
20
20
 
21
- // Handle nil pointer to struct type conversions: (*struct{})(nil)
22
- if starExpr, isStarExpr := exp.Fun.(*ast.StarExpr); isStarExpr {
23
- if _, isStructType := starExpr.X.(*ast.StructType); isStructType {
24
- c.tsw.WriteLiterally("null")
21
+ // Check if this is actually a type conversion, not a method/function call
22
+ // For type conversions, exp.Fun is a type expression (IsType() is true)
23
+ // For method calls like s.ptr.Swap(nil), exp.Fun is a selector expression (IsType() is false)
24
+ if tv, ok := c.pkg.TypesInfo.Types[exp.Fun]; !ok || !tv.IsType() {
25
+ // This is not a type conversion, let the normal call handling proceed
26
+ return false, nil
27
+ }
28
+
29
+ // Get the type being converted to
30
+ if typ := c.pkg.TypesInfo.TypeOf(exp.Fun); typ != nil {
31
+ // For pointer types, create a typed nil that preserves type information
32
+ if ptrType, ok := typ.(*types.Pointer); ok {
33
+ // Use a qualifier that returns the package name for local types
34
+ // This matches Go's reflect output format (e.g., "main.Stringer")
35
+ qualifier := func(pkg *types.Package) string {
36
+ if pkg == nil {
37
+ return ""
38
+ }
39
+ return pkg.Name()
40
+ }
41
+ typeName := types.TypeString(ptrType, qualifier)
42
+ c.tsw.WriteLiterallyf("$.typedNil(%q)", typeName)
25
43
  return true, nil
26
44
  }
27
45
  }
28
46
 
47
+ // For non-pointer types (or if type info is unavailable), use plain null
29
48
  c.tsw.WriteLiterally("null")
30
49
  return true, nil
31
50
  }
@@ -141,8 +160,21 @@ func (c *GoToTSCompiler) writeStringConversion(exp *ast.CallExpr) error {
141
160
 
142
161
  // Handle direct string(int32) conversion
143
162
  if tv, ok := c.pkg.TypesInfo.Types[arg]; ok {
144
- // Case 3a: Argument is already a string - no-op
163
+ // Case 3a: Argument is already a string - no-op (unless it's a named type with toString)
145
164
  if c.isStringType(tv.Type) {
165
+ // Check if this is a named type from the reflect package (like StructTag)
166
+ // which is implemented as a class in TypeScript with a toString() method
167
+ if namedType, isNamed := tv.Type.(*types.Named); isNamed {
168
+ obj := namedType.Obj()
169
+ if obj != nil && obj.Pkg() != nil && obj.Pkg().Path() == "reflect" && obj.Name() == "StructTag" {
170
+ // Call toString() for reflect.StructTag
171
+ if err := c.WriteValueExpr(arg); err != nil {
172
+ return fmt.Errorf("failed to write argument for string(reflect.StructTag) conversion: %w", err)
173
+ }
174
+ c.tsw.WriteLiterally(".toString()")
175
+ return nil
176
+ }
177
+ }
146
178
  // Translate string(stringValue) to stringValue (no-op)
147
179
  if err := c.WriteValueExpr(arg); err != nil {
148
180
  return fmt.Errorf("failed to write argument for string(string) no-op conversion: %w", err)
@@ -5,7 +5,6 @@ import (
5
5
  "go/ast"
6
6
  "go/token"
7
7
  "go/types"
8
- "strings"
9
8
  )
10
9
 
11
10
  // WriteCallExpr translates a Go function call expression (`ast.CallExpr`)
@@ -62,7 +61,8 @@ func (c *GoToTSCompiler) WriteCallExpr(exp *ast.CallExpr) error {
62
61
  // For built-ins that don't return early, write the arguments
63
62
  if funIdent.String() != "new" && funIdent.String() != "close" && funIdent.String() != "make" &&
64
63
  funIdent.String() != "string" && funIdent.String() != "append" && funIdent.String() != "byte" &&
65
- funIdent.String() != "int" {
64
+ funIdent.String() != "int" && funIdent.String() != "min" && funIdent.String() != "max" &&
65
+ funIdent.String() != "clear" {
66
66
  return c.writeCallArguments(exp)
67
67
  }
68
68
  return nil
@@ -97,6 +97,15 @@ func (c *GoToTSCompiler) WriteCallExpr(exp *ast.CallExpr) error {
97
97
  }
98
98
  }
99
99
 
100
+ // Handle reflect.TypeFor[T]() - Fun is IndexExpr where X is SelectorExpr
101
+ if indexExpr, ok := expFun.(*ast.IndexExpr); ok {
102
+ if selectorExpr, ok := indexExpr.X.(*ast.SelectorExpr); ok {
103
+ if handled, err := c.writeReflectTypeFor(exp, selectorExpr); handled {
104
+ return err
105
+ }
106
+ }
107
+ }
108
+
100
109
  // Handle non-identifier function expressions (method calls, function literals, etc.)
101
110
  // Check if this is an async method call (e.g., mu.Lock())
102
111
  c.writeAsyncCallIfNeeded(exp)
@@ -109,14 +118,26 @@ func (c *GoToTSCompiler) WriteCallExpr(exp *ast.CallExpr) error {
109
118
  }
110
119
  c.tsw.WriteLiterally(")")
111
120
  } else {
121
+ // Check if this is a function call that returns a function (e.g., simpleIterator(m)())
122
+ // and if the inner call is async, wrap it in parentheses
123
+ innerCallExpr, isCallExpr := expFun.(*ast.CallExpr)
124
+ needsParens := isCallExpr && c.isCallExprAsync(innerCallExpr)
125
+
126
+ if needsParens {
127
+ c.tsw.WriteLiterally("(")
128
+ }
129
+
112
130
  // Not an identifier (e.g., method call on a value, function call result)
113
131
  if err := c.WriteValueExpr(expFun); err != nil {
114
132
  return fmt.Errorf("failed to write method expression in call: %w", err)
115
133
  }
116
134
 
117
- // Check if this is a function call that returns a function (e.g., simpleIterator(m)())
135
+ if needsParens {
136
+ c.tsw.WriteLiterally(")")
137
+ }
138
+
118
139
  // Add non-null assertion since the returned function could be null
119
- if _, isCallExpr := expFun.(*ast.CallExpr); isCallExpr {
140
+ if isCallExpr {
120
141
  c.tsw.WriteLiterally("!")
121
142
  } else {
122
143
  c.addNonNullAssertion(expFun)
@@ -246,35 +267,6 @@ func (c *GoToTSCompiler) getQualifiedTypeName(t types.Type) string {
246
267
  return obj.Name()
247
268
  }
248
269
 
249
- // getImportAlias returns the import alias for a given package path
250
- // Deprecated: use resolveImportAlias instead for better type safety
251
- func (c *GoToTSCompiler) getImportAlias(pkgPath string) string {
252
- if c.analysis == nil {
253
- return ""
254
- }
255
-
256
- // First try to find by exact package path
257
- for importAlias := range c.analysis.Imports {
258
- if importInfo := c.analysis.Imports[importAlias]; importInfo != nil {
259
- if importInfo.importPath == pkgPath {
260
- return importAlias
261
- }
262
- }
263
- }
264
-
265
- // Fallback: try to match by package name extracted from path
266
- parts := strings.Split(pkgPath, "/")
267
- defaultPkgName := parts[len(parts)-1]
268
-
269
- for importAlias := range c.analysis.Imports {
270
- if importAlias == defaultPkgName {
271
- return importAlias
272
- }
273
- }
274
-
275
- return ""
276
- }
277
-
278
270
  // writeAutoWrappedArgument writes an argument, auto-wrapping it if needed based on the expected parameter type
279
271
  func (c *GoToTSCompiler) writeAutoWrappedArgument(arg ast.Expr, expectedType types.Type) error {
280
272
  // For wrapper types (now type aliases), no auto-wrapping is needed
@@ -27,10 +27,18 @@ func (c *GoToTSCompiler) WriteSelectorExpr(exp *ast.SelectorExpr) error {
27
27
  // Check if this is a package selector (e.g., time.Now)
28
28
  if pkgIdent, isPkgIdent := exp.X.(*ast.Ident); isPkgIdent {
29
29
  if obj := c.pkg.TypesInfo.ObjectOf(pkgIdent); obj != nil {
30
- if _, isPkg := obj.(*types.PkgName); isPkg {
30
+ if pkgName, isPkg := obj.(*types.PkgName); isPkg {
31
31
  // Package selectors should never use .value on the package name
32
32
  c.tsw.WriteLiterally(pkgIdent.Name)
33
33
  c.tsw.WriteLiterally(".")
34
+
35
+ // Special case: reflect.Pointer should be translated to reflect.Ptr
36
+ // (Go has both names for the same Kind constant)
37
+ if pkgName.Imported().Path() == "reflect" && exp.Sel.Name == "Pointer" {
38
+ c.tsw.WriteLiterally("Ptr")
39
+ return nil
40
+ }
41
+
34
42
  // Write the selected identifier, allowing .value if it's a varrefed package variable
35
43
  c.WriteIdent(exp.Sel, true)
36
44
  return nil
@@ -122,10 +130,23 @@ func (c *GoToTSCompiler) WriteSelectorExpr(exp *ast.SelectorExpr) error {
122
130
 
123
131
  // Fallback / Normal Case (e.g., obj.Field, pkg.Var, method calls)
124
132
  // WriteValueExpr handles adding .value for the base variable itself if it's varrefed.
133
+
134
+ // Check if the base expression is an async call - if so, we need to wrap it in parentheses
135
+ // so that await binds correctly: (await asyncFn()).method instead of await asyncFn().method
136
+ needsParensForAsync := false
137
+ if callExpr, isCall := exp.X.(*ast.CallExpr); isCall && c.isCallExprAsync(callExpr) {
138
+ needsParensForAsync = true
139
+ c.tsw.WriteLiterally("(")
140
+ }
141
+
125
142
  if err := c.WriteValueExpr(exp.X); err != nil {
126
143
  return fmt.Errorf("failed to write selector base expression: %w", err)
127
144
  }
128
145
 
146
+ if needsParensForAsync {
147
+ c.tsw.WriteLiterally(")")
148
+ }
149
+
129
150
  // Add null assertion for selector expressions when accessing fields/methods on nullable types
130
151
  // In Go, accessing fields or calling methods on nil pointers/interfaces panics, so we should throw in TypeScript
131
152
  baseType := c.pkg.TypesInfo.TypeOf(exp.X)
@@ -189,6 +210,55 @@ func (c *GoToTSCompiler) writeMethodValue(exp *ast.SelectorExpr, selection *type
189
210
  baseIsPointer = true
190
211
  }
191
212
 
213
+ // Check if the receiver is a primitive/wrapper type
214
+ underlyingRecvType := recvType
215
+ if ptr, ok := recvType.(*types.Pointer); ok {
216
+ underlyingRecvType = ptr.Elem()
217
+ }
218
+ isPrimitiveReceiver := c.isWrapperType(underlyingRecvType)
219
+
220
+ // For primitive types, generate a closure that captures the receiver and calls the free function
221
+ if isPrimitiveReceiver {
222
+ // Get the type name for the free function
223
+ typeName := c.getQualifiedTypeName(underlyingRecvType)
224
+ if typeName == "" {
225
+ return fmt.Errorf("failed to get qualified type name for primitive receiver")
226
+ }
227
+
228
+ // Get the method parameters to forward them
229
+ params := sig.Params()
230
+ paramNames := make([]string, params.Len())
231
+ for i := 0; i < params.Len(); i++ {
232
+ paramNames[i] = fmt.Sprintf("_p%d", i)
233
+ }
234
+
235
+ // Generate: ((_p0: type0, _p1: type1, ...) => TypeName_MethodName(receiverValue, _p0, _p1, ...))
236
+ c.tsw.WriteLiterally("((")
237
+ for i, name := range paramNames {
238
+ if i > 0 {
239
+ c.tsw.WriteLiterally(", ")
240
+ }
241
+ c.tsw.WriteLiterally(name)
242
+ c.tsw.WriteLiterally(": ")
243
+ c.WriteGoType(params.At(i).Type(), GoTypeContextGeneral)
244
+ }
245
+ c.tsw.WriteLiterally(") => ")
246
+ c.tsw.WriteLiterally(typeName)
247
+ c.tsw.WriteLiterally("_")
248
+ c.tsw.WriteLiterally(exp.Sel.Name)
249
+ c.tsw.WriteLiterally("(")
250
+ if err := c.WriteValueExpr(exp.X); err != nil {
251
+ return fmt.Errorf("failed to write method value receiver: %w", err)
252
+ }
253
+ for _, name := range paramNames {
254
+ c.tsw.WriteLiterally(", ")
255
+ c.tsw.WriteLiterally(name)
256
+ }
257
+ c.tsw.WriteLiterally("))")
258
+
259
+ return nil
260
+ }
261
+
192
262
  // Write the receiver expression
193
263
  if err := c.WriteValueExpr(exp.X); err != nil {
194
264
  return fmt.Errorf("failed to write method value receiver: %w", err)
@@ -26,13 +26,23 @@ func (c *GoToTSCompiler) WriteTypeExpr(a ast.Expr) {
26
26
  // Check if this is a package selector (e.g., os.FileInfo)
27
27
  if obj := c.pkg.TypesInfo.Uses[pkgIdent]; obj != nil {
28
28
  if _, isPkg := obj.(*types.PkgName); isPkg {
29
- // This is a package.Type reference - write the qualified name
29
+ // This is a package.Type reference
30
+ typ := c.pkg.TypesInfo.TypeOf(a)
31
+
32
+ // Check if this is an interface type and add null | prefix
33
+ if typ != nil {
34
+ if _, isInterface := typ.Underlying().(*types.Interface); isInterface {
35
+ c.tsw.WriteLiterally("null | ")
36
+ }
37
+ }
38
+
39
+ // Write the qualified name
30
40
  c.tsw.WriteLiterally(pkgIdent.Name)
31
41
  c.tsw.WriteLiterally(".")
32
42
  c.tsw.WriteLiterally(selectorExpr.Sel.Name)
33
43
 
34
44
  // Check if this is a function type and add | null
35
- if typ := c.pkg.TypesInfo.TypeOf(a); typ != nil {
45
+ if typ != nil {
36
46
  if namedType, isNamed := typ.(*types.Named); isNamed {
37
47
  if _, isSignature := namedType.Underlying().(*types.Signature); isSignature {
38
48
  c.tsw.WriteLiterally(" | null")
@@ -134,11 +144,47 @@ func (c *GoToTSCompiler) writeTypeDescription(typeExpr ast.Expr) {
134
144
  c.tsw.WriteLiterally("}")
135
145
  }
136
146
  } else {
137
- // For named types, just use the name string
147
+ // For named types, use the fully qualified name with package path
148
+ if goType != nil {
149
+ if namedType, isNamed := goType.(*types.Named); isNamed {
150
+ typeName := namedType.Obj().Name()
151
+ if pkg := namedType.Obj().Pkg(); pkg != nil {
152
+ pkgPath := pkg.Path()
153
+ pkgName := pkg.Name()
154
+ if pkgPath != "" && pkgName != "main" {
155
+ typeName = pkgPath + "." + typeName
156
+ } else if pkgName == "main" {
157
+ typeName = "main." + typeName
158
+ }
159
+ }
160
+ c.tsw.WriteLiterallyf("'%s'", typeName)
161
+ return
162
+ }
163
+ }
164
+ // Fallback to short name if type info unavailable
138
165
  c.tsw.WriteLiterallyf("'%s'", t.Name)
139
166
  }
140
167
  case *ast.SelectorExpr:
141
168
  if ident, ok := t.X.(*ast.Ident); ok {
169
+ // Use type info to get the actual package path
170
+ goType := c.pkg.TypesInfo.TypeOf(t)
171
+ if goType != nil {
172
+ if namedType, isNamed := goType.(*types.Named); isNamed {
173
+ typeName := namedType.Obj().Name()
174
+ if pkg := namedType.Obj().Pkg(); pkg != nil {
175
+ pkgPath := pkg.Path()
176
+ pkgName := pkg.Name()
177
+ if pkgPath != "" && pkgName != "main" {
178
+ typeName = pkgPath + "." + typeName
179
+ } else if pkgName == "main" {
180
+ typeName = "main." + typeName
181
+ }
182
+ }
183
+ c.tsw.WriteLiterallyf("'%s'", typeName)
184
+ return
185
+ }
186
+ }
187
+ // Fallback to using the identifier name (package alias)
142
188
  c.tsw.WriteLiterallyf("'%s.%s'", ident.Name, t.Sel.Name)
143
189
  }
144
190
  case *ast.ArrayType: