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.
- package/README.md +13 -1
- package/cmd/goscript/cmd_compile.go +70 -69
- package/cmd/goscript/cmd_compile_test.go +79 -0
- package/cmd/goscript/main.go +10 -5
- package/compiler/compile-request.go +218 -0
- package/compiler/compiler.go +16 -1336
- package/compiler/compliance_test.go +196 -0
- package/compiler/config.go +6 -13
- package/compiler/diagnostic.go +70 -0
- package/compiler/index.test.ts +28 -28
- package/compiler/index.ts +40 -72
- package/compiler/lowered-program.go +132 -0
- package/compiler/lowering.go +3576 -0
- package/compiler/override-registry.go +422 -0
- package/compiler/override-registry_test.go +207 -0
- package/compiler/package-graph.go +231 -0
- package/compiler/package-graph_test.go +281 -0
- package/compiler/result.go +13 -0
- package/compiler/runtime-contract.go +279 -0
- package/compiler/runtime-contract_test.go +90 -0
- package/compiler/semantic-model-types.go +110 -0
- package/compiler/semantic-model.go +922 -0
- package/compiler/semantic-model_test.go +416 -0
- package/compiler/service.go +133 -0
- package/compiler/skeleton_test.go +1145 -0
- package/compiler/typescript-emitter.go +663 -0
- package/compiler/wasm/compile.go +2 -3
- package/compiler/wasm/compile_test.go +29 -0
- package/compiler/wasm_api.go +10 -159
- package/dist/compiler/index.d.ts +1 -3
- package/dist/compiler/index.js +31 -55
- package/dist/compiler/index.js.map +1 -1
- package/dist/gs/builtin/builtin.d.ts +13 -0
- package/dist/gs/builtin/builtin.js +27 -7
- package/dist/gs/builtin/builtin.js.map +1 -1
- package/dist/gs/builtin/channel.d.ts +3 -3
- package/dist/gs/builtin/channel.js.map +1 -1
- package/dist/gs/builtin/hostio.d.ts +86 -0
- package/dist/gs/builtin/hostio.js +266 -0
- package/dist/gs/builtin/hostio.js.map +1 -0
- package/dist/gs/builtin/index.d.ts +1 -0
- package/dist/gs/builtin/index.js +1 -0
- package/dist/gs/builtin/index.js.map +1 -1
- package/dist/gs/builtin/print.d.ts +8 -0
- package/dist/gs/builtin/print.js +111 -0
- package/dist/gs/builtin/print.js.map +1 -0
- package/dist/gs/builtin/slice.d.ts +1 -1
- package/dist/gs/builtin/slice.js.map +1 -1
- package/dist/gs/builtin/type.d.ts +11 -0
- package/dist/gs/builtin/type.js +55 -1
- package/dist/gs/builtin/type.js.map +1 -1
- package/dist/gs/bytes/buffer.gs.js.map +1 -1
- package/dist/gs/bytes/bytes.gs.js.map +1 -1
- package/dist/gs/bytes/reader.gs.js.map +1 -1
- package/dist/gs/context/context.js.map +1 -1
- package/dist/gs/crypto/rand/index.d.ts +5 -0
- package/dist/gs/crypto/rand/index.js +77 -0
- package/dist/gs/crypto/rand/index.js.map +1 -0
- package/dist/gs/encoding/json/index.d.ts +3 -0
- package/dist/gs/encoding/json/index.js +160 -0
- package/dist/gs/encoding/json/index.js.map +1 -0
- package/dist/gs/fmt/fmt.js +2 -22
- package/dist/gs/fmt/fmt.js.map +1 -1
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.d.ts +1 -1
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js +1 -1
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js.map +1 -1
- package/dist/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/browser.js.map +1 -1
- package/dist/gs/github.com/pkg/errors/errors.js.map +1 -1
- package/dist/gs/github.com/pkg/errors/stack.js.map +1 -1
- package/dist/gs/go/scanner/index.d.ts +29 -0
- package/dist/gs/go/scanner/index.js +120 -0
- package/dist/gs/go/scanner/index.js.map +1 -0
- package/dist/gs/go/token/index.d.ts +31 -0
- package/dist/gs/go/token/index.js +82 -0
- package/dist/gs/go/token/index.js.map +1 -0
- package/dist/gs/internal/abi/index.js.map +1 -1
- package/dist/gs/io/fs/fs.js.map +1 -1
- package/dist/gs/io/fs/readdir.js.map +1 -1
- package/dist/gs/io/fs/readfile.js.map +1 -1
- package/dist/gs/io/fs/stat.js.map +1 -1
- package/dist/gs/io/fs/sub.js.map +1 -1
- package/dist/gs/io/io.js.map +1 -1
- package/dist/gs/os/dir_unix.gs.js.map +1 -1
- package/dist/gs/os/error.gs.js +2 -4
- package/dist/gs/os/error.gs.js.map +1 -1
- package/dist/gs/os/exec.gs.js.map +1 -1
- package/dist/gs/os/exec_posix.gs.js.map +1 -1
- package/dist/gs/os/rawconn_js.gs.js.map +1 -1
- package/dist/gs/os/root_js.gs.js.map +1 -1
- package/dist/gs/os/tempfile.gs.js +66 -9
- package/dist/gs/os/tempfile.gs.js.map +1 -1
- package/dist/gs/os/types.gs.js.map +1 -1
- package/dist/gs/os/types_js.gs.d.ts +2 -51
- package/dist/gs/os/types_js.gs.js +67 -105
- package/dist/gs/os/types_js.gs.js.map +1 -1
- package/dist/gs/os/types_unix.gs.js.map +1 -1
- package/dist/gs/path/filepath/match.js.map +1 -1
- package/dist/gs/path/match.js.map +1 -1
- package/dist/gs/path/path.js.map +1 -1
- package/dist/gs/reflect/index.d.ts +2 -2
- package/dist/gs/reflect/index.js +1 -1
- package/dist/gs/reflect/index.js.map +1 -1
- package/dist/gs/reflect/map.js.map +1 -1
- package/dist/gs/reflect/type.d.ts +2 -1
- package/dist/gs/reflect/type.js +85 -14
- package/dist/gs/reflect/type.js.map +1 -1
- package/dist/gs/reflect/types.js.map +1 -1
- package/dist/gs/reflect/visiblefields.js.map +1 -1
- package/dist/gs/runtime/runtime.js.map +1 -1
- package/dist/gs/sort/sort.gs.js.map +1 -1
- package/dist/gs/strconv/atoi.gs.js.map +1 -1
- package/dist/gs/strconv/quote.gs.js.map +1 -1
- package/dist/gs/strings/builder.js.map +1 -1
- package/dist/gs/strings/reader.js.map +1 -1
- package/dist/gs/strings/replace.js.map +1 -1
- package/dist/gs/sync/atomic/type.gs.js.map +1 -1
- package/dist/gs/sync/atomic/value.gs.js.map +1 -1
- package/dist/gs/sync/sync.d.ts +1 -0
- package/dist/gs/sync/sync.js +12 -0
- package/dist/gs/sync/sync.js.map +1 -1
- package/dist/gs/time/time.js.map +1 -1
- package/dist/gs/unicode/unicode.js.map +1 -1
- package/go.mod +2 -2
- package/gs/builtin/builtin.ts +31 -6
- package/gs/builtin/hostio.test.ts +246 -0
- package/gs/builtin/hostio.ts +413 -0
- package/gs/builtin/index.ts +1 -0
- package/gs/builtin/print.test.ts +48 -0
- package/gs/builtin/print.ts +154 -0
- package/gs/builtin/runtime-contract.test.ts +230 -0
- package/gs/builtin/type.ts +84 -1
- package/gs/crypto/rand/index.test.ts +32 -0
- package/gs/crypto/rand/index.ts +90 -0
- package/gs/crypto/rand/meta.json +5 -0
- package/gs/encoding/json/index.test.ts +65 -0
- package/gs/encoding/json/index.ts +186 -0
- package/gs/fmt/fmt.test.ts +41 -30
- package/gs/fmt/fmt.ts +2 -22
- package/gs/github.com/aperturerobotics/protobuf-go-lite/index.test.ts +23 -0
- package/gs/github.com/aperturerobotics/protobuf-go-lite/index.ts +3 -1
- package/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/meta.json +3 -1
- package/gs/go/scanner/index.test.ts +50 -0
- package/gs/go/scanner/index.ts +157 -0
- package/gs/go/token/index.test.ts +21 -0
- package/gs/go/token/index.ts +120 -0
- package/gs/os/file_unix_js.test.ts +103 -0
- package/gs/os/meta.json +1 -2
- package/gs/os/tempfile.gs.test.ts +85 -0
- package/gs/os/tempfile.gs.ts +71 -11
- package/gs/os/types_js.gs.ts +74 -153
- package/gs/reflect/index.ts +1 -1
- package/gs/reflect/type.ts +106 -17
- package/gs/reflect/typefor.test.ts +75 -0
- package/gs/sync/sync.test.ts +24 -0
- package/gs/sync/sync.ts +12 -0
- package/package.json +13 -13
- package/compiler/analysis.go +0 -3475
- package/compiler/analysis_test.go +0 -338
- package/compiler/assignment.go +0 -580
- package/compiler/builtin_test.go +0 -92
- package/compiler/code-writer.go +0 -115
- package/compiler/compiler_test.go +0 -149
- package/compiler/composite-lit.go +0 -779
- package/compiler/config_test.go +0 -62
- package/compiler/constraint.go +0 -86
- package/compiler/decl.go +0 -801
- package/compiler/expr-call-async.go +0 -188
- package/compiler/expr-call-builtins.go +0 -208
- package/compiler/expr-call-helpers.go +0 -382
- package/compiler/expr-call-make.go +0 -318
- package/compiler/expr-call-type-conversion.go +0 -520
- package/compiler/expr-call.go +0 -413
- package/compiler/expr-selector.go +0 -343
- package/compiler/expr-star.go +0 -82
- package/compiler/expr-type.go +0 -442
- package/compiler/expr-value.go +0 -89
- package/compiler/expr.go +0 -773
- package/compiler/field.go +0 -183
- package/compiler/gs_dependencies_test.go +0 -298
- package/compiler/lit.go +0 -322
- package/compiler/output.go +0 -72
- package/compiler/primitive.go +0 -149
- package/compiler/protobuf.go +0 -697
- package/compiler/sanitize.go +0 -100
- package/compiler/spec-struct.go +0 -995
- package/compiler/spec-value.go +0 -540
- package/compiler/spec.go +0 -725
- package/compiler/stmt-assign.go +0 -664
- package/compiler/stmt-for.go +0 -266
- package/compiler/stmt-range.go +0 -475
- package/compiler/stmt-select.go +0 -262
- package/compiler/stmt-type-switch.go +0 -147
- package/compiler/stmt.go +0 -1308
- package/compiler/type-assert.go +0 -386
- package/compiler/type-info.go +0 -156
- package/compiler/type-utils.go +0 -207
- 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
|
-
}
|