goscript 0.0.33 → 0.0.35

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 (347) hide show
  1. package/compiler/analysis.go +30 -22
  2. package/compiler/analysis_test.go +14 -0
  3. package/compiler/assignment.go +45 -7
  4. package/compiler/builtin_test.go +2 -0
  5. package/compiler/compiler.go +15 -89
  6. package/compiler/compiler_test.go +0 -53
  7. package/compiler/composite-lit.go +60 -17
  8. package/compiler/decl.go +1 -1
  9. package/compiler/expr-call.go +347 -30
  10. package/compiler/expr-selector.go +28 -2
  11. package/compiler/expr.go +79 -38
  12. package/compiler/lit.go +112 -3
  13. package/compiler/primitive.go +6 -6
  14. package/compiler/protobuf.go +0 -5
  15. package/compiler/sanitize.go +101 -0
  16. package/compiler/spec-value.go +25 -18
  17. package/compiler/stmt-assign.go +128 -91
  18. package/compiler/stmt-for.go +78 -1
  19. package/compiler/stmt-range.go +333 -461
  20. package/compiler/stmt.go +46 -9
  21. package/compiler/type.go +14 -11
  22. package/dist/gs/builtin/builtin.d.ts +8 -0
  23. package/dist/gs/builtin/builtin.js +31 -0
  24. package/dist/gs/builtin/builtin.js.map +1 -1
  25. package/dist/gs/builtin/map.d.ts +4 -4
  26. package/dist/gs/builtin/map.js +12 -6
  27. package/dist/gs/builtin/map.js.map +1 -1
  28. package/dist/gs/builtin/slice.d.ts +14 -8
  29. package/dist/gs/builtin/slice.js +131 -31
  30. package/dist/gs/builtin/slice.js.map +1 -1
  31. package/dist/gs/github.com/pkg/errors/errors.d.ts +13 -0
  32. package/dist/gs/github.com/pkg/errors/errors.js +232 -0
  33. package/dist/gs/github.com/pkg/errors/errors.js.map +1 -0
  34. package/dist/gs/github.com/pkg/errors/go113.d.ts +4 -0
  35. package/dist/gs/github.com/pkg/errors/go113.js +34 -0
  36. package/dist/gs/github.com/pkg/errors/go113.js.map +1 -0
  37. package/dist/gs/github.com/pkg/errors/index.d.ts +3 -0
  38. package/dist/gs/github.com/pkg/errors/index.js +4 -0
  39. package/dist/gs/github.com/pkg/errors/index.js.map +1 -0
  40. package/dist/gs/github.com/pkg/errors/stack.d.ts +32 -0
  41. package/dist/gs/github.com/pkg/errors/stack.js +111 -0
  42. package/dist/gs/github.com/pkg/errors/stack.js.map +1 -0
  43. package/dist/gs/maps/index.d.ts +2 -0
  44. package/dist/gs/maps/index.js +3 -0
  45. package/dist/gs/maps/index.js.map +1 -0
  46. package/dist/gs/maps/iter.d.ts +7 -0
  47. package/dist/gs/maps/iter.gs.d.ts +7 -0
  48. package/dist/gs/maps/iter.gs.js +65 -0
  49. package/dist/gs/maps/iter.gs.js.map +1 -0
  50. package/dist/gs/maps/iter.js +57 -0
  51. package/dist/gs/maps/iter.js.map +1 -0
  52. package/dist/gs/maps/maps.d.ts +7 -0
  53. package/dist/gs/maps/maps.gs.d.ts +7 -0
  54. package/dist/gs/maps/maps.gs.js +79 -0
  55. package/dist/gs/maps/maps.gs.js.map +1 -0
  56. package/dist/gs/maps/maps.js +67 -0
  57. package/dist/gs/maps/maps.js.map +1 -0
  58. package/dist/gs/math/abs.gs.d.ts +1 -0
  59. package/dist/gs/math/abs.gs.js +10 -0
  60. package/dist/gs/math/abs.gs.js.map +1 -0
  61. package/dist/gs/math/acosh.gs.d.ts +2 -0
  62. package/dist/gs/math/acosh.gs.js +14 -0
  63. package/dist/gs/math/acosh.gs.js.map +1 -0
  64. package/dist/gs/math/asin.gs.d.ts +4 -0
  65. package/dist/gs/math/asin.gs.js +24 -0
  66. package/dist/gs/math/asin.gs.js.map +1 -0
  67. package/dist/gs/math/asinh.gs.d.ts +2 -0
  68. package/dist/gs/math/asinh.gs.js +14 -0
  69. package/dist/gs/math/asinh.gs.js.map +1 -0
  70. package/dist/gs/math/atan.gs.d.ts +4 -0
  71. package/dist/gs/math/atan.gs.js +22 -0
  72. package/dist/gs/math/atan.gs.js.map +1 -0
  73. package/dist/gs/math/atan2.gs.d.ts +2 -0
  74. package/dist/gs/math/atan2.gs.js +30 -0
  75. package/dist/gs/math/atan2.gs.js.map +1 -0
  76. package/dist/gs/math/atanh.gs.d.ts +2 -0
  77. package/dist/gs/math/atanh.gs.js +16 -0
  78. package/dist/gs/math/atanh.gs.js.map +1 -0
  79. package/dist/gs/math/bits.gs.d.ts +5 -0
  80. package/dist/gs/math/bits.gs.js +46 -0
  81. package/dist/gs/math/bits.gs.js.map +1 -0
  82. package/dist/gs/math/cbrt.gs.d.ts +2 -0
  83. package/dist/gs/math/cbrt.gs.js +14 -0
  84. package/dist/gs/math/cbrt.gs.js.map +1 -0
  85. package/dist/gs/math/const.gs.d.ts +30 -0
  86. package/dist/gs/math/const.gs.js +61 -0
  87. package/dist/gs/math/const.gs.js.map +1 -0
  88. package/dist/gs/math/copysign.gs.d.ts +1 -0
  89. package/dist/gs/math/copysign.gs.js +20 -0
  90. package/dist/gs/math/copysign.gs.js.map +1 -0
  91. package/dist/gs/math/dim.gs.d.ts +5 -0
  92. package/dist/gs/math/dim.gs.js +69 -0
  93. package/dist/gs/math/dim.gs.js.map +1 -0
  94. package/dist/gs/math/erf.gs.d.ts +4 -0
  95. package/dist/gs/math/erf.gs.js +336 -0
  96. package/dist/gs/math/erf.gs.js.map +1 -0
  97. package/dist/gs/math/erfinv.gs.d.ts +2 -0
  98. package/dist/gs/math/erfinv.gs.js +118 -0
  99. package/dist/gs/math/erfinv.gs.js.map +1 -0
  100. package/dist/gs/math/exp.gs.d.ts +5 -0
  101. package/dist/gs/math/exp.gs.js +30 -0
  102. package/dist/gs/math/exp.gs.js.map +1 -0
  103. package/dist/gs/math/expm1.gs.d.ts +2 -0
  104. package/dist/gs/math/expm1.gs.js +17 -0
  105. package/dist/gs/math/expm1.gs.js.map +1 -0
  106. package/dist/gs/math/floor.gs.d.ts +8 -0
  107. package/dist/gs/math/floor.gs.js +75 -0
  108. package/dist/gs/math/floor.gs.js.map +1 -0
  109. package/dist/gs/math/fma.gs.d.ts +1 -0
  110. package/dist/gs/math/fma.gs.js +8 -0
  111. package/dist/gs/math/fma.gs.js.map +1 -0
  112. package/dist/gs/math/frexp.gs.d.ts +2 -0
  113. package/dist/gs/math/frexp.gs.js +28 -0
  114. package/dist/gs/math/frexp.gs.js.map +1 -0
  115. package/dist/gs/math/gamma.gs.d.ts +3 -0
  116. package/dist/gs/math/gamma.gs.js +149 -0
  117. package/dist/gs/math/gamma.gs.js.map +1 -0
  118. package/dist/gs/math/hypot.gs.d.ts +2 -0
  119. package/dist/gs/math/hypot.gs.js +16 -0
  120. package/dist/gs/math/hypot.gs.js.map +1 -0
  121. package/dist/gs/math/index.d.ts +44 -0
  122. package/dist/gs/math/index.js +45 -0
  123. package/dist/gs/math/index.js.map +1 -0
  124. package/dist/gs/math/j0.gs.d.ts +4 -0
  125. package/dist/gs/math/j0.gs.js +228 -0
  126. package/dist/gs/math/j0.gs.js.map +1 -0
  127. package/dist/gs/math/j1.gs.d.ts +4 -0
  128. package/dist/gs/math/j1.gs.js +211 -0
  129. package/dist/gs/math/j1.gs.js.map +1 -0
  130. package/dist/gs/math/jn.gs.d.ts +2 -0
  131. package/dist/gs/math/jn.gs.js +412 -0
  132. package/dist/gs/math/jn.gs.js.map +1 -0
  133. package/dist/gs/math/ldexp.gs.d.ts +2 -0
  134. package/dist/gs/math/ldexp.gs.js +20 -0
  135. package/dist/gs/math/ldexp.gs.js.map +1 -0
  136. package/dist/gs/math/lgamma.gs.d.ts +2 -0
  137. package/dist/gs/math/lgamma.gs.js +243 -0
  138. package/dist/gs/math/lgamma.gs.js.map +1 -0
  139. package/dist/gs/math/log.gs.d.ts +2 -0
  140. package/dist/gs/math/log.gs.js +16 -0
  141. package/dist/gs/math/log.gs.js.map +1 -0
  142. package/dist/gs/math/log10.gs.d.ts +4 -0
  143. package/dist/gs/math/log10.gs.js +17 -0
  144. package/dist/gs/math/log10.gs.js.map +1 -0
  145. package/dist/gs/math/log1p.gs.d.ts +2 -0
  146. package/dist/gs/math/log1p.gs.js +17 -0
  147. package/dist/gs/math/log1p.gs.js.map +1 -0
  148. package/dist/gs/math/logb.gs.d.ts +3 -0
  149. package/dist/gs/math/logb.gs.js +43 -0
  150. package/dist/gs/math/logb.gs.js.map +1 -0
  151. package/dist/gs/math/mod.gs.d.ts +2 -0
  152. package/dist/gs/math/mod.gs.js +26 -0
  153. package/dist/gs/math/mod.gs.js.map +1 -0
  154. package/dist/gs/math/modf.gs.d.ts +2 -0
  155. package/dist/gs/math/modf.gs.js +24 -0
  156. package/dist/gs/math/modf.gs.js.map +1 -0
  157. package/dist/gs/math/nextafter.gs.d.ts +2 -0
  158. package/dist/gs/math/nextafter.gs.js +66 -0
  159. package/dist/gs/math/nextafter.gs.js.map +1 -0
  160. package/dist/gs/math/pow.gs.d.ts +3 -0
  161. package/dist/gs/math/pow.gs.js +40 -0
  162. package/dist/gs/math/pow.gs.js.map +1 -0
  163. package/dist/gs/math/pow10.gs.d.ts +1 -0
  164. package/dist/gs/math/pow10.gs.js +14 -0
  165. package/dist/gs/math/pow10.gs.js.map +1 -0
  166. package/dist/gs/math/remainder.gs.d.ts +2 -0
  167. package/dist/gs/math/remainder.gs.js +25 -0
  168. package/dist/gs/math/remainder.gs.js.map +1 -0
  169. package/dist/gs/math/signbit.gs.d.ts +1 -0
  170. package/dist/gs/math/signbit.gs.js +5 -0
  171. package/dist/gs/math/signbit.gs.js.map +1 -0
  172. package/dist/gs/math/sin.gs.d.ts +4 -0
  173. package/dist/gs/math/sin.gs.js +29 -0
  174. package/dist/gs/math/sin.gs.js.map +1 -0
  175. package/dist/gs/math/sincos.gs.d.ts +1 -0
  176. package/dist/gs/math/sincos.gs.js +11 -0
  177. package/dist/gs/math/sincos.gs.js.map +1 -0
  178. package/dist/gs/math/sinh.gs.d.ts +4 -0
  179. package/dist/gs/math/sinh.gs.js +27 -0
  180. package/dist/gs/math/sinh.gs.js.map +1 -0
  181. package/dist/gs/math/sqrt.gs.d.ts +2 -0
  182. package/dist/gs/math/sqrt.gs.js +15 -0
  183. package/dist/gs/math/sqrt.gs.js.map +1 -0
  184. package/dist/gs/math/tan.gs.d.ts +2 -0
  185. package/dist/gs/math/tan.gs.js +17 -0
  186. package/dist/gs/math/tan.gs.js.map +1 -0
  187. package/dist/gs/math/tanh.gs.d.ts +2 -0
  188. package/dist/gs/math/tanh.gs.js +17 -0
  189. package/dist/gs/math/tanh.gs.js.map +1 -0
  190. package/dist/gs/math/trig_reduce.gs.d.ts +1 -0
  191. package/dist/gs/math/trig_reduce.gs.js +62 -0
  192. package/dist/gs/math/trig_reduce.gs.js.map +1 -0
  193. package/dist/gs/math/unsafe.gs.d.ts +4 -0
  194. package/dist/gs/math/unsafe.gs.js +47 -0
  195. package/dist/gs/math/unsafe.gs.js.map +1 -0
  196. package/dist/gs/slices/slices.d.ts +6 -0
  197. package/dist/gs/slices/slices.js +8 -0
  198. package/dist/gs/slices/slices.js.map +1 -1
  199. package/dist/gs/strconv/atob.gs.d.ts +4 -0
  200. package/dist/gs/strconv/atob.gs.js +42 -0
  201. package/dist/gs/strconv/atob.gs.js.map +1 -0
  202. package/dist/gs/strconv/atof.gs.d.ts +2 -0
  203. package/dist/gs/strconv/atof.gs.js +51 -0
  204. package/dist/gs/strconv/atof.gs.js.map +1 -0
  205. package/dist/gs/strconv/atoi.gs.d.ts +33 -0
  206. package/dist/gs/strconv/atoi.gs.js +200 -0
  207. package/dist/gs/strconv/atoi.gs.js.map +1 -0
  208. package/dist/gs/strconv/doc.gs.d.ts +1 -0
  209. package/dist/gs/strconv/doc.gs.js +2 -0
  210. package/dist/gs/strconv/doc.gs.js.map +1 -0
  211. package/dist/gs/strconv/ftoa.gs.d.ts +3 -0
  212. package/dist/gs/strconv/ftoa.gs.js +58 -0
  213. package/dist/gs/strconv/ftoa.gs.js.map +1 -0
  214. package/dist/gs/strconv/index.d.ts +6 -0
  215. package/dist/gs/strconv/index.js +7 -0
  216. package/dist/gs/strconv/index.js.map +1 -0
  217. package/dist/gs/strconv/itoa.gs.d.ts +6 -0
  218. package/dist/gs/strconv/itoa.gs.js +37 -0
  219. package/dist/gs/strconv/itoa.gs.js.map +1 -0
  220. package/dist/gs/strconv/quote.gs.d.ts +19 -0
  221. package/dist/gs/strconv/quote.gs.js +217 -0
  222. package/dist/gs/strconv/quote.gs.js.map +1 -0
  223. package/dist/gs/strings/index.d.ts +3 -0
  224. package/dist/gs/strings/index.js +4 -0
  225. package/dist/gs/strings/index.js.map +1 -1
  226. package/dist/gs/strings/replace.d.ts +0 -74
  227. package/dist/gs/strings/replace.js +6 -204
  228. package/dist/gs/strings/replace.js.map +1 -1
  229. package/dist/gs/strings/search.d.ts +0 -1
  230. package/dist/gs/strings/search.js +0 -21
  231. package/dist/gs/strings/search.js.map +1 -1
  232. package/gs/builtin/builtin.ts +40 -0
  233. package/gs/builtin/map.ts +12 -7
  234. package/gs/builtin/slice.ts +174 -34
  235. package/gs/github.com/pkg/errors/errors.ts +307 -0
  236. package/gs/github.com/pkg/errors/go113.ts +39 -0
  237. package/gs/github.com/pkg/errors/index.ts +3 -0
  238. package/gs/github.com/pkg/errors/stack.ts +127 -0
  239. package/gs/maps/index.ts +2 -0
  240. package/gs/maps/iter.ts +67 -0
  241. package/gs/maps/maps.ts +89 -0
  242. package/gs/math/TODO.md +156 -0
  243. package/gs/math/abs.gs.test.ts +29 -0
  244. package/gs/math/abs.gs.ts +13 -0
  245. package/gs/math/acosh.gs.test.ts +39 -0
  246. package/gs/math/acosh.gs.ts +21 -0
  247. package/gs/math/asin.gs.test.ts +66 -0
  248. package/gs/math/asin.gs.ts +27 -0
  249. package/gs/math/asinh.gs.test.ts +37 -0
  250. package/gs/math/asinh.gs.ts +21 -0
  251. package/gs/math/atan.gs.test.ts +49 -0
  252. package/gs/math/atan.gs.ts +27 -0
  253. package/gs/math/atan2.gs.test.ts +55 -0
  254. package/gs/math/atan2.gs.ts +37 -0
  255. package/gs/math/atanh.gs.test.ts +47 -0
  256. package/gs/math/atanh.gs.ts +21 -0
  257. package/gs/math/bits.gs.test.ts +88 -0
  258. package/gs/math/bits.gs.ts +61 -0
  259. package/gs/math/cbrt.gs.test.ts +57 -0
  260. package/gs/math/cbrt.gs.ts +20 -0
  261. package/gs/math/const.gs.test.ts +54 -0
  262. package/gs/math/const.gs.ts +93 -0
  263. package/gs/math/copysign.gs.test.ts +44 -0
  264. package/gs/math/copysign.gs.ts +27 -0
  265. package/gs/math/dim.gs.test.ts +102 -0
  266. package/gs/math/dim.gs.ts +84 -0
  267. package/gs/math/erf.gs.test.ts +92 -0
  268. package/gs/math/erf.gs.ts +409 -0
  269. package/gs/math/erfinv.gs.test.ts +104 -0
  270. package/gs/math/erfinv.gs.ts +169 -0
  271. package/gs/math/exp.gs.test.ts +82 -0
  272. package/gs/math/exp.gs.ts +39 -0
  273. package/gs/math/expm1.gs.test.ts +48 -0
  274. package/gs/math/expm1.gs.ts +23 -0
  275. package/gs/math/floor.gs.test.ts +146 -0
  276. package/gs/math/floor.gs.ts +88 -0
  277. package/gs/math/fma.gs.test.ts +83 -0
  278. package/gs/math/fma.gs.ts +7 -0
  279. package/gs/math/frexp.gs.test.ts +146 -0
  280. package/gs/math/frexp.gs.ts +37 -0
  281. package/gs/math/gamma.gs.test.ts +66 -0
  282. package/gs/math/gamma.gs.ts +158 -0
  283. package/gs/math/hypot.gs.test.ts +73 -0
  284. package/gs/math/hypot.gs.ts +23 -0
  285. package/gs/math/index.ts +44 -0
  286. package/gs/math/j0.gs.test.ts +74 -0
  287. package/gs/math/j0.gs.ts +257 -0
  288. package/gs/math/j1.gs.test.ts +81 -0
  289. package/gs/math/j1.gs.ts +231 -0
  290. package/gs/math/jn.gs.test.ts +133 -0
  291. package/gs/math/jn.gs.ts +447 -0
  292. package/gs/math/ldexp.gs.test.ts +128 -0
  293. package/gs/math/ldexp.gs.ts +28 -0
  294. package/gs/math/lgamma.gs.test.ts +102 -0
  295. package/gs/math/lgamma.gs.ts +251 -0
  296. package/gs/math/log.gs.test.ts +40 -0
  297. package/gs/math/log.gs.ts +21 -0
  298. package/gs/math/log10.gs.test.ts +80 -0
  299. package/gs/math/log10.gs.ts +25 -0
  300. package/gs/math/log1p.gs.test.ts +55 -0
  301. package/gs/math/log1p.gs.ts +24 -0
  302. package/gs/math/logb.gs.test.ts +87 -0
  303. package/gs/math/logb.gs.ts +54 -0
  304. package/gs/math/mod.gs.test.ts +64 -0
  305. package/gs/math/mod.gs.ts +36 -0
  306. package/gs/math/modf.gs.test.ts +80 -0
  307. package/gs/math/modf.gs.ts +32 -0
  308. package/gs/math/nextafter.gs.test.ts +107 -0
  309. package/gs/math/nextafter.gs.ts +71 -0
  310. package/gs/math/pow.gs.test.ts +103 -0
  311. package/gs/math/pow.gs.ts +55 -0
  312. package/gs/math/pow10.gs.test.ts +58 -0
  313. package/gs/math/pow10.gs.ts +19 -0
  314. package/gs/math/remainder.gs.test.ts +70 -0
  315. package/gs/math/remainder.gs.ts +33 -0
  316. package/gs/math/signbit.gs.test.ts +33 -0
  317. package/gs/math/signbit.gs.ts +8 -0
  318. package/gs/math/sin.gs.test.ts +83 -0
  319. package/gs/math/sin.gs.ts +38 -0
  320. package/gs/math/sincos.gs.test.ts +91 -0
  321. package/gs/math/sincos.gs.ts +15 -0
  322. package/gs/math/sinh.gs.test.ts +66 -0
  323. package/gs/math/sinh.gs.ts +34 -0
  324. package/gs/math/sqrt.gs.test.ts +49 -0
  325. package/gs/math/sqrt.gs.ts +20 -0
  326. package/gs/math/tan.gs.test.ts +50 -0
  327. package/gs/math/tan.gs.ts +23 -0
  328. package/gs/math/tanh.gs.test.ts +52 -0
  329. package/gs/math/tanh.gs.ts +23 -0
  330. package/gs/math/trig_reduce.gs.ts +66 -0
  331. package/gs/math/unsafe.gs.ts +52 -0
  332. package/gs/slices/slices.ts +9 -0
  333. package/gs/strconv/atob.gs.ts +45 -0
  334. package/gs/strconv/atof.gs.ts +60 -0
  335. package/gs/strconv/atoi.gs.ts +243 -0
  336. package/gs/strconv/doc.gs.ts +2 -0
  337. package/gs/strconv/ftoa.gs.ts +66 -0
  338. package/gs/strconv/index.ts +6 -0
  339. package/gs/strconv/itoa.gs.ts +41 -0
  340. package/gs/strconv/quote.gs.ts +245 -0
  341. package/gs/strings/index.ts +4 -0
  342. package/gs/strings/replace.ts +9 -237
  343. package/gs/strings/search.ts +0 -28
  344. package/package.json +1 -1
  345. package/gs/stringslite/godoc.txt +0 -17
  346. package/gs/stringslite/index.ts +0 -1
  347. package/gs/stringslite/strings.ts +0 -82
@@ -222,10 +222,25 @@ func (c *GoToTSCompiler) WriteStmtAssign(exp *ast.AssignStmt) error {
222
222
  }
223
223
 
224
224
  // For simple cases without selector expressions, use array destructuring
225
+ // Add semicolon before destructuring assignment to prevent TypeScript
226
+ // from interpreting it as array access on the previous line
227
+ if tok != token.DEFINE {
228
+ c.tsw.WriteLiterally(";")
229
+ }
225
230
  c.tsw.WriteLiterally("[")
226
231
 
232
+ // Find the last non-blank identifier to avoid trailing commas
233
+ lastNonBlankIndex := -1
234
+ for i := len(lhs) - 1; i >= 0; i-- {
235
+ if ident, ok := lhs[i].(*ast.Ident); !ok || ident.Name != "_" {
236
+ lastNonBlankIndex = i
237
+ break
238
+ }
239
+ }
240
+
227
241
  for i, lhsExpr := range lhs {
228
- if i != 0 {
242
+ // Write comma before non-first elements
243
+ if i > 0 {
229
244
  c.tsw.WriteLiterally(", ")
230
245
  }
231
246
 
@@ -234,6 +249,7 @@ func (c *GoToTSCompiler) WriteStmtAssign(exp *ast.AssignStmt) error {
234
249
  if ident.Name != "_" {
235
250
  c.WriteIdent(ident, false)
236
251
  }
252
+ // For blank identifiers, we write nothing (empty slot)
237
253
  } else if selectorExpr, ok := lhsExpr.(*ast.SelectorExpr); ok {
238
254
  // Handle selector expressions (e.g., a.b) by using WriteValueExpr
239
255
  if err := c.WriteValueExpr(selectorExpr); err != nil {
@@ -263,6 +279,11 @@ func (c *GoToTSCompiler) WriteStmtAssign(exp *ast.AssignStmt) error {
263
279
  // Should not happen for valid Go code in this context, but handle defensively
264
280
  return errors.Errorf("unhandled LHS expression in destructuring: %T", lhsExpr)
265
281
  }
282
+
283
+ // Stop writing if we've reached the last non-blank element
284
+ if i == lastNonBlankIndex {
285
+ break
286
+ }
266
287
  }
267
288
  c.tsw.WriteLiterally("] = ")
268
289
 
@@ -276,122 +297,106 @@ func (c *GoToTSCompiler) WriteStmtAssign(exp *ast.AssignStmt) error {
276
297
  }
277
298
 
278
299
  // writeMapLookupWithExists handles the map comma-ok idiom: value, exists := myMap[key]
279
- // Note: We don't use WriteIndexExpr here because we need to handle .has() and .get() separately
300
+ // Uses array destructuring with the tuple-returning $.mapGet function
280
301
  writeMapLookupWithExists := func(lhs []ast.Expr, indexExpr *ast.IndexExpr, tok token.Token) error {
281
302
  // First check that we have exactly two LHS expressions (value and exists)
282
303
  if len(lhs) != 2 {
283
304
  return fmt.Errorf("map comma-ok idiom requires exactly 2 variables on LHS, got %d", len(lhs))
284
305
  }
285
306
 
286
- // Check for blank identifiers and get variable names
307
+ // Check for blank identifiers
287
308
  valueIsBlank := false
288
309
  existsIsBlank := false
289
- var valueName string
290
- var existsName string
291
310
 
292
- if valIdent, ok := lhs[0].(*ast.Ident); ok {
293
- if valIdent.Name == "_" {
294
- valueIsBlank = true
295
- } else {
296
- valueName = valIdent.Name
297
- }
298
- } else {
299
- return fmt.Errorf("unhandled LHS expression type for value in map comma-ok: %T", lhs[0])
311
+ if valIdent, ok := lhs[0].(*ast.Ident); ok && valIdent.Name == "_" {
312
+ valueIsBlank = true
313
+ }
314
+ if existsIdent, ok := lhs[1].(*ast.Ident); ok && existsIdent.Name == "_" {
315
+ existsIsBlank = true
300
316
  }
301
317
 
302
- if existsIdent, ok := lhs[1].(*ast.Ident); ok {
303
- if existsIdent.Name == "_" {
304
- existsIsBlank = true
305
- } else {
306
- existsName = existsIdent.Name
307
- }
318
+ // Use array destructuring with mapGet tuple return
319
+ if tok == token.DEFINE {
320
+ c.tsw.WriteLiterally("let ")
308
321
  } else {
309
- return fmt.Errorf("unhandled LHS expression type for exists in map comma-ok: %T", lhs[1])
322
+ // Add semicolon before destructuring assignment to prevent TypeScript
323
+ // from interpreting it as array access on the previous line
324
+ c.tsw.WriteLiterally(";")
310
325
  }
311
326
 
312
- // Declare variables if using := and not blank
313
- if tok == token.DEFINE {
314
- if !valueIsBlank {
315
- c.tsw.WriteLiterally("let ")
316
- c.tsw.WriteLiterally(valueName)
317
- // TODO: Add type annotation based on map value type
318
- c.tsw.WriteLine("")
319
- }
320
- if !existsIsBlank {
321
- c.tsw.WriteLiterally("let ")
322
- c.tsw.WriteLiterally(existsName)
323
- c.tsw.WriteLiterally(": boolean") // exists is always boolean
324
- c.tsw.WriteLine("")
327
+ c.tsw.WriteLiterally("[")
328
+
329
+ // Write LHS variables, handling blanks
330
+ if !valueIsBlank {
331
+ if err := c.WriteValueExpr(lhs[0]); err != nil {
332
+ return err
325
333
  }
326
334
  }
335
+ // Note: for blank identifiers, we just omit the variable name entirely
336
+
337
+ c.tsw.WriteLiterally(", ")
327
338
 
328
- // Assign 'exists'
329
339
  if !existsIsBlank {
330
- c.tsw.WriteLiterally(existsName)
331
- c.tsw.WriteLiterally(" = ")
332
- c.tsw.WriteLiterally("$.mapHas(")
333
- if err := c.WriteValueExpr(indexExpr.X); err != nil { // Map
340
+ if err := c.WriteValueExpr(lhs[1]); err != nil {
334
341
  return err
335
342
  }
336
- c.tsw.WriteLiterally(", ")
337
- if err := c.WriteValueExpr(indexExpr.Index); err != nil { // Key
338
- return err
339
- }
340
- c.tsw.WriteLiterally(")")
341
- c.tsw.WriteLine("")
342
343
  }
344
+ // Note: for blank identifiers, we just omit the variable name entirely
343
345
 
344
- // Assign 'value'
345
- if !valueIsBlank {
346
- c.tsw.WriteLiterally(valueName)
347
- c.tsw.WriteLiterally(" = ")
348
- c.tsw.WriteLiterally("$.mapGet(")
349
- if err := c.WriteValueExpr(indexExpr.X); err != nil { // Map
350
- return err
351
- }
352
- c.tsw.WriteLiterally(", ")
353
- if err := c.WriteValueExpr(indexExpr.Index); err != nil { // Key
354
- return err
355
- }
356
- c.tsw.WriteLiterally(", ")
357
- // Write the zero value for the map's value type
358
- if tv, ok := c.pkg.TypesInfo.Types[indexExpr.X]; ok {
359
- if mapType, isMap := tv.Type.Underlying().(*types.Map); isMap {
360
- c.WriteZeroValueForType(mapType.Elem())
346
+ c.tsw.WriteLiterally("] = $.mapGet(")
347
+
348
+ // Write map expression
349
+ if err := c.WriteValueExpr(indexExpr.X); err != nil {
350
+ return err
351
+ }
352
+
353
+ c.tsw.WriteLiterally(", ")
354
+
355
+ // Write key expression
356
+ if err := c.WriteValueExpr(indexExpr.Index); err != nil {
357
+ return err
358
+ }
359
+
360
+ c.tsw.WriteLiterally(", ")
361
+
362
+ // Write the zero value for the map's value type
363
+ if tv, ok := c.pkg.TypesInfo.Types[indexExpr.X]; ok {
364
+ if mapType, isMap := tv.Type.Underlying().(*types.Map); isMap {
365
+ c.WriteZeroValueForType(mapType.Elem())
366
+ } else if typeParam, isTypeParam := tv.Type.(*types.TypeParam); isTypeParam {
367
+ // Handle type parameter constrained to be a map type
368
+ constraint := typeParam.Constraint()
369
+ if constraint != nil {
370
+ underlying := constraint.Underlying()
371
+ if iface, isInterface := underlying.(*types.Interface); isInterface {
372
+ if hasMapConstraint(iface) {
373
+ // Get the value type from the constraint
374
+ mapValueType := getMapValueTypeFromConstraint(iface)
375
+ if mapValueType != nil {
376
+ c.WriteZeroValueForType(mapValueType)
377
+ } else {
378
+ c.tsw.WriteLiterally("null")
379
+ }
380
+ } else {
381
+ c.tsw.WriteLiterally("null")
382
+ }
383
+ } else {
384
+ c.tsw.WriteLiterally("null")
385
+ }
361
386
  } else {
362
- // Fallback zero value if type info is missing or not a map
363
387
  c.tsw.WriteLiterally("null")
364
388
  }
365
389
  } else {
390
+ // Fallback zero value if type info is missing or not a map
366
391
  c.tsw.WriteLiterally("null")
367
392
  }
368
- c.tsw.WriteLiterally(")")
369
- c.tsw.WriteLine("")
370
- } else if existsIsBlank {
371
- // If both are blank, still evaluate for side effects (though .has/.get are usually pure)
372
- // We add a ; otherwise TypeScript thinks we are invoking a function.
373
- c.tsw.WriteLiterally(";(") // Wrap in parens to make it an expression statement
374
- c.tsw.WriteLiterally("$.mapHas(")
375
- if err := c.WriteValueExpr(indexExpr.X); err != nil { // Map
376
- return err
377
- }
378
- c.tsw.WriteLiterally(", ")
379
- if err := c.WriteValueExpr(indexExpr.Index); err != nil { // Key
380
- return err
381
- }
382
- c.tsw.WriteLiterally("), ") // Evaluate .has
383
- c.tsw.WriteLiterally("$.mapGet(")
384
- if err := c.WriteValueExpr(indexExpr.X); err != nil { // Map
385
- return err
386
- }
387
- c.tsw.WriteLiterally(", ")
388
- if err := c.WriteValueExpr(indexExpr.Index); err != nil { // Key
389
- return err
390
- }
391
- c.tsw.WriteLiterally(", null))") // Evaluate .get with null as default
392
- c.tsw.WriteLine("")
393
+ } else {
394
+ c.tsw.WriteLiterally("null")
393
395
  }
394
396
 
397
+ c.tsw.WriteLiterally(")")
398
+ c.tsw.WriteLine("")
399
+
395
400
  return nil
396
401
  }
397
402
 
@@ -417,6 +422,8 @@ func (c *GoToTSCompiler) WriteStmtAssign(exp *ast.AssignStmt) error {
417
422
  }
418
423
  return nil
419
424
  }
425
+ // Handle general function calls that return multiple values
426
+ return writeMultiVarAssignFromCall(exp.Lhs, callExpr, exp.Tok)
420
427
  }
421
428
 
422
429
  if typeAssertExpr, ok := rhsExpr.(*ast.TypeAssertExpr); ok {
@@ -428,10 +435,22 @@ func (c *GoToTSCompiler) WriteStmtAssign(exp *ast.AssignStmt) error {
428
435
  if c.pkg != nil && c.pkg.TypesInfo != nil {
429
436
  tv, ok := c.pkg.TypesInfo.Types[indexExpr.X]
430
437
  if ok {
431
- // Check if it's a map type
438
+ // Check if it's a concrete map type
432
439
  if _, isMap := tv.Type.Underlying().(*types.Map); isMap {
433
440
  return writeMapLookupWithExists(exp.Lhs, indexExpr, exp.Tok)
434
441
  }
442
+ // Check if it's a type parameter constrained to be a map type
443
+ if typeParam, isTypeParam := tv.Type.(*types.TypeParam); isTypeParam {
444
+ constraint := typeParam.Constraint()
445
+ if constraint != nil {
446
+ underlying := constraint.Underlying()
447
+ if iface, isInterface := underlying.(*types.Interface); isInterface {
448
+ if hasMapConstraint(iface) {
449
+ return writeMapLookupWithExists(exp.Lhs, indexExpr, exp.Tok)
450
+ }
451
+ }
452
+ }
453
+ }
435
454
  }
436
455
  }
437
456
  }
@@ -441,8 +460,6 @@ func (c *GoToTSCompiler) WriteStmtAssign(exp *ast.AssignStmt) error {
441
460
  return c.writeChannelReceiveWithOk(exp.Lhs, unaryExpr, exp.Tok)
442
461
  }
443
462
  // If LHS count is not 2, fall through to error or other handling
444
- } else if callExpr, ok := rhsExpr.(*ast.CallExpr); ok {
445
- return writeMultiVarAssignFromCall(exp.Lhs, callExpr, exp.Tok)
446
463
  }
447
464
  // If none of the specific multi-assign patterns match, fall through to the error check below
448
465
  }
@@ -463,7 +480,27 @@ func (c *GoToTSCompiler) WriteStmtAssign(exp *ast.AssignStmt) error {
463
480
 
464
481
  // Ensure LHS and RHS have the same length for valid Go code in these cases
465
482
  if len(exp.Lhs) != len(exp.Rhs) {
466
- return fmt.Errorf("invalid assignment statement: LHS count (%d) != RHS count (%d)", len(exp.Lhs), len(exp.Rhs))
483
+ // Special case: allow multiple LHS with single RHS if RHS can produce multiple values
484
+ // This handles cases like: x, y := getValue() where getValue() returns multiple values
485
+ // or other expressions that can produce multiple values
486
+ if len(exp.Rhs) == 1 {
487
+ // Allow single RHS expressions that can produce multiple values:
488
+ // - Function calls that return multiple values
489
+ // - Type assertions with comma-ok
490
+ // - Map lookups with comma-ok
491
+ // - Channel receives with comma-ok
492
+ // The Go type checker should have already verified this is valid
493
+ rhsExpr := exp.Rhs[0]
494
+ switch rhsExpr.(type) {
495
+ case *ast.CallExpr, *ast.TypeAssertExpr, *ast.IndexExpr, *ast.UnaryExpr:
496
+ // These expression types can potentially produce multiple values
497
+ // Let the general assignment logic handle them
498
+ default:
499
+ return fmt.Errorf("invalid assignment statement: LHS count (%d) != RHS count (%d)", len(exp.Lhs), len(exp.Rhs))
500
+ }
501
+ } else {
502
+ return fmt.Errorf("invalid assignment statement: LHS count (%d) != RHS count (%d)", len(exp.Lhs), len(exp.Rhs))
503
+ }
467
504
  }
468
505
 
469
506
  // Handle multi-variable assignment (e.g., swaps) using writeAssignmentCore
@@ -4,6 +4,7 @@ import (
4
4
  "fmt"
5
5
  "go/ast"
6
6
  "go/token"
7
+ "go/types"
7
8
 
8
9
  "github.com/pkg/errors"
9
10
  )
@@ -64,7 +65,25 @@ func (c *GoToTSCompiler) WriteStmtForInit(stmt ast.Stmt) error {
64
65
  case *ast.AssignStmt:
65
66
  // Handle assignment in init (e.g., i := 0 or i = 0)
66
67
  // For TypeScript for-loop init, we need to handle multi-variable declarations differently
67
- if s.Tok == token.DEFINE && len(s.Lhs) > 1 && len(s.Rhs) > 0 {
68
+ if s.Tok == token.DEFINE && len(s.Lhs) > 1 && len(s.Rhs) == 1 {
69
+ // Handle the case where we have multiple LHS variables but only one RHS expression
70
+ // Use array destructuring for all cases including map comma-ok idiom
71
+ rhsExpr := s.Rhs[0]
72
+ c.tsw.WriteLiterally("let [")
73
+ for i, lhs := range s.Lhs {
74
+ if i > 0 {
75
+ c.tsw.WriteLiterally(", ")
76
+ }
77
+ if err := c.WriteValueExpr(lhs); err != nil {
78
+ return err
79
+ }
80
+ }
81
+ c.tsw.WriteLiterally("] = ")
82
+ if err := c.writeDestructuringValue(rhsExpr); err != nil {
83
+ return err
84
+ }
85
+ return nil
86
+ } else if s.Tok == token.DEFINE && len(s.Lhs) > 1 && len(s.Rhs) > 0 {
68
87
  // For loop initialization with multiple variables (e.g., let i = 0, j = 10)
69
88
  c.tsw.WriteLiterally("let ")
70
89
 
@@ -121,6 +140,64 @@ func (c *GoToTSCompiler) WriteStmtForInit(stmt ast.Stmt) error {
121
140
  }
122
141
  }
123
142
 
143
+ // writeDestructuringValue writes a value expression in a destructuring context.
144
+ // For map index expressions, it generates the full tuple without [0] indexing.
145
+ func (c *GoToTSCompiler) writeDestructuringValue(expr ast.Expr) error {
146
+ // Check if this is a map index expression that should return a tuple
147
+ if indexExpr, ok := expr.(*ast.IndexExpr); ok {
148
+ if tv, ok := c.pkg.TypesInfo.Types[indexExpr.X]; ok {
149
+ underlyingType := tv.Type.Underlying()
150
+ // Check if it's a map type
151
+ if mapType, isMap := underlyingType.(*types.Map); isMap {
152
+ c.tsw.WriteLiterally("$.mapGet(")
153
+ if err := c.WriteValueExpr(indexExpr.X); err != nil {
154
+ return err
155
+ }
156
+ c.tsw.WriteLiterally(", ")
157
+ if err := c.WriteValueExpr(indexExpr.Index); err != nil {
158
+ return err
159
+ }
160
+ c.tsw.WriteLiterally(", ")
161
+ // Write the zero value as the default value for mapGet
162
+ c.WriteZeroValueForType(mapType.Elem())
163
+ c.tsw.WriteLiterally(")") // Don't add [0] for destructuring
164
+ return nil
165
+ }
166
+ // Check if it's a type parameter constrained to be a map type
167
+ if typeParam, isTypeParam := tv.Type.(*types.TypeParam); isTypeParam {
168
+ constraint := typeParam.Constraint()
169
+ if constraint != nil {
170
+ underlying := constraint.Underlying()
171
+ if iface, isInterface := underlying.(*types.Interface); isInterface {
172
+ if hasMapConstraint(iface) {
173
+ c.tsw.WriteLiterally("$.mapGet(")
174
+ if err := c.WriteValueExpr(indexExpr.X); err != nil {
175
+ return err
176
+ }
177
+ c.tsw.WriteLiterally(", ")
178
+ if err := c.WriteValueExpr(indexExpr.Index); err != nil {
179
+ return err
180
+ }
181
+ c.tsw.WriteLiterally(", ")
182
+ // Generate the zero value as the default value for mapGet
183
+ mapValueType := getMapValueTypeFromConstraint(iface)
184
+ if mapValueType != nil {
185
+ c.WriteZeroValueForType(mapValueType)
186
+ } else {
187
+ c.tsw.WriteLiterally("null")
188
+ }
189
+ c.tsw.WriteLiterally(")") // Don't add [0] for destructuring
190
+ return nil
191
+ }
192
+ }
193
+ }
194
+ }
195
+ }
196
+ }
197
+ // For non-map expressions, use the regular WriteValueExpr
198
+ return c.WriteValueExpr(expr)
199
+ }
200
+
124
201
  // WriteStmtForPost translates the post-iteration part of a Go `for` loop header
125
202
  // (e.g., `i++` or `i, j = i+1, j-1` in `for ...; i++`) into its TypeScript
126
203
  // equivalent.