goscript 0.0.77 → 0.0.79
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 +24 -25
- package/compiler/spec-struct.go +397 -0
- package/compiler/spec.go +23 -1
- package/package.json +1 -1
package/compiler/analysis.go
CHANGED
|
@@ -2756,23 +2756,25 @@ func (v *analysisVisitor) analyzeAllMethodsAsync() {
|
|
|
2756
2756
|
// Topologically sort methods by their dependencies
|
|
2757
2757
|
sorted, cycles := v.topologicalSortMethods(methodCalls)
|
|
2758
2758
|
|
|
2759
|
-
//
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
//
|
|
2759
|
+
// Analyze methods in dependency order (dependencies analyzed before dependents)
|
|
2760
|
+
for _, methodKey := range sorted {
|
|
2761
|
+
v.analyzeMethodAsyncTopological(methodKey, methodCalls[methodKey])
|
|
2762
|
+
}
|
|
2763
|
+
|
|
2764
|
+
// Analyze methods in cycles after the acyclic portion of the graph is known.
|
|
2765
|
+
// This lets recursive methods observe async callees outside the cycle while
|
|
2766
|
+
// still converging over recursive edges inside the cycle.
|
|
2765
2767
|
maxIterations := 10
|
|
2766
2768
|
for range maxIterations {
|
|
2767
2769
|
changed := false
|
|
2768
2770
|
|
|
2769
2771
|
for _, methodKey := range cycles {
|
|
2770
|
-
// For methods in cycles, we need to check their body directly for async operations
|
|
2771
2772
|
pkg := v.analysis.AllPackages[methodKey.PackagePath]
|
|
2772
2773
|
if pkg == nil && methodKey.PackagePath == v.pkg.Types.Path() {
|
|
2773
2774
|
pkg = v.pkg
|
|
2774
2775
|
}
|
|
2775
2776
|
|
|
2777
|
+
isAsync := false
|
|
2776
2778
|
if pkg != nil {
|
|
2777
2779
|
var funcDecl *ast.FuncDecl
|
|
2778
2780
|
if methodKey.ReceiverType == "" {
|
|
@@ -2782,37 +2784,29 @@ func (v *analysisVisitor) analyzeAllMethodsAsync() {
|
|
|
2782
2784
|
}
|
|
2783
2785
|
|
|
2784
2786
|
if funcDecl != nil && funcDecl.Body != nil {
|
|
2785
|
-
|
|
2786
|
-
isAsync
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2787
|
+
isAsync = v.containsAsyncOperationsComplete(funcDecl.Body, pkg)
|
|
2788
|
+
if !isAsync {
|
|
2789
|
+
for _, callee := range methodCalls[methodKey] {
|
|
2790
|
+
if calleeAsync, exists := v.analysis.MethodAsyncStatus[callee]; exists && calleeAsync {
|
|
2791
|
+
isAsync = true
|
|
2792
|
+
break
|
|
2793
|
+
}
|
|
2794
|
+
}
|
|
2791
2795
|
}
|
|
2792
|
-
|
|
2793
|
-
v.analysis.MethodAsyncStatus[methodKey] = isAsync
|
|
2794
|
-
continue
|
|
2795
2796
|
}
|
|
2796
2797
|
}
|
|
2797
2798
|
|
|
2798
|
-
|
|
2799
|
-
if _, exists := v.analysis.MethodAsyncStatus[methodKey]; !exists {
|
|
2800
|
-
v.analysis.MethodAsyncStatus[methodKey] = false
|
|
2799
|
+
if oldStatus, exists := v.analysis.MethodAsyncStatus[methodKey]; !exists || oldStatus != isAsync {
|
|
2801
2800
|
changed = true
|
|
2802
2801
|
}
|
|
2802
|
+
v.analysis.MethodAsyncStatus[methodKey] = isAsync
|
|
2803
2803
|
}
|
|
2804
2804
|
|
|
2805
|
-
// If no changes in this iteration, we're done
|
|
2806
2805
|
if !changed {
|
|
2807
2806
|
break
|
|
2808
2807
|
}
|
|
2809
2808
|
}
|
|
2810
2809
|
|
|
2811
|
-
// Analyze methods in dependency order (dependencies analyzed before dependents)
|
|
2812
|
-
for _, methodKey := range sorted {
|
|
2813
|
-
v.analyzeMethodAsyncTopological(methodKey, methodCalls[methodKey])
|
|
2814
|
-
}
|
|
2815
|
-
|
|
2816
2810
|
// Track async-returning variables BEFORE analyzing function literals
|
|
2817
2811
|
// This detects variables assigned from higher-order functions with async function literal args
|
|
2818
2812
|
// e.g., indirect := sync.OnceValue(asyncFunc)
|
|
@@ -3259,6 +3253,11 @@ func (v *analysisVisitor) containsAsyncOperationsComplete(node ast.Node, pkg *pa
|
|
|
3259
3253
|
if n == nil {
|
|
3260
3254
|
return false
|
|
3261
3255
|
}
|
|
3256
|
+
if n != node {
|
|
3257
|
+
if _, ok := n.(*ast.FuncLit); ok {
|
|
3258
|
+
return false
|
|
3259
|
+
}
|
|
3260
|
+
}
|
|
3262
3261
|
|
|
3263
3262
|
switch s := n.(type) {
|
|
3264
3263
|
case *ast.SendStmt:
|
package/compiler/spec-struct.go
CHANGED
|
@@ -512,6 +512,403 @@ 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 another named struct. The emitted class copies the field
|
|
517
|
+
// layout without inheriting the underlying named type's prototype methods.
|
|
518
|
+
func (c *GoToTSCompiler) WriteNamedStructTypeSpec(a *ast.TypeSpec, named *types.Named) error {
|
|
519
|
+
isInsideFunction := false
|
|
520
|
+
if nodeInfo := c.analysis.NodeData[a]; nodeInfo != nil {
|
|
521
|
+
isInsideFunction = nodeInfo.IsInsideFunction
|
|
522
|
+
}
|
|
523
|
+
if !isInsideFunction {
|
|
524
|
+
c.tsw.WriteLiterally("export ")
|
|
525
|
+
}
|
|
526
|
+
c.tsw.WriteLiterally("class ")
|
|
527
|
+
if err := c.WriteValueExpr(a.Name); err != nil {
|
|
528
|
+
return err
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
if a.TypeParams != nil {
|
|
532
|
+
c.WriteTypeParameters(a.TypeParams)
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
c.tsw.WriteLiterally(" ")
|
|
536
|
+
c.tsw.WriteLine("{")
|
|
537
|
+
c.tsw.Indent(1)
|
|
538
|
+
|
|
539
|
+
className := sanitizeIdentifier(a.Name.Name)
|
|
540
|
+
underlyingStruct, ok := named.Underlying().(*types.Struct)
|
|
541
|
+
if !ok {
|
|
542
|
+
return fmt.Errorf("underlying type of %s is not a struct", a.Name.Name)
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
underlyingType := c.pkg.TypesInfo.TypeOf(a.Type)
|
|
546
|
+
underlyingInitType := "{}"
|
|
547
|
+
if underlyingNamed, ok := underlyingType.(*types.Named); ok {
|
|
548
|
+
underlyingInitType = c.generateFlattenedInitTypeString(underlyingNamed, nil)
|
|
549
|
+
}
|
|
550
|
+
underlyingTypeName := c.getASTTypeString(a.Type, underlyingType)
|
|
551
|
+
|
|
552
|
+
for i := 0; i < underlyingStruct.NumFields(); i++ {
|
|
553
|
+
field := underlyingStruct.Field(i)
|
|
554
|
+
if field.Anonymous() {
|
|
555
|
+
continue
|
|
556
|
+
}
|
|
557
|
+
if !field.Exported() && field.Pkg() != c.pkg.Types {
|
|
558
|
+
continue
|
|
559
|
+
}
|
|
560
|
+
c.writeGetterSetter(field.Name(), field.Type(), nil, nil, nil)
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
for field := range underlyingStruct.Fields() {
|
|
564
|
+
if field.Anonymous() {
|
|
565
|
+
fieldKeyName := c.getEmbeddedFieldKeyName(field.Type())
|
|
566
|
+
c.writeGetterSetter(fieldKeyName, field.Type(), nil, nil, nil)
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
c.tsw.WriteLiterally("public _fields: {")
|
|
571
|
+
c.tsw.Indent(1)
|
|
572
|
+
c.tsw.WriteLine("")
|
|
573
|
+
for i := 0; i < underlyingStruct.NumFields(); i++ {
|
|
574
|
+
field := underlyingStruct.Field(i)
|
|
575
|
+
fieldKeyName := field.Name()
|
|
576
|
+
if field.Anonymous() {
|
|
577
|
+
fieldKeyName = c.getEmbeddedFieldKeyName(field.Type())
|
|
578
|
+
}
|
|
579
|
+
if fieldKeyName == "_" {
|
|
580
|
+
continue
|
|
581
|
+
}
|
|
582
|
+
c.tsw.WriteLinef("%s: $.VarRef<%s>;", fieldKeyName, c.getTypeString(field.Type()))
|
|
583
|
+
}
|
|
584
|
+
c.tsw.Indent(-1)
|
|
585
|
+
c.tsw.WriteLine("}")
|
|
586
|
+
c.tsw.WriteLine("")
|
|
587
|
+
|
|
588
|
+
c.tsw.WriteLinef("constructor(init?: Partial<%s>) {", underlyingInitType)
|
|
589
|
+
c.tsw.Indent(1)
|
|
590
|
+
c.tsw.WriteLinef("const base = new %s(init)", underlyingTypeName)
|
|
591
|
+
c.tsw.WriteLine("this._fields = base._fields")
|
|
592
|
+
c.tsw.Indent(-1)
|
|
593
|
+
c.tsw.WriteLine("}")
|
|
594
|
+
c.tsw.WriteLine("")
|
|
595
|
+
|
|
596
|
+
var cloneReturnType strings.Builder
|
|
597
|
+
cloneReturnType.WriteString(className)
|
|
598
|
+
if a.TypeParams != nil && len(a.TypeParams.List) > 0 {
|
|
599
|
+
cloneReturnType.WriteString("<")
|
|
600
|
+
first := true
|
|
601
|
+
for _, field := range a.TypeParams.List {
|
|
602
|
+
for _, name := range field.Names {
|
|
603
|
+
if !first {
|
|
604
|
+
cloneReturnType.WriteString(", ")
|
|
605
|
+
}
|
|
606
|
+
first = false
|
|
607
|
+
cloneReturnType.WriteString(name.Name)
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
cloneReturnType.WriteString(">")
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
c.tsw.WriteLinef("public clone(): %s {", cloneReturnType.String())
|
|
614
|
+
c.tsw.Indent(1)
|
|
615
|
+
c.tsw.WriteLinef("const cloned = new %s()", cloneReturnType.String())
|
|
616
|
+
c.tsw.WriteLine("cloned._fields = {")
|
|
617
|
+
c.tsw.Indent(1)
|
|
618
|
+
|
|
619
|
+
firstFieldWritten := false
|
|
620
|
+
for i := 0; i < underlyingStruct.NumFields(); i++ {
|
|
621
|
+
field := underlyingStruct.Field(i)
|
|
622
|
+
fieldType := field.Type()
|
|
623
|
+
fieldKeyName := field.Name()
|
|
624
|
+
if field.Anonymous() {
|
|
625
|
+
fieldKeyName = c.getEmbeddedFieldKeyName(field.Type())
|
|
626
|
+
}
|
|
627
|
+
if fieldKeyName == "_" {
|
|
628
|
+
continue
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
if firstFieldWritten {
|
|
632
|
+
c.tsw.WriteLine(",")
|
|
633
|
+
}
|
|
634
|
+
c.writeClonedFieldInitializer(fieldKeyName, fieldType, field.Anonymous())
|
|
635
|
+
firstFieldWritten = true
|
|
636
|
+
}
|
|
637
|
+
if firstFieldWritten {
|
|
638
|
+
c.tsw.WriteLine("")
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
c.tsw.Indent(-1)
|
|
642
|
+
c.tsw.WriteLine("}")
|
|
643
|
+
c.tsw.WriteLine("return cloned")
|
|
644
|
+
c.tsw.Indent(-1)
|
|
645
|
+
c.tsw.WriteLine("}")
|
|
646
|
+
|
|
647
|
+
for _, fileSyntax := range c.pkg.Syntax {
|
|
648
|
+
for _, decl := range fileSyntax.Decls {
|
|
649
|
+
funcDecl, isFunc := decl.(*ast.FuncDecl)
|
|
650
|
+
if !isFunc || funcDecl.Recv == nil || len(funcDecl.Recv.List) == 0 {
|
|
651
|
+
continue
|
|
652
|
+
}
|
|
653
|
+
recvType := funcDecl.Recv.List[0].Type
|
|
654
|
+
if starExpr, ok := recvType.(*ast.StarExpr); ok {
|
|
655
|
+
recvType = starExpr.X
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
var recvTypeName string
|
|
659
|
+
if ident, ok := recvType.(*ast.Ident); ok {
|
|
660
|
+
recvTypeName = sanitizeIdentifier(ident.Name)
|
|
661
|
+
} else if indexExpr, ok := recvType.(*ast.IndexExpr); ok {
|
|
662
|
+
if ident, ok := indexExpr.X.(*ast.Ident); ok {
|
|
663
|
+
recvTypeName = sanitizeIdentifier(ident.Name)
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
if recvTypeName == className {
|
|
668
|
+
c.tsw.WriteLine("")
|
|
669
|
+
if err := c.WriteFuncDeclAsMethod(funcDecl); err != nil {
|
|
670
|
+
return err
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
seenPromotedFields := make(map[string]bool)
|
|
677
|
+
directMethods := make(map[string]bool)
|
|
678
|
+
for method := range named.Methods() {
|
|
679
|
+
sig := method.Type().(*types.Signature)
|
|
680
|
+
if sig.Recv() != nil {
|
|
681
|
+
recvType := sig.Recv().Type()
|
|
682
|
+
if namedRecv, ok := recvType.(*types.Named); ok && namedRecv.Obj() == named.Obj() {
|
|
683
|
+
directMethods[method.Name()] = true
|
|
684
|
+
} else if ptrRecv, ok := recvType.(*types.Pointer); ok {
|
|
685
|
+
if namedElem, ok := ptrRecv.Elem().(*types.Named); ok && namedElem.Obj() == named.Obj() {
|
|
686
|
+
directMethods[method.Name()] = true
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
for field := range underlyingStruct.Fields() {
|
|
693
|
+
if !field.Anonymous() {
|
|
694
|
+
continue
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
embeddedFieldType := field.Type()
|
|
698
|
+
embeddedFieldKeyName := c.getEmbeddedFieldKeyName(field.Type())
|
|
699
|
+
|
|
700
|
+
trueEmbeddedType := embeddedFieldType
|
|
701
|
+
if ptr, isPtr := trueEmbeddedType.(*types.Pointer); isPtr {
|
|
702
|
+
trueEmbeddedType = ptr.Elem()
|
|
703
|
+
}
|
|
704
|
+
if _, isNamed := trueEmbeddedType.(*types.Named); !isNamed {
|
|
705
|
+
continue
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
if namedEmbedded, ok := trueEmbeddedType.(*types.Named); ok {
|
|
709
|
+
if underlyingEmbeddedStruct, ok := namedEmbedded.Underlying().(*types.Struct); ok {
|
|
710
|
+
for promotedField := range underlyingEmbeddedStruct.Fields() {
|
|
711
|
+
if !promotedField.Exported() && promotedField.Pkg() != c.pkg.Types {
|
|
712
|
+
continue
|
|
713
|
+
}
|
|
714
|
+
promotedFieldName := promotedField.Name()
|
|
715
|
+
if seenPromotedFields[promotedFieldName] {
|
|
716
|
+
continue
|
|
717
|
+
}
|
|
718
|
+
conflict := false
|
|
719
|
+
for field := range underlyingStruct.Fields() {
|
|
720
|
+
if !field.Anonymous() && field.Name() == promotedFieldName {
|
|
721
|
+
conflict = true
|
|
722
|
+
break
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
if conflict {
|
|
726
|
+
continue
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
seenPromotedFields[promotedFieldName] = true
|
|
730
|
+
tsPromotedFieldType := c.getTypeString(promotedField.Type())
|
|
731
|
+
c.tsw.WriteLine("")
|
|
732
|
+
c.tsw.WriteLinef("public get %s(): %s {", promotedFieldName, tsPromotedFieldType)
|
|
733
|
+
c.tsw.Indent(1)
|
|
734
|
+
embeddedFieldTypeUnderlying := embeddedFieldType
|
|
735
|
+
if ptr, isPtr := embeddedFieldTypeUnderlying.(*types.Pointer); isPtr {
|
|
736
|
+
embeddedFieldTypeUnderlying = ptr.Elem()
|
|
737
|
+
}
|
|
738
|
+
if named, isNamed := embeddedFieldTypeUnderlying.(*types.Named); isNamed {
|
|
739
|
+
embeddedFieldTypeUnderlying = named.Underlying()
|
|
740
|
+
}
|
|
741
|
+
if _, isInterface := embeddedFieldTypeUnderlying.(*types.Interface); isInterface {
|
|
742
|
+
c.tsw.WriteLinef("return this.%s!.%s", embeddedFieldKeyName, promotedFieldName)
|
|
743
|
+
} else {
|
|
744
|
+
c.tsw.WriteLinef("return this.%s.%s", embeddedFieldKeyName, promotedFieldName)
|
|
745
|
+
}
|
|
746
|
+
c.tsw.Indent(-1)
|
|
747
|
+
c.tsw.WriteLine("}")
|
|
748
|
+
c.tsw.WriteLinef("public set %s(value: %s) {", promotedFieldName, tsPromotedFieldType)
|
|
749
|
+
c.tsw.Indent(1)
|
|
750
|
+
if _, isInterface := embeddedFieldTypeUnderlying.(*types.Interface); isInterface {
|
|
751
|
+
c.tsw.WriteLinef("this.%s!.%s = value", embeddedFieldKeyName, promotedFieldName)
|
|
752
|
+
} else {
|
|
753
|
+
c.tsw.WriteLinef("this.%s.%s = value", embeddedFieldKeyName, promotedFieldName)
|
|
754
|
+
}
|
|
755
|
+
c.tsw.Indent(-1)
|
|
756
|
+
c.tsw.WriteLine("}")
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
methodSetType := embeddedFieldType
|
|
762
|
+
if _, isPtr := embeddedFieldType.(*types.Pointer); !isPtr {
|
|
763
|
+
if _, isInterface := embeddedFieldType.Underlying().(*types.Interface); !isInterface {
|
|
764
|
+
methodSetType = types.NewPointer(embeddedFieldType)
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
embeddedMethodSet := types.NewMethodSet(methodSetType)
|
|
768
|
+
for methodSelection := range embeddedMethodSet.Methods() {
|
|
769
|
+
method := methodSelection.Obj().(*types.Func)
|
|
770
|
+
methodName := method.Name()
|
|
771
|
+
|
|
772
|
+
if len(methodSelection.Index()) == 1 && !directMethods[methodName] && !seenPromotedFields[methodName] {
|
|
773
|
+
conflictWithField := false
|
|
774
|
+
for field := range underlyingStruct.Fields() {
|
|
775
|
+
if !field.Anonymous() && field.Name() == methodName {
|
|
776
|
+
conflictWithField = true
|
|
777
|
+
break
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
if conflictWithField {
|
|
781
|
+
continue
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
seenPromotedFields[methodName] = true
|
|
785
|
+
sig := method.Type().(*types.Signature)
|
|
786
|
+
c.tsw.WriteLine("")
|
|
787
|
+
c.tsw.WriteLiterally("public ")
|
|
788
|
+
c.tsw.WriteLiterally(methodName)
|
|
789
|
+
c.tsw.WriteLiterally("(")
|
|
790
|
+
params := sig.Params()
|
|
791
|
+
paramNames := make([]string, params.Len())
|
|
792
|
+
for j := 0; j < params.Len(); j++ {
|
|
793
|
+
param := params.At(j)
|
|
794
|
+
paramName := param.Name()
|
|
795
|
+
if paramName == "" || paramName == "_" {
|
|
796
|
+
paramName = fmt.Sprintf("_p%d", j)
|
|
797
|
+
}
|
|
798
|
+
paramNames[j] = paramName
|
|
799
|
+
if j > 0 {
|
|
800
|
+
c.tsw.WriteLiterally(", ")
|
|
801
|
+
}
|
|
802
|
+
c.tsw.WriteLiterally(paramName)
|
|
803
|
+
c.tsw.WriteLiterally(": ")
|
|
804
|
+
c.WriteGoType(param.Type(), GoTypeContextGeneral)
|
|
805
|
+
}
|
|
806
|
+
c.tsw.WriteLiterally(")")
|
|
807
|
+
results := sig.Results()
|
|
808
|
+
if results.Len() > 0 {
|
|
809
|
+
c.tsw.WriteLiterally(": ")
|
|
810
|
+
if results.Len() == 1 {
|
|
811
|
+
c.WriteGoType(results.At(0).Type(), GoTypeContextFunctionReturn)
|
|
812
|
+
} else {
|
|
813
|
+
c.tsw.WriteLiterally("[")
|
|
814
|
+
for j := 0; j < results.Len(); j++ {
|
|
815
|
+
if j > 0 {
|
|
816
|
+
c.tsw.WriteLiterally(", ")
|
|
817
|
+
}
|
|
818
|
+
c.WriteGoType(results.At(j).Type(), GoTypeContextFunctionReturn)
|
|
819
|
+
}
|
|
820
|
+
c.tsw.WriteLiterally("]")
|
|
821
|
+
}
|
|
822
|
+
} else {
|
|
823
|
+
c.tsw.WriteLiterally(": void")
|
|
824
|
+
}
|
|
825
|
+
c.tsw.WriteLine(" {")
|
|
826
|
+
c.tsw.Indent(1)
|
|
827
|
+
if results.Len() > 0 {
|
|
828
|
+
c.tsw.WriteLiterally("return ")
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
assertionPrefix := "this.%s"
|
|
832
|
+
if _, isInterface := embeddedFieldType.Underlying().(*types.Interface); isInterface {
|
|
833
|
+
assertionPrefix = "this.%s!"
|
|
834
|
+
}
|
|
835
|
+
c.tsw.WriteLiterallyf(assertionPrefix+".%s(%s)", embeddedFieldKeyName, methodName, strings.Join(paramNames, ", "))
|
|
836
|
+
|
|
837
|
+
c.tsw.WriteLine("")
|
|
838
|
+
c.tsw.Indent(-1)
|
|
839
|
+
c.tsw.WriteLine("}")
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
c.tsw.WriteLine("")
|
|
845
|
+
c.tsw.WriteLine("// Register this type with the runtime type system")
|
|
846
|
+
|
|
847
|
+
structName := className
|
|
848
|
+
pkgPath := c.pkg.Types.Path()
|
|
849
|
+
pkgName := c.pkg.Types.Name()
|
|
850
|
+
if pkgPath != "" && pkgName != "main" {
|
|
851
|
+
structName = pkgPath + "." + className
|
|
852
|
+
} else if pkgName == "main" {
|
|
853
|
+
structName = "main." + className
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
c.tsw.WriteLine("static __typeInfo = $.registerStructType(")
|
|
857
|
+
c.tsw.WriteLinef(" %q,", structName)
|
|
858
|
+
c.tsw.WriteLinef(" new %s(),", className)
|
|
859
|
+
c.tsw.WriteLiterally(" [")
|
|
860
|
+
|
|
861
|
+
var structMethods []*types.Func
|
|
862
|
+
for method := range named.Methods() {
|
|
863
|
+
sig := method.Type().(*types.Signature)
|
|
864
|
+
recv := sig.Recv().Type()
|
|
865
|
+
if ptr, ok := recv.(*types.Pointer); ok {
|
|
866
|
+
recv = ptr.Elem()
|
|
867
|
+
}
|
|
868
|
+
if namedRecv, ok := recv.(*types.Named); ok && namedRecv.Obj() == named.Obj() {
|
|
869
|
+
structMethods = append(structMethods, method)
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
c.writeMethodSignatures(structMethods)
|
|
873
|
+
c.tsw.WriteLiterally("],")
|
|
874
|
+
c.tsw.WriteLine("")
|
|
875
|
+
|
|
876
|
+
c.tsw.WriteLinef(" %s,", className)
|
|
877
|
+
c.tsw.WriteLiterally(" {")
|
|
878
|
+
firstField := true
|
|
879
|
+
for i := 0; i < underlyingStruct.NumFields(); i++ {
|
|
880
|
+
field := underlyingStruct.Field(i)
|
|
881
|
+
fieldKeyName := field.Name()
|
|
882
|
+
if field.Anonymous() {
|
|
883
|
+
fieldKeyName = c.getEmbeddedFieldKeyName(field.Type())
|
|
884
|
+
}
|
|
885
|
+
if fieldKeyName == "_" {
|
|
886
|
+
continue
|
|
887
|
+
}
|
|
888
|
+
if !firstField {
|
|
889
|
+
c.tsw.WriteLiterally(", ")
|
|
890
|
+
}
|
|
891
|
+
firstField = false
|
|
892
|
+
c.tsw.WriteLiterallyf("%q: ", fieldKeyName)
|
|
893
|
+
|
|
894
|
+
tag := underlyingStruct.Tag(i)
|
|
895
|
+
if tag != "" {
|
|
896
|
+
c.tsw.WriteLiterally("{ type: ")
|
|
897
|
+
c.writeTypeInfoObject(field.Type())
|
|
898
|
+
c.tsw.WriteLiterallyf(", tag: %q }", tag)
|
|
899
|
+
} else {
|
|
900
|
+
c.writeTypeInfoObject(field.Type())
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
c.tsw.WriteLiterally("}")
|
|
904
|
+
c.tsw.WriteLine("")
|
|
905
|
+
c.tsw.WriteLine(");")
|
|
906
|
+
|
|
907
|
+
c.tsw.Indent(-1)
|
|
908
|
+
c.tsw.WriteLine("}")
|
|
909
|
+
return nil
|
|
910
|
+
}
|
|
911
|
+
|
|
515
912
|
// generateFlattenedInitTypeString generates a TypeScript type string for the
|
|
516
913
|
// initialization object passed to a Go struct's constructor (`_init` method in TypeScript).
|
|
517
914
|
// The generated type is a `Partial`-like structure, `"{ Field1?: Type1, Field2?: Type2, ... }"`,
|
package/compiler/spec.go
CHANGED
|
@@ -366,6 +366,13 @@ 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
|
+
c.tsw.WriteLiterally("async ")
|
|
375
|
+
}
|
|
369
376
|
c.tsw.WriteLiterally(className)
|
|
370
377
|
c.tsw.WriteLiterally("_")
|
|
371
378
|
c.tsw.WriteLiterally(funcDecl.Name.Name)
|
|
@@ -403,6 +410,9 @@ func (c *GoToTSCompiler) WriteNamedTypeWithMethods(a *ast.TypeSpec) error {
|
|
|
403
410
|
// Add return type
|
|
404
411
|
if funcDecl.Type.Results != nil && len(funcDecl.Type.Results.List) > 0 {
|
|
405
412
|
c.tsw.WriteLiterally(": ")
|
|
413
|
+
if isAsync {
|
|
414
|
+
c.tsw.WriteLiterally("Promise<")
|
|
415
|
+
}
|
|
406
416
|
if len(funcDecl.Type.Results.List) == 1 {
|
|
407
417
|
c.WriteTypeExpr(funcDecl.Type.Results.List[0].Type)
|
|
408
418
|
} else {
|
|
@@ -424,8 +434,15 @@ func (c *GoToTSCompiler) WriteNamedTypeWithMethods(a *ast.TypeSpec) error {
|
|
|
424
434
|
}
|
|
425
435
|
c.tsw.WriteLiterally("]")
|
|
426
436
|
}
|
|
437
|
+
if isAsync {
|
|
438
|
+
c.tsw.WriteLiterally(">")
|
|
439
|
+
}
|
|
427
440
|
} else {
|
|
428
|
-
|
|
441
|
+
if isAsync {
|
|
442
|
+
c.tsw.WriteLiterally(": Promise<void>")
|
|
443
|
+
} else {
|
|
444
|
+
c.tsw.WriteLiterally(": void")
|
|
445
|
+
}
|
|
429
446
|
}
|
|
430
447
|
|
|
431
448
|
c.tsw.WriteLine(" {")
|
|
@@ -476,6 +493,11 @@ func (c *GoToTSCompiler) WriteTypeSpec(a *ast.TypeSpec) error {
|
|
|
476
493
|
default:
|
|
477
494
|
// Check if this type has receiver methods
|
|
478
495
|
if c.hasReceiverMethods(a.Name.Name) {
|
|
496
|
+
if named, ok := c.pkg.TypesInfo.Defs[a.Name].Type().(*types.Named); ok {
|
|
497
|
+
if _, isStruct := named.Underlying().(*types.Struct); isStruct {
|
|
498
|
+
return c.WriteNamedStructTypeSpec(a, named)
|
|
499
|
+
}
|
|
500
|
+
}
|
|
479
501
|
return c.WriteNamedTypeWithMethods(a)
|
|
480
502
|
}
|
|
481
503
|
|