goscript 0.0.57 → 0.0.58
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/compiler/decl.go +360 -7
- package/compiler/stmt.go +38 -0
- package/package.json +1 -1
package/compiler/decl.go
CHANGED
|
@@ -3,7 +3,9 @@ package compiler
|
|
|
3
3
|
import (
|
|
4
4
|
"fmt"
|
|
5
5
|
"go/ast"
|
|
6
|
+
"go/token"
|
|
6
7
|
"go/types"
|
|
8
|
+
"sort"
|
|
7
9
|
)
|
|
8
10
|
|
|
9
11
|
// WriteDecls iterates through a slice of Go top-level declarations (`ast.Decl`)
|
|
@@ -17,33 +19,384 @@ import (
|
|
|
17
19
|
// variables, or type definitions: It iterates through `d.Specs` and calls
|
|
18
20
|
// `WriteSpec` for each specification.
|
|
19
21
|
//
|
|
22
|
+
// Type declarations are sorted by dependencies to ensure referenced types are
|
|
23
|
+
// defined before types that reference them, avoiding initialization order issues.
|
|
20
24
|
// A newline is added after each processed declaration or spec group for readability.
|
|
21
25
|
// Unknown declaration types result in a printed diagnostic message.
|
|
22
26
|
func (c *GoToTSCompiler) WriteDecls(decls []ast.Decl) error {
|
|
27
|
+
// Separate type declarations from other declarations for dependency sorting
|
|
28
|
+
var typeSpecs []*ast.TypeSpec
|
|
29
|
+
var varSpecs []*ast.ValueSpec
|
|
30
|
+
var otherDecls []ast.Decl
|
|
31
|
+
var otherSpecs []ast.Spec
|
|
32
|
+
|
|
23
33
|
for _, decl := range decls {
|
|
24
34
|
switch d := decl.(type) {
|
|
25
35
|
case *ast.FuncDecl:
|
|
26
36
|
// Only handle top-level functions here. Methods are handled within WriteTypeSpec.
|
|
27
37
|
if d.Recv == nil {
|
|
28
|
-
|
|
29
|
-
return err
|
|
30
|
-
}
|
|
31
|
-
c.tsw.WriteLine("") // Add space after function
|
|
38
|
+
otherDecls = append(otherDecls, d)
|
|
32
39
|
}
|
|
33
40
|
case *ast.GenDecl:
|
|
34
41
|
for _, spec := range d.Specs {
|
|
35
|
-
if
|
|
36
|
-
|
|
42
|
+
if typeSpec, ok := spec.(*ast.TypeSpec); ok {
|
|
43
|
+
typeSpecs = append(typeSpecs, typeSpec)
|
|
44
|
+
} else if varSpec, ok := spec.(*ast.ValueSpec); ok && d.Tok == token.VAR {
|
|
45
|
+
varSpecs = append(varSpecs, varSpec)
|
|
46
|
+
} else {
|
|
47
|
+
otherSpecs = append(otherSpecs, spec)
|
|
37
48
|
}
|
|
38
|
-
c.tsw.WriteLine("") // Add space after spec
|
|
39
49
|
}
|
|
50
|
+
default:
|
|
51
|
+
otherDecls = append(otherDecls, d)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Sort type declarations by dependencies
|
|
56
|
+
sortedTypeSpecs, err := c.sortTypeSpecsByDependencies(typeSpecs)
|
|
57
|
+
if err != nil {
|
|
58
|
+
return fmt.Errorf("failed to sort type declarations: %w", err)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Sort variable declarations by type dependencies
|
|
62
|
+
sortedVarSpecs, err := c.sortVarSpecsByTypeDependencies(varSpecs, typeSpecs)
|
|
63
|
+
if err != nil {
|
|
64
|
+
return fmt.Errorf("failed to sort variable declarations: %w", err)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Write non-type, non-var declarations first (imports, constants)
|
|
68
|
+
for _, spec := range otherSpecs {
|
|
69
|
+
if err := c.WriteSpec(spec); err != nil {
|
|
70
|
+
return err
|
|
71
|
+
}
|
|
72
|
+
c.tsw.WriteLine("") // Add space after spec
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Write sorted type declarations
|
|
76
|
+
for _, typeSpec := range sortedTypeSpecs {
|
|
77
|
+
if err := c.WriteSpec(typeSpec); err != nil {
|
|
78
|
+
return err
|
|
79
|
+
}
|
|
80
|
+
c.tsw.WriteLine("") // Add space after spec
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Write sorted variable declarations
|
|
84
|
+
for _, varSpec := range sortedVarSpecs {
|
|
85
|
+
if err := c.WriteSpec(varSpec); err != nil {
|
|
86
|
+
return err
|
|
87
|
+
}
|
|
88
|
+
c.tsw.WriteLine("") // Add space after spec
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Write function declarations last
|
|
92
|
+
for _, decl := range otherDecls {
|
|
93
|
+
switch d := decl.(type) {
|
|
94
|
+
case *ast.FuncDecl:
|
|
95
|
+
if err := c.WriteFuncDeclAsFunction(d); err != nil {
|
|
96
|
+
return err
|
|
97
|
+
}
|
|
98
|
+
c.tsw.WriteLine("") // Add space after function
|
|
40
99
|
default:
|
|
41
100
|
return fmt.Errorf("unknown decl: %#v", decl)
|
|
42
101
|
}
|
|
43
102
|
}
|
|
103
|
+
|
|
44
104
|
return nil
|
|
45
105
|
}
|
|
46
106
|
|
|
107
|
+
// sortTypeSpecsByDependencies performs a topological sort of type specifications
|
|
108
|
+
// based on their dependencies to ensure referenced types are defined before
|
|
109
|
+
// types that reference them.
|
|
110
|
+
func (c *GoToTSCompiler) sortTypeSpecsByDependencies(typeSpecs []*ast.TypeSpec) ([]*ast.TypeSpec, error) {
|
|
111
|
+
if len(typeSpecs) <= 1 {
|
|
112
|
+
return typeSpecs, nil
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Build dependency graph
|
|
116
|
+
dependencies := make(map[string][]string) // typeName -> list of types it depends on
|
|
117
|
+
typeSpecMap := make(map[string]*ast.TypeSpec)
|
|
118
|
+
|
|
119
|
+
// First pass: collect all type names
|
|
120
|
+
for _, typeSpec := range typeSpecs {
|
|
121
|
+
typeName := typeSpec.Name.Name
|
|
122
|
+
typeSpecMap[typeName] = typeSpec
|
|
123
|
+
dependencies[typeName] = []string{}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Second pass: analyze dependencies
|
|
127
|
+
for _, typeSpec := range typeSpecs {
|
|
128
|
+
typeName := typeSpec.Name.Name
|
|
129
|
+
deps := c.extractTypeDependencies(typeSpec.Type, typeSpecMap)
|
|
130
|
+
dependencies[typeName] = deps
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Perform topological sort
|
|
134
|
+
sorted, err := c.topologicalSort(dependencies)
|
|
135
|
+
if err != nil {
|
|
136
|
+
return nil, err
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Build result in sorted order
|
|
140
|
+
var result []*ast.TypeSpec
|
|
141
|
+
for _, typeName := range sorted {
|
|
142
|
+
if typeSpec, exists := typeSpecMap[typeName]; exists {
|
|
143
|
+
result = append(result, typeSpec)
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return result, nil
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// extractTypeDependencies extracts structural type dependencies from a type expression.
|
|
151
|
+
// Only dependencies that affect class initialization order are considered:
|
|
152
|
+
// - Struct field types (cause initialization order issues)
|
|
153
|
+
// - Embedded types (directly affect struct layout)
|
|
154
|
+
// - Type aliases (direct type references)
|
|
155
|
+
// Method parameters and return types are ignored as they're just annotations.
|
|
156
|
+
func (c *GoToTSCompiler) extractTypeDependencies(typeExpr ast.Expr, typeSpecMap map[string]*ast.TypeSpec) []string {
|
|
157
|
+
var deps []string
|
|
158
|
+
|
|
159
|
+
switch t := typeExpr.(type) {
|
|
160
|
+
case *ast.Ident:
|
|
161
|
+
// Direct type reference (e.g., type MyType OtherType)
|
|
162
|
+
if _, isLocalType := typeSpecMap[t.Name]; isLocalType {
|
|
163
|
+
deps = append(deps, t.Name)
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
case *ast.StructType:
|
|
167
|
+
// Struct type - check field types only
|
|
168
|
+
if t.Fields != nil {
|
|
169
|
+
for _, field := range t.Fields.List {
|
|
170
|
+
fieldDeps := c.extractTypeDependencies(field.Type, typeSpecMap)
|
|
171
|
+
deps = append(deps, fieldDeps...)
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
case *ast.ArrayType:
|
|
176
|
+
// Array type - check element type
|
|
177
|
+
elemDeps := c.extractTypeDependencies(t.Elt, typeSpecMap)
|
|
178
|
+
deps = append(deps, elemDeps...)
|
|
179
|
+
|
|
180
|
+
case *ast.StarExpr:
|
|
181
|
+
// Pointer type - check pointed-to type
|
|
182
|
+
ptrDeps := c.extractTypeDependencies(t.X, typeSpecMap)
|
|
183
|
+
deps = append(deps, ptrDeps...)
|
|
184
|
+
|
|
185
|
+
case *ast.MapType:
|
|
186
|
+
// Map type - check key and value types
|
|
187
|
+
keyDeps := c.extractTypeDependencies(t.Key, typeSpecMap)
|
|
188
|
+
valueDeps := c.extractTypeDependencies(t.Value, typeSpecMap)
|
|
189
|
+
deps = append(deps, keyDeps...)
|
|
190
|
+
deps = append(deps, valueDeps...)
|
|
191
|
+
|
|
192
|
+
case *ast.InterfaceType:
|
|
193
|
+
// Interface type - methods don't create initialization dependencies
|
|
194
|
+
// Only embedded interfaces matter, but those are rare and complex to handle
|
|
195
|
+
// For now, interfaces are considered to have no dependencies
|
|
196
|
+
|
|
197
|
+
case *ast.FuncType:
|
|
198
|
+
// Function types don't create initialization dependencies
|
|
199
|
+
|
|
200
|
+
case *ast.SelectorExpr:
|
|
201
|
+
// External package types don't create local dependencies
|
|
202
|
+
|
|
203
|
+
// Add other type expressions as needed
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Sort dependencies for deterministic output
|
|
207
|
+
sort.Strings(deps)
|
|
208
|
+
return deps
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// sortVarSpecsByTypeDependencies sorts variable declarations based on their type dependencies
|
|
212
|
+
func (c *GoToTSCompiler) sortVarSpecsByTypeDependencies(varSpecs []*ast.ValueSpec, typeSpecs []*ast.TypeSpec) ([]*ast.ValueSpec, error) {
|
|
213
|
+
if len(varSpecs) <= 1 {
|
|
214
|
+
return varSpecs, nil
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Build type name map
|
|
218
|
+
typeSpecMap := make(map[string]*ast.TypeSpec)
|
|
219
|
+
for _, typeSpec := range typeSpecs {
|
|
220
|
+
typeSpecMap[typeSpec.Name.Name] = typeSpec
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Group variables by dependency status with names for sorting
|
|
224
|
+
type namedVarSpec struct {
|
|
225
|
+
spec *ast.ValueSpec
|
|
226
|
+
name string
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
var independentVars []namedVarSpec
|
|
230
|
+
var dependentVars []namedVarSpec
|
|
231
|
+
|
|
232
|
+
for _, varSpec := range varSpecs {
|
|
233
|
+
// Get variable name for sorting
|
|
234
|
+
varName := ""
|
|
235
|
+
if len(varSpec.Names) > 0 {
|
|
236
|
+
varName = varSpec.Names[0].Name
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
hasDependency := false
|
|
240
|
+
|
|
241
|
+
// Check type annotation
|
|
242
|
+
if varSpec.Type != nil {
|
|
243
|
+
deps := c.extractTypeDependencies(varSpec.Type, typeSpecMap)
|
|
244
|
+
if len(deps) > 0 {
|
|
245
|
+
hasDependency = true
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// Check initializer expressions for type usage
|
|
250
|
+
if !hasDependency {
|
|
251
|
+
for _, value := range varSpec.Values {
|
|
252
|
+
if c.hasTypeReferences(value, typeSpecMap) {
|
|
253
|
+
hasDependency = true
|
|
254
|
+
break
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
namedVar := namedVarSpec{spec: varSpec, name: varName}
|
|
260
|
+
if hasDependency {
|
|
261
|
+
dependentVars = append(dependentVars, namedVar)
|
|
262
|
+
} else {
|
|
263
|
+
independentVars = append(independentVars, namedVar)
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Sort both groups by name for deterministic output
|
|
268
|
+
sort.Slice(independentVars, func(i, j int) bool {
|
|
269
|
+
return independentVars[i].name < independentVars[j].name
|
|
270
|
+
})
|
|
271
|
+
sort.Slice(dependentVars, func(i, j int) bool {
|
|
272
|
+
return dependentVars[i].name < dependentVars[j].name
|
|
273
|
+
})
|
|
274
|
+
|
|
275
|
+
// Return independent variables first, then dependent ones
|
|
276
|
+
result := make([]*ast.ValueSpec, 0, len(varSpecs))
|
|
277
|
+
for _, namedVar := range independentVars {
|
|
278
|
+
result = append(result, namedVar.spec)
|
|
279
|
+
}
|
|
280
|
+
for _, namedVar := range dependentVars {
|
|
281
|
+
result = append(result, namedVar.spec)
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
return result, nil
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// hasTypeReferences checks if an expression contains references to local types
|
|
288
|
+
func (c *GoToTSCompiler) hasTypeReferences(expr ast.Expr, typeSpecMap map[string]*ast.TypeSpec) bool {
|
|
289
|
+
hasRef := false
|
|
290
|
+
|
|
291
|
+
ast.Inspect(expr, func(n ast.Node) bool {
|
|
292
|
+
switch t := n.(type) {
|
|
293
|
+
case *ast.CallExpr:
|
|
294
|
+
// Check function calls like new Message(), makeChannel<Message>()
|
|
295
|
+
if ident, ok := t.Fun.(*ast.Ident); ok {
|
|
296
|
+
if _, isLocalType := typeSpecMap[ident.Name]; isLocalType {
|
|
297
|
+
hasRef = true
|
|
298
|
+
return false
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
// Check type arguments in generic calls
|
|
302
|
+
if funcType, ok := t.Fun.(*ast.IndexExpr); ok {
|
|
303
|
+
if c.hasTypeReferences(funcType.Index, typeSpecMap) {
|
|
304
|
+
hasRef = true
|
|
305
|
+
return false
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
case *ast.CompositeLit:
|
|
309
|
+
// Check composite literals like Message{...}
|
|
310
|
+
if ident, ok := t.Type.(*ast.Ident); ok {
|
|
311
|
+
if _, isLocalType := typeSpecMap[ident.Name]; isLocalType {
|
|
312
|
+
hasRef = true
|
|
313
|
+
return false
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
case *ast.Ident:
|
|
317
|
+
// Check direct type references
|
|
318
|
+
if _, isLocalType := typeSpecMap[t.Name]; isLocalType {
|
|
319
|
+
hasRef = true
|
|
320
|
+
return false
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
return !hasRef // Stop walking if we found a reference
|
|
324
|
+
})
|
|
325
|
+
|
|
326
|
+
return hasRef
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// topologicalSort performs a topological sort of the dependency graph
|
|
330
|
+
func (c *GoToTSCompiler) topologicalSort(dependencies map[string][]string) ([]string, error) {
|
|
331
|
+
// Kahn's algorithm for topological sorting with deterministic ordering
|
|
332
|
+
inDegree := make(map[string]int)
|
|
333
|
+
graph := make(map[string][]string)
|
|
334
|
+
|
|
335
|
+
// Initialize in-degree counts and reverse graph
|
|
336
|
+
for node := range dependencies {
|
|
337
|
+
inDegree[node] = 0
|
|
338
|
+
graph[node] = []string{}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// Build reverse graph and count in-degrees
|
|
342
|
+
for node, deps := range dependencies {
|
|
343
|
+
// Sort dependencies for consistent output
|
|
344
|
+
sortedDeps := make([]string, len(deps))
|
|
345
|
+
copy(sortedDeps, deps)
|
|
346
|
+
sort.Strings(sortedDeps)
|
|
347
|
+
|
|
348
|
+
for _, dep := range sortedDeps {
|
|
349
|
+
if _, exists := inDegree[dep]; exists {
|
|
350
|
+
graph[dep] = append(graph[dep], node)
|
|
351
|
+
inDegree[node]++
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// Sort neighbors in graph for consistency
|
|
357
|
+
for node := range graph {
|
|
358
|
+
sort.Strings(graph[node])
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// Find nodes with no incoming edges and sort them
|
|
362
|
+
var queue []string
|
|
363
|
+
for node, degree := range inDegree {
|
|
364
|
+
if degree == 0 {
|
|
365
|
+
queue = append(queue, node)
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
sort.Strings(queue) // Sort initial queue for deterministic output
|
|
369
|
+
|
|
370
|
+
var result []string
|
|
371
|
+
|
|
372
|
+
for len(queue) > 0 {
|
|
373
|
+
// Remove node from queue (already sorted)
|
|
374
|
+
current := queue[0]
|
|
375
|
+
queue = queue[1:]
|
|
376
|
+
result = append(result, current)
|
|
377
|
+
|
|
378
|
+
// Collect new zero-degree nodes
|
|
379
|
+
var newZeroNodes []string
|
|
380
|
+
for _, neighbor := range graph[current] {
|
|
381
|
+
inDegree[neighbor]--
|
|
382
|
+
if inDegree[neighbor] == 0 {
|
|
383
|
+
newZeroNodes = append(newZeroNodes, neighbor)
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// Sort new zero-degree nodes and add to queue
|
|
388
|
+
sort.Strings(newZeroNodes)
|
|
389
|
+
queue = append(queue, newZeroNodes...)
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// Check for cycles
|
|
393
|
+
if len(result) != len(dependencies) {
|
|
394
|
+
return nil, fmt.Errorf("circular dependency detected in type declarations")
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
return result, nil
|
|
398
|
+
}
|
|
399
|
+
|
|
47
400
|
// WriteFuncDeclAsFunction translates a Go function declaration (`ast.FuncDecl`)
|
|
48
401
|
// that does not have a receiver (i.e., it's a regular function, not a method)
|
|
49
402
|
// into a TypeScript function.
|
package/compiler/stmt.go
CHANGED
|
@@ -680,6 +680,12 @@ func (c *GoToTSCompiler) WriteStmtBlock(exp *ast.BlockStmt, suppressNewline bool
|
|
|
680
680
|
hasAsyncDefer = true
|
|
681
681
|
break
|
|
682
682
|
}
|
|
683
|
+
} else {
|
|
684
|
+
// Check if the deferred call is to an async function
|
|
685
|
+
if c.isCallAsyncInDefer(deferStmt.Call) {
|
|
686
|
+
hasAsyncDefer = true
|
|
687
|
+
break
|
|
688
|
+
}
|
|
683
689
|
}
|
|
684
690
|
}
|
|
685
691
|
}
|
|
@@ -877,6 +883,9 @@ func (c *GoToTSCompiler) WriteStmtDefer(exp *ast.DeferStmt) error {
|
|
|
877
883
|
isAsyncDeferred := false
|
|
878
884
|
if funcLit, ok := exp.Call.Fun.(*ast.FuncLit); ok {
|
|
879
885
|
isAsyncDeferred = c.analysis.IsFuncLitAsync(funcLit)
|
|
886
|
+
} else {
|
|
887
|
+
// Check if the deferred call is to an async function
|
|
888
|
+
isAsyncDeferred = c.isCallAsyncInDefer(exp.Call)
|
|
880
889
|
}
|
|
881
890
|
|
|
882
891
|
// Set async prefix based on pre-computed async status
|
|
@@ -914,6 +923,35 @@ func (c *GoToTSCompiler) WriteStmtDefer(exp *ast.DeferStmt) error {
|
|
|
914
923
|
return nil
|
|
915
924
|
}
|
|
916
925
|
|
|
926
|
+
// isCallAsyncInDefer determines if a call expression in a defer statement is async
|
|
927
|
+
func (c *GoToTSCompiler) isCallAsyncInDefer(callExpr *ast.CallExpr) bool {
|
|
928
|
+
switch fun := callExpr.Fun.(type) {
|
|
929
|
+
case *ast.Ident:
|
|
930
|
+
// Direct function call (e.g., defer myFunc())
|
|
931
|
+
if obj := c.pkg.TypesInfo.Uses[fun]; obj != nil {
|
|
932
|
+
return c.analysis.IsAsyncFunc(obj)
|
|
933
|
+
}
|
|
934
|
+
case *ast.SelectorExpr:
|
|
935
|
+
// Method call (e.g., defer handle.Release()) or package function call
|
|
936
|
+
if selection := c.pkg.TypesInfo.Selections[fun]; selection != nil {
|
|
937
|
+
// Method call on an object
|
|
938
|
+
if methodObj := selection.Obj(); methodObj != nil {
|
|
939
|
+
return c.analysis.IsAsyncFunc(methodObj)
|
|
940
|
+
}
|
|
941
|
+
} else if ident, ok := fun.X.(*ast.Ident); ok {
|
|
942
|
+
// Package-level function call (e.g., defer time.Sleep())
|
|
943
|
+
if obj := c.pkg.TypesInfo.Uses[ident]; obj != nil {
|
|
944
|
+
if pkgName, isPkg := obj.(*types.PkgName); isPkg {
|
|
945
|
+
methodName := fun.Sel.Name
|
|
946
|
+
pkgPath := pkgName.Imported().Path()
|
|
947
|
+
return c.analysis.IsMethodAsync(pkgPath, "", methodName)
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
return false
|
|
953
|
+
}
|
|
954
|
+
|
|
917
955
|
// WriteStmtLabeled handles labeled statements (ast.LabeledStmt), such as "label: statement".
|
|
918
956
|
// In TypeScript, labels cannot be used with variable declarations, so we need to handle this case specially.
|
|
919
957
|
func (c *GoToTSCompiler) WriteStmtLabeled(stmt *ast.LabeledStmt) error {
|