Skip to content

Commit

Permalink
url: expose the WHATWG URL API globally
Browse files Browse the repository at this point in the history
Install URL and URLSearchParams on the global object, like they can be
found in browser environments.

PR-URL: #18281
Reviewed-By: Anatoli Papirovski <apapirovski@mac.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Daijiro Wachi <daijiro.wachi@gmail.com>
Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com>
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Evan Lucas <evanlucas@me.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
  • Loading branch information
targos committed Jan 31, 2018
1 parent 332b56c commit 3124146
Show file tree
Hide file tree
Showing 10 changed files with 77 additions and 45 deletions.
1 change: 0 additions & 1 deletion doc/api/errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -1204,7 +1204,6 @@ A Node.js API function was called with an incompatible `this` value.
Example:

```js
const { URLSearchParams } = require('url');
const urlSearchParams = new URLSearchParams('foo=bar&baz=new');

const buf = Buffer.alloc(1);
Expand Down
3 changes: 1 addition & 2 deletions doc/api/esm.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,6 @@ rules with only JS file extension and Node builtin modules support could
be written:

```js
import url from 'url';
import path from 'path';
import process from 'process';
import Module from 'module';
Expand All @@ -164,7 +163,7 @@ export function resolve(specifier, parentModuleURL/*, defaultResolve */) {
throw new Error(
`imports must begin with '/', './', or '../'; '${specifier}' does not`);
}
const resolved = new url.URL(specifier, parentModuleURL);
const resolved = new URL(specifier, parentModuleURL);
const ext = path.extname(resolved.pathname);
if (!JS_EXTENSIONS.has(ext)) {
throw new Error(
Expand Down
1 change: 0 additions & 1 deletion doc/api/fs.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,6 @@ are supported.

```js
const fs = require('fs');
const { URL } = require('url');
const fileUrl = new URL('file:///tmp/hello');

fs.readFileSync(fileUrl);
Expand Down
20 changes: 20 additions & 0 deletions doc/api/globals.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,24 @@ added: v0.0.1

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

## URL
<!-- YAML
added: REPLACEME
-->

<!-- type=global -->

The WHATWG `URL` class. See the [`URL`][] section.

## URLSearchParams
<!-- YAML
added: REPLACEME
-->

<!-- type=global -->

The WHATWG `URLSearchParams` class. See the [`URLSearchParams`][] section.

[`__dirname`]: modules.html#modules_dirname
[`__filename`]: modules.html#modules_filename
[`clearImmediate`]: timers.html#timers_clearimmediate_immediate
Expand All @@ -151,6 +169,8 @@ added: v0.0.1
[`setImmediate`]: timers.html#timers_setimmediate_callback_args
[`setInterval`]: timers.html#timers_setinterval_callback_delay_args
[`setTimeout`]: timers.html#timers_settimeout_callback_delay_args
[`URL`]: url.html#url_class_url
[`URLSearchParams`]: url.html#url_class_urlsearchparams
[buffer section]: buffer.html
[built-in objects]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects
[module system documentation]: modules.html
Expand Down
2 changes: 0 additions & 2 deletions doc/api/http.md
Original file line number Diff line number Diff line change
Expand Up @@ -1871,8 +1871,6 @@ There are a few special headers that should be noted.
Example using a [`URL`][] as `options`:

```js
const { URL } = require('url');

const options = new URL('http://abc:xyz@example.com');

const req = http.request(options, (res) => {
Expand Down
1 change: 0 additions & 1 deletion doc/api/http2.md
Original file line number Diff line number Diff line change
Expand Up @@ -2186,7 +2186,6 @@ An HTTP/2 CONNECT proxy:
const http2 = require('http2');
const { NGHTTP2_REFUSED_STREAM } = http2.constants;
const net = require('net');
const { URL } = require('url');

const proxy = http2.createServer();
proxy.on('stream', (stream, headers) => {
Expand Down
2 changes: 0 additions & 2 deletions doc/api/https.md
Original file line number Diff line number Diff line change
Expand Up @@ -242,8 +242,6 @@ const req = https.request(options, (res) => {
Example using a [`URL`][] as `options`:

```js
const { URL } = require('url');

const options = new URL('https://abc:xyz@example.com');

const req = https.request(options, (res) => {
Expand Down
48 changes: 12 additions & 36 deletions doc/api/url.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,10 @@ properties of a WHATWG `URL` object.
Parsing the URL string using the WHATWG API:

```js
const { URL } = require('url');
const myURL =
new URL('https://user:pass@sub.host.com:8080/p/a/t/h?query=string#hash');
```

*Note*: In Web Browsers, the WHATWG `URL` class is a global that is always
available. In Node.js, however, the `URL` class must be accessed via
`require('url').URL`.

Parsing the URL string using the Legacy API:

```js
Expand All @@ -75,14 +70,19 @@ const myURL =
```

## The WHATWG URL API

### Class: URL
<!-- YAML
added: v7.0.0
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/18281
description: The class is now available on the global object.
-->

### Class: URL

Browser-compatible `URL` class, implemented by following the WHATWG URL
Standard. [Examples of parsed URLs][] may be found in the Standard itself.
The `URL` class is also available on the global object.

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

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

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

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

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

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

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

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

```js
const { URL } = require('url');
const myURL = new URL('https://example.org/foo/bar?baz');
console.log(myURL.origin);
// Prints https://example.org
```

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

```js
const { URL } = require('url');
const myURL = new URL('https://abc:xyz@example.com');
console.log(myURL.password);
// Prints xyz
Expand All @@ -269,7 +259,6 @@ percent-encode may vary somewhat from what the [`url.parse()`][] and
Gets and sets the path portion of the URL.

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

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

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

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

```js
const { URL } = require('url');
const myURL = new URL('https://abc:xyz@example.com');
console.log(myURL.username);
// Prints abc
Expand Down Expand Up @@ -435,7 +420,6 @@ This method is automatically called when an `URL` object is serialized
with [`JSON.stringify()`][].

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

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

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

```js
const { URL, URLSearchParams } = require('url');

const myURL = new URL('https://example.org/?abc=123');
console.log(myURL.searchParams.get('abc'));
// Prints 123
Expand Down Expand Up @@ -505,7 +492,6 @@ Parse the `string` as a query string, and use it to instantiate a new
`URLSearchParams` object. A leading `'?'`, if present, is ignored.

```js
const { URLSearchParams } = require('url');
let params;

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

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

```js
const { URLSearchParams } = require('url');
let params;

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

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

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

```js
const { URLSearchParams } = require('url');

const params = new URLSearchParams();
params.append('foo', 'bar');
params.append('foo', 'baz');
Expand All @@ -720,7 +700,6 @@ with the same name is preserved.
This method can be used, in particular, to increase cache hits.

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

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

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

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

```js
const { URL } = require('url');
const myURL = new URL('https://%CF%80.com/foo');
console.log(myURL.href);
// Prints https://xn--1xa.com/foo
Expand Down
19 changes: 19 additions & 0 deletions lib/internal/bootstrap_node.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
if (browserGlobals) {
setupGlobalTimeouts();
setupGlobalConsole();
setupGlobalURL();
}

// Ensure setURLConstructor() is called before the native
Expand Down Expand Up @@ -372,6 +373,24 @@
setupInspector(originalConsole, wrappedConsole, Module);
}

function setupGlobalURL() {
const { URL, URLSearchParams } = NativeModule.require('internal/url');
Object.defineProperties(global, {
URL: {
value: URL,
writable: true,
configurable: true,
enumerable: false
},
URLSearchParams: {
value: URLSearchParams,
writable: true,
configurable: true,
enumerable: false
}
});
}

function setupInspector(originalConsole, wrappedConsole, Module) {
if (!process.config.variables.v8_enable_inspector) {
return;
Expand Down

0 comments on commit 3124146

Please sign in to comment.