diff --git a/spec.bs b/spec.bs index cec6cbe..a567e5a 100644 --- a/spec.bs +++ b/spec.bs @@ -23,9 +23,11 @@ spec: URL; urlPrefix: https://url.spec.whatwg.org/ text: serialize an integer; url: #serialize-an-integer -

The {{URLPattern}} class

+

URL patterns

-A {{URLPattern}} consists of several [=components=], each of which represents a [=/pattern string|pattern=] which could be matched against the corresponding component of a [=/URL=]. +

Introduction

+ +A [=URL pattern=] consists of several [=components=], each of which represents a [=/pattern string|pattern=] which could be matched against the corresponding component of a [=/URL=]. It can be constructed using a string for each component, or from a shorthand string. It can optionally be resolved relative to a base URL. @@ -33,28 +35,28 @@ It can be constructed using a string for each component, or from a shorthand str

The shorthand "`https://example.com/:category/*`" corresponds to the following components:

-
[=URLPattern/protocol component|protocol=] +
[=URL pattern/protocol component|protocol=]
"`https`" -
[=URLPattern/username component|username=] +
[=URL pattern/username component|username=]
"`*`" -
[=URLPattern/password component|password=] +
[=URL pattern/password component|password=]
"`*`" -
[=URLPattern/hostname component|hostname=] +
[=URL pattern/hostname component|hostname=]
"`example.com`" -
[=URLPattern/port component|port=] +
[=URL pattern/port component|port=]
"" -
[=URLPattern/pathname component|pathname=] +
[=URL pattern/pathname component|pathname=]
"`/:category/*`" -
[=URLPattern/search component|search=] +
[=URL pattern/search component|search=]
"`*`" -
[=URLPattern/hash component|hash=] +
[=URL pattern/hash component|hash=]
"`*`"
@@ -78,28 +80,28 @@ It can be constructed using a string for each component, or from a shorthand str

The shorthand "`http{s}?://{:subdomain.}?shop.example/products/:id([0-9]+)#reviews`" corresponds to the following components:

-
[=URLPattern/protocol component|protocol=] +
[=URL pattern/protocol component|protocol=]
"`http{s}?`" -
[=URLPattern/username component|username=] +
[=URL pattern/username component|username=]
"`*`" -
[=URLPattern/password component|password=] +
[=URL pattern/password component|password=]
"`*`" -
[=URLPattern/hostname component|hostname=] +
[=URL pattern/hostname component|hostname=]
"`{:subdomain.}?shop.example`" -
[=URLPattern/port component|port=] +
[=URL pattern/port component|port=]
"" -
[=URLPattern/pathname component|pathname=] +
[=URL pattern/pathname component|pathname=]
"`/products/:id([0-9]+)`" -
[=URLPattern/search component|search=] +
[=URL pattern/search component|search=]
"" -
[=URLPattern/hash component|hash=] +
[=URL pattern/hash component|hash=]
"`reviews`"
@@ -125,28 +127,28 @@ It can be constructed using a string for each component, or from a shorthand str

The shorthand "`../admin/*`" with the base URL "`https://discussion.example/forum/?page=2`" corresponds to the following components:

-
[=URLPattern/protocol component|protocol=] +
[=URL pattern/protocol component|protocol=]
"`https`" -
[=URLPattern/username component|username=] +
[=URL pattern/username component|username=]
"`*`" -
[=URLPattern/password component|password=] +
[=URL pattern/password component|password=]
"`*`" -
[=URLPattern/hostname component|hostname=] +
[=URL pattern/hostname component|hostname=]
"`discussion.example`" -
[=URLPattern/port component|port=] +
[=URL pattern/port component|port=]
"" -
[=URLPattern/pathname component|pathname=] +
[=URL pattern/pathname component|pathname=]
"`/admin/*`" -
[=URLPattern/search component|search=] +
[=URL pattern/search component|search=]
"`*`" -
[=URLPattern/hash component|hash=] +
[=URL pattern/hash component|hash=]
"`*`"
@@ -165,6 +167,8 @@ It can be constructed using a string for each component, or from a shorthand str +

The {{URLPattern}} class

+ typedef (USVString or URLPatternInit) URLPatternInput; @@ -224,21 +228,7 @@ dictionary URLPatternComponentResult { }; -Each {{URLPattern}} object has an associated protocol component, a [=component=], which must be set upon creation. - -Each {{URLPattern}} object has an associated username component, a [=component=], which must be set upon creation. - -Each {{URLPattern}} object has an associated password component, a [=component=], which must be set upon creation. - -Each {{URLPattern}} object has an associated hostname component, a [=component=], which must be set upon creation. - -Each {{URLPattern}} object has an associated port component, a [=component=], which must be set upon creation. - -Each {{URLPattern}} object has an associated pathname component, a [=component=], which must be set upon creation. - -Each {{URLPattern}} object has an associated search component, a [=component=], which must be set upon creation. - -Each {{URLPattern}} object has an associated hash component, a [=component=], which must be set upon creation. +Each {{URLPattern}} has an associated URL pattern, a [=URL pattern=].
|urlPattern| = new {{URLPattern/constructor(input, baseURL, options)|URLPattern}}(|input|)
@@ -350,93 +340,68 @@ Each {{URLPattern}} object has an associated hash component<
To initialize a {{URLPattern}} given a {{URLPattern}} |this|, {{URLPatternInput}} |input|, string or null |baseURL|, and {{URLPatternOptions}} |options|: - 1. Let |init| be null. - 1. If |input| is a [=scalar value string=] then: - 1. Set |init| to the result of running [=parse a constructor string=] given |input|. - 1. If |baseURL| is null and |init|["{{URLPatternInit/protocol}}"] does not [=map/exist=], then throw a {{TypeError}}. - 1. If |baseURL| is not null, [=map/set=] |init|["{{URLPatternInit/baseURL}}"] to |baseURL|. - 1. Otherwise: - 1. [=Assert=]: |input| is a {{URLPatternInit}}. - 1. If |baseURL| is not null, then throw a {{TypeError}}. - 1. Set |init| to |input|. - 1. Let |processedInit| be the result of [=process a URLPatternInit=] given |init|, "`pattern`", null, null, null, null, null, null, null, and null. - 1. [=list/For each=] |componentName| of « "{{URLPatternInit/protocol}}", "{{URLPatternInit/username}}", "{{URLPatternInit/password}}", "{{URLPatternInit/hostname}}", "{{URLPatternInit/port}}", "{{URLPatternInit/pathname}}", "{{URLPatternInit/search}}", "{{URLPatternInit/hash}}" »: - 1. If |processedInit|[|componentName|] does not [=map/exist=], then [=map/set=] |processedInit|[|componentName|] to "`*`". - 1. If |processedInit|["{{URLPatternInit/protocol}}"] is a [=special scheme=] and |processedInit|["{{URLPatternInit/port}}"] is a string which represents its corresponding [=default port=] in radix-10 using [=ASCII digits=] then set |processedInit|["{{URLPatternInit/port}}"] to the empty string. - 1. Set |this|'s [=URLPattern/protocol component=] to the result of [=compiling a component=] given |processedInit|["{{URLPatternInit/protocol}}"], [=canonicalize a protocol=], and [=default options=]. - 1. Set |this|'s [=URLPattern/username component=] to the result of [=compiling a component=] given |processedInit|["{{URLPatternInit/username}}"], [=canonicalize a username=], and [=default options=]. - 1. Set |this|'s [=URLPattern/password component=] to the result of [=compiling a component=] given |processedInit|["{{URLPatternInit/password}}"], [=canonicalize a password=], and [=default options=]. - 1. If the result running [=hostname pattern is an IPv6 address=] given |processedInit|["{{URLPatternInit/hostname}}"] is true, then set |this|'s [=URLPattern/hostname component=] to the result of [=compiling a component=] given |processedInit|["{{URLPatternInit/hostname}}"], [=canonicalize an IPv6 hostname=], and [=hostname options=]. - 1. Otherwise, set |this|'s [=URLPattern/hostname component=] to the result of [=compiling a component=] given |processedInit|["{{URLPatternInit/hostname}}"], [=canonicalize a hostname=], and [=hostname options=]. - 1. Set |this|'s [=URLPattern/port component=] to the result of [=compiling a component=] given |processedInit|["{{URLPatternInit/port}}"], [=canonicalize a port=], and [=default options=]. - 1. Let |compileOptions| be a copy of the [=default options=] with the [=options/ignore case=] property set to |options|["{{URLPatternOptions/ignoreCase}}"]. - 1. If the result of running [=protocol component matches a special scheme=] given |this|'s [=URLPattern/protocol component=] is true, then: - 1. Let |pathCompileOptions| be copy of the [=pathname options=] with the [=options/ignore case=] property set to |options|["{{URLPatternOptions/ignoreCase}}"]. - 1. Set |this|'s [=URLPattern/pathname component=] to the result of [=compiling a component=] given |processedInit|["{{URLPatternInit/pathname}}"], [=canonicalize a pathname=], and |pathCompileOptions|. - 1. Otherwise set |this|'s [=URLPattern/pathname component=] to the result of [=compiling a component=] given |processedInit|["{{URLPatternInit/pathname}}"], [=canonicalize an opaque pathname=], and |compileOptions|. - 1. Set |this|'s [=URLPattern/search component=] to the result of [=compiling a component=] given |processedInit|["{{URLPatternInit/search}}"], [=canonicalize a search=], and |compileOptions|. - 1. Set |this|'s [=URLPattern/hash component=] to the result of [=compiling a component=] given |processedInit|["{{URLPatternInit/hash}}"], [=canonicalize a hash=], and |compileOptions|. + 1. Set |this|'s [=URLPattern/associated URL pattern=] to the result of [=create=] given |input|, |baseURL|, and |options|.
The protocol getter steps are: - 1. Return [=this=]'s [=URLPattern/protocol component=]'s [=component/pattern string=]. + 1. Return [=this=]'s [=URLPattern/associated URL pattern=]'s [=URL pattern/protocol component=]'s [=component/pattern string=].
The username getter steps are: - 1. Return [=this=]'s [=URLPattern/username component=]'s [=component/pattern string=]. + 1. Return [=this=]'s [=URLPattern/associated URL pattern=]'s [=URL pattern/username component=]'s [=component/pattern string=].
The password getter steps are: - 1. Return [=this=]'s [=URLPattern/password component=]'s [=component/pattern string=]. + 1. Return [=this=]'s [=URLPattern/associated URL pattern=]'s [=URL pattern/password component=]'s [=component/pattern string=].
The hostname getter steps are: - 1. Return [=this=]'s [=URLPattern/hostname component=]'s [=component/pattern string=]. + 1. Return [=this=]'s [=URLPattern/associated URL pattern=]'s [=URL pattern/hostname component=]'s [=component/pattern string=].
The port getter steps are: - 1. Return [=this=]'s [=URLPattern/port component=]'s [=component/pattern string=]. + 1. Return [=this=]'s [=URLPattern/associated URL pattern=]'s [=URL pattern/port component=]'s [=component/pattern string=].
The pathname getter steps are: - 1. Return [=this=]'s [=URLPattern/pathname component=]'s [=component/pattern string=]. + 1. Return [=this=]'s [=URLPattern/associated URL pattern=]'s [=URL pattern/pathname component=]'s [=component/pattern string=].
The search getter steps are: - 1. Return [=this=]'s [=URLPattern/search component=]'s [=component/pattern string=]. + 1. Return [=this=]'s [=URLPattern/associated URL pattern=]'s [=URL pattern/search component=]'s [=component/pattern string=].
The hash getter steps are: - 1. Return [=this=]'s [=URLPattern/hash component=]'s [=component/pattern string=]. + 1. Return [=this=]'s [=URLPattern/associated URL pattern=]'s [=URL pattern/hash component=]'s [=component/pattern string=].
The hasRegExpGroups getter steps are: - 1. If [=this=] [=URLPattern/has regexp groups=], then return true. + 1. If [=this=]'s [=URLPattern/associated URL pattern=]'s [=URL pattern/has regexp groups=], then return true. 1. Return false.
The test(|input|, |baseURL|) method steps are: - 1. Let |result| be the result of [=URLPattern/match=] given [=this=], |input|, and |baseURL| if given. + 1. Let |result| be the result of [=URL pattern/match=] given [=this=]'s [=URLPattern/associated URL pattern=], |input|, and |baseURL| if given. 1. If |result| is null, return false. 1. Return true.
@@ -444,54 +409,66 @@ Each {{URLPattern}} object has an associated hash component<
The exec(|input|, |baseURL|) method steps are: - 1. Return the result of [=URLPattern/match=] given [=this=], |input|, and |baseURL| if given. + 1. Return the result of [=URL pattern/match=] given [=this=]'s [=URLPattern/associated URL pattern=], |input|, and |baseURL| if given.
-

Internals

+

The URL pattern struct

-A {{URLPattern}} is associated with multiple component [=structs=]. +A URL pattern is a [=struct=] with the following [=struct/items=]: -A [=component=] has an associated pattern string, a [=pattern string/well formed=] [=/pattern string=], which must be set upon creation. +* protocol component, a [=component=] +* username component, a [=component=] +* password component, a [=component=] +* hostname component, a [=component=] +* port component, a [=component=] +* pathname component, a [=component=] +* search component, a [=component=] +* hash component, a [=component=] -A [=component=] has an associated regular expression, a {{RegExp}}, which must be set upon creation. +A component is a [=struct=] with the following [=struct/items=]: -A [=component=] has an associated group name list, a [=list=] of strings, which must be set upon creation. +* pattern string, a [=pattern string/well formed=] [=/pattern string=] +* regular expression, a {{RegExp}} +* group name list, a [=list=] of strings +* has regexp groups, a [=boolean=] -A [=component=] has an associated has regexp groups, a [=boolean=], which must be set upon creation. +

High-level operations

- To compile a component given a string |input|, [=/encoding callback=] |encoding callback|, and [=/options=] |options|: + To create a [=URL pattern=] given a {{URLPatternInput}} |input|, string or null |baseURL|, and {{URLPatternOptions}} |options|: - 1. Let |part list| be the result of running [=parse a pattern string=] given |input|, |options|, and |encoding callback|. - 1. Let (|regular expression string|, |name list|) be the result of running [=generate a regular expression and name list=] given |part list| and |options|. - 1. Let |flags| be an empty string. - 1. If |options|'s [=options/ignore case=] is true then set |flags| to "`vi`". - 1. Otherwise set |flags| to "`v`" - 1. Let |regular expression| be [$RegExpCreate$](|regular expression string|, |flags|). If this throws an exception, catch it, and throw a {{TypeError}}. -

The specification uses regular expressions to perform all matching, but this is not mandated. Implementations are free to perform matching directly against the [=/part list=] when possible; e.g. when there are no custom regexp matching groups. If there are custom regular expressions, however, its important that they be immediately evaluated in the [=compile a component=] algorithm so an error can be thrown if they are invalid. - 1. Let |pattern string| be the result of running [=generate a pattern string=] given |part list| and |options|. - 1. Let |has regexp groups| be false. - 1. [=list/For each=] |part| of |part list|: - 1. If |part|'s [=part/type=] is "`regexp`", then set |has regexp groups| to true. - 1. Return a new [=component=] whose [=component/pattern string=] is |pattern string|, [=component/regular expression=] is |regular expression|, [=component/group name list=] is |name list|, and [=component/has regexp groups=] is |has regexp groups|. -

- -
- A {{URLPattern}} |pattern| has regexp groups if the following steps return true: - - 1. If |pattern|'s [=URLPattern/protocol component=] [=component/has regexp groups=] is true, then return true. - 1. If |pattern|'s [=URLPattern/username component=] [=component/has regexp groups=] is true, then return true. - 1. If |pattern|'s [=URLPattern/password component=] [=component/has regexp groups=] is true, then return true. - 1. If |pattern|'s [=URLPattern/hostname component=] [=component/has regexp groups=] is true, then return true. - 1. If |pattern|'s [=URLPattern/port component=] [=component/has regexp groups=] is true, then return true. - 1. If |pattern|'s [=URLPattern/pathname component=] [=component/has regexp groups=] is true, then return true. - 1. If |pattern|'s [=URLPattern/search component=] [=component/has regexp groups=] is true, then return true. - 1. If |pattern|'s [=URLPattern/hash component=] [=component/has regexp groups=] is true, then return true. - 1. Return false. + 1. Let |init| be null. + 1. If |input| is a [=scalar value string=] then: + 1. Set |init| to the result of running [=parse a constructor string=] given |input|. + 1. If |baseURL| is null and |init|["{{URLPatternInit/protocol}}"] does not [=map/exist=], then throw a {{TypeError}}. + 1. If |baseURL| is not null, [=map/set=] |init|["{{URLPatternInit/baseURL}}"] to |baseURL|. + 1. Otherwise: + 1. [=Assert=]: |input| is a {{URLPatternInit}}. + 1. If |baseURL| is not null, then throw a {{TypeError}}. + 1. Set |init| to |input|. + 1. Let |processedInit| be the result of [=process a URLPatternInit=] given |init|, "`pattern`", null, null, null, null, null, null, null, and null. + 1. [=list/For each=] |componentName| of « "{{URLPatternInit/protocol}}", "{{URLPatternInit/username}}", "{{URLPatternInit/password}}", "{{URLPatternInit/hostname}}", "{{URLPatternInit/port}}", "{{URLPatternInit/pathname}}", "{{URLPatternInit/search}}", "{{URLPatternInit/hash}}" »: + 1. If |processedInit|[|componentName|] does not [=map/exist=], then [=map/set=] |processedInit|[|componentName|] to "`*`". + 1. If |processedInit|["{{URLPatternInit/protocol}}"] is a [=special scheme=] and |processedInit|["{{URLPatternInit/port}}"] is a string which represents its corresponding [=default port=] in radix-10 using [=ASCII digits=] then set |processedInit|["{{URLPatternInit/port}}"] to the empty string. + 1. Let |urlPattern| be a new [=URL pattern=]. + 1. Set |urlPattern|'s [=URL pattern/protocol component=] to the result of [=compiling a component=] given |processedInit|["{{URLPatternInit/protocol}}"], [=canonicalize a protocol=], and [=default options=]. + 1. Set |urlPattern|'s [=URL pattern/username component=] to the result of [=compiling a component=] given |processedInit|["{{URLPatternInit/username}}"], [=canonicalize a username=], and [=default options=]. + 1. Set |urlPattern|'s [=URL pattern/password component=] to the result of [=compiling a component=] given |processedInit|["{{URLPatternInit/password}}"], [=canonicalize a password=], and [=default options=]. + 1. If the result running [=hostname pattern is an IPv6 address=] given |processedInit|["{{URLPatternInit/hostname}}"] is true, then set |urlPattern|'s [=URL pattern/hostname component=] to the result of [=compiling a component=] given |processedInit|["{{URLPatternInit/hostname}}"], [=canonicalize an IPv6 hostname=], and [=hostname options=]. + 1. Otherwise, set |urlPattern|'s [=URL pattern/hostname component=] to the result of [=compiling a component=] given |processedInit|["{{URLPatternInit/hostname}}"], [=canonicalize a hostname=], and [=hostname options=]. + 1. Set |urlPattern|'s [=URL pattern/port component=] to the result of [=compiling a component=] given |processedInit|["{{URLPatternInit/port}}"], [=canonicalize a port=], and [=default options=]. + 1. Let |compileOptions| be a copy of the [=default options=] with the [=options/ignore case=] property set to |options|["{{URLPatternOptions/ignoreCase}}"]. + 1. If the result of running [=protocol component matches a special scheme=] given |urlPattern|'s [=URL pattern/protocol component=] is true, then: + 1. Let |pathCompileOptions| be copy of the [=pathname options=] with the [=options/ignore case=] property set to |options|["{{URLPatternOptions/ignoreCase}}"]. + 1. Set |urlPattern|'s [=URL pattern/pathname component=] to the result of [=compiling a component=] given |processedInit|["{{URLPatternInit/pathname}}"], [=canonicalize a pathname=], and |pathCompileOptions|. + 1. Otherwise set |urlPattern|'s [=URL pattern/pathname component=] to the result of [=compiling a component=] given |processedInit|["{{URLPatternInit/pathname}}"], [=canonicalize an opaque pathname=], and |compileOptions|. + 1. Set |urlPattern|'s [=URL pattern/search component=] to the result of [=compiling a component=] given |processedInit|["{{URLPatternInit/search}}"], [=canonicalize a search=], and |compileOptions|. + 1. Set |urlPattern|'s [=URL pattern/hash component=] to the result of [=compiling a component=] given |processedInit|["{{URLPatternInit/hash}}"], [=canonicalize a hash=], and |compileOptions|. + 1. Return |urlPattern|.
- To perform a match given a {{URLPattern}} |urlpattern|, a {{URLPatternInput}} |input|, and an optional string |baseURLString|: + To perform a match given a [=URL pattern=] |urlPattern|, a {{URLPatternInput}} |input|, and an optional string |baseURLString|: 1. Let |protocol| be the empty string. 1. Let |username| be the empty string. @@ -530,28 +507,61 @@ A [=component=] has an associated has regexp groups, a 1. Set |pathname| to the result of [=URL path serializing=] |url|. 1. Set |search| to |url|'s [=url/query=] or the empty string if the value is null. 1. Set |hash| to |url|'s [=url/fragment=] or the empty string if the value is null. - 1. Let |protocolExecResult| be [$RegExpBuiltinExec$](|urlpattern|'s [=URLPattern/protocol component=]'s [=component/regular expression=], |protocol|). - 1. Let |usernameExecResult| be [$RegExpBuiltinExec$](|urlpattern|'s [=URLPattern/username component=]'s [=component/regular expression=], |username|). - 1. Let |passwordExecResult| be [$RegExpBuiltinExec$](|urlpattern|'s [=URLPattern/password component=]'s [=component/regular expression=], |password|). - 1. Let |hostnameExecResult| be [$RegExpBuiltinExec$](|urlpattern|'s [=URLPattern/hostname component=]'s [=component/regular expression=], |hostname|). - 1. Let |portExecResult| be [$RegExpBuiltinExec$](|urlpattern|'s [=URLPattern/port component=]'s [=component/regular expression=], |port|). - 1. Let |pathnameExecResult| be [$RegExpBuiltinExec$](|urlpattern|'s [=URLPattern/pathname component=]'s [=component/regular expression=], |pathname|). - 1. Let |searchExecResult| be [$RegExpBuiltinExec$](|urlpattern|'s [=URLPattern/search component=]'s [=component/regular expression=], |search|). - 1. Let |hashExecResult| be [$RegExpBuiltinExec$](|urlpattern|'s [=URLPattern/hash component=]'s [=component/regular expression=], |hash|). + 1. Let |protocolExecResult| be [$RegExpBuiltinExec$](|urlPattern|'s [=URL pattern/protocol component=]'s [=component/regular expression=], |protocol|). + 1. Let |usernameExecResult| be [$RegExpBuiltinExec$](|urlPattern|'s [=URL pattern/username component=]'s [=component/regular expression=], |username|). + 1. Let |passwordExecResult| be [$RegExpBuiltinExec$](|urlPattern|'s [=URL pattern/password component=]'s [=component/regular expression=], |password|). + 1. Let |hostnameExecResult| be [$RegExpBuiltinExec$](|urlPattern|'s [=URL pattern/hostname component=]'s [=component/regular expression=], |hostname|). + 1. Let |portExecResult| be [$RegExpBuiltinExec$](|urlPattern|'s [=URL pattern/port component=]'s [=component/regular expression=], |port|). + 1. Let |pathnameExecResult| be [$RegExpBuiltinExec$](|urlPattern|'s [=URL pattern/pathname component=]'s [=component/regular expression=], |pathname|). + 1. Let |searchExecResult| be [$RegExpBuiltinExec$](|urlPattern|'s [=URL pattern/search component=]'s [=component/regular expression=], |search|). + 1. Let |hashExecResult| be [$RegExpBuiltinExec$](|urlPattern|'s [=URL pattern/hash component=]'s [=component/regular expression=], |hash|). 1. If |protocolExecResult|, |usernameExecResult|, |passwordExecResult|, |hostnameExecResult|, |portExecResult|, |pathnameExecResult|, |searchExecResult|, or |hashExecResult| are null then return null. 1. Let |result| be a new {{URLPatternResult}}. 1. Set |result|["{{URLPatternResult/inputs}}"] to |inputs|. - 1. Set |result|["{{URLPatternResult/protocol}}"] to the result of [=creating a component match result=] given |urlpattern|'s [=URLPattern/protocol component=], |protocol|, and |protocolExecResult|. - 1. Set |result|["{{URLPatternResult/username}}"] to the result of [=creating a component match result=] given |urlpattern|'s [=URLPattern/username component=], |username|, and |usernameExecResult|. - 1. Set |result|["{{URLPatternResult/password}}"] to the result of [=creating a component match result=] given |urlpattern|'s [=URLPattern/password component=], |password|, and |passwordExecResult|. - 1. Set |result|["{{URLPatternResult/hostname}}"] to the result of [=creating a component match result=] given |urlpattern|'s [=URLPattern/hostname component=], |hostname|, and |hostnameExecResult|. - 1. Set |result|["{{URLPatternResult/port}}"] to the result of [=creating a component match result=] given |urlpattern|'s [=URLPattern/port component=], |port|, and |portExecResult|. - 1. Set |result|["{{URLPatternResult/pathname}}"] to the result of [=creating a component match result=] given |urlpattern|'s [=URLPattern/pathname component=], |pathname|, and |pathnameExecResult|. - 1. Set |result|["{{URLPatternResult/search}}"] to the result of [=creating a component match result=] given |urlpattern|'s [=URLPattern/search component=], |search|, and |searchExecResult|. - 1. Set |result|["{{URLPatternResult/hash}}"] to the result of [=creating a component match result=] given |urlpattern|'s [=URLPattern/hash component=], |hash|, and |hashExecResult|. + 1. Set |result|["{{URLPatternResult/protocol}}"] to the result of [=creating a component match result=] given |urlPattern|'s [=URL pattern/protocol component=], |protocol|, and |protocolExecResult|. + 1. Set |result|["{{URLPatternResult/username}}"] to the result of [=creating a component match result=] given |urlPattern|'s [=URL pattern/username component=], |username|, and |usernameExecResult|. + 1. Set |result|["{{URLPatternResult/password}}"] to the result of [=creating a component match result=] given |urlPattern|'s [=URL pattern/password component=], |password|, and |passwordExecResult|. + 1. Set |result|["{{URLPatternResult/hostname}}"] to the result of [=creating a component match result=] given |urlPattern|'s [=URL pattern/hostname component=], |hostname|, and |hostnameExecResult|. + 1. Set |result|["{{URLPatternResult/port}}"] to the result of [=creating a component match result=] given |urlPattern|'s [=URL pattern/port component=], |port|, and |portExecResult|. + 1. Set |result|["{{URLPatternResult/pathname}}"] to the result of [=creating a component match result=] given |urlPattern|'s [=URL pattern/pathname component=], |pathname|, and |pathnameExecResult|. + 1. Set |result|["{{URLPatternResult/search}}"] to the result of [=creating a component match result=] given |urlPattern|'s [=URL pattern/search component=], |search|, and |searchExecResult|. + 1. Set |result|["{{URLPatternResult/hash}}"] to the result of [=creating a component match result=] given |urlPattern|'s [=URL pattern/hash component=], |hash|, and |hashExecResult|. 1. Return |result|.
+
+ A [=URL pattern=] |urlPattern| has regexp groups if the following steps return true: + + 1. If |urlPattern|'s [=URL pattern/protocol component=] [=component/has regexp groups=] is true, then return true. + 1. If |urlPattern|'s [=URL pattern/username component=] [=component/has regexp groups=] is true, then return true. + 1. If |urlPattern|'s [=URL pattern/password component=] [=component/has regexp groups=] is true, then return true. + 1. If |urlPattern|'s [=URL pattern/hostname component=] [=component/has regexp groups=] is true, then return true. + 1. If |urlPattern|'s [=URL pattern/port component=] [=component/has regexp groups=] is true, then return true. + 1. If |urlPattern|'s [=URL pattern/pathname component=] [=component/has regexp groups=] is true, then return true. + 1. If |urlPattern|'s [=URL pattern/search component=] [=component/has regexp groups=] is true, then return true. + 1. If |urlPattern|'s [=URL pattern/hash component=] [=component/has regexp groups=] is true, then return true. + 1. Return false. +
+ +

Internals

+ +
+ To compile a component given a string |input|, [=/encoding callback=] |encoding callback|, and [=/options=] |options|: + + 1. Let |part list| be the result of running [=parse a pattern string=] given |input|, |options|, and |encoding callback|. + 1. Let (|regular expression string|, |name list|) be the result of running [=generate a regular expression and name list=] given |part list| and |options|. + 1. Let |flags| be an empty string. + 1. If |options|'s [=options/ignore case=] is true then set |flags| to "`vi`". + 1. Otherwise set |flags| to "`v`" + 1. Let |regular expression| be [$RegExpCreate$](|regular expression string|, |flags|). If this throws an exception, catch it, and throw a {{TypeError}}. +

The specification uses regular expressions to perform all matching, but this is not mandated. Implementations are free to perform matching directly against the [=/part list=] when possible; e.g. when there are no custom regexp matching groups. If there are custom regular expressions, however, its important that they be immediately evaluated in the [=compile a component=] algorithm so an error can be thrown if they are invalid. + 1. Let |pattern string| be the result of running [=generate a pattern string=] given |part list| and |options|. + 1. Let |has regexp groups| be false. + 1. [=list/For each=] |part| of |part list|: + 1. If |part|'s [=part/type=] is "`regexp`", then set |has regexp groups| to true. + 1. Return a new [=component=] whose [=component/pattern string=] is |pattern string|, [=component/regular expression=] is |regular expression|, [=component/group name list=] is |name list|, and [=component/has regexp groups=] is |has regexp groups|. +

+
To create a component match result given a [=component=] |component|, a string |input|, and an array representing the output of [$RegExpBuiltinExec$] |execResult|: @@ -926,7 +936,7 @@ To compute protocol matches a special scheme flag given a [=construct 1. If the result of running [=protocol component matches a special scheme=] given |protocol component| is true, then set |parser|'s [=constructor string parser/protocol matches a special scheme flag=] to true.
-

Patterns

+

Pattern strings

A pattern string is a string that is written to match a set of target strings. A well formed pattern string conforms to a particular pattern syntax. This pattern syntax is directly based on the syntax used by the popular [path-to-regexp](https://github.com/pillarjs/path-to-regexp) JavaScript library. @@ -942,7 +952,7 @@ It can be [=parse a pattern string|parsed=] to produce a [=/part list=] which de A full wildcard `*` can also be used to match as much as possible, as in the pathname pattern "`/products/*`". -

Parsing patterns

+

Parsing pattern strings

Tokens

@@ -1956,7 +1966,7 @@ To promote consistency on the web platform, other documents integrating with thi 1. **Accept shorthands**. Most author patterns will be simple and straightforward. Accordingly, APIs should accept shorthands for those common cases and avoid the need for authors to take additional steps to transform these into complete {{URLPattern}} objects. 1. **Respect the base URL**. Just as URLs are generally parsed relative to a base URL for their environment (most commonly, a [=document base URL=]), URL patterns should respect this as well. The {{URLPattern}} constructor itself is an exception because it directly exposes the concept itself, similar to how the URL constructor does not respect the base URL even though the rest of the platform does. -1. **Be clear about regexp groups**. Some APIs may benefit from only allowing URL patterns which do not [=URLPattern/has regexp groups|have regexp groups=], for example, because user agents are likely to implement them in a different thread or process from those executing author script, and because of security or performance concerns, a JavaScript engine would not ordinarily run there. If so, this should be clearly documented (with reference to [=URLPattern/has regexp groups=]) and the operation should report an error as soon as possible (e.g., by throwing a JavaScript exception). If possible, this should be feature-detectable to allow for the possibility of this constraint being lifted in the future. Avoid creating different subsets of URL patterns without consulting the editors of this specification. +1. **Be clear about regexp groups**. Some APIs may benefit from only allowing URL patterns which do not [=URL pattern/has regexp groups|have regexp groups=], for example, because user agents are likely to implement them in a different thread or process from those executing author script, and because of security or performance concerns, a JavaScript engine would not ordinarily run there. If so, this should be clearly documented (with reference to [=URL pattern/has regexp groups=]) and the operation should report an error as soon as possible (e.g., by throwing a JavaScript exception). If possible, this should be feature-detectable to allow for the possibility of this constraint being lifted in the future. Avoid creating different subsets of URL patterns without consulting the editors of this specification. 1. **Be clear about what URLs will be matched**. For instance, algorithms during fetching are likely to operate on URLs with no [=url/fragment=]. If so, the specification should be clear that this is the case, and may advise showing a developer warning if a pattern which cannot match (e.g., because it requires a non-empty fragment) is used.

Integrating with JavaScript APIs

@@ -1973,23 +1983,28 @@ JavaScript APIs should accept all of: To accomplish this, specifications should accept {{URLPatternCompatible}} as an argument to an [=operation=] or [=dictionary member=], and process it using the following algorithm, using the appropriate [=environment settings object=]'s [=environment settings object/API base URL=] or equivalent.
- To build a {{URLPattern}} from a Web IDL value {{URLPatternCompatible}} |input| given [=/URL=] |baseURL| and [=ECMAScript/realm=] |realm|, perform the following steps: + To build a {{URLPattern}} object from a Web IDL value {{URLPatternCompatible}} |input| given [=/URL=] |baseURL| and [=ECMAScript/realm=] |realm|, perform the following steps: 1. If the [=specific type=] of |input| is {{URLPattern}}: 1. Return |input|. + 1. Otherwise: + 1. Let |pattern| be a [=new=] {{URLPattern}} with |realm|. + 1. Set |pattern|'s [=URLPattern/associated URL pattern=] to the result of [=building a URL pattern from a Web IDL value=] given |input| and |baseURL|. + 1. Return |pattern|. +
+ +
+ To build a [=URL pattern=] from a Web IDL value {{URLPatternCompatible}} |input| given [=/URL=] |baseURL|, perform the following steps: + + 1. If the [=specific type=] of |input| is {{URLPattern}}: + 1. Return |input|'s [=URLPattern/associated URL pattern=]. 1. Otherwise, if the [=specific type=] of |input| is {{URLPatternInit}}: 1. Let |init| be a [=map/clone=] of |input|. 1. If |init|["{{URLPatternInit/baseURL}}"] does not [=map/exist=], set it to the [=URL serializer|serialization=] of |baseURL|. - 1. Let |pattern| be a [=new=] {{URLPattern}} with |realm|. - 1. Run [=initialize=] given |pattern|, |init|, null, and an empty [=map=]. - 1. Return |pattern|. + 1. Return the result of [=creating=] a URL pattern given |init|, null, and an empty [=map=]. 1. Otherwise: 1. [=Assert=]: The [=specific type=] of |input| is {{USVString}}. - 1. Let |pattern| be a [=new=] {{URLPattern}} with |realm|. - 1. Run [=initialize=] given |pattern|, |input|, the [=URL serializer|serialization=] of |baseURL|, and an empty [=map=]. - 1. Return |pattern|. - -

Ideally we wouldn't need a realm here. If we extricate the URL pattern concept from the {{URLPattern}} interface, we won't anymore.

+ 1. Return the result of [=creating=] a URL pattern given |input|, the [=URL serializer|serialization=] of |baseURL|, and an empty [=map=].
This allows authors to concisely specify most patterns, and use the constructor to access uncommon options if necessary. The implicit use of the base URL is similar to, and consistent with, HTML's [=parse a URL=] algorithm. [[HTML]] @@ -2003,15 +2018,14 @@ JSON data formats which include URL patterns should mirror the behavior of - To build a {{URLPattern}} from an Infra value |rawPattern| given [=/URL=] |baseURL| and [=ECMAScript/realm=] |realm|, perform the following steps. + To build a [=URL pattern=] from an Infra value |rawPattern| given [=/URL=] |baseURL|, perform the following steps. 1. Let |serializedBaseURL| be the [=URL serializer|serialization=] of |baseURL|. 1. If |rawPattern| is a [=string=], then: - 1. Let |pattern| be a [=new=] {{URLPattern}} with |realm|. - 1. Run [=initialize=] given |pattern|, |rawPattern|, |serializedBaseURL|, and an empty [=map=]. + 1. Return the result of [=creating=] a URL pattern given |rawPattern|, |serializedBaseURL|, and an empty [=map=].
It may become necessary in the future to plumb non-empty options here.
- 1. Return |pattern|. + 1. Otherwise, if |rawPattern| is a [=map=], then: 1. Let |init| be «[ "{{URLPatternInit/baseURL}}" → |serializedBaseURL| ]», representing a dictionary of type {{URLPatternInit}}. 1. [=map/For each=] |key| → |value| of |rawPattern|: @@ -2020,14 +2034,12 @@ If a specification has an Infra value (e.g., after using [=parse a JSON string t
This will need to be updated if {{URLPatternInit}} gains members of other types.
A future version of this specification might also have a less strict mode, if that proves useful to other specifications.
1. Set |init|[|key|] to |value|. - 1. Let |pattern| be a [=new=] {{URLPattern}} with |realm|. - 1. Run [=initialize=] given |pattern|, |init|, null, and an empty [=map=]. + 1. Return the result of [=creating=] a URL pattern given |init|, null, and an empty [=map=].
It may become necessary in the future to plumb non-empty options here.
- 1. Return |pattern|. + 1. Otherwise, return null. -

Ideally we wouldn't need a realm here. If we extricate the URL pattern concept from the {{URLPattern}} interface, we won't anymore.

Specifications may wish to leave room in their formats to accept options for {{URLPatternOptions}}, override the base URL, or similar, since it is not possible to construct a {{URLPattern}} object directly in this case, unlike in a JavaScript API. For example, Speculation Rules accepts a "`relative_to`" key which can be used to switch to using the [=document base URL=] instead of the JSON resource's URL. [[SPECULATION-RULES]] @@ -2069,7 +2081,8 @@ Rajesh Jagannathan, Ralph Chelala, Sangwhan Moon, Sayan Pal, -Victor Costan, and +Victor Costan, +Yoshisato Yanagisawa, and Youenn Fablet for their contributors to this specification.