Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support for case-insensitive matches #168

Merged
merged 8 commits into from
Sep 22, 2022
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 35 additions & 9 deletions spec.bs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ spec: ECMASCRIPT; urlPrefix: https://tc39.es/ecma262/
text: RegExpBuiltinExec; url: #sec-regexpbuiltinexec
text: RegExpCreate; url: #sec-regexpcreate
text: ToString; url: #sec-tostring
text: Object.assign; url: #sec-object.assign
type: dfn
text: IdentifierPart; url: #prod-IdentifierPart
text: IdentifierStart; url: #prod-IdentifierStart
Expand Down Expand Up @@ -120,7 +121,7 @@ typedef (USVString or URLPatternInit) URLPatternInput;

[Exposed=(Window,Worker)]
interface URLPattern {
constructor(optional URLPatternInput input = {}, optional USVString baseURL);
constructor(optional URLPatternInput input = {}, optional USVString baseURL, optional URLPatternOptions options = {});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we also need a second constructor form to do what you want:

 constructor(optional URLPatternInput input = {}, optional URLPatternOptions options = {});

Otherwise you cannot specify options without also specifying a base URL second arg.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm going to fix this in a follow-up commit.


boolean test(optional URLPatternInput input = {}, optional USVString baseURL);

Expand Down Expand Up @@ -148,6 +149,10 @@ dictionary URLPatternInit {
USVString baseURL;
};

dictionary URLPatternOptions {
boolean ignoreCase;
wanderview marked this conversation as resolved.
Show resolved Hide resolved
};

dictionary URLPatternResult {
sequence<URLPatternInput> inputs;

Expand Down Expand Up @@ -184,16 +189,28 @@ Each {{URLPattern}} object has an associated <dfn for=URLPattern>search componen
Each {{URLPattern}} object has an associated <dfn for=URLPattern>hash component</dfn>, a [=component=], which must be set upon creation.

<dl class="domintro non-normative">
<dt><code>|urlPattern| = new {{URLPattern/constructor(input, baseURL)|URLPattern}}(|input|)</code></dt>
<dt><code>|urlPattern| = new {{URLPattern/constructor(input, baseURL, options)|URLPattern}}(|input|)</code></dt>
<dd>
Constructs a new {{URLPattern}} object. The |input| is an object containing separate patterns for each URL component; e.g. hostname, pathname, etc. Missing components will default to a wildcard pattern. In addition, |input| can contain a {{URLPatternInit/baseURL}} property that provides static text patterns for any missing components.
</dd>

<dt><code>|urlPattern| = new {{URLPattern/constructor(input, baseURL)|URLPattern}}(|patternString|, |baseURL|)</code></dt>
<dt><code>|urlPattern| = new {{URLPattern/constructor(input, baseURL, options)|URLPattern}}(|patternString|, |baseURL|)</code></dt>
<dd>
Constructs a new {{URLPattern}} object. |patternString| is a URL string containing pattern syntax for one or more components. If |baseURL| is provided, then |patternString| can be relative. This constructor will always set at least an empty string value and does not default any components to wildcard patterns.
</dd>

<dt><code>|urlPattern| = new {{URLPattern/constructor(input, baseURL, options)|URLPattern}}(|input|, |options|)</code></dt>
<dd>
Constructs a new {{URLPattern}} object. The |options| is an object containing the additional configuration options that can affect how the components are matched. Currently it has only one property {{URLPatternOptions/ignoreCase}} which can be set to true to have case-insensitive matching for pathname, search, and hash.
wanderview marked this conversation as resolved.
Show resolved Hide resolved

Note that by default, that is in the absence of the |options| argument, matching is always case-sensitive.
</dd>

<dt><code>|urlPattern| = new {{URLPattern/constructor(input, baseURL, options)|URLPattern}}(|input|, |baseURL|, |options|)</code></dt>
wanderview marked this conversation as resolved.
Show resolved Hide resolved
<dd>
Constructs a new {{URLPattern}} object just like the previous overload, additionally supporting |baseURL|.
wanderview marked this conversation as resolved.
Show resolved Hide resolved
</dd>

<dt><code>|matches| = |urlPattern|.{{URLPattern/test(input, baseURL)|test}}(|input|)</code></dt>
<dd>
Tests if |urlPattern| matches the given arguments. The |input| is an object containing strings representing each URL component; e.g. hostname, pathname, etc. Missing components are treated as empty strings. In addition, |input| can contain a {{URLPatternInit/baseURL}} property that provides values for any missing components. If |urlPattern| matches the |input| on a component-by-component basis then true is returned. Otherwise, false is returned.
Expand Down Expand Up @@ -262,7 +279,7 @@ Each {{URLPattern}} object has an associated <dfn for=URLPattern>hash component<
</dl>

<div algorithm>
The <dfn constructor for=URLPattern lt="URLPattern(input, baseURL)">new URLPattern(|input|, |baseURL|)</dfn> constructor steps are:
The <dfn constructor for=URLPattern lt="URLPattern(input, baseURL, options)">new URLPattern(|input|, |baseURL|, |options|)</dfn> constructor steps are:

1. Let |init| be null.
1. If |input| is a [=scalar value string=] then:
Expand All @@ -273,6 +290,9 @@ Each {{URLPattern}} object has an associated <dfn for=URLPattern>hash component<
1. [=Assert=]: |input| is a {{URLPatternInit}}.
1. If |baseURL| is given, then throw a {{TypeError}}.
1. Set |init| to |input|.
1. Let |ignoreCase| be false.
wanderview marked this conversation as resolved.
Show resolved Hide resolved
1. If |options| has a boolean {{URLPatternOptions/ignoreCase}} property then:
1. Set |ignoreCase| to |options|["{{URLPatternOptions/ignoreCase}}"].
1. Let |processedInit| be the result of [=process a URLPatternInit=] given |init|, "`pattern`", null, null, null, null, null, null, null, and null.
1. If |processedInit|["{{URLPatternInit/protocol}}"] is a [=special scheme=] and |processedInit|["{{URLPatternInit/port}}"] is its corresponding [=default port=], 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=].
Expand All @@ -281,10 +301,13 @@ Each {{URLPattern}} object has an associated <dfn for=URLPattern>hash component<
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. Else, 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. If the result of running [=protocol component matches a special scheme=] given [=this=]'s [=URLPattern/protocol component=] is true, then set [=this=]'s [=URLPattern/pathname component=] to the result of [=compiling a component=] given |processedInit|["{{URLPatternInit/pathname}}"], [=canonicalize a pathname=], and [=pathname options=].
1. Else set [=this=]'s [=URLPattern/pathname component=] to the result of [=compiling a component=] given |processedInit|["{{URLPatternInit/pathname}}"], [=canonicalize an opaque pathname=], and [=default options=]
1. Set [=this=]'s [=URLPattern/search component=] to the result of [=compiling a component=] given |processedInit|["{{URLPatternInit/search}}"], [=canonicalize a search=], and [=default options=].
1. Set [=this=]'s [=URLPattern/hash component=] to the result of [=compiling a component=] given |processedInit|["{{URLPatternInit/hash}}"], [=canonicalize a hash=], and [=default options=].
1. Let |defaultOptions| be the result of running [$Object.assign$]({}, [=default options=], {sensitive: !ignoreCase})
wanderview marked this conversation as resolved.
Show resolved Hide resolved
wanderview marked this conversation as resolved.
Show resolved Hide resolved
wanderview marked this conversation as resolved.
Show resolved Hide resolved
1. If the result of running [=protocol component matches a special scheme=] given [=this=]'s [=URLPattern/protocol component=] is true, then:
1. Let |pathOptions| be the result of running [$Object.assign$]({}, [=pathname options=], {sensitive: !ignoreCase}).
1. Set [=this=]'s [=URLPattern/pathname component=] to the result of [=compiling a component=] given |processedInit|["{{URLPatternInit/pathname}}"], [=canonicalize a pathname=], and |pathOptions|.
1. Else set [=this=]'s [=URLPattern/pathname component=] to the result of [=compiling a component=] given |processedInit|["{{URLPatternInit/pathname}}"], [=canonicalize an opaque pathname=], and |defaultOptions|.
1. Set [=this=]'s [=URLPattern/search component=] to the result of [=compiling a component=] given |processedInit|["{{URLPatternInit/search}}"], [=canonicalize a search=], and |defaultOptions|.
1. Set [=this=]'s [=URLPattern/hash component=] to the result of [=compiling a component=] given |processedInit|["{{URLPatternInit/hash}}"], [=canonicalize a hash=], and |defaultOptions|.
</div>

<div algorithm>
Expand Down Expand Up @@ -365,7 +388,10 @@ A [=component=] has an associated <dfn for=component>group name list</dfn>, a [=
1. If |input| is null, then set |input| to "`*`".
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 |regular expression| be [$RegExpCreate$](|regular expression string|, "`u`"). If this throws an exception, catch it, and throw a {{TypeError}}.
1. Let |flags| be an empty string.
1. If |options|["sensitive"] is true then set |flags| to "`u`".
1. Else set |flags| to "`ui`"
1. Let |regular expression| be [$RegExpCreate$](|regular expression string|, |flags|). If this throws an exception, catch it, and throw a {{TypeError}}.
<p class="note allow-2119">The specification uses regular expressions to perform all matching, but this is not required. 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 should 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|.
Expand Down