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.
- package/compiler/analysis.go +260 -2
- package/compiler/assignment.go +6 -0
- package/compiler/compiler.go +98 -8
- package/compiler/decl.go +42 -20
- package/compiler/expr-call.go +37 -1
- package/compiler/expr-type.go +20 -0
- package/compiler/lit.go +4 -20
- package/compiler/spec-struct.go +3 -4
- package/compiler/spec-value.go +18 -1
- package/compiler/spec.go +15 -8
- package/compiler/stmt-range.go +1 -1
- package/compiler/stmt.go +118 -17
- package/compiler/type-assert.go +4 -4
- package/compiler/type.go +63 -5
- package/dist/gs/builtin/map.d.ts +4 -4
- package/dist/gs/builtin/map.js +6 -3
- package/dist/gs/builtin/map.js.map +1 -1
- package/dist/gs/builtin/slice.d.ts +7 -0
- package/dist/gs/builtin/slice.js +12 -0
- package/dist/gs/builtin/slice.js.map +1 -1
- package/dist/gs/builtin/type.js +8 -70
- package/dist/gs/builtin/type.js.map +1 -1
- package/dist/gs/fmt/fmt.d.ts +22 -21
- package/dist/gs/fmt/fmt.js +12 -12
- package/dist/gs/fmt/fmt.js.map +1 -1
- package/dist/gs/internal/testlog/index.d.ts +1 -0
- package/dist/gs/internal/testlog/index.js +5 -0
- package/dist/gs/internal/testlog/index.js.map +1 -0
- package/dist/gs/io/io.d.ts +13 -13
- package/dist/gs/io/io.js +31 -21
- package/dist/gs/io/io.js.map +1 -1
- package/dist/gs/maps/iter.gs.d.ts +7 -0
- package/dist/gs/maps/iter.gs.js +65 -0
- package/dist/gs/maps/iter.gs.js.map +1 -0
- package/dist/gs/maps/maps.gs.d.ts +7 -0
- package/dist/gs/maps/maps.gs.js +79 -0
- package/dist/gs/maps/maps.gs.js.map +1 -0
- package/dist/gs/path/filepath/match.d.ts +4 -3
- package/dist/gs/path/filepath/match.js +2 -2
- package/dist/gs/path/filepath/match.js.map +1 -1
- package/dist/gs/path/filepath/path.d.ts +2 -2
- package/dist/gs/path/filepath/path.js +3 -3
- package/dist/gs/path/filepath/path.js.map +1 -1
- package/dist/gs/reflect/abi.d.ts +59 -0
- package/dist/gs/reflect/abi.gs.d.ts +59 -0
- package/dist/gs/reflect/abi.gs.js +79 -0
- package/dist/gs/reflect/abi.gs.js.map +1 -0
- package/dist/gs/reflect/abi.js +79 -0
- package/dist/gs/reflect/abi.js.map +1 -0
- package/dist/gs/reflect/badlinkname.d.ts +52 -0
- package/dist/gs/reflect/badlinkname.gs.d.ts +52 -0
- package/dist/gs/reflect/badlinkname.gs.js +72 -0
- package/dist/gs/reflect/badlinkname.gs.js.map +1 -0
- package/dist/gs/reflect/badlinkname.js +72 -0
- package/dist/gs/reflect/badlinkname.js.map +1 -0
- package/dist/gs/reflect/deepequal.gs.d.ts +25 -0
- package/dist/gs/reflect/deepequal.gs.js +308 -0
- package/dist/gs/reflect/deepequal.gs.js.map +1 -0
- package/dist/gs/reflect/float32reg_generic.gs.d.ts +2 -0
- package/dist/gs/reflect/float32reg_generic.gs.js +10 -0
- package/dist/gs/reflect/float32reg_generic.gs.js.map +1 -0
- package/dist/gs/reflect/index.gs.d.ts +1 -0
- package/dist/gs/reflect/index.gs.js +3 -0
- package/dist/gs/reflect/index.gs.js.map +1 -0
- package/dist/gs/reflect/iter.gs.d.ts +3 -0
- package/dist/gs/reflect/iter.gs.js +24 -0
- package/dist/gs/reflect/iter.gs.js.map +1 -0
- package/dist/gs/reflect/makefunc.gs.d.ts +34 -0
- package/dist/gs/reflect/makefunc.gs.js +288 -0
- package/dist/gs/reflect/makefunc.gs.js.map +1 -0
- package/dist/gs/reflect/map_swiss.gs.d.ts +14 -0
- package/dist/gs/reflect/map_swiss.gs.js +70 -0
- package/dist/gs/reflect/map_swiss.gs.js.map +1 -0
- package/dist/gs/reflect/reflect.gs.d.ts +132 -0
- package/dist/gs/reflect/reflect.gs.js +437 -0
- package/dist/gs/reflect/reflect.gs.js.map +1 -0
- package/dist/gs/reflect/swapper.gs.d.ts +1 -0
- package/dist/gs/reflect/swapper.gs.js +32 -0
- package/dist/gs/reflect/swapper.gs.js.map +1 -0
- package/dist/gs/reflect/type.gs.d.ts +4 -0
- package/dist/gs/reflect/type.gs.js +21 -0
- package/dist/gs/reflect/type.gs.js.map +1 -0
- package/dist/gs/reflect/value.gs.d.ts +4 -0
- package/dist/gs/reflect/value.gs.js +12 -0
- package/dist/gs/reflect/value.gs.js.map +1 -0
- package/dist/gs/reflect/visiblefields.gs.d.ts +3 -0
- package/dist/gs/reflect/visiblefields.gs.js +123 -0
- package/dist/gs/reflect/visiblefields.gs.js.map +1 -0
- package/dist/gs/strings/reader.d.ts +1 -1
- package/dist/gs/strings/reader.js.map +1 -1
- package/dist/gs/stringslite/index.d.ts +1 -0
- package/dist/gs/stringslite/index.js +2 -0
- package/dist/gs/stringslite/index.js.map +1 -0
- package/dist/gs/stringslite/strings.d.ts +11 -0
- package/dist/gs/stringslite/strings.js +67 -0
- package/dist/gs/stringslite/strings.js.map +1 -0
- package/dist/gs/time/time.d.ts +69 -0
- package/dist/gs/time/time.js +350 -0
- package/dist/gs/time/time.js.map +1 -1
- package/gs/builtin/map.ts +12 -8
- package/gs/builtin/slice.ts +13 -0
- package/gs/builtin/type.ts +8 -100
- package/gs/fmt/fmt.ts +33 -33
- package/gs/io/io.ts +47 -39
- package/gs/path/filepath/match.ts +4 -4
- package/gs/path/filepath/path.ts +3 -3
- package/gs/strings/reader.ts +1 -1
- package/gs/time/time.ts +403 -0
- 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
|
|
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
|
-
|
|
183
|
-
|
|
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
|
}
|
package/compiler/spec-struct.go
CHANGED
|
@@ -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
|
-
//
|
|
24
|
-
|
|
25
|
-
|
|
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
|
package/compiler/spec-value.go
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
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
|
|
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
|
|
448
|
+
if !isInsideFunction {
|
|
442
449
|
c.tsw.WriteLiterally("export ")
|
|
443
450
|
}
|
|
444
451
|
c.tsw.WriteLiterally("type ")
|
package/compiler/stmt-range.go
CHANGED
|
@@ -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("
|
|
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 (
|
|
447
|
+
func (c *GoToTSCompiler) WriteStmtIf(exp *ast.IfStmt) error {
|
|
448
448
|
if exp.Init != nil {
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
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
|
-
|
|
454
|
-
|
|
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
|
-
|
|
460
|
-
|
|
461
|
-
|
|
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
|
-
|
|
466
|
-
|
|
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
|
-
|
|
506
|
+
c.tsw.WriteLiterally(") ")
|
|
470
507
|
|
|
471
508
|
if exp.Body != nil {
|
|
472
|
-
if err :=
|
|
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 :=
|
|
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
|
-
|
|
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 :=
|
|
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 :=
|
|
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
|
+
}
|
package/compiler/type-assert.go
CHANGED
|
@@ -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_" //
|
|
100
|
-
tempOkName := "_gs_ta_ok_" //
|
|
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_" //
|
|
221
|
-
tempOkName := "_gs_ta_ok_" //
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
}
|
package/dist/gs/builtin/map.d.ts
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
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
|
|
33
|
+
export declare const mapHas: <K, V>(map: Map<K, V> | null, key: K) => boolean;
|
package/dist/gs/builtin/map.js
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
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;
|
|
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.
|
package/dist/gs/builtin/slice.js
CHANGED
|
@@ -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.
|