goscript 0.0.45 → 0.0.48
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/README.md +198 -504
- package/compiler/compiler.go +20 -70
- package/compiler/decl.go +52 -38
- package/compiler/expr-call-async.go +101 -0
- package/compiler/expr-call-builtins.go +133 -0
- package/compiler/expr-call-helpers.go +138 -0
- package/compiler/expr-call-make.go +568 -0
- package/compiler/expr-call-type-conversion.go +424 -0
- package/compiler/expr-call.go +59 -1305
- package/compiler/expr.go +126 -4
- package/compiler/spec-struct.go +22 -9
- package/compiler/spec.go +53 -118
- package/compiler/type.go +51 -0
- package/dist/gs/builtin/builtin.d.ts +3 -1
- package/dist/gs/builtin/builtin.js +6 -0
- package/dist/gs/builtin/builtin.js.map +1 -1
- package/dist/gs/io/fs/fs.d.ts +12 -1
- package/dist/gs/io/fs/fs.js +106 -30
- package/dist/gs/io/fs/fs.js.map +1 -1
- package/dist/gs/os/types_js.gs.d.ts +1 -3
- package/dist/gs/os/types_js.gs.js +2 -1
- package/dist/gs/os/types_js.gs.js.map +1 -1
- package/dist/gs/os/types_unix.gs.js +2 -2
- package/dist/gs/os/types_unix.gs.js.map +1 -1
- package/gs/builtin/builtin.ts +7 -2
- package/gs/io/fs/fs.ts +100 -31
- package/gs/io/fs/godoc.txt +370 -17
- package/gs/os/types_js.gs.ts +2 -2
- package/gs/os/types_unix.gs.ts +2 -2
- package/package.json +1 -1
package/compiler/expr-call.go
CHANGED
|
@@ -5,9 +5,6 @@ import (
|
|
|
5
5
|
"go/ast"
|
|
6
6
|
"go/token"
|
|
7
7
|
"go/types"
|
|
8
|
-
"strings"
|
|
9
|
-
|
|
10
|
-
"github.com/pkg/errors"
|
|
11
8
|
)
|
|
12
9
|
|
|
13
10
|
// WriteCallExpr translates a Go function call expression (`ast.CallExpr`)
|
|
@@ -25,7 +22,7 @@ import (
|
|
|
25
22
|
// - `string(runeVal)` becomes `$.runeOrStringToString(runeVal)`.
|
|
26
23
|
// - `string([]runeVal)` becomes `$.runesToString(sliceVal)`.
|
|
27
24
|
// - `string([]byteVal)` becomes `$.bytesToString(sliceVal)`.
|
|
28
|
-
// - `[]rune(stringVal)` becomes `$.stringToRunes(stringVal)
|
|
25
|
+
// - `[]rune(stringVal)` becomes `$.stringToRunes(stringVal)".
|
|
29
26
|
// - `[]byte(stringVal)` becomes `$.stringToBytes(stringVal)`.
|
|
30
27
|
// - `close(ch)` becomes `ch.close()`.
|
|
31
28
|
// - `append(slice, elems...)` becomes `$.append(slice, elems...)`.
|
|
@@ -45,1221 +42,86 @@ func (c *GoToTSCompiler) WriteCallExpr(exp *ast.CallExpr) error {
|
|
|
45
42
|
}
|
|
46
43
|
|
|
47
44
|
// Handle any type conversion with nil argument
|
|
48
|
-
if
|
|
49
|
-
|
|
50
|
-
// Handle nil pointer to struct type conversions: (*struct{})(nil)
|
|
51
|
-
if starExpr, isStarExpr := expFun.(*ast.StarExpr); isStarExpr {
|
|
52
|
-
if _, isStructType := starExpr.X.(*ast.StructType); isStructType {
|
|
53
|
-
c.tsw.WriteLiterally("null")
|
|
54
|
-
return nil
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
c.tsw.WriteLiterally("null")
|
|
59
|
-
return nil
|
|
60
|
-
}
|
|
45
|
+
if handled, err := c.writeNilConversion(exp); handled {
|
|
46
|
+
return err
|
|
61
47
|
}
|
|
62
48
|
|
|
63
49
|
// Handle array type conversions like []rune(string)
|
|
64
|
-
if
|
|
65
|
-
|
|
66
|
-
if ident, isIdent := arrayType.Elt.(*ast.Ident); isIdent && ident.Name == "rune" {
|
|
67
|
-
// Check if the argument is a string
|
|
68
|
-
if len(exp.Args) == 1 {
|
|
69
|
-
arg := exp.Args[0]
|
|
70
|
-
if tv, ok := c.pkg.TypesInfo.Types[arg]; ok && tv.Type != nil {
|
|
71
|
-
if basic, isBasic := tv.Type.Underlying().(*types.Basic); isBasic && basic.Kind() == types.String {
|
|
72
|
-
// Translate []rune(stringValue) to $.stringToRunes(stringValue)
|
|
73
|
-
c.tsw.WriteLiterally("$.stringToRunes(")
|
|
74
|
-
if err := c.WriteValueExpr(arg); err != nil {
|
|
75
|
-
return fmt.Errorf("failed to write argument for []rune(string) conversion: %w", err)
|
|
76
|
-
}
|
|
77
|
-
c.tsw.WriteLiterally(")")
|
|
78
|
-
return nil // Handled []rune(string)
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
// Check if it's a []byte type and the argument is a string
|
|
84
|
-
if eltIdent, ok := arrayType.Elt.(*ast.Ident); ok && eltIdent.Name == "byte" && arrayType.Len == nil {
|
|
85
|
-
if len(exp.Args) == 1 {
|
|
86
|
-
arg := exp.Args[0]
|
|
87
|
-
// Ensure TypesInfo is available and the argument type can be determined
|
|
88
|
-
if tv, typeOk := c.pkg.TypesInfo.Types[arg]; typeOk && tv.Type != nil {
|
|
89
|
-
if basicArgType, isBasic := tv.Type.Underlying().(*types.Basic); isBasic && (basicArgType.Info()&types.IsString) != 0 {
|
|
90
|
-
c.tsw.WriteLiterally("$.stringToBytes(")
|
|
91
|
-
if err := c.WriteValueExpr(arg); err != nil {
|
|
92
|
-
return fmt.Errorf("failed to write argument for []byte(string) conversion: %w", err)
|
|
93
|
-
}
|
|
94
|
-
c.tsw.WriteLiterally(")")
|
|
95
|
-
return nil // Handled []byte(string)
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// Handle general slice type conversions like []T(namedType) where namedType has underlying type []T
|
|
102
|
-
if arrayType.Len == nil && len(exp.Args) == 1 {
|
|
103
|
-
arg := exp.Args[0]
|
|
104
|
-
if argType := c.pkg.TypesInfo.TypeOf(arg); argType != nil {
|
|
105
|
-
// Check if the argument is a named type with a slice underlying type
|
|
106
|
-
if namedArgType, isNamed := argType.(*types.Named); isNamed {
|
|
107
|
-
// Check if the named type has receiver methods (is a wrapper class)
|
|
108
|
-
typeName := namedArgType.Obj().Name()
|
|
109
|
-
if c.hasReceiverMethods(typeName) {
|
|
110
|
-
// Check if the underlying type matches the target slice type
|
|
111
|
-
if sliceUnderlying, isSlice := namedArgType.Underlying().(*types.Slice); isSlice {
|
|
112
|
-
// Get the target slice type
|
|
113
|
-
targetType := c.pkg.TypesInfo.TypeOf(arrayType)
|
|
114
|
-
if targetSliceType, isTargetSlice := targetType.Underlying().(*types.Slice); isTargetSlice {
|
|
115
|
-
// Check if element types are compatible
|
|
116
|
-
if types.Identical(sliceUnderlying.Elem(), targetSliceType.Elem()) {
|
|
117
|
-
// This is a conversion from NamedType to []T where NamedType has underlying []T
|
|
118
|
-
// Use valueOf() to get the underlying slice
|
|
119
|
-
if err := c.WriteValueExpr(arg); err != nil {
|
|
120
|
-
return fmt.Errorf("failed to write argument for slice type conversion: %w", err)
|
|
121
|
-
}
|
|
122
|
-
c.tsw.WriteLiterally(".valueOf()")
|
|
123
|
-
return nil // Handled named type to slice conversion
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
}
|
|
50
|
+
if handled, err := c.writeArrayTypeConversion(exp); handled {
|
|
51
|
+
return err
|
|
131
52
|
}
|
|
132
53
|
|
|
54
|
+
// Handle built-in functions called as identifiers
|
|
133
55
|
if funIdent, funIsIdent := expFun.(*ast.Ident); funIsIdent {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
c.tsw.WriteLiterally("console.log")
|
|
139
|
-
case "len":
|
|
140
|
-
// Translate len(arg) to $.len(arg)
|
|
141
|
-
if len(exp.Args) != 1 {
|
|
142
|
-
return errors.Errorf("unhandled len call with incorrect number of arguments: %d != 1", len(exp.Args))
|
|
56
|
+
// Check for built-in functions first
|
|
57
|
+
if handled, err := c.writeBuiltinFunction(exp, funIdent.String()); handled {
|
|
58
|
+
if err != nil {
|
|
59
|
+
return err
|
|
143
60
|
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
return
|
|
61
|
+
// For built-ins that don't return early, write the arguments
|
|
62
|
+
if funIdent.String() != "new" && funIdent.String() != "close" && funIdent.String() != "make" &&
|
|
63
|
+
funIdent.String() != "string" && funIdent.String() != "append" && funIdent.String() != "byte" &&
|
|
64
|
+
funIdent.String() != "int" {
|
|
65
|
+
return c.writeCallArguments(exp)
|
|
149
66
|
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
// Translate new(T) to new T_ts()
|
|
153
|
-
if len(exp.Args) != 1 {
|
|
154
|
-
return errors.Errorf("unhandled new call with incorrect number of arguments: %d != 1", len(exp.Args))
|
|
155
|
-
}
|
|
156
|
-
c.tsw.WriteLiterally("new ")
|
|
157
|
-
c.WriteTypeExpr(exp.Args[0]) // This should write the TypeScript type T_ts
|
|
158
|
-
c.tsw.WriteLiterally("()")
|
|
159
|
-
return nil // Prevent falling through to generic argument handling
|
|
160
|
-
case "delete":
|
|
161
|
-
// Translate delete(map, key) to $.deleteMapEntry(map, key)
|
|
162
|
-
if len(exp.Args) != 2 {
|
|
163
|
-
return errors.Errorf("unhandled delete call with incorrect number of arguments: %d != 2", len(exp.Args))
|
|
164
|
-
}
|
|
165
|
-
c.tsw.WriteLiterally("$.deleteMapEntry")
|
|
166
|
-
case "copy":
|
|
167
|
-
// Translate copy(dst, src) to $.copy(dst, src)
|
|
168
|
-
if len(exp.Args) != 2 {
|
|
169
|
-
return errors.Errorf("unhandled copy call with incorrect number of arguments: %d != 2", len(exp.Args))
|
|
170
|
-
}
|
|
171
|
-
c.tsw.WriteLiterally("$.copy")
|
|
172
|
-
case "recover":
|
|
173
|
-
// Translate recover() to $.recover()
|
|
174
|
-
if len(exp.Args) != 0 {
|
|
175
|
-
return errors.Errorf("unhandled recover call with incorrect number of arguments: %d != 0", len(exp.Args))
|
|
176
|
-
}
|
|
177
|
-
c.tsw.WriteLiterally("$.recover")
|
|
178
|
-
case "make":
|
|
179
|
-
// First check if we have a channel type
|
|
180
|
-
if typ := c.pkg.TypesInfo.TypeOf(exp.Args[0]); typ != nil {
|
|
181
|
-
if chanType, ok := typ.Underlying().(*types.Chan); ok {
|
|
182
|
-
// Handle channel creation: make(chan T, bufferSize) or make(chan T)
|
|
183
|
-
c.tsw.WriteLiterally("$.makeChannel<")
|
|
184
|
-
c.WriteGoType(chanType.Elem(), GoTypeContextGeneral)
|
|
185
|
-
c.tsw.WriteLiterally(">(")
|
|
186
|
-
|
|
187
|
-
// If buffer size is provided, add it
|
|
188
|
-
if len(exp.Args) >= 2 {
|
|
189
|
-
if err := c.WriteValueExpr(exp.Args[1]); err != nil {
|
|
190
|
-
return fmt.Errorf("failed to write buffer size in makeChannel: %w", err)
|
|
191
|
-
}
|
|
192
|
-
} else {
|
|
193
|
-
// Default to 0 (unbuffered channel)
|
|
194
|
-
c.tsw.WriteLiterally("0")
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
c.tsw.WriteLiterally(", ") // Add comma for zero value argument
|
|
198
|
-
|
|
199
|
-
// Write the zero value for the channel's element type
|
|
200
|
-
if chanType.Elem().String() == "struct{}" {
|
|
201
|
-
c.tsw.WriteLiterally("{}")
|
|
202
|
-
} else {
|
|
203
|
-
c.WriteZeroValueForType(chanType.Elem())
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
// Add direction parameter
|
|
207
|
-
c.tsw.WriteLiterally(", ")
|
|
208
|
-
|
|
209
|
-
// Determine channel direction
|
|
210
|
-
switch chanType.Dir() {
|
|
211
|
-
case types.SendRecv:
|
|
212
|
-
c.tsw.WriteLiterally("'both'")
|
|
213
|
-
case types.SendOnly:
|
|
214
|
-
c.tsw.WriteLiterally("'send'")
|
|
215
|
-
case types.RecvOnly:
|
|
216
|
-
c.tsw.WriteLiterally("'receive'")
|
|
217
|
-
default:
|
|
218
|
-
c.tsw.WriteLiterally("'both'") // Default to bidirectional
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
c.tsw.WriteLiterally(")")
|
|
222
|
-
return nil // Handled make for channel
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
// Handle make for slices: make([]T, len, cap) or make([]T, len)
|
|
226
|
-
if len(exp.Args) >= 1 {
|
|
227
|
-
// Handle map creation: make(map[K]V)
|
|
228
|
-
if mapType, ok := exp.Args[0].(*ast.MapType); ok {
|
|
229
|
-
c.tsw.WriteLiterally("$.makeMap<")
|
|
230
|
-
c.WriteTypeExpr(mapType.Key) // Write the key type
|
|
231
|
-
c.tsw.WriteLiterally(", ")
|
|
232
|
-
c.WriteTypeExpr(mapType.Value) // Write the value type
|
|
233
|
-
c.tsw.WriteLiterally(">()")
|
|
234
|
-
return nil // Handled make for map
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
// Handle slice creation
|
|
238
|
-
if _, ok := exp.Args[0].(*ast.ArrayType); ok {
|
|
239
|
-
// Get the slice type information
|
|
240
|
-
sliceType := c.pkg.TypesInfo.TypeOf(exp.Args[0])
|
|
241
|
-
if sliceType == nil {
|
|
242
|
-
return errors.New("could not get type information for slice in make call")
|
|
243
|
-
}
|
|
244
|
-
goUnderlyingType, ok := sliceType.Underlying().(*types.Slice)
|
|
245
|
-
if !ok {
|
|
246
|
-
return errors.New("expected slice type for make call")
|
|
247
|
-
}
|
|
248
|
-
goElemType := goUnderlyingType.Elem()
|
|
249
|
-
|
|
250
|
-
// Check if it's make([]byte, ...)
|
|
251
|
-
if basicElem, isBasic := goElemType.(*types.Basic); isBasic && basicElem.Kind() == types.Uint8 {
|
|
252
|
-
// Check if capacity is different from length
|
|
253
|
-
if len(exp.Args) == 3 {
|
|
254
|
-
// make([]byte, len, cap) - need to handle capacity
|
|
255
|
-
c.tsw.WriteLiterally("$.makeSlice<number>(")
|
|
256
|
-
if err := c.WriteValueExpr(exp.Args[1]); err != nil { // Length
|
|
257
|
-
return err
|
|
258
|
-
}
|
|
259
|
-
c.tsw.WriteLiterally(", ")
|
|
260
|
-
if err := c.WriteValueExpr(exp.Args[2]); err != nil { // Capacity
|
|
261
|
-
return err
|
|
262
|
-
}
|
|
263
|
-
c.tsw.WriteLiterally(", 'byte')")
|
|
264
|
-
} else {
|
|
265
|
-
// make([]byte, len) - capacity equals length, use Uint8Array
|
|
266
|
-
c.tsw.WriteLiterally("new Uint8Array(")
|
|
267
|
-
if len(exp.Args) >= 2 {
|
|
268
|
-
if err := c.WriteValueExpr(exp.Args[1]); err != nil { // Length
|
|
269
|
-
return err
|
|
270
|
-
}
|
|
271
|
-
} else {
|
|
272
|
-
// If no length is provided, default to 0
|
|
273
|
-
c.tsw.WriteLiterally("0")
|
|
274
|
-
}
|
|
275
|
-
c.tsw.WriteLiterally(")")
|
|
276
|
-
}
|
|
277
|
-
return nil // Handled make for []byte
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
// Check if the element type is a generic type parameter
|
|
281
|
-
if _, isTypeParam := goElemType.(*types.TypeParam); isTypeParam {
|
|
282
|
-
// This is make([]E, n) where E is a type parameter
|
|
283
|
-
c.tsw.WriteLiterally("$.makeSlice<")
|
|
284
|
-
c.WriteGoType(goElemType, GoTypeContextGeneral) // Write the element type parameter
|
|
285
|
-
c.tsw.WriteLiterally(">(")
|
|
286
|
-
|
|
287
|
-
if len(exp.Args) >= 2 {
|
|
288
|
-
if err := c.WriteValueExpr(exp.Args[1]); err != nil { // Length
|
|
289
|
-
return err
|
|
290
|
-
}
|
|
291
|
-
if len(exp.Args) == 3 {
|
|
292
|
-
c.tsw.WriteLiterally(", ")
|
|
293
|
-
if err := c.WriteValueExpr(exp.Args[2]); err != nil { // Capacity
|
|
294
|
-
return err
|
|
295
|
-
}
|
|
296
|
-
} else if len(exp.Args) > 3 {
|
|
297
|
-
return errors.New("makeSlice expects 2 or 3 arguments")
|
|
298
|
-
}
|
|
299
|
-
} else {
|
|
300
|
-
// If no length is provided, default to 0
|
|
301
|
-
c.tsw.WriteLiterally("0")
|
|
302
|
-
}
|
|
303
|
-
c.tsw.WriteLiterally(")")
|
|
304
|
-
return nil // Handled make for []E where E is type parameter
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
c.tsw.WriteLiterally("$.makeSlice<")
|
|
308
|
-
// Use AST-based type writing to preserve qualified names
|
|
309
|
-
if arrType, ok := exp.Args[0].(*ast.ArrayType); ok {
|
|
310
|
-
c.WriteTypeExpr(arrType.Elt)
|
|
311
|
-
} else {
|
|
312
|
-
c.WriteGoType(goElemType, GoTypeContextGeneral)
|
|
313
|
-
}
|
|
314
|
-
c.tsw.WriteLiterally(">(")
|
|
315
|
-
|
|
316
|
-
hasCapacity := len(exp.Args) == 3
|
|
317
|
-
|
|
318
|
-
if len(exp.Args) >= 2 {
|
|
319
|
-
if err := c.WriteValueExpr(exp.Args[1]); err != nil { // Length
|
|
320
|
-
return err
|
|
321
|
-
}
|
|
322
|
-
if hasCapacity {
|
|
323
|
-
c.tsw.WriteLiterally(", ")
|
|
324
|
-
if err := c.WriteValueExpr(exp.Args[2]); err != nil { // Capacity
|
|
325
|
-
return err
|
|
326
|
-
}
|
|
327
|
-
} else if len(exp.Args) > 3 {
|
|
328
|
-
return errors.New("makeSlice expects 2 or 3 arguments")
|
|
329
|
-
}
|
|
330
|
-
} else {
|
|
331
|
-
// If no length is provided, default to 0
|
|
332
|
-
c.tsw.WriteLiterally("0")
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
// Add type hint for proper zero value initialization
|
|
336
|
-
typeHint := c.getTypeHintForSliceElement(goElemType)
|
|
337
|
-
if typeHint != "" {
|
|
338
|
-
if !hasCapacity {
|
|
339
|
-
// If no capacity was provided, add undefined for capacity parameter
|
|
340
|
-
c.tsw.WriteLiterally(", undefined")
|
|
341
|
-
}
|
|
342
|
-
c.tsw.WriteLiterally(", '")
|
|
343
|
-
c.tsw.WriteLiterally(typeHint)
|
|
344
|
-
c.tsw.WriteLiterally("'")
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
c.tsw.WriteLiterally(")")
|
|
348
|
-
return nil // Handled make for slice
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
// Handle generic type parameter make calls: make(S, len, cap) where S ~[]E
|
|
352
|
-
if ident, ok := exp.Args[0].(*ast.Ident); ok {
|
|
353
|
-
// Check if this identifier refers to a type parameter
|
|
354
|
-
if obj := c.pkg.TypesInfo.Uses[ident]; obj != nil {
|
|
355
|
-
if typeName, isTypeName := obj.(*types.TypeName); isTypeName {
|
|
356
|
-
if typeParam, isTypeParam := typeName.Type().(*types.TypeParam); isTypeParam {
|
|
357
|
-
// Check if the type parameter is constrained to slice types
|
|
358
|
-
constraint := typeParam.Constraint()
|
|
359
|
-
if constraint != nil {
|
|
360
|
-
underlying := constraint.Underlying()
|
|
361
|
-
if iface, isInterface := underlying.(*types.Interface); isInterface {
|
|
362
|
-
// Check if the constraint includes slice types
|
|
363
|
-
// For constraints like ~[]E, we need to look at the type terms
|
|
364
|
-
if hasSliceConstraint(iface) {
|
|
365
|
-
// This is a generic slice type parameter
|
|
366
|
-
// We need to determine the element type from the constraint
|
|
367
|
-
elemType := getSliceElementTypeFromConstraint(iface)
|
|
368
|
-
if elemType != nil {
|
|
369
|
-
// Check if it's make(S, ...) where S constrains to []byte
|
|
370
|
-
if basicElem, isBasic := elemType.(*types.Basic); isBasic && basicElem.Kind() == types.Uint8 {
|
|
371
|
-
// Check if capacity is different from length
|
|
372
|
-
if len(exp.Args) == 3 {
|
|
373
|
-
// make([]byte, len, cap) - need to handle capacity
|
|
374
|
-
c.tsw.WriteLiterally("$.makeSlice<number>(")
|
|
375
|
-
if err := c.WriteValueExpr(exp.Args[1]); err != nil { // Length
|
|
376
|
-
return err
|
|
377
|
-
}
|
|
378
|
-
c.tsw.WriteLiterally(", ")
|
|
379
|
-
if err := c.WriteValueExpr(exp.Args[2]); err != nil { // Capacity
|
|
380
|
-
return err
|
|
381
|
-
}
|
|
382
|
-
c.tsw.WriteLiterally(", 'byte')")
|
|
383
|
-
} else {
|
|
384
|
-
// make([]byte, len) - capacity equals length, use Uint8Array
|
|
385
|
-
c.tsw.WriteLiterally("new Uint8Array(")
|
|
386
|
-
if len(exp.Args) >= 2 {
|
|
387
|
-
if err := c.WriteValueExpr(exp.Args[1]); err != nil { // Length
|
|
388
|
-
return err
|
|
389
|
-
}
|
|
390
|
-
} else {
|
|
391
|
-
// If no length is provided, default to 0
|
|
392
|
-
c.tsw.WriteLiterally("0")
|
|
393
|
-
}
|
|
394
|
-
c.tsw.WriteLiterally(")")
|
|
395
|
-
}
|
|
396
|
-
return nil // Handled make for generic []byte
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
c.tsw.WriteLiterally("$.makeSlice<")
|
|
400
|
-
c.WriteGoType(elemType, GoTypeContextGeneral) // Write the element type
|
|
401
|
-
c.tsw.WriteLiterally(">(")
|
|
402
|
-
|
|
403
|
-
hasCapacity := len(exp.Args) == 3
|
|
404
|
-
|
|
405
|
-
if len(exp.Args) >= 2 {
|
|
406
|
-
if err := c.WriteValueExpr(exp.Args[1]); err != nil { // Length
|
|
407
|
-
return err
|
|
408
|
-
}
|
|
409
|
-
if hasCapacity {
|
|
410
|
-
c.tsw.WriteLiterally(", ")
|
|
411
|
-
if err := c.WriteValueExpr(exp.Args[2]); err != nil { // Capacity
|
|
412
|
-
return err
|
|
413
|
-
}
|
|
414
|
-
} else if len(exp.Args) > 3 {
|
|
415
|
-
return errors.New("makeSlice expects 2 or 3 arguments")
|
|
416
|
-
}
|
|
417
|
-
} else {
|
|
418
|
-
// If no length is provided, default to 0
|
|
419
|
-
c.tsw.WriteLiterally("0")
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
// Add type hint for proper zero value initialization
|
|
423
|
-
typeHint := c.getTypeHintForSliceElement(elemType)
|
|
424
|
-
if typeHint != "" {
|
|
425
|
-
if !hasCapacity {
|
|
426
|
-
// If no capacity was provided, add undefined for capacity parameter
|
|
427
|
-
c.tsw.WriteLiterally(", undefined")
|
|
428
|
-
}
|
|
429
|
-
c.tsw.WriteLiterally(", '")
|
|
430
|
-
c.tsw.WriteLiterally(typeHint)
|
|
431
|
-
c.tsw.WriteLiterally("'")
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
c.tsw.WriteLiterally(")")
|
|
435
|
-
return nil // Handled make for generic slice
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
} else {
|
|
441
|
-
// Handle named types with slice underlying types: make(NamedSliceType, len, cap)
|
|
442
|
-
// This handles cases like: type appendSliceWriter []byte; make(appendSliceWriter, 0, len(s))
|
|
443
|
-
namedType := typeName.Type()
|
|
444
|
-
if sliceType, isSlice := namedType.Underlying().(*types.Slice); isSlice {
|
|
445
|
-
goElemType := sliceType.Elem()
|
|
446
|
-
|
|
447
|
-
// Check if it's a named type with []byte underlying type
|
|
448
|
-
if basicElem, isBasic := goElemType.(*types.Basic); isBasic && basicElem.Kind() == types.Uint8 {
|
|
449
|
-
// Check if capacity is different from length
|
|
450
|
-
if len(exp.Args) == 3 {
|
|
451
|
-
// make([]byte, len, cap) - need to handle capacity
|
|
452
|
-
c.tsw.WriteLiterally("$.makeSlice<number>(")
|
|
453
|
-
if err := c.WriteValueExpr(exp.Args[1]); err != nil { // Length
|
|
454
|
-
return err
|
|
455
|
-
}
|
|
456
|
-
c.tsw.WriteLiterally(", ")
|
|
457
|
-
if err := c.WriteValueExpr(exp.Args[2]); err != nil { // Capacity
|
|
458
|
-
return err
|
|
459
|
-
}
|
|
460
|
-
c.tsw.WriteLiterally(", 'byte')")
|
|
461
|
-
} else {
|
|
462
|
-
// make([]byte, len) - capacity equals length, use Uint8Array
|
|
463
|
-
c.tsw.WriteLiterally("new Uint8Array(")
|
|
464
|
-
if len(exp.Args) >= 2 {
|
|
465
|
-
if err := c.WriteValueExpr(exp.Args[1]); err != nil { // Length
|
|
466
|
-
return err
|
|
467
|
-
}
|
|
468
|
-
} else {
|
|
469
|
-
// If no length is provided, default to 0
|
|
470
|
-
c.tsw.WriteLiterally("0")
|
|
471
|
-
}
|
|
472
|
-
c.tsw.WriteLiterally(")")
|
|
473
|
-
}
|
|
474
|
-
return nil // Handled make for named []byte type
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
// Handle other named slice types
|
|
478
|
-
c.tsw.WriteLiterally("$.makeSlice<")
|
|
479
|
-
c.WriteGoType(goElemType, GoTypeContextGeneral) // Write the element type
|
|
480
|
-
c.tsw.WriteLiterally(">(")
|
|
481
|
-
|
|
482
|
-
hasCapacity := len(exp.Args) == 3
|
|
483
|
-
|
|
484
|
-
if len(exp.Args) >= 2 {
|
|
485
|
-
if err := c.WriteValueExpr(exp.Args[1]); err != nil { // Length
|
|
486
|
-
return err
|
|
487
|
-
}
|
|
488
|
-
if hasCapacity {
|
|
489
|
-
c.tsw.WriteLiterally(", ")
|
|
490
|
-
if err := c.WriteValueExpr(exp.Args[2]); err != nil { // Capacity
|
|
491
|
-
return err
|
|
492
|
-
}
|
|
493
|
-
} else if len(exp.Args) > 3 {
|
|
494
|
-
return errors.New("makeSlice expects 2 or 3 arguments")
|
|
495
|
-
}
|
|
496
|
-
} else {
|
|
497
|
-
// If no length is provided, default to 0
|
|
498
|
-
c.tsw.WriteLiterally("0")
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
// Add type hint for proper zero value initialization
|
|
502
|
-
typeHint := c.getTypeHintForSliceElement(goElemType)
|
|
503
|
-
if typeHint != "" {
|
|
504
|
-
if !hasCapacity {
|
|
505
|
-
// If no capacity was provided, add undefined for capacity parameter
|
|
506
|
-
c.tsw.WriteLiterally(", undefined")
|
|
507
|
-
}
|
|
508
|
-
c.tsw.WriteLiterally(", '")
|
|
509
|
-
c.tsw.WriteLiterally(typeHint)
|
|
510
|
-
c.tsw.WriteLiterally("'")
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
c.tsw.WriteLiterally(")")
|
|
514
|
-
return nil // Handled make for named slice type
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
// Handle named types with map underlying types: make(NamedMapType)
|
|
518
|
-
if mapType, isMap := namedType.Underlying().(*types.Map); isMap {
|
|
519
|
-
c.tsw.WriteLiterally("$.makeMap<")
|
|
520
|
-
c.WriteGoType(mapType.Key(), GoTypeContextGeneral) // Write the key type
|
|
521
|
-
c.tsw.WriteLiterally(", ")
|
|
522
|
-
c.WriteGoType(mapType.Elem(), GoTypeContextGeneral) // Write the value type
|
|
523
|
-
c.tsw.WriteLiterally(">()")
|
|
524
|
-
return nil // Handled make for named map type
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
// Handle named types with channel underlying types: make(NamedChannelType, bufferSize)
|
|
528
|
-
if chanType, isChan := namedType.Underlying().(*types.Chan); isChan {
|
|
529
|
-
c.tsw.WriteLiterally("$.makeChannel<")
|
|
530
|
-
c.WriteGoType(chanType.Elem(), GoTypeContextGeneral)
|
|
531
|
-
c.tsw.WriteLiterally(">(")
|
|
532
|
-
|
|
533
|
-
// If buffer size is provided, add it
|
|
534
|
-
if len(exp.Args) >= 2 {
|
|
535
|
-
if err := c.WriteValueExpr(exp.Args[1]); err != nil {
|
|
536
|
-
return fmt.Errorf("failed to write buffer size in makeChannel: %w", err)
|
|
537
|
-
}
|
|
538
|
-
} else {
|
|
539
|
-
// Default to 0 (unbuffered channel)
|
|
540
|
-
c.tsw.WriteLiterally("0")
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
c.tsw.WriteLiterally(", ") // Add comma for zero value argument
|
|
544
|
-
|
|
545
|
-
// Write the zero value for the channel's element type
|
|
546
|
-
if chanType.Elem().String() == "struct{}" {
|
|
547
|
-
c.tsw.WriteLiterally("{}")
|
|
548
|
-
} else {
|
|
549
|
-
c.WriteZeroValueForType(chanType.Elem())
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
// Add direction parameter
|
|
553
|
-
c.tsw.WriteLiterally(", ")
|
|
554
|
-
|
|
555
|
-
// Determine channel direction
|
|
556
|
-
switch chanType.Dir() {
|
|
557
|
-
case types.SendRecv:
|
|
558
|
-
c.tsw.WriteLiterally("'both'")
|
|
559
|
-
case types.SendOnly:
|
|
560
|
-
c.tsw.WriteLiterally("'send'")
|
|
561
|
-
case types.RecvOnly:
|
|
562
|
-
c.tsw.WriteLiterally("'receive'")
|
|
563
|
-
default:
|
|
564
|
-
c.tsw.WriteLiterally("'both'") // Default to bidirectional
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
c.tsw.WriteLiterally(")")
|
|
568
|
-
return nil // Handled make for named channel type
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
}
|
|
575
|
-
// Handle instantiated generic types: make(GenericType[TypeArg], ...)
|
|
576
|
-
// This handles cases like: make(Ints[int64]) where Ints[T] is a generic type
|
|
577
|
-
if indexExpr, ok := exp.Args[0].(*ast.IndexExpr); ok {
|
|
578
|
-
// Get the type information for the instantiated generic type
|
|
579
|
-
if typ := c.pkg.TypesInfo.TypeOf(indexExpr); typ != nil {
|
|
580
|
-
// Check the underlying type of the instantiated generic type
|
|
581
|
-
underlying := typ.Underlying()
|
|
582
|
-
|
|
583
|
-
// Handle instantiated generic map types: make(GenericMap[K, V])
|
|
584
|
-
if mapType, isMap := underlying.(*types.Map); isMap {
|
|
585
|
-
c.tsw.WriteLiterally("$.makeMap<")
|
|
586
|
-
c.WriteGoType(mapType.Key(), GoTypeContextGeneral) // Write the key type
|
|
587
|
-
c.tsw.WriteLiterally(", ")
|
|
588
|
-
c.WriteGoType(mapType.Elem(), GoTypeContextGeneral) // Write the value type
|
|
589
|
-
c.tsw.WriteLiterally(">()")
|
|
590
|
-
return nil // Handled make for instantiated generic map type
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
// Handle instantiated generic slice types: make(GenericSlice[T], len, cap)
|
|
594
|
-
if sliceType, isSlice := underlying.(*types.Slice); isSlice {
|
|
595
|
-
goElemType := sliceType.Elem()
|
|
596
|
-
|
|
597
|
-
// Check if it's an instantiated generic type with []byte underlying type
|
|
598
|
-
if basicElem, isBasic := goElemType.(*types.Basic); isBasic && basicElem.Kind() == types.Uint8 {
|
|
599
|
-
// Check if capacity is different from length
|
|
600
|
-
if len(exp.Args) == 3 {
|
|
601
|
-
// make([]byte, len, cap) - need to handle capacity
|
|
602
|
-
c.tsw.WriteLiterally("$.makeSlice<number>(")
|
|
603
|
-
if err := c.WriteValueExpr(exp.Args[1]); err != nil { // Length
|
|
604
|
-
return err
|
|
605
|
-
}
|
|
606
|
-
c.tsw.WriteLiterally(", ")
|
|
607
|
-
if err := c.WriteValueExpr(exp.Args[2]); err != nil { // Capacity
|
|
608
|
-
return err
|
|
609
|
-
}
|
|
610
|
-
c.tsw.WriteLiterally(", 'byte')")
|
|
611
|
-
} else {
|
|
612
|
-
// make([]byte, len) - capacity equals length, use Uint8Array
|
|
613
|
-
c.tsw.WriteLiterally("new Uint8Array(")
|
|
614
|
-
if len(exp.Args) >= 2 {
|
|
615
|
-
if err := c.WriteValueExpr(exp.Args[1]); err != nil { // Length
|
|
616
|
-
return err
|
|
617
|
-
}
|
|
618
|
-
} else {
|
|
619
|
-
// If no length is provided, default to 0
|
|
620
|
-
c.tsw.WriteLiterally("0")
|
|
621
|
-
}
|
|
622
|
-
c.tsw.WriteLiterally(")")
|
|
623
|
-
}
|
|
624
|
-
return nil // Handled make for instantiated generic []byte type
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
// Handle other instantiated generic slice types
|
|
628
|
-
c.tsw.WriteLiterally("$.makeSlice<")
|
|
629
|
-
c.WriteGoType(goElemType, GoTypeContextGeneral) // Write the element type
|
|
630
|
-
c.tsw.WriteLiterally(">(")
|
|
631
|
-
|
|
632
|
-
hasCapacity := len(exp.Args) == 3
|
|
633
|
-
|
|
634
|
-
if len(exp.Args) >= 2 {
|
|
635
|
-
if err := c.WriteValueExpr(exp.Args[1]); err != nil { // Length
|
|
636
|
-
return err
|
|
637
|
-
}
|
|
638
|
-
if hasCapacity {
|
|
639
|
-
c.tsw.WriteLiterally(", ")
|
|
640
|
-
if err := c.WriteValueExpr(exp.Args[2]); err != nil { // Capacity
|
|
641
|
-
return err
|
|
642
|
-
}
|
|
643
|
-
} else if len(exp.Args) > 3 {
|
|
644
|
-
return errors.New("makeSlice expects 2 or 3 arguments")
|
|
645
|
-
}
|
|
646
|
-
} else {
|
|
647
|
-
// If no length is provided, default to 0
|
|
648
|
-
c.tsw.WriteLiterally("0")
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
// Add type hint for proper zero value initialization
|
|
652
|
-
typeHint := c.getTypeHintForSliceElement(goElemType)
|
|
653
|
-
if typeHint != "" {
|
|
654
|
-
if !hasCapacity {
|
|
655
|
-
// If no capacity was provided, add undefined for capacity parameter
|
|
656
|
-
c.tsw.WriteLiterally(", undefined")
|
|
657
|
-
}
|
|
658
|
-
c.tsw.WriteLiterally(", '")
|
|
659
|
-
c.tsw.WriteLiterally(typeHint)
|
|
660
|
-
c.tsw.WriteLiterally("'")
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
c.tsw.WriteLiterally(")")
|
|
664
|
-
return nil // Handled make for instantiated generic slice type
|
|
665
|
-
}
|
|
666
|
-
|
|
667
|
-
// Handle instantiated generic channel types: make(GenericChannel[T], bufferSize)
|
|
668
|
-
if chanType, isChan := underlying.(*types.Chan); isChan {
|
|
669
|
-
c.tsw.WriteLiterally("$.makeChannel<")
|
|
670
|
-
c.WriteGoType(chanType.Elem(), GoTypeContextGeneral)
|
|
671
|
-
c.tsw.WriteLiterally(">(")
|
|
672
|
-
|
|
673
|
-
// If buffer size is provided, add it
|
|
674
|
-
if len(exp.Args) >= 2 {
|
|
675
|
-
if err := c.WriteValueExpr(exp.Args[1]); err != nil {
|
|
676
|
-
return fmt.Errorf("failed to write buffer size in makeChannel: %w", err)
|
|
677
|
-
}
|
|
678
|
-
} else {
|
|
679
|
-
// Default to 0 (unbuffered channel)
|
|
680
|
-
c.tsw.WriteLiterally("0")
|
|
681
|
-
}
|
|
682
|
-
|
|
683
|
-
c.tsw.WriteLiterally(", ") // Add comma for zero value argument
|
|
684
|
-
|
|
685
|
-
// Write the zero value for the channel's element type
|
|
686
|
-
if chanType.Elem().String() == "struct{}" {
|
|
687
|
-
c.tsw.WriteLiterally("{}")
|
|
688
|
-
} else {
|
|
689
|
-
c.WriteZeroValueForType(chanType.Elem())
|
|
690
|
-
}
|
|
691
|
-
|
|
692
|
-
// Add direction parameter
|
|
693
|
-
c.tsw.WriteLiterally(", ")
|
|
694
|
-
|
|
695
|
-
// Determine channel direction
|
|
696
|
-
switch chanType.Dir() {
|
|
697
|
-
case types.SendRecv:
|
|
698
|
-
c.tsw.WriteLiterally("'both'")
|
|
699
|
-
case types.SendOnly:
|
|
700
|
-
c.tsw.WriteLiterally("'send'")
|
|
701
|
-
case types.RecvOnly:
|
|
702
|
-
c.tsw.WriteLiterally("'receive'")
|
|
703
|
-
default:
|
|
704
|
-
c.tsw.WriteLiterally("'both'") // Default to bidirectional
|
|
705
|
-
}
|
|
706
|
-
|
|
707
|
-
c.tsw.WriteLiterally(")")
|
|
708
|
-
return nil // Handled make for instantiated generic channel type
|
|
709
|
-
}
|
|
710
|
-
}
|
|
711
|
-
}
|
|
712
|
-
// Handle selector expressions: make(pkg.TypeName, ...)
|
|
713
|
-
// This handles cases like: make(fstest.MapFS) where fstest.MapFS is map[string]*MapFile
|
|
714
|
-
if selectorExpr, ok := exp.Args[0].(*ast.SelectorExpr); ok {
|
|
715
|
-
// Get the type information for the selector expression
|
|
716
|
-
if typ := c.pkg.TypesInfo.TypeOf(selectorExpr); typ != nil {
|
|
717
|
-
// Check the underlying type of the selector expression
|
|
718
|
-
underlying := typ.Underlying()
|
|
719
|
-
|
|
720
|
-
// Handle selector expression map types: make(pkg.MapType)
|
|
721
|
-
if mapType, isMap := underlying.(*types.Map); isMap {
|
|
722
|
-
c.tsw.WriteLiterally("$.makeMap<")
|
|
723
|
-
c.WriteGoType(mapType.Key(), GoTypeContextGeneral) // Write the key type
|
|
724
|
-
c.tsw.WriteLiterally(", ")
|
|
725
|
-
c.WriteGoType(mapType.Elem(), GoTypeContextGeneral) // Write the value type
|
|
726
|
-
c.tsw.WriteLiterally(">()")
|
|
727
|
-
return nil // Handled make for selector expression map type
|
|
728
|
-
}
|
|
729
|
-
|
|
730
|
-
// Handle selector expression slice types: make(pkg.SliceType, len, cap)
|
|
731
|
-
if sliceType, isSlice := underlying.(*types.Slice); isSlice {
|
|
732
|
-
goElemType := sliceType.Elem()
|
|
733
|
-
|
|
734
|
-
// Check if it's a selector expression with []byte underlying type
|
|
735
|
-
if basicElem, isBasic := goElemType.(*types.Basic); isBasic && basicElem.Kind() == types.Uint8 {
|
|
736
|
-
// Check if capacity is different from length
|
|
737
|
-
if len(exp.Args) == 3 {
|
|
738
|
-
// make([]byte, len, cap) - need to handle capacity
|
|
739
|
-
c.tsw.WriteLiterally("$.makeSlice<number>(")
|
|
740
|
-
if err := c.WriteValueExpr(exp.Args[1]); err != nil { // Length
|
|
741
|
-
return err
|
|
742
|
-
}
|
|
743
|
-
c.tsw.WriteLiterally(", ")
|
|
744
|
-
if err := c.WriteValueExpr(exp.Args[2]); err != nil { // Capacity
|
|
745
|
-
return err
|
|
746
|
-
}
|
|
747
|
-
c.tsw.WriteLiterally(", 'byte')")
|
|
748
|
-
} else {
|
|
749
|
-
// make([]byte, len) - capacity equals length, use Uint8Array
|
|
750
|
-
c.tsw.WriteLiterally("new Uint8Array(")
|
|
751
|
-
if len(exp.Args) >= 2 {
|
|
752
|
-
if err := c.WriteValueExpr(exp.Args[1]); err != nil { // Length
|
|
753
|
-
return err
|
|
754
|
-
}
|
|
755
|
-
} else {
|
|
756
|
-
// If no length is provided, default to 0
|
|
757
|
-
c.tsw.WriteLiterally("0")
|
|
758
|
-
}
|
|
759
|
-
c.tsw.WriteLiterally(")")
|
|
760
|
-
}
|
|
761
|
-
return nil // Handled make for selector expression []byte type
|
|
762
|
-
}
|
|
763
|
-
|
|
764
|
-
// Handle other selector expression slice types
|
|
765
|
-
c.tsw.WriteLiterally("$.makeSlice<")
|
|
766
|
-
c.WriteGoType(goElemType, GoTypeContextGeneral) // Write the element type
|
|
767
|
-
c.tsw.WriteLiterally(">(")
|
|
768
|
-
|
|
769
|
-
hasCapacity := len(exp.Args) == 3
|
|
770
|
-
|
|
771
|
-
if len(exp.Args) >= 2 {
|
|
772
|
-
if err := c.WriteValueExpr(exp.Args[1]); err != nil { // Length
|
|
773
|
-
return err
|
|
774
|
-
}
|
|
775
|
-
if hasCapacity {
|
|
776
|
-
c.tsw.WriteLiterally(", ")
|
|
777
|
-
if err := c.WriteValueExpr(exp.Args[2]); err != nil { // Capacity
|
|
778
|
-
return err
|
|
779
|
-
}
|
|
780
|
-
} else if len(exp.Args) > 3 {
|
|
781
|
-
return errors.New("makeSlice expects 2 or 3 arguments")
|
|
782
|
-
}
|
|
783
|
-
} else {
|
|
784
|
-
// If no length is provided, default to 0
|
|
785
|
-
c.tsw.WriteLiterally("0")
|
|
786
|
-
}
|
|
787
|
-
|
|
788
|
-
// Add type hint for proper zero value initialization
|
|
789
|
-
typeHint := c.getTypeHintForSliceElement(goElemType)
|
|
790
|
-
if typeHint != "" {
|
|
791
|
-
if !hasCapacity {
|
|
792
|
-
// If no capacity was provided, add undefined for capacity parameter
|
|
793
|
-
c.tsw.WriteLiterally(", undefined")
|
|
794
|
-
}
|
|
795
|
-
c.tsw.WriteLiterally(", '")
|
|
796
|
-
c.tsw.WriteLiterally(typeHint)
|
|
797
|
-
c.tsw.WriteLiterally("'")
|
|
798
|
-
}
|
|
799
|
-
|
|
800
|
-
c.tsw.WriteLiterally(")")
|
|
801
|
-
return nil // Handled make for selector expression slice type
|
|
802
|
-
}
|
|
803
|
-
|
|
804
|
-
// Handle selector expression channel types: make(pkg.ChannelType, bufferSize)
|
|
805
|
-
if chanType, isChan := underlying.(*types.Chan); isChan {
|
|
806
|
-
c.tsw.WriteLiterally("$.makeChannel<")
|
|
807
|
-
c.WriteGoType(chanType.Elem(), GoTypeContextGeneral)
|
|
808
|
-
c.tsw.WriteLiterally(">(")
|
|
809
|
-
|
|
810
|
-
// If buffer size is provided, add it
|
|
811
|
-
if len(exp.Args) >= 2 {
|
|
812
|
-
if err := c.WriteValueExpr(exp.Args[1]); err != nil {
|
|
813
|
-
return fmt.Errorf("failed to write buffer size in makeChannel: %w", err)
|
|
814
|
-
}
|
|
815
|
-
} else {
|
|
816
|
-
// Default to 0 (unbuffered channel)
|
|
817
|
-
c.tsw.WriteLiterally("0")
|
|
818
|
-
}
|
|
819
|
-
|
|
820
|
-
c.tsw.WriteLiterally(", ") // Add comma for zero value argument
|
|
821
|
-
|
|
822
|
-
// Write the zero value for the channel's element type
|
|
823
|
-
if chanType.Elem().String() == "struct{}" {
|
|
824
|
-
c.tsw.WriteLiterally("{}")
|
|
825
|
-
} else {
|
|
826
|
-
c.WriteZeroValueForType(chanType.Elem())
|
|
827
|
-
}
|
|
828
|
-
|
|
829
|
-
// Add direction parameter
|
|
830
|
-
c.tsw.WriteLiterally(", ")
|
|
831
|
-
|
|
832
|
-
// Determine channel direction
|
|
833
|
-
switch chanType.Dir() {
|
|
834
|
-
case types.SendRecv:
|
|
835
|
-
c.tsw.WriteLiterally("'both'")
|
|
836
|
-
case types.SendOnly:
|
|
837
|
-
c.tsw.WriteLiterally("'send'")
|
|
838
|
-
case types.RecvOnly:
|
|
839
|
-
c.tsw.WriteLiterally("'receive'")
|
|
840
|
-
default:
|
|
841
|
-
c.tsw.WriteLiterally("'both'") // Default to bidirectional
|
|
842
|
-
}
|
|
843
|
-
|
|
844
|
-
c.tsw.WriteLiterally(")")
|
|
845
|
-
return nil // Handled make for selector expression channel type
|
|
846
|
-
}
|
|
847
|
-
}
|
|
848
|
-
}
|
|
849
|
-
// Fallthrough for unhandled make calls (e.g., channels)
|
|
850
|
-
return errors.New("unhandled make call")
|
|
851
|
-
case "string":
|
|
852
|
-
// Handle string() conversion
|
|
853
|
-
if len(exp.Args) == 1 {
|
|
854
|
-
arg := exp.Args[0]
|
|
855
|
-
|
|
856
|
-
// Case 1: Argument is a string literal string("...")
|
|
857
|
-
if basicLit, isBasicLit := arg.(*ast.BasicLit); isBasicLit && basicLit.Kind == token.STRING {
|
|
858
|
-
// Translate string("...") to "..." (no-op)
|
|
859
|
-
c.WriteBasicLit(basicLit)
|
|
860
|
-
return nil // Handled string literal conversion
|
|
861
|
-
}
|
|
862
|
-
|
|
863
|
-
// Case 2: Argument is a rune (int32) or a call to rune()
|
|
864
|
-
innerCall, isCallExpr := arg.(*ast.CallExpr)
|
|
865
|
-
|
|
866
|
-
if isCallExpr {
|
|
867
|
-
// Check if it's a call to rune()
|
|
868
|
-
if innerFunIdent, innerFunIsIdent := innerCall.Fun.(*ast.Ident); innerFunIsIdent && innerFunIdent.String() == "rune" {
|
|
869
|
-
// Translate string(rune(val)) to $.runeOrStringToString(val)
|
|
870
|
-
if len(innerCall.Args) == 1 {
|
|
871
|
-
c.tsw.WriteLiterally("$.runeOrStringToString(")
|
|
872
|
-
if err := c.WriteValueExpr(innerCall.Args[0]); err != nil {
|
|
873
|
-
return fmt.Errorf("failed to write argument for string(rune) conversion: %w", err)
|
|
874
|
-
}
|
|
875
|
-
c.tsw.WriteLiterally(")")
|
|
876
|
-
return nil // Handled string(rune)
|
|
877
|
-
}
|
|
878
|
-
}
|
|
879
|
-
}
|
|
880
|
-
|
|
881
|
-
// Handle direct string(int32) conversion
|
|
882
|
-
// This assumes 'rune' is int32
|
|
883
|
-
if tv, ok := c.pkg.TypesInfo.Types[arg]; ok {
|
|
884
|
-
// Case 3a: Argument is already a string - no-op
|
|
885
|
-
if basic, isBasic := tv.Type.Underlying().(*types.Basic); isBasic && basic.Kind() == types.String {
|
|
886
|
-
// Translate string(stringValue) to stringValue (no-op)
|
|
887
|
-
if err := c.WriteValueExpr(arg); err != nil {
|
|
888
|
-
return fmt.Errorf("failed to write argument for string(string) no-op conversion: %w", err)
|
|
889
|
-
}
|
|
890
|
-
return nil // Handled string(string) no-op
|
|
891
|
-
}
|
|
892
|
-
|
|
893
|
-
if basic, isBasic := tv.Type.Underlying().(*types.Basic); isBasic && (basic.Kind() == types.Int32 || basic.Kind() == types.UntypedRune) {
|
|
894
|
-
// Translate string(rune_val) to $.runeOrStringToString(rune_val)
|
|
895
|
-
c.tsw.WriteLiterally("$.runeOrStringToString(")
|
|
896
|
-
if err := c.WriteValueExpr(arg); err != nil {
|
|
897
|
-
return fmt.Errorf("failed to write argument for string(int32) conversion: %w", err)
|
|
898
|
-
}
|
|
899
|
-
c.tsw.WriteLiterally(")")
|
|
900
|
-
return nil // Handled string(int32)
|
|
901
|
-
}
|
|
902
|
-
|
|
903
|
-
// Case 3: Argument is a slice of runes or bytes string([]rune{...}) or string([]byte{...})
|
|
904
|
-
if sliceType, isSlice := tv.Type.Underlying().(*types.Slice); isSlice {
|
|
905
|
-
if basic, isBasic := sliceType.Elem().Underlying().(*types.Basic); isBasic {
|
|
906
|
-
// Handle string([]byte)
|
|
907
|
-
if basic.Kind() == types.Uint8 {
|
|
908
|
-
c.tsw.WriteLiterally("$.bytesToString(")
|
|
909
|
-
if err := c.WriteValueExpr(arg); err != nil {
|
|
910
|
-
return fmt.Errorf("failed to write argument for string([]byte) conversion: %w", err)
|
|
911
|
-
}
|
|
912
|
-
c.tsw.WriteLiterally(")")
|
|
913
|
-
return nil // Handled string([]byte)
|
|
914
|
-
}
|
|
915
|
-
// Handle both runes (int32)
|
|
916
|
-
if basic.Kind() == types.Int32 {
|
|
917
|
-
// Translate string([]rune) to $.runesToString(...)
|
|
918
|
-
c.tsw.WriteLiterally("$.runesToString(")
|
|
919
|
-
if err := c.WriteValueExpr(arg); err != nil {
|
|
920
|
-
return fmt.Errorf("failed to write argument for string([]rune) conversion: %w", err)
|
|
921
|
-
}
|
|
922
|
-
c.tsw.WriteLiterally(")")
|
|
923
|
-
return nil // Handled string([]rune)
|
|
924
|
-
}
|
|
925
|
-
}
|
|
926
|
-
}
|
|
927
|
-
|
|
928
|
-
// Case 4: Argument is a generic type parameter (e.g., string | []byte)
|
|
929
|
-
if typeParam, isTypeParam := tv.Type.(*types.TypeParam); isTypeParam {
|
|
930
|
-
// Check if this is a []byte | string union constraint
|
|
931
|
-
constraint := typeParam.Constraint()
|
|
932
|
-
if constraint != nil {
|
|
933
|
-
// For now, assume any type parameter that could be string or []byte needs the helper
|
|
934
|
-
// This is a heuristic - in the future we could parse the constraint more precisely
|
|
935
|
-
c.tsw.WriteLiterally("$.genericBytesOrStringToString(")
|
|
936
|
-
if err := c.WriteValueExpr(arg); err != nil {
|
|
937
|
-
return fmt.Errorf("failed to write argument for string(generic) conversion: %w", err)
|
|
938
|
-
}
|
|
939
|
-
c.tsw.WriteLiterally(")")
|
|
940
|
-
return nil // Handled string(generic type parameter)
|
|
941
|
-
}
|
|
942
|
-
}
|
|
943
|
-
}
|
|
944
|
-
}
|
|
945
|
-
// Return error for other unhandled string conversions
|
|
946
|
-
return fmt.Errorf("unhandled string conversion: %s", exp.Fun)
|
|
947
|
-
case "close":
|
|
948
|
-
// Translate close(ch) to ch.close()
|
|
949
|
-
if len(exp.Args) == 1 {
|
|
950
|
-
if err := c.WriteValueExpr(exp.Args[0]); err != nil {
|
|
951
|
-
return fmt.Errorf("failed to write channel in close call: %w", err)
|
|
952
|
-
}
|
|
953
|
-
c.tsw.WriteLiterally(".close()")
|
|
954
|
-
return nil // Handled close
|
|
955
|
-
}
|
|
956
|
-
return errors.New("unhandled close call with incorrect number of arguments")
|
|
957
|
-
case "append":
|
|
958
|
-
// Translate append(slice, elements...) to $.append(slice, elements...)
|
|
959
|
-
if len(exp.Args) >= 1 {
|
|
960
|
-
c.tsw.WriteLiterally("$.append(")
|
|
961
|
-
// The first argument is the slice
|
|
962
|
-
if err := c.WriteValueExpr(exp.Args[0]); err != nil {
|
|
963
|
-
return fmt.Errorf("failed to write slice in append call: %w", err)
|
|
964
|
-
}
|
|
965
|
-
// The remaining arguments are the elements to append
|
|
966
|
-
for i, arg := range exp.Args[1:] {
|
|
967
|
-
if i > 0 || len(exp.Args) > 1 { // Add comma before elements if there are any
|
|
968
|
-
c.tsw.WriteLiterally(", ")
|
|
969
|
-
}
|
|
970
|
-
|
|
971
|
-
// Special case: append([]byte, string...) should convert string to bytes
|
|
972
|
-
if exp.Ellipsis != token.NoPos && i == 0 { // This is the first element after slice and has ellipsis
|
|
973
|
-
// Check if the slice is []byte and the argument is a string
|
|
974
|
-
sliceType := c.pkg.TypesInfo.TypeOf(exp.Args[0])
|
|
975
|
-
argType := c.pkg.TypesInfo.TypeOf(arg)
|
|
976
|
-
|
|
977
|
-
if sliceType != nil && argType != nil {
|
|
978
|
-
// Check if slice is []byte (Uint8Array)
|
|
979
|
-
isSliceOfBytes := false
|
|
980
|
-
if sliceUnder, ok := sliceType.Underlying().(*types.Slice); ok {
|
|
981
|
-
if basicElem, ok := sliceUnder.Elem().(*types.Basic); ok && basicElem.Kind() == types.Uint8 {
|
|
982
|
-
isSliceOfBytes = true
|
|
983
|
-
}
|
|
984
|
-
}
|
|
985
|
-
|
|
986
|
-
// Check if argument is string (including untyped string)
|
|
987
|
-
isArgString := false
|
|
988
|
-
if basicArg, ok := argType.Underlying().(*types.Basic); ok && (basicArg.Kind() == types.String || basicArg.Kind() == types.UntypedString) {
|
|
989
|
-
isArgString = true
|
|
990
|
-
}
|
|
991
|
-
|
|
992
|
-
if isSliceOfBytes && isArgString {
|
|
993
|
-
// Convert string to bytes: append([]byte, string...) -> $.append(slice, ...$.stringToBytes(string))
|
|
994
|
-
c.tsw.WriteLiterally("...$.stringToBytes(")
|
|
995
|
-
if err := c.WriteValueExpr(arg); err != nil {
|
|
996
|
-
return fmt.Errorf("failed to write string argument in append call: %w", err)
|
|
997
|
-
}
|
|
998
|
-
c.tsw.WriteLiterally(")")
|
|
999
|
-
continue
|
|
1000
|
-
}
|
|
1001
|
-
}
|
|
1002
|
-
}
|
|
1003
|
-
|
|
1004
|
-
if err := c.WriteValueExpr(arg); err != nil {
|
|
1005
|
-
return fmt.Errorf("failed to write argument %d in append call: %w", i+1, err)
|
|
1006
|
-
}
|
|
1007
|
-
}
|
|
1008
|
-
c.tsw.WriteLiterally(")")
|
|
1009
|
-
return nil // Handled append
|
|
1010
|
-
}
|
|
1011
|
-
return errors.New("unhandled append call with incorrect number of arguments")
|
|
1012
|
-
case "byte":
|
|
1013
|
-
// Translate byte(arg) to $.byte(arg)
|
|
1014
|
-
if len(exp.Args) != 1 {
|
|
1015
|
-
return errors.Errorf("unhandled byte call with incorrect number of arguments: %d != 1", len(exp.Args))
|
|
1016
|
-
}
|
|
1017
|
-
c.tsw.WriteLiterally("$.byte(")
|
|
1018
|
-
if err := c.WriteValueExpr(exp.Args[0]); err != nil {
|
|
1019
|
-
return fmt.Errorf("failed to write argument for byte() conversion: %w", err)
|
|
1020
|
-
}
|
|
1021
|
-
c.tsw.WriteLiterally(")")
|
|
1022
|
-
return nil // Handled byte() conversion
|
|
1023
|
-
case "int":
|
|
1024
|
-
// Handle int() conversion
|
|
1025
|
-
if len(exp.Args) == 1 {
|
|
1026
|
-
arg := exp.Args[0]
|
|
1027
|
-
|
|
1028
|
-
// Check if we're converting FROM a type with receiver methods TO int
|
|
1029
|
-
if argType := c.pkg.TypesInfo.TypeOf(arg); argType != nil {
|
|
1030
|
-
if namedArgType, isNamed := argType.(*types.Named); isNamed {
|
|
1031
|
-
argTypeName := namedArgType.Obj().Name()
|
|
1032
|
-
// Check if the argument type has receiver methods
|
|
1033
|
-
if c.hasReceiverMethods(argTypeName) {
|
|
1034
|
-
// Check if we're converting to int (the underlying type)
|
|
1035
|
-
if types.Identical(types.Typ[types.Int], namedArgType.Underlying()) {
|
|
1036
|
-
// This is a conversion from a type with methods to int
|
|
1037
|
-
// Use valueOf() instead of $.int()
|
|
1038
|
-
if err := c.WriteValueExpr(arg); err != nil {
|
|
1039
|
-
return fmt.Errorf("failed to write argument for valueOf conversion: %w", err)
|
|
1040
|
-
}
|
|
1041
|
-
c.tsw.WriteLiterally(".valueOf()")
|
|
1042
|
-
return nil // Handled conversion from type with methods to int
|
|
1043
|
-
}
|
|
1044
|
-
}
|
|
1045
|
-
}
|
|
1046
|
-
}
|
|
1047
|
-
|
|
1048
|
-
// Default case: Translate int(value) to $.int(value)
|
|
1049
|
-
c.tsw.WriteLiterally("$.int(")
|
|
1050
|
-
if err := c.WriteValueExpr(exp.Args[0]); err != nil {
|
|
1051
|
-
return fmt.Errorf("failed to write argument for int() conversion: %w", err)
|
|
1052
|
-
}
|
|
1053
|
-
c.tsw.WriteLiterally(")")
|
|
1054
|
-
return nil // Handled int() conversion
|
|
1055
|
-
}
|
|
1056
|
-
// Return error for incorrect number of arguments
|
|
1057
|
-
return fmt.Errorf("unhandled int conversion with incorrect number of arguments: %d != 1", len(exp.Args))
|
|
1058
|
-
default:
|
|
1059
|
-
// Check if this is a type conversion to a function type
|
|
1060
|
-
if funIdent != nil {
|
|
1061
|
-
if obj := c.pkg.TypesInfo.Uses[funIdent]; obj != nil {
|
|
1062
|
-
// Check if the object is a type name
|
|
1063
|
-
if typeName, isType := obj.(*types.TypeName); isType {
|
|
1064
|
-
// Make sure we have exactly one argument
|
|
1065
|
-
if len(exp.Args) == 1 {
|
|
1066
|
-
arg := exp.Args[0]
|
|
1067
|
-
|
|
1068
|
-
// Check if we're converting FROM a type with receiver methods TO its underlying type
|
|
1069
|
-
if argType := c.pkg.TypesInfo.TypeOf(arg); argType != nil {
|
|
1070
|
-
if namedArgType, isNamed := argType.(*types.Named); isNamed {
|
|
1071
|
-
argTypeName := namedArgType.Obj().Name()
|
|
1072
|
-
// Check if the argument type has receiver methods
|
|
1073
|
-
if c.hasReceiverMethods(argTypeName) {
|
|
1074
|
-
// Check if we're converting to the underlying type
|
|
1075
|
-
targetType := typeName.Type()
|
|
1076
|
-
underlyingType := namedArgType.Underlying()
|
|
1077
|
-
if types.Identical(targetType, underlyingType) {
|
|
1078
|
-
// This is a conversion from a type with methods to its underlying type
|
|
1079
|
-
// Use valueOf() instead of TypeScript cast
|
|
1080
|
-
if err := c.WriteValueExpr(arg); err != nil {
|
|
1081
|
-
return fmt.Errorf("failed to write argument for valueOf conversion: %w", err)
|
|
1082
|
-
}
|
|
1083
|
-
c.tsw.WriteLiterally(".valueOf()")
|
|
1084
|
-
return nil // Handled conversion from type with methods to underlying type
|
|
1085
|
-
}
|
|
1086
|
-
}
|
|
1087
|
-
}
|
|
1088
|
-
}
|
|
1089
|
-
|
|
1090
|
-
// Check if this is a function type
|
|
1091
|
-
if _, isFuncType := typeName.Type().Underlying().(*types.Signature); isFuncType {
|
|
1092
|
-
// For function types, we need to add a __goTypeName property
|
|
1093
|
-
c.tsw.WriteLiterally("Object.assign(")
|
|
67
|
+
return nil
|
|
68
|
+
}
|
|
1094
69
|
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
70
|
+
// Check for type conversions
|
|
71
|
+
if handled, err := c.writeTypeConversion(exp, funIdent); handled {
|
|
72
|
+
return err
|
|
73
|
+
}
|
|
1099
74
|
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
return nil // Handled function type cast
|
|
1103
|
-
} else {
|
|
1104
|
-
// Check if this type has receiver methods
|
|
1105
|
-
if c.hasReceiverMethods(funIdent.String()) {
|
|
1106
|
-
// For types with methods, use class constructor
|
|
1107
|
-
c.tsw.WriteLiterally("new ")
|
|
1108
|
-
c.tsw.WriteLiterally(funIdent.String())
|
|
1109
|
-
c.tsw.WriteLiterally("(")
|
|
1110
|
-
if err := c.WriteValueExpr(exp.Args[0]); err != nil {
|
|
1111
|
-
return fmt.Errorf("failed to write argument for type constructor: %w", err)
|
|
1112
|
-
}
|
|
1113
|
-
c.tsw.WriteLiterally(")")
|
|
1114
|
-
return nil // Handled type with methods conversion
|
|
1115
|
-
} else {
|
|
1116
|
-
// For non-function types without methods, use the TypeScript "as" operator
|
|
1117
|
-
c.tsw.WriteLiterally("(")
|
|
1118
|
-
if err := c.WriteValueExpr(exp.Args[0]); err != nil {
|
|
1119
|
-
return fmt.Errorf("failed to write argument for type cast: %w", err)
|
|
1120
|
-
}
|
|
75
|
+
// Check if this is an async function call
|
|
76
|
+
_ = c.writeAsyncCall(exp, funIdent)
|
|
1121
77
|
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
return nil // Handled non-function type cast
|
|
1127
|
-
}
|
|
1128
|
-
}
|
|
1129
|
-
}
|
|
1130
|
-
}
|
|
1131
|
-
}
|
|
1132
|
-
}
|
|
78
|
+
// Not a special built-in, treat as a regular function call
|
|
79
|
+
if err := c.WriteValueExpr(expFun); err != nil {
|
|
80
|
+
return fmt.Errorf("failed to write function expression in call: %w", err)
|
|
81
|
+
}
|
|
1133
82
|
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
if obj := c.pkg.TypesInfo.Uses[funIdent]; obj != nil && c.analysis.IsAsyncFunc(obj) {
|
|
1138
|
-
// This is an async function
|
|
1139
|
-
c.tsw.WriteLiterally("await ")
|
|
1140
|
-
}
|
|
1141
|
-
}
|
|
83
|
+
c.addNonNullAssertion(expFun)
|
|
84
|
+
return c.writeCallArguments(exp)
|
|
85
|
+
}
|
|
1142
86
|
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
87
|
+
// Handle qualified type conversions like os.FileMode(value)
|
|
88
|
+
if selectorExpr, ok := expFun.(*ast.SelectorExpr); ok {
|
|
89
|
+
if handled, err := c.writeQualifiedTypeConversion(exp, selectorExpr); handled {
|
|
90
|
+
return err
|
|
91
|
+
}
|
|
92
|
+
}
|
|
1147
93
|
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
if ident, isIdent := expFun.(*ast.Ident); isIdent {
|
|
1152
|
-
// Check if this identifier is a function parameter
|
|
1153
|
-
if obj := c.pkg.TypesInfo.Uses[ident]; obj != nil {
|
|
1154
|
-
if _, isVar := obj.(*types.Var); isVar {
|
|
1155
|
-
// This is a variable (including function parameters)
|
|
1156
|
-
// Function parameters that are function types need ! assertion
|
|
1157
|
-
c.tsw.WriteLiterally("!")
|
|
1158
|
-
}
|
|
1159
|
-
}
|
|
1160
|
-
} else if _, isNamed := funType.(*types.Named); isNamed {
|
|
1161
|
-
c.tsw.WriteLiterally("!")
|
|
1162
|
-
}
|
|
1163
|
-
}
|
|
1164
|
-
}
|
|
94
|
+
// Handle non-identifier function expressions (method calls, function literals, etc.)
|
|
95
|
+
// Check if this is an async method call (e.g., mu.Lock())
|
|
96
|
+
_ = c.writeAsyncMethodCall(exp)
|
|
1165
97
|
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
// Check if this is the last argument and we have ellipsis (variadic call)
|
|
1172
|
-
if exp.Ellipsis != token.NoPos && i == len(exp.Args)-1 {
|
|
1173
|
-
c.tsw.WriteLiterally("...")
|
|
1174
|
-
}
|
|
1175
|
-
if err := c.WriteValueExpr(arg); err != nil {
|
|
1176
|
-
return fmt.Errorf("failed to write argument %d in call: %w", i, err)
|
|
1177
|
-
}
|
|
1178
|
-
// Add non-null assertion for spread arguments that might be null
|
|
1179
|
-
if exp.Ellipsis != token.NoPos && i == len(exp.Args)-1 {
|
|
1180
|
-
// Check if the argument type is potentially nullable (slice)
|
|
1181
|
-
if argType := c.pkg.TypesInfo.TypeOf(arg); argType != nil {
|
|
1182
|
-
if _, isSlice := argType.Underlying().(*types.Slice); isSlice {
|
|
1183
|
-
c.tsw.WriteLiterally("!")
|
|
1184
|
-
}
|
|
1185
|
-
}
|
|
1186
|
-
}
|
|
1187
|
-
}
|
|
1188
|
-
c.tsw.WriteLiterally(")")
|
|
1189
|
-
return nil // Handled regular function call
|
|
98
|
+
// If expFun is a function literal, it needs to be wrapped in parentheses for IIFE syntax
|
|
99
|
+
if _, isFuncLit := expFun.(*ast.FuncLit); isFuncLit {
|
|
100
|
+
c.tsw.WriteLiterally("(")
|
|
101
|
+
if err := c.WriteValueExpr(expFun); err != nil {
|
|
102
|
+
return fmt.Errorf("failed to write function literal in call: %w", err)
|
|
1190
103
|
}
|
|
104
|
+
c.tsw.WriteLiterally(")")
|
|
1191
105
|
} else {
|
|
1192
|
-
//
|
|
1193
|
-
if
|
|
1194
|
-
|
|
1195
|
-
if ident, ok := selExpr.X.(*ast.Ident); ok {
|
|
1196
|
-
// Get the type of the receiver
|
|
1197
|
-
if obj := c.pkg.TypesInfo.Uses[ident]; obj != nil {
|
|
1198
|
-
if varObj, ok := obj.(*types.Var); ok {
|
|
1199
|
-
// Get the type name and package
|
|
1200
|
-
if namedType, ok := varObj.Type().(*types.Named); ok {
|
|
1201
|
-
typeName := namedType.Obj().Name()
|
|
1202
|
-
methodName := selExpr.Sel.Name
|
|
1203
|
-
|
|
1204
|
-
// Check if the type is from an imported package
|
|
1205
|
-
if typePkg := namedType.Obj().Pkg(); typePkg != nil && typePkg != c.pkg.Types {
|
|
1206
|
-
// Use the actual package name from the type information
|
|
1207
|
-
pkgName := typePkg.Name()
|
|
1208
|
-
|
|
1209
|
-
// Check if this method is async based on metadata
|
|
1210
|
-
if c.analysis.IsMethodAsync(pkgName, typeName, methodName) {
|
|
1211
|
-
c.tsw.WriteLiterally("await ")
|
|
1212
|
-
}
|
|
1213
|
-
}
|
|
1214
|
-
}
|
|
1215
|
-
}
|
|
1216
|
-
}
|
|
1217
|
-
}
|
|
106
|
+
// Not an identifier (e.g., method call on a value, function call result)
|
|
107
|
+
if err := c.WriteValueExpr(expFun); err != nil {
|
|
108
|
+
return fmt.Errorf("failed to write method expression in call: %w", err)
|
|
1218
109
|
}
|
|
1219
110
|
|
|
1220
|
-
//
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
return fmt.Errorf("failed to write function literal in call: %w", err)
|
|
1225
|
-
}
|
|
1226
|
-
c.tsw.WriteLiterally(")")
|
|
111
|
+
// Check if this is a function call that returns a function (e.g., simpleIterator(m)())
|
|
112
|
+
// Add non-null assertion since the returned function could be null
|
|
113
|
+
if _, isCallExpr := expFun.(*ast.CallExpr); isCallExpr {
|
|
114
|
+
c.tsw.WriteLiterally("!")
|
|
1227
115
|
} else {
|
|
1228
|
-
|
|
1229
|
-
if err := c.WriteValueExpr(expFun); err != nil {
|
|
1230
|
-
return fmt.Errorf("failed to write method expression in call: %w", err)
|
|
1231
|
-
}
|
|
1232
|
-
|
|
1233
|
-
// Check if this is a function call that returns a function (e.g., simpleIterator(m)())
|
|
1234
|
-
// Add non-null assertion since the returned function could be null
|
|
1235
|
-
if _, isCallExpr := expFun.(*ast.CallExpr); isCallExpr {
|
|
1236
|
-
c.tsw.WriteLiterally("!")
|
|
1237
|
-
} else if funType := c.pkg.TypesInfo.TypeOf(expFun); funType != nil {
|
|
1238
|
-
if _, ok := funType.Underlying().(*types.Signature); ok {
|
|
1239
|
-
// Check if this is a function parameter identifier that needs not-null assertion
|
|
1240
|
-
if ident, isIdent := expFun.(*ast.Ident); isIdent {
|
|
1241
|
-
// Check if this identifier is a function parameter
|
|
1242
|
-
if obj := c.pkg.TypesInfo.Uses[ident]; obj != nil {
|
|
1243
|
-
if _, isVar := obj.(*types.Var); isVar {
|
|
1244
|
-
// This is a variable (including function parameters)
|
|
1245
|
-
// Function parameters that are function types need ! assertion
|
|
1246
|
-
c.tsw.WriteLiterally("!")
|
|
1247
|
-
}
|
|
1248
|
-
}
|
|
1249
|
-
} else if _, isNamed := funType.(*types.Named); isNamed {
|
|
1250
|
-
c.tsw.WriteLiterally("!")
|
|
1251
|
-
}
|
|
1252
|
-
} else {
|
|
1253
|
-
// Check if the function type is nullable (e.g., func(...) | null)
|
|
1254
|
-
// This handles cases where a function call returns a nullable function
|
|
1255
|
-
funTypeStr := funType.String()
|
|
1256
|
-
if strings.Contains(funTypeStr, "| null") || strings.Contains(funTypeStr, "null |") {
|
|
1257
|
-
c.tsw.WriteLiterally("!")
|
|
1258
|
-
}
|
|
1259
|
-
}
|
|
1260
|
-
}
|
|
116
|
+
c.addNonNullAssertion(expFun)
|
|
1261
117
|
}
|
|
1262
118
|
}
|
|
119
|
+
|
|
120
|
+
return c.writeCallArguments(exp)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// writeCallArguments writes the argument list for a function call
|
|
124
|
+
func (c *GoToTSCompiler) writeCallArguments(exp *ast.CallExpr) error {
|
|
1263
125
|
c.tsw.WriteLiterally("(")
|
|
1264
126
|
for i, arg := range exp.Args {
|
|
1265
127
|
if i != 0 {
|
|
@@ -1285,111 +147,3 @@ func (c *GoToTSCompiler) WriteCallExpr(exp *ast.CallExpr) error {
|
|
|
1285
147
|
c.tsw.WriteLiterally(")")
|
|
1286
148
|
return nil
|
|
1287
149
|
}
|
|
1288
|
-
|
|
1289
|
-
// hasSliceConstraint checks if an interface constraint includes slice types
|
|
1290
|
-
// For constraints like ~[]E, this returns true
|
|
1291
|
-
func hasSliceConstraint(iface *types.Interface) bool {
|
|
1292
|
-
// Check if the interface has type terms that include slice types
|
|
1293
|
-
for i := 0; i < iface.NumEmbeddeds(); i++ {
|
|
1294
|
-
embedded := iface.EmbeddedType(i)
|
|
1295
|
-
if union, ok := embedded.(*types.Union); ok {
|
|
1296
|
-
for j := 0; j < union.Len(); j++ {
|
|
1297
|
-
term := union.Term(j)
|
|
1298
|
-
if _, isSlice := term.Type().Underlying().(*types.Slice); isSlice {
|
|
1299
|
-
return true
|
|
1300
|
-
}
|
|
1301
|
-
}
|
|
1302
|
-
} else if _, isSlice := embedded.Underlying().(*types.Slice); isSlice {
|
|
1303
|
-
return true
|
|
1304
|
-
}
|
|
1305
|
-
}
|
|
1306
|
-
return false
|
|
1307
|
-
}
|
|
1308
|
-
|
|
1309
|
-
// getSliceElementTypeFromConstraint extracts the element type from a slice constraint
|
|
1310
|
-
// For constraints like ~[]E, this returns E
|
|
1311
|
-
func getSliceElementTypeFromConstraint(iface *types.Interface) types.Type {
|
|
1312
|
-
// Check if the interface has type terms that include slice types
|
|
1313
|
-
for i := 0; i < iface.NumEmbeddeds(); i++ {
|
|
1314
|
-
embedded := iface.EmbeddedType(i)
|
|
1315
|
-
if union, ok := embedded.(*types.Union); ok {
|
|
1316
|
-
for j := 0; j < union.Len(); j++ {
|
|
1317
|
-
term := union.Term(j)
|
|
1318
|
-
if sliceType, isSlice := term.Type().Underlying().(*types.Slice); isSlice {
|
|
1319
|
-
return sliceType.Elem()
|
|
1320
|
-
}
|
|
1321
|
-
}
|
|
1322
|
-
} else if sliceType, isSlice := embedded.Underlying().(*types.Slice); isSlice {
|
|
1323
|
-
return sliceType.Elem()
|
|
1324
|
-
}
|
|
1325
|
-
}
|
|
1326
|
-
return nil
|
|
1327
|
-
}
|
|
1328
|
-
|
|
1329
|
-
// hasMixedStringByteConstraint checks if an interface constraint includes both string and []byte types
|
|
1330
|
-
// For constraints like string | []byte, this returns true
|
|
1331
|
-
// For pure slice constraints like ~[]E, this returns false
|
|
1332
|
-
func hasMixedStringByteConstraint(iface *types.Interface) bool {
|
|
1333
|
-
hasString := false
|
|
1334
|
-
hasByteSlice := false
|
|
1335
|
-
|
|
1336
|
-
// Check if the interface has type terms that include both string and []byte
|
|
1337
|
-
for i := 0; i < iface.NumEmbeddeds(); i++ {
|
|
1338
|
-
embedded := iface.EmbeddedType(i)
|
|
1339
|
-
if union, ok := embedded.(*types.Union); ok {
|
|
1340
|
-
for j := 0; j < union.Len(); j++ {
|
|
1341
|
-
term := union.Term(j)
|
|
1342
|
-
termType := term.Type().Underlying()
|
|
1343
|
-
|
|
1344
|
-
// Check for string type
|
|
1345
|
-
if basicType, isBasic := termType.(*types.Basic); isBasic && (basicType.Info()&types.IsString) != 0 {
|
|
1346
|
-
hasString = true
|
|
1347
|
-
}
|
|
1348
|
-
|
|
1349
|
-
// Check for []byte type
|
|
1350
|
-
if sliceType, isSlice := termType.(*types.Slice); isSlice {
|
|
1351
|
-
if elemType, isBasic := sliceType.Elem().(*types.Basic); isBasic && elemType.Kind() == types.Uint8 {
|
|
1352
|
-
hasByteSlice = true
|
|
1353
|
-
}
|
|
1354
|
-
}
|
|
1355
|
-
}
|
|
1356
|
-
} else {
|
|
1357
|
-
// Handle non-union embedded types
|
|
1358
|
-
termType := embedded.Underlying()
|
|
1359
|
-
|
|
1360
|
-
// Check for string type
|
|
1361
|
-
if basicType, isBasic := termType.(*types.Basic); isBasic && (basicType.Info()&types.IsString) != 0 {
|
|
1362
|
-
hasString = true
|
|
1363
|
-
}
|
|
1364
|
-
|
|
1365
|
-
// Check for []byte type
|
|
1366
|
-
if sliceType, isSlice := termType.(*types.Slice); isSlice {
|
|
1367
|
-
if elemType, isBasic := sliceType.Elem().(*types.Basic); isBasic && elemType.Kind() == types.Uint8 {
|
|
1368
|
-
hasByteSlice = true
|
|
1369
|
-
}
|
|
1370
|
-
}
|
|
1371
|
-
}
|
|
1372
|
-
}
|
|
1373
|
-
|
|
1374
|
-
// Return true only if we have both string and []byte in the constraint
|
|
1375
|
-
return hasString && hasByteSlice
|
|
1376
|
-
}
|
|
1377
|
-
|
|
1378
|
-
// getTypeHintForSliceElement returns the appropriate type hint for makeSlice based on the Go element type
|
|
1379
|
-
func (c *GoToTSCompiler) getTypeHintForSliceElement(elemType types.Type) string {
|
|
1380
|
-
if basicType, isBasic := elemType.(*types.Basic); isBasic {
|
|
1381
|
-
switch basicType.Kind() {
|
|
1382
|
-
case types.Int, types.Int8, types.Int16, types.Int32, types.Int64,
|
|
1383
|
-
types.Uint, types.Uint8, types.Uint16, types.Uint32, types.Uint64,
|
|
1384
|
-
types.Float32, types.Float64, types.Complex64, types.Complex128:
|
|
1385
|
-
return "number"
|
|
1386
|
-
case types.Bool:
|
|
1387
|
-
return "boolean"
|
|
1388
|
-
case types.String:
|
|
1389
|
-
return "string"
|
|
1390
|
-
}
|
|
1391
|
-
}
|
|
1392
|
-
// For other types (structs, interfaces, pointers, etc.), don't provide a hint
|
|
1393
|
-
// This will use the default null initialization which is appropriate for object types
|
|
1394
|
-
return ""
|
|
1395
|
-
}
|