goscript 0.0.42 → 0.0.43

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 (108) hide show
  1. package/compiler/analysis.go +87 -0
  2. package/compiler/assignment.go +6 -0
  3. package/compiler/compiler.go +85 -5
  4. package/compiler/decl.go +42 -20
  5. package/compiler/expr-call.go +37 -1
  6. package/compiler/expr-type.go +20 -0
  7. package/compiler/lit.go +4 -20
  8. package/compiler/spec-struct.go +3 -4
  9. package/compiler/spec-value.go +18 -1
  10. package/compiler/spec.go +15 -8
  11. package/compiler/stmt-range.go +1 -1
  12. package/compiler/type-assert.go +4 -4
  13. package/compiler/type.go +63 -5
  14. package/dist/gs/builtin/map.d.ts +4 -4
  15. package/dist/gs/builtin/map.js +6 -3
  16. package/dist/gs/builtin/map.js.map +1 -1
  17. package/dist/gs/builtin/slice.d.ts +7 -0
  18. package/dist/gs/builtin/slice.js +12 -0
  19. package/dist/gs/builtin/slice.js.map +1 -1
  20. package/dist/gs/builtin/type.js +8 -70
  21. package/dist/gs/builtin/type.js.map +1 -1
  22. package/dist/gs/fmt/fmt.d.ts +22 -21
  23. package/dist/gs/fmt/fmt.js +12 -12
  24. package/dist/gs/fmt/fmt.js.map +1 -1
  25. package/dist/gs/internal/testlog/index.d.ts +1 -0
  26. package/dist/gs/internal/testlog/index.js +5 -0
  27. package/dist/gs/internal/testlog/index.js.map +1 -0
  28. package/dist/gs/io/io.d.ts +13 -13
  29. package/dist/gs/io/io.js +31 -21
  30. package/dist/gs/io/io.js.map +1 -1
  31. package/dist/gs/maps/iter.gs.d.ts +7 -0
  32. package/dist/gs/maps/iter.gs.js +65 -0
  33. package/dist/gs/maps/iter.gs.js.map +1 -0
  34. package/dist/gs/maps/maps.gs.d.ts +7 -0
  35. package/dist/gs/maps/maps.gs.js +79 -0
  36. package/dist/gs/maps/maps.gs.js.map +1 -0
  37. package/dist/gs/path/filepath/match.d.ts +4 -3
  38. package/dist/gs/path/filepath/match.js +2 -2
  39. package/dist/gs/path/filepath/match.js.map +1 -1
  40. package/dist/gs/path/filepath/path.d.ts +2 -2
  41. package/dist/gs/path/filepath/path.js +3 -3
  42. package/dist/gs/path/filepath/path.js.map +1 -1
  43. package/dist/gs/reflect/abi.d.ts +59 -0
  44. package/dist/gs/reflect/abi.gs.d.ts +59 -0
  45. package/dist/gs/reflect/abi.gs.js +79 -0
  46. package/dist/gs/reflect/abi.gs.js.map +1 -0
  47. package/dist/gs/reflect/abi.js +79 -0
  48. package/dist/gs/reflect/abi.js.map +1 -0
  49. package/dist/gs/reflect/badlinkname.d.ts +52 -0
  50. package/dist/gs/reflect/badlinkname.gs.d.ts +52 -0
  51. package/dist/gs/reflect/badlinkname.gs.js +72 -0
  52. package/dist/gs/reflect/badlinkname.gs.js.map +1 -0
  53. package/dist/gs/reflect/badlinkname.js +72 -0
  54. package/dist/gs/reflect/badlinkname.js.map +1 -0
  55. package/dist/gs/reflect/deepequal.gs.d.ts +25 -0
  56. package/dist/gs/reflect/deepequal.gs.js +308 -0
  57. package/dist/gs/reflect/deepequal.gs.js.map +1 -0
  58. package/dist/gs/reflect/float32reg_generic.gs.d.ts +2 -0
  59. package/dist/gs/reflect/float32reg_generic.gs.js +10 -0
  60. package/dist/gs/reflect/float32reg_generic.gs.js.map +1 -0
  61. package/dist/gs/reflect/index.gs.d.ts +1 -0
  62. package/dist/gs/reflect/index.gs.js +3 -0
  63. package/dist/gs/reflect/index.gs.js.map +1 -0
  64. package/dist/gs/reflect/iter.gs.d.ts +3 -0
  65. package/dist/gs/reflect/iter.gs.js +24 -0
  66. package/dist/gs/reflect/iter.gs.js.map +1 -0
  67. package/dist/gs/reflect/makefunc.gs.d.ts +34 -0
  68. package/dist/gs/reflect/makefunc.gs.js +288 -0
  69. package/dist/gs/reflect/makefunc.gs.js.map +1 -0
  70. package/dist/gs/reflect/map_swiss.gs.d.ts +14 -0
  71. package/dist/gs/reflect/map_swiss.gs.js +70 -0
  72. package/dist/gs/reflect/map_swiss.gs.js.map +1 -0
  73. package/dist/gs/reflect/reflect.gs.d.ts +132 -0
  74. package/dist/gs/reflect/reflect.gs.js +437 -0
  75. package/dist/gs/reflect/reflect.gs.js.map +1 -0
  76. package/dist/gs/reflect/swapper.gs.d.ts +1 -0
  77. package/dist/gs/reflect/swapper.gs.js +32 -0
  78. package/dist/gs/reflect/swapper.gs.js.map +1 -0
  79. package/dist/gs/reflect/type.gs.d.ts +4 -0
  80. package/dist/gs/reflect/type.gs.js +21 -0
  81. package/dist/gs/reflect/type.gs.js.map +1 -0
  82. package/dist/gs/reflect/value.gs.d.ts +4 -0
  83. package/dist/gs/reflect/value.gs.js +12 -0
  84. package/dist/gs/reflect/value.gs.js.map +1 -0
  85. package/dist/gs/reflect/visiblefields.gs.d.ts +3 -0
  86. package/dist/gs/reflect/visiblefields.gs.js +123 -0
  87. package/dist/gs/reflect/visiblefields.gs.js.map +1 -0
  88. package/dist/gs/strings/reader.d.ts +1 -1
  89. package/dist/gs/strings/reader.js.map +1 -1
  90. package/dist/gs/stringslite/index.d.ts +1 -0
  91. package/dist/gs/stringslite/index.js +2 -0
  92. package/dist/gs/stringslite/index.js.map +1 -0
  93. package/dist/gs/stringslite/strings.d.ts +11 -0
  94. package/dist/gs/stringslite/strings.js +67 -0
  95. package/dist/gs/stringslite/strings.js.map +1 -0
  96. package/dist/gs/time/time.d.ts +69 -0
  97. package/dist/gs/time/time.js +350 -0
  98. package/dist/gs/time/time.js.map +1 -1
  99. package/gs/builtin/map.ts +12 -8
  100. package/gs/builtin/slice.ts +13 -0
  101. package/gs/builtin/type.ts +8 -100
  102. package/gs/fmt/fmt.ts +33 -33
  103. package/gs/io/io.ts +47 -39
  104. package/gs/path/filepath/match.ts +4 -4
  105. package/gs/path/filepath/path.ts +3 -3
  106. package/gs/strings/reader.ts +1 -1
  107. package/gs/time/time.ts +403 -0
  108. package/package.json +1 -1
@@ -125,6 +125,14 @@ type PackageAnalysis struct {
125
125
  // FunctionCalls maps file names to the functions they call from other files
126
126
  // Key: filename (without .go extension), Value: map[sourceFile][]functionNames
127
127
  FunctionCalls map[string]map[string][]string
128
+
129
+ // TypeDefs maps file names to the types defined in that file
130
+ // Key: filename (without .go extension), Value: list of type names
131
+ TypeDefs map[string][]string
132
+
133
+ // TypeCalls maps file names to the types they reference from other files
134
+ // Key: filename (without .go extension), Value: map[sourceFile][]typeNames
135
+ TypeCalls map[string]map[string][]string
128
136
  }
129
137
 
130
138
  // NewAnalysis creates a new Analysis instance.
@@ -146,6 +154,8 @@ func NewPackageAnalysis() *PackageAnalysis {
146
154
  return &PackageAnalysis{
147
155
  FunctionDefs: make(map[string][]string),
148
156
  FunctionCalls: make(map[string]map[string][]string),
157
+ TypeDefs: make(map[string][]string),
158
+ TypeCalls: make(map[string]map[string][]string),
149
159
  }
150
160
  }
151
161
 
@@ -1036,6 +1046,7 @@ func AnalyzePackage(pkg *packages.Package) *PackageAnalysis {
1036
1046
  baseFileName := strings.TrimSuffix(filepath.Base(fileName), ".go")
1037
1047
 
1038
1048
  var functions []string
1049
+ var types []string
1039
1050
  for _, decl := range syntax.Decls {
1040
1051
  if funcDecl, ok := decl.(*ast.FuncDecl); ok {
1041
1052
  // Only collect top-level functions (not methods)
@@ -1043,11 +1054,22 @@ func AnalyzePackage(pkg *packages.Package) *PackageAnalysis {
1043
1054
  functions = append(functions, funcDecl.Name.Name)
1044
1055
  }
1045
1056
  }
1057
+ if genDecl, ok := decl.(*ast.GenDecl); ok {
1058
+ // Collect type declarations
1059
+ for _, spec := range genDecl.Specs {
1060
+ if typeSpec, ok := spec.(*ast.TypeSpec); ok {
1061
+ types = append(types, typeSpec.Name.Name)
1062
+ }
1063
+ }
1064
+ }
1046
1065
  }
1047
1066
 
1048
1067
  if len(functions) > 0 {
1049
1068
  analysis.FunctionDefs[baseFileName] = functions
1050
1069
  }
1070
+ if len(types) > 0 {
1071
+ analysis.TypeDefs[baseFileName] = types
1072
+ }
1051
1073
  }
1052
1074
 
1053
1075
  // Second pass: analyze function calls and determine which need imports
@@ -1111,6 +1133,71 @@ func AnalyzePackage(pkg *packages.Package) *PackageAnalysis {
1111
1133
  }
1112
1134
  }
1113
1135
 
1136
+ // Third pass: analyze type references and determine which need imports
1137
+ for i, syntax := range pkg.Syntax {
1138
+ fileName := pkg.CompiledGoFiles[i]
1139
+ baseFileName := strings.TrimSuffix(filepath.Base(fileName), ".go")
1140
+
1141
+ // Find all type references in this file
1142
+ typeRefsFromOtherFiles := make(map[string][]string)
1143
+
1144
+ ast.Inspect(syntax, func(n ast.Node) bool {
1145
+ // Look for type references in struct fields, function parameters, etc.
1146
+ if ident, ok := n.(*ast.Ident); ok {
1147
+ // Check if this identifier refers to a type
1148
+ if obj := pkg.TypesInfo.Uses[ident]; obj != nil {
1149
+ if _, ok := obj.(*types.TypeName); ok {
1150
+ typeName := ident.Name
1151
+
1152
+ // Check if this type is defined in the current file
1153
+ currentFileTypes := analysis.TypeDefs[baseFileName]
1154
+ isDefinedInCurrentFile := false
1155
+ for _, t := range currentFileTypes {
1156
+ if t == typeName {
1157
+ isDefinedInCurrentFile = true
1158
+ break
1159
+ }
1160
+ }
1161
+
1162
+ // If not defined in current file, find which file defines it
1163
+ if !isDefinedInCurrentFile {
1164
+ for sourceFile, types := range analysis.TypeDefs {
1165
+ if sourceFile == baseFileName {
1166
+ continue // Skip current file
1167
+ }
1168
+ for _, t := range types {
1169
+ if t == typeName {
1170
+ // Found the type in another file
1171
+ if typeRefsFromOtherFiles[sourceFile] == nil {
1172
+ typeRefsFromOtherFiles[sourceFile] = []string{}
1173
+ }
1174
+ // Check if already added to avoid duplicates
1175
+ found := false
1176
+ for _, existing := range typeRefsFromOtherFiles[sourceFile] {
1177
+ if existing == typeName {
1178
+ found = true
1179
+ break
1180
+ }
1181
+ }
1182
+ if !found {
1183
+ typeRefsFromOtherFiles[sourceFile] = append(typeRefsFromOtherFiles[sourceFile], typeName)
1184
+ }
1185
+ break
1186
+ }
1187
+ }
1188
+ }
1189
+ }
1190
+ }
1191
+ }
1192
+ }
1193
+ return true
1194
+ })
1195
+
1196
+ if len(typeRefsFromOtherFiles) > 0 {
1197
+ analysis.TypeCalls[baseFileName] = typeRefsFromOtherFiles
1198
+ }
1199
+ }
1200
+
1114
1201
  return analysis
1115
1202
  }
1116
1203
 
@@ -124,6 +124,12 @@ func (c *GoToTSCompiler) writeAssignmentCore(lhs, rhs []ast.Expr, tok token.Toke
124
124
  }
125
125
  }
126
126
 
127
+ // Add semicolon before destructuring assignment to prevent TypeScript
128
+ // from interpreting it as array access on the previous line
129
+ if tok != token.DEFINE {
130
+ c.tsw.WriteLiterally(";")
131
+ }
132
+
127
133
  // Use array destructuring for multi-variable assignments
128
134
  c.tsw.WriteLiterally("[")
129
135
  for i, l := range lhs {
@@ -621,6 +621,61 @@ func (c *FileCompiler) Compile(ctx context.Context) error {
621
621
  }
622
622
  }
623
623
 
624
+ // Generate auto-imports for types from other files in the same package
625
+ if typeImports := c.PackageAnalysis.TypeCalls[currentFileName]; typeImports != nil {
626
+ // Sort source files for consistent import order
627
+ var sourceFiles []string
628
+ for sourceFile := range typeImports {
629
+ sourceFiles = append(sourceFiles, sourceFile)
630
+ }
631
+ sort.Strings(sourceFiles)
632
+
633
+ for _, sourceFile := range sourceFiles {
634
+ typeImports := typeImports[sourceFile]
635
+ if len(typeImports) > 0 {
636
+ // Filter out protobuf types - they should be imported from .pb.js files, not .gs.js files
637
+ var nonProtobufTypes []string
638
+ for _, typeName := range typeImports {
639
+ // Check if this type is a protobuf type by looking for it in the package
640
+ isProtobuf := false
641
+ if typeObj := c.pkg.Types.Scope().Lookup(typeName); typeObj != nil {
642
+ objType := typeObj.Type()
643
+ if namedType, ok := objType.(*types.Named); ok {
644
+ obj := namedType.Obj()
645
+ if obj != nil && obj.Pkg() != nil {
646
+ // Check if the type is defined in the current package and has a corresponding .pb.go file
647
+ if obj.Pkg() == c.pkg.Types {
648
+ // Check if there's a .pb.go file in the package that exports this type
649
+ // For now, we'll use a simple heuristic: if the type name ends with "Msg"
650
+ // and there's a .pb.go file in the package, assume it's a protobuf type
651
+ if strings.HasSuffix(typeName, "Msg") {
652
+ // Check if there are any .pb.go files in this package
653
+ for _, fileName := range c.pkg.CompiledGoFiles {
654
+ if strings.HasSuffix(fileName, ".pb.go") {
655
+ isProtobuf = true
656
+ break
657
+ }
658
+ }
659
+ }
660
+ }
661
+ }
662
+ }
663
+ }
664
+ if !isProtobuf {
665
+ nonProtobufTypes = append(nonProtobufTypes, typeName)
666
+ }
667
+ }
668
+
669
+ if len(nonProtobufTypes) > 0 {
670
+ // Sort types for consistent output
671
+ sort.Strings(nonProtobufTypes)
672
+ c.codeWriter.WriteLinef("import { %s } from \"./%s.gs.js\";",
673
+ strings.Join(nonProtobufTypes, ", "), sourceFile)
674
+ }
675
+ }
676
+ }
677
+ }
678
+
624
679
  c.codeWriter.WriteLine("") // Add a newline after imports
625
680
 
626
681
  if err := goWriter.WriteDecls(f.Decls); err != nil {
@@ -690,11 +745,30 @@ func (c *GoToTSCompiler) WriteIdent(exp *ast.Ident, accessVarRefedValue bool) {
690
745
  // Check if this identifier refers to a constant
691
746
  if obj != nil {
692
747
  if constObj, isConst := obj.(*types.Const); isConst {
693
- // Only evaluate constants from the current package being compiled
694
- // Don't evaluate constants from imported packages (they should use their exported names)
695
- // Special case: predeclared constants like iota have a nil package, so we should evaluate them
696
- if constObj.Pkg() == c.pkg.Types || constObj.Pkg() == nil {
697
- // Write the constant's evaluated value instead of the identifier name
748
+ // Evaluate constants to literals in these cases:
749
+ // 1. Predeclared constants (like iota, true, false) - these have nil package
750
+ // 2. Constants from the current package that are computed expressions
751
+ // (like iota-based constants or mathematical expressions)
752
+ //
753
+ // For simple assignments from imported constants (const x = pkg.Y),
754
+ // preserve the variable name for better readability.
755
+
756
+ if constObj.Pkg() == nil {
757
+ // Predeclared constants - always evaluate to literals
758
+ c.writeConstantValue(constObj)
759
+ return
760
+ }
761
+
762
+ if constObj.Pkg() == c.pkg.Types {
763
+ // This is a constant from the current package.
764
+ // Check if it's a simple assignment by looking at the constant value:
765
+ // If the constant has the same name as an identifier in the import,
766
+ // it's likely a simple assignment and we should preserve the name.
767
+ // Otherwise, evaluate to literal (for computed expressions like iota).
768
+
769
+ // For now, let's be conservative and evaluate current package constants
770
+ // to literals to maintain compatibility with existing behavior.
771
+ // This handles iota-based constants correctly.
698
772
  c.writeConstantValue(constObj)
699
773
  return
700
774
  }
@@ -980,6 +1054,12 @@ func (c *Compiler) copyEmbeddedPackage(embeddedPath string, outputPath string) e
980
1054
  continue
981
1055
  }
982
1056
 
1057
+ // Skip .test.ts files
1058
+ if strings.HasSuffix(fileName, ".test.ts") {
1059
+ // c.le.Debugf("Skipping test file: %s", fileName)
1060
+ continue
1061
+ }
1062
+
983
1063
  // Remove existing file if it exists (but preserve directories)
984
1064
  if stat, err := os.Stat(outputEntryPath); err == nil && !stat.IsDir() {
985
1065
  if err := os.Remove(outputEntryPath); err != nil {
package/compiler/decl.go CHANGED
@@ -101,29 +101,13 @@ func (c *GoToTSCompiler) WriteFuncDeclAsFunction(decl *ast.FuncDecl) error {
101
101
  c.WriteFuncType(decl.Type, isAsync) // Write signature (params, return type)
102
102
  c.tsw.WriteLiterally(" ")
103
103
 
104
- hasNamedReturns := false
105
- if decl.Type.Results != nil {
106
- for _, field := range decl.Type.Results.List {
107
- if len(field.Names) > 0 {
108
- hasNamedReturns = true
109
- break
110
- }
111
- }
112
- }
113
-
114
- if hasNamedReturns {
104
+ if c.hasNamedReturns(decl.Type.Results) {
115
105
  c.tsw.WriteLine("{")
116
106
  c.tsw.Indent(1)
117
107
 
118
108
  // Declare named return variables and initialize them to their zero values
119
- for _, field := range decl.Type.Results.List {
120
- for _, name := range field.Names {
121
- c.tsw.WriteLiterallyf("let %s: ", c.sanitizeIdentifier(name.Name))
122
- c.WriteTypeExpr(field.Type)
123
- c.tsw.WriteLiterally(" = ")
124
- c.WriteZeroValueForType(c.pkg.TypesInfo.TypeOf(field.Type))
125
- c.tsw.WriteLine("")
126
- }
109
+ if err := c.writeNamedReturnDeclarations(decl.Type.Results); err != nil {
110
+ return fmt.Errorf("failed to write named return declarations: %w", err)
127
111
  }
128
112
  }
129
113
 
@@ -131,7 +115,7 @@ func (c *GoToTSCompiler) WriteFuncDeclAsFunction(decl *ast.FuncDecl) error {
131
115
  return fmt.Errorf("failed to write function body: %w", err)
132
116
  }
133
117
 
134
- if hasNamedReturns {
118
+ if c.hasNamedReturns(decl.Type.Results) {
135
119
  c.tsw.Indent(-1)
136
120
  c.tsw.WriteLine("}")
137
121
  }
@@ -244,6 +228,11 @@ func (c *GoToTSCompiler) WriteFuncDeclAsMethod(decl *ast.FuncDecl) error {
244
228
  }
245
229
  }
246
230
 
231
+ // Declare named return variables and initialize them to their zero values
232
+ if err := c.writeNamedReturnDeclarations(decl.Type.Results); err != nil {
233
+ return fmt.Errorf("failed to write named return declarations: %w", err)
234
+ }
235
+
247
236
  // write method body without outer braces
248
237
  for _, stmt := range decl.Body.List {
249
238
  if err := c.WriteStmt(stmt); err != nil {
@@ -263,3 +252,36 @@ func (c *GoToTSCompiler) WriteFuncDeclAsMethod(decl *ast.FuncDecl) error {
263
252
 
264
253
  return nil
265
254
  }
255
+
256
+ // writeNamedReturnDeclarations generates TypeScript variable declarations for named return parameters.
257
+ // It declares each named return variable with its appropriate type and zero value.
258
+ func (c *GoToTSCompiler) writeNamedReturnDeclarations(results *ast.FieldList) error {
259
+ if results == nil {
260
+ return nil
261
+ }
262
+
263
+ for _, field := range results.List {
264
+ for _, name := range field.Names {
265
+ c.tsw.WriteLiterallyf("let %s: ", c.sanitizeIdentifier(name.Name))
266
+ c.WriteTypeExpr(field.Type)
267
+ c.tsw.WriteLiterally(" = ")
268
+ c.WriteZeroValueForType(c.pkg.TypesInfo.TypeOf(field.Type))
269
+ c.tsw.WriteLine("")
270
+ }
271
+ }
272
+ return nil
273
+ }
274
+
275
+ // hasNamedReturns checks if a function type has any named return parameters.
276
+ func (c *GoToTSCompiler) hasNamedReturns(results *ast.FieldList) bool {
277
+ if results == nil {
278
+ return false
279
+ }
280
+
281
+ for _, field := range results.List {
282
+ if len(field.Names) > 0 {
283
+ return true
284
+ }
285
+ }
286
+ return false
287
+ }
@@ -97,6 +97,37 @@ func (c *GoToTSCompiler) WriteCallExpr(exp *ast.CallExpr) error {
97
97
  }
98
98
  }
99
99
  }
100
+
101
+ // Handle general slice type conversions like []T(namedType) where namedType has underlying type []T
102
+ if arrayType.Len == nil && len(exp.Args) == 1 {
103
+ arg := exp.Args[0]
104
+ if argType := c.pkg.TypesInfo.TypeOf(arg); argType != nil {
105
+ // Check if the argument is a named type with a slice underlying type
106
+ if namedArgType, isNamed := argType.(*types.Named); isNamed {
107
+ // Check if the named type has receiver methods (is a wrapper class)
108
+ typeName := namedArgType.Obj().Name()
109
+ if c.hasReceiverMethods(typeName) {
110
+ // Check if the underlying type matches the target slice type
111
+ if sliceUnderlying, isSlice := namedArgType.Underlying().(*types.Slice); isSlice {
112
+ // Get the target slice type
113
+ targetType := c.pkg.TypesInfo.TypeOf(arrayType)
114
+ if targetSliceType, isTargetSlice := targetType.Underlying().(*types.Slice); isTargetSlice {
115
+ // Check if element types are compatible
116
+ if types.Identical(sliceUnderlying.Elem(), targetSliceType.Elem()) {
117
+ // This is a conversion from NamedType to []T where NamedType has underlying []T
118
+ // Use valueOf() to get the underlying slice
119
+ if err := c.WriteValueExpr(arg); err != nil {
120
+ return fmt.Errorf("failed to write argument for slice type conversion: %w", err)
121
+ }
122
+ c.tsw.WriteLiterally(".valueOf()")
123
+ return nil // Handled named type to slice conversion
124
+ }
125
+ }
126
+ }
127
+ }
128
+ }
129
+ }
130
+ }
100
131
  }
101
132
 
102
133
  if funIdent, funIsIdent := expFun.(*ast.Ident); funIsIdent {
@@ -274,7 +305,12 @@ func (c *GoToTSCompiler) WriteCallExpr(exp *ast.CallExpr) error {
274
305
  }
275
306
 
276
307
  c.tsw.WriteLiterally("$.makeSlice<")
277
- c.WriteGoType(goElemType, GoTypeContextGeneral) // Write the element type
308
+ // Use AST-based type writing to preserve qualified names
309
+ if arrType, ok := exp.Args[0].(*ast.ArrayType); ok {
310
+ c.WriteTypeExpr(arrType.Elt)
311
+ } else {
312
+ c.WriteGoType(goElemType, GoTypeContextGeneral)
313
+ }
278
314
  c.tsw.WriteLiterally(">(")
279
315
 
280
316
  hasCapacity := len(exp.Args) == 3
@@ -45,6 +45,26 @@ func (c *GoToTSCompiler) WriteTypeExpr(a ast.Expr) {
45
45
  }
46
46
  }
47
47
 
48
+ // Handle array/slice types to preserve qualified names in element types
49
+ if arrayType, ok := a.(*ast.ArrayType); ok {
50
+ if arrayType.Len == nil {
51
+ // Slice type: []T -> $.Slice<T>
52
+ // Check if it's a []byte slice first
53
+ if ident, ok := arrayType.Elt.(*ast.Ident); ok && ident.Name == "byte" {
54
+ c.tsw.WriteLiterally("$.Bytes")
55
+ return
56
+ }
57
+ c.tsw.WriteLiterally("$.Slice<")
58
+ c.WriteTypeExpr(arrayType.Elt) // Recursively handle element type preserving qualified names
59
+ c.tsw.WriteLiterally(">")
60
+ } else {
61
+ // Array type: [N]T -> T[]
62
+ c.WriteTypeExpr(arrayType.Elt) // Recursively handle element type preserving qualified names
63
+ c.tsw.WriteLiterally("[]")
64
+ }
65
+ return
66
+ }
67
+
48
68
  // Get type information for the expression and use WriteGoType
49
69
  typ := c.pkg.TypesInfo.TypeOf(a)
50
70
  c.WriteGoType(typ, GoTypeContextGeneral)
package/compiler/lit.go CHANGED
@@ -164,29 +164,13 @@ func (c *GoToTSCompiler) WriteFuncLitValue(exp *ast.FuncLit) error {
164
164
 
165
165
  c.tsw.WriteLiterally(" => ")
166
166
 
167
- hasNamedReturns := false
168
- if exp.Type.Results != nil {
169
- for _, field := range exp.Type.Results.List {
170
- if len(field.Names) > 0 {
171
- hasNamedReturns = true
172
- break
173
- }
174
- }
175
- }
176
-
177
- if hasNamedReturns {
167
+ if c.hasNamedReturns(exp.Type.Results) {
178
168
  c.tsw.WriteLine("{")
179
169
  c.tsw.Indent(1)
180
170
 
181
171
  // Declare named return variables and initialize them to their zero values
182
- for _, field := range exp.Type.Results.List {
183
- for _, name := range field.Names {
184
- c.tsw.WriteLiterallyf("let %s: ", c.sanitizeIdentifier(name.Name))
185
- c.WriteTypeExpr(field.Type)
186
- c.tsw.WriteLiterally(" = ")
187
- c.WriteZeroValueForType(c.pkg.TypesInfo.TypeOf(field.Type))
188
- c.tsw.WriteLine("")
189
- }
172
+ if err := c.writeNamedReturnDeclarations(exp.Type.Results); err != nil {
173
+ return fmt.Errorf("failed to write named return declarations: %w", err)
190
174
  }
191
175
  }
192
176
 
@@ -195,7 +179,7 @@ func (c *GoToTSCompiler) WriteFuncLitValue(exp *ast.FuncLit) error {
195
179
  return fmt.Errorf("failed to write block statement: %w", err)
196
180
  }
197
181
 
198
- if hasNamedReturns {
182
+ if c.hasNamedReturns(exp.Type.Results) {
199
183
  c.tsw.Indent(-1)
200
184
  c.tsw.WriteLiterally("}")
201
185
  }
@@ -20,10 +20,9 @@ import (
20
20
  // - Wrapper methods for promoted fields and methods from embedded structs,
21
21
  // ensuring correct access and behavior.
22
22
  func (c *GoToTSCompiler) WriteStructTypeSpec(a *ast.TypeSpec, t *ast.StructType) error {
23
- // Add export for Go-exported structs
24
- if a.Name.IsExported() {
25
- c.tsw.WriteLiterally("export ")
26
- }
23
+ // Always export types for cross-file imports within the same package
24
+ // This allows unexported Go types to be imported by other files in the same package
25
+ c.tsw.WriteLiterally("export ")
27
26
  c.tsw.WriteLiterally("class ")
28
27
  if err := c.WriteValueExpr(a.Name); err != nil {
29
28
  return err
@@ -153,7 +153,14 @@ func (c *GoToTSCompiler) WriteValueSpec(a *ast.ValueSpec) error {
153
153
  }
154
154
  } else {
155
155
  // Not a pointer type, write as is.
156
- c.WriteGoType(goType, GoTypeContextGeneral)
156
+ // Use AST-based type writing if explicit type is provided, otherwise use WriteGoType
157
+ if a.Type != nil {
158
+ // Explicit type annotation in Go code - use AST to preserve qualified names
159
+ c.WriteTypeExpr(a.Type)
160
+ } else {
161
+ // No explicit type - use type inference from WriteGoType
162
+ c.WriteGoType(goType, GoTypeContextGeneral)
163
+ }
157
164
  }
158
165
  }
159
166
  }
@@ -249,6 +256,16 @@ func (c *GoToTSCompiler) WriteValueSpec(a *ast.ValueSpec) error {
249
256
  }
250
257
  }
251
258
  }
259
+ case *ast.CallExpr:
260
+ // Check if this is a make() call that returns the underlying type
261
+ if funIdent, ok := expr.Fun.(*ast.Ident); ok && funIdent.Name == "make" {
262
+ // Check if the make call returns a type that matches the underlying type
263
+ if exprType := c.pkg.TypesInfo.TypeOf(expr); exprType != nil {
264
+ if types.Identical(exprType, namedType.Underlying()) {
265
+ needsConstructor = true
266
+ }
267
+ }
268
+ }
252
269
  }
253
270
 
254
271
  if needsConstructor {
package/compiler/spec.go CHANGED
@@ -188,7 +188,6 @@ func (c *GoToTSCompiler) hasReceiverMethods(typeName string) bool {
188
188
  // WriteNamedTypeWithMethods generates a TypeScript class for a Go named type that has receiver methods
189
189
  func (c *GoToTSCompiler) WriteNamedTypeWithMethods(a *ast.TypeSpec) error {
190
190
  className := a.Name.Name
191
- underlyingType := c.pkg.TypesInfo.TypeOf(a.Type)
192
191
 
193
192
  // Add export for Go-exported types (but not if inside a function)
194
193
  isInsideFunction := false
@@ -196,7 +195,7 @@ func (c *GoToTSCompiler) WriteNamedTypeWithMethods(a *ast.TypeSpec) error {
196
195
  isInsideFunction = nodeInfo.IsInsideFunction
197
196
  }
198
197
 
199
- if a.Name.IsExported() && !isInsideFunction {
198
+ if !isInsideFunction {
200
199
  c.tsw.WriteLiterally("export ")
201
200
  }
202
201
 
@@ -206,13 +205,15 @@ func (c *GoToTSCompiler) WriteNamedTypeWithMethods(a *ast.TypeSpec) error {
206
205
 
207
206
  // Constructor that takes the underlying type value
208
207
  c.tsw.WriteLiterally("constructor(private _value: ")
209
- c.WriteGoType(underlyingType, GoTypeContextGeneral)
208
+ // Use AST-based type writing to preserve qualified names like os.FileInfo
209
+ c.WriteTypeExpr(a.Type)
210
210
  c.tsw.WriteLine(") {}")
211
211
  c.tsw.WriteLine("")
212
212
 
213
213
  // valueOf method to get the underlying value (for type conversions and operations)
214
214
  c.tsw.WriteLiterally("valueOf(): ")
215
- c.WriteGoType(underlyingType, GoTypeContextGeneral)
215
+ // Use AST-based type writing to preserve qualified names like os.FileInfo
216
+ c.WriteTypeExpr(a.Type)
216
217
  c.tsw.WriteLine(" {")
217
218
  c.tsw.Indent(1)
218
219
  c.tsw.WriteLine("return this._value")
@@ -230,7 +231,8 @@ func (c *GoToTSCompiler) WriteNamedTypeWithMethods(a *ast.TypeSpec) error {
230
231
 
231
232
  // Static from method for type conversion
232
233
  c.tsw.WriteLiterallyf("static from(value: ")
233
- c.WriteGoType(underlyingType, GoTypeContextGeneral)
234
+ // Use AST-based type writing to preserve qualified names like os.FileInfo
235
+ c.WriteTypeExpr(a.Type)
234
236
  c.tsw.WriteLiterallyf("): %s {", className)
235
237
  c.tsw.WriteLine("")
236
238
  c.tsw.Indent(1)
@@ -364,6 +366,11 @@ func (c *GoToTSCompiler) writeNamedTypeMethod(decl *ast.FuncDecl) error {
364
366
  }
365
367
  }
366
368
 
369
+ // Declare named return variables and initialize them to their zero values
370
+ if err := c.writeNamedReturnDeclarations(decl.Type.Results); err != nil {
371
+ return fmt.Errorf("failed to write named return declarations: %w", err)
372
+ }
373
+
367
374
  // write method body without outer braces
368
375
  for _, stmt := range decl.Body.List {
369
376
  if err := c.WriteStmt(stmt); err != nil {
@@ -404,13 +411,13 @@ func (c *GoToTSCompiler) WriteTypeSpec(a *ast.TypeSpec) error {
404
411
  return c.WriteNamedTypeWithMethods(a)
405
412
  }
406
413
 
407
- // type alias - add export for Go-exported types (but not if inside a function)
414
+ // Always export types for cross-file imports within the same package (but not if inside a function)
408
415
  isInsideFunction := false
409
416
  if nodeInfo := c.analysis.NodeData[a]; nodeInfo != nil {
410
417
  isInsideFunction = nodeInfo.IsInsideFunction
411
418
  }
412
419
 
413
- if a.Name.IsExported() && !isInsideFunction {
420
+ if !isInsideFunction {
414
421
  c.tsw.WriteLiterally("export ")
415
422
  }
416
423
  c.tsw.WriteLiterally("type ")
@@ -438,7 +445,7 @@ func (c *GoToTSCompiler) WriteInterfaceTypeSpec(a *ast.TypeSpec, t *ast.Interfac
438
445
  isInsideFunction = nodeInfo.IsInsideFunction
439
446
  }
440
447
 
441
- if a.Name.IsExported() && !isInsideFunction {
448
+ if !isInsideFunction {
442
449
  c.tsw.WriteLiterally("export ")
443
450
  }
444
451
  c.tsw.WriteLiterally("type ")
@@ -157,7 +157,7 @@ func (c *GoToTSCompiler) writeMapRange(exp *ast.RangeStmt) error {
157
157
  if err := c.WriteValueExpr(exp.X); err != nil {
158
158
  return fmt.Errorf("failed to write range loop map expression: %w", err)
159
159
  }
160
- c.tsw.WriteLiterally(".entries()) {")
160
+ c.tsw.WriteLiterally("?.entries() ?? []) {")
161
161
  c.tsw.Indent(1)
162
162
  c.tsw.WriteLine("")
163
163
 
@@ -96,8 +96,8 @@ func (c *GoToTSCompiler) writeTypeAssert(lhs []ast.Expr, typeAssertExpr *ast.Typ
96
96
  // For selector expressions as ok, we need to use temporary variables approach
97
97
  if okIsSelectorExpr {
98
98
  // Use temporary variables approach similar to SelectorExpr case
99
- tempValName := "_gs_ta_val_" // Fixed name for temporary value
100
- tempOkName := "_gs_ta_ok_" // Fixed name for temporary ok status
99
+ tempValName := fmt.Sprintf("_gs_ta_val_%d_", typeAssertExpr.Pos()) // Unique name based on AST position
100
+ tempOkName := fmt.Sprintf("_gs_ta_ok_%d_", typeAssertExpr.Pos()) // Unique name based on AST position
101
101
 
102
102
  // Declare temporary variables:
103
103
  // let _gs_ta_val_: AssertedTypeTS;
@@ -217,8 +217,8 @@ func (c *GoToTSCompiler) writeTypeAssert(lhs []ast.Expr, typeAssertExpr *ast.Typ
217
217
 
218
218
  case *ast.SelectorExpr:
219
219
  // Handle s.field, ok := expr.(Type)
220
- tempValName := "_gs_ta_val_" // Fixed name for temporary value
221
- tempOkName := "_gs_ta_ok_" // Fixed name for temporary ok status
220
+ tempValName := fmt.Sprintf("_gs_ta_val_%d_", typeAssertExpr.Pos()) // Unique name based on AST position
221
+ tempOkName := fmt.Sprintf("_gs_ta_ok_%d_", typeAssertExpr.Pos()) // Unique name based on AST position
222
222
 
223
223
  // Declare temporary variables:
224
224
  // let _gs_ta_val_: AssertedTypeTS;