Start implementing the URLPattern API (#36144)

* Start working on a basic URLPattern implementation

This is API part of Interop 2025, so we should definitely support it!

This change implements the basic workflow for parsing
and compiling URL patterns. Parts of it are stubbed out and will be
implemented later.

For now the API is preference-gated behind "dom_urlpattern_enabled".

Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>

* Preference-gate the URLPattern API

Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>

* Update WPT expectations

Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>

* Fix full wildcard value (Should be ".*" not "*")

Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>

---------

Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
This commit is contained in:
Simon Wülker 2025-03-27 11:39:57 +01:00 committed by GitHub
parent e4efdfe668
commit 517f99e067
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 906 additions and 189 deletions

View file

@ -1 +1 @@
prefs: ["dom_imagebitmap_enabled:true", "dom_offscreen_canvas_enabled:true", "dom_xpath_enabled:true", "dom_intersection_observer_enabled:true", "dom_resize_observer_enabled:true", "dom_notification_enabled:true", "dom_fontface_enabled:true"]
prefs: ["dom_imagebitmap_enabled:true", "dom_offscreen_canvas_enabled:true", "dom_xpath_enabled:true", "dom_intersection_observer_enabled:true", "dom_resize_observer_enabled:true", "dom_notification_enabled:true", "dom_fontface_enabled:true", "dom_urlpattern_enabled:true"]

View file

@ -464,9 +464,6 @@
[Pattern: ["http://🚲.com/"\] Inputs: ["http://🚲.com/"\]]
expected: FAIL
[Pattern: ["http://\\ud83d \\udeb2"\] Inputs: undefined]
expected: FAIL
[Pattern: [{"hostname":"\\ud83d \\udeb2"}\] Inputs: undefined]
expected: FAIL
@ -629,12 +626,6 @@
[Pattern: ["/foo?bar#baz","https://example.com:8080"\] Inputs: [{"pathname":"/foo","search":"bar","hash":"baz","baseURL":"https://example.com:8080"}\]]
expected: FAIL
[Pattern: ["/foo"\] Inputs: undefined]
expected: FAIL
[Pattern: ["example.com/foo"\] Inputs: undefined]
expected: FAIL
[Pattern: ["http{s}?://{*.}?example.com/:product/:endpoint"\] Inputs: ["https://sub.example.com/foo/bar"\]]
expected: FAIL
@ -683,33 +674,18 @@
[Pattern: ["https://example.com/"\] Inputs: ["https://example.com:8080/"\]]
expected: FAIL
[Pattern: ["data:foobar"\] Inputs: ["data:foobar"\]]
expected: FAIL
[Pattern: ["data\\\\:foobar"\] Inputs: ["data:foobar"\]]
expected: FAIL
[Pattern: ["https://{sub.}?example.com/foo"\] Inputs: ["https://example.com/foo"\]]
expected: FAIL
[Pattern: ["https://{sub.}?example{.com/}foo"\] Inputs: ["https://example.com/foo"\]]
expected: FAIL
[Pattern: ["{https://}example.com/foo"\] Inputs: ["https://example.com/foo"\]]
expected: FAIL
[Pattern: ["https://(sub.)?example.com/foo"\] Inputs: ["https://example.com/foo"\]]
expected: FAIL
[Pattern: ["https://(sub.)?example(.com/)foo"\] Inputs: ["https://example.com/foo"\]]
expected: FAIL
[Pattern: ["(https://)example.com/foo"\] Inputs: ["https://example.com/foo"\]]
expected: FAIL
[Pattern: ["https://{sub{.}}example.com/foo"\] Inputs: ["https://example.com/foo"\]]
expected: FAIL
[Pattern: ["https://(sub(?:.))?example.com/foo"\] Inputs: ["https://example.com/foo"\]]
expected: FAIL
@ -722,9 +698,6 @@
[Pattern: ["foo://bar"\] Inputs: ["foo://bad_url_browser_interop"\]]
expected: FAIL
[Pattern: ["(café)://foo"\] Inputs: undefined]
expected: FAIL
[Pattern: ["https://example.com/foo?bar#baz"\] Inputs: [{"protocol":"https:","search":"?bar","hash":"#baz","baseURL":"http://example.com/foo"}\]]
expected: FAIL
@ -812,27 +785,12 @@
[Pattern: [{"hostname":"*\\\\:1\]"}\] Inputs: undefined]
expected: FAIL
[Pattern: ["https://foo{{@}}example.com"\] Inputs: ["https://foo@example.com"\]]
expected: FAIL
[Pattern: ["https://foo{@example.com"\] Inputs: ["https://foo@example.com"\]]
expected: FAIL
[Pattern: ["data\\\\:text/javascript,let x = 100/:tens?5;"\] Inputs: ["data:text/javascript,let x = 100/5;"\]]
expected: FAIL
[Pattern: [{"pathname":"/:id/:id"}\] Inputs: undefined]
expected: FAIL
[Pattern: [{"pathname":"/foo","baseURL":""}\] Inputs: undefined]
expected: FAIL
[Pattern: ["/foo",""\] Inputs: undefined]
expected: FAIL
[Pattern: [{"pathname":"/foo"},"https://example.com"\] Inputs: undefined]
expected: FAIL
[Pattern: [{"pathname":":name*"}\] Inputs: [{"pathname":"foobar"}\]]
expected: FAIL
@ -1022,9 +980,6 @@
[Pattern: ["/foo?bar#baz","https://example.com:8080",{"ignoreCase":true}\] Inputs: [{"pathname":"/FOO","search":"BAR","hash":"BAZ","baseURL":"https://example.com:8080"}\]]
expected: FAIL
[Pattern: ["/foo?bar#baz",{"ignoreCase":true},"https://example.com:8080"\] Inputs: [{"pathname":"/FOO","search":"BAR","hash":"BAZ","baseURL":"https://example.com:8080"}\]]
expected: FAIL
[Pattern: [{"search":"foo","baseURL":"https://example.com/a/+/b"}\] Inputs: [{"search":"foo","baseURL":"https://example.com/a/+/b"}\]]
expected: FAIL
@ -1516,9 +1471,6 @@
[Pattern: ["http://🚲.com/"\] Inputs: ["http://🚲.com/"\]]
expected: FAIL
[Pattern: ["http://\\ud83d \\udeb2"\] Inputs: undefined]
expected: FAIL
[Pattern: [{"hostname":"\\ud83d \\udeb2"}\] Inputs: undefined]
expected: FAIL
@ -1681,12 +1633,6 @@
[Pattern: ["/foo?bar#baz","https://example.com:8080"\] Inputs: [{"pathname":"/foo","search":"bar","hash":"baz","baseURL":"https://example.com:8080"}\]]
expected: FAIL
[Pattern: ["/foo"\] Inputs: undefined]
expected: FAIL
[Pattern: ["example.com/foo"\] Inputs: undefined]
expected: FAIL
[Pattern: ["http{s}?://{*.}?example.com/:product/:endpoint"\] Inputs: ["https://sub.example.com/foo/bar"\]]
expected: FAIL
@ -1735,33 +1681,18 @@
[Pattern: ["https://example.com/"\] Inputs: ["https://example.com:8080/"\]]
expected: FAIL
[Pattern: ["data:foobar"\] Inputs: ["data:foobar"\]]
expected: FAIL
[Pattern: ["data\\\\:foobar"\] Inputs: ["data:foobar"\]]
expected: FAIL
[Pattern: ["https://{sub.}?example.com/foo"\] Inputs: ["https://example.com/foo"\]]
expected: FAIL
[Pattern: ["https://{sub.}?example{.com/}foo"\] Inputs: ["https://example.com/foo"\]]
expected: FAIL
[Pattern: ["{https://}example.com/foo"\] Inputs: ["https://example.com/foo"\]]
expected: FAIL
[Pattern: ["https://(sub.)?example.com/foo"\] Inputs: ["https://example.com/foo"\]]
expected: FAIL
[Pattern: ["https://(sub.)?example(.com/)foo"\] Inputs: ["https://example.com/foo"\]]
expected: FAIL
[Pattern: ["(https://)example.com/foo"\] Inputs: ["https://example.com/foo"\]]
expected: FAIL
[Pattern: ["https://{sub{.}}example.com/foo"\] Inputs: ["https://example.com/foo"\]]
expected: FAIL
[Pattern: ["https://(sub(?:.))?example.com/foo"\] Inputs: ["https://example.com/foo"\]]
expected: FAIL
@ -1774,9 +1705,6 @@
[Pattern: ["foo://bar"\] Inputs: ["foo://bad_url_browser_interop"\]]
expected: FAIL
[Pattern: ["(café)://foo"\] Inputs: undefined]
expected: FAIL
[Pattern: ["https://example.com/foo?bar#baz"\] Inputs: [{"protocol":"https:","search":"?bar","hash":"#baz","baseURL":"http://example.com/foo"}\]]
expected: FAIL
@ -1864,27 +1792,12 @@
[Pattern: [{"hostname":"*\\\\:1\]"}\] Inputs: undefined]
expected: FAIL
[Pattern: ["https://foo{{@}}example.com"\] Inputs: ["https://foo@example.com"\]]
expected: FAIL
[Pattern: ["https://foo{@example.com"\] Inputs: ["https://foo@example.com"\]]
expected: FAIL
[Pattern: ["data\\\\:text/javascript,let x = 100/:tens?5;"\] Inputs: ["data:text/javascript,let x = 100/5;"\]]
expected: FAIL
[Pattern: [{"pathname":"/:id/:id"}\] Inputs: undefined]
expected: FAIL
[Pattern: [{"pathname":"/foo","baseURL":""}\] Inputs: undefined]
expected: FAIL
[Pattern: ["/foo",""\] Inputs: undefined]
expected: FAIL
[Pattern: [{"pathname":"/foo"},"https://example.com"\] Inputs: undefined]
expected: FAIL
[Pattern: [{"pathname":":name*"}\] Inputs: [{"pathname":"foobar"}\]]
expected: FAIL
@ -2074,9 +1987,6 @@
[Pattern: ["/foo?bar#baz","https://example.com:8080",{"ignoreCase":true}\] Inputs: [{"pathname":"/FOO","search":"BAR","hash":"BAZ","baseURL":"https://example.com:8080"}\]]
expected: FAIL
[Pattern: ["/foo?bar#baz",{"ignoreCase":true},"https://example.com:8080"\] Inputs: [{"pathname":"/FOO","search":"BAR","hash":"BAZ","baseURL":"https://example.com:8080"}\]]
expected: FAIL
[Pattern: [{"search":"foo","baseURL":"https://example.com/a/+/b"}\] Inputs: [{"search":"foo","baseURL":"https://example.com/a/+/b"}\]]
expected: FAIL

View file

@ -467,9 +467,6 @@
[Pattern: ["http://🚲.com/"\] Inputs: ["http://🚲.com/"\]]
expected: FAIL
[Pattern: ["http://\\ud83d \\udeb2"\] Inputs: undefined]
expected: FAIL
[Pattern: [{"hostname":"\\ud83d \\udeb2"}\] Inputs: undefined]
expected: FAIL
@ -632,12 +629,6 @@
[Pattern: ["/foo?bar#baz","https://example.com:8080"\] Inputs: [{"pathname":"/foo","search":"bar","hash":"baz","baseURL":"https://example.com:8080"}\]]
expected: FAIL
[Pattern: ["/foo"\] Inputs: undefined]
expected: FAIL
[Pattern: ["example.com/foo"\] Inputs: undefined]
expected: FAIL
[Pattern: ["http{s}?://{*.}?example.com/:product/:endpoint"\] Inputs: ["https://sub.example.com/foo/bar"\]]
expected: FAIL
@ -686,33 +677,18 @@
[Pattern: ["https://example.com/"\] Inputs: ["https://example.com:8080/"\]]
expected: FAIL
[Pattern: ["data:foobar"\] Inputs: ["data:foobar"\]]
expected: FAIL
[Pattern: ["data\\\\:foobar"\] Inputs: ["data:foobar"\]]
expected: FAIL
[Pattern: ["https://{sub.}?example.com/foo"\] Inputs: ["https://example.com/foo"\]]
expected: FAIL
[Pattern: ["https://{sub.}?example{.com/}foo"\] Inputs: ["https://example.com/foo"\]]
expected: FAIL
[Pattern: ["{https://}example.com/foo"\] Inputs: ["https://example.com/foo"\]]
expected: FAIL
[Pattern: ["https://(sub.)?example.com/foo"\] Inputs: ["https://example.com/foo"\]]
expected: FAIL
[Pattern: ["https://(sub.)?example(.com/)foo"\] Inputs: ["https://example.com/foo"\]]
expected: FAIL
[Pattern: ["(https://)example.com/foo"\] Inputs: ["https://example.com/foo"\]]
expected: FAIL
[Pattern: ["https://{sub{.}}example.com/foo"\] Inputs: ["https://example.com/foo"\]]
expected: FAIL
[Pattern: ["https://(sub(?:.))?example.com/foo"\] Inputs: ["https://example.com/foo"\]]
expected: FAIL
@ -725,9 +701,6 @@
[Pattern: ["foo://bar"\] Inputs: ["foo://bad_url_browser_interop"\]]
expected: FAIL
[Pattern: ["(café)://foo"\] Inputs: undefined]
expected: FAIL
[Pattern: ["https://example.com/foo?bar#baz"\] Inputs: [{"protocol":"https:","search":"?bar","hash":"#baz","baseURL":"http://example.com/foo"}\]]
expected: FAIL
@ -815,27 +788,12 @@
[Pattern: [{"hostname":"*\\\\:1\]"}\] Inputs: undefined]
expected: FAIL
[Pattern: ["https://foo{{@}}example.com"\] Inputs: ["https://foo@example.com"\]]
expected: FAIL
[Pattern: ["https://foo{@example.com"\] Inputs: ["https://foo@example.com"\]]
expected: FAIL
[Pattern: ["data\\\\:text/javascript,let x = 100/:tens?5;"\] Inputs: ["data:text/javascript,let x = 100/5;"\]]
expected: FAIL
[Pattern: [{"pathname":"/:id/:id"}\] Inputs: undefined]
expected: FAIL
[Pattern: [{"pathname":"/foo","baseURL":""}\] Inputs: undefined]
expected: FAIL
[Pattern: ["/foo",""\] Inputs: undefined]
expected: FAIL
[Pattern: [{"pathname":"/foo"},"https://example.com"\] Inputs: undefined]
expected: FAIL
[Pattern: [{"pathname":":name*"}\] Inputs: [{"pathname":"foobar"}\]]
expected: FAIL
@ -1025,9 +983,6 @@
[Pattern: ["/foo?bar#baz","https://example.com:8080",{"ignoreCase":true}\] Inputs: [{"pathname":"/FOO","search":"BAR","hash":"BAZ","baseURL":"https://example.com:8080"}\]]
expected: FAIL
[Pattern: ["/foo?bar#baz",{"ignoreCase":true},"https://example.com:8080"\] Inputs: [{"pathname":"/FOO","search":"BAR","hash":"BAZ","baseURL":"https://example.com:8080"}\]]
expected: FAIL
[Pattern: [{"search":"foo","baseURL":"https://example.com/a/+/b"}\] Inputs: [{"search":"foo","baseURL":"https://example.com/a/+/b"}\]]
expected: FAIL
@ -1516,9 +1471,6 @@
[Pattern: ["http://🚲.com/"\] Inputs: ["http://🚲.com/"\]]
expected: FAIL
[Pattern: ["http://\\ud83d \\udeb2"\] Inputs: undefined]
expected: FAIL
[Pattern: [{"hostname":"\\ud83d \\udeb2"}\] Inputs: undefined]
expected: FAIL
@ -1681,12 +1633,6 @@
[Pattern: ["/foo?bar#baz","https://example.com:8080"\] Inputs: [{"pathname":"/foo","search":"bar","hash":"baz","baseURL":"https://example.com:8080"}\]]
expected: FAIL
[Pattern: ["/foo"\] Inputs: undefined]
expected: FAIL
[Pattern: ["example.com/foo"\] Inputs: undefined]
expected: FAIL
[Pattern: ["http{s}?://{*.}?example.com/:product/:endpoint"\] Inputs: ["https://sub.example.com/foo/bar"\]]
expected: FAIL
@ -1735,33 +1681,18 @@
[Pattern: ["https://example.com/"\] Inputs: ["https://example.com:8080/"\]]
expected: FAIL
[Pattern: ["data:foobar"\] Inputs: ["data:foobar"\]]
expected: FAIL
[Pattern: ["data\\\\:foobar"\] Inputs: ["data:foobar"\]]
expected: FAIL
[Pattern: ["https://{sub.}?example.com/foo"\] Inputs: ["https://example.com/foo"\]]
expected: FAIL
[Pattern: ["https://{sub.}?example{.com/}foo"\] Inputs: ["https://example.com/foo"\]]
expected: FAIL
[Pattern: ["{https://}example.com/foo"\] Inputs: ["https://example.com/foo"\]]
expected: FAIL
[Pattern: ["https://(sub.)?example.com/foo"\] Inputs: ["https://example.com/foo"\]]
expected: FAIL
[Pattern: ["https://(sub.)?example(.com/)foo"\] Inputs: ["https://example.com/foo"\]]
expected: FAIL
[Pattern: ["(https://)example.com/foo"\] Inputs: ["https://example.com/foo"\]]
expected: FAIL
[Pattern: ["https://{sub{.}}example.com/foo"\] Inputs: ["https://example.com/foo"\]]
expected: FAIL
[Pattern: ["https://(sub(?:.))?example.com/foo"\] Inputs: ["https://example.com/foo"\]]
expected: FAIL
@ -1774,9 +1705,6 @@
[Pattern: ["foo://bar"\] Inputs: ["foo://bad_url_browser_interop"\]]
expected: FAIL
[Pattern: ["(café)://foo"\] Inputs: undefined]
expected: FAIL
[Pattern: ["https://example.com/foo?bar#baz"\] Inputs: [{"protocol":"https:","search":"?bar","hash":"#baz","baseURL":"http://example.com/foo"}\]]
expected: FAIL
@ -1864,27 +1792,12 @@
[Pattern: [{"hostname":"*\\\\:1\]"}\] Inputs: undefined]
expected: FAIL
[Pattern: ["https://foo{{@}}example.com"\] Inputs: ["https://foo@example.com"\]]
expected: FAIL
[Pattern: ["https://foo{@example.com"\] Inputs: ["https://foo@example.com"\]]
expected: FAIL
[Pattern: ["data\\\\:text/javascript,let x = 100/:tens?5;"\] Inputs: ["data:text/javascript,let x = 100/5;"\]]
expected: FAIL
[Pattern: [{"pathname":"/:id/:id"}\] Inputs: undefined]
expected: FAIL
[Pattern: [{"pathname":"/foo","baseURL":""}\] Inputs: undefined]
expected: FAIL
[Pattern: ["/foo",""\] Inputs: undefined]
expected: FAIL
[Pattern: [{"pathname":"/foo"},"https://example.com"\] Inputs: undefined]
expected: FAIL
[Pattern: [{"pathname":":name*"}\] Inputs: [{"pathname":"foobar"}\]]
expected: FAIL
@ -2074,9 +1987,6 @@
[Pattern: ["/foo?bar#baz","https://example.com:8080",{"ignoreCase":true}\] Inputs: [{"pathname":"/FOO","search":"BAR","hash":"BAZ","baseURL":"https://example.com:8080"}\]]
expected: FAIL
[Pattern: ["/foo?bar#baz",{"ignoreCase":true},"https://example.com:8080"\] Inputs: [{"pathname":"/FOO","search":"BAR","hash":"BAZ","baseURL":"https://example.com:8080"}\]]
expected: FAIL
[Pattern: [{"search":"foo","baseURL":"https://example.com/a/+/b"}\] Inputs: [{"search":"foo","baseURL":"https://example.com/a/+/b"}\]]
expected: FAIL

View file

@ -13503,14 +13503,14 @@
]
],
"interfaces.https.html": [
"ad0b03ac70483c152220978cee8b49e74b330fc6",
"3c6184a527d0f5b993e753ce22012210c56a40e5",
[
null,
{}
]
],
"interfaces.worker.js": [
"f93f9c9f6c877e1915217b64591fe7e34fa7244c",
"dde3a2cb97675c27d292fb3f15e98bc383d58a4a",
[
"mozilla/interfaces.worker.html",
{}

View file

@ -1 +1 @@
prefs: ["dom_imagebitmap_enabled:true", "dom_offscreen_canvas_enabled:true", "dom_xpath_enabled:true", "dom_intersection_observer_enabled:true", "dom_resize_observer_enabled:true", "dom_notification_enabled:true", "dom_fontface_enabled:true"]
prefs: ["dom_imagebitmap_enabled:true", "dom_offscreen_canvas_enabled:true", "dom_xpath_enabled:true", "dom_intersection_observer_enabled:true", "dom_resize_observer_enabled:true", "dom_notification_enabled:true", "dom_fontface_enabled:true", "dom_urlpattern_enabled:true"]

View file

@ -282,6 +282,7 @@ test_interfaces([
"TreeWalker",
"UIEvent",
"URL",
"URLPattern",
"URLSearchParams",
"ValidityState",
"VideoTrack",

View file

@ -68,6 +68,7 @@ test_interfaces([
"TextDecoder",
"TextEncoder",
"URL",
"URLPattern",
"URLSearchParams",
"WebGLActiveInfo",
"WebGLBuffer",