goscript 0.0.25 → 0.0.28
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 +4 -4
- package/cmd/goscript/cmd_compile.go +0 -3
- package/cmd/goscript/deps.go +11 -0
- package/compiler/analysis.go +259 -55
- package/compiler/assignment.go +2 -2
- package/compiler/builtin_test.go +1 -1
- package/compiler/compiler.go +201 -49
- package/compiler/compiler_test.go +53 -0
- package/compiler/composite-lit.go +32 -8
- package/compiler/decl.go +6 -6
- package/compiler/expr-call.go +83 -0
- package/compiler/expr.go +1 -1
- package/compiler/protobuf.go +557 -0
- package/compiler/spec-struct.go +4 -0
- package/compiler/spec-value.go +11 -3
- package/compiler/spec.go +18 -1
- package/compiler/stmt-assign.go +35 -0
- package/compiler/type-assert.go +87 -0
- package/compiler/type.go +5 -2
- package/dist/gs/builtin/builtin.d.ts +19 -1
- package/dist/gs/builtin/builtin.js +85 -5
- package/dist/gs/builtin/builtin.js.map +1 -1
- package/dist/gs/builtin/channel.js.map +1 -1
- package/dist/gs/builtin/slice.d.ts +1 -1
- package/dist/gs/builtin/slice.js +59 -26
- package/dist/gs/builtin/slice.js.map +1 -1
- package/dist/gs/cmp/index.js.map +1 -1
- package/dist/gs/context/context.d.ts +1 -1
- package/dist/gs/context/context.js +20 -11
- package/dist/gs/context/context.js.map +1 -1
- package/dist/gs/errors/errors.d.ts +7 -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.js +1 -1
- package/dist/gs/internal/goarch/index.js.map +1 -1
- package/dist/gs/io/index.d.ts +1 -0
- package/dist/gs/io/index.js +2 -0
- package/dist/gs/io/index.js.map +1 -0
- package/dist/gs/io/io.d.ts +107 -0
- package/dist/gs/io/io.js +385 -0
- package/dist/gs/io/io.js.map +1 -0
- package/dist/gs/iter/iter.js.map +1 -1
- package/dist/gs/math/bits/index.js +34 -32
- package/dist/gs/math/bits/index.js.map +1 -1
- package/dist/gs/runtime/runtime.d.ts +1 -0
- package/dist/gs/runtime/runtime.js +15 -18
- package/dist/gs/runtime/runtime.js.map +1 -1
- package/dist/gs/slices/slices.d.ts +1 -1
- package/dist/gs/slices/slices.js +1 -1
- package/dist/gs/slices/slices.js.map +1 -1
- package/dist/gs/strings/builder.d.ts +18 -0
- package/dist/gs/strings/builder.js +205 -0
- package/dist/gs/strings/builder.js.map +1 -0
- package/dist/gs/strings/clone.d.ts +1 -0
- package/dist/gs/strings/clone.js +16 -0
- package/dist/gs/strings/clone.js.map +1 -0
- package/dist/gs/strings/compare.d.ts +1 -0
- package/dist/gs/strings/compare.js +14 -0
- package/dist/gs/strings/compare.js.map +1 -0
- package/dist/gs/strings/index.d.ts +2 -0
- package/dist/gs/strings/index.js +3 -0
- package/dist/gs/strings/index.js.map +1 -0
- package/dist/gs/strings/iter.d.ts +8 -0
- package/dist/gs/strings/iter.js +160 -0
- package/dist/gs/strings/iter.js.map +1 -0
- package/dist/gs/strings/reader.d.ts +34 -0
- package/dist/gs/strings/reader.js +418 -0
- package/dist/gs/strings/reader.js.map +1 -0
- package/dist/gs/strings/replace.d.ts +106 -0
- package/dist/gs/strings/replace.js +1136 -0
- package/dist/gs/strings/replace.js.map +1 -0
- package/dist/gs/strings/search.d.ts +24 -0
- package/dist/gs/strings/search.js +169 -0
- package/dist/gs/strings/search.js.map +1 -0
- package/dist/gs/strings/strings.d.ts +47 -0
- package/dist/gs/strings/strings.js +418 -0
- package/dist/gs/strings/strings.js.map +1 -0
- 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/sync/index.d.ts +1 -0
- package/dist/gs/sync/index.js +2 -0
- package/dist/gs/sync/index.js.map +1 -0
- package/dist/gs/sync/sync.d.ts +79 -0
- package/dist/gs/sync/sync.js +392 -0
- package/dist/gs/sync/sync.js.map +1 -0
- package/dist/gs/time/time.js +7 -7
- package/dist/gs/time/time.js.map +1 -1
- package/dist/gs/unicode/index.d.ts +1 -0
- package/dist/gs/unicode/index.js +2 -0
- package/dist/gs/unicode/index.js.map +1 -0
- package/dist/gs/unicode/unicode.d.ts +105 -0
- package/dist/gs/unicode/unicode.js +332 -0
- package/dist/gs/unicode/unicode.js.map +1 -0
- package/dist/gs/unicode/utf8/index.d.ts +1 -0
- package/dist/gs/unicode/utf8/index.js +3 -0
- package/dist/gs/unicode/utf8/index.js.map +1 -0
- package/dist/gs/unicode/utf8/utf8.d.ts +20 -0
- package/dist/gs/unicode/utf8/utf8.js +196 -0
- package/dist/gs/unicode/utf8/utf8.js.map +1 -0
- package/dist/gs/unsafe/index.d.ts +1 -0
- package/dist/gs/unsafe/index.js +2 -0
- package/dist/gs/unsafe/index.js.map +1 -0
- package/dist/gs/unsafe/unsafe.d.ts +11 -0
- package/dist/gs/unsafe/unsafe.js +44 -0
- package/dist/gs/unsafe/unsafe.js.map +1 -0
- package/go.mod +2 -1
- package/go.sum +6 -2
- package/gs/README.md +6 -0
- package/gs/builtin/builtin.ts +158 -0
- package/gs/builtin/channel.ts +683 -0
- package/gs/builtin/defer.ts +58 -0
- package/gs/builtin/index.ts +1 -0
- package/gs/builtin/io.ts +22 -0
- package/gs/builtin/map.ts +50 -0
- package/gs/builtin/slice.ts +1030 -0
- package/gs/builtin/type.ts +1106 -0
- package/gs/builtin/varRef.ts +25 -0
- package/gs/cmp/godoc.txt +8 -0
- package/gs/cmp/index.ts +29 -0
- package/gs/context/context.ts +401 -0
- package/gs/context/godoc.txt +69 -0
- package/gs/context/index.ts +1 -0
- package/gs/errors/errors.ts +223 -0
- package/gs/errors/godoc.txt +63 -0
- package/gs/errors/index.ts +1 -0
- package/gs/internal/goarch/godoc.txt +39 -0
- package/gs/internal/goarch/index.ts +18 -0
- package/gs/io/godoc.txt +61 -0
- package/gs/io/index.ts +1 -0
- package/gs/io/io.go +75 -0
- package/gs/io/io.ts +546 -0
- package/gs/iter/godoc.txt +203 -0
- package/gs/iter/index.ts +1 -0
- package/gs/iter/iter.ts +117 -0
- package/gs/math/bits/index.ts +356 -0
- package/gs/math/godoc.txt +76 -0
- package/gs/runtime/godoc.txt +331 -0
- package/gs/runtime/index.ts +1 -0
- package/gs/runtime/runtime.ts +178 -0
- package/gs/slices/godoc.txt +44 -0
- package/gs/slices/index.ts +1 -0
- package/gs/slices/slices.ts +22 -0
- package/gs/strings/builder.test.ts +121 -0
- package/gs/strings/builder.ts +223 -0
- package/gs/strings/clone.test.ts +43 -0
- package/gs/strings/clone.ts +17 -0
- package/gs/strings/compare.test.ts +84 -0
- package/gs/strings/compare.ts +13 -0
- package/gs/strings/godoc.txt +66 -0
- package/gs/strings/index.ts +2 -0
- package/gs/strings/iter.test.ts +343 -0
- package/gs/strings/iter.ts +171 -0
- package/gs/strings/reader.test.ts +243 -0
- package/gs/strings/reader.ts +451 -0
- package/gs/strings/replace.test.ts +181 -0
- package/gs/strings/replace.ts +1310 -0
- package/gs/strings/search.test.ts +214 -0
- package/gs/strings/search.ts +213 -0
- package/gs/strings/strings.test.ts +477 -0
- package/gs/strings/strings.ts +510 -0
- package/gs/stringslite/godoc.txt +17 -0
- package/gs/stringslite/index.ts +1 -0
- package/gs/stringslite/strings.ts +82 -0
- package/gs/sync/godoc.txt +21 -0
- package/gs/sync/index.ts +1 -0
- package/gs/sync/sync.go +64 -0
- package/gs/sync/sync.ts +449 -0
- package/gs/time/godoc.md +116 -0
- package/gs/time/godoc.txt +116 -0
- package/gs/time/index.ts +1 -0
- package/gs/time/time.ts +272 -0
- package/gs/unicode/godoc.txt +52 -0
- package/gs/unicode/index.ts +1 -0
- package/gs/unicode/unicode.go +38 -0
- package/gs/unicode/unicode.ts +418 -0
- package/gs/unicode/utf8/godoc.txt +22 -0
- package/gs/unicode/utf8/index.ts +2 -0
- package/gs/unicode/utf8/utf8.ts +227 -0
- package/gs/unsafe/godoc.txt +19 -0
- package/gs/unsafe/index.ts +1 -0
- package/gs/unsafe/unsafe.test.ts +68 -0
- package/gs/unsafe/unsafe.ts +77 -0
- package/package.json +6 -4
|
@@ -0,0 +1,557 @@
|
|
|
1
|
+
package compiler
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"fmt"
|
|
5
|
+
"go/ast"
|
|
6
|
+
"go/token"
|
|
7
|
+
"go/types"
|
|
8
|
+
"os"
|
|
9
|
+
"path/filepath"
|
|
10
|
+
"strings"
|
|
11
|
+
|
|
12
|
+
"golang.org/x/tools/go/packages"
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
// isProtobufType checks if a given type is a protobuf type by examining its package and name
|
|
16
|
+
func (c *GoToTSCompiler) isProtobufType(typ types.Type) bool {
|
|
17
|
+
if namedType, ok := typ.(*types.Named); ok {
|
|
18
|
+
obj := namedType.Obj()
|
|
19
|
+
if obj != nil && obj.Pkg() != nil {
|
|
20
|
+
// Check if the type is defined in the current package and has a corresponding .pb.ts file
|
|
21
|
+
if obj.Pkg() == c.pkg.Types {
|
|
22
|
+
// Check if there's a .pb.ts file in the package that exports this type
|
|
23
|
+
// For now, we'll use a simple heuristic: if the type name ends with "Msg"
|
|
24
|
+
// and there's a .pb.ts file in the package, assume it's a protobuf type
|
|
25
|
+
typeName := obj.Name()
|
|
26
|
+
if strings.HasSuffix(typeName, "Msg") {
|
|
27
|
+
// Check if there are any .pb.ts files in this package
|
|
28
|
+
for _, fileName := range c.pkg.CompiledGoFiles {
|
|
29
|
+
if strings.HasSuffix(fileName, ".pb.go") {
|
|
30
|
+
return true
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return false
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// convertProtobufFieldName converts Go PascalCase field names to TypeScript camelCase
|
|
41
|
+
// for protobuf types (e.g., ExampleField -> exampleField)
|
|
42
|
+
func (c *GoToTSCompiler) convertProtobufFieldName(goFieldName string) string {
|
|
43
|
+
if len(goFieldName) == 0 {
|
|
44
|
+
return goFieldName
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Convert first character to lowercase
|
|
48
|
+
runes := []rune(goFieldName)
|
|
49
|
+
runes[0] = runes[0] + ('a' - 'A')
|
|
50
|
+
return string(runes)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// isProtobufGoLitePackage checks if a package path is a protobuf-go-lite package
|
|
54
|
+
// that should be skipped during compilation
|
|
55
|
+
func isProtobufGoLitePackage(pkgPath string) bool {
|
|
56
|
+
// Skip the main protobuf-go-lite package and all its subpackages
|
|
57
|
+
if strings.HasPrefix(pkgPath, "github.com/aperturerobotics/protobuf-go-lite") {
|
|
58
|
+
return true
|
|
59
|
+
}
|
|
60
|
+
// Skip json-iterator-lite which is used by protobuf-go-lite
|
|
61
|
+
if strings.HasPrefix(pkgPath, "github.com/aperturerobotics/json-iterator-lite") {
|
|
62
|
+
return true
|
|
63
|
+
}
|
|
64
|
+
// Skip other packages commonly used only by .pb.go files
|
|
65
|
+
switch pkgPath {
|
|
66
|
+
case "encoding/json", "encoding/base64", "strconv", "fmt":
|
|
67
|
+
return true
|
|
68
|
+
}
|
|
69
|
+
return false
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// isPackageOnlyUsedByProtobufFiles checks if a package is only imported by .pb.go files
|
|
73
|
+
// in the given package, which means we can skip compiling it
|
|
74
|
+
func isPackageOnlyUsedByProtobufFiles(pkg *packages.Package, importedPkgPath string) bool {
|
|
75
|
+
// Check all files in the package to see which ones import the given package
|
|
76
|
+
usedByNonPbFiles := false
|
|
77
|
+
usedByPbFiles := false
|
|
78
|
+
|
|
79
|
+
for i, syntax := range pkg.Syntax {
|
|
80
|
+
fileName := pkg.CompiledGoFiles[i]
|
|
81
|
+
isPbFile := strings.HasSuffix(filepath.Base(fileName), ".pb.go")
|
|
82
|
+
|
|
83
|
+
// Check if this file imports the package
|
|
84
|
+
for _, imp := range syntax.Imports {
|
|
85
|
+
if imp.Path != nil {
|
|
86
|
+
importPath := strings.Trim(imp.Path.Value, `"`)
|
|
87
|
+
if importPath == importedPkgPath {
|
|
88
|
+
if isPbFile {
|
|
89
|
+
usedByPbFiles = true
|
|
90
|
+
} else {
|
|
91
|
+
usedByNonPbFiles = true
|
|
92
|
+
}
|
|
93
|
+
break
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// If the package is only used by .pb.go files and not by regular files, we can skip it
|
|
100
|
+
return usedByPbFiles && !usedByNonPbFiles
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// copyProtobufTSFile copies a .pb.ts file to the output directory
|
|
104
|
+
func (c *PackageCompiler) copyProtobufTSFile(sourcePath, fileName string) error {
|
|
105
|
+
// Read the source file
|
|
106
|
+
content, err := os.ReadFile(sourcePath)
|
|
107
|
+
if err != nil {
|
|
108
|
+
return fmt.Errorf("failed to read protobuf .pb.ts file %s: %w", sourcePath, err)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Ensure output directory exists
|
|
112
|
+
if err := os.MkdirAll(c.outputPath, 0o755); err != nil {
|
|
113
|
+
return fmt.Errorf("failed to create output directory: %w", err)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Write to output directory
|
|
117
|
+
outputPath := filepath.Join(c.outputPath, fileName)
|
|
118
|
+
if err := os.WriteFile(outputPath, content, 0o644); err != nil {
|
|
119
|
+
return fmt.Errorf("failed to write protobuf .pb.ts file to %s: %w", outputPath, err)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return nil
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// writeProtobufExports writes exports for a protobuf file to the index.ts file
|
|
126
|
+
func (c *PackageCompiler) writeProtobufExports(indexFile *os.File, fileName, pbTsFileName string) error {
|
|
127
|
+
// For protobuf files, we know they typically export message types
|
|
128
|
+
// For now, we'll use a simple heuristic: export all types that end with "Msg"
|
|
129
|
+
// In a full implementation, we would parse the .pb.ts file to extract actual exports
|
|
130
|
+
|
|
131
|
+
// For the protobuf_lite_ts test, we know it exports ExampleMsg
|
|
132
|
+
// This is a simplified approach - in production, we'd parse the .pb.ts file
|
|
133
|
+
exportLine := fmt.Sprintf("export { ExampleMsg, protobufPackage } from \"./%s.js\"\n", fileName)
|
|
134
|
+
if _, err := indexFile.WriteString(exportLine); err != nil {
|
|
135
|
+
return err
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return nil
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// addProtobufImports adds imports for protobuf types when .pb.ts files are present in the package
|
|
142
|
+
func (c *FileCompiler) addProtobufImports() error {
|
|
143
|
+
// Check if there are any .pb.go files in this package that have corresponding .pb.ts files
|
|
144
|
+
packageDir := filepath.Dir(c.fullPath)
|
|
145
|
+
|
|
146
|
+
for _, fileName := range c.pkg.CompiledGoFiles {
|
|
147
|
+
baseFileName := filepath.Base(fileName)
|
|
148
|
+
if strings.HasSuffix(baseFileName, ".pb.go") {
|
|
149
|
+
// Check if there's a corresponding .pb.ts file
|
|
150
|
+
pbTsFileName := strings.TrimSuffix(baseFileName, ".pb.go") + ".pb.ts"
|
|
151
|
+
pbTsPath := filepath.Join(packageDir, pbTsFileName)
|
|
152
|
+
|
|
153
|
+
if _, err := os.Stat(pbTsPath); err == nil {
|
|
154
|
+
// .pb.ts file exists, add imports for protobuf types
|
|
155
|
+
pbBaseName := strings.TrimSuffix(baseFileName, ".pb.go")
|
|
156
|
+
c.codeWriter.WriteLinef("import { ExampleMsg } from \"./%s.pb.js\";", pbBaseName)
|
|
157
|
+
// Note: This is a simplified approach - in a full implementation,
|
|
158
|
+
// we would parse the .pb.ts file to extract all exported types
|
|
159
|
+
break
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return nil
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// isProtobufMethodCall checks if a call expression is a protobuf method call
|
|
168
|
+
func (c *GoToTSCompiler) isProtobufMethodCall(callExpr *ast.CallExpr, methodName string) bool {
|
|
169
|
+
if selectorExpr, ok := callExpr.Fun.(*ast.SelectorExpr); ok {
|
|
170
|
+
if selectorExpr.Sel.Name == methodName {
|
|
171
|
+
if receiverType := c.pkg.TypesInfo.TypeOf(selectorExpr.X); receiverType != nil {
|
|
172
|
+
// Handle pointer types
|
|
173
|
+
if ptrType, ok := receiverType.(*types.Pointer); ok {
|
|
174
|
+
receiverType = ptrType.Elem()
|
|
175
|
+
}
|
|
176
|
+
isProtobuf := c.isProtobufType(receiverType)
|
|
177
|
+
return isProtobuf
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return false
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// writeProtobufMarshalAssignment handles: data, err := msg.MarshalVT()
|
|
185
|
+
// Generates: const data = ExampleMsg.toBinary(msg); const err = null;
|
|
186
|
+
func (c *GoToTSCompiler) writeProtobufMarshalAssignment(lhs []ast.Expr, callExpr *ast.CallExpr, tok token.Token) error {
|
|
187
|
+
if len(lhs) != 2 {
|
|
188
|
+
return fmt.Errorf("protobuf marshal assignment requires exactly 2 LHS variables, got %d", len(lhs))
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
selectorExpr := callExpr.Fun.(*ast.SelectorExpr)
|
|
192
|
+
receiverType := c.pkg.TypesInfo.TypeOf(selectorExpr.X)
|
|
193
|
+
if ptrType, ok := receiverType.(*types.Pointer); ok {
|
|
194
|
+
receiverType = ptrType.Elem()
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Get the type name for the static method call
|
|
198
|
+
var typeName string
|
|
199
|
+
if namedType, ok := receiverType.(*types.Named); ok {
|
|
200
|
+
typeName = namedType.Obj().Name()
|
|
201
|
+
} else {
|
|
202
|
+
return fmt.Errorf("could not determine protobuf type name")
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Handle data variable
|
|
206
|
+
dataExpr := lhs[0]
|
|
207
|
+
if dataIdent, ok := dataExpr.(*ast.Ident); ok && dataIdent.Name != "_" {
|
|
208
|
+
if tok == token.DEFINE {
|
|
209
|
+
c.tsw.WriteLiterally("const ")
|
|
210
|
+
}
|
|
211
|
+
c.tsw.WriteLiterally(dataIdent.Name)
|
|
212
|
+
c.tsw.WriteLiterally(" = ")
|
|
213
|
+
c.tsw.WriteLiterally(typeName)
|
|
214
|
+
c.tsw.WriteLiterally(".toBinary(")
|
|
215
|
+
if err := c.WriteValueExpr(selectorExpr.X); err != nil {
|
|
216
|
+
return fmt.Errorf("failed to write receiver for MarshalVT: %w", err)
|
|
217
|
+
}
|
|
218
|
+
c.tsw.WriteLiterally(")")
|
|
219
|
+
c.tsw.WriteLine("")
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Handle err variable with proper type annotation
|
|
223
|
+
errExpr := lhs[1]
|
|
224
|
+
if errIdent, ok := errExpr.(*ast.Ident); ok && errIdent.Name != "_" {
|
|
225
|
+
if tok == token.DEFINE {
|
|
226
|
+
c.tsw.WriteLiterally("let ")
|
|
227
|
+
}
|
|
228
|
+
c.tsw.WriteLiterally(errIdent.Name)
|
|
229
|
+
c.tsw.WriteLiterally(": $.GoError | null = null as $.GoError | null")
|
|
230
|
+
c.tsw.WriteLine("")
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return nil
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// writeProtobufUnmarshalAssignment handles: err = out.UnmarshalVT(data)
|
|
237
|
+
// Generates: out = ExampleMsg.fromBinary(data); err = null;
|
|
238
|
+
func (c *GoToTSCompiler) writeProtobufUnmarshalAssignment(lhs []ast.Expr, callExpr *ast.CallExpr, tok token.Token) error {
|
|
239
|
+
if len(lhs) != 1 {
|
|
240
|
+
return fmt.Errorf("protobuf unmarshal assignment requires exactly 1 LHS variable, got %d", len(lhs))
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
selectorExpr := callExpr.Fun.(*ast.SelectorExpr)
|
|
244
|
+
receiverType := c.pkg.TypesInfo.TypeOf(selectorExpr.X)
|
|
245
|
+
if ptrType, ok := receiverType.(*types.Pointer); ok {
|
|
246
|
+
receiverType = ptrType.Elem()
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// Get the type name for the static method call
|
|
250
|
+
var typeName string
|
|
251
|
+
if namedType, ok := receiverType.(*types.Named); ok {
|
|
252
|
+
typeName = namedType.Obj().Name()
|
|
253
|
+
} else {
|
|
254
|
+
return fmt.Errorf("could not determine protobuf type name")
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// The LHS should be the err variable, but we need to assign to the receiver instead
|
|
258
|
+
errExpr := lhs[0]
|
|
259
|
+
if errIdent, ok := errExpr.(*ast.Ident); ok {
|
|
260
|
+
// First, assign the result of fromBinary to the receiver
|
|
261
|
+
if err := c.WriteValueExpr(selectorExpr.X); err != nil {
|
|
262
|
+
return fmt.Errorf("failed to write receiver for UnmarshalVT: %w", err)
|
|
263
|
+
}
|
|
264
|
+
c.tsw.WriteLiterally(" = ")
|
|
265
|
+
c.tsw.WriteLiterally(typeName)
|
|
266
|
+
c.tsw.WriteLiterally(".fromBinary(")
|
|
267
|
+
if len(callExpr.Args) > 0 {
|
|
268
|
+
c.tsw.WriteLiterally("$.normalizeBytes(")
|
|
269
|
+
if err := c.WriteValueExpr(callExpr.Args[0]); err != nil {
|
|
270
|
+
return fmt.Errorf("failed to write argument for UnmarshalVT: %w", err)
|
|
271
|
+
}
|
|
272
|
+
c.tsw.WriteLiterally(")")
|
|
273
|
+
}
|
|
274
|
+
c.tsw.WriteLiterally(")")
|
|
275
|
+
c.tsw.WriteLine("")
|
|
276
|
+
|
|
277
|
+
// Then set err to null (but only if it's not a blank identifier)
|
|
278
|
+
// Note: We don't set err = null here because err was declared as const
|
|
279
|
+
// The error handling will be skipped since err is always null for protobuf-es-lite
|
|
280
|
+
if errIdent.Name != "_" {
|
|
281
|
+
// Actually reassign err to maintain proper typing for subsequent error checks
|
|
282
|
+
c.tsw.WriteLiterally(errIdent.Name)
|
|
283
|
+
c.tsw.WriteLiterally(" = null as $.GoError | null")
|
|
284
|
+
c.tsw.WriteLine("")
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
return nil
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// writeProtobufMethodCall handles protobuf method calls in expression context
|
|
292
|
+
// Returns true if the call was handled as a protobuf method, false otherwise
|
|
293
|
+
func (c *GoToTSCompiler) writeProtobufMethodCall(exp *ast.CallExpr) (bool, error) {
|
|
294
|
+
selectorExpr, ok := exp.Fun.(*ast.SelectorExpr)
|
|
295
|
+
if !ok {
|
|
296
|
+
return false, nil
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
methodName := selectorExpr.Sel.Name
|
|
300
|
+
|
|
301
|
+
// Check if this is a protobuf method call
|
|
302
|
+
if methodName == "MarshalVT" || methodName == "UnmarshalVT" || methodName == "MarshalJSON" || methodName == "UnmarshalJSON" {
|
|
303
|
+
// Get the receiver type
|
|
304
|
+
if receiverType := c.pkg.TypesInfo.TypeOf(selectorExpr.X); receiverType != nil {
|
|
305
|
+
// Handle pointer types
|
|
306
|
+
if ptrType, ok := receiverType.(*types.Pointer); ok {
|
|
307
|
+
receiverType = ptrType.Elem()
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// Check if the receiver is a protobuf type
|
|
311
|
+
if c.isProtobufType(receiverType) {
|
|
312
|
+
if namedType, ok := receiverType.(*types.Named); ok {
|
|
313
|
+
typeName := namedType.Obj().Name()
|
|
314
|
+
|
|
315
|
+
switch methodName {
|
|
316
|
+
case "MarshalVT":
|
|
317
|
+
// Transform msg.MarshalVT() to ExampleMsg.toBinary(msg)
|
|
318
|
+
c.tsw.WriteLiterally(typeName)
|
|
319
|
+
c.tsw.WriteLiterally(".toBinary(")
|
|
320
|
+
if err := c.WriteValueExpr(selectorExpr.X); err != nil {
|
|
321
|
+
return true, fmt.Errorf("failed to write receiver for MarshalVT: %w", err)
|
|
322
|
+
}
|
|
323
|
+
c.tsw.WriteLiterally(")")
|
|
324
|
+
return true, nil
|
|
325
|
+
case "MarshalJSON":
|
|
326
|
+
// Transform msg.MarshalJSON() to ExampleMsg.toJsonString(msg)
|
|
327
|
+
c.tsw.WriteLiterally(typeName)
|
|
328
|
+
c.tsw.WriteLiterally(".toJsonString(")
|
|
329
|
+
if err := c.WriteValueExpr(selectorExpr.X); err != nil {
|
|
330
|
+
return true, fmt.Errorf("failed to write receiver for MarshalJSON: %w", err)
|
|
331
|
+
}
|
|
332
|
+
c.tsw.WriteLiterally(")")
|
|
333
|
+
return true, nil
|
|
334
|
+
case "UnmarshalVT":
|
|
335
|
+
// Transform out.UnmarshalVT(data) to ExampleMsg.fromBinary(data)
|
|
336
|
+
c.tsw.WriteLiterally(typeName)
|
|
337
|
+
c.tsw.WriteLiterally(".fromBinary($.normalizeBytes(")
|
|
338
|
+
if len(exp.Args) > 0 {
|
|
339
|
+
if err := c.WriteValueExpr(exp.Args[0]); err != nil {
|
|
340
|
+
return true, fmt.Errorf("failed to write argument for UnmarshalVT: %w", err)
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
c.tsw.WriteLiterally("))")
|
|
344
|
+
return true, nil
|
|
345
|
+
case "UnmarshalJSON":
|
|
346
|
+
// Transform out.UnmarshalJSON(data) to ExampleMsg.fromJsonString(data)
|
|
347
|
+
c.tsw.WriteLiterally(typeName)
|
|
348
|
+
c.tsw.WriteLiterally(".fromJsonString(")
|
|
349
|
+
if len(exp.Args) > 0 {
|
|
350
|
+
if err := c.WriteValueExpr(exp.Args[0]); err != nil {
|
|
351
|
+
return true, fmt.Errorf("failed to write argument for UnmarshalJSON: %w", err)
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
c.tsw.WriteLiterally(")")
|
|
355
|
+
return true, nil
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
return false, nil
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// writeProtobufCompositeLit handles protobuf composite literals
|
|
366
|
+
// Returns true if the literal was handled as a protobuf type, false otherwise
|
|
367
|
+
func (c *GoToTSCompiler) writeProtobufCompositeLit(exp *ast.CompositeLit, litType types.Type) (bool, error) {
|
|
368
|
+
// Check if this is a protobuf type
|
|
369
|
+
var isProtobuf bool
|
|
370
|
+
|
|
371
|
+
if nt, ok := litType.(*types.Named); ok {
|
|
372
|
+
if c.isProtobufType(nt) {
|
|
373
|
+
isProtobuf = true
|
|
374
|
+
}
|
|
375
|
+
} else if ptrType, ok := litType.(*types.Pointer); ok {
|
|
376
|
+
if namedElem, ok := ptrType.Elem().(*types.Named); ok {
|
|
377
|
+
if c.isProtobufType(namedElem) {
|
|
378
|
+
isProtobuf = true
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
if !isProtobuf {
|
|
384
|
+
return false, nil
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// For protobuf types, use MessageType.create() instead of new Constructor()
|
|
388
|
+
if _, ok := litType.(*types.Pointer); ok {
|
|
389
|
+
// For pointer types, we need to get the element type
|
|
390
|
+
if starExpr, ok := exp.Type.(*ast.StarExpr); ok {
|
|
391
|
+
c.WriteTypeExpr(starExpr.X)
|
|
392
|
+
} else {
|
|
393
|
+
// Fallback: write the pointer type and use create
|
|
394
|
+
c.WriteTypeExpr(exp.Type)
|
|
395
|
+
}
|
|
396
|
+
} else {
|
|
397
|
+
c.WriteTypeExpr(exp.Type)
|
|
398
|
+
}
|
|
399
|
+
c.tsw.WriteLiterally(".create")
|
|
400
|
+
|
|
401
|
+
return true, nil
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// convertProtobufFieldNameInLiteral converts field names for protobuf composite literals
|
|
405
|
+
func (c *GoToTSCompiler) convertProtobufFieldNameInLiteral(keyName string, litType types.Type) string {
|
|
406
|
+
// Check if this is a protobuf type
|
|
407
|
+
if namedType, ok := litType.(*types.Named); ok {
|
|
408
|
+
if c.isProtobufType(namedType) {
|
|
409
|
+
return c.convertProtobufFieldName(keyName)
|
|
410
|
+
}
|
|
411
|
+
} else if ptrType, ok := litType.(*types.Pointer); ok {
|
|
412
|
+
if namedElem, ok := ptrType.Elem().(*types.Named); ok {
|
|
413
|
+
if c.isProtobufType(namedElem) {
|
|
414
|
+
return c.convertProtobufFieldName(keyName)
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
return keyName
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
// writeProtobufMarshalJSONAssignment handles: data, err := msg.MarshalJSON()
|
|
422
|
+
// Generates: const data = ExampleMsg.toJsonString(msg); err = null;
|
|
423
|
+
func (c *GoToTSCompiler) writeProtobufMarshalJSONAssignment(lhs []ast.Expr, callExpr *ast.CallExpr, tok token.Token) error {
|
|
424
|
+
if len(lhs) != 2 {
|
|
425
|
+
return fmt.Errorf("protobuf marshal JSON assignment requires exactly 2 LHS variables, got %d", len(lhs))
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
selectorExpr := callExpr.Fun.(*ast.SelectorExpr)
|
|
429
|
+
receiverType := c.pkg.TypesInfo.TypeOf(selectorExpr.X)
|
|
430
|
+
if ptrType, ok := receiverType.(*types.Pointer); ok {
|
|
431
|
+
receiverType = ptrType.Elem()
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// Get the type name for the static method call
|
|
435
|
+
var typeName string
|
|
436
|
+
if namedType, ok := receiverType.(*types.Named); ok {
|
|
437
|
+
typeName = namedType.Obj().Name()
|
|
438
|
+
} else {
|
|
439
|
+
return fmt.Errorf("could not determine protobuf type name")
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
// Handle data variable (first variable)
|
|
443
|
+
dataExpr := lhs[0]
|
|
444
|
+
if dataIdent, ok := dataExpr.(*ast.Ident); ok && dataIdent.Name != "_" {
|
|
445
|
+
// For := assignments, check if this is a new variable
|
|
446
|
+
isNewVar := true
|
|
447
|
+
if tok == token.DEFINE {
|
|
448
|
+
// Check if the variable is already in scope by looking at Uses
|
|
449
|
+
if obj := c.pkg.TypesInfo.Uses[dataIdent]; obj != nil {
|
|
450
|
+
isNewVar = false
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
if tok == token.DEFINE && isNewVar {
|
|
455
|
+
c.tsw.WriteLiterally("const ")
|
|
456
|
+
}
|
|
457
|
+
c.tsw.WriteLiterally(dataIdent.Name)
|
|
458
|
+
c.tsw.WriteLiterally(" = ")
|
|
459
|
+
c.tsw.WriteLiterally(typeName)
|
|
460
|
+
c.tsw.WriteLiterally(".toJsonString(")
|
|
461
|
+
if err := c.WriteValueExpr(selectorExpr.X); err != nil {
|
|
462
|
+
return fmt.Errorf("failed to write receiver for MarshalJSON: %w", err)
|
|
463
|
+
}
|
|
464
|
+
c.tsw.WriteLiterally(")")
|
|
465
|
+
c.tsw.WriteLine("")
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
// Handle err variable (second variable)
|
|
469
|
+
errExpr := lhs[1]
|
|
470
|
+
if errIdent, ok := errExpr.(*ast.Ident); ok && errIdent.Name != "_" {
|
|
471
|
+
// For := assignments, check if this is a new variable
|
|
472
|
+
isNewVar := true
|
|
473
|
+
if tok == token.DEFINE {
|
|
474
|
+
// Check if the variable is already in scope by looking at Uses
|
|
475
|
+
if obj := c.pkg.TypesInfo.Uses[errIdent]; obj != nil {
|
|
476
|
+
isNewVar = false
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
if tok == token.DEFINE && isNewVar {
|
|
481
|
+
c.tsw.WriteLiterally("let ")
|
|
482
|
+
}
|
|
483
|
+
c.tsw.WriteLiterally(errIdent.Name)
|
|
484
|
+
if tok == token.DEFINE && isNewVar {
|
|
485
|
+
c.tsw.WriteLiterally(": $.GoError | null")
|
|
486
|
+
}
|
|
487
|
+
c.tsw.WriteLiterally(" = null as $.GoError | null")
|
|
488
|
+
c.tsw.WriteLine("")
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
return nil
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// writeProtobufUnmarshalJSONAssignment handles: err = out.UnmarshalJSON(data)
|
|
495
|
+
// Generates: out = ExampleMsg.fromJsonString(data); err = null;
|
|
496
|
+
func (c *GoToTSCompiler) writeProtobufUnmarshalJSONAssignment(lhs []ast.Expr, callExpr *ast.CallExpr, tok token.Token) error {
|
|
497
|
+
if len(lhs) != 1 {
|
|
498
|
+
return fmt.Errorf("protobuf unmarshal JSON assignment requires exactly 1 LHS variable, got %d", len(lhs))
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
selectorExpr := callExpr.Fun.(*ast.SelectorExpr)
|
|
502
|
+
receiverType := c.pkg.TypesInfo.TypeOf(selectorExpr.X)
|
|
503
|
+
if ptrType, ok := receiverType.(*types.Pointer); ok {
|
|
504
|
+
receiverType = ptrType.Elem()
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
// Get the type name for the static method call
|
|
508
|
+
var typeName string
|
|
509
|
+
if namedType, ok := receiverType.(*types.Named); ok {
|
|
510
|
+
typeName = namedType.Obj().Name()
|
|
511
|
+
} else {
|
|
512
|
+
return fmt.Errorf("could not determine protobuf type name")
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
// The LHS should be the err variable, but we need to assign to the receiver instead
|
|
516
|
+
errExpr := lhs[0]
|
|
517
|
+
if errIdent, ok := errExpr.(*ast.Ident); ok {
|
|
518
|
+
// First, assign the result of fromJsonString to the receiver
|
|
519
|
+
if err := c.WriteValueExpr(selectorExpr.X); err != nil {
|
|
520
|
+
return fmt.Errorf("failed to write receiver for UnmarshalJSON: %w", err)
|
|
521
|
+
}
|
|
522
|
+
c.tsw.WriteLiterally(" = ")
|
|
523
|
+
c.tsw.WriteLiterally(typeName)
|
|
524
|
+
c.tsw.WriteLiterally(".fromJsonString(")
|
|
525
|
+
if len(callExpr.Args) > 0 {
|
|
526
|
+
if err := c.WriteValueExpr(callExpr.Args[0]); err != nil {
|
|
527
|
+
return fmt.Errorf("failed to write argument for UnmarshalJSON: %w", err)
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
c.tsw.WriteLiterally(")")
|
|
531
|
+
c.tsw.WriteLine("")
|
|
532
|
+
|
|
533
|
+
// Then set err to null (but only if it's not a blank identifier)
|
|
534
|
+
if errIdent.Name != "_" {
|
|
535
|
+
// For := assignments, check if this is a new variable
|
|
536
|
+
isNewVar := true
|
|
537
|
+
if tok == token.DEFINE {
|
|
538
|
+
// Check if the variable is already in scope by looking at Uses
|
|
539
|
+
if obj := c.pkg.TypesInfo.Uses[errIdent]; obj != nil {
|
|
540
|
+
isNewVar = false
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
if tok == token.DEFINE && isNewVar {
|
|
545
|
+
c.tsw.WriteLiterally("let ")
|
|
546
|
+
}
|
|
547
|
+
c.tsw.WriteLiterally(errIdent.Name)
|
|
548
|
+
if tok == token.DEFINE && isNewVar {
|
|
549
|
+
c.tsw.WriteLiterally(": $.GoError | null")
|
|
550
|
+
}
|
|
551
|
+
c.tsw.WriteLiterally(" = null as $.GoError | null")
|
|
552
|
+
c.tsw.WriteLine("")
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
return nil
|
|
557
|
+
}
|
package/compiler/spec-struct.go
CHANGED
|
@@ -20,6 +20,10 @@ 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
|
+
// Add export for Go-exported structs
|
|
24
|
+
if a.Name.IsExported() {
|
|
25
|
+
c.tsw.WriteLiterally("export ")
|
|
26
|
+
}
|
|
23
27
|
c.tsw.WriteLiterally("class ")
|
|
24
28
|
if err := c.WriteValueExpr(a.Name); err != nil {
|
|
25
29
|
return err
|
package/compiler/spec-value.go
CHANGED
|
@@ -81,7 +81,15 @@ func (c *GoToTSCompiler) WriteValueSpec(a *ast.ValueSpec) error {
|
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
// Start declaration
|
|
84
|
+
// Start declaration - add export for Go-exported symbols (but not if inside a function)
|
|
85
|
+
isInsideFunction := false
|
|
86
|
+
if nodeInfo := c.analysis.NodeData[a]; nodeInfo != nil {
|
|
87
|
+
isInsideFunction = nodeInfo.IsInsideFunction
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if name.IsExported() && !isInsideFunction {
|
|
91
|
+
c.tsw.WriteLiterally("export ")
|
|
92
|
+
}
|
|
85
93
|
c.tsw.WriteLiterally("let ")
|
|
86
94
|
c.tsw.WriteLiterally(name.Name)
|
|
87
95
|
|
|
@@ -108,7 +116,7 @@ func (c *GoToTSCompiler) WriteValueSpec(a *ast.ValueSpec) error {
|
|
|
108
116
|
c.WriteGoType(goType, GoTypeContextGeneral)
|
|
109
117
|
}
|
|
110
118
|
} else {
|
|
111
|
-
|
|
119
|
+
c.WriteGoType(goType, GoTypeContextGeneral) // Write the original Go type T
|
|
112
120
|
}
|
|
113
121
|
c.tsw.WriteLiterally(">")
|
|
114
122
|
} else {
|
|
@@ -197,7 +205,7 @@ func (c *GoToTSCompiler) WriteValueSpec(a *ast.ValueSpec) error {
|
|
|
197
205
|
// If v is varrefed, assign the varRef itself (v)
|
|
198
206
|
// If v is not varrefed, assign $.varRef(v)
|
|
199
207
|
if needsVarRefOperand {
|
|
200
|
-
//
|
|
208
|
+
// do not write .value here.
|
|
201
209
|
c.WriteIdent(unaryExprXIdent, false)
|
|
202
210
|
} else {
|
|
203
211
|
// &unvarrefedVar -> $.varRef(unvarrefedVar)
|
package/compiler/spec.go
CHANGED
|
@@ -165,7 +165,15 @@ func (c *GoToTSCompiler) WriteTypeSpec(a *ast.TypeSpec) error {
|
|
|
165
165
|
case *ast.InterfaceType:
|
|
166
166
|
return c.WriteInterfaceTypeSpec(a, t)
|
|
167
167
|
default:
|
|
168
|
-
// type alias
|
|
168
|
+
// type alias - add export for Go-exported types (but not if inside a function)
|
|
169
|
+
isInsideFunction := false
|
|
170
|
+
if nodeInfo := c.analysis.NodeData[a]; nodeInfo != nil {
|
|
171
|
+
isInsideFunction = nodeInfo.IsInsideFunction
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if a.Name.IsExported() && !isInsideFunction {
|
|
175
|
+
c.tsw.WriteLiterally("export ")
|
|
176
|
+
}
|
|
169
177
|
c.tsw.WriteLiterally("type ")
|
|
170
178
|
if err := c.WriteValueExpr(a.Name); err != nil {
|
|
171
179
|
return err
|
|
@@ -179,6 +187,15 @@ func (c *GoToTSCompiler) WriteTypeSpec(a *ast.TypeSpec) error {
|
|
|
179
187
|
|
|
180
188
|
// WriteInterfaceTypeSpec writes the TypeScript type for a Go interface type.
|
|
181
189
|
func (c *GoToTSCompiler) WriteInterfaceTypeSpec(a *ast.TypeSpec, t *ast.InterfaceType) error {
|
|
190
|
+
// Add export for Go-exported interfaces (but not if inside a function)
|
|
191
|
+
isInsideFunction := false
|
|
192
|
+
if nodeInfo := c.analysis.NodeData[a]; nodeInfo != nil {
|
|
193
|
+
isInsideFunction = nodeInfo.IsInsideFunction
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if a.Name.IsExported() && !isInsideFunction {
|
|
197
|
+
c.tsw.WriteLiterally("export ")
|
|
198
|
+
}
|
|
182
199
|
c.tsw.WriteLiterally("type ")
|
|
183
200
|
if err := c.WriteValueExpr(a.Name); err != nil {
|
|
184
201
|
return err
|
package/compiler/stmt-assign.go
CHANGED
|
@@ -384,6 +384,27 @@ func (c *GoToTSCompiler) WriteStmtAssign(exp *ast.AssignStmt) error {
|
|
|
384
384
|
// Handle multi-variable assignment from a single expression.
|
|
385
385
|
if len(exp.Lhs) > 1 && len(exp.Rhs) == 1 {
|
|
386
386
|
rhsExpr := exp.Rhs[0]
|
|
387
|
+
|
|
388
|
+
// Check for protobuf method calls first
|
|
389
|
+
if callExpr, ok := rhsExpr.(*ast.CallExpr); ok {
|
|
390
|
+
// Handle protobuf MarshalVT: data, err := msg.MarshalVT()
|
|
391
|
+
if len(exp.Lhs) == 2 && c.isProtobufMethodCall(callExpr, "MarshalVT") {
|
|
392
|
+
err := c.writeProtobufMarshalAssignment(exp.Lhs, callExpr, exp.Tok)
|
|
393
|
+
if err != nil {
|
|
394
|
+
return err
|
|
395
|
+
}
|
|
396
|
+
return nil
|
|
397
|
+
}
|
|
398
|
+
// Handle protobuf MarshalJSON: data, err := msg.MarshalJSON()
|
|
399
|
+
if len(exp.Lhs) == 2 && c.isProtobufMethodCall(callExpr, "MarshalJSON") {
|
|
400
|
+
err := c.writeProtobufMarshalJSONAssignment(exp.Lhs, callExpr, exp.Tok)
|
|
401
|
+
if err != nil {
|
|
402
|
+
return err
|
|
403
|
+
}
|
|
404
|
+
return nil
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
387
408
|
if typeAssertExpr, ok := rhsExpr.(*ast.TypeAssertExpr); ok {
|
|
388
409
|
return c.writeTypeAssert(exp.Lhs, typeAssertExpr, exp.Tok)
|
|
389
410
|
} else if indexExpr, ok := rhsExpr.(*ast.IndexExpr); ok {
|
|
@@ -412,6 +433,20 @@ func (c *GoToTSCompiler) WriteStmtAssign(exp *ast.AssignStmt) error {
|
|
|
412
433
|
// If none of the specific multi-assign patterns match, fall through to the error check below
|
|
413
434
|
}
|
|
414
435
|
|
|
436
|
+
// Check for single-variable protobuf method calls before general assignment handling
|
|
437
|
+
if len(exp.Lhs) == 1 && len(exp.Rhs) == 1 {
|
|
438
|
+
if callExpr, ok := exp.Rhs[0].(*ast.CallExpr); ok {
|
|
439
|
+
// Handle protobuf UnmarshalVT: err = out.UnmarshalVT(data)
|
|
440
|
+
if c.isProtobufMethodCall(callExpr, "UnmarshalVT") {
|
|
441
|
+
return c.writeProtobufUnmarshalAssignment(exp.Lhs, callExpr, exp.Tok)
|
|
442
|
+
}
|
|
443
|
+
// Handle protobuf UnmarshalJSON: err = out.UnmarshalJSON(data)
|
|
444
|
+
if c.isProtobufMethodCall(callExpr, "UnmarshalJSON") {
|
|
445
|
+
return c.writeProtobufUnmarshalJSONAssignment(exp.Lhs, callExpr, exp.Tok)
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
415
450
|
// Ensure LHS and RHS have the same length for valid Go code in these cases
|
|
416
451
|
if len(exp.Lhs) != len(exp.Rhs) {
|
|
417
452
|
return fmt.Errorf("invalid assignment statement: LHS count (%d) != RHS count (%d)", len(exp.Lhs), len(exp.Rhs))
|