From 32fcbab657eb923bfea13727e370c1f3a9d3704a Mon Sep 17 00:00:00 2001 From: Denis Pushkarev Date: Mon, 3 Apr 2023 18:14:23 +0700 Subject: [PATCH] add `URL.canParse` method https://url.spec.whatwg.org/#dom-url-canparse https://github.com/whatwg/url/pull/763 --- CHANGELOG.md | 1 + README.md | 9 +++++-- packages/core-js-compat/src/data.mjs | 2 ++ .../src/modules-by-versions.mjs | 3 +++ packages/core-js/actual/url/can-parse.js | 3 +++ packages/core-js/full/url/can-parse.js | 3 +++ packages/core-js/modules/web.url.can-parse.js | 21 ++++++++++++++++ packages/core-js/proposals/url.js | 1 + packages/core-js/stable/url/can-parse.js | 5 ++++ packages/core-js/web/index.js | 1 + packages/core-js/web/url.js | 1 + tests/compat/tests.js | 3 +++ tests/entries/unit.mjs | 1 + tests/unit-global/web.url.can-parse.js | 25 +++++++++++++++++++ tests/unit-pure/web.url.can-parse.js | 24 ++++++++++++++++++ 15 files changed, 101 insertions(+), 2 deletions(-) create mode 100644 packages/core-js/actual/url/can-parse.js create mode 100644 packages/core-js/full/url/can-parse.js create mode 100644 packages/core-js/modules/web.url.can-parse.js create mode 100644 packages/core-js/stable/url/can-parse.js create mode 100644 tests/unit-global/web.url.can-parse.js create mode 100644 tests/unit-pure/web.url.can-parse.js diff --git a/CHANGELOG.md b/CHANGELOG.md index a2afd769812c..8e88b91b5f81 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ ## Changelog ##### Unreleased +- Added [`URL.canParse` method](https://url.spec.whatwg.org/#dom-url-canparse), [url/763](https://github.com/whatwg/url/pull/763) - [`Set` methods proposal](https://github.com/tc39/proposal-set-methods): - Removed sort from `Set.prototype.intersection`, [March 2023 TC39 meeting](https://github.com/babel/proposals/issues/87#issuecomment-1478610425), [proposal-set-methods/94](https://github.com/tc39/proposal-set-methods/pull/94) - (Async) Iterator Helpers proposals ([sync](https://github.com/tc39/proposal-iterator-helpers), [async](https://github.com/tc39/proposal-async-iterator-helpers)): diff --git a/README.md b/README.md index 076ea5ba4fb6..4881319d6a94 100644 --- a/README.md +++ b/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), [`web.url-search-params.size`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/web.url-search-params.size.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.can-parse`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/web.url.can-parse.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); @@ -3231,6 +3231,7 @@ class URL { attribute hash: string; toJSON(): string; toString(): string; + static canParse(url: string, base?: string): boolean; } class URLSearchParams { @@ -3255,11 +3256,15 @@ class URLSearchParams { ```js core-js/proposals/url core-js(-pure)/stable|actual|full/url +core-js(-pure)/stable|actual|full/url/can-parse core-js/stable|actual|full/url/to-json core-js(-pure)/stable|actual|full/url-search-params ``` -[*Examples*](https://tinyurl.com/2fccy7sb): +[*Examples*](https://tinyurl.com/2ovt23zn): ```js +URL.canParse('https://login:password@example.com:8080/?a=1&b=2&a=3&c=4#fragment'); // => true +URL.canParse('https'); // => false + const url = new URL('https://login:password@example.com:8080/foo/bar?a=1&b=2&a=3#fragment'); console.log(url.href); // => 'https://login:password@example.com:8080/foo/bar?a=1&b=2&a=3#fragment' diff --git a/packages/core-js-compat/src/data.mjs b/packages/core-js-compat/src/data.mjs index becdd7d58582..da26ab0fe8e0 100644 --- a/packages/core-js-compat/src/data.mjs +++ b/packages/core-js-compat/src/data.mjs @@ -2456,6 +2456,8 @@ export const data = { node: '10.0', safari: '14.0', }, + 'web.url.can-parse': { + }, 'web.url.to-json': { bun: '0.1.1', chrome: '71', diff --git a/packages/core-js-compat/src/modules-by-versions.mjs b/packages/core-js-compat/src/modules-by-versions.mjs index 6656aabc67f6..1672e28c9382 100644 --- a/packages/core-js-compat/src/modules-by-versions.mjs +++ b/packages/core-js-compat/src/modules-by-versions.mjs @@ -199,4 +199,7 @@ export default { 3.29: [ 'web.url-search-params.size', ], + '3.30': [ + 'web.url.can-parse', + ], }; diff --git a/packages/core-js/actual/url/can-parse.js b/packages/core-js/actual/url/can-parse.js new file mode 100644 index 000000000000..844b9d5b0704 --- /dev/null +++ b/packages/core-js/actual/url/can-parse.js @@ -0,0 +1,3 @@ +var parent = require('../../stable/url/can-parse'); + +module.exports = parent; diff --git a/packages/core-js/full/url/can-parse.js b/packages/core-js/full/url/can-parse.js new file mode 100644 index 000000000000..67fc55ef491e --- /dev/null +++ b/packages/core-js/full/url/can-parse.js @@ -0,0 +1,3 @@ +var parent = require('../../actual/url/can-parse'); + +module.exports = parent; diff --git a/packages/core-js/modules/web.url.can-parse.js b/packages/core-js/modules/web.url.can-parse.js new file mode 100644 index 000000000000..5ccdf85ec2fd --- /dev/null +++ b/packages/core-js/modules/web.url.can-parse.js @@ -0,0 +1,21 @@ +var $ = require('../internals/export'); +var getBuiltIn = require('../internals/get-built-in'); +var validateArgumentsLength = require('../internals/validate-arguments-length'); +var toString = require('../internals/to-string'); + +var URL = getBuiltIn('URL'); + +// `URL.canParse` method +// https://url.spec.whatwg.org/#dom-url-canparse +$({ target: 'URL', stat: true }, { + canParse: function canParse(url) { + var length = validateArgumentsLength(arguments.length, 1); + var urlString = toString(url); + var base = length < 2 || arguments[1] === undefined ? undefined : toString(arguments[1]); + try { + return !!new URL(urlString, base); + } catch (error) { + return false; + } + } +}); diff --git a/packages/core-js/proposals/url.js b/packages/core-js/proposals/url.js index 7591928fce9f..9ec967cd119f 100644 --- a/packages/core-js/proposals/url.js +++ b/packages/core-js/proposals/url.js @@ -1,5 +1,6 @@ // https://github.com/jasnell/proposal-url require('../modules/web.url'); +require('../modules/web.url.can-parse'); 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/stable/url/can-parse.js b/packages/core-js/stable/url/can-parse.js new file mode 100644 index 000000000000..96a67da8ff7c --- /dev/null +++ b/packages/core-js/stable/url/can-parse.js @@ -0,0 +1,5 @@ +require('../../modules/web.url'); +require('../../modules/web.url.can-parse'); +var path = require('../../internals/path'); + +module.exports = path.URL.canParse; diff --git a/packages/core-js/web/index.js b/packages/core-js/web/index.js index 3f490d4eb05b..7c20cb74ce77 100644 --- a/packages/core-js/web/index.js +++ b/packages/core-js/web/index.js @@ -11,6 +11,7 @@ require('../modules/web.self'); require('../modules/web.structured-clone'); require('../modules/web.timers'); require('../modules/web.url'); +require('../modules/web.url.can-parse'); 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/url.js b/packages/core-js/web/url.js index 8a17e4847bc7..ea29f180b9b9 100644 --- a/packages/core-js/web/url.js +++ b/packages/core-js/web/url.js @@ -1,4 +1,5 @@ require('../modules/web.url'); +require('../modules/web.url.can-parse'); require('../modules/web.url.to-json'); require('../modules/web.url-search-params'); require('../modules/web.url-search-params.size'); diff --git a/tests/compat/tests.js b/tests/compat/tests.js index d4924a8f06f7..2c1facc541e7 100644 --- a/tests/compat/tests.js +++ b/tests/compat/tests.js @@ -1936,6 +1936,9 @@ GLOBAL.tests = { // TODO: Remove this module from `core-js@4` since it's split to submodules 'web.timers': TIMERS, 'web.url.constructor': URL_AND_URL_SEARCH_PARAMS_SUPPORT, + 'web.url.can-parse': [URL_AND_URL_SEARCH_PARAMS_SUPPORT, function () { + return URL.canParse; + }], 'web.url.to-json': [URL_AND_URL_SEARCH_PARAMS_SUPPORT, function () { return URL.prototype.toJSON; }], diff --git a/tests/entries/unit.mjs b/tests/entries/unit.mjs index 668b53d2ea02..b11826d9fecf 100644 --- a/tests/entries/unit.mjs +++ b/tests/entries/unit.mjs @@ -626,6 +626,7 @@ for (PATH of ['core-js-pure', 'core-js']) { ok(typeof load(NS, 'clear-immediate') == 'function'); ok(typeof load(NS, 'queue-microtask') == 'function'); ok(typeof load(NS, 'url') == 'function'); + ok(load(NS, 'url/can-parse')('a:b')); load(NS, 'url/to-json'); ok(typeof load(NS, 'url-search-params') == 'function'); } diff --git a/tests/unit-global/web.url.can-parse.js b/tests/unit-global/web.url.can-parse.js new file mode 100644 index 000000000000..7182bb0db05e --- /dev/null +++ b/tests/unit-global/web.url.can-parse.js @@ -0,0 +1,25 @@ +QUnit.test('URL.canParse', assert => { + const { canParse } = URL; + + assert.isFunction(canParse); + assert.arity(canParse, 1); + assert.name(canParse, 'canParse'); + assert.looksNative(canParse); + + assert.false(canParse(undefined), 'undefined'); + assert.false(canParse(undefined, undefined), 'undefined, undefined'); + assert.true(canParse('q:w'), 'q:w'); + assert.true(canParse('q:w', undefined), 'q:w, undefined'); + assert.false(canParse(undefined, 'q:w'), 'undefined, q:w'); + assert.true(canParse('q:/w'), 'q:/w'); + assert.true(canParse('q:/w', undefined), 'q:w, undefined'); + assert.true(canParse(undefined, 'q:/w'), 'undefined, q:w'); + assert.false(canParse('https://login:password@examp:le.com:8080/?a=1&b=2&a=3&c=4#fragment'), 'https://login:password@examp:le.com:8080/?a=1&b=2&a=3&c=4#fragment'); + assert.true(canParse('https://login:password@example.com:8080/?a=1&b=2&a=3&c=4#fragment'), 'https://login:password@example.com:8080/?a=1&b=2&a=3&c=4#fragment'); + assert.true(canParse('https://login:password@example.com:8080/?a=1&b=2&a=3&c=4#fragment', undefined), 'https://login:password@example.com:8080/?a=1&b=2&a=3&c=4#fragment, undefined'); + assert.true(canParse('x', 'https://login:password@example.com:8080/?a=1&b=2&a=3&c=4#fragment'), 'x, https://login:password@example.com:8080/?a=1&b=2&a=3&c=4#fragment'); + + assert.throws(() => canParse(), 'no args'); + assert.throws(() => canParse({ toString() { throw Error('thrower'); } }), 'conversion thrower #1'); + assert.throws(() => canParse('q:w', { toString() { throw Error('thrower'); } }), 'conversion thrower #2'); +}); diff --git a/tests/unit-pure/web.url.can-parse.js b/tests/unit-pure/web.url.can-parse.js new file mode 100644 index 000000000000..15a2b931ee6c --- /dev/null +++ b/tests/unit-pure/web.url.can-parse.js @@ -0,0 +1,24 @@ +import canParse from 'core-js-pure/stable/url/can-parse'; + +QUnit.test('URL.canParse', assert => { + assert.isFunction(canParse); + assert.arity(canParse, 1); + assert.name(canParse, 'canParse'); + + assert.false(canParse(undefined), 'undefined'); + assert.false(canParse(undefined, undefined), 'undefined, undefined'); + assert.true(canParse('q:w'), 'q:w'); + assert.true(canParse('q:w', undefined), 'q:w, undefined'); + assert.false(canParse(undefined, 'q:w'), 'undefined, q:w'); + assert.true(canParse('q:/w'), 'q:/w'); + assert.true(canParse('q:/w', undefined), 'q:w, undefined'); + assert.true(canParse(undefined, 'q:/w'), 'undefined, q:w'); + assert.false(canParse('https://login:password@examp:le.com:8080/?a=1&b=2&a=3&c=4#fragment'), 'https://login:password@examp:le.com:8080/?a=1&b=2&a=3&c=4#fragment'); + assert.true(canParse('https://login:password@example.com:8080/?a=1&b=2&a=3&c=4#fragment'), 'https://login:password@example.com:8080/?a=1&b=2&a=3&c=4#fragment'); + assert.true(canParse('https://login:password@example.com:8080/?a=1&b=2&a=3&c=4#fragment', undefined), 'https://login:password@example.com:8080/?a=1&b=2&a=3&c=4#fragment, undefined'); + assert.true(canParse('x', 'https://login:password@example.com:8080/?a=1&b=2&a=3&c=4#fragment'), 'x, https://login:password@example.com:8080/?a=1&b=2&a=3&c=4#fragment'); + + assert.throws(() => canParse(), 'no args'); + assert.throws(() => canParse({ toString() { throw Error('thrower'); } }), 'conversion thrower #1'); + assert.throws(() => canParse('q:w', { toString() { throw Error('thrower'); } }), 'conversion thrower #2'); +});