goscript 0.0.20 → 0.0.22

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.
@@ -0,0 +1,223 @@
1
+ package compiler
2
+
3
+ import (
4
+ "fmt"
5
+ "go/ast"
6
+ )
7
+
8
+ // WriteDecls iterates through a slice of Go top-level declarations (`ast.Decl`)
9
+ // and translates each one into its TypeScript equivalent.
10
+ // It distinguishes between:
11
+ // - Function declarations (`ast.FuncDecl`):
12
+ // - If it's a regular function (no receiver), it delegates to `WriteFuncDeclAsFunction`.
13
+ // - Methods (with receivers) are handled within `WriteTypeSpec` when their
14
+ // associated struct/type is defined, so they are skipped here.
15
+ // - General declarations (`ast.GenDecl`), which can contain imports, constants,
16
+ // variables, or type definitions: It iterates through `d.Specs` and calls
17
+ // `WriteSpec` for each specification.
18
+ //
19
+ // A newline is added after each processed declaration or spec group for readability.
20
+ // Unknown declaration types result in a printed diagnostic message.
21
+ func (c *GoToTSCompiler) WriteDecls(decls []ast.Decl) error {
22
+ for _, decl := range decls {
23
+ switch d := decl.(type) {
24
+ case *ast.FuncDecl:
25
+ // Only handle top-level functions here. Methods are handled within WriteTypeSpec.
26
+ if d.Recv == nil {
27
+ if err := c.WriteFuncDeclAsFunction(d); err != nil {
28
+ return err
29
+ }
30
+ c.tsw.WriteLine("") // Add space after function
31
+ }
32
+ case *ast.GenDecl:
33
+ for _, spec := range d.Specs {
34
+ if err := c.WriteSpec(spec); err != nil {
35
+ return err
36
+ }
37
+ c.tsw.WriteLine("") // Add space after spec
38
+ }
39
+ default:
40
+ fmt.Printf("unknown decl: %#v\n", decl)
41
+ }
42
+ }
43
+ return nil
44
+ }
45
+
46
+ // WriteFuncDeclAsFunction translates a Go function declaration (`ast.FuncDecl`)
47
+ // that does not have a receiver (i.e., it's a regular function, not a method)
48
+ // into a TypeScript function.
49
+ // - Go documentation comments (`decl.Doc`) are preserved.
50
+ // - If the Go function is exported (name starts with an uppercase letter) or is
51
+ // the `main` function, the `export` keyword is added to the TypeScript output.
52
+ // - If the `Analysis` data indicates the function is asynchronous, the `async`
53
+ // keyword is prepended.
54
+ // - The function signature (parameters and return type) is translated using `WriteFuncType`,
55
+ // passing the `isAsync` status.
56
+ // - The function body (`decl.Body`) is translated using `WriteStmt`.
57
+ //
58
+ // This function specifically handles top-level functions; methods are generated
59
+ // by `WriteFuncDeclAsMethod` within the context of their type definition.
60
+ func (c *GoToTSCompiler) WriteFuncDeclAsFunction(decl *ast.FuncDecl) error {
61
+ if decl.Recv != nil {
62
+ // This function should not be called for methods.
63
+ // Methods are handled by WriteFuncDeclAsMethod within WriteTypeSpec.
64
+ return nil
65
+ }
66
+
67
+ if decl.Doc != nil {
68
+ c.WriteDoc(decl.Doc)
69
+ }
70
+
71
+ // Exported functions start with uppercase in Go, or special-case "main" entry point
72
+ isExported := decl.Name.IsExported() || decl.Name.Name == "main"
73
+ if isExported {
74
+ c.tsw.WriteLiterally("export ")
75
+ }
76
+
77
+ // Check if this function is async using the analysis data
78
+ var isAsync bool
79
+ if obj := c.pkg.TypesInfo.Defs[decl.Name]; obj != nil {
80
+ isAsync = c.analysis.IsAsyncFunc(obj)
81
+ }
82
+ if isAsync {
83
+ c.tsw.WriteLiterally("async ")
84
+ }
85
+
86
+ c.tsw.WriteLiterally("function ")
87
+ if err := c.WriteValueExpr(decl.Name); err != nil { // Function name is a value identifier
88
+ return fmt.Errorf("failed to write function name: %w", err)
89
+ }
90
+
91
+ // WriteFuncType needs to be aware if the function is async
92
+ c.WriteFuncType(decl.Type, isAsync) // Write signature (params, return type)
93
+ c.tsw.WriteLiterally(" ")
94
+
95
+ if err := c.WriteStmt(decl.Body); err != nil {
96
+ return fmt.Errorf("failed to write function body: %w", err)
97
+ }
98
+
99
+ return nil
100
+ }
101
+
102
+ // WriteFuncDeclAsMethod translates a Go function declaration (`ast.FuncDecl`)
103
+ // that has a receiver (i.e., it's a method) into a TypeScript class method.
104
+ // - It preserves Go documentation comments (`decl.Doc`).
105
+ // - The method is declared as `public`.
106
+ // - If the `Analysis` data indicates the method is asynchronous, the `async`
107
+ // keyword is prepended.
108
+ // - The method name retains its original Go casing.
109
+ // - Parameters and return types are translated using `WriteFieldList` and
110
+ // `WriteTypeExpr`, respectively. Async methods have their return types
111
+ // wrapped in `Promise<>`.
112
+ // - The method body is translated. If the Go receiver has a name (e.g., `(s *MyStruct)`),
113
+ // a `const receiverName = this;` binding is generated at the start of the
114
+ // TypeScript method body to make `this` available via the Go receiver's name.
115
+ // If the method body requires deferred cleanup (`NeedsDefer`), the appropriate
116
+ // `using __defer = new $.DisposableStack()` (or `AsyncDisposableStack`)
117
+ // is also generated.
118
+ //
119
+ // This function assumes it is called only for `FuncDecl` nodes that are methods.
120
+ func (c *GoToTSCompiler) WriteFuncDeclAsMethod(decl *ast.FuncDecl) error {
121
+ if decl.Doc != nil {
122
+ c.WriteDoc(decl.Doc)
123
+ }
124
+
125
+ // Determine if method is async
126
+ var isAsync bool
127
+ if obj := c.pkg.TypesInfo.Defs[decl.Name]; obj != nil {
128
+ isAsync = c.analysis.IsAsyncFunc(obj)
129
+ }
130
+
131
+ // Methods are typically public in the TS output
132
+ c.tsw.WriteLiterally("public ")
133
+
134
+ // Add async modifier if needed
135
+ if isAsync {
136
+ c.tsw.WriteLiterally("async ")
137
+ }
138
+
139
+ // Keep original Go casing for method names
140
+ if err := c.WriteValueExpr(decl.Name); err != nil { // Method name is a value identifier
141
+ return err
142
+ }
143
+
144
+ // Write signature (parameters and return type)
145
+ // We adapt the logic from WriteFuncType here, but without the 'function' keyword
146
+ funcType := decl.Type
147
+ c.tsw.WriteLiterally("(")
148
+ if funcType.Params != nil {
149
+ c.WriteFieldList(funcType.Params, true) // true = arguments
150
+ }
151
+ c.tsw.WriteLiterally(")")
152
+
153
+ // Handle return type
154
+ if funcType.Results != nil && len(funcType.Results.List) > 0 {
155
+ c.tsw.WriteLiterally(": ")
156
+ if isAsync {
157
+ c.tsw.WriteLiterally("Promise<")
158
+ }
159
+ if len(funcType.Results.List) == 1 {
160
+ // Single return value
161
+ resultType := funcType.Results.List[0].Type
162
+ c.WriteTypeExpr(resultType)
163
+ } else {
164
+ // Multiple return values -> tuple type
165
+ c.tsw.WriteLiterally("[")
166
+ for i, field := range funcType.Results.List {
167
+ if i > 0 {
168
+ c.tsw.WriteLiterally(", ")
169
+ }
170
+ c.WriteTypeExpr(field.Type)
171
+ }
172
+ c.tsw.WriteLiterally("]")
173
+ }
174
+ if isAsync {
175
+ c.tsw.WriteLiterally(">")
176
+ }
177
+ } else {
178
+ // No return value -> void
179
+ if isAsync {
180
+ c.tsw.WriteLiterally(": Promise<void>")
181
+ } else {
182
+ c.tsw.WriteLiterally(": void")
183
+ }
184
+ }
185
+
186
+ c.tsw.WriteLiterally(" ")
187
+
188
+ // Bind receiver name to this
189
+ if recvField := decl.Recv.List[0]; len(recvField.Names) > 0 {
190
+ recvName := recvField.Names[0].Name
191
+ if recvName != "_" {
192
+ c.tsw.WriteLine("{")
193
+ c.tsw.Indent(1)
194
+ c.tsw.WriteLinef("const %s = this", recvName)
195
+
196
+ // Add using statement if needed
197
+ if c.analysis.NeedsDefer(decl.Body) {
198
+ if c.analysis.IsInAsyncFunction(decl) {
199
+ c.tsw.WriteLine("await using __defer = new $.AsyncDisposableStack();")
200
+ } else {
201
+ c.tsw.WriteLine("using cleanup = new $.DisposableStack();")
202
+ }
203
+ }
204
+
205
+ // write method body without outer braces
206
+ for _, stmt := range decl.Body.List {
207
+ if err := c.WriteStmt(stmt); err != nil {
208
+ return fmt.Errorf("failed to write statement in function body: %w", err)
209
+ }
210
+ }
211
+ c.tsw.Indent(-1)
212
+ c.tsw.WriteLine("}")
213
+
214
+ return nil
215
+ }
216
+ }
217
+ // no named receiver, write whole body
218
+ if err := c.WriteStmt(decl.Body); err != nil {
219
+ return fmt.Errorf("failed to write function body: %w", err)
220
+ }
221
+
222
+ return nil
223
+ }
@@ -0,0 +1,423 @@
1
+ package compiler
2
+
3
+ import (
4
+ "fmt"
5
+ "go/ast"
6
+ "go/token"
7
+ "go/types"
8
+
9
+ "github.com/pkg/errors"
10
+ )
11
+
12
+ // WriteCallExpr translates a Go function call expression (`ast.CallExpr`)
13
+ // into its TypeScript equivalent.
14
+ // It handles several Go built-in functions specially:
15
+ // - `println(...)` becomes `console.log(...)`.
16
+ // - `len(arg)` becomes `$.len(arg)`.
17
+ // - `cap(arg)` becomes `$.cap(arg)`.
18
+ // - `delete(m, k)` becomes `$.deleteMapEntry(m, k)`.
19
+ // - `make(chan T, size)` becomes `$.makeChannel<T_ts>(size, zeroValueForT)`.
20
+ // - `make(map[K]V)` becomes `$.makeMap<K_ts, V_ts>()`.
21
+ // - `make([]T, len, cap)` becomes `$.makeSlice<T_ts>(len, cap)`.
22
+ // - `string(runeVal)` becomes `String.fromCharCode(runeVal)`.
23
+ // - `string([]runeVal)` or `string([]byteVal)` becomes `$.runesToString(sliceVal)`.
24
+ // - `[]rune(stringVal)` becomes `$.stringToRunes(stringVal)`.
25
+ // - `close(ch)` becomes `ch.close()`.
26
+ // - `append(slice, elems...)` becomes `$.append(slice, elems...)`.
27
+ // - `byte(val)` becomes `$.byte(val)`.
28
+ // For other function calls:
29
+ // - If the `Analysis` data indicates the function is asynchronous (e.g., due to
30
+ // channel operations or `go`/`defer` usage within it), the call is prefixed with `await`.
31
+ // - Otherwise, it's translated as a standard TypeScript function call: `funcName(arg1, arg2)`.
32
+ //
33
+ // Arguments are recursively translated using `WriteValueExpr`.
34
+ func (c *GoToTSCompiler) WriteCallExpr(exp *ast.CallExpr) error {
35
+ expFun := exp.Fun
36
+
37
+ // Handle any type conversion with nil argument
38
+ if len(exp.Args) == 1 {
39
+ if nilIdent, isIdent := exp.Args[0].(*ast.Ident); isIdent && nilIdent.Name == "nil" {
40
+ // Handle nil pointer to struct type conversions: (*struct{})(nil)
41
+ if starExpr, isStarExpr := expFun.(*ast.StarExpr); isStarExpr {
42
+ if _, isStructType := starExpr.X.(*ast.StructType); isStructType {
43
+ c.tsw.WriteLiterally("null")
44
+ return nil
45
+ }
46
+ }
47
+
48
+ c.tsw.WriteLiterally("null")
49
+ return nil
50
+ }
51
+ }
52
+
53
+ // Handle array type conversions like []rune(string)
54
+ if arrayType, isArrayType := expFun.(*ast.ArrayType); isArrayType {
55
+ // Check if it's a []rune type
56
+ if ident, isIdent := arrayType.Elt.(*ast.Ident); isIdent && ident.Name == "rune" {
57
+ // Check if the argument is a string
58
+ if len(exp.Args) == 1 {
59
+ arg := exp.Args[0]
60
+ if tv, ok := c.pkg.TypesInfo.Types[arg]; ok && tv.Type != nil {
61
+ if basic, isBasic := tv.Type.Underlying().(*types.Basic); isBasic && basic.Kind() == types.String {
62
+ // Translate []rune(stringValue) to $.stringToRunes(stringValue)
63
+ c.tsw.WriteLiterally("$.stringToRunes(")
64
+ if err := c.WriteValueExpr(arg); err != nil {
65
+ return fmt.Errorf("failed to write argument for []rune(string) conversion: %w", err)
66
+ }
67
+ c.tsw.WriteLiterally(")")
68
+ return nil // Handled []rune(string)
69
+ }
70
+ }
71
+ }
72
+ }
73
+ }
74
+
75
+ if funIdent, funIsIdent := expFun.(*ast.Ident); funIsIdent {
76
+ switch funIdent.String() {
77
+ case "println":
78
+ c.tsw.WriteLiterally("console.log(")
79
+ for i, arg := range exp.Args {
80
+ if i != 0 {
81
+ c.tsw.WriteLiterally(", ")
82
+ }
83
+ if err := c.WriteValueExpr(arg); err != nil {
84
+ return err
85
+ }
86
+ }
87
+ c.tsw.WriteLiterally(")")
88
+ return nil
89
+ case "len":
90
+ // Translate len(arg) to $.len(arg)
91
+ if len(exp.Args) == 1 {
92
+ c.tsw.WriteLiterally("$.len(")
93
+ if err := c.WriteValueExpr(exp.Args[0]); err != nil {
94
+ return err
95
+ }
96
+ c.tsw.WriteLiterally(")")
97
+ return nil // Handled len
98
+ }
99
+ return errors.New("unhandled len call with incorrect number of arguments")
100
+ case "cap":
101
+ // Translate cap(arg) to $.cap(arg)
102
+ if len(exp.Args) == 1 {
103
+ c.tsw.WriteLiterally("$.cap(")
104
+ if err := c.WriteValueExpr(exp.Args[0]); err != nil {
105
+ return err
106
+ }
107
+ c.tsw.WriteLiterally(")")
108
+ return nil // Handled cap
109
+ }
110
+ return errors.New("unhandled cap call with incorrect number of arguments")
111
+ case "delete":
112
+ // Translate delete(map, key) to $.deleteMapEntry(map, key)
113
+ if len(exp.Args) == 2 {
114
+ c.tsw.WriteLiterally("$.deleteMapEntry(")
115
+ if err := c.WriteValueExpr(exp.Args[0]); err != nil { // Map
116
+ return err
117
+ }
118
+ c.tsw.WriteLiterally(", ")
119
+ if err := c.WriteValueExpr(exp.Args[1]); err != nil { // Key
120
+ return err
121
+ }
122
+ c.tsw.WriteLiterally(")")
123
+ return nil // Handled delete
124
+ }
125
+ return errors.New("unhandled delete call with incorrect number of arguments")
126
+ case "make":
127
+ // First check if we have a channel type
128
+ if typ := c.pkg.TypesInfo.TypeOf(exp.Args[0]); typ != nil {
129
+ if chanType, ok := typ.Underlying().(*types.Chan); ok {
130
+ // Handle channel creation: make(chan T, bufferSize) or make(chan T)
131
+ c.tsw.WriteLiterally("$.makeChannel<")
132
+ c.WriteGoType(chanType.Elem())
133
+ c.tsw.WriteLiterally(">(")
134
+
135
+ // If buffer size is provided, add it
136
+ if len(exp.Args) >= 2 {
137
+ if err := c.WriteValueExpr(exp.Args[1]); err != nil {
138
+ return fmt.Errorf("failed to write buffer size in makeChannel: %w", err)
139
+ }
140
+ } else {
141
+ // Default to 0 (unbuffered channel)
142
+ c.tsw.WriteLiterally("0")
143
+ }
144
+
145
+ c.tsw.WriteLiterally(", ") // Add comma for zero value argument
146
+
147
+ // Write the zero value for the channel's element type
148
+ if chanType.Elem().String() == "struct{}" {
149
+ c.tsw.WriteLiterally("{}")
150
+ } else {
151
+ c.WriteZeroValueForType(chanType.Elem())
152
+ }
153
+
154
+ // Add direction parameter
155
+ c.tsw.WriteLiterally(", ")
156
+
157
+ // Determine channel direction
158
+ switch chanType.Dir() {
159
+ case types.SendRecv:
160
+ c.tsw.WriteLiterally("'both'")
161
+ case types.SendOnly:
162
+ c.tsw.WriteLiterally("'send'")
163
+ case types.RecvOnly:
164
+ c.tsw.WriteLiterally("'receive'")
165
+ default:
166
+ c.tsw.WriteLiterally("'both'") // Default to bidirectional
167
+ }
168
+
169
+ c.tsw.WriteLiterally(")")
170
+ return nil // Handled make for channel
171
+ }
172
+ }
173
+ // Handle make for slices: make([]T, len, cap) or make([]T, len)
174
+ if len(exp.Args) >= 1 {
175
+ // Handle map creation: make(map[K]V)
176
+ if mapType, ok := exp.Args[0].(*ast.MapType); ok {
177
+ c.tsw.WriteLiterally("$.makeMap<")
178
+ c.WriteTypeExpr(mapType.Key) // Write the key type
179
+ c.tsw.WriteLiterally(", ")
180
+ c.WriteTypeExpr(mapType.Value) // Write the value type
181
+ c.tsw.WriteLiterally(">()")
182
+ return nil // Handled make for map
183
+ }
184
+
185
+ // Handle slice creation
186
+ if _, ok := exp.Args[0].(*ast.ArrayType); ok {
187
+ // Get the slice type information
188
+ sliceType := c.pkg.TypesInfo.TypeOf(exp.Args[0])
189
+ if sliceType == nil {
190
+ return errors.New("could not get type information for slice in make call")
191
+ }
192
+ goElemType, ok := sliceType.Underlying().(*types.Slice)
193
+ if !ok {
194
+ return errors.New("expected slice type for make call")
195
+ }
196
+
197
+ c.tsw.WriteLiterally("$.makeSlice<")
198
+ c.WriteGoType(goElemType.Elem()) // Write the element type
199
+ c.tsw.WriteLiterally(">(")
200
+
201
+ if len(exp.Args) >= 2 {
202
+ if err := c.WriteValueExpr(exp.Args[1]); err != nil { // Length
203
+ return err
204
+ }
205
+ if len(exp.Args) == 3 {
206
+ c.tsw.WriteLiterally(", ")
207
+ if err := c.WriteValueExpr(exp.Args[2]); err != nil { // Capacity
208
+ return err
209
+ }
210
+ } else if len(exp.Args) > 3 {
211
+ return errors.New("makeSlice expects 2 or 3 arguments")
212
+ }
213
+ } else {
214
+ // If no length is provided, default to 0
215
+ c.tsw.WriteLiterally("0")
216
+ }
217
+ c.tsw.WriteLiterally(")")
218
+ return nil // Handled make for slice
219
+ }
220
+ }
221
+ // Fallthrough for unhandled make calls (e.g., channels)
222
+ return errors.New("unhandled make call")
223
+ case "string":
224
+ // Handle string() conversion
225
+ if len(exp.Args) == 1 {
226
+ arg := exp.Args[0]
227
+
228
+ // Case 1: Argument is a string literal string("...")
229
+ if basicLit, isBasicLit := arg.(*ast.BasicLit); isBasicLit && basicLit.Kind == token.STRING {
230
+ // Translate string("...") to "..." (no-op)
231
+ c.WriteBasicLit(basicLit)
232
+ return nil // Handled string literal conversion
233
+ }
234
+
235
+ // Case 2: Argument is a rune (int32) or a call to rune()
236
+ innerCall, isCallExpr := arg.(*ast.CallExpr)
237
+
238
+ if isCallExpr {
239
+ // Check if it's a call to rune()
240
+ if innerFunIdent, innerFunIsIdent := innerCall.Fun.(*ast.Ident); innerFunIsIdent && innerFunIdent.String() == "rune" {
241
+ // Translate string(rune(val)) to String.fromCharCode(val)
242
+ if len(innerCall.Args) == 1 {
243
+ c.tsw.WriteLiterally("String.fromCharCode(")
244
+ if err := c.WriteValueExpr(innerCall.Args[0]); err != nil {
245
+ return fmt.Errorf("failed to write argument for string(rune) conversion: %w", err)
246
+ }
247
+ c.tsw.WriteLiterally(")")
248
+ return nil // Handled string(rune)
249
+ }
250
+ }
251
+ }
252
+
253
+ // Handle direct string(int32) conversion
254
+ // This assumes 'rune' is int32
255
+ if tv, ok := c.pkg.TypesInfo.Types[arg]; ok {
256
+ if basic, isBasic := tv.Type.Underlying().(*types.Basic); isBasic && basic.Kind() == types.Int32 {
257
+ // Translate string(rune_val) to String.fromCharCode(rune_val)
258
+ c.tsw.WriteLiterally("String.fromCharCode(")
259
+ if err := c.WriteValueExpr(arg); err != nil {
260
+ return fmt.Errorf("failed to write argument for string(int32) conversion: %w", err)
261
+ }
262
+ c.tsw.WriteLiterally(")")
263
+ return nil // Handled string(int32)
264
+ }
265
+
266
+ // Case 3: Argument is a slice of runes or bytes string([]rune{...}) or string([]byte{...})
267
+ if sliceType, isSlice := tv.Type.Underlying().(*types.Slice); isSlice {
268
+ if basic, isBasic := sliceType.Elem().Underlying().(*types.Basic); isBasic {
269
+ // Handle both runes (int32) and bytes (uint8)
270
+ if basic.Kind() == types.Int32 || basic.Kind() == types.Uint8 {
271
+ // Translate string([]rune) or string([]byte) to $.runesToString(...)
272
+ c.tsw.WriteLiterally("$.runesToString(")
273
+ if err := c.WriteValueExpr(arg); err != nil {
274
+ return fmt.Errorf("failed to write argument for string([]rune/[]byte) conversion: %w", err)
275
+ }
276
+ c.tsw.WriteLiterally(")")
277
+ return nil // Handled string([]rune) or string([]byte)
278
+ }
279
+ }
280
+ }
281
+ }
282
+ }
283
+ // Return error for other unhandled string conversions
284
+ return fmt.Errorf("unhandled string conversion: %s", exp.Fun)
285
+ case "close":
286
+ // Translate close(ch) to ch.close()
287
+ if len(exp.Args) == 1 {
288
+ if err := c.WriteValueExpr(exp.Args[0]); err != nil {
289
+ return fmt.Errorf("failed to write channel in close call: %w", err)
290
+ }
291
+ c.tsw.WriteLiterally(".close()")
292
+ return nil // Handled close
293
+ }
294
+ return errors.New("unhandled close call with incorrect number of arguments")
295
+ case "append":
296
+ // Translate append(slice, elements...) to $.append(slice, elements...)
297
+ if len(exp.Args) >= 1 {
298
+ c.tsw.WriteLiterally("$.append(")
299
+ // The first argument is the slice
300
+ if err := c.WriteValueExpr(exp.Args[0]); err != nil {
301
+ return fmt.Errorf("failed to write slice in append call: %w", err)
302
+ }
303
+ // The remaining arguments are the elements to append
304
+ for i, arg := range exp.Args[1:] {
305
+ if i > 0 || len(exp.Args) > 1 { // Add comma before elements if there are any
306
+ c.tsw.WriteLiterally(", ")
307
+ }
308
+ if err := c.WriteValueExpr(arg); err != nil {
309
+ return fmt.Errorf("failed to write argument %d in append call: %w", i+1, err)
310
+ }
311
+ }
312
+ c.tsw.WriteLiterally(")")
313
+ return nil // Handled append
314
+ }
315
+ return errors.New("unhandled append call with incorrect number of arguments")
316
+ case "byte":
317
+ // Translate byte(val) to $.byte(val)
318
+ if len(exp.Args) == 1 {
319
+ c.tsw.WriteLiterally("$.byte(")
320
+ if err := c.WriteValueExpr(exp.Args[0]); err != nil {
321
+ return err
322
+ }
323
+ c.tsw.WriteLiterally(")")
324
+ return nil // Handled byte
325
+ }
326
+ return errors.New("unhandled byte call with incorrect number of arguments")
327
+ default:
328
+ // Check if this is a type conversion to a function type
329
+ if funIdent != nil {
330
+ if obj := c.pkg.TypesInfo.Uses[funIdent]; obj != nil {
331
+ // Check if the object is a type name
332
+ if typeName, isType := obj.(*types.TypeName); isType {
333
+ // Make sure we have exactly one argument
334
+ if len(exp.Args) == 1 {
335
+ // Check if this is a function type
336
+ if _, isFuncType := typeName.Type().Underlying().(*types.Signature); isFuncType {
337
+ // For function types, we need to add a __goTypeName property
338
+ c.tsw.WriteLiterally("Object.assign(")
339
+
340
+ // Write the argument first
341
+ if err := c.WriteValueExpr(exp.Args[0]); err != nil {
342
+ return fmt.Errorf("failed to write argument for function type cast: %w", err)
343
+ }
344
+
345
+ // Add the __goTypeName property with the function type name
346
+ c.tsw.WriteLiterallyf(", { __goTypeName: '%s' })", funIdent.String())
347
+ return nil // Handled function type cast
348
+ } else {
349
+ // For non-function types, use the TypeScript "as" operator
350
+ c.tsw.WriteLiterally("(")
351
+ if err := c.WriteValueExpr(exp.Args[0]); err != nil {
352
+ return fmt.Errorf("failed to write argument for type cast: %w", err)
353
+ }
354
+
355
+ // Then use the TypeScript "as" operator with the type name
356
+ c.tsw.WriteLiterallyf(" as %s)", funIdent.String())
357
+ return nil // Handled non-function type cast
358
+ }
359
+ }
360
+ }
361
+ }
362
+ }
363
+
364
+ // Check if this is an async function call
365
+ if funIdent != nil {
366
+ // Get the object for this function identifier
367
+ if obj := c.pkg.TypesInfo.Uses[funIdent]; obj != nil && c.analysis.IsAsyncFunc(obj) {
368
+ // This is an async function
369
+ c.tsw.WriteLiterally("await ")
370
+ }
371
+ }
372
+
373
+ // Not a special built-in, treat as a regular function call
374
+ if err := c.WriteValueExpr(expFun); err != nil {
375
+ return fmt.Errorf("failed to write function expression in call: %w", err)
376
+ }
377
+
378
+ if funType := c.pkg.TypesInfo.TypeOf(expFun); funType != nil {
379
+ if _, ok := funType.Underlying().(*types.Signature); ok {
380
+ if _, isNamed := funType.(*types.Named); isNamed {
381
+ c.tsw.WriteLiterally("!")
382
+ }
383
+ }
384
+ }
385
+
386
+ c.tsw.WriteLiterally("(")
387
+ for i, arg := range exp.Args {
388
+ if i != 0 {
389
+ c.tsw.WriteLiterally(", ")
390
+ }
391
+ if err := c.WriteValueExpr(arg); err != nil {
392
+ return fmt.Errorf("failed to write argument %d in call: %w", i, err)
393
+ }
394
+ }
395
+ c.tsw.WriteLiterally(")")
396
+ return nil // Handled regular function call
397
+ }
398
+ } else {
399
+ // Not an identifier (e.g., method call on a value)
400
+ if err := c.WriteValueExpr(expFun); err != nil {
401
+ return fmt.Errorf("failed to write method expression in call: %w", err)
402
+ }
403
+
404
+ if funType := c.pkg.TypesInfo.TypeOf(expFun); funType != nil {
405
+ if _, ok := funType.Underlying().(*types.Signature); ok {
406
+ if _, isNamed := funType.(*types.Named); isNamed {
407
+ c.tsw.WriteLiterally("!")
408
+ }
409
+ }
410
+ }
411
+ }
412
+ c.tsw.WriteLiterally("(")
413
+ for i, arg := range exp.Args {
414
+ if i != 0 {
415
+ c.tsw.WriteLiterally(", ")
416
+ }
417
+ if err := c.WriteValueExpr(arg); err != nil {
418
+ return fmt.Errorf("failed to write argument %d in call: %w", i, err)
419
+ }
420
+ }
421
+ c.tsw.WriteLiterally(")")
422
+ return nil
423
+ }