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.
- package/compiler/analysis.go +1021 -561
- package/compiler/analysis_test.go +12 -15
- package/compiler/compiler.go +75 -39
- package/compiler/decl.go +22 -0
- package/compiler/expr-call-async.go +239 -40
- package/compiler/expr-call-type-conversion.go +6 -10
- package/compiler/expr-call.go +58 -27
- package/compiler/sanitize.go +1 -2
- package/compiler/spec-struct.go +3 -3
- package/compiler/spec-value.go +2 -2
- package/compiler/spec.go +66 -43
- package/compiler/stmt-assign.go +7 -4
- package/compiler/stmt-select.go +52 -1
- package/compiler/stmt.go +63 -5
- package/compiler/type.go +16 -3
- package/dist/gs/builtin/builtin.js.map +1 -1
- package/dist/gs/builtin/channel.d.ts +2 -2
- package/dist/gs/builtin/channel.js +12 -7
- package/dist/gs/builtin/channel.js.map +1 -1
- package/dist/gs/context/context.d.ts +16 -18
- package/dist/gs/context/context.js +23 -13
- package/dist/gs/context/context.js.map +1 -1
- package/dist/gs/fmt/fmt.js +3 -1
- package/dist/gs/fmt/fmt.js.map +1 -1
- package/dist/gs/reflect/type.js +5 -8
- package/dist/gs/reflect/type.js.map +1 -1
- package/dist/gs/syscall/constants.d.ts +24 -0
- package/dist/gs/syscall/constants.js +27 -0
- package/dist/gs/syscall/constants.js.map +1 -0
- package/dist/gs/syscall/env.d.ts +6 -0
- package/dist/gs/syscall/env.js +43 -0
- package/dist/gs/syscall/env.js.map +1 -0
- package/dist/gs/syscall/errors.d.ts +111 -0
- package/dist/gs/syscall/errors.js +547 -0
- package/dist/gs/syscall/errors.js.map +1 -0
- package/dist/gs/syscall/fs.d.ts +29 -0
- package/dist/gs/syscall/fs.js +53 -0
- package/dist/gs/syscall/fs.js.map +1 -0
- package/dist/gs/syscall/index.d.ts +6 -80
- package/dist/gs/syscall/index.js +12 -168
- package/dist/gs/syscall/index.js.map +1 -1
- package/dist/gs/syscall/rawconn.d.ts +7 -0
- package/dist/gs/syscall/rawconn.js +19 -0
- package/dist/gs/syscall/rawconn.js.map +1 -0
- package/dist/gs/syscall/types.d.ts +12 -0
- package/dist/gs/syscall/types.js +2 -0
- package/dist/gs/syscall/types.js.map +1 -0
- package/dist/gs/time/time.d.ts +2 -1
- package/dist/gs/time/time.js +29 -19
- package/dist/gs/time/time.js.map +1 -1
- package/gs/builtin/builtin.ts +1 -7
- package/gs/builtin/channel.ts +18 -12
- package/gs/context/context.ts +63 -45
- package/gs/fmt/fmt.ts +5 -1
- package/gs/reflect/type.ts +5 -10
- package/gs/syscall/constants.ts +29 -0
- package/gs/syscall/env.ts +47 -0
- package/gs/syscall/errors.ts +658 -0
- package/gs/syscall/fs.ts +62 -0
- package/gs/syscall/index.ts +12 -207
- package/gs/syscall/rawconn.ts +23 -0
- package/gs/syscall/types.ts +18 -0
- package/gs/time/time.ts +35 -21
- package/package.json +2 -2
- 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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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("(")
|
package/compiler/expr-call.go
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
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
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
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
|
}
|
package/compiler/sanitize.go
CHANGED
|
@@ -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
|
-
"
|
|
15
|
-
// Add other built-in types as needed
|
|
14
|
+
"Promise": "PromiseType",
|
|
16
15
|
}
|
|
17
16
|
|
|
18
17
|
if replacement, exists := builtinTypes[name]; exists {
|
package/compiler/spec-struct.go
CHANGED
|
@@ -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
|
|
package/compiler/spec-value.go
CHANGED
|
@@ -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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
213
|
-
if
|
|
214
|
-
|
|
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
|
-
|
|
218
|
-
|
|
219
|
-
return false // Not imported or is local
|
|
200
|
+
_, isBasic := underlying.(*types.Basic)
|
|
201
|
+
return isBasic
|
|
220
202
|
}
|
|
221
203
|
|
|
222
|
-
|
|
223
|
-
if
|
|
224
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
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")
|
package/compiler/stmt-assign.go
CHANGED
|
@@ -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
|
-
//
|
|
291
|
-
|
|
292
|
-
|
|
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
|
package/compiler/stmt-select.go
CHANGED
|
@@ -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.
|
|
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
|
-
//
|
|
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
|
-
|
|
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
|
-
|
|
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)
|