url: improve WHATWG URL inspection
PR-URL: https://github.com/nodejs/node/pull/12253 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
This commit is contained in:
parent
aff5cc92b9
commit
2841f478e4
@ -184,6 +184,17 @@ function onParseHashComplete(flags, protocol, username, password,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getEligibleConstructor(obj) {
|
||||||
|
while (obj !== null) {
|
||||||
|
if (Object.prototype.hasOwnProperty.call(obj, 'constructor') &&
|
||||||
|
typeof obj.constructor === 'function') {
|
||||||
|
return obj.constructor;
|
||||||
|
}
|
||||||
|
obj = Object.getPrototypeOf(obj);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
class URL {
|
class URL {
|
||||||
constructor(input, base) {
|
constructor(input, base) {
|
||||||
// toUSVString is not needed.
|
// toUSVString is not needed.
|
||||||
@ -204,33 +215,43 @@ class URL {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[util.inspect.custom](depth, opts) {
|
[util.inspect.custom](depth, opts) {
|
||||||
|
if (this == null ||
|
||||||
|
Object.getPrototypeOf(this[context]) !== URLContext.prototype) {
|
||||||
|
throw new TypeError('Value of `this` is not a URL');
|
||||||
|
}
|
||||||
|
|
||||||
const ctx = this[context];
|
const ctx = this[context];
|
||||||
var ret = 'URL {\n';
|
|
||||||
ret += ` href: ${this.href}\n`;
|
if (typeof depth === 'number' && depth < 0)
|
||||||
if (ctx.scheme !== undefined)
|
return opts.stylize('[Object]', 'special');
|
||||||
ret += ` protocol: ${this.protocol}\n`;
|
|
||||||
if (ctx.username !== undefined)
|
const ctor = getEligibleConstructor(this);
|
||||||
ret += ` username: ${this.username}\n`;
|
|
||||||
if (ctx.password !== undefined) {
|
const obj = Object.create({
|
||||||
const pwd = opts.showHidden ? ctx.password : '--------';
|
constructor: ctor === null ? URL : ctor
|
||||||
ret += ` password: ${pwd}\n`;
|
});
|
||||||
}
|
|
||||||
if (ctx.host !== undefined)
|
obj.href = this.href;
|
||||||
ret += ` hostname: ${this.hostname}\n`;
|
obj.origin = this.origin;
|
||||||
if (ctx.port !== undefined)
|
obj.protocol = this.protocol;
|
||||||
ret += ` port: ${this.port}\n`;
|
obj.username = this.username;
|
||||||
if (ctx.path !== undefined)
|
obj.password = (opts.showHidden || ctx.password == null) ?
|
||||||
ret += ` pathname: ${this.pathname}\n`;
|
this.password : '--------';
|
||||||
if (ctx.query !== undefined)
|
obj.host = this.host;
|
||||||
ret += ` search: ${this.search}\n`;
|
obj.hostname = this.hostname;
|
||||||
if (ctx.fragment !== undefined)
|
obj.port = this.port;
|
||||||
ret += ` hash: ${this.hash}\n`;
|
obj.pathname = this.pathname;
|
||||||
|
obj.search = this.search;
|
||||||
|
obj.searchParams = this.searchParams;
|
||||||
|
obj.hash = this.hash;
|
||||||
|
|
||||||
if (opts.showHidden) {
|
if (opts.showHidden) {
|
||||||
ret += ` cannot-be-base: ${this[cannotBeBase]}\n`;
|
obj.cannotBeBase = this[cannotBeBase];
|
||||||
ret += ` special: ${this[special]}\n`;
|
obj.special = this[special];
|
||||||
|
obj[context] = this[context];
|
||||||
}
|
}
|
||||||
ret += '}';
|
|
||||||
return ret;
|
return util.inspect(obj, opts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -858,6 +879,9 @@ class URLSearchParams {
|
|||||||
throw new TypeError('Value of `this` is not a URLSearchParams');
|
throw new TypeError('Value of `this` is not a URLSearchParams');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (typeof recurseTimes === 'number' && recurseTimes < 0)
|
||||||
|
return ctx.stylize('[Object]', 'special');
|
||||||
|
|
||||||
const separator = ', ';
|
const separator = ', ';
|
||||||
const innerOpts = Object.assign({}, ctx);
|
const innerOpts = Object.assign({}, ctx);
|
||||||
if (recurseTimes !== null) {
|
if (recurseTimes !== null) {
|
||||||
@ -1211,6 +1235,12 @@ defineIDLClass(URLSearchParamsIteratorPrototype, 'URLSearchParamsIterator', {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
[util.inspect.custom](recurseTimes, ctx) {
|
[util.inspect.custom](recurseTimes, ctx) {
|
||||||
|
if (this == null || this[context] == null || this[context].target == null)
|
||||||
|
throw new TypeError('Value of `this` is not a URLSearchParamsIterator');
|
||||||
|
|
||||||
|
if (typeof recurseTimes === 'number' && recurseTimes < 0)
|
||||||
|
return ctx.stylize('[Object]', 'special');
|
||||||
|
|
||||||
const innerOpts = Object.assign({}, ctx);
|
const innerOpts = Object.assign({}, ctx);
|
||||||
if (recurseTimes !== null) {
|
if (recurseTimes !== null) {
|
||||||
innerOpts.depth = recurseTimes - 1;
|
innerOpts.depth = recurseTimes - 1;
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
const common = require('../common');
|
const common = require('../common');
|
||||||
const util = require('util');
|
const util = require('util');
|
||||||
const URL = require('url').URL;
|
const URL = require('url').URL;
|
||||||
const path = require('path');
|
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
|
|
||||||
if (!common.hasIntl) {
|
if (!common.hasIntl) {
|
||||||
@ -13,71 +12,56 @@ if (!common.hasIntl) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Tests below are not from WPT.
|
// Tests below are not from WPT.
|
||||||
const tests = require(path.join(common.fixturesDir, 'url-tests'));
|
const url = new URL('https://username:password@host.name:8080/path/name/?que=ry#hash');
|
||||||
const additional_tests = require(
|
|
||||||
path.join(common.fixturesDir, 'url-tests-additional'));
|
|
||||||
|
|
||||||
const allTests = additional_tests.slice();
|
assert.strictEqual(
|
||||||
for (const test of tests) {
|
util.inspect(url),
|
||||||
if (test.failure || typeof test === 'string') continue;
|
`URL {
|
||||||
allTests.push(test);
|
href: 'https://username:password@host.name:8080/path/name/?que=ry#hash',
|
||||||
}
|
origin: 'https://host.name:8080',
|
||||||
|
protocol: 'https:',
|
||||||
|
username: 'username',
|
||||||
|
password: '--------',
|
||||||
|
host: 'host.name:8080',
|
||||||
|
hostname: 'host.name',
|
||||||
|
port: '8080',
|
||||||
|
pathname: '/path/name/',
|
||||||
|
search: '?que=ry',
|
||||||
|
searchParams: URLSearchParams { 'que' => 'ry' },
|
||||||
|
hash: '#hash' }`);
|
||||||
|
|
||||||
for (const test of allTests) {
|
assert.strictEqual(
|
||||||
const url = test.url ? new URL(test.url) : new URL(test.input, test.base);
|
util.inspect(url, { showHidden: true }),
|
||||||
|
`URL {
|
||||||
|
href: 'https://username:password@host.name:8080/path/name/?que=ry#hash',
|
||||||
|
origin: 'https://host.name:8080',
|
||||||
|
protocol: 'https:',
|
||||||
|
username: 'username',
|
||||||
|
password: 'password',
|
||||||
|
host: 'host.name:8080',
|
||||||
|
hostname: 'host.name',
|
||||||
|
port: '8080',
|
||||||
|
pathname: '/path/name/',
|
||||||
|
search: '?que=ry',
|
||||||
|
searchParams: URLSearchParams { 'que' => 'ry' },
|
||||||
|
hash: '#hash',
|
||||||
|
cannotBeBase: false,
|
||||||
|
special: true,
|
||||||
|
[Symbol(context)]:\x20
|
||||||
|
URLContext {
|
||||||
|
flags: 2032,
|
||||||
|
scheme: 'https:',
|
||||||
|
username: 'username',
|
||||||
|
password: 'password',
|
||||||
|
host: 'host.name',
|
||||||
|
port: 8080,
|
||||||
|
path: [ 'path', 'name', '', [length]: 3 ],
|
||||||
|
query: 'que=ry',
|
||||||
|
fragment: 'hash' } }`);
|
||||||
|
|
||||||
for (const showHidden of [true, false]) {
|
assert.strictEqual(
|
||||||
const res = util.inspect(url, {
|
util.inspect({ a: url }, { depth: 0 }),
|
||||||
showHidden
|
'{ a: [Object] }');
|
||||||
});
|
|
||||||
|
|
||||||
const lines = res.split('\n');
|
class MyURL extends URL {}
|
||||||
|
assert(util.inspect(new MyURL(url.href)).startsWith('MyURL {'));
|
||||||
const firstLine = lines[0];
|
|
||||||
assert.strictEqual(firstLine, 'URL {');
|
|
||||||
|
|
||||||
const lastLine = lines[lines.length - 1];
|
|
||||||
assert.strictEqual(lastLine, '}');
|
|
||||||
|
|
||||||
const innerLines = lines.slice(1, lines.length - 1);
|
|
||||||
const keys = new Set();
|
|
||||||
for (const line of innerLines) {
|
|
||||||
const i = line.indexOf(': ');
|
|
||||||
const k = line.slice(0, i).trim();
|
|
||||||
const v = line.slice(i + 2);
|
|
||||||
assert.strictEqual(keys.has(k), false, 'duplicate key found: ' + k);
|
|
||||||
keys.add(k);
|
|
||||||
|
|
||||||
const hidden = new Set([
|
|
||||||
'password',
|
|
||||||
'cannot-be-base',
|
|
||||||
'special'
|
|
||||||
]);
|
|
||||||
if (showHidden) {
|
|
||||||
if (!hidden.has(k)) {
|
|
||||||
assert.strictEqual(v, url[k], k);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (k === 'password') {
|
|
||||||
assert.strictEqual(v, url[k], k);
|
|
||||||
}
|
|
||||||
if (k === 'cannot-be-base') {
|
|
||||||
assert.ok(v.match(/^true$|^false$/), k + ' is Boolean');
|
|
||||||
}
|
|
||||||
if (k === 'special') {
|
|
||||||
assert.ok(v.match(/^true$|^false$/), k + ' is Boolean');
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// showHidden is false
|
|
||||||
if (k === 'password') {
|
|
||||||
assert.strictEqual(v, '--------', k);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
assert.strictEqual(hidden.has(k), false, 'no hidden keys: ' + k);
|
|
||||||
assert.strictEqual(v, url[k], k);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user