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.
- package/LICENSE +2 -1
- package/README.md +163 -45
- package/builtin/builtin.ts +1169 -178
- package/cmd/goscript/cmd_compile.go +2 -2
- package/compiler/analysis.go +726 -0
- package/compiler/compiler.go +5701 -4
- package/compiler/compiler_test.go +104 -0
- package/compiler/config.go +3 -3
- package/compiler/config_test.go +89 -0
- package/compiler/index.ts +1 -1
- package/compiler/output.go +26 -0
- package/compiler/write-type-spec.go +506 -0
- package/compiler/writer.go +11 -0
- package/dist/builtin/builtin.d.ts +204 -67
- package/dist/builtin/builtin.js +846 -144
- package/dist/builtin/builtin.js.map +1 -1
- package/dist/compiler/index.d.ts +1 -1
- package/go.mod +5 -6
- package/go.sum +6 -11
- package/package.json +21 -5
- package/compiler/compile.go +0 -190
- package/compiler/compile_comment.go +0 -41
- package/compiler/compile_decls.go +0 -84
- package/compiler/compile_expr.go +0 -1022
- package/compiler/compile_field.go +0 -110
- package/compiler/compile_spec.go +0 -566
- package/compiler/compile_stmt.go +0 -1616
- package/compiler/context.go +0 -9
- package/compiler/file_compiler.go +0 -80
- package/compiler/output_path.go +0 -31
- package/compiler/pkg_compiler.go +0 -72
- package/compiler/types/tokens.go +0 -66
- package/compiler/types/types.go +0 -46
- package/dist/compliance/tests/array_literal/array_literal.gs.d.ts +0 -1
- package/dist/compliance/tests/array_literal/array_literal.gs.js +0 -15
- package/dist/compliance/tests/array_literal/array_literal.gs.js.map +0 -1
- package/dist/compliance/tests/async_basic/async_basic.gs.d.ts +0 -1
- package/dist/compliance/tests/async_basic/async_basic.gs.js +0 -24
- package/dist/compliance/tests/async_basic/async_basic.gs.js.map +0 -1
- package/dist/compliance/tests/async_defer_statement/async_defer_statement.gs.d.ts +0 -1
- package/dist/compliance/tests/async_defer_statement/async_defer_statement.gs.js +0 -82
- package/dist/compliance/tests/async_defer_statement/async_defer_statement.gs.js.map +0 -1
- package/dist/compliance/tests/basic_arithmetic/basic_arithmetic.gs.d.ts +0 -1
- package/dist/compliance/tests/basic_arithmetic/basic_arithmetic.gs.js +0 -16
- package/dist/compliance/tests/basic_arithmetic/basic_arithmetic.gs.js.map +0 -1
- package/dist/compliance/tests/boolean_logic/boolean_logic.gs.d.ts +0 -1
- package/dist/compliance/tests/boolean_logic/boolean_logic.gs.js +0 -14
- package/dist/compliance/tests/boolean_logic/boolean_logic.gs.js.map +0 -1
- package/dist/compliance/tests/channel_basic/channel_basic.gs.d.ts +0 -1
- package/dist/compliance/tests/channel_basic/channel_basic.gs.js +0 -14
- package/dist/compliance/tests/channel_basic/channel_basic.gs.js.map +0 -1
- package/dist/compliance/tests/composite_literal_assignment/composite_literal_assignment.gs.d.ts +0 -1
- package/dist/compliance/tests/composite_literal_assignment/composite_literal_assignment.gs.js +0 -27
- package/dist/compliance/tests/composite_literal_assignment/composite_literal_assignment.gs.js.map +0 -1
- package/dist/compliance/tests/constants/constants.gs.d.ts +0 -1
- package/dist/compliance/tests/constants/constants.gs.js +0 -16
- package/dist/compliance/tests/constants/constants.gs.js.map +0 -1
- package/dist/compliance/tests/copy_independence/copy_independence.gs.d.ts +0 -1
- package/dist/compliance/tests/copy_independence/copy_independence.gs.js +0 -33
- package/dist/compliance/tests/copy_independence/copy_independence.gs.js.map +0 -1
- package/dist/compliance/tests/defer_statement/defer_statement.gs.d.ts +0 -1
- package/dist/compliance/tests/defer_statement/defer_statement.gs.js +0 -75
- package/dist/compliance/tests/defer_statement/defer_statement.gs.js.map +0 -1
- package/dist/compliance/tests/embedded_interface_assertion/embedded_interface_assertion.gs.d.ts +0 -1
- package/dist/compliance/tests/embedded_interface_assertion/embedded_interface_assertion.gs.js +0 -37
- package/dist/compliance/tests/embedded_interface_assertion/embedded_interface_assertion.gs.js.map +0 -1
- package/dist/compliance/tests/flag_bitwise_op/flag_bitwise_op.gs.d.ts +0 -1
- package/dist/compliance/tests/flag_bitwise_op/flag_bitwise_op.gs.js +0 -29
- package/dist/compliance/tests/flag_bitwise_op/flag_bitwise_op.gs.js.map +0 -1
- package/dist/compliance/tests/float64/float64.gs.d.ts +0 -1
- package/dist/compliance/tests/float64/float64.gs.js +0 -24
- package/dist/compliance/tests/float64/float64.gs.js.map +0 -1
- package/dist/compliance/tests/for_loop_basic/for_loop_basic.gs.d.ts +0 -1
- package/dist/compliance/tests/for_loop_basic/for_loop_basic.gs.js +0 -10
- package/dist/compliance/tests/for_loop_basic/for_loop_basic.gs.js.map +0 -1
- package/dist/compliance/tests/for_loop_condition_only/for_loop_condition_only.gs.d.ts +0 -1
- package/dist/compliance/tests/for_loop_condition_only/for_loop_condition_only.gs.js +0 -11
- package/dist/compliance/tests/for_loop_condition_only/for_loop_condition_only.gs.js.map +0 -1
- package/dist/compliance/tests/for_loop_condition_only/main.gs.d.ts +0 -1
- package/dist/compliance/tests/for_loop_condition_only/main.gs.js +0 -10
- package/dist/compliance/tests/for_loop_condition_only/main.gs.js.map +0 -1
- package/dist/compliance/tests/for_loop_infinite/for_loop_infinite.gs.d.ts +0 -1
- package/dist/compliance/tests/for_loop_infinite/for_loop_infinite.gs.js +0 -14
- package/dist/compliance/tests/for_loop_infinite/for_loop_infinite.gs.js.map +0 -1
- package/dist/compliance/tests/for_range/for_range.gs.d.ts +0 -1
- package/dist/compliance/tests/for_range/for_range.gs.js +0 -39
- package/dist/compliance/tests/for_range/for_range.gs.js.map +0 -1
- package/dist/compliance/tests/for_range_index_use/for_range_index_use.gs.d.ts +0 -1
- package/dist/compliance/tests/for_range_index_use/for_range_index_use.gs.js +0 -15
- package/dist/compliance/tests/for_range_index_use/for_range_index_use.gs.js.map +0 -1
- package/dist/compliance/tests/func_literal/func_literal.gs.d.ts +0 -1
- package/dist/compliance/tests/func_literal/func_literal.gs.js +0 -10
- package/dist/compliance/tests/func_literal/func_literal.gs.js.map +0 -1
- package/dist/compliance/tests/function_call_result_assignment/function_call_result_assignment.gs.d.ts +0 -12
- package/dist/compliance/tests/function_call_result_assignment/function_call_result_assignment.gs.js +0 -30
- package/dist/compliance/tests/function_call_result_assignment/function_call_result_assignment.gs.js.map +0 -1
- package/dist/compliance/tests/if_statement/if_statement.gs.d.ts +0 -1
- package/dist/compliance/tests/if_statement/if_statement.gs.js +0 -13
- package/dist/compliance/tests/if_statement/if_statement.gs.js.map +0 -1
- package/dist/compliance/tests/interface_method_comments/interface_method_comments.gs.d.ts +0 -1
- package/dist/compliance/tests/interface_method_comments/interface_method_comments.gs.js +0 -12
- package/dist/compliance/tests/interface_method_comments/interface_method_comments.gs.js.map +0 -1
- package/dist/compliance/tests/interface_multi_param_return/interface_multi_param_return.gs.d.ts +0 -1
- package/dist/compliance/tests/interface_multi_param_return/interface_multi_param_return.gs.js +0 -34
- package/dist/compliance/tests/interface_multi_param_return/interface_multi_param_return.gs.js.map +0 -1
- package/dist/compliance/tests/interface_to_interface_type_assertion/interface_to_interface_type_assertion.gs.d.ts +0 -1
- package/dist/compliance/tests/interface_to_interface_type_assertion/interface_to_interface_type_assertion.gs.js +0 -32
- package/dist/compliance/tests/interface_to_interface_type_assertion/interface_to_interface_type_assertion.gs.js.map +0 -1
- package/dist/compliance/tests/interface_type_assertion/interface_type_assertion.gs.d.ts +0 -1
- package/dist/compliance/tests/interface_type_assertion/interface_type_assertion.gs.js +0 -40
- package/dist/compliance/tests/interface_type_assertion/interface_type_assertion.gs.js.map +0 -1
- package/dist/compliance/tests/interface_type_assertion_signature_mismatch/interface_type_assertion_signature_mismatch.gs.d.ts +0 -1
- package/dist/compliance/tests/interface_type_assertion_signature_mismatch/interface_type_assertion_signature_mismatch.gs.js +0 -51
- package/dist/compliance/tests/interface_type_assertion_signature_mismatch/interface_type_assertion_signature_mismatch.gs.js.map +0 -1
- package/dist/compliance/tests/map_support/map_support.gs.d.ts +0 -1
- package/dist/compliance/tests/map_support/map_support.gs.js +0 -88
- package/dist/compliance/tests/map_support/map_support.gs.js.map +0 -1
- package/dist/compliance/tests/method_call_on_pointer_receiver/method_call_on_pointer_receiver.gs.d.ts +0 -1
- package/dist/compliance/tests/method_call_on_pointer_receiver/method_call_on_pointer_receiver.gs.js +0 -24
- package/dist/compliance/tests/method_call_on_pointer_receiver/method_call_on_pointer_receiver.gs.js.map +0 -1
- package/dist/compliance/tests/method_call_on_pointer_via_value/method_call_on_pointer_via_value.gs.d.ts +0 -1
- package/dist/compliance/tests/method_call_on_pointer_via_value/method_call_on_pointer_via_value.gs.js +0 -33
- package/dist/compliance/tests/method_call_on_pointer_via_value/method_call_on_pointer_via_value.gs.js.map +0 -1
- package/dist/compliance/tests/method_call_on_value_receiver/method_call_on_value_receiver.gs.d.ts +0 -1
- package/dist/compliance/tests/method_call_on_value_receiver/method_call_on_value_receiver.gs.js +0 -22
- package/dist/compliance/tests/method_call_on_value_receiver/method_call_on_value_receiver.gs.js.map +0 -1
- package/dist/compliance/tests/method_call_on_value_via_pointer/method_call_on_value_via_pointer.gs.d.ts +0 -1
- package/dist/compliance/tests/method_call_on_value_via_pointer/method_call_on_value_via_pointer.gs.js +0 -33
- package/dist/compliance/tests/method_call_on_value_via_pointer/method_call_on_value_via_pointer.gs.js.map +0 -1
- package/dist/compliance/tests/multiple_return_values/multiple_return_values.gs.d.ts +0 -1
- package/dist/compliance/tests/multiple_return_values/multiple_return_values.gs.js +0 -17
- package/dist/compliance/tests/multiple_return_values/multiple_return_values.gs.js.map +0 -1
- package/dist/compliance/tests/pointer_assignment_no_copy/pointer_assignment_no_copy.gs.d.ts +0 -1
- package/dist/compliance/tests/pointer_assignment_no_copy/pointer_assignment_no_copy.gs.js +0 -29
- package/dist/compliance/tests/pointer_assignment_no_copy/pointer_assignment_no_copy.gs.js.map +0 -1
- package/dist/compliance/tests/pointer_composite_literal_assignment/pointer_composite_literal_assignment.gs.d.ts +0 -1
- package/dist/compliance/tests/pointer_composite_literal_assignment/pointer_composite_literal_assignment.gs.js +0 -27
- package/dist/compliance/tests/pointer_composite_literal_assignment/pointer_composite_literal_assignment.gs.js.map +0 -1
- package/dist/compliance/tests/pointer_deref_multiassign/pointer_deref_multiassign.gs.d.ts +0 -1
- package/dist/compliance/tests/pointer_deref_multiassign/pointer_deref_multiassign.gs.js +0 -22
- package/dist/compliance/tests/pointer_deref_multiassign/pointer_deref_multiassign.gs.js.map +0 -1
- package/dist/compliance/tests/pointer_initialization/pointer_initialization.gs.d.ts +0 -1
- package/dist/compliance/tests/pointer_initialization/pointer_initialization.gs.js +0 -20
- package/dist/compliance/tests/pointer_initialization/pointer_initialization.gs.js.map +0 -1
- package/dist/compliance/tests/select_receive_on_closed_channel_no_default/select_receive_on_closed_channel_no_default.gs.d.ts +0 -1
- package/dist/compliance/tests/select_receive_on_closed_channel_no_default/select_receive_on_closed_channel_no_default.gs.js +0 -28
- package/dist/compliance/tests/select_receive_on_closed_channel_no_default/select_receive_on_closed_channel_no_default.gs.js.map +0 -1
- 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
- package/dist/compliance/tests/select_send_on_full_buffered_channel_with_default/select_send_on_full_buffered_channel_with_default.gs.js +0 -30
- 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
- package/dist/compliance/tests/select_statement/select_statement.gs.d.ts +0 -1
- package/dist/compliance/tests/select_statement/select_statement.gs.js +0 -207
- package/dist/compliance/tests/select_statement/select_statement.gs.js.map +0 -1
- package/dist/compliance/tests/simple/simple.gs.d.ts +0 -1
- package/dist/compliance/tests/simple/simple.gs.js +0 -6
- package/dist/compliance/tests/simple/simple.gs.js.map +0 -1
- package/dist/compliance/tests/simple_deref_assignment/simple_deref_assignment.gs.d.ts +0 -1
- package/dist/compliance/tests/simple_deref_assignment/simple_deref_assignment.gs.js +0 -24
- package/dist/compliance/tests/simple_deref_assignment/simple_deref_assignment.gs.js.map +0 -1
- package/dist/compliance/tests/slices/slices.gs.d.ts +0 -1
- package/dist/compliance/tests/slices/slices.gs.js +0 -294
- package/dist/compliance/tests/slices/slices.gs.js.map +0 -1
- package/dist/compliance/tests/string_conversion/string_conversion.gs.d.ts +0 -1
- package/dist/compliance/tests/string_conversion/string_conversion.gs.js +0 -41
- package/dist/compliance/tests/string_conversion/string_conversion.gs.js.map +0 -1
- package/dist/compliance/tests/string_rune_conversion/string_rune_conversion.gs.d.ts +0 -1
- package/dist/compliance/tests/string_rune_conversion/string_rune_conversion.gs.js +0 -17
- package/dist/compliance/tests/string_rune_conversion/string_rune_conversion.gs.js.map +0 -1
- package/dist/compliance/tests/struct_embedding/struct_embedding.gs.d.ts +0 -1
- package/dist/compliance/tests/struct_embedding/struct_embedding.gs.js +0 -48
- package/dist/compliance/tests/struct_embedding/struct_embedding.gs.js.map +0 -1
- package/dist/compliance/tests/struct_field_access/struct_field_access.gs.d.ts +0 -1
- package/dist/compliance/tests/struct_field_access/struct_field_access.gs.js +0 -19
- package/dist/compliance/tests/struct_field_access/struct_field_access.gs.js.map +0 -1
- package/dist/compliance/tests/struct_pointer_interface_fields/struct_pointer_interface_fields.gs.d.ts +0 -1
- package/dist/compliance/tests/struct_pointer_interface_fields/struct_pointer_interface_fields.gs.js +0 -26
- package/dist/compliance/tests/struct_pointer_interface_fields/struct_pointer_interface_fields.gs.js.map +0 -1
- package/dist/compliance/tests/struct_value_init_clone/struct_value_init_clone.gs.d.ts +0 -1
- package/dist/compliance/tests/struct_value_init_clone/struct_value_init_clone.gs.js +0 -30
- package/dist/compliance/tests/struct_value_init_clone/struct_value_init_clone.gs.js.map +0 -1
- package/dist/compliance/tests/switch_statement/switch_statement.gs.d.ts +0 -1
- package/dist/compliance/tests/switch_statement/switch_statement.gs.js +0 -76
- package/dist/compliance/tests/switch_statement/switch_statement.gs.js.map +0 -1
- package/dist/compliance/tests/value_type_copy_behavior/value_type_copy_behavior.gs.d.ts +0 -1
- package/dist/compliance/tests/value_type_copy_behavior/value_type_copy_behavior.gs.js +0 -31
- 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
|
+
}
|
package/compiler/writer.go
CHANGED
|
@@ -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 {
|