Browse Source

url: improve WHATWG URL inspection

PR-URL: https://github.com/nodejs/node/pull/12507
Reviewed-By: James M Snell <jasnell@gmail.com>
v7.x
Timothy Gu 8 years ago
committed by Evan Lucas
parent
commit
dfc801737f
  1. 78
      lib/internal/url.js
  2. 114
      test/parallel/test-whatwg-url-inspect.js

78
lib/internal/url.js

@ -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;

114
test/parallel/test-whatwg-url-inspect.js

@ -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:',
for (const test of allTests) { username: 'username',
const url = test.url ? new URL(test.url) : new URL(test.input, test.base); password: '--------',
host: 'host.name:8080',
for (const showHidden of [true, false]) { hostname: 'host.name',
const res = util.inspect(url, { port: '8080',
showHidden pathname: '/path/name/',
}); search: '?que=ry',
searchParams: URLSearchParams { 'que' => 'ry' },
const lines = res.split('\n'); hash: '#hash' }`);
const firstLine = lines[0]; assert.strictEqual(
assert.strictEqual(firstLine, 'URL {'); 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' } }`);
const lastLine = lines[lines.length - 1]; assert.strictEqual(
assert.strictEqual(lastLine, '}'); util.inspect({ a: url }, { depth: 0 }),
'{ a: [Object] }');
const innerLines = lines.slice(1, lines.length - 1); class MyURL extends URL {}
const keys = new Set(); assert(util.inspect(new MyURL(url.href)).startsWith('MyURL {'));
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…
Cancel
Save