Skip to content

Commit 3124146

Browse files
committed
url: expose the WHATWG URL API globally
Install URL and URLSearchParams on the global object, like they can be found in browser environments. PR-URL: #18281 Reviewed-By: Anatoli Papirovski <[email protected]> Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Daijiro Wachi <[email protected]> Reviewed-By: Tiancheng "Timothy" Gu <[email protected]> Reviewed-By: Ruben Bridgewater <[email protected]> Reviewed-By: Joyee Cheung <[email protected]> Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Evan Lucas <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent 332b56c commit 3124146

File tree

10 files changed

+77
-45
lines changed

10 files changed

+77
-45
lines changed

doc/api/errors.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1204,7 +1204,6 @@ A Node.js API function was called with an incompatible `this` value.
12041204
Example:
12051205

12061206
```js
1207-
const { URLSearchParams } = require('url');
12081207
const urlSearchParams = new URLSearchParams('foo=bar&baz=new');
12091208

12101209
const buf = Buffer.alloc(1);

doc/api/esm.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,6 @@ rules with only JS file extension and Node builtin modules support could
143143
be written:
144144

145145
```js
146-
import url from 'url';
147146
import path from 'path';
148147
import process from 'process';
149148
import Module from 'module';
@@ -164,7 +163,7 @@ export function resolve(specifier, parentModuleURL/*, defaultResolve */) {
164163
throw new Error(
165164
`imports must begin with '/', './', or '../'; '${specifier}' does not`);
166165
}
167-
const resolved = new url.URL(specifier, parentModuleURL);
166+
const resolved = new URL(specifier, parentModuleURL);
168167
const ext = path.extname(resolved.pathname);
169168
if (!JS_EXTENSIONS.has(ext)) {
170169
throw new Error(

doc/api/fs.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,6 @@ are supported.
173173

174174
```js
175175
const fs = require('fs');
176-
const { URL } = require('url');
177176
const fileUrl = new URL('file:///tmp/hello');
178177

179178
fs.readFileSync(fileUrl);

doc/api/globals.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,24 @@ added: v0.0.1
138138

139139
[`setTimeout`] is described in the [timers][] section.
140140

141+
## URL
142+
<!-- YAML
143+
added: REPLACEME
144+
-->
145+
146+
<!-- type=global -->
147+
148+
The WHATWG `URL` class. See the [`URL`][] section.
149+
150+
## URLSearchParams
151+
<!-- YAML
152+
added: REPLACEME
153+
-->
154+
155+
<!-- type=global -->
156+
157+
The WHATWG `URLSearchParams` class. See the [`URLSearchParams`][] section.
158+
141159
[`__dirname`]: modules.html#modules_dirname
142160
[`__filename`]: modules.html#modules_filename
143161
[`clearImmediate`]: timers.html#timers_clearimmediate_immediate
@@ -151,6 +169,8 @@ added: v0.0.1
151169
[`setImmediate`]: timers.html#timers_setimmediate_callback_args
152170
[`setInterval`]: timers.html#timers_setinterval_callback_delay_args
153171
[`setTimeout`]: timers.html#timers_settimeout_callback_delay_args
172+
[`URL`]: url.html#url_class_url
173+
[`URLSearchParams`]: url.html#url_class_urlsearchparams
154174
[buffer section]: buffer.html
155175
[built-in objects]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects
156176
[module system documentation]: modules.html

doc/api/http.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1871,8 +1871,6 @@ There are a few special headers that should be noted.
18711871
Example using a [`URL`][] as `options`:
18721872

18731873
```js
1874-
const { URL } = require('url');
1875-
18761874
const options = new URL('http://abc:[email protected]');
18771875

18781876
const req = http.request(options, (res) => {

doc/api/http2.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2186,7 +2186,6 @@ An HTTP/2 CONNECT proxy:
21862186
const http2 = require('http2');
21872187
const { NGHTTP2_REFUSED_STREAM } = http2.constants;
21882188
const net = require('net');
2189-
const { URL } = require('url');
21902189

21912190
const proxy = http2.createServer();
21922191
proxy.on('stream', (stream, headers) => {

doc/api/https.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -242,8 +242,6 @@ const req = https.request(options, (res) => {
242242
Example using a [`URL`][] as `options`:
243243

244244
```js
245-
const { URL } = require('url');
246-
247245
const options = new URL('https://abc:[email protected]');
248246

249247
const req = https.request(options, (res) => {

doc/api/url.md

Lines changed: 12 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -57,15 +57,10 @@ properties of a WHATWG `URL` object.
5757
Parsing the URL string using the WHATWG API:
5858

5959
```js
60-
const { URL } = require('url');
6160
const myURL =
6261
new URL('https://user:[email protected]:8080/p/a/t/h?query=string#hash');
6362
```
6463

65-
*Note*: In Web Browsers, the WHATWG `URL` class is a global that is always
66-
available. In Node.js, however, the `URL` class must be accessed via
67-
`require('url').URL`.
68-
6964
Parsing the URL string using the Legacy API:
7065

7166
```js
@@ -75,14 +70,19 @@ const myURL =
7570
```
7671

7772
## The WHATWG URL API
73+
74+
### Class: URL
7875
<!-- YAML
7976
added: v7.0.0
77+
changes:
78+
- version: REPLACEME
79+
pr-url: https://github.com/nodejs/node/pull/18281
80+
description: The class is now available on the global object.
8081
-->
8182

82-
### Class: URL
83-
8483
Browser-compatible `URL` class, implemented by following the WHATWG URL
8584
Standard. [Examples of parsed URLs][] may be found in the Standard itself.
85+
The `URL` class is also available on the global object.
8686

8787
*Note*: In accordance with browser conventions, all properties of `URL` objects
8888
are implemented as getters and setters on the class prototype, rather than as
@@ -101,7 +101,6 @@ Creates a new `URL` object by parsing the `input` relative to the `base`. If
101101
`base` is passed as a string, it will be parsed equivalent to `new URL(base)`.
102102

103103
```js
104-
const { URL } = require('url');
105104
const myURL = new URL('/foo', 'https://example.org/');
106105
// https://example.org/foo
107106
```
@@ -111,7 +110,6 @@ that an effort will be made to coerce the given values into strings. For
111110
instance:
112111

113112
```js
114-
const { URL } = require('url');
115113
const myURL = new URL({ toString: () => 'https://example.org/' });
116114
// https://example.org/
117115
```
@@ -120,7 +118,6 @@ Unicode characters appearing within the hostname of `input` will be
120118
automatically converted to ASCII using the [Punycode][] algorithm.
121119

122120
```js
123-
const { URL } = require('url');
124121
const myURL = new URL('https://你好你好');
125122
// https://xn--6qqa088eba/
126123
```
@@ -135,7 +132,6 @@ with [ICU][] enabled. If not, the domain names are passed through unchanged.
135132
Gets and sets the fragment portion of the URL.
136133

137134
```js
138-
const { URL } = require('url');
139135
const myURL = new URL('https://example.org/foo#bar');
140136
console.log(myURL.hash);
141137
// Prints #bar
@@ -157,7 +153,6 @@ percent-encode may vary somewhat from what the [`url.parse()`][] and
157153
Gets and sets the host portion of the URL.
158154

159155
```js
160-
const { URL } = require('url');
161156
const myURL = new URL('https://example.org:81/foo');
162157
console.log(myURL.host);
163158
// Prints example.org:81
@@ -178,7 +173,6 @@ Gets and sets the hostname portion of the URL. The key difference between
178173
port.
179174

180175
```js
181-
const { URL } = require('url');
182176
const myURL = new URL('https://example.org:81/foo');
183177
console.log(myURL.hostname);
184178
// Prints example.org
@@ -197,7 +191,6 @@ Invalid hostname values assigned to the `hostname` property are ignored.
197191
Gets and sets the serialized URL.
198192

199193
```js
200-
const { URL } = require('url');
201194
const myURL = new URL('https://example.org/foo');
202195
console.log(myURL.href);
203196
// Prints https://example.org/foo
@@ -224,14 +217,12 @@ will be thrown.
224217
Gets the read-only serialization of the URL's origin.
225218

226219
```js
227-
const { URL } = require('url');
228220
const myURL = new URL('https://example.org/foo/bar?baz');
229221
console.log(myURL.origin);
230222
// Prints https://example.org
231223
```
232224

233225
```js
234-
const { URL } = require('url');
235226
const idnURL = new URL('https://你好你好');
236227
console.log(idnURL.origin);
237228
// Prints https://xn--6qqa088eba
@@ -247,7 +238,6 @@ console.log(idnURL.hostname);
247238
Gets and sets the password portion of the URL.
248239

249240
```js
250-
const { URL } = require('url');
251241
const myURL = new URL('https://abc:[email protected]');
252242
console.log(myURL.password);
253243
// Prints xyz
@@ -269,7 +259,6 @@ percent-encode may vary somewhat from what the [`url.parse()`][] and
269259
Gets and sets the path portion of the URL.
270260

271261
```js
272-
const { URL } = require('url');
273262
const myURL = new URL('https://example.org/abc/xyz?123');
274263
console.log(myURL.pathname);
275264
// Prints /abc/xyz
@@ -291,7 +280,6 @@ to percent-encode may vary somewhat from what the [`url.parse()`][] and
291280
Gets and sets the port portion of the URL.
292281

293282
```js
294-
const { URL } = require('url');
295283
const myURL = new URL('https://example.org:8888');
296284
console.log(myURL.port);
297285
// Prints 8888
@@ -347,7 +335,6 @@ lies outside the range denoted above, it is ignored.
347335
Gets and sets the protocol portion of the URL.
348336

349337
```js
350-
const { URL } = require('url');
351338
const myURL = new URL('https://example.org');
352339
console.log(myURL.protocol);
353340
// Prints https:
@@ -366,7 +353,6 @@ Invalid URL protocol values assigned to the `protocol` property are ignored.
366353
Gets and sets the serialized query portion of the URL.
367354

368355
```js
369-
const { URL } = require('url');
370356
const myURL = new URL('https://example.org/abc?123');
371357
console.log(myURL.search);
372358
// Prints ?123
@@ -397,7 +383,6 @@ documentation for details.
397383
Gets and sets the username portion of the URL.
398384

399385
```js
400-
const { URL } = require('url');
401386
const myURL = new URL('https://abc:[email protected]');
402387
console.log(myURL.username);
403388
// Prints abc
@@ -435,7 +420,6 @@ This method is automatically called when an `URL` object is serialized
435420
with [`JSON.stringify()`][].
436421

437422
```js
438-
const { URL } = require('url');
439423
const myURLs = [
440424
new URL('https://www.example.com'),
441425
new URL('https://test.example.org')
@@ -447,20 +431,23 @@ console.log(JSON.stringify(myURLs));
447431
### Class: URLSearchParams
448432
<!-- YAML
449433
added: v7.5.0
434+
changes:
435+
- version: REPLACEME
436+
pr-url: https://github.com/nodejs/node/pull/18281
437+
description: The class is now available on the global object.
450438
-->
451439

452440
The `URLSearchParams` API provides read and write access to the query of a
453441
`URL`. The `URLSearchParams` class can also be used standalone with one of the
454442
four following constructors.
443+
The `URLSearchParams` class is also available on the global object.
455444

456445
The WHATWG `URLSearchParams` interface and the [`querystring`][] module have
457446
similar purpose, but the purpose of the [`querystring`][] module is more
458447
general, as it allows the customization of delimiter characters (`&` and `=`).
459448
On the other hand, this API is designed purely for URL query strings.
460449

461450
```js
462-
const { URL, URLSearchParams } = require('url');
463-
464451
const myURL = new URL('https://example.org/?abc=123');
465452
console.log(myURL.searchParams.get('abc'));
466453
// Prints 123
@@ -505,7 +492,6 @@ Parse the `string` as a query string, and use it to instantiate a new
505492
`URLSearchParams` object. A leading `'?'`, if present, is ignored.
506493

507494
```js
508-
const { URLSearchParams } = require('url');
509495
let params;
510496

511497
params = new URLSearchParams('user=abc&query=xyz');
@@ -534,7 +520,6 @@ values are not allowed. Arrays are stringified using [`array.toString()`][],
534520
which simply joins all array elements with commas.
535521

536522
```js
537-
const { URLSearchParams } = require('url');
538523
const params = new URLSearchParams({
539524
user: 'abc',
540525
query: ['first', 'second']
@@ -562,7 +547,6 @@ themselves be any iterable object.
562547
Duplicate keys are allowed.
563548

564549
```js
565-
const { URLSearchParams } = require('url');
566550
let params;
567551

568552
// Using an array
@@ -631,7 +615,6 @@ Alias for [`urlSearchParams[@@iterator]()`][`urlSearchParams@@iterator()`].
631615
Iterates over each name-value pair in the query and invokes the given function.
632616

633617
```js
634-
const { URL } = require('url');
635618
const myURL = new URL('https://example.org/?a=b&c=d');
636619
myURL.searchParams.forEach((value, name, searchParams) => {
637620
console.log(name, value, myURL.searchParams === searchParams);
@@ -672,7 +655,6 @@ Returns `true` if there is at least one name-value pair whose name is `name`.
672655
Returns an ES6 Iterator over the names of each name-value pair.
673656

674657
```js
675-
const { URLSearchParams } = require('url');
676658
const params = new URLSearchParams('foo=bar&foo=baz');
677659
for (const name of params.keys()) {
678660
console.log(name);
@@ -693,8 +675,6 @@ set the first such pair's value to `value` and remove all others. If not,
693675
append the name-value pair to the query string.
694676

695677
```js
696-
const { URLSearchParams } = require('url');
697-
698678
const params = new URLSearchParams();
699679
params.append('foo', 'bar');
700680
params.append('foo', 'baz');
@@ -720,7 +700,6 @@ with the same name is preserved.
720700
This method can be used, in particular, to increase cache hits.
721701

722702
```js
723-
const { URLSearchParams } = require('url');
724703
const params = new URLSearchParams('query[]=abc&type=search&query[]=123');
725704
params.sort();
726705
console.log(params.toString());
@@ -751,7 +730,6 @@ is the `name`, the second item of the Array is the `value`.
751730
Alias for [`urlSearchParams.entries()`][].
752731

753732
```js
754-
const { URLSearchParams } = require('url');
755733
const params = new URLSearchParams('foo=bar&xyz=baz');
756734
for (const [name, value] of params) {
757735
console.log(name, value);
@@ -835,7 +813,6 @@ of the output.
835813
For example:
836814

837815
```js
838-
const { URL } = require('url');
839816
const myURL = new URL('https://a:b@你好你好?abc#foo');
840817

841818
console.log(myURL.href);
@@ -1135,7 +1112,6 @@ using the [Punycode][] algorithm. Note, however, that a hostname *may* contain
11351112
*both* Punycode encoded and percent-encoded characters. For example:
11361113

11371114
```js
1138-
const { URL } = require('url');
11391115
const myURL = new URL('https://%CF%80.com/foo');
11401116
console.log(myURL.href);
11411117
// Prints https://xn--1xa.com/foo

lib/internal/bootstrap_node.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
if (browserGlobals) {
7373
setupGlobalTimeouts();
7474
setupGlobalConsole();
75+
setupGlobalURL();
7576
}
7677

7778
// Ensure setURLConstructor() is called before the native
@@ -372,6 +373,24 @@
372373
setupInspector(originalConsole, wrappedConsole, Module);
373374
}
374375

376+
function setupGlobalURL() {
377+
const { URL, URLSearchParams } = NativeModule.require('internal/url');
378+
Object.defineProperties(global, {
379+
URL: {
380+
value: URL,
381+
writable: true,
382+
configurable: true,
383+
enumerable: false
384+
},
385+
URLSearchParams: {
386+
value: URLSearchParams,
387+
writable: true,
388+
configurable: true,
389+
enumerable: false
390+
}
391+
});
392+
}
393+
375394
function setupInspector(originalConsole, wrappedConsole, Module) {
376395
if (!process.config.variables.v8_enable_inspector) {
377396
return;

0 commit comments

Comments
 (0)