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.
Files changed (39) hide show
  1. package/compiler/analysis.go +465 -336
  2. package/compiler/compiler.go +10 -4
  3. package/compiler/decl.go +47 -87
  4. package/compiler/expr-call-helpers.go +182 -0
  5. package/compiler/expr-call.go +9 -30
  6. package/compiler/expr-selector.go +38 -1
  7. package/compiler/expr-type.go +37 -1
  8. package/compiler/expr.go +0 -28
  9. package/compiler/spec-struct.go +12 -1
  10. package/compiler/spec.go +21 -1
  11. package/compiler/stmt.go +2 -10
  12. package/compiler/type-utils.go +0 -15
  13. package/dist/gs/builtin/slice.js +6 -7
  14. package/dist/gs/builtin/slice.js.map +1 -1
  15. package/dist/gs/builtin/type.d.ts +5 -0
  16. package/dist/gs/builtin/type.js +7 -0
  17. package/dist/gs/builtin/type.js.map +1 -1
  18. package/dist/gs/internal/byteorder/index.d.ts +6 -0
  19. package/dist/gs/internal/byteorder/index.js +34 -0
  20. package/dist/gs/internal/byteorder/index.js.map +1 -1
  21. package/dist/gs/reflect/index.d.ts +3 -3
  22. package/dist/gs/reflect/index.js +2 -2
  23. package/dist/gs/reflect/index.js.map +1 -1
  24. package/dist/gs/reflect/type.d.ts +9 -0
  25. package/dist/gs/reflect/type.js +73 -0
  26. package/dist/gs/reflect/type.js.map +1 -1
  27. package/dist/gs/slices/slices.d.ts +11 -0
  28. package/dist/gs/slices/slices.js +33 -0
  29. package/dist/gs/slices/slices.js.map +1 -1
  30. package/go.mod +4 -4
  31. package/go.sum +8 -8
  32. package/gs/builtin/slice.ts +6 -7
  33. package/gs/builtin/type.ts +8 -0
  34. package/gs/internal/byteorder/index.ts +40 -0
  35. package/gs/reflect/index.ts +3 -1
  36. package/gs/reflect/type.ts +97 -0
  37. package/gs/slices/slices.ts +37 -0
  38. package/gs/sync/meta.json +1 -1
  39. package/package.json +1 -1
@@ -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 _, caseExpr := range exp.List {
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
- c.tsw.WriteLine("")
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
- // Indentation for the body starts here.
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 type dependencies
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 type name map
262
- typeSpecMap := make(map[string]*ast.TypeSpec)
263
- for _, typeSpec := range typeSpecs {
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
- varName = varSpec.Names[0].Name
268
+ name := varSpec.Names[0].Name
269
+ varSpecMap[name] = varSpec
270
+ varNames = append(varNames, name)
281
271
  }
272
+ }
282
273
 
283
- hasDependency := false
284
-
285
- // Check type annotation
286
- if varSpec.Type != nil {
287
- deps := c.extractTypeDependencies(varSpec.Type, typeSpecMap)
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
- // Check initializer expressions for type usage
294
- if !hasDependency {
295
- for _, value := range varSpec.Values {
296
- if c.hasTypeReferences(value, typeSpecMap) {
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
- namedVar := namedVarSpec{spec: varSpec, name: varName}
304
- if hasDependency {
305
- dependentVars = append(dependentVars, namedVar)
306
- } else {
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
- // Sort both groups by name for deterministic output
312
- sort.Slice(independentVars, func(i, j int) bool {
313
- return independentVars[i].name < independentVars[j].name
314
- })
315
- sort.Slice(dependentVars, func(i, j int) bool {
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
- // Return independent variables first, then dependent ones
300
+ // Build result in sorted order
320
301
  result := make([]*ast.ValueSpec, 0, len(varSpecs))
321
- for _, namedVar := range independentVars {
322
- result = append(result, namedVar.spec)
323
- }
324
- for _, namedVar := range dependentVars {
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
- // hasTypeReferences checks if an expression contains references to local types
332
- func (c *GoToTSCompiler) hasTypeReferences(expr ast.Expr, typeSpecMap map[string]*ast.TypeSpec) bool {
333
- hasRef := false
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
- switch t := n.(type) {
337
- case *ast.CallExpr:
338
- // Check function calls like new Message(), makeChannel<Message>()
339
- if ident, ok := t.Fun.(*ast.Ident); ok {
340
- if _, isLocalType := typeSpecMap[ident.Name]; isLocalType {
341
- hasRef = true
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 !hasRef // Stop walking if we found a reference
327
+ return true
368
328
  })
369
329
 
370
- return hasRef
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
+ }
@@ -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 _, isPkg := obj.(*types.PkgName); isPkg {
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)
@@ -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, just use the name string
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:
@@ -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',", className)
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 := fieldName
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)