url: extend URLSearchParams constructor
PR-URL: https://github.com/nodejs/node/pull/11060 Fixes: https://github.com/nodejs/node/issues/10635 Ref: https://github.com/whatwg/url/pull/175 Ref: https://github.com/w3c/web-platform-tests/pull/4523 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
This commit is contained in:
parent
a1c91eccbb
commit
cc48f21c83
@ -677,11 +677,53 @@ function defineIDLClass(proto, classStr, obj) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class URLSearchParams {
|
class URLSearchParams {
|
||||||
constructor(init = '') {
|
// URL Standard says the default value is '', but as undefined and '' have
|
||||||
if (init instanceof URLSearchParams) {
|
// the same result, undefined is used to prevent unnecessary parsing.
|
||||||
const childParams = init[searchParams];
|
// Default parameter is necessary to keep URLSearchParams.length === 0 in
|
||||||
this[searchParams] = childParams.slice();
|
// accordance with Web IDL spec.
|
||||||
|
constructor(init = undefined) {
|
||||||
|
if (init === null || init === undefined) {
|
||||||
|
this[searchParams] = [];
|
||||||
|
} else if (typeof init === 'object') {
|
||||||
|
const method = init[Symbol.iterator];
|
||||||
|
if (method === this[Symbol.iterator]) {
|
||||||
|
// While the spec does not have this branch, we can use it as a
|
||||||
|
// shortcut to avoid having to go through the costly generic iterator.
|
||||||
|
const childParams = init[searchParams];
|
||||||
|
this[searchParams] = childParams.slice();
|
||||||
|
} else if (method !== null && method !== undefined) {
|
||||||
|
if (typeof method !== 'function') {
|
||||||
|
throw new TypeError('Query pairs must be iterable');
|
||||||
|
}
|
||||||
|
|
||||||
|
// sequence<sequence<USVString>>
|
||||||
|
// Note: per spec we have to first exhaust the lists then process them
|
||||||
|
const pairs = [];
|
||||||
|
for (const pair of init) {
|
||||||
|
if (typeof pair !== 'object' ||
|
||||||
|
typeof pair[Symbol.iterator] !== 'function') {
|
||||||
|
throw new TypeError('Each query pair must be iterable');
|
||||||
|
}
|
||||||
|
pairs.push(Array.from(pair));
|
||||||
|
}
|
||||||
|
|
||||||
|
this[searchParams] = [];
|
||||||
|
for (const pair of pairs) {
|
||||||
|
if (pair.length !== 2) {
|
||||||
|
throw new TypeError('Each query pair must be a name/value tuple');
|
||||||
|
}
|
||||||
|
this[searchParams].push(String(pair[0]), String(pair[1]));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// record<USVString, USVString>
|
||||||
|
this[searchParams] = [];
|
||||||
|
for (const key of Object.keys(init)) {
|
||||||
|
const value = String(init[key]);
|
||||||
|
this[searchParams].push(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// USVString
|
||||||
init = String(init);
|
init = String(init);
|
||||||
if (init[0] === '?') init = init.slice(1);
|
if (init[0] === '?') init = init.slice(1);
|
||||||
initSearchParams(this, init);
|
initSearchParams(this, init);
|
||||||
|
@ -16,23 +16,30 @@ assert.strictEqual(params + '', 'a=b');
|
|||||||
params = new URLSearchParams(params);
|
params = new URLSearchParams(params);
|
||||||
assert.strictEqual(params + '', 'a=b');
|
assert.strictEqual(params + '', 'a=b');
|
||||||
|
|
||||||
// URLSearchParams constructor, empty.
|
// URLSearchParams constructor, no arguments
|
||||||
|
params = new URLSearchParams();
|
||||||
|
assert.strictEqual(params.toString(), '');
|
||||||
|
|
||||||
assert.throws(() => URLSearchParams(), TypeError,
|
assert.throws(() => URLSearchParams(), TypeError,
|
||||||
'Calling \'URLSearchParams\' without \'new\' should throw.');
|
'Calling \'URLSearchParams\' without \'new\' should throw.');
|
||||||
// assert.throws(() => new URLSearchParams(DOMException.prototype), TypeError);
|
|
||||||
assert.throws(() => {
|
// URLSearchParams constructor, undefined and null as argument
|
||||||
new URLSearchParams({
|
params = new URLSearchParams(undefined);
|
||||||
toString() { throw new TypeError('Illegal invocation'); }
|
assert.strictEqual(params.toString(), '');
|
||||||
});
|
params = new URLSearchParams(null);
|
||||||
}, TypeError);
|
assert.strictEqual(params.toString(), '');
|
||||||
|
|
||||||
|
// URLSearchParams constructor, empty string as argument
|
||||||
params = new URLSearchParams('');
|
params = new URLSearchParams('');
|
||||||
assert.notStrictEqual(params, null, 'constructor returned non-null value.');
|
// eslint-disable-next-line no-restricted-properties
|
||||||
|
assert.notEqual(params, null, 'constructor returned non-null value.');
|
||||||
// eslint-disable-next-line no-proto
|
// eslint-disable-next-line no-proto
|
||||||
assert.strictEqual(params.__proto__, URLSearchParams.prototype,
|
assert.strictEqual(params.__proto__, URLSearchParams.prototype,
|
||||||
'expected URLSearchParams.prototype as prototype.');
|
'expected URLSearchParams.prototype as prototype.');
|
||||||
|
|
||||||
|
// URLSearchParams constructor, {} as argument
|
||||||
params = new URLSearchParams({});
|
params = new URLSearchParams({});
|
||||||
// assert.strictEqual(params + '', '%5Bobject+Object%5D=');
|
assert.strictEqual(params + '', '');
|
||||||
assert.strictEqual(params + '', '%5Bobject%20Object%5D=');
|
|
||||||
|
|
||||||
// URLSearchParams constructor, string.
|
// URLSearchParams constructor, string.
|
||||||
params = new URLSearchParams('a=b');
|
params = new URLSearchParams('a=b');
|
||||||
@ -128,3 +135,56 @@ params = new URLSearchParams('a=b%f0%9f%92%a9c');
|
|||||||
assert.strictEqual(params.get('a'), 'b\uD83D\uDCA9c');
|
assert.strictEqual(params.get('a'), 'b\uD83D\uDCA9c');
|
||||||
params = new URLSearchParams('a%f0%9f%92%a9b=c');
|
params = new URLSearchParams('a%f0%9f%92%a9b=c');
|
||||||
assert.strictEqual(params.get('a\uD83D\uDCA9b'), 'c');
|
assert.strictEqual(params.get('a\uD83D\uDCA9b'), 'c');
|
||||||
|
|
||||||
|
// Constructor with sequence of sequences of strings
|
||||||
|
params = new URLSearchParams([]);
|
||||||
|
// eslint-disable-next-line no-restricted-properties
|
||||||
|
assert.notEqual(params, null, 'constructor returned non-null value.');
|
||||||
|
params = new URLSearchParams([['a', 'b'], ['c', 'd']]);
|
||||||
|
assert.strictEqual(params.get('a'), 'b');
|
||||||
|
assert.strictEqual(params.get('c'), 'd');
|
||||||
|
assert.throws(() => new URLSearchParams([[1]]),
|
||||||
|
/^TypeError: Each query pair must be a name\/value tuple$/);
|
||||||
|
assert.throws(() => new URLSearchParams([[1, 2, 3]]),
|
||||||
|
/^TypeError: Each query pair must be a name\/value tuple$/);
|
||||||
|
|
||||||
|
[
|
||||||
|
// Further confirmation needed
|
||||||
|
// https://github.com/w3c/web-platform-tests/pull/4523#discussion_r98337513
|
||||||
|
// {
|
||||||
|
// input: {'+': '%C2'},
|
||||||
|
// output: [[' ', '\uFFFD']],
|
||||||
|
// name: 'object with +'
|
||||||
|
// },
|
||||||
|
{
|
||||||
|
input: {c: 'x', a: '?'},
|
||||||
|
output: [['c', 'x'], ['a', '?']],
|
||||||
|
name: 'object with two keys'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: [['c', 'x'], ['a', '?']],
|
||||||
|
output: [['c', 'x'], ['a', '?']],
|
||||||
|
name: 'array with two keys'
|
||||||
|
}
|
||||||
|
].forEach((val) => {
|
||||||
|
const params = new URLSearchParams(val.input);
|
||||||
|
assert.deepStrictEqual(Array.from(params), val.output,
|
||||||
|
`Construct with ${val.name}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Custom [Symbol.iterator]
|
||||||
|
params = new URLSearchParams();
|
||||||
|
params[Symbol.iterator] = function *() {
|
||||||
|
yield ['a', 'b'];
|
||||||
|
};
|
||||||
|
const params2 = new URLSearchParams(params);
|
||||||
|
assert.strictEqual(params2.get('a'), 'b');
|
||||||
|
|
||||||
|
assert.throws(() => new URLSearchParams({ [Symbol.iterator]: 42 }),
|
||||||
|
/^TypeError: Query pairs must be iterable$/);
|
||||||
|
assert.throws(() => new URLSearchParams([{}]),
|
||||||
|
/^TypeError: Each query pair must be iterable$/);
|
||||||
|
assert.throws(() => new URLSearchParams(['a']),
|
||||||
|
/^TypeError: Each query pair must be iterable$/);
|
||||||
|
assert.throws(() => new URLSearchParams([{ [Symbol.iterator]: 42 }]),
|
||||||
|
/^TypeError: Each query pair must be iterable$/);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user