From 2f0c87ff684f1c4f197b35c29b1cd7c7ef65cc9d Mon Sep 17 00:00:00 2001 From: Denis Pushkarev Date: Tue, 24 Jan 2023 13:07:53 +0700 Subject: [PATCH] add `URLSearchParams.prototype.size` --- CHANGELOG.md | 1 + ORIGINAL_README.md | 7 +++++-- packages/core-js-compat/src/data.mjs | 2 ++ .../src/modules-by-versions.mjs | 1 + .../modules/web.url-search-params.size.js | 1 + .../internals/url-constructor-detection.js | 2 ++ .../web.url-search-params.constructor.js | 17 ++++++++++++++- .../modules/web.url-search-params.size.js | 21 +++++++++++++++++++ packages/core-js/proposals/url.js | 1 + packages/core-js/web/index.js | 1 + packages/core-js/web/url-search-params.js | 1 + packages/core-js/web/url.js | 1 + tests/compat/tests.js | 5 ++++- tests/unit-global/web.url-search-params.js | 19 +++++++++++++++++ tests/unit-pure/web.url-search-params.js | 17 +++++++++++++++ 15 files changed, 93 insertions(+), 4 deletions(-) create mode 100644 packages/core-js-pure/override/modules/web.url-search-params.size.js create mode 100644 packages/core-js/modules/web.url-search-params.size.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 10832be9537f..ab7b53bee88d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ ## Changelog ##### Unreleased +- Added `URLSearchParams.prototype.size` getter, [url/734](https://github.com/whatwg/url/pull/734) - Allowed cloning resizable `ArrayBuffer`s in the `structuredClone` polyfill - Fixed wrong export in `/(stable|actual|full)/instance/unshift` entries, [#1207](https://github.com/zloirock/core-js/issues/1207) - Compat data improvements: diff --git a/ORIGINAL_README.md b/ORIGINAL_README.md index 1a7af9bd2c60..5ea061c94007 100644 --- a/ORIGINAL_README.md +++ b/ORIGINAL_README.md @@ -3213,7 +3213,7 @@ queueMicrotask(() => console.log('called as microtask')); ``` #### `URL` and `URLSearchParams`[⬆](#index) -[`URL` standard](https://url.spec.whatwg.org/) implementation. Modules [`web.url`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/web.url.js), [`web.url.to-json`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/web.url.to-json.js), [`web.url-search-params`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/web.url-search-params.js). +[`URL` standard](https://url.spec.whatwg.org/) implementation. Modules [`web.url`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/web.url.js), [`web.url.to-json`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/web.url.to-json.js), [`web.url-search-params`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/web.url-search-params.js), [`web.url-search-params.size`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/web.url-search-params.size.js). ```js class URL { constructor(url: string, base?: string); @@ -3248,6 +3248,7 @@ class URLSearchParams { keys(): Iterator; values(): Iterator; @@iterator(): Iterator<[key, value]>; + readonly attribute size: number; } ``` [*CommonJS entry points:*](#commonjs-api) @@ -3257,7 +3258,7 @@ core-js(-pure)/stable|actual|full/url core-js/stable|actual|full/url/to-json core-js(-pure)/stable|actual|full/url-search-params ``` -[*Examples*](https://is.gd/AfIwve): +[*Examples*](https://tinyurl.com/2fccy7sb): ```js const url = new URL('https://login:password@example.com:8080/foo/bar?a=1&b=2&a=3#fragment'); @@ -3292,6 +3293,8 @@ params.append('c', 4); params.append('a', 2); params.sort(); +console.log(params.size); // => 5 + for (let [key, value] of params) { console.log(key); // => 'a', 'a', 'a', 'b', 'c' console.log(value); // => '1', '3', '2', '2', '4' diff --git a/packages/core-js-compat/src/data.mjs b/packages/core-js-compat/src/data.mjs index 0805f844f671..3fa6f29d145c 100644 --- a/packages/core-js-compat/src/data.mjs +++ b/packages/core-js-compat/src/data.mjs @@ -2466,6 +2466,8 @@ export const data = { node: '10.0', safari: '14.0', }, + 'web.url-search-params.size': { + }, }; export const renamed = new Map([ diff --git a/packages/core-js-compat/src/modules-by-versions.mjs b/packages/core-js-compat/src/modules-by-versions.mjs index 73dbf0fac2dd..d855020e77fe 100644 --- a/packages/core-js-compat/src/modules-by-versions.mjs +++ b/packages/core-js-compat/src/modules-by-versions.mjs @@ -195,5 +195,6 @@ export default { 'esnext.json.raw-json', 'esnext.symbol.is-registered', 'esnext.symbol.is-well-known', + 'web.url-search-params.size', ], }; diff --git a/packages/core-js-pure/override/modules/web.url-search-params.size.js b/packages/core-js-pure/override/modules/web.url-search-params.size.js new file mode 100644 index 000000000000..8b1a393741c9 --- /dev/null +++ b/packages/core-js-pure/override/modules/web.url-search-params.size.js @@ -0,0 +1 @@ +// empty diff --git a/packages/core-js/internals/url-constructor-detection.js b/packages/core-js/internals/url-constructor-detection.js index 8435fff5ffdd..d9dade4b2c22 100644 --- a/packages/core-js/internals/url-constructor-detection.js +++ b/packages/core-js/internals/url-constructor-detection.js @@ -1,5 +1,6 @@ var fails = require('../internals/fails'); var wellKnownSymbol = require('../internals/well-known-symbol'); +var DESCRIPTORS = require('../internals/descriptors'); var IS_PURE = require('../internals/is-pure'); var ITERATOR = wellKnownSymbol('iterator'); @@ -15,6 +16,7 @@ module.exports = !fails(function () { result += key + value; }); return (IS_PURE && !url.toJSON) + || (!searchParams.size && (IS_PURE || !DESCRIPTORS)) || !searchParams.sort || url.href !== 'http://a/c%20d?a=1&c=3' || searchParams.get('c') !== '3' diff --git a/packages/core-js/modules/web.url-search-params.constructor.js b/packages/core-js/modules/web.url-search-params.constructor.js index be5a155b55ab..fe05a05b71d4 100644 --- a/packages/core-js/modules/web.url-search-params.constructor.js +++ b/packages/core-js/modules/web.url-search-params.constructor.js @@ -8,6 +8,7 @@ var uncurryThis = require('../internals/function-uncurry-this'); var DESCRIPTORS = require('../internals/descriptors'); var USE_NATIVE_URL = require('../internals/url-constructor-detection'); var defineBuiltIn = require('../internals/define-built-in'); +var defineBuiltInAccessor = require('../internals/define-built-in-accessor'); var defineBuiltIns = require('../internals/define-built-ins'); var setToStringTag = require('../internals/set-to-string-tag'); var createIteratorConstructor = require('../internals/iterator-create-constructor'); @@ -203,7 +204,8 @@ URLSearchParamsState.prototype = { var URLSearchParamsConstructor = function URLSearchParams(/* init */) { anInstance(this, URLSearchParamsPrototype); var init = arguments.length > 0 ? arguments[0] : undefined; - setInternalState(this, new URLSearchParamsState(init)); + var state = setInternalState(this, new URLSearchParamsState(init)); + if (!DESCRIPTORS) this.length = state.entries.length; }; var URLSearchParamsPrototype = URLSearchParamsConstructor.prototype; @@ -215,6 +217,7 @@ defineBuiltIns(URLSearchParamsPrototype, { validateArgumentsLength(arguments.length, 2); var state = getInternalParamsState(this); push(state.entries, { key: $toString(name), value: $toString(value) }); + if (!DESCRIPTORS) this.length++; state.updateURL(); }, // `URLSearchParams.prototype.delete` method @@ -229,6 +232,7 @@ defineBuiltIns(URLSearchParamsPrototype, { if (entries[index].key === key) splice(entries, index, 1); else index++; } + if (!DESCRIPTORS) this.length = entries.length; state.updateURL(); }, // `URLSearchParams.prototype.get` method @@ -290,6 +294,7 @@ defineBuiltIns(URLSearchParamsPrototype, { } } if (!found) push(entries, { key: key, value: val }); + if (!DESCRIPTORS) this.length = entries.length; state.updateURL(); }, // `URLSearchParams.prototype.sort` method @@ -335,6 +340,16 @@ defineBuiltIn(URLSearchParamsPrototype, 'toString', function toString() { return getInternalParamsState(this).serialize(); }, { enumerable: true }); +// `URLSearchParams.prototype.size` getter +// https://github.com/whatwg/url/pull/734 +if (DESCRIPTORS) defineBuiltInAccessor(URLSearchParamsPrototype, 'size', { + get: function size() { + return getInternalParamsState(this).entries.length; + }, + configurable: true, + enumerable: true +}); + setToStringTag(URLSearchParamsConstructor, URL_SEARCH_PARAMS); $({ global: true, constructor: true, forced: !USE_NATIVE_URL }, { diff --git a/packages/core-js/modules/web.url-search-params.size.js b/packages/core-js/modules/web.url-search-params.size.js new file mode 100644 index 000000000000..65ab25dea8af --- /dev/null +++ b/packages/core-js/modules/web.url-search-params.size.js @@ -0,0 +1,21 @@ +'use strict'; +var DESCRIPTORS = require('../internals/descriptors'); +var uncurryThis = require('../internals/function-uncurry-this'); +var defineBuiltInAccessor = require('../internals/define-built-in-accessor'); + +var URLSearchParamsPrototype = URLSearchParams.prototype; +var forEach = uncurryThis(URLSearchParamsPrototype.forEach); + +// `URLSearchParams.prototype.size` getter +// https://github.com/whatwg/url/pull/734 +if (DESCRIPTORS && !('size' in URLSearchParamsPrototype)) { + defineBuiltInAccessor(URLSearchParamsPrototype, 'size', { + get: function size() { + var count = 0; + forEach(this, function () { count++; }); + return count; + }, + configurable: true, + enumerable: true + }); +} diff --git a/packages/core-js/proposals/url.js b/packages/core-js/proposals/url.js index 83d7df8cd429..7591928fce9f 100644 --- a/packages/core-js/proposals/url.js +++ b/packages/core-js/proposals/url.js @@ -2,3 +2,4 @@ require('../modules/web.url'); require('../modules/web.url.to-json'); require('../modules/web.url-search-params'); +require('../modules/web.url-search-params.size'); diff --git a/packages/core-js/web/index.js b/packages/core-js/web/index.js index 78cf6b984a9e..3f490d4eb05b 100644 --- a/packages/core-js/web/index.js +++ b/packages/core-js/web/index.js @@ -13,6 +13,7 @@ require('../modules/web.timers'); require('../modules/web.url'); require('../modules/web.url.to-json'); require('../modules/web.url-search-params'); +require('../modules/web.url-search-params.size'); var path = require('../internals/path'); module.exports = path; diff --git a/packages/core-js/web/url-search-params.js b/packages/core-js/web/url-search-params.js index 9434608bbbd8..427ccc4a6aa4 100644 --- a/packages/core-js/web/url-search-params.js +++ b/packages/core-js/web/url-search-params.js @@ -1,4 +1,5 @@ require('../modules/web.url-search-params'); +require('../modules/web.url-search-params.size'); var path = require('../internals/path'); module.exports = path.URLSearchParams; diff --git a/packages/core-js/web/url.js b/packages/core-js/web/url.js index 2faed2eddc1b..8a17e4847bc7 100644 --- a/packages/core-js/web/url.js +++ b/packages/core-js/web/url.js @@ -1,6 +1,7 @@ require('../modules/web.url'); require('../modules/web.url.to-json'); require('../modules/web.url-search-params'); +require('../modules/web.url-search-params.size'); var path = require('../internals/path'); module.exports = path.URL; diff --git a/tests/compat/tests.js b/tests/compat/tests.js index 0d5206b25730..effebb5ccb56 100644 --- a/tests/compat/tests.js +++ b/tests/compat/tests.js @@ -1945,5 +1945,8 @@ GLOBAL.tests = { 'web.url.to-json': [URL_AND_URL_SEARCH_PARAMS_SUPPORT, function () { return URL.prototype.toJSON; }], - 'web.url-search-params.constructor': URL_AND_URL_SEARCH_PARAMS_SUPPORT + 'web.url-search-params.constructor': URL_AND_URL_SEARCH_PARAMS_SUPPORT, + 'web.url-search-params.size': [URL_AND_URL_SEARCH_PARAMS_SUPPORT, function () { + return 'size' in URLSearchParams.prototype; + }] }; diff --git a/tests/unit-global/web.url-search-params.js b/tests/unit-global/web.url-search-params.js index 9f3887e79cf5..f300f6b4f767 100644 --- a/tests/unit-global/web.url-search-params.js +++ b/tests/unit-global/web.url-search-params.js @@ -850,6 +850,25 @@ QUnit.test('URLSearchParams#@@iterator', assert => { if (DESCRIPTORS) assert.true(getOwnPropertyDescriptor(getPrototypeOf(new URLSearchParams()[Symbol.iterator]()), 'next').enumerable, 'enumerable .next'); }); +QUnit.test('URLSearchParams#size', assert => { + const params = new URLSearchParams('a=1&b=2&b=3'); + assert.true('size' in params); + assert.same(params.size, 3); + + if (DESCRIPTORS) { + assert.true('size' in URLSearchParams.prototype); + + const { enumerable, configurable, get } = getOwnPropertyDescriptor(URLSearchParams.prototype, 'size'); + + assert.true(enumerable, 'enumerable'); + assert.true(configurable, 'configurable'); + + if (!NODE) assert.looksNative(get); + + assert.throws(() => get.call([])); + } +}); + QUnit.test('URLSearchParams#@@toStringTag', assert => { const params = new URLSearchParams('a=b'); assert.same(({}).toString.call(params), '[object URLSearchParams]'); diff --git a/tests/unit-pure/web.url-search-params.js b/tests/unit-pure/web.url-search-params.js index e6c9cecfa67f..e6ee20b474a2 100644 --- a/tests/unit-pure/web.url-search-params.js +++ b/tests/unit-pure/web.url-search-params.js @@ -826,3 +826,20 @@ QUnit.test('URLSearchParams#@@iterator', assert => { if (DESCRIPTORS) assert.true(getOwnPropertyDescriptor(getPrototypeOf(new URLSearchParams()[Symbol.iterator]()), 'next').enumerable, 'enumerable .next'); }); + +QUnit.test('URLSearchParams#size', assert => { + const params = new URLSearchParams('a=1&b=2&b=3'); + assert.true('size' in params); + assert.same(params.size, 3); + + if (DESCRIPTORS) { + assert.true('size' in URLSearchParams.prototype); + + const { enumerable, configurable, get } = getOwnPropertyDescriptor(URLSearchParams.prototype, 'size'); + + assert.true(enumerable, 'enumerable'); + assert.true(configurable, 'configurable'); + + assert.throws(() => get.call([])); + } +});