goscript 0.0.49 → 0.0.51

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 (65) hide show
  1. package/compiler/analysis.go +1021 -561
  2. package/compiler/analysis_test.go +12 -15
  3. package/compiler/compiler.go +75 -39
  4. package/compiler/decl.go +22 -0
  5. package/compiler/expr-call-async.go +239 -40
  6. package/compiler/expr-call-type-conversion.go +6 -10
  7. package/compiler/expr-call.go +58 -27
  8. package/compiler/sanitize.go +1 -2
  9. package/compiler/spec-struct.go +3 -3
  10. package/compiler/spec-value.go +2 -2
  11. package/compiler/spec.go +66 -43
  12. package/compiler/stmt-assign.go +7 -4
  13. package/compiler/stmt-select.go +52 -1
  14. package/compiler/stmt.go +63 -5
  15. package/compiler/type.go +16 -3
  16. package/dist/gs/builtin/builtin.js.map +1 -1
  17. package/dist/gs/builtin/channel.d.ts +2 -2
  18. package/dist/gs/builtin/channel.js +12 -7
  19. package/dist/gs/builtin/channel.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 +3 -1
  24. package/dist/gs/fmt/fmt.js.map +1 -1
  25. package/dist/gs/reflect/type.js +5 -8
  26. package/dist/gs/reflect/type.js.map +1 -1
  27. package/dist/gs/syscall/constants.d.ts +24 -0
  28. package/dist/gs/syscall/constants.js +27 -0
  29. package/dist/gs/syscall/constants.js.map +1 -0
  30. package/dist/gs/syscall/env.d.ts +6 -0
  31. package/dist/gs/syscall/env.js +43 -0
  32. package/dist/gs/syscall/env.js.map +1 -0
  33. package/dist/gs/syscall/errors.d.ts +111 -0
  34. package/dist/gs/syscall/errors.js +547 -0
  35. package/dist/gs/syscall/errors.js.map +1 -0
  36. package/dist/gs/syscall/fs.d.ts +29 -0
  37. package/dist/gs/syscall/fs.js +53 -0
  38. package/dist/gs/syscall/fs.js.map +1 -0
  39. package/dist/gs/syscall/index.d.ts +6 -80
  40. package/dist/gs/syscall/index.js +12 -168
  41. package/dist/gs/syscall/index.js.map +1 -1
  42. package/dist/gs/syscall/rawconn.d.ts +7 -0
  43. package/dist/gs/syscall/rawconn.js +19 -0
  44. package/dist/gs/syscall/rawconn.js.map +1 -0
  45. package/dist/gs/syscall/types.d.ts +12 -0
  46. package/dist/gs/syscall/types.js +2 -0
  47. package/dist/gs/syscall/types.js.map +1 -0
  48. package/dist/gs/time/time.d.ts +2 -1
  49. package/dist/gs/time/time.js +29 -19
  50. package/dist/gs/time/time.js.map +1 -1
  51. package/gs/builtin/builtin.ts +1 -7
  52. package/gs/builtin/channel.ts +18 -12
  53. package/gs/context/context.ts +63 -45
  54. package/gs/fmt/fmt.ts +5 -1
  55. package/gs/reflect/type.ts +5 -10
  56. package/gs/syscall/constants.ts +29 -0
  57. package/gs/syscall/env.ts +47 -0
  58. package/gs/syscall/errors.ts +658 -0
  59. package/gs/syscall/fs.ts +62 -0
  60. package/gs/syscall/index.ts +12 -207
  61. package/gs/syscall/rawconn.ts +23 -0
  62. package/gs/syscall/types.ts +18 -0
  63. package/gs/time/time.ts +35 -21
  64. package/package.json +2 -2
  65. package/gs/TODO.md +0 -129
@@ -81,7 +81,7 @@ func (c *GoToTSCompiler) writeArrayTypeConversion(exp *ast.CallExpr) (handled bo
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
83
  // Check if the named type has receiver methods (is a wrapper type)
84
- if c.analysis.IsWrapperType(namedArgType) {
84
+ if c.analysis.IsNamedBasicType(namedArgType) {
85
85
  // Check if the underlying type matches the target slice type
86
86
  if sliceUnderlying, isSlice := namedArgType.Underlying().(*types.Slice); isSlice {
87
87
  // Get the target slice type
@@ -216,7 +216,7 @@ func (c *GoToTSCompiler) writeTypeConversion(exp *ast.CallExpr, funIdent *ast.Id
216
216
  if argType := c.pkg.TypesInfo.TypeOf(arg); argType != nil {
217
217
  if namedArgType, isNamed := argType.(*types.Named); isNamed {
218
218
  // Check if the argument type is a wrapper type
219
- if c.analysis.IsWrapperType(namedArgType) {
219
+ if c.analysis.IsNamedBasicType(namedArgType) {
220
220
  // Check if we're converting to the underlying type
221
221
  targetType := typeName.Type()
222
222
  underlyingType := namedArgType.Underlying()
@@ -247,7 +247,7 @@ func (c *GoToTSCompiler) writeTypeConversion(exp *ast.CallExpr, funIdent *ast.Id
247
247
  return true, nil
248
248
  } else {
249
249
  // Check if this is a wrapper type
250
- isWrapperType := c.analysis.IsWrapperType(typeName.Type())
250
+ isWrapperType := c.analysis.IsNamedBasicType(typeName.Type())
251
251
  if isWrapperType {
252
252
  // For wrapper types, use type casting instead of constructor calls
253
253
  c.tsw.WriteLiterally("(")
@@ -288,8 +288,6 @@ func (c *GoToTSCompiler) writeTypeConversion(exp *ast.CallExpr, funIdent *ast.Id
288
288
  c.tsw.WriteLiterally(funIdent.String())
289
289
  c.tsw.WriteLiterally("(")
290
290
 
291
- fmt.Printf("DEBUG: Type conversion constructor for %s\n", funIdent.String())
292
-
293
291
  // Use auto-wrapping for the constructor argument
294
292
  // The constructor parameter type is the underlying type of the named type
295
293
  // For MyMode (which is type MyMode os.FileMode), the constructor expects os.FileMode
@@ -299,8 +297,6 @@ func (c *GoToTSCompiler) writeTypeConversion(exp *ast.CallExpr, funIdent *ast.Id
299
297
  constructorParamType = namedType.Underlying()
300
298
  }
301
299
 
302
- fmt.Printf("DEBUG: Constructor param type: %v\n", constructorParamType)
303
-
304
300
  if err := c.writeAutoWrappedArgument(exp.Args[0], constructorParamType); err != nil {
305
301
  return true, fmt.Errorf("failed to write argument for type constructor: %w", err)
306
302
  }
@@ -376,7 +372,7 @@ func (c *GoToTSCompiler) writeIntConversion(exp *ast.CallExpr) error {
376
372
  if argType := c.pkg.TypesInfo.TypeOf(arg); argType != nil {
377
373
  if namedArgType, isNamed := argType.(*types.Named); isNamed {
378
374
  // Check if the argument type is a wrapper type
379
- if c.analysis.IsWrapperType(namedArgType) {
375
+ if c.analysis.IsNamedBasicType(namedArgType) {
380
376
  // Check if we're converting to int (the underlying type)
381
377
  if types.Identical(types.Typ[types.Int], namedArgType.Underlying()) {
382
378
  // This is a conversion from a wrapper type to int
@@ -413,7 +409,7 @@ func (c *GoToTSCompiler) writeQualifiedTypeConversion(exp *ast.CallExpr, selecto
413
409
  if argType := c.pkg.TypesInfo.TypeOf(arg); argType != nil {
414
410
  if namedArgType, isNamed := argType.(*types.Named); isNamed {
415
411
  // Check if the argument type is a wrapper type
416
- if c.analysis.IsWrapperType(namedArgType) {
412
+ if c.analysis.IsNamedBasicType(namedArgType) {
417
413
  // Check if we're converting to the underlying type
418
414
  targetType := typeName.Type()
419
415
  underlyingType := namedArgType.Underlying()
@@ -444,7 +440,7 @@ func (c *GoToTSCompiler) writeQualifiedTypeConversion(exp *ast.CallExpr, selecto
444
440
  return true, nil
445
441
  } else {
446
442
  // Check if this is a wrapper type
447
- isWrapperType := c.analysis.IsWrapperType(typeName.Type())
443
+ isWrapperType := c.analysis.IsNamedBasicType(typeName.Type())
448
444
  if isWrapperType {
449
445
  // For wrapper types, use type casting instead of constructor calls
450
446
  c.tsw.WriteLiterally("(")
@@ -74,7 +74,7 @@ func (c *GoToTSCompiler) WriteCallExpr(exp *ast.CallExpr) error {
74
74
  }
75
75
 
76
76
  // Check if this is an async function call
77
- _ = c.writeAsyncCall(exp, funIdent)
77
+ c.writeAsyncCallIfNeeded(exp)
78
78
 
79
79
  // Not a special built-in, treat as a regular function call
80
80
  if err := c.WriteValueExpr(expFun); err != nil {
@@ -99,7 +99,7 @@ func (c *GoToTSCompiler) WriteCallExpr(exp *ast.CallExpr) error {
99
99
 
100
100
  // Handle non-identifier function expressions (method calls, function literals, etc.)
101
101
  // Check if this is an async method call (e.g., mu.Lock())
102
- _ = c.writeAsyncMethodCall(exp)
102
+ c.writeAsyncCallIfNeeded(exp)
103
103
 
104
104
  // If expFun is a function literal, it needs to be wrapped in parentheses for IIFE syntax
105
105
  if _, isFuncLit := expFun.(*ast.FuncLit); isFuncLit {
@@ -169,7 +169,7 @@ func (c *GoToTSCompiler) writeCallArguments(exp *ast.CallExpr) error {
169
169
  func (c *GoToTSCompiler) writeArgumentWithTypeHandling(arg ast.Expr, funcSig *types.Signature, argIndex int) error {
170
170
  if funcSig != nil && argIndex < funcSig.Params().Len() {
171
171
  paramType := funcSig.Params().At(argIndex).Type()
172
- isWrapper := c.analysis.IsWrapperType(paramType)
172
+ isWrapper := c.analysis.IsNamedBasicType(paramType)
173
173
 
174
174
  if isWrapper {
175
175
  // For wrapper types (now type aliases), no auto-wrapping is needed
@@ -234,7 +234,7 @@ func (c *GoToTSCompiler) getImportAlias(pkgPath string) string {
234
234
  func (c *GoToTSCompiler) writeAutoWrappedArgument(arg ast.Expr, expectedType types.Type) error {
235
235
  // For wrapper types (now type aliases), no auto-wrapping is needed
236
236
  // Just use type casting if the types don't match exactly
237
- if c.analysis.IsWrapperType(expectedType) {
237
+ if c.analysis.IsNamedBasicType(expectedType) {
238
238
  argType := c.pkg.TypesInfo.TypeOf(arg)
239
239
 
240
240
  // Only add type casting if needed
@@ -271,39 +271,70 @@ func (c *GoToTSCompiler) writeWrapperTypeMethodCall(exp *ast.CallExpr, selectorE
271
271
  return false, nil
272
272
  }
273
273
 
274
- // Check if this is a wrapper type
275
- if !c.analysis.IsWrapperType(baseType) {
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 {
276
306
  return false, nil
277
307
  }
278
308
 
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()
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
+ }
287
320
  } else {
321
+ // Local type
288
322
  typeName = obj.Name()
289
323
  }
290
- } else {
291
- // Local type
292
- typeName = obj.Name()
293
324
  }
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()
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
+ }
301
334
  } else {
335
+ // Local type alias
302
336
  typeName = obj.Name()
303
337
  }
304
- } else {
305
- // Local type alias
306
- typeName = obj.Name()
307
338
  }
308
339
  }
309
340
  }
@@ -11,8 +11,7 @@ func sanitizeIdentifier(name string) string {
11
11
 
12
12
  // Handle TypeScript built-in types that conflict with Go type parameter names
13
13
  builtinTypes := map[string]string{
14
- "Map": "MapType",
15
- // Add other built-in types as needed
14
+ "Promise": "PromiseType",
16
15
  }
17
16
 
18
17
  if replacement, exists := builtinTypes[name]; exists {
@@ -37,7 +37,7 @@ func (c *GoToTSCompiler) WriteStructTypeSpec(a *ast.TypeSpec, t *ast.StructType)
37
37
  c.tsw.WriteLine("{")
38
38
  c.tsw.Indent(1)
39
39
 
40
- className := a.Name.Name
40
+ className := sanitizeIdentifier(a.Name.Name)
41
41
 
42
42
  goStructType, ok := c.pkg.TypesInfo.Defs[a.Name].Type().(*types.Named)
43
43
  if !ok {
@@ -231,10 +231,10 @@ func (c *GoToTSCompiler) WriteStructTypeSpec(a *ast.TypeSpec, t *ast.StructType)
231
231
  // Check for both simple identifiers (Pair) and generic types (Pair[T])
232
232
  var recvTypeName string
233
233
  if ident, ok := recvType.(*ast.Ident); ok {
234
- recvTypeName = ident.Name
234
+ recvTypeName = sanitizeIdentifier(ident.Name)
235
235
  } else if indexExpr, ok := recvType.(*ast.IndexExpr); ok {
236
236
  if ident, ok := indexExpr.X.(*ast.Ident); ok {
237
- recvTypeName = ident.Name
237
+ recvTypeName = sanitizeIdentifier(ident.Name)
238
238
  }
239
239
  }
240
240
 
@@ -237,7 +237,7 @@ func (c *GoToTSCompiler) WriteValueSpec(a *ast.ValueSpec) error {
237
237
  // Check if this is a named type with methods and the initializer is a basic value
238
238
  if namedType, isNamed := goType.(*types.Named); isNamed {
239
239
  // Check if this is a wrapper type first
240
- isWrapperType := c.analysis.IsWrapperType(namedType)
240
+ isWrapperType := c.analysis.IsNamedBasicType(namedType)
241
241
  if isWrapperType {
242
242
  // For wrapper types, no constructor wrapping needed
243
243
  if shouldApplyClone(c.pkg, initializerExpr) {
@@ -334,7 +334,7 @@ func (c *GoToTSCompiler) WriteValueSpec(a *ast.ValueSpec) error {
334
334
  // No initializer, use the zero value directly
335
335
  // Check if this is a wrapper type first
336
336
  if namedType, isNamed := goType.(*types.Named); isNamed {
337
- isWrapperType := c.analysis.IsWrapperType(namedType)
337
+ isWrapperType := c.analysis.IsNamedBasicType(namedType)
338
338
  if isWrapperType {
339
339
  // For wrapper types, just use zero value directly
340
340
  c.WriteZeroValueForType(goType)
package/compiler/spec.go CHANGED
@@ -136,27 +136,8 @@ func (c *GoToTSCompiler) writeRegularFieldInitializer(fieldName string, fieldTyp
136
136
 
137
137
  c.tsw.WriteLiterallyf("init?.%s ?? ", fieldName)
138
138
 
139
- // Debugging: print field type info
140
- if astType != nil {
141
- if named, ok := fieldType.(*types.Named); ok {
142
- if pkgPath := named.Obj().Pkg().Path(); pkgPath != "" {
143
- c.tsw.WriteCommentLinef("DEBUG: Field %s has type %s (%T)", fieldName, fieldType, fieldType)
144
- }
145
- } else {
146
- c.tsw.WriteCommentLinef("DEBUG: Field %s has type %s (%T)", fieldName, fieldType, fieldType)
147
- }
148
- if typeName, ok := c.pkg.TypesInfo.TypeOf(astType).(*types.Named); ok {
149
- pkgPath := ""
150
- if typeName.Obj().Pkg() != nil {
151
- pkgPath = typeName.Obj().Pkg().Path()
152
- }
153
- c.tsw.WriteCommentLinef("DEBUG: Package=%s, TypeName=%s", pkgPath, typeName)
154
- }
155
- }
156
-
157
139
  // Priority 1: Check if this is a wrapper type
158
- if c.analysis.IsWrapperType(fieldType) {
159
- c.tsw.WriteCommentLinef("DEBUG: Using wrapper type zero value")
140
+ if c.analysis.IsNamedBasicType(fieldType) {
160
141
  // For wrapper types, use the zero value of the underlying type with type casting
161
142
  if named, ok := fieldType.(*types.Named); ok {
162
143
  c.WriteZeroValueForType(named.Underlying())
@@ -175,27 +156,22 @@ func (c *GoToTSCompiler) writeRegularFieldInitializer(fieldName string, fieldTyp
175
156
 
176
157
  // Priority 2: Handle imported types with basic underlying types (like os.FileMode)
177
158
  if c.isImportedBasicType(fieldType) {
178
- c.tsw.WriteCommentLinef("DEBUG: Using imported basic type zero value")
179
159
  c.writeImportedBasicTypeZeroValue(fieldType)
180
160
  return
181
161
  }
182
162
 
183
163
  // Priority 3: Handle named types
184
164
  if named, isNamed := fieldType.(*types.Named); isNamed {
185
- c.tsw.WriteCommentLinef("DEBUG: Using named type zero value")
186
165
  c.writeNamedTypeZeroValue(named)
187
166
  return
188
167
  }
189
168
 
190
169
  // Priority 4: Handle type aliases
191
170
  if alias, isAlias := fieldType.(*types.Alias); isAlias {
192
- c.tsw.WriteCommentLinef("DEBUG: Using type alias zero value")
193
171
  c.writeTypeAliasZeroValue(alias, astType)
194
172
  return
195
173
  }
196
174
 
197
- // Default: use WriteZeroValueForType
198
- c.tsw.WriteCommentLinef("DEBUG: Using default zero value")
199
175
  c.WriteZeroValueForType(fieldType)
200
176
  }
201
177
 
@@ -209,36 +185,74 @@ func (c *GoToTSCompiler) isStructValueType(fieldType types.Type) bool {
209
185
  }
210
186
 
211
187
  func (c *GoToTSCompiler) isImportedBasicType(fieldType types.Type) bool {
212
- named, isNamed := fieldType.(*types.Named)
213
- if !isNamed {
214
- return false
215
- }
188
+ // Handle named types
189
+ if named, isNamed := fieldType.(*types.Named); isNamed {
190
+ obj := named.Obj()
191
+ if obj == nil || obj.Pkg() == nil || obj.Pkg() == c.pkg.Types {
192
+ return false // Not imported or is local
193
+ }
194
+
195
+ underlying := named.Underlying()
196
+ if underlying == nil {
197
+ return false
198
+ }
216
199
 
217
- obj := named.Obj()
218
- if obj == nil || obj.Pkg() == nil || obj.Pkg() == c.pkg.Types {
219
- return false // Not imported or is local
200
+ _, isBasic := underlying.(*types.Basic)
201
+ return isBasic
220
202
  }
221
203
 
222
- underlying := named.Underlying()
223
- if underlying == nil {
224
- return false
204
+ // Handle type aliases (like os.FileMode = fs.FileMode)
205
+ if alias, isAlias := fieldType.(*types.Alias); isAlias {
206
+ obj := alias.Obj()
207
+ if obj == nil || obj.Pkg() == nil || obj.Pkg() == c.pkg.Types {
208
+ return false // Not imported or is local
209
+ }
210
+
211
+ underlying := alias.Underlying()
212
+ if underlying == nil {
213
+ return false
214
+ }
215
+
216
+ _, isBasic := underlying.(*types.Basic)
217
+ return isBasic
225
218
  }
226
219
 
227
- _, isBasic := underlying.(*types.Basic)
228
- return isBasic
220
+ return false
229
221
  }
230
222
 
231
223
  func (c *GoToTSCompiler) writeImportedBasicTypeZeroValue(fieldType types.Type) {
232
- named := fieldType.(*types.Named)
233
- underlying := named.Underlying()
224
+ if named, ok := fieldType.(*types.Named); ok {
225
+ underlying := named.Underlying()
226
+ // Write zero value of underlying type with type casting
227
+ c.WriteZeroValueForType(underlying)
228
+ c.tsw.WriteLiterally(" as ")
229
+ c.WriteGoType(fieldType, GoTypeContextGeneral)
230
+ return
231
+ }
234
232
 
235
- // Write zero value of underlying type with type casting
236
- c.WriteZeroValueForType(underlying)
237
- c.tsw.WriteLiterally(" as ")
238
- c.WriteGoType(fieldType, GoTypeContextGeneral)
233
+ if alias, ok := fieldType.(*types.Alias); ok {
234
+ underlying := alias.Underlying()
235
+ // Write zero value of underlying type with type casting
236
+ c.WriteZeroValueForType(underlying)
237
+ c.tsw.WriteLiterally(" as ")
238
+ c.WriteGoType(fieldType, GoTypeContextGeneral)
239
+ return
240
+ }
241
+
242
+ // Fallback (should not happen if isImportedBasicType was correct)
243
+ c.WriteZeroValueForType(fieldType)
239
244
  }
240
245
 
241
246
  func (c *GoToTSCompiler) writeNamedTypeZeroValue(named *types.Named) {
247
+ // Check if this is a wrapper type first
248
+ if c.analysis.IsNamedBasicType(named) {
249
+ // For wrapper types, use the zero value of the underlying type with type casting
250
+ c.WriteZeroValueForType(named.Underlying())
251
+ c.tsw.WriteLiterally(" as ")
252
+ c.WriteGoType(named, GoTypeContextGeneral)
253
+ return
254
+ }
255
+
242
256
  // Check if underlying type is an interface
243
257
  if _, isInterface := named.Underlying().(*types.Interface); isInterface {
244
258
  c.tsw.WriteLiterally("null")
@@ -260,6 +274,15 @@ func (c *GoToTSCompiler) writeNamedTypeZeroValue(named *types.Named) {
260
274
  }
261
275
 
262
276
  func (c *GoToTSCompiler) writeTypeAliasZeroValue(alias *types.Alias, astType ast.Expr) {
277
+ // Check if this is a wrapper type first
278
+ if c.analysis.IsNamedBasicType(alias) {
279
+ // For wrapper types, use the zero value of the underlying type with type casting
280
+ c.WriteZeroValueForType(alias.Underlying())
281
+ c.tsw.WriteLiterally(" as ")
282
+ c.WriteGoType(alias, GoTypeContextGeneral)
283
+ return
284
+ }
285
+
263
286
  // Check if underlying type is an interface
264
287
  if _, isInterface := alias.Underlying().(*types.Interface); isInterface {
265
288
  c.tsw.WriteLiterally("null")
@@ -117,6 +117,8 @@ func (c *GoToTSCompiler) WriteStmtAssign(exp *ast.AssignStmt) error {
117
117
  }
118
118
  }
119
119
  c.tsw.WriteLiterally("] = ")
120
+ // Add await if the call is async
121
+ c.writeAsyncCallIfNeeded(callExpr)
120
122
  c.WriteValueExpr(callExpr)
121
123
  c.tsw.WriteLine("")
122
124
  return nil
@@ -165,6 +167,8 @@ func (c *GoToTSCompiler) WriteStmtAssign(exp *ast.AssignStmt) error {
165
167
 
166
168
  // Write a temporary variable to hold the function call result
167
169
  c.tsw.WriteLiterally(" const _tmp = ")
170
+ // Add await if the call is async
171
+ c.writeAsyncCallIfNeeded(callExpr)
168
172
  if err := c.WriteValueExpr(callExpr); err != nil {
169
173
  return fmt.Errorf("failed to write RHS call expression in assignment: %w", err)
170
174
  }
@@ -287,10 +291,9 @@ func (c *GoToTSCompiler) WriteStmtAssign(exp *ast.AssignStmt) error {
287
291
  }
288
292
  c.tsw.WriteLiterally("] = ")
289
293
 
290
- // Write the right-hand side (the function call)
291
- if err := c.WriteValueExpr(callExpr); err != nil {
292
- return fmt.Errorf("failed to write RHS call expression in assignment: %w", err)
293
- }
294
+ // Add await if the call is async
295
+ c.writeAsyncCallIfNeeded(callExpr)
296
+ c.WriteValueExpr(callExpr)
294
297
 
295
298
  c.tsw.WriteLine("")
296
299
  return nil
@@ -8,6 +8,18 @@ import (
8
8
  "github.com/pkg/errors"
9
9
  )
10
10
 
11
+ // caseEndsWithReturn checks if a case body ends with a return statement
12
+ func (c *GoToTSCompiler) caseEndsWithReturn(body []ast.Stmt) bool {
13
+ if len(body) == 0 {
14
+ return false
15
+ }
16
+
17
+ // Check if the last statement is a return statement
18
+ lastStmt := body[len(body)-1]
19
+ _, isReturn := lastStmt.(*ast.ReturnStmt)
20
+ return isReturn
21
+ }
22
+
11
23
  // WriteStmtSelect translates a Go `select` statement into an asynchronous
12
24
  // TypeScript operation using the `$.selectStatement` runtime helper.
13
25
  // Go's `select` provides non-deterministic choice over channel operations.
@@ -38,8 +50,29 @@ func (c *GoToTSCompiler) WriteStmtSelect(exp *ast.SelectStmt) error {
38
50
  // Variable to track whether we have a default case
39
51
  hasDefault := false
40
52
 
53
+ // Analyze if all cases end with return statements
54
+ allCasesReturn := true
55
+ for _, stmt := range exp.Body.List {
56
+ if commClause, ok := stmt.(*ast.CommClause); ok {
57
+ if commClause.Comm == nil {
58
+ // Default case - check if it ends with return
59
+ if !c.caseEndsWithReturn(commClause.Body) {
60
+ allCasesReturn = false
61
+ }
62
+ } else {
63
+ // Regular case - check if it ends with return
64
+ if !c.caseEndsWithReturn(commClause.Body) {
65
+ allCasesReturn = false
66
+ }
67
+ }
68
+ }
69
+ }
70
+
71
+ // Generate unique variable names for this select statement
72
+ selectID := fmt.Sprintf("%d", exp.Pos()) // Use AST position for uniqueness
73
+
41
74
  // Start the selectStatement call and the array literal
42
- c.tsw.WriteLiterally("await $.selectStatement(")
75
+ c.tsw.WriteLiterallyf("const [_selectHasReturn%s, _selectValue%s] = await $.selectStatement(", selectID, selectID)
43
76
  c.tsw.WriteLine("[") // Put bracket on new line
44
77
  c.tsw.Indent(1)
45
78
 
@@ -207,5 +240,23 @@ func (c *GoToTSCompiler) WriteStmtSelect(exp *ast.SelectStmt) error {
207
240
  c.tsw.WriteLiterally(")")
208
241
  c.tsw.WriteLine("")
209
242
 
243
+ // Add code to handle the return value from selectStatement
244
+ c.tsw.WriteLiterallyf("if (_selectHasReturn%s) {", selectID)
245
+ c.tsw.WriteLine("")
246
+ c.tsw.Indent(1)
247
+ c.tsw.WriteLiterallyf("return _selectValue%s!", selectID)
248
+ c.tsw.WriteLine("")
249
+ c.tsw.Indent(-1)
250
+ c.tsw.WriteLine("}")
251
+
252
+ // If all cases return, add a TypeScript-satisfying fallback return
253
+ if allCasesReturn {
254
+ c.tsw.WriteLine("// All cases should return, this fallback should never execute")
255
+ c.tsw.WriteLine("throw new Error('Unexpected: select statement did not return when all cases should return')")
256
+ } else {
257
+ c.tsw.WriteLiterallyf("// If _selectHasReturn%s is false, continue execution", selectID)
258
+ c.tsw.WriteLine("")
259
+ }
260
+
210
261
  return nil
211
262
  }
package/compiler/stmt.go CHANGED
@@ -451,13 +451,29 @@ func (c *GoToTSCompiler) WriteStmtIf(exp *ast.IfStmt) error {
451
451
  if c.analysis.HasVariableShadowing(exp) {
452
452
  shadowingInfo := c.analysis.GetShadowingInfo(exp)
453
453
  if shadowingInfo != nil {
454
- // Create temporary variables BEFORE the block to avoid temporal dead zone
454
+ // Handle variable shadowing by creating temporary variables
455
455
  for varName, tempVarName := range shadowingInfo.TempVariables {
456
- // Declare: const _temp_x = x (using the outer scope value)
457
456
  c.tsw.WriteLiterally("const ")
458
457
  c.tsw.WriteLiterally(tempVarName)
459
458
  c.tsw.WriteLiterally(" = ")
460
- c.tsw.WriteLiterally(varName)
459
+
460
+ // Check if this is a built-in function and handle it directly
461
+ if c.isBuiltinFunction(varName) {
462
+ c.tsw.WriteLiterally("$.")
463
+ c.tsw.WriteLiterally(varName)
464
+ } else {
465
+ // Get the original object for this shadowed variable
466
+ if originalObj, exists := shadowingInfo.ShadowedVariables[varName]; exists {
467
+ // Create an identifier with the original name and use WriteValueExpr to properly resolve it
468
+ originalIdent := &ast.Ident{Name: varName}
469
+ // Set the identifier in the Uses map so WriteValueExpr can find the object
470
+ c.pkg.TypesInfo.Uses[originalIdent] = originalObj
471
+ c.WriteValueExpr(originalIdent)
472
+ } else {
473
+ // Fallback to literal name if no object found (shouldn't happen in normal cases)
474
+ c.tsw.WriteLiterally(varName)
475
+ }
476
+ }
461
477
  c.tsw.WriteLine("")
462
478
  }
463
479
  }
@@ -943,11 +959,27 @@ func (c *GoToTSCompiler) WriteStmtLabeled(stmt *ast.LabeledStmt) error {
943
959
  func (c *GoToTSCompiler) writeShadowedAssignment(stmt *ast.AssignStmt, shadowingInfo *ShadowingInfo) error {
944
960
  // First, create temporary variables for the shadowed variables
945
961
  for varName, tempVarName := range shadowingInfo.TempVariables {
946
- // Declare: const _temp_x = x (using the outer scope value)
947
962
  c.tsw.WriteLiterally("const ")
948
963
  c.tsw.WriteLiterally(tempVarName)
949
964
  c.tsw.WriteLiterally(" = ")
950
- c.tsw.WriteLiterally(varName)
965
+
966
+ // Check if this is a built-in function and handle it directly
967
+ if c.isBuiltinFunction(varName) {
968
+ c.tsw.WriteLiterally("$.")
969
+ c.tsw.WriteLiterally(varName)
970
+ } else {
971
+ // Get the original object for this shadowed variable
972
+ if originalObj, exists := shadowingInfo.ShadowedVariables[varName]; exists {
973
+ // Create an identifier with the original name and use WriteValueExpr to properly resolve it
974
+ originalIdent := &ast.Ident{Name: varName}
975
+ // Set the identifier in the Uses map so WriteValueExpr can find the object
976
+ c.pkg.TypesInfo.Uses[originalIdent] = originalObj
977
+ c.WriteValueExpr(originalIdent)
978
+ } else {
979
+ // Fallback to literal name if no object found (shouldn't happen in normal cases)
980
+ c.tsw.WriteLiterally(varName)
981
+ }
982
+ }
951
983
  c.tsw.WriteLine("")
952
984
  }
953
985
 
@@ -1047,6 +1079,10 @@ func (c *GoToTSCompiler) writeShadowedRHSExpression(expr ast.Expr, shadowingInfo
1047
1079
  if err := c.writeShadowedRHSExpression(e.Fun, shadowingInfo); err != nil {
1048
1080
  return err
1049
1081
  }
1082
+
1083
+ // Add non-null assertion for function calls (same logic as WriteCallExpr)
1084
+ c.addNonNullAssertion(e.Fun)
1085
+
1050
1086
  c.tsw.WriteLiterally("(")
1051
1087
  for i, arg := range e.Args {
1052
1088
  if i > 0 {
@@ -1109,3 +1145,25 @@ func (c *GoToTSCompiler) writeShadowedRHSExpression(expr ast.Expr, shadowingInfo
1109
1145
  return c.WriteValueExpr(expr)
1110
1146
  }
1111
1147
  }
1148
+
1149
+ // isBuiltinFunction checks if the given name is a Go built-in function
1150
+ func (c *GoToTSCompiler) isBuiltinFunction(name string) bool {
1151
+ builtins := map[string]bool{
1152
+ "len": true,
1153
+ "cap": true,
1154
+ "make": true,
1155
+ "new": true,
1156
+ "append": true,
1157
+ "copy": true,
1158
+ "delete": true,
1159
+ "complex": true,
1160
+ "real": true,
1161
+ "imag": true,
1162
+ "close": true,
1163
+ "panic": true,
1164
+ "recover": true,
1165
+ "print": true,
1166
+ "println": true,
1167
+ }
1168
+ return builtins[name]
1169
+ }
package/compiler/type.go CHANGED
@@ -278,7 +278,7 @@ func (c *GoToTSCompiler) WriteNamedType(t *types.Named) {
278
278
  // Write the qualified name: importAlias.TypeName
279
279
  c.tsw.WriteLiterally(importAlias)
280
280
  c.tsw.WriteLiterally(".")
281
- c.tsw.WriteLiterally(t.Obj().Name())
281
+ c.tsw.WriteLiterally(c.sanitizeIdentifier(t.Obj().Name()))
282
282
 
283
283
  // For generic types, include type arguments
284
284
  if t.TypeArgs() != nil && t.TypeArgs().Len() > 0 {
@@ -306,7 +306,7 @@ func (c *GoToTSCompiler) WriteNamedType(t *types.Named) {
306
306
  // Write the qualified name: importAlias.TypeName
307
307
  c.tsw.WriteLiterally(importAlias)
308
308
  c.tsw.WriteLiterally(".")
309
- c.tsw.WriteLiterally(t.Obj().Name())
309
+ c.tsw.WriteLiterally(c.sanitizeIdentifier(t.Obj().Name()))
310
310
 
311
311
  // For generic types, include type arguments
312
312
  if t.TypeArgs() != nil && t.TypeArgs().Len() > 0 {
@@ -330,7 +330,7 @@ func (c *GoToTSCompiler) WriteNamedType(t *types.Named) {
330
330
  }
331
331
 
332
332
  // Use Obj().Name() for the original defined name (local types or unmatched imports)
333
- c.tsw.WriteLiterally(t.Obj().Name())
333
+ c.tsw.WriteLiterally(c.sanitizeIdentifier(t.Obj().Name()))
334
334
 
335
335
  // For generic types, include type arguments
336
336
  if t.TypeArgs() != nil && t.TypeArgs().Len() > 0 {
@@ -656,6 +656,14 @@ func (c *GoToTSCompiler) writeInterfaceStructure(iface *types.Interface, astNode
656
656
  // Return type
657
657
  c.tsw.WriteLiterally(": ")
658
658
  results := sig.Results()
659
+
660
+ // Determine if this interface method should be async based on implementations
661
+ isMethodAsync := c.analysis.IsInterfaceMethodAsync(iface, method.Name())
662
+
663
+ if isMethodAsync {
664
+ c.tsw.WriteLiterally("Promise<")
665
+ }
666
+
659
667
  if results.Len() == 0 {
660
668
  c.tsw.WriteLiterally("void")
661
669
  } else if results.Len() == 1 {
@@ -688,6 +696,11 @@ func (c *GoToTSCompiler) writeInterfaceStructure(iface *types.Interface, astNode
688
696
  }
689
697
  c.tsw.WriteLiterally("]")
690
698
  }
699
+
700
+ if isMethodAsync {
701
+ c.tsw.WriteLiterally(">")
702
+ }
703
+
691
704
  c.tsw.WriteLine("") // newline for each method
692
705
  }
693
706
  c.tsw.Indent(-1)