fix(ext/url): align URLSearchParams with Node for node:url compat (#34119)
## Summary
Brings the global `URLSearchParams` (also re-exported by `node:url`) in
line with Node.js where node-compat tests assert behaviors the WHATWG
spec doesn't pin down or that browsers and Node diverge on. Unblocks
**14 previously-failing whatwg-url node-compat tests**.
### Changes
1. **`new URLSearchParams(null)` / `new URLSearchParams(undefined)`**
now produce empty params instead of stringifying `null` to `"null"`.
Browsers/spec stringify but Node treats null/undefined as "no arg" — and
WPT has no test for the `null` case, so this only diverges from the
letter of the spec. The constructor is rewritten to dispatch the union
overloads (string / iterable-of-pairs / record) directly so it can
surface Node-style `ERR_INVALID_TUPLE` and `ERR_ARG_NOT_ITERABLE` errors
that the previous "Item N does not have length 2 exactly" wording
masked.
2. **Iterator `.next()` error message.** The iterators produced by
`mixinPairIterable` (URLSearchParams keys/values/entries) now throw
`TypeError [ERR_INVALID_THIS]: Value of "this" must be of type
URLSearchParamsIterator` when invoked on a non-iterator `this`, matching
the message Node tests assert.
3. **`Symbol.for("nodejs.util.inspect.custom")` methods** added to
`URLSearchParams.prototype` and `URL.prototype` so Node's
property-descriptor sanity test sees them. The methods delegate to the
existing `Deno.privateCustomInspect` path, so the spec-side formatting
is unchanged.
4. **Method shape.** `entries`/`keys`/`values`/`forEach` are now defined
with object-method shorthand so they no longer carry an own `prototype`
property, matching Node's class-method shape. The iterator prototype
gets a `Deno.privateCustomInspect` method so `util.inspect(sp.keys())`
returns `URLSearchParams Iterator { 'a', 'b' }` instead of `'Object
[URLSearchParams Iterator] {}'`.
5. **`forEach` callback `this`** defaults to `undefined` (per WebIDL
spec and Node), not `globalThis`. A missing/non-function callback now
throws `TypeError [ERR_INVALID_ARG_TYPE]` to match Node.
### Tests enabled in `tests/node_compat/config.jsonc`
- `parallel/test-whatwg-url-custom-searchparams-constructor.js`
- `parallel/test-whatwg-url-custom-searchparams-delete.js`
- `parallel/test-whatwg-url-custom-searchparams-entries.js`
- `parallel/test-whatwg-url-custom-searchparams-foreach.js`
- `parallel/test-whatwg-url-custom-searchparams-get.js`
- `parallel/test-whatwg-url-custom-searchparams-getall.js`
- `parallel/test-whatwg-url-custom-searchparams-has.js`
- `parallel/test-whatwg-url-custom-searchparams-inspect.js`
- `parallel/test-whatwg-url-custom-searchparams-keys.js`
- `parallel/test-whatwg-url-custom-searchparams-set.js`
- `parallel/test-whatwg-url-custom-searchparams-stringifier.js`
- `parallel/test-whatwg-url-custom-searchparams-values.js`
- `parallel/test-whatwg-url-custom-searchparams.js`
- `parallel/test-whatwg-url-properties.js`
## Test plan
- [x] `cargo build --bin deno`
- [x] All 14 newly-enabled node-compat tests pass end-to-end
- [x] Previously-enabled
`test-whatwg-url-custom-{inspect,searchparams-append,searchparams-sort}.js`
still pass
- [x] `deno fmt` clean
- [x] `tools/lint.js --js` clean on changed files
- [x] Spot-check that other webidl pair-iterable consumers
(FormData/Headers) still see `this === undefined` (correct per spec) in
forEach
Closes denoland/orchid#99
---------
Co-authored-by: divybot <divybot@users.noreply.github.com>