Skip to content

Commit bc97a90

Browse files
anonriglemire
authored andcommitted
url: add URLPattern implementation
Co-authored-by: Daniel Lemire <[email protected]> PR-URL: #56452 Reviewed-By: Daniel Lemire <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Benjamin Gruenbaum <[email protected]> Reviewed-By: Jordan Harband <[email protected]> Reviewed-By: Stephen Belanger <[email protected]>
1 parent e11cda0 commit bc97a90

14 files changed

+1073
-0
lines changed

doc/api/errors.md

+7
Original file line numberDiff line numberDiff line change
@@ -2116,6 +2116,13 @@ constructor][`new URL(input)`] or the legacy [`url.parse()`][] to be parsed.
21162116
The thrown error object typically has an additional property `'input'` that
21172117
contains the URL that failed to parse.
21182118

2119+
<a id="ERR_INVALID_URL_PATTERN"></a>
2120+
2121+
### `ERR_INVALID_URL_PATTERN`
2122+
2123+
An invalid URLPattern was passed to the [WHATWG][WHATWG URL API] \[`URLPattern`
2124+
constructor]\[`new URLPattern(input)`] to be parsed.
2125+
21192126
<a id="ERR_INVALID_URL_SCHEME"></a>
21202127

21212128
### `ERR_INVALID_URL_SCHEME`

doc/api/url.md

+123
Original file line numberDiff line numberDiff line change
@@ -714,6 +714,129 @@ Parses a string as a URL. If `base` is provided, it will be used as the base
714714
URL for the purpose of resolving non-absolute `input` URLs. Returns `null`
715715
if `input` is not a valid.
716716

717+
### Class: `URLPattern`
718+
719+
> Stability: 1 - Experimental
720+
721+
<!-- YAML
722+
added: REPLACEME
723+
-->
724+
725+
The `URLPattern` API provides an interface to match URLs or parts of URLs
726+
against a pattern.
727+
728+
```js
729+
const myPattern = new URLPattern('https://nodejs.org/docs/latest/api/*.html');
730+
console.log(myPattern.exec('https://nodejs.org/docs/latest/api/dns.html'));
731+
// Prints:
732+
// {
733+
// "hash": { "groups": { "0": "" }, "input": "" },
734+
// "hostname": { "groups": {}, "input": "nodejs.org" },
735+
// "inputs": [
736+
// "https://nodejs.org/docs/latest/api/dns.html"
737+
// ],
738+
// "password": { "groups": { "0": "" }, "input": "" },
739+
// "pathname": { "groups": { "0": "dns" }, "input": "/docs/latest/api/dns.html" },
740+
// "port": { "groups": {}, "input": "" },
741+
// "protocol": { "groups": {}, "input": "https" },
742+
// "search": { "groups": { "0": "" }, "input": "" },
743+
// "username": { "groups": { "0": "" }, "input": "" }
744+
// }
745+
746+
console.log(myPattern.test('https://nodejs.org/docs/latest/api/dns.html'));
747+
// Prints: true
748+
```
749+
750+
#### `new URLPattern()`
751+
752+
Instantiate a new empty `URLPattern` object.
753+
754+
#### `new URLPattern(string[, baseURL][, options])`
755+
756+
* `string` {string} A URL string
757+
* `baseURL` {string | undefined} A base URL string
758+
* `options` {Object} Options
759+
760+
Parse the `string` as a URL, and use it to instantiate a new
761+
`URLPattern` object.
762+
763+
If `baseURL` is not specified, it defaults to `undefined`.
764+
765+
An option can have `ignoreCase` boolean attribute which enables
766+
case-insensitive matching if set to true.
767+
768+
The constructor can throw a `TypeError` to indicate parsing failure.
769+
770+
#### `new URLPattern(objg[, baseURL][, options])`
771+
772+
* `obj` {Object} An input pattern
773+
* `baseURL` {string | undefined} A base URL string
774+
* `options` {Object} Options
775+
776+
Parse the `Object` as an input pattern, and use it to instantiate a new
777+
`URLPattern` object. The object members can be any of `protocol`, `username`,
778+
`password`, `hostname`, `port`, `pathname`, `search`, `hash` or `baseURL`.
779+
780+
If `baseURL` is not specified, it defaults to `undefined`.
781+
782+
An option can have `ignoreCase` boolean attribute which enables
783+
case-insensitive matching if set to true.
784+
785+
The constructor can throw a `TypeError` to indicate parsing failure.
786+
787+
#### `urlPattern.exec(input[, baseURL])`
788+
789+
* `input` {string | Object} A URL or URL parts
790+
* `baseURL` {string | undefined} A base URL string
791+
792+
Input can be a string or an object providing the individual URL parts. The
793+
object members can be any of `protocol`, `username`, `password`, `hostname`,
794+
`port`, `pathname`, `search`, `hash` or `baseURL`.
795+
796+
If `baseURL` is not specified, it will default to `undefined`.
797+
798+
Returns an object with an `inputs` key containing the array of arguments
799+
passed into the function and keys of the URL components which contains the
800+
matched input and matched groups.
801+
802+
```js
803+
const myPattern = new URLPattern('https://nodejs.org/docs/latest/api/*.html');
804+
console.log(myPattern.exec('https://nodejs.org/docs/latest/api/dns.html'));
805+
// Prints:
806+
// {
807+
// "hash": { "groups": { "0": "" }, "input": "" },
808+
// "hostname": { "groups": {}, "input": "nodejs.org" },
809+
// "inputs": [
810+
// "https://nodejs.org/docs/latest/api/dns.html"
811+
// ],
812+
// "password": { "groups": { "0": "" }, "input": "" },
813+
// "pathname": { "groups": { "0": "dns" }, "input": "/docs/latest/api/dns.html" },
814+
// "port": { "groups": {}, "input": "" },
815+
// "protocol": { "groups": {}, "input": "https" },
816+
// "search": { "groups": { "0": "" }, "input": "" },
817+
// "username": { "groups": { "0": "" }, "input": "" }
818+
// }
819+
```
820+
821+
#### `urlPattern.test(input[, baseURL])`
822+
823+
* `input` {string | Object} A URL or URL parts
824+
* `baseURL` {string | undefined} A base URL string
825+
826+
Input can be a string or an object providing the individual URL parts. The
827+
object members can be any of `protocol`, `username`, `password`, `hostname`,
828+
`port`, `pathname`, `search`, `hash` or `baseURL`.
829+
830+
If `baseURL` is not specified, it will default to `undefined`.
831+
832+
Returns a boolean indicating if the input matches the current pattern.
833+
834+
```js
835+
const myPattern = new URLPattern('https://nodejs.org/docs/latest/api/*.html');
836+
console.log(myPattern.test('https://nodejs.org/docs/latest/api/dns.html'));
837+
// Prints: true
838+
```
839+
717840
### Class: `URLSearchParams`
718841

719842
<!-- YAML

lib/internal/url.js

+2
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ const {
3232
decodeURIComponent,
3333
} = primordials;
3434

35+
const { URLPattern } = internalBinding('url_pattern');
3536
const { inspect } = require('internal/util/inspect');
3637
const {
3738
encodeStr,
@@ -1574,6 +1575,7 @@ module.exports = {
15741575
toPathIfFileURL,
15751576
installObjectURLMethods,
15761577
URL,
1578+
URLPattern,
15771579
URLSearchParams,
15781580
URLParse: URL.parse,
15791581
domainToASCII,

lib/url.js

+2
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ const {
3030
decodeURIComponent,
3131
} = primordials;
3232

33+
const { URLPattern } = internalBinding('url_pattern');
3334
const { toASCII } = internalBinding('encoding_binding');
3435
const { encodeStr, hexTable } = require('internal/querystring');
3536
const querystring = require('querystring');
@@ -1030,6 +1031,7 @@ module.exports = {
10301031

10311032
// WHATWG API
10321033
URL,
1034+
URLPattern,
10331035
URLSearchParams,
10341036
domainToASCII,
10351037
domainToUnicode,

node.gyp

+2
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@
146146
'src/node_trace_events.cc',
147147
'src/node_types.cc',
148148
'src/node_url.cc',
149+
'src/node_url_pattern.cc',
149150
'src/node_util.cc',
150151
'src/node_v8.cc',
151152
'src/node_wasi.cc',
@@ -275,6 +276,7 @@
275276
'src/node_stat_watcher.h',
276277
'src/node_union_bytes.h',
277278
'src/node_url.h',
279+
'src/node_url_pattern.h',
278280
'src/node_version.h',
279281
'src/node_v8.h',
280282
'src/node_v8_platform-inl.h',

src/env_properties.h

+10
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@
7878
V(async_ids_stack_string, "async_ids_stack") \
7979
V(attributes_string, "attributes") \
8080
V(base_string, "base") \
81+
V(base_url_string, "baseURL") \
8182
V(bits_string, "bits") \
8283
V(block_list_string, "blockList") \
8384
V(buffer_string, "buffer") \
@@ -179,20 +180,26 @@
179180
V(get_data_clone_error_string, "_getDataCloneError") \
180181
V(get_shared_array_buffer_id_string, "_getSharedArrayBufferId") \
181182
V(gid_string, "gid") \
183+
V(groups_string, "groups") \
184+
V(has_regexp_groups_string, "hasRegExpGroups") \
185+
V(hash_string, "hash") \
182186
V(h2_string, "h2") \
183187
V(handle_string, "handle") \
184188
V(hash_algorithm_string, "hashAlgorithm") \
185189
V(help_text_string, "helpText") \
186190
V(homedir_string, "homedir") \
187191
V(host_string, "host") \
188192
V(hostmaster_string, "hostmaster") \
193+
V(hostname_string, "hostname") \
189194
V(http_1_1_string, "http/1.1") \
190195
V(id_string, "id") \
191196
V(identity_string, "identity") \
197+
V(ignore_case_string, "ignoreCase") \
192198
V(ignore_string, "ignore") \
193199
V(infoaccess_string, "infoAccess") \
194200
V(inherit_string, "inherit") \
195201
V(input_string, "input") \
202+
V(inputs_string, "inputs") \
196203
V(internal_binding_string, "internalBinding") \
197204
V(internal_string, "internal") \
198205
V(ipv4_string, "IPv4") \
@@ -280,6 +287,7 @@
280287
V(parse_error_string, "Parse Error") \
281288
V(password_string, "password") \
282289
V(path_string, "path") \
290+
V(pathname_string, "pathname") \
283291
V(pending_handle_string, "pendingHandle") \
284292
V(permission_string, "permission") \
285293
V(pid_string, "pid") \
@@ -295,6 +303,7 @@
295303
V(priority_string, "priority") \
296304
V(process_string, "process") \
297305
V(promise_string, "promise") \
306+
V(protocol_string, "protocol") \
298307
V(prototype_string, "prototype") \
299308
V(psk_string, "psk") \
300309
V(pubkey_string, "pubkey") \
@@ -323,6 +332,7 @@
323332
V(scopeid_string, "scopeid") \
324333
V(script_id_string, "scriptId") \
325334
V(script_name_string, "scriptName") \
335+
V(search_string, "search") \
326336
V(serial_number_string, "serialNumber") \
327337
V(serial_string, "serial") \
328338
V(servername_string, "servername") \

src/node_binding.cc

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "node_builtins.h"
55
#include "node_errors.h"
66
#include "node_external_reference.h"
7+
#include "node_url_pattern.h"
78
#include "util.h"
89

910
#include <string>
@@ -87,6 +88,7 @@
8788
V(types) \
8889
V(udp_wrap) \
8990
V(url) \
91+
V(url_pattern) \
9092
V(util) \
9193
V(uv) \
9294
V(v8) \

src/node_errors.h

+2
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ void OOMErrorHandler(const char* location, const v8::OOMDetails& details);
9090
V(ERR_INVALID_STATE, Error) \
9191
V(ERR_INVALID_THIS, TypeError) \
9292
V(ERR_INVALID_URL, TypeError) \
93+
V(ERR_INVALID_URL_PATTERN, TypeError) \
9394
V(ERR_INVALID_URL_SCHEME, TypeError) \
9495
V(ERR_LOAD_SQLITE_EXTENSION, Error) \
9596
V(ERR_MEMORY_ALLOCATION_FAILED, Error) \
@@ -99,6 +100,7 @@ void OOMErrorHandler(const char* location, const v8::OOMDetails& details);
99100
V(ERR_MISSING_PLATFORM_FOR_WORKER, Error) \
100101
V(ERR_MODULE_NOT_FOUND, Error) \
101102
V(ERR_NON_CONTEXT_AWARE_DISABLED, Error) \
103+
V(ERR_OPERATION_FAILED, TypeError) \
102104
V(ERR_OUT_OF_RANGE, RangeError) \
103105
V(ERR_REQUIRE_ASYNC_MODULE, Error) \
104106
V(ERR_SCRIPT_EXECUTION_INTERRUPTED, Error) \

src/node_external_reference.h

+1
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ class ExternalReferenceRegistry {
180180
V(tty_wrap) \
181181
V(udp_wrap) \
182182
V(url) \
183+
V(url_pattern) \
183184
V(util) \
184185
V(pipe_wrap) \
185186
V(sea) \

0 commit comments

Comments
 (0)