1use dom_struct::dom_struct;
6use js::rust::HandleObject;
7use script_bindings::codegen::GenericBindings::URLPatternBinding::URLPatternResult;
8use script_bindings::codegen::GenericUnionTypes::USVStringOrURLPatternInit;
9use script_bindings::error::{Error, Fallible};
10use script_bindings::reflector::Reflector;
11use script_bindings::root::DomRoot;
12use script_bindings::script_runtime::CanGc;
13use script_bindings::str::USVString;
14
15use crate::dom::bindings::codegen::Bindings::URLPatternBinding;
16use crate::dom::bindings::codegen::Bindings::URLPatternBinding::URLPatternMethods;
17use crate::dom::bindings::reflector::reflect_dom_object_with_proto;
18use crate::dom::globalscope::GlobalScope;
19
20#[dom_struct]
22pub(crate) struct URLPattern {
23 reflector: Reflector,
24
25 #[no_trace]
27 associated_url_pattern: urlpattern::UrlPattern,
28}
29
30impl URLPattern {
31 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
32 fn new_inherited(associated_url_pattern: urlpattern::UrlPattern) -> URLPattern {
33 URLPattern {
34 reflector: Reflector::new(),
35 associated_url_pattern,
36 }
37 }
38
39 pub(crate) fn initialize(
41 global: &GlobalScope,
42 proto: Option<HandleObject>,
43 input: USVStringOrURLPatternInit,
44 base_url: Option<USVString>,
45 options: &URLPatternBinding::URLPatternOptions,
46 can_gc: CanGc,
47 ) -> Fallible<DomRoot<URLPattern>> {
48 let base_url = base_url.map(|usv_string| usv_string.0);
50 let input = bindings_to_third_party::map_urlpattern_input(input);
51 let options = urlpattern::UrlPatternOptions {
52 ignore_case: options.ignoreCase,
53 };
54
55 let pattern_init =
57 urlpattern::quirks::process_construct_pattern_input(input, base_url.as_deref())
58 .map_err(|error| Error::Type(format!("{error}")))?;
59
60 let pattern = urlpattern::UrlPattern::parse(pattern_init, options)
61 .map_err(|error| Error::Type(format!("{error}")))?;
62
63 let url_pattern = reflect_dom_object_with_proto(
64 Box::new(URLPattern::new_inherited(pattern)),
65 global,
66 proto,
67 can_gc,
68 );
69 Ok(url_pattern)
70 }
71}
72
73impl URLPatternMethods<crate::DomTypeHolder> for URLPattern {
74 fn Constructor(
76 global: &GlobalScope,
77 proto: Option<HandleObject>,
78 can_gc: CanGc,
79 input: USVStringOrURLPatternInit,
80 base_url: USVString,
81 options: &URLPatternBinding::URLPatternOptions,
82 ) -> Fallible<DomRoot<URLPattern>> {
83 URLPattern::initialize(global, proto, input, Some(base_url), options, can_gc)
84 }
85
86 fn Constructor_(
88 global: &GlobalScope,
89 proto: Option<HandleObject>,
90 can_gc: CanGc,
91 input: USVStringOrURLPatternInit,
92 options: &URLPatternBinding::URLPatternOptions,
93 ) -> Fallible<DomRoot<URLPattern>> {
94 URLPattern::initialize(global, proto, input, None, options, can_gc)
96 }
97
98 fn Test(
100 &self,
101 input: USVStringOrURLPatternInit,
102 base_url: Option<USVString>,
103 ) -> Fallible<bool> {
104 let input = bindings_to_third_party::map_urlpattern_input(input);
105 let inputs = urlpattern::quirks::process_match_input(input, base_url.as_deref())
106 .map_err(|error| Error::Type(format!("{error}")))?;
107 let Some((match_input, _)) = inputs else {
108 return Ok(false);
109 };
110
111 self.associated_url_pattern
112 .test(match_input)
113 .map_err(|error| Error::Type(format!("{error}")))
114 }
115
116 fn Exec(
118 &self,
119 input: USVStringOrURLPatternInit,
120 base_url: Option<USVString>,
121 ) -> Fallible<Option<URLPatternResult>> {
122 let input = bindings_to_third_party::map_urlpattern_input(input);
123 let inputs = urlpattern::quirks::process_match_input(input, base_url.as_deref())
124 .map_err(|error| Error::Type(format!("{error}")))?;
125 let Some((match_input, inputs)) = inputs else {
126 return Ok(None);
127 };
128
129 let result = self
130 .associated_url_pattern
131 .exec(match_input)
132 .map_err(|error| Error::Type(format!("{error}")))?;
133 let Some(result) = result else {
134 return Ok(None);
135 };
136
137 Ok(Some(third_party_to_bindings::map_urlpattern_result(
138 result, inputs,
139 )))
140 }
141
142 fn Protocol(&self) -> USVString {
144 USVString(self.associated_url_pattern.protocol().to_owned())
146 }
147
148 fn Username(&self) -> USVString {
150 USVString(self.associated_url_pattern.username().to_owned())
152 }
153
154 fn Password(&self) -> USVString {
156 USVString(self.associated_url_pattern.password().to_owned())
158 }
159
160 fn Hostname(&self) -> USVString {
162 USVString(self.associated_url_pattern.hostname().to_owned())
164 }
165
166 fn Port(&self) -> USVString {
168 USVString(self.associated_url_pattern.port().to_owned())
170 }
171
172 fn Pathname(&self) -> USVString {
174 USVString(self.associated_url_pattern.pathname().to_owned())
176 }
177
178 fn Search(&self) -> USVString {
180 USVString(self.associated_url_pattern.search().to_owned())
182 }
183
184 fn Hash(&self) -> USVString {
186 USVString(self.associated_url_pattern.hash().to_owned())
188 }
189
190 fn HasRegExpGroups(&self) -> bool {
192 self.associated_url_pattern.has_regexp_groups()
195 }
196}
197
198mod bindings_to_third_party {
199 use script_bindings::codegen::GenericBindings::URLPatternBinding::URLPatternInit;
200
201 use crate::dom::urlpattern::USVStringOrURLPatternInit;
202
203 fn map_urlpatterninit(pattern_init: URLPatternInit) -> urlpattern::quirks::UrlPatternInit {
204 urlpattern::quirks::UrlPatternInit {
205 protocol: pattern_init.protocol.map(|protocol| protocol.0),
206 username: pattern_init.username.map(|username| username.0),
207 password: pattern_init.password.map(|password| password.0),
208 hostname: pattern_init.hostname.map(|hostname| hostname.0),
209 port: pattern_init.port.map(|hash| hash.0),
210 pathname: pattern_init
211 .pathname
212 .as_ref()
213 .map(|usv_string| usv_string.to_string()),
214 search: pattern_init.search.map(|search| search.0),
215 hash: pattern_init.hash.map(|hash| hash.0),
216 base_url: pattern_init.baseURL.map(|base_url| base_url.0),
217 }
218 }
219
220 pub(super) fn map_urlpattern_input(
221 input: USVStringOrURLPatternInit,
222 ) -> urlpattern::quirks::StringOrInit {
223 match input {
224 USVStringOrURLPatternInit::USVString(usv_string) => {
225 urlpattern::quirks::StringOrInit::String(usv_string.0)
226 },
227 USVStringOrURLPatternInit::URLPatternInit(pattern_init) => {
228 urlpattern::quirks::StringOrInit::Init(map_urlpatterninit(pattern_init))
229 },
230 }
231 }
232}
233
234mod third_party_to_bindings {
235 use script_bindings::codegen::GenericBindings::URLPatternBinding::{
236 URLPatternComponentResult, URLPatternInit, URLPatternResult,
237 };
238 use script_bindings::codegen::GenericUnionTypes::USVStringOrUndefined;
239 use script_bindings::record::Record;
240 use script_bindings::str::USVString;
241
242 use crate::dom::bindings::codegen::UnionTypes::USVStringOrURLPatternInit;
243
244 fn map_component_result(
247 component_result: urlpattern::UrlPatternComponentResult,
248 ) -> URLPatternComponentResult {
249 let mut groups = Record::new();
250 for (key, value) in component_result.groups.iter() {
251 let value = match value {
252 Some(value) => USVStringOrUndefined::USVString(USVString(value.to_owned())),
253 None => USVStringOrUndefined::Undefined(()),
254 };
255
256 groups.insert(USVString(key.to_owned()), value);
257 }
258
259 URLPatternComponentResult {
260 input: Some(component_result.input.into()),
261 groups: Some(groups),
262 }
263 }
264
265 fn map_urlpatterninit(pattern_init: urlpattern::quirks::UrlPatternInit) -> URLPatternInit {
266 URLPatternInit {
267 baseURL: pattern_init.base_url.map(USVString),
268 protocol: pattern_init.protocol.map(USVString),
269 username: pattern_init.username.map(USVString),
270 password: pattern_init.password.map(USVString),
271 hostname: pattern_init.hostname.map(USVString),
272 port: pattern_init.port.map(USVString),
273 pathname: pattern_init.pathname.map(USVString),
274 search: pattern_init.search.map(USVString),
275 hash: pattern_init.hash.map(USVString),
276 }
277 }
278
279 pub(super) fn map_urlpattern_result(
280 result: urlpattern::UrlPatternResult,
281 (string_or_init, base_url): urlpattern::quirks::Inputs,
282 ) -> URLPatternResult {
283 let string_or_init = match string_or_init {
284 urlpattern::quirks::StringOrInit::String(string) => {
285 USVStringOrURLPatternInit::USVString(USVString(string))
286 },
287 urlpattern::quirks::StringOrInit::Init(pattern_init) => {
288 USVStringOrURLPatternInit::URLPatternInit(map_urlpatterninit(pattern_init))
289 },
290 };
291
292 let mut inputs = vec![string_or_init];
293
294 if let Some(base_url) = base_url {
295 inputs.push(USVStringOrURLPatternInit::USVString(USVString(base_url)));
296 }
297
298 URLPatternResult {
299 inputs: Some(inputs),
300 protocol: Some(map_component_result(result.protocol)),
301 username: Some(map_component_result(result.username)),
302 password: Some(map_component_result(result.password)),
303 hostname: Some(map_component_result(result.hostname)),
304 port: Some(map_component_result(result.port)),
305 pathname: Some(map_component_result(result.pathname)),
306 search: Some(map_component_result(result.search)),
307 hash: Some(map_component_result(result.hash)),
308 }
309 }
310}