goscript 0.0.26 → 0.0.29

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.
Files changed (228) hide show
  1. package/README.md +4 -4
  2. package/cmd/goscript/cmd_compile.go +0 -3
  3. package/cmd/goscript/deps.go +11 -0
  4. package/compiler/analysis.go +298 -55
  5. package/compiler/assignment.go +2 -2
  6. package/compiler/builtin_test.go +1 -1
  7. package/compiler/compiler.go +200 -68
  8. package/compiler/compiler_test.go +17 -24
  9. package/compiler/composite-lit.go +32 -8
  10. package/compiler/decl.go +6 -6
  11. package/compiler/expr-call.go +170 -15
  12. package/compiler/expr-selector.go +100 -0
  13. package/compiler/expr.go +1 -1
  14. package/compiler/protobuf.go +557 -0
  15. package/compiler/spec-struct.go +4 -0
  16. package/compiler/spec-value.go +89 -10
  17. package/compiler/spec.go +254 -1
  18. package/compiler/stmt-assign.go +35 -0
  19. package/compiler/type-assert.go +87 -0
  20. package/compiler/type.go +4 -1
  21. package/dist/gs/builtin/builtin.d.ts +20 -1
  22. package/dist/gs/builtin/builtin.js +95 -4
  23. package/dist/gs/builtin/builtin.js.map +1 -1
  24. package/dist/gs/builtin/slice.d.ts +1 -1
  25. package/dist/gs/builtin/slice.js +21 -2
  26. package/dist/gs/builtin/slice.js.map +1 -1
  27. package/dist/gs/errors/errors.d.ts +5 -6
  28. package/dist/gs/errors/errors.js.map +1 -1
  29. package/dist/gs/internal/oserror/errors.d.ts +6 -0
  30. package/dist/gs/internal/oserror/errors.js +7 -0
  31. package/dist/gs/internal/oserror/errors.js.map +1 -0
  32. package/dist/gs/internal/oserror/index.d.ts +1 -0
  33. package/dist/gs/internal/oserror/index.js +2 -0
  34. package/dist/gs/internal/oserror/index.js.map +1 -0
  35. package/dist/gs/io/fs/format.d.ts +3 -0
  36. package/dist/gs/io/fs/format.js +56 -0
  37. package/dist/gs/io/fs/format.js.map +1 -0
  38. package/dist/gs/io/fs/fs.d.ts +79 -0
  39. package/dist/gs/io/fs/fs.js +200 -0
  40. package/dist/gs/io/fs/fs.js.map +1 -0
  41. package/dist/gs/io/fs/glob.d.ts +10 -0
  42. package/dist/gs/io/fs/glob.js +141 -0
  43. package/dist/gs/io/fs/glob.js.map +1 -0
  44. package/dist/gs/io/fs/index.d.ts +8 -0
  45. package/dist/gs/io/fs/index.js +9 -0
  46. package/dist/gs/io/fs/index.js.map +1 -0
  47. package/dist/gs/io/fs/readdir.d.ts +7 -0
  48. package/dist/gs/io/fs/readdir.js +152 -0
  49. package/dist/gs/io/fs/readdir.js.map +1 -0
  50. package/dist/gs/io/fs/readfile.d.ts +6 -0
  51. package/dist/gs/io/fs/readfile.js +118 -0
  52. package/dist/gs/io/fs/readfile.js.map +1 -0
  53. package/dist/gs/io/fs/stat.d.ts +6 -0
  54. package/dist/gs/io/fs/stat.js +87 -0
  55. package/dist/gs/io/fs/stat.js.map +1 -0
  56. package/dist/gs/io/fs/sub.d.ts +6 -0
  57. package/dist/gs/io/fs/sub.js +172 -0
  58. package/dist/gs/io/fs/sub.js.map +1 -0
  59. package/dist/gs/io/fs/walk.d.ts +7 -0
  60. package/dist/gs/io/fs/walk.js +76 -0
  61. package/dist/gs/io/fs/walk.js.map +1 -0
  62. package/dist/gs/io/index.d.ts +1 -0
  63. package/dist/gs/io/index.js +2 -0
  64. package/dist/gs/io/index.js.map +1 -0
  65. package/dist/gs/io/io.d.ts +107 -0
  66. package/dist/gs/io/io.js +385 -0
  67. package/dist/gs/io/io.js.map +1 -0
  68. package/dist/gs/path/index.d.ts +2 -0
  69. package/dist/gs/path/index.js +3 -0
  70. package/dist/gs/path/index.js.map +1 -0
  71. package/dist/gs/path/match.d.ts +6 -0
  72. package/dist/gs/path/match.js +281 -0
  73. package/dist/gs/path/match.js.map +1 -0
  74. package/dist/gs/path/path.d.ts +7 -0
  75. package/dist/gs/path/path.js +256 -0
  76. package/dist/gs/path/path.js.map +1 -0
  77. package/dist/gs/strings/builder.d.ts +18 -0
  78. package/dist/gs/strings/builder.js +205 -0
  79. package/dist/gs/strings/builder.js.map +1 -0
  80. package/dist/gs/strings/clone.d.ts +1 -0
  81. package/dist/gs/strings/clone.js +16 -0
  82. package/dist/gs/strings/clone.js.map +1 -0
  83. package/dist/gs/strings/compare.d.ts +1 -0
  84. package/dist/gs/strings/compare.js +14 -0
  85. package/dist/gs/strings/compare.js.map +1 -0
  86. package/dist/gs/strings/index.d.ts +2 -0
  87. package/dist/gs/strings/index.js +3 -0
  88. package/dist/gs/strings/index.js.map +1 -0
  89. package/dist/gs/strings/iter.d.ts +8 -0
  90. package/dist/gs/strings/iter.js +160 -0
  91. package/dist/gs/strings/iter.js.map +1 -0
  92. package/dist/gs/strings/reader.d.ts +34 -0
  93. package/dist/gs/strings/reader.js +418 -0
  94. package/dist/gs/strings/reader.js.map +1 -0
  95. package/dist/gs/strings/replace.d.ts +106 -0
  96. package/dist/gs/strings/replace.js +1136 -0
  97. package/dist/gs/strings/replace.js.map +1 -0
  98. package/dist/gs/strings/search.d.ts +24 -0
  99. package/dist/gs/strings/search.js +169 -0
  100. package/dist/gs/strings/search.js.map +1 -0
  101. package/dist/gs/strings/strings.d.ts +47 -0
  102. package/dist/gs/strings/strings.js +418 -0
  103. package/dist/gs/strings/strings.js.map +1 -0
  104. package/dist/gs/stringslite/index.d.ts +1 -0
  105. package/dist/gs/stringslite/index.js +2 -0
  106. package/dist/gs/stringslite/index.js.map +1 -0
  107. package/dist/gs/stringslite/strings.d.ts +11 -0
  108. package/dist/gs/stringslite/strings.js +67 -0
  109. package/dist/gs/stringslite/strings.js.map +1 -0
  110. package/dist/gs/sync/index.d.ts +1 -0
  111. package/dist/gs/sync/index.js +2 -0
  112. package/dist/gs/sync/index.js.map +1 -0
  113. package/dist/gs/sync/sync.d.ts +79 -0
  114. package/dist/gs/sync/sync.js +392 -0
  115. package/dist/gs/sync/sync.js.map +1 -0
  116. package/dist/gs/time/time.d.ts +11 -2
  117. package/dist/gs/time/time.js +337 -12
  118. package/dist/gs/time/time.js.map +1 -1
  119. package/dist/gs/unicode/index.d.ts +1 -0
  120. package/dist/gs/unicode/index.js +2 -0
  121. package/dist/gs/unicode/index.js.map +1 -0
  122. package/dist/gs/unicode/unicode.d.ts +105 -0
  123. package/dist/gs/unicode/unicode.js +332 -0
  124. package/dist/gs/unicode/unicode.js.map +1 -0
  125. package/dist/gs/unicode/utf8/index.d.ts +1 -0
  126. package/dist/gs/unicode/utf8/index.js +3 -0
  127. package/dist/gs/unicode/utf8/index.js.map +1 -0
  128. package/dist/gs/unicode/utf8/utf8.d.ts +20 -0
  129. package/dist/gs/unicode/utf8/utf8.js +196 -0
  130. package/dist/gs/unicode/utf8/utf8.js.map +1 -0
  131. package/dist/gs/unsafe/index.d.ts +1 -0
  132. package/dist/gs/unsafe/index.js +2 -0
  133. package/dist/gs/unsafe/index.js.map +1 -0
  134. package/dist/gs/unsafe/unsafe.d.ts +11 -0
  135. package/dist/gs/unsafe/unsafe.js +44 -0
  136. package/dist/gs/unsafe/unsafe.js.map +1 -0
  137. package/go.mod +2 -1
  138. package/go.sum +6 -2
  139. package/gs/README.md +6 -0
  140. package/gs/builtin/builtin.ts +171 -0
  141. package/gs/builtin/channel.ts +683 -0
  142. package/gs/builtin/defer.ts +58 -0
  143. package/gs/builtin/index.ts +1 -0
  144. package/gs/builtin/io.ts +22 -0
  145. package/gs/builtin/map.ts +50 -0
  146. package/gs/builtin/slice.ts +1030 -0
  147. package/gs/builtin/type.ts +1106 -0
  148. package/gs/builtin/varRef.ts +25 -0
  149. package/gs/cmp/godoc.txt +8 -0
  150. package/gs/cmp/index.ts +29 -0
  151. package/gs/context/context.ts +401 -0
  152. package/gs/context/godoc.txt +69 -0
  153. package/gs/context/index.ts +1 -0
  154. package/gs/errors/errors.ts +223 -0
  155. package/gs/errors/godoc.txt +63 -0
  156. package/gs/errors/index.ts +1 -0
  157. package/gs/internal/goarch/godoc.txt +39 -0
  158. package/gs/internal/goarch/index.ts +18 -0
  159. package/gs/internal/oserror/errors.ts +14 -0
  160. package/gs/internal/oserror/index.ts +1 -0
  161. package/gs/io/fs/format.ts +65 -0
  162. package/gs/io/fs/fs.ts +359 -0
  163. package/gs/io/fs/glob.ts +167 -0
  164. package/gs/io/fs/godoc.txt +35 -0
  165. package/gs/io/fs/index.ts +8 -0
  166. package/gs/io/fs/readdir.ts +126 -0
  167. package/gs/io/fs/readfile.ts +77 -0
  168. package/gs/io/fs/stat.ts +38 -0
  169. package/gs/io/fs/sub.ts +208 -0
  170. package/gs/io/fs/walk.ts +89 -0
  171. package/gs/io/godoc.txt +61 -0
  172. package/gs/io/index.ts +1 -0
  173. package/gs/io/io.go +75 -0
  174. package/gs/io/io.ts +546 -0
  175. package/gs/iter/godoc.txt +203 -0
  176. package/gs/iter/index.ts +1 -0
  177. package/gs/iter/iter.ts +117 -0
  178. package/gs/math/bits/index.ts +356 -0
  179. package/gs/math/godoc.txt +76 -0
  180. package/gs/path/index.ts +2 -0
  181. package/gs/path/match.ts +307 -0
  182. package/gs/path/path.ts +301 -0
  183. package/gs/runtime/godoc.txt +331 -0
  184. package/gs/runtime/index.ts +1 -0
  185. package/gs/runtime/runtime.ts +178 -0
  186. package/gs/slices/godoc.txt +44 -0
  187. package/gs/slices/index.ts +1 -0
  188. package/gs/slices/slices.ts +22 -0
  189. package/gs/strings/builder.test.ts +121 -0
  190. package/gs/strings/builder.ts +223 -0
  191. package/gs/strings/clone.test.ts +43 -0
  192. package/gs/strings/clone.ts +17 -0
  193. package/gs/strings/compare.test.ts +84 -0
  194. package/gs/strings/compare.ts +13 -0
  195. package/gs/strings/godoc.txt +66 -0
  196. package/gs/strings/index.ts +2 -0
  197. package/gs/strings/iter.test.ts +343 -0
  198. package/gs/strings/iter.ts +171 -0
  199. package/gs/strings/reader.test.ts +242 -0
  200. package/gs/strings/reader.ts +451 -0
  201. package/gs/strings/replace.test.ts +181 -0
  202. package/gs/strings/replace.ts +1310 -0
  203. package/gs/strings/search.test.ts +214 -0
  204. package/gs/strings/search.ts +213 -0
  205. package/gs/strings/strings.test.ts +477 -0
  206. package/gs/strings/strings.ts +510 -0
  207. package/gs/stringslite/godoc.txt +17 -0
  208. package/gs/stringslite/index.ts +1 -0
  209. package/gs/stringslite/strings.ts +82 -0
  210. package/gs/sync/godoc.txt +21 -0
  211. package/gs/sync/index.ts +1 -0
  212. package/gs/sync/sync.go +64 -0
  213. package/gs/sync/sync.ts +449 -0
  214. package/gs/time/godoc.txt +116 -0
  215. package/gs/time/index.ts +1 -0
  216. package/gs/time/time.ts +585 -0
  217. package/gs/unicode/godoc.txt +52 -0
  218. package/gs/unicode/index.ts +1 -0
  219. package/gs/unicode/unicode.go +38 -0
  220. package/gs/unicode/unicode.ts +418 -0
  221. package/gs/unicode/utf8/godoc.txt +22 -0
  222. package/gs/unicode/utf8/index.ts +2 -0
  223. package/gs/unicode/utf8/utf8.ts +227 -0
  224. package/gs/unsafe/godoc.txt +19 -0
  225. package/gs/unsafe/index.ts +1 -0
  226. package/gs/unsafe/unsafe.test.ts +68 -0
  227. package/gs/unsafe/unsafe.ts +77 -0
  228. package/package.json +4 -3
@@ -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
+ }
@@ -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
@@ -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
 
@@ -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
- // special handling: do not write .value here.
208
+ // do not write .value here.
201
209
  c.WriteIdent(unaryExprXIdent, false)
202
210
  } else {
203
211
  // &unvarrefedVar -> $.varRef(unvarrefedVar)
@@ -208,21 +216,92 @@ func (c *GoToTSCompiler) WriteValueSpec(a *ast.ValueSpec) error {
208
216
  c.tsw.WriteLiterally(")")
209
217
  }
210
218
  } else {
211
- // Regular initializer, clone if needed
212
- if shouldApplyClone(c.pkg, initializerExpr) {
213
- if err := c.WriteValueExpr(initializerExpr); err != nil {
214
- return err
219
+ // Check if this is a named type with methods and the initializer is a basic value
220
+ if namedType, isNamed := goType.(*types.Named); isNamed {
221
+ typeName := namedType.Obj().Name()
222
+ if c.hasReceiverMethods(typeName) {
223
+ // Check if the initializer is a basic literal or simple value that needs wrapping
224
+ needsConstructor := false
225
+ switch initializerExpr.(type) {
226
+ case *ast.BasicLit:
227
+ needsConstructor = true
228
+ case *ast.Ident:
229
+ // Check if it's a simple identifier (not a function call or complex expression)
230
+ if ident := initializerExpr.(*ast.Ident); ident.Name != "nil" {
231
+ // Check if this identifier refers to a value of the underlying type
232
+ if obj := c.pkg.TypesInfo.Uses[ident]; obj != nil {
233
+ if objType := obj.Type(); objType != nil {
234
+ // If the identifier's type matches the underlying type, wrap it
235
+ if types.Identical(objType, namedType.Underlying()) {
236
+ needsConstructor = true
237
+ }
238
+ }
239
+ }
240
+ }
241
+ }
242
+
243
+ if needsConstructor {
244
+ c.tsw.WriteLiterallyf("new %s(", typeName)
245
+ if err := c.WriteValueExpr(initializerExpr); err != nil {
246
+ return err
247
+ }
248
+ c.tsw.WriteLiterally(")")
249
+ } else {
250
+ // Regular initializer for named type (e.g., function call that returns the type)
251
+ if shouldApplyClone(c.pkg, initializerExpr) {
252
+ if err := c.WriteValueExpr(initializerExpr); err != nil {
253
+ return err
254
+ }
255
+ c.tsw.WriteLiterally(".clone()")
256
+ } else {
257
+ if err := c.WriteValueExpr(initializerExpr); err != nil {
258
+ return err
259
+ }
260
+ }
261
+ }
262
+ } else {
263
+ // Named type without methods, handle normally
264
+ if shouldApplyClone(c.pkg, initializerExpr) {
265
+ if err := c.WriteValueExpr(initializerExpr); err != nil {
266
+ return err
267
+ }
268
+ c.tsw.WriteLiterally(".clone()")
269
+ } else {
270
+ if err := c.WriteValueExpr(initializerExpr); err != nil {
271
+ return err
272
+ }
273
+ }
215
274
  }
216
- c.tsw.WriteLiterally(".clone()")
217
275
  } else {
218
- if err := c.WriteValueExpr(initializerExpr); err != nil {
219
- return err
276
+ // Regular initializer, clone if needed
277
+ if shouldApplyClone(c.pkg, initializerExpr) {
278
+ if err := c.WriteValueExpr(initializerExpr); err != nil {
279
+ return err
280
+ }
281
+ c.tsw.WriteLiterally(".clone()")
282
+ } else {
283
+ if err := c.WriteValueExpr(initializerExpr); err != nil {
284
+ return err
285
+ }
220
286
  }
221
287
  }
222
288
  }
223
289
  } else {
224
290
  // No initializer, use the zero value directly
225
- c.WriteZeroValueForType(goType)
291
+ // Check if this is a named type with methods
292
+ if namedType, isNamed := goType.(*types.Named); isNamed {
293
+ typeName := namedType.Obj().Name()
294
+ if c.hasReceiverMethods(typeName) {
295
+ // For named types with methods, create a new instance with zero value
296
+ c.tsw.WriteLiterallyf("new %s(", typeName)
297
+ c.WriteZeroValueForType(namedType.Underlying())
298
+ c.tsw.WriteLiterally(")")
299
+ } else {
300
+ c.WriteZeroValueForType(goType)
301
+ }
302
+ } else {
303
+ c.WriteZeroValueForType(goType)
304
+ }
226
305
  }
227
306
  }
228
307
  c.tsw.WriteLine("") // Finish the declaration line