goscript 0.0.14 → 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/README.md +154 -40
- package/builtin/builtin.ts +1168 -178
- 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/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 +845 -144
- package/dist/builtin/builtin.js.map +1 -1
- package/go.mod +4 -5
- package/go.sum +6 -11
- package/package.json +4 -3
- 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
|
@@ -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
|
-
}
|
package/compiler/compile_spec.go
DELETED
|
@@ -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
|
-
}
|