goscript 0.0.38 → 0.0.40

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 (180) hide show
  1. package/compiler/analysis.go +15 -6
  2. package/compiler/compiler.go +184 -34
  3. package/compiler/expr-call.go +19 -9
  4. package/compiler/field.go +17 -3
  5. package/compiler/gs_dependencies_test.go +80 -0
  6. package/compiler/lit.go +12 -6
  7. package/compiler/output.go +10 -4
  8. package/compiler/spec.go +15 -2
  9. package/compiler/type-assert.go +111 -21
  10. package/compiler/type.go +37 -8
  11. package/dist/gs/builtin/builtin.d.ts +55 -0
  12. package/dist/gs/builtin/builtin.js +213 -0
  13. package/dist/gs/builtin/builtin.js.map +1 -1
  14. package/dist/gs/builtin/slice.js +13 -0
  15. package/dist/gs/builtin/slice.js.map +1 -1
  16. package/dist/gs/bytes/buffer.gs.d.ts +56 -0
  17. package/dist/gs/bytes/buffer.gs.js +611 -0
  18. package/dist/gs/bytes/buffer.gs.js.map +1 -0
  19. package/dist/gs/bytes/bytes.gs.d.ts +78 -0
  20. package/dist/gs/bytes/bytes.gs.js +1107 -0
  21. package/dist/gs/bytes/bytes.gs.js.map +1 -0
  22. package/dist/gs/bytes/index.d.ts +4 -0
  23. package/dist/gs/bytes/index.js +5 -0
  24. package/dist/gs/bytes/index.js.map +1 -0
  25. package/dist/gs/bytes/iter.gs.d.ts +9 -0
  26. package/dist/gs/bytes/iter.gs.js +143 -0
  27. package/dist/gs/bytes/iter.gs.js.map +1 -0
  28. package/dist/gs/bytes/reader.gs.d.ts +34 -0
  29. package/dist/gs/bytes/reader.gs.js +198 -0
  30. package/dist/gs/bytes/reader.gs.js.map +1 -0
  31. package/dist/gs/fmt/fmt.d.ts +49 -0
  32. package/dist/gs/fmt/fmt.js +322 -0
  33. package/dist/gs/fmt/fmt.js.map +1 -0
  34. package/dist/gs/fmt/index.d.ts +1 -0
  35. package/dist/gs/fmt/index.js +2 -0
  36. package/dist/gs/fmt/index.js.map +1 -0
  37. package/dist/gs/internal/bytealg/index.d.ts +14 -2
  38. package/dist/gs/internal/bytealg/index.js +114 -8
  39. package/dist/gs/internal/bytealg/index.js.map +1 -1
  40. package/dist/gs/path/filepath/index.d.ts +3 -0
  41. package/dist/gs/path/filepath/index.js +3 -0
  42. package/dist/gs/path/filepath/index.js.map +1 -0
  43. package/dist/gs/path/filepath/match.d.ts +3 -0
  44. package/dist/gs/path/filepath/match.js +212 -0
  45. package/dist/gs/path/filepath/match.js.map +1 -0
  46. package/dist/gs/path/filepath/path.d.ts +25 -0
  47. package/dist/gs/path/filepath/path.js +265 -0
  48. package/dist/gs/path/filepath/path.js.map +1 -0
  49. package/dist/gs/reflect/deepequal.d.ts +2 -1
  50. package/dist/gs/reflect/deepequal.js +5 -53
  51. package/dist/gs/reflect/deepequal.js.map +1 -1
  52. package/dist/gs/reflect/map.d.ts +14 -8
  53. package/dist/gs/reflect/map.js +15 -11
  54. package/dist/gs/reflect/map.js.map +1 -1
  55. package/dist/gs/reflect/type.d.ts +17 -9
  56. package/dist/gs/reflect/type.js +1 -1
  57. package/dist/gs/reflect/type.js.map +1 -1
  58. package/dist/gs/reflect/value.js +15 -6
  59. package/dist/gs/reflect/value.js.map +1 -1
  60. package/dist/gs/reflect/visiblefields.js +18 -12
  61. package/dist/gs/reflect/visiblefields.js.map +1 -1
  62. package/dist/gs/sort/index.d.ts +4 -0
  63. package/dist/gs/sort/index.js +4 -0
  64. package/dist/gs/sort/index.js.map +1 -0
  65. package/dist/gs/sort/search.gs.d.ts +6 -0
  66. package/dist/gs/sort/search.gs.js +125 -0
  67. package/dist/gs/sort/search.gs.js.map +1 -0
  68. package/dist/gs/sort/slice.gs.d.ts +4 -0
  69. package/dist/gs/sort/slice.gs.js +49 -0
  70. package/dist/gs/sort/slice.gs.js.map +1 -0
  71. package/dist/gs/sort/sort.gs.d.ts +37 -0
  72. package/dist/gs/sort/sort.gs.js +203 -0
  73. package/dist/gs/sort/sort.gs.js.map +1 -0
  74. package/dist/gs/unicode/utf8/utf8.d.ts +1 -1
  75. package/dist/gs/unicode/utf8/utf8.js +4 -2
  76. package/dist/gs/unicode/utf8/utf8.js.map +1 -1
  77. package/gs/builtin/builtin.ts +236 -0
  78. package/gs/builtin/slice.ts +17 -1
  79. package/gs/bytes/buffer.gs.ts +614 -0
  80. package/gs/bytes/bytes.gs.ts +1288 -0
  81. package/gs/bytes/godoc.txt +69 -0
  82. package/gs/bytes/index.ts +69 -0
  83. package/gs/bytes/iter.gs.ts +149 -0
  84. package/gs/bytes/metadata.go +12 -0
  85. package/gs/bytes/reader.gs.ts +230 -0
  86. package/gs/fmt/fmt.ts +407 -0
  87. package/gs/fmt/godoc.txt +382 -0
  88. package/gs/fmt/index.ts +31 -0
  89. package/gs/fmt/metadata.go +7 -0
  90. package/gs/internal/bytealg/index.ts +125 -10
  91. package/gs/internal/metadata.go +7 -0
  92. package/gs/io/metadata.go +11 -0
  93. package/gs/maps/metadata.go +8 -0
  94. package/gs/math/metadata.go +7 -0
  95. package/gs/os/metadata.go +17 -0
  96. package/gs/path/filepath/godoc.txt +35 -0
  97. package/gs/path/filepath/index.ts +27 -0
  98. package/gs/path/filepath/match.test.ts +274 -0
  99. package/gs/path/filepath/match.ts +249 -0
  100. package/gs/path/filepath/path.test.ts +246 -0
  101. package/gs/path/filepath/path.ts +328 -0
  102. package/gs/path/metadata.go +8 -0
  103. package/gs/reflect/deepequal.test.ts +41 -0
  104. package/gs/reflect/deepequal.ts +19 -4
  105. package/gs/reflect/map.test.ts +30 -0
  106. package/gs/reflect/map.ts +22 -18
  107. package/gs/reflect/metadata.go +7 -0
  108. package/gs/reflect/type.ts +19 -15
  109. package/gs/reflect/value.ts +21 -7
  110. package/gs/reflect/visiblefields.ts +17 -13
  111. package/gs/sort/godoc.txt +27 -0
  112. package/gs/sort/index.ts +24 -0
  113. package/gs/sort/search.gs.ts +128 -0
  114. package/gs/sort/slice.gs.ts +59 -0
  115. package/gs/sort/sort.gs.ts +227 -0
  116. package/gs/strconv/metadata.go +7 -0
  117. package/gs/strings/metadata.go +11 -0
  118. package/gs/sync/metadata.go +7 -0
  119. package/gs/unicode/utf8/utf8.ts +8 -5
  120. package/package.json +1 -1
  121. package/dist/gs/internal/testlog/index.d.ts +0 -1
  122. package/dist/gs/internal/testlog/index.js +0 -5
  123. package/dist/gs/internal/testlog/index.js.map +0 -1
  124. package/dist/gs/maps/iter.gs.d.ts +0 -7
  125. package/dist/gs/maps/iter.gs.js +0 -65
  126. package/dist/gs/maps/iter.gs.js.map +0 -1
  127. package/dist/gs/maps/maps.gs.d.ts +0 -7
  128. package/dist/gs/maps/maps.gs.js +0 -79
  129. package/dist/gs/maps/maps.gs.js.map +0 -1
  130. package/dist/gs/reflect/abi.d.ts +0 -59
  131. package/dist/gs/reflect/abi.gs.d.ts +0 -59
  132. package/dist/gs/reflect/abi.gs.js +0 -79
  133. package/dist/gs/reflect/abi.gs.js.map +0 -1
  134. package/dist/gs/reflect/abi.js +0 -79
  135. package/dist/gs/reflect/abi.js.map +0 -1
  136. package/dist/gs/reflect/badlinkname.d.ts +0 -52
  137. package/dist/gs/reflect/badlinkname.gs.d.ts +0 -52
  138. package/dist/gs/reflect/badlinkname.gs.js +0 -72
  139. package/dist/gs/reflect/badlinkname.gs.js.map +0 -1
  140. package/dist/gs/reflect/badlinkname.js +0 -72
  141. package/dist/gs/reflect/badlinkname.js.map +0 -1
  142. package/dist/gs/reflect/deepequal.gs.d.ts +0 -25
  143. package/dist/gs/reflect/deepequal.gs.js +0 -308
  144. package/dist/gs/reflect/deepequal.gs.js.map +0 -1
  145. package/dist/gs/reflect/float32reg_generic.gs.d.ts +0 -2
  146. package/dist/gs/reflect/float32reg_generic.gs.js +0 -10
  147. package/dist/gs/reflect/float32reg_generic.gs.js.map +0 -1
  148. package/dist/gs/reflect/index.gs.d.ts +0 -1
  149. package/dist/gs/reflect/index.gs.js +0 -3
  150. package/dist/gs/reflect/index.gs.js.map +0 -1
  151. package/dist/gs/reflect/iter.gs.d.ts +0 -3
  152. package/dist/gs/reflect/iter.gs.js +0 -24
  153. package/dist/gs/reflect/iter.gs.js.map +0 -1
  154. package/dist/gs/reflect/makefunc.gs.d.ts +0 -34
  155. package/dist/gs/reflect/makefunc.gs.js +0 -288
  156. package/dist/gs/reflect/makefunc.gs.js.map +0 -1
  157. package/dist/gs/reflect/map_swiss.gs.d.ts +0 -14
  158. package/dist/gs/reflect/map_swiss.gs.js +0 -70
  159. package/dist/gs/reflect/map_swiss.gs.js.map +0 -1
  160. package/dist/gs/reflect/reflect.gs.d.ts +0 -132
  161. package/dist/gs/reflect/reflect.gs.js +0 -437
  162. package/dist/gs/reflect/reflect.gs.js.map +0 -1
  163. package/dist/gs/reflect/swapper.gs.d.ts +0 -1
  164. package/dist/gs/reflect/swapper.gs.js +0 -32
  165. package/dist/gs/reflect/swapper.gs.js.map +0 -1
  166. package/dist/gs/reflect/type.gs.d.ts +0 -4
  167. package/dist/gs/reflect/type.gs.js +0 -21
  168. package/dist/gs/reflect/type.gs.js.map +0 -1
  169. package/dist/gs/reflect/value.gs.d.ts +0 -4
  170. package/dist/gs/reflect/value.gs.js +0 -12
  171. package/dist/gs/reflect/value.gs.js.map +0 -1
  172. package/dist/gs/reflect/visiblefields.gs.d.ts +0 -3
  173. package/dist/gs/reflect/visiblefields.gs.js +0 -123
  174. package/dist/gs/reflect/visiblefields.gs.js.map +0 -1
  175. package/dist/gs/stringslite/index.d.ts +0 -1
  176. package/dist/gs/stringslite/index.js +0 -2
  177. package/dist/gs/stringslite/index.js.map +0 -1
  178. package/dist/gs/stringslite/strings.d.ts +0 -11
  179. package/dist/gs/stringslite/strings.js +0 -67
  180. package/dist/gs/stringslite/strings.js.map +0 -1
@@ -831,10 +831,8 @@ func (v *analysisVisitor) containsAsyncOperations(node ast.Node) bool {
831
831
 
832
832
  // Check if the type is from an imported package
833
833
  if typePkg := namedType.Obj().Pkg(); typePkg != nil && typePkg != v.pkg.Types {
834
- pkgPath := typePkg.Path()
835
- // Extract package name from path (e.g., "sync" from "github.com/.../gs/sync")
836
- parts := strings.Split(pkgPath, "/")
837
- pkgName := parts[len(parts)-1]
834
+ // Use the actual package name from the type information
835
+ pkgName := typePkg.Name()
838
836
 
839
837
  // Check if this method is async based on metadata
840
838
  if v.analysis.IsMethodAsync(pkgName, typeName, methodName) {
@@ -905,10 +903,21 @@ func AnalyzeFile(file *ast.File, pkg *packages.Package, analysis *Analysis, cmap
905
903
  importVars: make(map[string]struct{}),
906
904
  }
907
905
 
908
- // Use the import name or package name as the key
909
- key := packageNameFromGoPath(path)
906
+ // Use the import name or the actual package name as the key
907
+ var key string
910
908
  if name != "" {
909
+ // Explicit alias provided
911
910
  key = name
911
+ } else {
912
+ // No explicit alias, use the actual package name from type information
913
+ // This handles cases where package name differs from the last path segment
914
+ if actualName, err := getActualPackageName(path, pkg.Imports); err == nil {
915
+ key = actualName
916
+ } else {
917
+ // Fallback to last segment of path if package not found in type information
918
+ pts := strings.Split(path, "/")
919
+ key = pts[len(pts)-1]
920
+ }
912
921
  }
913
922
 
914
923
  analysis.Imports[key] = fileImp
@@ -5,6 +5,7 @@ import (
5
5
  "fmt"
6
6
  "go/ast"
7
7
  "go/constant"
8
+ "go/parser"
8
9
  "go/token"
9
10
  "go/types"
10
11
  "os"
@@ -140,7 +141,7 @@ func (c *Compiler) CompilePackages(ctx context.Context, patterns ...string) (*Co
140
141
  // Check if this package has a handwritten equivalent
141
142
  if hasHandwrittenEquivalent(pkg.PkgPath) {
142
143
  // Add this package but don't visit its dependencies
143
- c.le.Debugf("Skipping dependencies of handwritten package: %s", pkg.PkgPath)
144
+ // c.le.Debugf("Skipping dependencies of handwritten package: %s", pkg.PkgPath)
144
145
  return
145
146
  }
146
147
 
@@ -148,13 +149,13 @@ func (c *Compiler) CompilePackages(ctx context.Context, patterns ...string) (*Co
148
149
  for _, imp := range pkg.Imports {
149
150
  // Skip protobuf-go-lite packages and their dependencies
150
151
  if isProtobufGoLitePackage(imp.PkgPath) {
151
- c.le.Debugf("Skipping protobuf-go-lite package: %s", imp.PkgPath)
152
+ // c.le.Debugf("Skipping protobuf-go-lite package: %s", imp.PkgPath)
152
153
  continue
153
154
  }
154
155
 
155
156
  // Skip packages that are only used by .pb.go files
156
157
  if isPackageOnlyUsedByProtobufFiles(pkg, imp.PkgPath) {
157
- c.le.Debugf("Skipping package only used by .pb.go files: %s", imp.PkgPath)
158
+ // c.le.Debugf("Skipping package only used by .pb.go files: %s", imp.PkgPath)
158
159
  continue
159
160
  }
160
161
 
@@ -193,7 +194,7 @@ func (c *Compiler) CompilePackages(ctx context.Context, patterns ...string) (*Co
193
194
 
194
195
  // If DisableEmitBuiltin is false, we need to copy the builtin package to the output directory
195
196
  if !c.config.DisableEmitBuiltin {
196
- c.le.Infof("Copying builtin package to output directory")
197
+ c.le.Debugf("Copying builtin package to output directory")
197
198
  builtinPath := "gs/builtin"
198
199
  outputPath := ComputeModulePath(c.config.OutputPath, "builtin")
199
200
  if err := c.copyEmbeddedPackage(builtinPath, outputPath); err != nil {
@@ -202,6 +203,9 @@ func (c *Compiler) CompilePackages(ctx context.Context, patterns ...string) (*Co
202
203
  result.CopiedPackages = append(result.CopiedPackages, "builtin")
203
204
  }
204
205
 
206
+ // Track which gs packages have been processed to avoid duplicates
207
+ processedGsPackages := make(map[string]bool)
208
+
205
209
  // Compile all packages
206
210
  for _, pkg := range pkgs {
207
211
  // Check if the package has a handwritten equivalent
@@ -214,32 +218,14 @@ func (c *Compiler) CompilePackages(ctx context.Context, patterns ...string) (*Co
214
218
  }
215
219
  if gsErr == nil {
216
220
  if c.config.DisableEmitBuiltin {
217
- c.le.Infof("Skipping compilation for overridden package %s", pkg.PkgPath)
221
+ // c.le.Infof("Skipping compilation for overridden package %s", pkg.PkgPath)
218
222
  result.CopiedPackages = append(result.CopiedPackages, pkg.PkgPath)
219
223
  continue
220
224
  } else {
221
- // If DisableEmitBuiltin is false, we need to copy the handwritten package to the output directory
222
- c.le.Infof("Copying handwritten package %s to output directory", pkg.PkgPath)
223
-
224
- // Compute output path for this package
225
- outputPath := ComputeModulePath(c.config.OutputPath, pkg.PkgPath)
226
-
227
- // Remove existing directory if it exists
228
- if err := os.RemoveAll(outputPath); err != nil {
229
- return nil, fmt.Errorf("failed to remove existing output directory for %s: %w", pkg.PkgPath, err)
230
- }
231
-
232
- // Create the output directory
233
- if err := os.MkdirAll(outputPath, 0o755); err != nil {
234
- return nil, fmt.Errorf("failed to create output directory for %s: %w", pkg.PkgPath, err)
225
+ // If DisableEmitBuiltin is false, we need to copy the handwritten package and its dependencies
226
+ if err := c.copyGsPackageWithDependencies(pkg.PkgPath, processedGsPackages, result); err != nil {
227
+ return nil, fmt.Errorf("failed to copy handwritten package %s with dependencies: %w", pkg.PkgPath, err)
235
228
  }
236
-
237
- // Copy files from embedded FS to output directory
238
- if err := c.copyEmbeddedPackage(gsSourcePath, outputPath); err != nil {
239
- return nil, fmt.Errorf("failed to copy embedded package %s: %w", pkg.PkgPath, err)
240
- }
241
-
242
- result.CopiedPackages = append(result.CopiedPackages, pkg.PkgPath)
243
229
  continue
244
230
  }
245
231
  }
@@ -260,6 +246,8 @@ func (c *Compiler) CompilePackages(ctx context.Context, patterns ...string) (*Co
260
246
  return nil, fmt.Errorf("failed to compile package %s: %w", pkg.PkgPath, err)
261
247
  }
262
248
 
249
+ c.le.Info(pkg.PkgPath)
250
+
263
251
  result.CompiledPackages = append(result.CompiledPackages, pkg.PkgPath)
264
252
  }
265
253
 
@@ -352,7 +340,8 @@ func (c *PackageCompiler) Compile(ctx context.Context) error {
352
340
  }
353
341
  }
354
342
 
355
- c.le.WithField("file", relWdFileName).Debug("compiling file")
343
+ // log just the filename
344
+ c.le.Debugf("GS: %s", filepath.Base(fileName))
356
345
  if err := c.CompileFile(ctx, fileName, f, packageAnalysis); err != nil {
357
346
  return err
358
347
  }
@@ -945,13 +934,9 @@ func (c *GoToTSCompiler) writeConstantValue(constObj *types.Const) {
945
934
 
946
935
  // copyEmbeddedPackage recursively copies files from an embedded FS path to a filesystem directory.
947
936
  // It handles both regular files and directories, but only copies .gs.ts and .ts files.
937
+ // It preserves existing subdirectories that aren't being overwritten.
948
938
  func (c *Compiler) copyEmbeddedPackage(embeddedPath string, outputPath string) error {
949
- // Remove the output path if it exists
950
- if err := os.RemoveAll(outputPath); err != nil {
951
- return fmt.Errorf("failed to remove output directory %s: %w", outputPath, err)
952
- }
953
-
954
- // Create the output path
939
+ // Create the output path if it doesn't exist
955
940
  if err := os.MkdirAll(outputPath, 0o755); err != nil {
956
941
  return fmt.Errorf("failed to create output directory %s: %w", outputPath, err)
957
942
  }
@@ -981,10 +966,17 @@ func (c *Compiler) copyEmbeddedPackage(embeddedPath string, outputPath string) e
981
966
  // Only copy .gs.ts and .ts files, skip .go files and others
982
967
  fileName := entry.Name()
983
968
  if !strings.HasSuffix(fileName, ".gs.ts") && !strings.HasSuffix(fileName, ".ts") {
984
- c.le.Debugf("Skipping non-TypeScript file: %s", fileName)
969
+ // c.le.Debugf("Skipping non-TypeScript file: %s", fileName)
985
970
  continue
986
971
  }
987
972
 
973
+ // Remove existing file if it exists (but preserve directories)
974
+ if stat, err := os.Stat(outputEntryPath); err == nil && !stat.IsDir() {
975
+ if err := os.Remove(outputEntryPath); err != nil {
976
+ return fmt.Errorf("failed to remove existing file %s: %w", outputEntryPath, err)
977
+ }
978
+ }
979
+
988
980
  // Read the file content from the embedded FS
989
981
  content, err := gs.GsOverrides.ReadFile(entryPath)
990
982
  if err != nil {
@@ -1000,3 +992,161 @@ func (c *Compiler) copyEmbeddedPackage(embeddedPath string, outputPath string) e
1000
992
 
1001
993
  return nil
1002
994
  }
995
+
996
+ // GsPackageMetadata holds metadata about a gs/ package
997
+ type GsPackageMetadata struct {
998
+ // Dependencies lists the import paths that this gs/ package requires
999
+ Dependencies []string
1000
+ }
1001
+
1002
+ // ReadGsPackageMetadata reads dependency metadata from .go files in a gs/ package
1003
+ // It looks for a var variable named "GsDependencies" which should be a slice of strings
1004
+ // containing the import paths that this package depends on.
1005
+ func (c *Compiler) ReadGsPackageMetadata(gsSourcePath string) (*GsPackageMetadata, error) {
1006
+ metadata := &GsPackageMetadata{
1007
+ Dependencies: []string{},
1008
+ }
1009
+
1010
+ // Check if there are any .go files in the gs package directory
1011
+ entries, err := gs.GsOverrides.ReadDir(gsSourcePath)
1012
+ if err != nil {
1013
+ return metadata, nil // No metadata files, return empty metadata
1014
+ }
1015
+
1016
+ // Look for .go files containing metadata
1017
+ for _, entry := range entries {
1018
+ if !entry.IsDir() && strings.HasSuffix(entry.Name(), ".go") {
1019
+ metadataFilePath := filepath.Join(gsSourcePath, entry.Name())
1020
+
1021
+ // Read the .go file content
1022
+ content, err := gs.GsOverrides.ReadFile(metadataFilePath)
1023
+ if err != nil {
1024
+ continue // Skip files we can't read
1025
+ }
1026
+
1027
+ // Parse the file to extract metadata
1028
+ if deps, err := c.extractDependenciesFromGoFile(content); err == nil {
1029
+ metadata.Dependencies = append(metadata.Dependencies, deps...)
1030
+ }
1031
+ }
1032
+ }
1033
+
1034
+ return metadata, nil
1035
+ }
1036
+
1037
+ // extractDependenciesFromGoFile parses a .go file and extracts the GsDependencies var
1038
+ func (c *Compiler) extractDependenciesFromGoFile(content []byte) ([]string, error) {
1039
+ // Parse the Go file
1040
+ fset := token.NewFileSet()
1041
+ file, err := parser.ParseFile(fset, "metadata.go", content, 0)
1042
+ if err != nil {
1043
+ return nil, err
1044
+ }
1045
+
1046
+ var dependencies []string
1047
+
1048
+ // Look for var declarations
1049
+ for _, decl := range file.Decls {
1050
+ if genDecl, ok := decl.(*ast.GenDecl); ok && genDecl.Tok == token.VAR {
1051
+ for _, spec := range genDecl.Specs {
1052
+ if valueSpec, ok := spec.(*ast.ValueSpec); ok {
1053
+ for i, name := range valueSpec.Names {
1054
+ if name.Name == "GsDependencies" {
1055
+ // Found the GsDependencies var, extract its value
1056
+ if i < len(valueSpec.Values) {
1057
+ if deps := c.extractStringSliceFromExpr(valueSpec.Values[i]); deps != nil {
1058
+ dependencies = append(dependencies, deps...)
1059
+ }
1060
+ }
1061
+ }
1062
+ }
1063
+ }
1064
+ }
1065
+ }
1066
+ }
1067
+
1068
+ return dependencies, nil
1069
+ }
1070
+
1071
+ // extractStringSliceFromExpr extracts string values from a composite literal expression
1072
+ func (c *Compiler) extractStringSliceFromExpr(expr ast.Expr) []string {
1073
+ var result []string
1074
+
1075
+ if compLit, ok := expr.(*ast.CompositeLit); ok {
1076
+ for _, elt := range compLit.Elts {
1077
+ if basicLit, ok := elt.(*ast.BasicLit); ok && basicLit.Kind == token.STRING {
1078
+ // Remove quotes from string literal
1079
+ value := basicLit.Value
1080
+ if len(value) >= 2 && value[0] == '"' && value[len(value)-1] == '"' {
1081
+ result = append(result, value[1:len(value)-1])
1082
+ }
1083
+ }
1084
+ }
1085
+ }
1086
+
1087
+ return result
1088
+ }
1089
+
1090
+ // copyGsPackageWithDependencies copies a gs/ package and all its dependencies recursively
1091
+ // It tracks already processed packages to avoid infinite loops and duplicate work
1092
+ func (c *Compiler) copyGsPackageWithDependencies(packagePath string, processedPackages map[string]bool, result *CompilationResult) error {
1093
+ // Check if we've already processed this package
1094
+ if processedPackages[packagePath] {
1095
+ return nil
1096
+ }
1097
+
1098
+ // Mark this package as being processed
1099
+ processedPackages[packagePath] = true
1100
+
1101
+ gsSourcePath := "gs/" + packagePath
1102
+
1103
+ // Check if the gs package actually exists
1104
+ _, gsErr := gs.GsOverrides.ReadDir(gsSourcePath)
1105
+ if gsErr != nil {
1106
+ if os.IsNotExist(gsErr) {
1107
+ c.le.Debugf("gs package %s does not exist, skipping", packagePath)
1108
+ return nil
1109
+ }
1110
+ return gsErr
1111
+ }
1112
+
1113
+ // Read metadata to get dependencies
1114
+ metadata, err := c.ReadGsPackageMetadata(gsSourcePath)
1115
+ if err != nil {
1116
+ c.le.WithError(err).Warnf("Failed to read metadata for gs package %s, continuing without dependencies", packagePath)
1117
+ metadata = &GsPackageMetadata{Dependencies: []string{}}
1118
+ }
1119
+
1120
+ // Log dependencies if any are found
1121
+ /*
1122
+ if len(metadata.Dependencies) > 0 {
1123
+ c.le.Debugf("Package %s has dependencies: %v", packagePath, metadata.Dependencies)
1124
+ }
1125
+ */
1126
+
1127
+ // First, recursively process all dependencies
1128
+ for _, depPath := range metadata.Dependencies {
1129
+ if err := c.copyGsPackageWithDependencies(depPath, processedPackages, result); err != nil {
1130
+ return fmt.Errorf("failed to copy dependency %s of package %s: %w", depPath, packagePath, err)
1131
+ }
1132
+ }
1133
+
1134
+ // Now copy the package itself
1135
+ // c.le.Debugf("Copying handwritten package %s to output directory", packagePath)
1136
+
1137
+ // Compute output path for this package
1138
+ outputPath := ComputeModulePath(c.config.OutputPath, packagePath)
1139
+
1140
+ // Create the output directory
1141
+ if err := os.MkdirAll(outputPath, 0o755); err != nil {
1142
+ return fmt.Errorf("failed to create output directory for %s: %w", packagePath, err)
1143
+ }
1144
+
1145
+ // Copy files from embedded FS to output directory
1146
+ if err := c.copyEmbeddedPackage(gsSourcePath, outputPath); err != nil {
1147
+ return fmt.Errorf("failed to copy embedded package %s: %w", packagePath, err)
1148
+ }
1149
+
1150
+ result.CopiedPackages = append(result.CopiedPackages, packagePath)
1151
+ return nil
1152
+ }
@@ -22,7 +22,7 @@ import (
22
22
  // - `make(map[K]V)` becomes `$.makeMap<K_ts, V_ts>()`.
23
23
  // - `make([]T, len, cap)` becomes `$.makeSlice<T_ts>(len, cap)`.
24
24
  // - `make([]byte, len, cap)` becomes `new Uint8Array(len)`.
25
- // - `string(runeVal)` becomes `String.fromCharCode(runeVal)`.
25
+ // - `string(runeVal)` becomes `$.runeOrStringToString(runeVal)`.
26
26
  // - `string([]runeVal)` becomes `$.runesToString(sliceVal)`.
27
27
  // - `string([]byteVal)` becomes `$.bytesToString(sliceVal)`.
28
28
  // - `[]rune(stringVal)` becomes `$.stringToRunes(stringVal)“.
@@ -132,6 +132,18 @@ func (c *GoToTSCompiler) WriteCallExpr(exp *ast.CallExpr) error {
132
132
  return errors.Errorf("unhandled delete call with incorrect number of arguments: %d != 2", len(exp.Args))
133
133
  }
134
134
  c.tsw.WriteLiterally("$.deleteMapEntry")
135
+ case "copy":
136
+ // Translate copy(dst, src) to $.copy(dst, src)
137
+ if len(exp.Args) != 2 {
138
+ return errors.Errorf("unhandled copy call with incorrect number of arguments: %d != 2", len(exp.Args))
139
+ }
140
+ c.tsw.WriteLiterally("$.copy")
141
+ case "recover":
142
+ // Translate recover() to $.recover()
143
+ if len(exp.Args) != 0 {
144
+ return errors.Errorf("unhandled recover call with incorrect number of arguments: %d != 0", len(exp.Args))
145
+ }
146
+ c.tsw.WriteLiterally("$.recover")
135
147
  case "make":
136
148
  // First check if we have a channel type
137
149
  if typ := c.pkg.TypesInfo.TypeOf(exp.Args[0]); typ != nil {
@@ -818,9 +830,9 @@ func (c *GoToTSCompiler) WriteCallExpr(exp *ast.CallExpr) error {
818
830
  if isCallExpr {
819
831
  // Check if it's a call to rune()
820
832
  if innerFunIdent, innerFunIsIdent := innerCall.Fun.(*ast.Ident); innerFunIsIdent && innerFunIdent.String() == "rune" {
821
- // Translate string(rune(val)) to String.fromCharCode(val)
833
+ // Translate string(rune(val)) to $.runeOrStringToString(val)
822
834
  if len(innerCall.Args) == 1 {
823
- c.tsw.WriteLiterally("String.fromCharCode(")
835
+ c.tsw.WriteLiterally("$.runeOrStringToString(")
824
836
  if err := c.WriteValueExpr(innerCall.Args[0]); err != nil {
825
837
  return fmt.Errorf("failed to write argument for string(rune) conversion: %w", err)
826
838
  }
@@ -843,8 +855,8 @@ func (c *GoToTSCompiler) WriteCallExpr(exp *ast.CallExpr) error {
843
855
  }
844
856
 
845
857
  if basic, isBasic := tv.Type.Underlying().(*types.Basic); isBasic && (basic.Kind() == types.Int32 || basic.Kind() == types.UntypedRune) {
846
- // Translate string(rune_val) to String.fromCharCode(rune_val)
847
- c.tsw.WriteLiterally("String.fromCharCode(")
858
+ // Translate string(rune_val) to $.runeOrStringToString(rune_val)
859
+ c.tsw.WriteLiterally("$.runeOrStringToString(")
848
860
  if err := c.WriteValueExpr(arg); err != nil {
849
861
  return fmt.Errorf("failed to write argument for string(int32) conversion: %w", err)
850
862
  }
@@ -1155,10 +1167,8 @@ func (c *GoToTSCompiler) WriteCallExpr(exp *ast.CallExpr) error {
1155
1167
 
1156
1168
  // Check if the type is from an imported package
1157
1169
  if typePkg := namedType.Obj().Pkg(); typePkg != nil && typePkg != c.pkg.Types {
1158
- pkgPath := typePkg.Path()
1159
- // Extract package name from path (e.g., "sync" from "github.com/.../gs/sync")
1160
- parts := strings.Split(pkgPath, "/")
1161
- pkgName := parts[len(parts)-1]
1170
+ // Use the actual package name from the type information
1171
+ pkgName := typePkg.Name()
1162
1172
 
1163
1173
  // Check if this method is async based on metadata
1164
1174
  if c.analysis.IsMethodAsync(pkgName, typeName, methodName) {
package/compiler/field.go CHANGED
@@ -1,6 +1,9 @@
1
1
  package compiler
2
2
 
3
- import "go/ast"
3
+ import (
4
+ "go/ast"
5
+ "go/types"
6
+ )
4
7
 
5
8
  // WriteFieldList translates a Go field list (`ast.FieldList`), which can represent
6
9
  // function parameters, function results, or struct fields, into its TypeScript equivalent.
@@ -70,8 +73,19 @@ func (c *GoToTSCompiler) WriteFieldList(a *ast.FieldList, isArguments bool) {
70
73
 
71
74
  c.tsw.WriteLiterally(": ")
72
75
  if ellipsis, ok := lastParam.Type.(*ast.Ellipsis); ok {
73
- c.WriteTypeExpr(ellipsis.Elt)
74
- c.tsw.WriteLiterally("[]")
76
+ // Get the actual variadic parameter type from the type checker
77
+ // This gives us the slice type (e.g., []interface{})
78
+ variadicType := c.pkg.TypesInfo.TypeOf(lastParam.Type)
79
+ if sliceType, isSlice := variadicType.(*types.Slice); isSlice {
80
+ // For variadic parameters, write the element type followed by []
81
+ // This handles interface{} properly by generating "any[]" instead of "null | any[]"
82
+ c.WriteGoType(sliceType.Elem(), GoTypeContextVariadicParam)
83
+ c.tsw.WriteLiterally("[]")
84
+ } else {
85
+ // Fallback to the original AST-based approach for edge cases
86
+ c.WriteTypeExpr(ellipsis.Elt)
87
+ c.tsw.WriteLiterally("[]")
88
+ }
75
89
  }
76
90
  } else {
77
91
  // Handle regular parameter list for function declarations
@@ -0,0 +1,80 @@
1
+ package compiler
2
+
3
+ import (
4
+ "testing"
5
+
6
+ "github.com/sirupsen/logrus"
7
+ )
8
+
9
+ func TestReadGsPackageMetadata(t *testing.T) {
10
+ // Create a basic compiler configuration
11
+ config := &Config{
12
+ OutputPath: "./test_output",
13
+ Dir: ".",
14
+ }
15
+
16
+ // Create a logger (set to warn level to reduce noise in tests)
17
+ logger := logrus.New()
18
+ logger.SetLevel(logrus.WarnLevel)
19
+ le := logrus.NewEntry(logger)
20
+
21
+ // Create a compiler
22
+ comp, err := NewCompiler(config, le, nil)
23
+ if err != nil {
24
+ t.Fatalf("Failed to create compiler: %v", err)
25
+ }
26
+
27
+ // Test reading metadata from the bytes package
28
+ metadata, err := comp.ReadGsPackageMetadata("gs/bytes")
29
+ if err != nil {
30
+ t.Fatalf("Failed to read metadata: %v", err)
31
+ }
32
+
33
+ // Check that we found the expected dependency
34
+ if len(metadata.Dependencies) == 0 {
35
+ t.Errorf("Expected at least one dependency, got none")
36
+ }
37
+
38
+ // Check for the specific "iter" dependency
39
+ foundIter := false
40
+ for _, dep := range metadata.Dependencies {
41
+ if dep == "iter" {
42
+ foundIter = true
43
+ break
44
+ }
45
+ }
46
+
47
+ if !foundIter {
48
+ t.Errorf("Expected to find 'iter' dependency, got dependencies: %v", metadata.Dependencies)
49
+ }
50
+ }
51
+
52
+ func TestReadGsPackageMetadataNonExistent(t *testing.T) {
53
+ // Create a basic compiler configuration
54
+ config := &Config{
55
+ OutputPath: "./test_output",
56
+ Dir: ".",
57
+ }
58
+
59
+ // Create a logger (set to warn level to reduce noise in tests)
60
+ logger := logrus.New()
61
+ logger.SetLevel(logrus.WarnLevel)
62
+ le := logrus.NewEntry(logger)
63
+
64
+ // Create a compiler
65
+ comp, err := NewCompiler(config, le, nil)
66
+ if err != nil {
67
+ t.Fatalf("Failed to create compiler: %v", err)
68
+ }
69
+
70
+ // Test reading metadata from a non-existent package
71
+ metadata, err := comp.ReadGsPackageMetadata("gs/nonexistent")
72
+ if err != nil {
73
+ t.Fatalf("Expected no error for non-existent package, got: %v", err)
74
+ }
75
+
76
+ // Should return empty metadata for non-existent packages
77
+ if len(metadata.Dependencies) != 0 {
78
+ t.Errorf("Expected empty dependencies for non-existent package, got: %v", metadata.Dependencies)
79
+ }
80
+ }
package/compiler/lit.go CHANGED
@@ -70,14 +70,20 @@ func (c *GoToTSCompiler) WriteBasicLit(exp *ast.BasicLit) {
70
70
 
71
71
  // Check if this is a raw string literal (starts and ends with backticks)
72
72
  if len(value) >= 2 && value[0] == '`' && value[len(value)-1] == '`' {
73
- // This is a Go raw string - need to escape invalid \x sequences for JavaScript
73
+ // This is a Go raw string
74
74
  content := value[1 : len(value)-1] // Remove surrounding backticks
75
75
 
76
- // Escape invalid \x, \u, and \U sequences that would cause TS1125 errors
77
- content = c.escapeInvalidEscapeSequences(content)
78
-
79
- // Write as template literal with corrected content
80
- c.tsw.WriteLiterallyf("`%s`", content)
76
+ // Check if the raw string contains backslashes that would be problematic in template literals
77
+ if strings.Contains(content, `\`) {
78
+ // Convert to a regular string literal with proper escaping
79
+ c.tsw.WriteLiterallyf("%q", content)
80
+ } else {
81
+ // No backslashes, safe to use template literal
82
+ // Escape invalid \x, \u, and \U sequences that would cause TS1125 errors
83
+ content = c.escapeInvalidEscapeSequences(content)
84
+ // Write as template literal with corrected content
85
+ c.tsw.WriteLiterallyf("`%s`", content)
86
+ }
81
87
  } else {
82
88
  // Regular string literal (double quotes) - write as-is
83
89
  c.tsw.WriteLiterally(value)
@@ -4,6 +4,8 @@ import (
4
4
  "fmt"
5
5
  "path/filepath"
6
6
  "strings"
7
+
8
+ "golang.org/x/tools/go/packages"
7
9
  )
8
10
 
9
11
  // ComputeModulePath computes the root of the output typescript module.
@@ -21,10 +23,14 @@ func translateGoPathToTypescriptPath(goImportPath string) string {
21
23
  return fmt.Sprintf("@goscript/%s", goImportPath)
22
24
  }
23
25
 
24
- // packageNameFromGoPath attempts to determine the package name from the last segment of the go path.
25
- func packageNameFromGoPath(goPkgPath string) string {
26
- pts := strings.Split(goPkgPath, "/")
27
- return pts[len(pts)-1]
26
+ // getActualPackageName returns the actual Go package name from package information.
27
+ // If the package is not found in the imports map, returns an error instead of falling back.
28
+ // This handles cases where the package name differs from the last segment of the import path.
29
+ func getActualPackageName(importPath string, importsMap map[string]*packages.Package) (string, error) {
30
+ if pkg, exists := importsMap[importPath]; exists && pkg.Name != "" {
31
+ return pkg.Name, nil
32
+ }
33
+ return "", fmt.Errorf("package %s not found in imports map", importPath)
28
34
  }
29
35
 
30
36
  // TranslateGoFilePathToTypescriptFilePath converts the go package path and typescript filename to output path within the typescript output dir
package/compiler/spec.go CHANGED
@@ -499,7 +499,7 @@ func (c *GoToTSCompiler) WriteInterfaceTypeSpec(a *ast.TypeSpec, t *ast.Interfac
499
499
  // It extracts the Go import path (e.g., `"path/to/pkg"`) and determines the
500
500
  // import alias/name for TypeScript. If the Go import has an explicit name
501
501
  // (e.g., `alias "path/to/pkg"`), that alias is used. Otherwise, the package
502
- // name is derived from the Go path.
502
+ // name is derived from the actual Go package name, not the import path.
503
503
  //
504
504
  // The Go path is then translated to a TypeScript module path using
505
505
  // `translateGoPathToTypescriptPath`.
@@ -516,9 +516,22 @@ func (c *GoToTSCompiler) WriteImportSpec(a *ast.ImportSpec) {
516
516
  }
517
517
 
518
518
  goPath := a.Path.Value[1 : len(a.Path.Value)-1]
519
- impName := packageNameFromGoPath(goPath)
519
+
520
+ // Determine the import name to use in TypeScript
521
+ var impName string
520
522
  if a.Name != nil && a.Name.Name != "" {
523
+ // Explicit alias provided: import alias "path/to/pkg"
521
524
  impName = a.Name.Name
525
+ } else {
526
+ // No explicit alias, use the actual package name from type information
527
+ // This handles cases where package name differs from the last path segment
528
+ if actualName, err := getActualPackageName(goPath, c.pkg.Imports); err == nil {
529
+ impName = actualName
530
+ } else {
531
+ // Fallback to last segment of path if package not found in type information
532
+ pts := strings.Split(goPath, "/")
533
+ impName = pts[len(pts)-1]
534
+ }
522
535
  }
523
536
 
524
537
  // All Go package imports are mapped to the @goscript/ scope.