goscript 0.0.41 → 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 (109) hide show
  1. package/compiler/analysis.go +260 -2
  2. package/compiler/assignment.go +6 -0
  3. package/compiler/compiler.go +98 -8
  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/stmt.go +118 -17
  13. package/compiler/type-assert.go +4 -4
  14. package/compiler/type.go +63 -5
  15. package/dist/gs/builtin/map.d.ts +4 -4
  16. package/dist/gs/builtin/map.js +6 -3
  17. package/dist/gs/builtin/map.js.map +1 -1
  18. package/dist/gs/builtin/slice.d.ts +7 -0
  19. package/dist/gs/builtin/slice.js +12 -0
  20. package/dist/gs/builtin/slice.js.map +1 -1
  21. package/dist/gs/builtin/type.js +8 -70
  22. package/dist/gs/builtin/type.js.map +1 -1
  23. package/dist/gs/fmt/fmt.d.ts +22 -21
  24. package/dist/gs/fmt/fmt.js +12 -12
  25. package/dist/gs/fmt/fmt.js.map +1 -1
  26. package/dist/gs/internal/testlog/index.d.ts +1 -0
  27. package/dist/gs/internal/testlog/index.js +5 -0
  28. package/dist/gs/internal/testlog/index.js.map +1 -0
  29. package/dist/gs/io/io.d.ts +13 -13
  30. package/dist/gs/io/io.js +31 -21
  31. package/dist/gs/io/io.js.map +1 -1
  32. package/dist/gs/maps/iter.gs.d.ts +7 -0
  33. package/dist/gs/maps/iter.gs.js +65 -0
  34. package/dist/gs/maps/iter.gs.js.map +1 -0
  35. package/dist/gs/maps/maps.gs.d.ts +7 -0
  36. package/dist/gs/maps/maps.gs.js +79 -0
  37. package/dist/gs/maps/maps.gs.js.map +1 -0
  38. package/dist/gs/path/filepath/match.d.ts +4 -3
  39. package/dist/gs/path/filepath/match.js +2 -2
  40. package/dist/gs/path/filepath/match.js.map +1 -1
  41. package/dist/gs/path/filepath/path.d.ts +2 -2
  42. package/dist/gs/path/filepath/path.js +3 -3
  43. package/dist/gs/path/filepath/path.js.map +1 -1
  44. package/dist/gs/reflect/abi.d.ts +59 -0
  45. package/dist/gs/reflect/abi.gs.d.ts +59 -0
  46. package/dist/gs/reflect/abi.gs.js +79 -0
  47. package/dist/gs/reflect/abi.gs.js.map +1 -0
  48. package/dist/gs/reflect/abi.js +79 -0
  49. package/dist/gs/reflect/abi.js.map +1 -0
  50. package/dist/gs/reflect/badlinkname.d.ts +52 -0
  51. package/dist/gs/reflect/badlinkname.gs.d.ts +52 -0
  52. package/dist/gs/reflect/badlinkname.gs.js +72 -0
  53. package/dist/gs/reflect/badlinkname.gs.js.map +1 -0
  54. package/dist/gs/reflect/badlinkname.js +72 -0
  55. package/dist/gs/reflect/badlinkname.js.map +1 -0
  56. package/dist/gs/reflect/deepequal.gs.d.ts +25 -0
  57. package/dist/gs/reflect/deepequal.gs.js +308 -0
  58. package/dist/gs/reflect/deepequal.gs.js.map +1 -0
  59. package/dist/gs/reflect/float32reg_generic.gs.d.ts +2 -0
  60. package/dist/gs/reflect/float32reg_generic.gs.js +10 -0
  61. package/dist/gs/reflect/float32reg_generic.gs.js.map +1 -0
  62. package/dist/gs/reflect/index.gs.d.ts +1 -0
  63. package/dist/gs/reflect/index.gs.js +3 -0
  64. package/dist/gs/reflect/index.gs.js.map +1 -0
  65. package/dist/gs/reflect/iter.gs.d.ts +3 -0
  66. package/dist/gs/reflect/iter.gs.js +24 -0
  67. package/dist/gs/reflect/iter.gs.js.map +1 -0
  68. package/dist/gs/reflect/makefunc.gs.d.ts +34 -0
  69. package/dist/gs/reflect/makefunc.gs.js +288 -0
  70. package/dist/gs/reflect/makefunc.gs.js.map +1 -0
  71. package/dist/gs/reflect/map_swiss.gs.d.ts +14 -0
  72. package/dist/gs/reflect/map_swiss.gs.js +70 -0
  73. package/dist/gs/reflect/map_swiss.gs.js.map +1 -0
  74. package/dist/gs/reflect/reflect.gs.d.ts +132 -0
  75. package/dist/gs/reflect/reflect.gs.js +437 -0
  76. package/dist/gs/reflect/reflect.gs.js.map +1 -0
  77. package/dist/gs/reflect/swapper.gs.d.ts +1 -0
  78. package/dist/gs/reflect/swapper.gs.js +32 -0
  79. package/dist/gs/reflect/swapper.gs.js.map +1 -0
  80. package/dist/gs/reflect/type.gs.d.ts +4 -0
  81. package/dist/gs/reflect/type.gs.js +21 -0
  82. package/dist/gs/reflect/type.gs.js.map +1 -0
  83. package/dist/gs/reflect/value.gs.d.ts +4 -0
  84. package/dist/gs/reflect/value.gs.js +12 -0
  85. package/dist/gs/reflect/value.gs.js.map +1 -0
  86. package/dist/gs/reflect/visiblefields.gs.d.ts +3 -0
  87. package/dist/gs/reflect/visiblefields.gs.js +123 -0
  88. package/dist/gs/reflect/visiblefields.gs.js.map +1 -0
  89. package/dist/gs/strings/reader.d.ts +1 -1
  90. package/dist/gs/strings/reader.js.map +1 -1
  91. package/dist/gs/stringslite/index.d.ts +1 -0
  92. package/dist/gs/stringslite/index.js +2 -0
  93. package/dist/gs/stringslite/index.js.map +1 -0
  94. package/dist/gs/stringslite/strings.d.ts +11 -0
  95. package/dist/gs/stringslite/strings.js +67 -0
  96. package/dist/gs/stringslite/strings.js.map +1 -0
  97. package/dist/gs/time/time.d.ts +69 -0
  98. package/dist/gs/time/time.js +350 -0
  99. package/dist/gs/time/time.js.map +1 -1
  100. package/gs/builtin/map.ts +12 -8
  101. package/gs/builtin/slice.ts +13 -0
  102. package/gs/builtin/type.ts +8 -100
  103. package/gs/fmt/fmt.ts +33 -33
  104. package/gs/io/io.ts +47 -39
  105. package/gs/path/filepath/match.ts +4 -4
  106. package/gs/path/filepath/path.ts +3 -3
  107. package/gs/strings/reader.ts +1 -1
  108. package/gs/time/time.ts +403 -0
  109. package/package.json +1 -1
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
 
package/compiler/stmt.go CHANGED
@@ -444,53 +444,90 @@ func (c *GoToTSCompiler) WriteStmtSend(exp *ast.SendStmt) error {
444
444
  // recursively calling `WriteStmtIf`.
445
445
  //
446
446
  // The function aims to produce idiomatic TypeScript `if/else if/else` structures.
447
- func (s *GoToTSCompiler) WriteStmtIf(exp *ast.IfStmt) error {
447
+ func (c *GoToTSCompiler) WriteStmtIf(exp *ast.IfStmt) error {
448
448
  if exp.Init != nil {
449
- s.tsw.WriteLiterally("{") // Write opening brace
450
- s.tsw.WriteLine("") // Add newline immediately after opening brace
451
- s.tsw.Indent(1) // Indent for the initializer
449
+ // Check if we need to handle variable shadowing BEFORE creating the block
450
+ var shadowingInfo *ShadowingInfo
451
+ if assignStmt, ok := exp.Init.(*ast.AssignStmt); ok {
452
+ shadowingInfo = c.analysis.GetShadowingInfo(assignStmt)
453
+ }
454
+
455
+ // Generate temporary variables OUTSIDE the block to avoid temporal dead zone
456
+ if shadowingInfo != nil {
457
+ for varName, tempVarName := range shadowingInfo.TempVariables {
458
+ c.tsw.WriteLiterally("let ")
459
+ c.tsw.WriteLiterally(tempVarName)
460
+ c.tsw.WriteLiterally(" = ")
461
+ c.tsw.WriteLiterally(c.sanitizeIdentifier(varName))
462
+ c.tsw.WriteLine("")
463
+ }
464
+ }
452
465
 
453
- if err := s.WriteStmt(exp.Init); err != nil { // Write the initializer
454
- return err
466
+ c.tsw.WriteLiterally("{") // Write opening brace
467
+ c.tsw.WriteLine("") // Add newline immediately after opening brace
468
+ c.tsw.Indent(1) // Indent for the initializer
469
+
470
+ // Check if we need to handle variable shadowing
471
+ if assignStmt, ok := exp.Init.(*ast.AssignStmt); ok {
472
+ if shadowingInfo != nil {
473
+ // Write the assignment statement with special handling for shadowing
474
+ if err := c.writeShadowedAssignment(assignStmt, shadowingInfo); err != nil {
475
+ return err
476
+ }
477
+ } else {
478
+ // No shadowing, write normally
479
+ if err := c.WriteStmt(exp.Init); err != nil {
480
+ return err
481
+ }
482
+ }
483
+ } else {
484
+ // Not an assignment statement, write normally
485
+ if err := c.WriteStmt(exp.Init); err != nil {
486
+ return err
487
+ }
455
488
  }
456
489
 
457
490
  // This defer handles closing the synthetic block for the initializer
458
491
  defer func() {
459
- s.tsw.Indent(-1)
460
- s.tsw.WriteLiterally("}") // Write the closing brace at the now-correct indent level
461
- s.tsw.WriteLine("") // Ensure a newline *after* this '}', critical for preventing '}}'
492
+ c.tsw.Indent(-1)
493
+ c.tsw.WriteLiterally("}") // Write the closing brace at the now-correct indent level
494
+ c.tsw.WriteLine("") // Ensure a newline *after* this '}', critical for preventing '}}'
462
495
  }()
463
496
  }
464
497
 
465
- s.tsw.WriteLiterally("if (")
466
- if err := s.WriteValueExpr(exp.Cond); err != nil { // Condition is a value
498
+ // Ensure shadowing context is clear before writing condition
499
+ // (condition should refer to new local variables, not temp variables)
500
+ c.shadowingContext = make(map[string]string)
501
+
502
+ c.tsw.WriteLiterally("if (")
503
+ if err := c.WriteValueExpr(exp.Cond); err != nil { // Condition is a value
467
504
  return err
468
505
  }
469
- s.tsw.WriteLiterally(") ")
506
+ c.tsw.WriteLiterally(") ")
470
507
 
471
508
  if exp.Body != nil {
472
- if err := s.WriteStmtBlock(exp.Body, exp.Else != nil); err != nil {
509
+ if err := c.WriteStmtBlock(exp.Body, exp.Else != nil); err != nil {
473
510
  return fmt.Errorf("failed to write if body block statement: %w", err)
474
511
  }
475
512
  } else {
476
513
  // Handle nil body case using WriteStmtBlock with an empty block
477
- if err := s.WriteStmtBlock(&ast.BlockStmt{}, exp.Else != nil); err != nil {
514
+ if err := c.WriteStmtBlock(&ast.BlockStmt{}, exp.Else != nil); err != nil {
478
515
  return fmt.Errorf("failed to write empty block statement in if statement: %w", err)
479
516
  }
480
517
  }
481
518
 
482
519
  // handle else branch
483
520
  if exp.Else != nil {
484
- s.tsw.WriteLiterally(" else ")
521
+ c.tsw.WriteLiterally(" else ")
485
522
  switch elseStmt := exp.Else.(type) {
486
523
  case *ast.BlockStmt:
487
524
  // Always pass false for suppressNewline here
488
- if err := s.WriteStmtBlock(elseStmt, false); err != nil {
525
+ if err := c.WriteStmtBlock(elseStmt, false); err != nil {
489
526
  return fmt.Errorf("failed to write else block statement in if statement: %w", err)
490
527
  }
491
528
  case *ast.IfStmt:
492
529
  // Recursive call handles its own block formatting
493
- if err := s.WriteStmtIf(elseStmt); err != nil {
530
+ if err := c.WriteStmtIf(elseStmt); err != nil {
494
531
  return fmt.Errorf("failed to write else if statement in if statement: %w", err)
495
532
  }
496
533
  }
@@ -897,3 +934,67 @@ func (c *GoToTSCompiler) WriteStmtLabeled(stmt *ast.LabeledStmt) error {
897
934
 
898
935
  return nil
899
936
  }
937
+
938
+ // writeShadowedAssignment writes an assignment statement that has variable shadowing,
939
+ // applying the shadowing context only to RHS expressions.
940
+ func (c *GoToTSCompiler) writeShadowedAssignment(stmt *ast.AssignStmt, shadowingInfo *ShadowingInfo) error {
941
+ // Write the LHS variables (these are new declarations, don't use temp variables)
942
+ for i, lhsExpr := range stmt.Lhs {
943
+ if i > 0 {
944
+ c.tsw.WriteLiterally(", ")
945
+ }
946
+
947
+ if ident, ok := lhsExpr.(*ast.Ident); ok {
948
+ if ident.Name == "_" {
949
+ c.tsw.WriteLiterally("_")
950
+ } else {
951
+ c.tsw.WriteLiterally("let ")
952
+ c.WriteIdent(ident, false) // Don't use temp variable for LHS
953
+ }
954
+ } else {
955
+ // For non-identifier LHS (shouldn't happen in := assignments), write normally
956
+ if err := c.WriteValueExpr(lhsExpr); err != nil {
957
+ return err
958
+ }
959
+ }
960
+ }
961
+
962
+ c.tsw.WriteLiterally(" = ")
963
+
964
+ // Set up shadowing context for RHS expressions only
965
+ originalContext := make(map[string]string)
966
+ for varName, tempVarName := range shadowingInfo.TempVariables {
967
+ originalContext[varName] = c.shadowingContext[varName] // backup original
968
+ c.shadowingContext[varName] = tempVarName
969
+ }
970
+
971
+ // Write RHS expressions with shadowing context
972
+ for i, rhsExpr := range stmt.Rhs {
973
+ if i > 0 {
974
+ c.tsw.WriteLiterally(", ")
975
+ }
976
+ if err := c.WriteValueExpr(rhsExpr); err != nil {
977
+ // Restore context on error
978
+ for varName := range shadowingInfo.TempVariables {
979
+ if original, existed := originalContext[varName]; existed {
980
+ c.shadowingContext[varName] = original
981
+ } else {
982
+ delete(c.shadowingContext, varName)
983
+ }
984
+ }
985
+ return err
986
+ }
987
+ }
988
+
989
+ // Restore original context after writing RHS
990
+ for varName := range shadowingInfo.TempVariables {
991
+ if original, existed := originalContext[varName]; existed {
992
+ c.shadowingContext[varName] = original
993
+ } else {
994
+ delete(c.shadowingContext, varName)
995
+ }
996
+ }
997
+
998
+ c.tsw.WriteLine("")
999
+ return nil
1000
+ }
@@ -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;
package/compiler/type.go CHANGED
@@ -373,14 +373,15 @@ func (c *GoToTSCompiler) WriteArrayType(t *types.Array) {
373
373
  }
374
374
 
375
375
  // WriteMapType translates a Go map type (map[K]V) to its TypeScript equivalent.
376
- // It generates Map<K_ts, V_ts>, where K_ts and V_ts are the translated key
376
+ // It generates Map<K_ts, V_ts> | null, where K_ts and V_ts are the translated key
377
377
  // and element types respectively.
378
+ // Maps are nilable in Go, so they are represented as nullable types in TypeScript.
378
379
  func (c *GoToTSCompiler) WriteMapType(t *types.Map) {
379
380
  c.tsw.WriteLiterally("Map<")
380
381
  c.WriteGoType(t.Key(), GoTypeContextGeneral)
381
382
  c.tsw.WriteLiterally(", ")
382
383
  c.WriteGoType(t.Elem(), GoTypeContextGeneral)
383
- c.tsw.WriteLiterally(">")
384
+ c.tsw.WriteLiterally("> | null")
384
385
  }
385
386
 
386
387
  // WriteChannelType translates a Go channel type (chan T) to its TypeScript equivalent.
@@ -566,7 +567,17 @@ func (c *GoToTSCompiler) writeInterfaceStructure(iface *types.Interface, astNode
566
567
  c.tsw.WriteLiterally(method.Name())
567
568
  c.tsw.WriteLiterally("(") // Start params
568
569
  params := sig.Params()
569
- for j := 0; j < params.Len(); j++ {
570
+
571
+ // Check if this is a variadic method
572
+ isVariadic := sig.Variadic()
573
+
574
+ // Handle regular parameters (all parameters if not variadic, or all but last if variadic)
575
+ paramCount := params.Len()
576
+ if isVariadic && paramCount > 0 {
577
+ paramCount-- // Don't process the last parameter in the regular loop for variadic functions
578
+ }
579
+
580
+ for j := 0; j < paramCount; j++ {
570
581
  if j > 0 {
571
582
  c.tsw.WriteLiterally(", ")
572
583
  }
@@ -579,6 +590,35 @@ func (c *GoToTSCompiler) writeInterfaceStructure(iface *types.Interface, astNode
579
590
  c.tsw.WriteLiterally(": ")
580
591
  c.WriteGoType(paramVar.Type(), GoTypeContextGeneral) // Recursive call for param type
581
592
  }
593
+
594
+ // Handle variadic parameter if present
595
+ if isVariadic && params.Len() > 0 {
596
+ if paramCount > 0 { // Add comma if there were regular parameters
597
+ c.tsw.WriteLiterally(", ")
598
+ }
599
+
600
+ // Get the last parameter (the variadic one)
601
+ paramVar := params.At(params.Len() - 1)
602
+ paramName := paramVar.Name()
603
+ if paramName == "" || paramName == "_" {
604
+ paramName = fmt.Sprintf("_p%d", params.Len()-1)
605
+ }
606
+
607
+ // Write variadic parameter with ... prefix
608
+ c.tsw.WriteLiterally("...")
609
+ c.tsw.WriteLiterally(c.sanitizeIdentifier(paramName))
610
+ c.tsw.WriteLiterally(": ")
611
+
612
+ // For variadic parameters, the type is a slice, so we need the element type + []
613
+ if sliceType, ok := paramVar.Type().(*types.Slice); ok {
614
+ c.WriteGoType(sliceType.Elem(), GoTypeContextVariadicParam) // Use variadic context to avoid null prefix
615
+ c.tsw.WriteLiterally("[]")
616
+ } else {
617
+ // Fallback if it's not a slice type (shouldn't happen for valid variadic parameters)
618
+ c.WriteGoType(paramVar.Type(), GoTypeContextGeneral)
619
+ }
620
+ }
621
+
582
622
  c.tsw.WriteLiterally(")") // End params
583
623
 
584
624
  // Return type
@@ -587,14 +627,32 @@ func (c *GoToTSCompiler) writeInterfaceStructure(iface *types.Interface, astNode
587
627
  if results.Len() == 0 {
588
628
  c.tsw.WriteLiterally("void")
589
629
  } else if results.Len() == 1 {
590
- c.WriteGoType(results.At(0).Type(), GoTypeContextFunctionReturn) // Recursive call for result type
630
+ // Try to use AST information if available to preserve qualified names
631
+ if astField != nil && astField.Type != nil {
632
+ if funcType, ok := astField.Type.(*ast.FuncType); ok && funcType.Results != nil && len(funcType.Results.List) == 1 {
633
+ c.WriteTypeExpr(funcType.Results.List[0].Type)
634
+ } else {
635
+ c.WriteGoType(results.At(0).Type(), GoTypeContextFunctionReturn) // Fallback
636
+ }
637
+ } else {
638
+ c.WriteGoType(results.At(0).Type(), GoTypeContextFunctionReturn) // Fallback
639
+ }
591
640
  } else {
592
641
  c.tsw.WriteLiterally("[")
593
642
  for j := 0; j < results.Len(); j++ {
594
643
  if j > 0 {
595
644
  c.tsw.WriteLiterally(", ")
596
645
  }
597
- c.WriteGoType(results.At(j).Type(), GoTypeContextFunctionReturn) // Recursive call for result type
646
+ // Try to use AST information if available to preserve qualified names
647
+ if astField != nil && astField.Type != nil {
648
+ if funcType, ok := astField.Type.(*ast.FuncType); ok && funcType.Results != nil && j < len(funcType.Results.List) {
649
+ c.WriteTypeExpr(funcType.Results.List[j].Type)
650
+ } else {
651
+ c.WriteGoType(results.At(j).Type(), GoTypeContextFunctionReturn) // Fallback
652
+ }
653
+ } else {
654
+ c.WriteGoType(results.At(j).Type(), GoTypeContextFunctionReturn) // Fallback
655
+ }
598
656
  }
599
657
  c.tsw.WriteLiterally("]")
600
658
  }
@@ -10,24 +10,24 @@ export declare const makeMap: <K, V>() => Map<K, V>;
10
10
  * @param defaultValue The default value to return if the key doesn't exist.
11
11
  * @returns A tuple [value, exists] where value is the map value or defaultValue, and exists is whether the key was found.
12
12
  */
13
- export declare function mapGet<K, V, D>(map: Map<K, V>, key: K, defaultValue: D): [V, true] | [D, false];
13
+ export declare function mapGet<K, V, D>(map: Map<K, V> | null, key: K, defaultValue: D): [V, true] | [D, false];
14
14
  /**
15
15
  * Sets a value in a map.
16
16
  * @param map The map to set in.
17
17
  * @param key The key to set.
18
18
  * @param value The value to set.
19
19
  */
20
- export declare const mapSet: <K, V>(map: Map<K, V>, key: K, value: V) => void;
20
+ export declare const mapSet: <K, V>(map: Map<K, V> | null, key: K, value: V) => void;
21
21
  /**
22
22
  * Deletes a key from a map.
23
23
  * @param map The map to delete from.
24
24
  * @param key The key to delete.
25
25
  */
26
- export declare const deleteMapEntry: <K, V>(map: Map<K, V>, key: K) => void;
26
+ export declare const deleteMapEntry: <K, V>(map: Map<K, V> | null, key: K) => void;
27
27
  /**
28
28
  * Checks if a key exists in a map.
29
29
  * @param map The map to check in.
30
30
  * @param key The key to check.
31
31
  * @returns True if the key exists, false otherwise.
32
32
  */
33
- export declare const mapHas: <K, V>(map: Map<K, V>, key: K) => boolean;
33
+ export declare const mapHas: <K, V>(map: Map<K, V> | null, key: K) => boolean;
@@ -13,7 +13,7 @@ export const makeMap = () => {
13
13
  * @returns A tuple [value, exists] where value is the map value or defaultValue, and exists is whether the key was found.
14
14
  */
15
15
  export function mapGet(map, key, defaultValue) {
16
- const exists = map.has(key);
16
+ const exists = map?.has(key);
17
17
  if (exists) {
18
18
  return [map.get(key), true];
19
19
  }
@@ -28,6 +28,9 @@ export function mapGet(map, key, defaultValue) {
28
28
  * @param value The value to set.
29
29
  */
30
30
  export const mapSet = (map, key, value) => {
31
+ if (!map) {
32
+ throw new Error('assign to nil map');
33
+ }
31
34
  map.set(key, value);
32
35
  };
33
36
  /**
@@ -36,7 +39,7 @@ export const mapSet = (map, key, value) => {
36
39
  * @param key The key to delete.
37
40
  */
38
41
  export const deleteMapEntry = (map, key) => {
39
- map.delete(key);
42
+ map?.delete(key);
40
43
  };
41
44
  /**
42
45
  * Checks if a key exists in a map.
@@ -45,6 +48,6 @@ export const deleteMapEntry = (map, key) => {
45
48
  * @returns True if the key exists, false otherwise.
46
49
  */
47
50
  export const mapHas = (map, key) => {
48
- return map.has(key);
51
+ return map?.has(key) ?? false;
49
52
  };
50
53
  //# sourceMappingURL=map.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"map.js","sourceRoot":"","sources":["../../../gs/builtin/map.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,GAAoB,EAAE;IAC3C,OAAO,IAAI,GAAG,EAAQ,CAAA;AACxB,CAAC,CAAA;AACD;;;;;;GAMG;AACH,MAAM,UAAU,MAAM,CACpB,GAAc,EACd,GAAM,EACN,YAAe;IAEf,MAAM,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IAC3B,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAE,EAAE,IAAI,CAAC,CAAA;IAC9B,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,YAAY,EAAE,KAAK,CAAC,CAAA;IAC9B,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,CAAO,GAAc,EAAE,GAAM,EAAE,KAAQ,EAAQ,EAAE;IACrE,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;AACrB,CAAC,CAAA;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAO,GAAc,EAAE,GAAM,EAAQ,EAAE;IACnE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;AACjB,CAAC,CAAA;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,CAAO,GAAc,EAAE,GAAM,EAAW,EAAE;IAC9D,OAAO,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;AACrB,CAAC,CAAA"}
1
+ {"version":3,"file":"map.js","sourceRoot":"","sources":["../../../gs/builtin/map.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,GAAoB,EAAE;IAC3C,OAAO,IAAI,GAAG,EAAQ,CAAA;AACxB,CAAC,CAAA;AAED;;;;;;GAMG;AACH,MAAM,UAAU,MAAM,CACpB,GAAqB,EACrB,GAAM,EACN,YAAe;IAEf,MAAM,MAAM,GAAG,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,CAAA;IAC5B,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,CAAC,GAAI,CAAC,GAAG,CAAC,GAAG,CAAE,EAAE,IAAI,CAAC,CAAA;IAC/B,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,YAAY,EAAE,KAAK,CAAC,CAAA;IAC9B,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,CAAO,GAAqB,EAAE,GAAM,EAAE,KAAQ,EAAQ,EAAE;IAC5E,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAA;IACtC,CAAC;IACD,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;AACrB,CAAC,CAAA;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAO,GAAqB,EAAE,GAAM,EAAQ,EAAE;IAC1E,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,CAAA;AAClB,CAAC,CAAA;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,CAAO,GAAqB,EAAE,GAAM,EAAW,EAAE;IACrE,OAAO,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,IAAI,KAAK,CAAA;AAC/B,CAAC,CAAA"}
@@ -102,6 +102,13 @@ export declare function index<T>(collection: string | Slice<T> | T[], index: num
102
102
  * @returns An array of numbers representing the Unicode code points.
103
103
  */
104
104
  export declare const stringToRunes: (str: string) => number[];
105
+ /**
106
+ * Converts a single-character string to its Unicode code point (rune).
107
+ * Used for readable rune constants like $.stringToRune('/') instead of 47.
108
+ * @param str A single-character string.
109
+ * @returns The Unicode code point as a number.
110
+ */
111
+ export declare const stringToRune: (str: string) => number;
105
112
  /**
106
113
  * Converts an array of Unicode code points (runes) to a string.
107
114
  * @param runes The input array of numbers representing Unicode code points.
@@ -793,6 +793,18 @@ export function index(collection, index) {
793
793
  export const stringToRunes = (str) => {
794
794
  return Array.from(str).map((c) => c.codePointAt(0) || 0);
795
795
  };
796
+ /**
797
+ * Converts a single-character string to its Unicode code point (rune).
798
+ * Used for readable rune constants like $.stringToRune('/') instead of 47.
799
+ * @param str A single-character string.
800
+ * @returns The Unicode code point as a number.
801
+ */
802
+ export const stringToRune = (str) => {
803
+ if (str.length === 0) {
804
+ return 0;
805
+ }
806
+ return str.codePointAt(0) || 0;
807
+ };
796
808
  /**
797
809
  * Converts an array of Unicode code points (runes) to a string.
798
810
  * @param runes The input array of numbers representing Unicode code points.