goscript 0.0.59 → 0.0.61
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/compiler/analysis.go +465 -336
- package/compiler/compiler.go +10 -4
- package/compiler/decl.go +47 -87
- package/compiler/expr-call-helpers.go +182 -0
- package/compiler/expr-call.go +9 -30
- package/compiler/expr-selector.go +38 -1
- package/compiler/expr-type.go +37 -1
- package/compiler/expr.go +0 -28
- package/compiler/spec-struct.go +12 -1
- package/compiler/spec.go +21 -1
- package/compiler/stmt.go +2 -10
- package/compiler/type-utils.go +0 -15
- package/dist/gs/builtin/slice.js +6 -7
- package/dist/gs/builtin/slice.js.map +1 -1
- package/dist/gs/builtin/type.d.ts +5 -0
- package/dist/gs/builtin/type.js +7 -0
- package/dist/gs/builtin/type.js.map +1 -1
- package/dist/gs/internal/byteorder/index.d.ts +6 -0
- package/dist/gs/internal/byteorder/index.js +34 -0
- package/dist/gs/internal/byteorder/index.js.map +1 -1
- package/dist/gs/reflect/index.d.ts +3 -3
- package/dist/gs/reflect/index.js +2 -2
- package/dist/gs/reflect/index.js.map +1 -1
- package/dist/gs/reflect/type.d.ts +9 -0
- package/dist/gs/reflect/type.js +73 -0
- package/dist/gs/reflect/type.js.map +1 -1
- package/dist/gs/slices/slices.d.ts +11 -0
- package/dist/gs/slices/slices.js +33 -0
- package/dist/gs/slices/slices.js.map +1 -1
- package/go.mod +4 -4
- package/go.sum +8 -8
- package/gs/builtin/slice.ts +6 -7
- package/gs/builtin/type.ts +8 -0
- package/gs/internal/byteorder/index.ts +40 -0
- package/gs/reflect/index.ts +3 -1
- package/gs/reflect/type.ts +97 -0
- package/gs/slices/slices.ts +37 -0
- package/gs/sync/meta.json +1 -1
- package/package.json +1 -1
package/compiler/compiler.go
CHANGED
|
@@ -844,7 +844,7 @@ func (c *GoToTSCompiler) WriteCaseClause(exp *ast.CaseClause) error {
|
|
|
844
844
|
if exp.List == nil {
|
|
845
845
|
// Default case
|
|
846
846
|
c.tsw.WriteLiterally("default:")
|
|
847
|
-
c.tsw.WriteLine("")
|
|
847
|
+
c.tsw.WriteLine(" {")
|
|
848
848
|
} else {
|
|
849
849
|
// Case with expressions
|
|
850
850
|
// For Go's `case expr1, expr2:`, we translate to:
|
|
@@ -852,18 +852,23 @@ func (c *GoToTSCompiler) WriteCaseClause(exp *ast.CaseClause) error {
|
|
|
852
852
|
// case expr2:
|
|
853
853
|
// ... body ...
|
|
854
854
|
// break
|
|
855
|
-
for
|
|
855
|
+
for i, caseExpr := range exp.List {
|
|
856
856
|
c.tsw.WriteLiterally("case ")
|
|
857
857
|
if err := c.WriteValueExpr(caseExpr); err != nil {
|
|
858
858
|
return fmt.Errorf("failed to write case clause expression: %w", err)
|
|
859
859
|
}
|
|
860
860
|
c.tsw.WriteLiterally(":")
|
|
861
|
-
|
|
861
|
+
// Only add opening brace after the last case label
|
|
862
|
+
if i == len(exp.List)-1 {
|
|
863
|
+
c.tsw.WriteLine(" {")
|
|
864
|
+
} else {
|
|
865
|
+
c.tsw.WriteLine("")
|
|
866
|
+
}
|
|
862
867
|
}
|
|
863
868
|
}
|
|
864
869
|
|
|
865
870
|
// The body is written once, after all case labels for this clause.
|
|
866
|
-
//
|
|
871
|
+
// Wrap in block to provide Go-like case scope semantics.
|
|
867
872
|
c.tsw.Indent(1)
|
|
868
873
|
for _, stmt := range exp.Body {
|
|
869
874
|
if err := c.WriteStmt(stmt); err != nil {
|
|
@@ -873,6 +878,7 @@ func (c *GoToTSCompiler) WriteCaseClause(exp *ast.CaseClause) error {
|
|
|
873
878
|
// Add break statement (Go's switch has implicit breaks, TS needs explicit break)
|
|
874
879
|
c.tsw.WriteLine("break")
|
|
875
880
|
c.tsw.Indent(-1)
|
|
881
|
+
c.tsw.WriteLine("}")
|
|
876
882
|
return nil
|
|
877
883
|
}
|
|
878
884
|
|
package/compiler/decl.go
CHANGED
|
@@ -252,122 +252,82 @@ func (c *GoToTSCompiler) extractStructFieldDependencies(fieldType ast.Expr, type
|
|
|
252
252
|
return deps
|
|
253
253
|
}
|
|
254
254
|
|
|
255
|
-
// sortVarSpecsByTypeDependencies sorts variable declarations based on their
|
|
255
|
+
// sortVarSpecsByTypeDependencies sorts variable declarations based on their value dependencies
|
|
256
|
+
// to ensure that variables are initialized in the correct order (respecting JavaScript's TDZ).
|
|
257
|
+
// For example: var StdEncoding = NewEncoding(...) must come before var RawStdEncoding = StdEncoding.WithPadding(...)
|
|
256
258
|
func (c *GoToTSCompiler) sortVarSpecsByTypeDependencies(varSpecs []*ast.ValueSpec, typeSpecs []*ast.TypeSpec) ([]*ast.ValueSpec, error) {
|
|
257
259
|
if len(varSpecs) <= 1 {
|
|
258
260
|
return varSpecs, nil
|
|
259
261
|
}
|
|
260
262
|
|
|
261
|
-
// Build
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
typeSpecMap[typeSpec.Name.Name] = typeSpec
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
// Group variables by dependency status with names for sorting
|
|
268
|
-
type namedVarSpec struct {
|
|
269
|
-
spec *ast.ValueSpec
|
|
270
|
-
name string
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
var independentVars []namedVarSpec
|
|
274
|
-
var dependentVars []namedVarSpec
|
|
275
|
-
|
|
263
|
+
// Build a map of variable names to their specs
|
|
264
|
+
varSpecMap := make(map[string]*ast.ValueSpec)
|
|
265
|
+
varNames := []string{}
|
|
276
266
|
for _, varSpec := range varSpecs {
|
|
277
|
-
// Get variable name for sorting
|
|
278
|
-
varName := ""
|
|
279
267
|
if len(varSpec.Names) > 0 {
|
|
280
|
-
|
|
268
|
+
name := varSpec.Names[0].Name
|
|
269
|
+
varSpecMap[name] = varSpec
|
|
270
|
+
varNames = append(varNames, name)
|
|
281
271
|
}
|
|
272
|
+
}
|
|
282
273
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
if len(deps) > 0 {
|
|
289
|
-
hasDependency = true
|
|
290
|
-
}
|
|
291
|
-
}
|
|
274
|
+
// Build dependency graph: varName -> list of variables it depends on
|
|
275
|
+
dependencies := make(map[string][]string)
|
|
276
|
+
for _, name := range varNames {
|
|
277
|
+
dependencies[name] = []string{}
|
|
278
|
+
}
|
|
292
279
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
hasDependency = true
|
|
298
|
-
break
|
|
299
|
-
}
|
|
300
|
-
}
|
|
280
|
+
// Extract value dependencies from initializer expressions
|
|
281
|
+
for _, varSpec := range varSpecs {
|
|
282
|
+
if len(varSpec.Names) == 0 {
|
|
283
|
+
continue
|
|
301
284
|
}
|
|
285
|
+
varName := varSpec.Names[0].Name
|
|
302
286
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
independentVars = append(independentVars, namedVar)
|
|
287
|
+
// Check initializer expressions for variable references
|
|
288
|
+
for _, value := range varSpec.Values {
|
|
289
|
+
deps := c.extractVarDependencies(value, varSpecMap)
|
|
290
|
+
dependencies[varName] = append(dependencies[varName], deps...)
|
|
308
291
|
}
|
|
309
292
|
}
|
|
310
293
|
|
|
311
|
-
//
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
return dependentVars[i].name < dependentVars[j].name
|
|
317
|
-
})
|
|
294
|
+
// Perform topological sort
|
|
295
|
+
sorted, err := c.topologicalSort(dependencies)
|
|
296
|
+
if err != nil {
|
|
297
|
+
return nil, err
|
|
298
|
+
}
|
|
318
299
|
|
|
319
|
-
//
|
|
300
|
+
// Build result in sorted order
|
|
320
301
|
result := make([]*ast.ValueSpec, 0, len(varSpecs))
|
|
321
|
-
for _,
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
result = append(result, namedVar.spec)
|
|
302
|
+
for _, varName := range sorted {
|
|
303
|
+
if spec, exists := varSpecMap[varName]; exists {
|
|
304
|
+
result = append(result, spec)
|
|
305
|
+
}
|
|
326
306
|
}
|
|
327
307
|
|
|
328
308
|
return result, nil
|
|
329
309
|
}
|
|
330
310
|
|
|
331
|
-
//
|
|
332
|
-
|
|
333
|
-
|
|
311
|
+
// extractVarDependencies extracts variable dependencies from an initializer expression.
|
|
312
|
+
// It returns a list of variable names that the expression depends on.
|
|
313
|
+
func (c *GoToTSCompiler) extractVarDependencies(expr ast.Expr, varSpecMap map[string]*ast.ValueSpec) []string {
|
|
314
|
+
var deps []string
|
|
315
|
+
seen := make(map[string]bool)
|
|
334
316
|
|
|
335
317
|
ast.Inspect(expr, func(n ast.Node) bool {
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
return false
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
// Check type arguments in generic calls
|
|
346
|
-
if funcType, ok := t.Fun.(*ast.IndexExpr); ok {
|
|
347
|
-
if c.hasTypeReferences(funcType.Index, typeSpecMap) {
|
|
348
|
-
hasRef = true
|
|
349
|
-
return false
|
|
318
|
+
if ident, ok := n.(*ast.Ident); ok {
|
|
319
|
+
// Check if this identifier refers to a package-level variable
|
|
320
|
+
if _, isVar := varSpecMap[ident.Name]; isVar {
|
|
321
|
+
if !seen[ident.Name] {
|
|
322
|
+
deps = append(deps, ident.Name)
|
|
323
|
+
seen[ident.Name] = true
|
|
350
324
|
}
|
|
351
325
|
}
|
|
352
|
-
case *ast.CompositeLit:
|
|
353
|
-
// Check composite literals like Message{...}
|
|
354
|
-
if ident, ok := t.Type.(*ast.Ident); ok {
|
|
355
|
-
if _, isLocalType := typeSpecMap[ident.Name]; isLocalType {
|
|
356
|
-
hasRef = true
|
|
357
|
-
return false
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
case *ast.Ident:
|
|
361
|
-
// Check direct type references
|
|
362
|
-
if _, isLocalType := typeSpecMap[t.Name]; isLocalType {
|
|
363
|
-
hasRef = true
|
|
364
|
-
return false
|
|
365
|
-
}
|
|
366
326
|
}
|
|
367
|
-
return
|
|
327
|
+
return true
|
|
368
328
|
})
|
|
369
329
|
|
|
370
|
-
return
|
|
330
|
+
return deps
|
|
371
331
|
}
|
|
372
332
|
|
|
373
333
|
// topologicalSort performs a topological sort of the dependency graph
|
|
@@ -108,3 +108,185 @@ func (c *GoToTSCompiler) writeExprOrDefault(expr interface{}, defaultValue strin
|
|
|
108
108
|
return errors.Errorf("unsupported expression type in writeExprOrDefault: %T", e)
|
|
109
109
|
}
|
|
110
110
|
}
|
|
111
|
+
|
|
112
|
+
// writeReflectTypeFor handles reflect.TypeFor[T]() calls by generating appropriate TypeScript
|
|
113
|
+
func (c *GoToTSCompiler) writeReflectTypeFor(exp *ast.CallExpr, selectorExpr *ast.SelectorExpr) (handled bool, err error) {
|
|
114
|
+
// Check if this is reflect.TypeFor
|
|
115
|
+
if selectorExpr.Sel.Name != "TypeFor" {
|
|
116
|
+
return false, nil
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Check if X is an identifier referring to the reflect package
|
|
120
|
+
xIdent, ok := selectorExpr.X.(*ast.Ident)
|
|
121
|
+
if !ok {
|
|
122
|
+
return false, nil
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
obj := c.objectOfIdent(xIdent)
|
|
126
|
+
if obj == nil {
|
|
127
|
+
return false, nil
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
pkgName, ok := obj.(*types.PkgName)
|
|
131
|
+
if !ok || pkgName.Imported().Path() != "reflect" {
|
|
132
|
+
return false, nil
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// DEBUG: We found reflect.TypeFor
|
|
136
|
+
// fmt.Printf("DEBUG: Found reflect.TypeFor call\n")
|
|
137
|
+
|
|
138
|
+
// This is reflect.TypeFor - now get the type argument
|
|
139
|
+
if c.pkg.TypesInfo.Instances == nil {
|
|
140
|
+
return false, errors.New("reflect.TypeFor called but no type instances available")
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
instance, hasInstance := c.pkg.TypesInfo.Instances[selectorExpr.Sel]
|
|
144
|
+
if !hasInstance || instance.TypeArgs == nil || instance.TypeArgs.Len() == 0 {
|
|
145
|
+
return false, errors.New("reflect.TypeFor called without type arguments")
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Get the first type argument
|
|
149
|
+
typeArg := instance.TypeArgs.At(0)
|
|
150
|
+
// fmt.Printf("DEBUG: Type argument: %v\n", typeArg)
|
|
151
|
+
|
|
152
|
+
// Generate TypeScript code to create a Type for this type
|
|
153
|
+
if err := c.writeTypeForTypeArg(typeArg); err != nil {
|
|
154
|
+
return true, err
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return true, nil
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// writeTypeForTypeArg generates TypeScript code to create a reflect.Type for the given Go type
|
|
161
|
+
func (c *GoToTSCompiler) writeTypeForTypeArg(t types.Type) error {
|
|
162
|
+
// Handle basic types
|
|
163
|
+
switch underlying := t.Underlying().(type) {
|
|
164
|
+
case *types.Basic:
|
|
165
|
+
return c.writeBasicTypeFor(underlying)
|
|
166
|
+
case *types.Named:
|
|
167
|
+
// For named types, use TypeOf with a zero value
|
|
168
|
+
return c.writeNamedTypeFor(t)
|
|
169
|
+
case *types.Pointer:
|
|
170
|
+
// For pointer types, use PointerTo
|
|
171
|
+
c.tsw.WriteLiterally("reflect.PointerTo(")
|
|
172
|
+
if err := c.writeTypeForTypeArg(underlying.Elem()); err != nil {
|
|
173
|
+
return err
|
|
174
|
+
}
|
|
175
|
+
c.tsw.WriteLiterally(")")
|
|
176
|
+
return nil
|
|
177
|
+
case *types.Slice:
|
|
178
|
+
// For slice types, use TypeOf with an empty slice
|
|
179
|
+
c.tsw.WriteLiterally("reflect.TypeOf([])")
|
|
180
|
+
return nil
|
|
181
|
+
case *types.Array:
|
|
182
|
+
// For array types, use TypeOf with an empty array
|
|
183
|
+
c.tsw.WriteLiterally("reflect.TypeOf([])")
|
|
184
|
+
return nil
|
|
185
|
+
case *types.Struct:
|
|
186
|
+
// For struct types, use TypeOf with zero value
|
|
187
|
+
return c.writeNamedTypeFor(t)
|
|
188
|
+
case *types.Interface:
|
|
189
|
+
// For interface types, use TypeOf with null
|
|
190
|
+
return c.writeNamedTypeFor(t)
|
|
191
|
+
default:
|
|
192
|
+
return errors.Errorf("unsupported type for reflect.TypeFor: %T", underlying)
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// writeBasicTypeFor generates code for basic types
|
|
197
|
+
func (c *GoToTSCompiler) writeBasicTypeFor(basic *types.Basic) error {
|
|
198
|
+
// Map basic types to their reflect constructors or TypeOf calls
|
|
199
|
+
// Note: We don't pass type parameters to TypeOf - it infers from the value
|
|
200
|
+
switch basic.Kind() {
|
|
201
|
+
case types.Bool:
|
|
202
|
+
c.tsw.WriteLiterally("reflect.TypeOf(false)")
|
|
203
|
+
case types.Int:
|
|
204
|
+
c.tsw.WriteLiterally("reflect.TypeOf(0)")
|
|
205
|
+
case types.Int8:
|
|
206
|
+
c.tsw.WriteLiterally("reflect.TypeOf(0)")
|
|
207
|
+
case types.Int16:
|
|
208
|
+
c.tsw.WriteLiterally("reflect.TypeOf(0)")
|
|
209
|
+
case types.Int32:
|
|
210
|
+
c.tsw.WriteLiterally("reflect.TypeOf(0)")
|
|
211
|
+
case types.Int64:
|
|
212
|
+
c.tsw.WriteLiterally("reflect.TypeOf(0n)")
|
|
213
|
+
case types.Uint:
|
|
214
|
+
c.tsw.WriteLiterally("reflect.TypeOf(0)")
|
|
215
|
+
case types.Uint8:
|
|
216
|
+
c.tsw.WriteLiterally("reflect.TypeOf(0)")
|
|
217
|
+
case types.Uint16:
|
|
218
|
+
c.tsw.WriteLiterally("reflect.TypeOf(0)")
|
|
219
|
+
case types.Uint32:
|
|
220
|
+
c.tsw.WriteLiterally("reflect.TypeOf(0)")
|
|
221
|
+
case types.Uint64:
|
|
222
|
+
c.tsw.WriteLiterally("reflect.TypeOf(0n)")
|
|
223
|
+
case types.Uintptr:
|
|
224
|
+
c.tsw.WriteLiterally("reflect.TypeOf(0)")
|
|
225
|
+
case types.Float32:
|
|
226
|
+
c.tsw.WriteLiterally("reflect.TypeOf(0)")
|
|
227
|
+
case types.Float64:
|
|
228
|
+
c.tsw.WriteLiterally("reflect.TypeOf(0)")
|
|
229
|
+
case types.Complex64:
|
|
230
|
+
c.tsw.WriteLiterally("reflect.TypeOf([0, 0])")
|
|
231
|
+
case types.Complex128:
|
|
232
|
+
c.tsw.WriteLiterally("reflect.TypeOf([0, 0])")
|
|
233
|
+
case types.String:
|
|
234
|
+
c.tsw.WriteLiterally("reflect.TypeOf(\"\")")
|
|
235
|
+
case types.UnsafePointer:
|
|
236
|
+
c.tsw.WriteLiterally("reflect.TypeOf(null)")
|
|
237
|
+
default:
|
|
238
|
+
return errors.Errorf("unsupported basic type for reflect.TypeFor: %v", basic)
|
|
239
|
+
}
|
|
240
|
+
return nil
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// writeNamedTypeFor generates code for named types (structs, interfaces, etc.)
|
|
244
|
+
func (c *GoToTSCompiler) writeNamedTypeFor(t types.Type) error {
|
|
245
|
+
// For interface types, we need special handling since null doesn't carry type info
|
|
246
|
+
if _, ok := t.Underlying().(*types.Interface); ok {
|
|
247
|
+
if named, ok := t.(*types.Named); ok {
|
|
248
|
+
obj := named.Obj()
|
|
249
|
+
pkgPath := ""
|
|
250
|
+
if pkg := obj.Pkg(); pkg != nil {
|
|
251
|
+
if pkg.Name() == "main" {
|
|
252
|
+
pkgPath = "main."
|
|
253
|
+
} else if pkg.Path() != "" {
|
|
254
|
+
pkgPath = pkg.Path() + "."
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
typeName := pkgPath + obj.Name()
|
|
258
|
+
c.tsw.WriteLiterally("reflect.getInterfaceTypeByName(\"" + typeName + "\")")
|
|
259
|
+
return nil
|
|
260
|
+
}
|
|
261
|
+
// For anonymous interfaces, use TypeOf(null)
|
|
262
|
+
c.tsw.WriteLiterally("reflect.TypeOf(null)")
|
|
263
|
+
return nil
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// For named types, we need to create a zero value and call TypeOf
|
|
267
|
+
// Note: We don't pass a type parameter to TypeOf - it infers the type from the value
|
|
268
|
+
c.tsw.WriteLiterally("reflect.TypeOf(")
|
|
269
|
+
|
|
270
|
+
// Generate a zero value for this type
|
|
271
|
+
switch underlying := t.Underlying().(type) {
|
|
272
|
+
case *types.Struct:
|
|
273
|
+
// For struct types: new MyStruct()
|
|
274
|
+
// Check if this is a named type
|
|
275
|
+
if _, ok := t.(*types.Named); ok {
|
|
276
|
+
c.tsw.WriteLiterally("new ")
|
|
277
|
+
c.WriteGoType(t, GoTypeContextGeneral)
|
|
278
|
+
c.tsw.WriteLiterally("()")
|
|
279
|
+
} else {
|
|
280
|
+
// Anonymous struct
|
|
281
|
+
c.tsw.WriteLiterally("{}")
|
|
282
|
+
}
|
|
283
|
+
case *types.Basic:
|
|
284
|
+
// For basic types wrapped in named types
|
|
285
|
+
return c.writeBasicTypeFor(underlying)
|
|
286
|
+
default:
|
|
287
|
+
return errors.Errorf("unsupported named type underlying for reflect.TypeFor: %T", underlying)
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
c.tsw.WriteLiterally(")")
|
|
291
|
+
return nil
|
|
292
|
+
}
|
package/compiler/expr-call.go
CHANGED
|
@@ -5,7 +5,6 @@ import (
|
|
|
5
5
|
"go/ast"
|
|
6
6
|
"go/token"
|
|
7
7
|
"go/types"
|
|
8
|
-
"strings"
|
|
9
8
|
)
|
|
10
9
|
|
|
11
10
|
// WriteCallExpr translates a Go function call expression (`ast.CallExpr`)
|
|
@@ -97,6 +96,15 @@ func (c *GoToTSCompiler) WriteCallExpr(exp *ast.CallExpr) error {
|
|
|
97
96
|
}
|
|
98
97
|
}
|
|
99
98
|
|
|
99
|
+
// Handle reflect.TypeFor[T]() - Fun is IndexExpr where X is SelectorExpr
|
|
100
|
+
if indexExpr, ok := expFun.(*ast.IndexExpr); ok {
|
|
101
|
+
if selectorExpr, ok := indexExpr.X.(*ast.SelectorExpr); ok {
|
|
102
|
+
if handled, err := c.writeReflectTypeFor(exp, selectorExpr); handled {
|
|
103
|
+
return err
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
100
108
|
// Handle non-identifier function expressions (method calls, function literals, etc.)
|
|
101
109
|
// Check if this is an async method call (e.g., mu.Lock())
|
|
102
110
|
c.writeAsyncCallIfNeeded(exp)
|
|
@@ -246,35 +254,6 @@ func (c *GoToTSCompiler) getQualifiedTypeName(t types.Type) string {
|
|
|
246
254
|
return obj.Name()
|
|
247
255
|
}
|
|
248
256
|
|
|
249
|
-
// getImportAlias returns the import alias for a given package path
|
|
250
|
-
// Deprecated: use resolveImportAlias instead for better type safety
|
|
251
|
-
func (c *GoToTSCompiler) getImportAlias(pkgPath string) string {
|
|
252
|
-
if c.analysis == nil {
|
|
253
|
-
return ""
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
// First try to find by exact package path
|
|
257
|
-
for importAlias := range c.analysis.Imports {
|
|
258
|
-
if importInfo := c.analysis.Imports[importAlias]; importInfo != nil {
|
|
259
|
-
if importInfo.importPath == pkgPath {
|
|
260
|
-
return importAlias
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
// Fallback: try to match by package name extracted from path
|
|
266
|
-
parts := strings.Split(pkgPath, "/")
|
|
267
|
-
defaultPkgName := parts[len(parts)-1]
|
|
268
|
-
|
|
269
|
-
for importAlias := range c.analysis.Imports {
|
|
270
|
-
if importAlias == defaultPkgName {
|
|
271
|
-
return importAlias
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
return ""
|
|
276
|
-
}
|
|
277
|
-
|
|
278
257
|
// writeAutoWrappedArgument writes an argument, auto-wrapping it if needed based on the expected parameter type
|
|
279
258
|
func (c *GoToTSCompiler) writeAutoWrappedArgument(arg ast.Expr, expectedType types.Type) error {
|
|
280
259
|
// For wrapper types (now type aliases), no auto-wrapping is needed
|
|
@@ -27,10 +27,18 @@ func (c *GoToTSCompiler) WriteSelectorExpr(exp *ast.SelectorExpr) error {
|
|
|
27
27
|
// Check if this is a package selector (e.g., time.Now)
|
|
28
28
|
if pkgIdent, isPkgIdent := exp.X.(*ast.Ident); isPkgIdent {
|
|
29
29
|
if obj := c.pkg.TypesInfo.ObjectOf(pkgIdent); obj != nil {
|
|
30
|
-
if
|
|
30
|
+
if pkgName, isPkg := obj.(*types.PkgName); isPkg {
|
|
31
31
|
// Package selectors should never use .value on the package name
|
|
32
32
|
c.tsw.WriteLiterally(pkgIdent.Name)
|
|
33
33
|
c.tsw.WriteLiterally(".")
|
|
34
|
+
|
|
35
|
+
// Special case: reflect.Pointer should be translated to reflect.Ptr
|
|
36
|
+
// (Go has both names for the same Kind constant)
|
|
37
|
+
if pkgName.Imported().Path() == "reflect" && exp.Sel.Name == "Pointer" {
|
|
38
|
+
c.tsw.WriteLiterally("Ptr")
|
|
39
|
+
return nil
|
|
40
|
+
}
|
|
41
|
+
|
|
34
42
|
// Write the selected identifier, allowing .value if it's a varrefed package variable
|
|
35
43
|
c.WriteIdent(exp.Sel, true)
|
|
36
44
|
return nil
|
|
@@ -189,6 +197,35 @@ func (c *GoToTSCompiler) writeMethodValue(exp *ast.SelectorExpr, selection *type
|
|
|
189
197
|
baseIsPointer = true
|
|
190
198
|
}
|
|
191
199
|
|
|
200
|
+
// Check if the receiver is a primitive/wrapper type
|
|
201
|
+
underlyingRecvType := recvType
|
|
202
|
+
if ptr, ok := recvType.(*types.Pointer); ok {
|
|
203
|
+
underlyingRecvType = ptr.Elem()
|
|
204
|
+
}
|
|
205
|
+
isPrimitiveReceiver := c.isWrapperType(underlyingRecvType)
|
|
206
|
+
|
|
207
|
+
// For primitive types, generate a closure that captures the receiver and calls the free function
|
|
208
|
+
if isPrimitiveReceiver {
|
|
209
|
+
// Get the type name for the free function
|
|
210
|
+
typeName := c.getQualifiedTypeName(underlyingRecvType)
|
|
211
|
+
if typeName == "" {
|
|
212
|
+
return fmt.Errorf("failed to get qualified type name for primitive receiver")
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Generate: () => TypeName_MethodName(receiverValue)
|
|
216
|
+
c.tsw.WriteLiterally("(() => ")
|
|
217
|
+
c.tsw.WriteLiterally(typeName)
|
|
218
|
+
c.tsw.WriteLiterally("_")
|
|
219
|
+
c.tsw.WriteLiterally(exp.Sel.Name)
|
|
220
|
+
c.tsw.WriteLiterally("(")
|
|
221
|
+
if err := c.WriteValueExpr(exp.X); err != nil {
|
|
222
|
+
return fmt.Errorf("failed to write method value receiver: %w", err)
|
|
223
|
+
}
|
|
224
|
+
c.tsw.WriteLiterally("))")
|
|
225
|
+
|
|
226
|
+
return nil
|
|
227
|
+
}
|
|
228
|
+
|
|
192
229
|
// Write the receiver expression
|
|
193
230
|
if err := c.WriteValueExpr(exp.X); err != nil {
|
|
194
231
|
return fmt.Errorf("failed to write method value receiver: %w", err)
|
package/compiler/expr-type.go
CHANGED
|
@@ -134,11 +134,47 @@ func (c *GoToTSCompiler) writeTypeDescription(typeExpr ast.Expr) {
|
|
|
134
134
|
c.tsw.WriteLiterally("}")
|
|
135
135
|
}
|
|
136
136
|
} else {
|
|
137
|
-
// For named types,
|
|
137
|
+
// For named types, use the fully qualified name with package path
|
|
138
|
+
if goType != nil {
|
|
139
|
+
if namedType, isNamed := goType.(*types.Named); isNamed {
|
|
140
|
+
typeName := namedType.Obj().Name()
|
|
141
|
+
if pkg := namedType.Obj().Pkg(); pkg != nil {
|
|
142
|
+
pkgPath := pkg.Path()
|
|
143
|
+
pkgName := pkg.Name()
|
|
144
|
+
if pkgPath != "" && pkgName != "main" {
|
|
145
|
+
typeName = pkgPath + "." + typeName
|
|
146
|
+
} else if pkgName == "main" {
|
|
147
|
+
typeName = "main." + typeName
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
c.tsw.WriteLiterallyf("'%s'", typeName)
|
|
151
|
+
return
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
// Fallback to short name if type info unavailable
|
|
138
155
|
c.tsw.WriteLiterallyf("'%s'", t.Name)
|
|
139
156
|
}
|
|
140
157
|
case *ast.SelectorExpr:
|
|
141
158
|
if ident, ok := t.X.(*ast.Ident); ok {
|
|
159
|
+
// Use type info to get the actual package path
|
|
160
|
+
goType := c.pkg.TypesInfo.TypeOf(t)
|
|
161
|
+
if goType != nil {
|
|
162
|
+
if namedType, isNamed := goType.(*types.Named); isNamed {
|
|
163
|
+
typeName := namedType.Obj().Name()
|
|
164
|
+
if pkg := namedType.Obj().Pkg(); pkg != nil {
|
|
165
|
+
pkgPath := pkg.Path()
|
|
166
|
+
pkgName := pkg.Name()
|
|
167
|
+
if pkgPath != "" && pkgName != "main" {
|
|
168
|
+
typeName = pkgPath + "." + typeName
|
|
169
|
+
} else if pkgName == "main" {
|
|
170
|
+
typeName = "main." + typeName
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
c.tsw.WriteLiterallyf("'%s'", typeName)
|
|
174
|
+
return
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
// Fallback to using the identifier name (package alias)
|
|
142
178
|
c.tsw.WriteLiterallyf("'%s.%s'", ident.Name, t.Sel.Name)
|
|
143
179
|
}
|
|
144
180
|
case *ast.ArrayType:
|
package/compiler/expr.go
CHANGED
|
@@ -251,34 +251,6 @@ func (c *GoToTSCompiler) getTypeNameString(typeExpr ast.Expr) string {
|
|
|
251
251
|
return "unknown"
|
|
252
252
|
}
|
|
253
253
|
|
|
254
|
-
// getFinalUnderlyingType traverses the chain of named types to find the ultimate underlying type.
|
|
255
|
-
// This handles cases like: type A B; type B C; type C string.
|
|
256
|
-
// Returns the final underlying type and whether the original type was a named type.
|
|
257
|
-
func (c *GoToTSCompiler) getFinalUnderlyingType(t types.Type) (types.Type, bool) {
|
|
258
|
-
if t == nil {
|
|
259
|
-
return nil, false
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
// Check if this is a named type
|
|
263
|
-
namedType, isNamed := t.(*types.Named)
|
|
264
|
-
if !isNamed {
|
|
265
|
-
return t, false
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
// Follow the chain of named types to find the ultimate underlying type
|
|
269
|
-
ultimate := namedType
|
|
270
|
-
for {
|
|
271
|
-
underlying := ultimate.Underlying()
|
|
272
|
-
if underlyingNamed, isNamedUnderlying := underlying.(*types.Named); isNamedUnderlying {
|
|
273
|
-
// Continue following the chain
|
|
274
|
-
ultimate = underlyingNamed
|
|
275
|
-
} else {
|
|
276
|
-
// We've reached the final underlying type
|
|
277
|
-
return underlying, true
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
|
|
282
254
|
// WriteBinaryExpr translates a Go binary expression (`ast.BinaryExpr`) into its
|
|
283
255
|
// TypeScript equivalent.
|
|
284
256
|
// It handles several cases:
|
package/compiler/spec-struct.go
CHANGED
|
@@ -429,8 +429,19 @@ func (c *GoToTSCompiler) WriteStructTypeSpec(a *ast.TypeSpec, t *ast.StructType)
|
|
|
429
429
|
// Add code to register the type with the runtime type system
|
|
430
430
|
c.tsw.WriteLine("")
|
|
431
431
|
c.tsw.WriteLinef("// Register this type with the runtime type system")
|
|
432
|
+
|
|
433
|
+
// Build full package path name for registration
|
|
434
|
+
structName := className
|
|
435
|
+
pkgPath := c.pkg.Types.Path()
|
|
436
|
+
pkgName := c.pkg.Types.Name()
|
|
437
|
+
if pkgPath != "" && pkgName != "main" {
|
|
438
|
+
structName = pkgPath + "." + className
|
|
439
|
+
} else if pkgName == "main" {
|
|
440
|
+
structName = "main." + className
|
|
441
|
+
}
|
|
442
|
+
|
|
432
443
|
c.tsw.WriteLinef("static __typeInfo = $.registerStructType(")
|
|
433
|
-
c.tsw.WriteLinef(" '%s',",
|
|
444
|
+
c.tsw.WriteLinef(" '%s',", structName)
|
|
434
445
|
c.tsw.WriteLinef(" new %s(),", className)
|
|
435
446
|
c.tsw.WriteLiterally(" [")
|
|
436
447
|
// Collect methods for the struct type
|
package/compiler/spec.go
CHANGED
|
@@ -121,7 +121,7 @@ func (c *GoToTSCompiler) writeEmbeddedFieldInitializer(fieldName string, fieldTy
|
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
// For structs, instantiate with provided fields
|
|
124
|
-
typeForNew :=
|
|
124
|
+
typeForNew := c.getTypeString(fieldType)
|
|
125
125
|
c.tsw.WriteLiterallyf("new %s(init?.%s)", typeForNew, fieldName)
|
|
126
126
|
}
|
|
127
127
|
|
|
@@ -224,6 +224,12 @@ func (c *GoToTSCompiler) writeNamedTypeZeroValue(named *types.Named) {
|
|
|
224
224
|
return
|
|
225
225
|
}
|
|
226
226
|
|
|
227
|
+
// Check if underlying type is a function
|
|
228
|
+
if _, isFunc := named.Underlying().(*types.Signature); isFunc {
|
|
229
|
+
c.tsw.WriteLiterally("null")
|
|
230
|
+
return
|
|
231
|
+
}
|
|
232
|
+
|
|
227
233
|
// For non-struct, non-interface named types, use constructor
|
|
228
234
|
c.tsw.WriteLiterally("new ")
|
|
229
235
|
c.WriteNamedType(named)
|
|
@@ -254,6 +260,12 @@ func (c *GoToTSCompiler) writeTypeAliasZeroValue(alias *types.Alias, astType ast
|
|
|
254
260
|
return
|
|
255
261
|
}
|
|
256
262
|
|
|
263
|
+
// Check if underlying type is a function
|
|
264
|
+
if _, isFunc := alias.Underlying().(*types.Signature); isFunc {
|
|
265
|
+
c.tsw.WriteLiterally("null")
|
|
266
|
+
return
|
|
267
|
+
}
|
|
268
|
+
|
|
257
269
|
// For non-struct, non-interface type aliases, use constructor
|
|
258
270
|
c.tsw.WriteLiterally("new ")
|
|
259
271
|
// Use AST type information if available to preserve qualified names
|
|
@@ -521,7 +533,15 @@ func (c *GoToTSCompiler) WriteInterfaceTypeSpec(a *ast.TypeSpec, t *ast.Interfac
|
|
|
521
533
|
c.tsw.WriteLine("")
|
|
522
534
|
|
|
523
535
|
// Add code to register the interface with the runtime system
|
|
536
|
+
// Build full package path name for registration
|
|
524
537
|
interfaceName := a.Name.Name
|
|
538
|
+
pkgPath := c.pkg.Types.Path()
|
|
539
|
+
pkgName := c.pkg.Types.Name()
|
|
540
|
+
if pkgPath != "" && pkgName != "main" {
|
|
541
|
+
interfaceName = pkgPath + "." + interfaceName
|
|
542
|
+
} else if pkgName == "main" {
|
|
543
|
+
interfaceName = "main." + interfaceName
|
|
544
|
+
}
|
|
525
545
|
c.tsw.WriteLine("")
|
|
526
546
|
c.tsw.WriteLinef("$.registerInterfaceType(")
|
|
527
547
|
c.tsw.WriteLinef(" '%s',", interfaceName)
|