goscript 0.0.24 → 0.0.26
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 +1 -1
- package/cmd/goscript/cmd_compile.go +17 -1
- package/compiler/analysis.go +1 -1
- package/compiler/builtin_test.go +2 -14
- package/compiler/compiler.go +251 -11
- package/compiler/compiler_test.go +60 -0
- package/compiler/decl.go +7 -1
- package/compiler/expr-call.go +212 -2
- package/compiler/expr.go +46 -2
- package/compiler/field.go +4 -4
- package/compiler/spec-value.go +1 -1
- package/compiler/stmt-range.go +204 -1
- package/compiler/type.go +47 -4
- package/dist/gs/builtin/builtin.d.ts +9 -0
- package/dist/gs/builtin/builtin.js +10 -1
- package/dist/gs/builtin/builtin.js.map +1 -1
- package/dist/gs/builtin/channel.d.ts +193 -0
- package/dist/gs/builtin/channel.js.map +1 -1
- package/dist/gs/builtin/defer.d.ts +38 -0
- package/dist/gs/builtin/defer.js.map +1 -1
- package/dist/gs/builtin/index.d.ts +1 -0
- package/dist/gs/builtin/index.js +2 -0
- package/dist/gs/builtin/index.js.map +1 -0
- package/dist/gs/builtin/io.d.ts +16 -0
- package/dist/gs/builtin/io.js.map +1 -1
- package/dist/gs/builtin/map.d.ts +33 -0
- package/dist/gs/builtin/map.js.map +1 -1
- package/dist/gs/builtin/slice.d.ts +173 -0
- package/dist/gs/builtin/slice.js +38 -24
- package/dist/gs/builtin/slice.js.map +1 -1
- package/dist/gs/builtin/type.d.ts +203 -0
- package/dist/gs/builtin/type.js +1 -2
- package/dist/gs/builtin/type.js.map +1 -1
- package/dist/gs/builtin/varRef.d.ts +14 -0
- package/dist/gs/builtin/varRef.js.map +1 -1
- package/dist/gs/cmp/index.d.ts +4 -0
- package/dist/gs/cmp/index.js +27 -0
- package/dist/gs/cmp/index.js.map +1 -0
- package/dist/gs/context/context.d.ts +26 -0
- package/dist/gs/context/context.js +297 -38
- package/dist/gs/context/context.js.map +1 -1
- package/dist/gs/context/index.d.ts +1 -0
- package/dist/gs/errors/errors.d.ts +8 -0
- package/dist/gs/errors/errors.js +190 -0
- package/dist/gs/errors/errors.js.map +1 -0
- package/dist/gs/errors/index.d.ts +1 -0
- package/dist/gs/errors/index.js +2 -0
- package/dist/gs/errors/index.js.map +1 -0
- package/dist/gs/internal/goarch/index.d.ts +6 -0
- package/dist/gs/internal/goarch/index.js +14 -0
- package/dist/gs/internal/goarch/index.js.map +1 -0
- package/dist/gs/iter/index.d.ts +1 -0
- package/dist/gs/iter/index.js +2 -0
- package/dist/gs/iter/index.js.map +1 -0
- package/dist/gs/iter/iter.d.ts +4 -0
- package/dist/gs/iter/iter.js +91 -0
- package/dist/gs/iter/iter.js.map +1 -0
- package/dist/gs/math/bits/index.d.ts +47 -0
- package/dist/gs/math/bits/index.js +300 -0
- package/dist/gs/math/bits/index.js.map +1 -0
- package/dist/gs/runtime/index.d.ts +1 -0
- package/dist/gs/runtime/runtime.d.ts +42 -0
- package/dist/gs/runtime/runtime.js +15 -18
- package/dist/gs/runtime/runtime.js.map +1 -1
- package/dist/gs/slices/index.d.ts +1 -0
- package/dist/gs/slices/index.js +2 -0
- package/dist/gs/slices/index.js.map +1 -0
- package/dist/gs/slices/slices.d.ts +8 -0
- package/dist/gs/slices/slices.js +20 -0
- package/dist/gs/slices/slices.js.map +1 -0
- package/dist/gs/time/index.d.ts +1 -0
- package/dist/gs/time/time.d.ts +57 -0
- package/dist/gs/time/time.js +108 -15
- package/dist/gs/time/time.js.map +1 -1
- package/package.json +3 -2
package/compiler/expr-call.go
CHANGED
|
@@ -111,6 +111,15 @@ func (c *GoToTSCompiler) WriteCallExpr(exp *ast.CallExpr) error {
|
|
|
111
111
|
return errors.Errorf("unhandled cap call with incorrect number of arguments: %d != 1", len(exp.Args))
|
|
112
112
|
}
|
|
113
113
|
c.tsw.WriteLiterally("$.cap")
|
|
114
|
+
case "new":
|
|
115
|
+
// Translate new(T) to new T_ts()
|
|
116
|
+
if len(exp.Args) != 1 {
|
|
117
|
+
return errors.Errorf("unhandled new call with incorrect number of arguments: %d != 1", len(exp.Args))
|
|
118
|
+
}
|
|
119
|
+
c.tsw.WriteLiterally("new ")
|
|
120
|
+
c.WriteTypeExpr(exp.Args[0]) // This should write the TypeScript type T_ts
|
|
121
|
+
c.tsw.WriteLiterally("()")
|
|
122
|
+
return nil // Prevent falling through to generic argument handling
|
|
114
123
|
case "delete":
|
|
115
124
|
// Translate delete(map, key) to $.deleteMapEntry(map, key)
|
|
116
125
|
if len(exp.Args) != 2 {
|
|
@@ -205,6 +214,33 @@ func (c *GoToTSCompiler) WriteCallExpr(exp *ast.CallExpr) error {
|
|
|
205
214
|
return nil // Handled make for []byte
|
|
206
215
|
}
|
|
207
216
|
|
|
217
|
+
// Check if the element type is a generic type parameter
|
|
218
|
+
if _, isTypeParam := goElemType.(*types.TypeParam); isTypeParam {
|
|
219
|
+
// This is make([]E, n) where E is a type parameter
|
|
220
|
+
c.tsw.WriteLiterally("$.makeSlice<")
|
|
221
|
+
c.WriteGoType(goElemType, GoTypeContextGeneral) // Write the element type parameter
|
|
222
|
+
c.tsw.WriteLiterally(">(")
|
|
223
|
+
|
|
224
|
+
if len(exp.Args) >= 2 {
|
|
225
|
+
if err := c.WriteValueExpr(exp.Args[1]); err != nil { // Length
|
|
226
|
+
return err
|
|
227
|
+
}
|
|
228
|
+
if len(exp.Args) == 3 {
|
|
229
|
+
c.tsw.WriteLiterally(", ")
|
|
230
|
+
if err := c.WriteValueExpr(exp.Args[2]); err != nil { // Capacity
|
|
231
|
+
return err
|
|
232
|
+
}
|
|
233
|
+
} else if len(exp.Args) > 3 {
|
|
234
|
+
return errors.New("makeSlice expects 2 or 3 arguments")
|
|
235
|
+
}
|
|
236
|
+
} else {
|
|
237
|
+
// If no length is provided, default to 0
|
|
238
|
+
c.tsw.WriteLiterally("0")
|
|
239
|
+
}
|
|
240
|
+
c.tsw.WriteLiterally(")")
|
|
241
|
+
return nil // Handled make for []E where E is type parameter
|
|
242
|
+
}
|
|
243
|
+
|
|
208
244
|
c.tsw.WriteLiterally("$.makeSlice<")
|
|
209
245
|
c.WriteGoType(goElemType, GoTypeContextGeneral) // Write the element type
|
|
210
246
|
c.tsw.WriteLiterally(">(")
|
|
@@ -228,6 +264,71 @@ func (c *GoToTSCompiler) WriteCallExpr(exp *ast.CallExpr) error {
|
|
|
228
264
|
c.tsw.WriteLiterally(")")
|
|
229
265
|
return nil // Handled make for slice
|
|
230
266
|
}
|
|
267
|
+
|
|
268
|
+
// Handle generic type parameter make calls: make(S, len, cap) where S ~[]E
|
|
269
|
+
if ident, ok := exp.Args[0].(*ast.Ident); ok {
|
|
270
|
+
// Check if this identifier refers to a type parameter
|
|
271
|
+
if obj := c.pkg.TypesInfo.Uses[ident]; obj != nil {
|
|
272
|
+
if typeName, isTypeName := obj.(*types.TypeName); isTypeName {
|
|
273
|
+
if typeParam, isTypeParam := typeName.Type().(*types.TypeParam); isTypeParam {
|
|
274
|
+
// Check if the type parameter is constrained to slice types
|
|
275
|
+
constraint := typeParam.Constraint()
|
|
276
|
+
if constraint != nil {
|
|
277
|
+
underlying := constraint.Underlying()
|
|
278
|
+
if iface, isInterface := underlying.(*types.Interface); isInterface {
|
|
279
|
+
// Check if the constraint includes slice types
|
|
280
|
+
// For constraints like ~[]E, we need to look at the type terms
|
|
281
|
+
if hasSliceConstraint(iface) {
|
|
282
|
+
// This is a generic slice type parameter
|
|
283
|
+
// We need to determine the element type from the constraint
|
|
284
|
+
elemType := getSliceElementTypeFromConstraint(iface)
|
|
285
|
+
if elemType != nil {
|
|
286
|
+
// Check if it's make(S, ...) where S constrains to []byte
|
|
287
|
+
if basicElem, isBasic := elemType.(*types.Basic); isBasic && basicElem.Kind() == types.Uint8 {
|
|
288
|
+
c.tsw.WriteLiterally("new Uint8Array(")
|
|
289
|
+
if len(exp.Args) >= 2 {
|
|
290
|
+
if err := c.WriteValueExpr(exp.Args[1]); err != nil { // Length
|
|
291
|
+
return err
|
|
292
|
+
}
|
|
293
|
+
// Capacity argument for make([]byte, len, cap) is ignored for new Uint8Array(len)
|
|
294
|
+
} else {
|
|
295
|
+
// If no length is provided, default to 0
|
|
296
|
+
c.tsw.WriteLiterally("0")
|
|
297
|
+
}
|
|
298
|
+
c.tsw.WriteLiterally(")")
|
|
299
|
+
return nil // Handled make for generic []byte
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
c.tsw.WriteLiterally("$.makeSlice<")
|
|
303
|
+
c.WriteGoType(elemType, GoTypeContextGeneral) // Write the element type
|
|
304
|
+
c.tsw.WriteLiterally(">(")
|
|
305
|
+
|
|
306
|
+
if len(exp.Args) >= 2 {
|
|
307
|
+
if err := c.WriteValueExpr(exp.Args[1]); err != nil { // Length
|
|
308
|
+
return err
|
|
309
|
+
}
|
|
310
|
+
if len(exp.Args) == 3 {
|
|
311
|
+
c.tsw.WriteLiterally(", ")
|
|
312
|
+
if err := c.WriteValueExpr(exp.Args[2]); err != nil { // Capacity
|
|
313
|
+
return err
|
|
314
|
+
}
|
|
315
|
+
} else if len(exp.Args) > 3 {
|
|
316
|
+
return errors.New("makeSlice expects 2 or 3 arguments")
|
|
317
|
+
}
|
|
318
|
+
} else {
|
|
319
|
+
// If no length is provided, default to 0
|
|
320
|
+
c.tsw.WriteLiterally("0")
|
|
321
|
+
}
|
|
322
|
+
c.tsw.WriteLiterally(")")
|
|
323
|
+
return nil // Handled make for generic slice
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
231
332
|
}
|
|
232
333
|
// Fallthrough for unhandled make calls (e.g., channels)
|
|
233
334
|
return errors.New("unhandled make call")
|
|
@@ -424,7 +525,17 @@ func (c *GoToTSCompiler) WriteCallExpr(exp *ast.CallExpr) error {
|
|
|
424
525
|
|
|
425
526
|
if funType := c.pkg.TypesInfo.TypeOf(expFun); funType != nil {
|
|
426
527
|
if _, ok := funType.Underlying().(*types.Signature); ok {
|
|
427
|
-
if
|
|
528
|
+
// Check if this is a function parameter identifier that needs not-null assertion
|
|
529
|
+
if ident, isIdent := expFun.(*ast.Ident); isIdent {
|
|
530
|
+
// Check if this identifier is a function parameter
|
|
531
|
+
if obj := c.pkg.TypesInfo.Uses[ident]; obj != nil {
|
|
532
|
+
if _, isVar := obj.(*types.Var); isVar {
|
|
533
|
+
// This is a variable (including function parameters)
|
|
534
|
+
// Function parameters that are function types need ! assertion
|
|
535
|
+
c.tsw.WriteLiterally("!")
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
} else if _, isNamed := funType.(*types.Named); isNamed {
|
|
428
539
|
c.tsw.WriteLiterally("!")
|
|
429
540
|
}
|
|
430
541
|
}
|
|
@@ -458,7 +569,17 @@ func (c *GoToTSCompiler) WriteCallExpr(exp *ast.CallExpr) error {
|
|
|
458
569
|
|
|
459
570
|
if funType := c.pkg.TypesInfo.TypeOf(expFun); funType != nil {
|
|
460
571
|
if _, ok := funType.Underlying().(*types.Signature); ok {
|
|
461
|
-
if
|
|
572
|
+
// Check if this is a function parameter identifier that needs not-null assertion
|
|
573
|
+
if ident, isIdent := expFun.(*ast.Ident); isIdent {
|
|
574
|
+
// Check if this identifier is a function parameter
|
|
575
|
+
if obj := c.pkg.TypesInfo.Uses[ident]; obj != nil {
|
|
576
|
+
if _, isVar := obj.(*types.Var); isVar {
|
|
577
|
+
// This is a variable (including function parameters)
|
|
578
|
+
// Function parameters that are function types need ! assertion
|
|
579
|
+
c.tsw.WriteLiterally("!")
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
} else if _, isNamed := funType.(*types.Named); isNamed {
|
|
462
583
|
c.tsw.WriteLiterally("!")
|
|
463
584
|
}
|
|
464
585
|
}
|
|
@@ -477,3 +598,92 @@ func (c *GoToTSCompiler) WriteCallExpr(exp *ast.CallExpr) error {
|
|
|
477
598
|
c.tsw.WriteLiterally(")")
|
|
478
599
|
return nil
|
|
479
600
|
}
|
|
601
|
+
|
|
602
|
+
// hasSliceConstraint checks if an interface constraint includes slice types
|
|
603
|
+
// For constraints like ~[]E, this returns true
|
|
604
|
+
func hasSliceConstraint(iface *types.Interface) bool {
|
|
605
|
+
// Check if the interface has type terms that include slice types
|
|
606
|
+
for i := 0; i < iface.NumEmbeddeds(); i++ {
|
|
607
|
+
embedded := iface.EmbeddedType(i)
|
|
608
|
+
if union, ok := embedded.(*types.Union); ok {
|
|
609
|
+
for j := 0; j < union.Len(); j++ {
|
|
610
|
+
term := union.Term(j)
|
|
611
|
+
if _, isSlice := term.Type().Underlying().(*types.Slice); isSlice {
|
|
612
|
+
return true
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
} else if _, isSlice := embedded.Underlying().(*types.Slice); isSlice {
|
|
616
|
+
return true
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
return false
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
// getSliceElementTypeFromConstraint extracts the element type from a slice constraint
|
|
623
|
+
// For constraints like ~[]E, this returns E
|
|
624
|
+
func getSliceElementTypeFromConstraint(iface *types.Interface) types.Type {
|
|
625
|
+
// Check if the interface has type terms that include slice types
|
|
626
|
+
for i := 0; i < iface.NumEmbeddeds(); i++ {
|
|
627
|
+
embedded := iface.EmbeddedType(i)
|
|
628
|
+
if union, ok := embedded.(*types.Union); ok {
|
|
629
|
+
for j := 0; j < union.Len(); j++ {
|
|
630
|
+
term := union.Term(j)
|
|
631
|
+
if sliceType, isSlice := term.Type().Underlying().(*types.Slice); isSlice {
|
|
632
|
+
return sliceType.Elem()
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
} else if sliceType, isSlice := embedded.Underlying().(*types.Slice); isSlice {
|
|
636
|
+
return sliceType.Elem()
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
return nil
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
// hasMixedStringByteConstraint checks if an interface constraint includes both string and []byte types
|
|
643
|
+
// For constraints like string | []byte, this returns true
|
|
644
|
+
// For pure slice constraints like ~[]E, this returns false
|
|
645
|
+
func hasMixedStringByteConstraint(iface *types.Interface) bool {
|
|
646
|
+
hasString := false
|
|
647
|
+
hasByteSlice := false
|
|
648
|
+
|
|
649
|
+
// Check if the interface has type terms that include both string and []byte
|
|
650
|
+
for i := 0; i < iface.NumEmbeddeds(); i++ {
|
|
651
|
+
embedded := iface.EmbeddedType(i)
|
|
652
|
+
if union, ok := embedded.(*types.Union); ok {
|
|
653
|
+
for j := 0; j < union.Len(); j++ {
|
|
654
|
+
term := union.Term(j)
|
|
655
|
+
termType := term.Type().Underlying()
|
|
656
|
+
|
|
657
|
+
// Check for string type
|
|
658
|
+
if basicType, isBasic := termType.(*types.Basic); isBasic && (basicType.Info()&types.IsString) != 0 {
|
|
659
|
+
hasString = true
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
// Check for []byte type
|
|
663
|
+
if sliceType, isSlice := termType.(*types.Slice); isSlice {
|
|
664
|
+
if elemType, isBasic := sliceType.Elem().(*types.Basic); isBasic && elemType.Kind() == types.Uint8 {
|
|
665
|
+
hasByteSlice = true
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
} else {
|
|
670
|
+
// Handle non-union embedded types
|
|
671
|
+
termType := embedded.Underlying()
|
|
672
|
+
|
|
673
|
+
// Check for string type
|
|
674
|
+
if basicType, isBasic := termType.(*types.Basic); isBasic && (basicType.Info()&types.IsString) != 0 {
|
|
675
|
+
hasString = true
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
// Check for []byte type
|
|
679
|
+
if sliceType, isSlice := termType.(*types.Slice); isSlice {
|
|
680
|
+
if elemType, isBasic := sliceType.Elem().(*types.Basic); isBasic && elemType.Kind() == types.Uint8 {
|
|
681
|
+
hasByteSlice = true
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
// Return true only if we have both string and []byte in the constraint
|
|
688
|
+
return hasString && hasByteSlice
|
|
689
|
+
}
|
package/compiler/expr.go
CHANGED
|
@@ -71,8 +71,44 @@ func (c *GoToTSCompiler) WriteIndexExpr(exp *ast.IndexExpr) error {
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
// Check if it's a type parameter with a union constraint (e.g., string | []byte)
|
|
74
|
-
if
|
|
75
|
-
//
|
|
74
|
+
if typeParam, isTypeParam := tv.Type.(*types.TypeParam); isTypeParam {
|
|
75
|
+
// Check if the type parameter is constrained to slice types
|
|
76
|
+
constraint := typeParam.Constraint()
|
|
77
|
+
if constraint != nil {
|
|
78
|
+
underlying := constraint.Underlying()
|
|
79
|
+
if iface, isInterface := underlying.(*types.Interface); isInterface {
|
|
80
|
+
// Check if this is a mixed string/byte constraint (like string | []byte)
|
|
81
|
+
if hasMixedStringByteConstraint(iface) {
|
|
82
|
+
// For mixed constraints, use specialized function that returns number (byte value)
|
|
83
|
+
c.tsw.WriteLiterally("$.indexStringOrBytes(")
|
|
84
|
+
if err := c.WriteValueExpr(exp.X); err != nil {
|
|
85
|
+
return err
|
|
86
|
+
}
|
|
87
|
+
c.tsw.WriteLiterally(", ")
|
|
88
|
+
if err := c.WriteValueExpr(exp.Index); err != nil {
|
|
89
|
+
return err
|
|
90
|
+
}
|
|
91
|
+
c.tsw.WriteLiterally(")")
|
|
92
|
+
return nil
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Check if the constraint includes only slice types (pure slice constraint)
|
|
96
|
+
if hasSliceConstraint(iface) {
|
|
97
|
+
// This is a pure slice type parameter, use regular slice indexing
|
|
98
|
+
if err := c.WriteValueExpr(exp.X); err != nil {
|
|
99
|
+
return err
|
|
100
|
+
}
|
|
101
|
+
c.tsw.WriteLiterally("![") // non-null assertion
|
|
102
|
+
if err := c.WriteValueExpr(exp.Index); err != nil {
|
|
103
|
+
return err
|
|
104
|
+
}
|
|
105
|
+
c.tsw.WriteLiterally("]")
|
|
106
|
+
return nil
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// For other type parameters, use specialized function as fallback
|
|
76
112
|
// that returns number (byte value) for better TypeScript typing
|
|
77
113
|
c.tsw.WriteLiterally("$.indexStringOrBytes(")
|
|
78
114
|
if err := c.WriteValueExpr(exp.X); err != nil {
|
|
@@ -377,6 +413,7 @@ func (c *GoToTSCompiler) WriteBinaryExpr(exp *ast.BinaryExpr) error {
|
|
|
377
413
|
if !ok {
|
|
378
414
|
return errors.Errorf("unhandled binary op: %s", exp.Op.String())
|
|
379
415
|
}
|
|
416
|
+
|
|
380
417
|
c.tsw.WriteLiterally(tokStr)
|
|
381
418
|
c.tsw.WriteLiterally(" ")
|
|
382
419
|
if err := c.WriteValueExpr(exp.Y); err != nil {
|
|
@@ -452,6 +489,13 @@ func (c *GoToTSCompiler) WriteUnaryExpr(exp *ast.UnaryExpr) error {
|
|
|
452
489
|
if !ok {
|
|
453
490
|
return errors.Errorf("unhandled unary op: %s", exp.Op.String())
|
|
454
491
|
}
|
|
492
|
+
|
|
493
|
+
// Special case: In Go, ^ is bitwise NOT when used as unary operator
|
|
494
|
+
// In TypeScript, bitwise NOT is ~, not ^
|
|
495
|
+
if exp.Op == token.XOR {
|
|
496
|
+
tokStr = "~"
|
|
497
|
+
}
|
|
498
|
+
|
|
455
499
|
c.tsw.WriteLiterally(tokStr)
|
|
456
500
|
|
|
457
501
|
// Add space if operator is not postfix (e.g., !)
|
package/compiler/field.go
CHANGED
|
@@ -47,7 +47,7 @@ func (c *GoToTSCompiler) WriteFieldList(a *ast.FieldList, isArguments bool) {
|
|
|
47
47
|
if j > 0 {
|
|
48
48
|
c.tsw.WriteLiterally(", ")
|
|
49
49
|
}
|
|
50
|
-
c.tsw.WriteLiterally(name.Name)
|
|
50
|
+
c.tsw.WriteLiterally(c.sanitizeIdentifier(name.Name))
|
|
51
51
|
c.tsw.WriteLiterally(": ")
|
|
52
52
|
typ := c.pkg.TypesInfo.TypeOf(field.Type)
|
|
53
53
|
c.WriteGoType(typ, GoTypeContextGeneral)
|
|
@@ -65,7 +65,7 @@ func (c *GoToTSCompiler) WriteFieldList(a *ast.FieldList, isArguments bool) {
|
|
|
65
65
|
c.tsw.WriteLiterally(", ")
|
|
66
66
|
}
|
|
67
67
|
c.tsw.WriteLiterally("...")
|
|
68
|
-
c.tsw.WriteLiterally(name.Name)
|
|
68
|
+
c.tsw.WriteLiterally(c.sanitizeIdentifier(name.Name))
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
c.tsw.WriteLiterally(": ")
|
|
@@ -86,7 +86,7 @@ func (c *GoToTSCompiler) WriteFieldList(a *ast.FieldList, isArguments bool) {
|
|
|
86
86
|
if j > 0 {
|
|
87
87
|
c.tsw.WriteLiterally(", ")
|
|
88
88
|
}
|
|
89
|
-
c.tsw.WriteLiterally(name.Name)
|
|
89
|
+
c.tsw.WriteLiterally(c.sanitizeIdentifier(name.Name))
|
|
90
90
|
c.tsw.WriteLiterally(": ")
|
|
91
91
|
typ := c.pkg.TypesInfo.TypeOf(field.Type)
|
|
92
92
|
c.WriteGoType(typ, GoTypeContextGeneral) // Use WriteGoType for parameter type
|
|
@@ -143,7 +143,7 @@ func (c *GoToTSCompiler) WriteField(field *ast.Field, isArguments bool) {
|
|
|
143
143
|
|
|
144
144
|
// argument names: keep original casing, no access modifier
|
|
145
145
|
if isArguments {
|
|
146
|
-
c.tsw.WriteLiterally(name.Name)
|
|
146
|
+
c.tsw.WriteLiterally(c.sanitizeIdentifier(name.Name))
|
|
147
147
|
// Argument type is handled in WriteFieldList, so continue
|
|
148
148
|
continue
|
|
149
149
|
} else {
|
package/compiler/spec-value.go
CHANGED
|
@@ -108,7 +108,7 @@ func (c *GoToTSCompiler) WriteValueSpec(a *ast.ValueSpec) error {
|
|
|
108
108
|
c.WriteGoType(goType, GoTypeContextGeneral)
|
|
109
109
|
}
|
|
110
110
|
} else {
|
|
111
|
-
|
|
111
|
+
c.WriteGoType(goType, GoTypeContextGeneral) // Write the original Go type T
|
|
112
112
|
}
|
|
113
113
|
c.tsw.WriteLiterally(">")
|
|
114
114
|
} else {
|
package/compiler/stmt-range.go
CHANGED
|
@@ -146,13 +146,15 @@ func (c *GoToTSCompiler) WriteStmtRange(exp *ast.RangeStmt) error {
|
|
|
146
146
|
if err := c.WriteValueExpr(exp.X); err != nil { // This is N
|
|
147
147
|
return fmt.Errorf("failed to write range loop integer expression: %w", err)
|
|
148
148
|
}
|
|
149
|
-
c.tsw.WriteLiterallyf("; %s++) ", indexVarName)
|
|
149
|
+
c.tsw.WriteLiterallyf("; %s++) {", indexVarName)
|
|
150
150
|
|
|
151
151
|
// write body
|
|
152
152
|
if err := c.WriteStmtBlock(exp.Body, false); err != nil {
|
|
153
153
|
return fmt.Errorf("failed to write range loop integer body: %w", err)
|
|
154
154
|
}
|
|
155
155
|
|
|
156
|
+
c.tsw.Indent(-1)
|
|
157
|
+
c.tsw.WriteLine("}")
|
|
156
158
|
return nil
|
|
157
159
|
}
|
|
158
160
|
}
|
|
@@ -341,5 +343,206 @@ func (c *GoToTSCompiler) WriteStmtRange(exp *ast.RangeStmt) error {
|
|
|
341
343
|
}
|
|
342
344
|
}
|
|
343
345
|
|
|
346
|
+
// Handle iterator function signatures
|
|
347
|
+
if sig, ok := underlying.(*types.Signature); ok {
|
|
348
|
+
// Check if this is an iterator function signature
|
|
349
|
+
// Iterator functions have the form: func(yield func(...) bool)
|
|
350
|
+
params := sig.Params()
|
|
351
|
+
if params.Len() == 1 {
|
|
352
|
+
yieldParam := params.At(0).Type()
|
|
353
|
+
if yieldSig, ok := yieldParam.Underlying().(*types.Signature); ok {
|
|
354
|
+
yieldParams := yieldSig.Params()
|
|
355
|
+
yieldResults := yieldSig.Results()
|
|
356
|
+
|
|
357
|
+
// Verify the yield function returns bool
|
|
358
|
+
if yieldResults.Len() == 1 {
|
|
359
|
+
if basic, ok := yieldResults.At(0).Type().Underlying().(*types.Basic); ok && basic.Kind() == types.Bool {
|
|
360
|
+
// This is an iterator function
|
|
361
|
+
// Generate TypeScript code that calls the iterator with a yield function
|
|
362
|
+
|
|
363
|
+
if yieldParams.Len() == 0 {
|
|
364
|
+
// func(func() bool) - iterator with no values
|
|
365
|
+
c.tsw.WriteLiterally(";(() => {")
|
|
366
|
+
c.tsw.Indent(1)
|
|
367
|
+
c.tsw.WriteLine("")
|
|
368
|
+
c.tsw.WriteLiterally("let shouldContinue = true")
|
|
369
|
+
c.tsw.WriteLine("")
|
|
370
|
+
if err := c.WriteValueExpr(exp.X); err != nil {
|
|
371
|
+
return fmt.Errorf("failed to write iterator expression: %w", err)
|
|
372
|
+
}
|
|
373
|
+
c.tsw.WriteLiterally("(() => {")
|
|
374
|
+
c.tsw.Indent(1)
|
|
375
|
+
c.tsw.WriteLine("")
|
|
376
|
+
if err := c.WriteStmtBlock(exp.Body, false); err != nil {
|
|
377
|
+
return fmt.Errorf("failed to write iterator body: %w", err)
|
|
378
|
+
}
|
|
379
|
+
c.tsw.WriteLiterally("return shouldContinue")
|
|
380
|
+
c.tsw.WriteLine("")
|
|
381
|
+
c.tsw.Indent(-1)
|
|
382
|
+
c.tsw.WriteLiterally("})")
|
|
383
|
+
c.tsw.WriteLine("")
|
|
384
|
+
c.tsw.Indent(-1)
|
|
385
|
+
c.tsw.WriteLine("})()")
|
|
386
|
+
return nil
|
|
387
|
+
} else if yieldParams.Len() == 1 {
|
|
388
|
+
// func(func(V) bool) - iterator with one value
|
|
389
|
+
c.tsw.WriteLiterally(";(() => {")
|
|
390
|
+
c.tsw.Indent(1)
|
|
391
|
+
c.tsw.WriteLine("")
|
|
392
|
+
c.tsw.WriteLiterally("let shouldContinue = true")
|
|
393
|
+
c.tsw.WriteLine("")
|
|
394
|
+
if err := c.WriteValueExpr(exp.X); err != nil {
|
|
395
|
+
return fmt.Errorf("failed to write iterator expression: %w", err)
|
|
396
|
+
}
|
|
397
|
+
c.tsw.WriteLiterally("((")
|
|
398
|
+
if exp.Value != nil {
|
|
399
|
+
if ident, ok := exp.Value.(*ast.Ident); ok && ident.Name != "_" {
|
|
400
|
+
c.WriteIdent(ident, false)
|
|
401
|
+
} else {
|
|
402
|
+
c.tsw.WriteLiterally("v")
|
|
403
|
+
}
|
|
404
|
+
} else {
|
|
405
|
+
c.tsw.WriteLiterally("v")
|
|
406
|
+
}
|
|
407
|
+
c.tsw.WriteLiterally(") => {")
|
|
408
|
+
c.tsw.Indent(1)
|
|
409
|
+
c.tsw.WriteLine("")
|
|
410
|
+
if err := c.WriteStmtBlock(exp.Body, false); err != nil {
|
|
411
|
+
return fmt.Errorf("failed to write iterator body: %w", err)
|
|
412
|
+
}
|
|
413
|
+
c.tsw.WriteLiterally("return shouldContinue")
|
|
414
|
+
c.tsw.WriteLine("")
|
|
415
|
+
c.tsw.Indent(-1)
|
|
416
|
+
c.tsw.WriteLiterally("})")
|
|
417
|
+
c.tsw.WriteLine("")
|
|
418
|
+
c.tsw.Indent(-1)
|
|
419
|
+
c.tsw.WriteLine("})()")
|
|
420
|
+
return nil
|
|
421
|
+
} else if yieldParams.Len() == 2 {
|
|
422
|
+
// func(func(K, V) bool) - iterator with key-value pairs
|
|
423
|
+
c.tsw.WriteLiterally(";(() => {")
|
|
424
|
+
c.tsw.Indent(1)
|
|
425
|
+
c.tsw.WriteLine("")
|
|
426
|
+
c.tsw.WriteLiterally("let shouldContinue = true")
|
|
427
|
+
c.tsw.WriteLine("")
|
|
428
|
+
if err := c.WriteValueExpr(exp.X); err != nil {
|
|
429
|
+
return fmt.Errorf("failed to write iterator expression: %w", err)
|
|
430
|
+
}
|
|
431
|
+
c.tsw.WriteLiterally("((")
|
|
432
|
+
if exp.Key != nil {
|
|
433
|
+
if ident, ok := exp.Key.(*ast.Ident); ok && ident.Name != "_" {
|
|
434
|
+
c.WriteIdent(ident, false)
|
|
435
|
+
} else {
|
|
436
|
+
c.tsw.WriteLiterally("k")
|
|
437
|
+
}
|
|
438
|
+
} else {
|
|
439
|
+
c.tsw.WriteLiterally("k")
|
|
440
|
+
}
|
|
441
|
+
c.tsw.WriteLiterally(", ")
|
|
442
|
+
if exp.Value != nil {
|
|
443
|
+
if ident, ok := exp.Value.(*ast.Ident); ok && ident.Name != "_" {
|
|
444
|
+
c.WriteIdent(ident, false)
|
|
445
|
+
} else {
|
|
446
|
+
c.tsw.WriteLiterally("v")
|
|
447
|
+
}
|
|
448
|
+
} else {
|
|
449
|
+
c.tsw.WriteLiterally("v")
|
|
450
|
+
}
|
|
451
|
+
c.tsw.WriteLiterally(") => {")
|
|
452
|
+
c.tsw.Indent(1)
|
|
453
|
+
c.tsw.WriteLine("")
|
|
454
|
+
if err := c.WriteStmtBlock(exp.Body, false); err != nil {
|
|
455
|
+
return fmt.Errorf("failed to write iterator body: %w", err)
|
|
456
|
+
}
|
|
457
|
+
c.tsw.WriteLiterally("return shouldContinue")
|
|
458
|
+
c.tsw.WriteLine("")
|
|
459
|
+
c.tsw.Indent(-1)
|
|
460
|
+
c.tsw.WriteLiterally("})")
|
|
461
|
+
c.tsw.WriteLine("")
|
|
462
|
+
c.tsw.Indent(-1)
|
|
463
|
+
c.tsw.WriteLine("})()")
|
|
464
|
+
return nil
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
// Handle interface types that may represent iterators
|
|
473
|
+
if _, ok := underlying.(*types.Interface); ok {
|
|
474
|
+
// For interface types, we need to treat them as potential iterators
|
|
475
|
+
// In Go 1.23+, interfaces can represent iterator functions
|
|
476
|
+
// We'll attempt to call them as iterator functions with a yield callback
|
|
477
|
+
|
|
478
|
+
// Try to determine the iterator pattern based on context or assume key-value pairs
|
|
479
|
+
// Since we can't easily determine the exact signature from just the interface,
|
|
480
|
+
// we'll generate a generic iterator call pattern
|
|
481
|
+
|
|
482
|
+
c.tsw.WriteLiterally(";(() => {")
|
|
483
|
+
c.tsw.Indent(1)
|
|
484
|
+
c.tsw.WriteLine("")
|
|
485
|
+
c.tsw.WriteLiterally("let shouldContinue = true")
|
|
486
|
+
c.tsw.WriteLine("")
|
|
487
|
+
|
|
488
|
+
// Call the interface as an iterator function
|
|
489
|
+
if err := c.WriteValueExpr(exp.X); err != nil {
|
|
490
|
+
return fmt.Errorf("failed to write interface iterator expression: %w", err)
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
// Generate the appropriate yield function based on the range variables
|
|
494
|
+
if exp.Key != nil && exp.Value != nil {
|
|
495
|
+
// Key-value iterator
|
|
496
|
+
c.tsw.WriteLiterally("((")
|
|
497
|
+
if ident, ok := exp.Key.(*ast.Ident); ok && ident.Name != "_" {
|
|
498
|
+
c.WriteIdent(ident, false)
|
|
499
|
+
} else {
|
|
500
|
+
c.tsw.WriteLiterally("k")
|
|
501
|
+
}
|
|
502
|
+
c.tsw.WriteLiterally(", ")
|
|
503
|
+
if ident, ok := exp.Value.(*ast.Ident); ok && ident.Name != "_" {
|
|
504
|
+
c.WriteIdent(ident, false)
|
|
505
|
+
} else {
|
|
506
|
+
c.tsw.WriteLiterally("v")
|
|
507
|
+
}
|
|
508
|
+
c.tsw.WriteLiterally(") => {")
|
|
509
|
+
} else if exp.Value != nil {
|
|
510
|
+
// Value-only iterator
|
|
511
|
+
c.tsw.WriteLiterally("((")
|
|
512
|
+
if ident, ok := exp.Value.(*ast.Ident); ok && ident.Name != "_" {
|
|
513
|
+
c.WriteIdent(ident, false)
|
|
514
|
+
} else {
|
|
515
|
+
c.tsw.WriteLiterally("v")
|
|
516
|
+
}
|
|
517
|
+
c.tsw.WriteLiterally(") => {")
|
|
518
|
+
} else if exp.Key != nil {
|
|
519
|
+
// Key-only iterator (treating it as value for single-param iterator)
|
|
520
|
+
c.tsw.WriteLiterally("((")
|
|
521
|
+
if ident, ok := exp.Key.(*ast.Ident); ok && ident.Name != "_" {
|
|
522
|
+
c.WriteIdent(ident, false)
|
|
523
|
+
} else {
|
|
524
|
+
c.tsw.WriteLiterally("k")
|
|
525
|
+
}
|
|
526
|
+
c.tsw.WriteLiterally(") => {")
|
|
527
|
+
} else {
|
|
528
|
+
// No variables iterator
|
|
529
|
+
c.tsw.WriteLiterally("(() => {")
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
c.tsw.Indent(1)
|
|
533
|
+
c.tsw.WriteLine("")
|
|
534
|
+
if err := c.WriteStmtBlock(exp.Body, false); err != nil {
|
|
535
|
+
return fmt.Errorf("failed to write interface iterator body: %w", err)
|
|
536
|
+
}
|
|
537
|
+
c.tsw.WriteLiterally("return shouldContinue")
|
|
538
|
+
c.tsw.WriteLine("")
|
|
539
|
+
c.tsw.Indent(-1)
|
|
540
|
+
c.tsw.WriteLiterally("})")
|
|
541
|
+
c.tsw.WriteLine("")
|
|
542
|
+
c.tsw.Indent(-1)
|
|
543
|
+
c.tsw.WriteLine("})()")
|
|
544
|
+
return nil
|
|
545
|
+
}
|
|
546
|
+
|
|
344
547
|
return errors.Errorf("unsupported range loop type: %T for expression %v", underlying, exp)
|
|
345
548
|
}
|
package/compiler/type.go
CHANGED
|
@@ -68,6 +68,15 @@ func (c *GoToTSCompiler) WriteGoType(typ types.Type, context GoTypeContext) {
|
|
|
68
68
|
case *types.TypeParam:
|
|
69
69
|
// For type parameters, write the type parameter name (e.g., "T", "K", etc.)
|
|
70
70
|
c.tsw.WriteLiterally(t.Obj().Name())
|
|
71
|
+
case *types.Union:
|
|
72
|
+
// Handle union types (e.g., string | []byte)
|
|
73
|
+
for i := 0; i < t.Len(); i++ {
|
|
74
|
+
if i > 0 {
|
|
75
|
+
c.tsw.WriteLiterally(" | ")
|
|
76
|
+
}
|
|
77
|
+
term := t.Term(i)
|
|
78
|
+
c.WriteGoType(term.Type(), context)
|
|
79
|
+
}
|
|
71
80
|
default:
|
|
72
81
|
// For other types, just write "any" and add a comment
|
|
73
82
|
c.tsw.WriteLiterally("any")
|
|
@@ -202,7 +211,8 @@ func (c *GoToTSCompiler) WriteBasicType(t *types.Basic) {
|
|
|
202
211
|
|
|
203
212
|
// WriteNamedType translates a Go named type to its TypeScript equivalent.
|
|
204
213
|
// It specially handles the error interface as $.GoError, and uses the original
|
|
205
|
-
// type name for other named types. For
|
|
214
|
+
// type name for other named types. For imported types, it writes the qualified
|
|
215
|
+
// name using the import alias found from the analysis imports. For generic types, it includes type arguments.
|
|
206
216
|
func (c *GoToTSCompiler) WriteNamedType(t *types.Named) {
|
|
207
217
|
// Check if the named type is the error interface
|
|
208
218
|
if iface, ok := t.Underlying().(*types.Interface); ok && iface.String() == "interface{Error() string}" {
|
|
@@ -210,7 +220,40 @@ func (c *GoToTSCompiler) WriteNamedType(t *types.Named) {
|
|
|
210
220
|
return
|
|
211
221
|
}
|
|
212
222
|
|
|
213
|
-
//
|
|
223
|
+
// Check if this type is from an imported package
|
|
224
|
+
typePkg := t.Obj().Pkg()
|
|
225
|
+
if typePkg != nil && typePkg != c.pkg.Types {
|
|
226
|
+
// This type is from an imported package, find the import alias
|
|
227
|
+
typePkgPath := typePkg.Path()
|
|
228
|
+
|
|
229
|
+
// Try to find the import alias by matching the package path
|
|
230
|
+
for importAlias := range c.analysis.Imports {
|
|
231
|
+
// The importAlias could be either the explicit alias or the default package name
|
|
232
|
+
// If it's the default package name, it should match the last segment of the path
|
|
233
|
+
defaultPkgName := packageNameFromGoPath(typePkgPath)
|
|
234
|
+
if importAlias == defaultPkgName || importAlias == typePkgPath {
|
|
235
|
+
// Write the qualified name: importAlias.TypeName
|
|
236
|
+
c.tsw.WriteLiterally(importAlias)
|
|
237
|
+
c.tsw.WriteLiterally(".")
|
|
238
|
+
c.tsw.WriteLiterally(t.Obj().Name())
|
|
239
|
+
|
|
240
|
+
// For generic types, include type arguments
|
|
241
|
+
if t.TypeArgs() != nil && t.TypeArgs().Len() > 0 {
|
|
242
|
+
c.tsw.WriteLiterally("<")
|
|
243
|
+
for i := 0; i < t.TypeArgs().Len(); i++ {
|
|
244
|
+
if i > 0 {
|
|
245
|
+
c.tsw.WriteLiterally(", ")
|
|
246
|
+
}
|
|
247
|
+
c.WriteGoType(t.TypeArgs().At(i), GoTypeContextGeneral)
|
|
248
|
+
}
|
|
249
|
+
c.tsw.WriteLiterally(">")
|
|
250
|
+
}
|
|
251
|
+
return
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Use Obj().Name() for the original defined name (local types or unmatched imports)
|
|
214
257
|
c.tsw.WriteLiterally(t.Obj().Name())
|
|
215
258
|
|
|
216
259
|
// For generic types, include type arguments
|
|
@@ -388,7 +431,7 @@ func (c *GoToTSCompiler) WriteSignatureType(t *types.Signature) {
|
|
|
388
431
|
|
|
389
432
|
// Use parameter name if available, otherwise use p0, p1, etc.
|
|
390
433
|
if param.Name() != "" {
|
|
391
|
-
c.tsw.WriteLiterally(param.Name())
|
|
434
|
+
c.tsw.WriteLiterally(c.sanitizeIdentifier(param.Name()))
|
|
392
435
|
} else {
|
|
393
436
|
c.tsw.WriteLiterallyf("p%d", i)
|
|
394
437
|
}
|
|
@@ -483,7 +526,7 @@ func (c *GoToTSCompiler) writeInterfaceStructure(iface *types.Interface, astNode
|
|
|
483
526
|
if paramName == "" || paramName == "_" {
|
|
484
527
|
paramName = fmt.Sprintf("_p%d", j)
|
|
485
528
|
}
|
|
486
|
-
c.tsw.WriteLiterally(paramName)
|
|
529
|
+
c.tsw.WriteLiterally(c.sanitizeIdentifier(paramName))
|
|
487
530
|
c.tsw.WriteLiterally(": ")
|
|
488
531
|
c.WriteGoType(paramVar.Type(), GoTypeContextGeneral) // Recursive call for param type
|
|
489
532
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export * from './varRef.js';
|
|
2
|
+
export * from './channel.js';
|
|
3
|
+
export * from './defer.js';
|
|
4
|
+
export * from './io.js';
|
|
5
|
+
export * from './map.js';
|
|
6
|
+
export * from './slice.js';
|
|
7
|
+
export * from './type.js';
|
|
8
|
+
export declare function copy<T>(dst: T[], src: T[]): number;
|
|
9
|
+
export declare function multiplyDuration(duration: any, multiplier: number): any;
|