Repository navigation
feat(runtime): ns:url builtin module mirroring node:url, with URL types - #497
Open
edusperoni wants to merge 2 commits into
Open
edusperoni wants to merge 2 commits into
edusperoni wants to merge 2 commits into
Conversation
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 31 minutes. View limit detailsLimit details: You’ve used all 2 included reviews currently available. Review configuration: ⚙️ Run configuration
📒 Files selected for processing (18)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
edusperoni
added this pull request to stack #495
October 8, 2026 19:29
edusperoni
marked this pull request as ready for review
October 8, 2026 19:33
Adds `ns:url`, exporting the runtime's own URL and URLSearchParams plus the
`fileURLToPath`/`pathToFileURL` converters, so typed code can name the URL
classes by specifier instead of through whatever `globalThis.URL` resolves to
in the program's type environment. Its surface is exactly `node:url`'s: the
standard module now owns the converters, and `node:url` becomes a re-export
shim over it on a distinct, separately frozen module object, the way
`node:util` sits over `ns:util`. `require("node:url")` behaves as before and
additionally exports URL and URLSearchParams, as Node's does. URLPattern stays
a global only; Node's `node:url` has no counterpart and nothing here needs it.
The binding takes both constructors from the templates URLImpl::Init and
URLSearchParamsImpl::Init installed, held per isolate the way Worker's is.
V8 instantiates a template once per context, so the module hands out the very
functions the globals were created with even after an app reassigns them.
types/ns-url.d.ts declares the module and, like @types/node does for its own
globals, merges the module's interfaces into the global URL and
URLSearchParams and declares the global variables through the `onmessage`
probe, so a program with a DOM lib keeps the lib's declarations and one
without gets the module's constructors. Verified with tsc --strict against a
DOM and a non-DOM program: both are clean, and the non-DOM one no longer
reports the two missing-`URL` errors ns-module.d.ts used to produce there.
Experimental, iOS-only until the Android runtime ships the module.
WHATWG URL defines toJSON as the href serialization, so JSON.stringify(url) yields the href string. The runtime's URL lacked it, which also kept a module URL from being assignable to lib.dom's URL in typed code. It is registered next to toString and shares its callback, so both return the same serialization. types/ns-url.d.ts declares it; tsc against the DOM and the non-DOM program stays clean, and the DOM program now assigns pathToFileURL()'s result to the global URL type. The searchParams wrapper that keeps a URL's query in sync forwarded only the name to the native delete, so url.searchParams.delete(name, value) removed every pair with that name. It now forwards the value whenever the caller passed one, by arity, so an explicit undefined still reaches the native coercion.
edusperoni
force-pushed
the
feat/ns-url-module
branch
from
October 8, 2026 19:38
b4cda0c to
aae08b4
Compare
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #494 (base branch
feat/ns-worker-module), which is stacked on #493; only the last two commits are this PR.What
A new
ns:urlbuiltin whose surface is exactlynode:url's: the runtime's ownURLandURLSearchParamsconstructors plus thefileURLToPath/pathToFileURLconverters. The standard module now owns the converters (moved verbatim fromnode-url.js, same Node error messages), andnode:urlbecomes a thin re-export shim over it on a distinct, separately frozen module object, the waynode:utilsits overns:util.Why a module
URLandURLSearchParamsare globals whose types come from whichever lib a program includes. A specifier gives typed code one fixed place to name them. The binding takes both constructors from the templatesURLImpl::Init/URLSearchParamsImpl::Initinstalled, held per isolate in aCaches::StateForslot exactly likeWorker::Constructorin #494. V8 instantiates a template once per context, so the module hands out the very functions the globals were created with, even after an app reassignsglobalThis.URL.Scope decision
The export set is
URL,URLSearchParams,fileURLToPath,pathToFileURL, identical tonode:url's, so the shim re-exports all four unchanged (nodeUrl.fileURLToPath === nsUrl.fileURLToPath). As a resultrequire("node:url")gainsURLandURLSearchParams, matching Node'snode:url; the converters behave exactly as before.URLPatternstays a global only: Node'snode:urlhas no counterpart, and nothing in the module needs it. It can joinns:urllater the same wayns:utilgrewTextEncoder.Types
types/ns-url.d.tsdeclares the module with standaloneURLandURLSearchParamsinterfaces limited to the members this runtime implements (notoJSON, no staticURL.parse;createObjectURL/revokeObjectURLandsearchParamsare included becauseblob-url.jsinstalls them), plus the two converters. At script level it does what@types/nodedoes for its own globals:interface URL extends NsURL {}/interface URLSearchParams extends NsURLSearchParams {}merges, written inside the module'sglobal {}block with a self-import, since an interface cannot extend animport()type;declare var URL/declare var URLSearchParamsthrough thetypeof globalThis extends { onmessage: any; URL: infer T }probe, so a program with a DOM lib keeps the lib's declarations and one without gets the module's constructors.Verified with
tsc --strictagainst a DOM program and a non-DOM program, each constructing both classes through the module and through the globals, with@ts-expect-errorchecks on wrong argument types: both are clean. The non-DOM program no longer reports the two pre-existingCannot find name 'URL'errors inns-module.d.ts, because the globalURLinterface now exists there.The DOM program also assigns
pathToFileURL()'s result to the globalURLtype, which holds because of thetoJSONthe second commit adds.Runtime gaps closed (second commit)
URLgainstoJSON, registered next totoStringwith the same callback, soJSON.stringify(url)gives the href string as WHATWG requires, and a moduleURLis assignable to lib.dom'sURL.searchParamssync wrapper inblob-url.jsforwarded only the name to the nativedelete, sourl.searchParams.delete(name, value)removed every pair with that name. It now forwards the value whenever one was passed (by arity, so an explicitundefinedstill reaches the native coercion).Both have specs, in
URL.jsandUrlSearchParamsTests.js.Docs and tests
docs/ns-builtin-modules.mdgains thens:urlreference section (marked experimental, iOS-only until Android ships it; it now carries the converter semantics and error-message table), the public-row count goes to nine, and thenode:urlshims row says it re-exports all four members fromns:url, still without legacyurl.parse/format/resolveorURLPattern.NsUrlTests.jspins the frozen export set, identity with the globals,URLPatternstaying out, the per-realm singleton, the converters returning the module's ownURL, the shim being a distinct frozen object whose every member is thens:urlone, and, through a worker fixture that reassignsglobalThis.URLbefore its firstrequire("ns:url"), that the module still exports the original constructor. The existingnode:urlexport-set assertion grows the two names.Full suite on a dedicated iOS 18.5 simulator, with both commits: 1764 test cases, 0 failures.