goscript 0.0.13 → 0.0.16

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 (186) hide show
  1. package/LICENSE +2 -1
  2. package/README.md +163 -45
  3. package/builtin/builtin.ts +1169 -178
  4. package/cmd/goscript/cmd_compile.go +2 -2
  5. package/compiler/analysis.go +726 -0
  6. package/compiler/compiler.go +5701 -4
  7. package/compiler/compiler_test.go +104 -0
  8. package/compiler/config.go +3 -3
  9. package/compiler/config_test.go +89 -0
  10. package/compiler/index.ts +1 -1
  11. package/compiler/output.go +26 -0
  12. package/compiler/write-type-spec.go +506 -0
  13. package/compiler/writer.go +11 -0
  14. package/dist/builtin/builtin.d.ts +204 -67
  15. package/dist/builtin/builtin.js +846 -144
  16. package/dist/builtin/builtin.js.map +1 -1
  17. package/dist/compiler/index.d.ts +1 -1
  18. package/go.mod +5 -6
  19. package/go.sum +6 -11
  20. package/package.json +21 -5
  21. package/compiler/compile.go +0 -190
  22. package/compiler/compile_comment.go +0 -41
  23. package/compiler/compile_decls.go +0 -84
  24. package/compiler/compile_expr.go +0 -1022
  25. package/compiler/compile_field.go +0 -110
  26. package/compiler/compile_spec.go +0 -566
  27. package/compiler/compile_stmt.go +0 -1616
  28. package/compiler/context.go +0 -9
  29. package/compiler/file_compiler.go +0 -80
  30. package/compiler/output_path.go +0 -31
  31. package/compiler/pkg_compiler.go +0 -72
  32. package/compiler/types/tokens.go +0 -66
  33. package/compiler/types/types.go +0 -46
  34. package/dist/compliance/tests/array_literal/array_literal.gs.d.ts +0 -1
  35. package/dist/compliance/tests/array_literal/array_literal.gs.js +0 -15
  36. package/dist/compliance/tests/array_literal/array_literal.gs.js.map +0 -1
  37. package/dist/compliance/tests/async_basic/async_basic.gs.d.ts +0 -1
  38. package/dist/compliance/tests/async_basic/async_basic.gs.js +0 -24
  39. package/dist/compliance/tests/async_basic/async_basic.gs.js.map +0 -1
  40. package/dist/compliance/tests/async_defer_statement/async_defer_statement.gs.d.ts +0 -1
  41. package/dist/compliance/tests/async_defer_statement/async_defer_statement.gs.js +0 -82
  42. package/dist/compliance/tests/async_defer_statement/async_defer_statement.gs.js.map +0 -1
  43. package/dist/compliance/tests/basic_arithmetic/basic_arithmetic.gs.d.ts +0 -1
  44. package/dist/compliance/tests/basic_arithmetic/basic_arithmetic.gs.js +0 -16
  45. package/dist/compliance/tests/basic_arithmetic/basic_arithmetic.gs.js.map +0 -1
  46. package/dist/compliance/tests/boolean_logic/boolean_logic.gs.d.ts +0 -1
  47. package/dist/compliance/tests/boolean_logic/boolean_logic.gs.js +0 -14
  48. package/dist/compliance/tests/boolean_logic/boolean_logic.gs.js.map +0 -1
  49. package/dist/compliance/tests/channel_basic/channel_basic.gs.d.ts +0 -1
  50. package/dist/compliance/tests/channel_basic/channel_basic.gs.js +0 -14
  51. package/dist/compliance/tests/channel_basic/channel_basic.gs.js.map +0 -1
  52. package/dist/compliance/tests/composite_literal_assignment/composite_literal_assignment.gs.d.ts +0 -1
  53. package/dist/compliance/tests/composite_literal_assignment/composite_literal_assignment.gs.js +0 -27
  54. package/dist/compliance/tests/composite_literal_assignment/composite_literal_assignment.gs.js.map +0 -1
  55. package/dist/compliance/tests/constants/constants.gs.d.ts +0 -1
  56. package/dist/compliance/tests/constants/constants.gs.js +0 -16
  57. package/dist/compliance/tests/constants/constants.gs.js.map +0 -1
  58. package/dist/compliance/tests/copy_independence/copy_independence.gs.d.ts +0 -1
  59. package/dist/compliance/tests/copy_independence/copy_independence.gs.js +0 -33
  60. package/dist/compliance/tests/copy_independence/copy_independence.gs.js.map +0 -1
  61. package/dist/compliance/tests/defer_statement/defer_statement.gs.d.ts +0 -1
  62. package/dist/compliance/tests/defer_statement/defer_statement.gs.js +0 -75
  63. package/dist/compliance/tests/defer_statement/defer_statement.gs.js.map +0 -1
  64. package/dist/compliance/tests/embedded_interface_assertion/embedded_interface_assertion.gs.d.ts +0 -1
  65. package/dist/compliance/tests/embedded_interface_assertion/embedded_interface_assertion.gs.js +0 -37
  66. package/dist/compliance/tests/embedded_interface_assertion/embedded_interface_assertion.gs.js.map +0 -1
  67. package/dist/compliance/tests/flag_bitwise_op/flag_bitwise_op.gs.d.ts +0 -1
  68. package/dist/compliance/tests/flag_bitwise_op/flag_bitwise_op.gs.js +0 -29
  69. package/dist/compliance/tests/flag_bitwise_op/flag_bitwise_op.gs.js.map +0 -1
  70. package/dist/compliance/tests/float64/float64.gs.d.ts +0 -1
  71. package/dist/compliance/tests/float64/float64.gs.js +0 -24
  72. package/dist/compliance/tests/float64/float64.gs.js.map +0 -1
  73. package/dist/compliance/tests/for_loop_basic/for_loop_basic.gs.d.ts +0 -1
  74. package/dist/compliance/tests/for_loop_basic/for_loop_basic.gs.js +0 -10
  75. package/dist/compliance/tests/for_loop_basic/for_loop_basic.gs.js.map +0 -1
  76. package/dist/compliance/tests/for_loop_condition_only/for_loop_condition_only.gs.d.ts +0 -1
  77. package/dist/compliance/tests/for_loop_condition_only/for_loop_condition_only.gs.js +0 -11
  78. package/dist/compliance/tests/for_loop_condition_only/for_loop_condition_only.gs.js.map +0 -1
  79. package/dist/compliance/tests/for_loop_condition_only/main.gs.d.ts +0 -1
  80. package/dist/compliance/tests/for_loop_condition_only/main.gs.js +0 -10
  81. package/dist/compliance/tests/for_loop_condition_only/main.gs.js.map +0 -1
  82. package/dist/compliance/tests/for_loop_infinite/for_loop_infinite.gs.d.ts +0 -1
  83. package/dist/compliance/tests/for_loop_infinite/for_loop_infinite.gs.js +0 -14
  84. package/dist/compliance/tests/for_loop_infinite/for_loop_infinite.gs.js.map +0 -1
  85. package/dist/compliance/tests/for_range/for_range.gs.d.ts +0 -1
  86. package/dist/compliance/tests/for_range/for_range.gs.js +0 -39
  87. package/dist/compliance/tests/for_range/for_range.gs.js.map +0 -1
  88. package/dist/compliance/tests/for_range_index_use/for_range_index_use.gs.d.ts +0 -1
  89. package/dist/compliance/tests/for_range_index_use/for_range_index_use.gs.js +0 -15
  90. package/dist/compliance/tests/for_range_index_use/for_range_index_use.gs.js.map +0 -1
  91. package/dist/compliance/tests/func_literal/func_literal.gs.d.ts +0 -1
  92. package/dist/compliance/tests/func_literal/func_literal.gs.js +0 -10
  93. package/dist/compliance/tests/func_literal/func_literal.gs.js.map +0 -1
  94. package/dist/compliance/tests/function_call_result_assignment/function_call_result_assignment.gs.d.ts +0 -12
  95. package/dist/compliance/tests/function_call_result_assignment/function_call_result_assignment.gs.js +0 -30
  96. package/dist/compliance/tests/function_call_result_assignment/function_call_result_assignment.gs.js.map +0 -1
  97. package/dist/compliance/tests/if_statement/if_statement.gs.d.ts +0 -1
  98. package/dist/compliance/tests/if_statement/if_statement.gs.js +0 -13
  99. package/dist/compliance/tests/if_statement/if_statement.gs.js.map +0 -1
  100. package/dist/compliance/tests/interface_method_comments/interface_method_comments.gs.d.ts +0 -1
  101. package/dist/compliance/tests/interface_method_comments/interface_method_comments.gs.js +0 -12
  102. package/dist/compliance/tests/interface_method_comments/interface_method_comments.gs.js.map +0 -1
  103. package/dist/compliance/tests/interface_multi_param_return/interface_multi_param_return.gs.d.ts +0 -1
  104. package/dist/compliance/tests/interface_multi_param_return/interface_multi_param_return.gs.js +0 -34
  105. package/dist/compliance/tests/interface_multi_param_return/interface_multi_param_return.gs.js.map +0 -1
  106. package/dist/compliance/tests/interface_to_interface_type_assertion/interface_to_interface_type_assertion.gs.d.ts +0 -1
  107. package/dist/compliance/tests/interface_to_interface_type_assertion/interface_to_interface_type_assertion.gs.js +0 -32
  108. package/dist/compliance/tests/interface_to_interface_type_assertion/interface_to_interface_type_assertion.gs.js.map +0 -1
  109. package/dist/compliance/tests/interface_type_assertion/interface_type_assertion.gs.d.ts +0 -1
  110. package/dist/compliance/tests/interface_type_assertion/interface_type_assertion.gs.js +0 -40
  111. package/dist/compliance/tests/interface_type_assertion/interface_type_assertion.gs.js.map +0 -1
  112. package/dist/compliance/tests/interface_type_assertion_signature_mismatch/interface_type_assertion_signature_mismatch.gs.d.ts +0 -1
  113. package/dist/compliance/tests/interface_type_assertion_signature_mismatch/interface_type_assertion_signature_mismatch.gs.js +0 -51
  114. package/dist/compliance/tests/interface_type_assertion_signature_mismatch/interface_type_assertion_signature_mismatch.gs.js.map +0 -1
  115. package/dist/compliance/tests/map_support/map_support.gs.d.ts +0 -1
  116. package/dist/compliance/tests/map_support/map_support.gs.js +0 -88
  117. package/dist/compliance/tests/map_support/map_support.gs.js.map +0 -1
  118. package/dist/compliance/tests/method_call_on_pointer_receiver/method_call_on_pointer_receiver.gs.d.ts +0 -1
  119. package/dist/compliance/tests/method_call_on_pointer_receiver/method_call_on_pointer_receiver.gs.js +0 -24
  120. package/dist/compliance/tests/method_call_on_pointer_receiver/method_call_on_pointer_receiver.gs.js.map +0 -1
  121. package/dist/compliance/tests/method_call_on_pointer_via_value/method_call_on_pointer_via_value.gs.d.ts +0 -1
  122. package/dist/compliance/tests/method_call_on_pointer_via_value/method_call_on_pointer_via_value.gs.js +0 -33
  123. package/dist/compliance/tests/method_call_on_pointer_via_value/method_call_on_pointer_via_value.gs.js.map +0 -1
  124. package/dist/compliance/tests/method_call_on_value_receiver/method_call_on_value_receiver.gs.d.ts +0 -1
  125. package/dist/compliance/tests/method_call_on_value_receiver/method_call_on_value_receiver.gs.js +0 -22
  126. package/dist/compliance/tests/method_call_on_value_receiver/method_call_on_value_receiver.gs.js.map +0 -1
  127. package/dist/compliance/tests/method_call_on_value_via_pointer/method_call_on_value_via_pointer.gs.d.ts +0 -1
  128. package/dist/compliance/tests/method_call_on_value_via_pointer/method_call_on_value_via_pointer.gs.js +0 -33
  129. package/dist/compliance/tests/method_call_on_value_via_pointer/method_call_on_value_via_pointer.gs.js.map +0 -1
  130. package/dist/compliance/tests/multiple_return_values/multiple_return_values.gs.d.ts +0 -1
  131. package/dist/compliance/tests/multiple_return_values/multiple_return_values.gs.js +0 -17
  132. package/dist/compliance/tests/multiple_return_values/multiple_return_values.gs.js.map +0 -1
  133. package/dist/compliance/tests/pointer_assignment_no_copy/pointer_assignment_no_copy.gs.d.ts +0 -1
  134. package/dist/compliance/tests/pointer_assignment_no_copy/pointer_assignment_no_copy.gs.js +0 -29
  135. package/dist/compliance/tests/pointer_assignment_no_copy/pointer_assignment_no_copy.gs.js.map +0 -1
  136. package/dist/compliance/tests/pointer_composite_literal_assignment/pointer_composite_literal_assignment.gs.d.ts +0 -1
  137. package/dist/compliance/tests/pointer_composite_literal_assignment/pointer_composite_literal_assignment.gs.js +0 -27
  138. package/dist/compliance/tests/pointer_composite_literal_assignment/pointer_composite_literal_assignment.gs.js.map +0 -1
  139. package/dist/compliance/tests/pointer_deref_multiassign/pointer_deref_multiassign.gs.d.ts +0 -1
  140. package/dist/compliance/tests/pointer_deref_multiassign/pointer_deref_multiassign.gs.js +0 -22
  141. package/dist/compliance/tests/pointer_deref_multiassign/pointer_deref_multiassign.gs.js.map +0 -1
  142. package/dist/compliance/tests/pointer_initialization/pointer_initialization.gs.d.ts +0 -1
  143. package/dist/compliance/tests/pointer_initialization/pointer_initialization.gs.js +0 -20
  144. package/dist/compliance/tests/pointer_initialization/pointer_initialization.gs.js.map +0 -1
  145. package/dist/compliance/tests/select_receive_on_closed_channel_no_default/select_receive_on_closed_channel_no_default.gs.d.ts +0 -1
  146. package/dist/compliance/tests/select_receive_on_closed_channel_no_default/select_receive_on_closed_channel_no_default.gs.js +0 -28
  147. package/dist/compliance/tests/select_receive_on_closed_channel_no_default/select_receive_on_closed_channel_no_default.gs.js.map +0 -1
  148. package/dist/compliance/tests/select_send_on_full_buffered_channel_with_default/select_send_on_full_buffered_channel_with_default.gs.d.ts +0 -1
  149. package/dist/compliance/tests/select_send_on_full_buffered_channel_with_default/select_send_on_full_buffered_channel_with_default.gs.js +0 -30
  150. package/dist/compliance/tests/select_send_on_full_buffered_channel_with_default/select_send_on_full_buffered_channel_with_default.gs.js.map +0 -1
  151. package/dist/compliance/tests/select_statement/select_statement.gs.d.ts +0 -1
  152. package/dist/compliance/tests/select_statement/select_statement.gs.js +0 -207
  153. package/dist/compliance/tests/select_statement/select_statement.gs.js.map +0 -1
  154. package/dist/compliance/tests/simple/simple.gs.d.ts +0 -1
  155. package/dist/compliance/tests/simple/simple.gs.js +0 -6
  156. package/dist/compliance/tests/simple/simple.gs.js.map +0 -1
  157. package/dist/compliance/tests/simple_deref_assignment/simple_deref_assignment.gs.d.ts +0 -1
  158. package/dist/compliance/tests/simple_deref_assignment/simple_deref_assignment.gs.js +0 -24
  159. package/dist/compliance/tests/simple_deref_assignment/simple_deref_assignment.gs.js.map +0 -1
  160. package/dist/compliance/tests/slices/slices.gs.d.ts +0 -1
  161. package/dist/compliance/tests/slices/slices.gs.js +0 -294
  162. package/dist/compliance/tests/slices/slices.gs.js.map +0 -1
  163. package/dist/compliance/tests/string_conversion/string_conversion.gs.d.ts +0 -1
  164. package/dist/compliance/tests/string_conversion/string_conversion.gs.js +0 -41
  165. package/dist/compliance/tests/string_conversion/string_conversion.gs.js.map +0 -1
  166. package/dist/compliance/tests/string_rune_conversion/string_rune_conversion.gs.d.ts +0 -1
  167. package/dist/compliance/tests/string_rune_conversion/string_rune_conversion.gs.js +0 -17
  168. package/dist/compliance/tests/string_rune_conversion/string_rune_conversion.gs.js.map +0 -1
  169. package/dist/compliance/tests/struct_embedding/struct_embedding.gs.d.ts +0 -1
  170. package/dist/compliance/tests/struct_embedding/struct_embedding.gs.js +0 -48
  171. package/dist/compliance/tests/struct_embedding/struct_embedding.gs.js.map +0 -1
  172. package/dist/compliance/tests/struct_field_access/struct_field_access.gs.d.ts +0 -1
  173. package/dist/compliance/tests/struct_field_access/struct_field_access.gs.js +0 -19
  174. package/dist/compliance/tests/struct_field_access/struct_field_access.gs.js.map +0 -1
  175. package/dist/compliance/tests/struct_pointer_interface_fields/struct_pointer_interface_fields.gs.d.ts +0 -1
  176. package/dist/compliance/tests/struct_pointer_interface_fields/struct_pointer_interface_fields.gs.js +0 -26
  177. package/dist/compliance/tests/struct_pointer_interface_fields/struct_pointer_interface_fields.gs.js.map +0 -1
  178. package/dist/compliance/tests/struct_value_init_clone/struct_value_init_clone.gs.d.ts +0 -1
  179. package/dist/compliance/tests/struct_value_init_clone/struct_value_init_clone.gs.js +0 -30
  180. package/dist/compliance/tests/struct_value_init_clone/struct_value_init_clone.gs.js.map +0 -1
  181. package/dist/compliance/tests/switch_statement/switch_statement.gs.d.ts +0 -1
  182. package/dist/compliance/tests/switch_statement/switch_statement.gs.js +0 -76
  183. package/dist/compliance/tests/switch_statement/switch_statement.gs.js.map +0 -1
  184. package/dist/compliance/tests/value_type_copy_behavior/value_type_copy_behavior.gs.d.ts +0 -1
  185. package/dist/compliance/tests/value_type_copy_behavior/value_type_copy_behavior.gs.js +0 -31
  186. package/dist/compliance/tests/value_type_copy_behavior/value_type_copy_behavior.gs.js.map +0 -1
@@ -1,110 +0,0 @@
1
- package compiler
2
-
3
- import (
4
- "fmt"
5
- "go/ast"
6
- gtypes "go/types"
7
- )
8
-
9
- // WriteFieldList writes a field list.
10
- func (c *GoToTSCompiler) WriteFieldList(a *ast.FieldList, isArguments bool) {
11
- if !isArguments && (a == nil || a.NumFields() == 0) {
12
- c.tsw.WriteLiterally("{}")
13
- return
14
- }
15
-
16
- if !isArguments && a.Opening.IsValid() {
17
- c.tsw.WriteLine("{")
18
- c.tsw.Indent(1)
19
- }
20
-
21
- // Handle parameter list for function declarations
22
- for i, field := range a.List {
23
- if i > 0 && isArguments {
24
- c.tsw.WriteLiterally(", ")
25
- }
26
-
27
- if isArguments {
28
- // For function parameters, write "name: type"
29
- c.WriteField(field, true)
30
- c.tsw.WriteLiterally(": ")
31
- c.WriteTypeExpr(field.Type) // Use WriteTypeExpr for parameter type
32
- } else {
33
- // For struct fields and other non-argument fields
34
- c.WriteField(field, false)
35
- }
36
- }
37
-
38
- if !isArguments && a.Closing.IsValid() {
39
- c.tsw.Indent(-1)
40
- c.tsw.WriteLine("}")
41
- }
42
- }
43
-
44
- // WriteField writes a field definition.
45
- func (c *GoToTSCompiler) WriteField(field *ast.Field, isArguments bool) {
46
- if !isArguments {
47
- if field.Doc != nil {
48
- c.WriteDoc(field.Doc)
49
- }
50
- if field.Comment != nil {
51
- c.WriteDoc(field.Comment)
52
- }
53
- }
54
-
55
- for _, name := range field.Names {
56
- isExported := name.IsExported()
57
-
58
- // argument names: keep original casing, no access modifier
59
- if isArguments {
60
- c.tsw.WriteLiterally(name.Name)
61
- // Argument type is handled in WriteFieldList, so continue
62
- continue
63
- } else if isExported {
64
- // exported struct fields become public, keep original casing
65
- c.tsw.WriteLiterally("public ")
66
- c.tsw.WriteLiterally(name.Name)
67
- } else {
68
- // unexported struct fields become private, keep original casing
69
- c.tsw.WriteLiterally("private ")
70
- c.tsw.WriteLiterally(name.Name)
71
- }
72
-
73
- // Check if field type is an interface
74
- isInterface := false
75
- if c.pkg != nil && c.pkg.TypesInfo != nil {
76
- if tv, ok := c.pkg.TypesInfo.Types[field.Type]; ok && tv.Type != nil {
77
- _, isInterface = tv.Type.Underlying().(*gtypes.Interface)
78
- }
79
- }
80
-
81
- // write type for struct fields (not arguments)
82
- c.tsw.WriteLiterally(": ")
83
- c.WriteTypeExpr(field.Type) // Use WriteTypeExpr for field type
84
-
85
- // Append "| null" for interface fields
86
- if !isArguments && isInterface {
87
- c.tsw.WriteLiterally(" | null")
88
- }
89
-
90
- if !isArguments {
91
- // write initializer with zero value for struct fields
92
- c.tsw.WriteLiterally(" = ")
93
-
94
- // Special initialization for interface fields
95
- if isInterface {
96
- c.tsw.WriteLiterally("null")
97
- } else {
98
- c.WriteZeroValueForType(field.Type)
99
- }
100
-
101
- // write tag comment if any for struct fields
102
- if field.Tag != nil {
103
- c.tsw.WriteLiterally(";")
104
- c.tsw.WriteCommentLine(fmt.Sprintf("tag: %s", field.Tag.Value))
105
- } else {
106
- c.tsw.WriteLine(";")
107
- }
108
- }
109
- }
110
- }
@@ -1,566 +0,0 @@
1
- package compiler
2
-
3
- import (
4
- "fmt"
5
- "go/ast"
6
- "go/types"
7
- gtypes "go/types"
8
- "sort"
9
- "strings"
10
- )
11
-
12
- // WriteSpec writes a specification to the output.
13
- func (c *GoToTSCompiler) WriteSpec(a ast.Spec) error {
14
- switch d := a.(type) {
15
- case *ast.ImportSpec:
16
- c.WriteImportSpec(d)
17
- case *ast.ValueSpec:
18
- if err := c.WriteValueSpec(d); err != nil {
19
- return err
20
- }
21
- case *ast.TypeSpec:
22
- if err := c.WriteTypeSpec(d); err != nil {
23
- return err
24
- }
25
- default:
26
- return fmt.Errorf("unknown spec type: %T", a)
27
- }
28
- return nil
29
- }
30
-
31
- // collectMethodNames returns a comma-separated string of method names for a struct
32
- func (c *GoToTSCompiler) collectMethodNames(structName string) string {
33
- var methodNames []string
34
-
35
- for _, fileSyntax := range c.pkg.Syntax {
36
- for _, decl := range fileSyntax.Decls {
37
- funcDecl, isFunc := decl.(*ast.FuncDecl)
38
- if !isFunc || funcDecl.Recv == nil || len(funcDecl.Recv.List) == 0 {
39
- continue // Skip non-functions or functions without receivers
40
- }
41
-
42
- // Check if the receiver type matches the struct name
43
- recvField := funcDecl.Recv.List[0]
44
- recvType := recvField.Type
45
- // Handle pointer receivers (*MyStruct) and value receivers (MyStruct)
46
- if starExpr, ok := recvType.(*ast.StarExpr); ok {
47
- recvType = starExpr.X // Get the type being pointed to
48
- }
49
-
50
- // Check if the receiver identifier name matches the struct name
51
- if ident, ok := recvType.(*ast.Ident); ok && ident.Name == structName {
52
- // Found a method for this struct
53
- methodNames = append(methodNames, fmt.Sprintf("'%s'", funcDecl.Name.Name))
54
- }
55
- }
56
- }
57
-
58
- return strings.Join(methodNames, ", ")
59
- }
60
-
61
- // getTypeExprName returns a string representation of a type expression.
62
- func (c *GoToTSCompiler) getTypeExprName(expr ast.Expr) string {
63
- switch t := expr.(type) {
64
- case *ast.Ident:
65
- return t.Name
66
- case *ast.SelectorExpr:
67
- return fmt.Sprintf("%s.%s", c.getTypeExprName(t.X), t.Sel.Name)
68
- case *ast.StarExpr:
69
- return c.getTypeExprName(t.X) // Unwrap pointer type
70
- default:
71
- return "embedded" // Fallback for complex type expressions
72
- }
73
- }
74
-
75
- // collectInterfaceMethods returns a comma-separated string of method names for an interface
76
- func (c *GoToTSCompiler) collectInterfaceMethods(interfaceType *ast.InterfaceType) string {
77
- // Use a map to ensure uniqueness of method names
78
- methodNamesMap := make(map[string]struct{})
79
-
80
- if interfaceType.Methods != nil {
81
- for _, method := range interfaceType.Methods.List {
82
- if len(method.Names) > 0 {
83
- // Named method
84
- methodNamesMap[method.Names[0].Name] = struct{}{}
85
- } else {
86
- // Embedded interface - resolve it and collect its methods
87
- embeddedType := method.Type
88
-
89
- // Resolve the embedded interface using type information
90
- if tv, ok := c.pkg.TypesInfo.Types[embeddedType]; ok && tv.Type != nil {
91
- // Get the underlying interface type
92
- var ifaceType *types.Interface
93
- if named, ok := tv.Type.(*types.Named); ok {
94
- if underlying, ok := named.Underlying().(*types.Interface); ok {
95
- ifaceType = underlying
96
- }
97
- } else if underlying, ok := tv.Type.(*types.Interface); ok {
98
- ifaceType = underlying
99
- }
100
-
101
- // Collect methods from the interface
102
- if ifaceType != nil {
103
- for i := 0; i < ifaceType.NumMethods(); i++ {
104
- methodNamesMap[ifaceType.Method(i).Name()] = struct{}{}
105
- }
106
- }
107
- } else {
108
- // Couldn't resolve the embedded interface
109
- c.tsw.WriteCommentLine("// Note: Some embedded interface methods may not be fully resolved")
110
- }
111
- }
112
- }
113
- }
114
-
115
- // Convert the map to a slice for a deterministic output order
116
- var methodNames []string
117
- for name := range methodNamesMap {
118
- methodNames = append(methodNames, fmt.Sprintf("'%s'", name))
119
- }
120
-
121
- // Sort for deterministic output
122
- sort.Strings(methodNames)
123
-
124
- return strings.Join(methodNames, ", ")
125
- }
126
-
127
- // WriteTypeSpec writes the type specification to the output.
128
- func (c *GoToTSCompiler) WriteTypeSpec(a *ast.TypeSpec) error {
129
- if a.Doc != nil {
130
- c.WriteDoc(a.Doc)
131
- }
132
- if a.Comment != nil {
133
- c.WriteDoc(a.Comment)
134
- }
135
-
136
- switch t := a.Type.(type) {
137
- case *ast.StructType:
138
- // Detect embedded struct (anonymous field) to support Go struct embedding.
139
- var embeddedExpr ast.Expr
140
- for _, f := range t.Fields.List {
141
- if len(f.Names) == 0 { // anonymous field ⇒ embedded type
142
- embeddedExpr = f.Type
143
- break // only the first embedded struct is supported for now
144
- }
145
- }
146
- // Write the class header, adding "extends Embedded" when an embedded struct is present.
147
- c.tsw.WriteLiterally("class ")
148
- if err := c.WriteValueExpr(a.Name); err != nil { // Class name is a value identifier
149
- return err
150
- }
151
- c.tsw.WriteLiterally(" ")
152
-
153
- if embeddedExpr != nil {
154
- // For pointer embedding (*T) unwrap the star so we extend T, not (T|null)
155
- if star, ok := embeddedExpr.(*ast.StarExpr); ok {
156
- embeddedExpr = star.X
157
- }
158
- c.tsw.WriteLiterally("extends ")
159
- c.WriteTypeExpr(embeddedExpr) // Embedded type name
160
- c.tsw.WriteLiterally(" ")
161
- }
162
-
163
- c.tsw.WriteLine("{")
164
- c.tsw.Indent(1)
165
-
166
- // className is the name of the class type
167
- className := a.Name.Name
168
- for _, field := range t.Fields.List {
169
- c.WriteField(field, false)
170
- }
171
-
172
- // Methods for this struct are discovered by scanning all package declarations.
173
- // Future improvement: use pkg.TypesInfo.MethodSet (go/types) for direct method lookup.
174
- for _, fileSyntax := range c.pkg.Syntax {
175
- for _, decl := range fileSyntax.Decls {
176
- funcDecl, isFunc := decl.(*ast.FuncDecl)
177
- if !isFunc || funcDecl.Recv == nil || len(funcDecl.Recv.List) == 0 {
178
- continue // Skip non-functions or functions without receivers
179
- }
180
-
181
- // Check if the receiver type matches the struct name
182
- recvField := funcDecl.Recv.List[0]
183
- recvType := recvField.Type
184
- // Handle pointer receivers (*MyStruct) and value receivers (MyStruct)
185
- if starExpr, ok := recvType.(*ast.StarExpr); ok {
186
- recvType = starExpr.X // Get the type being pointed to
187
- }
188
-
189
- // Check if the receiver identifier name matches the current struct name
190
- if ident, ok := recvType.(*ast.Ident); ok && ident.Name == className {
191
- // Found a method for this struct
192
- c.tsw.WriteLine("") // Add space between methods
193
- if err := c.WriteFuncDeclAsMethod(funcDecl); err != nil {
194
- return err
195
- }
196
- }
197
- }
198
- }
199
-
200
- // constructor and clone using Object.assign for compactness
201
- c.tsw.WriteLine("")
202
- if embeddedExpr != nil {
203
- // Determine the embedded type's identifier (strip any package prefix)
204
- embeddedTypeNameFull := c.getTypeExprName(embeddedExpr)
205
- propName := embeddedTypeNameFull
206
- if idx := strings.LastIndex(propName, "."); idx != -1 {
207
- propName = propName[idx+1:] // keep only the last segment for the property key
208
- }
209
-
210
- // The init parameter allows either flattened fields or a nested {Embedded: {...}} object
211
- c.tsw.WriteLinef(
212
- "constructor(init?: Partial<%s> & { %s?: Partial<%s> }) {",
213
- className, propName, propName,
214
- )
215
- c.tsw.Indent(1)
216
-
217
- // Pass either the nested embedded object or the full init directly to super()
218
- c.tsw.WriteLinef("super(init?.%s || init);", propName)
219
-
220
- // Copy fields that belong only to this derived class
221
- c.tsw.WriteLine("if (init) {")
222
- c.tsw.Indent(1)
223
- c.tsw.WriteLinef("const { %s, ...rest } = init as any;", propName)
224
- c.tsw.WriteLine("Object.assign(this, rest);")
225
- c.tsw.Indent(-1)
226
- c.tsw.WriteLine("}")
227
-
228
- c.tsw.Indent(-1)
229
- c.tsw.WriteLine("}")
230
- } else {
231
- // For a base class without embedding, use simple constructor
232
- c.tsw.WriteLinef("constructor(init?: Partial<%s>) { if (init) Object.assign(this, init as any); }", className)
233
- }
234
- c.tsw.WriteLinef("public clone(): %s { return Object.assign(Object.create(%s.prototype) as %s, this); }", className, className, className)
235
-
236
- // Add code to register the type with the runtime system
237
- c.tsw.WriteLine("")
238
- c.tsw.WriteLinef("// Register this type with the runtime type system")
239
- c.tsw.WriteLinef("static __typeInfo = goscript.registerType(")
240
- c.tsw.WriteLinef(" '%s',", className)
241
- c.tsw.WriteLinef(" goscript.TypeKind.Struct,")
242
- c.tsw.WriteLinef(" new %s(),", className)
243
- c.tsw.WriteLinef(" new Set([%s]),", c.collectMethodNames(className))
244
- c.tsw.WriteLinef(" %s", className)
245
- c.tsw.WriteLinef(");")
246
-
247
- c.tsw.Indent(-1)
248
- c.tsw.WriteLine("}")
249
- case *ast.InterfaceType:
250
- c.tsw.WriteLiterally("interface ")
251
- if err := c.WriteValueExpr(a.Name); err != nil { // Interface name is a value identifier
252
- return err
253
- }
254
- c.tsw.WriteLiterally(" ") // Changed from WriteLine to WriteLiterally
255
- c.WriteTypeExpr(a.Type) // The interface definition itself is a type
256
-
257
- // Add code to register the interface with the runtime system
258
- interfaceName := a.Name.Name
259
- c.tsw.WriteLine("")
260
- c.tsw.WriteLinef("// Register this interface with the runtime type system")
261
- c.tsw.WriteLinef("const %s__typeInfo = goscript.registerType(", interfaceName)
262
- c.tsw.WriteLinef(" '%s',", interfaceName)
263
- c.tsw.WriteLinef(" goscript.TypeKind.Interface,")
264
- c.tsw.WriteLinef(" null,") // Zero value for interface is null
265
- c.tsw.WriteLinef(" new Set([%s]),", c.collectInterfaceMethods(t))
266
- c.tsw.WriteLinef(" undefined")
267
- c.tsw.WriteLinef(");")
268
- default:
269
- // type alias
270
- c.tsw.WriteLiterally("type ")
271
- if err := c.WriteValueExpr(a.Name); err != nil { // Type alias name is a value identifier
272
- return err
273
- }
274
- c.tsw.WriteLiterally(" = ")
275
- c.WriteTypeExpr(a.Type) // The aliased type
276
- c.tsw.WriteLine(";")
277
- }
278
- return nil
279
- }
280
-
281
- // WriteFuncDeclAsMethod writes a TypeScript method declaration from a Go FuncDecl.
282
- // Assumes it's called only for functions with receivers.
283
- func (c *GoToTSCompiler) WriteFuncDeclAsMethod(decl *ast.FuncDecl) error {
284
- if decl.Doc != nil {
285
- c.WriteDoc(decl.Doc)
286
- }
287
-
288
- // Determine if method is async by checking for async operations in the body
289
- isAsync := c.containsAsyncOperations(decl.Body)
290
-
291
- // Methods are typically public in the TS output
292
- c.tsw.WriteLiterally("public ")
293
-
294
- // Add async modifier if needed
295
- if isAsync {
296
- c.tsw.WriteLiterally("async ")
297
- }
298
-
299
- // Keep original Go casing for method names
300
- if err := c.WriteValueExpr(decl.Name); err != nil { // Method name is a value identifier
301
- return err
302
- }
303
-
304
- // Write signature (parameters and return type)
305
- // We adapt the logic from WriteFuncType here, but without the 'function' keyword
306
- funcType := decl.Type
307
- c.tsw.WriteLiterally("(")
308
- if funcType.Params != nil {
309
- c.WriteFieldList(funcType.Params, true) // true = arguments
310
- }
311
- c.tsw.WriteLiterally(")")
312
-
313
- // Handle return type
314
- if funcType.Results != nil && len(funcType.Results.List) > 0 {
315
- c.tsw.WriteLiterally(": ")
316
- if isAsync {
317
- c.tsw.WriteLiterally("Promise<")
318
- }
319
- if len(funcType.Results.List) == 1 {
320
- // Single return value
321
- resultType := funcType.Results.List[0].Type
322
- c.WriteTypeExpr(resultType)
323
- } else {
324
- // Multiple return values -> tuple type
325
- c.tsw.WriteLiterally("[")
326
- for i, field := range funcType.Results.List {
327
- if i > 0 {
328
- c.tsw.WriteLiterally(", ")
329
- }
330
- c.WriteTypeExpr(field.Type)
331
- }
332
- c.tsw.WriteLiterally("]")
333
- }
334
- if isAsync {
335
- c.tsw.WriteLiterally(">")
336
- }
337
- } else {
338
- // No return value -> void
339
- if isAsync {
340
- c.tsw.WriteLiterally(": Promise<void>")
341
- } else {
342
- c.tsw.WriteLiterally(": void")
343
- }
344
- }
345
-
346
- c.tsw.WriteLiterally(" ")
347
-
348
- // Check if function body has defer statements
349
- c.nextBlockNeedsDefer = c.scanForDefer(decl.Body)
350
-
351
- // Save previous async state and set current state based on isAsync
352
- previousAsyncState := c.inAsyncFunction
353
- c.inAsyncFunction = isAsync
354
-
355
- // Bind receiver name to this
356
- if recvField := decl.Recv.List[0]; len(recvField.Names) > 0 {
357
- recvName := recvField.Names[0].Name
358
- if recvName != "_" {
359
- c.tsw.WriteLine("{")
360
- c.tsw.Indent(1)
361
- c.tsw.WriteLinef("const %s = this", recvName)
362
-
363
- // Add using statement if needed
364
- if c.nextBlockNeedsDefer {
365
- if c.inAsyncFunction {
366
- c.tsw.WriteLine("await using __defer = new goscript.AsyncDisposableStack();")
367
- } else {
368
- c.tsw.WriteLine("using cleanup = new goscript.DisposableStack();")
369
- }
370
- c.nextBlockNeedsDefer = false
371
- }
372
-
373
- // write method body without outer braces
374
- for _, stmt := range decl.Body.List {
375
- if err := c.WriteStmt(stmt); err != nil {
376
- c.inAsyncFunction = previousAsyncState // Restore state before returning error
377
- return fmt.Errorf("failed to write statement in function body: %w", err)
378
- }
379
- }
380
- c.tsw.Indent(-1)
381
- c.tsw.WriteLine("}")
382
-
383
- // Restore previous async state
384
- c.inAsyncFunction = previousAsyncState
385
- return nil
386
- }
387
- }
388
- // no named receiver, write whole body
389
- if err := c.WriteStmt(decl.Body); err != nil {
390
- c.inAsyncFunction = previousAsyncState // Restore state before returning error
391
- return fmt.Errorf("failed to write function body: %w", err)
392
- }
393
-
394
- // Restore previous async state
395
- c.inAsyncFunction = previousAsyncState
396
- return nil
397
- }
398
-
399
- // WriteValueSpec writes the value specification to the output.
400
- func (c *GoToTSCompiler) WriteValueSpec(a *ast.ValueSpec) error {
401
- if a.Doc != nil {
402
- c.WriteDoc(a.Doc)
403
- }
404
- if a.Comment != nil {
405
- c.WriteDoc(a.Comment)
406
- }
407
- c.tsw.WriteLiterally("let ")
408
- if len(a.Names) == 1 {
409
- name := a.Names[0]
410
- c.tsw.WriteLiterally(name.Name)
411
-
412
- // Check if it's an interface type
413
- isInterface := false
414
- if c.pkg != nil && c.pkg.TypesInfo != nil && a.Type != nil {
415
- if tv, ok := c.pkg.TypesInfo.Types[a.Type]; ok && tv.Type != nil {
416
- _, isInterface = tv.Type.Underlying().(*gtypes.Interface)
417
- }
418
- }
419
-
420
- if a.Type != nil {
421
- c.tsw.WriteLiterally(": ")
422
- c.WriteTypeExpr(a.Type) // Variable type annotation
423
-
424
- // Append "| null" for interface types
425
- if isInterface {
426
- c.tsw.WriteLiterally(" | null")
427
- }
428
-
429
- // Check if it's an array type declaration without an initial value
430
- if _, isArrayType := a.Type.(*ast.ArrayType); isArrayType && len(a.Values) == 0 {
431
- c.tsw.WriteLiterally(" = []")
432
- } else if isInterface && len(a.Values) == 0 {
433
- // Interface with no initialization value, initialize to null
434
- c.tsw.WriteLiterally(" = null")
435
- }
436
- }
437
- if len(a.Values) > 0 {
438
- c.tsw.WriteLiterally(" = ")
439
- for i, val := range a.Values {
440
- if i != 0 {
441
- c.tsw.WriteLiterally(", ")
442
- }
443
- if err := c.WriteValueExpr(val); err != nil { // Initializer is a value
444
- return err
445
- }
446
- }
447
- }
448
- } else {
449
- c.tsw.WriteLiterally("{")
450
- for i, name := range a.Names {
451
- if i != 0 {
452
- c.tsw.WriteLiterally(", ")
453
- }
454
- c.tsw.WriteLiterally(name.Name)
455
- }
456
- c.tsw.WriteLiterally("}")
457
- for i, val := range a.Values {
458
- if i == 0 {
459
- c.tsw.WriteLiterally(" = ")
460
- } else {
461
- c.tsw.WriteLiterally(", ")
462
- }
463
- if err := c.WriteValueExpr(val); err != nil { // Initializers are values
464
- return err
465
- }
466
- }
467
- }
468
- c.tsw.WriteLine(";")
469
- return nil
470
- }
471
-
472
- // WriteImportSpec writes an import specification to the output.
473
- func (c *GoToTSCompiler) WriteImportSpec(a *ast.ImportSpec) {
474
- if a.Doc != nil {
475
- c.WriteDoc(a.Doc)
476
- }
477
- if a.Comment != nil {
478
- c.WriteDoc(a.Comment)
479
- }
480
-
481
- goPath := a.Path.Value[1 : len(a.Path.Value)-1]
482
- impName := packageNameFromGoPath(goPath)
483
- if a.Name != nil && a.Name.Name != "" {
484
- impName = a.Name.Name
485
- }
486
-
487
- importPath := translateGoPathToTypescriptPath(goPath)
488
- c.imports[impName] = &fileImport{
489
- importPath: importPath,
490
- importVars: make(map[string]struct{}),
491
- }
492
-
493
- c.tsw.WriteImport(impName, importPath)
494
- }
495
-
496
- // WriteInterfaceMethodSignature writes a TypeScript interface method signature from a Go ast.Field.
497
- func (c *GoToTSCompiler) WriteInterfaceMethodSignature(field *ast.Field) error {
498
- // Include comments
499
- if field.Doc != nil {
500
- c.WriteDoc(field.Doc)
501
- }
502
- if field.Comment != nil {
503
- c.WriteDoc(field.Comment)
504
- }
505
-
506
- if len(field.Names) == 0 {
507
- // Should not happen for named methods in an interface, but handle defensively
508
- return fmt.Errorf("interface method field has no name")
509
- }
510
-
511
- methodName := field.Names[0]
512
- funcType, ok := field.Type.(*ast.FuncType)
513
- if !ok {
514
- // Should not happen for valid interface methods, but handle defensively
515
- c.tsw.WriteCommentInline("unexpected interface method type")
516
- return fmt.Errorf("interface method type is not a FuncType")
517
- }
518
-
519
- // Write method name
520
- c.WriteIdentValue(methodName)
521
-
522
- // Write parameter list (name: type)
523
- c.tsw.WriteLiterally("(")
524
- if funcType.Params != nil {
525
- for i, param := range funcType.Params.List {
526
- if i > 0 {
527
- c.tsw.WriteLiterally(", ")
528
- }
529
- // Determine parameter name
530
- paramName := fmt.Sprintf("_p%d", i) // Default placeholder
531
- if len(param.Names) > 0 && param.Names[0].Name != "" && param.Names[0].Name != "_" {
532
- paramName = param.Names[0].Name
533
- }
534
- c.tsw.WriteLiterally(paramName)
535
- c.tsw.WriteLiterally(": ")
536
- c.WriteTypeExpr(param.Type)
537
- }
538
- }
539
- c.tsw.WriteLiterally(")")
540
-
541
- // Write return type
542
- // Use WriteFuncType's logic for return types, but without the async handling
543
- if funcType.Results != nil && len(funcType.Results.List) > 0 {
544
- c.tsw.WriteLiterally(": ")
545
- if len(funcType.Results.List) == 1 && len(funcType.Results.List[0].Names) == 0 {
546
- // Single unnamed return type
547
- c.WriteTypeExpr(funcType.Results.List[0].Type)
548
- } else {
549
- // Multiple or named return types -> tuple
550
- c.tsw.WriteLiterally("[")
551
- for i, result := range funcType.Results.List {
552
- if i > 0 {
553
- c.tsw.WriteLiterally(", ")
554
- }
555
- c.WriteTypeExpr(result.Type)
556
- }
557
- c.tsw.WriteLiterally("]")
558
- }
559
- } else {
560
- // No return value -> void
561
- c.tsw.WriteLiterally(": void")
562
- }
563
-
564
- c.tsw.WriteLine(";") // Semicolon at the end of the method signature
565
- return nil
566
- }