goscript 0.0.83 → 0.1.0
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 +13 -1
- package/cmd/goscript/cmd_compile.go +70 -69
- package/cmd/goscript/cmd_compile_test.go +79 -0
- package/cmd/goscript/main.go +10 -5
- package/compiler/compile-request.go +218 -0
- package/compiler/compiler.go +16 -1336
- package/compiler/compliance_test.go +196 -0
- package/compiler/config.go +6 -13
- package/compiler/diagnostic.go +70 -0
- package/compiler/index.test.ts +28 -28
- package/compiler/index.ts +40 -72
- package/compiler/lowered-program.go +132 -0
- package/compiler/lowering.go +3576 -0
- package/compiler/override-registry.go +422 -0
- package/compiler/override-registry_test.go +207 -0
- package/compiler/package-graph.go +231 -0
- package/compiler/package-graph_test.go +281 -0
- package/compiler/result.go +13 -0
- package/compiler/runtime-contract.go +279 -0
- package/compiler/runtime-contract_test.go +90 -0
- package/compiler/semantic-model-types.go +110 -0
- package/compiler/semantic-model.go +922 -0
- package/compiler/semantic-model_test.go +416 -0
- package/compiler/service.go +133 -0
- package/compiler/skeleton_test.go +1145 -0
- package/compiler/typescript-emitter.go +663 -0
- package/compiler/wasm/compile.go +2 -3
- package/compiler/wasm/compile_test.go +29 -0
- package/compiler/wasm_api.go +10 -159
- package/dist/compiler/index.d.ts +1 -3
- package/dist/compiler/index.js +31 -55
- package/dist/compiler/index.js.map +1 -1
- package/dist/gs/builtin/builtin.d.ts +13 -0
- package/dist/gs/builtin/builtin.js +27 -7
- package/dist/gs/builtin/builtin.js.map +1 -1
- package/dist/gs/builtin/channel.d.ts +3 -3
- package/dist/gs/builtin/channel.js.map +1 -1
- package/dist/gs/builtin/hostio.d.ts +86 -0
- package/dist/gs/builtin/hostio.js +266 -0
- package/dist/gs/builtin/hostio.js.map +1 -0
- package/dist/gs/builtin/index.d.ts +1 -0
- package/dist/gs/builtin/index.js +1 -0
- package/dist/gs/builtin/index.js.map +1 -1
- package/dist/gs/builtin/print.d.ts +8 -0
- package/dist/gs/builtin/print.js +111 -0
- package/dist/gs/builtin/print.js.map +1 -0
- package/dist/gs/builtin/slice.d.ts +1 -1
- package/dist/gs/builtin/slice.js.map +1 -1
- package/dist/gs/builtin/type.d.ts +11 -0
- package/dist/gs/builtin/type.js +55 -1
- package/dist/gs/builtin/type.js.map +1 -1
- package/dist/gs/bytes/buffer.gs.js.map +1 -1
- package/dist/gs/bytes/bytes.gs.js.map +1 -1
- package/dist/gs/bytes/reader.gs.js.map +1 -1
- package/dist/gs/context/context.js.map +1 -1
- package/dist/gs/crypto/rand/index.d.ts +5 -0
- package/dist/gs/crypto/rand/index.js +77 -0
- package/dist/gs/crypto/rand/index.js.map +1 -0
- package/dist/gs/encoding/json/index.d.ts +3 -0
- package/dist/gs/encoding/json/index.js +160 -0
- package/dist/gs/encoding/json/index.js.map +1 -0
- package/dist/gs/fmt/fmt.js +2 -22
- package/dist/gs/fmt/fmt.js.map +1 -1
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.d.ts +1 -1
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js +1 -1
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js.map +1 -1
- package/dist/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/browser.js.map +1 -1
- package/dist/gs/github.com/pkg/errors/errors.js.map +1 -1
- package/dist/gs/github.com/pkg/errors/stack.js.map +1 -1
- package/dist/gs/go/scanner/index.d.ts +29 -0
- package/dist/gs/go/scanner/index.js +120 -0
- package/dist/gs/go/scanner/index.js.map +1 -0
- package/dist/gs/go/token/index.d.ts +31 -0
- package/dist/gs/go/token/index.js +82 -0
- package/dist/gs/go/token/index.js.map +1 -0
- package/dist/gs/internal/abi/index.js.map +1 -1
- package/dist/gs/io/fs/fs.js.map +1 -1
- package/dist/gs/io/fs/readdir.js.map +1 -1
- package/dist/gs/io/fs/readfile.js.map +1 -1
- package/dist/gs/io/fs/stat.js.map +1 -1
- package/dist/gs/io/fs/sub.js.map +1 -1
- package/dist/gs/io/io.js.map +1 -1
- package/dist/gs/os/dir_unix.gs.js.map +1 -1
- package/dist/gs/os/error.gs.js +2 -4
- package/dist/gs/os/error.gs.js.map +1 -1
- package/dist/gs/os/exec.gs.js.map +1 -1
- package/dist/gs/os/exec_posix.gs.js.map +1 -1
- package/dist/gs/os/rawconn_js.gs.js.map +1 -1
- package/dist/gs/os/root_js.gs.js.map +1 -1
- package/dist/gs/os/tempfile.gs.js +66 -9
- package/dist/gs/os/tempfile.gs.js.map +1 -1
- package/dist/gs/os/types.gs.js.map +1 -1
- package/dist/gs/os/types_js.gs.d.ts +2 -51
- package/dist/gs/os/types_js.gs.js +67 -105
- package/dist/gs/os/types_js.gs.js.map +1 -1
- package/dist/gs/os/types_unix.gs.js.map +1 -1
- package/dist/gs/path/filepath/match.js.map +1 -1
- package/dist/gs/path/match.js.map +1 -1
- package/dist/gs/path/path.js.map +1 -1
- package/dist/gs/reflect/index.d.ts +2 -2
- package/dist/gs/reflect/index.js +1 -1
- package/dist/gs/reflect/index.js.map +1 -1
- package/dist/gs/reflect/map.js.map +1 -1
- package/dist/gs/reflect/type.d.ts +2 -1
- package/dist/gs/reflect/type.js +85 -14
- package/dist/gs/reflect/type.js.map +1 -1
- package/dist/gs/reflect/types.js.map +1 -1
- package/dist/gs/reflect/visiblefields.js.map +1 -1
- package/dist/gs/runtime/runtime.js.map +1 -1
- package/dist/gs/sort/sort.gs.js.map +1 -1
- package/dist/gs/strconv/atoi.gs.js.map +1 -1
- package/dist/gs/strconv/quote.gs.js.map +1 -1
- package/dist/gs/strings/builder.js.map +1 -1
- package/dist/gs/strings/reader.js.map +1 -1
- package/dist/gs/strings/replace.js.map +1 -1
- package/dist/gs/sync/atomic/type.gs.js.map +1 -1
- package/dist/gs/sync/atomic/value.gs.js.map +1 -1
- package/dist/gs/sync/sync.d.ts +1 -0
- package/dist/gs/sync/sync.js +12 -0
- package/dist/gs/sync/sync.js.map +1 -1
- package/dist/gs/time/time.js.map +1 -1
- package/dist/gs/unicode/unicode.js.map +1 -1
- package/go.mod +2 -2
- package/gs/builtin/builtin.ts +31 -6
- package/gs/builtin/hostio.test.ts +246 -0
- package/gs/builtin/hostio.ts +413 -0
- package/gs/builtin/index.ts +1 -0
- package/gs/builtin/print.test.ts +48 -0
- package/gs/builtin/print.ts +154 -0
- package/gs/builtin/runtime-contract.test.ts +230 -0
- package/gs/builtin/type.ts +84 -1
- package/gs/crypto/rand/index.test.ts +32 -0
- package/gs/crypto/rand/index.ts +90 -0
- package/gs/crypto/rand/meta.json +5 -0
- package/gs/encoding/json/index.test.ts +65 -0
- package/gs/encoding/json/index.ts +186 -0
- package/gs/fmt/fmt.test.ts +41 -30
- package/gs/fmt/fmt.ts +2 -22
- package/gs/github.com/aperturerobotics/protobuf-go-lite/index.test.ts +23 -0
- package/gs/github.com/aperturerobotics/protobuf-go-lite/index.ts +3 -1
- package/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/meta.json +3 -1
- package/gs/go/scanner/index.test.ts +50 -0
- package/gs/go/scanner/index.ts +157 -0
- package/gs/go/token/index.test.ts +21 -0
- package/gs/go/token/index.ts +120 -0
- package/gs/os/file_unix_js.test.ts +103 -0
- package/gs/os/meta.json +1 -2
- package/gs/os/tempfile.gs.test.ts +85 -0
- package/gs/os/tempfile.gs.ts +71 -11
- package/gs/os/types_js.gs.ts +74 -153
- package/gs/reflect/index.ts +1 -1
- package/gs/reflect/type.ts +106 -17
- package/gs/reflect/typefor.test.ts +75 -0
- package/gs/sync/sync.test.ts +24 -0
- package/gs/sync/sync.ts +12 -0
- package/package.json +13 -13
- package/compiler/analysis.go +0 -3475
- package/compiler/analysis_test.go +0 -338
- package/compiler/assignment.go +0 -580
- package/compiler/builtin_test.go +0 -92
- package/compiler/code-writer.go +0 -115
- package/compiler/compiler_test.go +0 -149
- package/compiler/composite-lit.go +0 -779
- package/compiler/config_test.go +0 -62
- package/compiler/constraint.go +0 -86
- package/compiler/decl.go +0 -801
- package/compiler/expr-call-async.go +0 -188
- package/compiler/expr-call-builtins.go +0 -208
- package/compiler/expr-call-helpers.go +0 -382
- package/compiler/expr-call-make.go +0 -318
- package/compiler/expr-call-type-conversion.go +0 -520
- package/compiler/expr-call.go +0 -413
- package/compiler/expr-selector.go +0 -343
- package/compiler/expr-star.go +0 -82
- package/compiler/expr-type.go +0 -442
- package/compiler/expr-value.go +0 -89
- package/compiler/expr.go +0 -773
- package/compiler/field.go +0 -183
- package/compiler/gs_dependencies_test.go +0 -298
- package/compiler/lit.go +0 -322
- package/compiler/output.go +0 -72
- package/compiler/primitive.go +0 -149
- package/compiler/protobuf.go +0 -697
- package/compiler/sanitize.go +0 -100
- package/compiler/spec-struct.go +0 -995
- package/compiler/spec-value.go +0 -540
- package/compiler/spec.go +0 -725
- package/compiler/stmt-assign.go +0 -664
- package/compiler/stmt-for.go +0 -266
- package/compiler/stmt-range.go +0 -475
- package/compiler/stmt-select.go +0 -262
- package/compiler/stmt-type-switch.go +0 -147
- package/compiler/stmt.go +0 -1308
- package/compiler/type-assert.go +0 -386
- package/compiler/type-info.go +0 -156
- package/compiler/type-utils.go +0 -207
- package/compiler/type.go +0 -892
|
@@ -1,520 +0,0 @@
|
|
|
1
|
-
package compiler
|
|
2
|
-
|
|
3
|
-
import (
|
|
4
|
-
"fmt"
|
|
5
|
-
"go/ast"
|
|
6
|
-
"go/token"
|
|
7
|
-
"go/types"
|
|
8
|
-
)
|
|
9
|
-
|
|
10
|
-
// writeNilConversion handles type conversions with nil argument
|
|
11
|
-
func (c *GoToTSCompiler) writeNilConversion(exp *ast.CallExpr) (handled bool, err error) {
|
|
12
|
-
if len(exp.Args) != 1 {
|
|
13
|
-
return false, nil
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
nilIdent, isIdent := exp.Args[0].(*ast.Ident)
|
|
17
|
-
if !isIdent || nilIdent.Name != "nil" {
|
|
18
|
-
return false, nil
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
// Check if this is actually a type conversion, not a method/function call
|
|
22
|
-
// For type conversions, exp.Fun is a type expression (IsType() is true)
|
|
23
|
-
// For method calls like s.ptr.Swap(nil), exp.Fun is a selector expression (IsType() is false)
|
|
24
|
-
if tv, ok := c.pkg.TypesInfo.Types[exp.Fun]; !ok || !tv.IsType() {
|
|
25
|
-
// This is not a type conversion, let the normal call handling proceed
|
|
26
|
-
return false, nil
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// Get the type being converted to
|
|
30
|
-
if typ := c.pkg.TypesInfo.TypeOf(exp.Fun); typ != nil {
|
|
31
|
-
// For pointer types, create a typed nil that preserves type information
|
|
32
|
-
if ptrType, ok := typ.(*types.Pointer); ok {
|
|
33
|
-
// Use a qualifier that returns the package name for local types
|
|
34
|
-
// This matches Go's reflect output format (e.g., "main.Stringer")
|
|
35
|
-
qualifier := func(pkg *types.Package) string {
|
|
36
|
-
if pkg == nil {
|
|
37
|
-
return ""
|
|
38
|
-
}
|
|
39
|
-
return pkg.Name()
|
|
40
|
-
}
|
|
41
|
-
typeName := types.TypeString(ptrType, qualifier)
|
|
42
|
-
c.tsw.WriteLiterallyf("$.typedNil(%q)", typeName)
|
|
43
|
-
return true, nil
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// For non-pointer types (or if type info is unavailable), use plain null
|
|
48
|
-
c.tsw.WriteLiterally("null")
|
|
49
|
-
return true, nil
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// writeArrayTypeConversion handles array type conversions like []rune(string)
|
|
53
|
-
func (c *GoToTSCompiler) writeArrayTypeConversion(exp *ast.CallExpr) (handled bool, err error) {
|
|
54
|
-
arrayType, isArrayType := exp.Fun.(*ast.ArrayType)
|
|
55
|
-
if !isArrayType {
|
|
56
|
-
return false, nil
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Check if it's a []rune type
|
|
60
|
-
if ident, isIdent := arrayType.Elt.(*ast.Ident); isIdent && ident.Name == "rune" {
|
|
61
|
-
// Check if the argument is a string
|
|
62
|
-
if len(exp.Args) == 1 {
|
|
63
|
-
arg := exp.Args[0]
|
|
64
|
-
if tv, ok := c.pkg.TypesInfo.Types[arg]; ok && tv.Type != nil {
|
|
65
|
-
if c.isStringType(tv.Type) {
|
|
66
|
-
// Translate []rune(stringValue) to $.stringToRunes(stringValue)
|
|
67
|
-
c.tsw.WriteLiterally("$.stringToRunes(")
|
|
68
|
-
if err := c.WriteValueExpr(arg); err != nil {
|
|
69
|
-
return true, fmt.Errorf("failed to write argument for []rune(string) conversion: %w", err)
|
|
70
|
-
}
|
|
71
|
-
c.tsw.WriteLiterally(")")
|
|
72
|
-
return true, nil
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// Check if it's a []byte type and the argument is a string
|
|
79
|
-
if eltIdent, ok := arrayType.Elt.(*ast.Ident); ok && eltIdent.Name == "byte" && arrayType.Len == nil {
|
|
80
|
-
if len(exp.Args) == 1 {
|
|
81
|
-
arg := exp.Args[0]
|
|
82
|
-
// Ensure TypesInfo is available and the argument type can be determined
|
|
83
|
-
if tv, typeOk := c.pkg.TypesInfo.Types[arg]; typeOk && tv.Type != nil {
|
|
84
|
-
if c.isStringType(tv.Type) {
|
|
85
|
-
c.tsw.WriteLiterally("$.stringToBytes(")
|
|
86
|
-
if err := c.WriteValueExpr(arg); err != nil {
|
|
87
|
-
return true, fmt.Errorf("failed to write argument for []byte(string) conversion: %w", err)
|
|
88
|
-
}
|
|
89
|
-
c.tsw.WriteLiterally(")")
|
|
90
|
-
return true, nil
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// Handle general slice type conversions like []T(namedType) where namedType has underlying type []T
|
|
97
|
-
if arrayType.Len == nil && len(exp.Args) == 1 {
|
|
98
|
-
arg := exp.Args[0]
|
|
99
|
-
if argType := c.pkg.TypesInfo.TypeOf(arg); argType != nil {
|
|
100
|
-
// Check if the argument is a named type with a slice underlying type
|
|
101
|
-
if namedArgType, isNamed := argType.(*types.Named); isNamed {
|
|
102
|
-
// Check if the named type has receiver methods (is a wrapper type)
|
|
103
|
-
if c.isWrapperType(namedArgType) {
|
|
104
|
-
// Check if the underlying type matches the target slice type
|
|
105
|
-
if sliceUnderlying, isSlice := namedArgType.Underlying().(*types.Slice); isSlice {
|
|
106
|
-
// Get the target slice type
|
|
107
|
-
targetType := c.pkg.TypesInfo.TypeOf(arrayType)
|
|
108
|
-
if targetSliceType, isTargetSlice := targetType.Underlying().(*types.Slice); isTargetSlice {
|
|
109
|
-
// Check if element types are compatible
|
|
110
|
-
if types.Identical(sliceUnderlying.Elem(), targetSliceType.Elem()) {
|
|
111
|
-
// This is a conversion from wrapper slice type to []T
|
|
112
|
-
// Since wrapper types are now type aliases, just write the value directly
|
|
113
|
-
if err := c.WriteValueExpr(arg); err != nil {
|
|
114
|
-
return true, fmt.Errorf("failed to write argument for slice type conversion: %w", err)
|
|
115
|
-
}
|
|
116
|
-
return true, nil
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
return false, nil
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// writeStringConversion handles string() conversion
|
|
129
|
-
func (c *GoToTSCompiler) writeStringConversion(exp *ast.CallExpr) error {
|
|
130
|
-
if len(exp.Args) != 1 {
|
|
131
|
-
return fmt.Errorf("string() conversion expects exactly 1 argument, got %d", len(exp.Args))
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
arg := exp.Args[0]
|
|
135
|
-
|
|
136
|
-
// Case 1: Argument is a string literal string("...")
|
|
137
|
-
if basicLit, isBasicLit := arg.(*ast.BasicLit); isBasicLit && basicLit.Kind == token.STRING {
|
|
138
|
-
// Translate string("...") to "..." (no-op)
|
|
139
|
-
c.WriteBasicLit(basicLit)
|
|
140
|
-
return nil
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
// Case 2: Argument is a rune (int32) or a call to rune()
|
|
144
|
-
innerCall, isCallExpr := arg.(*ast.CallExpr)
|
|
145
|
-
|
|
146
|
-
if isCallExpr {
|
|
147
|
-
// Check if it's a call to rune()
|
|
148
|
-
if innerFunIdent, innerFunIsIdent := innerCall.Fun.(*ast.Ident); innerFunIsIdent && innerFunIdent.String() == "rune" {
|
|
149
|
-
// Translate string(rune(val)) to $.runeOrStringToString(val)
|
|
150
|
-
if len(innerCall.Args) == 1 {
|
|
151
|
-
c.tsw.WriteLiterally("$.runeOrStringToString(")
|
|
152
|
-
if err := c.WriteValueExpr(innerCall.Args[0]); err != nil {
|
|
153
|
-
return fmt.Errorf("failed to write argument for string(rune) conversion: %w", err)
|
|
154
|
-
}
|
|
155
|
-
c.tsw.WriteLiterally(")")
|
|
156
|
-
return nil
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// Handle direct string(int32) conversion
|
|
162
|
-
if tv, ok := c.pkg.TypesInfo.Types[arg]; ok {
|
|
163
|
-
// Case 3a: Argument is already a string - no-op (unless it's a named type with toString)
|
|
164
|
-
if c.isStringType(tv.Type) {
|
|
165
|
-
// Check if this is a named type from the reflect package (like StructTag)
|
|
166
|
-
// which is implemented as a class in TypeScript with a toString() method
|
|
167
|
-
if namedType, isNamed := tv.Type.(*types.Named); isNamed {
|
|
168
|
-
obj := namedType.Obj()
|
|
169
|
-
if obj != nil && obj.Pkg() != nil && obj.Pkg().Path() == "reflect" && obj.Name() == "StructTag" {
|
|
170
|
-
// Call toString() for reflect.StructTag
|
|
171
|
-
if err := c.WriteValueExpr(arg); err != nil {
|
|
172
|
-
return fmt.Errorf("failed to write argument for string(reflect.StructTag) conversion: %w", err)
|
|
173
|
-
}
|
|
174
|
-
c.tsw.WriteLiterally(".toString()")
|
|
175
|
-
return nil
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
// Translate string(stringValue) to stringValue (no-op)
|
|
179
|
-
if err := c.WriteValueExpr(arg); err != nil {
|
|
180
|
-
return fmt.Errorf("failed to write argument for string(string) no-op conversion: %w", err)
|
|
181
|
-
}
|
|
182
|
-
return nil
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
if basic, isBasic := tv.Type.Underlying().(*types.Basic); isBasic && (basic.Kind() == types.Int32 || basic.Kind() == types.UntypedRune) {
|
|
186
|
-
// Translate string(rune_val) to $.runeOrStringToString(rune_val)
|
|
187
|
-
c.tsw.WriteLiterally("$.runeOrStringToString(")
|
|
188
|
-
if err := c.WriteValueExpr(arg); err != nil {
|
|
189
|
-
return fmt.Errorf("failed to write argument for string(int32) conversion: %w", err)
|
|
190
|
-
}
|
|
191
|
-
c.tsw.WriteLiterally(")")
|
|
192
|
-
return nil
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
if basic, isBasic := tv.Type.Underlying().(*types.Basic); isBasic && basic.Kind() == types.Uint8 {
|
|
196
|
-
// Translate string(byte_val) to $.runeOrStringToString(byte_val)
|
|
197
|
-
c.tsw.WriteLiterally("$.runeOrStringToString(")
|
|
198
|
-
if err := c.WriteValueExpr(arg); err != nil {
|
|
199
|
-
return fmt.Errorf("failed to write argument for string(byte) conversion: %w", err)
|
|
200
|
-
}
|
|
201
|
-
c.tsw.WriteLiterally(")")
|
|
202
|
-
return nil
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
// Case 3: Argument is a slice of runes or bytes string([]rune{...}) or string([]byte{...})
|
|
206
|
-
if c.isByteSliceType(tv.Type) {
|
|
207
|
-
c.tsw.WriteLiterally("$.bytesToString(")
|
|
208
|
-
if err := c.WriteValueExpr(arg); err != nil {
|
|
209
|
-
return fmt.Errorf("failed to write argument for string([]byte) conversion: %w", err)
|
|
210
|
-
}
|
|
211
|
-
c.tsw.WriteLiterally(")")
|
|
212
|
-
return nil
|
|
213
|
-
}
|
|
214
|
-
if c.isRuneSliceType(tv.Type) {
|
|
215
|
-
c.tsw.WriteLiterally("$.runesToString(")
|
|
216
|
-
if err := c.WriteValueExpr(arg); err != nil {
|
|
217
|
-
return fmt.Errorf("failed to write argument for string([]rune) conversion: %w", err)
|
|
218
|
-
}
|
|
219
|
-
c.tsw.WriteLiterally(")")
|
|
220
|
-
return nil
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
// Case 4: Argument is a generic type parameter (e.g., string | []byte)
|
|
224
|
-
if typeParam, isTypeParam := tv.Type.(*types.TypeParam); isTypeParam {
|
|
225
|
-
// Check if this is a []byte | string union constraint precisely
|
|
226
|
-
constraint := typeParam.Constraint()
|
|
227
|
-
if constraint != nil {
|
|
228
|
-
hasString := constraintIncludesString(constraint)
|
|
229
|
-
hasBytes := constraintIncludesByteSlice(constraint)
|
|
230
|
-
|
|
231
|
-
if hasString && hasBytes {
|
|
232
|
-
c.tsw.WriteLiterally("$.genericBytesOrStringToString(")
|
|
233
|
-
if err := c.WriteValueExpr(arg); err != nil {
|
|
234
|
-
return fmt.Errorf("failed to write argument for string(generic union) conversion: %w", err)
|
|
235
|
-
}
|
|
236
|
-
c.tsw.WriteLiterally(")")
|
|
237
|
-
return nil
|
|
238
|
-
}
|
|
239
|
-
if hasString {
|
|
240
|
-
// string(T) where T is constrained to string: no-op
|
|
241
|
-
if err := c.WriteValueExpr(arg); err != nil {
|
|
242
|
-
return fmt.Errorf("failed to write argument for string(string-constrained) conversion: %w", err)
|
|
243
|
-
}
|
|
244
|
-
return nil
|
|
245
|
-
}
|
|
246
|
-
if hasBytes {
|
|
247
|
-
// string(T) where T is constrained to []byte
|
|
248
|
-
c.tsw.WriteLiterally("$.bytesToString(")
|
|
249
|
-
if err := c.WriteValueExpr(arg); err != nil {
|
|
250
|
-
return fmt.Errorf("failed to write argument for string([]byte-constrained) conversion: %w", err)
|
|
251
|
-
}
|
|
252
|
-
c.tsw.WriteLiterally(")")
|
|
253
|
-
return nil
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
// Fallback to previous behavior if we cannot determine precisely
|
|
257
|
-
c.tsw.WriteLiterally("$.genericBytesOrStringToString(")
|
|
258
|
-
if err := c.WriteValueExpr(arg); err != nil {
|
|
259
|
-
return fmt.Errorf("failed to write argument for string(generic fallback) conversion: %w", err)
|
|
260
|
-
}
|
|
261
|
-
c.tsw.WriteLiterally(")")
|
|
262
|
-
return nil
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
// Fallback: when type info is not available (e.g., in WASM context),
|
|
268
|
-
// use a generic conversion that handles both []byte and string
|
|
269
|
-
c.tsw.WriteLiterally("$.genericBytesOrStringToString(")
|
|
270
|
-
if err := c.WriteValueExpr(arg); err != nil {
|
|
271
|
-
return fmt.Errorf("failed to write argument for string(unknown type) conversion: %w", err)
|
|
272
|
-
}
|
|
273
|
-
c.tsw.WriteLiterally(")")
|
|
274
|
-
return nil
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
// handleTypeConversionCommon contains the shared logic for type conversions
|
|
278
|
-
func (c *GoToTSCompiler) handleTypeConversionCommon(
|
|
279
|
-
typeName *types.TypeName,
|
|
280
|
-
arg ast.Expr,
|
|
281
|
-
typeNameStr string,
|
|
282
|
-
writeTypeNameFunc func() error,
|
|
283
|
-
) error {
|
|
284
|
-
// Check if we're converting FROM a type with receiver methods TO its underlying type
|
|
285
|
-
if argType := c.pkg.TypesInfo.TypeOf(arg); argType != nil {
|
|
286
|
-
if namedArgType, isNamed := argType.(*types.Named); isNamed {
|
|
287
|
-
// Check if the argument type is a wrapper type
|
|
288
|
-
if c.isWrapperType(namedArgType) {
|
|
289
|
-
// Check if we're converting to the underlying type
|
|
290
|
-
targetType := typeName.Type()
|
|
291
|
-
underlyingType := namedArgType.Underlying()
|
|
292
|
-
if types.Identical(targetType, underlyingType) {
|
|
293
|
-
// This is a conversion from a wrapper type to its underlying type
|
|
294
|
-
// Since wrapper types are now type aliases, just write the value directly
|
|
295
|
-
return c.WriteValueExpr(arg)
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
// Check if this is a function type
|
|
302
|
-
if _, isFuncType := typeName.Type().Underlying().(*types.Signature); isFuncType {
|
|
303
|
-
// For function types, we need to add a __goTypeName property
|
|
304
|
-
c.tsw.WriteLiterally("Object.assign(")
|
|
305
|
-
|
|
306
|
-
// Write the argument first
|
|
307
|
-
if err := c.WriteValueExpr(arg); err != nil {
|
|
308
|
-
return fmt.Errorf("failed to write argument for function type cast: %w", err)
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
// Add the __goTypeName property with the function type name
|
|
312
|
-
c.tsw.WriteLiterallyf(", { __goTypeName: '%s' })", typeNameStr)
|
|
313
|
-
return nil
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
// Check if this is a wrapper type
|
|
317
|
-
if c.isWrapperType(typeName.Type()) {
|
|
318
|
-
// For wrapper types, use type casting instead of constructor calls
|
|
319
|
-
c.tsw.WriteLiterally("(")
|
|
320
|
-
if err := c.WriteValueExpr(arg); err != nil {
|
|
321
|
-
return fmt.Errorf("failed to write argument for wrapper type cast: %w", err)
|
|
322
|
-
}
|
|
323
|
-
c.tsw.WriteLiterally(" as ")
|
|
324
|
-
c.WriteGoType(typeName.Type(), GoTypeContextGeneral)
|
|
325
|
-
c.tsw.WriteLiterally(")")
|
|
326
|
-
return nil
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
// Check if this is a simple named type (no methods, not struct, not interface)
|
|
330
|
-
if namedType, ok := typeName.Type().(*types.Named); ok {
|
|
331
|
-
// Don't use constructors for simple named types without methods
|
|
332
|
-
if namedType.NumMethods() == 0 {
|
|
333
|
-
// Exclude struct and interface types - they should still use constructors
|
|
334
|
-
if _, isStruct := namedType.Underlying().(*types.Struct); !isStruct {
|
|
335
|
-
if _, isInterface := namedType.Underlying().(*types.Interface); !isInterface {
|
|
336
|
-
// Simple named type without methods - use type casting
|
|
337
|
-
c.tsw.WriteLiterally("(")
|
|
338
|
-
if err := c.WriteValueExpr(arg); err != nil {
|
|
339
|
-
return fmt.Errorf("failed to write argument for simple named type cast: %w", err)
|
|
340
|
-
}
|
|
341
|
-
c.tsw.WriteLiterally(" as ")
|
|
342
|
-
c.WriteGoType(typeName.Type(), GoTypeContextGeneral)
|
|
343
|
-
c.tsw.WriteLiterally(")")
|
|
344
|
-
return nil
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
// Check if this type has receiver methods
|
|
351
|
-
if c.hasReceiverMethods(typeNameStr) {
|
|
352
|
-
// For types with methods that are NOT wrapper types, still use class constructor
|
|
353
|
-
c.tsw.WriteLiterally("new ")
|
|
354
|
-
if err := writeTypeNameFunc(); err != nil {
|
|
355
|
-
return fmt.Errorf("failed to write type name: %w", err)
|
|
356
|
-
}
|
|
357
|
-
c.tsw.WriteLiterally("(")
|
|
358
|
-
|
|
359
|
-
// Use auto-wrapping for the constructor argument (only if writeTypeNameFunc writes a simple identifier)
|
|
360
|
-
// The constructor parameter type is the underlying type of the named type
|
|
361
|
-
// For MyMode (which is type MyMode os.FileMode), the constructor expects os.FileMode
|
|
362
|
-
constructorParamType := typeName.Type()
|
|
363
|
-
if namedType, ok := typeName.Type().(*types.Named); ok {
|
|
364
|
-
// For named types, the constructor expects the underlying type
|
|
365
|
-
constructorParamType = namedType.Underlying()
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
if err := c.writeAutoWrappedArgument(arg, constructorParamType); err != nil {
|
|
369
|
-
return fmt.Errorf("failed to write argument for type constructor: %w", err)
|
|
370
|
-
}
|
|
371
|
-
c.tsw.WriteLiterally(")")
|
|
372
|
-
return nil
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
// Determine if this type should use constructor syntax
|
|
376
|
-
shouldUseConstructor := false
|
|
377
|
-
|
|
378
|
-
// Check if it's a type alias (like os.FileMode)
|
|
379
|
-
if alias, isAlias := typeName.Type().(*types.Alias); isAlias {
|
|
380
|
-
// For type aliases, check the underlying type
|
|
381
|
-
if _, isInterface := alias.Underlying().(*types.Interface); !isInterface {
|
|
382
|
-
if _, isStruct := alias.Underlying().(*types.Struct); !isStruct {
|
|
383
|
-
// For non-struct, non-interface type aliases, use constructor
|
|
384
|
-
shouldUseConstructor = true
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
} else if namedType, isNamed := typeName.Type().(*types.Named); isNamed {
|
|
388
|
-
// For named types, check if they have receiver methods in the current package
|
|
389
|
-
// or if they follow the pattern of non-struct, non-interface named types
|
|
390
|
-
if c.hasReceiverMethods(typeNameStr) {
|
|
391
|
-
shouldUseConstructor = true
|
|
392
|
-
} else if _, isInterface := namedType.Underlying().(*types.Interface); !isInterface {
|
|
393
|
-
if _, isStruct := namedType.Underlying().(*types.Struct); !isStruct {
|
|
394
|
-
// For non-struct, non-interface named types, use constructor
|
|
395
|
-
shouldUseConstructor = true
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
if shouldUseConstructor {
|
|
401
|
-
// For types that should use constructors, use class constructor
|
|
402
|
-
c.tsw.WriteLiterally("new ")
|
|
403
|
-
if err := writeTypeNameFunc(); err != nil {
|
|
404
|
-
return fmt.Errorf("failed to write type name: %w", err)
|
|
405
|
-
}
|
|
406
|
-
c.tsw.WriteLiterally("(")
|
|
407
|
-
if err := c.WriteValueExpr(arg); err != nil {
|
|
408
|
-
return fmt.Errorf("failed to write argument for type constructor: %w", err)
|
|
409
|
-
}
|
|
410
|
-
c.tsw.WriteLiterally(")")
|
|
411
|
-
return nil
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
// For types that don't need constructors, use the TypeScript "as" operator
|
|
415
|
-
c.tsw.WriteLiterally("(")
|
|
416
|
-
if err := c.WriteValueExpr(arg); err != nil {
|
|
417
|
-
return fmt.Errorf("failed to write argument for type cast: %w", err)
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
// Then use the TypeScript "as" operator with the mapped type name
|
|
421
|
-
c.tsw.WriteLiterally(" as ")
|
|
422
|
-
c.WriteGoType(typeName.Type(), GoTypeContextGeneral)
|
|
423
|
-
c.tsw.WriteLiterally(")")
|
|
424
|
-
return nil
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
// writeTypeConversion handles named type conversions
|
|
428
|
-
func (c *GoToTSCompiler) writeTypeConversion(exp *ast.CallExpr, funIdent *ast.Ident) (handled bool, err error) {
|
|
429
|
-
// Check if this is a type conversion to a function type
|
|
430
|
-
if funIdent == nil {
|
|
431
|
-
return false, nil
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
if obj := c.objectOfIdent(funIdent); obj != nil {
|
|
435
|
-
// Check if the object is a type name
|
|
436
|
-
if typeName, isType := obj.(*types.TypeName); isType {
|
|
437
|
-
// Make sure we have exactly one argument
|
|
438
|
-
if len(exp.Args) == 1 {
|
|
439
|
-
err := c.handleTypeConversionCommon(typeName, exp.Args[0], funIdent.String(), func() error {
|
|
440
|
-
c.tsw.WriteLiterally(funIdent.String())
|
|
441
|
-
return nil
|
|
442
|
-
})
|
|
443
|
-
return true, err
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
return false, nil
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
// writeIntConversion handles int() conversion
|
|
452
|
-
func (c *GoToTSCompiler) writeIntConversion(exp *ast.CallExpr) error {
|
|
453
|
-
if len(exp.Args) != 1 {
|
|
454
|
-
return fmt.Errorf("int() conversion expects exactly 1 argument, got %d", len(exp.Args))
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
arg := exp.Args[0]
|
|
458
|
-
|
|
459
|
-
// Check if we're converting FROM a type with receiver methods TO int
|
|
460
|
-
if argType := c.pkg.TypesInfo.TypeOf(arg); argType != nil {
|
|
461
|
-
if namedArgType, isNamed := argType.(*types.Named); isNamed {
|
|
462
|
-
// Check if the argument type is a wrapper type
|
|
463
|
-
if c.isWrapperType(namedArgType) {
|
|
464
|
-
// Check if we're converting to int (the underlying type)
|
|
465
|
-
if types.Identical(types.Typ[types.Int], namedArgType.Underlying()) {
|
|
466
|
-
// This is a conversion from a wrapper type to int
|
|
467
|
-
// Since wrapper types are now type aliases, just write the value directly
|
|
468
|
-
if err := c.WriteValueExpr(arg); err != nil {
|
|
469
|
-
return fmt.Errorf("failed to write argument for int conversion: %w", err)
|
|
470
|
-
}
|
|
471
|
-
return nil
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
// Default case: Translate int(value) to $.int(value)
|
|
478
|
-
c.tsw.WriteLiterally("$.int(")
|
|
479
|
-
if err := c.WriteValueExpr(exp.Args[0]); err != nil {
|
|
480
|
-
return fmt.Errorf("failed to write argument for int() conversion: %w", err)
|
|
481
|
-
}
|
|
482
|
-
c.tsw.WriteLiterally(")")
|
|
483
|
-
return nil
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
// writeQualifiedTypeConversion handles qualified type conversions like os.FileMode(value)
|
|
487
|
-
func (c *GoToTSCompiler) writeQualifiedTypeConversion(exp *ast.CallExpr, selectorExpr *ast.SelectorExpr) (handled bool, err error) {
|
|
488
|
-
// Check if this is a type conversion by looking up the selector in the type info
|
|
489
|
-
if obj := c.objectOfIdent(selectorExpr.Sel); obj != nil {
|
|
490
|
-
// Check if the object is a type name
|
|
491
|
-
if typeName, isType := obj.(*types.TypeName); isType {
|
|
492
|
-
// Make sure we have exactly one argument
|
|
493
|
-
if len(exp.Args) == 1 {
|
|
494
|
-
err := c.handleTypeConversionCommon(typeName, exp.Args[0], selectorExpr.Sel.Name, func() error {
|
|
495
|
-
return c.WriteSelectorExpr(selectorExpr)
|
|
496
|
-
})
|
|
497
|
-
return true, err
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
return false, nil
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
// Helper: detect if a constraint includes string or []byte
|
|
506
|
-
func constraintIncludesString(t types.Type) bool {
|
|
507
|
-
iface, ok := t.Underlying().(*types.Interface)
|
|
508
|
-
if !ok {
|
|
509
|
-
return false
|
|
510
|
-
}
|
|
511
|
-
return analyzeConstraint(iface).HasString
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
func constraintIncludesByteSlice(t types.Type) bool {
|
|
515
|
-
iface, ok := t.Underlying().(*types.Interface)
|
|
516
|
-
if !ok {
|
|
517
|
-
return false
|
|
518
|
-
}
|
|
519
|
-
return analyzeConstraint(iface).HasByteSlice
|
|
520
|
-
}
|