goscript 0.0.77 → 0.0.78
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/decl.go +34 -0
- package/compiler/spec-struct.go +173 -0
- package/compiler/spec.go +30 -1
- package/package.json +1 -1
package/compiler/decl.go
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
package compiler
|
|
2
2
|
|
|
3
3
|
import (
|
|
4
|
+
"bytes"
|
|
4
5
|
"fmt"
|
|
5
6
|
"go/ast"
|
|
6
7
|
"go/token"
|
|
@@ -677,6 +678,14 @@ func (c *GoToTSCompiler) writeMethodSignature(decl *ast.FuncDecl) (bool, error)
|
|
|
677
678
|
}
|
|
678
679
|
}
|
|
679
680
|
|
|
681
|
+
if !isAsync {
|
|
682
|
+
bodyNeedsAsync, err := c.funcBodyNeedsAsync(decl, true)
|
|
683
|
+
if err != nil {
|
|
684
|
+
return false, err
|
|
685
|
+
}
|
|
686
|
+
isAsync = bodyNeedsAsync
|
|
687
|
+
}
|
|
688
|
+
|
|
680
689
|
// Methods are typically public in the TS output
|
|
681
690
|
c.tsw.WriteLiterally("public ")
|
|
682
691
|
|
|
@@ -744,6 +753,31 @@ func (c *GoToTSCompiler) writeMethodSignature(decl *ast.FuncDecl) (bool, error)
|
|
|
744
753
|
return isAsync, nil
|
|
745
754
|
}
|
|
746
755
|
|
|
756
|
+
// funcBodyNeedsAsync checks whether emitting a function body would generate await.
|
|
757
|
+
func (c *GoToTSCompiler) funcBodyNeedsAsync(decl *ast.FuncDecl, isMethod bool) (bool, error) {
|
|
758
|
+
if decl.Body == nil {
|
|
759
|
+
return false, nil
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
var body strings.Builder
|
|
763
|
+
writer := NewTSCodeWriter(&body)
|
|
764
|
+
tempCompiler := NewGoToTSCompiler(writer, c.pkg, c.analysis, c.currentFilePath)
|
|
765
|
+
|
|
766
|
+
if isMethod {
|
|
767
|
+
if err := tempCompiler.writeMethodBodyWithReceiverBinding(decl, "this"); err != nil {
|
|
768
|
+
return false, err
|
|
769
|
+
}
|
|
770
|
+
} else {
|
|
771
|
+
for _, stmt := range decl.Body.List {
|
|
772
|
+
if err := tempCompiler.WriteStmt(stmt); err != nil {
|
|
773
|
+
return false, err
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
return bytes.Contains([]byte(body.String()), []byte("await")), nil
|
|
779
|
+
}
|
|
780
|
+
|
|
747
781
|
// writeMethodBodyWithReceiverBinding writes the method body with optional receiver binding
|
|
748
782
|
// receiverTarget should be "this" for struct methods or "this._value" for named type methods
|
|
749
783
|
func (c *GoToTSCompiler) writeMethodBodyWithReceiverBinding(decl *ast.FuncDecl, receiverTarget string) error {
|
package/compiler/spec-struct.go
CHANGED
|
@@ -512,6 +512,179 @@ func (c *GoToTSCompiler) WriteStructTypeSpec(a *ast.TypeSpec, t *ast.StructType)
|
|
|
512
512
|
return nil
|
|
513
513
|
}
|
|
514
514
|
|
|
515
|
+
// WriteNamedStructTypeSpec generates a TypeScript class for a named type whose
|
|
516
|
+
// underlying type is a struct defined elsewhere.
|
|
517
|
+
func (c *GoToTSCompiler) WriteNamedStructTypeSpec(a *ast.TypeSpec, named *types.Named) error {
|
|
518
|
+
isInsideFunction := false
|
|
519
|
+
if nodeInfo := c.analysis.NodeData[a]; nodeInfo != nil {
|
|
520
|
+
isInsideFunction = nodeInfo.IsInsideFunction
|
|
521
|
+
}
|
|
522
|
+
if !isInsideFunction {
|
|
523
|
+
c.tsw.WriteLiterally("export ")
|
|
524
|
+
}
|
|
525
|
+
c.tsw.WriteLiterally("class ")
|
|
526
|
+
if err := c.WriteValueExpr(a.Name); err != nil {
|
|
527
|
+
return err
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
if a.TypeParams != nil {
|
|
531
|
+
c.WriteTypeParameters(a.TypeParams)
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
c.tsw.WriteLiterally(" extends ")
|
|
535
|
+
c.WriteTypeExpr(a.Type)
|
|
536
|
+
c.tsw.WriteLiterally(" ")
|
|
537
|
+
c.tsw.WriteLine("{")
|
|
538
|
+
c.tsw.Indent(1)
|
|
539
|
+
|
|
540
|
+
className := sanitizeIdentifier(a.Name.Name)
|
|
541
|
+
underlyingStruct, ok := named.Underlying().(*types.Struct)
|
|
542
|
+
if !ok {
|
|
543
|
+
return fmt.Errorf("underlying type of %s is not a struct", a.Name.Name)
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
c.tsw.WriteLine("constructor(init?: any) {")
|
|
547
|
+
c.tsw.Indent(1)
|
|
548
|
+
c.tsw.WriteLine("super(init)")
|
|
549
|
+
c.tsw.Indent(-1)
|
|
550
|
+
c.tsw.WriteLine("}")
|
|
551
|
+
c.tsw.WriteLine("")
|
|
552
|
+
|
|
553
|
+
c.tsw.WriteLinef("public clone(): %s {", className)
|
|
554
|
+
c.tsw.Indent(1)
|
|
555
|
+
c.tsw.WriteLinef("const cloned = new %s()", className)
|
|
556
|
+
c.tsw.WriteLine("cloned._fields = {")
|
|
557
|
+
c.tsw.Indent(1)
|
|
558
|
+
|
|
559
|
+
firstFieldWritten := false
|
|
560
|
+
for i := 0; i < underlyingStruct.NumFields(); i++ {
|
|
561
|
+
field := underlyingStruct.Field(i)
|
|
562
|
+
fieldType := field.Type()
|
|
563
|
+
var fieldKeyName string
|
|
564
|
+
if field.Anonymous() {
|
|
565
|
+
fieldKeyName = c.getEmbeddedFieldKeyName(field.Type())
|
|
566
|
+
} else {
|
|
567
|
+
fieldKeyName = field.Name()
|
|
568
|
+
}
|
|
569
|
+
if fieldKeyName == "_" {
|
|
570
|
+
continue
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
if firstFieldWritten {
|
|
574
|
+
c.tsw.WriteLine(",")
|
|
575
|
+
}
|
|
576
|
+
c.writeClonedFieldInitializer(fieldKeyName, fieldType, field.Anonymous())
|
|
577
|
+
firstFieldWritten = true
|
|
578
|
+
}
|
|
579
|
+
if firstFieldWritten {
|
|
580
|
+
c.tsw.WriteLine("")
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
c.tsw.Indent(-1)
|
|
584
|
+
c.tsw.WriteLine("}")
|
|
585
|
+
c.tsw.WriteLine("return cloned")
|
|
586
|
+
c.tsw.Indent(-1)
|
|
587
|
+
c.tsw.WriteLine("}")
|
|
588
|
+
|
|
589
|
+
for _, fileSyntax := range c.pkg.Syntax {
|
|
590
|
+
for _, decl := range fileSyntax.Decls {
|
|
591
|
+
funcDecl, isFunc := decl.(*ast.FuncDecl)
|
|
592
|
+
if !isFunc || funcDecl.Recv == nil || len(funcDecl.Recv.List) == 0 {
|
|
593
|
+
continue
|
|
594
|
+
}
|
|
595
|
+
recvType := funcDecl.Recv.List[0].Type
|
|
596
|
+
if starExpr, ok := recvType.(*ast.StarExpr); ok {
|
|
597
|
+
recvType = starExpr.X
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
var recvTypeName string
|
|
601
|
+
if ident, ok := recvType.(*ast.Ident); ok {
|
|
602
|
+
recvTypeName = sanitizeIdentifier(ident.Name)
|
|
603
|
+
} else if indexExpr, ok := recvType.(*ast.IndexExpr); ok {
|
|
604
|
+
if ident, ok := indexExpr.X.(*ast.Ident); ok {
|
|
605
|
+
recvTypeName = sanitizeIdentifier(ident.Name)
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
if recvTypeName == className {
|
|
610
|
+
c.tsw.WriteLine("")
|
|
611
|
+
if err := c.WriteFuncDeclAsMethod(funcDecl); err != nil {
|
|
612
|
+
return err
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
c.tsw.WriteLine("")
|
|
619
|
+
c.tsw.WriteLine("// Register this type with the runtime type system")
|
|
620
|
+
|
|
621
|
+
structName := className
|
|
622
|
+
pkgPath := c.pkg.Types.Path()
|
|
623
|
+
pkgName := c.pkg.Types.Name()
|
|
624
|
+
if pkgPath != "" && pkgName != "main" {
|
|
625
|
+
structName = pkgPath + "." + className
|
|
626
|
+
} else if pkgName == "main" {
|
|
627
|
+
structName = "main." + className
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
c.tsw.WriteLine("static __typeInfo = $.registerStructType(")
|
|
631
|
+
c.tsw.WriteLinef(" %q,", structName)
|
|
632
|
+
c.tsw.WriteLinef(" new %s(),", className)
|
|
633
|
+
c.tsw.WriteLiterally(" [")
|
|
634
|
+
|
|
635
|
+
var structMethods []*types.Func
|
|
636
|
+
for method := range named.Methods() {
|
|
637
|
+
sig := method.Type().(*types.Signature)
|
|
638
|
+
recv := sig.Recv().Type()
|
|
639
|
+
if ptr, ok := recv.(*types.Pointer); ok {
|
|
640
|
+
recv = ptr.Elem()
|
|
641
|
+
}
|
|
642
|
+
if namedRecv, ok := recv.(*types.Named); ok && namedRecv.Obj() == named.Obj() {
|
|
643
|
+
structMethods = append(structMethods, method)
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
c.writeMethodSignatures(structMethods)
|
|
647
|
+
c.tsw.WriteLiterally("],")
|
|
648
|
+
c.tsw.WriteLine("")
|
|
649
|
+
|
|
650
|
+
c.tsw.WriteLinef(" %s,", className)
|
|
651
|
+
c.tsw.WriteLiterally(" {")
|
|
652
|
+
firstField := true
|
|
653
|
+
for i := 0; i < underlyingStruct.NumFields(); i++ {
|
|
654
|
+
field := underlyingStruct.Field(i)
|
|
655
|
+
var fieldKeyName string
|
|
656
|
+
if field.Anonymous() {
|
|
657
|
+
fieldKeyName = c.getEmbeddedFieldKeyName(field.Type())
|
|
658
|
+
} else {
|
|
659
|
+
fieldKeyName = field.Name()
|
|
660
|
+
}
|
|
661
|
+
if fieldKeyName == "_" {
|
|
662
|
+
continue
|
|
663
|
+
}
|
|
664
|
+
if !firstField {
|
|
665
|
+
c.tsw.WriteLiterally(", ")
|
|
666
|
+
}
|
|
667
|
+
firstField = false
|
|
668
|
+
c.tsw.WriteLiterallyf("%q: ", fieldKeyName)
|
|
669
|
+
|
|
670
|
+
tag := underlyingStruct.Tag(i)
|
|
671
|
+
if tag != "" {
|
|
672
|
+
c.tsw.WriteLiterally("{ type: ")
|
|
673
|
+
c.writeTypeInfoObject(field.Type())
|
|
674
|
+
c.tsw.WriteLiterallyf(", tag: %q }", tag)
|
|
675
|
+
} else {
|
|
676
|
+
c.writeTypeInfoObject(field.Type())
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
c.tsw.WriteLiterally("}")
|
|
680
|
+
c.tsw.WriteLine("")
|
|
681
|
+
c.tsw.WriteLine(");")
|
|
682
|
+
|
|
683
|
+
c.tsw.Indent(-1)
|
|
684
|
+
c.tsw.WriteLine("}")
|
|
685
|
+
return nil
|
|
686
|
+
}
|
|
687
|
+
|
|
515
688
|
// generateFlattenedInitTypeString generates a TypeScript type string for the
|
|
516
689
|
// initialization object passed to a Go struct's constructor (`_init` method in TypeScript).
|
|
517
690
|
// The generated type is a `Partial`-like structure, `"{ Field1?: Type1, Field2?: Type2, ... }"`,
|
package/compiler/spec.go
CHANGED
|
@@ -366,6 +366,20 @@ func (c *GoToTSCompiler) WriteNamedTypeWithMethods(a *ast.TypeSpec) error {
|
|
|
366
366
|
|
|
367
367
|
if recvTypeName == className {
|
|
368
368
|
c.tsw.WriteLiterally("export function ")
|
|
369
|
+
var isAsync bool
|
|
370
|
+
if obj := c.pkg.TypesInfo.Defs[funcDecl.Name]; obj != nil {
|
|
371
|
+
isAsync = c.analysis.IsAsyncFunc(obj)
|
|
372
|
+
}
|
|
373
|
+
if !isAsync {
|
|
374
|
+
bodyNeedsAsync, err := c.funcBodyNeedsAsync(funcDecl, false)
|
|
375
|
+
if err != nil {
|
|
376
|
+
return err
|
|
377
|
+
}
|
|
378
|
+
isAsync = bodyNeedsAsync
|
|
379
|
+
}
|
|
380
|
+
if isAsync {
|
|
381
|
+
c.tsw.WriteLiterally("async ")
|
|
382
|
+
}
|
|
369
383
|
c.tsw.WriteLiterally(className)
|
|
370
384
|
c.tsw.WriteLiterally("_")
|
|
371
385
|
c.tsw.WriteLiterally(funcDecl.Name.Name)
|
|
@@ -403,6 +417,9 @@ func (c *GoToTSCompiler) WriteNamedTypeWithMethods(a *ast.TypeSpec) error {
|
|
|
403
417
|
// Add return type
|
|
404
418
|
if funcDecl.Type.Results != nil && len(funcDecl.Type.Results.List) > 0 {
|
|
405
419
|
c.tsw.WriteLiterally(": ")
|
|
420
|
+
if isAsync {
|
|
421
|
+
c.tsw.WriteLiterally("Promise<")
|
|
422
|
+
}
|
|
406
423
|
if len(funcDecl.Type.Results.List) == 1 {
|
|
407
424
|
c.WriteTypeExpr(funcDecl.Type.Results.List[0].Type)
|
|
408
425
|
} else {
|
|
@@ -424,8 +441,15 @@ func (c *GoToTSCompiler) WriteNamedTypeWithMethods(a *ast.TypeSpec) error {
|
|
|
424
441
|
}
|
|
425
442
|
c.tsw.WriteLiterally("]")
|
|
426
443
|
}
|
|
444
|
+
if isAsync {
|
|
445
|
+
c.tsw.WriteLiterally(">")
|
|
446
|
+
}
|
|
427
447
|
} else {
|
|
428
|
-
|
|
448
|
+
if isAsync {
|
|
449
|
+
c.tsw.WriteLiterally(": Promise<void>")
|
|
450
|
+
} else {
|
|
451
|
+
c.tsw.WriteLiterally(": void")
|
|
452
|
+
}
|
|
429
453
|
}
|
|
430
454
|
|
|
431
455
|
c.tsw.WriteLine(" {")
|
|
@@ -476,6 +500,11 @@ func (c *GoToTSCompiler) WriteTypeSpec(a *ast.TypeSpec) error {
|
|
|
476
500
|
default:
|
|
477
501
|
// Check if this type has receiver methods
|
|
478
502
|
if c.hasReceiverMethods(a.Name.Name) {
|
|
503
|
+
if named, ok := c.pkg.TypesInfo.Defs[a.Name].Type().(*types.Named); ok {
|
|
504
|
+
if _, isStruct := named.Underlying().(*types.Struct); isStruct {
|
|
505
|
+
return c.WriteNamedStructTypeSpec(a, named)
|
|
506
|
+
}
|
|
507
|
+
}
|
|
479
508
|
return c.WriteNamedTypeWithMethods(a)
|
|
480
509
|
}
|
|
481
510
|
|