From 3f1fcee99176898cf0d361fb636db9eba3813873 Mon Sep 17 00:00:00 2001 From: Jeremy Roman Date: Mon, 20 Nov 2023 23:33:33 -0500 Subject: [PATCH 01/11] Add a section on other specs integrating with URLPattern A section which covers how other specifications should use URLPattern and how developer-facing APIs should work is added, along with helpful algorithms. One of these is whether a pattern has regexp groups (which may require an ECMAScript regexp engine); a corresponding WebIDL attribute is added to expose this property to authors as well. --- spec.bs | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 93 insertions(+), 1 deletion(-) diff --git a/spec.bs b/spec.bs index 6412b28..1c679ab 100644 --- a/spec.bs +++ b/spec.bs @@ -182,6 +182,8 @@ interface URLPattern { readonly attribute USVString pathname; readonly attribute USVString search; readonly attribute USVString hash; + + readonly attribute boolean hasRegExpGroups; }; dictionary URLPatternInit { @@ -323,6 +325,11 @@ Each {{URLPattern}} object has an associated hash component<

Returns |urlPattern|'s normalized hash pattern string.

+ +
|urlPattern|.{{URLPattern/hasRegExpGroups}}
+
+

Returns whether |urlPattern| contains one or more groups which uses regular expression matching. +

@@ -414,6 +421,13 @@ Each {{URLPattern}} object has an associated hash component< 1. Return [=this=]'s [=URLPattern/hash component=]'s [=component/pattern string=].
+
+ The hasRegExpGroups getter steps are: + + 1. If [=this=] [=URLPattern/has regexp groups=], then return true. + 1. Return false. +
+
The test(|input|, |baseURL|) method steps are: @@ -438,6 +452,8 @@ A [=component=] has an associated regular expression, a A [=component=] has an associated group name list, a [=list=] of strings, which must be set upon creation. +A [=component=] has an associated has regexp groups flag, a [=boolean=], which must be set upon creation. +
To compile a component given a string |input|, [=/encoding callback=] |encoding callback|, and [=/options=] |options|: @@ -450,7 +466,24 @@ A [=component=] has an associated group name list, a [= 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. Return a new [=component=] whose [=component/pattern string=] is |pattern string|, [=component/regular expression=] is |regular expression|, and [=component/group name list=] is |name list|. + 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 flag=] 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 flag=] is true, then return true. + 1. If |pattern|'s [=URLPattern/username component=] [=component/has regexp groups flag=] is true, then return true. + 1. If |pattern|'s [=URLPattern/password component=] [=component/has regexp groups flag=] is true, then return true. + 1. If |pattern|'s [=URLPattern/hostname component=] [=component/has regexp groups flag=] is true, then return true. + 1. If |pattern|'s [=URLPattern/port component=] [=component/has regexp groups flag=] is true, then return true. + 1. If |pattern|'s [=URLPattern/pathname component=] [=component/has regexp groups flag=] is true, then return true. + 1. If |pattern|'s [=URLPattern/search component=] [=component/has regexp groups flag=] is true, then return true. + 1. If |pattern|'s [=URLPattern/hash component=] [=component/has regexp groups flag=] is true, then return true. + 1. Return false.
@@ -1902,6 +1935,65 @@ To convert a modifier to a string given a [=part/modifier=] |modifier 1. Return the result of running [=canonicalize a hash=] given |strippedValue|.
+

Integrating with other specs

+ +To promote consistency on the web platform, other documents integrating with this specification should adhere to the following guidelines, unless there is good reason to diverge. + +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/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/hasRegExpGroups}}) 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

+ +JavaScript APIs should accept all of: +* a {{URLPattern}} object +* a dictionary-like object which specifies the components required to construct a pattern +* a string (in the constructor string syntax) + +To accomplish this, specifications should accept {{URLPatternInput}} 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 WebIDL value {{URLPatternInput}} |input| given [=URL=] |baseURL|, perform the following steps: + + 1. If the [=specific type=] of |input| is {{USVString}}: + 1. Return the result of constructing a {{URLPattern/constructor(input, baseURL, options)}} given |input| and the [=URL serializer|serialization=] of |baseURL|. + 1. Otherwise: + 1. [=Assert=]: the [=specific type=] of |input| is {{URLPatternInit}}. + 1. If |input|["`baseURL`"] does not [=map/exist=], set it to the [=URL serializer|serialization=] of |baseURL|. + 1. Return the result of constructing a {{URLPattern/constructor(input, options)}} given |input|. + +
Currently, {{URLPattern}} objects are not handled specially here, but perhaps they should be, since even though {{URLPattern}} has the properties necessary for {{URLPatternInit}}, this loses the {{URLPatternOptions/ignoreCase}} option (which is not exposed on the {{URLPattern}} interface). +
+ +This allows authors to concisely specify most patterns, and use the {{URLPattern/constructor|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. + +

Integrating with JSON data formats

+ +JSON data formats which include URL patterns should mirror the behavior of JavaScript APIs and accept both: +* an object which specifies the components required to construct a pattern +* a string (in the constructor string syntax) + +If a specification has an [[INFRA]] value (e.g., after using [=parse a JSON string to an Infra value=]), use the following algorithm, using the appropriate base URL (by default, the URL of the JSON resource). + +
+ To build a {{URLPattern}} 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. Return the result of constructing a {{URLPattern}} using the {{URLPattern/URLPattern(input, baseURL)}} constructor steps given |rawPattern| and |serializedBaseURL|. + 1. Otherwise, if |rawPattern| is a [=map=], then: + 1. Let |init| be «[ "`baseURL`" → |serializedBaseURL| ]», representing a dictionary of type {{URLPatternInit}}. + 1. [=map/For each=] |key| → |value| of |rawPattern|: + 1. If |key| is not the [=identifier=] of a [=dictionary member=] of {{URLPatternInit}} or one of its [=inherited dictionaries=], |value| is not a [=string=], or the member's type is not declared to be {{USVString}}, then return null. + +
This will need to be updated if {{URLPatternInit}} gains members of other types.
+ 1. Set |init|[|key|] to |value|. + 1. Return the result of constructing a {{URLPattern}} using the {{URLPattern/URLPattern(input, baseURL)}} constructor steps given |init|. +
+ +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. +

Acknowledgments

The editors would like to thank From 9ce9724200759fe15b7bee9a52fab0366f9c191f Mon Sep 17 00:00:00 2001 From: Jeremy Roman Date: Tue, 21 Nov 2023 00:10:45 -0500 Subject: [PATCH 02/11] fix closing tag --- spec.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec.bs b/spec.bs index 1c679ab..bc6c83f 100644 --- a/spec.bs +++ b/spec.bs @@ -1963,7 +1963,7 @@ To accomplish this, specifications should accept {{URLPatternInput}} as an argum 1. If |input|["`baseURL`"] does not [=map/exist=], set it to the [=URL serializer|serialization=] of |baseURL|. 1. Return the result of constructing a {{URLPattern/constructor(input, options)}} given |input|. -
Currently, {{URLPattern}} objects are not handled specially here, but perhaps they should be, since even though {{URLPattern}} has the properties necessary for {{URLPatternInit}}, this loses the {{URLPatternOptions/ignoreCase}} option (which is not exposed on the {{URLPattern}} interface). +
Currently, {{URLPattern}} objects are not handled specially here, but perhaps they should be, since even though {{URLPattern}} has the properties necessary for {{URLPatternInit}}, this loses the {{URLPatternOptions/ignoreCase}} option (which is not exposed on the {{URLPattern}} interface).
This allows authors to concisely specify most patterns, and use the {{URLPattern/constructor|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. From b04c9824d891d07c56c211d8d9e398b2950a4b70 Mon Sep 17 00:00:00 2001 From: Jeremy Roman Date: Tue, 21 Nov 2023 00:43:00 -0500 Subject: [PATCH 03/11] create a separate enum for use of other APIs, to accept URLPattern directly --- spec.bs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/spec.bs b/spec.bs index bc6c83f..8ed1546 100644 --- a/spec.bs +++ b/spec.bs @@ -164,6 +164,7 @@ It can be constructed using a string for each component, or from a shorthand str typedef (USVString or URLPatternInit) URLPatternInput; +typedef (USVString or URLPatternInit or URLPattern) URLPatternCompatible; [Exposed=(Window,Worker)] interface URLPattern { @@ -1951,19 +1952,19 @@ JavaScript APIs should accept all of: * a dictionary-like object which specifies the components required to construct a pattern * a string (in the constructor string syntax) -To accomplish this, specifications should accept {{URLPatternInput}} 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 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. <div algorithm> - To <dfn for=URLPattern>build a {{URLPattern}} from a WebIDL value</dfn> {{URLPatternInput}} |input| given [=URL=] |baseURL|, perform the following steps: + To <dfn for=URLPattern>build a {{URLPattern}} from a WebIDL value</dfn> {{URLPatternCompatible}} |input| given [=URL=] |baseURL|, perform the following steps: - 1. If the [=specific type=] of |input| is {{USVString}}: - 1. Return the result of constructing a {{URLPattern/constructor(input, baseURL, options)}} given |input| and the [=URL serializer|serialization=] of |baseURL|. - 1. Otherwise: - 1. [=Assert=]: the [=specific type=] of |input| is {{URLPatternInit}}. + 1. If the [=specific type=] of |input| is {{URLPattern}}: + 1. Return |input|. + 1. Otherwise, if the [=specific type=] of |input| is {{URLPatternInit}}: 1. If |input|["`baseURL`"] does not [=map/exist=], set it to the [=URL serializer|serialization=] of |baseURL|. 1. Return the result of constructing a {{URLPattern/constructor(input, options)}} given |input|. - - <div class=issue>Currently, {{URLPattern}} objects are not handled specially here, but perhaps they should be, since even though {{URLPattern}} has the properties necessary for {{URLPatternInit}}, this loses the {{URLPatternOptions/ignoreCase}} option (which is not exposed on the {{URLPattern}} interface).</div> + 1. Otherwise: + 1. [=Assert=]: The [=specific type=] of |input| is {{USVString}}: + 1. Return the result of constructing a {{URLPattern/constructor(input, baseURL, options)}} given |input| and the [=URL serializer|serialization=] of |baseURL|. </div> This allows authors to concisely specify most patterns, and use the {{URLPattern/constructor|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. From f8a6c4793a7544c9ec6c6849937cd637e7f5cfc9 Mon Sep 17 00:00:00 2001 From: Jeremy Roman <jbroman@chromium.org> Date: Tue, 21 Nov 2023 00:45:47 -0500 Subject: [PATCH 04/11] refer to URL absolutely --- spec.bs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec.bs b/spec.bs index 8ed1546..cc00d4c 100644 --- a/spec.bs +++ b/spec.bs @@ -1955,7 +1955,7 @@ 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. <div algorithm> - To <dfn for=URLPattern>build a {{URLPattern}} from a WebIDL value</dfn> {{URLPatternCompatible}} |input| given [=URL=] |baseURL|, perform the following steps: + To <dfn for=URLPattern>build a {{URLPattern}} from a WebIDL value</dfn> {{URLPatternCompatible}} |input| given [=/URL=] |baseURL|, perform the following steps: 1. If the [=specific type=] of |input| is {{URLPattern}}: 1. Return |input|. @@ -1978,7 +1978,7 @@ JSON data formats which include URL patterns should mirror the behavior of <a hr If a specification has an [[INFRA]] value (e.g., after using [=parse a JSON string to an Infra value=]), use the following algorithm, using the appropriate base URL (by default, the URL of the JSON resource). <div algorithm> - To <dfn for=URLPattern>build a {{URLPattern}} from an Infra value</dfn> |rawPattern| given [=URL=] |baseURL|, perform the following steps. + To <dfn for=URLPattern>build a {{URLPattern}} from an Infra value</dfn> |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: From ea0cadb0cae5f7dff3a4a59a6b5f792214df102f Mon Sep 17 00:00:00 2001 From: Jeremy Roman <jbroman@chromium.org> Date: Tue, 21 Nov 2023 00:48:49 -0500 Subject: [PATCH 05/11] fix refs --- spec.bs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec.bs b/spec.bs index cc00d4c..0e00de8 100644 --- a/spec.bs +++ b/spec.bs @@ -1941,8 +1941,8 @@ To <dfn>convert a modifier to a string</dfn> given a [=part/modifier=] |modifier To promote consistency on the web platform, other documents integrating with this specification should adhere to the following guidelines, unless there is good reason to diverge. 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/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/hasRegExpGroups}}) 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. **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 <a interface spec=URL>URL</a> 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/hasRegExpGroups}}) 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. <h3 id=integrating-javascript>Integrating with JavaScript APIs</h3> @@ -1986,7 +1986,7 @@ If a specification has an [[INFRA]] value (e.g., after using [=parse a JSON stri 1. Otherwise, if |rawPattern| is a [=map=], then: 1. Let |init| be «[ "`baseURL`" → |serializedBaseURL| ]», representing a dictionary of type {{URLPatternInit}}. 1. [=map/For each=] |key| → |value| of |rawPattern|: - 1. If |key| is not the [=identifier=] of a [=dictionary member=] of {{URLPatternInit}} or one of its [=inherited dictionaries=], |value| is not a [=string=], or the member's type is not declared to be {{USVString}}, then return null. + 1. If |key| is not the <a spec=webidl>identifier</a> of a <a spec=webidl>dictionary member</a> of {{URLPatternInit}} or one of its <a spec=webidl>inherited dictionaries</a>, |value| is not a [=string=], or the member's type is not declared to be {{USVString}}, then return null. <div class="note">This will need to be updated if {{URLPatternInit}} gains members of other types.</div> 1. Set |init|[|key|] to |value|. From 759f2aebe660eeccf60273e541175dd6654ad049 Mon Sep 17 00:00:00 2001 From: Jeremy Roman <jbroman@chromium.org> Date: Tue, 21 Nov 2023 01:44:49 -0500 Subject: [PATCH 06/11] misc review comments --- spec.bs | 74 +++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 48 insertions(+), 26 deletions(-) diff --git a/spec.bs b/spec.bs index 0e00de8..9f54060 100644 --- a/spec.bs +++ b/spec.bs @@ -164,7 +164,6 @@ It can be constructed using a string for each component, or from a shorthand str <xmp class="idl"> typedef (USVString or URLPatternInit) URLPatternInput; -typedef (USVString or URLPatternInit or URLPattern) URLPatternCompatible; [Exposed=(Window,Worker)] interface URLPattern { @@ -453,7 +452,7 @@ A [=component=] has an associated <dfn for=component>regular expression</dfn>, a A [=component=] has an associated <dfn for=component>group name list</dfn>, a [=list=] of strings, which must be set upon creation. -A [=component=] has an associated <dfn for=component>has regexp groups flag</dfn>, a [=boolean=], which must be set upon creation. +A [=component=] has an associated <dfn for=component>has regexp groups</dfn>, a [=boolean=], which must be set upon creation. <div algorithm> To <dfn>compile a component</dfn> given a string |input|, [=/encoding callback=] |encoding callback|, and [=/options=] |options|: @@ -470,20 +469,20 @@ A [=component=] has an associated <dfn for=component>has regexp groups flag</dfn 1. Let |has regexp groups| be false. 1. [=list/For each=] |part| of |part list|: 1. If |part|'s [=part/type=] is "<a for=token/type>`regexp`</a>", 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 flag=] is |has regexp groups|. + 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|. </div> <div algorithm> A {{URLPattern}} |pattern| <dfn for=URLPattern>has regexp groups</dfn> if the following steps return true: - 1. If |pattern|'s [=URLPattern/protocol component=] [=component/has regexp groups flag=] is true, then return true. - 1. If |pattern|'s [=URLPattern/username component=] [=component/has regexp groups flag=] is true, then return true. - 1. If |pattern|'s [=URLPattern/password component=] [=component/has regexp groups flag=] is true, then return true. - 1. If |pattern|'s [=URLPattern/hostname component=] [=component/has regexp groups flag=] is true, then return true. - 1. If |pattern|'s [=URLPattern/port component=] [=component/has regexp groups flag=] is true, then return true. - 1. If |pattern|'s [=URLPattern/pathname component=] [=component/has regexp groups flag=] is true, then return true. - 1. If |pattern|'s [=URLPattern/search component=] [=component/has regexp groups flag=] is true, then return true. - 1. If |pattern|'s [=URLPattern/hash component=] [=component/has regexp groups flag=] is true, then 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. </div> @@ -1936,16 +1935,20 @@ To <dfn>convert a modifier to a string</dfn> given a [=part/modifier=] |modifier 1. Return the result of running [=canonicalize a hash=] given |strippedValue|. </div> -<h2 id=integrating>Integrating with other specs</h2> +<h2 id=other-specs>Using URL patterns in other specifications</h2> To promote consistency on the web platform, other documents integrating with this specification should adhere to the following guidelines, unless there is good reason to diverge. 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 <a interface spec=URL>URL</a> 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/hasRegExpGroups}}) 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 [=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 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. -<h3 id=integrating-javascript>Integrating with JavaScript APIs</h3> +<h3 id=other-specs-javascript>Integrating with JavaScript APIs</h3> + +<xmp class="idl"> +typedef (USVString or URLPatternInit or URLPattern) URLPatternCompatible; + JavaScript APIs should accept all of: * a {{URLPattern}} object @@ -1955,45 +1958,64 @@ 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 WebIDL value {{URLPatternCompatible}} |input| given [=/URL=] |baseURL|, perform the following steps: + To build a {{URLPattern}} from a WebIDL 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, if the [=specific type=] of |input| is {{URLPatternInit}}: - 1. If |input|["`baseURL`"] does not [=map/exist=], set it to the [=URL serializer|serialization=] of |baseURL|. - 1. Return the result of constructing a {{URLPattern/constructor(input, options)}} given |input|. + 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. Otherwise: - 1. [=Assert=]: The [=specific type=] of |input| is {{USVString}}: - 1. Return the result of constructing a {{URLPattern/constructor(input, baseURL, options)}} given |input| and the [=URL serializer|serialization=] of |baseURL|. + 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.
-This allows authors to concisely specify most patterns, and use the {{URLPattern/constructor|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. +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. -

Integrating with JSON data formats

+

Integrating with JSON data formats

-JSON data formats which include URL patterns should mirror the behavior of JavaScript APIs and accept both: +JSON data formats which include URL patterns should mirror the behavior of JavaScript APIs and accept both: * an object which specifies the components required to construct a pattern * a string (in the constructor string syntax) If a specification has an [[INFRA]] value (e.g., after using [=parse a JSON string to an Infra value=]), use the following algorithm, using the appropriate base URL (by default, the URL of the JSON resource).
- To build a {{URLPattern}} from an Infra value |rawPattern| given [=/URL=] |baseURL|, perform the following steps. + To build a {{URLPattern}} from an Infra value |rawPattern| given [=/URL=] |baseURL| and [=ECMAScript/realm=] |realm|, perform the following steps. 1. Let |serializedBaseURL| be the [=URL serializer|serialization=] of |baseURL|. 1. If |rawPattern| is a [=string=], then: - 1. Return the result of constructing a {{URLPattern}} using the {{URLPattern/URLPattern(input, baseURL)}} constructor steps given |rawPattern| and |serializedBaseURL|. + 1. Let |pattern| be a [=new=] {{URLPattern}} with |realm|. + 1. Run [=initialize=] given |pattern|, |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 «[ "`baseURL`" → |serializedBaseURL| ]», representing a dictionary of type {{URLPatternInit}}. 1. [=map/For each=] |key| → |value| of |rawPattern|: 1. If |key| is not the identifier of a dictionary member of {{URLPatternInit}} or one of its inherited dictionaries, |value| is not a [=string=], or the member's type is not declared to be {{USVString}}, then return null.
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. Return the result of constructing a {{URLPattern}} using the {{URLPattern/URLPattern(input, baseURL)}} constructor steps given |init|. + 1. Let |pattern| be a [=new=] {{URLPattern}} with |realm|. + 1. Run [=initialize=] given |pattern|, |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. +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 uses the [=document base URL=] instead of the JSON resource's URL.

Acknowledgments

From a5c84508dbf057e3c2c7f1bd0163ca170d879530 Mon Sep 17 00:00:00 2001 From: Jeremy Roman Date: Tue, 21 Nov 2023 01:47:48 -0500 Subject: [PATCH 07/11] defeat the evil trailing whitespace --- spec.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec.bs b/spec.bs index 9f54060..3dd788b 100644 --- a/spec.bs +++ b/spec.bs @@ -1973,7 +1973,7 @@ To accomplish this, specifications should accept {{URLPatternCompatible}} as an 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.
From 262ed3872e6f0aacf0c7aa9b8fda98d1aebc4a1a Mon Sep 17 00:00:00 2001 From: Jeremy Roman Date: Tue, 21 Nov 2023 14:20:53 -0500 Subject: [PATCH 08/11] address review comments --- spec.bs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/spec.bs b/spec.bs index 3dd788b..2b35d95 100644 --- a/spec.bs +++ b/spec.bs @@ -468,7 +468,7 @@ A [=component=] has an associated has regexp groups, a 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. 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|.
@@ -1974,10 +1974,10 @@ To accomplish this, specifications should accept {{URLPatternCompatible}} as an 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.
+

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

-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. +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]]

Integrating with JSON data formats

@@ -1985,7 +1985,7 @@ 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. @@ -1998,7 +1998,7 @@ If a specification has an [[INFRA]] value (e.g., after using [=parse a JSON stri
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 «[ "`baseURL`" → |serializedBaseURL| ]», representing a dictionary of type {{URLPatternInit}}. + 1. Let |init| be «[ "{{URLPatternInit/baseURL}}" → |serializedBaseURL| ]», representing a dictionary of type {{URLPatternInit}}. 1. [=map/For each=] |key| → |value| of |rawPattern|: 1. If |key| is not the
identifier of a dictionary member of {{URLPatternInit}} or one of its inherited dictionaries, |value| is not a [=string=], or the member's type is not declared to be {{USVString}}, then return null. @@ -2012,10 +2012,10 @@ If a specification has an [[INFRA]] value (e.g., after using [=parse a JSON stri 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.
+

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 uses the [=document base URL=] instead of the JSON resource's URL. +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]]

Acknowledgments

From 2b2afdd591b8823326639bb1d7758bfdf7b67b2f Mon Sep 17 00:00:00 2001 From: Jeremy Roman Date: Wed, 22 Nov 2023 11:54:03 -0500 Subject: [PATCH 09/11] --- spec.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec.bs b/spec.bs index 2b35d95..732e393 100644 --- a/spec.bs +++ b/spec.bs @@ -2015,7 +2015,7 @@ If a specification has an Infra value (e.g., after using [=parse a JSON string t

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]] +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]]

Acknowledgments

From c0c0204cd8d5eb88ec21d2864d2c60f8fd66a899 Mon Sep 17 00:00:00 2001 From: Jeremy Roman Date: Wed, 29 Nov 2023 15:35:25 -0500 Subject: [PATCH 10/11] review comments --- spec.bs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec.bs b/spec.bs index 732e393..d1e97de 100644 --- a/spec.bs +++ b/spec.bs @@ -473,7 +473,7 @@ A [=component=] has an associated has regexp groups, a
- A {{URLPattern}} |pattern| has regexp groups if the following steps return true: + 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. @@ -1958,7 +1958,7 @@ 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 WebIDL value {{URLPatternCompatible}} |input| given [=/URL=] |baseURL| and [=ECMAScript/realm=] |realm|, perform the following steps: + To build a {{URLPattern}} from a WebIDL 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|. @@ -1988,7 +1988,7 @@ 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 {{URLPattern}} from an Infra value |rawPattern| given [=/URL=] |baseURL| and [=ECMAScript/realm=] |realm|, perform the following steps. 1. Let |serializedBaseURL| be the [=URL serializer|serialization=] of |baseURL|. 1. If |rawPattern| is a [=string=], then: From 0dd8dc06f6b9dec9c8ed72fd0c13fb5d1509bd81 Mon Sep 17 00:00:00 2001 From: Jeremy Roman Date: Wed, 29 Nov 2023 21:11:06 -0500 Subject: [PATCH 11/11] export match --- spec.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec.bs b/spec.bs index d1e97de..ee63e05 100644 --- a/spec.bs +++ b/spec.bs @@ -487,7 +487,7 @@ A [=component=] has an associated has regexp groups, a
- To perform a match given a {{URLPattern}} |urlpattern|, a {{URLPatternInput}} |input|, and an optional string |baseURLString|: + To perform a match given a {{URLPattern}} |urlpattern|, a {{URLPatternInput}} |input|, and an optional string |baseURLString|: 1. Let |protocol| be the empty string. 1. Let |username| be the empty string.