goscript 0.0.58 → 0.0.60
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 +40 -33
- package/compiler/analysis.go +184 -43
- package/compiler/assignment.go +163 -217
- package/compiler/compiler.go +35 -31
- package/compiler/composite-lit.go +233 -196
- package/compiler/constraint.go +88 -0
- package/compiler/decl.go +82 -24
- package/compiler/expr-call-async.go +20 -34
- package/compiler/expr-call-builtins.go +19 -0
- package/compiler/expr-call-helpers.go +0 -28
- package/compiler/expr-call-make.go +93 -343
- package/compiler/expr-call-type-conversion.go +221 -249
- package/compiler/expr-call.go +70 -69
- package/compiler/expr-selector.go +21 -24
- package/compiler/expr.go +3 -60
- package/compiler/protobuf.go +180 -36
- package/compiler/spec-value.go +132 -24
- package/compiler/spec.go +14 -55
- package/compiler/stmt-assign.go +338 -356
- package/compiler/stmt-range.go +4 -24
- package/compiler/stmt.go +92 -203
- package/compiler/type-utils.go +185 -0
- package/compiler/type.go +26 -80
- package/dist/gs/builtin/slice.d.ts +1 -1
- package/dist/gs/builtin/slice.js +3 -0
- package/dist/gs/builtin/slice.js.map +1 -1
- package/dist/gs/builtin/type.js +8 -2
- package/dist/gs/builtin/type.js.map +1 -1
- package/dist/gs/fmt/fmt.js +113 -16
- package/dist/gs/fmt/fmt.js.map +1 -1
- package/dist/gs/runtime/runtime.d.ts +1 -1
- package/dist/gs/runtime/runtime.js +1 -1
- package/dist/gs/slices/slices.d.ts +23 -0
- package/dist/gs/slices/slices.js +61 -0
- package/dist/gs/slices/slices.js.map +1 -1
- package/go.mod +10 -10
- package/go.sum +22 -14
- package/gs/builtin/slice.ts +5 -2
- package/gs/builtin/type.ts +13 -6
- package/gs/fmt/fmt.test.ts +176 -0
- package/gs/fmt/fmt.ts +109 -18
- package/gs/runtime/runtime.ts +1 -1
- package/gs/slices/slices.ts +68 -0
- package/package.json +3 -3
|
@@ -43,7 +43,7 @@ func (c *GoToTSCompiler) writeArrayTypeConversion(exp *ast.CallExpr) (handled bo
|
|
|
43
43
|
if len(exp.Args) == 1 {
|
|
44
44
|
arg := exp.Args[0]
|
|
45
45
|
if tv, ok := c.pkg.TypesInfo.Types[arg]; ok && tv.Type != nil {
|
|
46
|
-
if
|
|
46
|
+
if c.isStringType(tv.Type) {
|
|
47
47
|
// Translate []rune(stringValue) to $.stringToRunes(stringValue)
|
|
48
48
|
c.tsw.WriteLiterally("$.stringToRunes(")
|
|
49
49
|
if err := c.WriteValueExpr(arg); err != nil {
|
|
@@ -81,7 +81,7 @@ func (c *GoToTSCompiler) writeArrayTypeConversion(exp *ast.CallExpr) (handled bo
|
|
|
81
81
|
// Check if the argument is a named type with a slice underlying type
|
|
82
82
|
if namedArgType, isNamed := argType.(*types.Named); isNamed {
|
|
83
83
|
// Check if the named type has receiver methods (is a wrapper type)
|
|
84
|
-
if c.
|
|
84
|
+
if c.isWrapperType(namedArgType) {
|
|
85
85
|
// Check if the underlying type matches the target slice type
|
|
86
86
|
if sliceUnderlying, isSlice := namedArgType.Underlying().(*types.Slice); isSlice {
|
|
87
87
|
// Get the target slice type
|
|
@@ -160,6 +160,16 @@ func (c *GoToTSCompiler) writeStringConversion(exp *ast.CallExpr) error {
|
|
|
160
160
|
return nil
|
|
161
161
|
}
|
|
162
162
|
|
|
163
|
+
if basic, isBasic := tv.Type.Underlying().(*types.Basic); isBasic && basic.Kind() == types.Uint8 {
|
|
164
|
+
// Translate string(byte_val) to $.runeOrStringToString(byte_val)
|
|
165
|
+
c.tsw.WriteLiterally("$.runeOrStringToString(")
|
|
166
|
+
if err := c.WriteValueExpr(arg); err != nil {
|
|
167
|
+
return fmt.Errorf("failed to write argument for string(byte) conversion: %w", err)
|
|
168
|
+
}
|
|
169
|
+
c.tsw.WriteLiterally(")")
|
|
170
|
+
return nil
|
|
171
|
+
}
|
|
172
|
+
|
|
163
173
|
// Case 3: Argument is a slice of runes or bytes string([]rune{...}) or string([]byte{...})
|
|
164
174
|
if c.isByteSliceType(tv.Type) {
|
|
165
175
|
c.tsw.WriteLiterally("$.bytesToString(")
|
|
@@ -180,14 +190,41 @@ func (c *GoToTSCompiler) writeStringConversion(exp *ast.CallExpr) error {
|
|
|
180
190
|
|
|
181
191
|
// Case 4: Argument is a generic type parameter (e.g., string | []byte)
|
|
182
192
|
if typeParam, isTypeParam := tv.Type.(*types.TypeParam); isTypeParam {
|
|
183
|
-
// Check if this is a []byte | string union constraint
|
|
193
|
+
// Check if this is a []byte | string union constraint precisely
|
|
184
194
|
constraint := typeParam.Constraint()
|
|
185
195
|
if constraint != nil {
|
|
186
|
-
|
|
187
|
-
|
|
196
|
+
hasString := constraintIncludesString(constraint)
|
|
197
|
+
hasBytes := constraintIncludesByteSlice(constraint)
|
|
198
|
+
|
|
199
|
+
if hasString && hasBytes {
|
|
200
|
+
c.tsw.WriteLiterally("$.genericBytesOrStringToString(")
|
|
201
|
+
if err := c.WriteValueExpr(arg); err != nil {
|
|
202
|
+
return fmt.Errorf("failed to write argument for string(generic union) conversion: %w", err)
|
|
203
|
+
}
|
|
204
|
+
c.tsw.WriteLiterally(")")
|
|
205
|
+
return nil
|
|
206
|
+
}
|
|
207
|
+
if hasString {
|
|
208
|
+
// string(T) where T is constrained to string: no-op
|
|
209
|
+
if err := c.WriteValueExpr(arg); err != nil {
|
|
210
|
+
return fmt.Errorf("failed to write argument for string(string-constrained) conversion: %w", err)
|
|
211
|
+
}
|
|
212
|
+
return nil
|
|
213
|
+
}
|
|
214
|
+
if hasBytes {
|
|
215
|
+
// string(T) where T is constrained to []byte
|
|
216
|
+
c.tsw.WriteLiterally("$.bytesToString(")
|
|
217
|
+
if err := c.WriteValueExpr(arg); err != nil {
|
|
218
|
+
return fmt.Errorf("failed to write argument for string([]byte-constrained) conversion: %w", err)
|
|
219
|
+
}
|
|
220
|
+
c.tsw.WriteLiterally(")")
|
|
221
|
+
return nil
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Fallback to previous behavior if we cannot determine precisely
|
|
188
225
|
c.tsw.WriteLiterally("$.genericBytesOrStringToString(")
|
|
189
226
|
if err := c.WriteValueExpr(arg); err != nil {
|
|
190
|
-
return fmt.Errorf("failed to write argument for string(generic) conversion: %w", err)
|
|
227
|
+
return fmt.Errorf("failed to write argument for string(generic fallback) conversion: %w", err)
|
|
191
228
|
}
|
|
192
229
|
c.tsw.WriteLiterally(")")
|
|
193
230
|
return nil
|
|
@@ -198,161 +235,173 @@ func (c *GoToTSCompiler) writeStringConversion(exp *ast.CallExpr) error {
|
|
|
198
235
|
return fmt.Errorf("unhandled string conversion: %s", exp.Fun)
|
|
199
236
|
}
|
|
200
237
|
|
|
201
|
-
//
|
|
202
|
-
func (c *GoToTSCompiler)
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
238
|
+
// handleTypeConversionCommon contains the shared logic for type conversions
|
|
239
|
+
func (c *GoToTSCompiler) handleTypeConversionCommon(
|
|
240
|
+
typeName *types.TypeName,
|
|
241
|
+
arg ast.Expr,
|
|
242
|
+
typeNameStr string,
|
|
243
|
+
writeTypeNameFunc func() error,
|
|
244
|
+
) error {
|
|
245
|
+
// Check if we're converting FROM a type with receiver methods TO its underlying type
|
|
246
|
+
if argType := c.pkg.TypesInfo.TypeOf(arg); argType != nil {
|
|
247
|
+
if namedArgType, isNamed := argType.(*types.Named); isNamed {
|
|
248
|
+
// Check if the argument type is a wrapper type
|
|
249
|
+
if c.isWrapperType(namedArgType) {
|
|
250
|
+
// Check if we're converting to the underlying type
|
|
251
|
+
targetType := typeName.Type()
|
|
252
|
+
underlyingType := namedArgType.Underlying()
|
|
253
|
+
if types.Identical(targetType, underlyingType) {
|
|
254
|
+
// This is a conversion from a wrapper type to its underlying type
|
|
255
|
+
// Since wrapper types are now type aliases, just write the value directly
|
|
256
|
+
return c.WriteValueExpr(arg)
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
206
260
|
}
|
|
207
261
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
262
|
+
// Check if this is a function type
|
|
263
|
+
if _, isFuncType := typeName.Type().Underlying().(*types.Signature); isFuncType {
|
|
264
|
+
// For function types, we need to add a __goTypeName property
|
|
265
|
+
c.tsw.WriteLiterally("Object.assign(")
|
|
266
|
+
|
|
267
|
+
// Write the argument first
|
|
268
|
+
if err := c.WriteValueExpr(arg); err != nil {
|
|
269
|
+
return fmt.Errorf("failed to write argument for function type cast: %w", err)
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Add the __goTypeName property with the function type name
|
|
273
|
+
c.tsw.WriteLiterallyf(", { __goTypeName: '%s' })", typeNameStr)
|
|
274
|
+
return nil
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// Check if this is a wrapper type
|
|
278
|
+
if c.isWrapperType(typeName.Type()) {
|
|
279
|
+
// For wrapper types, use type casting instead of constructor calls
|
|
280
|
+
c.tsw.WriteLiterally("(")
|
|
281
|
+
if err := c.WriteValueExpr(arg); err != nil {
|
|
282
|
+
return fmt.Errorf("failed to write argument for wrapper type cast: %w", err)
|
|
283
|
+
}
|
|
284
|
+
c.tsw.WriteLiterally(" as ")
|
|
285
|
+
c.WriteGoType(typeName.Type(), GoTypeContextGeneral)
|
|
286
|
+
c.tsw.WriteLiterally(")")
|
|
287
|
+
return nil
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// Check if this is a simple named type (no methods, not struct, not interface)
|
|
291
|
+
if namedType, ok := typeName.Type().(*types.Named); ok {
|
|
292
|
+
// Don't use constructors for simple named types without methods
|
|
293
|
+
if namedType.NumMethods() == 0 {
|
|
294
|
+
// Exclude struct and interface types - they should still use constructors
|
|
295
|
+
if _, isStruct := namedType.Underlying().(*types.Struct); !isStruct {
|
|
296
|
+
if _, isInterface := namedType.Underlying().(*types.Interface); !isInterface {
|
|
297
|
+
// Simple named type without methods - use type casting
|
|
298
|
+
c.tsw.WriteLiterally("(")
|
|
299
|
+
if err := c.WriteValueExpr(arg); err != nil {
|
|
300
|
+
return fmt.Errorf("failed to write argument for simple named type cast: %w", err)
|
|
232
301
|
}
|
|
302
|
+
c.tsw.WriteLiterally(" as ")
|
|
303
|
+
c.WriteGoType(typeName.Type(), GoTypeContextGeneral)
|
|
304
|
+
c.tsw.WriteLiterally(")")
|
|
305
|
+
return nil
|
|
233
306
|
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
234
310
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
311
|
+
// Check if this type has receiver methods
|
|
312
|
+
if c.hasReceiverMethods(typeNameStr) {
|
|
313
|
+
// For types with methods that are NOT wrapper types, still use class constructor
|
|
314
|
+
c.tsw.WriteLiterally("new ")
|
|
315
|
+
if err := writeTypeNameFunc(); err != nil {
|
|
316
|
+
return fmt.Errorf("failed to write type name: %w", err)
|
|
317
|
+
}
|
|
318
|
+
c.tsw.WriteLiterally("(")
|
|
319
|
+
|
|
320
|
+
// Use auto-wrapping for the constructor argument (only if writeTypeNameFunc writes a simple identifier)
|
|
321
|
+
// The constructor parameter type is the underlying type of the named type
|
|
322
|
+
// For MyMode (which is type MyMode os.FileMode), the constructor expects os.FileMode
|
|
323
|
+
constructorParamType := typeName.Type()
|
|
324
|
+
if namedType, ok := typeName.Type().(*types.Named); ok {
|
|
325
|
+
// For named types, the constructor expects the underlying type
|
|
326
|
+
constructorParamType = namedType.Underlying()
|
|
327
|
+
}
|
|
239
328
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
329
|
+
if err := c.writeAutoWrappedArgument(arg, constructorParamType); err != nil {
|
|
330
|
+
return fmt.Errorf("failed to write argument for type constructor: %w", err)
|
|
331
|
+
}
|
|
332
|
+
c.tsw.WriteLiterally(")")
|
|
333
|
+
return nil
|
|
334
|
+
}
|
|
244
335
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
return true, nil
|
|
248
|
-
} else {
|
|
249
|
-
// Check if this is a wrapper type
|
|
250
|
-
isWrapperType := c.analysis.IsNamedBasicType(typeName.Type())
|
|
251
|
-
if isWrapperType {
|
|
252
|
-
// For wrapper types, use type casting instead of constructor calls
|
|
253
|
-
c.tsw.WriteLiterally("(")
|
|
254
|
-
if err := c.WriteValueExpr(exp.Args[0]); err != nil {
|
|
255
|
-
return true, fmt.Errorf("failed to write argument for wrapper type cast: %w", err)
|
|
256
|
-
}
|
|
257
|
-
c.tsw.WriteLiterally(" as ")
|
|
258
|
-
c.WriteGoType(typeName.Type(), GoTypeContextGeneral)
|
|
259
|
-
c.tsw.WriteLiterally(")")
|
|
260
|
-
return true, nil
|
|
261
|
-
}
|
|
336
|
+
// Determine if this type should use constructor syntax
|
|
337
|
+
shouldUseConstructor := false
|
|
262
338
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
339
|
+
// Check if it's a type alias (like os.FileMode)
|
|
340
|
+
if alias, isAlias := typeName.Type().(*types.Alias); isAlias {
|
|
341
|
+
// For type aliases, check the underlying type
|
|
342
|
+
if _, isInterface := alias.Underlying().(*types.Interface); !isInterface {
|
|
343
|
+
if _, isStruct := alias.Underlying().(*types.Struct); !isStruct {
|
|
344
|
+
// For non-struct, non-interface type aliases, use constructor
|
|
345
|
+
shouldUseConstructor = true
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
} else if namedType, isNamed := typeName.Type().(*types.Named); isNamed {
|
|
349
|
+
// For named types, check if they have receiver methods in the current package
|
|
350
|
+
// or if they follow the pattern of non-struct, non-interface named types
|
|
351
|
+
if c.hasReceiverMethods(typeNameStr) {
|
|
352
|
+
shouldUseConstructor = true
|
|
353
|
+
} else if _, isInterface := namedType.Underlying().(*types.Interface); !isInterface {
|
|
354
|
+
if _, isStruct := namedType.Underlying().(*types.Struct); !isStruct {
|
|
355
|
+
// For non-struct, non-interface named types, use constructor
|
|
356
|
+
shouldUseConstructor = true
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
283
360
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
constructorParamType = namedType.Underlying()
|
|
298
|
-
}
|
|
361
|
+
if shouldUseConstructor {
|
|
362
|
+
// For types that should use constructors, use class constructor
|
|
363
|
+
c.tsw.WriteLiterally("new ")
|
|
364
|
+
if err := writeTypeNameFunc(); err != nil {
|
|
365
|
+
return fmt.Errorf("failed to write type name: %w", err)
|
|
366
|
+
}
|
|
367
|
+
c.tsw.WriteLiterally("(")
|
|
368
|
+
if err := c.WriteValueExpr(arg); err != nil {
|
|
369
|
+
return fmt.Errorf("failed to write argument for type constructor: %w", err)
|
|
370
|
+
}
|
|
371
|
+
c.tsw.WriteLiterally(")")
|
|
372
|
+
return nil
|
|
373
|
+
}
|
|
299
374
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
} else {
|
|
306
|
-
// Determine if this type should use constructor syntax
|
|
307
|
-
shouldUseConstructor := false
|
|
308
|
-
|
|
309
|
-
// Check if it's a type alias (like os.FileMode)
|
|
310
|
-
if alias, isAlias := typeName.Type().(*types.Alias); isAlias {
|
|
311
|
-
// For type aliases, check the underlying type
|
|
312
|
-
if _, isInterface := alias.Underlying().(*types.Interface); !isInterface {
|
|
313
|
-
if _, isStruct := alias.Underlying().(*types.Struct); !isStruct {
|
|
314
|
-
// For non-struct, non-interface type aliases, use constructor
|
|
315
|
-
shouldUseConstructor = true
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
} else if namedType, isNamed := typeName.Type().(*types.Named); isNamed {
|
|
319
|
-
// For named types, check if they have receiver methods in the current package
|
|
320
|
-
// or if they follow the pattern of non-struct, non-interface named types
|
|
321
|
-
if c.hasReceiverMethods(funIdent.String()) {
|
|
322
|
-
shouldUseConstructor = true
|
|
323
|
-
} else if _, isInterface := namedType.Underlying().(*types.Interface); !isInterface {
|
|
324
|
-
if _, isStruct := namedType.Underlying().(*types.Struct); !isStruct {
|
|
325
|
-
// For non-struct, non-interface named types, use constructor
|
|
326
|
-
shouldUseConstructor = true
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
}
|
|
375
|
+
// For types that don't need constructors, use the TypeScript "as" operator
|
|
376
|
+
c.tsw.WriteLiterally("(")
|
|
377
|
+
if err := c.WriteValueExpr(arg); err != nil {
|
|
378
|
+
return fmt.Errorf("failed to write argument for type cast: %w", err)
|
|
379
|
+
}
|
|
330
380
|
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
return true, fmt.Errorf("failed to write argument for type constructor: %w", err)
|
|
338
|
-
}
|
|
339
|
-
c.tsw.WriteLiterally(")")
|
|
340
|
-
return true, nil
|
|
341
|
-
} else {
|
|
342
|
-
// For types that don't need constructors, use the TypeScript "as" operator
|
|
343
|
-
c.tsw.WriteLiterally("(")
|
|
344
|
-
if err := c.WriteValueExpr(exp.Args[0]); err != nil {
|
|
345
|
-
return true, fmt.Errorf("failed to write argument for type cast: %w", err)
|
|
346
|
-
}
|
|
381
|
+
// Then use the TypeScript "as" operator with the mapped type name
|
|
382
|
+
c.tsw.WriteLiterally(" as ")
|
|
383
|
+
c.WriteGoType(typeName.Type(), GoTypeContextGeneral)
|
|
384
|
+
c.tsw.WriteLiterally(")")
|
|
385
|
+
return nil
|
|
386
|
+
}
|
|
347
387
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
388
|
+
// writeTypeConversion handles named type conversions
|
|
389
|
+
func (c *GoToTSCompiler) writeTypeConversion(exp *ast.CallExpr, funIdent *ast.Ident) (handled bool, err error) {
|
|
390
|
+
// Check if this is a type conversion to a function type
|
|
391
|
+
if funIdent == nil {
|
|
392
|
+
return false, nil
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
if obj := c.objectOfIdent(funIdent); obj != nil {
|
|
396
|
+
// Check if the object is a type name
|
|
397
|
+
if typeName, isType := obj.(*types.TypeName); isType {
|
|
398
|
+
// Make sure we have exactly one argument
|
|
399
|
+
if len(exp.Args) == 1 {
|
|
400
|
+
err := c.handleTypeConversionCommon(typeName, exp.Args[0], funIdent.String(), func() error {
|
|
401
|
+
c.tsw.WriteLiterally(funIdent.String())
|
|
402
|
+
return nil
|
|
403
|
+
})
|
|
404
|
+
return true, err
|
|
356
405
|
}
|
|
357
406
|
}
|
|
358
407
|
}
|
|
@@ -372,7 +421,7 @@ func (c *GoToTSCompiler) writeIntConversion(exp *ast.CallExpr) error {
|
|
|
372
421
|
if argType := c.pkg.TypesInfo.TypeOf(arg); argType != nil {
|
|
373
422
|
if namedArgType, isNamed := argType.(*types.Named); isNamed {
|
|
374
423
|
// Check if the argument type is a wrapper type
|
|
375
|
-
if c.
|
|
424
|
+
if c.isWrapperType(namedArgType) {
|
|
376
425
|
// Check if we're converting to int (the underlying type)
|
|
377
426
|
if types.Identical(types.Typ[types.Int], namedArgType.Underlying()) {
|
|
378
427
|
// This is a conversion from a wrapper type to int
|
|
@@ -398,112 +447,35 @@ func (c *GoToTSCompiler) writeIntConversion(exp *ast.CallExpr) error {
|
|
|
398
447
|
// writeQualifiedTypeConversion handles qualified type conversions like os.FileMode(value)
|
|
399
448
|
func (c *GoToTSCompiler) writeQualifiedTypeConversion(exp *ast.CallExpr, selectorExpr *ast.SelectorExpr) (handled bool, err error) {
|
|
400
449
|
// Check if this is a type conversion by looking up the selector in the type info
|
|
401
|
-
if obj := c.
|
|
450
|
+
if obj := c.objectOfIdent(selectorExpr.Sel); obj != nil {
|
|
402
451
|
// Check if the object is a type name
|
|
403
452
|
if typeName, isType := obj.(*types.TypeName); isType {
|
|
404
453
|
// Make sure we have exactly one argument
|
|
405
454
|
if len(exp.Args) == 1 {
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
if namedArgType, isNamed := argType.(*types.Named); isNamed {
|
|
411
|
-
// Check if the argument type is a wrapper type
|
|
412
|
-
if c.analysis.IsNamedBasicType(namedArgType) {
|
|
413
|
-
// Check if we're converting to the underlying type
|
|
414
|
-
targetType := typeName.Type()
|
|
415
|
-
underlyingType := namedArgType.Underlying()
|
|
416
|
-
if types.Identical(targetType, underlyingType) {
|
|
417
|
-
// This is a conversion from a wrapper type to its underlying type
|
|
418
|
-
// Since wrapper types are now type aliases, just write the value directly
|
|
419
|
-
if err := c.WriteValueExpr(arg); err != nil {
|
|
420
|
-
return true, fmt.Errorf("failed to write argument for type conversion: %w", err)
|
|
421
|
-
}
|
|
422
|
-
return true, nil
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
// Check if this is a function type
|
|
429
|
-
if _, isFuncType := typeName.Type().Underlying().(*types.Signature); isFuncType {
|
|
430
|
-
// For function types, we need to add a __goTypeName property
|
|
431
|
-
c.tsw.WriteLiterally("Object.assign(")
|
|
432
|
-
|
|
433
|
-
// Write the argument first
|
|
434
|
-
if err := c.WriteValueExpr(exp.Args[0]); err != nil {
|
|
435
|
-
return true, fmt.Errorf("failed to write argument for function type cast: %w", err)
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
// Add the __goTypeName property with the function type name
|
|
439
|
-
c.tsw.WriteLiterallyf(", { __goTypeName: '%s' })", selectorExpr.Sel.Name)
|
|
440
|
-
return true, nil
|
|
441
|
-
} else {
|
|
442
|
-
// Check if this is a wrapper type
|
|
443
|
-
isWrapperType := c.analysis.IsNamedBasicType(typeName.Type())
|
|
444
|
-
if isWrapperType {
|
|
445
|
-
// For wrapper types, use type casting instead of constructor calls
|
|
446
|
-
c.tsw.WriteLiterally("(")
|
|
447
|
-
if err := c.WriteValueExpr(exp.Args[0]); err != nil {
|
|
448
|
-
return true, fmt.Errorf("failed to write argument for wrapper type cast: %w", err)
|
|
449
|
-
}
|
|
450
|
-
c.tsw.WriteLiterally(" as ")
|
|
451
|
-
c.WriteGoType(typeName.Type(), GoTypeContextGeneral)
|
|
452
|
-
c.tsw.WriteLiterally(")")
|
|
453
|
-
return true, nil
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
// Check if this is a simple named type (no methods, not struct, not interface)
|
|
457
|
-
if namedType, ok := typeName.Type().(*types.Named); ok {
|
|
458
|
-
// Don't use constructors for simple named types without methods
|
|
459
|
-
if namedType.NumMethods() == 0 {
|
|
460
|
-
// Exclude struct and interface types - they should still use constructors
|
|
461
|
-
if _, isStruct := namedType.Underlying().(*types.Struct); !isStruct {
|
|
462
|
-
if _, isInterface := namedType.Underlying().(*types.Interface); !isInterface {
|
|
463
|
-
// Simple named type without methods - use type casting
|
|
464
|
-
c.tsw.WriteLiterally("(")
|
|
465
|
-
if err := c.WriteValueExpr(exp.Args[0]); err != nil {
|
|
466
|
-
return true, fmt.Errorf("failed to write argument for simple named type cast: %w", err)
|
|
467
|
-
}
|
|
468
|
-
c.tsw.WriteLiterally(" as ")
|
|
469
|
-
c.WriteGoType(typeName.Type(), GoTypeContextGeneral)
|
|
470
|
-
c.tsw.WriteLiterally(")")
|
|
471
|
-
return true, nil
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
// Check if this type has receiver methods
|
|
478
|
-
if c.hasReceiverMethods(selectorExpr.Sel.Name) {
|
|
479
|
-
// For types with methods that are NOT wrapper types, still use class constructor
|
|
480
|
-
c.tsw.WriteLiterally("new ")
|
|
481
|
-
if err := c.WriteSelectorExpr(selectorExpr); err != nil {
|
|
482
|
-
return true, fmt.Errorf("failed to write qualified type name: %w", err)
|
|
483
|
-
}
|
|
484
|
-
c.tsw.WriteLiterally("(")
|
|
485
|
-
if err := c.WriteValueExpr(exp.Args[0]); err != nil {
|
|
486
|
-
return true, fmt.Errorf("failed to write argument for type constructor: %w", err)
|
|
487
|
-
}
|
|
488
|
-
c.tsw.WriteLiterally(")")
|
|
489
|
-
return true, nil
|
|
490
|
-
} else {
|
|
491
|
-
// For types that don't need constructors, use the TypeScript "as" operator
|
|
492
|
-
c.tsw.WriteLiterally("(")
|
|
493
|
-
if err := c.WriteValueExpr(exp.Args[0]); err != nil {
|
|
494
|
-
return true, fmt.Errorf("failed to write argument for type cast: %w", err)
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
// Then use the TypeScript "as" operator with the mapped type name
|
|
498
|
-
c.tsw.WriteLiterally(" as ")
|
|
499
|
-
c.WriteGoType(typeName.Type(), GoTypeContextGeneral)
|
|
500
|
-
c.tsw.WriteLiterally(")")
|
|
501
|
-
return true, nil
|
|
502
|
-
}
|
|
503
|
-
}
|
|
455
|
+
err := c.handleTypeConversionCommon(typeName, exp.Args[0], selectorExpr.Sel.Name, func() error {
|
|
456
|
+
return c.WriteSelectorExpr(selectorExpr)
|
|
457
|
+
})
|
|
458
|
+
return true, err
|
|
504
459
|
}
|
|
505
460
|
}
|
|
506
461
|
}
|
|
507
462
|
|
|
508
463
|
return false, nil
|
|
509
464
|
}
|
|
465
|
+
|
|
466
|
+
// Helper: detect if a constraint includes string or []byte
|
|
467
|
+
func constraintIncludesString(t types.Type) bool {
|
|
468
|
+
iface, ok := t.Underlying().(*types.Interface)
|
|
469
|
+
if !ok {
|
|
470
|
+
return false
|
|
471
|
+
}
|
|
472
|
+
return analyzeConstraint(iface).HasString
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
func constraintIncludesByteSlice(t types.Type) bool {
|
|
476
|
+
iface, ok := t.Underlying().(*types.Interface)
|
|
477
|
+
if !ok {
|
|
478
|
+
return false
|
|
479
|
+
}
|
|
480
|
+
return analyzeConstraint(iface).HasByteSlice
|
|
481
|
+
}
|