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
@@ -0,0 +1,506 @@
1
+ package compiler
2
+
3
+ import (
4
+ "fmt"
5
+ "go/ast"
6
+ "go/types"
7
+ "strings"
8
+
9
+ // types provides type information for Go types.
10
+ "github.com/pkg/errors"
11
+ )
12
+
13
+ func (c *GoToTSCompiler) getEmbeddedFieldKeyName(fieldType types.Type) string {
14
+ trueType := fieldType
15
+ if ptr, isPtr := trueType.(*types.Pointer); isPtr {
16
+ trueType = ptr.Elem()
17
+ }
18
+
19
+ if named, isNamed := trueType.(*types.Named); isNamed {
20
+ return named.Obj().Name()
21
+ } else {
22
+ // Fallback for unnamed embedded types, though less common for structs
23
+ fieldKeyName := strings.Title(trueType.String()) // Simple heuristic
24
+ if dotIndex := strings.LastIndex(fieldKeyName, "."); dotIndex != -1 {
25
+ fieldKeyName = fieldKeyName[dotIndex+1:]
26
+ }
27
+ return fieldKeyName
28
+ }
29
+ }
30
+
31
+ func (c *GoToTSCompiler) writeGetterSetter(fieldName string, fieldType types.Type, doc, comment *ast.CommentGroup) {
32
+ fieldTypeStr := c.getTypeString(fieldType)
33
+
34
+ // Generate getter
35
+ if doc != nil {
36
+ c.WriteDoc(doc)
37
+ }
38
+ if comment != nil {
39
+ c.WriteDoc(comment)
40
+ }
41
+ c.tsw.WriteLinef("public get %s(): %s {", fieldName, fieldTypeStr)
42
+ c.tsw.Indent(1)
43
+ c.tsw.WriteLinef("return this._fields.%s.value", fieldName)
44
+ c.tsw.Indent(-1)
45
+ c.tsw.WriteLine("}")
46
+
47
+ // Generate setter (no comments)
48
+ c.tsw.WriteLinef("public set %s(value: %s) {", fieldName, fieldTypeStr)
49
+ c.tsw.Indent(1)
50
+ c.tsw.WriteLinef("this._fields.%s.value = value", fieldName)
51
+ c.tsw.Indent(-1)
52
+ c.tsw.WriteLine("}")
53
+ c.tsw.WriteLine("")
54
+ }
55
+
56
+ func (c *GoToTSCompiler) writeBoxedFieldInitializer(fieldName string, fieldType types.Type, isEmbedded bool) {
57
+ c.tsw.WriteLiterally(fieldName)
58
+ c.tsw.WriteLiterally(": $.box(")
59
+
60
+ if isEmbedded {
61
+ if _, isPtr := fieldType.(*types.Pointer); isPtr {
62
+ c.tsw.WriteLiterallyf("init?.%s ?? null", fieldName)
63
+ } else {
64
+ typeForNew := fieldName
65
+ c.tsw.WriteLiterallyf("new %s(init?.%s)", typeForNew, fieldName)
66
+ }
67
+ } else {
68
+ isStructValueType := false
69
+ var structTypeNameForClone string
70
+ if named, ok := fieldType.(*types.Named); ok {
71
+ if _, isStruct := named.Underlying().(*types.Struct); isStruct {
72
+ isStructValueType = true
73
+ structTypeNameForClone = named.Obj().Name()
74
+ }
75
+ }
76
+
77
+ if isStructValueType {
78
+ c.tsw.WriteLiterallyf("init?.%s?.clone() ?? new %s()", fieldName, structTypeNameForClone)
79
+ } else {
80
+ c.tsw.WriteLiterallyf("init?.%s ?? ", fieldName)
81
+ c.WriteZeroValueForType(fieldType)
82
+ }
83
+ }
84
+
85
+ c.tsw.WriteLiterally(")")
86
+ }
87
+
88
+ func (c *GoToTSCompiler) writeClonedFieldInitializer(fieldName string, fieldType types.Type, isEmbedded bool) {
89
+ c.tsw.WriteLiterally(fieldName)
90
+ c.tsw.WriteLiterally(": $.box(")
91
+
92
+ if isEmbedded {
93
+ isPointerToStruct := false
94
+ trueType := fieldType
95
+ if ptr, isPtr := trueType.(*types.Pointer); isPtr {
96
+ trueType = ptr.Elem()
97
+ isPointerToStruct = true
98
+ }
99
+
100
+ if named, isNamed := trueType.(*types.Named); isNamed {
101
+ _, isUnderlyingStruct := named.Underlying().(*types.Struct)
102
+ if isUnderlyingStruct && !isPointerToStruct { // Is a value struct
103
+ c.tsw.WriteLiterallyf("this._fields.%s.value.clone()", fieldName)
104
+ } else { // Is a pointer to a struct, or not a struct
105
+ c.tsw.WriteLiterallyf("this._fields.%s.value", fieldName)
106
+ }
107
+ } else {
108
+ c.tsw.WriteLiterallyf("this._fields.%s.value", fieldName)
109
+ }
110
+ } else {
111
+ isValueTypeStruct := false
112
+ if named, ok := fieldType.(*types.Named); ok {
113
+ if _, isStruct := named.Underlying().(*types.Struct); isStruct {
114
+ isValueTypeStruct = true
115
+ }
116
+ }
117
+
118
+ if isValueTypeStruct {
119
+ c.tsw.WriteLiterallyf("this._fields.%s.value?.clone() ?? null", fieldName)
120
+ } else {
121
+ c.tsw.WriteLiterallyf("this._fields.%s.value", fieldName)
122
+ }
123
+ }
124
+
125
+ c.tsw.WriteLiterally(")")
126
+ }
127
+
128
+ // WriteTypeSpec writes the type specification to the output.
129
+ func (c *GoToTSCompiler) WriteTypeSpec(a *ast.TypeSpec) error {
130
+ if a.Doc != nil {
131
+ c.WriteDoc(a.Doc)
132
+ }
133
+ if a.Comment != nil {
134
+ c.WriteDoc(a.Comment)
135
+ }
136
+
137
+ switch t := a.Type.(type) {
138
+ case *ast.StructType:
139
+ return c.WriteStructTypeSpec(a, t)
140
+ case *ast.InterfaceType:
141
+ return c.WriteInterfaceTypeSpec(a, t)
142
+ default:
143
+ // type alias
144
+ c.tsw.WriteLiterally("type ")
145
+ if err := c.WriteValueExpr(a.Name); err != nil {
146
+ return err
147
+ }
148
+ c.tsw.WriteLiterally(" = ")
149
+ c.WriteTypeExpr(a.Type) // The aliased type
150
+ c.tsw.WriteLine(";")
151
+ }
152
+ return nil
153
+ }
154
+
155
+ func (c *GoToTSCompiler) WriteStructTypeSpec(a *ast.TypeSpec, t *ast.StructType) error {
156
+ c.tsw.WriteLiterally("class ")
157
+ if err := c.WriteValueExpr(a.Name); err != nil {
158
+ return err
159
+ }
160
+ c.tsw.WriteLiterally(" ")
161
+ c.tsw.WriteLine("{")
162
+ c.tsw.Indent(1)
163
+
164
+ className := a.Name.Name
165
+
166
+ goStructType, ok := c.pkg.TypesInfo.Defs[a.Name].Type().(*types.Named)
167
+ if !ok {
168
+ return fmt.Errorf("could not get named type for %s", a.Name.Name)
169
+ }
170
+ underlyingStruct, ok := goStructType.Underlying().(*types.Struct)
171
+ if !ok {
172
+ return fmt.Errorf("underlying type of %s is not a struct", a.Name.Name)
173
+ }
174
+
175
+ // Generate getters and setters for each non-embedded field first
176
+ for _, field := range t.Fields.List {
177
+ if len(field.Names) == 0 { // Skip anonymous/embedded fields here; they are handled below or via promotion
178
+ continue
179
+ }
180
+ for _, name := range field.Names {
181
+ fieldName := name.Name
182
+ fieldType := c.pkg.TypesInfo.TypeOf(field.Type)
183
+ if fieldType == nil {
184
+ fieldType = types.Typ[types.Invalid]
185
+ }
186
+ c.writeGetterSetter(fieldName, fieldType, field.Doc, field.Comment)
187
+ }
188
+ }
189
+
190
+ // Generate getters and setters for EMBEDDED struct fields themselves
191
+ for i := 0; i < underlyingStruct.NumFields(); i++ {
192
+ field := underlyingStruct.Field(i)
193
+ if field.Anonymous() {
194
+ fieldKeyName := c.getEmbeddedFieldKeyName(field.Type())
195
+ c.writeGetterSetter(fieldKeyName, field.Type(), nil, nil)
196
+ }
197
+ }
198
+
199
+ // Define the _fields property type
200
+ c.tsw.WriteLiterally("public _fields: {")
201
+ c.tsw.Indent(1)
202
+ c.tsw.WriteLine("")
203
+
204
+ for i := 0; i < underlyingStruct.NumFields(); i++ {
205
+ field := underlyingStruct.Field(i)
206
+ var fieldKeyName string
207
+ if field.Anonymous() {
208
+ fieldKeyName = c.getEmbeddedFieldKeyName(field.Type())
209
+ } else {
210
+ fieldKeyName = field.Name()
211
+ }
212
+ fieldTsType := c.getTypeString(field.Type())
213
+ c.tsw.WriteLinef("%s: $.Box<%s>;", fieldKeyName, fieldTsType)
214
+ }
215
+ c.tsw.Indent(-1)
216
+ c.tsw.WriteLine("}")
217
+
218
+ // Generate the flattened type string for the constructor init parameter
219
+ flattenedInitType := c.generateFlattenedInitTypeString(goStructType)
220
+
221
+ c.tsw.WriteLine("")
222
+ c.tsw.WriteLinef("constructor(init?: Partial<%s>) {", flattenedInitType)
223
+ c.tsw.Indent(1)
224
+ c.tsw.WriteLine("this._fields = {")
225
+ c.tsw.Indent(1)
226
+
227
+ numFields := underlyingStruct.NumFields()
228
+ for i := 0; i < numFields; i++ {
229
+ field := underlyingStruct.Field(i)
230
+ fieldType := field.Type()
231
+ var fieldKeyName string
232
+ if field.Anonymous() {
233
+ fieldKeyName = c.getEmbeddedFieldKeyName(field.Type())
234
+ } else {
235
+ fieldKeyName = field.Name()
236
+ }
237
+
238
+ c.writeBoxedFieldInitializer(fieldKeyName, fieldType, field.Anonymous())
239
+
240
+ if i < numFields-1 {
241
+ c.tsw.WriteLine(",")
242
+ } else {
243
+ c.tsw.WriteLine("")
244
+ }
245
+ }
246
+
247
+ c.tsw.Indent(-1)
248
+ c.tsw.WriteLine("}")
249
+ c.tsw.Indent(-1)
250
+ c.tsw.WriteLine("}")
251
+ c.tsw.WriteLine("")
252
+
253
+ // Generate the clone method
254
+ c.tsw.WriteLinef("public clone(): %s {", className)
255
+ c.tsw.Indent(1)
256
+ c.tsw.WriteLinef("const cloned = new %s()", className)
257
+ c.tsw.WriteLine("cloned._fields = {")
258
+ c.tsw.Indent(1)
259
+
260
+ for i := 0; i < numFields; i++ {
261
+ field := underlyingStruct.Field(i)
262
+ fieldType := field.Type()
263
+ var fieldKeyName string
264
+ if field.Anonymous() {
265
+ fieldKeyName = c.getEmbeddedFieldKeyName(field.Type())
266
+ } else {
267
+ fieldKeyName = field.Name()
268
+ }
269
+
270
+ c.writeClonedFieldInitializer(fieldKeyName, fieldType, field.Anonymous())
271
+
272
+ if i < numFields-1 {
273
+ c.tsw.WriteLine(",")
274
+ } else {
275
+ c.tsw.WriteLine("")
276
+ }
277
+ }
278
+
279
+ c.tsw.Indent(-1)
280
+ c.tsw.WriteLine("}")
281
+ c.tsw.WriteLine("return cloned")
282
+ c.tsw.Indent(-1)
283
+ c.tsw.WriteLine("}")
284
+
285
+ // Methods for this struct (direct methods)
286
+ for _, fileSyntax := range c.pkg.Syntax {
287
+ for _, decl := range fileSyntax.Decls {
288
+ funcDecl, isFunc := decl.(*ast.FuncDecl)
289
+ if !isFunc || funcDecl.Recv == nil || len(funcDecl.Recv.List) == 0 {
290
+ continue
291
+ }
292
+ recvField := funcDecl.Recv.List[0]
293
+ recvType := recvField.Type
294
+ if starExpr, ok := recvType.(*ast.StarExpr); ok {
295
+ recvType = starExpr.X
296
+ }
297
+ if ident, ok := recvType.(*ast.Ident); ok && ident.Name == className {
298
+ c.tsw.WriteLine("")
299
+ if err := c.WriteFuncDeclAsMethod(funcDecl); err != nil {
300
+ return err
301
+ }
302
+ }
303
+ }
304
+ }
305
+
306
+ // Generate getters/setters and wrapper methods for PROMOTED fields/methods from embedded structs
307
+ seenPromotedFields := make(map[string]bool)
308
+ directMethods := make(map[string]bool)
309
+ // Populate directMethods (methods defined directly on this struct type)
310
+ for i := 0; i < goStructType.NumMethods(); i++ {
311
+ method := goStructType.Method(i)
312
+ sig := method.Type().(*types.Signature)
313
+ if sig.Recv() != nil {
314
+ recvType := sig.Recv().Type()
315
+ if namedRecv, ok := recvType.(*types.Named); ok && namedRecv.Obj() == goStructType.Obj() {
316
+ directMethods[method.Name()] = true
317
+ } else if ptrRecv, ok := recvType.(*types.Pointer); ok {
318
+ if namedElem, ok := ptrRecv.Elem().(*types.Named); ok && namedElem.Obj() == goStructType.Obj() {
319
+ directMethods[method.Name()] = true
320
+ }
321
+ }
322
+ }
323
+ }
324
+
325
+ for i := 0; i < underlyingStruct.NumFields(); i++ {
326
+ field := underlyingStruct.Field(i)
327
+ if !field.Anonymous() {
328
+ continue
329
+ }
330
+
331
+ embeddedFieldType := field.Type()
332
+ embeddedFieldKeyName := c.getEmbeddedFieldKeyName(field.Type())
333
+
334
+ // Skip if not a named type (required for proper embedding promotion)
335
+ trueEmbeddedType := embeddedFieldType
336
+ if ptr, isPtr := trueEmbeddedType.(*types.Pointer); isPtr {
337
+ trueEmbeddedType = ptr.Elem()
338
+ }
339
+ if _, isNamed := trueEmbeddedType.(*types.Named); !isNamed {
340
+ continue
341
+ }
342
+
343
+ // Promoted fields
344
+ if namedEmbedded, ok := trueEmbeddedType.(*types.Named); ok {
345
+ if underlyingEmbeddedStruct, ok := namedEmbedded.Underlying().(*types.Struct); ok {
346
+ for j := 0; j < underlyingEmbeddedStruct.NumFields(); j++ {
347
+ promotedField := underlyingEmbeddedStruct.Field(j)
348
+ if !promotedField.Exported() && promotedField.Pkg() != c.pkg.Types {
349
+ continue
350
+ }
351
+ promotedFieldName := promotedField.Name()
352
+ if seenPromotedFields[promotedFieldName] {
353
+ continue
354
+ }
355
+ // Check for conflicts with outer struct's own fields or other promoted fields
356
+ conflict := false
357
+ for k := 0; k < underlyingStruct.NumFields(); k++ {
358
+ if !underlyingStruct.Field(k).Anonymous() && underlyingStruct.Field(k).Name() == promotedFieldName {
359
+ conflict = true
360
+ break
361
+ }
362
+ }
363
+ if conflict {
364
+ continue
365
+ }
366
+
367
+ seenPromotedFields[promotedFieldName] = true
368
+ tsPromotedFieldType := c.getTypeString(promotedField.Type())
369
+ c.tsw.WriteLine("")
370
+ c.tsw.WriteLinef("public get %s(): %s {", promotedFieldName, tsPromotedFieldType)
371
+ c.tsw.Indent(1)
372
+ c.tsw.WriteLinef("return this.%s.%s", embeddedFieldKeyName, promotedFieldName)
373
+ c.tsw.Indent(-1)
374
+ c.tsw.WriteLine("}")
375
+ c.tsw.WriteLinef("public set %s(value: %s) {", promotedFieldName, tsPromotedFieldType)
376
+ c.tsw.Indent(1)
377
+ c.tsw.WriteLinef("this.%s.%s = value", embeddedFieldKeyName, promotedFieldName)
378
+ c.tsw.Indent(-1)
379
+ c.tsw.WriteLine("}")
380
+ }
381
+ }
382
+ }
383
+
384
+ // Promoted methods
385
+ embeddedMethodSet := types.NewMethodSet(embeddedFieldType) // Use original field type for method set
386
+ for k := 0; k < embeddedMethodSet.Len(); k++ {
387
+ methodSelection := embeddedMethodSet.At(k)
388
+ method := methodSelection.Obj().(*types.Func)
389
+ methodName := method.Name()
390
+
391
+ // Skip if it's not a promoted method (indirect) or if it's shadowed by a direct method or an already processed promoted method
392
+ if len(methodSelection.Index()) == 1 && !directMethods[methodName] && !seenPromotedFields[methodName] {
393
+ // Check for conflict with outer struct's own fields
394
+ conflictWithField := false
395
+ for k_idx := 0; k_idx < underlyingStruct.NumFields(); k_idx++ {
396
+ if !underlyingStruct.Field(k_idx).Anonymous() && underlyingStruct.Field(k_idx).Name() == methodName {
397
+ conflictWithField = true
398
+ break
399
+ }
400
+ }
401
+ if conflictWithField {
402
+ continue
403
+ }
404
+
405
+ seenPromotedFields[methodName] = true // Mark as handled to avoid duplicates from other embeddings
406
+ sig := method.Type().(*types.Signature)
407
+ c.tsw.WriteLine("")
408
+ c.tsw.WriteLiterally("public ")
409
+ c.tsw.WriteLiterally(methodName)
410
+ c.tsw.WriteLiterally("(")
411
+ params := sig.Params()
412
+ paramNames := make([]string, params.Len())
413
+ for j := 0; j < params.Len(); j++ {
414
+ param := params.At(j)
415
+ paramName := param.Name()
416
+ if paramName == "" || paramName == "_" {
417
+ paramName = fmt.Sprintf("_p%d", j)
418
+ }
419
+ paramNames[j] = paramName
420
+ if j > 0 {
421
+ c.tsw.WriteLiterally(", ")
422
+ }
423
+ c.tsw.WriteLiterally(paramName)
424
+ c.tsw.WriteLiterally(": ")
425
+ c.WriteGoType(param.Type())
426
+ }
427
+ c.tsw.WriteLiterally(")")
428
+ results := sig.Results()
429
+ if results.Len() > 0 {
430
+ c.tsw.WriteLiterally(": ")
431
+ if results.Len() == 1 {
432
+ c.WriteGoType(results.At(0).Type())
433
+ } else {
434
+ c.tsw.WriteLiterally("[")
435
+ for j := 0; j < results.Len(); j++ {
436
+ if j > 0 {
437
+ c.tsw.WriteLiterally(", ")
438
+ }
439
+ c.WriteGoType(results.At(j).Type())
440
+ }
441
+ c.tsw.WriteLiterally("]")
442
+ }
443
+ } else {
444
+ c.tsw.WriteLiterally(": void")
445
+ }
446
+ c.tsw.WriteLine(" {")
447
+ c.tsw.Indent(1)
448
+ if results.Len() > 0 {
449
+ c.tsw.WriteLiterally("return ")
450
+ }
451
+ c.tsw.WriteLiterallyf("this.%s.%s(%s)", embeddedFieldKeyName, methodName, strings.Join(paramNames, ", "))
452
+ c.tsw.WriteLine("")
453
+ c.tsw.Indent(-1)
454
+ c.tsw.WriteLine("}")
455
+ }
456
+ }
457
+ }
458
+
459
+ // Add code to register the type with the runtime system
460
+ c.tsw.WriteLine("")
461
+ c.tsw.WriteLinef("// Register this type with the runtime type system")
462
+ c.tsw.WriteLinef("static __typeInfo = $.registerStructType(")
463
+ c.tsw.WriteLinef(" '%s',", className)
464
+ c.tsw.WriteLinef(" new %s(),", className)
465
+ c.tsw.WriteLinef(" new Set([%s]),", c.collectMethodNames(className)) // collectMethodNames should ideally consider promoted methods too
466
+ c.tsw.WriteLinef(" %s", className)
467
+ c.tsw.WriteLinef(");")
468
+
469
+ c.tsw.Indent(-1)
470
+ c.tsw.WriteLine("}")
471
+ return nil
472
+ }
473
+
474
+ // WriteInterfaceTypeSpec writes the TypeScript type for a Go interface type.
475
+ func (c *GoToTSCompiler) WriteInterfaceTypeSpec(a *ast.TypeSpec, t *ast.InterfaceType) error {
476
+ c.tsw.WriteLiterally("type ")
477
+ if err := c.WriteValueExpr(a.Name); err != nil {
478
+ return err
479
+ }
480
+ c.tsw.WriteLiterally(" = ")
481
+ // Get the types.Interface from the ast.InterfaceType.
482
+ // For an interface definition like `type MyInterface interface { M() }`,
483
+ // 't' is the *ast.InterfaceType representing `interface { M() }`.
484
+ // TypesInfo.TypeOf(t) will give the *types.Interface.
485
+ goType := c.pkg.TypesInfo.TypeOf(t)
486
+ if goType == nil {
487
+ return errors.Errorf("could not get type for interface AST node for %s", a.Name.Name)
488
+ }
489
+ ifaceType, ok := goType.(*types.Interface)
490
+ if !ok {
491
+ return errors.Errorf("expected *types.Interface, got %T for %s when processing interface literal", goType, a.Name.Name)
492
+ }
493
+ c.WriteInterfaceType(ifaceType, t) // Pass the *ast.InterfaceType for comment fetching
494
+ c.tsw.WriteLine("")
495
+
496
+ // Add code to register the interface with the runtime system
497
+ interfaceName := a.Name.Name
498
+ c.tsw.WriteLine("")
499
+ c.tsw.WriteLinef("$.registerInterfaceType(")
500
+ c.tsw.WriteLinef(" '%s',", interfaceName)
501
+ c.tsw.WriteLinef(" null, // Zero value for interface is null")
502
+ c.tsw.WriteLinef(" new Set([%s]),", c.collectInterfaceMethods(t))
503
+ c.tsw.WriteLinef(");")
504
+
505
+ return nil
506
+ }
@@ -81,6 +81,17 @@ func (w *TSCodeWriter) WriteLiterally(literal string) {
81
81
  w.w.Write([]byte(literal)) //nolint:errcheck
82
82
  }
83
83
 
84
+ // WriteLiterallyf writes something to the output with formatting.
85
+ func (w *TSCodeWriter) WriteLiterallyf(literal string, args ...any) {
86
+ w.sectionWrittenFlag = true
87
+ if w.lineWritten {
88
+ w.WriteLinePreamble()
89
+ }
90
+
91
+ l := fmt.Sprintf(literal, args...)
92
+ w.w.Write([]byte(l)) //nolint:errcheck
93
+ }
94
+
84
95
  // WriteSectionTail writes the end of a section.
85
96
  func (w *TSCodeWriter) WriteSectionTail() {
86
97
  if w.sectionWrittenFlag {