goscript 0.0.83 → 0.1.0

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 (197) hide show
  1. package/README.md +13 -1
  2. package/cmd/goscript/cmd_compile.go +70 -69
  3. package/cmd/goscript/cmd_compile_test.go +79 -0
  4. package/cmd/goscript/main.go +10 -5
  5. package/compiler/compile-request.go +218 -0
  6. package/compiler/compiler.go +16 -1336
  7. package/compiler/compliance_test.go +196 -0
  8. package/compiler/config.go +6 -13
  9. package/compiler/diagnostic.go +70 -0
  10. package/compiler/index.test.ts +28 -28
  11. package/compiler/index.ts +40 -72
  12. package/compiler/lowered-program.go +132 -0
  13. package/compiler/lowering.go +3576 -0
  14. package/compiler/override-registry.go +422 -0
  15. package/compiler/override-registry_test.go +207 -0
  16. package/compiler/package-graph.go +231 -0
  17. package/compiler/package-graph_test.go +281 -0
  18. package/compiler/result.go +13 -0
  19. package/compiler/runtime-contract.go +279 -0
  20. package/compiler/runtime-contract_test.go +90 -0
  21. package/compiler/semantic-model-types.go +110 -0
  22. package/compiler/semantic-model.go +922 -0
  23. package/compiler/semantic-model_test.go +416 -0
  24. package/compiler/service.go +133 -0
  25. package/compiler/skeleton_test.go +1145 -0
  26. package/compiler/typescript-emitter.go +663 -0
  27. package/compiler/wasm/compile.go +2 -3
  28. package/compiler/wasm/compile_test.go +29 -0
  29. package/compiler/wasm_api.go +10 -159
  30. package/dist/compiler/index.d.ts +1 -3
  31. package/dist/compiler/index.js +31 -55
  32. package/dist/compiler/index.js.map +1 -1
  33. package/dist/gs/builtin/builtin.d.ts +13 -0
  34. package/dist/gs/builtin/builtin.js +27 -7
  35. package/dist/gs/builtin/builtin.js.map +1 -1
  36. package/dist/gs/builtin/channel.d.ts +3 -3
  37. package/dist/gs/builtin/channel.js.map +1 -1
  38. package/dist/gs/builtin/hostio.d.ts +86 -0
  39. package/dist/gs/builtin/hostio.js +266 -0
  40. package/dist/gs/builtin/hostio.js.map +1 -0
  41. package/dist/gs/builtin/index.d.ts +1 -0
  42. package/dist/gs/builtin/index.js +1 -0
  43. package/dist/gs/builtin/index.js.map +1 -1
  44. package/dist/gs/builtin/print.d.ts +8 -0
  45. package/dist/gs/builtin/print.js +111 -0
  46. package/dist/gs/builtin/print.js.map +1 -0
  47. package/dist/gs/builtin/slice.d.ts +1 -1
  48. package/dist/gs/builtin/slice.js.map +1 -1
  49. package/dist/gs/builtin/type.d.ts +11 -0
  50. package/dist/gs/builtin/type.js +55 -1
  51. package/dist/gs/builtin/type.js.map +1 -1
  52. package/dist/gs/bytes/buffer.gs.js.map +1 -1
  53. package/dist/gs/bytes/bytes.gs.js.map +1 -1
  54. package/dist/gs/bytes/reader.gs.js.map +1 -1
  55. package/dist/gs/context/context.js.map +1 -1
  56. package/dist/gs/crypto/rand/index.d.ts +5 -0
  57. package/dist/gs/crypto/rand/index.js +77 -0
  58. package/dist/gs/crypto/rand/index.js.map +1 -0
  59. package/dist/gs/encoding/json/index.d.ts +3 -0
  60. package/dist/gs/encoding/json/index.js +160 -0
  61. package/dist/gs/encoding/json/index.js.map +1 -0
  62. package/dist/gs/fmt/fmt.js +2 -22
  63. package/dist/gs/fmt/fmt.js.map +1 -1
  64. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.d.ts +1 -1
  65. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js +1 -1
  66. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js.map +1 -1
  67. package/dist/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/browser.js.map +1 -1
  68. package/dist/gs/github.com/pkg/errors/errors.js.map +1 -1
  69. package/dist/gs/github.com/pkg/errors/stack.js.map +1 -1
  70. package/dist/gs/go/scanner/index.d.ts +29 -0
  71. package/dist/gs/go/scanner/index.js +120 -0
  72. package/dist/gs/go/scanner/index.js.map +1 -0
  73. package/dist/gs/go/token/index.d.ts +31 -0
  74. package/dist/gs/go/token/index.js +82 -0
  75. package/dist/gs/go/token/index.js.map +1 -0
  76. package/dist/gs/internal/abi/index.js.map +1 -1
  77. package/dist/gs/io/fs/fs.js.map +1 -1
  78. package/dist/gs/io/fs/readdir.js.map +1 -1
  79. package/dist/gs/io/fs/readfile.js.map +1 -1
  80. package/dist/gs/io/fs/stat.js.map +1 -1
  81. package/dist/gs/io/fs/sub.js.map +1 -1
  82. package/dist/gs/io/io.js.map +1 -1
  83. package/dist/gs/os/dir_unix.gs.js.map +1 -1
  84. package/dist/gs/os/error.gs.js +2 -4
  85. package/dist/gs/os/error.gs.js.map +1 -1
  86. package/dist/gs/os/exec.gs.js.map +1 -1
  87. package/dist/gs/os/exec_posix.gs.js.map +1 -1
  88. package/dist/gs/os/rawconn_js.gs.js.map +1 -1
  89. package/dist/gs/os/root_js.gs.js.map +1 -1
  90. package/dist/gs/os/tempfile.gs.js +66 -9
  91. package/dist/gs/os/tempfile.gs.js.map +1 -1
  92. package/dist/gs/os/types.gs.js.map +1 -1
  93. package/dist/gs/os/types_js.gs.d.ts +2 -51
  94. package/dist/gs/os/types_js.gs.js +67 -105
  95. package/dist/gs/os/types_js.gs.js.map +1 -1
  96. package/dist/gs/os/types_unix.gs.js.map +1 -1
  97. package/dist/gs/path/filepath/match.js.map +1 -1
  98. package/dist/gs/path/match.js.map +1 -1
  99. package/dist/gs/path/path.js.map +1 -1
  100. package/dist/gs/reflect/index.d.ts +2 -2
  101. package/dist/gs/reflect/index.js +1 -1
  102. package/dist/gs/reflect/index.js.map +1 -1
  103. package/dist/gs/reflect/map.js.map +1 -1
  104. package/dist/gs/reflect/type.d.ts +2 -1
  105. package/dist/gs/reflect/type.js +85 -14
  106. package/dist/gs/reflect/type.js.map +1 -1
  107. package/dist/gs/reflect/types.js.map +1 -1
  108. package/dist/gs/reflect/visiblefields.js.map +1 -1
  109. package/dist/gs/runtime/runtime.js.map +1 -1
  110. package/dist/gs/sort/sort.gs.js.map +1 -1
  111. package/dist/gs/strconv/atoi.gs.js.map +1 -1
  112. package/dist/gs/strconv/quote.gs.js.map +1 -1
  113. package/dist/gs/strings/builder.js.map +1 -1
  114. package/dist/gs/strings/reader.js.map +1 -1
  115. package/dist/gs/strings/replace.js.map +1 -1
  116. package/dist/gs/sync/atomic/type.gs.js.map +1 -1
  117. package/dist/gs/sync/atomic/value.gs.js.map +1 -1
  118. package/dist/gs/sync/sync.d.ts +1 -0
  119. package/dist/gs/sync/sync.js +12 -0
  120. package/dist/gs/sync/sync.js.map +1 -1
  121. package/dist/gs/time/time.js.map +1 -1
  122. package/dist/gs/unicode/unicode.js.map +1 -1
  123. package/go.mod +2 -2
  124. package/gs/builtin/builtin.ts +31 -6
  125. package/gs/builtin/hostio.test.ts +246 -0
  126. package/gs/builtin/hostio.ts +413 -0
  127. package/gs/builtin/index.ts +1 -0
  128. package/gs/builtin/print.test.ts +48 -0
  129. package/gs/builtin/print.ts +154 -0
  130. package/gs/builtin/runtime-contract.test.ts +230 -0
  131. package/gs/builtin/type.ts +84 -1
  132. package/gs/crypto/rand/index.test.ts +32 -0
  133. package/gs/crypto/rand/index.ts +90 -0
  134. package/gs/crypto/rand/meta.json +5 -0
  135. package/gs/encoding/json/index.test.ts +65 -0
  136. package/gs/encoding/json/index.ts +186 -0
  137. package/gs/fmt/fmt.test.ts +41 -30
  138. package/gs/fmt/fmt.ts +2 -22
  139. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.test.ts +23 -0
  140. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.ts +3 -1
  141. package/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/meta.json +3 -1
  142. package/gs/go/scanner/index.test.ts +50 -0
  143. package/gs/go/scanner/index.ts +157 -0
  144. package/gs/go/token/index.test.ts +21 -0
  145. package/gs/go/token/index.ts +120 -0
  146. package/gs/os/file_unix_js.test.ts +103 -0
  147. package/gs/os/meta.json +1 -2
  148. package/gs/os/tempfile.gs.test.ts +85 -0
  149. package/gs/os/tempfile.gs.ts +71 -11
  150. package/gs/os/types_js.gs.ts +74 -153
  151. package/gs/reflect/index.ts +1 -1
  152. package/gs/reflect/type.ts +106 -17
  153. package/gs/reflect/typefor.test.ts +75 -0
  154. package/gs/sync/sync.test.ts +24 -0
  155. package/gs/sync/sync.ts +12 -0
  156. package/package.json +13 -13
  157. package/compiler/analysis.go +0 -3475
  158. package/compiler/analysis_test.go +0 -338
  159. package/compiler/assignment.go +0 -580
  160. package/compiler/builtin_test.go +0 -92
  161. package/compiler/code-writer.go +0 -115
  162. package/compiler/compiler_test.go +0 -149
  163. package/compiler/composite-lit.go +0 -779
  164. package/compiler/config_test.go +0 -62
  165. package/compiler/constraint.go +0 -86
  166. package/compiler/decl.go +0 -801
  167. package/compiler/expr-call-async.go +0 -188
  168. package/compiler/expr-call-builtins.go +0 -208
  169. package/compiler/expr-call-helpers.go +0 -382
  170. package/compiler/expr-call-make.go +0 -318
  171. package/compiler/expr-call-type-conversion.go +0 -520
  172. package/compiler/expr-call.go +0 -413
  173. package/compiler/expr-selector.go +0 -343
  174. package/compiler/expr-star.go +0 -82
  175. package/compiler/expr-type.go +0 -442
  176. package/compiler/expr-value.go +0 -89
  177. package/compiler/expr.go +0 -773
  178. package/compiler/field.go +0 -183
  179. package/compiler/gs_dependencies_test.go +0 -298
  180. package/compiler/lit.go +0 -322
  181. package/compiler/output.go +0 -72
  182. package/compiler/primitive.go +0 -149
  183. package/compiler/protobuf.go +0 -697
  184. package/compiler/sanitize.go +0 -100
  185. package/compiler/spec-struct.go +0 -995
  186. package/compiler/spec-value.go +0 -540
  187. package/compiler/spec.go +0 -725
  188. package/compiler/stmt-assign.go +0 -664
  189. package/compiler/stmt-for.go +0 -266
  190. package/compiler/stmt-range.go +0 -475
  191. package/compiler/stmt-select.go +0 -262
  192. package/compiler/stmt-type-switch.go +0 -147
  193. package/compiler/stmt.go +0 -1308
  194. package/compiler/type-assert.go +0 -386
  195. package/compiler/type-info.go +0 -156
  196. package/compiler/type-utils.go +0 -207
  197. package/compiler/type.go +0 -892
@@ -1,540 +0,0 @@
1
- package compiler
2
-
3
- import (
4
- "fmt"
5
- "go/ast"
6
- "go/token"
7
- "go/types"
8
-
9
- "golang.org/x/tools/go/packages"
10
- )
11
-
12
- // shouldApplyClone determines whether a `.clone()` method call should be appended
13
- // to the TypeScript translation of a Go expression `rhs` when it appears on the
14
- // right-hand side of an assignment. This is primarily to emulate Go's value
15
- // semantics for struct assignments, where assigning one struct variable to another
16
- // creates a copy of the struct.
17
- //
18
- // It uses `go/types` information (`pkg.TypesInfo`) to determine the type of `rhs`.
19
- // - If `rhs` is identified as a struct type (either directly, as a named type
20
- // whose underlying type is a struct, or an unnamed type whose underlying type
21
- // is a struct), it returns `true`.
22
- // - An optimization: if `rhs` is a composite literal (`*ast.CompositeLit`),
23
- // it returns `false` because a composite literal already produces a new value,
24
- // so cloning is unnecessary.
25
- // - If type information is unavailable or `rhs` is not a struct type, it returns `false`.
26
- //
27
- // This function is crucial for ensuring that assignments of struct values in
28
- // TypeScript behave like copies, as they do in Go, rather than reference assignments.
29
- func shouldApplyClone(pkg *packages.Package, rhs ast.Expr) bool {
30
- if pkg == nil || pkg.TypesInfo == nil {
31
- // Cannot determine type without type info, default to no clone
32
- return false
33
- }
34
-
35
- // Get the type of the RHS expression
36
- var exprType types.Type
37
-
38
- // Handle identifiers (variables) directly - the most common case
39
- if ident, ok := rhs.(*ast.Ident); ok {
40
- if obj := pkg.TypesInfo.Uses[ident]; obj != nil {
41
- // Get the type directly from the object
42
- exprType = obj.Type()
43
- } else if obj := pkg.TypesInfo.Defs[ident]; obj != nil {
44
- // Also check Defs map for definitions
45
- exprType = obj.Type()
46
- }
47
- }
48
-
49
- // If we couldn't get the type from Uses/Defs, try getting it from Types
50
- if exprType == nil {
51
- if tv, found := pkg.TypesInfo.Types[rhs]; found && tv.Type != nil {
52
- exprType = tv.Type
53
- }
54
- }
55
-
56
- // No type information available
57
- if exprType == nil {
58
- return false
59
- }
60
-
61
- // Optimization: If it's a composite literal for a struct, no need to clone
62
- // as it's already a fresh value
63
- if _, isCompositeLit := rhs.(*ast.CompositeLit); isCompositeLit {
64
- return false
65
- }
66
-
67
- // Check if it's a struct type (directly, through named type, or underlying)
68
- if named, ok := exprType.(*types.Named); ok {
69
- if _, isStruct := named.Underlying().(*types.Struct); isStruct {
70
- return true // Named struct type
71
- }
72
- } else if _, ok := exprType.(*types.Struct); ok {
73
- return true // Direct struct type
74
- } else if underlying := exprType.Underlying(); underlying != nil {
75
- if _, isStruct := underlying.(*types.Struct); isStruct {
76
- return true // Underlying is a struct
77
- }
78
- }
79
-
80
- return false // Not a struct, do not apply clone
81
- }
82
-
83
- // WriteValueSpec translates a Go value specification (`ast.ValueSpec`),
84
- // which represents `var` or `const` declarations, into TypeScript `let`
85
- // declarations.
86
- //
87
- // For single variable declarations (`var x T = val` or `var x = val` or `var x T`):
88
- // - It determines if the variable `x` needs to be varrefed (e.g., if its address is taken)
89
- // using `c.analysis.NeedsVarRef(obj)`.
90
- // - If variable referenced: `let x: $.VarRef<T_ts> = $.varRef(initializer_ts_or_zero_ts);`
91
- // The type annotation is `$.VarRef<T_ts>`, and the initializer is wrapped in `$.varRef()`.
92
- // - If not variable referenced: `let x: T_ts = initializer_ts_or_zero_ts;`
93
- // The type annotation is `T_ts`. If the initializer is `&unvarrefedVar`, it becomes `$.varRef(unvarrefedVar_ts)`.
94
- // - If no initializer is provided, the TypeScript zero value (from `WriteZeroValueForType`)
95
- // is used.
96
- // - Type `T` (or `T_ts`) is obtained from `obj.Type()` and translated via `WriteGoType`.
97
- //
98
- // For multiple variable declarations (`var a, b = val1, val2` or `a, b := val1, val2`):
99
- // - It uses TypeScript array destructuring: `let [a, b] = [val1_ts, val2_ts];`.
100
- // - If initialized from a single multi-return function call (`a, b := func()`),
101
- // it becomes `let [a, b] = func_ts();`.
102
- // - If no initializers are provided, it defaults to `let [a,b] = []` (with a TODO
103
- // to assign correct individual zero values).
104
- //
105
- // Documentation comments associated with the `ValueSpec` are preserved.
106
- func (c *GoToTSCompiler) WriteValueSpec(a *ast.ValueSpec) error {
107
- if a.Doc != nil {
108
- c.WriteDoc(a.Doc)
109
- }
110
- if a.Comment != nil {
111
- c.WriteDoc(a.Comment)
112
- }
113
-
114
- // Handle single variable declaration
115
- if len(a.Names) == 1 {
116
- name := a.Names[0]
117
- // Skip underscore variables
118
- if name.Name == "_" {
119
- return nil
120
- }
121
- obj := c.pkg.TypesInfo.Defs[name]
122
- if obj == nil {
123
- return fmt.Errorf("could not resolve type: %v", name)
124
- }
125
-
126
- goType := obj.Type()
127
- needsVarRef := c.analysis.NeedsVarRef(obj) // Check if address is taken
128
-
129
- hasInitializer := len(a.Values) > 0
130
- var initializerExpr ast.Expr
131
- if hasInitializer {
132
- initializerExpr = a.Values[0]
133
- }
134
-
135
- // Check if the initializer will result in an $.arrayToSlice call in TypeScript
136
- isSliceConversion := false
137
- if hasInitializer {
138
- // Case 1: Direct call to $.arrayToSlice in Go source (less common for typical array literals)
139
- if callExpr, isCallExpr := initializerExpr.(*ast.CallExpr); isCallExpr {
140
- if selExpr, isSelExpr := callExpr.Fun.(*ast.SelectorExpr); isSelExpr {
141
- if pkgIdent, isPkgIdent := selExpr.X.(*ast.Ident); isPkgIdent && pkgIdent.Name == "$" {
142
- if selExpr.Sel.Name == "arrayToSlice" {
143
- isSliceConversion = true
144
- }
145
- }
146
- }
147
- }
148
-
149
- // Case 2: Go array or slice literal, which will be compiled to $.arrayToSlice
150
- // We also check if the original Go type is actually a slice or array.
151
- if !isSliceConversion { // Only check if not already determined by Case 1
152
- if _, isCompositeLit := initializerExpr.(*ast.CompositeLit); isCompositeLit {
153
- switch goType.Underlying().(type) {
154
- case *types.Slice, *types.Array:
155
- isSliceConversion = true
156
- }
157
- }
158
- }
159
- }
160
-
161
- // Start declaration - add export for Go-exported symbols (but not if inside a function)
162
- isInsideFunction := false
163
- if nodeInfo := c.analysis.NodeData[a]; nodeInfo != nil {
164
- isInsideFunction = nodeInfo.IsInsideFunction
165
- }
166
-
167
- if !isInsideFunction {
168
- c.tsw.WriteLiterally("export ")
169
- }
170
- c.tsw.WriteLiterally("let ")
171
- c.tsw.WriteLiterally(c.sanitizeIdentifier(name.Name))
172
-
173
- // Write type annotation if:
174
- // 1. Not a slice conversion (normal case), OR
175
- // 2. Is a slice conversion but needs varRefing (we need explicit type for $.varRef())
176
- if !isSliceConversion || needsVarRef {
177
- c.tsw.WriteLiterally(": ")
178
- // Write type annotation
179
- if needsVarRef {
180
- // If varrefed, the variable holds VarRef<OriginalGoType>
181
- c.tsw.WriteLiterally("$.VarRef<")
182
-
183
- // Special case: if this is a slice conversion from an array type,
184
- // we should use the slice type instead of the array type
185
- if isSliceConversion {
186
- if arrayType, isArray := goType.Underlying().(*types.Array); isArray {
187
- // Convert [N]T to $.Slice<T>
188
- c.tsw.WriteLiterally("$.Slice<")
189
- c.WriteGoType(arrayType.Elem(), GoTypeContextGeneral)
190
- c.tsw.WriteLiterally(">")
191
- } else {
192
- // For slice types, write as-is (already $.Slice<T>)
193
- c.WriteGoType(goType, GoTypeContextGeneral)
194
- }
195
- } else {
196
- c.WriteGoType(goType, GoTypeContextGeneral) // Write the original Go type T
197
- }
198
- c.tsw.WriteLiterally(">")
199
- } else {
200
- // If not varrefed, the variable holds the translated Go type directly
201
- // Custom logic for non-var-ref'd pointers to structs/interfaces.
202
- if ptrType, isPtr := goType.(*types.Pointer); isPtr {
203
- elemType := ptrType.Elem()
204
- actualElemType := elemType.Underlying() // Get the true underlying type (e.g., struct, interface, basic)
205
-
206
- isStruct := false
207
- if _, ok := actualElemType.(*types.Struct); ok {
208
- isStruct = true
209
- }
210
-
211
- isInterface := false
212
- if _, ok := actualElemType.(*types.Interface); ok {
213
- isInterface = true
214
- }
215
-
216
- if isStruct || isInterface {
217
- // For non-var-ref'd pointers to structs or interfaces,
218
- // the type is T | null, not $.VarRef<T> | null.
219
- c.WriteGoType(elemType, GoTypeContextGeneral) // Write the element type itself (e.g., MyStruct)
220
- c.tsw.WriteLiterally(" | null")
221
- } else {
222
- // For other pointer types (e.g., *int, *string, *[]int, **MyStruct),
223
- // or pointers to types that are not structs/interfaces,
224
- // use the standard pointer type translation.
225
- c.WriteGoType(goType, GoTypeContextGeneral)
226
- }
227
- } else {
228
- // Not a pointer type, write as is.
229
- // Use AST-based type writing if explicit type is provided, otherwise use WriteGoType
230
- if a.Type != nil {
231
- // Explicit type annotation in Go code - use AST to preserve qualified names
232
- c.WriteTypeExpr(a.Type)
233
- } else {
234
- // No explicit type - use type inference from WriteGoType
235
- c.WriteGoType(goType, GoTypeContextGeneral)
236
- }
237
- }
238
- }
239
- }
240
-
241
- // Write initializer
242
- c.tsw.WriteLiterally(" = ")
243
-
244
- // Special case for nil pointer to struct type: (*struct{})(nil)
245
- if hasInitializer {
246
- if callExpr, isCallExpr := initializerExpr.(*ast.CallExpr); isCallExpr {
247
- if starExpr, isStarExpr := callExpr.Fun.(*ast.StarExpr); isStarExpr {
248
- if _, isStructType := starExpr.X.(*ast.StructType); isStructType {
249
- // Check if the argument is nil
250
- if len(callExpr.Args) == 1 {
251
- if nilIdent, isIdent := callExpr.Args[0].(*ast.Ident); isIdent && nilIdent.Name == "nil" {
252
- c.tsw.WriteLiterally("null")
253
- c.tsw.WriteLine("") // Ensure newline after null
254
- return nil
255
- }
256
- }
257
- }
258
- }
259
- }
260
- }
261
-
262
- if needsVarRef {
263
- // VarRef variable: let v: VarRef<T> = $.varRef(init_or_zero);
264
- c.tsw.WriteLiterally("$.varRef(")
265
- if hasInitializer {
266
- // Write the compiled initializer expression normally
267
- if err := c.WriteValueExpr(initializerExpr); err != nil {
268
- return err
269
- }
270
- } else {
271
- // No initializer, varRef the zero value
272
- c.WriteZeroValueForType(goType)
273
- }
274
- c.tsw.WriteLiterally(")")
275
- } else {
276
- // Unvarrefed variable: let v: T = init_or_zero;
277
- if hasInitializer {
278
- // Handle &v initializer specifically for unvarrefed variables
279
- if unaryExpr, isUnary := initializerExpr.(*ast.UnaryExpr); isUnary && unaryExpr.Op == token.AND {
280
- // Initializer is &expr
281
- // Check if expr is an identifier (variable) or something else (e.g., composite literal)
282
- if unaryExprXIdent, ok := unaryExpr.X.(*ast.Ident); ok {
283
- // Case: &variable
284
- // Check if the variable is varrefed
285
- innerObj := c.objectOfIdent(unaryExprXIdent)
286
- needsVarRefOperand := innerObj != nil && c.analysis.NeedsVarRef(innerObj)
287
-
288
- // If variable is varrefed, assign the varRef itself (variable)
289
- // If variable is not varrefed, assign $.varRef(variable)
290
- if needsVarRefOperand {
291
- // do not write .value here.
292
- c.WriteIdent(unaryExprXIdent, false)
293
- } else {
294
- // &unvarrefedVar -> $.varRef(unvarrefedVar)
295
- c.tsw.WriteLiterally("$.varRef(")
296
- if err := c.WriteValueExpr(unaryExpr.X); err != nil { // Write 'variable'
297
- return err
298
- }
299
- c.tsw.WriteLiterally(")")
300
- }
301
- } else {
302
- // Case: &compositeLiteral or &otherExpression
303
- // Let WriteUnaryExpr handle this properly (note: markAsStructValue is now applied in WriteCompositeLit)
304
- if err := c.WriteValueExpr(unaryExpr); err != nil {
305
- return err
306
- }
307
- }
308
- } else {
309
- // Check if this is a named type with methods and the initializer is a basic value
310
- if namedType, isNamed := goType.(*types.Named); isNamed {
311
- // Check if this is a wrapper type first
312
- if c.isWrapperType(namedType) {
313
- // For wrapper types, no constructor wrapping needed
314
- if shouldApplyClone(c.pkg, initializerExpr) {
315
- // When cloning for value assignment, mark the result as struct value
316
- c.tsw.WriteLiterally("$.markAsStructValue(")
317
- if err := c.WriteValueExpr(initializerExpr); err != nil {
318
- return err
319
- }
320
- c.tsw.WriteLiterally(".clone())")
321
- } else {
322
- if err := c.WriteValueExpr(initializerExpr); err != nil {
323
- return err
324
- }
325
- }
326
- } else {
327
- typeName := namedType.Obj().Name()
328
- if c.hasReceiverMethods(typeName) {
329
- // Check if the initializer is a basic literal or simple value that needs wrapping
330
- needsConstructor := false
331
- switch expr := initializerExpr.(type) {
332
- case *ast.BasicLit:
333
- needsConstructor = true
334
- case *ast.Ident:
335
- // Check if it's a simple identifier (not a function call or complex expression)
336
- if expr.Name != "nil" {
337
- // Check if this identifier refers to a value of the underlying type
338
- if obj := c.objectOfIdent(expr); obj != nil {
339
- if objType := obj.Type(); objType != nil {
340
- // If the identifier's type matches the underlying type, wrap it
341
- if types.Identical(objType, namedType.Underlying()) {
342
- needsConstructor = true
343
- }
344
- }
345
- }
346
- }
347
- case *ast.CallExpr:
348
- // Check if this is a make() call that returns the underlying type
349
- if funIdent, ok := expr.Fun.(*ast.Ident); ok && funIdent.Name == "make" {
350
- // Check if the make call returns a type that matches the underlying type
351
- if exprType := c.pkg.TypesInfo.TypeOf(expr); exprType != nil {
352
- if types.Identical(exprType, namedType.Underlying()) {
353
- needsConstructor = true
354
- }
355
- }
356
- }
357
- }
358
-
359
- if needsConstructor {
360
- c.tsw.WriteLiterallyf("new %s(", typeName)
361
- if err := c.WriteValueExpr(initializerExpr); err != nil {
362
- return err
363
- }
364
- c.tsw.WriteLiterally(")")
365
- } else {
366
- // Regular initializer for named type (e.g., function call that returns the type)
367
- if shouldApplyClone(c.pkg, initializerExpr) {
368
- // When cloning for value assignment, mark the result as struct value
369
- c.tsw.WriteLiterally("$.markAsStructValue(")
370
- if err := c.WriteValueExpr(initializerExpr); err != nil {
371
- return err
372
- }
373
- c.tsw.WriteLiterally(".clone())")
374
- } else {
375
- if err := c.writeInitializerForInterface(initializerExpr, goType); err != nil {
376
- return err
377
- }
378
- }
379
- }
380
- } else {
381
- // Named type without methods, handle normally
382
- if shouldApplyClone(c.pkg, initializerExpr) {
383
- // When cloning for value assignment, mark the result as struct value
384
- c.tsw.WriteLiterally("$.markAsStructValue(")
385
- if err := c.WriteValueExpr(initializerExpr); err != nil {
386
- return err
387
- }
388
- c.tsw.WriteLiterally(".clone())")
389
- } else {
390
- if err := c.writeInitializerForInterface(initializerExpr, goType); err != nil {
391
- return err
392
- }
393
- }
394
- }
395
- }
396
- } else {
397
- // Regular initializer, clone if needed
398
- if shouldApplyClone(c.pkg, initializerExpr) {
399
- // When cloning for value assignment, mark the result as struct value
400
- c.tsw.WriteLiterally("$.markAsStructValue(")
401
- if err := c.WriteValueExpr(initializerExpr); err != nil {
402
- return err
403
- }
404
- c.tsw.WriteLiterally(".clone())")
405
- } else {
406
- // Check if this is a pointer variable assigned to interface
407
- if err := c.writeInitializerForInterface(initializerExpr, goType); err != nil {
408
- return err
409
- }
410
- }
411
- }
412
- }
413
- } else {
414
- // No initializer, use the zero value directly
415
- // Check if this is a wrapper type first
416
- if namedType, isNamed := goType.(*types.Named); isNamed {
417
- if c.isWrapperType(namedType) {
418
- // For wrapper types, just use zero value directly
419
- c.WriteZeroValueForType(goType)
420
- } else {
421
- typeName := namedType.Obj().Name()
422
- if c.hasReceiverMethods(typeName) {
423
- // For named types with methods, create a new instance with zero value
424
- c.tsw.WriteLiterallyf("new %s(", typeName)
425
- c.WriteZeroValueForType(namedType.Underlying())
426
- c.tsw.WriteLiterally(")")
427
- } else {
428
- c.WriteZeroValueForType(goType)
429
- }
430
- }
431
- } else {
432
- c.WriteZeroValueForType(goType)
433
- }
434
- }
435
- }
436
- c.tsw.WriteLine("") // Finish the declaration line
437
- return nil
438
- }
439
-
440
- // --- Multi-variable declaration with proper individual declarations ---
441
- // Instead of using array destructuring which creates undefined types,
442
- // generate individual variable declarations with proper types and zero values
443
- if len(a.Values) > 0 {
444
- // Has initializers - use array destructuring for multiple assignments
445
- c.tsw.WriteLiterally("let ")
446
- c.tsw.WriteLiterally("[") // Use array destructuring for multi-assign
447
- for i, name := range a.Names {
448
- if i != 0 {
449
- c.tsw.WriteLiterally(", ")
450
- }
451
- c.tsw.WriteLiterally(c.sanitizeIdentifier(name.Name))
452
- }
453
- c.tsw.WriteLiterally("]")
454
-
455
- c.tsw.WriteLiterally(" = ")
456
- if len(a.Values) == 1 && len(a.Names) > 1 {
457
- // Assign from a single multi-return value
458
- if err := c.WriteValueExpr(a.Values[0]); err != nil {
459
- return err
460
- }
461
- } else {
462
- // Assign from multiple values
463
- c.tsw.WriteLiterally("[")
464
- for i, val := range a.Values {
465
- if i != 0 {
466
- c.tsw.WriteLiterally(", ")
467
- }
468
- if err := c.WriteValueExpr(val); err != nil { // Initializers are values
469
- return err
470
- }
471
- }
472
- c.tsw.WriteLiterally("]")
473
- }
474
- c.tsw.WriteLine("")
475
- } else {
476
- // No initializers - generate individual variable declarations with zero values
477
- for _, name := range a.Names {
478
- // Skip underscore variables
479
- if name.Name == "_" {
480
- continue
481
- }
482
-
483
- obj := c.pkg.TypesInfo.Defs[name]
484
- if obj == nil {
485
- return fmt.Errorf("could not resolve type for variable %v", name.Name)
486
- }
487
-
488
- goType := obj.Type()
489
-
490
- // Check if exported and not inside function
491
- isInsideFunction := false
492
- if nodeInfo := c.analysis.NodeData[a]; nodeInfo != nil {
493
- isInsideFunction = nodeInfo.IsInsideFunction
494
- }
495
-
496
- if !isInsideFunction {
497
- c.tsw.WriteLiterally("export ")
498
- }
499
-
500
- c.tsw.WriteLiterally("let ")
501
- c.tsw.WriteLiterally(c.sanitizeIdentifier(name.Name))
502
- c.tsw.WriteLiterally(": ")
503
-
504
- // Write type annotation - use AST-based type if available, otherwise infer from goType
505
- if a.Type != nil {
506
- c.WriteTypeExpr(a.Type)
507
- } else {
508
- c.WriteGoType(goType, GoTypeContextGeneral)
509
- }
510
-
511
- c.tsw.WriteLiterally(" = ")
512
- c.WriteZeroValueForType(goType)
513
- c.tsw.WriteLine("")
514
- }
515
- }
516
- return nil
517
- }
518
-
519
- // writeInitializerForInterface handles writing initializer expressions for interface variables,
520
- // with special handling for pointer variable assignments to avoid automatic .value dereferencing
521
- func (c *GoToTSCompiler) writeInitializerForInterface(initializerExpr ast.Expr, goType types.Type) error {
522
- // Check if this is a pointer variable assigned to interface
523
- if rhsIdent, isIdent := initializerExpr.(*ast.Ident); isIdent {
524
- if rhsObj := c.objectOfIdent(rhsIdent); rhsObj != nil {
525
- // Check if LHS is interface and RHS is pointer
526
- if _, isInterface := goType.Underlying().(*types.Interface); isInterface {
527
- if _, isPtr := rhsObj.Type().(*types.Pointer); isPtr {
528
- // For pointer variables that point to varrefed values, write without .value
529
- // We want to pass the VarRef object itself to the interface, not its .value
530
- if c.analysis.NeedsVarRefAccess(rhsObj) {
531
- c.WriteIdent(rhsIdent, false)
532
- return nil
533
- }
534
- }
535
- }
536
- }
537
- }
538
- // Default case: use regular WriteValueExpr
539
- return c.WriteValueExpr(initializerExpr)
540
- }