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/spec-struct.go
DELETED
|
@@ -1,995 +0,0 @@
|
|
|
1
|
-
package compiler
|
|
2
|
-
|
|
3
|
-
import (
|
|
4
|
-
"fmt"
|
|
5
|
-
"go/ast"
|
|
6
|
-
"go/types"
|
|
7
|
-
"maps"
|
|
8
|
-
"slices"
|
|
9
|
-
"strings"
|
|
10
|
-
)
|
|
11
|
-
|
|
12
|
-
// WriteStructTypeSpec generates the TypeScript class definition for a Go struct type.
|
|
13
|
-
// It handles the generation of:
|
|
14
|
-
// - The class declaration.
|
|
15
|
-
// - Getters and setters for all fields (both direct and embedded).
|
|
16
|
-
// - The internal `_fields` property, which stores field values in `$.VarRef` containers
|
|
17
|
-
// to maintain Go's value semantics.
|
|
18
|
-
// - A constructor that initializes the `_fields` and allows partial initialization.
|
|
19
|
-
// - A `clone` method for creating a deep copy of the struct instance.
|
|
20
|
-
// - Methods defined directly on the struct.
|
|
21
|
-
// - Wrapper methods for promoted fields and methods from embedded structs,
|
|
22
|
-
// ensuring correct access and behavior.
|
|
23
|
-
func (c *GoToTSCompiler) WriteStructTypeSpec(a *ast.TypeSpec, t *ast.StructType) error {
|
|
24
|
-
isInsideFunction := false
|
|
25
|
-
if nodeInfo := c.analysis.NodeData[a]; nodeInfo != nil {
|
|
26
|
-
isInsideFunction = nodeInfo.IsInsideFunction
|
|
27
|
-
}
|
|
28
|
-
if !isInsideFunction {
|
|
29
|
-
c.tsw.WriteLiterally("export ")
|
|
30
|
-
}
|
|
31
|
-
c.tsw.WriteLiterally("class ")
|
|
32
|
-
if err := c.WriteValueExpr(a.Name); err != nil {
|
|
33
|
-
return err
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// Write type parameters if present (for generics)
|
|
37
|
-
if a.TypeParams != nil {
|
|
38
|
-
c.WriteTypeParameters(a.TypeParams)
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
c.tsw.WriteLiterally(" ")
|
|
42
|
-
c.tsw.WriteLine("{")
|
|
43
|
-
c.tsw.Indent(1)
|
|
44
|
-
|
|
45
|
-
className := sanitizeIdentifier(a.Name.Name)
|
|
46
|
-
|
|
47
|
-
goStructType, ok := c.pkg.TypesInfo.Defs[a.Name].Type().(*types.Named)
|
|
48
|
-
if !ok {
|
|
49
|
-
return fmt.Errorf("could not get named type for %s", a.Name.Name)
|
|
50
|
-
}
|
|
51
|
-
underlyingStruct, ok := goStructType.Underlying().(*types.Struct)
|
|
52
|
-
if !ok {
|
|
53
|
-
return fmt.Errorf("underlying type of %s is not a struct", a.Name.Name)
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// Generate getters and setters for each non-embedded field first
|
|
57
|
-
for _, field := range t.Fields.List {
|
|
58
|
-
if len(field.Names) == 0 { // Skip anonymous/embedded fields here; they are handled below or via promotion
|
|
59
|
-
continue
|
|
60
|
-
}
|
|
61
|
-
for _, name := range field.Names {
|
|
62
|
-
fieldName := name.Name
|
|
63
|
-
// Skip underscore fields
|
|
64
|
-
if fieldName == "_" {
|
|
65
|
-
continue
|
|
66
|
-
}
|
|
67
|
-
fieldType := c.pkg.TypesInfo.TypeOf(field.Type)
|
|
68
|
-
if fieldType == nil {
|
|
69
|
-
fieldType = types.Typ[types.Invalid]
|
|
70
|
-
}
|
|
71
|
-
c.writeGetterSetter(fieldName, fieldType, field.Doc, field.Comment, field.Type)
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// Generate getters and setters for EMBEDDED struct fields themselves
|
|
76
|
-
for field := range underlyingStruct.Fields() {
|
|
77
|
-
if field.Anonymous() {
|
|
78
|
-
fieldKeyName := c.getEmbeddedFieldKeyName(field.Type())
|
|
79
|
-
c.writeGetterSetter(fieldKeyName, field.Type(), nil, nil, nil)
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// Create a mapping from field names to AST types for preserving qualified names
|
|
84
|
-
fieldASTTypes := make(map[string]ast.Expr)
|
|
85
|
-
for _, field := range t.Fields.List {
|
|
86
|
-
if len(field.Names) > 0 {
|
|
87
|
-
for _, name := range field.Names {
|
|
88
|
-
fieldASTTypes[name.Name] = field.Type
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// Define the _fields property type
|
|
94
|
-
c.tsw.WriteLiterally("public _fields: {")
|
|
95
|
-
c.tsw.Indent(1)
|
|
96
|
-
c.tsw.WriteLine("")
|
|
97
|
-
|
|
98
|
-
for field := range underlyingStruct.Fields() {
|
|
99
|
-
var fieldKeyName string
|
|
100
|
-
if field.Anonymous() {
|
|
101
|
-
fieldKeyName = c.getEmbeddedFieldKeyName(field.Type())
|
|
102
|
-
} else {
|
|
103
|
-
fieldKeyName = field.Name()
|
|
104
|
-
}
|
|
105
|
-
// Skip underscore fields
|
|
106
|
-
if fieldKeyName == "_" {
|
|
107
|
-
continue
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// Use AST-based type string when available, fall back to types-based
|
|
111
|
-
// Note: getASTTypeString already includes "null |" for interface types
|
|
112
|
-
astType := fieldASTTypes[fieldKeyName]
|
|
113
|
-
fieldTsType := c.getASTTypeString(astType, field.Type())
|
|
114
|
-
|
|
115
|
-
c.tsw.WriteLinef("%s: $.VarRef<%s>;", fieldKeyName, fieldTsType)
|
|
116
|
-
}
|
|
117
|
-
c.tsw.Indent(-1)
|
|
118
|
-
c.tsw.WriteLine("}")
|
|
119
|
-
|
|
120
|
-
// Generate the flattened type string for the constructor init parameter
|
|
121
|
-
flattenedInitType := c.generateFlattenedInitTypeString(goStructType, fieldASTTypes)
|
|
122
|
-
|
|
123
|
-
c.tsw.WriteLine("")
|
|
124
|
-
c.tsw.WriteLinef("constructor(init?: Partial<%s>) {", flattenedInitType)
|
|
125
|
-
c.tsw.Indent(1)
|
|
126
|
-
c.tsw.WriteLiterally("this._fields = {")
|
|
127
|
-
|
|
128
|
-
numFields := underlyingStruct.NumFields()
|
|
129
|
-
if numFields != 0 {
|
|
130
|
-
c.tsw.WriteLine("")
|
|
131
|
-
c.tsw.Indent(1)
|
|
132
|
-
|
|
133
|
-
firstFieldWritten := false
|
|
134
|
-
for i := range numFields {
|
|
135
|
-
field := underlyingStruct.Field(i)
|
|
136
|
-
fieldType := field.Type()
|
|
137
|
-
var fieldKeyName string
|
|
138
|
-
if field.Anonymous() {
|
|
139
|
-
fieldKeyName = c.getEmbeddedFieldKeyName(field.Type())
|
|
140
|
-
} else {
|
|
141
|
-
fieldKeyName = field.Name()
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// Skip underscore fields
|
|
145
|
-
if fieldKeyName == "_" {
|
|
146
|
-
continue
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
if firstFieldWritten {
|
|
150
|
-
c.tsw.WriteLine(",")
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
c.writeVarRefedFieldInitializer(fieldKeyName, fieldType, field.Anonymous(), fieldASTTypes[fieldKeyName])
|
|
154
|
-
firstFieldWritten = true
|
|
155
|
-
}
|
|
156
|
-
if firstFieldWritten {
|
|
157
|
-
c.tsw.WriteLine("")
|
|
158
|
-
}
|
|
159
|
-
c.tsw.Indent(-1)
|
|
160
|
-
}
|
|
161
|
-
c.tsw.WriteLine("}")
|
|
162
|
-
|
|
163
|
-
c.tsw.Indent(-1)
|
|
164
|
-
c.tsw.WriteLine("}")
|
|
165
|
-
c.tsw.WriteLine("")
|
|
166
|
-
|
|
167
|
-
// Generate the clone method
|
|
168
|
-
var cloneReturnType strings.Builder
|
|
169
|
-
cloneReturnType.WriteString(className)
|
|
170
|
-
if a.TypeParams != nil && len(a.TypeParams.List) > 0 {
|
|
171
|
-
cloneReturnType.WriteString("<")
|
|
172
|
-
first := true
|
|
173
|
-
for _, field := range a.TypeParams.List {
|
|
174
|
-
for _, name := range field.Names {
|
|
175
|
-
if !first {
|
|
176
|
-
cloneReturnType.WriteString(", ")
|
|
177
|
-
}
|
|
178
|
-
first = false
|
|
179
|
-
cloneReturnType.WriteString(name.Name)
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
cloneReturnType.WriteString(">")
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
c.tsw.WriteLinef("public clone(): %s {", cloneReturnType.String())
|
|
186
|
-
c.tsw.Indent(1)
|
|
187
|
-
c.tsw.WriteLinef("const cloned = new %s()", cloneReturnType.String())
|
|
188
|
-
c.tsw.WriteLine("cloned._fields = {")
|
|
189
|
-
c.tsw.Indent(1)
|
|
190
|
-
|
|
191
|
-
firstFieldWritten := false
|
|
192
|
-
for i := range numFields {
|
|
193
|
-
field := underlyingStruct.Field(i)
|
|
194
|
-
fieldType := field.Type()
|
|
195
|
-
var fieldKeyName string
|
|
196
|
-
if field.Anonymous() {
|
|
197
|
-
fieldKeyName = c.getEmbeddedFieldKeyName(field.Type())
|
|
198
|
-
} else {
|
|
199
|
-
fieldKeyName = field.Name()
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
// Skip underscore fields
|
|
203
|
-
if fieldKeyName == "_" {
|
|
204
|
-
continue
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
if firstFieldWritten {
|
|
208
|
-
c.tsw.WriteLine(",")
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
c.writeClonedFieldInitializer(fieldKeyName, fieldType, field.Anonymous())
|
|
212
|
-
firstFieldWritten = true
|
|
213
|
-
}
|
|
214
|
-
if firstFieldWritten {
|
|
215
|
-
c.tsw.WriteLine("")
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
c.tsw.Indent(-1)
|
|
219
|
-
c.tsw.WriteLine("}")
|
|
220
|
-
c.tsw.WriteLine("return cloned")
|
|
221
|
-
c.tsw.Indent(-1)
|
|
222
|
-
c.tsw.WriteLine("}")
|
|
223
|
-
|
|
224
|
-
// Methods for this struct (direct methods)
|
|
225
|
-
for _, fileSyntax := range c.pkg.Syntax {
|
|
226
|
-
for _, decl := range fileSyntax.Decls {
|
|
227
|
-
funcDecl, isFunc := decl.(*ast.FuncDecl)
|
|
228
|
-
if !isFunc || funcDecl.Recv == nil || len(funcDecl.Recv.List) == 0 {
|
|
229
|
-
continue
|
|
230
|
-
}
|
|
231
|
-
recvField := funcDecl.Recv.List[0]
|
|
232
|
-
recvType := recvField.Type
|
|
233
|
-
if starExpr, ok := recvType.(*ast.StarExpr); ok {
|
|
234
|
-
recvType = starExpr.X
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
// Check for both simple identifiers (Pair) and generic types (Pair[T])
|
|
238
|
-
var recvTypeName string
|
|
239
|
-
if ident, ok := recvType.(*ast.Ident); ok {
|
|
240
|
-
recvTypeName = sanitizeIdentifier(ident.Name)
|
|
241
|
-
} else if indexExpr, ok := recvType.(*ast.IndexExpr); ok {
|
|
242
|
-
if ident, ok := indexExpr.X.(*ast.Ident); ok {
|
|
243
|
-
recvTypeName = sanitizeIdentifier(ident.Name)
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
if recvTypeName == className {
|
|
248
|
-
c.tsw.WriteLine("")
|
|
249
|
-
if err := c.WriteFuncDeclAsMethod(funcDecl); err != nil {
|
|
250
|
-
return err
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
// Generate getters/setters and wrapper methods for PROMOTED fields/methods from embedded structs
|
|
257
|
-
seenPromotedFields := make(map[string]bool)
|
|
258
|
-
directMethods := make(map[string]bool)
|
|
259
|
-
// Populate directMethods (methods defined directly on this struct type)
|
|
260
|
-
for method := range goStructType.Methods() {
|
|
261
|
-
sig := method.Type().(*types.Signature)
|
|
262
|
-
if sig.Recv() != nil {
|
|
263
|
-
recvType := sig.Recv().Type()
|
|
264
|
-
if namedRecv, ok := recvType.(*types.Named); ok && namedRecv.Obj() == goStructType.Obj() {
|
|
265
|
-
directMethods[method.Name()] = true
|
|
266
|
-
} else if ptrRecv, ok := recvType.(*types.Pointer); ok {
|
|
267
|
-
if namedElem, ok := ptrRecv.Elem().(*types.Named); ok && namedElem.Obj() == goStructType.Obj() {
|
|
268
|
-
directMethods[method.Name()] = true
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
for field := range underlyingStruct.Fields() {
|
|
275
|
-
if !field.Anonymous() {
|
|
276
|
-
continue
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
embeddedFieldType := field.Type()
|
|
280
|
-
embeddedFieldKeyName := c.getEmbeddedFieldKeyName(field.Type())
|
|
281
|
-
|
|
282
|
-
// Skip if not a named type (required for proper embedding promotion)
|
|
283
|
-
trueEmbeddedType := embeddedFieldType
|
|
284
|
-
if ptr, isPtr := trueEmbeddedType.(*types.Pointer); isPtr {
|
|
285
|
-
trueEmbeddedType = ptr.Elem()
|
|
286
|
-
}
|
|
287
|
-
if _, isNamed := trueEmbeddedType.(*types.Named); !isNamed {
|
|
288
|
-
continue
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
// Promoted fields
|
|
292
|
-
if namedEmbedded, ok := trueEmbeddedType.(*types.Named); ok {
|
|
293
|
-
if underlyingEmbeddedStruct, ok := namedEmbedded.Underlying().(*types.Struct); ok {
|
|
294
|
-
for promotedField := range underlyingEmbeddedStruct.Fields() {
|
|
295
|
-
if !promotedField.Exported() && promotedField.Pkg() != c.pkg.Types {
|
|
296
|
-
continue
|
|
297
|
-
}
|
|
298
|
-
promotedFieldName := promotedField.Name()
|
|
299
|
-
if seenPromotedFields[promotedFieldName] {
|
|
300
|
-
continue
|
|
301
|
-
}
|
|
302
|
-
// Check for conflicts with outer struct's own fields or other promoted fields
|
|
303
|
-
conflict := false
|
|
304
|
-
for field := range underlyingStruct.Fields() {
|
|
305
|
-
if !field.Anonymous() && field.Name() == promotedFieldName {
|
|
306
|
-
conflict = true
|
|
307
|
-
break
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
if conflict {
|
|
311
|
-
continue
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
seenPromotedFields[promotedFieldName] = true
|
|
315
|
-
tsPromotedFieldType := c.getTypeString(promotedField.Type())
|
|
316
|
-
c.tsw.WriteLine("")
|
|
317
|
-
c.tsw.WriteLinef("public get %s(): %s {", promotedFieldName, tsPromotedFieldType)
|
|
318
|
-
c.tsw.Indent(1)
|
|
319
|
-
// Check if the embedded type is an interface and add null assertion
|
|
320
|
-
embeddedFieldTypeUnderlying := embeddedFieldType
|
|
321
|
-
if ptr, isPtr := embeddedFieldTypeUnderlying.(*types.Pointer); isPtr {
|
|
322
|
-
embeddedFieldTypeUnderlying = ptr.Elem()
|
|
323
|
-
}
|
|
324
|
-
if named, isNamed := embeddedFieldTypeUnderlying.(*types.Named); isNamed {
|
|
325
|
-
embeddedFieldTypeUnderlying = named.Underlying()
|
|
326
|
-
}
|
|
327
|
-
if _, isInterface := embeddedFieldTypeUnderlying.(*types.Interface); isInterface {
|
|
328
|
-
c.tsw.WriteLinef("return this.%s!.%s", embeddedFieldKeyName, promotedFieldName)
|
|
329
|
-
} else {
|
|
330
|
-
c.tsw.WriteLinef("return this.%s.%s", embeddedFieldKeyName, promotedFieldName)
|
|
331
|
-
}
|
|
332
|
-
c.tsw.Indent(-1)
|
|
333
|
-
c.tsw.WriteLine("}")
|
|
334
|
-
c.tsw.WriteLinef("public set %s(value: %s) {", promotedFieldName, tsPromotedFieldType)
|
|
335
|
-
c.tsw.Indent(1)
|
|
336
|
-
if _, isInterface := embeddedFieldTypeUnderlying.(*types.Interface); isInterface {
|
|
337
|
-
c.tsw.WriteLinef("this.%s!.%s = value", embeddedFieldKeyName, promotedFieldName)
|
|
338
|
-
} else {
|
|
339
|
-
c.tsw.WriteLinef("this.%s.%s = value", embeddedFieldKeyName, promotedFieldName)
|
|
340
|
-
}
|
|
341
|
-
c.tsw.Indent(-1)
|
|
342
|
-
c.tsw.WriteLine("}")
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
// Promoted methods
|
|
348
|
-
// Use pointer to embedded type to get both value and pointer receiver methods
|
|
349
|
-
// This matches Go's behavior where embedding T promotes both T and *T methods
|
|
350
|
-
// Exception: For interfaces, use the interface directly as pointer-to-interface has no methods
|
|
351
|
-
methodSetType := embeddedFieldType
|
|
352
|
-
if _, isPtr := embeddedFieldType.(*types.Pointer); !isPtr {
|
|
353
|
-
if _, isInterface := embeddedFieldType.Underlying().(*types.Interface); !isInterface {
|
|
354
|
-
methodSetType = types.NewPointer(embeddedFieldType)
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
embeddedMethodSet := types.NewMethodSet(methodSetType)
|
|
358
|
-
for methodSelection := range embeddedMethodSet.Methods() {
|
|
359
|
-
method := methodSelection.Obj().(*types.Func)
|
|
360
|
-
methodName := method.Name()
|
|
361
|
-
|
|
362
|
-
// Skip if it's not a promoted method (indirect) or if it's shadowed by a direct method or an already processed promoted method
|
|
363
|
-
if len(methodSelection.Index()) == 1 && !directMethods[methodName] && !seenPromotedFields[methodName] {
|
|
364
|
-
// Check for conflict with outer struct's own fields
|
|
365
|
-
conflictWithField := false
|
|
366
|
-
for field := range underlyingStruct.Fields() {
|
|
367
|
-
if !field.Anonymous() && field.Name() == methodName {
|
|
368
|
-
conflictWithField = true
|
|
369
|
-
break
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
if conflictWithField {
|
|
373
|
-
continue
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
seenPromotedFields[methodName] = true // Mark as handled to avoid duplicates from other embeddings
|
|
377
|
-
sig := method.Type().(*types.Signature)
|
|
378
|
-
c.tsw.WriteLine("")
|
|
379
|
-
c.tsw.WriteLiterally("public ")
|
|
380
|
-
c.tsw.WriteLiterally(methodName)
|
|
381
|
-
c.tsw.WriteLiterally("(")
|
|
382
|
-
params := sig.Params()
|
|
383
|
-
paramNames := make([]string, params.Len())
|
|
384
|
-
for j := 0; j < params.Len(); j++ {
|
|
385
|
-
param := params.At(j)
|
|
386
|
-
paramName := param.Name()
|
|
387
|
-
if paramName == "" || paramName == "_" {
|
|
388
|
-
paramName = fmt.Sprintf("_p%d", j)
|
|
389
|
-
}
|
|
390
|
-
paramNames[j] = paramName
|
|
391
|
-
if j > 0 {
|
|
392
|
-
c.tsw.WriteLiterally(", ")
|
|
393
|
-
}
|
|
394
|
-
c.tsw.WriteLiterally(paramName)
|
|
395
|
-
c.tsw.WriteLiterally(": ")
|
|
396
|
-
c.WriteGoType(param.Type(), GoTypeContextGeneral)
|
|
397
|
-
}
|
|
398
|
-
c.tsw.WriteLiterally(")")
|
|
399
|
-
results := sig.Results()
|
|
400
|
-
if results.Len() > 0 {
|
|
401
|
-
c.tsw.WriteLiterally(": ")
|
|
402
|
-
if results.Len() == 1 {
|
|
403
|
-
c.WriteGoType(results.At(0).Type(), GoTypeContextFunctionReturn)
|
|
404
|
-
} else {
|
|
405
|
-
c.tsw.WriteLiterally("[")
|
|
406
|
-
for j := 0; j < results.Len(); j++ {
|
|
407
|
-
if j > 0 {
|
|
408
|
-
c.tsw.WriteLiterally(", ")
|
|
409
|
-
}
|
|
410
|
-
c.WriteGoType(results.At(j).Type(), GoTypeContextFunctionReturn)
|
|
411
|
-
}
|
|
412
|
-
c.tsw.WriteLiterally("]")
|
|
413
|
-
}
|
|
414
|
-
} else {
|
|
415
|
-
c.tsw.WriteLiterally(": void")
|
|
416
|
-
}
|
|
417
|
-
c.tsw.WriteLine(" {")
|
|
418
|
-
c.tsw.Indent(1)
|
|
419
|
-
if results.Len() > 0 {
|
|
420
|
-
c.tsw.WriteLiterally("return ")
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
assertionPrefix := "this.%s"
|
|
424
|
-
if _, isInterface := embeddedFieldType.Underlying().(*types.Interface); isInterface {
|
|
425
|
-
assertionPrefix = "this.%s!"
|
|
426
|
-
}
|
|
427
|
-
c.tsw.WriteLiterallyf(assertionPrefix+".%s(%s)", embeddedFieldKeyName, methodName, strings.Join(paramNames, ", "))
|
|
428
|
-
|
|
429
|
-
c.tsw.WriteLine("")
|
|
430
|
-
c.tsw.Indent(-1)
|
|
431
|
-
c.tsw.WriteLine("}")
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
// Add code to register the type with the runtime type system
|
|
437
|
-
c.tsw.WriteLine("")
|
|
438
|
-
c.tsw.WriteLinef("// Register this type with the runtime type system")
|
|
439
|
-
|
|
440
|
-
// Build full package path name for registration
|
|
441
|
-
structName := className
|
|
442
|
-
pkgPath := c.pkg.Types.Path()
|
|
443
|
-
pkgName := c.pkg.Types.Name()
|
|
444
|
-
if pkgPath != "" && pkgName != "main" {
|
|
445
|
-
structName = pkgPath + "." + className
|
|
446
|
-
} else if pkgName == "main" {
|
|
447
|
-
structName = "main." + className
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
c.tsw.WriteLinef("static __typeInfo = $.registerStructType(")
|
|
451
|
-
c.tsw.WriteLinef(" '%s',", structName)
|
|
452
|
-
c.tsw.WriteLinef(" new %s(),", className)
|
|
453
|
-
c.tsw.WriteLiterally(" [")
|
|
454
|
-
// Collect methods for the struct type
|
|
455
|
-
var structMethods []*types.Func
|
|
456
|
-
for method := range goStructType.Methods() {
|
|
457
|
-
// Ensure it's a method directly on this type (not promoted here, promotion handled separately)
|
|
458
|
-
// Check if receiver is *T or T where T is goStructType
|
|
459
|
-
sig := method.Type().(*types.Signature)
|
|
460
|
-
recv := sig.Recv().Type()
|
|
461
|
-
if ptr, ok := recv.(*types.Pointer); ok {
|
|
462
|
-
recv = ptr.Elem()
|
|
463
|
-
}
|
|
464
|
-
if namedRecv, ok := recv.(*types.Named); ok && namedRecv.Obj() == goStructType.Obj() {
|
|
465
|
-
structMethods = append(structMethods, method)
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
c.writeMethodSignatures(structMethods)
|
|
469
|
-
c.tsw.WriteLiterally("],")
|
|
470
|
-
c.tsw.WriteLine("")
|
|
471
|
-
|
|
472
|
-
c.tsw.WriteLinef(" %s,", className)
|
|
473
|
-
// Add field type information for type assertions
|
|
474
|
-
c.tsw.WriteLiterally(" {")
|
|
475
|
-
firstField := true
|
|
476
|
-
for i := 0; i < underlyingStruct.NumFields(); i++ {
|
|
477
|
-
field := underlyingStruct.Field(i)
|
|
478
|
-
var fieldKeyName string
|
|
479
|
-
if field.Anonymous() {
|
|
480
|
-
fieldKeyName = c.getEmbeddedFieldKeyName(field.Type())
|
|
481
|
-
} else {
|
|
482
|
-
fieldKeyName = field.Name()
|
|
483
|
-
}
|
|
484
|
-
// Skip underscore fields
|
|
485
|
-
if fieldKeyName == "_" {
|
|
486
|
-
continue
|
|
487
|
-
}
|
|
488
|
-
if !firstField {
|
|
489
|
-
c.tsw.WriteLiterally(", ")
|
|
490
|
-
}
|
|
491
|
-
firstField = false
|
|
492
|
-
c.tsw.WriteLiterallyf("%q: ", fieldKeyName)
|
|
493
|
-
|
|
494
|
-
// Get the struct tag for this field
|
|
495
|
-
tag := underlyingStruct.Tag(i)
|
|
496
|
-
if tag != "" {
|
|
497
|
-
// Write field info with tag as StructFieldInfo object
|
|
498
|
-
c.tsw.WriteLiterally("{ type: ")
|
|
499
|
-
c.writeTypeInfoObject(field.Type())
|
|
500
|
-
c.tsw.WriteLiterallyf(", tag: %q }", tag)
|
|
501
|
-
} else {
|
|
502
|
-
// No tag, write type info directly for backwards compatibility
|
|
503
|
-
c.writeTypeInfoObject(field.Type())
|
|
504
|
-
}
|
|
505
|
-
}
|
|
506
|
-
c.tsw.WriteLiterally("}")
|
|
507
|
-
c.tsw.WriteLine("")
|
|
508
|
-
c.tsw.WriteLinef(");")
|
|
509
|
-
|
|
510
|
-
c.tsw.Indent(-1)
|
|
511
|
-
c.tsw.WriteLine("}")
|
|
512
|
-
return nil
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
// WriteNamedStructTypeSpec generates a TypeScript class for a named type whose
|
|
516
|
-
// underlying type is another named struct. The emitted class copies the field
|
|
517
|
-
// layout without inheriting the underlying named type's prototype methods.
|
|
518
|
-
func (c *GoToTSCompiler) WriteNamedStructTypeSpec(a *ast.TypeSpec, named *types.Named) error {
|
|
519
|
-
isInsideFunction := false
|
|
520
|
-
if nodeInfo := c.analysis.NodeData[a]; nodeInfo != nil {
|
|
521
|
-
isInsideFunction = nodeInfo.IsInsideFunction
|
|
522
|
-
}
|
|
523
|
-
if !isInsideFunction {
|
|
524
|
-
c.tsw.WriteLiterally("export ")
|
|
525
|
-
}
|
|
526
|
-
c.tsw.WriteLiterally("class ")
|
|
527
|
-
if err := c.WriteValueExpr(a.Name); err != nil {
|
|
528
|
-
return err
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
if a.TypeParams != nil {
|
|
532
|
-
c.WriteTypeParameters(a.TypeParams)
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
c.tsw.WriteLiterally(" ")
|
|
536
|
-
c.tsw.WriteLine("{")
|
|
537
|
-
c.tsw.Indent(1)
|
|
538
|
-
|
|
539
|
-
className := sanitizeIdentifier(a.Name.Name)
|
|
540
|
-
underlyingStruct, ok := named.Underlying().(*types.Struct)
|
|
541
|
-
if !ok {
|
|
542
|
-
return fmt.Errorf("underlying type of %s is not a struct", a.Name.Name)
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
underlyingType := c.pkg.TypesInfo.TypeOf(a.Type)
|
|
546
|
-
underlyingInitType := "{}"
|
|
547
|
-
if underlyingNamed, ok := underlyingType.(*types.Named); ok {
|
|
548
|
-
underlyingInitType = c.generateFlattenedInitTypeString(underlyingNamed, nil)
|
|
549
|
-
}
|
|
550
|
-
underlyingTypeName := c.getASTTypeString(a.Type, underlyingType)
|
|
551
|
-
|
|
552
|
-
for i := 0; i < underlyingStruct.NumFields(); i++ {
|
|
553
|
-
field := underlyingStruct.Field(i)
|
|
554
|
-
if field.Anonymous() {
|
|
555
|
-
continue
|
|
556
|
-
}
|
|
557
|
-
if !field.Exported() && field.Pkg() != c.pkg.Types {
|
|
558
|
-
continue
|
|
559
|
-
}
|
|
560
|
-
c.writeGetterSetter(field.Name(), field.Type(), nil, nil, nil)
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
for field := range underlyingStruct.Fields() {
|
|
564
|
-
if field.Anonymous() {
|
|
565
|
-
fieldKeyName := c.getEmbeddedFieldKeyName(field.Type())
|
|
566
|
-
c.writeGetterSetter(fieldKeyName, field.Type(), nil, nil, nil)
|
|
567
|
-
}
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
c.tsw.WriteLiterally("public _fields: {")
|
|
571
|
-
c.tsw.Indent(1)
|
|
572
|
-
c.tsw.WriteLine("")
|
|
573
|
-
for i := 0; i < underlyingStruct.NumFields(); i++ {
|
|
574
|
-
field := underlyingStruct.Field(i)
|
|
575
|
-
fieldKeyName := field.Name()
|
|
576
|
-
if field.Anonymous() {
|
|
577
|
-
fieldKeyName = c.getEmbeddedFieldKeyName(field.Type())
|
|
578
|
-
}
|
|
579
|
-
if fieldKeyName == "_" {
|
|
580
|
-
continue
|
|
581
|
-
}
|
|
582
|
-
c.tsw.WriteLinef("%s: $.VarRef<%s>;", fieldKeyName, c.getTypeString(field.Type()))
|
|
583
|
-
}
|
|
584
|
-
c.tsw.Indent(-1)
|
|
585
|
-
c.tsw.WriteLine("}")
|
|
586
|
-
c.tsw.WriteLine("")
|
|
587
|
-
|
|
588
|
-
c.tsw.WriteLinef("constructor(init?: Partial<%s>) {", underlyingInitType)
|
|
589
|
-
c.tsw.Indent(1)
|
|
590
|
-
c.tsw.WriteLinef("const base = new %s(init)", underlyingTypeName)
|
|
591
|
-
c.tsw.WriteLine("this._fields = base._fields")
|
|
592
|
-
c.tsw.Indent(-1)
|
|
593
|
-
c.tsw.WriteLine("}")
|
|
594
|
-
c.tsw.WriteLine("")
|
|
595
|
-
|
|
596
|
-
var cloneReturnType strings.Builder
|
|
597
|
-
cloneReturnType.WriteString(className)
|
|
598
|
-
if a.TypeParams != nil && len(a.TypeParams.List) > 0 {
|
|
599
|
-
cloneReturnType.WriteString("<")
|
|
600
|
-
first := true
|
|
601
|
-
for _, field := range a.TypeParams.List {
|
|
602
|
-
for _, name := range field.Names {
|
|
603
|
-
if !first {
|
|
604
|
-
cloneReturnType.WriteString(", ")
|
|
605
|
-
}
|
|
606
|
-
first = false
|
|
607
|
-
cloneReturnType.WriteString(name.Name)
|
|
608
|
-
}
|
|
609
|
-
}
|
|
610
|
-
cloneReturnType.WriteString(">")
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
c.tsw.WriteLinef("public clone(): %s {", cloneReturnType.String())
|
|
614
|
-
c.tsw.Indent(1)
|
|
615
|
-
c.tsw.WriteLinef("const cloned = new %s()", cloneReturnType.String())
|
|
616
|
-
c.tsw.WriteLine("cloned._fields = {")
|
|
617
|
-
c.tsw.Indent(1)
|
|
618
|
-
|
|
619
|
-
firstFieldWritten := false
|
|
620
|
-
for i := 0; i < underlyingStruct.NumFields(); i++ {
|
|
621
|
-
field := underlyingStruct.Field(i)
|
|
622
|
-
fieldType := field.Type()
|
|
623
|
-
fieldKeyName := field.Name()
|
|
624
|
-
if field.Anonymous() {
|
|
625
|
-
fieldKeyName = c.getEmbeddedFieldKeyName(field.Type())
|
|
626
|
-
}
|
|
627
|
-
if fieldKeyName == "_" {
|
|
628
|
-
continue
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
if firstFieldWritten {
|
|
632
|
-
c.tsw.WriteLine(",")
|
|
633
|
-
}
|
|
634
|
-
c.writeClonedFieldInitializer(fieldKeyName, fieldType, field.Anonymous())
|
|
635
|
-
firstFieldWritten = true
|
|
636
|
-
}
|
|
637
|
-
if firstFieldWritten {
|
|
638
|
-
c.tsw.WriteLine("")
|
|
639
|
-
}
|
|
640
|
-
|
|
641
|
-
c.tsw.Indent(-1)
|
|
642
|
-
c.tsw.WriteLine("}")
|
|
643
|
-
c.tsw.WriteLine("return cloned")
|
|
644
|
-
c.tsw.Indent(-1)
|
|
645
|
-
c.tsw.WriteLine("}")
|
|
646
|
-
|
|
647
|
-
for _, fileSyntax := range c.pkg.Syntax {
|
|
648
|
-
for _, decl := range fileSyntax.Decls {
|
|
649
|
-
funcDecl, isFunc := decl.(*ast.FuncDecl)
|
|
650
|
-
if !isFunc || funcDecl.Recv == nil || len(funcDecl.Recv.List) == 0 {
|
|
651
|
-
continue
|
|
652
|
-
}
|
|
653
|
-
recvType := funcDecl.Recv.List[0].Type
|
|
654
|
-
if starExpr, ok := recvType.(*ast.StarExpr); ok {
|
|
655
|
-
recvType = starExpr.X
|
|
656
|
-
}
|
|
657
|
-
|
|
658
|
-
var recvTypeName string
|
|
659
|
-
if ident, ok := recvType.(*ast.Ident); ok {
|
|
660
|
-
recvTypeName = sanitizeIdentifier(ident.Name)
|
|
661
|
-
} else if indexExpr, ok := recvType.(*ast.IndexExpr); ok {
|
|
662
|
-
if ident, ok := indexExpr.X.(*ast.Ident); ok {
|
|
663
|
-
recvTypeName = sanitizeIdentifier(ident.Name)
|
|
664
|
-
}
|
|
665
|
-
}
|
|
666
|
-
|
|
667
|
-
if recvTypeName == className {
|
|
668
|
-
c.tsw.WriteLine("")
|
|
669
|
-
if err := c.WriteFuncDeclAsMethod(funcDecl); err != nil {
|
|
670
|
-
return err
|
|
671
|
-
}
|
|
672
|
-
}
|
|
673
|
-
}
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
seenPromotedFields := make(map[string]bool)
|
|
677
|
-
directMethods := make(map[string]bool)
|
|
678
|
-
for method := range named.Methods() {
|
|
679
|
-
sig := method.Type().(*types.Signature)
|
|
680
|
-
if sig.Recv() != nil {
|
|
681
|
-
recvType := sig.Recv().Type()
|
|
682
|
-
if namedRecv, ok := recvType.(*types.Named); ok && namedRecv.Obj() == named.Obj() {
|
|
683
|
-
directMethods[method.Name()] = true
|
|
684
|
-
} else if ptrRecv, ok := recvType.(*types.Pointer); ok {
|
|
685
|
-
if namedElem, ok := ptrRecv.Elem().(*types.Named); ok && namedElem.Obj() == named.Obj() {
|
|
686
|
-
directMethods[method.Name()] = true
|
|
687
|
-
}
|
|
688
|
-
}
|
|
689
|
-
}
|
|
690
|
-
}
|
|
691
|
-
|
|
692
|
-
for field := range underlyingStruct.Fields() {
|
|
693
|
-
if !field.Anonymous() {
|
|
694
|
-
continue
|
|
695
|
-
}
|
|
696
|
-
|
|
697
|
-
embeddedFieldType := field.Type()
|
|
698
|
-
embeddedFieldKeyName := c.getEmbeddedFieldKeyName(field.Type())
|
|
699
|
-
|
|
700
|
-
trueEmbeddedType := embeddedFieldType
|
|
701
|
-
if ptr, isPtr := trueEmbeddedType.(*types.Pointer); isPtr {
|
|
702
|
-
trueEmbeddedType = ptr.Elem()
|
|
703
|
-
}
|
|
704
|
-
if _, isNamed := trueEmbeddedType.(*types.Named); !isNamed {
|
|
705
|
-
continue
|
|
706
|
-
}
|
|
707
|
-
|
|
708
|
-
if namedEmbedded, ok := trueEmbeddedType.(*types.Named); ok {
|
|
709
|
-
if underlyingEmbeddedStruct, ok := namedEmbedded.Underlying().(*types.Struct); ok {
|
|
710
|
-
for promotedField := range underlyingEmbeddedStruct.Fields() {
|
|
711
|
-
if !promotedField.Exported() && promotedField.Pkg() != c.pkg.Types {
|
|
712
|
-
continue
|
|
713
|
-
}
|
|
714
|
-
promotedFieldName := promotedField.Name()
|
|
715
|
-
if seenPromotedFields[promotedFieldName] {
|
|
716
|
-
continue
|
|
717
|
-
}
|
|
718
|
-
conflict := false
|
|
719
|
-
for field := range underlyingStruct.Fields() {
|
|
720
|
-
if !field.Anonymous() && field.Name() == promotedFieldName {
|
|
721
|
-
conflict = true
|
|
722
|
-
break
|
|
723
|
-
}
|
|
724
|
-
}
|
|
725
|
-
if conflict {
|
|
726
|
-
continue
|
|
727
|
-
}
|
|
728
|
-
|
|
729
|
-
seenPromotedFields[promotedFieldName] = true
|
|
730
|
-
tsPromotedFieldType := c.getTypeString(promotedField.Type())
|
|
731
|
-
c.tsw.WriteLine("")
|
|
732
|
-
c.tsw.WriteLinef("public get %s(): %s {", promotedFieldName, tsPromotedFieldType)
|
|
733
|
-
c.tsw.Indent(1)
|
|
734
|
-
embeddedFieldTypeUnderlying := embeddedFieldType
|
|
735
|
-
if ptr, isPtr := embeddedFieldTypeUnderlying.(*types.Pointer); isPtr {
|
|
736
|
-
embeddedFieldTypeUnderlying = ptr.Elem()
|
|
737
|
-
}
|
|
738
|
-
if named, isNamed := embeddedFieldTypeUnderlying.(*types.Named); isNamed {
|
|
739
|
-
embeddedFieldTypeUnderlying = named.Underlying()
|
|
740
|
-
}
|
|
741
|
-
if _, isInterface := embeddedFieldTypeUnderlying.(*types.Interface); isInterface {
|
|
742
|
-
c.tsw.WriteLinef("return this.%s!.%s", embeddedFieldKeyName, promotedFieldName)
|
|
743
|
-
} else {
|
|
744
|
-
c.tsw.WriteLinef("return this.%s.%s", embeddedFieldKeyName, promotedFieldName)
|
|
745
|
-
}
|
|
746
|
-
c.tsw.Indent(-1)
|
|
747
|
-
c.tsw.WriteLine("}")
|
|
748
|
-
c.tsw.WriteLinef("public set %s(value: %s) {", promotedFieldName, tsPromotedFieldType)
|
|
749
|
-
c.tsw.Indent(1)
|
|
750
|
-
if _, isInterface := embeddedFieldTypeUnderlying.(*types.Interface); isInterface {
|
|
751
|
-
c.tsw.WriteLinef("this.%s!.%s = value", embeddedFieldKeyName, promotedFieldName)
|
|
752
|
-
} else {
|
|
753
|
-
c.tsw.WriteLinef("this.%s.%s = value", embeddedFieldKeyName, promotedFieldName)
|
|
754
|
-
}
|
|
755
|
-
c.tsw.Indent(-1)
|
|
756
|
-
c.tsw.WriteLine("}")
|
|
757
|
-
}
|
|
758
|
-
}
|
|
759
|
-
}
|
|
760
|
-
|
|
761
|
-
methodSetType := embeddedFieldType
|
|
762
|
-
if _, isPtr := embeddedFieldType.(*types.Pointer); !isPtr {
|
|
763
|
-
if _, isInterface := embeddedFieldType.Underlying().(*types.Interface); !isInterface {
|
|
764
|
-
methodSetType = types.NewPointer(embeddedFieldType)
|
|
765
|
-
}
|
|
766
|
-
}
|
|
767
|
-
embeddedMethodSet := types.NewMethodSet(methodSetType)
|
|
768
|
-
for methodSelection := range embeddedMethodSet.Methods() {
|
|
769
|
-
method := methodSelection.Obj().(*types.Func)
|
|
770
|
-
methodName := method.Name()
|
|
771
|
-
|
|
772
|
-
if len(methodSelection.Index()) == 1 && !directMethods[methodName] && !seenPromotedFields[methodName] {
|
|
773
|
-
conflictWithField := false
|
|
774
|
-
for field := range underlyingStruct.Fields() {
|
|
775
|
-
if !field.Anonymous() && field.Name() == methodName {
|
|
776
|
-
conflictWithField = true
|
|
777
|
-
break
|
|
778
|
-
}
|
|
779
|
-
}
|
|
780
|
-
if conflictWithField {
|
|
781
|
-
continue
|
|
782
|
-
}
|
|
783
|
-
|
|
784
|
-
seenPromotedFields[methodName] = true
|
|
785
|
-
sig := method.Type().(*types.Signature)
|
|
786
|
-
c.tsw.WriteLine("")
|
|
787
|
-
c.tsw.WriteLiterally("public ")
|
|
788
|
-
c.tsw.WriteLiterally(methodName)
|
|
789
|
-
c.tsw.WriteLiterally("(")
|
|
790
|
-
params := sig.Params()
|
|
791
|
-
paramNames := make([]string, params.Len())
|
|
792
|
-
for j := 0; j < params.Len(); j++ {
|
|
793
|
-
param := params.At(j)
|
|
794
|
-
paramName := param.Name()
|
|
795
|
-
if paramName == "" || paramName == "_" {
|
|
796
|
-
paramName = fmt.Sprintf("_p%d", j)
|
|
797
|
-
}
|
|
798
|
-
paramNames[j] = paramName
|
|
799
|
-
if j > 0 {
|
|
800
|
-
c.tsw.WriteLiterally(", ")
|
|
801
|
-
}
|
|
802
|
-
c.tsw.WriteLiterally(paramName)
|
|
803
|
-
c.tsw.WriteLiterally(": ")
|
|
804
|
-
c.WriteGoType(param.Type(), GoTypeContextGeneral)
|
|
805
|
-
}
|
|
806
|
-
c.tsw.WriteLiterally(")")
|
|
807
|
-
results := sig.Results()
|
|
808
|
-
if results.Len() > 0 {
|
|
809
|
-
c.tsw.WriteLiterally(": ")
|
|
810
|
-
if results.Len() == 1 {
|
|
811
|
-
c.WriteGoType(results.At(0).Type(), GoTypeContextFunctionReturn)
|
|
812
|
-
} else {
|
|
813
|
-
c.tsw.WriteLiterally("[")
|
|
814
|
-
for j := 0; j < results.Len(); j++ {
|
|
815
|
-
if j > 0 {
|
|
816
|
-
c.tsw.WriteLiterally(", ")
|
|
817
|
-
}
|
|
818
|
-
c.WriteGoType(results.At(j).Type(), GoTypeContextFunctionReturn)
|
|
819
|
-
}
|
|
820
|
-
c.tsw.WriteLiterally("]")
|
|
821
|
-
}
|
|
822
|
-
} else {
|
|
823
|
-
c.tsw.WriteLiterally(": void")
|
|
824
|
-
}
|
|
825
|
-
c.tsw.WriteLine(" {")
|
|
826
|
-
c.tsw.Indent(1)
|
|
827
|
-
if results.Len() > 0 {
|
|
828
|
-
c.tsw.WriteLiterally("return ")
|
|
829
|
-
}
|
|
830
|
-
|
|
831
|
-
assertionPrefix := "this.%s"
|
|
832
|
-
if _, isInterface := embeddedFieldType.Underlying().(*types.Interface); isInterface {
|
|
833
|
-
assertionPrefix = "this.%s!"
|
|
834
|
-
}
|
|
835
|
-
c.tsw.WriteLiterallyf(assertionPrefix+".%s(%s)", embeddedFieldKeyName, methodName, strings.Join(paramNames, ", "))
|
|
836
|
-
|
|
837
|
-
c.tsw.WriteLine("")
|
|
838
|
-
c.tsw.Indent(-1)
|
|
839
|
-
c.tsw.WriteLine("}")
|
|
840
|
-
}
|
|
841
|
-
}
|
|
842
|
-
}
|
|
843
|
-
|
|
844
|
-
c.tsw.WriteLine("")
|
|
845
|
-
c.tsw.WriteLine("// Register this type with the runtime type system")
|
|
846
|
-
|
|
847
|
-
structName := className
|
|
848
|
-
pkgPath := c.pkg.Types.Path()
|
|
849
|
-
pkgName := c.pkg.Types.Name()
|
|
850
|
-
if pkgPath != "" && pkgName != "main" {
|
|
851
|
-
structName = pkgPath + "." + className
|
|
852
|
-
} else if pkgName == "main" {
|
|
853
|
-
structName = "main." + className
|
|
854
|
-
}
|
|
855
|
-
|
|
856
|
-
c.tsw.WriteLine("static __typeInfo = $.registerStructType(")
|
|
857
|
-
c.tsw.WriteLinef(" %q,", structName)
|
|
858
|
-
c.tsw.WriteLinef(" new %s(),", className)
|
|
859
|
-
c.tsw.WriteLiterally(" [")
|
|
860
|
-
|
|
861
|
-
var structMethods []*types.Func
|
|
862
|
-
for method := range named.Methods() {
|
|
863
|
-
sig := method.Type().(*types.Signature)
|
|
864
|
-
recv := sig.Recv().Type()
|
|
865
|
-
if ptr, ok := recv.(*types.Pointer); ok {
|
|
866
|
-
recv = ptr.Elem()
|
|
867
|
-
}
|
|
868
|
-
if namedRecv, ok := recv.(*types.Named); ok && namedRecv.Obj() == named.Obj() {
|
|
869
|
-
structMethods = append(structMethods, method)
|
|
870
|
-
}
|
|
871
|
-
}
|
|
872
|
-
c.writeMethodSignatures(structMethods)
|
|
873
|
-
c.tsw.WriteLiterally("],")
|
|
874
|
-
c.tsw.WriteLine("")
|
|
875
|
-
|
|
876
|
-
c.tsw.WriteLinef(" %s,", className)
|
|
877
|
-
c.tsw.WriteLiterally(" {")
|
|
878
|
-
firstField := true
|
|
879
|
-
for i := 0; i < underlyingStruct.NumFields(); i++ {
|
|
880
|
-
field := underlyingStruct.Field(i)
|
|
881
|
-
fieldKeyName := field.Name()
|
|
882
|
-
if field.Anonymous() {
|
|
883
|
-
fieldKeyName = c.getEmbeddedFieldKeyName(field.Type())
|
|
884
|
-
}
|
|
885
|
-
if fieldKeyName == "_" {
|
|
886
|
-
continue
|
|
887
|
-
}
|
|
888
|
-
if !firstField {
|
|
889
|
-
c.tsw.WriteLiterally(", ")
|
|
890
|
-
}
|
|
891
|
-
firstField = false
|
|
892
|
-
c.tsw.WriteLiterallyf("%q: ", fieldKeyName)
|
|
893
|
-
|
|
894
|
-
tag := underlyingStruct.Tag(i)
|
|
895
|
-
if tag != "" {
|
|
896
|
-
c.tsw.WriteLiterally("{ type: ")
|
|
897
|
-
c.writeTypeInfoObject(field.Type())
|
|
898
|
-
c.tsw.WriteLiterallyf(", tag: %q }", tag)
|
|
899
|
-
} else {
|
|
900
|
-
c.writeTypeInfoObject(field.Type())
|
|
901
|
-
}
|
|
902
|
-
}
|
|
903
|
-
c.tsw.WriteLiterally("}")
|
|
904
|
-
c.tsw.WriteLine("")
|
|
905
|
-
c.tsw.WriteLine(");")
|
|
906
|
-
|
|
907
|
-
c.tsw.Indent(-1)
|
|
908
|
-
c.tsw.WriteLine("}")
|
|
909
|
-
return nil
|
|
910
|
-
}
|
|
911
|
-
|
|
912
|
-
// generateFlattenedInitTypeString generates a TypeScript type string for the
|
|
913
|
-
// initialization object passed to a Go struct's constructor (`_init` method in TypeScript).
|
|
914
|
-
// The generated type is a `Partial`-like structure, `"{ Field1?: Type1, Field2?: Type2, ... }"`,
|
|
915
|
-
// including all direct and promoted fields of the `structType`.
|
|
916
|
-
// - It iterates through the direct fields of the `structType`. Exported fields
|
|
917
|
-
// are included with their TypeScript types (obtained via `WriteGoType`).
|
|
918
|
-
// - For anonymous (embedded) fields, it generates a type like `EmbeddedName?: ConstructorParameters<typeof EmbeddedName>[0]`,
|
|
919
|
-
// allowing initialization of the embedded struct's fields directly within the outer struct's initializer.
|
|
920
|
-
// - It then uses `types.NewMethodSet` and checks for `types.Var` objects that are fields
|
|
921
|
-
// to find promoted fields from embedded structs, adding them to the type string if not already present.
|
|
922
|
-
//
|
|
923
|
-
// The resulting string is sorted by field name for deterministic output and represents
|
|
924
|
-
// the shape of the object expected by the struct's TypeScript constructor.
|
|
925
|
-
func (c *GoToTSCompiler) generateFlattenedInitTypeString(structType *types.Named, fieldASTTypes map[string]ast.Expr) string {
|
|
926
|
-
if structType == nil {
|
|
927
|
-
return "{}"
|
|
928
|
-
}
|
|
929
|
-
|
|
930
|
-
// Use a map to collect unique field names and their types
|
|
931
|
-
fieldMap := make(map[string]string)
|
|
932
|
-
embeddedTypeMap := make(map[string]string) // Stores TS type string for embedded struct initializers
|
|
933
|
-
|
|
934
|
-
underlying, ok := structType.Underlying().(*types.Struct)
|
|
935
|
-
if !ok {
|
|
936
|
-
return "{}"
|
|
937
|
-
}
|
|
938
|
-
|
|
939
|
-
// First add the direct fields and track embedded types
|
|
940
|
-
for field := range underlying.Fields() {
|
|
941
|
-
fieldName := field.Name()
|
|
942
|
-
|
|
943
|
-
// Skip underscore fields
|
|
944
|
-
if fieldName == "_" {
|
|
945
|
-
continue
|
|
946
|
-
}
|
|
947
|
-
|
|
948
|
-
if !field.Exported() && field.Pkg() != c.pkg.Types {
|
|
949
|
-
continue
|
|
950
|
-
}
|
|
951
|
-
|
|
952
|
-
if field.Anonymous() {
|
|
953
|
-
fieldType := field.Type()
|
|
954
|
-
if ptr, ok := fieldType.(*types.Pointer); ok {
|
|
955
|
-
fieldType = ptr.Elem()
|
|
956
|
-
}
|
|
957
|
-
|
|
958
|
-
if _, ok := fieldType.(*types.Named); ok {
|
|
959
|
-
// Check if the embedded type is an interface
|
|
960
|
-
if _, isInterface := fieldType.Underlying().(*types.Interface); isInterface {
|
|
961
|
-
// For embedded interfaces, use the full qualified interface type
|
|
962
|
-
embeddedTypeMap[c.getEmbeddedFieldKeyName(field.Type())] = c.getTypeString(field.Type())
|
|
963
|
-
} else {
|
|
964
|
-
// For embedded structs, use ConstructorParameters for field-based initialization
|
|
965
|
-
// Use getTypeString to get the qualified type name (e.g., bytes.Buffer not just Buffer)
|
|
966
|
-
qualifiedTypeName := c.getTypeString(fieldType)
|
|
967
|
-
embeddedTypeMap[c.getEmbeddedFieldKeyName(field.Type())] = fmt.Sprintf("Partial<ConstructorParameters<typeof %s>[0]>", qualifiedTypeName)
|
|
968
|
-
}
|
|
969
|
-
}
|
|
970
|
-
continue
|
|
971
|
-
}
|
|
972
|
-
fieldMap[fieldName] = c.getASTTypeString(fieldASTTypes[fieldName], field.Type())
|
|
973
|
-
}
|
|
974
|
-
|
|
975
|
-
// Promoted fields (handled by Go's embedding, init should use direct/embedded names)
|
|
976
|
-
// The current logic for `generateFlattenedInitTypeString` seems to focus on top-level
|
|
977
|
-
// settable properties in the constructor. Promoted fields are accessed via `this.promotedField`,
|
|
978
|
-
// not typically set directly in `init?` unless the embedded struct itself is named in `init?`.
|
|
979
|
-
|
|
980
|
-
// Add embedded types to the field map (these are the names of the embedded structs themselves)
|
|
981
|
-
maps.Copy(fieldMap, embeddedTypeMap)
|
|
982
|
-
|
|
983
|
-
var fieldNames []string
|
|
984
|
-
for name := range fieldMap {
|
|
985
|
-
fieldNames = append(fieldNames, name)
|
|
986
|
-
}
|
|
987
|
-
slices.Sort(fieldNames)
|
|
988
|
-
|
|
989
|
-
var fieldDefs []string
|
|
990
|
-
for _, fieldName := range fieldNames {
|
|
991
|
-
fieldDefs = append(fieldDefs, fmt.Sprintf("%s?: %s", fieldName, fieldMap[fieldName]))
|
|
992
|
-
}
|
|
993
|
-
|
|
994
|
-
return "{" + strings.Join(fieldDefs, ", ") + "}"
|
|
995
|
-
}
|