goscript 0.0.42 → 0.0.43
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 +87 -0
- package/compiler/assignment.go +6 -0
- package/compiler/compiler.go +85 -5
- package/compiler/decl.go +42 -20
- package/compiler/expr-call.go +37 -1
- package/compiler/expr-type.go +20 -0
- package/compiler/lit.go +4 -20
- package/compiler/spec-struct.go +3 -4
- package/compiler/spec-value.go +18 -1
- package/compiler/spec.go +15 -8
- package/compiler/stmt-range.go +1 -1
- package/compiler/type-assert.go +4 -4
- package/compiler/type.go +63 -5
- package/dist/gs/builtin/map.d.ts +4 -4
- package/dist/gs/builtin/map.js +6 -3
- package/dist/gs/builtin/map.js.map +1 -1
- package/dist/gs/builtin/slice.d.ts +7 -0
- package/dist/gs/builtin/slice.js +12 -0
- package/dist/gs/builtin/slice.js.map +1 -1
- package/dist/gs/builtin/type.js +8 -70
- package/dist/gs/builtin/type.js.map +1 -1
- package/dist/gs/fmt/fmt.d.ts +22 -21
- package/dist/gs/fmt/fmt.js +12 -12
- package/dist/gs/fmt/fmt.js.map +1 -1
- package/dist/gs/internal/testlog/index.d.ts +1 -0
- package/dist/gs/internal/testlog/index.js +5 -0
- package/dist/gs/internal/testlog/index.js.map +1 -0
- package/dist/gs/io/io.d.ts +13 -13
- package/dist/gs/io/io.js +31 -21
- package/dist/gs/io/io.js.map +1 -1
- package/dist/gs/maps/iter.gs.d.ts +7 -0
- package/dist/gs/maps/iter.gs.js +65 -0
- package/dist/gs/maps/iter.gs.js.map +1 -0
- package/dist/gs/maps/maps.gs.d.ts +7 -0
- package/dist/gs/maps/maps.gs.js +79 -0
- package/dist/gs/maps/maps.gs.js.map +1 -0
- package/dist/gs/path/filepath/match.d.ts +4 -3
- package/dist/gs/path/filepath/match.js +2 -2
- package/dist/gs/path/filepath/match.js.map +1 -1
- package/dist/gs/path/filepath/path.d.ts +2 -2
- package/dist/gs/path/filepath/path.js +3 -3
- package/dist/gs/path/filepath/path.js.map +1 -1
- package/dist/gs/reflect/abi.d.ts +59 -0
- package/dist/gs/reflect/abi.gs.d.ts +59 -0
- package/dist/gs/reflect/abi.gs.js +79 -0
- package/dist/gs/reflect/abi.gs.js.map +1 -0
- package/dist/gs/reflect/abi.js +79 -0
- package/dist/gs/reflect/abi.js.map +1 -0
- package/dist/gs/reflect/badlinkname.d.ts +52 -0
- package/dist/gs/reflect/badlinkname.gs.d.ts +52 -0
- package/dist/gs/reflect/badlinkname.gs.js +72 -0
- package/dist/gs/reflect/badlinkname.gs.js.map +1 -0
- package/dist/gs/reflect/badlinkname.js +72 -0
- package/dist/gs/reflect/badlinkname.js.map +1 -0
- package/dist/gs/reflect/deepequal.gs.d.ts +25 -0
- package/dist/gs/reflect/deepequal.gs.js +308 -0
- package/dist/gs/reflect/deepequal.gs.js.map +1 -0
- package/dist/gs/reflect/float32reg_generic.gs.d.ts +2 -0
- package/dist/gs/reflect/float32reg_generic.gs.js +10 -0
- package/dist/gs/reflect/float32reg_generic.gs.js.map +1 -0
- package/dist/gs/reflect/index.gs.d.ts +1 -0
- package/dist/gs/reflect/index.gs.js +3 -0
- package/dist/gs/reflect/index.gs.js.map +1 -0
- package/dist/gs/reflect/iter.gs.d.ts +3 -0
- package/dist/gs/reflect/iter.gs.js +24 -0
- package/dist/gs/reflect/iter.gs.js.map +1 -0
- package/dist/gs/reflect/makefunc.gs.d.ts +34 -0
- package/dist/gs/reflect/makefunc.gs.js +288 -0
- package/dist/gs/reflect/makefunc.gs.js.map +1 -0
- package/dist/gs/reflect/map_swiss.gs.d.ts +14 -0
- package/dist/gs/reflect/map_swiss.gs.js +70 -0
- package/dist/gs/reflect/map_swiss.gs.js.map +1 -0
- package/dist/gs/reflect/reflect.gs.d.ts +132 -0
- package/dist/gs/reflect/reflect.gs.js +437 -0
- package/dist/gs/reflect/reflect.gs.js.map +1 -0
- package/dist/gs/reflect/swapper.gs.d.ts +1 -0
- package/dist/gs/reflect/swapper.gs.js +32 -0
- package/dist/gs/reflect/swapper.gs.js.map +1 -0
- package/dist/gs/reflect/type.gs.d.ts +4 -0
- package/dist/gs/reflect/type.gs.js +21 -0
- package/dist/gs/reflect/type.gs.js.map +1 -0
- package/dist/gs/reflect/value.gs.d.ts +4 -0
- package/dist/gs/reflect/value.gs.js +12 -0
- package/dist/gs/reflect/value.gs.js.map +1 -0
- package/dist/gs/reflect/visiblefields.gs.d.ts +3 -0
- package/dist/gs/reflect/visiblefields.gs.js +123 -0
- package/dist/gs/reflect/visiblefields.gs.js.map +1 -0
- package/dist/gs/strings/reader.d.ts +1 -1
- package/dist/gs/strings/reader.js.map +1 -1
- package/dist/gs/stringslite/index.d.ts +1 -0
- package/dist/gs/stringslite/index.js +2 -0
- package/dist/gs/stringslite/index.js.map +1 -0
- package/dist/gs/stringslite/strings.d.ts +11 -0
- package/dist/gs/stringslite/strings.js +67 -0
- package/dist/gs/stringslite/strings.js.map +1 -0
- package/dist/gs/time/time.d.ts +69 -0
- package/dist/gs/time/time.js +350 -0
- package/dist/gs/time/time.js.map +1 -1
- package/gs/builtin/map.ts +12 -8
- package/gs/builtin/slice.ts +13 -0
- package/gs/builtin/type.ts +8 -100
- package/gs/fmt/fmt.ts +33 -33
- package/gs/io/io.ts +47 -39
- package/gs/path/filepath/match.ts +4 -4
- package/gs/path/filepath/path.ts +3 -3
- package/gs/strings/reader.ts +1 -1
- package/gs/time/time.ts +403 -0
- package/package.json +1 -1
package/compiler/analysis.go
CHANGED
|
@@ -125,6 +125,14 @@ type PackageAnalysis struct {
|
|
|
125
125
|
// FunctionCalls maps file names to the functions they call from other files
|
|
126
126
|
// Key: filename (without .go extension), Value: map[sourceFile][]functionNames
|
|
127
127
|
FunctionCalls map[string]map[string][]string
|
|
128
|
+
|
|
129
|
+
// TypeDefs maps file names to the types defined in that file
|
|
130
|
+
// Key: filename (without .go extension), Value: list of type names
|
|
131
|
+
TypeDefs map[string][]string
|
|
132
|
+
|
|
133
|
+
// TypeCalls maps file names to the types they reference from other files
|
|
134
|
+
// Key: filename (without .go extension), Value: map[sourceFile][]typeNames
|
|
135
|
+
TypeCalls map[string]map[string][]string
|
|
128
136
|
}
|
|
129
137
|
|
|
130
138
|
// NewAnalysis creates a new Analysis instance.
|
|
@@ -146,6 +154,8 @@ func NewPackageAnalysis() *PackageAnalysis {
|
|
|
146
154
|
return &PackageAnalysis{
|
|
147
155
|
FunctionDefs: make(map[string][]string),
|
|
148
156
|
FunctionCalls: make(map[string]map[string][]string),
|
|
157
|
+
TypeDefs: make(map[string][]string),
|
|
158
|
+
TypeCalls: make(map[string]map[string][]string),
|
|
149
159
|
}
|
|
150
160
|
}
|
|
151
161
|
|
|
@@ -1036,6 +1046,7 @@ func AnalyzePackage(pkg *packages.Package) *PackageAnalysis {
|
|
|
1036
1046
|
baseFileName := strings.TrimSuffix(filepath.Base(fileName), ".go")
|
|
1037
1047
|
|
|
1038
1048
|
var functions []string
|
|
1049
|
+
var types []string
|
|
1039
1050
|
for _, decl := range syntax.Decls {
|
|
1040
1051
|
if funcDecl, ok := decl.(*ast.FuncDecl); ok {
|
|
1041
1052
|
// Only collect top-level functions (not methods)
|
|
@@ -1043,11 +1054,22 @@ func AnalyzePackage(pkg *packages.Package) *PackageAnalysis {
|
|
|
1043
1054
|
functions = append(functions, funcDecl.Name.Name)
|
|
1044
1055
|
}
|
|
1045
1056
|
}
|
|
1057
|
+
if genDecl, ok := decl.(*ast.GenDecl); ok {
|
|
1058
|
+
// Collect type declarations
|
|
1059
|
+
for _, spec := range genDecl.Specs {
|
|
1060
|
+
if typeSpec, ok := spec.(*ast.TypeSpec); ok {
|
|
1061
|
+
types = append(types, typeSpec.Name.Name)
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1046
1065
|
}
|
|
1047
1066
|
|
|
1048
1067
|
if len(functions) > 0 {
|
|
1049
1068
|
analysis.FunctionDefs[baseFileName] = functions
|
|
1050
1069
|
}
|
|
1070
|
+
if len(types) > 0 {
|
|
1071
|
+
analysis.TypeDefs[baseFileName] = types
|
|
1072
|
+
}
|
|
1051
1073
|
}
|
|
1052
1074
|
|
|
1053
1075
|
// Second pass: analyze function calls and determine which need imports
|
|
@@ -1111,6 +1133,71 @@ func AnalyzePackage(pkg *packages.Package) *PackageAnalysis {
|
|
|
1111
1133
|
}
|
|
1112
1134
|
}
|
|
1113
1135
|
|
|
1136
|
+
// Third pass: analyze type references and determine which need imports
|
|
1137
|
+
for i, syntax := range pkg.Syntax {
|
|
1138
|
+
fileName := pkg.CompiledGoFiles[i]
|
|
1139
|
+
baseFileName := strings.TrimSuffix(filepath.Base(fileName), ".go")
|
|
1140
|
+
|
|
1141
|
+
// Find all type references in this file
|
|
1142
|
+
typeRefsFromOtherFiles := make(map[string][]string)
|
|
1143
|
+
|
|
1144
|
+
ast.Inspect(syntax, func(n ast.Node) bool {
|
|
1145
|
+
// Look for type references in struct fields, function parameters, etc.
|
|
1146
|
+
if ident, ok := n.(*ast.Ident); ok {
|
|
1147
|
+
// Check if this identifier refers to a type
|
|
1148
|
+
if obj := pkg.TypesInfo.Uses[ident]; obj != nil {
|
|
1149
|
+
if _, ok := obj.(*types.TypeName); ok {
|
|
1150
|
+
typeName := ident.Name
|
|
1151
|
+
|
|
1152
|
+
// Check if this type is defined in the current file
|
|
1153
|
+
currentFileTypes := analysis.TypeDefs[baseFileName]
|
|
1154
|
+
isDefinedInCurrentFile := false
|
|
1155
|
+
for _, t := range currentFileTypes {
|
|
1156
|
+
if t == typeName {
|
|
1157
|
+
isDefinedInCurrentFile = true
|
|
1158
|
+
break
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
// If not defined in current file, find which file defines it
|
|
1163
|
+
if !isDefinedInCurrentFile {
|
|
1164
|
+
for sourceFile, types := range analysis.TypeDefs {
|
|
1165
|
+
if sourceFile == baseFileName {
|
|
1166
|
+
continue // Skip current file
|
|
1167
|
+
}
|
|
1168
|
+
for _, t := range types {
|
|
1169
|
+
if t == typeName {
|
|
1170
|
+
// Found the type in another file
|
|
1171
|
+
if typeRefsFromOtherFiles[sourceFile] == nil {
|
|
1172
|
+
typeRefsFromOtherFiles[sourceFile] = []string{}
|
|
1173
|
+
}
|
|
1174
|
+
// Check if already added to avoid duplicates
|
|
1175
|
+
found := false
|
|
1176
|
+
for _, existing := range typeRefsFromOtherFiles[sourceFile] {
|
|
1177
|
+
if existing == typeName {
|
|
1178
|
+
found = true
|
|
1179
|
+
break
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
if !found {
|
|
1183
|
+
typeRefsFromOtherFiles[sourceFile] = append(typeRefsFromOtherFiles[sourceFile], typeName)
|
|
1184
|
+
}
|
|
1185
|
+
break
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
return true
|
|
1194
|
+
})
|
|
1195
|
+
|
|
1196
|
+
if len(typeRefsFromOtherFiles) > 0 {
|
|
1197
|
+
analysis.TypeCalls[baseFileName] = typeRefsFromOtherFiles
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1114
1201
|
return analysis
|
|
1115
1202
|
}
|
|
1116
1203
|
|
package/compiler/assignment.go
CHANGED
|
@@ -124,6 +124,12 @@ func (c *GoToTSCompiler) writeAssignmentCore(lhs, rhs []ast.Expr, tok token.Toke
|
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
+
// Add semicolon before destructuring assignment to prevent TypeScript
|
|
128
|
+
// from interpreting it as array access on the previous line
|
|
129
|
+
if tok != token.DEFINE {
|
|
130
|
+
c.tsw.WriteLiterally(";")
|
|
131
|
+
}
|
|
132
|
+
|
|
127
133
|
// Use array destructuring for multi-variable assignments
|
|
128
134
|
c.tsw.WriteLiterally("[")
|
|
129
135
|
for i, l := range lhs {
|
package/compiler/compiler.go
CHANGED
|
@@ -621,6 +621,61 @@ func (c *FileCompiler) Compile(ctx context.Context) error {
|
|
|
621
621
|
}
|
|
622
622
|
}
|
|
623
623
|
|
|
624
|
+
// Generate auto-imports for types from other files in the same package
|
|
625
|
+
if typeImports := c.PackageAnalysis.TypeCalls[currentFileName]; typeImports != nil {
|
|
626
|
+
// Sort source files for consistent import order
|
|
627
|
+
var sourceFiles []string
|
|
628
|
+
for sourceFile := range typeImports {
|
|
629
|
+
sourceFiles = append(sourceFiles, sourceFile)
|
|
630
|
+
}
|
|
631
|
+
sort.Strings(sourceFiles)
|
|
632
|
+
|
|
633
|
+
for _, sourceFile := range sourceFiles {
|
|
634
|
+
typeImports := typeImports[sourceFile]
|
|
635
|
+
if len(typeImports) > 0 {
|
|
636
|
+
// Filter out protobuf types - they should be imported from .pb.js files, not .gs.js files
|
|
637
|
+
var nonProtobufTypes []string
|
|
638
|
+
for _, typeName := range typeImports {
|
|
639
|
+
// Check if this type is a protobuf type by looking for it in the package
|
|
640
|
+
isProtobuf := false
|
|
641
|
+
if typeObj := c.pkg.Types.Scope().Lookup(typeName); typeObj != nil {
|
|
642
|
+
objType := typeObj.Type()
|
|
643
|
+
if namedType, ok := objType.(*types.Named); ok {
|
|
644
|
+
obj := namedType.Obj()
|
|
645
|
+
if obj != nil && obj.Pkg() != nil {
|
|
646
|
+
// Check if the type is defined in the current package and has a corresponding .pb.go file
|
|
647
|
+
if obj.Pkg() == c.pkg.Types {
|
|
648
|
+
// Check if there's a .pb.go file in the package that exports this type
|
|
649
|
+
// For now, we'll use a simple heuristic: if the type name ends with "Msg"
|
|
650
|
+
// and there's a .pb.go file in the package, assume it's a protobuf type
|
|
651
|
+
if strings.HasSuffix(typeName, "Msg") {
|
|
652
|
+
// Check if there are any .pb.go files in this package
|
|
653
|
+
for _, fileName := range c.pkg.CompiledGoFiles {
|
|
654
|
+
if strings.HasSuffix(fileName, ".pb.go") {
|
|
655
|
+
isProtobuf = true
|
|
656
|
+
break
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
if !isProtobuf {
|
|
665
|
+
nonProtobufTypes = append(nonProtobufTypes, typeName)
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
if len(nonProtobufTypes) > 0 {
|
|
670
|
+
// Sort types for consistent output
|
|
671
|
+
sort.Strings(nonProtobufTypes)
|
|
672
|
+
c.codeWriter.WriteLinef("import { %s } from \"./%s.gs.js\";",
|
|
673
|
+
strings.Join(nonProtobufTypes, ", "), sourceFile)
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
|
|
624
679
|
c.codeWriter.WriteLine("") // Add a newline after imports
|
|
625
680
|
|
|
626
681
|
if err := goWriter.WriteDecls(f.Decls); err != nil {
|
|
@@ -690,11 +745,30 @@ func (c *GoToTSCompiler) WriteIdent(exp *ast.Ident, accessVarRefedValue bool) {
|
|
|
690
745
|
// Check if this identifier refers to a constant
|
|
691
746
|
if obj != nil {
|
|
692
747
|
if constObj, isConst := obj.(*types.Const); isConst {
|
|
693
|
-
//
|
|
694
|
-
//
|
|
695
|
-
//
|
|
696
|
-
|
|
697
|
-
|
|
748
|
+
// Evaluate constants to literals in these cases:
|
|
749
|
+
// 1. Predeclared constants (like iota, true, false) - these have nil package
|
|
750
|
+
// 2. Constants from the current package that are computed expressions
|
|
751
|
+
// (like iota-based constants or mathematical expressions)
|
|
752
|
+
//
|
|
753
|
+
// For simple assignments from imported constants (const x = pkg.Y),
|
|
754
|
+
// preserve the variable name for better readability.
|
|
755
|
+
|
|
756
|
+
if constObj.Pkg() == nil {
|
|
757
|
+
// Predeclared constants - always evaluate to literals
|
|
758
|
+
c.writeConstantValue(constObj)
|
|
759
|
+
return
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
if constObj.Pkg() == c.pkg.Types {
|
|
763
|
+
// This is a constant from the current package.
|
|
764
|
+
// Check if it's a simple assignment by looking at the constant value:
|
|
765
|
+
// If the constant has the same name as an identifier in the import,
|
|
766
|
+
// it's likely a simple assignment and we should preserve the name.
|
|
767
|
+
// Otherwise, evaluate to literal (for computed expressions like iota).
|
|
768
|
+
|
|
769
|
+
// For now, let's be conservative and evaluate current package constants
|
|
770
|
+
// to literals to maintain compatibility with existing behavior.
|
|
771
|
+
// This handles iota-based constants correctly.
|
|
698
772
|
c.writeConstantValue(constObj)
|
|
699
773
|
return
|
|
700
774
|
}
|
|
@@ -980,6 +1054,12 @@ func (c *Compiler) copyEmbeddedPackage(embeddedPath string, outputPath string) e
|
|
|
980
1054
|
continue
|
|
981
1055
|
}
|
|
982
1056
|
|
|
1057
|
+
// Skip .test.ts files
|
|
1058
|
+
if strings.HasSuffix(fileName, ".test.ts") {
|
|
1059
|
+
// c.le.Debugf("Skipping test file: %s", fileName)
|
|
1060
|
+
continue
|
|
1061
|
+
}
|
|
1062
|
+
|
|
983
1063
|
// Remove existing file if it exists (but preserve directories)
|
|
984
1064
|
if stat, err := os.Stat(outputEntryPath); err == nil && !stat.IsDir() {
|
|
985
1065
|
if err := os.Remove(outputEntryPath); err != nil {
|
package/compiler/decl.go
CHANGED
|
@@ -101,29 +101,13 @@ func (c *GoToTSCompiler) WriteFuncDeclAsFunction(decl *ast.FuncDecl) error {
|
|
|
101
101
|
c.WriteFuncType(decl.Type, isAsync) // Write signature (params, return type)
|
|
102
102
|
c.tsw.WriteLiterally(" ")
|
|
103
103
|
|
|
104
|
-
hasNamedReturns
|
|
105
|
-
if decl.Type.Results != nil {
|
|
106
|
-
for _, field := range decl.Type.Results.List {
|
|
107
|
-
if len(field.Names) > 0 {
|
|
108
|
-
hasNamedReturns = true
|
|
109
|
-
break
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
if hasNamedReturns {
|
|
104
|
+
if c.hasNamedReturns(decl.Type.Results) {
|
|
115
105
|
c.tsw.WriteLine("{")
|
|
116
106
|
c.tsw.Indent(1)
|
|
117
107
|
|
|
118
108
|
// Declare named return variables and initialize them to their zero values
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
c.tsw.WriteLiterallyf("let %s: ", c.sanitizeIdentifier(name.Name))
|
|
122
|
-
c.WriteTypeExpr(field.Type)
|
|
123
|
-
c.tsw.WriteLiterally(" = ")
|
|
124
|
-
c.WriteZeroValueForType(c.pkg.TypesInfo.TypeOf(field.Type))
|
|
125
|
-
c.tsw.WriteLine("")
|
|
126
|
-
}
|
|
109
|
+
if err := c.writeNamedReturnDeclarations(decl.Type.Results); err != nil {
|
|
110
|
+
return fmt.Errorf("failed to write named return declarations: %w", err)
|
|
127
111
|
}
|
|
128
112
|
}
|
|
129
113
|
|
|
@@ -131,7 +115,7 @@ func (c *GoToTSCompiler) WriteFuncDeclAsFunction(decl *ast.FuncDecl) error {
|
|
|
131
115
|
return fmt.Errorf("failed to write function body: %w", err)
|
|
132
116
|
}
|
|
133
117
|
|
|
134
|
-
if hasNamedReturns {
|
|
118
|
+
if c.hasNamedReturns(decl.Type.Results) {
|
|
135
119
|
c.tsw.Indent(-1)
|
|
136
120
|
c.tsw.WriteLine("}")
|
|
137
121
|
}
|
|
@@ -244,6 +228,11 @@ func (c *GoToTSCompiler) WriteFuncDeclAsMethod(decl *ast.FuncDecl) error {
|
|
|
244
228
|
}
|
|
245
229
|
}
|
|
246
230
|
|
|
231
|
+
// Declare named return variables and initialize them to their zero values
|
|
232
|
+
if err := c.writeNamedReturnDeclarations(decl.Type.Results); err != nil {
|
|
233
|
+
return fmt.Errorf("failed to write named return declarations: %w", err)
|
|
234
|
+
}
|
|
235
|
+
|
|
247
236
|
// write method body without outer braces
|
|
248
237
|
for _, stmt := range decl.Body.List {
|
|
249
238
|
if err := c.WriteStmt(stmt); err != nil {
|
|
@@ -263,3 +252,36 @@ func (c *GoToTSCompiler) WriteFuncDeclAsMethod(decl *ast.FuncDecl) error {
|
|
|
263
252
|
|
|
264
253
|
return nil
|
|
265
254
|
}
|
|
255
|
+
|
|
256
|
+
// writeNamedReturnDeclarations generates TypeScript variable declarations for named return parameters.
|
|
257
|
+
// It declares each named return variable with its appropriate type and zero value.
|
|
258
|
+
func (c *GoToTSCompiler) writeNamedReturnDeclarations(results *ast.FieldList) error {
|
|
259
|
+
if results == nil {
|
|
260
|
+
return nil
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
for _, field := range results.List {
|
|
264
|
+
for _, name := range field.Names {
|
|
265
|
+
c.tsw.WriteLiterallyf("let %s: ", c.sanitizeIdentifier(name.Name))
|
|
266
|
+
c.WriteTypeExpr(field.Type)
|
|
267
|
+
c.tsw.WriteLiterally(" = ")
|
|
268
|
+
c.WriteZeroValueForType(c.pkg.TypesInfo.TypeOf(field.Type))
|
|
269
|
+
c.tsw.WriteLine("")
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
return nil
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// hasNamedReturns checks if a function type has any named return parameters.
|
|
276
|
+
func (c *GoToTSCompiler) hasNamedReturns(results *ast.FieldList) bool {
|
|
277
|
+
if results == nil {
|
|
278
|
+
return false
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
for _, field := range results.List {
|
|
282
|
+
if len(field.Names) > 0 {
|
|
283
|
+
return true
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
return false
|
|
287
|
+
}
|
package/compiler/expr-call.go
CHANGED
|
@@ -97,6 +97,37 @@ func (c *GoToTSCompiler) WriteCallExpr(exp *ast.CallExpr) error {
|
|
|
97
97
|
}
|
|
98
98
|
}
|
|
99
99
|
}
|
|
100
|
+
|
|
101
|
+
// Handle general slice type conversions like []T(namedType) where namedType has underlying type []T
|
|
102
|
+
if arrayType.Len == nil && len(exp.Args) == 1 {
|
|
103
|
+
arg := exp.Args[0]
|
|
104
|
+
if argType := c.pkg.TypesInfo.TypeOf(arg); argType != nil {
|
|
105
|
+
// Check if the argument is a named type with a slice underlying type
|
|
106
|
+
if namedArgType, isNamed := argType.(*types.Named); isNamed {
|
|
107
|
+
// Check if the named type has receiver methods (is a wrapper class)
|
|
108
|
+
typeName := namedArgType.Obj().Name()
|
|
109
|
+
if c.hasReceiverMethods(typeName) {
|
|
110
|
+
// Check if the underlying type matches the target slice type
|
|
111
|
+
if sliceUnderlying, isSlice := namedArgType.Underlying().(*types.Slice); isSlice {
|
|
112
|
+
// Get the target slice type
|
|
113
|
+
targetType := c.pkg.TypesInfo.TypeOf(arrayType)
|
|
114
|
+
if targetSliceType, isTargetSlice := targetType.Underlying().(*types.Slice); isTargetSlice {
|
|
115
|
+
// Check if element types are compatible
|
|
116
|
+
if types.Identical(sliceUnderlying.Elem(), targetSliceType.Elem()) {
|
|
117
|
+
// This is a conversion from NamedType to []T where NamedType has underlying []T
|
|
118
|
+
// Use valueOf() to get the underlying slice
|
|
119
|
+
if err := c.WriteValueExpr(arg); err != nil {
|
|
120
|
+
return fmt.Errorf("failed to write argument for slice type conversion: %w", err)
|
|
121
|
+
}
|
|
122
|
+
c.tsw.WriteLiterally(".valueOf()")
|
|
123
|
+
return nil // Handled named type to slice conversion
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
100
131
|
}
|
|
101
132
|
|
|
102
133
|
if funIdent, funIsIdent := expFun.(*ast.Ident); funIsIdent {
|
|
@@ -274,7 +305,12 @@ func (c *GoToTSCompiler) WriteCallExpr(exp *ast.CallExpr) error {
|
|
|
274
305
|
}
|
|
275
306
|
|
|
276
307
|
c.tsw.WriteLiterally("$.makeSlice<")
|
|
277
|
-
|
|
308
|
+
// Use AST-based type writing to preserve qualified names
|
|
309
|
+
if arrType, ok := exp.Args[0].(*ast.ArrayType); ok {
|
|
310
|
+
c.WriteTypeExpr(arrType.Elt)
|
|
311
|
+
} else {
|
|
312
|
+
c.WriteGoType(goElemType, GoTypeContextGeneral)
|
|
313
|
+
}
|
|
278
314
|
c.tsw.WriteLiterally(">(")
|
|
279
315
|
|
|
280
316
|
hasCapacity := len(exp.Args) == 3
|
package/compiler/expr-type.go
CHANGED
|
@@ -45,6 +45,26 @@ func (c *GoToTSCompiler) WriteTypeExpr(a ast.Expr) {
|
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
// Handle array/slice types to preserve qualified names in element types
|
|
49
|
+
if arrayType, ok := a.(*ast.ArrayType); ok {
|
|
50
|
+
if arrayType.Len == nil {
|
|
51
|
+
// Slice type: []T -> $.Slice<T>
|
|
52
|
+
// Check if it's a []byte slice first
|
|
53
|
+
if ident, ok := arrayType.Elt.(*ast.Ident); ok && ident.Name == "byte" {
|
|
54
|
+
c.tsw.WriteLiterally("$.Bytes")
|
|
55
|
+
return
|
|
56
|
+
}
|
|
57
|
+
c.tsw.WriteLiterally("$.Slice<")
|
|
58
|
+
c.WriteTypeExpr(arrayType.Elt) // Recursively handle element type preserving qualified names
|
|
59
|
+
c.tsw.WriteLiterally(">")
|
|
60
|
+
} else {
|
|
61
|
+
// Array type: [N]T -> T[]
|
|
62
|
+
c.WriteTypeExpr(arrayType.Elt) // Recursively handle element type preserving qualified names
|
|
63
|
+
c.tsw.WriteLiterally("[]")
|
|
64
|
+
}
|
|
65
|
+
return
|
|
66
|
+
}
|
|
67
|
+
|
|
48
68
|
// Get type information for the expression and use WriteGoType
|
|
49
69
|
typ := c.pkg.TypesInfo.TypeOf(a)
|
|
50
70
|
c.WriteGoType(typ, GoTypeContextGeneral)
|
package/compiler/lit.go
CHANGED
|
@@ -164,29 +164,13 @@ func (c *GoToTSCompiler) WriteFuncLitValue(exp *ast.FuncLit) error {
|
|
|
164
164
|
|
|
165
165
|
c.tsw.WriteLiterally(" => ")
|
|
166
166
|
|
|
167
|
-
hasNamedReturns
|
|
168
|
-
if exp.Type.Results != nil {
|
|
169
|
-
for _, field := range exp.Type.Results.List {
|
|
170
|
-
if len(field.Names) > 0 {
|
|
171
|
-
hasNamedReturns = true
|
|
172
|
-
break
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
if hasNamedReturns {
|
|
167
|
+
if c.hasNamedReturns(exp.Type.Results) {
|
|
178
168
|
c.tsw.WriteLine("{")
|
|
179
169
|
c.tsw.Indent(1)
|
|
180
170
|
|
|
181
171
|
// Declare named return variables and initialize them to their zero values
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
c.tsw.WriteLiterallyf("let %s: ", c.sanitizeIdentifier(name.Name))
|
|
185
|
-
c.WriteTypeExpr(field.Type)
|
|
186
|
-
c.tsw.WriteLiterally(" = ")
|
|
187
|
-
c.WriteZeroValueForType(c.pkg.TypesInfo.TypeOf(field.Type))
|
|
188
|
-
c.tsw.WriteLine("")
|
|
189
|
-
}
|
|
172
|
+
if err := c.writeNamedReturnDeclarations(exp.Type.Results); err != nil {
|
|
173
|
+
return fmt.Errorf("failed to write named return declarations: %w", err)
|
|
190
174
|
}
|
|
191
175
|
}
|
|
192
176
|
|
|
@@ -195,7 +179,7 @@ func (c *GoToTSCompiler) WriteFuncLitValue(exp *ast.FuncLit) error {
|
|
|
195
179
|
return fmt.Errorf("failed to write block statement: %w", err)
|
|
196
180
|
}
|
|
197
181
|
|
|
198
|
-
if hasNamedReturns {
|
|
182
|
+
if c.hasNamedReturns(exp.Type.Results) {
|
|
199
183
|
c.tsw.Indent(-1)
|
|
200
184
|
c.tsw.WriteLiterally("}")
|
|
201
185
|
}
|
package/compiler/spec-struct.go
CHANGED
|
@@ -20,10 +20,9 @@ import (
|
|
|
20
20
|
// - Wrapper methods for promoted fields and methods from embedded structs,
|
|
21
21
|
// ensuring correct access and behavior.
|
|
22
22
|
func (c *GoToTSCompiler) WriteStructTypeSpec(a *ast.TypeSpec, t *ast.StructType) error {
|
|
23
|
-
//
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
23
|
+
// Always export types for cross-file imports within the same package
|
|
24
|
+
// This allows unexported Go types to be imported by other files in the same package
|
|
25
|
+
c.tsw.WriteLiterally("export ")
|
|
27
26
|
c.tsw.WriteLiterally("class ")
|
|
28
27
|
if err := c.WriteValueExpr(a.Name); err != nil {
|
|
29
28
|
return err
|
package/compiler/spec-value.go
CHANGED
|
@@ -153,7 +153,14 @@ func (c *GoToTSCompiler) WriteValueSpec(a *ast.ValueSpec) error {
|
|
|
153
153
|
}
|
|
154
154
|
} else {
|
|
155
155
|
// Not a pointer type, write as is.
|
|
156
|
-
|
|
156
|
+
// Use AST-based type writing if explicit type is provided, otherwise use WriteGoType
|
|
157
|
+
if a.Type != nil {
|
|
158
|
+
// Explicit type annotation in Go code - use AST to preserve qualified names
|
|
159
|
+
c.WriteTypeExpr(a.Type)
|
|
160
|
+
} else {
|
|
161
|
+
// No explicit type - use type inference from WriteGoType
|
|
162
|
+
c.WriteGoType(goType, GoTypeContextGeneral)
|
|
163
|
+
}
|
|
157
164
|
}
|
|
158
165
|
}
|
|
159
166
|
}
|
|
@@ -249,6 +256,16 @@ func (c *GoToTSCompiler) WriteValueSpec(a *ast.ValueSpec) error {
|
|
|
249
256
|
}
|
|
250
257
|
}
|
|
251
258
|
}
|
|
259
|
+
case *ast.CallExpr:
|
|
260
|
+
// Check if this is a make() call that returns the underlying type
|
|
261
|
+
if funIdent, ok := expr.Fun.(*ast.Ident); ok && funIdent.Name == "make" {
|
|
262
|
+
// Check if the make call returns a type that matches the underlying type
|
|
263
|
+
if exprType := c.pkg.TypesInfo.TypeOf(expr); exprType != nil {
|
|
264
|
+
if types.Identical(exprType, namedType.Underlying()) {
|
|
265
|
+
needsConstructor = true
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
252
269
|
}
|
|
253
270
|
|
|
254
271
|
if needsConstructor {
|
package/compiler/spec.go
CHANGED
|
@@ -188,7 +188,6 @@ func (c *GoToTSCompiler) hasReceiverMethods(typeName string) bool {
|
|
|
188
188
|
// WriteNamedTypeWithMethods generates a TypeScript class for a Go named type that has receiver methods
|
|
189
189
|
func (c *GoToTSCompiler) WriteNamedTypeWithMethods(a *ast.TypeSpec) error {
|
|
190
190
|
className := a.Name.Name
|
|
191
|
-
underlyingType := c.pkg.TypesInfo.TypeOf(a.Type)
|
|
192
191
|
|
|
193
192
|
// Add export for Go-exported types (but not if inside a function)
|
|
194
193
|
isInsideFunction := false
|
|
@@ -196,7 +195,7 @@ func (c *GoToTSCompiler) WriteNamedTypeWithMethods(a *ast.TypeSpec) error {
|
|
|
196
195
|
isInsideFunction = nodeInfo.IsInsideFunction
|
|
197
196
|
}
|
|
198
197
|
|
|
199
|
-
if
|
|
198
|
+
if !isInsideFunction {
|
|
200
199
|
c.tsw.WriteLiterally("export ")
|
|
201
200
|
}
|
|
202
201
|
|
|
@@ -206,13 +205,15 @@ func (c *GoToTSCompiler) WriteNamedTypeWithMethods(a *ast.TypeSpec) error {
|
|
|
206
205
|
|
|
207
206
|
// Constructor that takes the underlying type value
|
|
208
207
|
c.tsw.WriteLiterally("constructor(private _value: ")
|
|
209
|
-
|
|
208
|
+
// Use AST-based type writing to preserve qualified names like os.FileInfo
|
|
209
|
+
c.WriteTypeExpr(a.Type)
|
|
210
210
|
c.tsw.WriteLine(") {}")
|
|
211
211
|
c.tsw.WriteLine("")
|
|
212
212
|
|
|
213
213
|
// valueOf method to get the underlying value (for type conversions and operations)
|
|
214
214
|
c.tsw.WriteLiterally("valueOf(): ")
|
|
215
|
-
|
|
215
|
+
// Use AST-based type writing to preserve qualified names like os.FileInfo
|
|
216
|
+
c.WriteTypeExpr(a.Type)
|
|
216
217
|
c.tsw.WriteLine(" {")
|
|
217
218
|
c.tsw.Indent(1)
|
|
218
219
|
c.tsw.WriteLine("return this._value")
|
|
@@ -230,7 +231,8 @@ func (c *GoToTSCompiler) WriteNamedTypeWithMethods(a *ast.TypeSpec) error {
|
|
|
230
231
|
|
|
231
232
|
// Static from method for type conversion
|
|
232
233
|
c.tsw.WriteLiterallyf("static from(value: ")
|
|
233
|
-
|
|
234
|
+
// Use AST-based type writing to preserve qualified names like os.FileInfo
|
|
235
|
+
c.WriteTypeExpr(a.Type)
|
|
234
236
|
c.tsw.WriteLiterallyf("): %s {", className)
|
|
235
237
|
c.tsw.WriteLine("")
|
|
236
238
|
c.tsw.Indent(1)
|
|
@@ -364,6 +366,11 @@ func (c *GoToTSCompiler) writeNamedTypeMethod(decl *ast.FuncDecl) error {
|
|
|
364
366
|
}
|
|
365
367
|
}
|
|
366
368
|
|
|
369
|
+
// Declare named return variables and initialize them to their zero values
|
|
370
|
+
if err := c.writeNamedReturnDeclarations(decl.Type.Results); err != nil {
|
|
371
|
+
return fmt.Errorf("failed to write named return declarations: %w", err)
|
|
372
|
+
}
|
|
373
|
+
|
|
367
374
|
// write method body without outer braces
|
|
368
375
|
for _, stmt := range decl.Body.List {
|
|
369
376
|
if err := c.WriteStmt(stmt); err != nil {
|
|
@@ -404,13 +411,13 @@ func (c *GoToTSCompiler) WriteTypeSpec(a *ast.TypeSpec) error {
|
|
|
404
411
|
return c.WriteNamedTypeWithMethods(a)
|
|
405
412
|
}
|
|
406
413
|
|
|
407
|
-
//
|
|
414
|
+
// Always export types for cross-file imports within the same package (but not if inside a function)
|
|
408
415
|
isInsideFunction := false
|
|
409
416
|
if nodeInfo := c.analysis.NodeData[a]; nodeInfo != nil {
|
|
410
417
|
isInsideFunction = nodeInfo.IsInsideFunction
|
|
411
418
|
}
|
|
412
419
|
|
|
413
|
-
if
|
|
420
|
+
if !isInsideFunction {
|
|
414
421
|
c.tsw.WriteLiterally("export ")
|
|
415
422
|
}
|
|
416
423
|
c.tsw.WriteLiterally("type ")
|
|
@@ -438,7 +445,7 @@ func (c *GoToTSCompiler) WriteInterfaceTypeSpec(a *ast.TypeSpec, t *ast.Interfac
|
|
|
438
445
|
isInsideFunction = nodeInfo.IsInsideFunction
|
|
439
446
|
}
|
|
440
447
|
|
|
441
|
-
if
|
|
448
|
+
if !isInsideFunction {
|
|
442
449
|
c.tsw.WriteLiterally("export ")
|
|
443
450
|
}
|
|
444
451
|
c.tsw.WriteLiterally("type ")
|
package/compiler/stmt-range.go
CHANGED
|
@@ -157,7 +157,7 @@ func (c *GoToTSCompiler) writeMapRange(exp *ast.RangeStmt) error {
|
|
|
157
157
|
if err := c.WriteValueExpr(exp.X); err != nil {
|
|
158
158
|
return fmt.Errorf("failed to write range loop map expression: %w", err)
|
|
159
159
|
}
|
|
160
|
-
c.tsw.WriteLiterally("
|
|
160
|
+
c.tsw.WriteLiterally("?.entries() ?? []) {")
|
|
161
161
|
c.tsw.Indent(1)
|
|
162
162
|
c.tsw.WriteLine("")
|
|
163
163
|
|
package/compiler/type-assert.go
CHANGED
|
@@ -96,8 +96,8 @@ func (c *GoToTSCompiler) writeTypeAssert(lhs []ast.Expr, typeAssertExpr *ast.Typ
|
|
|
96
96
|
// For selector expressions as ok, we need to use temporary variables approach
|
|
97
97
|
if okIsSelectorExpr {
|
|
98
98
|
// Use temporary variables approach similar to SelectorExpr case
|
|
99
|
-
tempValName := "_gs_ta_val_" //
|
|
100
|
-
tempOkName := "_gs_ta_ok_" //
|
|
99
|
+
tempValName := fmt.Sprintf("_gs_ta_val_%d_", typeAssertExpr.Pos()) // Unique name based on AST position
|
|
100
|
+
tempOkName := fmt.Sprintf("_gs_ta_ok_%d_", typeAssertExpr.Pos()) // Unique name based on AST position
|
|
101
101
|
|
|
102
102
|
// Declare temporary variables:
|
|
103
103
|
// let _gs_ta_val_: AssertedTypeTS;
|
|
@@ -217,8 +217,8 @@ func (c *GoToTSCompiler) writeTypeAssert(lhs []ast.Expr, typeAssertExpr *ast.Typ
|
|
|
217
217
|
|
|
218
218
|
case *ast.SelectorExpr:
|
|
219
219
|
// Handle s.field, ok := expr.(Type)
|
|
220
|
-
tempValName := "_gs_ta_val_" //
|
|
221
|
-
tempOkName := "_gs_ta_ok_" //
|
|
220
|
+
tempValName := fmt.Sprintf("_gs_ta_val_%d_", typeAssertExpr.Pos()) // Unique name based on AST position
|
|
221
|
+
tempOkName := fmt.Sprintf("_gs_ta_ok_%d_", typeAssertExpr.Pos()) // Unique name based on AST position
|
|
222
222
|
|
|
223
223
|
// Declare temporary variables:
|
|
224
224
|
// let _gs_ta_val_: AssertedTypeTS;
|