Deduplicate jsc bindings, runtime api, test matchers, and shell builtins
Dedup pass over the jsc bindings, runtime APIs, bun:test matchers and shell builtins. Only moves and removes code; no intended behavior change. 45 files, about -1.4k lines net.
- ConsoleObject:
TagPayload(a mirror ofTagthat existed to carry one variant's payload) is gone;TagResultcarries the payload as anOption.WrappedWriter::newreplaces 32 struct literals and the per-functionpf!macros. - VirtualMachine / jsc_hooks: one wait loop behind
load_entry_pointandload_entry_point_for_test_runner;auto_tick/auto_tick_activebecomeauto_tick<const ACTIVE: bool>. - bun:test:
toEqual/toStrictEqualshare one implementation; thetoHave*Withfamily shares argument comparison,mock.resultsparsing and failure epilogues. - Shell:
basename/dirnamesharePathBuiltin; cp/ls/mkdir/touch get theirOutputTaskVTableimpl from one macro;subprocstdio init is one match with per-armcfg; the Blob stdin writer is shared withBun.spawn. - dns: generic
PendingCacheKey<Req>and one pending-chain drain replace the per-record-kind copies. - valkey: the seven command-shape macros collapse into
cmd!andcmd_varargs!; all commands keep their name, wire command, argument names and state requirement. - Smaller: AsyncModule error builders, CryptoHasher / PasswordObject / csrf argument parsing, napi
create_string_*prologue, bakeinit_transpiler_impland theDevServerfield-exhaustiveness macro, udp setsockopt helpers, ipc drain loops, socket callback tail,CodeCoverageline mapping.
One deliberate non-1:1 spot: mkdir's on_io_writer_chunk alone had an Idle | Done => panic! arm, which the macro drops to match the other three builtins; Idle still panics one frame down in Mkdir::next, and Done is only set after the last chunk callback has run.
Dropped along the way because main landed its own version: the cron consolidation (#40024) and the URL unification (#40238).
Verified with a debug build, cargo clippy --workspace, rust:check-all (12 targets), and the touched suites (console / inspect, expect + matchers, shell, crypto, csrf, dns, ipc, socket, udp, napi, bake, coverage, valkey), plus byte-for-byte differential checks against canary for the matcher messages, shell output and publish errors. The unified auto_tick is re-compared statement for statement against main's two functions after every rebase.
Review-driven commits
- Second commit: mordant's
same_match_twiceontoHaveNthReturnedWith/toHaveLastReturnedWith, which now sharemock::check_returned_with. - Third commit:
parse_mock_resultlooks the result tag up through the existingRETURN_STATUS_MAP. - Fourth commit:
call_socket_handlertakes its optional extra argument as anOption<JSValue>.
Rebase notes
Rebased onto main nineteen times. Where main changed code this PR had moved into a helper, the change is applied once inside the helper; where main landed its own version of a piece (cron #40024, URL #40238, the websocket publish prologue #39389), the piece was dropped. The larger re-derivations:
- #40238 and #40374 (String ownership and borrowed-bytes lifetimes): applied inside the ConsoleObject
print_*functions,parse_verify_algorithm,CryptoHasher::hash, the napi string helpers, the shell argument helper,parse_mock_result, and the AsyncModule error builders (now fallible, same nine properties in the same order as main's inlined versions). - #40251 and #40410 (redundant exception checks, missing exception checks): applied inside
parse_verify_algorithm, the ipc drain helpers (dispatch::foldaroundhandle_ipc_message), and the matchers'get_direct_indexcalls. - #40478 (
RefPtrreleases on Drop):DNSLookup.resolveris aRefPtras on main; the manualderefsites main deleted were never in this PR's helpers. - #40511 (
Stdio::ArrayBufferremoved,PinnedArrayBufferredirects): the shared stdin writer is Blob-only on both platform arms; the shell's singleReadable::inittakes main'sredirect_bufand hands theBufferedOutputtoPipeReader::createas main does. - #40516 (refcounted types own their teardown): the shell's unified
Writable::initkeeps main'sFileSink::create_with_pipevalue return on the Windows arm; the dnsResolverDrop/RefPtr::init_refguards and theProcessHandleholder land outside this PR's helpers. - #40678 (
bun test --parallelcoverage wire format): theresolve_line/map_to_originalclosures inCodeCoverage::generatesit on top of main'sByteRangeloops (for block in blocks,set(stmts.len())). - #40068 (missing exception checks in the matchers):
DiffFormatter::new(global, received, expected, not)?replaces the struct literal once insidemock::throw_diffand once in the unifiedtoEqual, so the sixtoHave*Withmatchers andtoStrictEqualget main's fallible formatting through the shared code. The matcher suites pass underBUN_JSC_validateExceptionChecks=1. - #39541 (no startup GC): the
perform_gc()removal applied once in the shared entry-point wait; #39541's own tests pass here. - #29339's 45 new redis commands converted to the new macros; #38379 / #40091 (mkdir, touch, ls) and #39615 / #39856 / #40022 (socket) land beside the shared code, not inside it.
Pre-existing items surfaced by review, not changed here
Handed off: the redis bitcount range / hscan cursor argument handling.
Follow-ups: shell stdio init StdioResult::unwraps as error returns; redis keys argument reported as key rather than pattern; dns PendingCacheKey::append as an unsafe fn; bake production init_transpiler freeing the arena projection like DevServer does; sealing StaticHasher so the Digest cast is enforced by the trait; harmonizing the three napi string failure paths; the cron consolidation redone against #40024's shape.