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
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
package compiler
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"fmt"
|
|
5
|
+
"go/ast"
|
|
6
|
+
"go/token"
|
|
7
|
+
"go/types"
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
// writeNilConversion handles type conversions with nil argument
|
|
11
|
+
func (c *GoToTSCompiler) writeNilConversion(exp *ast.CallExpr) (handled bool, err error) {
|
|
12
|
+
if len(exp.Args) != 1 {
|
|
13
|
+
return false, nil
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
nilIdent, isIdent := exp.Args[0].(*ast.Ident)
|
|
17
|
+
if !isIdent || nilIdent.Name != "nil" {
|
|
18
|
+
return false, nil
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Handle nil pointer to struct type conversions: (*struct{})(nil)
|
|
22
|
+
if starExpr, isStarExpr := exp.Fun.(*ast.StarExpr); isStarExpr {
|
|
23
|
+
if _, isStructType := starExpr.X.(*ast.StructType); isStructType {
|
|
24
|
+
c.tsw.WriteLiterally("null")
|
|
25
|
+
return true, nil
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
c.tsw.WriteLiterally("null")
|
|
30
|
+
return true, nil
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// writeArrayTypeConversion handles array type conversions like []rune(string)
|
|
34
|
+
func (c *GoToTSCompiler) writeArrayTypeConversion(exp *ast.CallExpr) (handled bool, err error) {
|
|
35
|
+
arrayType, isArrayType := exp.Fun.(*ast.ArrayType)
|
|
36
|
+
if !isArrayType {
|
|
37
|
+
return false, nil
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Check if it's a []rune type
|
|
41
|
+
if ident, isIdent := arrayType.Elt.(*ast.Ident); isIdent && ident.Name == "rune" {
|
|
42
|
+
// Check if the argument is a string
|
|
43
|
+
if len(exp.Args) == 1 {
|
|
44
|
+
arg := exp.Args[0]
|
|
45
|
+
if tv, ok := c.pkg.TypesInfo.Types[arg]; ok && tv.Type != nil {
|
|
46
|
+
if basic, isBasic := tv.Type.Underlying().(*types.Basic); isBasic && basic.Kind() == types.String {
|
|
47
|
+
// Translate []rune(stringValue) to $.stringToRunes(stringValue)
|
|
48
|
+
c.tsw.WriteLiterally("$.stringToRunes(")
|
|
49
|
+
if err := c.WriteValueExpr(arg); err != nil {
|
|
50
|
+
return true, fmt.Errorf("failed to write argument for []rune(string) conversion: %w", err)
|
|
51
|
+
}
|
|
52
|
+
c.tsw.WriteLiterally(")")
|
|
53
|
+
return true, nil
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Check if it's a []byte type and the argument is a string
|
|
60
|
+
if eltIdent, ok := arrayType.Elt.(*ast.Ident); ok && eltIdent.Name == "byte" && arrayType.Len == nil {
|
|
61
|
+
if len(exp.Args) == 1 {
|
|
62
|
+
arg := exp.Args[0]
|
|
63
|
+
// Ensure TypesInfo is available and the argument type can be determined
|
|
64
|
+
if tv, typeOk := c.pkg.TypesInfo.Types[arg]; typeOk && tv.Type != nil {
|
|
65
|
+
if c.isStringType(tv.Type) {
|
|
66
|
+
c.tsw.WriteLiterally("$.stringToBytes(")
|
|
67
|
+
if err := c.WriteValueExpr(arg); err != nil {
|
|
68
|
+
return true, fmt.Errorf("failed to write argument for []byte(string) conversion: %w", err)
|
|
69
|
+
}
|
|
70
|
+
c.tsw.WriteLiterally(")")
|
|
71
|
+
return true, nil
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Handle general slice type conversions like []T(namedType) where namedType has underlying type []T
|
|
78
|
+
if arrayType.Len == nil && len(exp.Args) == 1 {
|
|
79
|
+
arg := exp.Args[0]
|
|
80
|
+
if argType := c.pkg.TypesInfo.TypeOf(arg); argType != nil {
|
|
81
|
+
// Check if the argument is a named type with a slice underlying type
|
|
82
|
+
if namedArgType, isNamed := argType.(*types.Named); isNamed {
|
|
83
|
+
// Check if the named type has receiver methods (is a wrapper class)
|
|
84
|
+
typeName := namedArgType.Obj().Name()
|
|
85
|
+
if c.hasReceiverMethods(typeName) {
|
|
86
|
+
// Check if the underlying type matches the target slice type
|
|
87
|
+
if sliceUnderlying, isSlice := namedArgType.Underlying().(*types.Slice); isSlice {
|
|
88
|
+
// Get the target slice type
|
|
89
|
+
targetType := c.pkg.TypesInfo.TypeOf(arrayType)
|
|
90
|
+
if targetSliceType, isTargetSlice := targetType.Underlying().(*types.Slice); isTargetSlice {
|
|
91
|
+
// Check if element types are compatible
|
|
92
|
+
if types.Identical(sliceUnderlying.Elem(), targetSliceType.Elem()) {
|
|
93
|
+
// This is a conversion from NamedType to []T where NamedType has underlying []T
|
|
94
|
+
// Use valueOf() to get the underlying slice
|
|
95
|
+
if err := c.WriteValueExpr(arg); err != nil {
|
|
96
|
+
return true, fmt.Errorf("failed to write argument for slice type conversion: %w", err)
|
|
97
|
+
}
|
|
98
|
+
c.tsw.WriteLiterally(".valueOf()")
|
|
99
|
+
return true, nil
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return false, nil
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// writeStringConversion handles string() conversion
|
|
112
|
+
func (c *GoToTSCompiler) writeStringConversion(exp *ast.CallExpr) error {
|
|
113
|
+
if len(exp.Args) != 1 {
|
|
114
|
+
return fmt.Errorf("string() conversion expects exactly 1 argument, got %d", len(exp.Args))
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
arg := exp.Args[0]
|
|
118
|
+
|
|
119
|
+
// Case 1: Argument is a string literal string("...")
|
|
120
|
+
if basicLit, isBasicLit := arg.(*ast.BasicLit); isBasicLit && basicLit.Kind == token.STRING {
|
|
121
|
+
// Translate string("...") to "..." (no-op)
|
|
122
|
+
c.WriteBasicLit(basicLit)
|
|
123
|
+
return nil
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Case 2: Argument is a rune (int32) or a call to rune()
|
|
127
|
+
innerCall, isCallExpr := arg.(*ast.CallExpr)
|
|
128
|
+
|
|
129
|
+
if isCallExpr {
|
|
130
|
+
// Check if it's a call to rune()
|
|
131
|
+
if innerFunIdent, innerFunIsIdent := innerCall.Fun.(*ast.Ident); innerFunIsIdent && innerFunIdent.String() == "rune" {
|
|
132
|
+
// Translate string(rune(val)) to $.runeOrStringToString(val)
|
|
133
|
+
if len(innerCall.Args) == 1 {
|
|
134
|
+
c.tsw.WriteLiterally("$.runeOrStringToString(")
|
|
135
|
+
if err := c.WriteValueExpr(innerCall.Args[0]); err != nil {
|
|
136
|
+
return fmt.Errorf("failed to write argument for string(rune) conversion: %w", err)
|
|
137
|
+
}
|
|
138
|
+
c.tsw.WriteLiterally(")")
|
|
139
|
+
return nil
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Handle direct string(int32) conversion
|
|
145
|
+
if tv, ok := c.pkg.TypesInfo.Types[arg]; ok {
|
|
146
|
+
// Case 3a: Argument is already a string - no-op
|
|
147
|
+
if c.isStringType(tv.Type) {
|
|
148
|
+
// Translate string(stringValue) to stringValue (no-op)
|
|
149
|
+
if err := c.WriteValueExpr(arg); err != nil {
|
|
150
|
+
return fmt.Errorf("failed to write argument for string(string) no-op conversion: %w", err)
|
|
151
|
+
}
|
|
152
|
+
return nil
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if basic, isBasic := tv.Type.Underlying().(*types.Basic); isBasic && (basic.Kind() == types.Int32 || basic.Kind() == types.UntypedRune) {
|
|
156
|
+
// Translate string(rune_val) to $.runeOrStringToString(rune_val)
|
|
157
|
+
c.tsw.WriteLiterally("$.runeOrStringToString(")
|
|
158
|
+
if err := c.WriteValueExpr(arg); err != nil {
|
|
159
|
+
return fmt.Errorf("failed to write argument for string(int32) conversion: %w", err)
|
|
160
|
+
}
|
|
161
|
+
c.tsw.WriteLiterally(")")
|
|
162
|
+
return nil
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Case 3: Argument is a slice of runes or bytes string([]rune{...}) or string([]byte{...})
|
|
166
|
+
if c.isByteSliceType(tv.Type) {
|
|
167
|
+
c.tsw.WriteLiterally("$.bytesToString(")
|
|
168
|
+
if err := c.WriteValueExpr(arg); err != nil {
|
|
169
|
+
return fmt.Errorf("failed to write argument for string([]byte) conversion: %w", err)
|
|
170
|
+
}
|
|
171
|
+
c.tsw.WriteLiterally(")")
|
|
172
|
+
return nil
|
|
173
|
+
}
|
|
174
|
+
if c.isRuneSliceType(tv.Type) {
|
|
175
|
+
c.tsw.WriteLiterally("$.runesToString(")
|
|
176
|
+
if err := c.WriteValueExpr(arg); err != nil {
|
|
177
|
+
return fmt.Errorf("failed to write argument for string([]rune) conversion: %w", err)
|
|
178
|
+
}
|
|
179
|
+
c.tsw.WriteLiterally(")")
|
|
180
|
+
return nil
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Case 4: Argument is a generic type parameter (e.g., string | []byte)
|
|
184
|
+
if typeParam, isTypeParam := tv.Type.(*types.TypeParam); isTypeParam {
|
|
185
|
+
// Check if this is a []byte | string union constraint
|
|
186
|
+
constraint := typeParam.Constraint()
|
|
187
|
+
if constraint != nil {
|
|
188
|
+
// For now, assume any type parameter that could be string or []byte needs the helper
|
|
189
|
+
// This is a heuristic - in the future we could parse the constraint more precisely
|
|
190
|
+
c.tsw.WriteLiterally("$.genericBytesOrStringToString(")
|
|
191
|
+
if err := c.WriteValueExpr(arg); err != nil {
|
|
192
|
+
return fmt.Errorf("failed to write argument for string(generic) conversion: %w", err)
|
|
193
|
+
}
|
|
194
|
+
c.tsw.WriteLiterally(")")
|
|
195
|
+
return nil
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return fmt.Errorf("unhandled string conversion: %s", exp.Fun)
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// writeTypeConversion handles named type conversions
|
|
204
|
+
func (c *GoToTSCompiler) writeTypeConversion(exp *ast.CallExpr, funIdent *ast.Ident) (handled bool, err error) {
|
|
205
|
+
// Check if this is a type conversion to a function type
|
|
206
|
+
if funIdent == nil {
|
|
207
|
+
return false, nil
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if obj := c.pkg.TypesInfo.Uses[funIdent]; obj != nil {
|
|
211
|
+
// Check if the object is a type name
|
|
212
|
+
if typeName, isType := obj.(*types.TypeName); isType {
|
|
213
|
+
// Make sure we have exactly one argument
|
|
214
|
+
if len(exp.Args) == 1 {
|
|
215
|
+
arg := exp.Args[0]
|
|
216
|
+
|
|
217
|
+
// Check if we're converting FROM a type with receiver methods TO its underlying type
|
|
218
|
+
if argType := c.pkg.TypesInfo.TypeOf(arg); argType != nil {
|
|
219
|
+
if namedArgType, isNamed := argType.(*types.Named); isNamed {
|
|
220
|
+
argTypeName := namedArgType.Obj().Name()
|
|
221
|
+
// Check if the argument type has receiver methods
|
|
222
|
+
if c.hasReceiverMethods(argTypeName) {
|
|
223
|
+
// Check if we're converting to the underlying type
|
|
224
|
+
targetType := typeName.Type()
|
|
225
|
+
underlyingType := namedArgType.Underlying()
|
|
226
|
+
if types.Identical(targetType, underlyingType) {
|
|
227
|
+
// This is a conversion from a type with methods to its underlying type
|
|
228
|
+
// Use valueOf() instead of TypeScript cast
|
|
229
|
+
if err := c.WriteValueExpr(arg); err != nil {
|
|
230
|
+
return true, fmt.Errorf("failed to write argument for valueOf conversion: %w", err)
|
|
231
|
+
}
|
|
232
|
+
c.tsw.WriteLiterally(".valueOf()")
|
|
233
|
+
return true, nil
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Check if this is a function type
|
|
240
|
+
if _, isFuncType := typeName.Type().Underlying().(*types.Signature); isFuncType {
|
|
241
|
+
// For function types, we need to add a __goTypeName property
|
|
242
|
+
c.tsw.WriteLiterally("Object.assign(")
|
|
243
|
+
|
|
244
|
+
// Write the argument first
|
|
245
|
+
if err := c.WriteValueExpr(exp.Args[0]); err != nil {
|
|
246
|
+
return true, fmt.Errorf("failed to write argument for function type cast: %w", err)
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// Add the __goTypeName property with the function type name
|
|
250
|
+
c.tsw.WriteLiterallyf(", { __goTypeName: '%s' })", funIdent.String())
|
|
251
|
+
return true, nil
|
|
252
|
+
} else {
|
|
253
|
+
// Check if this type has receiver methods
|
|
254
|
+
if c.hasReceiverMethods(funIdent.String()) {
|
|
255
|
+
// For types with methods, use class constructor
|
|
256
|
+
c.tsw.WriteLiterally("new ")
|
|
257
|
+
c.tsw.WriteLiterally(funIdent.String())
|
|
258
|
+
c.tsw.WriteLiterally("(")
|
|
259
|
+
if err := c.WriteValueExpr(exp.Args[0]); err != nil {
|
|
260
|
+
return true, fmt.Errorf("failed to write argument for type constructor: %w", err)
|
|
261
|
+
}
|
|
262
|
+
c.tsw.WriteLiterally(")")
|
|
263
|
+
return true, nil
|
|
264
|
+
} else {
|
|
265
|
+
// For non-function types without methods, use the TypeScript "as" operator
|
|
266
|
+
c.tsw.WriteLiterally("(")
|
|
267
|
+
if err := c.WriteValueExpr(exp.Args[0]); err != nil {
|
|
268
|
+
return true, fmt.Errorf("failed to write argument for type cast: %w", err)
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Then use the TypeScript "as" operator with the mapped type name
|
|
272
|
+
c.tsw.WriteLiterally(" as ")
|
|
273
|
+
c.WriteGoType(typeName.Type(), GoTypeContextGeneral)
|
|
274
|
+
c.tsw.WriteLiterally(")")
|
|
275
|
+
return true, nil
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
return false, nil
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// writeIntConversion handles int() conversion
|
|
286
|
+
func (c *GoToTSCompiler) writeIntConversion(exp *ast.CallExpr) error {
|
|
287
|
+
if len(exp.Args) != 1 {
|
|
288
|
+
return fmt.Errorf("int() conversion expects exactly 1 argument, got %d", len(exp.Args))
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
arg := exp.Args[0]
|
|
292
|
+
|
|
293
|
+
// Check if we're converting FROM a type with receiver methods TO int
|
|
294
|
+
if argType := c.pkg.TypesInfo.TypeOf(arg); argType != nil {
|
|
295
|
+
if namedArgType, isNamed := argType.(*types.Named); isNamed {
|
|
296
|
+
argTypeName := namedArgType.Obj().Name()
|
|
297
|
+
// Check if the argument type has receiver methods
|
|
298
|
+
if c.hasReceiverMethods(argTypeName) {
|
|
299
|
+
// Check if we're converting to int (the underlying type)
|
|
300
|
+
if types.Identical(types.Typ[types.Int], namedArgType.Underlying()) {
|
|
301
|
+
// This is a conversion from a type with methods to int
|
|
302
|
+
// Use valueOf() instead of $.int()
|
|
303
|
+
if err := c.WriteValueExpr(arg); err != nil {
|
|
304
|
+
return fmt.Errorf("failed to write argument for valueOf conversion: %w", err)
|
|
305
|
+
}
|
|
306
|
+
c.tsw.WriteLiterally(".valueOf()")
|
|
307
|
+
return nil
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// Default case: Translate int(value) to $.int(value)
|
|
314
|
+
c.tsw.WriteLiterally("$.int(")
|
|
315
|
+
if err := c.WriteValueExpr(exp.Args[0]); err != nil {
|
|
316
|
+
return fmt.Errorf("failed to write argument for int() conversion: %w", err)
|
|
317
|
+
}
|
|
318
|
+
c.tsw.WriteLiterally(")")
|
|
319
|
+
return nil
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// writeQualifiedTypeConversion handles qualified type conversions like os.FileMode(value)
|
|
323
|
+
func (c *GoToTSCompiler) writeQualifiedTypeConversion(exp *ast.CallExpr, selectorExpr *ast.SelectorExpr) (handled bool, err error) {
|
|
324
|
+
// Check if this is a type conversion by looking up the selector in the type info
|
|
325
|
+
if obj := c.pkg.TypesInfo.Uses[selectorExpr.Sel]; obj != nil {
|
|
326
|
+
// Check if the object is a type name
|
|
327
|
+
if typeName, isType := obj.(*types.TypeName); isType {
|
|
328
|
+
// Make sure we have exactly one argument
|
|
329
|
+
if len(exp.Args) == 1 {
|
|
330
|
+
arg := exp.Args[0]
|
|
331
|
+
|
|
332
|
+
// Check if we're converting FROM a type with receiver methods TO its underlying type
|
|
333
|
+
if argType := c.pkg.TypesInfo.TypeOf(arg); argType != nil {
|
|
334
|
+
if namedArgType, isNamed := argType.(*types.Named); isNamed {
|
|
335
|
+
argTypeName := namedArgType.Obj().Name()
|
|
336
|
+
// Check if the argument type has receiver methods
|
|
337
|
+
if c.hasReceiverMethods(argTypeName) {
|
|
338
|
+
// Check if we're converting to the underlying type
|
|
339
|
+
targetType := typeName.Type()
|
|
340
|
+
underlyingType := namedArgType.Underlying()
|
|
341
|
+
if types.Identical(targetType, underlyingType) {
|
|
342
|
+
// This is a conversion from a type with methods to its underlying type
|
|
343
|
+
// Use valueOf() instead of TypeScript cast
|
|
344
|
+
if err := c.WriteValueExpr(arg); err != nil {
|
|
345
|
+
return true, fmt.Errorf("failed to write argument for valueOf conversion: %w", err)
|
|
346
|
+
}
|
|
347
|
+
c.tsw.WriteLiterally(".valueOf()")
|
|
348
|
+
return true, nil
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// Check if this is a function type
|
|
355
|
+
if _, isFuncType := typeName.Type().Underlying().(*types.Signature); isFuncType {
|
|
356
|
+
// For function types, we need to add a __goTypeName property
|
|
357
|
+
c.tsw.WriteLiterally("Object.assign(")
|
|
358
|
+
|
|
359
|
+
// Write the argument first
|
|
360
|
+
if err := c.WriteValueExpr(exp.Args[0]); err != nil {
|
|
361
|
+
return true, fmt.Errorf("failed to write argument for function type cast: %w", err)
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// Add the __goTypeName property with the function type name
|
|
365
|
+
c.tsw.WriteLiterallyf(", { __goTypeName: '%s' })", selectorExpr.Sel.Name)
|
|
366
|
+
return true, nil
|
|
367
|
+
} else {
|
|
368
|
+
// Determine if this type should use constructor syntax
|
|
369
|
+
shouldUseConstructor := false
|
|
370
|
+
|
|
371
|
+
// Check if it's a type alias (like os.FileMode)
|
|
372
|
+
if alias, isAlias := typeName.Type().(*types.Alias); isAlias {
|
|
373
|
+
// For type aliases, check the underlying type
|
|
374
|
+
if _, isInterface := alias.Underlying().(*types.Interface); !isInterface {
|
|
375
|
+
if _, isStruct := alias.Underlying().(*types.Struct); !isStruct {
|
|
376
|
+
// For non-struct, non-interface type aliases, use constructor
|
|
377
|
+
shouldUseConstructor = true
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
} else if namedType, isNamed := typeName.Type().(*types.Named); isNamed {
|
|
381
|
+
// For named types, check if they have receiver methods in the current package
|
|
382
|
+
// or if they follow the pattern of non-struct, non-interface named types
|
|
383
|
+
if c.hasReceiverMethods(selectorExpr.Sel.Name) {
|
|
384
|
+
shouldUseConstructor = true
|
|
385
|
+
} else if _, isInterface := namedType.Underlying().(*types.Interface); !isInterface {
|
|
386
|
+
if _, isStruct := namedType.Underlying().(*types.Struct); !isStruct {
|
|
387
|
+
// For non-struct, non-interface named types, use constructor
|
|
388
|
+
shouldUseConstructor = true
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
if shouldUseConstructor {
|
|
394
|
+
// For types that should use constructors, use class constructor
|
|
395
|
+
c.tsw.WriteLiterally("new ")
|
|
396
|
+
if err := c.WriteSelectorExpr(selectorExpr); err != nil {
|
|
397
|
+
return true, fmt.Errorf("failed to write qualified type name: %w", err)
|
|
398
|
+
}
|
|
399
|
+
c.tsw.WriteLiterally("(")
|
|
400
|
+
if err := c.WriteValueExpr(exp.Args[0]); err != nil {
|
|
401
|
+
return true, fmt.Errorf("failed to write argument for type constructor: %w", err)
|
|
402
|
+
}
|
|
403
|
+
c.tsw.WriteLiterally(")")
|
|
404
|
+
return true, nil
|
|
405
|
+
} else {
|
|
406
|
+
// For types that don't need constructors, use the TypeScript "as" operator
|
|
407
|
+
c.tsw.WriteLiterally("(")
|
|
408
|
+
if err := c.WriteValueExpr(exp.Args[0]); err != nil {
|
|
409
|
+
return true, fmt.Errorf("failed to write argument for type cast: %w", err)
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// Then use the TypeScript "as" operator with the mapped type name
|
|
413
|
+
c.tsw.WriteLiterally(" as ")
|
|
414
|
+
c.WriteGoType(typeName.Type(), GoTypeContextGeneral)
|
|
415
|
+
c.tsw.WriteLiterally(")")
|
|
416
|
+
return true, nil
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
return false, nil
|
|
424
|
+
}
|