Permalink
Browse files

url: improve WHATWG URL inspection

PR-URL: #12253
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
  • Loading branch information...
TimothyGu authored and addaleax committed Apr 5, 2017
1 parent aff5cc9 commit 2841f478e46c77feb56aa9712f78afb64daba004
Showing with 103 additions and 89 deletions.
  1. +54 −24 lib/internal/url.js
  2. +49 −65 test/parallel/test-whatwg-url-inspect.js
View
@@ -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 {
constructor(input, base) {
// toUSVString is not needed.
@@ -204,33 +215,43 @@ class URL {
}
[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];
- var ret = 'URL {\n';
- ret += ` href: ${this.href}\n`;
- if (ctx.scheme !== undefined)
- ret += ` protocol: ${this.protocol}\n`;
- if (ctx.username !== undefined)
- ret += ` username: ${this.username}\n`;
- if (ctx.password !== undefined) {
- const pwd = opts.showHidden ? ctx.password : '--------';
- ret += ` password: ${pwd}\n`;
- }
- if (ctx.host !== undefined)
- ret += ` hostname: ${this.hostname}\n`;
- if (ctx.port !== undefined)
- ret += ` port: ${this.port}\n`;
- if (ctx.path !== undefined)
- ret += ` pathname: ${this.pathname}\n`;
- if (ctx.query !== undefined)
- ret += ` search: ${this.search}\n`;
- if (ctx.fragment !== undefined)
- ret += ` hash: ${this.hash}\n`;
+
+ if (typeof depth === 'number' && depth < 0)
+ return opts.stylize('[Object]', 'special');
+
+ const ctor = getEligibleConstructor(this);
+
+ const obj = Object.create({
+ constructor: ctor === null ? URL : ctor
+ });
+
+ obj.href = this.href;
+ obj.origin = this.origin;
+ obj.protocol = this.protocol;
+ obj.username = this.username;
+ obj.password = (opts.showHidden || ctx.password == null) ?
+ this.password : '--------';
+ obj.host = this.host;
+ obj.hostname = this.hostname;
+ obj.port = this.port;
+ obj.pathname = this.pathname;
+ obj.search = this.search;
+ obj.searchParams = this.searchParams;
+ obj.hash = this.hash;
+
if (opts.showHidden) {
- ret += ` cannot-be-base: ${this[cannotBeBase]}\n`;
- ret += ` special: ${this[special]}\n`;
+ obj.cannotBeBase = this[cannotBeBase];
+ 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');
}
+ if (typeof recurseTimes === 'number' && recurseTimes < 0)
+ return ctx.stylize('[Object]', 'special');
+
const separator = ', ';
const innerOpts = Object.assign({}, ctx);
if (recurseTimes !== null) {
@@ -1211,6 +1235,12 @@ defineIDLClass(URLSearchParamsIteratorPrototype, 'URLSearchParamsIterator', {
};
},
[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);
if (recurseTimes !== null) {
innerOpts.depth = recurseTimes - 1;
@@ -3,7 +3,6 @@
const common = require('../common');
const util = require('util');
const URL = require('url').URL;
-const path = require('path');
const assert = require('assert');
if (!common.hasIntl) {
@@ -13,71 +12,56 @@ if (!common.hasIntl) {
}
// Tests below are not from WPT.
-const tests = require(path.join(common.fixturesDir, 'url-tests'));
-const additional_tests = require(
- path.join(common.fixturesDir, 'url-tests-additional'));
+const url = new URL('https://username:password@host.name:8080/path/name/?que=ry#hash');
-const allTests = additional_tests.slice();
-for (const test of tests) {
- if (test.failure || typeof test === 'string') continue;
- allTests.push(test);
-}
-
-for (const test of allTests) {
- const url = test.url ? new URL(test.url) : new URL(test.input, test.base);
-
- for (const showHidden of [true, false]) {
- const res = util.inspect(url, {
- showHidden
- });
-
- const lines = res.split('\n');
+assert.strictEqual(
+ util.inspect(url),
+ `URL {
+ 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' }`);
- const firstLine = lines[0];
- assert.strictEqual(firstLine, 'URL {');
+assert.strictEqual(
+ 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(lastLine, '}');
+assert.strictEqual(
+ util.inspect({ a: url }, { depth: 0 }),
+ '{ a: [Object] }');
- 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);
- }
- }
-}
+class MyURL extends URL {}
+assert(util.inspect(new MyURL(url.href)).startsWith('MyURL {'));

0 comments on commit 2841f47

Please sign in to comment.