Skip to content

Commit 315c3aa

Browse files
TimothyGujasnell
authored andcommitted
url: more precise URLSearchParams constructor
PR-URL: #13026 Ref: web-platform-tests/wpt#5813 Reviewed-By: Daijiro Wachi <[email protected]> Reviewed-By: Joyee Cheung <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent b3c9bff commit 315c3aa

File tree

2 files changed

+58
-30
lines changed

2 files changed

+58
-30
lines changed

‎lib/internal/url.js‎

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -814,7 +814,8 @@ class URLSearchParams{
814814
constructor(init=undefined){
815815
if(init===null||init===undefined){
816816
this[searchParams]=[];
817-
}elseif(typeofinit==='object'){
817+
}elseif((typeofinit==='object'&&init!==null)||
818+
typeofinit==='function'){
818819
constmethod=init[Symbol.iterator];
819820
if(method===this[Symbol.iterator]){
820821
// While the spec does not have this branch, we can use it as a
@@ -830,12 +831,16 @@ class URLSearchParams{
830831
// Note: per spec we have to first exhaust the lists then process them
831832
constpairs=[];
832833
for(constpairofinit){
833-
if(typeofpair!=='object'||
834+
if((typeofpair!=='object'&&typeofpair!=='function')||
835+
pair===null||
834836
typeofpair[Symbol.iterator]!=='function'){
835837
thrownewerrors.TypeError('ERR_INVALID_TUPLE','Each query pair',
836838
'[name, value]');
837839
}
838-
pairs.push(Array.from(pair));
840+
constconvertedPair=[];
841+
for(constelementofpair)
842+
convertedPair.push(toUSVString(element));
843+
pairs.push(convertedPair);
839844
}
840845

841846
this[searchParams]=[];
@@ -844,17 +849,21 @@ class URLSearchParams{
844849
thrownewerrors.TypeError('ERR_INVALID_TUPLE','Each query pair',
845850
'[name, value]');
846851
}
847-
constkey=toUSVString(pair[0]);
848-
constvalue=toUSVString(pair[1]);
849-
this[searchParams].push(key,value);
852+
this[searchParams].push(pair[0],pair[1]);
850853
}
851854
}else{
852855
// record<USVString, USVString>
856+
// Need to use reflection APIs for full spec compliance.
853857
this[searchParams]=[];
854-
for(varkeyofObject.keys(init)){
855-
key=toUSVString(key);
856-
constvalue=toUSVString(init[key]);
857-
this[searchParams].push(key,value);
858+
constkeys=Reflect.ownKeys(init);
859+
for(vari=0;i<keys.length;i++){
860+
constkey=keys[i];
861+
constdesc=Reflect.getOwnPropertyDescriptor(init,key);
862+
if(desc!==undefined&&desc.enumerable){
863+
consttypedKey=toUSVString(key);
864+
consttypedValue=toUSVString(init[key]);
865+
this[searchParams].push(typedKey,typedValue);
866+
}
858867
}
859868
}
860869
}else{

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

Lines changed: 39 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const{
1111
/* eslint-disable */
1212
varparams;// Strict mode fix for WPT.
1313
/* WPT Refs:
14-
https://github.com/w3c/web-platform-tests/blob/e94c604916/url/urlsearchparams-constructor.html
14+
https://github.com/w3c/web-platform-tests/blob/54c3502d7b/url/urlsearchparams-constructor.html
1515
License: http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html
1616
*/
1717
test(function(){
@@ -87,6 +87,17 @@ test(function(){
8787
assert_equals(params.get('a b'),'c');
8888
},'Parse +');
8989

90+
test(function(){
91+
consttestValue='+15555555555';
92+
constparams=newURLSearchParams();
93+
params.set('query',testValue);
94+
varnewParams=newURLSearchParams(params.toString());
95+
96+
assert_equals(params.toString(),'query=%2B15555555555');
97+
assert_equals(params.get('query'),testValue);
98+
assert_equals(newParams.get('query'),testValue);
99+
},'Parse encoded +');
100+
90101
test(function(){
91102
varparams=newURLSearchParams('a=b c');
92103
assert_equals(params.get('a'),'b c');
@@ -156,7 +167,8 @@ test(function(){
156167
[
157168
{"input": {"+": "%C2"},"output": [["+","%C2"]],"name": "object with +"},
158169
{"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"}
170+
{"input": [["c","x"],["a","?"]],"output": [["c","x"],["a","?"]],"name": "array with two keys"},
171+
{"input": {"a\0b": "42","c\uD83D": "23","d\u1234": "foo"},"output": [["a\0b","42"],["c\uFFFD","23"],["d\u1234","foo"]],"name": "object with NULL, non-ASCII, and surrogate keys"}
160172
].forEach((val)=>{
161173
test(()=>{
162174
letparams=newURLSearchParams(val.input),
@@ -179,12 +191,12 @@ test(() =>{
179191
/* eslint-enable */
180192

181193
// Tests below are not from WPT.
182-
{
183-
// assert.throws(() =>{
184-
// new URLSearchParams({
185-
// toString(){throw new TypeError('Illegal invocation')}
186-
// });
187-
// }, TypeError);
194+
functionmakeIterableFunc(array){
195+
returnObject.assign(()=>{},{
196+
[Symbol.iterator](){
197+
returnarray[Symbol.iterator]();
198+
}
199+
});
188200
}
189201

190202
{
@@ -200,17 +212,25 @@ test(() =>{
200212
});
201213

202214
letparams;
203-
// URLSearchParams constructor, undefined and null as argument
204215
params=newURLSearchParams(undefined);
205216
assert.strictEqual(params.toString(),'');
206217
params=newURLSearchParams(null);
207218
assert.strictEqual(params.toString(),'');
219+
params=newURLSearchParams(
220+
makeIterableFunc([['key','val'],['key2','val2']])
221+
);
222+
assert.strictEqual(params.toString(),'key=val&key2=val2');
223+
params=newURLSearchParams(
224+
makeIterableFunc([['key','val'],['key2','val2']].map(makeIterableFunc))
225+
);
226+
assert.strictEqual(params.toString(),'key=val&key2=val2');
208227
assert.throws(()=>newURLSearchParams([[1]]),tupleError);
209228
assert.throws(()=>newURLSearchParams([[1,2,3]]),tupleError);
210229
assert.throws(()=>newURLSearchParams({[Symbol.iterator]: 42}),
211230
iterableError);
212231
assert.throws(()=>newURLSearchParams([{}]),tupleError);
213232
assert.throws(()=>newURLSearchParams(['a']),tupleError);
233+
assert.throws(()=>newURLSearchParams([null]),tupleError);
214234
assert.throws(()=>newURLSearchParams([{[Symbol.iterator]: 42}]),
215235
tupleError);
216236
}
@@ -221,15 +241,14 @@ test(() =>{
221241
valueOf(){thrownewError('valueOf');}
222242
};
223243
constsym=Symbol();
224-
225-
assert.throws(()=>newURLSearchParams({a: obj}),/^Error:toString$/);
226-
assert.throws(()=>newURLSearchParams([['a',obj]]),/^Error:toString$/);
227-
assert.throws(()=>newURLSearchParams(sym),
228-
/^TypeError:CannotconvertaSymbolvaluetoastring$/);
229-
assert.throws(()=>newURLSearchParams({a: sym}),
230-
/^TypeError:CannotconvertaSymbolvaluetoastring$/);
231-
assert.throws(()=>newURLSearchParams([[sym,'a']]),
232-
/^TypeError:CannotconvertaSymbolvaluetoastring$/);
233-
assert.throws(()=>newURLSearchParams([['a',sym]]),
234-
/^TypeError:CannotconvertaSymbolvaluetoastring$/);
244+
consttoStringError=/^Error:toString$/;
245+
constsymbolError=/^TypeError:CannotconvertaSymbolvaluetoastring$/;
246+
247+
assert.throws(()=>newURLSearchParams({a: obj}),toStringError);
248+
assert.throws(()=>newURLSearchParams([['a',obj]]),toStringError);
249+
assert.throws(()=>newURLSearchParams(sym),symbolError);
250+
assert.throws(()=>newURLSearchParams({[sym]: 'a'}),symbolError);
251+
assert.throws(()=>newURLSearchParams({a: sym}),symbolError);
252+
assert.throws(()=>newURLSearchParams([[sym,'a']]),symbolError);
253+
assert.throws(()=>newURLSearchParams([['a',sym]]),symbolError);
235254
}

0 commit comments

Comments
(0)