typenative 0.1.3 → 0.2.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.
Files changed (500) hide show
  1. package/.gitattributes +1 -0
  2. package/.github/workflows/ci.yml +1 -1
  3. package/.github/workflows/npm-publish-github-packages.yml +1 -1
  4. package/CHANGELOG.md +247 -0
  5. package/CONTRIBUTION.md +1 -1
  6. package/README.md +4 -4
  7. package/bin/cli.js +3 -1
  8. package/bin/go/bridge.js +919 -0
  9. package/bin/go/convert.js +238 -0
  10. package/bin/go/metadata.js +211 -0
  11. package/bin/go/overrides.js +68 -0
  12. package/bin/go/stdlib.generated.js +175 -0
  13. package/bin/index.js +294 -240
  14. package/bin/main.js +4 -1
  15. package/bin/node/assert.js +344 -0
  16. package/bin/node/async_hooks.js +273 -0
  17. package/bin/node/buffer.js +765 -0
  18. package/bin/node/child_process.js +600 -0
  19. package/bin/node/cluster.js +1002 -0
  20. package/bin/node/console.js +121 -0
  21. package/bin/node/core.js +111 -0
  22. package/bin/node/crypto.js +414 -0
  23. package/bin/node/crypto_keys.js +2685 -0
  24. package/bin/node/dgram.js +388 -0
  25. package/bin/node/diagnostics_channel.js +534 -0
  26. package/bin/node/dns.js +635 -0
  27. package/bin/node/events.js +743 -0
  28. package/bin/node/fetch.js +737 -0
  29. package/bin/node/fs.js +998 -0
  30. package/bin/node/http.js +1500 -0
  31. package/bin/node/http2.js +688 -0
  32. package/bin/node/net.js +1143 -0
  33. package/bin/node/os.js +257 -0
  34. package/bin/node/path.js +758 -0
  35. package/bin/node/process.js +316 -0
  36. package/bin/node/punycode.js +195 -0
  37. package/bin/node/querystring.js +143 -0
  38. package/bin/node/readline.js +299 -0
  39. package/bin/node/registry.js +161 -0
  40. package/bin/node/sqlite.js +1142 -0
  41. package/bin/node/stream.js +1221 -0
  42. package/bin/node/stream_web.js +2259 -0
  43. package/bin/node/string_decoder.js +101 -0
  44. package/bin/node/system_extra.js +661 -0
  45. package/bin/node/test.js +1068 -0
  46. package/bin/node/timers.js +250 -0
  47. package/bin/node/tls.js +719 -0
  48. package/bin/node/url.js +861 -0
  49. package/bin/node/util.js +1311 -0
  50. package/bin/node/util_extra.js +599 -0
  51. package/bin/node/worker_threads.js +745 -0
  52. package/bin/node/zlib.js +263 -0
  53. package/bin/transpiler.js +2650 -575
  54. package/bin/version.js +2 -0
  55. package/conformance.md +707 -241
  56. package/govendor/github.com/ncruces/go-sqlite3/LICENSE +21 -0
  57. package/govendor/github.com/ncruces/go-sqlite3/README.md +121 -0
  58. package/govendor/github.com/ncruces/go-sqlite3/backup.go +132 -0
  59. package/govendor/github.com/ncruces/go-sqlite3/blob.go +266 -0
  60. package/govendor/github.com/ncruces/go-sqlite3/config.go +397 -0
  61. package/govendor/github.com/ncruces/go-sqlite3/conn.go +540 -0
  62. package/govendor/github.com/ncruces/go-sqlite3/conn_127.go +93 -0
  63. package/govendor/github.com/ncruces/go-sqlite3/const.go +436 -0
  64. package/govendor/github.com/ncruces/go-sqlite3/context.go +222 -0
  65. package/govendor/github.com/ncruces/go-sqlite3/error.go +182 -0
  66. package/govendor/github.com/ncruces/go-sqlite3/ext.go +153 -0
  67. package/govendor/github.com/ncruces/go-sqlite3/func.go +309 -0
  68. package/govendor/github.com/ncruces/go-sqlite3/go.mod +3 -0
  69. package/govendor/github.com/ncruces/go-sqlite3/internal/dotlk/dotlk.go +29 -0
  70. package/govendor/github.com/ncruces/go-sqlite3/internal/dotlk/dotlk_other.go +13 -0
  71. package/govendor/github.com/ncruces/go-sqlite3/internal/dotlk/dotlk_unix.go +57 -0
  72. package/govendor/github.com/ncruces/go-sqlite3/internal/errutil/error.go +41 -0
  73. package/govendor/github.com/ncruces/go-sqlite3/internal/sqlite3_wrap/alloc.go +128 -0
  74. package/govendor/github.com/ncruces/go-sqlite3/internal/sqlite3_wrap/const.go +122 -0
  75. package/govendor/github.com/ncruces/go-sqlite3/internal/sqlite3_wrap/error.go +77 -0
  76. package/govendor/github.com/ncruces/go-sqlite3/internal/sqlite3_wrap/mem.go +116 -0
  77. package/govendor/github.com/ncruces/go-sqlite3/internal/sqlite3_wrap/mem_other.go +34 -0
  78. package/govendor/github.com/ncruces/go-sqlite3/internal/sqlite3_wrap/mem_unix.go +87 -0
  79. package/govendor/github.com/ncruces/go-sqlite3/internal/sqlite3_wrap/mem_windows.go +149 -0
  80. package/govendor/github.com/ncruces/go-sqlite3/internal/sqlite3_wrap/mmap_unix.go +80 -0
  81. package/govendor/github.com/ncruces/go-sqlite3/internal/sqlite3_wrap/mmap_windows.go +129 -0
  82. package/govendor/github.com/ncruces/go-sqlite3/internal/sqlite3_wrap/sys_windows.go +60 -0
  83. package/govendor/github.com/ncruces/go-sqlite3/internal/sqlite3_wrap/wrap.go +82 -0
  84. package/govendor/github.com/ncruces/go-sqlite3/internal/sqlite3_wrap/wrap_sys.go +113 -0
  85. package/govendor/github.com/ncruces/go-sqlite3/internal/sqlite3_wrap/wrap_vfs.go +181 -0
  86. package/govendor/github.com/ncruces/go-sqlite3/internal/testenv/env.go +55 -0
  87. package/govendor/github.com/ncruces/go-sqlite3/internal/util/json.go +54 -0
  88. package/govendor/github.com/ncruces/go-sqlite3/internal/util/json_v2.go +54 -0
  89. package/govendor/github.com/ncruces/go-sqlite3/internal/util/math.go +29 -0
  90. package/govendor/github.com/ncruces/go-sqlite3/internal/util/page.go +5 -0
  91. package/govendor/github.com/ncruces/go-sqlite3/internal/util/parse.go +142 -0
  92. package/govendor/github.com/ncruces/go-sqlite3/internal/util/pointer.go +3 -0
  93. package/govendor/github.com/ncruces/go-sqlite3/internal/util/reflect.go +10 -0
  94. package/govendor/github.com/ncruces/go-sqlite3/json.go +100 -0
  95. package/govendor/github.com/ncruces/go-sqlite3/json_v2.go +116 -0
  96. package/govendor/github.com/ncruces/go-sqlite3/pointer.go +13 -0
  97. package/govendor/github.com/ncruces/go-sqlite3/quote.go +140 -0
  98. package/govendor/github.com/ncruces/go-sqlite3/stmt.go +692 -0
  99. package/govendor/github.com/ncruces/go-sqlite3/time.go +360 -0
  100. package/govendor/github.com/ncruces/go-sqlite3/txn.go +374 -0
  101. package/govendor/github.com/ncruces/go-sqlite3/value.go +212 -0
  102. package/govendor/github.com/ncruces/go-sqlite3/vfs/README.md +133 -0
  103. package/govendor/github.com/ncruces/go-sqlite3/vfs/api.go +239 -0
  104. package/govendor/github.com/ncruces/go-sqlite3/vfs/cksm.go +143 -0
  105. package/govendor/github.com/ncruces/go-sqlite3/vfs/const.go +256 -0
  106. package/govendor/github.com/ncruces/go-sqlite3/vfs/file.go +260 -0
  107. package/govendor/github.com/ncruces/go-sqlite3/vfs/filename.go +187 -0
  108. package/govendor/github.com/ncruces/go-sqlite3/vfs/lock.go +128 -0
  109. package/govendor/github.com/ncruces/go-sqlite3/vfs/lock_other.go +23 -0
  110. package/govendor/github.com/ncruces/go-sqlite3/vfs/map.go +63 -0
  111. package/govendor/github.com/ncruces/go-sqlite3/vfs/map_other.go +13 -0
  112. package/govendor/github.com/ncruces/go-sqlite3/vfs/os_bsd.go +110 -0
  113. package/govendor/github.com/ncruces/go-sqlite3/vfs/os_darwin.go +131 -0
  114. package/govendor/github.com/ncruces/go-sqlite3/vfs/os_dotlk.go +140 -0
  115. package/govendor/github.com/ncruces/go-sqlite3/vfs/os_f2fs_linux.go +56 -0
  116. package/govendor/github.com/ncruces/go-sqlite3/vfs/os_linux.go +117 -0
  117. package/govendor/github.com/ncruces/go-sqlite3/vfs/os_ofd.go +59 -0
  118. package/govendor/github.com/ncruces/go-sqlite3/vfs/os_std.go +50 -0
  119. package/govendor/github.com/ncruces/go-sqlite3/vfs/os_std_alloc.go +19 -0
  120. package/govendor/github.com/ncruces/go-sqlite3/vfs/os_std_atomic.go +9 -0
  121. package/govendor/github.com/ncruces/go-sqlite3/vfs/os_std_rw.go +13 -0
  122. package/govendor/github.com/ncruces/go-sqlite3/vfs/os_std_sync.go +9 -0
  123. package/govendor/github.com/ncruces/go-sqlite3/vfs/os_std_temp.go +16 -0
  124. package/govendor/github.com/ncruces/go-sqlite3/vfs/os_unix.go +108 -0
  125. package/govendor/github.com/ncruces/go-sqlite3/vfs/os_windows.go +180 -0
  126. package/govendor/github.com/ncruces/go-sqlite3/vfs/registry.go +48 -0
  127. package/govendor/github.com/ncruces/go-sqlite3/vfs/shm.go +26 -0
  128. package/govendor/github.com/ncruces/go-sqlite3/vfs/shm_bsd.go +258 -0
  129. package/govendor/github.com/ncruces/go-sqlite3/vfs/shm_copy.go +90 -0
  130. package/govendor/github.com/ncruces/go-sqlite3/vfs/shm_dotlk.go +168 -0
  131. package/govendor/github.com/ncruces/go-sqlite3/vfs/shm_memlk.go +52 -0
  132. package/govendor/github.com/ncruces/go-sqlite3/vfs/shm_ofd.go +185 -0
  133. package/govendor/github.com/ncruces/go-sqlite3/vfs/shm_other.go +21 -0
  134. package/govendor/github.com/ncruces/go-sqlite3/vfs/shm_windows.go +124 -0
  135. package/govendor/github.com/ncruces/go-sqlite3/vfs/vfs.go +455 -0
  136. package/govendor/github.com/ncruces/go-sqlite3/vtab.go +677 -0
  137. package/govendor/github.com/ncruces/go-sqlite3/wrap.go +48 -0
  138. package/govendor/github.com/ncruces/go-sqlite3-wasm/v6/LICENSE +18 -0
  139. package/govendor/github.com/ncruces/go-sqlite3-wasm/v6/README.md +11 -0
  140. package/govendor/github.com/ncruces/go-sqlite3-wasm/v6/go.mod +3 -0
  141. package/govendor/github.com/ncruces/go-sqlite3-wasm/v6/libc.go +215 -0
  142. package/govendor/github.com/ncruces/go-sqlite3-wasm/v6/sqlite3.dat +0 -0
  143. package/govendor/github.com/ncruces/go-sqlite3-wasm/v6/sqlite3.go +157903 -0
  144. package/govendor/github.com/ncruces/go-sqlite3-wasm/v6/tools.sh +38 -0
  145. package/govendor/github.com/ncruces/julianday/LICENSE +21 -0
  146. package/govendor/github.com/ncruces/julianday/README.md +9 -0
  147. package/govendor/github.com/ncruces/julianday/go.mod +3 -0
  148. package/govendor/github.com/ncruces/julianday/julianday.go +124 -0
  149. package/govendor/golang.org/x/sys/LICENSE +27 -0
  150. package/govendor/golang.org/x/sys/PATENTS +22 -0
  151. package/govendor/golang.org/x/sys/go.mod +3 -0
  152. package/govendor/golang.org/x/sys/unix/README.md +184 -0
  153. package/govendor/golang.org/x/sys/unix/affinity_linux.go +189 -0
  154. package/govendor/golang.org/x/sys/unix/aliases.go +13 -0
  155. package/govendor/golang.org/x/sys/unix/asm_aix_ppc64.s +17 -0
  156. package/govendor/golang.org/x/sys/unix/asm_bsd_386.s +27 -0
  157. package/govendor/golang.org/x/sys/unix/asm_bsd_amd64.s +27 -0
  158. package/govendor/golang.org/x/sys/unix/asm_bsd_arm.s +27 -0
  159. package/govendor/golang.org/x/sys/unix/asm_bsd_arm64.s +27 -0
  160. package/govendor/golang.org/x/sys/unix/asm_bsd_ppc64.s +29 -0
  161. package/govendor/golang.org/x/sys/unix/asm_bsd_riscv64.s +27 -0
  162. package/govendor/golang.org/x/sys/unix/asm_linux_386.s +65 -0
  163. package/govendor/golang.org/x/sys/unix/asm_linux_amd64.s +57 -0
  164. package/govendor/golang.org/x/sys/unix/asm_linux_arm.s +56 -0
  165. package/govendor/golang.org/x/sys/unix/asm_linux_arm64.s +50 -0
  166. package/govendor/golang.org/x/sys/unix/asm_linux_loong64.s +51 -0
  167. package/govendor/golang.org/x/sys/unix/asm_linux_mips64x.s +54 -0
  168. package/govendor/golang.org/x/sys/unix/asm_linux_mipsx.s +52 -0
  169. package/govendor/golang.org/x/sys/unix/asm_linux_ppc64x.s +42 -0
  170. package/govendor/golang.org/x/sys/unix/asm_linux_riscv64.s +47 -0
  171. package/govendor/golang.org/x/sys/unix/asm_linux_s390x.s +54 -0
  172. package/govendor/golang.org/x/sys/unix/asm_openbsd_mips64.s +29 -0
  173. package/govendor/golang.org/x/sys/unix/asm_solaris_amd64.s +17 -0
  174. package/govendor/golang.org/x/sys/unix/asm_zos_s390x.s +382 -0
  175. package/govendor/golang.org/x/sys/unix/auxv.go +36 -0
  176. package/govendor/golang.org/x/sys/unix/auxv_unsupported.go +13 -0
  177. package/govendor/golang.org/x/sys/unix/bluetooth_linux.go +36 -0
  178. package/govendor/golang.org/x/sys/unix/bpxsvc_zos.go +657 -0
  179. package/govendor/golang.org/x/sys/unix/bpxsvc_zos.s +192 -0
  180. package/govendor/golang.org/x/sys/unix/cap_freebsd.go +195 -0
  181. package/govendor/golang.org/x/sys/unix/constants.go +13 -0
  182. package/govendor/golang.org/x/sys/unix/dev_aix_ppc.go +26 -0
  183. package/govendor/golang.org/x/sys/unix/dev_aix_ppc64.go +28 -0
  184. package/govendor/golang.org/x/sys/unix/dev_darwin.go +24 -0
  185. package/govendor/golang.org/x/sys/unix/dev_dragonfly.go +30 -0
  186. package/govendor/golang.org/x/sys/unix/dev_freebsd.go +30 -0
  187. package/govendor/golang.org/x/sys/unix/dev_linux.go +42 -0
  188. package/govendor/golang.org/x/sys/unix/dev_netbsd.go +29 -0
  189. package/govendor/golang.org/x/sys/unix/dev_openbsd.go +29 -0
  190. package/govendor/golang.org/x/sys/unix/dev_zos.go +28 -0
  191. package/govendor/golang.org/x/sys/unix/dirent.go +102 -0
  192. package/govendor/golang.org/x/sys/unix/endian_big.go +9 -0
  193. package/govendor/golang.org/x/sys/unix/endian_little.go +9 -0
  194. package/govendor/golang.org/x/sys/unix/env_unix.go +31 -0
  195. package/govendor/golang.org/x/sys/unix/fcntl.go +36 -0
  196. package/govendor/golang.org/x/sys/unix/fcntl_darwin.go +24 -0
  197. package/govendor/golang.org/x/sys/unix/fcntl_linux_32bit.go +13 -0
  198. package/govendor/golang.org/x/sys/unix/fdset.go +27 -0
  199. package/govendor/golang.org/x/sys/unix/gccgo.go +59 -0
  200. package/govendor/golang.org/x/sys/unix/gccgo_c.c +44 -0
  201. package/govendor/golang.org/x/sys/unix/gccgo_linux_amd64.go +20 -0
  202. package/govendor/golang.org/x/sys/unix/ifreq_linux.go +145 -0
  203. package/govendor/golang.org/x/sys/unix/ioctl_linux.go +341 -0
  204. package/govendor/golang.org/x/sys/unix/ioctl_signed.go +74 -0
  205. package/govendor/golang.org/x/sys/unix/ioctl_unsigned.go +74 -0
  206. package/govendor/golang.org/x/sys/unix/ioctl_zos.go +71 -0
  207. package/govendor/golang.org/x/sys/unix/mkall.sh +250 -0
  208. package/govendor/golang.org/x/sys/unix/mkerrors.sh +807 -0
  209. package/govendor/golang.org/x/sys/unix/mmap_nomremap.go +13 -0
  210. package/govendor/golang.org/x/sys/unix/mremap.go +57 -0
  211. package/govendor/golang.org/x/sys/unix/pagesize_unix.go +15 -0
  212. package/govendor/golang.org/x/sys/unix/pledge_openbsd.go +111 -0
  213. package/govendor/golang.org/x/sys/unix/ptrace_darwin.go +11 -0
  214. package/govendor/golang.org/x/sys/unix/ptrace_ios.go +11 -0
  215. package/govendor/golang.org/x/sys/unix/race.go +30 -0
  216. package/govendor/golang.org/x/sys/unix/race0.go +25 -0
  217. package/govendor/golang.org/x/sys/unix/readdirent_getdents.go +12 -0
  218. package/govendor/golang.org/x/sys/unix/readdirent_getdirentries.go +19 -0
  219. package/govendor/golang.org/x/sys/unix/readv_unix.go +103 -0
  220. package/govendor/golang.org/x/sys/unix/sockcmsg_dragonfly.go +16 -0
  221. package/govendor/golang.org/x/sys/unix/sockcmsg_linux.go +85 -0
  222. package/govendor/golang.org/x/sys/unix/sockcmsg_unix.go +106 -0
  223. package/govendor/golang.org/x/sys/unix/sockcmsg_unix_other.go +46 -0
  224. package/govendor/golang.org/x/sys/unix/sockcmsg_zos.go +58 -0
  225. package/govendor/golang.org/x/sys/unix/symaddr_zos_s390x.s +75 -0
  226. package/govendor/golang.org/x/sys/unix/syscall.go +86 -0
  227. package/govendor/golang.org/x/sys/unix/syscall_aix.go +582 -0
  228. package/govendor/golang.org/x/sys/unix/syscall_aix_ppc.go +52 -0
  229. package/govendor/golang.org/x/sys/unix/syscall_aix_ppc64.go +83 -0
  230. package/govendor/golang.org/x/sys/unix/syscall_bsd.go +609 -0
  231. package/govendor/golang.org/x/sys/unix/syscall_darwin.go +711 -0
  232. package/govendor/golang.org/x/sys/unix/syscall_darwin_amd64.go +50 -0
  233. package/govendor/golang.org/x/sys/unix/syscall_darwin_arm64.go +50 -0
  234. package/govendor/golang.org/x/sys/unix/syscall_darwin_libSystem.go +26 -0
  235. package/govendor/golang.org/x/sys/unix/syscall_dragonfly.go +359 -0
  236. package/govendor/golang.org/x/sys/unix/syscall_dragonfly_amd64.go +56 -0
  237. package/govendor/golang.org/x/sys/unix/syscall_freebsd.go +455 -0
  238. package/govendor/golang.org/x/sys/unix/syscall_freebsd_386.go +64 -0
  239. package/govendor/golang.org/x/sys/unix/syscall_freebsd_amd64.go +64 -0
  240. package/govendor/golang.org/x/sys/unix/syscall_freebsd_arm.go +60 -0
  241. package/govendor/golang.org/x/sys/unix/syscall_freebsd_arm64.go +60 -0
  242. package/govendor/golang.org/x/sys/unix/syscall_freebsd_riscv64.go +60 -0
  243. package/govendor/golang.org/x/sys/unix/syscall_hurd.go +30 -0
  244. package/govendor/golang.org/x/sys/unix/syscall_hurd_386.go +28 -0
  245. package/govendor/golang.org/x/sys/unix/syscall_illumos.go +78 -0
  246. package/govendor/golang.org/x/sys/unix/syscall_linux.go +2574 -0
  247. package/govendor/golang.org/x/sys/unix/syscall_linux_386.go +313 -0
  248. package/govendor/golang.org/x/sys/unix/syscall_linux_alarm.go +12 -0
  249. package/govendor/golang.org/x/sys/unix/syscall_linux_amd64.go +144 -0
  250. package/govendor/golang.org/x/sys/unix/syscall_linux_amd64_gc.go +12 -0
  251. package/govendor/golang.org/x/sys/unix/syscall_linux_arm.go +218 -0
  252. package/govendor/golang.org/x/sys/unix/syscall_linux_arm64.go +188 -0
  253. package/govendor/golang.org/x/sys/unix/syscall_linux_gc.go +14 -0
  254. package/govendor/golang.org/x/sys/unix/syscall_linux_gc_386.go +16 -0
  255. package/govendor/golang.org/x/sys/unix/syscall_linux_gc_arm.go +13 -0
  256. package/govendor/golang.org/x/sys/unix/syscall_linux_gccgo_386.go +30 -0
  257. package/govendor/golang.org/x/sys/unix/syscall_linux_gccgo_arm.go +20 -0
  258. package/govendor/golang.org/x/sys/unix/syscall_linux_loong64.go +220 -0
  259. package/govendor/golang.org/x/sys/unix/syscall_linux_mips64x.go +187 -0
  260. package/govendor/golang.org/x/sys/unix/syscall_linux_mipsx.go +173 -0
  261. package/govendor/golang.org/x/sys/unix/syscall_linux_ppc.go +203 -0
  262. package/govendor/golang.org/x/sys/unix/syscall_linux_ppc64x.go +114 -0
  263. package/govendor/golang.org/x/sys/unix/syscall_linux_riscv64.go +193 -0
  264. package/govendor/golang.org/x/sys/unix/syscall_linux_s390x.go +295 -0
  265. package/govendor/golang.org/x/sys/unix/syscall_linux_sparc64.go +111 -0
  266. package/govendor/golang.org/x/sys/unix/syscall_netbsd.go +388 -0
  267. package/govendor/golang.org/x/sys/unix/syscall_netbsd_386.go +37 -0
  268. package/govendor/golang.org/x/sys/unix/syscall_netbsd_amd64.go +37 -0
  269. package/govendor/golang.org/x/sys/unix/syscall_netbsd_arm.go +37 -0
  270. package/govendor/golang.org/x/sys/unix/syscall_netbsd_arm64.go +37 -0
  271. package/govendor/golang.org/x/sys/unix/syscall_openbsd.go +346 -0
  272. package/govendor/golang.org/x/sys/unix/syscall_openbsd_386.go +41 -0
  273. package/govendor/golang.org/x/sys/unix/syscall_openbsd_amd64.go +41 -0
  274. package/govendor/golang.org/x/sys/unix/syscall_openbsd_arm.go +41 -0
  275. package/govendor/golang.org/x/sys/unix/syscall_openbsd_arm64.go +41 -0
  276. package/govendor/golang.org/x/sys/unix/syscall_openbsd_libc.go +26 -0
  277. package/govendor/golang.org/x/sys/unix/syscall_openbsd_mips64.go +39 -0
  278. package/govendor/golang.org/x/sys/unix/syscall_openbsd_ppc64.go +41 -0
  279. package/govendor/golang.org/x/sys/unix/syscall_openbsd_riscv64.go +41 -0
  280. package/govendor/golang.org/x/sys/unix/syscall_solaris.go +1183 -0
  281. package/govendor/golang.org/x/sys/unix/syscall_solaris_amd64.go +27 -0
  282. package/govendor/golang.org/x/sys/unix/syscall_unix.go +619 -0
  283. package/govendor/golang.org/x/sys/unix/syscall_unix_gc.go +14 -0
  284. package/govendor/golang.org/x/sys/unix/syscall_unix_gc_ppc64x.go +22 -0
  285. package/govendor/golang.org/x/sys/unix/syscall_zos_s390x.go +3213 -0
  286. package/govendor/golang.org/x/sys/unix/sysvshm_linux.go +20 -0
  287. package/govendor/golang.org/x/sys/unix/sysvshm_unix.go +51 -0
  288. package/govendor/golang.org/x/sys/unix/sysvshm_unix_other.go +13 -0
  289. package/govendor/golang.org/x/sys/unix/timestruct.go +76 -0
  290. package/govendor/golang.org/x/sys/unix/unveil_openbsd.go +51 -0
  291. package/govendor/golang.org/x/sys/unix/vgetrandom_linux.go +13 -0
  292. package/govendor/golang.org/x/sys/unix/vgetrandom_unsupported.go +11 -0
  293. package/govendor/golang.org/x/sys/unix/xattr_bsd.go +280 -0
  294. package/govendor/golang.org/x/sys/unix/zerrors_aix_ppc.go +1384 -0
  295. package/govendor/golang.org/x/sys/unix/zerrors_aix_ppc64.go +1385 -0
  296. package/govendor/golang.org/x/sys/unix/zerrors_darwin_amd64.go +1922 -0
  297. package/govendor/golang.org/x/sys/unix/zerrors_darwin_arm64.go +1922 -0
  298. package/govendor/golang.org/x/sys/unix/zerrors_dragonfly_amd64.go +1737 -0
  299. package/govendor/golang.org/x/sys/unix/zerrors_freebsd_386.go +2042 -0
  300. package/govendor/golang.org/x/sys/unix/zerrors_freebsd_amd64.go +2039 -0
  301. package/govendor/golang.org/x/sys/unix/zerrors_freebsd_arm.go +2033 -0
  302. package/govendor/golang.org/x/sys/unix/zerrors_freebsd_arm64.go +2033 -0
  303. package/govendor/golang.org/x/sys/unix/zerrors_freebsd_riscv64.go +2147 -0
  304. package/govendor/golang.org/x/sys/unix/zerrors_linux.go +4209 -0
  305. package/govendor/golang.org/x/sys/unix/zerrors_linux_386.go +882 -0
  306. package/govendor/golang.org/x/sys/unix/zerrors_linux_amd64.go +882 -0
  307. package/govendor/golang.org/x/sys/unix/zerrors_linux_arm.go +887 -0
  308. package/govendor/golang.org/x/sys/unix/zerrors_linux_arm64.go +884 -0
  309. package/govendor/golang.org/x/sys/unix/zerrors_linux_loong64.go +874 -0
  310. package/govendor/golang.org/x/sys/unix/zerrors_linux_mips.go +888 -0
  311. package/govendor/golang.org/x/sys/unix/zerrors_linux_mips64.go +888 -0
  312. package/govendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go +888 -0
  313. package/govendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go +888 -0
  314. package/govendor/golang.org/x/sys/unix/zerrors_linux_ppc.go +940 -0
  315. package/govendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go +944 -0
  316. package/govendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go +944 -0
  317. package/govendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go +884 -0
  318. package/govendor/golang.org/x/sys/unix/zerrors_linux_s390x.go +943 -0
  319. package/govendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go +992 -0
  320. package/govendor/golang.org/x/sys/unix/zerrors_netbsd_386.go +1779 -0
  321. package/govendor/golang.org/x/sys/unix/zerrors_netbsd_amd64.go +1769 -0
  322. package/govendor/golang.org/x/sys/unix/zerrors_netbsd_arm.go +1758 -0
  323. package/govendor/golang.org/x/sys/unix/zerrors_netbsd_arm64.go +1769 -0
  324. package/govendor/golang.org/x/sys/unix/zerrors_openbsd_386.go +1905 -0
  325. package/govendor/golang.org/x/sys/unix/zerrors_openbsd_amd64.go +1905 -0
  326. package/govendor/golang.org/x/sys/unix/zerrors_openbsd_arm.go +1905 -0
  327. package/govendor/golang.org/x/sys/unix/zerrors_openbsd_arm64.go +1905 -0
  328. package/govendor/golang.org/x/sys/unix/zerrors_openbsd_mips64.go +1905 -0
  329. package/govendor/golang.org/x/sys/unix/zerrors_openbsd_ppc64.go +1904 -0
  330. package/govendor/golang.org/x/sys/unix/zerrors_openbsd_riscv64.go +1903 -0
  331. package/govendor/golang.org/x/sys/unix/zerrors_solaris_amd64.go +1556 -0
  332. package/govendor/golang.org/x/sys/unix/zerrors_zos_s390x.go +990 -0
  333. package/govendor/golang.org/x/sys/unix/zptrace_armnn_linux.go +40 -0
  334. package/govendor/golang.org/x/sys/unix/zptrace_linux_arm64.go +17 -0
  335. package/govendor/golang.org/x/sys/unix/zptrace_mipsnn_linux.go +49 -0
  336. package/govendor/golang.org/x/sys/unix/zptrace_mipsnnle_linux.go +49 -0
  337. package/govendor/golang.org/x/sys/unix/zptrace_x86_linux.go +79 -0
  338. package/govendor/golang.org/x/sys/unix/zsymaddr_zos_s390x.s +364 -0
  339. package/govendor/golang.org/x/sys/unix/zsyscall_aix_ppc.go +1461 -0
  340. package/govendor/golang.org/x/sys/unix/zsyscall_aix_ppc64.go +1420 -0
  341. package/govendor/golang.org/x/sys/unix/zsyscall_aix_ppc64_gc.go +1188 -0
  342. package/govendor/golang.org/x/sys/unix/zsyscall_aix_ppc64_gccgo.go +1069 -0
  343. package/govendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go +2728 -0
  344. package/govendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s +799 -0
  345. package/govendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go +2728 -0
  346. package/govendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s +799 -0
  347. package/govendor/golang.org/x/sys/unix/zsyscall_dragonfly_amd64.go +1666 -0
  348. package/govendor/golang.org/x/sys/unix/zsyscall_freebsd_386.go +1886 -0
  349. package/govendor/golang.org/x/sys/unix/zsyscall_freebsd_amd64.go +1886 -0
  350. package/govendor/golang.org/x/sys/unix/zsyscall_freebsd_arm.go +1886 -0
  351. package/govendor/golang.org/x/sys/unix/zsyscall_freebsd_arm64.go +1886 -0
  352. package/govendor/golang.org/x/sys/unix/zsyscall_freebsd_riscv64.go +1886 -0
  353. package/govendor/golang.org/x/sys/unix/zsyscall_illumos_amd64.go +101 -0
  354. package/govendor/golang.org/x/sys/unix/zsyscall_linux.go +2267 -0
  355. package/govendor/golang.org/x/sys/unix/zsyscall_linux_386.go +469 -0
  356. package/govendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go +636 -0
  357. package/govendor/golang.org/x/sys/unix/zsyscall_linux_arm.go +584 -0
  358. package/govendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go +535 -0
  359. package/govendor/golang.org/x/sys/unix/zsyscall_linux_loong64.go +469 -0
  360. package/govendor/golang.org/x/sys/unix/zsyscall_linux_mips.go +636 -0
  361. package/govendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go +630 -0
  362. package/govendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go +619 -0
  363. package/govendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go +636 -0
  364. package/govendor/golang.org/x/sys/unix/zsyscall_linux_ppc.go +641 -0
  365. package/govendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go +687 -0
  366. package/govendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go +687 -0
  367. package/govendor/golang.org/x/sys/unix/zsyscall_linux_riscv64.go +531 -0
  368. package/govendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go +478 -0
  369. package/govendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go +631 -0
  370. package/govendor/golang.org/x/sys/unix/zsyscall_netbsd_386.go +1848 -0
  371. package/govendor/golang.org/x/sys/unix/zsyscall_netbsd_amd64.go +1848 -0
  372. package/govendor/golang.org/x/sys/unix/zsyscall_netbsd_arm.go +1848 -0
  373. package/govendor/golang.org/x/sys/unix/zsyscall_netbsd_arm64.go +1848 -0
  374. package/govendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go +2407 -0
  375. package/govendor/golang.org/x/sys/unix/zsyscall_openbsd_386.s +719 -0
  376. package/govendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go +2407 -0
  377. package/govendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.s +719 -0
  378. package/govendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go +2407 -0
  379. package/govendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.s +719 -0
  380. package/govendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.go +2407 -0
  381. package/govendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.s +719 -0
  382. package/govendor/golang.org/x/sys/unix/zsyscall_openbsd_mips64.go +2407 -0
  383. package/govendor/golang.org/x/sys/unix/zsyscall_openbsd_mips64.s +719 -0
  384. package/govendor/golang.org/x/sys/unix/zsyscall_openbsd_ppc64.go +2407 -0
  385. package/govendor/golang.org/x/sys/unix/zsyscall_openbsd_ppc64.s +862 -0
  386. package/govendor/golang.org/x/sys/unix/zsyscall_openbsd_riscv64.go +2407 -0
  387. package/govendor/golang.org/x/sys/unix/zsyscall_openbsd_riscv64.s +719 -0
  388. package/govendor/golang.org/x/sys/unix/zsyscall_solaris_amd64.go +2217 -0
  389. package/govendor/golang.org/x/sys/unix/zsyscall_zos_s390x.go +3458 -0
  390. package/govendor/golang.org/x/sys/unix/zsysctl_openbsd_386.go +280 -0
  391. package/govendor/golang.org/x/sys/unix/zsysctl_openbsd_amd64.go +280 -0
  392. package/govendor/golang.org/x/sys/unix/zsysctl_openbsd_arm.go +280 -0
  393. package/govendor/golang.org/x/sys/unix/zsysctl_openbsd_arm64.go +280 -0
  394. package/govendor/golang.org/x/sys/unix/zsysctl_openbsd_mips64.go +280 -0
  395. package/govendor/golang.org/x/sys/unix/zsysctl_openbsd_ppc64.go +280 -0
  396. package/govendor/golang.org/x/sys/unix/zsysctl_openbsd_riscv64.go +281 -0
  397. package/govendor/golang.org/x/sys/unix/zsysnum_darwin_amd64.go +439 -0
  398. package/govendor/golang.org/x/sys/unix/zsysnum_darwin_arm64.go +437 -0
  399. package/govendor/golang.org/x/sys/unix/zsysnum_dragonfly_amd64.go +316 -0
  400. package/govendor/golang.org/x/sys/unix/zsysnum_freebsd_386.go +393 -0
  401. package/govendor/golang.org/x/sys/unix/zsysnum_freebsd_amd64.go +393 -0
  402. package/govendor/golang.org/x/sys/unix/zsysnum_freebsd_arm.go +393 -0
  403. package/govendor/golang.org/x/sys/unix/zsysnum_freebsd_arm64.go +393 -0
  404. package/govendor/golang.org/x/sys/unix/zsysnum_freebsd_riscv64.go +393 -0
  405. package/govendor/golang.org/x/sys/unix/zsysnum_linux_386.go +470 -0
  406. package/govendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go +394 -0
  407. package/govendor/golang.org/x/sys/unix/zsysnum_linux_arm.go +434 -0
  408. package/govendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go +337 -0
  409. package/govendor/golang.org/x/sys/unix/zsysnum_linux_loong64.go +334 -0
  410. package/govendor/golang.org/x/sys/unix/zsysnum_linux_mips.go +454 -0
  411. package/govendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go +384 -0
  412. package/govendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go +384 -0
  413. package/govendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go +454 -0
  414. package/govendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go +461 -0
  415. package/govendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go +433 -0
  416. package/govendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go +433 -0
  417. package/govendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go +338 -0
  418. package/govendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go +399 -0
  419. package/govendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go +413 -0
  420. package/govendor/golang.org/x/sys/unix/zsysnum_netbsd_386.go +274 -0
  421. package/govendor/golang.org/x/sys/unix/zsysnum_netbsd_amd64.go +274 -0
  422. package/govendor/golang.org/x/sys/unix/zsysnum_netbsd_arm.go +274 -0
  423. package/govendor/golang.org/x/sys/unix/zsysnum_netbsd_arm64.go +274 -0
  424. package/govendor/golang.org/x/sys/unix/zsysnum_openbsd_386.go +219 -0
  425. package/govendor/golang.org/x/sys/unix/zsysnum_openbsd_amd64.go +219 -0
  426. package/govendor/golang.org/x/sys/unix/zsysnum_openbsd_arm.go +219 -0
  427. package/govendor/golang.org/x/sys/unix/zsysnum_openbsd_arm64.go +218 -0
  428. package/govendor/golang.org/x/sys/unix/zsysnum_openbsd_mips64.go +221 -0
  429. package/govendor/golang.org/x/sys/unix/zsysnum_openbsd_ppc64.go +217 -0
  430. package/govendor/golang.org/x/sys/unix/zsysnum_openbsd_riscv64.go +218 -0
  431. package/govendor/golang.org/x/sys/unix/zsysnum_zos_s390x.go +2852 -0
  432. package/govendor/golang.org/x/sys/unix/ztypes_aix_ppc.go +353 -0
  433. package/govendor/golang.org/x/sys/unix/ztypes_aix_ppc64.go +357 -0
  434. package/govendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go +878 -0
  435. package/govendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go +878 -0
  436. package/govendor/golang.org/x/sys/unix/ztypes_dragonfly_amd64.go +473 -0
  437. package/govendor/golang.org/x/sys/unix/ztypes_freebsd_386.go +651 -0
  438. package/govendor/golang.org/x/sys/unix/ztypes_freebsd_amd64.go +656 -0
  439. package/govendor/golang.org/x/sys/unix/ztypes_freebsd_arm.go +642 -0
  440. package/govendor/golang.org/x/sys/unix/ztypes_freebsd_arm64.go +636 -0
  441. package/govendor/golang.org/x/sys/unix/ztypes_freebsd_riscv64.go +638 -0
  442. package/govendor/golang.org/x/sys/unix/ztypes_linux.go +6547 -0
  443. package/govendor/golang.org/x/sys/unix/ztypes_linux_386.go +747 -0
  444. package/govendor/golang.org/x/sys/unix/ztypes_linux_amd64.go +761 -0
  445. package/govendor/golang.org/x/sys/unix/ztypes_linux_arm.go +741 -0
  446. package/govendor/golang.org/x/sys/unix/ztypes_linux_arm64.go +740 -0
  447. package/govendor/golang.org/x/sys/unix/ztypes_linux_loong64.go +741 -0
  448. package/govendor/golang.org/x/sys/unix/ztypes_linux_mips.go +746 -0
  449. package/govendor/golang.org/x/sys/unix/ztypes_linux_mips64.go +743 -0
  450. package/govendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go +743 -0
  451. package/govendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go +746 -0
  452. package/govendor/golang.org/x/sys/unix/ztypes_linux_ppc.go +754 -0
  453. package/govendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go +749 -0
  454. package/govendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go +749 -0
  455. package/govendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go +828 -0
  456. package/govendor/golang.org/x/sys/unix/ztypes_linux_s390x.go +763 -0
  457. package/govendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go +744 -0
  458. package/govendor/golang.org/x/sys/unix/ztypes_netbsd_386.go +585 -0
  459. package/govendor/golang.org/x/sys/unix/ztypes_netbsd_amd64.go +593 -0
  460. package/govendor/golang.org/x/sys/unix/ztypes_netbsd_arm.go +590 -0
  461. package/govendor/golang.org/x/sys/unix/ztypes_netbsd_arm64.go +593 -0
  462. package/govendor/golang.org/x/sys/unix/ztypes_openbsd_386.go +568 -0
  463. package/govendor/golang.org/x/sys/unix/ztypes_openbsd_amd64.go +568 -0
  464. package/govendor/golang.org/x/sys/unix/ztypes_openbsd_arm.go +575 -0
  465. package/govendor/golang.org/x/sys/unix/ztypes_openbsd_arm64.go +568 -0
  466. package/govendor/golang.org/x/sys/unix/ztypes_openbsd_mips64.go +568 -0
  467. package/govendor/golang.org/x/sys/unix/ztypes_openbsd_ppc64.go +570 -0
  468. package/govendor/golang.org/x/sys/unix/ztypes_openbsd_riscv64.go +570 -0
  469. package/govendor/golang.org/x/sys/unix/ztypes_solaris_amd64.go +516 -0
  470. package/govendor/golang.org/x/sys/unix/ztypes_zos_s390x.go +552 -0
  471. package/govendor/golang.org/x/sys/windows/aliases.go +13 -0
  472. package/govendor/golang.org/x/sys/windows/dll_windows.go +380 -0
  473. package/govendor/golang.org/x/sys/windows/env_windows.go +57 -0
  474. package/govendor/golang.org/x/sys/windows/eventlog.go +20 -0
  475. package/govendor/golang.org/x/sys/windows/exec_windows.go +248 -0
  476. package/govendor/golang.org/x/sys/windows/memory_windows.go +48 -0
  477. package/govendor/golang.org/x/sys/windows/mkerrors.bash +70 -0
  478. package/govendor/golang.org/x/sys/windows/mkknownfolderids.bash +27 -0
  479. package/govendor/golang.org/x/sys/windows/mksyscall.go +9 -0
  480. package/govendor/golang.org/x/sys/windows/race.go +30 -0
  481. package/govendor/golang.org/x/sys/windows/race0.go +25 -0
  482. package/govendor/golang.org/x/sys/windows/security_windows.go +1537 -0
  483. package/govendor/golang.org/x/sys/windows/service.go +257 -0
  484. package/govendor/golang.org/x/sys/windows/setupapi_windows.go +1425 -0
  485. package/govendor/golang.org/x/sys/windows/str.go +22 -0
  486. package/govendor/golang.org/x/sys/windows/syscall.go +104 -0
  487. package/govendor/golang.org/x/sys/windows/syscall_windows.go +1952 -0
  488. package/govendor/golang.org/x/sys/windows/types_windows.go +4058 -0
  489. package/govendor/golang.org/x/sys/windows/types_windows_386.go +35 -0
  490. package/govendor/golang.org/x/sys/windows/types_windows_amd64.go +34 -0
  491. package/govendor/golang.org/x/sys/windows/types_windows_arm.go +35 -0
  492. package/govendor/golang.org/x/sys/windows/types_windows_arm64.go +34 -0
  493. package/govendor/golang.org/x/sys/windows/zerrors_windows.go +9468 -0
  494. package/govendor/golang.org/x/sys/windows/zknownfolderids_windows.go +149 -0
  495. package/govendor/golang.org/x/sys/windows/zsyscall_windows.go +4828 -0
  496. package/govendor/manifest.txt +7 -0
  497. package/package.json +6 -1
  498. package/types/typenative-go.d.ts +15159 -5
  499. package/types/typenative-npm.d.ts +2637 -34
  500. package/types/typenative.d.ts +651 -8
package/bin/transpiler.js CHANGED
@@ -1,3 +1,46 @@
1
+ import { createNodeRegistry } from './node/registry.js';
2
+ import { registerPath } from './node/path.js';
3
+ import { registerFs } from './node/fs.js';
4
+ import { registerUrl } from './node/url.js';
5
+ import { registerOs } from './node/os.js';
6
+ import { registerChildProcess } from './node/child_process.js';
7
+ import { registerReadline } from './node/readline.js';
8
+ import { registerCore, registerConstants } from './node/core.js';
9
+ import { registerBuffer } from './node/buffer.js';
10
+ import { registerProcess } from './node/process.js';
11
+ import { registerUtil } from './node/util.js';
12
+ import { registerUtilExtra } from './node/util_extra.js';
13
+ import { registerConsole } from './node/console.js';
14
+ import { registerAssert } from './node/assert.js';
15
+ import { registerPunycode } from './node/punycode.js';
16
+ import { registerQuerystring } from './node/querystring.js';
17
+ import { registerStringDecoder } from './node/string_decoder.js';
18
+ import { registerCrypto } from './node/crypto.js';
19
+ import { registerCryptoKeys } from './node/crypto_keys.js';
20
+ import { registerZlib } from './node/zlib.js';
21
+ import { registerTimers } from './node/timers.js';
22
+ import { registerEvents } from './node/events.js';
23
+ import { registerStream } from './node/stream.js';
24
+ import { registerDiagnosticsChannel } from './node/diagnostics_channel.js';
25
+ import { registerNet } from './node/net.js';
26
+ import { registerDns } from './node/dns.js';
27
+ import { registerHttp } from './node/http.js';
28
+ import { registerTls } from './node/tls.js';
29
+ import { registerDgram } from './node/dgram.js';
30
+ import { registerSqlite } from './node/sqlite.js';
31
+ import { registerFetch } from './node/fetch.js';
32
+ import { registerStreamWeb } from './node/stream_web.js';
33
+ import { registerAsyncHooks } from './node/async_hooks.js';
34
+ import { registerTest } from './node/test.js';
35
+ import { registerWorkerThreads } from './node/worker_threads.js';
36
+ import { registerCluster } from './node/cluster.js';
37
+ import { registerHttp2 } from './node/http2.js';
38
+ import { registerSystemExtra } from './node/system_extra.js';
39
+ import { goStdlib } from './go/stdlib.generated.js';
40
+ import { goPackage, goTypeInfo as goMetaTypeInfo, hasGoPackage, isGoNumeric as isGoNumericType } from './go/metadata.js';
41
+ import { bindConvertServices, initConvertPaths, isGoBasicKind, isGoNumericKind, toGo as toGoType, fromGo as fromGoType } from './go/convert.js';
42
+ import { goPathAliases } from './go/overrides.js';
43
+ import { bindBridgeServices, resetGoBridge, initKnownPaths, goLocalType, ensureGoTypePackages, registerGoBuiltin, registerGoImport, goQualifier, goPathOf, goMemberOf, visitGoCall, visitGoMethod, visitGoNew, inferGoType, goFieldType, isGoRefCall, goTupleTypes, goCallbackResultType, ensureGoQualifier } from './go/bridge.js';
1
44
  // Shim over the removed `typescript` import: predicates and kind names operate
2
45
  // on the normalized JSON AST ({kind: 'Xxx', ...} plain objects) produced by
3
46
  // src/parse-node.ts (Node) or the tsparser Go tool (self-hosted).
@@ -260,6 +303,8 @@ const mainPackageVariables = [];
260
303
  // True while emitting a separate Go file, whose top-level statements sit at package scope
261
304
  let emittingModuleFile = false;
262
305
  const importedPackages = new Set();
306
+ // Side-effect `import 'go:time/tzdata'` packages, imported as `_`
307
+ const goSideEffectImports = new Set();
263
308
  let outsideNodes = [];
264
309
  const classNames = new Set();
265
310
  let promiseResolveName = '';
@@ -305,7 +350,7 @@ const referenceArrays = new Set();
305
350
  function setVarGoType(name, goType) {
306
351
  if (!name)
307
352
  return;
308
- if (goType && goType.startsWith('[]') && goType !== '[]interface{}') {
353
+ if (goType && goType.startsWith('[]') && goType !== '[]interface{}' && goType !== '[]byte') {
309
354
  variableGoTypes.set(name, `*${goType}`);
310
355
  referenceArrays.add(name);
311
356
  return;
@@ -795,17 +840,26 @@ export function transpileToNative(code, options) {
795
840
  fileResolver = options?.readFile ?? null;
796
841
  parseFunction = options?.parse ?? defaultParseFunction;
797
842
  currentFileIsTsx = !!options?.tsx;
843
+ consoleGroupsUsed = code.includes('console.group');
798
844
  declaredFunctions.clear();
799
845
  declaredInterfaces.clear();
800
846
  declaredTypeAliases.clear();
801
847
  variableTypeNodes.clear();
848
+ goRefVariables.clear();
802
849
  narrowedVariables.clear();
803
- nodeCallResultTypes.clear();
850
+ bindNodeRegistryServices();
851
+ nodeLocalNames.clear();
852
+ goPackageLocalNames.clear();
853
+ resetGoBridge();
854
+ initKnownPaths();
855
+ initConvertPaths();
856
+ nodeParentClassKeys.clear();
804
857
  asyncFunctionNames.clear();
805
858
  generatorFunctionNames.clear();
806
859
  currentFileDir = null;
807
860
  const sourceFile = parseSource(code);
808
861
  importedPackages.clear();
862
+ goSideEffectImports.clear();
809
863
  outsideNodes = [];
810
864
  classNames.clear();
811
865
  promiseResolveName = '';
@@ -828,6 +882,7 @@ export function transpileToNative(code, options) {
828
882
  classGetterMethods.clear();
829
883
  classSetterMethods.clear();
830
884
  classIteratorMethods.clear();
885
+ seedNodeClassTables();
831
886
  declaredClasses.clear();
832
887
  classParentNames.clear();
833
888
  referenceArrays.clear();
@@ -838,25 +893,49 @@ export function transpileToNative(code, options) {
838
893
  const transpiledCodeOutside = outsideNodes.map((n) => visit(n, { isOutside: true })).join('\n');
839
894
  // Keep the process alive until detached async work and timers settle
840
895
  const drains = [];
841
- if (usedHelpers.has('asyncWait'))
842
- drains.push('__tnWaitGroup.Wait()');
843
- if (usedHelpers.has('timerWait'))
844
- drains.unshift('TnRunMicrotasks()');
845
- if (usedHelpers.has('timerWait'))
846
- drains.push('__tnTimers.Wait()');
896
+ // The event loop runs until no timers, async work or open handles remain
897
+ if (usedHelpers.has('eventLoop'))
898
+ drains.push('TnRunLoop()');
899
+ // process.exitCode
900
+ if (usedHelpers.has('nodeProcess'))
901
+ drains.push('TnProcessExit()');
847
902
  const drainCode = drains.length > 0 ? `\n\t${drains.join('\n\t')}` : '';
903
+ // Go bridge types are qualified by path internally (net/http.Cookie)
904
+ const mainCode = localizeGoPaths(transpiledCode);
905
+ const outsideCode = localizeGoPaths(transpiledCodeOutside);
906
+ const packageVariables = mainPackageVariables.map((v) => localizeGoPaths(v));
907
+ // Go bridge packages pulled in for a type that never got emitted
908
+ // (a method's result type, a param type needing no conversion) would be
909
+ // unused imports, which Go rejects.
910
+ const emitted = stripGoStrings(`${mainCode}\n${outsideCode}\n${packageVariables.join('\n')}`);
911
+ const helpersCode = emitGoHelpers();
912
+ const mainImports = [...importedPackages].filter((pkg) => {
913
+ if (!hasGoPackage(pkg))
914
+ return true;
915
+ const pkgName = goPathAliases[pkg] ?? pkg.split('/').pop();
916
+ return referencesQualifier(emitted, pkgName) || referencesQualifier(helpersCode, pkgName);
917
+ });
918
+ for (const pkg of goSideEffectImports) {
919
+ if (!mainImports.includes(pkg))
920
+ mainImports.push(pkg);
921
+ }
922
+ const importLine = (pkg) => goSideEffectImports.has(pkg) && !importedPackages.has(pkg)
923
+ ? `import _ "${pkg}"`
924
+ : goImportLine(pkg);
925
+ // process.on('uncaughtException'): a throw in the top-level code is handed to it too
926
+ const body = usedHelpers.has('nodeUncaught') ? `func() {\n\tdefer TnMainRecover()\n\t${mainCode.trim()}\n\t}()` : mainCode.trim();
848
927
  const main = `package main
849
928
 
850
- ${[...importedPackages].sort().map((pkg) => goImportLine(pkg)).join('\n')}
929
+ ${mainImports.sort().map((pkg) => importLine(pkg)).join('\n')}
851
930
 
852
- ${mainPackageVariables.join('\n')}
931
+ ${packageVariables.join('\n')}
853
932
 
854
933
  func main() {
855
- ${transpiledCode.trim()}${drainCode}
934
+ ${body}${drainCode}
856
935
  }
857
936
 
858
- ${transpiledCodeOutside.trim()}
859
- ${emitGoHelpers()}`.trimEnd();
937
+ ${outsideCode.trim()}
938
+ ${helpersCode}`.trimEnd();
860
939
  return { main, files: localImportFiles };
861
940
  }
862
941
  export // Property map of an interface, including inherited properties (flattened —
@@ -919,10 +998,25 @@ function visit(node, options = {}) {
919
998
  }
920
999
  if (node.text === 'undefined')
921
1000
  return 'nil';
1001
+ // resolve / reject passed as values (setTimeout(resolve, ms)): closures over the channel
1002
+ const isCallee = isCallExpression(node.parent) && node.parent.expression === node;
1003
+ if (!isCallee && promiseResolveName && node.text === promiseResolveName) {
1004
+ useHelper('promise');
1005
+ return 'TnResolver(ch)';
1006
+ }
1007
+ if (!isCallee && promiseRejectName && node.text === promiseRejectName) {
1008
+ useHelper('promise');
1009
+ return 'TnRejecter(ch)';
1010
+ }
922
1011
  if (node.text === 'NaN' || node.text === 'Infinity') {
923
1012
  importedPackages.add('math');
924
1013
  return node.text === 'NaN' ? 'math.NaN()' : 'math.Inf(1)';
925
1014
  }
1015
+ if (nodeLocalNames.size > 0 || nodeRegistry.globals[node.text]) {
1016
+ const nodeValue = visitNodeValue(node);
1017
+ if (nodeValue !== undefined)
1018
+ return nodeValue;
1019
+ }
926
1020
  const goAlias = importAliases.get(node.text);
927
1021
  if (goAlias)
928
1022
  return goAlias;
@@ -1049,6 +1143,11 @@ function visit(node, options = {}) {
1049
1143
  if (isStringLiteral(node.argumentExpression)) {
1050
1144
  return `${visit(node.expression)}[${visit(node.argumentExpression)}]`;
1051
1145
  }
1146
+ // Buffer / Uint8Array elements read as numbers
1147
+ if (targetType === '[]byte' && !isAssignmentTarget(node)) {
1148
+ useHelper('dynamic');
1149
+ return `float64(TnAt(${visit(node.expression)}, ${visit(node.argumentExpression)}))`;
1150
+ }
1052
1151
  // Reading past the end of an array gives undefined in JS: the zero value here
1053
1152
  if (targetType?.startsWith('[]') && !isAssignmentTarget(node)) {
1054
1153
  useHelper('dynamic');
@@ -1057,9 +1156,28 @@ function visit(node, options = {}) {
1057
1156
  return `${visit(node.expression)}[int(${visit(node.argumentExpression)})]`;
1058
1157
  }
1059
1158
  else if (isPropertyAccessExpression(node)) {
1159
+ if (isMockAccess(node)) {
1160
+ nodeRegistry.helper('nodeTest');
1161
+ return `TnMockOf(${visit(node.expression)})`;
1162
+ }
1163
+ if (isProcessEnv(node.expression) && !isCallee(node) && !isAssignmentTarget(node)) {
1164
+ useHelper('getenv');
1165
+ return `TnGetenv("${node.name.text}")`;
1166
+ }
1167
+ if (!isCallee(node) && !isAssignmentTarget(node)) {
1168
+ const nodeValue = visitNodeValue(node);
1169
+ if (nodeValue !== undefined)
1170
+ return nodeValue;
1171
+ }
1060
1172
  const regexProperty = visitRegexProperty(node);
1061
1173
  if (regexProperty)
1062
1174
  return regexProperty;
1175
+ // Go package member or field on a Go value.
1176
+ if (!isCallee(node) || isCallee(node)) {
1177
+ const goProp = visitGoProperty(node);
1178
+ if (goProp !== undefined)
1179
+ return goProp;
1180
+ }
1063
1181
  // import.meta.url — the file URL of the running program
1064
1182
  if (isNewTargetNode(node.expression) && node.name.text === 'name')
1065
1183
  return '__newTarget';
@@ -1137,20 +1255,34 @@ function visit(node, options = {}) {
1137
1255
  return getAcessString(leftSide, rightSide, objectType);
1138
1256
  }
1139
1257
  else if (isVariableDeclaration(node)) {
1258
+ const nodeAlias = visitNodeAliasDeclaration(node);
1259
+ if (nodeAlias !== undefined)
1260
+ return nodeAlias;
1140
1261
  // Object destructuring: const { x, y } = obj
1141
1262
  if (isObjectBindingPattern(node.name) && node.initializer) {
1142
- const initExpr = visit(node.initializer);
1263
+ let initExpr = visit(node.initializer);
1143
1264
  const initType = inferExpressionType(node.initializer);
1144
1265
  const parts = [];
1266
+ // Evaluate the initializer once (const { a, b } = new X())
1267
+ if ((node.name.elements ?? []).length > 1 && !isIdentifier(node.initializer)) {
1268
+ const source = getTempName('src');
1269
+ parts.push(`${source} := ${initExpr}`);
1270
+ initExpr = source;
1271
+ }
1145
1272
  for (const el of node.name.elements ?? []) {
1146
1273
  const localName = visit(el.name);
1147
1274
  const rawProp = el.propertyName ?? el.name;
1148
1275
  const propName = isIdentifier(rawProp) ? rawProp.text : visit(rawProp);
1276
+ const structName = initType ? initType.replace(/^\*/, '') : '';
1277
+ // Struct literal fields, or the properties of a class (Node classes included)
1149
1278
  const fieldType = initType
1150
- ? getStructFieldGoType(initType.replace(/^\*/, ''), propName)
1279
+ ? (getStructFieldGoType(structName, propName) ?? classPropertyTypes.get(structName)?.get(propName))
1151
1280
  : undefined;
1152
1281
  const defaultVal = el.initializer;
1153
- if (defaultVal) {
1282
+ if (!defaultVal && classGetterMethods.has(`${structName}.${propName}`)) {
1283
+ parts.push(`${localName} := (${initExpr}).Get_${goFieldName(propName)}()`);
1284
+ }
1285
+ else if (defaultVal) {
1154
1286
  // Missing property (nil) takes the default
1155
1287
  const defType = inferExpressionType(defaultVal) ?? fieldType ?? 'interface{}';
1156
1288
  const tmp = getTempName('destructure');
@@ -1172,8 +1304,22 @@ function visit(node, options = {}) {
1172
1304
  : visit(node.initializer);
1173
1305
  const tmpVar = getTempName('arr');
1174
1306
  const elemType = initGoType?.startsWith('[]') ? initGoType.slice(2) : undefined;
1307
+ // Multi-value Go calls: each element asserts back to its own type
1308
+ const tupleTypes = goTupleTypes(unwrapParentheses(node.initializer));
1175
1309
  const parts = [`${tmpVar} := ${initExpr}`];
1176
1310
  node.name.elements.forEach((el, idx) => {
1311
+ const tupleType = tupleTypes?.[idx];
1312
+ if (tupleType && !isOmittedExpression(el) && isIdentifier(el.name) && !el.initializer) {
1313
+ const localName = visit(el.name);
1314
+ if (localName === '_' || localName.startsWith('_')) {
1315
+ parts.push(`_ = ${tmpVar}`);
1316
+ return;
1317
+ }
1318
+ ensureGoTypePackages(tupleType);
1319
+ parts.push(`${localName} := ${tmpVar}[${idx}].(${goLocalType(tupleType)})`);
1320
+ registerLocalVariable(localName, tupleType);
1321
+ return;
1322
+ }
1177
1323
  if (isOmittedExpression(el))
1178
1324
  return;
1179
1325
  const bindEl = el;
@@ -1231,6 +1377,10 @@ function visit(node, options = {}) {
1231
1377
  variableTypeNodes.set(node.name.text, node.type);
1232
1378
  else
1233
1379
  variableTypeNodes.delete(node.name.text);
1380
+ if (node.initializer && isGoRefCall(node.initializer))
1381
+ goRefVariables.add(node.name.text);
1382
+ else
1383
+ goRefVariables.delete(node.name.text);
1234
1384
  if (node.type && !isInferredAny) {
1235
1385
  variableGoTypes.set(node.name.text, getType(node.type));
1236
1386
  }
@@ -1309,7 +1459,8 @@ function visit(node, options = {}) {
1309
1459
  const packageType = type === ':' ? variableGoTypes.get(node.name.text) : type;
1310
1460
  if (isMainTopLevel && packageType && packageType !== 'nil' && isIdentifier(node.name)) {
1311
1461
  const name = getSafeName(node.name.text);
1312
- mainPackageVariables.push(`var ${name} ${packageType}`);
1462
+ ensureGoTypePackages(packageType);
1463
+ mainPackageVariables.push(`var ${name} ${goLocalType(packageType)}`);
1313
1464
  return initializer ? `${name} ${initializer}` : '';
1314
1465
  }
1315
1466
  const declName = isIdentifier(node.name) ? getSafeName(node.name.text) : visit(node.name);
@@ -1318,9 +1469,14 @@ function visit(node, options = {}) {
1318
1469
  if (type === ':' &&
1319
1470
  isIdentifier(node.name) &&
1320
1471
  containsNode(node.initializer, (n) => isIdentifier(n) && n.text === node.name.text && !isFieldNameIdentifier(n))) {
1321
- return `var ${declName} ${inferExpressionType(node.initializer)}\n\t\t${declName} ${initializer}`;
1472
+ const initType = inferExpressionType(node.initializer) ?? '';
1473
+ ensureGoTypePackages(initType);
1474
+ return `var ${declName} ${goLocalType(initType)}\n\t\t${declName} ${initializer}`;
1322
1475
  }
1323
- return `${type === ':' ? '' : 'var '}${declName} ${type}${type === ':' ? '' : ' '}${initializer}`;
1476
+ const emitType = type === ':' ? type : goLocalType(type);
1477
+ if (type !== ':')
1478
+ ensureGoTypePackages(type);
1479
+ return `${type === ':' ? '' : 'var '}${declName} ${emitType}${type === ':' ? '' : ' '}${initializer}`;
1324
1480
  }
1325
1481
  else if (isCallExpression(node)) {
1326
1482
  if (hasQuestionDot(node) ||
@@ -1333,6 +1489,26 @@ function visit(node, options = {}) {
1333
1489
  return visitNullablePrimitiveOptionalCall(node, visit(node.expression.expression), receiverType);
1334
1490
  }
1335
1491
  }
1492
+ const nodeCall = visitNodeCall(node);
1493
+ if (nodeCall !== undefined)
1494
+ return nodeCall;
1495
+ const goCall = visitGoCall(node);
1496
+ if (goCall !== undefined)
1497
+ return goCall;
1498
+ // Method call on a Go-typed receiver (pkg.Type value).
1499
+ if (isPropertyAccessExpression(node.expression)) {
1500
+ const recvType = inferExpressionType(node.expression.expression);
1501
+ if (recvType && recvType.startsWith('chan ')) {
1502
+ const chanCall = visitGoChanCall(node, visit(node.expression.expression));
1503
+ if (chanCall !== undefined)
1504
+ return chanCall;
1505
+ }
1506
+ if (recvType && goMetaTypeInfo(recvType)) {
1507
+ const goMethod = visitGoMethod(node, visit(node.expression.expression), recvType);
1508
+ if (goMethod !== undefined)
1509
+ return goMethod;
1510
+ }
1511
+ }
1336
1512
  const recordCall = visitRecordFunctionCall(node);
1337
1513
  if (recordCall)
1338
1514
  return recordCall;
@@ -1387,7 +1563,12 @@ function visit(node, options = {}) {
1387
1563
  const recv = visit(node.expression.expression);
1388
1564
  const cbs = (node.arguments ?? []).map((a) => visit(a));
1389
1565
  const cbExpr = cbs[0] ?? 'func(interface{}) {}';
1390
- return `__tnWaitGroup.Add(1)\n\t\tgo func() {\n\t\t\tdefer __tnWaitGroup.Done()\n\t\t\t__v := <-(${recv})\n\t\t\t(${cbExpr})(__v)\n\t\t}()`;
1566
+ useHelper('eventLoop');
1567
+ // A callback without parameters (then(() => …)) takes no value
1568
+ const takesValue = !(cb && (isArrowFunction(cb) || isFunctionExpression(cb)) && (cb.parameters ?? []).length === 0);
1569
+ const receive = takesValue ? `__v := <-(${recv})` : `<-(${recv})`;
1570
+ const invoke = takesValue ? `(${cbExpr})(__v)` : `(${cbExpr})()`;
1571
+ return `__tnWaitGroup.Add(1)\n\t\tgo func(__tnCtx TnAsyncContext) {\n\t\t\t${receive}\n\t\t\tTnLoopPost(func() {\n\t\t\t\tdefer __tnWaitGroup.Done()\n\t\t\t\tTnAsyncRun(__tnCtx, func() { ${invoke} })\n\t\t\t})\n\t\t}(TnAsyncSnapshot())`;
1391
1572
  }
1392
1573
  }
1393
1574
  // Array.from(arrayLike, mapFn) — array-likes are { length } structs
@@ -1453,6 +1634,19 @@ function visit(node, options = {}) {
1453
1634
  useHelper('dynamic');
1454
1635
  return `float64(^TnInt32(${visit(node.operand)}))`;
1455
1636
  }
1637
+ // -10n / -x on bigints (*big.Int)
1638
+ if (node.operator === 'MinusToken' && node.operand.kind === 'BigIntLiteral') {
1639
+ useHelper('bigint');
1640
+ return `TnBigInt("-${String(node.operand.text).replace(/n$/, '')}")`;
1641
+ }
1642
+ if (node.operator === 'MinusToken' && inferExpressionType(node.operand) === '*tnbig.Int') {
1643
+ return `new(tnbig.Int).Neg(${visit(node.operand)})`;
1644
+ }
1645
+ // -0: Go constant arithmetic has no negative zero
1646
+ if (node.operator === 'MinusToken' && isNumericLiteral(node.operand) && Number(node.operand.text) === 0) {
1647
+ importedPackages.add('math');
1648
+ return 'math.Copysign(0, -1)';
1649
+ }
1456
1650
  return `${getOperatorText(node.operator)}${visit(node.operand)}`;
1457
1651
  }
1458
1652
  else if (isPostfixUnaryExpression(node)) {
@@ -1480,11 +1674,22 @@ function visit(node, options = {}) {
1480
1674
  if (node.operatorToken.kind === 'QuestionQuestionToken') {
1481
1675
  return visitNullishCoalescingExpression(node);
1482
1676
  }
1677
+ if (node.operatorToken.kind === 'InstanceOfKeyword' &&
1678
+ isIdentifier(node.right) &&
1679
+ (node.right.text === 'Error' || BUILTIN_ERROR_NAMES.has(node.right.text)) &&
1680
+ !classNames.has(node.right.text)) {
1681
+ useHelper('error');
1682
+ return `TnIsErrorOf(${visit(node.left)}, ${toGoStringLiteral(node.right.text)})`;
1683
+ }
1483
1684
  if (node.operatorToken.kind === 'InstanceOfKeyword' && isIdentifier(node.right)) {
1484
1685
  // x instanceof C: the runtime type is C's pointer type
1485
1686
  return `func() bool { _, ok := interface{}(${visit(node.left)}).(*${getSafeName(node.right.text)}); return ok }()`;
1486
1687
  }
1487
1688
  if (node.operatorToken.kind === 'InKeyword') {
1689
+ if (isProcessEnv(node.right)) {
1690
+ useHelper('nodeProcess');
1691
+ return `TnHasEnv(${visit(node.left)})`;
1692
+ }
1488
1693
  if (isDynamicValue(node.right)) {
1489
1694
  useHelper('dynamic');
1490
1695
  return `TnHas(${visit(node.right)}, ${visit(node.left)})`;
@@ -1527,8 +1732,22 @@ function visit(node, options = {}) {
1527
1732
  const bigRight = inferExpressionType(node.right);
1528
1733
  if (bigLeft === '*tnbig.Int' || bigRight === '*tnbig.Int') {
1529
1734
  useHelper('bigint');
1530
- const bl = visit(node.left);
1531
- const br = visit(node.right);
1735
+ let bl = visit(node.left);
1736
+ let br = visit(node.right);
1737
+ // number | bigint values (node:sqlite's changes): === is true only for an
1738
+ // equal bigint; other operators convert the dynamic side
1739
+ const dynamicSide = bigLeft === 'interface{}' ? bl : bigRight === 'interface{}' ? br : '';
1740
+ if (dynamicSide) {
1741
+ const bigSide = dynamicSide === bl ? br : bl;
1742
+ if (op === '==')
1743
+ return `TnBigSame(${dynamicSide}, ${bigSide})`;
1744
+ if (op === '!=')
1745
+ return `!TnBigSame(${dynamicSide}, ${bigSide})`;
1746
+ if (dynamicSide === bl)
1747
+ bl = `TnToBigInt(${bl})`;
1748
+ else
1749
+ br = `TnToBigInt(${br})`;
1750
+ }
1532
1751
  if (op === '==')
1533
1752
  return `${bl}.Cmp(${br}) == 0`;
1534
1753
  if (op === '!=')
@@ -1558,6 +1777,19 @@ function visit(node, options = {}) {
1558
1777
  importedPackages.add('math');
1559
1778
  return `math.Pow(${visit(node.left)}, ${visit(node.right)})`;
1560
1779
  }
1780
+ // Named Go numerics (time.Duration): coerce the float64 side so Go's
1781
+ // operator type-checks (time.Second * 2 → time.Second * time.Duration(2)).
1782
+ if (['<', '>', '<=', '>=', '-', '*', '/', '+', '+=', '-=', '*=', '/='].includes(op)) {
1783
+ const numericCoercion = visitGoNumericArithmetic(node, op);
1784
+ if (numericCoercion)
1785
+ return numericCoercion;
1786
+ }
1787
+ // x.Kind() === reflect.String: the method result reads as a number
1788
+ if (op === '==' || op === '!=') {
1789
+ const numericEquality = visitGoNumericArithmetic(node, op);
1790
+ if (numericEquality)
1791
+ return numericEquality;
1792
+ }
1561
1793
  if (op === '**=') {
1562
1794
  importedPackages.add('math');
1563
1795
  const target = visit(node.left);
@@ -1620,6 +1852,17 @@ function visit(node, options = {}) {
1620
1852
  const other = isNewTargetNode(node.left) ? node.right : node.left;
1621
1853
  return `__newTarget ${op} ${isIdentifier(other) ? toGoStringLiteral(other.text) : '""'}`;
1622
1854
  }
1855
+ const nodeAssignment = visitNodeAssignment(node);
1856
+ if (nodeAssignment !== undefined)
1857
+ return nodeAssignment;
1858
+ const goFieldAssignment = visitGoFieldAssignment(node, op);
1859
+ if (goFieldAssignment !== undefined)
1860
+ return goFieldAssignment;
1861
+ // buf[i] = v on a Buffer / Uint8Array: bytes wrap modulo 256
1862
+ if (op === '=' && isElementAccessExpression(node.left) && inferExpressionType(node.left.expression) === '[]byte') {
1863
+ useHelper('buffer');
1864
+ return `${visit(node.left.expression)}[int(${visit(node.left.argumentExpression)})] = TnByte(${visit(node.right)})`;
1865
+ }
1623
1866
  // obj[key] = v on any
1624
1867
  if (op === '=' && isElementAccessExpression(node.left) && isDynamicValue(node.left.expression)) {
1625
1868
  useHelper('dynamic');
@@ -1699,11 +1942,10 @@ function visit(node, options = {}) {
1699
1942
  return '';
1700
1943
  }
1701
1944
  else if (isAwaitExpression(node)) {
1702
- if (inferExpressionType(node.expression)?.startsWith('chan ')) {
1703
- useHelper('promise');
1704
- return `TnAwait(${visit(node.expression)})`;
1705
- }
1706
- return `<-${visit(node.expression)}`;
1945
+ // Promises are channels: TnAwait keeps the event loop running while it waits
1946
+ // (a bare receive would block it, e.g. in async callbacks)
1947
+ useHelper('promise');
1948
+ return `TnAwait(${visit(node.expression)})`;
1707
1949
  }
1708
1950
  else if (isVariableDeclarationList(node)) {
1709
1951
  return ((node.declarations ?? []).map((n) => visit(n)).join(options.inline ? ';' : ';\n\t') +
@@ -1718,7 +1960,7 @@ function visit(node, options = {}) {
1718
1960
  !emittingModuleFile) {
1719
1961
  useHelper('asyncWait');
1720
1962
  useHelper('promise');
1721
- return `__tnWaitGroup.Add(1)\n\t\tgo func() {\n\t\t\tdefer __tnWaitGroup.Done()\n\t\t\tTnAwait(${getSafeName(exprStmt.expression.text)}())\n\t\t}();\n\t`;
1963
+ return `__tnWaitGroup.Add(1)\n\t\tTnDetach(${visit(exprStmt)});\n\t`;
1722
1964
  }
1723
1965
  return visit(node.expression) + (options.inline ? '' : ';\n\t');
1724
1966
  }
@@ -1748,10 +1990,17 @@ function visit(node, options = {}) {
1748
1990
  iterNode.arguments.length > 0) {
1749
1991
  iterNode = iterNode.arguments[0];
1750
1992
  }
1751
- const iterExpr = isDynamicValue(iterNode)
1993
+ let iterExpr = isDynamicValue(iterNode)
1752
1994
  ? toGoValueOfType(iterNode, '[]interface{}')
1753
1995
  : visit(iterNode, { inline: true });
1754
- const iterType = inferExpressionType(iterNode);
1996
+ let iterType = inferExpressionType(iterNode);
1997
+ // Node class instances iterate through their iterator method (URLSearchParams → entries())
1998
+ const nodeIterator = iterType ? nodeRegistry.iterators[iterType] : undefined;
1999
+ if (iterType && nodeIterator) {
2000
+ const cls = nodeRegistry.classes[nodeRegistry.classByGoType[iterType]];
2001
+ iterExpr = `${iterExpr}.${nodeIterator}()`;
2002
+ iterType = cls?.methods[nodeIterator] ?? iterType;
2003
+ }
1755
2004
  if (iterType && iterType.startsWith('*TnMap[')) {
1756
2005
  const valueType = extractMapValueType(iterType);
1757
2006
  const isSet = valueType === 'struct{}';
@@ -1861,7 +2110,13 @@ function visit(node, options = {}) {
1861
2110
  const enclosingFn = getEnclosingFunction(node);
1862
2111
  const isAsync = enclosingFn?.modifiers?.some((m) => m.kind === 'AsyncKeyword');
1863
2112
  const returnGoType = enclosingFn && !isAsync ? inferFunctionBodyReturnType(enclosingFn) : undefined;
1864
- const value = node.expression ? toGoValueOfType(node.expression, returnGoType) : '';
2113
+ // TS closures passed as Go callbacks return the Go result type
2114
+ const goCallbackResult = enclosingFn ? goCallbackResultType(enclosingFn) : undefined;
2115
+ const value = !node.expression
2116
+ ? ''
2117
+ : goCallbackResult !== undefined
2118
+ ? toGoType(visit(node.expression), inferExpressionType(node.expression) ?? '', goCallbackResult)
2119
+ : toGoValueOfType(node.expression, returnGoType);
1865
2120
  const terminator = options.inline ? '' : ';\n\t';
1866
2121
  if (tryReturn && enclosingFn === tryReturn.fn)
1867
2122
  return tryAwareReturn(value) + terminator;
@@ -1918,7 +2173,11 @@ function visit(node, options = {}) {
1918
2173
  if (!isBlock(node.body)) {
1919
2174
  // void-style calls (console.*, assert) emit statements, not values
1920
2175
  if (isVoidStatementCall(node.body) || !inferredRetType) {
1921
- return `func(${parameterInfo.signature})${returnType} { ${visit(node.body)}; }`;
2176
+ // `(c) => (body += c)`: the parenthesized expression is a statement
2177
+ let statement = node.body;
2178
+ while (statement.kind === 'ParenthesizedExpression')
2179
+ statement = statement.expression;
2180
+ return `func(${parameterInfo.signature})${returnType} { ${visit(statement)}; }`;
1922
2181
  }
1923
2182
  return `func(${parameterInfo.signature})${returnType} { return ${visit(node.body)}; }`;
1924
2183
  }
@@ -2090,7 +2349,7 @@ function visit(node, options = {}) {
2090
2349
  let parentClassName = null;
2091
2350
  for (const clause of node.heritageClauses ?? []) {
2092
2351
  if (clause.token === 'ExtendsKeyword') {
2093
- parentClassName = visit(clause.types[0].expression);
2352
+ parentClassName = nodeParentGoName(clause.types[0].expression) || visit(clause.types[0].expression);
2094
2353
  }
2095
2354
  }
2096
2355
  if (parentClassName && parentClassName !== 'Error') {
@@ -2126,13 +2385,14 @@ function visit(node, options = {}) {
2126
2385
  if ((node.heritageClauses ?? [])) {
2127
2386
  for (const clause of (node.heritageClauses ?? [])) {
2128
2387
  if (clause.token === 'ExtendsKeyword') {
2129
- parentClass = visit(clause.types[0].expression);
2388
+ parentClass = nodeParentGoName(clause.types[0].expression) || visit(clause.types[0].expression);
2130
2389
  }
2131
2390
  }
2132
2391
  }
2133
2392
  const extendsError = parentClass === 'Error';
2134
2393
  if (extendsError)
2135
2394
  useHelper('error');
2395
+ applyNodeHookTypes(parentClass, node);
2136
2396
  if (parentClass && !extendsError)
2137
2397
  classParentNames.set(name, parentClass);
2138
2398
  const isAbstractClass = (node.modifiers ?? []).some((m) => m.kind === 'AbstractKeyword');
@@ -2184,7 +2444,7 @@ function visit(node, options = {}) {
2184
2444
  const parentInit = parentClass && !extendsError && !superCalledInCtor
2185
2445
  ? `self.${goFieldName(parentClass)} = *${parentConstructorCall(parentClass, [])}\n\t\t`
2186
2446
  : '';
2187
- const ctorBody = `{\n\t\tself := &${name}${typeParamNames}{}\n\t\t${ctorParameterInfo.prefixBlockContent}${parentInit}${fieldInitializers(node)}${parameterAssignments}${bodyStatements}return self;\n\t}`;
2447
+ const ctorBody = `{\n\t\tself := &${name}${typeParamNames}{}\n\t\t${nodeSelfLink(parentClass)}${ctorParameterInfo.prefixBlockContent}${parentInit}${fieldInitializers(node)}${parameterAssignments}${bodyStatements}${nodeSelfLink(parentClass, node)}return self;\n\t}`;
2188
2448
  result += emitConstructor(name, typeParams, typeParamNames, ctorParameterInfo.signature, ctorBody);
2189
2449
  }
2190
2450
  else if (extendsError) {
@@ -2193,7 +2453,7 @@ function visit(node, options = {}) {
2193
2453
  }
2194
2454
  else {
2195
2455
  const parentInit = parentClass && !extendsError ? `self.${goFieldName(parentClass)} = *${parentConstructorCall(parentClass, [])}\n\t\t` : '';
2196
- const ctorBody = `{\n\t\tself := &${name}${typeParamNames}{}\n\t\t${parentInit}${fieldInitializers(node)}return self\n\t}`;
2456
+ const ctorBody = `{\n\t\tself := &${name}${typeParamNames}{}\n\t\t${parentInit}${fieldInitializers(node)}${nodeSelfLink(parentClass, node)}return self\n\t}`;
2197
2457
  result += emitConstructor(name, typeParams, typeParamNames, '', ctorBody);
2198
2458
  }
2199
2459
  // Inherited concrete methods are copied onto the subclass: Go embedding
@@ -2342,6 +2602,16 @@ function visit(node, options = {}) {
2342
2602
  return result.trim();
2343
2603
  }
2344
2604
  else if (isNewExpression(node)) {
2605
+ const nodeNew = visitNodeNew(node);
2606
+ if (nodeNew !== undefined)
2607
+ return nodeNew;
2608
+ const goTarget = goNewTarget(node);
2609
+ if (goTarget) {
2610
+ importedPackages.add(goTarget.path);
2611
+ const goNew = visitGoNew(node, goTarget.path, goTarget.typeName);
2612
+ if (goNew !== undefined)
2613
+ return goNew;
2614
+ }
2345
2615
  const className = visit(node.expression);
2346
2616
  if (className === 'Promise') {
2347
2617
  return visitNewPromise(node);
@@ -2365,17 +2635,25 @@ function visit(node, options = {}) {
2365
2635
  if (className === 'Set') {
2366
2636
  return visitNewSet(node);
2367
2637
  }
2638
+ // new TypeError(message) & co.: a TnError with that name
2639
+ if (BUILTIN_ERROR_NAMES.has(className) && !classNames.has(className)) {
2640
+ useHelper('error');
2641
+ const msg = (node.arguments ?? [])[0] ? visit(node.arguments[0]) : '""';
2642
+ return withErrorOptions(`TnNodeError(${toGoStringLiteral(className)}, "", ${msg})`, (node.arguments ?? [])[1]);
2643
+ }
2368
2644
  // new Error(message) → a TnError value with a .message
2369
2645
  if (className === 'Error') {
2370
2646
  useHelper('error');
2371
2647
  const msg = (node.arguments ?? [])[0] ? visit(node.arguments[0]) : '""';
2372
- return `TnNewError(${msg})`;
2648
+ return withErrorOptions(`TnNewError(${msg})`, (node.arguments ?? [])[1]);
2373
2649
  }
2374
2650
  // new Date() / new Date(ms) → Go time
2375
2651
  if (className === 'Date') {
2376
2652
  importedPackages.add('time');
2377
- if ((node.arguments ?? []).length === 0)
2378
- return 'time.Now()';
2653
+ if ((node.arguments ?? []).length === 0) {
2654
+ useHelper('clock');
2655
+ return 'TnTimeNow()';
2656
+ }
2379
2657
  return `time.UnixMilli(int64(${visit(node.arguments[0])})).UTC()`;
2380
2658
  }
2381
2659
  // new Array<number>(3) → make([]float64, 3)
@@ -2509,6 +2787,8 @@ function toGoValueOfType(expr, goType) {
2509
2787
  }
2510
2788
  // Array reference slots (*[]T): literals take an address, aliases pass through
2511
2789
  if (goType && goType.startsWith('*[]')) {
2790
+ // Go bridge element types are qualified (*[]io/fs.DirEntry)
2791
+ goType = goLocalType(goType);
2512
2792
  if (isIdentifier(expr) && referenceArrays.has(expr.text)) {
2513
2793
  return getSafeName(expr.text);
2514
2794
  }
@@ -2519,6 +2799,14 @@ function toGoValueOfType(expr, goType) {
2519
2799
  ? `&${code}`
2520
2800
  : `func() ${goType} { __v := ${code}; return &__v }()`;
2521
2801
  }
2802
+ // (x as string[]) on an any value, or (rows as Row[]) on an array of any
2803
+ // values (node:sqlite's all()): convert, then box
2804
+ const castSource = isAsExpression(expr) ? expr.expression : expr;
2805
+ const dynamicElements = goType !== '*[]interface{}' && inferExpressionType(castSource) === '[]interface{}';
2806
+ if (isDynamicValue(castSource) || dynamicElements) {
2807
+ useHelper('dynamic');
2808
+ return `func() ${goType} { __v := TnAs[${goType.slice(1)}](${visit(castSource)}); return &__v }()`;
2809
+ }
2522
2810
  return `func() ${goType} { __v := ${visit(expr)}; return &__v }()`;
2523
2811
  }
2524
2812
  const code = visit(expr);
@@ -2592,10 +2880,13 @@ function isProcessEnv(expr) {
2592
2880
  while (isParenthesizedExpression(expr) || isAsExpression(expr) || isNonNullExpression(expr)) {
2593
2881
  expr = expr.expression;
2594
2882
  }
2595
- return (isPropertyAccessExpression(expr) &&
2883
+ if (isPropertyAccessExpression(expr) &&
2596
2884
  isIdentifier(expr.expression) &&
2597
2885
  expr.expression.text === 'process' &&
2598
- expr.name.text === 'env');
2886
+ expr.name.text === 'env') {
2887
+ return true;
2888
+ }
2889
+ return resolveNodeKey(expr) === 'process.env';
2599
2890
  }
2600
2891
  // Whether an expression is (part of) an optional chain: a?.b, a?.b(), a?.b().c
2601
2892
  function isOptionalChain(expr) {
@@ -2765,18 +3056,41 @@ function visitUsingDeclaration(statement, rest) {
2765
3056
  return head + visitBlockStatements(rest);
2766
3057
  return `func() {\n\t\t${head}${visitBlockStatements(rest)}}()\n\t`;
2767
3058
  }
3059
+ // Binary arithmetic with a bridged named numeric: coerce the float64 side.
3060
+ function visitGoNumericArithmetic(node, op) {
3061
+ const leftType = inferExpressionType(node.left);
3062
+ const rightType = inferExpressionType(node.right);
3063
+ const leftNumeric = leftType && isGoNumericType(leftType) ? leftType : undefined;
3064
+ const rightNumeric = rightType && isGoNumericType(rightType) ? rightType : undefined;
3065
+ if (!leftNumeric && !rightNumeric)
3066
+ return undefined;
3067
+ if (leftNumeric && rightNumeric)
3068
+ return undefined;
3069
+ const numericType = leftNumeric ?? rightNumeric;
3070
+ if (!numericType)
3071
+ return undefined;
3072
+ const left = leftNumeric ? visit(node.left) : `${numericType}(${visit(node.left)})`;
3073
+ const right = rightNumeric ? visit(node.right) : `${numericType}(${visit(node.right)})`;
3074
+ if (['+=', '-=', '*=', '/='].includes(op)) {
3075
+ const target = visit(node.left);
3076
+ const baseOp = op.slice(0, -1);
3077
+ return `${target} = ${left} ${baseOp} ${right}`;
3078
+ }
3079
+ return `${left} ${op} ${right}`;
3080
+ }
2768
3081
  function visitDynamicArithmetic(node, op) {
2769
3082
  const leftDynamic = isDynamicValue(node.left);
2770
3083
  const rightDynamic = isDynamicValue(node.right);
2771
3084
  if (!leftDynamic && !rightDynamic)
2772
3085
  return undefined;
2773
- const isConcat = op === '+' && [node.left, node.right].some((side) => inferExpressionType(side) === 'string');
3086
+ const isConcat = (op === '+' || op === '+=') && [node.left, node.right].some((side) => inferExpressionType(side) === 'string');
2774
3087
  const operand = (side, dynamic) => {
2775
3088
  if (!dynamic)
2776
3089
  return visit(side);
2777
3090
  if (isConcat) {
2778
- importedPackages.add('fmt');
2779
- return `fmt.Sprint(${visit(side)})`;
3091
+ // String(x) as JS renders it (Buffers decode, numbers in JS notation)
3092
+ useHelper('dynamic');
3093
+ return `TnJSString(${visit(side)})`;
2780
3094
  }
2781
3095
  useHelper('dynamic');
2782
3096
  return `TnAs[float64](${visit(side)})`;
@@ -2886,6 +3200,10 @@ function getStructFieldGoType(structType, field) {
2886
3200
  function jsStringOf(code, goType) {
2887
3201
  if (goType === 'string')
2888
3202
  return code;
3203
+ if (goType === '[]byte') {
3204
+ useHelper('buffer');
3205
+ return `TnBufferToString(${code}, "")`;
3206
+ }
2889
3207
  if (goType === 'float64') {
2890
3208
  useHelper('dynamic');
2891
3209
  return `TnNumStr(${code})`;
@@ -2894,10 +3212,27 @@ function jsStringOf(code, goType) {
2894
3212
  importedPackages.add('strconv');
2895
3213
  return `strconv.FormatBool(${code})`;
2896
3214
  }
3215
+ if (goType === 'interface{}') {
3216
+ useHelper('dynamic');
3217
+ useHelper('error');
3218
+ return `TnJSString(${code})`;
3219
+ }
3220
+ // Node classes with a toString() (MIMEType, X509Certificate, …)
3221
+ const nodeKey = goType ? nodeRegistry.classByGoType[goType] : undefined;
3222
+ if (nodeKey && 'toString' in nodeRegistry.classes[nodeKey].methods)
3223
+ return `${code}.toString()`;
2897
3224
  importedPackages.add('fmt');
2898
3225
  return `fmt.Sprintf("%v", ${code})`;
2899
3226
  }
2900
3227
  // JS bitwise operators work on 32-bit integers (ToInt32 / ToUint32)
3228
+ // Go-typed numeric operands (typed constants like x509.KeyUsageCertSign,
3229
+ // int fields) read as float64 so the TnInt32 helpers accept them
3230
+ function asFloatOperand(node, code) {
3231
+ const goType = inferExpressionType(node);
3232
+ if (goType && goType !== 'float64' && isGoNumericKind(goType))
3233
+ return `float64(${code})`;
3234
+ return code;
3235
+ }
2901
3236
  function visitBitwise(node, op) {
2902
3237
  const kind = node.operatorToken.kind;
2903
3238
  const base = {
@@ -2918,8 +3253,8 @@ function visitBitwise(node, op) {
2918
3253
  if (!bitOp)
2919
3254
  return undefined;
2920
3255
  useHelper('dynamic');
2921
- const left = visit(node.left);
2922
- const right = visit(node.right);
3256
+ const left = asFloatOperand(node.left, visit(node.left));
3257
+ const right = asFloatOperand(node.right, visit(node.right));
2923
3258
  let value;
2924
3259
  if (bitOp === '>>>')
2925
3260
  value = `float64(TnUint32(${left}) >> (TnUint32(${right}) & 31))`;
@@ -2938,6 +3273,10 @@ function visitDelete(node) {
2938
3273
  const key = isPropertyAccessExpression(target)
2939
3274
  ? toGoStringLiteral(target.name.text)
2940
3275
  : visit(target.argumentExpression);
3276
+ if (isProcessEnv(object)) {
3277
+ importedPackages.add('os');
3278
+ return `func() bool { os.Unsetenv(${key}); return true }()`;
3279
+ }
2941
3280
  const objectType = inferExpressionType(object);
2942
3281
  if (objectType?.startsWith('*TnMap['))
2943
3282
  return `${visit(object)}.Delete(${key})`;
@@ -2990,7 +3329,60 @@ function isNewTargetNode(node) {
2990
3329
  return node?.kind === 'MetaProperty' && node.name?.text === 'target';
2991
3330
  }
2992
3331
  // The parent part of a subclass constructor: new.target-aware chains pass the target on
3332
+ // Subclass instances of Node classes with overridable methods register
3333
+ // themselves on the embedded struct (`self.TnTransform.tnSelf = self`)
3334
+ function nodeSelfLink(parentClass, classNode) {
3335
+ if (!parentClass || !nodeParentClassKeys.has(parentClass))
3336
+ return '';
3337
+ const key = nodeParentClassKeys.get(parentClass) ?? '';
3338
+ const cls = nodeRegistry.classes[key];
3339
+ if (!cls || !('tnSelf' in cls.props))
3340
+ return '';
3341
+ let code = `self.${parentClass}.tnSelf = self\n\t\t`;
3342
+ // Overridden hook methods (_transform …) are registered on the embedded struct
3343
+ if (classNode && nodeRegistry.hookPrefixes[key]) {
3344
+ for (const member of classNode.members ?? []) {
3345
+ if (!isMethodDeclaration(member) || !member.name || !isIdentifier(member.name))
3346
+ continue;
3347
+ const name = member.name.text;
3348
+ if (name in nodeRegistry.hookParams)
3349
+ code += `self.${parentClass}.setHook(${toGoStringLiteral(name)}, self.${name})\n\t\t`;
3350
+ }
3351
+ }
3352
+ return code;
3353
+ }
3354
+ // Hook methods of subclasses of Node classes take the hooks' parameter types
3355
+ function applyNodeHookTypes(parentClass, classNode) {
3356
+ if (!parentClass || !nodeParentClassKeys.has(parentClass))
3357
+ return;
3358
+ if (!nodeRegistry.hookPrefixes[nodeParentClassKeys.get(parentClass) ?? ''])
3359
+ return;
3360
+ for (const member of classNode.members ?? []) {
3361
+ if (!isMethodDeclaration(member) || !member.name || !isIdentifier(member.name))
3362
+ continue;
3363
+ const name = member.name.text;
3364
+ if (name in nodeRegistry.hookParams)
3365
+ member.tnParamTypes = nodeRegistry.hookParams[name];
3366
+ }
3367
+ }
3368
+ // class X extends EventEmitter: the parent is a Node helper struct
3369
+ const nodeParentClassKeys = new Map();
3370
+ function nodeParentGoName(expr) {
3371
+ const key = resolveNodeKey(expr);
3372
+ const cls = key ? nodeRegistry.classes[key] : undefined;
3373
+ if (!cls || !cls.goType.startsWith('*') || !nodeRegistry.constructors[key])
3374
+ return '';
3375
+ const goName = cls.goType.slice(1);
3376
+ nodeParentClassKeys.set(goName, key);
3377
+ return goName;
3378
+ }
2993
3379
  function parentConstructorCall(parentClass, args) {
3380
+ if (nodeParentClassKeys.has(parentClass)) {
3381
+ const key = nodeParentClassKeys.get(parentClass) ?? '';
3382
+ const call = { args, nodes: [], types: args.map(() => ''), recv: '' };
3383
+ const ctor = nodeRegistry.constructors[key](call);
3384
+ return ctor;
3385
+ }
2994
3386
  if (!usesNewTarget(parentClass))
2995
3387
  return `New${parentClass}(${args.join(', ')})`;
2996
3388
  return `new${parentClass}As(${['__newTarget', ...args].join(', ')})`;
@@ -3139,6 +3531,9 @@ function toFieldGoType(goType) {
3139
3531
  return !goType || goType === 'nil' ? 'interface{}' : goType;
3140
3532
  }
3141
3533
  function isDictionaryLiteral(node) {
3534
+ // Keys that are not Go identifiers ('Content-Type') can't be struct fields
3535
+ if (hasNonIdentifierKeys(node))
3536
+ return true;
3142
3537
  const declaration = node.parent;
3143
3538
  if (!isVariableDeclaration(declaration) || !isIdentifier(declaration.name))
3144
3539
  return false;
@@ -3153,6 +3548,24 @@ function isDictionaryLiteral(node) {
3153
3548
  n.expression.text === name &&
3154
3549
  !isStringLiteral(n.argumentExpression));
3155
3550
  }
3551
+ function hasNonIdentifierKeys(node) {
3552
+ if (!isObjectLiteralExpression(node))
3553
+ return false;
3554
+ let sawKey = false;
3555
+ for (const p of node.properties ?? []) {
3556
+ if (!isPropertyAssignment(p)) {
3557
+ if (p.kind === 'SpreadAssignment' || isMethodDeclaration(p) || isGetAccessor(p) || isSetAccessor(p))
3558
+ return false;
3559
+ continue;
3560
+ }
3561
+ // Go identifiers have no `$` ({ $id: 1 }, node:sqlite's named parameters)
3562
+ if (isStringLiteral(p.name) && !/^[A-Za-z_][A-Za-z0-9_]*$/.test(p.name.text))
3563
+ sawKey = true;
3564
+ if (isIdentifier(p.name) && p.name.text.includes('$'))
3565
+ sawKey = true;
3566
+ }
3567
+ return sawKey;
3568
+ }
3156
3569
  function containsNode(root, predicate) {
3157
3570
  for (const child of childNodes(root)) {
3158
3571
  if (predicate(child) || containsNode(child, predicate))
@@ -3253,6 +3666,9 @@ function getAsExpressionType(node) {
3253
3666
  return inferExpressionType(node.expression) ?? 'interface{}';
3254
3667
  }
3255
3668
  const target = getType(node.type);
3669
+ // (x as File): dynamic values holding Node class instances assert to them
3670
+ if (nodeRegistry.classByGoType[target])
3671
+ return target;
3256
3672
  if (isDynamicValue(node.expression) && (isStructGoType(target) || target.startsWith('*'))) {
3257
3673
  return 'interface{}';
3258
3674
  }
@@ -3554,6 +3970,8 @@ function getMemberTypeNode(typeNode, name) {
3554
3970
  // (TypeScript's "contextual type"), derived syntactically from declarations
3555
3971
  // Declared type nodes of variables/parameters in scope (latest declaration wins)
3556
3972
  const variableTypeNodes = new Map();
3973
+ // Variables initialized by go:builtin ref<T>() (their `.value` dereferences)
3974
+ const goRefVariables = new Set();
3557
3975
  // Declared type (as a type node) of an assignable expression, when known
3558
3976
  function getExpressionTypeNode(expr) {
3559
3977
  if (isIdentifier(expr))
@@ -3890,16 +4308,43 @@ function inferFunctionBodyReturnType(node) {
3890
4308
  if (contextualFn?.type)
3891
4309
  return getType(contextualFn.type);
3892
4310
  if (isArrowFunction(node) && !isBlock(node.body)) {
3893
- return inferExpressionType(node.body);
4311
+ const bodyType = inferExpressionType(node.body);
4312
+ // `() => undefined`: nil is not a Go type
4313
+ return bodyType === 'nil' ? 'interface{}' : bodyType;
3894
4314
  }
3895
4315
  if (node.body && isBlock(node.body)) {
3896
- for (const stmt of node.body.statements) {
4316
+ let returnsNil = false;
4317
+ for (const stmt of node.body.statements ?? []) {
3897
4318
  if (isReturnStatement(stmt) && stmt.expression) {
3898
4319
  const exprType = inferExpressionType(stmt.expression);
3899
- if (exprType)
4320
+ if (exprType === 'nil')
4321
+ returnsNil = true;
4322
+ else if (exprType)
3900
4323
  return exprType;
3901
4324
  }
3902
4325
  }
4326
+ if (returnsNil)
4327
+ return 'interface{}';
4328
+ }
4329
+ return undefined;
4330
+ }
4331
+ function getEnclosingParameterType(expr) {
4332
+ const primitives = ['NumberKeyword', 'StringKeyword', 'BooleanKeyword', 'BigIntKeyword'];
4333
+ for (let node = expr.parent; node; node = node.parent) {
4334
+ if (!isArrowFunction(node) && !isFunctionExpression(node) && node.kind !== 'FunctionDeclaration' && !isMethodDeclaration(node)) {
4335
+ continue;
4336
+ }
4337
+ const param = (node.parameters ?? []).find((p) => isIdentifier(p.name) && p.name.text === expr.text);
4338
+ if (!param)
4339
+ continue;
4340
+ if (!param.type || param.questionToken || param.initializer)
4341
+ return undefined;
4342
+ // ...values: number[] reads as []float64 in the body
4343
+ if (param.dotDotDotToken) {
4344
+ const elem = param.type.kind === 'ArrayType' ? param.type.elementType : undefined;
4345
+ return elem && primitives.includes(elem.kind) ? `[]${getType(elem)}` : undefined;
4346
+ }
4347
+ return primitives.includes(param.type.kind) ? getParameterGoType(param) : undefined;
3903
4348
  }
3904
4349
  return undefined;
3905
4350
  }
@@ -3916,7 +4361,15 @@ function inferArrowFunctionGoType(node) {
3916
4361
  const retType = inferFunctionBodyReturnType(node);
3917
4362
  return `func(${params})${retType ? ` ${retType}` : ''}`;
3918
4363
  }
4364
+ // fn.mock on a function value: the call record of a node:test mock (functions have no fields in Go)
4365
+ function isMockAccess(node) {
4366
+ if (!isPropertyAccessExpression(node) || node.name.text !== 'mock' || !nodeRegistry.modules['test'])
4367
+ return false;
4368
+ return !!inferExpressionType(node.expression)?.startsWith('func(');
4369
+ }
3919
4370
  function inferExpressionType(expr) {
4371
+ if (isMockAccess(expr))
4372
+ return '*TnMockFunctionContext';
3920
4373
  if (isAwaitExpression(expr)) {
3921
4374
  // await unwraps the promise channel
3922
4375
  const inner = inferExpressionType(expr.expression);
@@ -3935,6 +4388,12 @@ function inferExpressionType(expr) {
3935
4388
  return getAsExpressionType(expr);
3936
4389
  if (isTypeAssertionExpression(expr))
3937
4390
  return getType(expr.type);
4391
+ const nodeType = inferNodeExpressionType(expr);
4392
+ if (nodeType !== undefined)
4393
+ return nodeType === '' ? undefined : nodeType;
4394
+ const goType = inferGoExpressionType(expr);
4395
+ if (goType !== undefined)
4396
+ return goType;
3938
4397
  if (isStringLiteral(expr) ||
3939
4398
  isNoSubstitutionTemplateLiteral(expr) ||
3940
4399
  isTemplateExpression(expr)) {
@@ -3954,6 +4413,14 @@ function inferExpressionType(expr) {
3954
4413
  return 'TnJsxNode';
3955
4414
  if (expr.kind === 'TaggedTemplateExpression' && isStringRawTag(expr.tag))
3956
4415
  return 'string';
4416
+ // sql`…` with a Node class method as the tag (node:sqlite's tag store)
4417
+ if (expr.kind === 'TaggedTemplateExpression' && isPropertyAccessExpression(expr.tag)) {
4418
+ const recvType = inferExpressionType(expr.tag.expression);
4419
+ const cls = recvType ? nodeRegistry.classes[nodeRegistry.classByGoType[recvType]] : undefined;
4420
+ const result = cls?.methods[expr.tag.name.text];
4421
+ if (result)
4422
+ return result;
4423
+ }
3957
4424
  if (isRegularExpressionLiteral(expr)) {
3958
4425
  const lastSlash = expr.text.lastIndexOf('/');
3959
4426
  if (needsStatefulRegex(expr.text.substring(1, lastSlash), expr.text.substring(lastSlash + 1))) {
@@ -3971,6 +4438,12 @@ function inferExpressionType(expr) {
3971
4438
  if (isIdentifier(expr) && expr.text === 'undefined')
3972
4439
  return 'nil';
3973
4440
  if (isIdentifier(expr)) {
4441
+ // A primitive-typed parameter of an enclosing function: its annotation,
4442
+ // not a same-named variable registered earlier (inferring the return type
4443
+ // of an arrow before it is visited)
4444
+ const enclosingParamType = getEnclosingParameterType(expr);
4445
+ if (enclosingParamType)
4446
+ return enclosingParamType;
3974
4447
  let varType = variableGoTypes.get(expr.text);
3975
4448
  // Array references are read as the slice they point to
3976
4449
  if (varType?.startsWith('*[]'))
@@ -3986,7 +4459,7 @@ function inferExpressionType(expr) {
3986
4459
  const ctorName = expr.expression.text;
3987
4460
  if (classNames.has(ctorName))
3988
4461
  return `*${ctorName}`;
3989
- if (ctorName === 'Error')
4462
+ if (ctorName === 'Error' || (BUILTIN_ERROR_NAMES.has(ctorName) && !classNames.has(ctorName)))
3990
4463
  return '*TnError';
3991
4464
  if (ctorName === 'Promise' && (expr.typeArguments ?? []).length > 0) {
3992
4465
  return `chan ${getType(expr.typeArguments[0]) || 'struct{}'}`;
@@ -4076,13 +4549,10 @@ function inferExpressionType(expr) {
4076
4549
  if (fn)
4077
4550
  return `chan ${getGeneratorYieldType(fn)}`;
4078
4551
  }
4079
- const nodeResultType = callee ? nodeCallResultTypes.get(callee) : undefined;
4080
4552
  if (callee && BUILTIN_CALL_TYPES[callee])
4081
4553
  return BUILTIN_CALL_TYPES[callee];
4082
4554
  if (callee?.startsWith('Math.'))
4083
4555
  return 'float64';
4084
- if (nodeResultType)
4085
- return nodeResultType;
4086
4556
  }
4087
4557
  // Object.keys(map) / Object.values(map)
4088
4558
  if (isCallExpression(expr) &&
@@ -4181,6 +4651,15 @@ function inferExpressionType(expr) {
4181
4651
  const leftType = inferExpressionType(expr.expression);
4182
4652
  if (expr.name.text === 'length')
4183
4653
  return 'float64';
4654
+ // record.key reads the Record's value type
4655
+ if (leftType?.startsWith('*TnMap[') && expr.name.text !== 'size' && !isCallee(expr)) {
4656
+ const objectType = resolveExpressionType(expr.expression);
4657
+ if (objectType === 'Record' || objectType === 'Map' || objectType === undefined) {
4658
+ const valueType = extractMapValueType(leftType);
4659
+ if (valueType !== 'struct{}')
4660
+ return valueType;
4661
+ }
4662
+ }
4184
4663
  const resolvedLeftType = leftType?.replace(/^\*/, '').replace(/\[.*\]$/, '');
4185
4664
  const resolvedPropertyType = resolvedLeftType
4186
4665
  ? (classPropertyTypes.get(resolvedLeftType)?.get(expr.name.text) ??
@@ -4292,6 +4771,10 @@ function inferExpressionType(expr) {
4292
4771
  return ownerType;
4293
4772
  if (methodName === 'reduceRight' && expr.arguments?.[1])
4294
4773
  return inferExpressionType(expr.arguments[1]);
4774
+ // the accumulator: the initial value's type, else the element type
4775
+ if (methodName === 'reduce') {
4776
+ return (expr.arguments?.[1] ? inferExpressionType(expr.arguments[1]) : undefined) ?? elementType;
4777
+ }
4295
4778
  if (methodName === 'flat' && elementType.startsWith('[]'))
4296
4779
  return elementType;
4297
4780
  if (methodName === 'flat' || methodName === 'flatMap')
@@ -4562,7 +5045,7 @@ const BUILTIN_FUNCTION_TYPES = {
4562
5045
  parseInt: 'float64',
4563
5046
  Number: 'float64',
4564
5047
  String: 'string',
4565
- setTimeout: '*time.Timer',
5048
+ setTimeout: '*TnTimeout',
4566
5049
  setInterval: '*TnInterval'
4567
5050
  };
4568
5051
  const STRING_METHOD_RETURN_TYPES = {
@@ -4919,12 +5402,18 @@ function getMapLookup(expr) {
4919
5402
  return undefined;
4920
5403
  }
4921
5404
  function isNilableGoType(goType) {
4922
- return (goType.startsWith('*') ||
5405
+ if (goType.startsWith('*') ||
4923
5406
  goType.startsWith('[]') ||
4924
5407
  goType.startsWith('map[') ||
4925
5408
  goType.startsWith('func') ||
4926
5409
  goType.startsWith('chan ') ||
4927
- goType === 'interface{}');
5410
+ goType === 'interface{}' ||
5411
+ goType === 'error') {
5412
+ return true;
5413
+ }
5414
+ // Go bridge named types over nil-able kinds (net.IP, io.Reader, http.Header)
5415
+ const kind = goMetaTypeInfo(goType)?.kind;
5416
+ return kind === 'interface' || kind === 'slice' || kind === 'map' || kind === 'func' || kind === 'chan';
4928
5417
  }
4929
5418
  function visitOptionalPropertyAccess(node) {
4930
5419
  const baseExpr = visit(node.expression);
@@ -4944,7 +5433,10 @@ function visitOptionalPropertyAccess(node) {
4944
5433
  'interface{}';
4945
5434
  const nullableType = makeNullableType(propertyType);
4946
5435
  const tmp = getTempName('opt');
4947
- const propertyAccess = `${tmp}.${visit(node.name)}`;
5436
+ // Class getters (also Node classes' accessors such as err.syscall) are calls
5437
+ const propertyAccess = classGetterMethods.has(`${className}.${node.name.text}`)
5438
+ ? `${tmp}.Get_${visit(node.name)}()`
5439
+ : `${tmp}.${visit(node.name)}`;
4948
5440
  if (nullableType.startsWith('*') && nullableType.slice(1) === propertyType) {
4949
5441
  const valueTemp = getTempName('optv');
4950
5442
  return `func() ${nullableType} { ${tmp} := ${baseExpr}; if ${tmp} == nil { var __zero ${nullableType}; return __zero }; ${valueTemp} := ${propertyAccess}; return &${valueTemp} }()`;
@@ -5051,10 +5543,18 @@ function inferArrayCallbackReturnType(callback, elementType, fallbackType) {
5051
5543
  const explicitType = getType(callback.type);
5052
5544
  return explicitType || fallbackType;
5053
5545
  }
5054
- if (isBlock(callback.body)) {
5055
- return inferFunctionBodyReturnType(callback) ?? fallbackType;
5056
- }
5057
- const inferred = inferExpressionType(callback.body);
5546
+ // The element parameter has the element type while the body is inferred
5547
+ const param = (callback.parameters ?? [])[0];
5548
+ const paramName = param && isIdentifier(param.name) && !param.type ? param.name.text : '';
5549
+ const hadParam = paramName ? variableGoTypes.has(paramName) : false;
5550
+ const savedParam = paramName ? variableGoTypes.get(paramName) : undefined;
5551
+ if (paramName)
5552
+ variableGoTypes.set(paramName, elementType);
5553
+ const inferred = isBlock(callback.body) ? inferFunctionBodyReturnType(callback) : inferExpressionType(callback.body);
5554
+ if (paramName && hadParam && savedParam !== undefined)
5555
+ variableGoTypes.set(paramName, savedParam);
5556
+ else if (paramName)
5557
+ variableGoTypes.delete(paramName);
5058
5558
  return inferred ?? fallbackType;
5059
5559
  }
5060
5560
  if (isIdentifier(callback)) {
@@ -5493,7 +5993,10 @@ function getType(typeNode, getArrayType = false) {
5493
5993
  const params = (typeNode.parameters ?? [])
5494
5994
  .map((p) => {
5495
5995
  const paramType = p.type ? getType(p.type) : 'interface{}';
5496
- return p.dotDotDotToken && paramType.startsWith('[]') ? `...${paramType.slice(2)}` : paramType;
5996
+ if (p.dotDotDotToken && paramType.startsWith('[]'))
5997
+ return `...${paramType.slice(2)}`;
5998
+ // optional parameters are nullable (as in declarations and at call sites)
5999
+ return p.questionToken ? makeNullableType(paramType) : paramType;
5497
6000
  })
5498
6001
  .join(', ');
5499
6002
  const ret = typeNode.type ? ` ${getType(typeNode.type)}` : '';
@@ -5508,6 +6011,11 @@ function getType(typeNode, getArrayType = false) {
5508
6011
  useHelper('symbol');
5509
6012
  return '*TnSymbol';
5510
6013
  }
6014
+ if (isTypeReferenceNode(typeNode)) {
6015
+ const nodeClassKey = nodeClassKeyOfTypeName(typeNode.typeName);
6016
+ if (nodeClassKey)
6017
+ return nodeRegistry.classes[nodeClassKey].goType;
6018
+ }
5511
6019
  if (isTypeReferenceNode(typeNode) && isIdentifier(typeNode.typeName)) {
5512
6020
  const name = typeNode.typeName.text;
5513
6021
  if (enumNames.has(name)) {
@@ -5529,12 +6037,28 @@ function getType(typeNode, getArrayType = false) {
5529
6037
  if (name === 'RegExp') {
5530
6038
  return '*regexp.Regexp';
5531
6039
  }
5532
- if (name === 'Error') {
6040
+ // go:builtin GoError values are Go errors.
6041
+ if (name === 'GoError') {
6042
+ return 'error';
6043
+ }
6044
+ if (name === 'GoChan' && typeNode.typeArguments && typeNode.typeArguments.length > 0) {
6045
+ const inner = getType(typeNode.typeArguments[0]);
6046
+ return `chan ${inner || 'interface{}'}`;
6047
+ }
6048
+ if (name === 'GoRef' && typeNode.typeArguments && typeNode.typeArguments.length > 0) {
6049
+ const inner = getType(typeNode.typeArguments[0]);
6050
+ return `*${inner || 'interface{}'}`;
6051
+ }
6052
+ if (name === 'Error' || (BUILTIN_ERROR_NAMES.has(name) && !classNames.has(name))) {
5533
6053
  return '*TnError';
5534
6054
  }
5535
6055
  if (name === 'RegExpExecArray' || name === 'RegExpMatchArray') {
5536
6056
  return '[]string';
5537
6057
  }
6058
+ // Uint8Array / Buffer / ArrayBuffer annotations are Go []byte.
6059
+ if (name === 'Uint8Array' || name === 'Buffer' || name === 'ArrayBuffer') {
6060
+ return '[]byte';
6061
+ }
5538
6062
  if (name === 'TemplateStringsArray' || name === 'ReadonlyArray') {
5539
6063
  return name === 'TemplateStringsArray' ? '[]string' : getType(typeNode.typeArguments?.[0]);
5540
6064
  }
@@ -5608,6 +6132,11 @@ function getTypeCategory(typeNode) {
5608
6132
  if (nonNullTypes.length === 1)
5609
6133
  return getTypeCategory(nonNullTypes[0]);
5610
6134
  }
6135
+ if (isTypeReferenceNode(typeNode)) {
6136
+ const nodeClassKey = nodeClassKeyOfTypeName(typeNode.typeName);
6137
+ if (nodeClassKey)
6138
+ return nodeRegistry.classes[nodeClassKey].category;
6139
+ }
5611
6140
  if (isTypeReferenceNode(typeNode) && isIdentifier(typeNode.typeName)) {
5612
6141
  const name = typeNode.typeName.text;
5613
6142
  if (name === 'Map')
@@ -5649,16 +6178,25 @@ function goTypeCategory(goType) {
5649
6178
  return undefined;
5650
6179
  if (goType.startsWith('*TnMap['))
5651
6180
  return extractMapValueType(goType) === 'struct{}' ? 'Set' : 'Map';
6181
+ const nodeClassKey = nodeRegistry.classByGoType[goType];
6182
+ if (nodeClassKey)
6183
+ return nodeRegistry.classes[nodeClassKey].category;
5652
6184
  if (goType.startsWith('*[]'))
5653
6185
  goType = goType.slice(1);
5654
- if (goType.startsWith('[]'))
6186
+ if (goType.startsWith('[]')) {
6187
+ if (goType === '[]byte')
6188
+ return 'Buffer';
5655
6189
  return 'array';
6190
+ }
5656
6191
  if (goType === 'string')
5657
6192
  return 'string';
5658
6193
  if (goType === '*regexp.Regexp' || goType === '*TnRegex')
5659
6194
  return 'RegExp';
5660
6195
  if (goType === 'time.Time')
5661
6196
  return 'Date';
6197
+ // Bridged Go values: methods pass through as Go methods.
6198
+ if (goMetaTypeInfo(goType))
6199
+ return 'class';
5662
6200
  return undefined;
5663
6201
  }
5664
6202
  function isNilLiteral(node) {
@@ -5677,6 +6215,10 @@ function getAcessString(leftSide, rightSide, objectType) {
5677
6215
  if (rightSide === 'length' && objectType !== 'class') {
5678
6216
  return `float64(len(${leftSide}))`;
5679
6217
  }
6218
+ // Buffers / Uint8Arrays / ArrayBuffers are []byte
6219
+ if (rightSide === 'byteLength' && objectType === 'Buffer') {
6220
+ return `float64(len(${leftSide}))`;
6221
+ }
5680
6222
  if (rightSide === 'size' && (objectType === 'Map' || objectType === 'Set')) {
5681
6223
  return `float64(${leftSide}.Len())`;
5682
6224
  }
@@ -5739,18 +6281,61 @@ const callHandlers = {
5739
6281
  const message = args.length > 1 ? args[1] : '"Assertion failed"';
5740
6282
  return `if !(${args[0]}) {\n\t\tpanic(${message})\n\t}`;
5741
6283
  },
5742
- 'console.log': (_caller, args) => {
5743
- importedPackages.add('fmt');
5744
- return `fmt.Println(${args.join(', ')})`;
6284
+ 'console.log': (_caller, args) => consoleOut('Stdout', args),
6285
+ 'console.info': (_caller, args) => consoleOut('Stdout', args),
6286
+ 'console.debug': (_caller, args) => consoleOut('Stdout', args),
6287
+ 'console.trace': (_caller, args) => consoleOut('Stderr', args, 'Trace:'),
6288
+ 'console.dir': (_caller, args) => {
6289
+ useHelper('nodeUtil');
6290
+ return consoleOut('Stdout', [`TnInspect(${args.join(', ')})`], '', true);
6291
+ },
6292
+ 'console.assert': (_caller, args) => {
6293
+ const condition = args[0] ?? 'false';
6294
+ currentCallArgTypes = currentCallArgTypes.slice(1);
6295
+ const message = consoleOut('Stderr', args.slice(1), args.length > 1 ? 'Assertion failed:' : 'Assertion failed');
6296
+ return `if !(${condition}) {\n\t\t${message}\n\t}`;
6297
+ },
6298
+ 'console.table': (_caller, args) => {
6299
+ useHelper('nodeUtil');
6300
+ return consoleOut('Stdout', [`TnConsoleTableString(${args.join(', ')})`], '', true);
6301
+ },
6302
+ 'console.count': (_caller, args) => {
6303
+ useHelper('console');
6304
+ return `TnConsoleCount(${args.join(', ')})`;
6305
+ },
6306
+ 'console.countReset': (_caller, args) => {
6307
+ useHelper('console');
6308
+ return `TnConsoleCountReset(${args.join(', ')})`;
6309
+ },
6310
+ 'console.group': (_caller, args) => {
6311
+ useHelper('console');
6312
+ return `TnConsoleGroup(${consoleArgs(args).join(', ')})`;
6313
+ },
6314
+ 'console.groupCollapsed': (_caller, args) => {
6315
+ useHelper('console');
6316
+ return `TnConsoleGroup(${consoleArgs(args).join(', ')})`;
6317
+ },
6318
+ 'console.groupEnd': () => {
6319
+ useHelper('console');
6320
+ return 'TnConsoleGroupEnd()';
5745
6321
  },
5746
6322
  'console.time': (_caller, args) => {
5747
- importedPackages.add('time');
5748
- return `${getTimerName(args[0])} := time.Now()`;
6323
+ useHelper('console');
6324
+ return `TnConsoleTime(${args.slice(0, 1).join(', ')})`;
5749
6325
  },
5750
6326
  'console.timeEnd': (_caller, args) => {
5751
- importedPackages.add('time');
6327
+ useHelper('console');
6328
+ return `TnConsoleTimeEnd(${args.slice(0, 1).join(', ')})`;
6329
+ },
6330
+ 'console.timeLog': (_caller, args) => {
6331
+ useHelper('console');
6332
+ const label = args[0] ?? '"default"';
6333
+ currentCallArgTypes = currentCallArgTypes.slice(1);
6334
+ const extra = args.length > 1 ? consoleArgs(args.slice(1)) : [];
5752
6335
  importedPackages.add('fmt');
5753
- return `fmt.Println("Elapsed time:", time.Since(${getTimerName(args[0])}))`;
6336
+ importedPackages.add('strings');
6337
+ const text = extra.length > 0 ? `strings.TrimSuffix(fmt.Sprintln(${extra.join(', ')}), "\\n")` : '""';
6338
+ return `TnConsoleTimeLog(${label}, ${text})`;
5754
6339
  },
5755
6340
  'Math.hypot': (_caller, args) => mathCall('Hypot', args),
5756
6341
  'Math.cbrt': (_caller, args) => mathCall('Cbrt', args),
@@ -5925,18 +6510,11 @@ const callHandlers = {
5925
6510
  },
5926
6511
  'Date.now': () => {
5927
6512
  importedPackages.add('time');
5928
- return 'float64(time.Now().UnixMilli())';
5929
- },
5930
- 'console.error': (_caller, args) => {
5931
- importedPackages.add('fmt');
5932
- importedPackages.add('os');
5933
- return `fmt.Fprintln(os.Stderr, ${args.join(', ')})`;
5934
- },
5935
- 'console.warn': (_caller, args) => {
5936
- importedPackages.add('fmt');
5937
- importedPackages.add('os');
5938
- return `fmt.Fprintln(os.Stderr, ${args.join(', ')})`;
6513
+ useHelper('clock');
6514
+ return 'float64(TnTimeNow().UnixMilli())';
5939
6515
  },
6516
+ 'console.error': (_caller, args) => consoleOut('Stderr', args),
6517
+ 'console.warn': (_caller, args) => consoleOut('Stderr', args),
5940
6518
  'Array.isArray': (_caller, args) => {
5941
6519
  importedPackages.add('reflect');
5942
6520
  return `(reflect.ValueOf(${args[0]}).Kind() == reflect.Slice)`;
@@ -5970,6 +6548,59 @@ const callHandlers = {
5970
6548
  },
5971
6549
  'Boolean': (_caller, args) => `(${truthinessCheck(args[0] ?? 'false', currentCallArgTypes[0] ?? 'interface{}')})`,
5972
6550
  };
6551
+ // Built-in Error subclasses (TnErrors carrying their name)
6552
+ const BUILTIN_ERROR_NAMES = new Set(['TypeError', 'RangeError', 'SyntaxError', 'ReferenceError', 'EvalError', 'URIError']);
6553
+ // Whether the program uses console.group (then every console line is
6554
+ // written through the indentation-aware helper)
6555
+ let consoleGroupsUsed = false;
6556
+ // One console line to stdout / stderr, with an optional leading word
6557
+ function consoleOut(stream, args, prefix = '', formatted = false) {
6558
+ let parts = formatted ? args : consoleArgs(args);
6559
+ if (prefix)
6560
+ parts = [toGoStringLiteral(prefix), ...parts];
6561
+ importedPackages.add('fmt');
6562
+ if (consoleGroupsUsed) {
6563
+ useHelper('console');
6564
+ importedPackages.add('os');
6565
+ importedPackages.add('strings');
6566
+ return `TnConsoleWrite(os.${stream}, strings.TrimSuffix(fmt.Sprintln(${parts.join(', ')}), "\\n"))`;
6567
+ }
6568
+ if (stream === 'Stdout')
6569
+ return `fmt.Println(${parts.join(', ')})`;
6570
+ importedPackages.add('os');
6571
+ return `fmt.Fprintln(os.Stderr, ${parts.join(', ')})`;
6572
+ }
6573
+ // console.* arguments, printed like Node: strings as-is, numbers in JS
6574
+ // notation, everything else through util.inspect (and a format string first
6575
+ // argument through util.format)
6576
+ // The inferred type of call argument i ('' when unknown); a plain lookup keeps
6577
+ // the self-hosted build from dereferencing a missing (nil) entry
6578
+ function callArgType(i) {
6579
+ if (i >= currentCallArgTypes.length)
6580
+ return '';
6581
+ const t = currentCallArgTypes[i];
6582
+ return t ? t : '';
6583
+ }
6584
+ function consoleArgs(args) {
6585
+ const types = args.map((_arg, i) => callArgType(i));
6586
+ const isFormatString = args.length > 1 && types[0] === 'string' && args[0].includes('%');
6587
+ const needsInspect = args.some((_arg, i) => !['string', 'float64', 'bool', '[]byte'].includes(types[i]));
6588
+ if (isFormatString || needsInspect) {
6589
+ useHelper('nodeUtil');
6590
+ return [`TnUtilFormat(${args.join(', ')})`];
6591
+ }
6592
+ return args.map((arg, i) => {
6593
+ if (types[i] === 'float64') {
6594
+ useHelper('dynamic');
6595
+ return `TnNumStr(${arg})`;
6596
+ }
6597
+ if (types[i] === '[]byte') {
6598
+ useHelper('buffer');
6599
+ return `TnBufferInspect(${arg})`;
6600
+ }
6601
+ return arg;
6602
+ });
6603
+ }
5973
6604
  const stringMethodHandlers = {
5974
6605
  split: (obj, args) => {
5975
6606
  if (args[0]?.startsWith('regexp.MustCompile('))
@@ -6003,7 +6634,10 @@ const stringMethodHandlers = {
6003
6634
  },
6004
6635
  indexOf: (obj, args) => {
6005
6636
  importedPackages.add('strings');
6006
- return `float64(strings.Index(${obj}, ${args[0]}))`;
6637
+ if (args.length < 2)
6638
+ return `float64(strings.Index(${obj}, ${args[0]}))`;
6639
+ // indexOf(x, from): search from the clamped position, index into the whole string
6640
+ return `func() float64 { __s := ${obj}; __f := int(${args[1]}); if __f < 0 { __f = 0 }; if __f > len(__s) { __f = len(__s) }; __i := strings.Index(__s[__f:], ${args[0]}); if __i < 0 { return -1 }; return float64(__i + __f) }()`;
6007
6641
  },
6008
6642
  charCodeAt: (obj, args) => `float64(${obj}[int(${args[0]})])`,
6009
6643
  localeCompare: (obj, args) => {
@@ -6258,6 +6892,8 @@ function toGoRegexp(arg) {
6258
6892
  // A JS slice index: negative values count from the end
6259
6893
  // A JS slice index: negative values count from the end; out-of-range values clamp
6260
6894
  function sliceIndex(obj, index) {
6895
+ if (index === undefined || index === '')
6896
+ return '0';
6261
6897
  if (index.startsWith('-'))
6262
6898
  return `max(0, int(float64(len(${obj})) + ${index}))`;
6263
6899
  return `min(int(${index}), len(${obj}))`;
@@ -6296,9 +6932,21 @@ const setMethodHandlers = {
6296
6932
  isSupersetOf: (obj, args) => `${args[0]}.IsSubsetOf(${obj})`,
6297
6933
  isDisjointFrom: (obj, args) => `(${obj}.Intersection(${args[0]}).Len() == 0)`
6298
6934
  };
6935
+ // A table entry only when the table itself has it (not Object.prototype's valueOf …)
6936
+ function ownMethodHandler(table, key) {
6937
+ return Object.hasOwn(table, key) ? table[key] : undefined;
6938
+ }
6299
6939
  function getDynamicCallHandler(caller, objectType) {
6300
6940
  if (promiseResolveName && caller === promiseResolveName) {
6301
- return (_caller, args) => `ch <- ${args[0]}`;
6941
+ // The first resolution wins; later ones are ignored (as in JS)
6942
+ return (_caller, args) => {
6943
+ // resolve() without a value: the channel type's zero value
6944
+ if (args.length === 0 || args[0] === 'nil') {
6945
+ useHelper('promise');
6946
+ return 'TnResolveZero(ch)';
6947
+ }
6948
+ return `select { case ch <- ${args[0]}: default: }`;
6949
+ };
6302
6950
  }
6303
6951
  if (promiseRejectName && caller === promiseRejectName) {
6304
6952
  return (_caller, args) => {
@@ -6314,10 +6962,17 @@ function getDynamicCallHandler(caller, objectType) {
6314
6962
  return (c, args) => {
6315
6963
  const obj = c.substring(0, dotIndex);
6316
6964
  if (args.length > 0) {
6965
+ // bigint.toString(radix)
6966
+ if (currentReceiverGoType === '*tnbig.Int')
6967
+ return `${obj}.Text(int(${args[0]}))`;
6317
6968
  importedPackages.add('strconv');
6318
6969
  return `strconv.FormatInt(int64(${obj}), int(${args[0]}))`;
6319
6970
  }
6320
- return jsStringOf(obj, objectType === 'number' || objectType === 'float64' ? 'float64' : undefined);
6971
+ return jsStringOf(obj, objectType === 'number' || objectType === 'float64'
6972
+ ? 'float64'
6973
+ : currentReceiverGoType === 'interface{}'
6974
+ ? 'interface{}'
6975
+ : undefined);
6321
6976
  };
6322
6977
  }
6323
6978
  if (methodName === 'toPrecision') {
@@ -6338,29 +6993,29 @@ function getDynamicCallHandler(caller, objectType) {
6338
6993
  return null;
6339
6994
  let handler;
6340
6995
  if (objectType === 'string') {
6341
- handler = stringMethodHandlers[methodName];
6996
+ handler = ownMethodHandler(stringMethodHandlers, methodName);
6342
6997
  }
6343
6998
  else if (objectType === 'array') {
6344
- handler = arrayMethodHandlers[methodName];
6999
+ handler = ownMethodHandler(arrayMethodHandlers, methodName);
6345
7000
  }
6346
7001
  else if (objectType === 'RegExp') {
6347
- handler = regexpMethodHandlers[methodName];
7002
+ handler = ownMethodHandler(regexpMethodHandlers, methodName);
6348
7003
  }
6349
7004
  else if (objectType === 'Date') {
6350
- handler = dateMethodHandlers[methodName];
7005
+ handler = ownMethodHandler(dateMethodHandlers, methodName);
6351
7006
  }
6352
7007
  else if (objectType === 'Map') {
6353
- handler = mapMethodHandlers[methodName];
7008
+ handler = ownMethodHandler(mapMethodHandlers, methodName);
6354
7009
  }
6355
7010
  else if (objectType === 'Set') {
6356
- handler = setMethodHandlers[methodName];
7011
+ handler = ownMethodHandler(setMethodHandlers, methodName);
6357
7012
  }
6358
7013
  else {
6359
7014
  // Unknown type: try both maps for backward compatibility
6360
7015
  handler =
6361
- stringMethodHandlers[methodName] ??
6362
- arrayMethodHandlers[methodName] ??
6363
- regexpMethodHandlers[methodName];
7016
+ ownMethodHandler(stringMethodHandlers, methodName) ??
7017
+ ownMethodHandler(arrayMethodHandlers, methodName) ??
7018
+ ownMethodHandler(regexpMethodHandlers, methodName);
6364
7019
  }
6365
7020
  if (handler) {
6366
7021
  return (c, args) => {
@@ -6373,7 +7028,10 @@ function getDynamicCallHandler(caller, objectType) {
6373
7028
  }
6374
7029
  function getCallString(caller, args, typeArgs = '', objectType) {
6375
7030
  // Parentheses from casts like `(mod as any).fn(...)` are stripped for lookup
6376
- const handler = callHandlers[caller] ?? callHandlers[caller.replace(/[()]/g, '')] ??
7031
+ // (own entries only: a plain-object lookup would also find Object.prototype members)
7032
+ const bare = caller.replace(/[()]/g, '');
7033
+ const handler = (Object.hasOwn(callHandlers, caller) ? callHandlers[caller] : undefined) ??
7034
+ (Object.hasOwn(callHandlers, bare) ? callHandlers[bare] : undefined) ??
6377
7035
  getDynamicCallHandler(caller, objectType);
6378
7036
  if (handler) {
6379
7037
  return handler(caller, args, typeArgs);
@@ -6474,11 +7132,15 @@ function visitDynamicMethodCall(node) {
6474
7132
  includes: 'TnIncludes',
6475
7133
  indexOf: 'TnIndexOf',
6476
7134
  slice: 'TnSlice',
6477
- concat: 'TnConcat'
7135
+ concat: 'TnConcat',
7136
+ toString: 'TnJSString'
6478
7137
  };
6479
7138
  const helper = dynamicHelpers[method];
6480
- if (!helper)
7139
+ // (a plain-object lookup also finds Object.prototype members)
7140
+ if (!helper || typeof helper !== 'string')
6481
7141
  return undefined;
7142
+ if (method === 'toString')
7143
+ useHelper('error');
6482
7144
  useHelper('dynamic');
6483
7145
  const args = (node.arguments ?? []).map((a) => visit(a));
6484
7146
  return `${helper}(${[visit(node.expression.expression), ...args].join(', ')})`;
@@ -6901,6 +7563,13 @@ function getTypeArguments(typeArguments) {
6901
7563
  return `[${args.join(', ')}]`;
6902
7564
  }
6903
7565
  function getParameterGoType(param) {
7566
+ // Node callbacks / hooks: `any`-typed parameters take Node's types too
7567
+ const nodeHookTypes = param.parent?.tnParamTypes;
7568
+ if (nodeHookTypes && param.type?.kind === 'AnyKeyword' && !param.dotDotDotToken) {
7569
+ const hookType = nodeHookTypes[(param.parent.parameters ?? []).indexOf(param)];
7570
+ if (hookType)
7571
+ return hookType;
7572
+ }
6904
7573
  // Rest parameter: ...args — use variadic syntax
6905
7574
  if (param.dotDotDotToken) {
6906
7575
  if (param.type) {
@@ -6919,7 +7588,7 @@ function getParameterGoType(param) {
6919
7588
  // Array parameters are references (mutations are visible to the caller) —
6920
7589
  // except unbound type parameters (Go generics), template-tag arrays, and
6921
7590
  // dynamic []interface{} (runtime helper arrays)
6922
- if (explicitType.startsWith('[]') && explicitType !== '[]interface{}' && !param.dotDotDotToken) {
7591
+ if (explicitType.startsWith('[]') && explicitType !== '[]interface{}' && explicitType !== '[]byte' && !param.dotDotDotToken) {
6923
7592
  const isTaggedTemplateArray = isTypeReferenceNode(param.type) &&
6924
7593
  isIdentifier(param.type.typeName) &&
6925
7594
  param.type.typeName.text === 'TemplateStringsArray';
@@ -6943,9 +7612,19 @@ function getParameterGoType(param) {
6943
7612
  const contextualFn = param.parent ? getContextualFunctionType(param.parent) : undefined;
6944
7613
  if (contextualFn) {
6945
7614
  const index = (param.parent.parameters ?? []).indexOf(param);
6946
- const contextualParamType = contextualFn.parameters?.[index]?.type;
6947
- if (contextualParamType)
6948
- return getType(contextualParamType);
7615
+ const contextualParam = contextualFn.parameters?.[index];
7616
+ const contextualParamType = contextualParam?.type;
7617
+ if (contextualParamType) {
7618
+ const contextualGoType = getType(contextualParamType);
7619
+ return contextualParam.questionToken ? makeNullableType(contextualGoType) : contextualGoType;
7620
+ }
7621
+ }
7622
+ // Callbacks of Node APIs: parameter types from the registry
7623
+ const nodeParamTypes = param.parent?.tnParamTypes;
7624
+ if (nodeParamTypes) {
7625
+ const nodeParamType = nodeParamTypes[(param.parent.parameters ?? []).indexOf(param)];
7626
+ if (nodeParamType)
7627
+ return nodeParamType;
6949
7628
  }
6950
7629
  return 'interface{}';
6951
7630
  }
@@ -7153,8 +7832,27 @@ function getFunctionParametersInfo(parameters) {
7153
7832
  prefixBlockContent: prefixBlockContent + destructuring
7154
7833
  };
7155
7834
  }
7835
+ // Go packages the generated code may import: a user identifier with one of
7836
+ // these names would shadow the package, so it is renamed (unless the name is
7837
+ // itself a `go:` package import)
7838
+ const goPackageIdentifiers = new Set([
7839
+ 'aes', 'atomic', 'base64', 'binary', 'bufio', 'bytes', 'cipher', 'crc32', 'errors', 'exec', 'filepath',
7840
+ 'flate', 'fmt', 'fs', 'gzip', 'hash', 'hex', 'hkdf', 'hmac', 'html', 'io', 'iter', 'json', 'math', 'md5',
7841
+ 'net', 'os', 'pbkdf2', 'rand', 'reflect', 'regexp', 'runtime', 'sha1', 'sha256', 'sha3', 'sha512', 'signal',
7842
+ 'slices', 'sort', 'strconv', 'strings', 'subtle', 'sync', 'syscall', 'time', 'unicode', 'unsafe', 'user',
7843
+ 'utf16', 'utf8', 'zlib', 'asn1', 'bits', 'context', 'ecdh', 'ecdsa', 'ed25519', 'elliptic', 'encoding', 'http',
7844
+ 'log', 'mime', 'multipart', 'netip', 'pem', 'pkix', 'rsa', 'textproto', 'tls', 'x509',
7845
+ // Aliased imports (math/big, crypto, net/url, crypto/rand)
7846
+ 'tnbig', 'tncrypto', 'tnurl', 'cryptorand',
7847
+ // Go builtins: a package-level `var copy` would shadow copy() in the helpers
7848
+ 'append', 'cap', 'clear', 'close', 'complex', 'copy', 'imag', 'len', 'make', 'max', 'min', 'panic',
7849
+ 'print', 'println', 'real', 'recover', 'any', 'byte', 'error', 'float64', 'int', 'int64', 'rune',
7850
+ 'uint', 'uint8', 'uint32', 'nil', 'iota'
7851
+ ]);
7852
+ // Local names of `go:` package imports (`import * as strings from 'go:strings'`)
7853
+ const goPackageLocalNames = new Set();
7156
7854
  function getSafeName(name) {
7157
- if (!dangerousNames.has(name)) {
7855
+ if (!dangerousNames.has(name) && !(goPackageIdentifiers.has(name) && !goPackageLocalNames.has(name))) {
7158
7856
  return name;
7159
7857
  }
7160
7858
  if (!renamedFunctions.has(name)) {
@@ -7212,6 +7910,11 @@ function emitChannelFunction(node, isAsync) {
7212
7910
  const body = visit(node.body, { prefixBlockContent: parameterInfo.prefixBlockContent });
7213
7911
  asyncChannelVar = prevChannel;
7214
7912
  asyncFunctionNode = prevFn;
7913
+ if (isAsync) {
7914
+ // The body runs synchronously until its first await, holding the JS baton
7915
+ useHelper('eventLoop');
7916
+ return (`func ${name}${typeParams}(${parameterInfo.signature}) chan ${chanType} {\n\t${channelVar} := make(chan ${chanType}, 1)\n\tTnStartAsync(func() {\n\t\tdefer close(${channelVar})${rejectOnPanic}\n\t\t${body.trim()}\n\t})\n\treturn ${channelVar}\n}`);
7917
+ }
7215
7918
  return (`func ${name}${typeParams}(${parameterInfo.signature}) chan ${chanType} {\n\t${channelVar} := make(chan ${chanType})\n\tgo func() {\n\t\tdefer close(${channelVar})${rejectOnPanic}\n\t\t${body.trim()}\n\t}()\n\treturn ${channelVar}\n}`);
7216
7919
  }
7217
7920
  // The type a generator yields: from its first yield expression's operand
@@ -7231,6 +7934,7 @@ function visitPromiseReturn(node, options) {
7231
7934
  if (!callback || (!isArrowFunction(callback) && !isFunctionExpression(callback))) {
7232
7935
  return `return ${visit(node)}` + (options.inline ? '' : ';\n\t');
7233
7936
  }
7937
+ useHelper('promise');
7234
7938
  const channelType = getPromiseChannelType(node);
7235
7939
  const resolveParam = callback.parameters[0];
7236
7940
  const resolveName = resolveParam ? visit(resolveParam.name) : '';
@@ -7242,7 +7946,7 @@ function visitPromiseReturn(node, options) {
7242
7946
  const body = isBlock(callback.body) ? visit(callback.body) : `{ ${visit(callback.body)} }`;
7243
7947
  promiseResolveName = prevResolveName;
7244
7948
  promiseRejectName = prevRejectName;
7245
- return (`ch := make(chan ${channelType})\n\t\tgo func() ${body.trimEnd()}()\n\t\treturn ch` +
7949
+ return (`ch := make(chan ${channelType}, 1)\n\t\tfunc() {\n\t\t\tdefer TnRejectExecutor(ch)\n\t\t\tfunc() ${body.trimEnd()}()\n\t\t}()\n\t\treturn ch` +
7246
7950
  (options.inline ? '' : ';\n\t'));
7247
7951
  }
7248
7952
  function visitNewPromise(node) {
@@ -7261,7 +7965,10 @@ function visitNewPromise(node) {
7261
7965
  const body = isBlock(callback.body) ? visit(callback.body) : `{ ${visit(callback.body)} }`;
7262
7966
  promiseResolveName = prevResolveName;
7263
7967
  promiseRejectName = prevRejectName;
7264
- return `func() chan ${channelType} {\n\t\tch := make(chan ${channelType})\n\t\tgo func() ${body.trimEnd()}()\n\t\treturn ch;\n\t}()`;
7968
+ // Buffered: resolving never blocks (a loop task may resolve a promise its own goroutine awaits)
7969
+ // The executor runs synchronously, as in JS (a throw rejects the promise)
7970
+ useHelper('promise');
7971
+ return `func() chan ${channelType} {\n\t\tch := make(chan ${channelType}, 1)\n\t\tfunc() {\n\t\t\tdefer TnRejectExecutor(ch)\n\t\t\tfunc() ${body.trimEnd()}()\n\t\t}()\n\t\treturn ch;\n\t}()`;
7265
7972
  }
7266
7973
  function extractMapValueType(mapType) {
7267
7974
  const args = splitMapTypeArgs(mapType);
@@ -7374,6 +8081,9 @@ function includeLocalImport(code, dir, goFileName, tsx = false) {
7374
8081
  // `package main`, so helpers are emitted once in the main output file.
7375
8082
  const savedOutsideNodes = outsideNodes;
7376
8083
  const savedPackages = [...importedPackages];
8084
+ // Helper packages registered by the including file so far must survive this
8085
+ // file's own tracking (the main file imports them for the helpers it carries)
8086
+ const savedHelperPackages = [...helperProvidedPackages];
7377
8087
  outsideNodes = [];
7378
8088
  importedPackages.clear();
7379
8089
  helperProvidedPackages.clear();
@@ -7384,10 +8094,10 @@ function includeLocalImport(code, dir, goFileName, tsx = false) {
7384
8094
  for (const stmt of sf.statements) {
7385
8095
  const result = visit(stmt, { addFunctionOutside: true });
7386
8096
  if (result.trim())
7387
- inlineLines.push(result);
8097
+ inlineLines.push(localizeGoPaths(result));
7388
8098
  }
7389
8099
  emittingModuleFile = prevEmittingModuleFile;
7390
- const fileOutside = outsideNodes.map((n) => visit(n, { isOutside: true })).join('\n');
8100
+ const fileOutside = localizeGoPaths(outsideNodes.map((n) => visit(n, { isOutside: true })).join('\n'));
7391
8101
  const isDeclarationLine = (line) => /^(var|const|type|func|import)\b/.test(line.trim());
7392
8102
  const declarationLines = inlineLines.filter(isDeclarationLine);
7393
8103
  const statementLines = inlineLines.filter((line) => !isDeclarationLine(line));
@@ -7405,7 +8115,7 @@ function includeLocalImport(code, dir, goFileName, tsx = false) {
7405
8115
  .filter((pkg) => {
7406
8116
  if (!helperProvidedPackages.has(pkg))
7407
8117
  return true;
7408
- const pkgName = goImportAliases[pkg] ?? pkg.split('/').pop();
8118
+ const pkgName = goPathAliases[pkg] ?? pkg.split('/').pop();
7409
8119
  return stripGoStrings(fileCode).includes(`${pkgName}.`);
7410
8120
  })
7411
8121
  .sort()
@@ -7426,6 +8136,8 @@ function includeLocalImport(code, dir, goFileName, tsx = false) {
7426
8136
  for (const p of savedPackages)
7427
8137
  importedPackages.add(p);
7428
8138
  currentFileIsTsx = prevTsx;
8139
+ for (const p of savedHelperPackages)
8140
+ helperProvidedPackages.add(p);
7429
8141
  for (const p of helperProvidedPackages)
7430
8142
  importedPackages.add(p);
7431
8143
  currentFileDir = prevDir;
@@ -7434,21 +8146,63 @@ function includeLocalImport(code, dir, goFileName, tsx = false) {
7434
8146
  function stripGoStrings(code) {
7435
8147
  return code.replace(/"(?:[^"\\\n]|\\.)*"|`[^`]*`/g, '""');
7436
8148
  }
7437
- function registerGoPackageAliases(node, goPkg) {
7438
- const pkgName = goPkg.split('/').pop();
8149
+ // go:builtin is virtual: ref<T> → new(T), chan<T> → make(chan T),
8150
+ // GoError → *TnError. No Go import; local names map to inline emitters.
8151
+ function registerGoBuiltinAliases(node) {
7439
8152
  if (!node.importClause)
7440
8153
  return;
7441
8154
  const clause = node.importClause;
8155
+ if (clause.name)
8156
+ importAliases.set(clause.name.text, 'go:builtin');
8157
+ const bindings = clause.namedBindings;
8158
+ if (!bindings)
8159
+ return;
8160
+ if (isNamespaceImport(bindings)) {
8161
+ importAliases.set(bindings.name.text, 'go:builtin');
8162
+ return;
8163
+ }
8164
+ if (isNamedImports(bindings)) {
8165
+ for (const el of bindings.elements ?? []) {
8166
+ if (el.isTypeOnly)
8167
+ continue;
8168
+ const localName = el.name.text;
8169
+ const importedName = el.propertyName?.text ?? localName;
8170
+ importAliases.set(localName, `go:builtin.${importedName}`);
8171
+ registerGoBuiltin(localName, importedName);
8172
+ }
8173
+ }
8174
+ }
8175
+ function registerGoPackageAliases(node, goPkg) {
8176
+ // Real package name from metadata (math/rand/v2 → rand); fall back to the
8177
+ // last path segment for packages without metadata.
8178
+ const info = goPackage(goPkg);
8179
+ const pkgName = info ? info.name : goPkg.split('/').pop();
8180
+ // Collision alias (crypto/rand vs math/rand): the emitted qualifier.
8181
+ const qualifier = goPathAliases[goPkg] ?? pkgName;
8182
+ goPackageLocalNames.add(pkgName);
8183
+ goPackageLocalNames.add(qualifier);
8184
+ const named = [];
8185
+ let defaultName = null;
8186
+ let namespaceName = null;
8187
+ if (!node.importClause) {
8188
+ registerGoImport(goPkg, qualifier, null, null, []);
8189
+ return;
8190
+ }
8191
+ const clause = node.importClause;
7442
8192
  // Default import: `import fmt from 'go:fmt'` or `import myFmt from 'go:fmt'`
7443
- if (clause.name && clause.name.text !== pkgName) {
7444
- importAliases.set(clause.name.text, pkgName);
8193
+ if (clause.name) {
8194
+ defaultName = clause.name.text;
8195
+ if (clause.name.text !== pkgName && clause.name.text !== qualifier) {
8196
+ importAliases.set(clause.name.text, qualifier);
8197
+ }
7445
8198
  }
7446
8199
  if (clause.namedBindings) {
7447
8200
  if (isNamespaceImport(clause.namedBindings)) {
7448
8201
  // `import * as myFmt from 'go:fmt'`
7449
8202
  const localName = clause.namedBindings.name.text;
7450
- if (localName !== pkgName) {
7451
- importAliases.set(localName, pkgName);
8203
+ namespaceName = localName;
8204
+ if (localName !== pkgName && localName !== qualifier) {
8205
+ importAliases.set(localName, qualifier);
7452
8206
  }
7453
8207
  }
7454
8208
  else if (isNamedImports(clause.namedBindings)) {
@@ -7458,10 +8212,12 @@ function registerGoPackageAliases(node, goPkg) {
7458
8212
  continue;
7459
8213
  const localName = el.name.text;
7460
8214
  const importedName = el.propertyName?.text ?? localName;
7461
- importAliases.set(localName, `${pkgName}.${importedName}`);
8215
+ importAliases.set(localName, `${qualifier}.${importedName}`);
8216
+ named.push({ imported: importedName, local: localName });
7462
8217
  }
7463
8218
  }
7464
8219
  }
8220
+ registerGoImport(goPkg, qualifier, defaultName, namespaceName, named);
7465
8221
  }
7466
8222
  function getImportLocalName(node) {
7467
8223
  const clause = node.importClause;
@@ -7489,7 +8245,10 @@ function needPkg(pkg) {
7489
8245
  const helperRequires = {
7490
8246
  objectAssign: ['orderedMap'],
7491
8247
  promiseAll: ['orderedMap', 'asyncWait', 'promise'],
7492
- promise: ['error'],
8248
+ promise: ['error', 'eventLoop', 'asyncWait'],
8249
+ goMust: ['error'],
8250
+ bigint: ['error'],
8251
+ goBlocking: ['error', 'eventLoop'],
7493
8252
  decorators: [],
7494
8253
  jsx: [],
7495
8254
  objectIntegrity: [],
@@ -7499,8 +8258,10 @@ const helperRequires = {
7499
8258
  fancyRegex: ['orderedMap'],
7500
8259
  dynamic: ['error'],
7501
8260
  moduleUrl: ['pathToFileURL'],
7502
- timerWait: [],
7503
- asyncWait: []
8261
+ timerWait: ['eventLoop'],
8262
+ clock: [],
8263
+ asyncWait: ['eventLoop'],
8264
+ eventLoop: []
7504
8265
  };
7505
8266
  function useHelper(id) {
7506
8267
  if (usedHelpers.has(id))
@@ -7510,159 +8271,85 @@ function useHelper(id) {
7510
8271
  if (id === 'namedGroups') {
7511
8272
  interfacePropertyTypes.set('TnMatch', new Map([['groups', '*TnMap[string, string]']]));
7512
8273
  }
7513
- for (const dep of helperRequires[id] ?? [])
8274
+ for (const dep of helperRequires[id] ?? nodeRegistry.helperRequires[id] ?? [])
7514
8275
  useHelper(dep);
7515
- for (const pkg of helperPackages[id] ?? []) {
8276
+ for (const pkg of helperPackages[id] ?? nodeRegistry.helperPackages[id] ?? []) {
7516
8277
  importedPackages.add(pkg);
7517
8278
  helperProvidedPackages.add(pkg);
7518
8279
  }
7519
8280
  }
7520
- const nodeModuleMappings = {
7521
- path: {
7522
- functions: {
7523
- join: (args) => {
7524
- needPkg('path/filepath');
7525
- return `filepath.Join(${args.join(', ')})`;
7526
- },
7527
- dirname: (args) => {
7528
- needPkg('path/filepath');
7529
- return `filepath.Dir(${args[0]})`;
7530
- },
7531
- basename: (args) => {
7532
- needPkg('path/filepath');
7533
- if (args[1]) {
7534
- needPkg('strings');
7535
- return `strings.TrimSuffix(filepath.Base(${args[0]}), ${args[1]})`;
7536
- }
7537
- return `filepath.Base(${args[0]})`;
7538
- },
7539
- extname: (args) => {
7540
- needPkg('path/filepath');
7541
- return `filepath.Ext(${args[0]})`;
7542
- },
7543
- resolve: (args) => {
7544
- needPkg('path/filepath');
7545
- return `func() string { p, _ := filepath.Abs(filepath.Join(${args.join(', ')})); return p }()`;
7546
- }
7547
- }
7548
- },
7549
- fs: {
7550
- functions: {
7551
- readFileSync: (args) => {
7552
- useHelper('readFile');
7553
- return `TnReadFile(${args[0]})`;
7554
- },
7555
- writeFileSync: (args) => {
7556
- useHelper('writeFile');
7557
- return `TnWriteFile(${args[0]}, ${args[1]})`;
7558
- },
7559
- appendFileSync: (args) => {
7560
- useHelper('appendFile');
7561
- return `TnAppendFile(${args[0]}, ${args[1]})`;
7562
- },
7563
- existsSync: (args) => {
7564
- needPkg('os');
7565
- return `func() bool { _, err := os.Stat(${args[0]}); return !os.IsNotExist(err) }()`;
7566
- },
7567
- mkdirSync: (args) => {
7568
- useHelper('mkdirAll');
7569
- return `TnMkdirAll(${args[0]})`;
7570
- },
7571
- readdirSync: (args) => {
7572
- useHelper('readDir');
7573
- return `TnReadDir(${args[0]})`;
7574
- },
7575
- copyFileSync: (args) => {
7576
- useHelper('copyFile');
7577
- return `TnCopyFile(${args[0]}, ${args[1]})`;
7578
- },
7579
- rmSync: (args) => {
7580
- useHelper('removeAll');
7581
- return `TnRemoveAll(${args[0]})`;
7582
- },
7583
- unlinkSync: (args) => {
7584
- useHelper('removeAll');
7585
- return `TnRemoveAll(${args[0]})`;
7586
- }
7587
- }
7588
- },
7589
- url: {
7590
- functions: {
7591
- fileURLToPath: (args) => {
7592
- useHelper('fileURLToPath');
7593
- return `TnFileURLToPath(${args[0]})`;
7594
- },
7595
- pathToFileURL: (args) => {
7596
- useHelper('pathToFileURL');
7597
- return `TnPathToFileURL(${args[0]})`;
7598
- }
7599
- }
7600
- },
7601
- os: {
7602
- functions: {
7603
- platform: () => {
7604
- useHelper('osPlatform');
7605
- return 'TnOsPlatform()';
7606
- },
7607
- homedir: () => {
7608
- needPkg('os');
7609
- return `func() string { h, _ := os.UserHomeDir(); return h }()`;
7610
- },
7611
- tmpdir: () => {
7612
- needPkg('os');
7613
- return 'os.TempDir()';
7614
- }
7615
- }
7616
- },
7617
- child_process: {
7618
- functions: {
7619
- // exec(command) — run through the shell, returns { stdout, stderr, status }
7620
- exec: (args) => {
7621
- useHelper('exec');
7622
- return `TnExecShell(${args[0]})`;
7623
- },
7624
- // execSync(command) — run through the shell, returns stdout (panics on failure)
7625
- execSync: (args) => {
7626
- useHelper('exec');
7627
- useHelper('execSync');
7628
- return `TnExecShellSync(${args[0]})`;
7629
- },
7630
- // spawnSync(file, args, options) — matches Node's sync API.
7631
- // options with `inherit` → run with the parent's stdio (returns exit code);
7632
- // otherwise output is captured. Fields match Node: stdout/stderr/status.
7633
- spawnSync: (args) => {
7634
- useHelper('exec');
7635
- useHelper('runInherit');
7636
- // Untyped array literals visit as `[] {…}` — give them the []string
7637
- // type the variadic helper needs (`[]string{…}...` is valid Go spread)
7638
- const arrArg = args[1] ?? '[]string{}';
7639
- const typedArg = arrArg.startsWith('[]') && !arrArg.startsWith('[]string')
7640
- ? arrArg.replace(/^\[\]\S* \{/, '[]string{')
7641
- : arrArg;
7642
- if (args[2]?.includes('inherit')) {
7643
- return `TnRunInherit(${args[0]}, ${typedArg}...)`;
7644
- }
7645
- if (args[2]?.includes('input')) {
7646
- // {input: expr, ...} → run with expr as stdin
7647
- useHelper('execInput');
7648
- const m = /input:\s*([^,}]+)/.exec(args[2]);
7649
- const inputExpr = m ? m[1] : '""';
7650
- return `TnExecInput(${args[0]}, ${inputExpr}, ${typedArg}...)`;
7651
- }
7652
- return `TnExec(${args[0]}, ${typedArg}...)`;
7653
- }
7654
- }
7655
- },
7656
- readline: {
7657
- functions: {
7658
- // question(prompt) — print prompt and read one line from stdin (synchronous)
7659
- question: (args) => {
7660
- useHelper('question');
7661
- return `TnQuestion(${args[0] ?? '""'})`;
7662
- }
7663
- }
7664
- }
7665
- };
8281
+ // Node.js standard library (src/node/*): functions, values and classes the
8282
+ // transpiler resolves imports and Node globals against
8283
+ // (services are bound in transpileToNative: a Go package-level initializer
8284
+ // referring to visit() would be an initialization cycle)
8285
+ const nodeRegistry = createNodeRegistry();
8286
+ function bindNodeRegistryServices() {
8287
+ nodeRegistry.pkg = needPkg;
8288
+ nodeRegistry.helper = useHelper;
8289
+ nodeRegistry.temp = getTempName;
8290
+ nodeRegistry.typeOf = (node) => inferExpressionType(node) ?? '';
8291
+ nodeRegistry.visit = (node) => visit(node);
8292
+ nodeRegistry.categoryOf = (node) => resolveExpressionType(node) ?? '';
8293
+ bindConvertServices({
8294
+ pkg: needPkg,
8295
+ helper: useHelper,
8296
+ typeOf: (node) => inferExpressionType(node) ?? '',
8297
+ localType: goLocalType
8298
+ });
8299
+ bindBridgeServices({
8300
+ pkg: needPkg,
8301
+ helper: useHelper,
8302
+ temp: getTempName,
8303
+ typeOf: (node) => inferExpressionType(node) ?? '',
8304
+ visit: (node) => visit(node),
8305
+ categoryOf: (node) => resolveExpressionType(node) ?? '',
8306
+ goTypeOf: (node) => getType(node),
8307
+ isIdentifier: (node) => isIdentifier(node),
8308
+ isPropertyAccess: (node) => isPropertyAccessExpression(node),
8309
+ isArrowFunction: (node) => isArrowFunction(node),
8310
+ isFunctionExpression: (node) => isFunctionExpression(node),
8311
+ isObjectLiteral: (node) => isObjectLiteralExpression(node),
8312
+ declareLocal: (name, goType) => registerLocalVariable(name, goType)
8313
+ });
8314
+ }
8315
+ registerCore(nodeRegistry);
8316
+ registerBuffer(nodeRegistry);
8317
+ registerPath(nodeRegistry);
8318
+ registerFs(nodeRegistry);
8319
+ registerUrl(nodeRegistry);
8320
+ registerOs(nodeRegistry);
8321
+ registerProcess(nodeRegistry);
8322
+ registerUtil(nodeRegistry);
8323
+ registerUtilExtra(nodeRegistry);
8324
+ registerConsole(nodeRegistry);
8325
+ registerAssert(nodeRegistry);
8326
+ registerPunycode(nodeRegistry);
8327
+ registerQuerystring(nodeRegistry);
8328
+ registerStringDecoder(nodeRegistry);
8329
+ registerCrypto(nodeRegistry);
8330
+ registerCryptoKeys(nodeRegistry);
8331
+ registerZlib(nodeRegistry);
8332
+ registerTimers(nodeRegistry);
8333
+ registerEvents(nodeRegistry);
8334
+ registerStream(nodeRegistry);
8335
+ registerDiagnosticsChannel(nodeRegistry);
8336
+ registerConstants(nodeRegistry);
8337
+ registerChildProcess(nodeRegistry);
8338
+ registerReadline(nodeRegistry);
8339
+ registerNet(nodeRegistry);
8340
+ registerDns(nodeRegistry);
8341
+ registerTls(nodeRegistry);
8342
+ registerHttp(nodeRegistry);
8343
+ registerDgram(nodeRegistry);
8344
+ registerSqlite(nodeRegistry);
8345
+ registerFetch(nodeRegistry);
8346
+ registerStreamWeb(nodeRegistry);
8347
+ registerAsyncHooks(nodeRegistry);
8348
+ registerTest(nodeRegistry);
8349
+ registerWorkerThreads(nodeRegistry);
8350
+ registerCluster(nodeRegistry);
8351
+ registerHttp2(nodeRegistry);
8352
+ registerSystemExtra(nodeRegistry);
7666
8353
  // Go packages required by each helper, registered when the helper is used.
7667
8354
  const helperPackages = {
7668
8355
  regexReplaceFirst: ['regexp'],
@@ -7672,38 +8359,31 @@ const helperPackages = {
7672
8359
  typeOf: ['reflect'],
7673
8360
  dynamic: ['math', 'strings', 'fmt', 'sort', 'reflect', 'strconv', 'regexp', 'unsafe'],
7674
8361
  regexReplaceFunc: ['regexp'],
7675
- readFile: ['os'],
7676
- writeFile: ['os'],
7677
- appendFile: ['os'],
7678
- mkdirAll: ['os'],
7679
- readDir: ['os'],
7680
- copyFile: ['os', 'io', 'path/filepath'],
7681
- removeAll: ['os'],
7682
- fileURLToPath: ['net/url', 'path/filepath', 'strings'],
7683
- pathToFileURL: ['net/url', 'path/filepath'],
8362
+ pathToFileURL: ['net/url', 'path/filepath', 'strings'],
7684
8363
  osPlatform: ['runtime'],
7685
8364
  error: [],
7686
- bigint: ['math/big'],
8365
+ bigint: ['math/big', 'math'],
7687
8366
  symbol: [],
7688
8367
  fancyRegex: ['regexp', 'strings', 'strconv', 'fmt'],
7689
8368
  namedGroups: ['regexp'],
7690
8369
  moduleUrl: ['os'],
7691
- asyncWait: ['sync'],
7692
- timerWait: ['sync', 'time'],
8370
+ asyncWait: [],
8371
+ timerWait: ['sync', 'sync/atomic', 'time'],
8372
+ clock: ['time'],
8373
+ eventLoop: ['sync', 'sync/atomic', 'time'],
7693
8374
  uri: ['strings', 'fmt', 'net/url'],
7694
8375
  promiseAll: [],
7695
8376
  promise: ['sync'],
8377
+ goMust: [],
8378
+ goNums: [],
8379
+ goStrings: [],
8380
+ goBlocking: [],
7696
8381
  decorators: [],
7697
8382
  jsx: ['strings', 'html', 'reflect', 'strconv', 'fmt'],
7698
8383
  objectIntegrity: ['sync', 'reflect'],
7699
8384
  structuredClone: ['reflect', 'unsafe'],
7700
8385
  globalThis: [],
7701
- exec: ['os/exec', 'bytes', 'runtime'],
7702
- execSync: ['os/exec', 'bytes', 'runtime'],
7703
- runInherit: ['os/exec', 'os'],
7704
- question: ['bufio', 'fmt', 'os', 'strings'],
7705
8386
  getenv: ['os'],
7706
- execInput: ['os/exec', 'bytes', 'strings']
7707
8387
  };
7708
8388
  // Go helper sources emitted (once) into the main output file when used.
7709
8389
  // Field names are intentionally lowercase: every generated file is `package main`,
@@ -7723,10 +8403,27 @@ func TnGet(obj interface{}, key string) interface{} {
7723
8403
  if key == "length" {
7724
8404
  return float64(len(o))
7725
8405
  }
8406
+ case interface{ TnProp(string) (interface{}, bool) }:
8407
+ if v, ok := o.TnProp(key); ok || key != "length" {
8408
+ return v
8409
+ }
7726
8410
  case *TnError:
7727
8411
  if key == "message" {
7728
8412
  return o.message
7729
8413
  }
8414
+ if key == "code" {
8415
+ if o.code == "" {
8416
+ return o.prop("code")
8417
+ }
8418
+ return o.code
8419
+ }
8420
+ if key == "name" {
8421
+ return o.Get_name()
8422
+ }
8423
+ if key == "stack" {
8424
+ return o.Get_stack()
8425
+ }
8426
+ return o.prop(key)
7730
8427
  }
7731
8428
  rv := reflect.ValueOf(obj)
7732
8429
  if rv.Kind() == reflect.Pointer && !rv.IsNil() && rv.Elem().Kind() == reflect.Struct {
@@ -7743,6 +8440,27 @@ func TnGet(obj interface{}, key string) interface{} {
7743
8440
  return nil
7744
8441
  }
7745
8442
 
8443
+ // new Error(message, { cause })
8444
+ func TnErrorWithOptions(e *TnError, options interface{}) *TnError {
8445
+ if options == nil {
8446
+ return e
8447
+ }
8448
+ if e.props == nil {
8449
+ e.props = map[string]interface{}{}
8450
+ }
8451
+ if m, ok := options.(map[string]interface{}); ok {
8452
+ if cause, present := m["cause"]; present {
8453
+ e.props["cause"] = cause
8454
+ }
8455
+ return e
8456
+ }
8457
+ rv := reflect.ValueOf(options)
8458
+ if rv.Kind() == reflect.Pointer && !rv.IsNil() && rv.Elem().Kind() == reflect.Struct && rv.Elem().FieldByName("cause").IsValid() {
8459
+ e.props["cause"] = TnGet(options, "cause")
8460
+ }
8461
+ return e
8462
+ }
8463
+
7746
8464
  func TnSet(obj interface{}, key string, value interface{}) {
7747
8465
  if o, ok := obj.(map[string]interface{}); ok {
7748
8466
  o[key] = value
@@ -7781,6 +8499,15 @@ func TnIndex(obj interface{}, key interface{}) interface{} {
7781
8499
  if i, ok := key.(float64); ok && i >= 0 && int(i) < len(o) {
7782
8500
  return string(o[int(i)])
7783
8501
  }
8502
+ case []byte:
8503
+ if i, ok := key.(float64); ok && i >= 0 && int(i) < len(o) {
8504
+ return float64(o[int(i)])
8505
+ }
8506
+ case interface{ TnProp(string) (interface{}, bool) }:
8507
+ if k, ok := key.(string); ok {
8508
+ v, _ := o.TnProp(k)
8509
+ return v
8510
+ }
7784
8511
  }
7785
8512
  return nil
7786
8513
  }
@@ -7831,6 +8558,44 @@ func TnLength(v interface{}) float64 {
7831
8558
  }
7832
8559
 
7833
8560
  // A value as JS prints it in a template literal (nil pointers are "undefined")
8561
+ // String(v) of a dynamic value, as JS renders it
8562
+ func TnJSString(v interface{}) string {
8563
+ switch x := v.(type) {
8564
+ case nil:
8565
+ return "undefined"
8566
+ case string:
8567
+ return x
8568
+ case float64:
8569
+ return TnNumStr(x)
8570
+ case bool:
8571
+ if x {
8572
+ return "true"
8573
+ }
8574
+ return "false"
8575
+ case []byte:
8576
+ return strings.ToValidUTF8(string(x), "�")
8577
+ case []interface{}:
8578
+ parts := make([]string, len(x))
8579
+ for i, e := range x {
8580
+ if e != nil {
8581
+ parts[i] = TnJSString(e)
8582
+ }
8583
+ }
8584
+ return strings.Join(parts, ",")
8585
+ case []string:
8586
+ return strings.Join(x, ",")
8587
+ case map[string]interface{}:
8588
+ return "[object Object]"
8589
+ case *TnError:
8590
+ return x.Get_name() + ": " + x.message
8591
+ case fmt.Stringer:
8592
+ return x.String()
8593
+ case interface{ toString() string }:
8594
+ return x.toString()
8595
+ }
8596
+ return fmt.Sprintf("%v", v)
8597
+ }
8598
+
7834
8599
  func TnFormat(v interface{}) string {
7835
8600
  rv := reflect.ValueOf(v)
7836
8601
  if !rv.IsValid() || (rv.Kind() == reflect.Pointer && rv.IsNil()) {
@@ -8006,6 +8771,9 @@ func TnHas(obj interface{}, key interface{}) bool {
8006
8771
  }
8007
8772
 
8008
8773
  func TnKeys(obj interface{}) []string {
8774
+ if record, ok := obj.(interface{ Keys() []string }); ok {
8775
+ return append([]string{}, record.Keys()...)
8776
+ }
8009
8777
  o, _ := obj.(map[string]interface{})
8010
8778
  keys := make([]string, 0, len(o))
8011
8779
  for k := range o {
@@ -8093,6 +8861,10 @@ func TnAsPtr[T any](v interface{}) *T {
8093
8861
  if t, ok := v.(T); ok {
8094
8862
  return &t
8095
8863
  }
8864
+ var zero T
8865
+ if converted, ok := TnConvertDynamic(v, reflect.TypeOf(&zero)); ok {
8866
+ return converted.Interface().(*T)
8867
+ }
8096
8868
  return nil
8097
8869
  }
8098
8870
 
@@ -8100,25 +8872,108 @@ func TnAs[T any](v interface{}) T {
8100
8872
  if p, ok := v.(*T); ok && p != nil {
8101
8873
  return *p
8102
8874
  }
8103
- t, _ := v.(T)
8875
+ t, ok := v.(T)
8876
+ if !ok && v != nil {
8877
+ if converted, cok := TnConvertDynamic(v, reflect.TypeOf((*T)(nil)).Elem()); cok {
8878
+ return converted.Interface().(T)
8879
+ }
8880
+ }
8104
8881
  return t
8105
8882
  }
8106
8883
 
8107
- func TnTruthy(v interface{}) bool {
8108
- switch t := v.(type) {
8109
- case nil:
8110
- return false
8111
- case bool:
8112
- return t
8113
- case float64:
8114
- return t != 0 && !math.IsNaN(t)
8115
- case string:
8116
- return t != ""
8884
+ // Converts a dynamic value (decoded JSON: maps, []interface{}, float64 …) to a
8885
+ // Go type: structs (and pointers to them) field by field, slices element by
8886
+ // element, numbers between kinds
8887
+ func TnConvertDynamic(v interface{}, t reflect.Type) (reflect.Value, bool) {
8888
+ if v == nil {
8889
+ return reflect.Zero(t), true
8117
8890
  }
8118
8891
  rv := reflect.ValueOf(v)
8119
- switch rv.Kind() {
8120
- case reflect.Pointer, reflect.Interface, reflect.Map, reflect.Slice:
8121
- return !rv.IsNil()
8892
+ if rv.Type().AssignableTo(t) {
8893
+ return rv, true
8894
+ }
8895
+ switch t.Kind() {
8896
+ case reflect.Interface:
8897
+ if rv.Type().Implements(t) {
8898
+ return rv, true
8899
+ }
8900
+ case reflect.Pointer:
8901
+ if rv.Kind() == reflect.Pointer && rv.IsNil() {
8902
+ return reflect.Zero(t), true
8903
+ }
8904
+ inner, ok := TnConvertDynamic(v, t.Elem())
8905
+ if !ok {
8906
+ return reflect.Value{}, false
8907
+ }
8908
+ p := reflect.New(t.Elem())
8909
+ p.Elem().Set(inner)
8910
+ return p, true
8911
+ case reflect.Struct:
8912
+ m, ok := v.(map[string]interface{})
8913
+ if props, isRecord := v.(interface{ Entries() [][]interface{} }); !ok && isRecord {
8914
+ // A string-keyed TnMap (a Record, a node:sqlite row)
8915
+ m, ok = map[string]interface{}{}, true
8916
+ for _, e := range props.Entries() {
8917
+ if k, isString := e[0].(string); isString {
8918
+ m[k] = e[1]
8919
+ }
8920
+ }
8921
+ }
8922
+ if !ok {
8923
+ return reflect.Value{}, false
8924
+ }
8925
+ out := reflect.New(t).Elem()
8926
+ for i := 0; i < t.NumField(); i++ {
8927
+ field := t.Field(i)
8928
+ name := strings.TrimSuffix(field.Name, "_")
8929
+ value, present := m[name]
8930
+ if !present {
8931
+ continue
8932
+ }
8933
+ converted, ok := TnConvertDynamic(value, field.Type)
8934
+ if !ok {
8935
+ continue
8936
+ }
8937
+ f := out.Field(i)
8938
+ reflect.NewAt(f.Type(), unsafe.Pointer(f.UnsafeAddr())).Elem().Set(converted)
8939
+ }
8940
+ return out, true
8941
+ case reflect.Slice:
8942
+ if rv.Kind() != reflect.Slice {
8943
+ return reflect.Value{}, false
8944
+ }
8945
+ out := reflect.MakeSlice(t, rv.Len(), rv.Len())
8946
+ for i := 0; i < rv.Len(); i++ {
8947
+ converted, ok := TnConvertDynamic(rv.Index(i).Interface(), t.Elem())
8948
+ if !ok {
8949
+ return reflect.Value{}, false
8950
+ }
8951
+ out.Index(i).Set(converted)
8952
+ }
8953
+ return out, true
8954
+ case reflect.Float64, reflect.Float32, reflect.Int, reflect.Int64, reflect.Int32:
8955
+ if rv.CanConvert(t) && rv.Kind() >= reflect.Int && rv.Kind() <= reflect.Float64 {
8956
+ return rv.Convert(t), true
8957
+ }
8958
+ }
8959
+ return reflect.Value{}, false
8960
+ }
8961
+
8962
+ func TnTruthy(v interface{}) bool {
8963
+ switch t := v.(type) {
8964
+ case nil:
8965
+ return false
8966
+ case bool:
8967
+ return t
8968
+ case float64:
8969
+ return t != 0 && !math.IsNaN(t)
8970
+ case string:
8971
+ return t != ""
8972
+ }
8973
+ rv := reflect.ValueOf(v)
8974
+ switch rv.Kind() {
8975
+ case reflect.Pointer, reflect.Interface, reflect.Map, reflect.Slice:
8976
+ return !rv.IsNil()
8122
8977
  }
8123
8978
  return true
8124
8979
  }
@@ -8243,6 +9098,31 @@ func tnJSONWrite(buf *bytes.Buffer, rv reflect.Value, indent string, depth int)
8243
9098
  }
8244
9099
  buf.WriteByte('}')
8245
9100
  case reflect.Struct:
9101
+ // Records (TnMap) keep their key order; reached through a pointer, the
9102
+ // struct value needs Addr() for pointer-receiver methods
9103
+ if rv.CanAddr() {
9104
+ if m, ok := rv.Addr().Interface().(interface{ Entries() [][]interface{} }); ok {
9105
+ buf.WriteByte('{')
9106
+ for i, e := range m.Entries() {
9107
+ if i > 0 {
9108
+ buf.WriteByte(',')
9109
+ }
9110
+ tnJSONNewline(buf, indent, depth+1)
9111
+ kd, _ := tnJSONMarshal(fmt.Sprint(e[0]))
9112
+ buf.Write(kd)
9113
+ buf.WriteByte(':')
9114
+ if indent != "" {
9115
+ buf.WriteByte(' ')
9116
+ }
9117
+ tnJSONWrite(buf, reflect.ValueOf(e[1]), indent, depth+1)
9118
+ }
9119
+ if len(m.Entries()) > 0 {
9120
+ tnJSONNewline(buf, indent, depth)
9121
+ }
9122
+ buf.WriteByte('}')
9123
+ return
9124
+ }
9125
+ }
8246
9126
  if m, ok := rv.Interface().(json.Marshaler); ok {
8247
9127
  data, err := m.MarshalJSON()
8248
9128
  if err == nil {
@@ -8323,6 +9203,17 @@ func (m *TnMap[K, V]) Get(k K) V {
8323
9203
  return m.values[k]
8324
9204
  }
8325
9205
 
9206
+ // A string key's value when the map is held in a dynamic value (a Record or a
9207
+ // node:sqlite row read as \`row.name\`): TnGet finds it through this method
9208
+ func (m *TnMap[K, V]) TnProp(key string) (interface{}, bool) {
9209
+ k, ok := any(key).(K)
9210
+ if !ok || m == nil {
9211
+ return nil, false
9212
+ }
9213
+ v, present := m.values[k]
9214
+ return v, present
9215
+ }
9216
+
8326
9217
  func (m *TnMap[K, V]) Lookup(k K) (V, bool) {
8327
9218
  if m == nil {
8328
9219
  var zero V
@@ -8447,6 +9338,40 @@ func (m *TnMap[K, V]) All() iter.Seq2[K, V] {
8447
9338
  }
8448
9339
  }
8449
9340
 
9341
+ // JSON objects decode in document order (json.Unmarshal into a ref)
9342
+ func (m *TnMap[K, V]) UnmarshalJSON(data []byte) error {
9343
+ dec := json.NewDecoder(bytes.NewReader(data))
9344
+ tok, err := dec.Token()
9345
+ if err != nil {
9346
+ return err
9347
+ }
9348
+ if delim, ok := tok.(json.Delim); !ok || delim != '{' {
9349
+ return fmt.Errorf("json: cannot unmarshal %v into an object", tok)
9350
+ }
9351
+ m.keys = nil
9352
+ m.values = map[K]V{}
9353
+ for dec.More() {
9354
+ tok, err := dec.Token()
9355
+ if err != nil {
9356
+ return err
9357
+ }
9358
+ name, _ := tok.(string)
9359
+ var key K
9360
+ if p, ok := any(&key).(*string); ok {
9361
+ *p = name
9362
+ } else if err := json.Unmarshal([]byte(name), &key); err != nil {
9363
+ return err
9364
+ }
9365
+ var value V
9366
+ if err := dec.Decode(&value); err != nil {
9367
+ return err
9368
+ }
9369
+ m.Set(key, value)
9370
+ }
9371
+ _, err = dec.Token()
9372
+ return err
9373
+ }
9374
+
8450
9375
  // JSON objects keep insertion order
8451
9376
  func (m *TnMap[K, V]) MarshalJSON() ([]byte, error) {
8452
9377
  var buf bytes.Buffer
@@ -9424,81 +10349,17 @@ func TnGroup(groups []string, i int) string {
9424
10349
  return groups[i]
9425
10350
  }
9426
10351
  return ""
9427
- }`,
9428
- readFile: `func TnReadFile(path string) string {
9429
- data, err := os.ReadFile(path)
9430
- if err != nil {
9431
- panic(err)
9432
- }
9433
- return string(data)
9434
- }`,
9435
- writeFile: `func TnWriteFile(path string, content string) {
9436
- if err := os.WriteFile(path, []byte(content), 0o644); err != nil {
9437
- panic(err)
9438
- }
9439
- }`,
9440
- appendFile: `func TnAppendFile(path string, content string) {
9441
- f, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644)
9442
- if err != nil {
9443
- panic(err)
9444
- }
9445
- defer f.Close()
9446
- if _, err := f.WriteString(content); err != nil {
9447
- panic(err)
9448
- }
9449
- }`,
9450
- mkdirAll: `func TnMkdirAll(path string) {
9451
- if err := os.MkdirAll(path, 0o755); err != nil {
9452
- panic(err)
9453
- }
9454
- }`,
9455
- readDir: `func TnReadDir(path string) []string {
9456
- entries, err := os.ReadDir(path)
9457
- if err != nil {
9458
- panic(err)
9459
- }
9460
- names := make([]string, 0, len(entries))
9461
- for _, e := range entries {
9462
- names = append(names, e.Name())
9463
- }
9464
- return names
9465
- }`,
9466
- copyFile: `func TnCopyFile(src string, dst string) {
9467
- in, err := os.Open(src)
9468
- if err != nil {
9469
- panic(err)
9470
- }
9471
- defer in.Close()
9472
- if err := os.MkdirAll(filepath.Dir(dst), 0o755); err != nil {
9473
- panic(err)
9474
- }
9475
- out, err := os.Create(dst)
9476
- if err != nil {
9477
- panic(err)
9478
- }
9479
- defer out.Close()
9480
- if _, err := io.Copy(out, in); err != nil {
9481
- panic(err)
9482
- }
9483
- }`,
9484
- removeAll: `func TnRemoveAll(path string) {
9485
- if err := os.RemoveAll(path); err != nil {
9486
- panic(err)
9487
- }
9488
- }`,
9489
- fileURLToPath: `func TnFileURLToPath(u string) string {
9490
- trimmed := strings.TrimPrefix(u, "file://")
9491
- if unescaped, err := tnurl.PathUnescape(trimmed); err == nil {
9492
- trimmed = unescaped
9493
- }
9494
- return filepath.FromSlash(trimmed)
9495
10352
  }`,
9496
10353
  pathToFileURL: `func TnPathToFileURL(path string) string {
9497
10354
  abs, err := filepath.Abs(path)
9498
10355
  if err != nil {
9499
10356
  panic(err)
9500
10357
  }
9501
- return "file://" + tnurl.PathEscape(filepath.ToSlash(abs))
10358
+ slashed := filepath.ToSlash(abs)
10359
+ if !strings.HasPrefix(slashed, "/") {
10360
+ slashed = "/" + slashed
10361
+ }
10362
+ return "file://" + (&tnurl.URL{Path: slashed}).EscapedPath()
9502
10363
  }`,
9503
10364
  moduleUrl: `// import.meta.url: the file URL of the running program
9504
10365
  func TnModuleURL() string {
@@ -9517,22 +10378,223 @@ func TnModuleURL() string {
9517
10378
  }
9518
10379
  return runtime.GOOS
9519
10380
  }`,
9520
- error: `// TnError: JS Error values (thrown and caught) with a message
10381
+ error: `// TnError: JS Error values (thrown and caught) with a message; Node
10382
+ // errors also carry a code ('ENOENT', 'ERR_ASSERTION') and extra properties
9521
10383
  type TnError struct {
9522
10384
  message string
10385
+ code string
10386
+ props map[string]interface{}
10387
+ goErr error
9523
10388
  }
9524
10389
 
9525
10390
  func (e *TnError) Error() string { return e.message }
9526
10391
 
9527
10392
  func TnNewError(message string) *TnError {
9528
10393
  return &TnError{message: message}
10394
+ }
10395
+
10396
+
10397
+ // x instanceof Error / TypeError / …
10398
+ func TnIsErrorOf(v interface{}, name string) bool {
10399
+ if name == "Error" {
10400
+ _, ok := v.(error)
10401
+ return ok
10402
+ }
10403
+ e, ok := v.(*TnError)
10404
+ return ok && e.Get_name() == name
10405
+ }
10406
+
10407
+ // A Node error: name ('TypeError', 'AssertionError'), code and message
10408
+ func TnNodeError(name string, code string, message string) *TnError {
10409
+ return &TnError{message: message, code: code, props: map[string]interface{}{"name": name}}
10410
+ }
10411
+
10412
+ func (e *TnError) prop(key string) interface{} {
10413
+ if e.props == nil {
10414
+ return nil
10415
+ }
10416
+ return e.props[key]
10417
+ }
10418
+
10419
+ func (e *TnError) Get_name() string {
10420
+ if name, ok := e.prop("name").(string); ok {
10421
+ return name
10422
+ }
10423
+ return "Error"
10424
+ }
10425
+
10426
+ func (e *TnError) Get_stack() string { return e.Get_name() + ": " + e.message }
10427
+
10428
+ func (e *TnError) Get_syscall() string {
10429
+ s, _ := e.prop("syscall").(string)
10430
+ return s
10431
+ }
10432
+
10433
+ func (e *TnError) Get_path() string {
10434
+ s, _ := e.prop("path").(string)
10435
+ return s
10436
+ }
10437
+
10438
+ func (e *TnError) Get_errno() float64 {
10439
+ n, _ := e.prop("errno").(float64)
10440
+ return n
10441
+ }
10442
+
10443
+ func (e *TnError) Get_cause() interface{} { return e.prop("cause") }
10444
+
10445
+ func (e *TnError) Get_hostname() string {
10446
+ s, _ := e.prop("hostname").(string)
10447
+ return s
10448
+ }
10449
+
10450
+ func (e *TnError) Get_address() string {
10451
+ s, _ := e.prop("address").(string)
10452
+ return s
10453
+ }
10454
+
10455
+ func (e *TnError) Get_port() float64 {
10456
+ n, _ := e.prop("port").(float64)
10457
+ return n
10458
+ }
10459
+
10460
+ // AssertionError fields
10461
+ func (e *TnError) Get_actual() interface{} { return e.prop("actual") }
10462
+
10463
+ func (e *TnError) Get_expected() interface{} { return e.prop("expected") }
10464
+
10465
+ func (e *TnError) Get_operator() string {
10466
+ s, _ := e.prop("operator").(string)
10467
+ return s
10468
+ }
10469
+
10470
+ func (e *TnError) Get_generatedMessage() bool {
10471
+ b, _ := e.prop("generatedMessage").(bool)
10472
+ return b
10473
+ }`,
10474
+ asyncWait: `// Pending async work (promise callbacks, detached async calls) keeps the
10475
+ // event loop alive until it settles
10476
+ var __tnWaitGroup tnLoopGroup`,
10477
+ bigint: `// Base from the literal's prefix (0x / 0o / 0b), decimal otherwise
10478
+ func TnBigInt(s string) *tnbig.Int {
10479
+ v, ok := new(tnbig.Int).SetString(s, 0)
10480
+ if !ok {
10481
+ v, _ = new(tnbig.Int).SetString(s, 10)
10482
+ }
10483
+ return v
10484
+ }
10485
+
10486
+ // x === 1n where x is a dynamic (number | bigint) value
10487
+ func TnBigSame(v interface{}, b *tnbig.Int) bool {
10488
+ x, ok := v.(*tnbig.Int)
10489
+ return ok && x != nil && b != nil && x.Cmp(b) == 0
10490
+ }
10491
+
10492
+ // A dynamic value as a bigint operand: a bigint, or an integral number
10493
+ func TnToBigInt(v interface{}) *tnbig.Int {
10494
+ switch x := v.(type) {
10495
+ case *tnbig.Int:
10496
+ if x != nil {
10497
+ return x
10498
+ }
10499
+ case float64:
10500
+ if x == math.Trunc(x) && !math.IsInf(x, 0) {
10501
+ b, _ := new(tnbig.Float).SetFloat64(x).Int(nil)
10502
+ return b
10503
+ }
10504
+ }
10505
+ panic(TnNodeError("TypeError", "", "Cannot mix BigInt and other types, use explicit conversions"))
9529
10506
  }`,
9530
- asyncWait: `// Pending async work (promise callbacks, detached async calls) is drained
9531
- // before the process exits
9532
- var __tnWaitGroup sync.WaitGroup`,
9533
- bigint: `func TnBigInt(s string) *tnbig.Int {
9534
- v, _ := new(tnbig.Int).SetString(s, 10)
10507
+ goMust: `// Go bridge: (T, error) results throw a *TnError carrying the Go error
10508
+ func tnGoError(err error) *TnError {
10509
+ return &TnError{message: err.Error(), goErr: err}
10510
+ }
10511
+
10512
+ func tnGoMust[T any](v T, err error) T {
10513
+ if err != nil {
10514
+ panic(tnGoError(err))
10515
+ }
9535
10516
  return v
10517
+ }
10518
+
10519
+ func tnGoMust2[A any, B any](a A, b B, err error) (A, B) {
10520
+ if err != nil {
10521
+ panic(tnGoError(err))
10522
+ }
10523
+ return a, b
10524
+ }
10525
+
10526
+ func tnGoCheck(err error) {
10527
+ if err != nil {
10528
+ panic(tnGoError(err))
10529
+ }
10530
+ }`,
10531
+ goNums: `// Go bridge: numeric slice conversion ([]int ↔ []float64)
10532
+ type tnGoNumber interface {
10533
+ ~int | ~int8 | ~int16 | ~int32 | ~int64 |
10534
+ ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
10535
+ ~float32 | ~float64
10536
+ }
10537
+
10538
+ func tnGoNums[T tnGoNumber](s []float64) []T {
10539
+ out := make([]T, len(s))
10540
+ for i, v := range s {
10541
+ out[i] = T(v)
10542
+ }
10543
+ return out
10544
+ }
10545
+
10546
+ func tnGoFromNums[T tnGoNumber](s []T) []float64 {
10547
+ out := make([]float64, len(s))
10548
+ for i, v := range s {
10549
+ out[i] = float64(v)
10550
+ }
10551
+ return out
10552
+ }`,
10553
+ goStrings: `// Go bridge: first rune of a string (unicode funcs take rune)
10554
+ func tnGoRune(s string) rune {
10555
+ for _, r := range s {
10556
+ return r
10557
+ }
10558
+ return 0
10559
+ }`,
10560
+ goBlocking: `// Go bridge: blocking calls run on a goroutine while the baton holder
10561
+ // pumps pending loop tasks, so timers and handlers keep running
10562
+ func tnGoBlocking(fn func() interface{}) interface{} {
10563
+ done := make(chan interface{}, 1)
10564
+ go func() {
10565
+ defer func() {
10566
+ if r := recover(); r != nil {
10567
+ done <- r
10568
+ return
10569
+ }
10570
+ }()
10571
+ done <- fn()
10572
+ }()
10573
+ for {
10574
+ select {
10575
+ case v := <-done:
10576
+ if err, ok := v.(*TnError); ok {
10577
+ panic(err)
10578
+ }
10579
+ return v
10580
+ default:
10581
+ }
10582
+ TnRunMicrotasks()
10583
+ if TnLoopRunPending() {
10584
+ continue
10585
+ }
10586
+ tnRelease()
10587
+ select {
10588
+ case v := <-done:
10589
+ tnAcquire()
10590
+ if err, ok := v.(*TnError); ok {
10591
+ panic(err)
10592
+ }
10593
+ return v
10594
+ case <-tnLoopSignal:
10595
+ tnAcquire()
10596
+ }
10597
+ }
9536
10598
  }`,
9537
10599
  symbol: `// TnSymbol: JS symbol values (unique by identity)
9538
10600
  type TnSymbol struct {
@@ -9542,79 +10604,438 @@ type TnSymbol struct {
9542
10604
  func TnNewSymbol(description string) *TnSymbol {
9543
10605
  return &TnSymbol{description: description}
9544
10606
  }`,
9545
- timerWait: `// Pending setTimeout timers are waited on before the process exits
9546
- var __tnTimers sync.WaitGroup
10607
+ timerWait: `// Timers: callbacks run on the event loop; pending (ref'ed) timers keep the process alive
10608
+ var __tnTimers tnLoopGroup
10609
+
10610
+ // A setTimeout / setImmediate handle (Node's Timeout: ref / unref / hasRef / refresh / close)
10611
+ type TnTimeout struct {
10612
+ timer *time.Timer
10613
+ ms float64
10614
+ fn func()
10615
+ refd bool
10616
+ active bool
10617
+ gen int
10618
+ }
10619
+
10620
+ // node:test mock timers: when set (and the API is mocked) it takes over a timer;
10621
+ // run calls the callback and reports whether the timer repeats
10622
+ var tnMockTimerHook func(kind string, ms float64, run func() bool) bool
10623
+
10624
+ func TnSetTimeout(ms float64, fn func()) *TnTimeout { return tnSetTimeout("setTimeout", ms, fn) }
10625
+
10626
+ func TnSetImmediate(fn func()) *TnTimeout { return tnSetTimeout("setImmediate", 0, fn) }
9547
10627
 
9548
- func TnSetTimeout(ms float64, fn func()) *time.Timer {
10628
+ func tnSetTimeout(kind string, ms float64, fn func()) *TnTimeout {
10629
+ t := &TnTimeout{ms: ms, fn: TnAsyncWrap(fn), active: true}
10630
+ if tnMockTimerHook != nil && tnMockTimerHook(kind, ms, func() bool {
10631
+ if t.active {
10632
+ t.active = false
10633
+ t.fn()
10634
+ }
10635
+ return false
10636
+ }) {
10637
+ return t
10638
+ }
9549
10639
  __tnTimers.Add(1)
9550
- return time.AfterFunc(time.Duration(ms*float64(time.Millisecond)), func() {
9551
- defer __tnTimers.Done()
9552
- fn()
9553
- TnRunMicrotasks()
10640
+ t.refd = true
10641
+ t.arm()
10642
+ return t
10643
+ }
10644
+
10645
+ func (t *TnTimeout) arm() {
10646
+ t.gen++
10647
+ gen := t.gen
10648
+ t.timer = time.AfterFunc(time.Duration(t.ms*float64(time.Millisecond)), func() {
10649
+ TnLoopPost(func() {
10650
+ if !t.active || gen != t.gen {
10651
+ return
10652
+ }
10653
+ t.active = false
10654
+ if t.refd {
10655
+ t.refd = false
10656
+ __tnTimers.Done()
10657
+ }
10658
+ t.fn()
10659
+ })
9554
10660
  })
9555
10661
  }
9556
10662
 
9557
- // setInterval: fn every ms until cleared (the process lives until then)
10663
+ func (t *TnTimeout) ref() *TnTimeout {
10664
+ if !t.refd && t.active {
10665
+ t.refd = true
10666
+ __tnTimers.Add(1)
10667
+ }
10668
+ return t
10669
+ }
10670
+
10671
+ func (t *TnTimeout) unref() *TnTimeout {
10672
+ if t.refd {
10673
+ t.refd = false
10674
+ __tnTimers.Done()
10675
+ }
10676
+ return t
10677
+ }
10678
+
10679
+ func (t *TnTimeout) hasRef() bool { return t.refd }
10680
+
10681
+ // refresh(): restarts the countdown (a fired timeout runs again)
10682
+ func (t *TnTimeout) refresh() *TnTimeout {
10683
+ if t.timer == nil && t.active && !t.refd {
10684
+ // A mocked timer: node:test's clock owns it
10685
+ return t
10686
+ }
10687
+ if t.timer != nil {
10688
+ t.timer.Stop()
10689
+ }
10690
+ if !t.active {
10691
+ t.active = true
10692
+ if !t.refd {
10693
+ t.refd = true
10694
+ __tnTimers.Add(1)
10695
+ }
10696
+ }
10697
+ t.arm()
10698
+ return t
10699
+ }
10700
+
10701
+ func (t *TnTimeout) close() *TnTimeout {
10702
+ TnClearTimeout(t)
10703
+ return t
10704
+ }
10705
+
10706
+ // setInterval: fn every ms until cleared (the process lives until then, unless unref'ed)
9558
10707
  type TnInterval struct {
9559
- stop chan struct{}
9560
- once sync.Once
10708
+ stop chan struct{}
10709
+ once sync.Once
10710
+ stopped int32
10711
+ refd bool
10712
+ ms float64
10713
+ fn func()
9561
10714
  }
9562
10715
 
9563
10716
  func TnSetInterval(ms float64, fn func()) *TnInterval {
10717
+ t := &TnInterval{stop: make(chan struct{}), ms: ms, fn: TnAsyncWrap(fn)}
10718
+ if tnMockTimerHook != nil && tnMockTimerHook("setInterval", ms, func() bool {
10719
+ if atomic.LoadInt32(&t.stopped) != 0 {
10720
+ return false
10721
+ }
10722
+ t.fn()
10723
+ return atomic.LoadInt32(&t.stopped) == 0
10724
+ }) {
10725
+ return t
10726
+ }
9564
10727
  __tnTimers.Add(1)
9565
- t := &TnInterval{stop: make(chan struct{})}
10728
+ t.refd = true
10729
+ t.start(t.stop)
10730
+ return t
10731
+ }
10732
+
10733
+ func (t *TnInterval) start(stop chan struct{}) {
9566
10734
  go func() {
9567
- ticker := time.NewTicker(max(time.Duration(ms*float64(time.Millisecond)), time.Millisecond))
10735
+ ticker := time.NewTicker(max(time.Duration(t.ms*float64(time.Millisecond)), time.Millisecond))
9568
10736
  defer ticker.Stop()
9569
10737
  for {
9570
10738
  select {
9571
- case <-t.stop:
10739
+ case <-stop:
9572
10740
  return
9573
10741
  case <-ticker.C:
9574
- fn()
9575
- TnRunMicrotasks()
10742
+ TnLoopPost(func() {
10743
+ if atomic.LoadInt32(&t.stopped) == 0 {
10744
+ t.fn()
10745
+ }
10746
+ })
9576
10747
  }
9577
10748
  }
9578
10749
  }()
9579
- return t
9580
10750
  }
9581
10751
 
9582
10752
  func TnClearInterval(t *TnInterval) {
9583
10753
  if t != nil {
9584
10754
  t.once.Do(func() {
10755
+ atomic.StoreInt32(&t.stopped, 1)
9585
10756
  close(t.stop)
9586
- __tnTimers.Done()
10757
+ if t.refd {
10758
+ t.refd = false
10759
+ __tnTimers.Done()
10760
+ }
9587
10761
  })
9588
10762
  }
9589
10763
  }
9590
10764
 
9591
- // queueMicrotask: run after the current synchronous code (end of main or of a timer callback)
9592
- var tnMicrotasks []func()
9593
- var tnMicrotasksMu sync.Mutex
10765
+ func (t *TnInterval) ref() *TnInterval {
10766
+ if !t.refd && atomic.LoadInt32(&t.stopped) == 0 {
10767
+ t.refd = true
10768
+ __tnTimers.Add(1)
10769
+ }
10770
+ return t
10771
+ }
9594
10772
 
9595
- func TnQueueMicrotask(fn func()) {
9596
- tnMicrotasksMu.Lock()
9597
- tnMicrotasks = append(tnMicrotasks, fn)
9598
- tnMicrotasksMu.Unlock()
10773
+ func (t *TnInterval) unref() *TnInterval {
10774
+ if t.refd {
10775
+ t.refd = false
10776
+ __tnTimers.Done()
10777
+ }
10778
+ return t
9599
10779
  }
9600
10780
 
9601
- func TnRunMicrotasks() {
9602
- for {
9603
- tnMicrotasksMu.Lock()
9604
- if len(tnMicrotasks) == 0 {
9605
- tnMicrotasksMu.Unlock()
9606
- return
9607
- }
9608
- fn := tnMicrotasks[0]
9609
- tnMicrotasks = tnMicrotasks[1:]
9610
- tnMicrotasksMu.Unlock()
10781
+ func (t *TnInterval) hasRef() bool { return t.refd }
10782
+
10783
+ func (t *TnInterval) refresh() *TnInterval {
10784
+ if atomic.LoadInt32(&t.stopped) == 0 {
10785
+ close(t.stop)
10786
+ t.stop = make(chan struct{})
10787
+ t.start(t.stop)
10788
+ }
10789
+ return t
10790
+ }
10791
+
10792
+ func (t *TnInterval) close() *TnInterval {
10793
+ TnClearInterval(t)
10794
+ return t
10795
+ }
10796
+
10797
+ func TnClearTimeout(t *TnTimeout) {
10798
+ if t != nil && t.active {
10799
+ t.active = false
10800
+ if t.timer != nil {
10801
+ t.timer.Stop()
10802
+ }
10803
+ if t.refd {
10804
+ t.refd = false
10805
+ __tnTimers.Done()
10806
+ }
10807
+ }
10808
+ }`,
10809
+ clock: `// The current time; node:test mock timers can replace it (Date.now / new Date())
10810
+ var tnClockHook func() time.Time
10811
+
10812
+ func TnTimeNow() time.Time {
10813
+ if tnClockHook != nil {
10814
+ return tnClockHook()
10815
+ }
10816
+ return time.Now()
10817
+ }`,
10818
+ eventLoop: `// The event loop. JS runs one thing at a time: whoever holds the
10819
+ // baton (main, a loop task, a running async function body) runs JS code; the
10820
+ // others wait. An await runs pending loop tasks, then hands the baton over
10821
+ // while it waits. Callbacks from timers, I/O and other goroutines are posted
10822
+ // as tasks. Refs (pending timers, async work, open handles) keep it alive.
10823
+ var tnLoopMu sync.Mutex
10824
+ var tnLoopTasks []func()
10825
+ var tnLoopSignal = make(chan struct{}, 1)
10826
+ var tnLoopRefs int64
10827
+
10828
+ // The baton: free when it sits in the channel (main holds it at start).
10829
+ // A call of an async function lends it to the body until its first await.
10830
+ var tnBaton = make(chan struct{}, 1)
10831
+ var tnLendStack []chan struct{}
10832
+
10833
+ // Async context (AsyncLocalStorage): the baton holder's current stores. Callbacks
10834
+ // scheduled by JS code capture it (TnAsyncWrap) and run with it restored; an await
10835
+ // resumes with the context it started with. Other loop tasks run without stores.
10836
+ type TnAsyncContext map[interface{}]interface{}
10837
+
10838
+ var tnAsyncCtx TnAsyncContext
10839
+
10840
+ func TnAsyncSnapshot() TnAsyncContext { return tnAsyncCtx }
10841
+
10842
+ // Runs fn with ctx as the current context, restoring the previous one afterwards
10843
+ func TnAsyncRun(ctx TnAsyncContext, fn func()) {
10844
+ saved := tnAsyncCtx
10845
+ tnAsyncCtx = ctx
10846
+ defer func() { tnAsyncCtx = saved }()
10847
+ fn()
10848
+ }
10849
+
10850
+ // fn bound to the current context (no-op when there is none to keep)
10851
+ func TnAsyncWrap(fn func()) func() {
10852
+ ctx := tnAsyncCtx
10853
+ if ctx == nil {
10854
+ return fn
10855
+ }
10856
+ return func() { TnAsyncRun(ctx, fn) }
10857
+ }
10858
+
10859
+ func tnAcquire() { <-tnBaton }
10860
+
10861
+ func tnRelease() {
10862
+ if n := len(tnLendStack); n > 0 {
10863
+ lender := tnLendStack[n-1]
10864
+ tnLendStack = tnLendStack[:n-1]
10865
+ close(lender)
10866
+ return
10867
+ }
10868
+ tnBaton <- struct{}{}
10869
+ }
10870
+
10871
+ // Runs an async function body: synchronously until its first await (or the
10872
+ // end), then the caller continues while the body waits
10873
+ func TnStartAsync(body func()) {
10874
+ yielded := make(chan struct{})
10875
+ tnLendStack = append(tnLendStack, yielded)
10876
+ ctx := tnAsyncCtx
10877
+ go func() {
10878
+ defer tnRelease()
10879
+ tnAsyncCtx = ctx
10880
+ body()
10881
+ }()
10882
+ <-yielded
10883
+ tnAsyncCtx = ctx
10884
+ }
10885
+
10886
+ func tnLoopNotify() {
10887
+ select {
10888
+ case tnLoopSignal <- struct{}{}:
10889
+ default:
10890
+ }
10891
+ }
10892
+
10893
+ func TnLoopRef() { atomic.AddInt64(&tnLoopRefs, 1) }
10894
+
10895
+ func TnLoopUnref() {
10896
+ atomic.AddInt64(&tnLoopRefs, -1)
10897
+ tnLoopNotify()
10898
+ }
10899
+
10900
+ func TnLoopPost(fn func()) {
10901
+ tnLoopMu.Lock()
10902
+ tnLoopTasks = append(tnLoopTasks, fn)
10903
+ tnLoopMu.Unlock()
10904
+ tnLoopNotify()
10905
+ }
10906
+
10907
+ // Runs a callback on the loop from a goroutine that does not hold the baton,
10908
+ // and waits for it
10909
+ func TnLoopCall(fn func()) {
10910
+ done := make(chan struct{})
10911
+ TnLoopPost(func() {
10912
+ defer close(done)
9611
10913
  fn()
10914
+ })
10915
+ <-done
10916
+ }
10917
+
10918
+ // (baton holder) Runs the queued tasks, each followed by its microtasks
10919
+ func TnLoopRunPending() bool {
10920
+ ran := false
10921
+ for {
10922
+ tnLoopMu.Lock()
10923
+ if len(tnLoopTasks) == 0 {
10924
+ tnLoopMu.Unlock()
10925
+ return ran
10926
+ }
10927
+ fn := tnLoopTasks[0]
10928
+ tnLoopTasks = tnLoopTasks[1:]
10929
+ tnLoopMu.Unlock()
10930
+ ran = true
10931
+ tnRunTask(fn)
10932
+ TnRunMicrotasks()
9612
10933
  }
9613
10934
  }
9614
10935
 
9615
- func TnClearTimeout(t *time.Timer) {
9616
- if t != nil && t.Stop() {
9617
- __tnTimers.Done()
10936
+ // Set by process.on('uncaughtException'): handles a throw escaping a loop task
10937
+ // (true when handled); 'beforeExit' runs when the loop drains (true when it emitted)
10938
+ var tnUncaughtHook func(err interface{}) bool
10939
+ var tnBeforeExitHook func() bool
10940
+
10941
+ func tnRunTask(fn func()) {
10942
+ if tnUncaughtHook != nil {
10943
+ defer func() {
10944
+ if r := recover(); r != nil {
10945
+ if !tnUncaughtHook(r) {
10946
+ panic(r)
10947
+ }
10948
+ }
10949
+ }()
10950
+ }
10951
+ TnAsyncRun(nil, fn)
10952
+ }
10953
+
10954
+ func tnLoopIdle() bool {
10955
+ tnLoopMu.Lock()
10956
+ defer tnLoopMu.Unlock()
10957
+ return len(tnLoopTasks) == 0 && atomic.LoadInt64(&tnLoopRefs) <= 0
10958
+ }
10959
+
10960
+ // The end of main: run until nothing is pending
10961
+ func TnRunLoop() {
10962
+ for {
10963
+ TnRunMicrotasks()
10964
+ TnLoopRunPending()
10965
+ if tnLoopIdle() {
10966
+ if tnBeforeExitHook == nil || !tnBeforeExitHook() {
10967
+ return
10968
+ }
10969
+ TnRunMicrotasks()
10970
+ TnLoopRunPending()
10971
+ if tnLoopIdle() {
10972
+ return
10973
+ }
10974
+ continue
10975
+ }
10976
+ tnRelease()
10977
+ select {
10978
+ case <-tnLoopSignal:
10979
+ case <-time.After(10 * time.Millisecond):
10980
+ }
10981
+ tnAcquire()
10982
+ }
10983
+ }
10984
+
10985
+ // (baton holder) Receives from a channel, running loop tasks while waiting
10986
+ func TnLoopReceive[T any](ch chan T) (T, bool) {
10987
+ ctx := tnAsyncCtx
10988
+ defer func() { tnAsyncCtx = ctx }()
10989
+ for {
10990
+ select {
10991
+ case v, ok := <-ch:
10992
+ return v, ok
10993
+ default:
10994
+ }
10995
+ TnRunMicrotasks()
10996
+ if TnLoopRunPending() {
10997
+ continue
10998
+ }
10999
+ tnRelease()
11000
+ select {
11001
+ case v, ok := <-ch:
11002
+ tnAcquire()
11003
+ return v, ok
11004
+ case <-tnLoopSignal:
11005
+ tnAcquire()
11006
+ }
11007
+ }
11008
+ }
11009
+
11010
+ // A wait group that keeps the loop alive (detached async calls, .then callbacks)
11011
+ type tnLoopGroup struct{}
11012
+
11013
+ func (tnLoopGroup) Add(n int) { atomic.AddInt64(&tnLoopRefs, int64(n)) }
11014
+ func (tnLoopGroup) Done() { TnLoopUnref() }
11015
+ func (tnLoopGroup) Wait() { TnRunLoop() }
11016
+
11017
+ // queueMicrotask: run after the current synchronous code (end of main or of a loop task)
11018
+ var tnMicrotasks []func()
11019
+ var tnMicrotasksMu sync.Mutex
11020
+
11021
+ func TnQueueMicrotask(fn func()) {
11022
+ fn = TnAsyncWrap(fn)
11023
+ tnMicrotasksMu.Lock()
11024
+ tnMicrotasks = append(tnMicrotasks, fn)
11025
+ tnMicrotasksMu.Unlock()
11026
+ }
11027
+
11028
+ func TnRunMicrotasks() {
11029
+ for {
11030
+ tnMicrotasksMu.Lock()
11031
+ if len(tnMicrotasks) == 0 {
11032
+ tnMicrotasksMu.Unlock()
11033
+ return
11034
+ }
11035
+ fn := tnMicrotasks[0]
11036
+ tnMicrotasks = tnMicrotasks[1:]
11037
+ tnMicrotasksMu.Unlock()
11038
+ TnAsyncRun(nil, fn)
9618
11039
  }
9619
11040
  }`,
9620
11041
  uri: `// encodeURIComponent: escapes everything except A-Z a-z 0-9 - _ . ! ~ * ' ( )
@@ -9851,11 +11272,76 @@ func TnDecorateClass(result interface{}) {
9851
11272
  promise: `// Promises are channels; a rejected promise is a closed channel with a reason
9852
11273
  var tnRejections sync.Map
9853
11274
 
11275
+ // A throw inside a Promise executor rejects the promise
11276
+ func TnRejectExecutor[T any](ch chan T) {
11277
+ if r := recover(); r != nil {
11278
+ if _, rejected := tnRejections.Load(ch); !rejected && len(ch) == 0 {
11279
+ TnReject(ch, r)
11280
+ }
11281
+ }
11282
+ }
11283
+
11284
+ func TnResolveZero[T any](ch chan T) {
11285
+ var zero T
11286
+ select {
11287
+ case ch <- zero:
11288
+ default:
11289
+ }
11290
+ }
11291
+
11292
+ // resolve / reject of a Promise executor used as values
11293
+ func TnResolver[T any](ch chan T) func(...interface{}) {
11294
+ return func(args ...interface{}) {
11295
+ var v T
11296
+ if len(args) > 0 {
11297
+ if x, ok := args[0].(T); ok {
11298
+ v = x
11299
+ }
11300
+ }
11301
+ select {
11302
+ case ch <- v:
11303
+ default:
11304
+ }
11305
+ }
11306
+ }
11307
+
11308
+ func TnRejecter[T any](ch chan T) func(...interface{}) {
11309
+ return func(args ...interface{}) {
11310
+ var reason interface{}
11311
+ if len(args) > 0 {
11312
+ reason = args[0]
11313
+ }
11314
+ if _, rejected := tnRejections.Load(ch); rejected || len(ch) > 0 {
11315
+ return
11316
+ }
11317
+ TnReject(ch, reason)
11318
+ }
11319
+ }
11320
+
9854
11321
  func TnReject[T any](ch chan T, reason interface{}) {
9855
11322
  tnRejections.Store(ch, reason)
9856
11323
  close(ch)
9857
11324
  }
9858
11325
 
11326
+ // A detached call (\`main();\`): the process waits for it; a rejection is fatal
11327
+ // unless process.on('unhandledRejection') takes it
11328
+ var tnUnhandledHook func(reason interface{}) bool
11329
+
11330
+ func TnDetach[T any](ch chan T) {
11331
+ go func() {
11332
+ defer __tnWaitGroup.Done()
11333
+ _, reason, rejected := tnSettle(ch)
11334
+ if rejected {
11335
+ TnLoopCall(func() {
11336
+ if tnUnhandledHook != nil && tnUnhandledHook(reason) {
11337
+ return
11338
+ }
11339
+ panic(reason)
11340
+ })
11341
+ }
11342
+ }()
11343
+ }
11344
+
9859
11345
  // Deferred in async functions: a throw rejects the function's promise
9860
11346
  func TnRejectOnPanic[T any](ch chan T) {
9861
11347
  if r := recover(); r != nil {
@@ -9863,9 +11349,7 @@ func TnRejectOnPanic[T any](ch chan T) {
9863
11349
  }
9864
11350
  }
9865
11351
 
9866
- // Waits for a promise: its value, or its rejection reason
9867
- func tnSettle[T any](ch chan T) (T, interface{}, bool) {
9868
- v, ok := <-ch
11352
+ func tnSettled[T any](ch chan T, v T, ok bool) (T, interface{}, bool) {
9869
11353
  if !ok {
9870
11354
  if reason, rejected := tnRejections.Load(ch); rejected {
9871
11355
  return v, reason, true
@@ -9874,9 +11358,16 @@ func tnSettle[T any](ch chan T) (T, interface{}, bool) {
9874
11358
  return v, nil, false
9875
11359
  }
9876
11360
 
9877
- // await: the value, or the rejection rethrown
11361
+ // Waits for a promise (helper goroutines, without the baton): its value, or its rejection reason
11362
+ func tnSettle[T any](ch chan T) (T, interface{}, bool) {
11363
+ v, ok := <-ch
11364
+ return tnSettled(ch, v, ok)
11365
+ }
11366
+
11367
+ // await (baton holder): the value, or the rejection rethrown; loop tasks run meanwhile
9878
11368
  func TnAwait[T any](ch chan T) T {
9879
- v, reason, rejected := tnSettle(ch)
11369
+ received, ok := TnLoopReceive(ch)
11370
+ v, reason, rejected := tnSettled(ch, received, ok)
9880
11371
  if rejected {
9881
11372
  panic(reason)
9882
11373
  }
@@ -9891,11 +11382,12 @@ func TnPromiseReject[T any](reason interface{}) chan T {
9891
11382
 
9892
11383
  func TnPromiseCatch[T any, E any](p chan T, onRejected func(E)) chan T {
9893
11384
  out := make(chan T, 1)
11385
+ ctx := TnAsyncSnapshot()
9894
11386
  go func() {
9895
11387
  v, reason, rejected := tnSettle(p)
9896
11388
  if rejected {
9897
11389
  e, _ := reason.(E)
9898
- onRejected(e)
11390
+ TnLoopCall(func() { TnAsyncRun(ctx, func() { onRejected(e) }) })
9899
11391
  }
9900
11392
  out <- v
9901
11393
  close(out)
@@ -9905,11 +11397,12 @@ func TnPromiseCatch[T any, E any](p chan T, onRejected func(E)) chan T {
9905
11397
 
9906
11398
  func TnPromiseCatchValue[T any, E any](p chan T, onRejected func(E) T) chan T {
9907
11399
  out := make(chan T, 1)
11400
+ ctx := TnAsyncSnapshot()
9908
11401
  go func() {
9909
11402
  v, reason, rejected := tnSettle(p)
9910
11403
  if rejected {
9911
11404
  e, _ := reason.(E)
9912
- v = onRejected(e)
11405
+ TnLoopCall(func() { TnAsyncRun(ctx, func() { v = onRejected(e) }) })
9913
11406
  }
9914
11407
  out <- v
9915
11408
  close(out)
@@ -9919,9 +11412,10 @@ func TnPromiseCatchValue[T any, E any](p chan T, onRejected func(E) T) chan T {
9919
11412
 
9920
11413
  func TnPromiseFinally[T any](p chan T, onFinally func()) chan T {
9921
11414
  out := make(chan T, 1)
11415
+ onFinally = TnAsyncWrap(onFinally)
9922
11416
  go func() {
9923
11417
  v, reason, rejected := tnSettle(p)
9924
- onFinally()
11418
+ TnLoopCall(onFinally)
9925
11419
  if rejected {
9926
11420
  TnReject(out, reason)
9927
11421
  return
@@ -10022,170 +11516,587 @@ func TnPromiseAll[T any](chs []chan T) chan []T {
10022
11516
  close(out)
10023
11517
  }()
10024
11518
  return out
10025
- }`,
10026
- exec: `type tnExecResult struct {
10027
- stdout string
10028
- stderr string
10029
- status float64
10030
- }
10031
-
10032
- func TnExec(name string, args ...string) tnExecResult {
10033
- cmd := exec.Command(name, args...)
10034
- var stdout, stderr bytes.Buffer
10035
- cmd.Stdout = &stdout
10036
- cmd.Stderr = &stderr
10037
- err := cmd.Run()
10038
- status := 0.0
10039
- if err != nil {
10040
- if exitErr, ok := err.(*exec.ExitError); ok {
10041
- status = float64(exitErr.ExitCode())
10042
- } else {
10043
- panic(err)
10044
- }
10045
- }
10046
- return tnExecResult{stdout: stdout.String(), stderr: stderr.String(), status: status}
10047
- }
10048
-
10049
- func TnExecShell(command string) tnExecResult {
10050
- if runtime.GOOS == "windows" {
10051
- return TnExec("cmd", "/C", command)
10052
- }
10053
- return TnExec("sh", "-c", command)
10054
- }`,
10055
- execSync: `func TnExecShellSync(command string) string {
10056
- result := TnExecShell(command)
10057
- if result.status != 0 {
10058
- panic(result.stderr)
10059
- }
10060
- return result.stdout
10061
11519
  }`,
10062
11520
  getenv: `func TnGetenv(name string) string {
10063
11521
  return os.Getenv(name)
10064
11522
  }`,
10065
- execInput: `func TnExecInput(name string, input string, args ...string) tnExecResult {
10066
- cmd := exec.Command(name, args...)
10067
- cmd.Stdin = strings.NewReader(input)
10068
- var stdout, stderr bytes.Buffer
10069
- cmd.Stdout = &stdout
10070
- cmd.Stderr = &stderr
10071
- err := cmd.Run()
10072
- status := 0.0
10073
- if err != nil {
10074
- if exitErr, ok := err.(*exec.ExitError); ok {
10075
- status = float64(exitErr.ExitCode())
10076
- } else {
10077
- panic(err)
10078
- }
10079
- }
10080
- return tnExecResult{stdout: stdout.String(), stderr: stderr.String(), status: status}
10081
- }`,
10082
- runInherit: `func TnRunInherit(name string, args ...string) tnExecResult {
10083
- cmd := exec.Command(name, args...)
10084
- cmd.Stdin = os.Stdin
10085
- cmd.Stdout = os.Stdout
10086
- cmd.Stderr = os.Stderr
10087
- err := cmd.Run()
10088
- if err != nil {
10089
- if exitErr, ok := err.(*exec.ExitError); ok {
10090
- return tnExecResult{status: float64(exitErr.ExitCode())}
10091
- }
10092
- panic(err)
10093
- }
10094
- return tnExecResult{}
10095
- }`,
10096
- question: `var tnStdinReader = bufio.NewReader(os.Stdin)
10097
-
10098
- func TnQuestion(prompt string) string {
10099
- if prompt != "" {
10100
- fmt.Print(prompt)
10101
- }
10102
- // Reuse one buffered reader: a fresh reader per call would discard
10103
- // buffered stdin and hit EOF on the second question.
10104
- line, err := tnStdinReader.ReadString('\\n')
10105
- if err != nil && line == "" {
10106
- panic(err)
10107
- }
10108
- return strings.TrimRight(line, "\\r\\n")
10109
- }`
10110
11523
  };
10111
11524
  // Returns the Go source for all helpers used in this transpilation, or '' if none.
10112
11525
  // Emitted only into the main output file: every generated file shares `package main`,
10113
11526
  // so helpers are visible across files and must not be duplicated.
10114
11527
  function emitGoHelpers() {
10115
- return [...usedHelpers]
11528
+ const sources = [...usedHelpers]
10116
11529
  .sort()
10117
- .map((id) => goHelpers[id])
10118
- .filter(Boolean)
10119
- .join('\n\n');
10120
- }
10121
- // Result types of the mapped Node.js stdlib functions ('' = no result)
10122
- const NODE_FUNCTION_TYPES = {
10123
- path: {
10124
- join: 'string',
10125
- resolve: 'string',
10126
- dirname: 'string',
10127
- basename: 'string',
10128
- extname: 'string',
10129
- relative: 'string',
10130
- normalize: 'string'
10131
- },
10132
- fs: {
10133
- readFileSync: 'string',
10134
- existsSync: 'bool',
10135
- readdirSync: '[]string',
10136
- writeFileSync: '',
10137
- appendFileSync: '',
10138
- mkdirSync: '',
10139
- copyFileSync: '',
10140
- rmSync: '',
10141
- unlinkSync: ''
10142
- },
10143
- os: { platform: 'string', homedir: 'string', tmpdir: 'string' },
10144
- url: { fileURLToPath: 'string', pathToFileURL: 'string' },
10145
- child_process: { execSync: 'string' },
10146
- readline: { question: 'string' }
10147
- };
10148
- // Result types of imported Node.js functions by their local callee text
10149
- // (`join`, `path.join`)
10150
- const nodeCallResultTypes = new Map();
10151
- // Mapping from Node.js stdlib module names to Go setup functions.
10152
- // Each entry adds the required Go imports and registers call handlers for the local identifier.
11530
+ .map((id) => goHelpers[id] ?? nodeRegistry.goHelpers[id])
11531
+ .filter(Boolean);
11532
+ if (usedHelpers.has('nodeUtil')) {
11533
+ const names = [...classNames].sort().map((name) => `${toGoStringLiteral(getSafeName(name))}: true`);
11534
+ sources.push(`// Classes util.inspect prints as \`Name { … }\`\nvar tnInspectClassNames = map[string]bool{${names.join(', ')}}`);
11535
+ }
11536
+ return sources.join('\n\n');
11537
+ }
11538
+ /// Local names bound by Node.js imports → registry keys ('join' → 'path.join',
11539
+ // 'fs' → 'fs', 'fsp' → 'fs/promises', 'EventEmitter' → 'events.EventEmitter')
11540
+ const nodeLocalNames = new Map();
11541
+ // The registry name of a Node module specifier ('node:fs', 'fs', 'node:sys' → 'util'),
11542
+ // or '' when it is not a (supported) builtin
11543
+ function nodeModuleName(spec) {
11544
+ const prefixed = spec.startsWith('node:');
11545
+ let name = prefixed ? spec.slice(5) : spec;
11546
+ if (nodeRegistry.aliases[name])
11547
+ name = nodeRegistry.aliases[name];
11548
+ if (nodeRegistry.modules[name])
11549
+ return name;
11550
+ if (prefixed)
11551
+ console.warn(`[TypeNative] Unsupported Node.js module: ${spec}`);
11552
+ return '';
11553
+ }
11554
+ // Binds the import's local names to registry keys
10153
11555
  function setupNodeModuleImport(node, nodeModule) {
10154
- const mapping = nodeModuleMappings[nodeModule];
10155
- if (!mapping)
10156
- return;
10157
11556
  const clause = node.importClause;
10158
11557
  if (!clause)
10159
11558
  return;
10160
- if (clause.namedBindings && isNamedImports(clause.namedBindings)) {
10161
- // Named imports: `import { join, dirname } from 'node:path'`
10162
- // Map each local name directly to its Go qualified function via importAliases,
10163
- // so bare calls like `join(...)` resolve to `filepath.Join(...)`.
10164
- for (const el of clause.namedBindings.elements) {
10165
- if (el.isTypeOnly)
10166
- continue;
10167
- const localName = el.name.text;
10168
- const importedName = el.propertyName?.text ?? localName;
10169
- const resultType = NODE_FUNCTION_TYPES[nodeModule]?.[importedName];
10170
- if (resultType !== undefined)
10171
- nodeCallResultTypes.set(localName, resultType);
10172
- const fn = mapping.functions[importedName];
10173
- if (fn) {
10174
- // Register a call handler keyed on the local name
10175
- callHandlers[localName] = (_caller, args) => fn(args);
11559
+ const defaultKey = nodeRegistry.namespaces[`${nodeModule}.default`] || nodeModule;
11560
+ if (clause.name)
11561
+ nodeLocalNames.set(clause.name.text, defaultKey);
11562
+ const bindings = clause.namedBindings;
11563
+ if (!bindings)
11564
+ return;
11565
+ if (isNamespaceImport(bindings)) {
11566
+ nodeLocalNames.set(bindings.name.text, nodeModule);
11567
+ return;
11568
+ }
11569
+ for (const el of bindings.elements ?? []) {
11570
+ const importedName = el.propertyName?.text ?? el.name.text;
11571
+ if (importedName === 'default') {
11572
+ nodeLocalNames.set(el.name.text, defaultKey);
11573
+ continue;
11574
+ }
11575
+ const key = `${nodeModule}.${importedName}`;
11576
+ nodeLocalNames.set(el.name.text, nodeRegistry.namespaces[key] || key);
11577
+ }
11578
+ }
11579
+ // A Node global (Buffer, URL, process…) not shadowed by a user declaration
11580
+ function nodeGlobalKey(name) {
11581
+ const key = nodeRegistry.globals[name];
11582
+ if (!key || typeof key !== 'string')
11583
+ return '';
11584
+ if (variableGoTypes.has(name) || classNames.has(name) || declaredFunctions.has(name) || importAliases.has(name))
11585
+ return '';
11586
+ return key;
11587
+ }
11588
+ // Registry key of a Node binding expression (`join`, `fs.promises.readFile`,
11589
+ // `Buffer.from`, `(childProcess as any).spawnSync`), or '' when it is not one
11590
+ function resolveNodeKey(expr) {
11591
+ if (!expr)
11592
+ return '';
11593
+ if (isIdentifier(expr)) {
11594
+ if (nodeLocalNames.has(expr.text))
11595
+ return nodeLocalNames.get(expr.text) ?? '';
11596
+ return nodeGlobalKey(expr.text);
11597
+ }
11598
+ if (isParenthesizedExpression(expr) || isAsExpression(expr) || isNonNullExpression(expr)) {
11599
+ return resolveNodeKey(expr.expression);
11600
+ }
11601
+ // util.promisify(fs.readFile) → fs/promises.readFile
11602
+ if (isCallExpression(expr) && resolveNodeKey(expr.expression) === 'util.promisify') {
11603
+ return nodePromisifiedKey((expr.arguments ?? [])[0]);
11604
+ }
11605
+ if (isPropertyAccessExpression(expr) && !expr.questionDotToken) {
11606
+ const base = resolveNodeKey(expr.expression);
11607
+ if (!base)
11608
+ return '';
11609
+ const key = `${base}.${expr.name.text}`;
11610
+ return nodeRegistry.namespaces[key] || key;
11611
+ }
11612
+ return '';
11613
+ }
11614
+ // The promise variant of a Node function, '' when it has none
11615
+ function nodePromisifiedKey(fnExpr) {
11616
+ let key = resolveNodeKey(fnExpr);
11617
+ if (!key && isIdentifier(fnExpr) && (fnExpr.text === 'setTimeout' || fnExpr.text === 'setImmediate')) {
11618
+ key = `timers.${fnExpr.text}`;
11619
+ }
11620
+ if (!key)
11621
+ return '';
11622
+ if (nodeRegistry.functions[`${key}.__promisify__`])
11623
+ return `${key}.__promisify__`;
11624
+ const dot = key.lastIndexOf('.');
11625
+ const mod = key.slice(0, dot);
11626
+ const name = key.slice(dot + 1);
11627
+ const promisesKey = `${mod}/promises.${name}`;
11628
+ if (nodeRegistry.functions[promisesKey])
11629
+ return promisesKey;
11630
+ return '';
11631
+ }
11632
+ // The Node class of a Go type ('*TnEventEmitter', '[]byte'), '' when none
11633
+ function nodeClassKeyOfType(goType) {
11634
+ if (!goType)
11635
+ return '';
11636
+ return nodeRegistry.classByGoType[goType] ?? '';
11637
+ }
11638
+ // A user class extending a Node class (class X extends Transform): the Node
11639
+ // class key, for methods the user classes in the chain do not declare
11640
+ function nodeAncestorClassKey(goType, methodName) {
11641
+ if (!goType || !goType.startsWith('*'))
11642
+ return '';
11643
+ let name = goType.slice(1).replace(/\[.*\]$/, '');
11644
+ for (let depth = 0; depth < 20 && classParentNames.has(name); depth++) {
11645
+ if (declaredClassHasMethod(name, methodName))
11646
+ return '';
11647
+ const parent = classParentNames.get(name) ?? '';
11648
+ if (nodeParentClassKeys.has(parent))
11649
+ return nodeParentClassKeys.get(parent) ?? '';
11650
+ name = parent;
11651
+ }
11652
+ return '';
11653
+ }
11654
+ function declaredClassHasMethod(className, methodName) {
11655
+ const decl = declaredClasses.get(className);
11656
+ for (const member of decl?.members ?? []) {
11657
+ if (member.name && isIdentifier(member.name) && member.name.text === methodName)
11658
+ return true;
11659
+ }
11660
+ return false;
11661
+ }
11662
+ // The Node class key a type name refers to (imported or global), '' when none
11663
+ function nodeClassKeyOfName(name) {
11664
+ const key = nodeLocalNames.has(name) ? (nodeLocalNames.get(name) ?? '') : nodeGlobalKey(name);
11665
+ return key && nodeRegistry.classes[key] ? key : '';
11666
+ }
11667
+ // new Error(message, { cause }): the options set error.cause
11668
+ function withErrorOptions(errorExpr, options) {
11669
+ if (!options)
11670
+ return errorExpr;
11671
+ useHelper('dynamic');
11672
+ return `TnErrorWithOptions(${errorExpr}, ${visit(options)})`;
11673
+ }
11674
+ // The Node class key of a (qualified) type reference: `Stats`, `fs.Stats`, `NodeJS.ErrnoException`
11675
+ function nodeClassKeyOfTypeName(typeName) {
11676
+ if (isIdentifier(typeName))
11677
+ return nodeClassKeyOfName(typeName.text);
11678
+ if (typeName?.kind === 'QualifiedName') {
11679
+ const base = nodeQualifiedTypeBase(typeName.left);
11680
+ if (!base)
11681
+ return '';
11682
+ const key = `${base}.${typeName.right.text}`;
11683
+ return nodeRegistry.classes[key] ? key : '';
11684
+ }
11685
+ return '';
11686
+ }
11687
+ function nodeQualifiedTypeBase(left) {
11688
+ if (isIdentifier(left))
11689
+ return nodeLocalNames.has(left.text) ? (nodeLocalNames.get(left.text) ?? '') : nodeGlobalKey(left.text);
11690
+ if (left?.kind === 'QualifiedName') {
11691
+ const base = nodeQualifiedTypeBase(left.left);
11692
+ return base ? `${base}.${left.right.text}` : '';
11693
+ }
11694
+ return '';
11695
+ }
11696
+ // Option-object methods of Node constructors: their parameters get Node's types
11697
+ function applyNodeOptionTypes(key, options) {
11698
+ const typer = nodeRegistry.optionTypers[key];
11699
+ if (!typer || !isObjectLiteralExpression(options))
11700
+ return;
11701
+ const types = typer(options);
11702
+ for (const prop of options.properties ?? []) {
11703
+ if (!prop.name || !isIdentifier(prop.name))
11704
+ continue;
11705
+ const name = prop.name.text;
11706
+ if (!(name in types))
11707
+ continue;
11708
+ if (prop.kind === 'MethodDeclaration')
11709
+ prop.tnParamTypes = types[name];
11710
+ else if (isPropertyAssignment(prop) && (isArrowFunction(prop.initializer) || isFunctionExpression(prop.initializer))) {
11711
+ prop.initializer.tnParamTypes = types[name];
11712
+ }
11713
+ }
11714
+ }
11715
+ // Applies the registry's callback parameter types to the callback argument
11716
+ function applyNodeParamTypes(key, args) {
11717
+ const typer = nodeRegistry.paramTypers[key];
11718
+ if (!typer)
11719
+ return;
11720
+ for (let i = args.length - 1; i >= 0; i--) {
11721
+ if (isArrowFunction(args[i]) || isFunctionExpression(args[i])) {
11722
+ args[i].tnParamTypes = typer(args);
11723
+ return;
11724
+ }
11725
+ }
11726
+ }
11727
+ function makeNodeCall(node, recv) {
11728
+ const nodes = node.arguments ?? [];
11729
+ const hasSpread = nodes.some((a) => isSpreadElement(a));
11730
+ const args = hasSpread ? visitSpreadCallArguments(node) : nodes.map((a) => visit(a));
11731
+ const types = nodes.map((a) => inferExpressionType(a) ?? '');
11732
+ return { args, nodes, types, recv };
11733
+ }
11734
+ // Calls of Node APIs: imported functions, statics (Buffer.from) and methods of
11735
+ // Node class instances
11736
+ function visitNodeCall(node) {
11737
+ const callee = node.expression;
11738
+ const key = resolveNodeKey(callee);
11739
+ if (key) {
11740
+ const emit = nodeRegistry.functions[key];
11741
+ if (emit) {
11742
+ applyNodeParamTypes(key, node.arguments ?? []);
11743
+ return emit(makeNodeCall(node, ''));
11744
+ }
11745
+ // node:console re-exports the global console
11746
+ if (key.startsWith('console.') && callHandlers[key]) {
11747
+ const call = makeNodeCall(node, '');
11748
+ currentCallArgTypes = call.types.map((t) => t || undefined);
11749
+ const consoleCall = callHandlers[key](key, call.args, '');
11750
+ return consoleCall;
11751
+ }
11752
+ return undefined;
11753
+ }
11754
+ if (!isPropertyAccessExpression(callee) || callee.questionDotToken)
11755
+ return undefined;
11756
+ const receiverType = inferExpressionType(callee.expression);
11757
+ const classKey = nodeClassKeyOfType(receiverType) || nodeAncestorClassKey(receiverType, callee.name.text);
11758
+ if (!classKey)
11759
+ return undefined;
11760
+ const cls = nodeRegistry.classes[classKey];
11761
+ const methodKey = `${cls.key}#${callee.name.text}`;
11762
+ const emit = nodeRegistry.methods[methodKey];
11763
+ if (!emit && cls.category !== 'class')
11764
+ return undefined;
11765
+ applyNodeParamTypes(methodKey, node.arguments ?? []);
11766
+ const call = makeNodeCall(node, visit(callee.expression));
11767
+ if (emit)
11768
+ return emit(call);
11769
+ return `${call.recv}.${callee.name.text}(${call.args.join(', ')})`;
11770
+ }
11771
+ // Whether a registry key names a module or namespace object (path, fs/promises, process.stdout)
11772
+ function isNodeNamespaceKey(key) {
11773
+ return !!nodeRegistry.modules[key] || !!nodeRegistry.objects[key];
11774
+ }
11775
+ // `const win = path.win32` / `const { join, sep } = path` bind local names to
11776
+ // registry keys instead of declaring Go variables
11777
+ function visitNodeAliasDeclaration(node) {
11778
+ if (!node.initializer)
11779
+ return undefined;
11780
+ const key = resolveNodeKey(node.initializer);
11781
+ // const readFileAsync = promisify(fs.readFile): an alias of the promise variant
11782
+ if (key && isIdentifier(node.name) && isCallExpression(unwrapParentheses(node.initializer)) && nodeRegistry.functions[key]) {
11783
+ nodeLocalNames.set(node.name.text, key);
11784
+ return '';
11785
+ }
11786
+ if (!key || !isNodeNamespaceKey(key))
11787
+ return undefined;
11788
+ if (isIdentifier(node.name)) {
11789
+ nodeLocalNames.set(node.name.text, key);
11790
+ return '';
11791
+ }
11792
+ if (isObjectBindingPattern(node.name)) {
11793
+ for (const el of node.name.elements ?? []) {
11794
+ if (el.dotDotDotToken || el.initializer || !isIdentifier(el.name))
11795
+ return undefined;
11796
+ }
11797
+ for (const el of node.name.elements ?? []) {
11798
+ const member = (el.propertyName ?? el.name).text;
11799
+ const memberKey = `${key}.${member}`;
11800
+ nodeLocalNames.set(el.name.text, nodeRegistry.namespaces[memberKey] || memberKey);
11801
+ }
11802
+ return '';
11803
+ }
11804
+ return undefined;
11805
+ }
11806
+ // Reads of Node values (`path.sep`, `os.EOL`, an imported `sep`)
11807
+ function visitNodeValue(expr) {
11808
+ const key = resolveNodeKey(expr);
11809
+ if (!key)
11810
+ return undefined;
11811
+ if (key === 'process.env' && (isPropertyAccessExpression(expr.parent) || isElementAccessExpression(expr.parent)) && expr.parent.expression === expr) {
11812
+ return undefined;
11813
+ }
11814
+ const emit = nodeRegistry.values[key];
11815
+ if (!emit)
11816
+ return undefined;
11817
+ const value = emit(emptyNodeCall());
11818
+ return value;
11819
+ }
11820
+ function emptyNodeCall() {
11821
+ return { args: [], nodes: [], types: [], recv: '' };
11822
+ }
11823
+ // Writes of Node values (`process.exitCode = 1`): registered as 'key='
11824
+ function visitNodeAssignment(node) {
11825
+ if (node.operatorToken.kind !== 'EqualsToken')
11826
+ return undefined;
11827
+ // process.env.X = v / process.env[k] = v
11828
+ if ((isPropertyAccessExpression(node.left) || isElementAccessExpression(node.left)) && isProcessEnv(node.left.expression)) {
11829
+ importedPackages.add('os');
11830
+ const name = isPropertyAccessExpression(node.left) ? toGoStringLiteral(node.left.name.text) : visit(node.left.argumentExpression);
11831
+ return `os.Setenv(${name}, ${jsStringOf(visit(node.right), inferExpressionType(node.right))})`;
11832
+ }
11833
+ const key = resolveNodeKey(node.left);
11834
+ if (!key)
11835
+ return undefined;
11836
+ const emit = nodeRegistry.functions[`${key}=`];
11837
+ if (!emit)
11838
+ return undefined;
11839
+ const call = { args: [visit(node.right)], nodes: [node.right], types: [inferExpressionType(node.right) ?? ''], recv: '' };
11840
+ const assignment = emit(call);
11841
+ return assignment;
11842
+ }
11843
+ // Writes of Go struct fields convert to the field type: h.Size = 5 →
11844
+ // h.Size = int64(5); h.Size += 1 → h.Size = int64(float64(h.Size) + 1)
11845
+ function visitGoFieldAssignment(node, op) {
11846
+ if (!isPropertyAccessExpression(node.left))
11847
+ return undefined;
11848
+ const recvType = inferExpressionType(node.left.expression);
11849
+ if (!recvType)
11850
+ return undefined;
11851
+ const field = goFieldType(recvType, node.left.name.text);
11852
+ if (!field)
11853
+ return undefined;
11854
+ const target = `${visit(node.left.expression)}.${node.left.name.text}`;
11855
+ ensureGoTypePackages(field);
11856
+ if (op === '=') {
11857
+ return `${target} = ${toGoType(visit(node.right), inferExpressionType(node.right) ?? '', field)}`;
11858
+ }
11859
+ if (['+=', '-=', '*=', '/='].includes(op) && isGoNumericKind(field)) {
11860
+ const value = `${fromGoType(target, field)} ${op[0]} (${visit(node.right)})`;
11861
+ return `${target} = ${toGoType(value, 'float64', field)}`;
11862
+ }
11863
+ return undefined;
11864
+ }
11865
+ // new X(…) of a Node class
11866
+ function visitNodeNew(node) {
11867
+ const key = resolveNodeKey(node.expression);
11868
+ if (!key)
11869
+ return undefined;
11870
+ const emit = nodeRegistry.constructors[key];
11871
+ if (!emit)
11872
+ return undefined;
11873
+ applyNodeParamTypes(`${key}()`, node.arguments ?? []);
11874
+ applyNodeOptionTypes(key, (node.arguments ?? [])[0]);
11875
+ return emit(makeNodeCall(node, ''));
11876
+ }
11877
+ // The call a typer inspects: argument nodes and their Go types
11878
+ function nodeTypeCall(nodes) {
11879
+ return { args: [], nodes, types: nodes.map((a) => inferExpressionType(a) ?? ''), recv: '' };
11880
+ }
11881
+ // Go types of Node API expressions; undefined when the expression is not one
11882
+ // Property read on a Go package or Go value: consts, vars, fields.
11883
+ function visitGoProperty(node) {
11884
+ const base = node.expression;
11885
+ // Package member: strings.ToUpper (as a value), math.Pi, os.Stdout.
11886
+ const path = isIdentifier(base) ? goPathOf(base.text) : undefined;
11887
+ if (path) {
11888
+ const info = goPackage(path);
11889
+ if (!info)
11890
+ return undefined;
11891
+ const member = node.name.text;
11892
+ const qualifier = goQualifier(path);
11893
+ if (info.funcs[member])
11894
+ return `${qualifier}.${member}`;
11895
+ if (info.consts[member]) {
11896
+ const kind = info.consts[member].kind;
11897
+ // Untyped consts arrive as TS numbers; typed consts (time.Second)
11898
+ // keep their Go type so arithmetic stays well-typed.
11899
+ if (kind === 'typed')
11900
+ return `${qualifier}.${member}`;
11901
+ if (kind === 'string')
11902
+ return `${qualifier}.${member}`;
11903
+ if (kind === 'bool')
11904
+ return `${qualifier}.${member}`;
11905
+ return `float64(${qualifier}.${member})`;
11906
+ }
11907
+ if (info.vars[member]) {
11908
+ return `${qualifier}.${member}`;
11909
+ }
11910
+ if (info.types[member])
11911
+ return `${qualifier}.${member}`;
11912
+ return undefined;
11913
+ }
11914
+ // Field on a Go-typed value.
11915
+ if (isCallee(node) || isAssignmentTarget(node))
11916
+ return undefined;
11917
+ const recvType = inferExpressionType(base);
11918
+ if (!recvType)
11919
+ return undefined;
11920
+ const field = goFieldType(recvType, node.name.text);
11921
+ if (field) {
11922
+ const recv = visit(base);
11923
+ return fromGoType(`${recv}.${node.name.text}`, field);
11924
+ }
11925
+ // GoRef<T>.value dereferences the pointer cell (structs with a real
11926
+ // `value` field take the branch above). Only when the receiver is
11927
+ // declared as GoRef<...> or initialized by ref<T>(), or points to a
11928
+ // basic type (flag.String's *string has no fields to read).
11929
+ if (node.name.text === 'value' && recvType.startsWith('*') && isIdentifier(base)) {
11930
+ const base2 = recvType.slice(1);
11931
+ const isBasic = base2 === 'string' || base2 === 'float64' || base2 === 'bool' || isGoBasicKind(base2);
11932
+ if (isBasic || goRefVariables.has(base.text)) {
11933
+ return `(*${visit(base)})`;
11934
+ }
11935
+ const typeNode = variableTypeNodes.get(base.text);
11936
+ if (typeNode &&
11937
+ isTypeReferenceNode(typeNode) &&
11938
+ isIdentifier(typeNode.typeName) &&
11939
+ typeNode.typeName.text === 'GoRef') {
11940
+ return `(*${visit(base)})`;
11941
+ }
11942
+ }
11943
+ return undefined;
11944
+ }
11945
+ // Channel method call: ch.send(v) → ch <- v, ch.recv() → <-ch,
11946
+ // ch.close() → close(ch).
11947
+ function visitGoChanCall(node, recv) {
11948
+ if (!isPropertyAccessExpression(node.expression))
11949
+ return undefined;
11950
+ const method = node.expression.name.text;
11951
+ const args = node.arguments ?? [];
11952
+ if (method === 'send' && args.length === 1) {
11953
+ return `${recv} <- ${visit(args[0])}`;
11954
+ }
11955
+ if (method === 'recv' && args.length === 0) {
11956
+ return `<-${recv}`;
11957
+ }
11958
+ if (method === 'close' && args.length === 0) {
11959
+ return `close(${recv})`;
11960
+ }
11961
+ return undefined;
11962
+ }
11963
+ // Package + type of a `new pkg.T(...)` expression, null when none.
11964
+ function goNewTarget(node) {
11965
+ const ctor = node.expression;
11966
+ if (!ctor)
11967
+ return null;
11968
+ if (isIdentifier(ctor)) {
11969
+ const qualified = goMemberOf(ctor.text);
11970
+ if (!qualified)
11971
+ return null;
11972
+ const dot = qualified.indexOf('.');
11973
+ if (dot < 0)
11974
+ return null;
11975
+ const qualifier = qualified.slice(0, dot);
11976
+ const typeName = qualified.slice(dot + 1);
11977
+ for (const path of Object.keys(goStdlib)) {
11978
+ if (goQualifier(path) === qualifier && goPackage(path)?.types[typeName]) {
11979
+ return { path, typeName, qualifier };
10176
11980
  }
10177
11981
  }
11982
+ return null;
10178
11983
  }
10179
- else {
10180
- // Default import (`import path from 'node:path'`) or
10181
- // namespace import (`import * as path from 'node:path'`)
10182
- const localName = getImportLocalName(node) ?? nodeModule;
10183
- for (const [funcName, resultType] of Object.entries(NODE_FUNCTION_TYPES[nodeModule] ?? {})) {
10184
- nodeCallResultTypes.set(`${localName}.${funcName}`, resultType);
11984
+ if (isPropertyAccessExpression(ctor) && isIdentifier(ctor.expression)) {
11985
+ const path = goPathOf(ctor.expression.text);
11986
+ if (!path)
11987
+ return null;
11988
+ const typeName = ctor.name.text;
11989
+ if (!goPackage(path)?.types[typeName])
11990
+ return null;
11991
+ return { path, typeName, qualifier: goQualifier(path) };
11992
+ }
11993
+ return null;
11994
+ }
11995
+ function inferGoExpressionType(expr) {
11996
+ // ref<T>().value reads as the cell's element type.
11997
+ if (isPropertyAccessExpression(expr) &&
11998
+ expr.name.text === 'value' &&
11999
+ isIdentifier(expr.expression) &&
12000
+ goRefVariables.has(expr.expression.text)) {
12001
+ const refType = variableGoTypes.get(expr.expression.text);
12002
+ if (refType && refType.startsWith('*'))
12003
+ return refType.slice(1);
12004
+ }
12005
+ if (isCallExpression(expr) || isIdentifier(expr) || isPropertyAccessExpression(expr)) {
12006
+ return inferGoType(expr);
12007
+ }
12008
+ if (isNewExpression(expr)) {
12009
+ const target = goNewTarget(expr);
12010
+ if (target) {
12011
+ const info = goPackage(target.path);
12012
+ const type = info?.types[target.typeName];
12013
+ if (type) {
12014
+ for (const m of type.methods) {
12015
+ if (m.ptr)
12016
+ return `*${target.path}.${target.typeName}`;
12017
+ }
12018
+ return `${target.path}.${target.typeName}`;
12019
+ }
12020
+ }
12021
+ return undefined;
12022
+ }
12023
+ return undefined;
12024
+ }
12025
+ function inferNodeExpressionType(expr) {
12026
+ if (isCallExpression(expr)) {
12027
+ const callee = expr.expression;
12028
+ const key = resolveNodeKey(callee);
12029
+ const nodes = expr.arguments ?? [];
12030
+ if (key) {
12031
+ const typer = nodeRegistry.typers[key];
12032
+ if (typer)
12033
+ return typer(nodeTypeCall(nodes));
12034
+ if (key in nodeRegistry.results)
12035
+ return nodeRegistry.results[key];
12036
+ return undefined;
12037
+ }
12038
+ if (isPropertyAccessExpression(callee) && !callee.questionDotToken) {
12039
+ const receiverType = inferExpressionType(callee.expression);
12040
+ const classKey = nodeClassKeyOfType(receiverType) || nodeAncestorClassKey(receiverType, callee.name.text);
12041
+ if (!classKey)
12042
+ return undefined;
12043
+ const methodKey = `${nodeRegistry.classes[classKey].key}#${callee.name.text}`;
12044
+ const typer = nodeRegistry.typers[methodKey];
12045
+ if (typer)
12046
+ return typer(nodeTypeCall(nodes));
12047
+ if (methodKey in nodeRegistry.results)
12048
+ return nodeRegistry.results[methodKey];
12049
+ const cls = nodeRegistry.classes[classKey];
12050
+ const methodName = callee.name.text;
12051
+ if (methodName in cls.methods)
12052
+ return cls.methods[methodName];
10185
12053
  }
10186
- for (const [funcName, fn] of Object.entries(mapping.functions)) {
10187
- callHandlers[`${localName}.${funcName}`] = (_caller, args) => fn(args);
12054
+ return undefined;
12055
+ }
12056
+ if (isNewExpression(expr)) {
12057
+ const key = resolveNodeKey(expr.expression);
12058
+ if (key && nodeRegistry.constructors[key]) {
12059
+ const typer = nodeRegistry.typers[`${key}()`];
12060
+ const nodes = expr.arguments ?? [];
12061
+ if (typer)
12062
+ return typer(nodeTypeCall(nodes));
12063
+ return nodeRegistry.classes[key]?.goType;
10188
12064
  }
12065
+ return undefined;
12066
+ }
12067
+ if (isIdentifier(expr) || isPropertyAccessExpression(expr)) {
12068
+ const key = resolveNodeKey(expr);
12069
+ if (key && key in nodeRegistry.valueTypes)
12070
+ return nodeRegistry.valueTypes[key];
12071
+ return undefined;
12072
+ }
12073
+ if (isElementAccessExpression(expr) && inferExpressionType(expr.expression) === '[]byte')
12074
+ return 'float64';
12075
+ return undefined;
12076
+ }
12077
+ // Node classes are pseudo-classes: their methods, fields and accessors feed the
12078
+ // class tables, so dispatch and inference treat them like user classes
12079
+ function seedNodeClassTables() {
12080
+ for (const key of Object.keys(nodeRegistry.classes)) {
12081
+ const cls = nodeRegistry.classes[key];
12082
+ if (!cls.goType.startsWith('*'))
12083
+ continue;
12084
+ const goName = cls.goType.slice(1);
12085
+ // Classes sharing a Go type (ErrnoException / AssertionError on *TnError) merge their tables
12086
+ const methods = classMethodReturnTypes.get(goName) ?? new Map();
12087
+ for (const name of Object.keys(cls.methods))
12088
+ methods.set(name, cls.methods[name]);
12089
+ classMethodReturnTypes.set(goName, methods);
12090
+ const props = classPropertyTypes.get(goName) ?? new Map();
12091
+ for (const name of Object.keys(cls.props))
12092
+ props.set(name, cls.props[name]);
12093
+ for (const name of Object.keys(cls.getters)) {
12094
+ props.set(name, cls.getters[name]);
12095
+ classGetterMethods.add(`${goName}.${name}`);
12096
+ }
12097
+ for (const name of Object.keys(cls.setters))
12098
+ classSetterMethods.add(`${goName}.${name}`);
12099
+ classPropertyTypes.set(goName, props);
10189
12100
  }
10190
12101
  }
10191
12102
  function visitImportDeclaration(node) {
@@ -10199,7 +12110,12 @@ function visitImportDeclaration(node) {
10199
12110
  if (fileResolver && !includedLocalImports.has(key)) {
10200
12111
  includedLocalImports.add(key);
10201
12112
  const resolved = fileResolver(moduleSpec, currentFileDir);
10202
- if (resolved) {
12113
+ // The same file reached through different specifiers (./registry.js from
12114
+ // a sibling, ./node/registry.js from the parent) is included once
12115
+ const stem = (moduleSpec.split('/').pop() ?? moduleSpec).replace(/\.(js|ts|tsx|mjs)$/, '');
12116
+ const fileKey = resolved ? `file::${resolved.dir}::${stem}` : '';
12117
+ if (resolved && !includedLocalImports.has(fileKey)) {
12118
+ includedLocalImports.add(fileKey);
10203
12119
  const goFileName = specifierToGoFileName(moduleSpec);
10204
12120
  includeLocalImport(resolved.content, resolved.dir, goFileName, !!resolved.tsx);
10205
12121
  }
@@ -10220,22 +12136,35 @@ function visitImportDeclaration(node) {
10220
12136
  }
10221
12137
  return '';
10222
12138
  }
12139
+ // Node.js standard library (`node:path`, or a bare builtin name like `fs`):
12140
+ // local names resolve against the registry; type-only imports bind types
12141
+ const nodeModule = nodeModuleName(moduleSpec);
12142
+ if (nodeModule) {
12143
+ setupNodeModuleImport(node, nodeModule);
12144
+ return '';
12145
+ }
12146
+ if (moduleSpec.startsWith('node:'))
12147
+ return '';
10223
12148
  // Type-only imports contribute nothing to runtime
10224
12149
  if (node.importClause?.isTypeOnly)
10225
12150
  return '';
10226
12151
  // Go standard library: `import { Println } from 'go:fmt'` → import "fmt"
10227
12152
  if (moduleSpec.startsWith('go:')) {
10228
12153
  const goPkg = moduleSpec.slice(3);
12154
+ // go:builtin is virtual (ref/chan/GoError): no Go import, just aliases.
12155
+ if (goPkg === 'builtin') {
12156
+ registerGoBuiltinAliases(node);
12157
+ return '';
12158
+ }
12159
+ // Side-effect import (`import 'go:time/tzdata'`): blank Go import
12160
+ if (!node.importClause) {
12161
+ goSideEffectImports.add(goPkg);
12162
+ return '';
12163
+ }
10229
12164
  importedPackages.add(goPkg);
10230
12165
  registerGoPackageAliases(node, goPkg);
10231
12166
  return '';
10232
12167
  }
10233
- // Node.js standard library: `import path from 'node:path'` → mapped Go packages
10234
- if (moduleSpec.startsWith('node:')) {
10235
- const nodeModule = moduleSpec.slice(5);
10236
- setupNodeModuleImport(node, nodeModule);
10237
- return '';
10238
- }
10239
12168
  // npm package (bare specifier) → transpile to its own Go file
10240
12169
  const npmKey = `npm::${moduleSpec}`;
10241
12170
  if (fileResolver && !includedLocalImports.has(npmKey)) {
@@ -10260,14 +12189,39 @@ function visitImportDeclaration(node) {
10260
12189
  return '';
10261
12190
  }
10262
12191
  // Go packages imported under a fixed alias to avoid collisions with user
10263
- // variables (a variable named `big` would shadow the package name)
10264
- const goImportAliases = {
10265
- 'math/big': 'tnbig',
10266
- 'net/url': 'tnurl',
10267
- 'golang.org/x/text/unicode/norm': 'tnnorm'
10268
- };
12192
+ // variables (a variable named `big` would shadow the package name).
12193
+ // Table lives in src/go/overrides.ts (shared with the bridge qualifier).
12194
+ // Go bridge types are fully qualified internally (net/http.Cookie,
12195
+ // *[]io/fs.DirEntry); emitted code spells them with the import qualifier.
12196
+ // Rewrites path-qualified names outside string literals and comments, and
12197
+ // imports their packages.
12198
+ function localizeGoPaths(code) {
12199
+ if (code.indexOf('/') < 0)
12200
+ return code;
12201
+ // String/rune literals and line comments match first and pass through
12202
+ return code.replace(/"(?:[^"\\\n]|\\.)*"|`[^`]*`|'(?:[^'\\\n]|\\.)*'|\/\/[^\n]*|\b([a-z][a-z0-9_]*(?:\/[a-z0-9_]+)+)\./g, (match, path) => {
12203
+ if (!path || !hasGoPackage(path))
12204
+ return match;
12205
+ ensureGoQualifier(path);
12206
+ importedPackages.add(path);
12207
+ return `${goQualifier(path)}.`;
12208
+ });
12209
+ }
12210
+ // Whether Go code uses `name.` as a package qualifier (not the tail of a
12211
+ // longer identifier or selector: `ratio.` does not use `io`)
12212
+ function referencesQualifier(code, name) {
12213
+ const needle = `${name}.`;
12214
+ let at = code.indexOf(needle);
12215
+ while (at >= 0) {
12216
+ const prev = at > 0 ? code[at - 1] : ' ';
12217
+ if (!/[A-Za-z0-9_.]/.test(prev))
12218
+ return true;
12219
+ at = code.indexOf(needle, at + 1);
12220
+ }
12221
+ return false;
12222
+ }
10269
12223
  function goImportLine(pkg) {
10270
- const alias = goImportAliases[pkg];
12224
+ const alias = goPathAliases[pkg];
10271
12225
  return alias ? `import ${alias} "${pkg}"` : `import "${pkg}"`;
10272
12226
  }
10273
12227
  // Records the type of a variable introduced by a loop or binding
@@ -10286,9 +12240,89 @@ function registerLocalVariable(name, goType) {
10286
12240
  variableGoTypes.delete(name);
10287
12241
  }
10288
12242
  // for...of over arrays and strings (a string yields one-character strings)
12243
+ // Whether a Go type is an iter.Seq / Seq2 (range-over-func).
12244
+ function isGoIterSeq(goType) {
12245
+ const base = goType.replace(/^\*/, '');
12246
+ return base.startsWith('iter.Seq') || base.startsWith('import(\'go:iter\').Seq');
12247
+ }
12248
+ // Element type of an iter.Seq[V] (Seq2 yields its key type in for…of).
12249
+ function goIterElem(goType) {
12250
+ const start = goType.indexOf('[');
12251
+ const end = goType.lastIndexOf(']');
12252
+ if (start < 0 || end < 0)
12253
+ return 'interface{}';
12254
+ const inner = goType.slice(start + 1, end);
12255
+ let depth = 0;
12256
+ for (let i = 0; i < inner.length; i++) {
12257
+ if (inner[i] === '[' || inner[i] === '(')
12258
+ depth++;
12259
+ else if (inner[i] === ']' || inner[i] === ')')
12260
+ depth--;
12261
+ else if (inner[i] === ',' && depth === 0)
12262
+ return inner.slice(0, i).trim() || 'interface{}';
12263
+ }
12264
+ return inner.trim() || 'interface{}';
12265
+ }
12266
+ // Type args of an iter.Seq[V] / Seq2[K, V].
12267
+ function goIterElems(goType) {
12268
+ const start = goType.indexOf('[');
12269
+ const end = goType.lastIndexOf(']');
12270
+ if (start < 0 || end < 0)
12271
+ return [];
12272
+ const inner = goType.slice(start + 1, end);
12273
+ const out = [];
12274
+ let depth = 0;
12275
+ let from = 0;
12276
+ for (let i = 0; i < inner.length; i++) {
12277
+ if (inner[i] === '[' || inner[i] === '(')
12278
+ depth++;
12279
+ else if (inner[i] === ']' || inner[i] === ')')
12280
+ depth--;
12281
+ else if (inner[i] === ',' && depth === 0) {
12282
+ out.push(inner.slice(from, i).trim());
12283
+ from = i + 1;
12284
+ }
12285
+ }
12286
+ out.push(inner.slice(from).trim());
12287
+ return out;
12288
+ }
10289
12289
  function visitForOfSequence(node, iterExpr, iterType) {
10290
12290
  if (iterType === 'interface{}')
10291
12291
  iterType = '[]interface{}';
12292
+ // Go iter.Seq[V] / Seq2[K, V]: range the func directly.
12293
+ if (iterType && isGoIterSeq(iterType)) {
12294
+ const declaration = isVariableDeclarationList(node.initializer)
12295
+ ? node.initializer.declarations[0]
12296
+ : undefined;
12297
+ // Go ints arrive under a temp and re-bind as TS numbers
12298
+ let prefix = '';
12299
+ const bindIterVar = (name, goType) => {
12300
+ if (!name || isOmittedExpression(name) || !isIdentifier(name))
12301
+ return '_';
12302
+ const local = visit(name);
12303
+ if (goType !== 'float64' && isGoNumericKind(goType)) {
12304
+ const raw = getTempName('it');
12305
+ prefix += `${local} := float64(${raw}); _ = ${local};\n\t\t`;
12306
+ registerLocalVariable(name.text, 'float64');
12307
+ return raw;
12308
+ }
12309
+ registerLocalVariable(name.text, goType);
12310
+ return local;
12311
+ };
12312
+ // Seq2 destructures as [key, value]
12313
+ if (declaration && isArrayBindingPattern(declaration.name) && goIterElems(iterType).length === 2) {
12314
+ const elems = goIterElems(iterType);
12315
+ const bound = declaration.name.elements.map((el, i) => bindIterVar(isOmittedExpression(el) ? undefined : el.name, elems[i] ?? 'interface{}'));
12316
+ const key = bound[0] ?? '_';
12317
+ const value = bound[1] ?? '_';
12318
+ return `for ${key}, ${value} := range ${iterExpr}${visitLoopBody(node.statement, prefix)}`;
12319
+ }
12320
+ if (declaration && isIdentifier(declaration.name)) {
12321
+ const loopVar = bindIterVar(declaration.name, goIterElem(iterType));
12322
+ return `for ${loopVar} := range ${iterExpr}${visitLoopBody(node.statement, prefix)}`;
12323
+ }
12324
+ return `for _ = range ${iterExpr}${visitLoopBody(node.statement)}`;
12325
+ }
10292
12326
  // An iterable class instance: range its Symbol_iterator channel
10293
12327
  if (iterType?.startsWith('*')) {
10294
12328
  const iterClass = iterType.slice(1).replace(/\[.*\]$/, '');
@@ -10309,10 +12343,49 @@ function visitForOfSequence(node, iterExpr, iterType) {
10309
12343
  const declaration = isVariableDeclarationList(node.initializer)
10310
12344
  ? node.initializer.declarations[0]
10311
12345
  : undefined;
12346
+ // for await: receive through the event loop (the values may come from loop
12347
+ // tasks — stream data, events — that must run while this loop waits)
12348
+ if (node.awaitModifier) {
12349
+ useHelper('eventLoop');
12350
+ const chanVar = getTempName('chan');
12351
+ const valueVar = declaration && isIdentifier(declaration.name) ? visit(declaration.name) : getTempName('item');
12352
+ if (declaration && isIdentifier(declaration.name))
12353
+ registerLocalVariable(declaration.name.text, elemType);
12354
+ // A rejected iterator (a stream error) throws out of the loop
12355
+ useHelper('promise');
12356
+ let awaitPrefix = `${valueVar}, __ok := TnLoopReceive(${chanVar})\n\t\tif !__ok {\n\t\t\tif __reason, __rejected := tnRejections.Load(${chanVar}); __rejected {\n\t\t\t\tpanic(__reason)\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t\t_ = ${valueVar}\n\t\t`;
12357
+ if (declaration && isArrayBindingPattern(declaration.name)) {
12358
+ const memberType = elemType.startsWith('[]') ? elemType.slice(2) : undefined;
12359
+ useHelper('dynamic');
12360
+ (declaration.name.elements ?? []).forEach((el, index) => {
12361
+ if (isOmittedExpression(el))
12362
+ return;
12363
+ const name = visit(el.name);
12364
+ registerLocalVariable(name, memberType);
12365
+ awaitPrefix += `${name} := TnAt(${valueVar}, ${index})\n\t\t_ = ${name}\n\t\t`;
12366
+ });
12367
+ }
12368
+ return `${chanVar} := ${iterExpr}\n\t\tfor ${visitLoopBody(node.statement, awaitPrefix)}`;
12369
+ }
10312
12370
  if (declaration && isIdentifier(declaration.name)) {
10313
12371
  registerLocalVariable(declaration.name.text, elemType);
10314
12372
  return `for ${visit(declaration.name)} := range ${iterExpr}${visitLoopBody(node.statement)}`;
10315
12373
  }
12374
+ // for await (const [a, b] of channel) → a := item[0]; b := item[1]
12375
+ if (declaration && isArrayBindingPattern(declaration.name)) {
12376
+ const chanItem = getTempName('item');
12377
+ const memberType = elemType.startsWith('[]') ? elemType.slice(2) : undefined;
12378
+ let chanPrefix = '';
12379
+ (declaration.name.elements ?? []).forEach((el, index) => {
12380
+ if (isOmittedExpression(el))
12381
+ return;
12382
+ const name = visit(el.name);
12383
+ registerLocalVariable(name, memberType);
12384
+ chanPrefix += `${name} := TnAt(${chanItem}, ${index})\n\t\t_ = ${name}\n\t\t`;
12385
+ });
12386
+ useHelper('dynamic');
12387
+ return `for ${chanItem} := range ${iterExpr}${visitLoopBody(node.statement, chanPrefix)}`;
12388
+ }
10316
12389
  return `for _ = range ${iterExpr}${visitLoopBody(node.statement)}`;
10317
12390
  }
10318
12391
  const elementType = iterType === 'string' ? 'string' : iterType?.startsWith('[]') ? iterType.slice(2) : undefined;
@@ -10371,6 +12444,8 @@ function visitReturningTryStatement(node, fn, options) {
10371
12444
  if (node.catchClause) {
10372
12445
  const varDecl = node.catchClause.variableDeclaration;
10373
12446
  const catchVar = varDecl ? visit(varDecl.name) : '_r';
12447
+ if (varDecl && isIdentifier(varDecl.name))
12448
+ registerLocalVariable(varDecl.name.text, 'interface{}');
10374
12449
  const catchBody = blockCode(node.catchClause.block, true);
10375
12450
  deferreds.push(`defer func() {\n\t\t\tif r := recover(); r != nil {\n\t\t\t\t${catchVar} := r\n\t\t\t\t_ = ${catchVar}\n\t\t\t\t${catchBody}\t\t\t}\n\t\t\t}()`);
10376
12451
  }