url: add urlSearchParams.sort()
PR-URL: https://github.com/nodejs/node/pull/11098 Fixes: https://github.com/nodejs/node/issues/10760 Ref: https://github.com/whatwg/url/issues/26 Ref: https://github.com/whatwg/url/pull/199 Ref: https://github.com/w3c/web-platform-tests/pull/4531 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
This commit is contained in:
parent
a2fac322d5
commit
02d1e32fe3
@ -777,6 +777,21 @@ Returns an ES6 Iterator over the names of each name-value pair.
|
|||||||
Remove any existing name-value pairs whose name is `name` and append a new
|
Remove any existing name-value pairs whose name is `name` and append a new
|
||||||
name-value pair.
|
name-value pair.
|
||||||
|
|
||||||
|
#### urlSearchParams.sort()
|
||||||
|
|
||||||
|
Sort all existing name-value pairs in-place by their names. Sorting is done
|
||||||
|
with a [stable sorting algorithm][], so relative order between name-value pairs
|
||||||
|
with the same name is preserved.
|
||||||
|
|
||||||
|
This method can be used, in particular, to increase cache hits.
|
||||||
|
|
||||||
|
```js
|
||||||
|
const params = new URLSearchParams('query[]=abc&type=search&query[]=123');
|
||||||
|
params.sort();
|
||||||
|
console.log(params.toString());
|
||||||
|
// Prints query%5B%5D=abc&query%5B%5D=123&type=search
|
||||||
|
```
|
||||||
|
|
||||||
#### urlSearchParams.toString()
|
#### urlSearchParams.toString()
|
||||||
|
|
||||||
* Returns: {String}
|
* Returns: {String}
|
||||||
@ -872,3 +887,4 @@ console.log(myURL.origin);
|
|||||||
[`Map`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map
|
[`Map`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map
|
||||||
[`array.toString()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/toString
|
[`array.toString()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/toString
|
||||||
[WHATWG URL]: #url_the_whatwg_url_api
|
[WHATWG URL]: #url_the_whatwg_url_api
|
||||||
|
[stable sorting algorithm]: https://en.wikipedia.org/wiki/Sorting_algorithm#Stability
|
||||||
|
@ -766,6 +766,35 @@ class URLSearchParams {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// for merge sort
|
||||||
|
function merge(out, start, mid, end, lBuffer, rBuffer) {
|
||||||
|
const sizeLeft = mid - start;
|
||||||
|
const sizeRight = end - mid;
|
||||||
|
var l, r, o;
|
||||||
|
|
||||||
|
for (l = 0; l < sizeLeft; l++)
|
||||||
|
lBuffer[l] = out[start + l];
|
||||||
|
for (r = 0; r < sizeRight; r++)
|
||||||
|
rBuffer[r] = out[mid + r];
|
||||||
|
|
||||||
|
l = 0;
|
||||||
|
r = 0;
|
||||||
|
o = start;
|
||||||
|
while (l < sizeLeft && r < sizeRight) {
|
||||||
|
if (lBuffer[l] <= rBuffer[r]) {
|
||||||
|
out[o++] = lBuffer[l++];
|
||||||
|
out[o++] = lBuffer[l++];
|
||||||
|
} else {
|
||||||
|
out[o++] = rBuffer[r++];
|
||||||
|
out[o++] = rBuffer[r++];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (l < sizeLeft)
|
||||||
|
out[o++] = lBuffer[l++];
|
||||||
|
while (r < sizeRight)
|
||||||
|
out[o++] = rBuffer[r++];
|
||||||
|
}
|
||||||
|
|
||||||
defineIDLClass(URLSearchParams.prototype, 'URLSearchParams', {
|
defineIDLClass(URLSearchParams.prototype, 'URLSearchParams', {
|
||||||
append(name, value) {
|
append(name, value) {
|
||||||
if (!this || !(this instanceof URLSearchParams)) {
|
if (!this || !(this instanceof URLSearchParams)) {
|
||||||
@ -897,6 +926,51 @@ defineIDLClass(URLSearchParams.prototype, 'URLSearchParams', {
|
|||||||
update(this[context], this);
|
update(this[context], this);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
sort() {
|
||||||
|
const a = this[searchParams];
|
||||||
|
const len = a.length;
|
||||||
|
if (len <= 2) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// arbitrary number found through testing
|
||||||
|
if (len < 100) {
|
||||||
|
// Simple stable in-place insertion sort
|
||||||
|
// Derived from v8/src/js/array.js
|
||||||
|
for (var i = 2; i < len; i += 2) {
|
||||||
|
var curKey = a[i];
|
||||||
|
var curVal = a[i + 1];
|
||||||
|
var j;
|
||||||
|
for (j = i - 2; j >= 0; j -= 2) {
|
||||||
|
if (a[j] > curKey) {
|
||||||
|
a[j + 2] = a[j];
|
||||||
|
a[j + 3] = a[j + 1];
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
a[j + 2] = curKey;
|
||||||
|
a[j + 3] = curVal;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Bottom-up iterative stable merge sort
|
||||||
|
const lBuffer = new Array(len);
|
||||||
|
const rBuffer = new Array(len);
|
||||||
|
for (var step = 2; step < len; step *= 2) {
|
||||||
|
for (var start = 0; start < len - 2; start += 2 * step) {
|
||||||
|
var mid = start + step;
|
||||||
|
var end = mid + step;
|
||||||
|
end = end < len ? end : len;
|
||||||
|
if (mid > end)
|
||||||
|
continue;
|
||||||
|
merge(a, start, mid, end, lBuffer, rBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
update(this[context], this);
|
||||||
|
},
|
||||||
|
|
||||||
// https://heycam.github.io/webidl/#es-iterators
|
// https://heycam.github.io/webidl/#es-iterators
|
||||||
// Define entries here rather than [Symbol.iterator] as the function name
|
// Define entries here rather than [Symbol.iterator] as the function name
|
||||||
// must be set to `entries`.
|
// must be set to `entries`.
|
||||||
|
84
test/parallel/test-whatwg-url-searchparams-sort.js
Normal file
84
test/parallel/test-whatwg-url-searchparams-sort.js
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const common = require('../common');
|
||||||
|
const { URL, URLSearchParams } = require('url');
|
||||||
|
const { test, assert_array_equals } = common.WPT;
|
||||||
|
|
||||||
|
/* eslint-disable */
|
||||||
|
/* WPT Refs:
|
||||||
|
https://github.com/w3c/web-platform-tests/blob/5903e00e77e85f8bcb21c73d1d7819fcd04763bd/url/urlsearchparams-sort.html
|
||||||
|
License: http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html
|
||||||
|
*/
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"input": "z=b&a=b&z=a&a=a",
|
||||||
|
"output": [["a", "b"], ["a", "a"], ["z", "b"], ["z", "a"]]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "\uFFFD=x&\uFFFC&\uFFFD=a",
|
||||||
|
"output": [["\uFFFC", ""], ["\uFFFD", "x"], ["\uFFFD", "a"]]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "ffi&🌈", // 🌈 > code point, but < code unit because two code units
|
||||||
|
"output": [["🌈", ""], ["ffi", ""]]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "é&e\uFFFD&e\u0301",
|
||||||
|
"output": [["e\u0301", ""], ["e\uFFFD", ""], ["é", ""]]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "z=z&a=a&z=y&a=b&z=x&a=c&z=w&a=d&z=v&a=e&z=u&a=f&z=t&a=g",
|
||||||
|
"output": [["a", "a"], ["a", "b"], ["a", "c"], ["a", "d"], ["a", "e"], ["a", "f"], ["a", "g"], ["z", "z"], ["z", "y"], ["z", "x"], ["z", "w"], ["z", "v"], ["z", "u"], ["z", "t"]]
|
||||||
|
}
|
||||||
|
].forEach((val) => {
|
||||||
|
test(() => {
|
||||||
|
let params = new URLSearchParams(val.input),
|
||||||
|
i = 0
|
||||||
|
params.sort()
|
||||||
|
for(let param of params) {
|
||||||
|
assert_array_equals(param, val.output[i])
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}, "Parse and sort: " + val.input)
|
||||||
|
|
||||||
|
test(() => {
|
||||||
|
let url = new URL("?" + val.input, "https://example/")
|
||||||
|
url.searchParams.sort()
|
||||||
|
let params = new URLSearchParams(url.search),
|
||||||
|
i = 0
|
||||||
|
for(let param of params) {
|
||||||
|
assert_array_equals(param, val.output[i])
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}, "URL parse and sort: " + val.input)
|
||||||
|
})
|
||||||
|
/* eslint-enable */
|
||||||
|
|
||||||
|
// Tests below are not from WPT.
|
||||||
|
;[
|
||||||
|
{
|
||||||
|
'input': 'z=a&=b&c=d',
|
||||||
|
'output': [['', 'b'], ['c', 'd'], ['z', 'a']]
|
||||||
|
}
|
||||||
|
].forEach((val) => {
|
||||||
|
test(() => {
|
||||||
|
const params = new URLSearchParams(val.input);
|
||||||
|
let i = 0;
|
||||||
|
params.sort();
|
||||||
|
for (const param of params) {
|
||||||
|
assert_array_equals(param, val.output[i]);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}, 'Parse and sort: ' + val.input);
|
||||||
|
|
||||||
|
test(() => {
|
||||||
|
const url = new URL(`?${val.input}`, 'https://example/');
|
||||||
|
url.searchParams.sort();
|
||||||
|
const params = new URLSearchParams(url.search);
|
||||||
|
let i = 0;
|
||||||
|
for (const param of params) {
|
||||||
|
assert_array_equals(param, val.output[i]);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}, 'URL parse and sort: ' + val.input);
|
||||||
|
});
|
Loading…
x
Reference in New Issue
Block a user