Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(node/url): Add url.format(URL[, options]) #1420

Merged
merged 3 commits into from
Oct 17, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions node/_tools/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@
"test-net-write-fully-async-buffer.js",
"test-net-write-fully-async-hex-string.js",
"test-url-fileurltopath.js",
"test-url-format-whatwg.js",
"test-url-pathtofileurl.js",
"test-util-inherits.js"
],
Expand Down
128 changes: 128 additions & 0 deletions node/_tools/suites/parallel/test-url-format-whatwg.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
// deno-fmt-ignore-file
// deno-lint-ignore-file

// Copyright Joyent and Node contributors. All rights reserved. MIT license.
// Taken from Node 16.11.1
// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually

'use strict';

const common = require('../common');

// TODO(wafuwafu): Implement `hasIntl`, `skip`
// if (!common.hasIntl)
// common.skip('missing Intl');

const assert = require('assert');
const url = require('url');

const myURL = new URL('http://xn--lck1c3crb1723bpq4a.com/a?a=b#c');

assert.strictEqual(
url.format(myURL),
'http://xn--lck1c3crb1723bpq4a.com/a?a=b#c'
);

assert.strictEqual(
url.format(myURL, {}),
'http://xn--lck1c3crb1723bpq4a.com/a?a=b#c'
);

{
[true, 1, 'test', Infinity].forEach((value) => {
assert.throws(
() => url.format(myURL, value),
{
code: 'ERR_INVALID_ARG_TYPE',
name: 'TypeError',
message: 'The "options" argument must be of type object.' +
common.invalidArgTypeHelper(value)
}
);
});
}

// Any falsy value other than undefined will be treated as false.
// Any truthy value will be treated as true.

assert.strictEqual(
url.format(myURL, { fragment: false }),
'http://xn--lck1c3crb1723bpq4a.com/a?a=b'
);

assert.strictEqual(
url.format(myURL, { fragment: '' }),
'http://xn--lck1c3crb1723bpq4a.com/a?a=b'
);

assert.strictEqual(
url.format(myURL, { fragment: 0 }),
'http://xn--lck1c3crb1723bpq4a.com/a?a=b'
);

assert.strictEqual(
url.format(myURL, { fragment: 1 }),
'http://xn--lck1c3crb1723bpq4a.com/a?a=b#c'
);

assert.strictEqual(
url.format(myURL, { fragment: {} }),
'http://xn--lck1c3crb1723bpq4a.com/a?a=b#c'
);

assert.strictEqual(
url.format(myURL, { search: false }),
'http://xn--lck1c3crb1723bpq4a.com/a#c'
);

assert.strictEqual(
url.format(myURL, { search: '' }),
'http://xn--lck1c3crb1723bpq4a.com/a#c'
);

assert.strictEqual(
url.format(myURL, { search: 0 }),
'http://xn--lck1c3crb1723bpq4a.com/a#c'
);

assert.strictEqual(
url.format(myURL, { search: 1 }),
'http://xn--lck1c3crb1723bpq4a.com/a?a=b#c'
);

assert.strictEqual(
url.format(myURL, { search: {} }),
'http://xn--lck1c3crb1723bpq4a.com/a?a=b#c'
);

// TODO(wafuwafu13): Support unicode option

// assert.strictEqual(
// url.format(myURL, { unicode: true }),
// 'http://理容ナカムラ.com/a?a=b#c'
// );

// assert.strictEqual(
// url.format(myURL, { unicode: 1 }),
// 'http://理容ナカムラ.com/a?a=b#c'
// );

// assert.strictEqual(
// url.format(myURL, { unicode: {} }),
// 'http://理容ナカムラ.com/a?a=b#c'
// );

assert.strictEqual(
url.format(myURL, { unicode: false }),
'http://xn--lck1c3crb1723bpq4a.com/a?a=b#c'
);

assert.strictEqual(
url.format(myURL, { unicode: 0 }),
'http://xn--lck1c3crb1723bpq4a.com/a?a=b#c'
);

// assert.strictEqual(
// url.format(new URL('http://xn--0zwm56d.com:8080/path'), { unicode: true }),
// 'http://测试.com:8080/path'
// );
71 changes: 71 additions & 0 deletions node/url.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,76 @@ const tabRegEx = /\t/g;
const _url = URL;
export { _url as URL };

/**
* The URL object has both a `toString()` method and `href` property that return string serializations of the URL.
* These are not, however, customizable in any way.
* This method allows for basic customization of the output.
* @param urlObject
* @param options
* @param options.auth `true` if the serialized URL string should include the username and password, `false` otherwise. **Default**: `true`.
* @param options.fragment `true` if the serialized URL string should include the fragment, `false` otherwise. **Default**: `true`.
* @param options.search `true` if the serialized URL string should include the search query, **Default**: `true`.
* @param options.unicode `true` if Unicode characters appearing in the host component of the URL string should be encoded directly as opposed to being Punycode encoded. **Default**: `false`.
* @returns a customizable serialization of a URL `String` representation of a `WHATWG URL` object.
*/
export function format(
urlObject: URL,
options?: {
auth: boolean;
fragment: boolean;
search: boolean;
unicode: boolean;
},
): string {
if (options) {
if (typeof options !== "object") {
throw new ERR_INVALID_ARG_TYPE("options", "object", options);
}
}

options = {
auth: true,
fragment: true,
search: true,
unicode: false,
...options,
};

let ret = urlObject.protocol;
if (urlObject.host !== null) {
ret += "//";
const hasUsername = urlObject.username !== "";
const hasPassword = urlObject.password !== "";
if (options.auth && (hasUsername || hasPassword)) {
if (hasUsername) {
ret += urlObject.username;
}
if (hasPassword) {
ret += `:${urlObject.password}`;
}
ret += "@";
}
// TODO(wafuwfu13): Support unicode option
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still trying to figure out how to write the part of the node that is written in c++.
same #1365 (comment)

// ret += options.unicode ?
// domainToUnicode(urlObject.host) : urlObject.host;
ret += urlObject.host;
if (urlObject.port) {
ret += `:${urlObject.port}`;
}
}

ret += urlObject.pathname;

if (options.search) {
ret += urlObject.search;
}
if (options.fragment) {
ret += urlObject.hash;
}

return ret;
}

/**
* Get fully resolved platform-specific file path from the given URL string/ object
* @param path The file URL string or URL object to convert to a path
Expand Down Expand Up @@ -196,6 +266,7 @@ export function pathToFileURL(filepath: string): URL {
}

export default {
format,
fileURLToPath,
pathToFileURL,
URL,
Expand Down