goscript 0.0.76 → 0.0.77
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/compiler/analysis.go +100 -33
- package/compiler/analysis_test.go +2 -7
- package/compiler/code-writer.go +2 -2
- package/compiler/compiler.go +4 -4
- package/compiler/composite-lit.go +4 -6
- package/compiler/constraint.go +2 -4
- package/compiler/expr-call-async.go +4 -0
- package/compiler/expr-call-helpers.go +98 -8
- package/compiler/expr-call-make.go +4 -4
- package/compiler/expr-call.go +3 -0
- package/compiler/expr-type.go +42 -0
- package/compiler/gs_dependencies_test.go +3 -14
- package/compiler/index.ts +20 -5
- package/compiler/protobuf.go +21 -21
- package/compiler/spec-struct.go +22 -30
- package/compiler/spec.go +2 -2
- package/compiler/stmt-assign.go +2 -2
- package/compiler/type-info.go +20 -3
- package/compiler/type-utils.go +2 -4
- package/compiler/type.go +3 -4
- package/dist/compiler/index.js +13 -4
- package/dist/compiler/index.js.map +1 -1
- package/dist/gs/builtin/slice.js +2 -3
- package/dist/gs/builtin/slice.js.map +1 -1
- package/dist/gs/builtin/type.d.ts +1 -0
- package/dist/gs/builtin/type.js +8 -14
- package/dist/gs/builtin/type.js.map +1 -1
- package/dist/gs/bytes/buffer.gs.d.ts +1 -0
- package/dist/gs/bytes/buffer.gs.js +20 -0
- package/dist/gs/bytes/buffer.gs.js.map +1 -1
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.d.ts +5 -0
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js +10 -0
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js.map +1 -0
- package/dist/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/browser.d.ts +50 -0
- package/dist/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/browser.js +221 -0
- package/dist/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/browser.js.map +1 -0
- package/dist/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/index.d.ts +1 -0
- package/dist/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/index.js +2 -0
- package/dist/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/index.js.map +1 -0
- package/dist/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/index.d.ts +1 -0
- package/dist/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/index.js +2 -0
- package/dist/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/index.js.map +1 -0
- package/dist/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/runtime.d.ts +56 -0
- package/dist/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/runtime.js +17 -0
- package/dist/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/runtime.js.map +1 -0
- package/dist/gs/io/fs/format.js +2 -6
- package/dist/gs/io/fs/format.js.map +1 -1
- package/dist/gs/io/fs/glob.js +18 -23
- package/dist/gs/io/fs/glob.js.map +1 -1
- package/dist/gs/path/match.js +9 -22
- package/dist/gs/path/match.js.map +1 -1
- package/dist/gs/reflect/index.d.ts +1 -1
- package/dist/gs/reflect/index.js +1 -1
- package/dist/gs/reflect/index.js.map +1 -1
- package/dist/gs/reflect/type.d.ts +1 -0
- package/dist/gs/reflect/type.js +52 -23
- package/dist/gs/reflect/type.js.map +1 -1
- package/dist/gs/strings/iter.js +1 -1
- package/dist/gs/strings/iter.js.map +1 -1
- package/dist/gs/strings/reader.js +1 -1
- package/dist/gs/strings/reader.js.map +1 -1
- package/dist/gs/strings/replace.js +9 -20
- package/dist/gs/strings/replace.js.map +1 -1
- package/dist/gs/time/time.js +2 -2
- package/dist/gs/time/time.js.map +1 -1
- package/go.mod +1 -1
- package/go.sum +2 -2
- package/gs/builtin/slice.ts +2 -2
- package/gs/builtin/type.ts +14 -14
- package/gs/bytes/buffer.gs.ts +21 -1
- package/gs/fmt/fmt.test.ts +1 -1
- package/gs/github.com/aperturerobotics/protobuf-go-lite/index.ts +14 -0
- package/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/browser.ts +238 -0
- package/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/index.ts +1 -0
- package/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/meta.json +12 -0
- package/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/index.ts +1 -0
- package/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/meta.json +8 -0
- package/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/runtime.ts +94 -0
- package/gs/io/fs/format.ts +2 -5
- package/gs/io/fs/glob.ts +18 -21
- package/gs/path/match.ts +9 -22
- package/gs/reflect/index.ts +1 -0
- package/gs/reflect/type.ts +62 -25
- package/gs/strings/iter.ts +1 -1
- package/gs/strings/reader.ts +1 -1
- package/gs/strings/replace.ts +13 -18
- package/gs/time/time.ts +2 -2
- package/package.json +18 -15
package/compiler/analysis.go
CHANGED
|
@@ -240,6 +240,53 @@ func NewPackageAnalysis() *PackageAnalysis {
|
|
|
240
240
|
}
|
|
241
241
|
}
|
|
242
242
|
|
|
243
|
+
// collectZeroValueTypeNames records named struct types whose zero value emits a
|
|
244
|
+
// runtime constructor call.
|
|
245
|
+
func collectZeroValueTypeNames(typ types.Type, names map[string]struct{}) {
|
|
246
|
+
switch t := typ.(type) {
|
|
247
|
+
case *types.Array:
|
|
248
|
+
collectZeroValueTypeNames(t.Elem(), names)
|
|
249
|
+
case *types.Named:
|
|
250
|
+
if _, isStruct := t.Underlying().(*types.Struct); isStruct {
|
|
251
|
+
names[t.Obj().Name()] = struct{}{}
|
|
252
|
+
return
|
|
253
|
+
}
|
|
254
|
+
collectZeroValueTypeNames(t.Underlying(), names)
|
|
255
|
+
case *types.Alias:
|
|
256
|
+
collectZeroValueTypeNames(t.Underlying(), names)
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// addTypeRefsFromZeroValue adds same-package type imports needed when code
|
|
261
|
+
// generation synthesizes a zero value without an explicit AST type reference.
|
|
262
|
+
func addTypeRefsFromZeroValue(analysis *PackageAnalysis, currentFileName string, typ types.Type, refs map[string][]string) {
|
|
263
|
+
typeNames := make(map[string]struct{})
|
|
264
|
+
collectZeroValueTypeNames(typ, typeNames)
|
|
265
|
+
if len(typeNames) == 0 {
|
|
266
|
+
return
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
currentFileTypes := analysis.TypeDefs[currentFileName]
|
|
270
|
+
for typeName := range typeNames {
|
|
271
|
+
if slices.Contains(currentFileTypes, typeName) {
|
|
272
|
+
continue
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
for sourceFile, types := range analysis.TypeDefs {
|
|
276
|
+
if sourceFile == currentFileName || !slices.Contains(types, typeName) {
|
|
277
|
+
continue
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
if refs[sourceFile] == nil {
|
|
281
|
+
refs[sourceFile] = []string{}
|
|
282
|
+
}
|
|
283
|
+
if !slices.Contains(refs[sourceFile], typeName) {
|
|
284
|
+
refs[sourceFile] = append(refs[sourceFile], typeName)
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
243
290
|
// ensureNodeData ensures that NodeData exists for a given node and returns it
|
|
244
291
|
func (a *Analysis) ensureNodeData(node ast.Node) *NodeInfo {
|
|
245
292
|
if node == nil {
|
|
@@ -1148,8 +1195,7 @@ func (v *analysisVisitor) visitTypeAssertExpr(typeAssert *ast.TypeAssertExpr) as
|
|
|
1148
1195
|
}
|
|
1149
1196
|
|
|
1150
1197
|
// For each method in the interface, check if the struct implements it
|
|
1151
|
-
for
|
|
1152
|
-
interfaceMethod := interfaceType.ExplicitMethod(i)
|
|
1198
|
+
for interfaceMethod := range interfaceType.ExplicitMethods() {
|
|
1153
1199
|
|
|
1154
1200
|
// Find the corresponding method in the struct type
|
|
1155
1201
|
structMethod := v.findStructMethod(namedType, interfaceMethod.Name())
|
|
@@ -1417,8 +1463,7 @@ func (a *Analysis) addImportsForPromotedMethods(pkg *packages.Package) {
|
|
|
1417
1463
|
}
|
|
1418
1464
|
|
|
1419
1465
|
// Look for embedded fields
|
|
1420
|
-
for
|
|
1421
|
-
field := structType.Field(i)
|
|
1466
|
+
for field := range structType.Fields() {
|
|
1422
1467
|
if !field.Embedded() {
|
|
1423
1468
|
continue
|
|
1424
1469
|
}
|
|
@@ -1442,8 +1487,7 @@ func (a *Analysis) addImportsForPromotedMethods(pkg *packages.Package) {
|
|
|
1442
1487
|
embeddedMethodSet := types.NewMethodSet(methodSetType)
|
|
1443
1488
|
|
|
1444
1489
|
// Scan all methods in the method set
|
|
1445
|
-
for
|
|
1446
|
-
selection := embeddedMethodSet.At(j)
|
|
1490
|
+
for selection := range embeddedMethodSet.Methods() {
|
|
1447
1491
|
method := selection.Obj()
|
|
1448
1492
|
sig, ok := method.Type().(*types.Signature)
|
|
1449
1493
|
if !ok {
|
|
@@ -1452,16 +1496,14 @@ func (a *Analysis) addImportsForPromotedMethods(pkg *packages.Package) {
|
|
|
1452
1496
|
|
|
1453
1497
|
// Scan parameters
|
|
1454
1498
|
if sig.Params() != nil {
|
|
1455
|
-
for
|
|
1456
|
-
param := sig.Params().At(k)
|
|
1499
|
+
for param := range sig.Params().Variables() {
|
|
1457
1500
|
a.collectPackageFromType(param.Type(), pkg.Types, packagesToAdd)
|
|
1458
1501
|
}
|
|
1459
1502
|
}
|
|
1460
1503
|
|
|
1461
1504
|
// Scan results
|
|
1462
1505
|
if sig.Results() != nil {
|
|
1463
|
-
for
|
|
1464
|
-
result := sig.Results().At(k)
|
|
1506
|
+
for result := range sig.Results().Variables() {
|
|
1465
1507
|
a.collectPackageFromType(result.Type(), pkg.Types, packagesToAdd)
|
|
1466
1508
|
}
|
|
1467
1509
|
}
|
|
@@ -1494,17 +1536,16 @@ func (a *Analysis) collectPackageFromType(t types.Type, currentPkg *types.Packag
|
|
|
1494
1536
|
}
|
|
1495
1537
|
// Check type arguments for generics
|
|
1496
1538
|
if typ.TypeArgs() != nil {
|
|
1497
|
-
for
|
|
1498
|
-
a.collectPackageFromType(
|
|
1539
|
+
for t := range typ.TypeArgs().Types() {
|
|
1540
|
+
a.collectPackageFromType(t, currentPkg, packagesToAdd)
|
|
1499
1541
|
}
|
|
1500
1542
|
}
|
|
1501
1543
|
case *types.Interface:
|
|
1502
1544
|
// For interfaces, we need to check embedded interfaces and method signatures
|
|
1503
|
-
for
|
|
1504
|
-
a.collectPackageFromType(
|
|
1545
|
+
for etyp := range typ.EmbeddedTypes() {
|
|
1546
|
+
a.collectPackageFromType(etyp, currentPkg, packagesToAdd)
|
|
1505
1547
|
}
|
|
1506
|
-
for
|
|
1507
|
-
method := typ.ExplicitMethod(i)
|
|
1548
|
+
for method := range typ.ExplicitMethods() {
|
|
1508
1549
|
a.collectPackageFromType(method.Type(), currentPkg, packagesToAdd)
|
|
1509
1550
|
}
|
|
1510
1551
|
case *types.Pointer:
|
|
@@ -1521,14 +1562,14 @@ func (a *Analysis) collectPackageFromType(t types.Type, currentPkg *types.Packag
|
|
|
1521
1562
|
case *types.Signature:
|
|
1522
1563
|
// Collect from parameters
|
|
1523
1564
|
if typ.Params() != nil {
|
|
1524
|
-
for
|
|
1525
|
-
a.collectPackageFromType(
|
|
1565
|
+
for v := range typ.Params().Variables() {
|
|
1566
|
+
a.collectPackageFromType(v.Type(), currentPkg, packagesToAdd)
|
|
1526
1567
|
}
|
|
1527
1568
|
}
|
|
1528
1569
|
// Collect from results
|
|
1529
1570
|
if typ.Results() != nil {
|
|
1530
|
-
for
|
|
1531
|
-
a.collectPackageFromType(
|
|
1571
|
+
for v := range typ.Results().Variables() {
|
|
1572
|
+
a.collectPackageFromType(v.Type(), currentPkg, packagesToAdd)
|
|
1532
1573
|
}
|
|
1533
1574
|
}
|
|
1534
1575
|
}
|
|
@@ -1693,6 +1734,37 @@ func AnalyzePackageImports(pkg *packages.Package) *PackageAnalysis {
|
|
|
1693
1734
|
}
|
|
1694
1735
|
}
|
|
1695
1736
|
}
|
|
1737
|
+
|
|
1738
|
+
if callExpr, ok := n.(*ast.CallExpr); ok {
|
|
1739
|
+
if funIdent, ok := callExpr.Fun.(*ast.Ident); ok && funIdent.Name == "make" && len(callExpr.Args) > 0 {
|
|
1740
|
+
if typ := pkg.TypesInfo.TypeOf(callExpr.Args[0]); typ != nil {
|
|
1741
|
+
if chanType, ok := typ.Underlying().(*types.Chan); ok {
|
|
1742
|
+
addTypeRefsFromZeroValue(analysis, baseFileName, chanType.Elem(), typeRefsFromOtherFiles)
|
|
1743
|
+
}
|
|
1744
|
+
}
|
|
1745
|
+
}
|
|
1746
|
+
}
|
|
1747
|
+
|
|
1748
|
+
if indexExpr, ok := n.(*ast.IndexExpr); ok {
|
|
1749
|
+
if tv, ok := pkg.TypesInfo.Types[indexExpr.X]; ok {
|
|
1750
|
+
if mapType, ok := tv.Type.Underlying().(*types.Map); ok {
|
|
1751
|
+
addTypeRefsFromZeroValue(analysis, baseFileName, mapType.Elem(), typeRefsFromOtherFiles)
|
|
1752
|
+
return true
|
|
1753
|
+
}
|
|
1754
|
+
|
|
1755
|
+
if typeParam, ok := tv.Type.(*types.TypeParam); ok {
|
|
1756
|
+
constraint := typeParam.Constraint()
|
|
1757
|
+
if constraint == nil {
|
|
1758
|
+
return true
|
|
1759
|
+
}
|
|
1760
|
+
if iface, ok := constraint.Underlying().(*types.Interface); ok && hasMapConstraint(iface) {
|
|
1761
|
+
if mapValueType := getMapValueTypeFromConstraint(iface); mapValueType != nil {
|
|
1762
|
+
addTypeRefsFromZeroValue(analysis, baseFileName, mapValueType, typeRefsFromOtherFiles)
|
|
1763
|
+
}
|
|
1764
|
+
}
|
|
1765
|
+
}
|
|
1766
|
+
}
|
|
1767
|
+
}
|
|
1696
1768
|
return true
|
|
1697
1769
|
})
|
|
1698
1770
|
|
|
@@ -1830,8 +1902,8 @@ func AnalyzePackageImports(pkg *packages.Package) *PackageAnalysis {
|
|
|
1830
1902
|
// Check if this type has the method being called
|
|
1831
1903
|
methodName := selectorExpr.Sel.Name
|
|
1832
1904
|
found := false
|
|
1833
|
-
for
|
|
1834
|
-
if
|
|
1905
|
+
for method := range namedType.Methods() {
|
|
1906
|
+
if method.Name() == methodName {
|
|
1835
1907
|
found = true
|
|
1836
1908
|
break
|
|
1837
1909
|
}
|
|
@@ -2351,8 +2423,7 @@ func (a *Analysis) GetIdentifierMapping(ident *ast.Ident) string {
|
|
|
2351
2423
|
// findStructMethod finds a method with the given name on a named type
|
|
2352
2424
|
func (v *analysisVisitor) findStructMethod(namedType *types.Named, methodName string) *types.Func {
|
|
2353
2425
|
// Check methods directly on the type
|
|
2354
|
-
for
|
|
2355
|
-
method := namedType.Method(i)
|
|
2426
|
+
for method := range namedType.Methods() {
|
|
2356
2427
|
if method.Name() == methodName {
|
|
2357
2428
|
return method
|
|
2358
2429
|
}
|
|
@@ -2455,8 +2526,7 @@ func (v *analysisVisitor) trackInterfaceAssignments(assignStmt *ast.AssignStmt)
|
|
|
2455
2526
|
}
|
|
2456
2527
|
|
|
2457
2528
|
// Track implementations for all interface methods
|
|
2458
|
-
for
|
|
2459
|
-
interfaceMethod := interfaceType.ExplicitMethod(j)
|
|
2529
|
+
for interfaceMethod := range interfaceType.ExplicitMethods() {
|
|
2460
2530
|
|
|
2461
2531
|
structMethod := v.findStructMethod(namedType, interfaceMethod.Name())
|
|
2462
2532
|
if structMethod != nil {
|
|
@@ -2514,8 +2584,7 @@ func (v *analysisVisitor) trackInterfaceCallArguments(callExpr *ast.CallExpr) {
|
|
|
2514
2584
|
}
|
|
2515
2585
|
|
|
2516
2586
|
// Track implementations for all interface methods
|
|
2517
|
-
for
|
|
2518
|
-
interfaceMethod := interfaceType.ExplicitMethod(j)
|
|
2587
|
+
for interfaceMethod := range interfaceType.ExplicitMethods() {
|
|
2519
2588
|
|
|
2520
2589
|
structMethod := v.findStructMethod(namedType, interfaceMethod.Name())
|
|
2521
2590
|
if structMethod != nil {
|
|
@@ -2659,8 +2728,7 @@ func (v *interfaceImplementationVisitor) findImplementationsInPackage(interfaceT
|
|
|
2659
2728
|
// trackImplementation records that a named type implements an interface
|
|
2660
2729
|
func (v *interfaceImplementationVisitor) trackImplementation(interfaceType *types.Interface, namedType *types.Named) {
|
|
2661
2730
|
// For each method in the interface, find the corresponding implementation
|
|
2662
|
-
for
|
|
2663
|
-
interfaceMethod := interfaceType.ExplicitMethod(i)
|
|
2731
|
+
for interfaceMethod := range interfaceType.ExplicitMethods() {
|
|
2664
2732
|
|
|
2665
2733
|
// Find the method in the implementing type
|
|
2666
2734
|
structMethod := v.findMethodInType(namedType, interfaceMethod.Name())
|
|
@@ -2672,8 +2740,7 @@ func (v *interfaceImplementationVisitor) trackImplementation(interfaceType *type
|
|
|
2672
2740
|
|
|
2673
2741
|
// findMethodInType finds a method with the given name in a named type
|
|
2674
2742
|
func (v *interfaceImplementationVisitor) findMethodInType(namedType *types.Named, methodName string) *types.Func {
|
|
2675
|
-
for
|
|
2676
|
-
method := namedType.Method(i)
|
|
2743
|
+
for method := range namedType.Methods() {
|
|
2677
2744
|
if method.Name() == methodName {
|
|
2678
2745
|
return method
|
|
2679
2746
|
}
|
|
@@ -2696,7 +2763,7 @@ func (v *analysisVisitor) analyzeAllMethodsAsync() {
|
|
|
2696
2763
|
// We need to iterate multiple times because methods in cycles can call each other,
|
|
2697
2764
|
// and we need to propagate async status until no changes occur
|
|
2698
2765
|
maxIterations := 10
|
|
2699
|
-
for
|
|
2766
|
+
for range maxIterations {
|
|
2700
2767
|
changed := false
|
|
2701
2768
|
|
|
2702
2769
|
for _, methodKey := range cycles {
|
|
@@ -6,6 +6,7 @@ import (
|
|
|
6
6
|
"go/token"
|
|
7
7
|
"go/types"
|
|
8
8
|
"os"
|
|
9
|
+
"slices"
|
|
9
10
|
"testing"
|
|
10
11
|
|
|
11
12
|
"golang.org/x/tools/go/packages"
|
|
@@ -329,13 +330,7 @@ func TestDiscoverGsPackages(t *testing.T) {
|
|
|
329
330
|
// Check for some known packages that should exist
|
|
330
331
|
expectedPackages := []string{"sync", "bytes", "strings"}
|
|
331
332
|
for _, expected := range expectedPackages {
|
|
332
|
-
found :=
|
|
333
|
-
for _, pkg := range packages {
|
|
334
|
-
if pkg == expected {
|
|
335
|
-
found = true
|
|
336
|
-
break
|
|
337
|
-
}
|
|
338
|
-
}
|
|
333
|
+
found := slices.Contains(packages, expected)
|
|
339
334
|
if !found {
|
|
340
335
|
t.Logf("Expected package '%s' not found in discovered packages: %v", expected, packages)
|
|
341
336
|
}
|
package/compiler/code-writer.go
CHANGED
|
@@ -59,8 +59,8 @@ func (w *TSCodeWriter) WriteImport(symbolName, importPath string) {
|
|
|
59
59
|
|
|
60
60
|
// WriteCommentLine writes a comment as a // line.
|
|
61
61
|
func (w *TSCodeWriter) WriteCommentLine(commentText string) {
|
|
62
|
-
lines := strings.
|
|
63
|
-
for
|
|
62
|
+
lines := strings.SplitSeq(commentText, "\n")
|
|
63
|
+
for line := range lines {
|
|
64
64
|
w.WriteLinef("// %s", line)
|
|
65
65
|
}
|
|
66
66
|
}
|
package/compiler/compiler.go
CHANGED
|
@@ -414,9 +414,9 @@ func (c *PackageCompiler) Compile(ctx context.Context) error {
|
|
|
414
414
|
|
|
415
415
|
// Check if this is a .pb.go file that should be skipped
|
|
416
416
|
baseFileName := filepath.Base(fileName)
|
|
417
|
-
if strings.
|
|
417
|
+
if before, ok := strings.CutSuffix(baseFileName, ".pb.go"); ok {
|
|
418
418
|
// Check if there's a corresponding .pb.ts file
|
|
419
|
-
pbTsFileName :=
|
|
419
|
+
pbTsFileName := before + ".pb.ts"
|
|
420
420
|
packageDir := filepath.Dir(fileName)
|
|
421
421
|
pbTsPath := filepath.Join(packageDir, pbTsFileName)
|
|
422
422
|
|
|
@@ -1131,10 +1131,10 @@ func (c *GoToTSCompiler) WriteDoc(doc *ast.CommentGroup) {
|
|
|
1131
1131
|
// Preserve original comment style (// or /*)
|
|
1132
1132
|
if strings.HasPrefix(comment.Text, "//") {
|
|
1133
1133
|
c.tsw.WriteLine(comment.Text)
|
|
1134
|
-
} else if strings.
|
|
1134
|
+
} else if after, ok := strings.CutPrefix(comment.Text, "/*"); ok {
|
|
1135
1135
|
// Write block comments potentially spanning multiple lines
|
|
1136
1136
|
// Remove /* and */, then split by newline
|
|
1137
|
-
content := strings.TrimSuffix(
|
|
1137
|
+
content := strings.TrimSuffix(after, "*/")
|
|
1138
1138
|
lines := strings.Split(content, "\n") // Use \n as Split expects a separator string
|
|
1139
1139
|
|
|
1140
1140
|
if len(lines) == 1 && !strings.Contains(lines[0], "\n") { // Check again for internal newlines just in case
|
|
@@ -107,7 +107,7 @@ func (c *GoToTSCompiler) WriteCompositeLit(exp *ast.CompositeLit) error {
|
|
|
107
107
|
// Use type info to get array length and element type
|
|
108
108
|
var arrayLen int
|
|
109
109
|
var elemType ast.Expr
|
|
110
|
-
var goElemType
|
|
110
|
+
var goElemType any
|
|
111
111
|
if typ := c.pkg.TypesInfo.TypeOf(exp.Type); typ != nil {
|
|
112
112
|
if at, ok := typ.Underlying().(*types.Array); ok {
|
|
113
113
|
arrayLen = int(at.Len())
|
|
@@ -534,7 +534,7 @@ func (c *GoToTSCompiler) WriteVarRefedValue(expr ast.Expr) error {
|
|
|
534
534
|
// evaluateConstantExpr attempts to evaluate a Go expression as a compile-time constant.
|
|
535
535
|
// It returns the constant value if successful, or nil if the expression is not a constant.
|
|
536
536
|
// This is used for evaluating array literal keys that are constant expressions.
|
|
537
|
-
func (c *GoToTSCompiler) evaluateConstantExpr(expr ast.Expr)
|
|
537
|
+
func (c *GoToTSCompiler) evaluateConstantExpr(expr ast.Expr) any {
|
|
538
538
|
// Use the type checker's constant evaluation
|
|
539
539
|
if tv, ok := c.pkg.TypesInfo.Types[expr]; ok && tv.Value != nil {
|
|
540
540
|
// The expression has a constant value
|
|
@@ -575,8 +575,7 @@ func (c *GoToTSCompiler) categorizeStructFields(
|
|
|
575
575
|
explicitEmbedded = make(map[string]ast.Expr)
|
|
576
576
|
|
|
577
577
|
// Pre-populate embeddedFields map keys using the correct property name
|
|
578
|
-
for
|
|
579
|
-
field := structType.Field(i)
|
|
578
|
+
for field := range structType.Fields() {
|
|
580
579
|
if field.Anonymous() {
|
|
581
580
|
fieldType := field.Type()
|
|
582
581
|
if ptr, ok := fieldType.(*types.Pointer); ok {
|
|
@@ -611,8 +610,7 @@ func (c *GoToTSCompiler) categorizeStructFields(
|
|
|
611
610
|
}
|
|
612
611
|
|
|
613
612
|
isDirectField := false
|
|
614
|
-
for
|
|
615
|
-
field := structType.Field(i)
|
|
613
|
+
for field := range structType.Fields() {
|
|
616
614
|
if field.Name() == keyName {
|
|
617
615
|
isDirectField = true
|
|
618
616
|
directFields[keyName] = kv.Value
|
package/compiler/constraint.go
CHANGED
|
@@ -16,11 +16,9 @@ type ConstraintInfo struct {
|
|
|
16
16
|
func analyzeConstraint(iface *types.Interface) ConstraintInfo {
|
|
17
17
|
info := ConstraintInfo{}
|
|
18
18
|
|
|
19
|
-
for
|
|
20
|
-
embedded := iface.EmbeddedType(i)
|
|
19
|
+
for embedded := range iface.EmbeddedTypes() {
|
|
21
20
|
if union, ok := embedded.(*types.Union); ok {
|
|
22
|
-
for
|
|
23
|
-
term := union.Term(j)
|
|
21
|
+
for term := range union.Terms() {
|
|
24
22
|
checkType(term.Type(), &info)
|
|
25
23
|
}
|
|
26
24
|
} else {
|
|
@@ -169,6 +169,10 @@ func (c *GoToTSCompiler) addNonNullAssertion(expFun ast.Expr) {
|
|
|
169
169
|
c.tsw.WriteLiterally("!")
|
|
170
170
|
}
|
|
171
171
|
}
|
|
172
|
+
} else if _, isParenExpr := expFun.(*ast.ParenExpr); isParenExpr {
|
|
173
|
+
// Parenthesized function expressions often come from pointer dereferences
|
|
174
|
+
// like (*rel)(), which remain nullable in TypeScript.
|
|
175
|
+
c.tsw.WriteLiterally("!")
|
|
172
176
|
} else if _, isNamed := funType.(*types.Named); isNamed {
|
|
173
177
|
c.tsw.WriteLiterally("!")
|
|
174
178
|
}
|
|
@@ -8,12 +8,12 @@ import (
|
|
|
8
8
|
)
|
|
9
9
|
|
|
10
10
|
// writeByteSliceCreation handles the creation of []byte slices with proper Uint8Array handling
|
|
11
|
-
func (c *GoToTSCompiler) writeByteSliceCreation(lengthArg, capacityArg
|
|
11
|
+
func (c *GoToTSCompiler) writeByteSliceCreation(lengthArg, capacityArg any) error {
|
|
12
12
|
return c.writeSliceCreationForType(lengthArg, capacityArg, true)
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
// writeSliceCreationForType handles slice creation with special handling for byte slices
|
|
16
|
-
func (c *GoToTSCompiler) writeSliceCreationForType(lengthArg, capacityArg
|
|
16
|
+
func (c *GoToTSCompiler) writeSliceCreationForType(lengthArg, capacityArg any, isByteSlice bool) error {
|
|
17
17
|
hasCapacity := capacityArg != nil
|
|
18
18
|
|
|
19
19
|
if isByteSlice && !hasCapacity {
|
|
@@ -52,7 +52,7 @@ func (c *GoToTSCompiler) writeSliceCreationForType(lengthArg, capacityArg interf
|
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
// writeGenericSliceCreation handles the creation of generic slices with proper type hints
|
|
55
|
-
func (c *GoToTSCompiler) writeGenericSliceCreation(elemType types.Type, lengthArg, capacityArg
|
|
55
|
+
func (c *GoToTSCompiler) writeGenericSliceCreation(elemType types.Type, lengthArg, capacityArg any) error {
|
|
56
56
|
hasCapacity := capacityArg != nil
|
|
57
57
|
|
|
58
58
|
c.tsw.WriteLiterally("$.makeSlice<")
|
|
@@ -90,7 +90,7 @@ func (c *GoToTSCompiler) writeSliceTypeHint(elemType types.Type, hasCapacity boo
|
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
// writeExprOrDefault writes an expression if it's not nil, otherwise writes a default value
|
|
93
|
-
func (c *GoToTSCompiler) writeExprOrDefault(expr
|
|
93
|
+
func (c *GoToTSCompiler) writeExprOrDefault(expr any, defaultValue string) error {
|
|
94
94
|
if expr == nil {
|
|
95
95
|
c.tsw.WriteLiterally(defaultValue)
|
|
96
96
|
return nil
|
|
@@ -149,6 +149,14 @@ func (c *GoToTSCompiler) writeReflectTypeFor(exp *ast.CallExpr, selectorExpr *as
|
|
|
149
149
|
typeArg := instance.TypeArgs.At(0)
|
|
150
150
|
// fmt.Printf("DEBUG: Type argument: %v\n", typeArg)
|
|
151
151
|
|
|
152
|
+
if named, ok := typeArg.(*types.Named); ok {
|
|
153
|
+
if _, isInterface := named.Underlying().(*types.Interface); isInterface {
|
|
154
|
+
typeName := qualifiedTypeName(named)
|
|
155
|
+
c.tsw.WriteLiterally("reflect.getInterfaceLiteralTypeByName(\"" + typeName + "\")")
|
|
156
|
+
return true, nil
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
152
160
|
// Generate TypeScript code to create a Type for this type
|
|
153
161
|
if err := c.writeTypeForTypeArg(typeArg); err != nil {
|
|
154
162
|
return true, err
|
|
@@ -157,6 +165,54 @@ func (c *GoToTSCompiler) writeReflectTypeFor(exp *ast.CallExpr, selectorExpr *as
|
|
|
157
165
|
return true, nil
|
|
158
166
|
}
|
|
159
167
|
|
|
168
|
+
// writeReflectTypeAssert handles reflect.TypeAssert[T](v) calls.
|
|
169
|
+
func (c *GoToTSCompiler) writeReflectTypeAssert(exp *ast.CallExpr, selectorExpr *ast.SelectorExpr) (handled bool, err error) {
|
|
170
|
+
if selectorExpr.Sel.Name != "TypeAssert" {
|
|
171
|
+
return false, nil
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
xIdent, ok := selectorExpr.X.(*ast.Ident)
|
|
175
|
+
if !ok {
|
|
176
|
+
return false, nil
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
obj := c.objectOfIdent(xIdent)
|
|
180
|
+
if obj == nil {
|
|
181
|
+
return false, nil
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
pkgName, ok := obj.(*types.PkgName)
|
|
185
|
+
if !ok || pkgName.Imported().Path() != "reflect" {
|
|
186
|
+
return false, nil
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if len(exp.Args) != 1 {
|
|
190
|
+
return false, errors.New("reflect.TypeAssert called with unexpected argument count")
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if c.pkg.TypesInfo.Instances == nil {
|
|
194
|
+
return false, errors.New("reflect.TypeAssert called but no type instances available")
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
instance, hasInstance := c.pkg.TypesInfo.Instances[selectorExpr.Sel]
|
|
198
|
+
if !hasInstance || instance.TypeArgs == nil || instance.TypeArgs.Len() == 0 {
|
|
199
|
+
return false, errors.New("reflect.TypeAssert called without type arguments")
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
typeArg := instance.TypeArgs.At(0)
|
|
203
|
+
|
|
204
|
+
c.tsw.WriteLiterally("$.typeAssertTuple<")
|
|
205
|
+
c.WriteGoType(typeArg, GoTypeContextGeneral)
|
|
206
|
+
c.tsw.WriteLiterally(">(")
|
|
207
|
+
if err := c.WriteValueExpr(exp.Args[0]); err != nil {
|
|
208
|
+
return true, err
|
|
209
|
+
}
|
|
210
|
+
c.tsw.WriteLiterally(".Interface(), ")
|
|
211
|
+
c.writeTypeInfoObject(typeArg)
|
|
212
|
+
c.tsw.WriteLiterally(")")
|
|
213
|
+
return true, nil
|
|
214
|
+
}
|
|
215
|
+
|
|
160
216
|
// writeTypeForTypeArg generates TypeScript code to create a reflect.Type for the given Go type
|
|
161
217
|
func (c *GoToTSCompiler) writeTypeForTypeArg(t types.Type) error {
|
|
162
218
|
// Handle basic types
|
|
@@ -175,12 +231,46 @@ func (c *GoToTSCompiler) writeTypeForTypeArg(t types.Type) error {
|
|
|
175
231
|
c.tsw.WriteLiterally(")")
|
|
176
232
|
return nil
|
|
177
233
|
case *types.Slice:
|
|
178
|
-
|
|
179
|
-
c.
|
|
234
|
+
c.tsw.WriteLiterally("reflect.SliceOf(")
|
|
235
|
+
if err := c.writeTypeForTypeArg(underlying.Elem()); err != nil {
|
|
236
|
+
return err
|
|
237
|
+
}
|
|
238
|
+
c.tsw.WriteLiterally(")")
|
|
180
239
|
return nil
|
|
181
240
|
case *types.Array:
|
|
182
|
-
|
|
183
|
-
c.tsw.
|
|
241
|
+
c.tsw.WriteLiterally("reflect.ArrayOf(")
|
|
242
|
+
c.tsw.WriteLiterallyf("%d, ", underlying.Len())
|
|
243
|
+
if err := c.writeTypeForTypeArg(underlying.Elem()); err != nil {
|
|
244
|
+
return err
|
|
245
|
+
}
|
|
246
|
+
c.tsw.WriteLiterally(")")
|
|
247
|
+
return nil
|
|
248
|
+
case *types.Map:
|
|
249
|
+
c.tsw.WriteLiterally("reflect.MapOf(")
|
|
250
|
+
if err := c.writeTypeForTypeArg(underlying.Key()); err != nil {
|
|
251
|
+
return err
|
|
252
|
+
}
|
|
253
|
+
c.tsw.WriteLiterally(", ")
|
|
254
|
+
if err := c.writeTypeForTypeArg(underlying.Elem()); err != nil {
|
|
255
|
+
return err
|
|
256
|
+
}
|
|
257
|
+
c.tsw.WriteLiterally(")")
|
|
258
|
+
return nil
|
|
259
|
+
case *types.Chan:
|
|
260
|
+
c.tsw.WriteLiterally("reflect.ChanOf(")
|
|
261
|
+
switch underlying.Dir() {
|
|
262
|
+
case types.RecvOnly:
|
|
263
|
+
c.tsw.WriteLiterally("reflect.RecvDir")
|
|
264
|
+
case types.SendOnly:
|
|
265
|
+
c.tsw.WriteLiterally("reflect.SendDir")
|
|
266
|
+
default:
|
|
267
|
+
c.tsw.WriteLiterally("reflect.BothDir")
|
|
268
|
+
}
|
|
269
|
+
c.tsw.WriteLiterally(", ")
|
|
270
|
+
if err := c.writeTypeForTypeArg(underlying.Elem()); err != nil {
|
|
271
|
+
return err
|
|
272
|
+
}
|
|
273
|
+
c.tsw.WriteLiterally(")")
|
|
184
274
|
return nil
|
|
185
275
|
case *types.Struct:
|
|
186
276
|
// For struct types, use TypeOf with zero value
|
|
@@ -79,7 +79,7 @@ func (c *GoToTSCompiler) writeMakeSlice(sliceType *types.Slice, exp *ast.CallExp
|
|
|
79
79
|
|
|
80
80
|
// Check if it's []byte
|
|
81
81
|
if c.isByteSliceType(sliceType) {
|
|
82
|
-
var lengthArg, capacityArg
|
|
82
|
+
var lengthArg, capacityArg any
|
|
83
83
|
if len(exp.Args) >= 2 {
|
|
84
84
|
lengthArg = exp.Args[1]
|
|
85
85
|
}
|
|
@@ -90,7 +90,7 @@ func (c *GoToTSCompiler) writeMakeSlice(sliceType *types.Slice, exp *ast.CallExp
|
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
// Handle other slice types
|
|
93
|
-
var lengthArg, capacityArg
|
|
93
|
+
var lengthArg, capacityArg any
|
|
94
94
|
if len(exp.Args) >= 2 {
|
|
95
95
|
lengthArg = exp.Args[1]
|
|
96
96
|
}
|
|
@@ -193,7 +193,7 @@ func (c *GoToTSCompiler) WriteCallExprMake(exp *ast.CallExpr) error {
|
|
|
193
193
|
if elemType != nil {
|
|
194
194
|
// Check if it's make(S, ...) where S constrains to []byte
|
|
195
195
|
if c.isByteSliceType(types.NewSlice(elemType)) {
|
|
196
|
-
var lengthArg, capacityArg
|
|
196
|
+
var lengthArg, capacityArg any
|
|
197
197
|
if len(exp.Args) >= 2 {
|
|
198
198
|
lengthArg = exp.Args[1]
|
|
199
199
|
}
|
|
@@ -203,7 +203,7 @@ func (c *GoToTSCompiler) WriteCallExprMake(exp *ast.CallExpr) error {
|
|
|
203
203
|
return c.writeByteSliceCreation(lengthArg, capacityArg)
|
|
204
204
|
}
|
|
205
205
|
|
|
206
|
-
var lengthArg, capacityArg
|
|
206
|
+
var lengthArg, capacityArg any
|
|
207
207
|
if len(exp.Args) >= 2 {
|
|
208
208
|
lengthArg = exp.Args[1]
|
|
209
209
|
}
|
package/compiler/expr-call.go
CHANGED
|
@@ -100,6 +100,9 @@ func (c *GoToTSCompiler) WriteCallExpr(exp *ast.CallExpr) error {
|
|
|
100
100
|
// Handle reflect.TypeFor[T]() - Fun is IndexExpr where X is SelectorExpr
|
|
101
101
|
if indexExpr, ok := expFun.(*ast.IndexExpr); ok {
|
|
102
102
|
if selectorExpr, ok := indexExpr.X.(*ast.SelectorExpr); ok {
|
|
103
|
+
if handled, err := c.writeReflectTypeAssert(exp, selectorExpr); handled {
|
|
104
|
+
return err
|
|
105
|
+
}
|
|
103
106
|
if handled, err := c.writeReflectTypeFor(exp, selectorExpr); handled {
|
|
104
107
|
return err
|
|
105
108
|
}
|
package/compiler/expr-type.go
CHANGED
|
@@ -20,6 +20,48 @@ import (
|
|
|
20
20
|
// - Interface types -> TypeScript interface types or "any"
|
|
21
21
|
// - Function types -> TypeScript function signatures
|
|
22
22
|
func (c *GoToTSCompiler) WriteTypeExpr(a ast.Expr) {
|
|
23
|
+
// Handle qualified generic type references (e.g., pkg.Type[T]) preserving the package alias.
|
|
24
|
+
if indexExpr, ok := a.(*ast.IndexExpr); ok {
|
|
25
|
+
if selectorExpr, ok := indexExpr.X.(*ast.SelectorExpr); ok {
|
|
26
|
+
if pkgIdent, ok := selectorExpr.X.(*ast.Ident); ok {
|
|
27
|
+
if obj := c.pkg.TypesInfo.Uses[pkgIdent]; obj != nil {
|
|
28
|
+
if _, isPkg := obj.(*types.PkgName); isPkg {
|
|
29
|
+
c.tsw.WriteLiterally(pkgIdent.Name)
|
|
30
|
+
c.tsw.WriteLiterally(".")
|
|
31
|
+
c.tsw.WriteLiterally(selectorExpr.Sel.Name)
|
|
32
|
+
c.tsw.WriteLiterally("<")
|
|
33
|
+
c.WriteTypeExpr(indexExpr.Index)
|
|
34
|
+
c.tsw.WriteLiterally(">")
|
|
35
|
+
return
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if indexListExpr, ok := a.(*ast.IndexListExpr); ok {
|
|
43
|
+
if selectorExpr, ok := indexListExpr.X.(*ast.SelectorExpr); ok {
|
|
44
|
+
if pkgIdent, ok := selectorExpr.X.(*ast.Ident); ok {
|
|
45
|
+
if obj := c.pkg.TypesInfo.Uses[pkgIdent]; obj != nil {
|
|
46
|
+
if _, isPkg := obj.(*types.PkgName); isPkg {
|
|
47
|
+
c.tsw.WriteLiterally(pkgIdent.Name)
|
|
48
|
+
c.tsw.WriteLiterally(".")
|
|
49
|
+
c.tsw.WriteLiterally(selectorExpr.Sel.Name)
|
|
50
|
+
c.tsw.WriteLiterally("<")
|
|
51
|
+
for i, index := range indexListExpr.Indices {
|
|
52
|
+
if i > 0 {
|
|
53
|
+
c.tsw.WriteLiterally(", ")
|
|
54
|
+
}
|
|
55
|
+
c.WriteTypeExpr(index)
|
|
56
|
+
}
|
|
57
|
+
c.tsw.WriteLiterally(">")
|
|
58
|
+
return
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
23
65
|
// Handle selector expressions (e.g., os.FileInfo) specially to preserve qualified names
|
|
24
66
|
if selectorExpr, ok := a.(*ast.SelectorExpr); ok {
|
|
25
67
|
if pkgIdent, ok := selectorExpr.X.(*ast.Ident); ok {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
package compiler
|
|
2
2
|
|
|
3
3
|
import (
|
|
4
|
+
"slices"
|
|
4
5
|
"testing"
|
|
5
6
|
|
|
6
7
|
"github.com/sirupsen/logrus"
|
|
@@ -36,13 +37,7 @@ func TestReadGsPackageMetadata(t *testing.T) {
|
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
// Check for the specific "iter" dependency
|
|
39
|
-
foundIter :=
|
|
40
|
-
for _, dep := range metadata.Dependencies {
|
|
41
|
-
if dep == "iter" {
|
|
42
|
-
foundIter = true
|
|
43
|
-
break
|
|
44
|
-
}
|
|
45
|
-
}
|
|
40
|
+
foundIter := slices.Contains(metadata.Dependencies, "iter")
|
|
46
41
|
|
|
47
42
|
if !foundIter {
|
|
48
43
|
t.Errorf("Expected to find 'iter' dependency, got dependencies: %v", metadata.Dependencies)
|
|
@@ -51,13 +46,7 @@ func TestReadGsPackageMetadata(t *testing.T) {
|
|
|
51
46
|
// Also check for other expected dependencies from the bytes package
|
|
52
47
|
expectedDeps := []string{"errors", "io", "iter", "unicode", "unicode/utf8", "unsafe"}
|
|
53
48
|
for _, expected := range expectedDeps {
|
|
54
|
-
found :=
|
|
55
|
-
for _, dep := range metadata.Dependencies {
|
|
56
|
-
if dep == expected {
|
|
57
|
-
found = true
|
|
58
|
-
break
|
|
59
|
-
}
|
|
60
|
-
}
|
|
49
|
+
found := slices.Contains(metadata.Dependencies, expected)
|
|
61
50
|
if !found {
|
|
62
51
|
t.Errorf("Expected to find dependency '%s', got dependencies: %v", expected, metadata.Dependencies)
|
|
63
52
|
}
|