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,520 +0,0 @@
1
- package compiler
2
-
3
- import (
4
- "fmt"
5
- "go/ast"
6
- "go/token"
7
- "go/types"
8
- )
9
-
10
- // writeNilConversion handles type conversions with nil argument
11
- func (c *GoToTSCompiler) writeNilConversion(exp *ast.CallExpr) (handled bool, err error) {
12
- if len(exp.Args) != 1 {
13
- return false, nil
14
- }
15
-
16
- nilIdent, isIdent := exp.Args[0].(*ast.Ident)
17
- if !isIdent || nilIdent.Name != "nil" {
18
- return false, nil
19
- }
20
-
21
- // Check if this is actually a type conversion, not a method/function call
22
- // For type conversions, exp.Fun is a type expression (IsType() is true)
23
- // For method calls like s.ptr.Swap(nil), exp.Fun is a selector expression (IsType() is false)
24
- if tv, ok := c.pkg.TypesInfo.Types[exp.Fun]; !ok || !tv.IsType() {
25
- // This is not a type conversion, let the normal call handling proceed
26
- return false, nil
27
- }
28
-
29
- // Get the type being converted to
30
- if typ := c.pkg.TypesInfo.TypeOf(exp.Fun); typ != nil {
31
- // For pointer types, create a typed nil that preserves type information
32
- if ptrType, ok := typ.(*types.Pointer); ok {
33
- // Use a qualifier that returns the package name for local types
34
- // This matches Go's reflect output format (e.g., "main.Stringer")
35
- qualifier := func(pkg *types.Package) string {
36
- if pkg == nil {
37
- return ""
38
- }
39
- return pkg.Name()
40
- }
41
- typeName := types.TypeString(ptrType, qualifier)
42
- c.tsw.WriteLiterallyf("$.typedNil(%q)", typeName)
43
- return true, nil
44
- }
45
- }
46
-
47
- // For non-pointer types (or if type info is unavailable), use plain null
48
- c.tsw.WriteLiterally("null")
49
- return true, nil
50
- }
51
-
52
- // writeArrayTypeConversion handles array type conversions like []rune(string)
53
- func (c *GoToTSCompiler) writeArrayTypeConversion(exp *ast.CallExpr) (handled bool, err error) {
54
- arrayType, isArrayType := exp.Fun.(*ast.ArrayType)
55
- if !isArrayType {
56
- return false, nil
57
- }
58
-
59
- // Check if it's a []rune type
60
- if ident, isIdent := arrayType.Elt.(*ast.Ident); isIdent && ident.Name == "rune" {
61
- // Check if the argument is a string
62
- if len(exp.Args) == 1 {
63
- arg := exp.Args[0]
64
- if tv, ok := c.pkg.TypesInfo.Types[arg]; ok && tv.Type != nil {
65
- if c.isStringType(tv.Type) {
66
- // Translate []rune(stringValue) to $.stringToRunes(stringValue)
67
- c.tsw.WriteLiterally("$.stringToRunes(")
68
- if err := c.WriteValueExpr(arg); err != nil {
69
- return true, fmt.Errorf("failed to write argument for []rune(string) conversion: %w", err)
70
- }
71
- c.tsw.WriteLiterally(")")
72
- return true, nil
73
- }
74
- }
75
- }
76
- }
77
-
78
- // Check if it's a []byte type and the argument is a string
79
- if eltIdent, ok := arrayType.Elt.(*ast.Ident); ok && eltIdent.Name == "byte" && arrayType.Len == nil {
80
- if len(exp.Args) == 1 {
81
- arg := exp.Args[0]
82
- // Ensure TypesInfo is available and the argument type can be determined
83
- if tv, typeOk := c.pkg.TypesInfo.Types[arg]; typeOk && tv.Type != nil {
84
- if c.isStringType(tv.Type) {
85
- c.tsw.WriteLiterally("$.stringToBytes(")
86
- if err := c.WriteValueExpr(arg); err != nil {
87
- return true, fmt.Errorf("failed to write argument for []byte(string) conversion: %w", err)
88
- }
89
- c.tsw.WriteLiterally(")")
90
- return true, nil
91
- }
92
- }
93
- }
94
- }
95
-
96
- // Handle general slice type conversions like []T(namedType) where namedType has underlying type []T
97
- if arrayType.Len == nil && len(exp.Args) == 1 {
98
- arg := exp.Args[0]
99
- if argType := c.pkg.TypesInfo.TypeOf(arg); argType != nil {
100
- // Check if the argument is a named type with a slice underlying type
101
- if namedArgType, isNamed := argType.(*types.Named); isNamed {
102
- // Check if the named type has receiver methods (is a wrapper type)
103
- if c.isWrapperType(namedArgType) {
104
- // Check if the underlying type matches the target slice type
105
- if sliceUnderlying, isSlice := namedArgType.Underlying().(*types.Slice); isSlice {
106
- // Get the target slice type
107
- targetType := c.pkg.TypesInfo.TypeOf(arrayType)
108
- if targetSliceType, isTargetSlice := targetType.Underlying().(*types.Slice); isTargetSlice {
109
- // Check if element types are compatible
110
- if types.Identical(sliceUnderlying.Elem(), targetSliceType.Elem()) {
111
- // This is a conversion from wrapper slice type to []T
112
- // Since wrapper types are now type aliases, just write the value directly
113
- if err := c.WriteValueExpr(arg); err != nil {
114
- return true, fmt.Errorf("failed to write argument for slice type conversion: %w", err)
115
- }
116
- return true, nil
117
- }
118
- }
119
- }
120
- }
121
- }
122
- }
123
- }
124
-
125
- return false, nil
126
- }
127
-
128
- // writeStringConversion handles string() conversion
129
- func (c *GoToTSCompiler) writeStringConversion(exp *ast.CallExpr) error {
130
- if len(exp.Args) != 1 {
131
- return fmt.Errorf("string() conversion expects exactly 1 argument, got %d", len(exp.Args))
132
- }
133
-
134
- arg := exp.Args[0]
135
-
136
- // Case 1: Argument is a string literal string("...")
137
- if basicLit, isBasicLit := arg.(*ast.BasicLit); isBasicLit && basicLit.Kind == token.STRING {
138
- // Translate string("...") to "..." (no-op)
139
- c.WriteBasicLit(basicLit)
140
- return nil
141
- }
142
-
143
- // Case 2: Argument is a rune (int32) or a call to rune()
144
- innerCall, isCallExpr := arg.(*ast.CallExpr)
145
-
146
- if isCallExpr {
147
- // Check if it's a call to rune()
148
- if innerFunIdent, innerFunIsIdent := innerCall.Fun.(*ast.Ident); innerFunIsIdent && innerFunIdent.String() == "rune" {
149
- // Translate string(rune(val)) to $.runeOrStringToString(val)
150
- if len(innerCall.Args) == 1 {
151
- c.tsw.WriteLiterally("$.runeOrStringToString(")
152
- if err := c.WriteValueExpr(innerCall.Args[0]); err != nil {
153
- return fmt.Errorf("failed to write argument for string(rune) conversion: %w", err)
154
- }
155
- c.tsw.WriteLiterally(")")
156
- return nil
157
- }
158
- }
159
- }
160
-
161
- // Handle direct string(int32) conversion
162
- if tv, ok := c.pkg.TypesInfo.Types[arg]; ok {
163
- // Case 3a: Argument is already a string - no-op (unless it's a named type with toString)
164
- if c.isStringType(tv.Type) {
165
- // Check if this is a named type from the reflect package (like StructTag)
166
- // which is implemented as a class in TypeScript with a toString() method
167
- if namedType, isNamed := tv.Type.(*types.Named); isNamed {
168
- obj := namedType.Obj()
169
- if obj != nil && obj.Pkg() != nil && obj.Pkg().Path() == "reflect" && obj.Name() == "StructTag" {
170
- // Call toString() for reflect.StructTag
171
- if err := c.WriteValueExpr(arg); err != nil {
172
- return fmt.Errorf("failed to write argument for string(reflect.StructTag) conversion: %w", err)
173
- }
174
- c.tsw.WriteLiterally(".toString()")
175
- return nil
176
- }
177
- }
178
- // Translate string(stringValue) to stringValue (no-op)
179
- if err := c.WriteValueExpr(arg); err != nil {
180
- return fmt.Errorf("failed to write argument for string(string) no-op conversion: %w", err)
181
- }
182
- return nil
183
- }
184
-
185
- if basic, isBasic := tv.Type.Underlying().(*types.Basic); isBasic && (basic.Kind() == types.Int32 || basic.Kind() == types.UntypedRune) {
186
- // Translate string(rune_val) to $.runeOrStringToString(rune_val)
187
- c.tsw.WriteLiterally("$.runeOrStringToString(")
188
- if err := c.WriteValueExpr(arg); err != nil {
189
- return fmt.Errorf("failed to write argument for string(int32) conversion: %w", err)
190
- }
191
- c.tsw.WriteLiterally(")")
192
- return nil
193
- }
194
-
195
- if basic, isBasic := tv.Type.Underlying().(*types.Basic); isBasic && basic.Kind() == types.Uint8 {
196
- // Translate string(byte_val) to $.runeOrStringToString(byte_val)
197
- c.tsw.WriteLiterally("$.runeOrStringToString(")
198
- if err := c.WriteValueExpr(arg); err != nil {
199
- return fmt.Errorf("failed to write argument for string(byte) conversion: %w", err)
200
- }
201
- c.tsw.WriteLiterally(")")
202
- return nil
203
- }
204
-
205
- // Case 3: Argument is a slice of runes or bytes string([]rune{...}) or string([]byte{...})
206
- if c.isByteSliceType(tv.Type) {
207
- c.tsw.WriteLiterally("$.bytesToString(")
208
- if err := c.WriteValueExpr(arg); err != nil {
209
- return fmt.Errorf("failed to write argument for string([]byte) conversion: %w", err)
210
- }
211
- c.tsw.WriteLiterally(")")
212
- return nil
213
- }
214
- if c.isRuneSliceType(tv.Type) {
215
- c.tsw.WriteLiterally("$.runesToString(")
216
- if err := c.WriteValueExpr(arg); err != nil {
217
- return fmt.Errorf("failed to write argument for string([]rune) conversion: %w", err)
218
- }
219
- c.tsw.WriteLiterally(")")
220
- return nil
221
- }
222
-
223
- // Case 4: Argument is a generic type parameter (e.g., string | []byte)
224
- if typeParam, isTypeParam := tv.Type.(*types.TypeParam); isTypeParam {
225
- // Check if this is a []byte | string union constraint precisely
226
- constraint := typeParam.Constraint()
227
- if constraint != nil {
228
- hasString := constraintIncludesString(constraint)
229
- hasBytes := constraintIncludesByteSlice(constraint)
230
-
231
- if hasString && hasBytes {
232
- c.tsw.WriteLiterally("$.genericBytesOrStringToString(")
233
- if err := c.WriteValueExpr(arg); err != nil {
234
- return fmt.Errorf("failed to write argument for string(generic union) conversion: %w", err)
235
- }
236
- c.tsw.WriteLiterally(")")
237
- return nil
238
- }
239
- if hasString {
240
- // string(T) where T is constrained to string: no-op
241
- if err := c.WriteValueExpr(arg); err != nil {
242
- return fmt.Errorf("failed to write argument for string(string-constrained) conversion: %w", err)
243
- }
244
- return nil
245
- }
246
- if hasBytes {
247
- // string(T) where T is constrained to []byte
248
- c.tsw.WriteLiterally("$.bytesToString(")
249
- if err := c.WriteValueExpr(arg); err != nil {
250
- return fmt.Errorf("failed to write argument for string([]byte-constrained) conversion: %w", err)
251
- }
252
- c.tsw.WriteLiterally(")")
253
- return nil
254
- }
255
-
256
- // Fallback to previous behavior if we cannot determine precisely
257
- c.tsw.WriteLiterally("$.genericBytesOrStringToString(")
258
- if err := c.WriteValueExpr(arg); err != nil {
259
- return fmt.Errorf("failed to write argument for string(generic fallback) conversion: %w", err)
260
- }
261
- c.tsw.WriteLiterally(")")
262
- return nil
263
- }
264
- }
265
- }
266
-
267
- // Fallback: when type info is not available (e.g., in WASM context),
268
- // use a generic conversion that handles both []byte and string
269
- c.tsw.WriteLiterally("$.genericBytesOrStringToString(")
270
- if err := c.WriteValueExpr(arg); err != nil {
271
- return fmt.Errorf("failed to write argument for string(unknown type) conversion: %w", err)
272
- }
273
- c.tsw.WriteLiterally(")")
274
- return nil
275
- }
276
-
277
- // handleTypeConversionCommon contains the shared logic for type conversions
278
- func (c *GoToTSCompiler) handleTypeConversionCommon(
279
- typeName *types.TypeName,
280
- arg ast.Expr,
281
- typeNameStr string,
282
- writeTypeNameFunc func() error,
283
- ) error {
284
- // Check if we're converting FROM a type with receiver methods TO its underlying type
285
- if argType := c.pkg.TypesInfo.TypeOf(arg); argType != nil {
286
- if namedArgType, isNamed := argType.(*types.Named); isNamed {
287
- // Check if the argument type is a wrapper type
288
- if c.isWrapperType(namedArgType) {
289
- // Check if we're converting to the underlying type
290
- targetType := typeName.Type()
291
- underlyingType := namedArgType.Underlying()
292
- if types.Identical(targetType, underlyingType) {
293
- // This is a conversion from a wrapper type to its underlying type
294
- // Since wrapper types are now type aliases, just write the value directly
295
- return c.WriteValueExpr(arg)
296
- }
297
- }
298
- }
299
- }
300
-
301
- // Check if this is a function type
302
- if _, isFuncType := typeName.Type().Underlying().(*types.Signature); isFuncType {
303
- // For function types, we need to add a __goTypeName property
304
- c.tsw.WriteLiterally("Object.assign(")
305
-
306
- // Write the argument first
307
- if err := c.WriteValueExpr(arg); err != nil {
308
- return fmt.Errorf("failed to write argument for function type cast: %w", err)
309
- }
310
-
311
- // Add the __goTypeName property with the function type name
312
- c.tsw.WriteLiterallyf(", { __goTypeName: '%s' })", typeNameStr)
313
- return nil
314
- }
315
-
316
- // Check if this is a wrapper type
317
- if c.isWrapperType(typeName.Type()) {
318
- // For wrapper types, use type casting instead of constructor calls
319
- c.tsw.WriteLiterally("(")
320
- if err := c.WriteValueExpr(arg); err != nil {
321
- return fmt.Errorf("failed to write argument for wrapper type cast: %w", err)
322
- }
323
- c.tsw.WriteLiterally(" as ")
324
- c.WriteGoType(typeName.Type(), GoTypeContextGeneral)
325
- c.tsw.WriteLiterally(")")
326
- return nil
327
- }
328
-
329
- // Check if this is a simple named type (no methods, not struct, not interface)
330
- if namedType, ok := typeName.Type().(*types.Named); ok {
331
- // Don't use constructors for simple named types without methods
332
- if namedType.NumMethods() == 0 {
333
- // Exclude struct and interface types - they should still use constructors
334
- if _, isStruct := namedType.Underlying().(*types.Struct); !isStruct {
335
- if _, isInterface := namedType.Underlying().(*types.Interface); !isInterface {
336
- // Simple named type without methods - use type casting
337
- c.tsw.WriteLiterally("(")
338
- if err := c.WriteValueExpr(arg); err != nil {
339
- return fmt.Errorf("failed to write argument for simple named type cast: %w", err)
340
- }
341
- c.tsw.WriteLiterally(" as ")
342
- c.WriteGoType(typeName.Type(), GoTypeContextGeneral)
343
- c.tsw.WriteLiterally(")")
344
- return nil
345
- }
346
- }
347
- }
348
- }
349
-
350
- // Check if this type has receiver methods
351
- if c.hasReceiverMethods(typeNameStr) {
352
- // For types with methods that are NOT wrapper types, still use class constructor
353
- c.tsw.WriteLiterally("new ")
354
- if err := writeTypeNameFunc(); err != nil {
355
- return fmt.Errorf("failed to write type name: %w", err)
356
- }
357
- c.tsw.WriteLiterally("(")
358
-
359
- // Use auto-wrapping for the constructor argument (only if writeTypeNameFunc writes a simple identifier)
360
- // The constructor parameter type is the underlying type of the named type
361
- // For MyMode (which is type MyMode os.FileMode), the constructor expects os.FileMode
362
- constructorParamType := typeName.Type()
363
- if namedType, ok := typeName.Type().(*types.Named); ok {
364
- // For named types, the constructor expects the underlying type
365
- constructorParamType = namedType.Underlying()
366
- }
367
-
368
- if err := c.writeAutoWrappedArgument(arg, constructorParamType); err != nil {
369
- return fmt.Errorf("failed to write argument for type constructor: %w", err)
370
- }
371
- c.tsw.WriteLiterally(")")
372
- return nil
373
- }
374
-
375
- // Determine if this type should use constructor syntax
376
- shouldUseConstructor := false
377
-
378
- // Check if it's a type alias (like os.FileMode)
379
- if alias, isAlias := typeName.Type().(*types.Alias); isAlias {
380
- // For type aliases, check the underlying type
381
- if _, isInterface := alias.Underlying().(*types.Interface); !isInterface {
382
- if _, isStruct := alias.Underlying().(*types.Struct); !isStruct {
383
- // For non-struct, non-interface type aliases, use constructor
384
- shouldUseConstructor = true
385
- }
386
- }
387
- } else if namedType, isNamed := typeName.Type().(*types.Named); isNamed {
388
- // For named types, check if they have receiver methods in the current package
389
- // or if they follow the pattern of non-struct, non-interface named types
390
- if c.hasReceiverMethods(typeNameStr) {
391
- shouldUseConstructor = true
392
- } else if _, isInterface := namedType.Underlying().(*types.Interface); !isInterface {
393
- if _, isStruct := namedType.Underlying().(*types.Struct); !isStruct {
394
- // For non-struct, non-interface named types, use constructor
395
- shouldUseConstructor = true
396
- }
397
- }
398
- }
399
-
400
- if shouldUseConstructor {
401
- // For types that should use constructors, use class constructor
402
- c.tsw.WriteLiterally("new ")
403
- if err := writeTypeNameFunc(); err != nil {
404
- return fmt.Errorf("failed to write type name: %w", err)
405
- }
406
- c.tsw.WriteLiterally("(")
407
- if err := c.WriteValueExpr(arg); err != nil {
408
- return fmt.Errorf("failed to write argument for type constructor: %w", err)
409
- }
410
- c.tsw.WriteLiterally(")")
411
- return nil
412
- }
413
-
414
- // For types that don't need constructors, use the TypeScript "as" operator
415
- c.tsw.WriteLiterally("(")
416
- if err := c.WriteValueExpr(arg); err != nil {
417
- return fmt.Errorf("failed to write argument for type cast: %w", err)
418
- }
419
-
420
- // Then use the TypeScript "as" operator with the mapped type name
421
- c.tsw.WriteLiterally(" as ")
422
- c.WriteGoType(typeName.Type(), GoTypeContextGeneral)
423
- c.tsw.WriteLiterally(")")
424
- return nil
425
- }
426
-
427
- // writeTypeConversion handles named type conversions
428
- func (c *GoToTSCompiler) writeTypeConversion(exp *ast.CallExpr, funIdent *ast.Ident) (handled bool, err error) {
429
- // Check if this is a type conversion to a function type
430
- if funIdent == nil {
431
- return false, nil
432
- }
433
-
434
- if obj := c.objectOfIdent(funIdent); obj != nil {
435
- // Check if the object is a type name
436
- if typeName, isType := obj.(*types.TypeName); isType {
437
- // Make sure we have exactly one argument
438
- if len(exp.Args) == 1 {
439
- err := c.handleTypeConversionCommon(typeName, exp.Args[0], funIdent.String(), func() error {
440
- c.tsw.WriteLiterally(funIdent.String())
441
- return nil
442
- })
443
- return true, err
444
- }
445
- }
446
- }
447
-
448
- return false, nil
449
- }
450
-
451
- // writeIntConversion handles int() conversion
452
- func (c *GoToTSCompiler) writeIntConversion(exp *ast.CallExpr) error {
453
- if len(exp.Args) != 1 {
454
- return fmt.Errorf("int() conversion expects exactly 1 argument, got %d", len(exp.Args))
455
- }
456
-
457
- arg := exp.Args[0]
458
-
459
- // Check if we're converting FROM a type with receiver methods TO int
460
- if argType := c.pkg.TypesInfo.TypeOf(arg); argType != nil {
461
- if namedArgType, isNamed := argType.(*types.Named); isNamed {
462
- // Check if the argument type is a wrapper type
463
- if c.isWrapperType(namedArgType) {
464
- // Check if we're converting to int (the underlying type)
465
- if types.Identical(types.Typ[types.Int], namedArgType.Underlying()) {
466
- // This is a conversion from a wrapper type to int
467
- // Since wrapper types are now type aliases, just write the value directly
468
- if err := c.WriteValueExpr(arg); err != nil {
469
- return fmt.Errorf("failed to write argument for int conversion: %w", err)
470
- }
471
- return nil
472
- }
473
- }
474
- }
475
- }
476
-
477
- // Default case: Translate int(value) to $.int(value)
478
- c.tsw.WriteLiterally("$.int(")
479
- if err := c.WriteValueExpr(exp.Args[0]); err != nil {
480
- return fmt.Errorf("failed to write argument for int() conversion: %w", err)
481
- }
482
- c.tsw.WriteLiterally(")")
483
- return nil
484
- }
485
-
486
- // writeQualifiedTypeConversion handles qualified type conversions like os.FileMode(value)
487
- func (c *GoToTSCompiler) writeQualifiedTypeConversion(exp *ast.CallExpr, selectorExpr *ast.SelectorExpr) (handled bool, err error) {
488
- // Check if this is a type conversion by looking up the selector in the type info
489
- if obj := c.objectOfIdent(selectorExpr.Sel); obj != nil {
490
- // Check if the object is a type name
491
- if typeName, isType := obj.(*types.TypeName); isType {
492
- // Make sure we have exactly one argument
493
- if len(exp.Args) == 1 {
494
- err := c.handleTypeConversionCommon(typeName, exp.Args[0], selectorExpr.Sel.Name, func() error {
495
- return c.WriteSelectorExpr(selectorExpr)
496
- })
497
- return true, err
498
- }
499
- }
500
- }
501
-
502
- return false, nil
503
- }
504
-
505
- // Helper: detect if a constraint includes string or []byte
506
- func constraintIncludesString(t types.Type) bool {
507
- iface, ok := t.Underlying().(*types.Interface)
508
- if !ok {
509
- return false
510
- }
511
- return analyzeConstraint(iface).HasString
512
- }
513
-
514
- func constraintIncludesByteSlice(t types.Type) bool {
515
- iface, ok := t.Underlying().(*types.Interface)
516
- if !ok {
517
- return false
518
- }
519
- return analyzeConstraint(iface).HasByteSlice
520
- }