goscript 0.0.58 → 0.0.59

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +40 -33
  2. package/compiler/analysis.go +115 -19
  3. package/compiler/assignment.go +163 -217
  4. package/compiler/compiler.go +35 -31
  5. package/compiler/composite-lit.go +233 -196
  6. package/compiler/constraint.go +88 -0
  7. package/compiler/decl.go +82 -24
  8. package/compiler/expr-call-async.go +20 -34
  9. package/compiler/expr-call-builtins.go +19 -0
  10. package/compiler/expr-call-helpers.go +0 -28
  11. package/compiler/expr-call-make.go +93 -343
  12. package/compiler/expr-call-type-conversion.go +221 -249
  13. package/compiler/expr-call.go +70 -69
  14. package/compiler/expr-selector.go +21 -24
  15. package/compiler/expr.go +3 -60
  16. package/compiler/protobuf.go +180 -36
  17. package/compiler/spec-value.go +132 -24
  18. package/compiler/spec.go +14 -55
  19. package/compiler/stmt-assign.go +338 -356
  20. package/compiler/stmt-range.go +4 -24
  21. package/compiler/stmt.go +92 -203
  22. package/compiler/type-utils.go +185 -0
  23. package/compiler/type.go +26 -80
  24. package/dist/gs/builtin/slice.d.ts +1 -1
  25. package/dist/gs/builtin/slice.js +3 -0
  26. package/dist/gs/builtin/slice.js.map +1 -1
  27. package/dist/gs/builtin/type.js +8 -2
  28. package/dist/gs/builtin/type.js.map +1 -1
  29. package/dist/gs/fmt/fmt.js +113 -16
  30. package/dist/gs/fmt/fmt.js.map +1 -1
  31. package/dist/gs/runtime/runtime.d.ts +1 -1
  32. package/dist/gs/runtime/runtime.js +1 -1
  33. package/dist/gs/slices/slices.d.ts +23 -0
  34. package/dist/gs/slices/slices.js +61 -0
  35. package/dist/gs/slices/slices.js.map +1 -1
  36. package/go.mod +8 -8
  37. package/go.sum +14 -14
  38. package/gs/builtin/slice.ts +5 -2
  39. package/gs/builtin/type.ts +13 -6
  40. package/gs/fmt/fmt.test.ts +176 -0
  41. package/gs/fmt/fmt.ts +109 -18
  42. package/gs/runtime/runtime.ts +1 -1
  43. package/gs/slices/slices.ts +68 -0
  44. package/package.json +3 -3
@@ -1,11 +1,10 @@
1
1
  package compiler
2
2
 
3
3
  import (
4
+ "fmt"
4
5
  "go/ast"
5
6
  "go/token"
6
7
  "go/types"
7
-
8
- "golang.org/x/tools/go/packages"
9
8
  )
10
9
 
11
10
  // writeAssignmentCore handles the central logic for translating Go assignment
@@ -37,75 +36,19 @@ func (c *GoToTSCompiler) writeAssignmentCore(lhs, rhs []ast.Expr, tok token.Toke
37
36
  // Handle blank identifier (_) on the LHS for single assignments
38
37
  if len(lhs) == 1 && len(rhs) == 1 {
39
38
  if ident, ok := lhs[0].(*ast.Ident); ok && ident.Name == "_" {
40
- // Evaluate the RHS expression for side effects, but don't assign it
41
- c.tsw.WriteLiterally("/* _ = */ ")
42
- if err := c.WriteValueExpr(rhs[0]); err != nil {
43
- return err
44
- }
45
- return nil
39
+ return c.writeBlankIdentifierAssign(rhs[0])
46
40
  }
47
41
 
48
- // Handle the special case of "*p = val" (assignment to dereferenced pointer)
42
+ // Handle the special case of "*p = val" or "*p += val" (assignment to dereferenced pointer)
49
43
  if starExpr, ok := lhs[0].(*ast.StarExpr); ok {
50
- // For *p = val, we need to set p's .value property
51
- // Write "p!.value = " for the underlying value
52
- if err := c.WriteValueExpr(starExpr.X); err != nil { // p in *p
53
- return err
54
- }
55
- c.tsw.WriteLiterally("!.value = ") // Add non-null assertion for TS safety
56
-
57
- // Handle the RHS expression (potentially adding .clone() for structs)
58
- if shouldApplyClone(c.pkg, rhs[0]) {
59
- // When cloning for value assignment, mark the result as struct value
60
- c.tsw.WriteLiterally("$.markAsStructValue(")
61
- if err := c.WriteValueExpr(rhs[0]); err != nil {
62
- return err
63
- }
64
- c.tsw.WriteLiterally(".clone())")
65
- } else {
66
- if err := c.WriteValueExpr(rhs[0]); err != nil {
67
- return err
68
- }
69
- }
70
- return nil
44
+ return c.writePointerDerefAssign(starExpr, rhs[0], tok)
71
45
  }
72
46
 
73
47
  // Handle variable referenced variables in declarations
74
48
  if addDeclaration && tok == token.DEFINE {
75
- // Determine if LHS is variable referenced
76
- isLHSVarRefed := false
77
- var lhsIdent *ast.Ident
78
- var lhsObj types.Object
79
-
80
- if ident, ok := lhs[0].(*ast.Ident); ok {
81
- lhsIdent = ident
82
- // Get the types.Object from the identifier
83
- if use, ok := c.pkg.TypesInfo.Uses[ident]; ok {
84
- lhsObj = use
85
- } else if def, ok := c.pkg.TypesInfo.Defs[ident]; ok {
86
- lhsObj = def
87
- }
88
-
89
- // Check if this variable needs to be variable referenced
90
- if lhsObj != nil && c.analysis.NeedsVarRef(lhsObj) {
91
- isLHSVarRefed = true
92
- }
93
- }
94
-
95
- // Handle short declaration of variable referenced variables
96
- if isLHSVarRefed && lhsIdent != nil {
97
- c.tsw.WriteLiterally("let ")
98
- // Just write the identifier name without .value
99
- c.tsw.WriteLiterally(c.sanitizeIdentifier(lhsIdent.Name))
100
- // No type annotation, allow TypeScript to infer it from varRef.
101
- c.tsw.WriteLiterally(" = ")
102
-
103
- // Create the variable reference for the initializer
104
- c.tsw.WriteLiterally("$.varRef(")
105
- if err := c.WriteValueExpr(rhs[0]); err != nil {
106
- return err
107
- }
108
- c.tsw.WriteLiterally(")")
49
+ if handled, err := c.writeVarRefShortDecl(lhs[0], rhs[0]); err != nil {
50
+ return err
51
+ } else if handled {
109
52
  return nil
110
53
  }
111
54
 
@@ -115,82 +58,7 @@ func (c *GoToTSCompiler) writeAssignmentCore(lhs, rhs []ast.Expr, tok token.Toke
115
58
 
116
59
  // Special case for multi-variable assignment to handle array element swaps
117
60
  if len(lhs) > 1 && len(rhs) > 1 {
118
- // Check if this is an array element swap pattern (common pattern a[i], a[j] = a[j], a[i])
119
- // Identify if we're dealing with array index expressions that might need null assertions
120
- allIndexExprs := true
121
- for _, expr := range append(lhs, rhs...) {
122
- _, isIndexExpr := expr.(*ast.IndexExpr)
123
- if !isIndexExpr {
124
- allIndexExprs = false
125
- break
126
- }
127
- }
128
-
129
- // Add semicolon before destructuring assignment to prevent TypeScript
130
- // from interpreting it as array access on the previous line
131
- if tok != token.DEFINE {
132
- c.tsw.WriteLiterally(";")
133
- }
134
-
135
- // Use array destructuring for multi-variable assignments
136
- c.tsw.WriteLiterally("[")
137
- for i, l := range lhs {
138
- if i != 0 {
139
- c.tsw.WriteLiterally(", ")
140
- }
141
-
142
- // Handle blank identifier
143
- if ident, ok := l.(*ast.Ident); ok && ident.Name == "_" {
144
- // If it's a blank identifier, we write nothing,
145
- // leaving an empty slot in the destructuring array.
146
- } else if indexExpr, ok := l.(*ast.IndexExpr); ok && allIndexExprs { // MODIFICATION: Added 'else if'
147
- // Note: We don't use WriteIndexExpr here because we need direct array access for swapping
148
- if err := c.WriteValueExpr(indexExpr.X); err != nil {
149
- return err
150
- }
151
- c.tsw.WriteLiterally("!") // non-null assertion
152
- c.tsw.WriteLiterally("[")
153
- if err := c.WriteValueExpr(indexExpr.Index); err != nil {
154
- return err
155
- }
156
- c.tsw.WriteLiterally("]")
157
- } else {
158
- // Normal case - write the entire expression
159
- if err := c.WriteValueExpr(l); err != nil {
160
- return err
161
- }
162
- }
163
- }
164
- c.tsw.WriteLiterally("] = [")
165
- for i, r := range rhs {
166
- if i != 0 {
167
- c.tsw.WriteLiterally(", ")
168
- }
169
- if indexExpr, ok := r.(*ast.IndexExpr); ok && allIndexExprs {
170
- // Note: We don't use WriteIndexExpr here because we need direct array access for swapping
171
- if err := c.WriteValueExpr(indexExpr.X); err != nil {
172
- return err
173
- }
174
- c.tsw.WriteLiterally("!")
175
- c.tsw.WriteLiterally("[")
176
- if err := c.WriteValueExpr(indexExpr.Index); err != nil {
177
- return err
178
- }
179
- c.tsw.WriteLiterally("]")
180
- } else if callExpr, isCallExpr := r.(*ast.CallExpr); isCallExpr {
181
- // If the RHS is a function call, write it as a call
182
- if err := c.WriteCallExpr(callExpr); err != nil {
183
- return err
184
- }
185
- } else {
186
- // Normal case - write the entire expression
187
- if err := c.WriteValueExpr(r); err != nil {
188
- return err
189
- }
190
- }
191
- }
192
- c.tsw.WriteLiterally("]")
193
- return nil
61
+ return c.writeMultiVarAssign(lhs, rhs, tok)
194
62
  }
195
63
 
196
64
  // --- Logic for assignments ---
@@ -259,13 +127,8 @@ func (c *GoToTSCompiler) writeAssignmentCore(lhs, rhs []ast.Expr, tok token.Toke
259
127
  // Determine if LHS is variable referenced
260
128
  isLHSVarRefed := false
261
129
  var lhsObj types.Object
262
-
263
130
  // Get the types.Object from the identifier
264
- if use, ok := c.pkg.TypesInfo.Uses[lhsExprIdent]; ok {
265
- lhsObj = use
266
- } else if def, ok := c.pkg.TypesInfo.Defs[lhsExprIdent]; ok {
267
- lhsObj = def
268
- }
131
+ lhsObj = c.objectOfIdent(lhsExprIdent)
269
132
 
270
133
  // Check if this variable needs to be variable referenced
271
134
  if lhsObj != nil && c.analysis.NeedsVarRef(lhsObj) {
@@ -290,20 +153,8 @@ func (c *GoToTSCompiler) writeAssignmentCore(lhs, rhs []ast.Expr, tok token.Toke
290
153
  // Continue, we've already written part of the mapSet() function call
291
154
  } else {
292
155
  c.tsw.WriteLiterally(" ")
293
-
294
- // Special handling for &^= (bitwise AND NOT assignment)
295
- if tok == token.AND_NOT_ASSIGN {
296
- // Transform x &^= y to x &= ~(y)
297
- c.tsw.WriteLiterally("&= ~(")
298
- } else {
299
- tokStr, ok := TokenToTs(tok) // Use explicit gstypes alias
300
- if !ok {
301
- c.tsw.WriteLiterally("?= ")
302
- c.tsw.WriteCommentLine("Unknown token " + tok.String())
303
- } else {
304
- c.tsw.WriteLiterally(tokStr)
305
- }
306
- c.tsw.WriteLiterally(" ")
156
+ if err := c.writeAssignmentOperator(tok); err != nil {
157
+ return err
307
158
  }
308
159
  }
309
160
 
@@ -327,10 +178,7 @@ func (c *GoToTSCompiler) writeAssignmentCore(lhs, rhs []ast.Expr, tok token.Toke
327
178
  // Check if RHS is an identifier (variable name)
328
179
  rhsIdent, rhsIsIdent := r.(*ast.Ident)
329
180
  if rhsIsIdent {
330
- rhsObj = c.pkg.TypesInfo.Uses[rhsIdent]
331
- if rhsObj == nil {
332
- rhsObj = c.pkg.TypesInfo.Defs[rhsIdent]
333
- }
181
+ rhsObj = c.objectOfIdent(rhsIdent)
334
182
 
335
183
  // Important: For struct copying, we need to check if the variable itself is variable referenced
336
184
  // Important: For struct copying, we need to check if the variable needs variable referenced access
@@ -440,73 +288,171 @@ func (c *GoToTSCompiler) writeAssignmentCore(lhs, rhs []ast.Expr, tok token.Toke
440
288
  return nil
441
289
  }
442
290
 
443
- // shouldApplyClone determines whether a `.clone()` method call should be appended
444
- // to the TypeScript translation of a Go expression `rhs` when it appears on the
445
- // right-hand side of an assignment. This is primarily to emulate Go's value
446
- // semantics for struct assignments, where assigning one struct variable to another
447
- // creates a copy of the struct.
448
- //
449
- // It uses `go/types` information (`pkg.TypesInfo`) to determine the type of `rhs`.
450
- // - If `rhs` is identified as a struct type (either directly, as a named type
451
- // whose underlying type is a struct, or an unnamed type whose underlying type
452
- // is a struct), it returns `true`.
453
- // - An optimization: if `rhs` is a composite literal (`*ast.CompositeLit`),
454
- // it returns `false` because a composite literal already produces a new value,
455
- // so cloning is unnecessary.
456
- // - If type information is unavailable or `rhs` is not a struct type, it returns `false`.
457
- //
458
- // This function is crucial for ensuring that assignments of struct values in
459
- // TypeScript behave like copies, as they do in Go, rather than reference assignments.
460
- func shouldApplyClone(pkg *packages.Package, rhs ast.Expr) bool {
461
- if pkg == nil || pkg.TypesInfo == nil {
462
- // Cannot determine type without type info, default to no clone
463
- return false
291
+ // writeBlankIdentifierAssign handles assignment to blank identifier (_)
292
+ func (c *GoToTSCompiler) writeBlankIdentifierAssign(rhs ast.Expr) error {
293
+ c.tsw.WriteLiterally("/* _ = */ ")
294
+ return c.WriteValueExpr(rhs)
295
+ }
296
+
297
+ // writePointerDerefAssign handles assignments to dereferenced pointers (*p = val)
298
+ func (c *GoToTSCompiler) writePointerDerefAssign(starExpr *ast.StarExpr, rhs ast.Expr, tok token.Token) error {
299
+ // Write pointer dereference
300
+ if ident, ok := starExpr.X.(*ast.Ident); ok {
301
+ obj := c.objectOfIdent(ident)
302
+ if obj != nil && c.analysis.NeedsVarRef(obj) {
303
+ c.WriteIdent(ident, true)
304
+ c.tsw.WriteLiterally("!.value")
305
+ } else {
306
+ c.WriteIdent(ident, false)
307
+ c.tsw.WriteLiterally("!.value")
308
+ }
309
+ } else {
310
+ if err := c.WriteValueExpr(starExpr.X); err != nil {
311
+ return err
312
+ }
313
+ c.tsw.WriteLiterally("!.value")
464
314
  }
465
315
 
466
- // Get the type of the RHS expression
467
- var exprType types.Type
468
-
469
- // Handle identifiers (variables) directly - the most common case
470
- if ident, ok := rhs.(*ast.Ident); ok {
471
- if obj := pkg.TypesInfo.Uses[ident]; obj != nil {
472
- // Get the type directly from the object
473
- exprType = obj.Type()
474
- } else if obj := pkg.TypesInfo.Defs[ident]; obj != nil {
475
- // Also check Defs map for definitions
476
- exprType = obj.Type()
316
+ // Write assignment operator
317
+ if tok == token.AND_NOT_ASSIGN {
318
+ c.tsw.WriteLiterally(" &= ~(")
319
+ } else {
320
+ c.tsw.WriteLiterally(" ")
321
+ tokStr, ok := TokenToTs(tok)
322
+ if !ok {
323
+ return fmt.Errorf("unknown assignment token: %s", tok.String())
477
324
  }
325
+ c.tsw.WriteLiterally(tokStr)
326
+ c.tsw.WriteLiterally(" ")
327
+ }
328
+
329
+ // Write RHS with cloning if needed
330
+ if shouldApplyClone(c.pkg, rhs) {
331
+ c.tsw.WriteLiterally("$.markAsStructValue(")
332
+ if err := c.WriteValueExpr(rhs); err != nil {
333
+ return err
334
+ }
335
+ c.tsw.WriteLiterally(".clone())")
336
+ } else {
337
+ if err := c.WriteValueExpr(rhs); err != nil {
338
+ return err
339
+ }
340
+ }
341
+
342
+ if tok == token.AND_NOT_ASSIGN {
343
+ c.tsw.WriteLiterally(")")
478
344
  }
479
345
 
480
- // If we couldn't get the type from Uses/Defs, try getting it from Types
481
- if exprType == nil {
482
- if tv, found := pkg.TypesInfo.Types[rhs]; found && tv.Type != nil {
483
- exprType = tv.Type
346
+ return nil
347
+ }
348
+
349
+ // writeVarRefShortDecl handles short declarations of varrefed variables
350
+ // Returns true if handled, false otherwise
351
+ func (c *GoToTSCompiler) writeVarRefShortDecl(lhs, rhs ast.Expr) (bool, error) {
352
+ ident, ok := lhs.(*ast.Ident)
353
+ if !ok {
354
+ return false, nil
355
+ }
356
+
357
+ obj := c.objectOfIdent(ident)
358
+ if obj == nil || !c.analysis.NeedsVarRef(obj) {
359
+ return false, nil
360
+ }
361
+
362
+ c.tsw.WriteLiterally("let ")
363
+ c.tsw.WriteLiterally(c.sanitizeIdentifier(ident.Name))
364
+ c.tsw.WriteLiterally(" = $.varRef(")
365
+ if err := c.WriteValueExpr(rhs); err != nil {
366
+ return false, err
367
+ }
368
+ c.tsw.WriteLiterally(")")
369
+ return true, nil
370
+ }
371
+
372
+ // writeMultiVarAssign handles multi-variable assignments with array destructuring
373
+ func (c *GoToTSCompiler) writeMultiVarAssign(lhs, rhs []ast.Expr, tok token.Token) error {
374
+ // Check if all expressions are index expressions (for swap optimization)
375
+ allIndexExprs := true
376
+ for _, expr := range append(lhs, rhs...) {
377
+ if _, isIndexExpr := expr.(*ast.IndexExpr); !isIndexExpr {
378
+ allIndexExprs = false
379
+ break
484
380
  }
485
381
  }
486
382
 
487
- // No type information available
488
- if exprType == nil {
489
- return false
383
+ // Add semicolon to prevent TypeScript parsing issues
384
+ if tok != token.DEFINE {
385
+ c.tsw.WriteLiterally(";")
490
386
  }
491
387
 
492
- // Optimization: If it's a composite literal for a struct, no need to clone
493
- // as it's already a fresh value
494
- if _, isCompositeLit := rhs.(*ast.CompositeLit); isCompositeLit {
495
- return false
388
+ // Write LHS array destructuring pattern
389
+ c.tsw.WriteLiterally("[")
390
+ for i, l := range lhs {
391
+ if i != 0 {
392
+ c.tsw.WriteLiterally(", ")
393
+ }
394
+
395
+ if ident, ok := l.(*ast.Ident); ok && ident.Name == "_" {
396
+ // Blank identifier - leave empty slot
397
+ } else if indexExpr, ok := l.(*ast.IndexExpr); ok && allIndexExprs {
398
+ if err := c.WriteValueExpr(indexExpr.X); err != nil {
399
+ return err
400
+ }
401
+ c.tsw.WriteLiterally("![")
402
+ if err := c.WriteValueExpr(indexExpr.Index); err != nil {
403
+ return err
404
+ }
405
+ c.tsw.WriteLiterally("]")
406
+ } else {
407
+ if err := c.WriteValueExpr(l); err != nil {
408
+ return err
409
+ }
410
+ }
496
411
  }
497
412
 
498
- // Check if it's a struct type (directly, through named type, or underlying)
499
- if named, ok := exprType.(*types.Named); ok {
500
- if _, isStruct := named.Underlying().(*types.Struct); isStruct {
501
- return true // Named struct type
413
+ // Write RHS array
414
+ c.tsw.WriteLiterally("] = [")
415
+ for i, r := range rhs {
416
+ if i != 0 {
417
+ c.tsw.WriteLiterally(", ")
502
418
  }
503
- } else if _, ok := exprType.(*types.Struct); ok {
504
- return true // Direct struct type
505
- } else if underlying := exprType.Underlying(); underlying != nil {
506
- if _, isStruct := underlying.(*types.Struct); isStruct {
507
- return true // Underlying is a struct
419
+
420
+ if indexExpr, ok := r.(*ast.IndexExpr); ok && allIndexExprs {
421
+ if err := c.WriteValueExpr(indexExpr.X); err != nil {
422
+ return err
423
+ }
424
+ c.tsw.WriteLiterally("![")
425
+ if err := c.WriteValueExpr(indexExpr.Index); err != nil {
426
+ return err
427
+ }
428
+ c.tsw.WriteLiterally("]")
429
+ } else if callExpr, isCallExpr := r.(*ast.CallExpr); isCallExpr {
430
+ if err := c.WriteCallExpr(callExpr); err != nil {
431
+ return err
432
+ }
433
+ } else {
434
+ if err := c.WriteValueExpr(r); err != nil {
435
+ return err
436
+ }
508
437
  }
509
438
  }
439
+ c.tsw.WriteLiterally("]")
510
440
 
511
- return false // Not a struct, do not apply clone
441
+ return nil
442
+ }
443
+
444
+ // writeAssignmentOperator writes the TypeScript assignment operator
445
+ func (c *GoToTSCompiler) writeAssignmentOperator(tok token.Token) error {
446
+ if tok == token.AND_NOT_ASSIGN {
447
+ c.tsw.WriteLiterally("&= ~(")
448
+ return nil
449
+ }
450
+
451
+ tokStr, ok := TokenToTs(tok)
452
+ if !ok {
453
+ return fmt.Errorf("unknown assignment token: %s", tok.String())
454
+ }
455
+ c.tsw.WriteLiterally(tokStr)
456
+ c.tsw.WriteLiterally(" ")
457
+ return nil
512
458
  }
@@ -249,10 +249,14 @@ func (c *Compiler) CompilePackages(ctx context.Context, patterns ...string) (*Co
249
249
  }
250
250
  }
251
251
 
252
- // Skip packages that failed to load
252
+ // Fail fast on packages that failed to load to avoid hiding errors
253
253
  if len(pkg.Errors) > 0 {
254
- c.le.WithError(pkg.Errors[0]).Warnf("Skipping package %s due to errors", pkg.PkgPath)
255
- continue
254
+ var msgs []string
255
+ for _, e := range pkg.Errors {
256
+ // packages.Error is a struct; collect all messages
257
+ msgs = append(msgs, e.Error())
258
+ }
259
+ return nil, fmt.Errorf("package %s has load errors: %s", pkg.PkgPath, strings.Join(msgs, "; "))
256
260
  }
257
261
 
258
262
  pkgCompiler, err := NewPackageCompiler(c.le, &c.config, pkg, allPackages)
@@ -593,7 +597,7 @@ func (c *FileCompiler) Compile(ctx context.Context) error {
593
597
  goWriter := NewGoToTSCompiler(c.codeWriter, c.pkg, c.Analysis)
594
598
 
595
599
  // Add import for the goscript runtime using namespace import and alias
596
- c.codeWriter.WriteLinef("import * as $ from %q;", "@goscript/builtin/index.js")
600
+ c.codeWriter.WriteLinef("import * as $ from %q", "@goscript/builtin/index.js")
597
601
 
598
602
  // Check if there are any .pb.go files in this package and add imports for them
599
603
  if err := c.addProtobufImports(); err != nil {
@@ -641,28 +645,14 @@ func (c *FileCompiler) Compile(ctx context.Context) error {
641
645
  // Filter out protobuf types - they should be imported from .pb.js files, not .gs.js files
642
646
  var nonProtobufTypes []string
643
647
  for _, typeName := range typeImports {
644
- // Check if this type is a protobuf type by looking for it in the package
648
+ // Check if this type is a protobuf type by looking at its type info
645
649
  isProtobuf := false
646
650
  if typeObj := c.pkg.Types.Scope().Lookup(typeName); typeObj != nil {
647
651
  objType := typeObj.Type()
648
652
  if namedType, ok := objType.(*types.Named); ok {
649
- obj := namedType.Obj()
650
- if obj != nil && obj.Pkg() != nil {
651
- // Check if the type is defined in the current package and has a corresponding .pb.go file
652
- if obj.Pkg() == c.pkg.Types {
653
- // Check if there's a .pb.go file in the package that exports this type
654
- // For now, we'll use a simple heuristic: if the type name ends with "Msg"
655
- // and there's a .pb.go file in the package, assume it's a protobuf type
656
- if strings.HasSuffix(typeName, "Msg") {
657
- // Check if there are any .pb.go files in this package
658
- for _, fileName := range c.pkg.CompiledGoFiles {
659
- if strings.HasSuffix(fileName, ".pb.go") {
660
- isProtobuf = true
661
- break
662
- }
663
- }
664
- }
665
- }
653
+ // Use the same detection logic as codegen
654
+ if goWriter.isProtobufType(namedType) {
655
+ isProtobuf = true
666
656
  }
667
657
  }
668
658
  }
@@ -720,6 +710,21 @@ func NewGoToTSCompiler(tsw *TSCodeWriter, pkg *packages.Package, analysis *Analy
720
710
  }
721
711
  }
722
712
 
713
+ // objectOfIdent returns the types.Object associated with the identifier.
714
+ // It checks Uses first, then Defs, and returns nil if neither is found.
715
+ func (c *GoToTSCompiler) objectOfIdent(ident *ast.Ident) types.Object {
716
+ if ident == nil || c.pkg == nil || c.pkg.TypesInfo == nil {
717
+ return nil
718
+ }
719
+ if obj := c.pkg.TypesInfo.Uses[ident]; obj != nil {
720
+ return obj
721
+ }
722
+ if obj := c.pkg.TypesInfo.Defs[ident]; obj != nil {
723
+ return obj
724
+ }
725
+ return nil
726
+ }
727
+
723
728
  // getDeterministicID generates a deterministic unique ID based on file position
724
729
  // This replaces the non-deterministic Pos() values to ensure reproducible builds
725
730
  func (c *GoToTSCompiler) getDeterministicID(pos token.Pos) string {
@@ -778,11 +783,7 @@ func (c *GoToTSCompiler) WriteIdent(exp *ast.Ident, accessVarRefedValue bool) {
778
783
  }
779
784
 
780
785
  // Use TypesInfo to find the object associated with the identifier
781
- var obj types.Object
782
- obj = c.pkg.TypesInfo.Uses[exp]
783
- if obj == nil {
784
- obj = c.pkg.TypesInfo.Defs[exp]
785
- }
786
+ obj := c.objectOfIdent(exp)
786
787
 
787
788
  // Check if this identifier refers to a constant
788
789
  if obj != nil {
@@ -1143,8 +1144,11 @@ func (c *Compiler) ReadGsPackageMetadata(gsSourcePath string) (*GsPackageMetadat
1143
1144
  metaFilePath := filepath.Join(gsSourcePath, "meta.json")
1144
1145
  content, err := gs.GsOverrides.ReadFile(metaFilePath)
1145
1146
  if err != nil {
1146
- // No meta.json file found, return empty metadata
1147
- return metadata, nil
1147
+ // Only treat missing file as "no metadata"; surface other errors
1148
+ if os.IsNotExist(err) {
1149
+ return metadata, nil
1150
+ }
1151
+ return nil, fmt.Errorf("failed to read meta.json in %s: %w", gsSourcePath, err)
1148
1152
  }
1149
1153
 
1150
1154
  // Parse the JSON content
@@ -1181,8 +1185,8 @@ func (c *Compiler) copyGsPackageWithDependencies(packagePath string, processedPa
1181
1185
  // Read metadata to get dependencies
1182
1186
  metadata, err := c.ReadGsPackageMetadata(gsSourcePath)
1183
1187
  if err != nil {
1184
- c.le.WithError(err).Warnf("Failed to read metadata for gs package %s, continuing without dependencies", packagePath)
1185
- metadata = &GsPackageMetadata{Dependencies: []string{}}
1188
+ // Surface metadata errors instead of silently continuing
1189
+ return fmt.Errorf("failed to read metadata for gs package %s: %w", packagePath, err)
1186
1190
  }
1187
1191
 
1188
1192
  // Log dependencies if any are found