goscript 0.0.84 → 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 (188) 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 +23 -0
  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 +15 -1
  39. package/dist/gs/builtin/hostio.js +134 -49
  40. package/dist/gs/builtin/hostio.js.map +1 -1
  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/slice.d.ts +1 -1
  45. package/dist/gs/builtin/slice.js.map +1 -1
  46. package/dist/gs/builtin/type.d.ts +11 -0
  47. package/dist/gs/builtin/type.js +55 -1
  48. package/dist/gs/builtin/type.js.map +1 -1
  49. package/dist/gs/bytes/buffer.gs.js.map +1 -1
  50. package/dist/gs/bytes/bytes.gs.js.map +1 -1
  51. package/dist/gs/bytes/reader.gs.js.map +1 -1
  52. package/dist/gs/context/context.js.map +1 -1
  53. package/dist/gs/crypto/rand/index.d.ts +5 -0
  54. package/dist/gs/crypto/rand/index.js +77 -0
  55. package/dist/gs/crypto/rand/index.js.map +1 -0
  56. package/dist/gs/encoding/json/index.d.ts +3 -0
  57. package/dist/gs/encoding/json/index.js +160 -0
  58. package/dist/gs/encoding/json/index.js.map +1 -0
  59. package/dist/gs/fmt/fmt.js.map +1 -1
  60. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.d.ts +1 -1
  61. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js +1 -1
  62. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js.map +1 -1
  63. package/dist/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/browser.js.map +1 -1
  64. package/dist/gs/github.com/pkg/errors/errors.js.map +1 -1
  65. package/dist/gs/github.com/pkg/errors/stack.js.map +1 -1
  66. package/dist/gs/go/scanner/index.d.ts +29 -0
  67. package/dist/gs/go/scanner/index.js +120 -0
  68. package/dist/gs/go/scanner/index.js.map +1 -0
  69. package/dist/gs/go/token/index.d.ts +31 -0
  70. package/dist/gs/go/token/index.js +82 -0
  71. package/dist/gs/go/token/index.js.map +1 -0
  72. package/dist/gs/internal/abi/index.js.map +1 -1
  73. package/dist/gs/io/fs/fs.js.map +1 -1
  74. package/dist/gs/io/fs/readdir.js.map +1 -1
  75. package/dist/gs/io/fs/readfile.js.map +1 -1
  76. package/dist/gs/io/fs/stat.js.map +1 -1
  77. package/dist/gs/io/fs/sub.js.map +1 -1
  78. package/dist/gs/io/io.js.map +1 -1
  79. package/dist/gs/os/dir_unix.gs.js.map +1 -1
  80. package/dist/gs/os/error.gs.js +2 -4
  81. package/dist/gs/os/error.gs.js.map +1 -1
  82. package/dist/gs/os/exec.gs.js.map +1 -1
  83. package/dist/gs/os/exec_posix.gs.js.map +1 -1
  84. package/dist/gs/os/rawconn_js.gs.js.map +1 -1
  85. package/dist/gs/os/root_js.gs.js.map +1 -1
  86. package/dist/gs/os/tempfile.gs.js +66 -9
  87. package/dist/gs/os/tempfile.gs.js.map +1 -1
  88. package/dist/gs/os/types.gs.js.map +1 -1
  89. package/dist/gs/os/types_js.gs.js +9 -9
  90. package/dist/gs/os/types_js.gs.js.map +1 -1
  91. package/dist/gs/os/types_unix.gs.js.map +1 -1
  92. package/dist/gs/path/filepath/match.js.map +1 -1
  93. package/dist/gs/path/match.js.map +1 -1
  94. package/dist/gs/path/path.js.map +1 -1
  95. package/dist/gs/reflect/index.d.ts +2 -2
  96. package/dist/gs/reflect/index.js +1 -1
  97. package/dist/gs/reflect/index.js.map +1 -1
  98. package/dist/gs/reflect/map.js.map +1 -1
  99. package/dist/gs/reflect/type.d.ts +2 -1
  100. package/dist/gs/reflect/type.js +85 -14
  101. package/dist/gs/reflect/type.js.map +1 -1
  102. package/dist/gs/reflect/types.js.map +1 -1
  103. package/dist/gs/reflect/visiblefields.js.map +1 -1
  104. package/dist/gs/runtime/runtime.js.map +1 -1
  105. package/dist/gs/sort/sort.gs.js.map +1 -1
  106. package/dist/gs/strconv/atoi.gs.js.map +1 -1
  107. package/dist/gs/strconv/quote.gs.js.map +1 -1
  108. package/dist/gs/strings/builder.js.map +1 -1
  109. package/dist/gs/strings/reader.js.map +1 -1
  110. package/dist/gs/strings/replace.js.map +1 -1
  111. package/dist/gs/sync/atomic/type.gs.js.map +1 -1
  112. package/dist/gs/sync/atomic/value.gs.js.map +1 -1
  113. package/dist/gs/sync/sync.d.ts +1 -0
  114. package/dist/gs/sync/sync.js +12 -0
  115. package/dist/gs/sync/sync.js.map +1 -1
  116. package/dist/gs/time/time.js.map +1 -1
  117. package/dist/gs/unicode/unicode.js.map +1 -1
  118. package/go.mod +2 -2
  119. package/gs/builtin/builtin.ts +27 -0
  120. package/gs/builtin/hostio.test.ts +177 -0
  121. package/gs/builtin/hostio.ts +171 -56
  122. package/gs/builtin/index.ts +1 -0
  123. package/gs/builtin/runtime-contract.test.ts +230 -0
  124. package/gs/builtin/type.ts +84 -1
  125. package/gs/crypto/rand/index.test.ts +32 -0
  126. package/gs/crypto/rand/index.ts +90 -0
  127. package/gs/crypto/rand/meta.json +5 -0
  128. package/gs/encoding/json/index.test.ts +65 -0
  129. package/gs/encoding/json/index.ts +186 -0
  130. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.test.ts +23 -0
  131. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.ts +3 -1
  132. package/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/meta.json +3 -1
  133. package/gs/go/scanner/index.test.ts +50 -0
  134. package/gs/go/scanner/index.ts +157 -0
  135. package/gs/go/token/index.test.ts +21 -0
  136. package/gs/go/token/index.ts +120 -0
  137. package/gs/os/file_unix_js.test.ts +50 -0
  138. package/gs/os/meta.json +1 -2
  139. package/gs/os/tempfile.gs.test.ts +85 -0
  140. package/gs/os/tempfile.gs.ts +71 -11
  141. package/gs/os/types_js.gs.ts +9 -9
  142. package/gs/reflect/index.ts +1 -1
  143. package/gs/reflect/type.ts +106 -17
  144. package/gs/reflect/typefor.test.ts +75 -0
  145. package/gs/sync/sync.test.ts +24 -0
  146. package/gs/sync/sync.ts +12 -0
  147. package/package.json +13 -13
  148. package/compiler/analysis.go +0 -3475
  149. package/compiler/analysis_test.go +0 -338
  150. package/compiler/assignment.go +0 -580
  151. package/compiler/builtin_test.go +0 -92
  152. package/compiler/code-writer.go +0 -115
  153. package/compiler/compiler_test.go +0 -149
  154. package/compiler/composite-lit.go +0 -779
  155. package/compiler/config_test.go +0 -62
  156. package/compiler/constraint.go +0 -86
  157. package/compiler/decl.go +0 -801
  158. package/compiler/expr-call-async.go +0 -188
  159. package/compiler/expr-call-builtins.go +0 -208
  160. package/compiler/expr-call-helpers.go +0 -382
  161. package/compiler/expr-call-make.go +0 -318
  162. package/compiler/expr-call-type-conversion.go +0 -520
  163. package/compiler/expr-call.go +0 -413
  164. package/compiler/expr-selector.go +0 -343
  165. package/compiler/expr-star.go +0 -82
  166. package/compiler/expr-type.go +0 -442
  167. package/compiler/expr-value.go +0 -89
  168. package/compiler/expr.go +0 -773
  169. package/compiler/field.go +0 -183
  170. package/compiler/gs_dependencies_test.go +0 -298
  171. package/compiler/lit.go +0 -322
  172. package/compiler/output.go +0 -72
  173. package/compiler/primitive.go +0 -149
  174. package/compiler/protobuf.go +0 -697
  175. package/compiler/sanitize.go +0 -100
  176. package/compiler/spec-struct.go +0 -995
  177. package/compiler/spec-value.go +0 -540
  178. package/compiler/spec.go +0 -725
  179. package/compiler/stmt-assign.go +0 -664
  180. package/compiler/stmt-for.go +0 -266
  181. package/compiler/stmt-range.go +0 -475
  182. package/compiler/stmt-select.go +0 -262
  183. package/compiler/stmt-type-switch.go +0 -147
  184. package/compiler/stmt.go +0 -1308
  185. package/compiler/type-assert.go +0 -386
  186. package/compiler/type-info.go +0 -156
  187. package/compiler/type-utils.go +0 -207
  188. package/compiler/type.go +0 -892
package/compiler/type.go DELETED
@@ -1,892 +0,0 @@
1
- package compiler
2
-
3
- import (
4
- "fmt"
5
- "go/ast"
6
- "go/token"
7
- "go/types"
8
- "strings"
9
- )
10
-
11
- // GoTypeContext specifies the context in which a Go type is being translated to TypeScript.
12
- // This affects how certain types are handled, particularly interfaces and pointers.
13
- type GoTypeContext int
14
-
15
- const (
16
- // GoTypeContextGeneral is used for general type translation
17
- GoTypeContextGeneral GoTypeContext = iota
18
- // GoTypeContextFunctionReturn is used when translating types for function return values.
19
- // This affects how pointer types are handled (no VarRef wrapper for structs).
20
- GoTypeContextFunctionReturn
21
- // GoTypeContextVariadicParam is used when translating types for variadic parameter elements.
22
- // This affects how interface{} types are handled (no null prefix).
23
- GoTypeContextVariadicParam
24
- // GoTypeContextGenericTypeArg is used when translating type arguments for generic types.
25
- // This affects how function types are handled (no | null suffix for func() types).
26
- GoTypeContextGenericTypeArg
27
- )
28
-
29
- // WriteGoType is the main dispatcher for translating Go types to their TypeScript
30
- // equivalents. It examines the type and delegates to more specialized type writer
31
- // functions based on the specific Go type encountered.
32
- //
33
- // The context parameter controls how certain types (especially pointers) are handled:
34
- // - GoTypeContextGeneral: Standard type translation
35
- // - GoTypeContextFunctionReturn: Special handling for function return types where
36
- // pointer-to-struct types become `ClassName | null` instead of `$.VarRef<ClassName> | null`
37
- // - GoTypeContextVariadicParam: Special handling for variadic parameter elements
38
- //
39
- // It handles nil types as 'any' with a comment, and dispatches to appropriate
40
- // type-specific writers for all other recognized Go types.
41
- func (c *GoToTSCompiler) WriteGoType(typ types.Type, context GoTypeContext) {
42
- if typ == nil {
43
- c.tsw.WriteLiterally("any")
44
- c.tsw.WriteCommentInline("nil type")
45
- return
46
- }
47
-
48
- switch t := typ.(type) {
49
- case *types.Basic:
50
- c.WriteBasicType(t)
51
- case *types.Named:
52
- c.WriteNamedType(t)
53
- case *types.Pointer:
54
- if context == GoTypeContextFunctionReturn {
55
- c.writePointerTypeForFunctionReturn(t)
56
- } else {
57
- c.WritePointerType(t, context)
58
- }
59
- case *types.Slice:
60
- c.WriteSliceType(t)
61
- case *types.Array:
62
- c.WriteArrayType(t)
63
- case *types.Map:
64
- c.WriteMapType(t)
65
- case *types.Chan:
66
- c.WriteChannelType(t)
67
- case *types.Interface:
68
- if context == GoTypeContextVariadicParam {
69
- c.writeInterfaceStructure(t, nil) // Skip the "null |" prefix for variadic params
70
- } else {
71
- c.WriteInterfaceType(t, nil) // No ast.InterfaceType available here
72
- }
73
- case *types.Signature:
74
- c.WriteSignatureType(t, context)
75
- case *types.Struct:
76
- c.WriteStructType(t)
77
- case *types.Alias:
78
- // Check if this type alias is from an imported package
79
- aliasObj := t.Obj()
80
- if aliasObj != nil && aliasObj.Pkg() != nil && aliasObj.Pkg() != c.pkg.Types {
81
- // This type alias is from an imported package, find the import alias
82
- if alias, found := c.resolveImportAlias(aliasObj.Pkg()); found {
83
- // Write the qualified name: importAlias.TypeName
84
- c.tsw.WriteLiterally(alias)
85
- c.tsw.WriteLiterally(".")
86
- c.tsw.WriteLiterally(aliasObj.Name())
87
- return
88
- }
89
- }
90
- // For local type aliases or unmatched imports, expand to underlying type
91
- c.WriteGoType(t.Underlying(), context)
92
- case *types.TypeParam:
93
- // For type parameters, write the type parameter name (e.g., "T", "K", etc.)
94
- // Use sanitizeIdentifier to handle conflicts with TypeScript built-in types
95
- c.tsw.WriteLiterally(c.sanitizeIdentifier(t.Obj().Name()))
96
- case *types.Union:
97
- // Handle union types (e.g., string | []byte)
98
- for i := 0; i < t.Len(); i++ {
99
- if i > 0 {
100
- c.tsw.WriteLiterally(" | ")
101
- }
102
- term := t.Term(i)
103
- c.WriteGoType(term.Type(), context)
104
- }
105
- default:
106
- // For other types, just write "any" and add a comment
107
- c.tsw.WriteLiterally("any")
108
- c.tsw.WriteCommentInlinef("unhandled type: %T", typ)
109
- }
110
- }
111
-
112
- // writePointerTypeForFunctionReturn translates a Go pointer type (*T) to its TypeScript
113
- // equivalent for function return types. Unlike WritePointerType, this function
114
- // handles pointer-to-struct types specially: they become `ClassName | null` instead
115
- // of `$.VarRef<ClassName> | null` because function return values cannot be addressed.
116
- func (c *GoToTSCompiler) writePointerTypeForFunctionReturn(t *types.Pointer) {
117
- elemType := t.Elem()
118
-
119
- // Check if the element type is a struct (directly or via a named type)
120
- isStructType := false
121
- if _, ok := elemType.Underlying().(*types.Struct); ok {
122
- isStructType = true
123
- }
124
-
125
- if isStructType {
126
- // For pointer-to-struct in function returns, generate ClassName | null
127
- c.WriteGoType(elemType, GoTypeContextFunctionReturn)
128
- c.tsw.WriteLiterally(" | null")
129
- } else {
130
- // For pointer-to-primitive in function returns, still use varRefing
131
- c.tsw.WriteLiterally("$.VarRef<")
132
- c.WriteGoType(elemType, GoTypeContextFunctionReturn)
133
- c.tsw.WriteLiterally("> | null")
134
- }
135
- }
136
-
137
- // WriteZeroValueForType writes the TypeScript representation of the zero value
138
- // for a given Go type.
139
- // It handles `types.Array` by recursively writing zero values for each element
140
- // to form a TypeScript array literal (e.g., `[0, 0, 0]`).
141
- // For `types.Basic` (like `bool`, `string`, numeric types), it writes the
142
- // corresponding TypeScript zero value (`false`, `""`, `0`).
143
- // For `[]byte`, it writes `new Uint8Array(0)`.
144
- // Other types default to `null`. This function is primarily used for initializing
145
- // arrays and variables where an explicit initializer is absent.
146
- func (c *GoToTSCompiler) WriteZeroValueForType(typ any) {
147
- switch t := typ.(type) {
148
- case *types.Array:
149
- c.tsw.WriteLiterally("[")
150
- for i := 0; i < int(t.Len()); i++ {
151
- if i > 0 {
152
- c.tsw.WriteLiterally(", ")
153
- }
154
- c.WriteZeroValueForType(t.Elem())
155
- }
156
- c.tsw.WriteLiterally("]")
157
- case *ast.Expr:
158
- // For AST expressions, get the type and handle that instead
159
- if expr := *t; expr != nil {
160
- if typ := c.pkg.TypesInfo.TypeOf(expr); typ != nil {
161
- c.WriteZeroValueForType(typ)
162
- return
163
- }
164
- }
165
- c.tsw.WriteLiterally("null")
166
- case *types.Basic:
167
- switch t.Kind() {
168
- case types.Bool:
169
- c.tsw.WriteLiterally("false")
170
- case types.String:
171
- c.tsw.WriteLiterally(`""`)
172
- default:
173
- c.tsw.WriteLiterally("0")
174
- }
175
- case *types.Named:
176
- // Handle named types, especially struct types
177
- if _, isStruct := t.Underlying().(*types.Struct); isStruct {
178
- // Initialize struct types with a new instance
179
- // Use the same logic as WriteNamedType to handle imported types
180
- c.tsw.WriteLiterally("new ")
181
- c.WriteNamedType(t)
182
- c.tsw.WriteLiterally("()")
183
- return
184
- }
185
- // For other named types, use the zero value of the underlying type
186
- c.WriteZeroValueForType(t.Underlying())
187
- case *types.Slice:
188
- // Check if it's a []byte slice
189
- if c.isByteSliceType(t) {
190
- c.tsw.WriteLiterally("new Uint8Array(0)")
191
- return
192
- }
193
- // For other slice types, default to null
194
- c.tsw.WriteLiterally("null")
195
- case *types.Struct:
196
- // For anonymous struct types, initialize with {}
197
- c.tsw.WriteLiterally("{}")
198
- case *types.TypeParam:
199
- // For type parameters, use null with type assertion to work around TypeScript's strict checking
200
- // This allows null to be assigned to generic type parameters even when the constraint doesn't explicitly include null
201
- c.tsw.WriteLiterally("null as any")
202
- default:
203
- c.tsw.WriteLiterally("null")
204
- }
205
- }
206
-
207
- // WriteBasicType translates a Go basic type (primitives like int, string, bool)
208
- // to its TypeScript equivalent.
209
- // It handles untyped constants by mapping them to appropriate TypeScript types
210
- // (boolean, number, string, null) and uses GoBuiltinToTypescript for typed primitives.
211
- func (c *GoToTSCompiler) WriteBasicType(t *types.Basic) {
212
- name := t.Name()
213
-
214
- // Handle untyped constants by mapping them to appropriate TypeScript types
215
- if t.Info()&types.IsUntyped != 0 {
216
- switch t.Kind() {
217
- case types.UntypedBool:
218
- c.tsw.WriteLiterally("boolean")
219
- return
220
- case types.UntypedInt, types.UntypedFloat, types.UntypedComplex, types.UntypedRune:
221
- c.tsw.WriteLiterally("number")
222
- return
223
- case types.UntypedString:
224
- c.tsw.WriteLiterally("string")
225
- return
226
- case types.UntypedNil:
227
- c.tsw.WriteLiterally("null")
228
- return
229
- }
230
- }
231
-
232
- // For typed basic types, use the existing mapping
233
- if tsType, ok := GoBuiltinToTypescript(name); ok {
234
- c.tsw.WriteLiterally(tsType)
235
- } else {
236
- c.tsw.WriteLiterally(name)
237
- }
238
- }
239
-
240
- // WriteNamedType translates a Go named type to its TypeScript equivalent.
241
- // It specially handles the error interface as $.GoError, and uses the original
242
- // type name for other named types. For imported types, it writes the qualified
243
- // name using the import alias found from the analysis imports. For generic types, it includes type arguments.
244
- func (c *GoToTSCompiler) WriteNamedType(t *types.Named) {
245
- // Check if the named type is the error interface
246
- if iface, ok := t.Underlying().(*types.Interface); ok && iface.String() == "interface{Error() string}" {
247
- c.tsw.WriteLiterally("$.GoError")
248
- return
249
- }
250
-
251
- // Check if this type is from an imported package
252
- typePkg := t.Obj().Pkg()
253
- if typePkg != nil && typePkg != c.pkg.Types {
254
- // This type is from an imported package, find the import alias
255
- alias, found := c.resolveImportAlias(typePkg)
256
- if found && alias != "" {
257
- // Write the qualified name: importAlias.TypeName
258
- c.tsw.WriteLiterally(alias)
259
- c.tsw.WriteLiterally(".")
260
- c.tsw.WriteLiterally(c.sanitizeIdentifier(t.Obj().Name()))
261
-
262
- // For generic types, include type arguments
263
- if t.TypeArgs() != nil && t.TypeArgs().Len() > 0 {
264
- c.tsw.WriteLiterally("<")
265
- for i := 0; i < t.TypeArgs().Len(); i++ {
266
- if i > 0 {
267
- c.tsw.WriteLiterally(", ")
268
- }
269
- // Use GenericTypeArg context to avoid adding | null to function types
270
- c.WriteGoType(t.TypeArgs().At(i), GoTypeContextGenericTypeArg)
271
- }
272
- c.tsw.WriteLiterally(">")
273
- }
274
-
275
- // Check if the underlying type is a function signature and add | null
276
- if _, isSignature := t.Underlying().(*types.Signature); isSignature {
277
- c.tsw.WriteLiterally(" | null")
278
- }
279
- return
280
- }
281
- }
282
-
283
- // Use Obj().Name() for the original defined name (local types or unmatched imports)
284
- c.tsw.WriteLiterally(c.sanitizeIdentifier(t.Obj().Name()))
285
-
286
- // For generic types, include type arguments
287
- if t.TypeArgs() != nil && t.TypeArgs().Len() > 0 {
288
- c.tsw.WriteLiterally("<")
289
- for i := 0; i < t.TypeArgs().Len(); i++ {
290
- if i > 0 {
291
- c.tsw.WriteLiterally(", ")
292
- }
293
- // Use GenericTypeArg context to avoid adding | null to function types
294
- c.WriteGoType(t.TypeArgs().At(i), GoTypeContextGenericTypeArg)
295
- }
296
- c.tsw.WriteLiterally(">")
297
- }
298
-
299
- // Check if the underlying type is a function signature and add | null for local types too
300
- if _, isSignature := t.Underlying().(*types.Signature); isSignature {
301
- c.tsw.WriteLiterally(" | null")
302
- }
303
- }
304
-
305
- // WritePointerType translates a Go pointer type (*T) to its TypeScript equivalent.
306
- func (c *GoToTSCompiler) WritePointerType(t *types.Pointer, context GoTypeContext) {
307
- elemGoType := t.Elem()
308
- underlyingElemGoType := elemGoType.Underlying()
309
-
310
- // Handle pointers to functions: *func(...) -> func(...) | null
311
- if _, isSignature := underlyingElemGoType.(*types.Signature); isSignature {
312
- c.WriteGoType(elemGoType, context) // Write the function signature itself, pass context
313
- c.tsw.WriteLiterally(" | null") // Function pointers are nullable
314
- return
315
- }
316
-
317
- // Handle pointers to structs or interfaces: *MyStruct -> MyStruct | null
318
- _, isStruct := underlyingElemGoType.(*types.Struct)
319
- _, isInterface := underlyingElemGoType.(*types.Interface)
320
-
321
- if isStruct || isInterface {
322
- // For pointers to structs or interfaces, the TS type is StructName | null or InterfaceName | null.
323
- // This aligns with VAR_REFS.md and JS/TS object reference semantics.
324
- // TODO If the target variable is boxed, we have to wrap with VarRef as well?
325
- c.WriteGoType(elemGoType, context) // Write the struct/interface type directly, pass context
326
- c.tsw.WriteLiterally(" | null")
327
- } else {
328
- // For pointers to other types (primitives, slices, maps, other pointers like **MyStruct),
329
- // they are generally represented as $.VarRef<T_ts> | null.
330
- // Example: *int -> $.VarRef<number> | null
331
- // Example: **MyStruct -> $.VarRef<MyStruct | null> | null (recursive call handles inner part)
332
- c.tsw.WriteLiterally("$.VarRef<")
333
- c.WriteGoType(elemGoType, context) // Translate element type, pass context
334
- c.tsw.WriteLiterally("> | null") // Pointers are always nullable
335
- }
336
- }
337
-
338
- // WriteSliceType translates a Go slice type ([]T) to its TypeScript equivalent.
339
- // It generates $.Slice<T_ts>, where T_ts is the translated element type.
340
- // For []byte, it generates Uint8Array.
341
- func (c *GoToTSCompiler) WriteSliceType(t *types.Slice) {
342
- // Check if it's a []byte slice
343
- if c.isByteSliceType(t) {
344
- c.tsw.WriteLiterally("$.Bytes")
345
- return
346
- }
347
- c.tsw.WriteLiterally("$.Slice<")
348
- c.WriteGoType(t.Elem(), GoTypeContextGeneral)
349
- c.tsw.WriteLiterally(">")
350
- }
351
-
352
- // WriteArrayType translates a Go array type ([N]T) to its TypeScript equivalent.
353
- // It generates T_ts[], where T_ts is the translated element type.
354
- func (c *GoToTSCompiler) WriteArrayType(t *types.Array) {
355
- c.WriteGoType(t.Elem(), GoTypeContextGeneral)
356
- c.tsw.WriteLiterally("[]") // Arrays cannot be nil
357
- }
358
-
359
- // WriteMapType translates a Go map type (map[K]V) to its TypeScript equivalent.
360
- // It generates Map<K_ts, V_ts> | null, where K_ts and V_ts are the translated key
361
- // and element types respectively.
362
- // Maps are nilable in Go, so they are represented as nullable types in TypeScript.
363
- func (c *GoToTSCompiler) WriteMapType(t *types.Map) {
364
- c.tsw.WriteLiterally("Map<")
365
- c.WriteGoType(t.Key(), GoTypeContextGeneral)
366
- c.tsw.WriteLiterally(", ")
367
- c.WriteGoType(t.Elem(), GoTypeContextGeneral)
368
- c.tsw.WriteLiterally("> | null")
369
- }
370
-
371
- // WriteChannelType translates a Go channel type (chan T) to its TypeScript equivalent.
372
- // It generates $.Channel<T_ts> | null, where T_ts is the translated element type.
373
- // Channels are nilable in Go, so they are represented as nullable types in TypeScript.
374
- func (c *GoToTSCompiler) WriteChannelType(t *types.Chan) {
375
- c.tsw.WriteLiterally("$.Channel<")
376
- c.WriteGoType(t.Elem(), GoTypeContextGeneral)
377
- c.tsw.WriteLiterally("> | null")
378
- }
379
-
380
- // WriteFuncType translates a Go function type (`ast.FuncType`) into a TypeScript
381
- // function signature.
382
- // The signature is of the form `(param1: type1, param2: type2) => returnType`.
383
- // - Parameters are written using `WriteFieldList`.
384
- // - Return types:
385
- // - If there are no results, the return type is `void`.
386
- // - If there's a single, unnamed result, it's `resultType`.
387
- // - If there are multiple or named results, it's a tuple type `[typeA, typeB]`.
388
- // - If `isAsync` is true (indicating the function is known to perform async
389
- // operations like channel interactions or contains `go` or `defer` with async calls),
390
- // the return type is wrapped in `Promise<>` (e.g., `Promise<void>`, `Promise<number>`).
391
- func (c *GoToTSCompiler) WriteFuncType(exp *ast.FuncType, isAsync bool) {
392
- c.tsw.WriteLiterally("(")
393
- c.WriteFieldList(exp.Params, true) // true = arguments
394
- c.tsw.WriteLiterally(")")
395
- if exp.Results != nil && len(exp.Results.List) > 0 {
396
- // Use colon for return type annotation
397
- c.tsw.WriteLiterally(": ")
398
- if isAsync {
399
- c.tsw.WriteLiterally("Promise<")
400
- }
401
-
402
- // Count total number of return values (each field may have multiple names like "a, b int")
403
- totalResults := 0
404
- for _, field := range exp.Results.List {
405
- count := len(field.Names)
406
- if count == 0 {
407
- count = 1 // Unnamed return value
408
- }
409
- totalResults += count
410
- }
411
-
412
- if totalResults == 1 {
413
- // Single return type (named or unnamed)
414
- // Use WriteTypeExpr to preserve qualified names like os.FileInfo
415
- c.WriteTypeExpr(exp.Results.List[0].Type)
416
- } else {
417
- // Multiple return types -> tuple
418
- c.tsw.WriteLiterally("[")
419
- first := true
420
- for _, field := range exp.Results.List {
421
- // Each field may represent multiple return values (e.g., "a, b int")
422
- count := len(field.Names)
423
- if count == 0 {
424
- count = 1 // Unnamed return value
425
- }
426
- for j := 0; j < count; j++ {
427
- if !first {
428
- c.tsw.WriteLiterally(", ")
429
- }
430
- first = false
431
- // Use WriteTypeExpr to preserve qualified names like os.FileInfo
432
- c.WriteTypeExpr(field.Type)
433
- }
434
- }
435
- c.tsw.WriteLiterally("]")
436
- }
437
- if isAsync {
438
- c.tsw.WriteLiterally(">")
439
- }
440
- } else {
441
- // No return value -> void
442
- if isAsync {
443
- c.tsw.WriteLiterally(": Promise<void>")
444
- } else {
445
- c.tsw.WriteLiterally(": void")
446
- }
447
- }
448
- }
449
-
450
- // WriteFuncTypeAsArrow writes a function type using arrow function syntax.
451
- // This is used for type annotations where we need (params) => ReturnType format
452
- // instead of function(params): ReturnType format.
453
- // Example: (name: string, age: number) => boolean
454
- //
455
- // This helper does not perform any async detection and never wraps the
456
- // return type in Promise<>. The generated arrow function type reflects the
457
- // Go function's translated result types directly.
458
- func (c *GoToTSCompiler) WriteFuncTypeAsArrow(exp *ast.FuncType) {
459
- c.tsw.WriteLiterally("(")
460
- c.WriteFieldList(exp.Params, true) // true = arguments
461
- c.tsw.WriteLiterally(")")
462
- c.tsw.WriteLiterally(" => ")
463
-
464
- if exp.Results != nil && len(exp.Results.List) > 0 {
465
- // Count total number of return values
466
- totalResults := 0
467
- for _, field := range exp.Results.List {
468
- count := len(field.Names)
469
- if count == 0 {
470
- count = 1
471
- }
472
- totalResults += count
473
- }
474
-
475
- if totalResults == 1 {
476
- c.WriteTypeExpr(exp.Results.List[0].Type)
477
- } else {
478
- // Multiple return types -> tuple
479
- c.tsw.WriteLiterally("[")
480
- first := true
481
- for _, field := range exp.Results.List {
482
- count := len(field.Names)
483
- if count == 0 {
484
- count = 1
485
- }
486
- for j := 0; j < count; j++ {
487
- if !first {
488
- c.tsw.WriteLiterally(", ")
489
- }
490
- first = false
491
- c.WriteTypeExpr(field.Type)
492
- }
493
- }
494
- c.tsw.WriteLiterally("]")
495
- }
496
- } else {
497
- c.tsw.WriteLiterally("void")
498
- }
499
- }
500
-
501
- // WriteInterfaceType translates a Go interface type to its TypeScript equivalent.
502
- // It specially handles the error interface as $.GoError, and delegates to
503
- // writeInterfaceStructure for other interface types, prepending "null | ".
504
- // If astNode is provided (e.g., from a type spec), comments for methods will be included.
505
- func (c *GoToTSCompiler) WriteInterfaceType(t *types.Interface, astNode *ast.InterfaceType) {
506
- // Handle the built-in error interface specifically
507
- if t.String() == "interface{Error() string}" {
508
- c.tsw.WriteLiterally("$.GoError")
509
- return
510
- }
511
-
512
- // Prepend "null | " for all other interfaces.
513
- // writeInterfaceStructure will handle the actual structure like "{...}" or "any".
514
- c.tsw.WriteLiterally("null | ")
515
- c.writeInterfaceStructure(t, astNode)
516
- }
517
-
518
- // WriteSignatureType translates a Go function signature to its TypeScript equivalent.
519
- // It generates (param1: type1, param2: type2, ...): returnType for function types.
520
- // The context parameter determines whether to add | null suffix:
521
- // - GoTypeContextGeneral: Add | null (function values can be nil in Go)
522
- // - GoTypeContextFunctionReturn: Add | null (function return values can be nil)
523
- // - Other contexts (like type arguments): Don't add | null
524
- func (c *GoToTSCompiler) WriteSignatureType(t *types.Signature, context GoTypeContext) {
525
- c.tsw.WriteLiterally("(")
526
- c.tsw.WriteLiterally("(")
527
- params := t.Params()
528
- for i := 0; i < params.Len(); i++ {
529
- if i > 0 {
530
- c.tsw.WriteLiterally(", ")
531
- }
532
-
533
- param := params.At(i)
534
- paramSlice, paramIsSlice := param.Type().(*types.Slice)
535
-
536
- paramVariadic := i == params.Len()-1 && t.Variadic()
537
- if paramVariadic {
538
- c.tsw.WriteLiterally("...")
539
- }
540
-
541
- // Use parameter name if available, otherwise use p0, p1, etc.
542
- if param.Name() != "" {
543
- c.tsw.WriteLiterally(c.sanitizeIdentifier(param.Name()))
544
- } else {
545
- c.tsw.WriteLiterallyf("p%d", i)
546
- }
547
- c.tsw.WriteLiterally(": ")
548
-
549
- if paramVariadic && paramIsSlice {
550
- c.WriteGoType(paramSlice.Elem(), GoTypeContextGeneral)
551
- c.tsw.WriteLiterally("[]")
552
- } else {
553
- c.WriteGoType(param.Type(), GoTypeContextGeneral)
554
- }
555
- }
556
- c.tsw.WriteLiterally(")")
557
-
558
- // Handle return types
559
- c.tsw.WriteLiterally(" => ")
560
- results := t.Results()
561
- if results.Len() == 0 {
562
- c.tsw.WriteLiterally("void")
563
- } else if results.Len() == 1 {
564
- c.WriteGoType(results.At(0).Type(), GoTypeContextFunctionReturn)
565
- } else {
566
- // Multiple return values -> tuple
567
- c.tsw.WriteLiterally("[")
568
- for i := 0; i < results.Len(); i++ {
569
- if i > 0 {
570
- c.tsw.WriteLiterally(", ")
571
- }
572
- c.WriteGoType(results.At(i).Type(), GoTypeContextFunctionReturn)
573
- }
574
- c.tsw.WriteLiterally("]")
575
- }
576
- c.tsw.WriteLiterally(")")
577
-
578
- // In Go, function values (not pointers to functions) can be nil.
579
- // Add | null for general contexts and function return contexts.
580
- // Don't add | null for other contexts like type arguments to avoid
581
- // issues with generic types like atomic.Pointer[func()].
582
- if context == GoTypeContextGeneral || context == GoTypeContextFunctionReturn {
583
- c.tsw.WriteLiterally(" | null")
584
- }
585
- }
586
-
587
- // writeInterfaceStructure translates a Go `types.Interface` into its TypeScript structural representation.
588
- // If astNode is provided, it's used to fetch comments for methods.
589
- // For example, an interface `interface { MethodA(x int) string; EmbeddedB }` might become
590
- // `{ MethodA(_p0: number): string; } & B_ts`.
591
- func (c *GoToTSCompiler) writeInterfaceStructure(iface *types.Interface, astNode *ast.InterfaceType) {
592
- // Handle empty interface interface{}
593
- if iface.NumExplicitMethods() == 0 && iface.NumEmbeddeds() == 0 {
594
- c.tsw.WriteLiterally("any") // Matches current behavior for interface{}
595
- return
596
- }
597
-
598
- // Keep track if we've written any part (methods or first embedded type)
599
- // to correctly place " & " separators.
600
- firstPartWritten := false
601
-
602
- // Handle explicit methods
603
- if iface.NumExplicitMethods() > 0 {
604
- c.tsw.WriteLiterally("{") // Opening brace for the object type
605
- c.tsw.Indent(1)
606
- c.tsw.WriteLine("") // Newline after opening brace, before the first method
607
-
608
- for method := range iface.ExplicitMethods() {
609
- sig := method.Type().(*types.Signature)
610
-
611
- // Find corresponding ast.Field for comments if astNode is available
612
- var astField *ast.Field
613
- if astNode != nil && astNode.Methods != nil {
614
- for _, f := range astNode.Methods.List {
615
- // Ensure the field is a named method (not an embedded interface)
616
- if len(f.Names) > 0 && f.Names[0].Name == method.Name() {
617
- astField = f
618
- break
619
- }
620
- }
621
- }
622
-
623
- // Write comments if astField is found
624
- if astField != nil {
625
- if astField.Doc != nil {
626
- c.WriteDoc(astField.Doc) // WriteDoc handles newlines
627
- }
628
- if astField.Comment != nil { // For trailing comments on the same line in Go AST
629
- c.WriteDoc(astField.Comment)
630
- }
631
- }
632
-
633
- c.tsw.WriteLiterally(method.Name())
634
- c.tsw.WriteLiterally("(") // Start params
635
- params := sig.Params()
636
-
637
- // Check if this is a variadic method
638
- isVariadic := sig.Variadic()
639
-
640
- // Handle regular parameters (all parameters if not variadic, or all but last if variadic)
641
- paramCount := params.Len()
642
- if isVariadic && paramCount > 0 {
643
- paramCount-- // Don't process the last parameter in the regular loop for variadic functions
644
- }
645
-
646
- for j := 0; j < paramCount; j++ {
647
- if j > 0 {
648
- c.tsw.WriteLiterally(", ")
649
- }
650
- paramVar := params.At(j)
651
- paramName := paramVar.Name()
652
- if paramName == "" || paramName == "_" {
653
- paramName = fmt.Sprintf("_p%d", j)
654
- }
655
- c.tsw.WriteLiterally(c.sanitizeIdentifier(paramName))
656
- c.tsw.WriteLiterally(": ")
657
- c.WriteGoType(paramVar.Type(), GoTypeContextGeneral) // Recursive call for param type
658
- }
659
-
660
- // Handle variadic parameter if present
661
- if isVariadic && params.Len() > 0 {
662
- if paramCount > 0 { // Add comma if there were regular parameters
663
- c.tsw.WriteLiterally(", ")
664
- }
665
-
666
- // Get the last parameter (the variadic one)
667
- paramVar := params.At(params.Len() - 1)
668
- paramName := paramVar.Name()
669
- if paramName == "" || paramName == "_" {
670
- paramName = fmt.Sprintf("_p%d", params.Len()-1)
671
- }
672
-
673
- // Write variadic parameter with ... prefix
674
- c.tsw.WriteLiterally("...")
675
- c.tsw.WriteLiterally(c.sanitizeIdentifier(paramName))
676
- c.tsw.WriteLiterally(": ")
677
-
678
- // For variadic parameters, the type is a slice, so we need the element type + []
679
- if sliceType, ok := paramVar.Type().(*types.Slice); ok {
680
- c.WriteGoType(sliceType.Elem(), GoTypeContextVariadicParam) // Use variadic context to avoid null prefix
681
- c.tsw.WriteLiterally("[]")
682
- } else {
683
- // Fallback if it's not a slice type (shouldn't happen for valid variadic parameters)
684
- c.WriteGoType(paramVar.Type(), GoTypeContextGeneral)
685
- }
686
- }
687
-
688
- c.tsw.WriteLiterally(")") // End params
689
-
690
- // Return type
691
- c.tsw.WriteLiterally(": ")
692
- results := sig.Results()
693
-
694
- // Determine if this interface method should be async based on implementations
695
- isMethodAsync := c.analysis.IsInterfaceMethodAsync(iface, method.Name())
696
-
697
- if isMethodAsync {
698
- c.tsw.WriteLiterally("Promise<")
699
- }
700
-
701
- if results.Len() == 0 {
702
- c.tsw.WriteLiterally("void")
703
- } else if results.Len() == 1 {
704
- // Try to use AST information if available to preserve qualified names
705
- if astField != nil && astField.Type != nil {
706
- if funcType, ok := astField.Type.(*ast.FuncType); ok && funcType.Results != nil && len(funcType.Results.List) == 1 {
707
- c.WriteTypeExpr(funcType.Results.List[0].Type)
708
- } else {
709
- c.WriteGoType(results.At(0).Type(), GoTypeContextFunctionReturn) // Fallback
710
- }
711
- } else {
712
- c.WriteGoType(results.At(0).Type(), GoTypeContextFunctionReturn) // Fallback
713
- }
714
- } else {
715
- c.tsw.WriteLiterally("[")
716
- for j := 0; j < results.Len(); j++ {
717
- if j > 0 {
718
- c.tsw.WriteLiterally(", ")
719
- }
720
- // Try to use AST information if available to preserve qualified names
721
- if astField != nil && astField.Type != nil {
722
- if funcType, ok := astField.Type.(*ast.FuncType); ok && funcType.Results != nil && j < len(funcType.Results.List) {
723
- c.WriteTypeExpr(funcType.Results.List[j].Type)
724
- } else {
725
- c.WriteGoType(results.At(j).Type(), GoTypeContextFunctionReturn) // Fallback
726
- }
727
- } else {
728
- c.WriteGoType(results.At(j).Type(), GoTypeContextFunctionReturn) // Fallback
729
- }
730
- }
731
- c.tsw.WriteLiterally("]")
732
- }
733
-
734
- if isMethodAsync {
735
- c.tsw.WriteLiterally(">")
736
- }
737
-
738
- c.tsw.WriteLine("") // newline for each method
739
- }
740
- c.tsw.Indent(-1)
741
- c.tsw.WriteLiterally("}") // Closing brace for the object type
742
- firstPartWritten = true
743
- }
744
-
745
- // Handle embedded types
746
- if iface.NumEmbeddeds() > 0 {
747
- for etyp := range iface.EmbeddedTypes() {
748
- if firstPartWritten {
749
- c.tsw.WriteLiterally(" & ")
750
- } else {
751
- // This is the first part being written (no explicit methods, only embedded)
752
- firstPartWritten = true
753
- }
754
- embeddedType := etyp
755
- // When WriteGoType encounters an interface, it will call WriteInterfaceType
756
- // which will pass nil for astNode, so comments for deeply embedded interface literals
757
- // might not be available unless they are named types.
758
- c.WriteGoType(embeddedType, GoTypeContextGeneral)
759
- }
760
- }
761
- }
762
-
763
- // getTypeString is a utility function that converts a Go `types.Type` into its
764
- // TypeScript type string representation. It achieves this by creating a temporary
765
- // `GoToTSCompiler` and `TSCodeWriter` (writing to a `strings.Builder`) and then
766
- // calling `WriteGoType` on the provided Go type. This allows reusing the main
767
- // type translation logic to get a string representation of the TypeScript type.
768
- func (c *GoToTSCompiler) getTypeString(goType types.Type) string {
769
- var typeStr strings.Builder
770
- writer := NewTSCodeWriter(&typeStr)
771
- tempCompiler := NewGoToTSCompiler(writer, c.pkg, c.analysis, c.currentFilePath)
772
- tempCompiler.WriteGoType(goType, GoTypeContextGeneral)
773
- return typeStr.String()
774
- }
775
-
776
- // getASTTypeString is a utility function that converts a Go type to its TypeScript
777
- // type string representation, preferring AST-based type writing when available to
778
- // preserve qualified names like os.FileMode. Falls back to types.Type-based writing
779
- // when AST information is not available.
780
- func (c *GoToTSCompiler) getASTTypeString(astType ast.Expr, goType types.Type) string {
781
- var typeStr strings.Builder
782
- writer := NewTSCodeWriter(&typeStr)
783
- tempCompiler := NewGoToTSCompiler(writer, c.pkg, c.analysis, c.currentFilePath)
784
-
785
- if astType != nil {
786
- // Use AST-based type writing to preserve qualified names
787
- tempCompiler.WriteTypeExpr(astType)
788
- } else {
789
- // Fall back to types.Type-based writing
790
- tempCompiler.WriteGoType(goType, GoTypeContextGeneral)
791
- }
792
- return typeStr.String()
793
- }
794
-
795
- // WriteStructType translates a Go struct type definition (`ast.StructType`)
796
- // into a TypeScript anonymous object type (e.g., `{ Field1: Type1; Field2: Type2 }`).
797
- // If the struct has no fields, it writes `{}`. Otherwise, it delegates to
798
- // `WriteFieldList` to generate the list of field definitions.
799
- // Note: This is for anonymous struct type literals. Named struct types are usually
800
- // handled as classes via `WriteTypeSpec`.
801
- func (c *GoToTSCompiler) WriteStructType(t *types.Struct) {
802
- // Generate an interface with the struct's fields
803
- c.tsw.WriteLiterally("{ ")
804
- // Add field properties to the interface
805
- for i := range t.NumFields() {
806
- field := t.Field(i)
807
- if i > 0 {
808
- c.tsw.WriteLiterally("; ")
809
- }
810
- c.tsw.WriteLiterally(field.Name() + "?: ")
811
- c.WriteGoType(field.Type(), GoTypeContextGeneral)
812
- }
813
- c.tsw.WriteLiterally(" }")
814
- }
815
-
816
- // WriteTypeParameters translates Go type parameters to TypeScript generic parameters.
817
- // It handles the TypeParams field of ast.FuncDecl and ast.TypeSpec to generate
818
- // TypeScript generic parameter lists like <T extends SomeConstraint, U extends OtherConstraint>.
819
- func (c *GoToTSCompiler) WriteTypeParameters(typeParams *ast.FieldList) {
820
- if typeParams == nil || len(typeParams.List) == 0 {
821
- return
822
- }
823
-
824
- c.tsw.WriteLiterally("<")
825
- for i, field := range typeParams.List {
826
- if i > 0 {
827
- c.tsw.WriteLiterally(", ")
828
- }
829
- // Write each type parameter name and constraint
830
- for j, name := range field.Names {
831
- if j > 0 {
832
- c.tsw.WriteLiterally(", ")
833
- }
834
- // Use sanitizeIdentifier to handle conflicts with TypeScript built-in types
835
- c.tsw.WriteLiterally(c.sanitizeIdentifier(name.Name))
836
-
837
- // Write constraint if present
838
- if field.Type != nil {
839
- c.tsw.WriteLiterally(" extends ")
840
- c.WriteTypeConstraint(field.Type)
841
- }
842
- }
843
- }
844
- c.tsw.WriteLiterally(">")
845
- }
846
-
847
- // WriteTypeConstraint translates Go type constraints to TypeScript constraint expressions.
848
- // It handles different constraint types including:
849
- // - Union types: []byte | string -> string | Uint8Array
850
- // - Interface types: interface{Method()} -> {Method(): void}
851
- // - Basic types: any -> any, comparable -> $.Comparable
852
- func (c *GoToTSCompiler) WriteTypeConstraint(constraint ast.Expr) {
853
- switch t := constraint.(type) {
854
- case *ast.Ident:
855
- // Handle predeclared constraints
856
- switch t.Name {
857
- case "any":
858
- c.tsw.WriteLiterally("any")
859
- case "comparable":
860
- c.tsw.WriteLiterally("$.Comparable")
861
- default:
862
- // Use the type directly
863
- c.WriteTypeExpr(t)
864
- }
865
- case *ast.BinaryExpr:
866
- // Handle union types like []byte | string
867
- if t.Op == token.OR {
868
- c.WriteTypeConstraint(t.X)
869
- c.tsw.WriteLiterally(" | ")
870
- c.WriteTypeConstraint(t.Y)
871
- } else {
872
- // Fallback for other binary expressions
873
- c.WriteTypeExpr(constraint)
874
- }
875
- case *ast.InterfaceType:
876
- // Handle interface constraints
877
- c.WriteTypeExpr(constraint)
878
- case *ast.ArrayType:
879
- // Handle []byte specifically
880
- if ident, ok := t.Elt.(*ast.Ident); ok && ident.Name == "byte" {
881
- c.tsw.WriteLiterally("$.Bytes")
882
- } else {
883
- c.WriteTypeExpr(constraint)
884
- }
885
- case *ast.SliceExpr:
886
- // Handle slice types in constraints
887
- c.WriteTypeExpr(constraint)
888
- default:
889
- // Fallback: use the standard type expression writer
890
- c.WriteTypeExpr(constraint)
891
- }
892
- }