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.
- package/.gitattributes +1 -0
- package/.github/workflows/ci.yml +1 -1
- package/.github/workflows/npm-publish-github-packages.yml +1 -1
- package/CHANGELOG.md +247 -0
- package/CONTRIBUTION.md +1 -1
- package/README.md +4 -4
- package/bin/cli.js +3 -1
- package/bin/go/bridge.js +919 -0
- package/bin/go/convert.js +238 -0
- package/bin/go/metadata.js +211 -0
- package/bin/go/overrides.js +68 -0
- package/bin/go/stdlib.generated.js +175 -0
- package/bin/index.js +294 -240
- package/bin/main.js +4 -1
- package/bin/node/assert.js +344 -0
- package/bin/node/async_hooks.js +273 -0
- package/bin/node/buffer.js +765 -0
- package/bin/node/child_process.js +600 -0
- package/bin/node/cluster.js +1002 -0
- package/bin/node/console.js +121 -0
- package/bin/node/core.js +111 -0
- package/bin/node/crypto.js +414 -0
- package/bin/node/crypto_keys.js +2685 -0
- package/bin/node/dgram.js +388 -0
- package/bin/node/diagnostics_channel.js +534 -0
- package/bin/node/dns.js +635 -0
- package/bin/node/events.js +743 -0
- package/bin/node/fetch.js +737 -0
- package/bin/node/fs.js +998 -0
- package/bin/node/http.js +1500 -0
- package/bin/node/http2.js +688 -0
- package/bin/node/net.js +1143 -0
- package/bin/node/os.js +257 -0
- package/bin/node/path.js +758 -0
- package/bin/node/process.js +316 -0
- package/bin/node/punycode.js +195 -0
- package/bin/node/querystring.js +143 -0
- package/bin/node/readline.js +299 -0
- package/bin/node/registry.js +161 -0
- package/bin/node/sqlite.js +1142 -0
- package/bin/node/stream.js +1221 -0
- package/bin/node/stream_web.js +2259 -0
- package/bin/node/string_decoder.js +101 -0
- package/bin/node/system_extra.js +661 -0
- package/bin/node/test.js +1068 -0
- package/bin/node/timers.js +250 -0
- package/bin/node/tls.js +719 -0
- package/bin/node/url.js +861 -0
- package/bin/node/util.js +1311 -0
- package/bin/node/util_extra.js +599 -0
- package/bin/node/worker_threads.js +745 -0
- package/bin/node/zlib.js +263 -0
- package/bin/transpiler.js +2650 -575
- package/bin/version.js +2 -0
- package/conformance.md +707 -241
- package/govendor/github.com/ncruces/go-sqlite3/LICENSE +21 -0
- package/govendor/github.com/ncruces/go-sqlite3/README.md +121 -0
- package/govendor/github.com/ncruces/go-sqlite3/backup.go +132 -0
- package/govendor/github.com/ncruces/go-sqlite3/blob.go +266 -0
- package/govendor/github.com/ncruces/go-sqlite3/config.go +397 -0
- package/govendor/github.com/ncruces/go-sqlite3/conn.go +540 -0
- package/govendor/github.com/ncruces/go-sqlite3/conn_127.go +93 -0
- package/govendor/github.com/ncruces/go-sqlite3/const.go +436 -0
- package/govendor/github.com/ncruces/go-sqlite3/context.go +222 -0
- package/govendor/github.com/ncruces/go-sqlite3/error.go +182 -0
- package/govendor/github.com/ncruces/go-sqlite3/ext.go +153 -0
- package/govendor/github.com/ncruces/go-sqlite3/func.go +309 -0
- package/govendor/github.com/ncruces/go-sqlite3/go.mod +3 -0
- package/govendor/github.com/ncruces/go-sqlite3/internal/dotlk/dotlk.go +29 -0
- package/govendor/github.com/ncruces/go-sqlite3/internal/dotlk/dotlk_other.go +13 -0
- package/govendor/github.com/ncruces/go-sqlite3/internal/dotlk/dotlk_unix.go +57 -0
- package/govendor/github.com/ncruces/go-sqlite3/internal/errutil/error.go +41 -0
- package/govendor/github.com/ncruces/go-sqlite3/internal/sqlite3_wrap/alloc.go +128 -0
- package/govendor/github.com/ncruces/go-sqlite3/internal/sqlite3_wrap/const.go +122 -0
- package/govendor/github.com/ncruces/go-sqlite3/internal/sqlite3_wrap/error.go +77 -0
- package/govendor/github.com/ncruces/go-sqlite3/internal/sqlite3_wrap/mem.go +116 -0
- package/govendor/github.com/ncruces/go-sqlite3/internal/sqlite3_wrap/mem_other.go +34 -0
- package/govendor/github.com/ncruces/go-sqlite3/internal/sqlite3_wrap/mem_unix.go +87 -0
- package/govendor/github.com/ncruces/go-sqlite3/internal/sqlite3_wrap/mem_windows.go +149 -0
- package/govendor/github.com/ncruces/go-sqlite3/internal/sqlite3_wrap/mmap_unix.go +80 -0
- package/govendor/github.com/ncruces/go-sqlite3/internal/sqlite3_wrap/mmap_windows.go +129 -0
- package/govendor/github.com/ncruces/go-sqlite3/internal/sqlite3_wrap/sys_windows.go +60 -0
- package/govendor/github.com/ncruces/go-sqlite3/internal/sqlite3_wrap/wrap.go +82 -0
- package/govendor/github.com/ncruces/go-sqlite3/internal/sqlite3_wrap/wrap_sys.go +113 -0
- package/govendor/github.com/ncruces/go-sqlite3/internal/sqlite3_wrap/wrap_vfs.go +181 -0
- package/govendor/github.com/ncruces/go-sqlite3/internal/testenv/env.go +55 -0
- package/govendor/github.com/ncruces/go-sqlite3/internal/util/json.go +54 -0
- package/govendor/github.com/ncruces/go-sqlite3/internal/util/json_v2.go +54 -0
- package/govendor/github.com/ncruces/go-sqlite3/internal/util/math.go +29 -0
- package/govendor/github.com/ncruces/go-sqlite3/internal/util/page.go +5 -0
- package/govendor/github.com/ncruces/go-sqlite3/internal/util/parse.go +142 -0
- package/govendor/github.com/ncruces/go-sqlite3/internal/util/pointer.go +3 -0
- package/govendor/github.com/ncruces/go-sqlite3/internal/util/reflect.go +10 -0
- package/govendor/github.com/ncruces/go-sqlite3/json.go +100 -0
- package/govendor/github.com/ncruces/go-sqlite3/json_v2.go +116 -0
- package/govendor/github.com/ncruces/go-sqlite3/pointer.go +13 -0
- package/govendor/github.com/ncruces/go-sqlite3/quote.go +140 -0
- package/govendor/github.com/ncruces/go-sqlite3/stmt.go +692 -0
- package/govendor/github.com/ncruces/go-sqlite3/time.go +360 -0
- package/govendor/github.com/ncruces/go-sqlite3/txn.go +374 -0
- package/govendor/github.com/ncruces/go-sqlite3/value.go +212 -0
- package/govendor/github.com/ncruces/go-sqlite3/vfs/README.md +133 -0
- package/govendor/github.com/ncruces/go-sqlite3/vfs/api.go +239 -0
- package/govendor/github.com/ncruces/go-sqlite3/vfs/cksm.go +143 -0
- package/govendor/github.com/ncruces/go-sqlite3/vfs/const.go +256 -0
- package/govendor/github.com/ncruces/go-sqlite3/vfs/file.go +260 -0
- package/govendor/github.com/ncruces/go-sqlite3/vfs/filename.go +187 -0
- package/govendor/github.com/ncruces/go-sqlite3/vfs/lock.go +128 -0
- package/govendor/github.com/ncruces/go-sqlite3/vfs/lock_other.go +23 -0
- package/govendor/github.com/ncruces/go-sqlite3/vfs/map.go +63 -0
- package/govendor/github.com/ncruces/go-sqlite3/vfs/map_other.go +13 -0
- package/govendor/github.com/ncruces/go-sqlite3/vfs/os_bsd.go +110 -0
- package/govendor/github.com/ncruces/go-sqlite3/vfs/os_darwin.go +131 -0
- package/govendor/github.com/ncruces/go-sqlite3/vfs/os_dotlk.go +140 -0
- package/govendor/github.com/ncruces/go-sqlite3/vfs/os_f2fs_linux.go +56 -0
- package/govendor/github.com/ncruces/go-sqlite3/vfs/os_linux.go +117 -0
- package/govendor/github.com/ncruces/go-sqlite3/vfs/os_ofd.go +59 -0
- package/govendor/github.com/ncruces/go-sqlite3/vfs/os_std.go +50 -0
- package/govendor/github.com/ncruces/go-sqlite3/vfs/os_std_alloc.go +19 -0
- package/govendor/github.com/ncruces/go-sqlite3/vfs/os_std_atomic.go +9 -0
- package/govendor/github.com/ncruces/go-sqlite3/vfs/os_std_rw.go +13 -0
- package/govendor/github.com/ncruces/go-sqlite3/vfs/os_std_sync.go +9 -0
- package/govendor/github.com/ncruces/go-sqlite3/vfs/os_std_temp.go +16 -0
- package/govendor/github.com/ncruces/go-sqlite3/vfs/os_unix.go +108 -0
- package/govendor/github.com/ncruces/go-sqlite3/vfs/os_windows.go +180 -0
- package/govendor/github.com/ncruces/go-sqlite3/vfs/registry.go +48 -0
- package/govendor/github.com/ncruces/go-sqlite3/vfs/shm.go +26 -0
- package/govendor/github.com/ncruces/go-sqlite3/vfs/shm_bsd.go +258 -0
- package/govendor/github.com/ncruces/go-sqlite3/vfs/shm_copy.go +90 -0
- package/govendor/github.com/ncruces/go-sqlite3/vfs/shm_dotlk.go +168 -0
- package/govendor/github.com/ncruces/go-sqlite3/vfs/shm_memlk.go +52 -0
- package/govendor/github.com/ncruces/go-sqlite3/vfs/shm_ofd.go +185 -0
- package/govendor/github.com/ncruces/go-sqlite3/vfs/shm_other.go +21 -0
- package/govendor/github.com/ncruces/go-sqlite3/vfs/shm_windows.go +124 -0
- package/govendor/github.com/ncruces/go-sqlite3/vfs/vfs.go +455 -0
- package/govendor/github.com/ncruces/go-sqlite3/vtab.go +677 -0
- package/govendor/github.com/ncruces/go-sqlite3/wrap.go +48 -0
- package/govendor/github.com/ncruces/go-sqlite3-wasm/v6/LICENSE +18 -0
- package/govendor/github.com/ncruces/go-sqlite3-wasm/v6/README.md +11 -0
- package/govendor/github.com/ncruces/go-sqlite3-wasm/v6/go.mod +3 -0
- package/govendor/github.com/ncruces/go-sqlite3-wasm/v6/libc.go +215 -0
- package/govendor/github.com/ncruces/go-sqlite3-wasm/v6/sqlite3.dat +0 -0
- package/govendor/github.com/ncruces/go-sqlite3-wasm/v6/sqlite3.go +157903 -0
- package/govendor/github.com/ncruces/go-sqlite3-wasm/v6/tools.sh +38 -0
- package/govendor/github.com/ncruces/julianday/LICENSE +21 -0
- package/govendor/github.com/ncruces/julianday/README.md +9 -0
- package/govendor/github.com/ncruces/julianday/go.mod +3 -0
- package/govendor/github.com/ncruces/julianday/julianday.go +124 -0
- package/govendor/golang.org/x/sys/LICENSE +27 -0
- package/govendor/golang.org/x/sys/PATENTS +22 -0
- package/govendor/golang.org/x/sys/go.mod +3 -0
- package/govendor/golang.org/x/sys/unix/README.md +184 -0
- package/govendor/golang.org/x/sys/unix/affinity_linux.go +189 -0
- package/govendor/golang.org/x/sys/unix/aliases.go +13 -0
- package/govendor/golang.org/x/sys/unix/asm_aix_ppc64.s +17 -0
- package/govendor/golang.org/x/sys/unix/asm_bsd_386.s +27 -0
- package/govendor/golang.org/x/sys/unix/asm_bsd_amd64.s +27 -0
- package/govendor/golang.org/x/sys/unix/asm_bsd_arm.s +27 -0
- package/govendor/golang.org/x/sys/unix/asm_bsd_arm64.s +27 -0
- package/govendor/golang.org/x/sys/unix/asm_bsd_ppc64.s +29 -0
- package/govendor/golang.org/x/sys/unix/asm_bsd_riscv64.s +27 -0
- package/govendor/golang.org/x/sys/unix/asm_linux_386.s +65 -0
- package/govendor/golang.org/x/sys/unix/asm_linux_amd64.s +57 -0
- package/govendor/golang.org/x/sys/unix/asm_linux_arm.s +56 -0
- package/govendor/golang.org/x/sys/unix/asm_linux_arm64.s +50 -0
- package/govendor/golang.org/x/sys/unix/asm_linux_loong64.s +51 -0
- package/govendor/golang.org/x/sys/unix/asm_linux_mips64x.s +54 -0
- package/govendor/golang.org/x/sys/unix/asm_linux_mipsx.s +52 -0
- package/govendor/golang.org/x/sys/unix/asm_linux_ppc64x.s +42 -0
- package/govendor/golang.org/x/sys/unix/asm_linux_riscv64.s +47 -0
- package/govendor/golang.org/x/sys/unix/asm_linux_s390x.s +54 -0
- package/govendor/golang.org/x/sys/unix/asm_openbsd_mips64.s +29 -0
- package/govendor/golang.org/x/sys/unix/asm_solaris_amd64.s +17 -0
- package/govendor/golang.org/x/sys/unix/asm_zos_s390x.s +382 -0
- package/govendor/golang.org/x/sys/unix/auxv.go +36 -0
- package/govendor/golang.org/x/sys/unix/auxv_unsupported.go +13 -0
- package/govendor/golang.org/x/sys/unix/bluetooth_linux.go +36 -0
- package/govendor/golang.org/x/sys/unix/bpxsvc_zos.go +657 -0
- package/govendor/golang.org/x/sys/unix/bpxsvc_zos.s +192 -0
- package/govendor/golang.org/x/sys/unix/cap_freebsd.go +195 -0
- package/govendor/golang.org/x/sys/unix/constants.go +13 -0
- package/govendor/golang.org/x/sys/unix/dev_aix_ppc.go +26 -0
- package/govendor/golang.org/x/sys/unix/dev_aix_ppc64.go +28 -0
- package/govendor/golang.org/x/sys/unix/dev_darwin.go +24 -0
- package/govendor/golang.org/x/sys/unix/dev_dragonfly.go +30 -0
- package/govendor/golang.org/x/sys/unix/dev_freebsd.go +30 -0
- package/govendor/golang.org/x/sys/unix/dev_linux.go +42 -0
- package/govendor/golang.org/x/sys/unix/dev_netbsd.go +29 -0
- package/govendor/golang.org/x/sys/unix/dev_openbsd.go +29 -0
- package/govendor/golang.org/x/sys/unix/dev_zos.go +28 -0
- package/govendor/golang.org/x/sys/unix/dirent.go +102 -0
- package/govendor/golang.org/x/sys/unix/endian_big.go +9 -0
- package/govendor/golang.org/x/sys/unix/endian_little.go +9 -0
- package/govendor/golang.org/x/sys/unix/env_unix.go +31 -0
- package/govendor/golang.org/x/sys/unix/fcntl.go +36 -0
- package/govendor/golang.org/x/sys/unix/fcntl_darwin.go +24 -0
- package/govendor/golang.org/x/sys/unix/fcntl_linux_32bit.go +13 -0
- package/govendor/golang.org/x/sys/unix/fdset.go +27 -0
- package/govendor/golang.org/x/sys/unix/gccgo.go +59 -0
- package/govendor/golang.org/x/sys/unix/gccgo_c.c +44 -0
- package/govendor/golang.org/x/sys/unix/gccgo_linux_amd64.go +20 -0
- package/govendor/golang.org/x/sys/unix/ifreq_linux.go +145 -0
- package/govendor/golang.org/x/sys/unix/ioctl_linux.go +341 -0
- package/govendor/golang.org/x/sys/unix/ioctl_signed.go +74 -0
- package/govendor/golang.org/x/sys/unix/ioctl_unsigned.go +74 -0
- package/govendor/golang.org/x/sys/unix/ioctl_zos.go +71 -0
- package/govendor/golang.org/x/sys/unix/mkall.sh +250 -0
- package/govendor/golang.org/x/sys/unix/mkerrors.sh +807 -0
- package/govendor/golang.org/x/sys/unix/mmap_nomremap.go +13 -0
- package/govendor/golang.org/x/sys/unix/mremap.go +57 -0
- package/govendor/golang.org/x/sys/unix/pagesize_unix.go +15 -0
- package/govendor/golang.org/x/sys/unix/pledge_openbsd.go +111 -0
- package/govendor/golang.org/x/sys/unix/ptrace_darwin.go +11 -0
- package/govendor/golang.org/x/sys/unix/ptrace_ios.go +11 -0
- package/govendor/golang.org/x/sys/unix/race.go +30 -0
- package/govendor/golang.org/x/sys/unix/race0.go +25 -0
- package/govendor/golang.org/x/sys/unix/readdirent_getdents.go +12 -0
- package/govendor/golang.org/x/sys/unix/readdirent_getdirentries.go +19 -0
- package/govendor/golang.org/x/sys/unix/readv_unix.go +103 -0
- package/govendor/golang.org/x/sys/unix/sockcmsg_dragonfly.go +16 -0
- package/govendor/golang.org/x/sys/unix/sockcmsg_linux.go +85 -0
- package/govendor/golang.org/x/sys/unix/sockcmsg_unix.go +106 -0
- package/govendor/golang.org/x/sys/unix/sockcmsg_unix_other.go +46 -0
- package/govendor/golang.org/x/sys/unix/sockcmsg_zos.go +58 -0
- package/govendor/golang.org/x/sys/unix/symaddr_zos_s390x.s +75 -0
- package/govendor/golang.org/x/sys/unix/syscall.go +86 -0
- package/govendor/golang.org/x/sys/unix/syscall_aix.go +582 -0
- package/govendor/golang.org/x/sys/unix/syscall_aix_ppc.go +52 -0
- package/govendor/golang.org/x/sys/unix/syscall_aix_ppc64.go +83 -0
- package/govendor/golang.org/x/sys/unix/syscall_bsd.go +609 -0
- package/govendor/golang.org/x/sys/unix/syscall_darwin.go +711 -0
- package/govendor/golang.org/x/sys/unix/syscall_darwin_amd64.go +50 -0
- package/govendor/golang.org/x/sys/unix/syscall_darwin_arm64.go +50 -0
- package/govendor/golang.org/x/sys/unix/syscall_darwin_libSystem.go +26 -0
- package/govendor/golang.org/x/sys/unix/syscall_dragonfly.go +359 -0
- package/govendor/golang.org/x/sys/unix/syscall_dragonfly_amd64.go +56 -0
- package/govendor/golang.org/x/sys/unix/syscall_freebsd.go +455 -0
- package/govendor/golang.org/x/sys/unix/syscall_freebsd_386.go +64 -0
- package/govendor/golang.org/x/sys/unix/syscall_freebsd_amd64.go +64 -0
- package/govendor/golang.org/x/sys/unix/syscall_freebsd_arm.go +60 -0
- package/govendor/golang.org/x/sys/unix/syscall_freebsd_arm64.go +60 -0
- package/govendor/golang.org/x/sys/unix/syscall_freebsd_riscv64.go +60 -0
- package/govendor/golang.org/x/sys/unix/syscall_hurd.go +30 -0
- package/govendor/golang.org/x/sys/unix/syscall_hurd_386.go +28 -0
- package/govendor/golang.org/x/sys/unix/syscall_illumos.go +78 -0
- package/govendor/golang.org/x/sys/unix/syscall_linux.go +2574 -0
- package/govendor/golang.org/x/sys/unix/syscall_linux_386.go +313 -0
- package/govendor/golang.org/x/sys/unix/syscall_linux_alarm.go +12 -0
- package/govendor/golang.org/x/sys/unix/syscall_linux_amd64.go +144 -0
- package/govendor/golang.org/x/sys/unix/syscall_linux_amd64_gc.go +12 -0
- package/govendor/golang.org/x/sys/unix/syscall_linux_arm.go +218 -0
- package/govendor/golang.org/x/sys/unix/syscall_linux_arm64.go +188 -0
- package/govendor/golang.org/x/sys/unix/syscall_linux_gc.go +14 -0
- package/govendor/golang.org/x/sys/unix/syscall_linux_gc_386.go +16 -0
- package/govendor/golang.org/x/sys/unix/syscall_linux_gc_arm.go +13 -0
- package/govendor/golang.org/x/sys/unix/syscall_linux_gccgo_386.go +30 -0
- package/govendor/golang.org/x/sys/unix/syscall_linux_gccgo_arm.go +20 -0
- package/govendor/golang.org/x/sys/unix/syscall_linux_loong64.go +220 -0
- package/govendor/golang.org/x/sys/unix/syscall_linux_mips64x.go +187 -0
- package/govendor/golang.org/x/sys/unix/syscall_linux_mipsx.go +173 -0
- package/govendor/golang.org/x/sys/unix/syscall_linux_ppc.go +203 -0
- package/govendor/golang.org/x/sys/unix/syscall_linux_ppc64x.go +114 -0
- package/govendor/golang.org/x/sys/unix/syscall_linux_riscv64.go +193 -0
- package/govendor/golang.org/x/sys/unix/syscall_linux_s390x.go +295 -0
- package/govendor/golang.org/x/sys/unix/syscall_linux_sparc64.go +111 -0
- package/govendor/golang.org/x/sys/unix/syscall_netbsd.go +388 -0
- package/govendor/golang.org/x/sys/unix/syscall_netbsd_386.go +37 -0
- package/govendor/golang.org/x/sys/unix/syscall_netbsd_amd64.go +37 -0
- package/govendor/golang.org/x/sys/unix/syscall_netbsd_arm.go +37 -0
- package/govendor/golang.org/x/sys/unix/syscall_netbsd_arm64.go +37 -0
- package/govendor/golang.org/x/sys/unix/syscall_openbsd.go +346 -0
- package/govendor/golang.org/x/sys/unix/syscall_openbsd_386.go +41 -0
- package/govendor/golang.org/x/sys/unix/syscall_openbsd_amd64.go +41 -0
- package/govendor/golang.org/x/sys/unix/syscall_openbsd_arm.go +41 -0
- package/govendor/golang.org/x/sys/unix/syscall_openbsd_arm64.go +41 -0
- package/govendor/golang.org/x/sys/unix/syscall_openbsd_libc.go +26 -0
- package/govendor/golang.org/x/sys/unix/syscall_openbsd_mips64.go +39 -0
- package/govendor/golang.org/x/sys/unix/syscall_openbsd_ppc64.go +41 -0
- package/govendor/golang.org/x/sys/unix/syscall_openbsd_riscv64.go +41 -0
- package/govendor/golang.org/x/sys/unix/syscall_solaris.go +1183 -0
- package/govendor/golang.org/x/sys/unix/syscall_solaris_amd64.go +27 -0
- package/govendor/golang.org/x/sys/unix/syscall_unix.go +619 -0
- package/govendor/golang.org/x/sys/unix/syscall_unix_gc.go +14 -0
- package/govendor/golang.org/x/sys/unix/syscall_unix_gc_ppc64x.go +22 -0
- package/govendor/golang.org/x/sys/unix/syscall_zos_s390x.go +3213 -0
- package/govendor/golang.org/x/sys/unix/sysvshm_linux.go +20 -0
- package/govendor/golang.org/x/sys/unix/sysvshm_unix.go +51 -0
- package/govendor/golang.org/x/sys/unix/sysvshm_unix_other.go +13 -0
- package/govendor/golang.org/x/sys/unix/timestruct.go +76 -0
- package/govendor/golang.org/x/sys/unix/unveil_openbsd.go +51 -0
- package/govendor/golang.org/x/sys/unix/vgetrandom_linux.go +13 -0
- package/govendor/golang.org/x/sys/unix/vgetrandom_unsupported.go +11 -0
- package/govendor/golang.org/x/sys/unix/xattr_bsd.go +280 -0
- package/govendor/golang.org/x/sys/unix/zerrors_aix_ppc.go +1384 -0
- package/govendor/golang.org/x/sys/unix/zerrors_aix_ppc64.go +1385 -0
- package/govendor/golang.org/x/sys/unix/zerrors_darwin_amd64.go +1922 -0
- package/govendor/golang.org/x/sys/unix/zerrors_darwin_arm64.go +1922 -0
- package/govendor/golang.org/x/sys/unix/zerrors_dragonfly_amd64.go +1737 -0
- package/govendor/golang.org/x/sys/unix/zerrors_freebsd_386.go +2042 -0
- package/govendor/golang.org/x/sys/unix/zerrors_freebsd_amd64.go +2039 -0
- package/govendor/golang.org/x/sys/unix/zerrors_freebsd_arm.go +2033 -0
- package/govendor/golang.org/x/sys/unix/zerrors_freebsd_arm64.go +2033 -0
- package/govendor/golang.org/x/sys/unix/zerrors_freebsd_riscv64.go +2147 -0
- package/govendor/golang.org/x/sys/unix/zerrors_linux.go +4209 -0
- package/govendor/golang.org/x/sys/unix/zerrors_linux_386.go +882 -0
- package/govendor/golang.org/x/sys/unix/zerrors_linux_amd64.go +882 -0
- package/govendor/golang.org/x/sys/unix/zerrors_linux_arm.go +887 -0
- package/govendor/golang.org/x/sys/unix/zerrors_linux_arm64.go +884 -0
- package/govendor/golang.org/x/sys/unix/zerrors_linux_loong64.go +874 -0
- package/govendor/golang.org/x/sys/unix/zerrors_linux_mips.go +888 -0
- package/govendor/golang.org/x/sys/unix/zerrors_linux_mips64.go +888 -0
- package/govendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go +888 -0
- package/govendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go +888 -0
- package/govendor/golang.org/x/sys/unix/zerrors_linux_ppc.go +940 -0
- package/govendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go +944 -0
- package/govendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go +944 -0
- package/govendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go +884 -0
- package/govendor/golang.org/x/sys/unix/zerrors_linux_s390x.go +943 -0
- package/govendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go +992 -0
- package/govendor/golang.org/x/sys/unix/zerrors_netbsd_386.go +1779 -0
- package/govendor/golang.org/x/sys/unix/zerrors_netbsd_amd64.go +1769 -0
- package/govendor/golang.org/x/sys/unix/zerrors_netbsd_arm.go +1758 -0
- package/govendor/golang.org/x/sys/unix/zerrors_netbsd_arm64.go +1769 -0
- package/govendor/golang.org/x/sys/unix/zerrors_openbsd_386.go +1905 -0
- package/govendor/golang.org/x/sys/unix/zerrors_openbsd_amd64.go +1905 -0
- package/govendor/golang.org/x/sys/unix/zerrors_openbsd_arm.go +1905 -0
- package/govendor/golang.org/x/sys/unix/zerrors_openbsd_arm64.go +1905 -0
- package/govendor/golang.org/x/sys/unix/zerrors_openbsd_mips64.go +1905 -0
- package/govendor/golang.org/x/sys/unix/zerrors_openbsd_ppc64.go +1904 -0
- package/govendor/golang.org/x/sys/unix/zerrors_openbsd_riscv64.go +1903 -0
- package/govendor/golang.org/x/sys/unix/zerrors_solaris_amd64.go +1556 -0
- package/govendor/golang.org/x/sys/unix/zerrors_zos_s390x.go +990 -0
- package/govendor/golang.org/x/sys/unix/zptrace_armnn_linux.go +40 -0
- package/govendor/golang.org/x/sys/unix/zptrace_linux_arm64.go +17 -0
- package/govendor/golang.org/x/sys/unix/zptrace_mipsnn_linux.go +49 -0
- package/govendor/golang.org/x/sys/unix/zptrace_mipsnnle_linux.go +49 -0
- package/govendor/golang.org/x/sys/unix/zptrace_x86_linux.go +79 -0
- package/govendor/golang.org/x/sys/unix/zsymaddr_zos_s390x.s +364 -0
- package/govendor/golang.org/x/sys/unix/zsyscall_aix_ppc.go +1461 -0
- package/govendor/golang.org/x/sys/unix/zsyscall_aix_ppc64.go +1420 -0
- package/govendor/golang.org/x/sys/unix/zsyscall_aix_ppc64_gc.go +1188 -0
- package/govendor/golang.org/x/sys/unix/zsyscall_aix_ppc64_gccgo.go +1069 -0
- package/govendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go +2728 -0
- package/govendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s +799 -0
- package/govendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go +2728 -0
- package/govendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s +799 -0
- package/govendor/golang.org/x/sys/unix/zsyscall_dragonfly_amd64.go +1666 -0
- package/govendor/golang.org/x/sys/unix/zsyscall_freebsd_386.go +1886 -0
- package/govendor/golang.org/x/sys/unix/zsyscall_freebsd_amd64.go +1886 -0
- package/govendor/golang.org/x/sys/unix/zsyscall_freebsd_arm.go +1886 -0
- package/govendor/golang.org/x/sys/unix/zsyscall_freebsd_arm64.go +1886 -0
- package/govendor/golang.org/x/sys/unix/zsyscall_freebsd_riscv64.go +1886 -0
- package/govendor/golang.org/x/sys/unix/zsyscall_illumos_amd64.go +101 -0
- package/govendor/golang.org/x/sys/unix/zsyscall_linux.go +2267 -0
- package/govendor/golang.org/x/sys/unix/zsyscall_linux_386.go +469 -0
- package/govendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go +636 -0
- package/govendor/golang.org/x/sys/unix/zsyscall_linux_arm.go +584 -0
- package/govendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go +535 -0
- package/govendor/golang.org/x/sys/unix/zsyscall_linux_loong64.go +469 -0
- package/govendor/golang.org/x/sys/unix/zsyscall_linux_mips.go +636 -0
- package/govendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go +630 -0
- package/govendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go +619 -0
- package/govendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go +636 -0
- package/govendor/golang.org/x/sys/unix/zsyscall_linux_ppc.go +641 -0
- package/govendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go +687 -0
- package/govendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go +687 -0
- package/govendor/golang.org/x/sys/unix/zsyscall_linux_riscv64.go +531 -0
- package/govendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go +478 -0
- package/govendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go +631 -0
- package/govendor/golang.org/x/sys/unix/zsyscall_netbsd_386.go +1848 -0
- package/govendor/golang.org/x/sys/unix/zsyscall_netbsd_amd64.go +1848 -0
- package/govendor/golang.org/x/sys/unix/zsyscall_netbsd_arm.go +1848 -0
- package/govendor/golang.org/x/sys/unix/zsyscall_netbsd_arm64.go +1848 -0
- package/govendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go +2407 -0
- package/govendor/golang.org/x/sys/unix/zsyscall_openbsd_386.s +719 -0
- package/govendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go +2407 -0
- package/govendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.s +719 -0
- package/govendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go +2407 -0
- package/govendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.s +719 -0
- package/govendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.go +2407 -0
- package/govendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.s +719 -0
- package/govendor/golang.org/x/sys/unix/zsyscall_openbsd_mips64.go +2407 -0
- package/govendor/golang.org/x/sys/unix/zsyscall_openbsd_mips64.s +719 -0
- package/govendor/golang.org/x/sys/unix/zsyscall_openbsd_ppc64.go +2407 -0
- package/govendor/golang.org/x/sys/unix/zsyscall_openbsd_ppc64.s +862 -0
- package/govendor/golang.org/x/sys/unix/zsyscall_openbsd_riscv64.go +2407 -0
- package/govendor/golang.org/x/sys/unix/zsyscall_openbsd_riscv64.s +719 -0
- package/govendor/golang.org/x/sys/unix/zsyscall_solaris_amd64.go +2217 -0
- package/govendor/golang.org/x/sys/unix/zsyscall_zos_s390x.go +3458 -0
- package/govendor/golang.org/x/sys/unix/zsysctl_openbsd_386.go +280 -0
- package/govendor/golang.org/x/sys/unix/zsysctl_openbsd_amd64.go +280 -0
- package/govendor/golang.org/x/sys/unix/zsysctl_openbsd_arm.go +280 -0
- package/govendor/golang.org/x/sys/unix/zsysctl_openbsd_arm64.go +280 -0
- package/govendor/golang.org/x/sys/unix/zsysctl_openbsd_mips64.go +280 -0
- package/govendor/golang.org/x/sys/unix/zsysctl_openbsd_ppc64.go +280 -0
- package/govendor/golang.org/x/sys/unix/zsysctl_openbsd_riscv64.go +281 -0
- package/govendor/golang.org/x/sys/unix/zsysnum_darwin_amd64.go +439 -0
- package/govendor/golang.org/x/sys/unix/zsysnum_darwin_arm64.go +437 -0
- package/govendor/golang.org/x/sys/unix/zsysnum_dragonfly_amd64.go +316 -0
- package/govendor/golang.org/x/sys/unix/zsysnum_freebsd_386.go +393 -0
- package/govendor/golang.org/x/sys/unix/zsysnum_freebsd_amd64.go +393 -0
- package/govendor/golang.org/x/sys/unix/zsysnum_freebsd_arm.go +393 -0
- package/govendor/golang.org/x/sys/unix/zsysnum_freebsd_arm64.go +393 -0
- package/govendor/golang.org/x/sys/unix/zsysnum_freebsd_riscv64.go +393 -0
- package/govendor/golang.org/x/sys/unix/zsysnum_linux_386.go +470 -0
- package/govendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go +394 -0
- package/govendor/golang.org/x/sys/unix/zsysnum_linux_arm.go +434 -0
- package/govendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go +337 -0
- package/govendor/golang.org/x/sys/unix/zsysnum_linux_loong64.go +334 -0
- package/govendor/golang.org/x/sys/unix/zsysnum_linux_mips.go +454 -0
- package/govendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go +384 -0
- package/govendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go +384 -0
- package/govendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go +454 -0
- package/govendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go +461 -0
- package/govendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go +433 -0
- package/govendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go +433 -0
- package/govendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go +338 -0
- package/govendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go +399 -0
- package/govendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go +413 -0
- package/govendor/golang.org/x/sys/unix/zsysnum_netbsd_386.go +274 -0
- package/govendor/golang.org/x/sys/unix/zsysnum_netbsd_amd64.go +274 -0
- package/govendor/golang.org/x/sys/unix/zsysnum_netbsd_arm.go +274 -0
- package/govendor/golang.org/x/sys/unix/zsysnum_netbsd_arm64.go +274 -0
- package/govendor/golang.org/x/sys/unix/zsysnum_openbsd_386.go +219 -0
- package/govendor/golang.org/x/sys/unix/zsysnum_openbsd_amd64.go +219 -0
- package/govendor/golang.org/x/sys/unix/zsysnum_openbsd_arm.go +219 -0
- package/govendor/golang.org/x/sys/unix/zsysnum_openbsd_arm64.go +218 -0
- package/govendor/golang.org/x/sys/unix/zsysnum_openbsd_mips64.go +221 -0
- package/govendor/golang.org/x/sys/unix/zsysnum_openbsd_ppc64.go +217 -0
- package/govendor/golang.org/x/sys/unix/zsysnum_openbsd_riscv64.go +218 -0
- package/govendor/golang.org/x/sys/unix/zsysnum_zos_s390x.go +2852 -0
- package/govendor/golang.org/x/sys/unix/ztypes_aix_ppc.go +353 -0
- package/govendor/golang.org/x/sys/unix/ztypes_aix_ppc64.go +357 -0
- package/govendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go +878 -0
- package/govendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go +878 -0
- package/govendor/golang.org/x/sys/unix/ztypes_dragonfly_amd64.go +473 -0
- package/govendor/golang.org/x/sys/unix/ztypes_freebsd_386.go +651 -0
- package/govendor/golang.org/x/sys/unix/ztypes_freebsd_amd64.go +656 -0
- package/govendor/golang.org/x/sys/unix/ztypes_freebsd_arm.go +642 -0
- package/govendor/golang.org/x/sys/unix/ztypes_freebsd_arm64.go +636 -0
- package/govendor/golang.org/x/sys/unix/ztypes_freebsd_riscv64.go +638 -0
- package/govendor/golang.org/x/sys/unix/ztypes_linux.go +6547 -0
- package/govendor/golang.org/x/sys/unix/ztypes_linux_386.go +747 -0
- package/govendor/golang.org/x/sys/unix/ztypes_linux_amd64.go +761 -0
- package/govendor/golang.org/x/sys/unix/ztypes_linux_arm.go +741 -0
- package/govendor/golang.org/x/sys/unix/ztypes_linux_arm64.go +740 -0
- package/govendor/golang.org/x/sys/unix/ztypes_linux_loong64.go +741 -0
- package/govendor/golang.org/x/sys/unix/ztypes_linux_mips.go +746 -0
- package/govendor/golang.org/x/sys/unix/ztypes_linux_mips64.go +743 -0
- package/govendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go +743 -0
- package/govendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go +746 -0
- package/govendor/golang.org/x/sys/unix/ztypes_linux_ppc.go +754 -0
- package/govendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go +749 -0
- package/govendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go +749 -0
- package/govendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go +828 -0
- package/govendor/golang.org/x/sys/unix/ztypes_linux_s390x.go +763 -0
- package/govendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go +744 -0
- package/govendor/golang.org/x/sys/unix/ztypes_netbsd_386.go +585 -0
- package/govendor/golang.org/x/sys/unix/ztypes_netbsd_amd64.go +593 -0
- package/govendor/golang.org/x/sys/unix/ztypes_netbsd_arm.go +590 -0
- package/govendor/golang.org/x/sys/unix/ztypes_netbsd_arm64.go +593 -0
- package/govendor/golang.org/x/sys/unix/ztypes_openbsd_386.go +568 -0
- package/govendor/golang.org/x/sys/unix/ztypes_openbsd_amd64.go +568 -0
- package/govendor/golang.org/x/sys/unix/ztypes_openbsd_arm.go +575 -0
- package/govendor/golang.org/x/sys/unix/ztypes_openbsd_arm64.go +568 -0
- package/govendor/golang.org/x/sys/unix/ztypes_openbsd_mips64.go +568 -0
- package/govendor/golang.org/x/sys/unix/ztypes_openbsd_ppc64.go +570 -0
- package/govendor/golang.org/x/sys/unix/ztypes_openbsd_riscv64.go +570 -0
- package/govendor/golang.org/x/sys/unix/ztypes_solaris_amd64.go +516 -0
- package/govendor/golang.org/x/sys/unix/ztypes_zos_s390x.go +552 -0
- package/govendor/golang.org/x/sys/windows/aliases.go +13 -0
- package/govendor/golang.org/x/sys/windows/dll_windows.go +380 -0
- package/govendor/golang.org/x/sys/windows/env_windows.go +57 -0
- package/govendor/golang.org/x/sys/windows/eventlog.go +20 -0
- package/govendor/golang.org/x/sys/windows/exec_windows.go +248 -0
- package/govendor/golang.org/x/sys/windows/memory_windows.go +48 -0
- package/govendor/golang.org/x/sys/windows/mkerrors.bash +70 -0
- package/govendor/golang.org/x/sys/windows/mkknownfolderids.bash +27 -0
- package/govendor/golang.org/x/sys/windows/mksyscall.go +9 -0
- package/govendor/golang.org/x/sys/windows/race.go +30 -0
- package/govendor/golang.org/x/sys/windows/race0.go +25 -0
- package/govendor/golang.org/x/sys/windows/security_windows.go +1537 -0
- package/govendor/golang.org/x/sys/windows/service.go +257 -0
- package/govendor/golang.org/x/sys/windows/setupapi_windows.go +1425 -0
- package/govendor/golang.org/x/sys/windows/str.go +22 -0
- package/govendor/golang.org/x/sys/windows/syscall.go +104 -0
- package/govendor/golang.org/x/sys/windows/syscall_windows.go +1952 -0
- package/govendor/golang.org/x/sys/windows/types_windows.go +4058 -0
- package/govendor/golang.org/x/sys/windows/types_windows_386.go +35 -0
- package/govendor/golang.org/x/sys/windows/types_windows_amd64.go +34 -0
- package/govendor/golang.org/x/sys/windows/types_windows_arm.go +35 -0
- package/govendor/golang.org/x/sys/windows/types_windows_arm64.go +34 -0
- package/govendor/golang.org/x/sys/windows/zerrors_windows.go +9468 -0
- package/govendor/golang.org/x/sys/windows/zknownfolderids_windows.go +149 -0
- package/govendor/golang.org/x/sys/windows/zsyscall_windows.go +4828 -0
- package/govendor/manifest.txt +7 -0
- package/package.json +6 -1
- package/types/typenative-go.d.ts +15159 -5
- package/types/typenative-npm.d.ts +2637 -34
- 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
|
-
|
|
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
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
if (usedHelpers.has('
|
|
846
|
-
drains.push('
|
|
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
|
-
${
|
|
929
|
+
${mainImports.sort().map((pkg) => importLine(pkg)).join('\n')}
|
|
851
930
|
|
|
852
|
-
${
|
|
931
|
+
${packageVariables.join('\n')}
|
|
853
932
|
|
|
854
933
|
func main() {
|
|
855
|
-
${
|
|
934
|
+
${body}${drainCode}
|
|
856
935
|
}
|
|
857
936
|
|
|
858
|
-
${
|
|
859
|
-
${
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
1472
|
+
const initType = inferExpressionType(node.initializer) ?? '';
|
|
1473
|
+
ensureGoTypePackages(initType);
|
|
1474
|
+
return `var ${declName} ${goLocalType(initType)}\n\t\t${declName} ${initializer}`;
|
|
1322
1475
|
}
|
|
1323
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1531
|
-
|
|
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
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
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\
|
|
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
|
-
|
|
1993
|
+
let iterExpr = isDynamicValue(iterNode)
|
|
1752
1994
|
? toGoValueOfType(iterNode, '[]interface{}')
|
|
1753
1995
|
: visit(iterNode, { inline: true });
|
|
1754
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2779
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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: '*
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
5055
|
-
|
|
5056
|
-
|
|
5057
|
-
const
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
5744
|
-
|
|
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
|
-
|
|
5748
|
-
return
|
|
6323
|
+
useHelper('console');
|
|
6324
|
+
return `TnConsoleTime(${args.slice(0, 1).join(', ')})`;
|
|
5749
6325
|
},
|
|
5750
6326
|
'console.timeEnd': (_caller, args) => {
|
|
5751
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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'
|
|
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
|
|
6996
|
+
handler = ownMethodHandler(stringMethodHandlers, methodName);
|
|
6342
6997
|
}
|
|
6343
6998
|
else if (objectType === 'array') {
|
|
6344
|
-
handler = arrayMethodHandlers
|
|
6999
|
+
handler = ownMethodHandler(arrayMethodHandlers, methodName);
|
|
6345
7000
|
}
|
|
6346
7001
|
else if (objectType === 'RegExp') {
|
|
6347
|
-
handler = regexpMethodHandlers
|
|
7002
|
+
handler = ownMethodHandler(regexpMethodHandlers, methodName);
|
|
6348
7003
|
}
|
|
6349
7004
|
else if (objectType === 'Date') {
|
|
6350
|
-
handler = dateMethodHandlers
|
|
7005
|
+
handler = ownMethodHandler(dateMethodHandlers, methodName);
|
|
6351
7006
|
}
|
|
6352
7007
|
else if (objectType === 'Map') {
|
|
6353
|
-
handler = mapMethodHandlers
|
|
7008
|
+
handler = ownMethodHandler(mapMethodHandlers, methodName);
|
|
6354
7009
|
}
|
|
6355
7010
|
else if (objectType === 'Set') {
|
|
6356
|
-
handler = setMethodHandlers
|
|
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
|
|
6362
|
-
arrayMethodHandlers
|
|
6363
|
-
regexpMethodHandlers
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
6947
|
-
|
|
6948
|
-
|
|
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\
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
7438
|
-
|
|
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
|
|
7444
|
-
|
|
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
|
-
|
|
7451
|
-
|
|
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, `${
|
|
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
|
-
|
|
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
|
-
|
|
7521
|
-
|
|
7522
|
-
|
|
7523
|
-
|
|
7524
|
-
|
|
7525
|
-
|
|
7526
|
-
|
|
7527
|
-
|
|
7528
|
-
|
|
7529
|
-
|
|
7530
|
-
|
|
7531
|
-
|
|
7532
|
-
|
|
7533
|
-
|
|
7534
|
-
|
|
7535
|
-
|
|
7536
|
-
|
|
7537
|
-
|
|
7538
|
-
|
|
7539
|
-
|
|
7540
|
-
|
|
7541
|
-
|
|
7542
|
-
|
|
7543
|
-
|
|
7544
|
-
|
|
7545
|
-
|
|
7546
|
-
|
|
7547
|
-
|
|
7548
|
-
|
|
7549
|
-
|
|
7550
|
-
|
|
7551
|
-
|
|
7552
|
-
|
|
7553
|
-
|
|
7554
|
-
|
|
7555
|
-
|
|
7556
|
-
|
|
7557
|
-
|
|
7558
|
-
|
|
7559
|
-
|
|
7560
|
-
|
|
7561
|
-
|
|
7562
|
-
|
|
7563
|
-
|
|
7564
|
-
|
|
7565
|
-
|
|
7566
|
-
|
|
7567
|
-
|
|
7568
|
-
|
|
7569
|
-
|
|
7570
|
-
|
|
7571
|
-
|
|
7572
|
-
|
|
7573
|
-
|
|
7574
|
-
|
|
7575
|
-
|
|
7576
|
-
|
|
7577
|
-
|
|
7578
|
-
|
|
7579
|
-
|
|
7580
|
-
|
|
7581
|
-
|
|
7582
|
-
|
|
7583
|
-
|
|
7584
|
-
|
|
7585
|
-
|
|
7586
|
-
|
|
7587
|
-
|
|
7588
|
-
|
|
7589
|
-
|
|
7590
|
-
|
|
7591
|
-
|
|
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
|
-
|
|
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: [
|
|
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,
|
|
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
|
-
|
|
8108
|
-
|
|
8109
|
-
|
|
8110
|
-
|
|
8111
|
-
|
|
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
|
-
|
|
8120
|
-
|
|
8121
|
-
|
|
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
|
-
|
|
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
|
-
|
|
9531
|
-
|
|
9532
|
-
|
|
9533
|
-
|
|
9534
|
-
|
|
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: `//
|
|
9546
|
-
var __tnTimers
|
|
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
|
|
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
|
-
|
|
9551
|
-
|
|
9552
|
-
|
|
9553
|
-
|
|
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
|
-
|
|
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
|
|
9560
|
-
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
|
|
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 <-
|
|
10739
|
+
case <-stop:
|
|
9572
10740
|
return
|
|
9573
10741
|
case <-ticker.C:
|
|
9574
|
-
|
|
9575
|
-
|
|
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
|
-
|
|
10757
|
+
if t.refd {
|
|
10758
|
+
t.refd = false
|
|
10759
|
+
__tnTimers.Done()
|
|
10760
|
+
}
|
|
9587
10761
|
})
|
|
9588
10762
|
}
|
|
9589
10763
|
}
|
|
9590
10764
|
|
|
9591
|
-
|
|
9592
|
-
|
|
9593
|
-
|
|
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
|
|
9596
|
-
|
|
9597
|
-
|
|
9598
|
-
|
|
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
|
|
9602
|
-
|
|
9603
|
-
|
|
9604
|
-
|
|
9605
|
-
|
|
9606
|
-
|
|
9607
|
-
|
|
9608
|
-
|
|
9609
|
-
|
|
9610
|
-
|
|
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
|
-
|
|
9616
|
-
|
|
9617
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
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
|
-
|
|
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
|
-
|
|
11528
|
+
const sources = [...usedHelpers]
|
|
10116
11529
|
.sort()
|
|
10117
|
-
.map((id) => goHelpers[id])
|
|
10118
|
-
.filter(Boolean)
|
|
10119
|
-
|
|
10120
|
-
}
|
|
10121
|
-
|
|
10122
|
-
|
|
10123
|
-
|
|
10124
|
-
|
|
10125
|
-
|
|
10126
|
-
|
|
10127
|
-
|
|
10128
|
-
|
|
10129
|
-
|
|
10130
|
-
|
|
10131
|
-
|
|
10132
|
-
|
|
10133
|
-
|
|
10134
|
-
|
|
10135
|
-
|
|
10136
|
-
|
|
10137
|
-
|
|
10138
|
-
|
|
10139
|
-
|
|
10140
|
-
|
|
10141
|
-
|
|
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
|
-
|
|
10161
|
-
|
|
10162
|
-
|
|
10163
|
-
|
|
10164
|
-
|
|
10165
|
-
|
|
10166
|
-
|
|
10167
|
-
|
|
10168
|
-
|
|
10169
|
-
|
|
10170
|
-
|
|
10171
|
-
|
|
10172
|
-
|
|
10173
|
-
|
|
10174
|
-
|
|
10175
|
-
|
|
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
|
-
|
|
10180
|
-
|
|
10181
|
-
|
|
10182
|
-
|
|
10183
|
-
|
|
10184
|
-
|
|
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
|
-
|
|
10187
|
-
|
|
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
|
-
|
|
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
|
-
|
|
10265
|
-
|
|
10266
|
-
|
|
10267
|
-
|
|
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 =
|
|
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
|
}
|