Skip to content

Commit b4052e6

Browse files
TimothyGuevanlucas
authored andcommitted
url: extend URLSearchParams constructor
PR-URL: #12507Fixes: #10635 Reviewed-By: James M Snell <[email protected]>
1 parent 5ccafa2 commit b4052e6

File tree

2 files changed

+96
-41
lines changed

2 files changed

+96
-41
lines changed

‎lib/internal/url.js‎

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -614,11 +614,53 @@ function defineIDLClass(proto, classStr, obj){
614614
}
615615

616616
classURLSearchParams{
617-
constructor(init=''){
618-
if(initinstanceofURLSearchParams){
619-
constchildParams=init[searchParams];
620-
this[searchParams]=childParams.slice();
617+
// URL Standard says the default value is '', but as undefined and '' have
618+
// the same result, undefined is used to prevent unnecessary parsing.
619+
// Default parameter is necessary to keep URLSearchParams.length === 0 in
620+
// accordance with Web IDL spec.
621+
constructor(init=undefined){
622+
if(init===null||init===undefined){
623+
this[searchParams]=[];
624+
}elseif(typeofinit==='object'){
625+
constmethod=init[Symbol.iterator];
626+
if(method===this[Symbol.iterator]){
627+
// While the spec does not have this branch, we can use it as a
628+
// shortcut to avoid having to go through the costly generic iterator.
629+
constchildParams=init[searchParams];
630+
this[searchParams]=childParams.slice();
631+
}elseif(method!==null&&method!==undefined){
632+
if(typeofmethod!=='function'){
633+
thrownewTypeError('Query pairs must be iterable');
634+
}
635+
636+
// sequence<sequence<USVString>>
637+
// Note: per spec we have to first exhaust the lists then process them
638+
constpairs=[];
639+
for(constpairofinit){
640+
if(typeofpair!=='object'||
641+
typeofpair[Symbol.iterator]!=='function'){
642+
thrownewTypeError('Each query pair must be iterable');
643+
}
644+
pairs.push(Array.from(pair));
645+
}
646+
647+
this[searchParams]=[];
648+
for(constpairofpairs){
649+
if(pair.length!==2){
650+
thrownewTypeError('Each query pair must be a name/value tuple');
651+
}
652+
this[searchParams].push(String(pair[0]),String(pair[1]));
653+
}
654+
}else{
655+
// record<USVString, USVString>
656+
this[searchParams]=[];
657+
for(constkeyofObject.keys(init)){
658+
constvalue=String(init[key]);
659+
this[searchParams].push(key,value);
660+
}
661+
}
621662
}else{
663+
// USVString
622664
init=String(init);
623665
if(init[0]==='?')init=init.slice(1);
624666
initSearchParams(this,init);

‎test/parallel/test-whatwg-url-searchparams-constructor.js‎

Lines changed: 50 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ const common = require('../common');
44
constassert=require('assert');
55
constURLSearchParams=require('url').URLSearchParams;
66
const{
7-
test, assert_equals, assert_true, assert_false
7+
test, assert_equals, assert_true,
8+
assert_false, assert_throws, assert_array_equals
89
}=common.WPT;
910

1011
/* eslint-disable */
@@ -40,10 +41,10 @@ test(() =>{
4041
assert_equals(params.__proto__,URLSearchParams.prototype,'expected URLSearchParams.prototype as prototype.');
4142
},"URLSearchParams constructor, empty string as argument")
4243

43-
// test(() =>{
44-
// params = new URLSearchParams({});
45-
// assert_equals(params + '', "");
46-
// }, 'URLSearchParams constructor,{} as argument');
44+
test(()=>{
45+
params=newURLSearchParams({});
46+
assert_equals(params+'',"");
47+
},'URLSearchParams constructor,{} as argument');
4748

4849
test(function(){
4950
varparams=newURLSearchParams('a=b');
@@ -142,39 +143,39 @@ test(function(){
142143
assert_equals(params.get('a\uD83D\uDCA9b'),'c');
143144
},'Parse %f0%9f%92%a9');// Unicode Character 'PILE OF POO' (U+1F4A9)
144145

145-
// test(function(){
146-
// var params = new URLSearchParams([]);
147-
// assert_true(params != null, 'constructor returned non-null value.');
148-
// params = new URLSearchParams([['a', 'b'], ['c', 'd']]);
149-
// assert_equals(params.get("a"), "b");
150-
// assert_equals(params.get("c"), "d");
151-
// assert_throws(new TypeError(), function(){new URLSearchParams([[1]])});
152-
// assert_throws(new TypeError(), function(){new URLSearchParams([[1,2,3]])});
153-
// }, "Constructor with sequence of sequences of strings");
154-
155-
// [
146+
test(function(){
147+
varparams=newURLSearchParams([]);
148+
assert_true(params!=null,'constructor returned non-null value.');
149+
params=newURLSearchParams([['a','b'],['c','d']]);
150+
assert_equals(params.get("a"),"b");
151+
assert_equals(params.get("c"),"d");
152+
assert_throws(newTypeError(),function(){newURLSearchParams([[1]]);});
153+
assert_throws(newTypeError(),function(){newURLSearchParams([[1,2,3]]);});
154+
},"Constructor with sequence of sequences of strings");
155+
156+
[
156157
//{"input":{"+": "%C2"}, "output": [[" ", "\uFFFD"]], "name": "object with +" },
157-
// {"input":{c: "x", a: "?"}, "output": [["c", "x"], ["a", "?"]], "name": "object with two keys" },
158-
// {"input": [["c", "x"], ["a", "?"]], "output": [["c", "x"], ["a", "?"]], "name": "array with two keys" }
159-
// ].forEach((val) =>{
160-
// test(() =>{
161-
// let params = new URLSearchParams(val.input),
162-
// i = 0
163-
// for (let param of params){
164-
// assert_array_equals(param, val.output[i])
165-
// i++
166-
// }
167-
// }, "Construct with " + val.name)
168-
// })
158+
{"input": {c: "x",a: "?"},"output": [["c","x"],["a","?"]],"name": "object with two keys"},
159+
{"input": [["c","x"],["a","?"]],"output": [["c","x"],["a","?"]],"name": "array with two keys"}
160+
].forEach((val)=>{
161+
test(()=>{
162+
letparams=newURLSearchParams(val.input),
163+
i=0
164+
for(letparamofparams){
165+
assert_array_equals(param,val.output[i])
166+
i++
167+
}
168+
},"Construct with "+val.name)
169+
})
169170

170-
// test(() =>{
171-
// params = new URLSearchParams()
172-
// params[Symbol.iterator] = function *(){
173-
// yield ["a", "b"]
174-
// }
175-
// let params2 = new URLSearchParams(params)
176-
// assert_equals(params2.get("a"), "b")
177-
// }, "Custom [Symbol.iterator]")
171+
test(()=>{
172+
params=newURLSearchParams()
173+
params[Symbol.iterator]=function*(){
174+
yield["a","b"]
175+
}
176+
letparams2=newURLSearchParams(params)
177+
assert_equals(params2.get("a"),"b")
178+
},"Custom [Symbol.iterator]")
178179
/* eslint-enable */
179180

180181
// Tests below are not from WPT.
@@ -192,5 +193,17 @@ test(function(){
192193
params=newURLSearchParams(undefined);
193194
assert.strictEqual(params.toString(),'');
194195
params=newURLSearchParams(null);
195-
assert.strictEqual(params.toString(),'null=');
196+
assert.strictEqual(params.toString(),'');
197+
assert.throws(()=>newURLSearchParams([[1]]),
198+
/^TypeError:Eachquerypairmustbeaname\/valuetuple$/);
199+
assert.throws(()=>newURLSearchParams([[1,2,3]]),
200+
/^TypeError:Eachquerypairmustbeaname\/valuetuple$/);
201+
assert.throws(()=>newURLSearchParams({[Symbol.iterator]: 42}),
202+
/^TypeError:Querypairsmustbeiterable$/);
203+
assert.throws(()=>newURLSearchParams([{}]),
204+
/^TypeError:Eachquerypairmustbeiterable$/);
205+
assert.throws(()=>newURLSearchParams(['a']),
206+
/^TypeError:Eachquerypairmustbeiterable$/);
207+
assert.throws(()=>newURLSearchParams([{[Symbol.iterator]: 42}]),
208+
/^TypeError:Eachquerypairmustbeiterable$/);
196209
}

0 commit comments

Comments
(0)