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 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 {
@@ -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
- c.tsw.WriteLiterally(": void")
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
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "goscript",
3
3
  "description": "Go to TypeScript transpiler",
4
- "version": "0.0.77",
4
+ "version": "0.0.78",
5
5
  "author": {
6
6
  "name": "Aperture Robotics LLC.",
7
7
  "email": "support@aperture.us",