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 fn new_inherited(associated_url_pattern: urlpattern::UrlPattern) -> URLPattern {
32 URLPattern {
33 reflector: Reflector::new(),
34 associated_url_pattern,
35 }
36 }
37
38 pub(crate) fn initialize(
40 global: &GlobalScope,
41 proto: Option<HandleObject>,
42 input: USVStringOrURLPatternInit,
43 base_url: Option<USVString>,
44 options: &URLPatternBinding::URLPatternOptions,
45 can_gc: CanGc,
46 ) -> Fallible<DomRoot<URLPattern>> {
47 let base_url = base_url.map(|usv_string| usv_string.0);
49 let input = bindings_to_third_party::map_urlpattern_input(input);
50 let options = urlpattern::UrlPatternOptions {
51 ignore_case: options.ignoreCase,
52 };
53
54 let pattern_init =
56 urlpattern::quirks::process_construct_pattern_input(input, base_url.as_deref())
57 .map_err(|error| Error::Type(format!("{error}")))?;
58
59 let pattern = urlpattern::UrlPattern::parse(pattern_init, options)
60 .map_err(|error| Error::Type(format!("{error}")))?;
61
62 let url_pattern = reflect_dom_object_with_proto(
63 Box::new(URLPattern::new_inherited(pattern)),
64 global,
65 proto,
66 can_gc,
67 );
68 Ok(url_pattern)
69 }
70}
71
72impl URLPatternMethods<crate::DomTypeHolder> for URLPattern {
73 fn Constructor(
75 global: &GlobalScope,
76 proto: Option<HandleObject>,
77 can_gc: CanGc,
78 input: USVStringOrURLPatternInit,
79 base_url: USVString,
80 options: &URLPatternBinding::URLPatternOptions,
81 ) -> Fallible<DomRoot<URLPattern>> {
82 URLPattern::initialize(global, proto, input, Some(base_url), options, can_gc)
83 }
84
85 fn Constructor_(
87 global: &GlobalScope,
88 proto: Option<HandleObject>,
89 can_gc: CanGc,
90 input: USVStringOrURLPatternInit,
91 options: &URLPatternBinding::URLPatternOptions,
92 ) -> Fallible<DomRoot<URLPattern>> {
93 URLPattern::initialize(global, proto, input, None, options, can_gc)
95 }
96
97 fn Test(
99 &self,
100 input: USVStringOrURLPatternInit,
101 base_url: Option<USVString>,
102 ) -> Fallible<bool> {
103 let input = bindings_to_third_party::map_urlpattern_input(input);
104 let inputs = urlpattern::quirks::process_match_input(input, base_url.as_deref())
105 .map_err(|error| Error::Type(format!("{error}")))?;
106 let Some((match_input, _)) = inputs else {
107 return Ok(false);
108 };
109
110 self.associated_url_pattern
111 .test(match_input)
112 .map_err(|error| Error::Type(format!("{error}")))
113 }
114
115 fn Exec(
117 &self,
118 input: USVStringOrURLPatternInit,
119 base_url: Option<USVString>,
120 ) -> Fallible<Option<URLPatternResult>> {
121 let input = bindings_to_third_party::map_urlpattern_input(input);
122 let inputs = urlpattern::quirks::process_match_input(input, base_url.as_deref())
123 .map_err(|error| Error::Type(format!("{error}")))?;
124 let Some((match_input, inputs)) = inputs else {
125 return Ok(None);
126 };
127
128 let result = self
129 .associated_url_pattern
130 .exec(match_input)
131 .map_err(|error| Error::Type(format!("{error}")))?;
132 let Some(result) = result else {
133 return Ok(None);
134 };
135
136 Ok(Some(third_party_to_bindings::map_urlpattern_result(
137 result, inputs,
138 )))
139 }
140
141 fn Protocol(&self) -> USVString {
143 USVString(self.associated_url_pattern.protocol().to_owned())
145 }
146
147 fn Username(&self) -> USVString {
149 USVString(self.associated_url_pattern.username().to_owned())
151 }
152
153 fn Password(&self) -> USVString {
155 USVString(self.associated_url_pattern.password().to_owned())
157 }
158
159 fn Hostname(&self) -> USVString {
161 USVString(self.associated_url_pattern.hostname().to_owned())
163 }
164
165 fn Port(&self) -> USVString {
167 USVString(self.associated_url_pattern.port().to_owned())
169 }
170
171 fn Pathname(&self) -> USVString {
173 USVString(self.associated_url_pattern.pathname().to_owned())
175 }
176
177 fn Search(&self) -> USVString {
179 USVString(self.associated_url_pattern.search().to_owned())
181 }
182
183 fn Hash(&self) -> USVString {
185 USVString(self.associated_url_pattern.hash().to_owned())
187 }
188
189 fn HasRegExpGroups(&self) -> bool {
191 self.associated_url_pattern.has_regexp_groups()
194 }
195}
196
197mod bindings_to_third_party {
198 use script_bindings::codegen::GenericBindings::URLPatternBinding::URLPatternInit;
199
200 use crate::dom::urlpattern::USVStringOrURLPatternInit;
201
202 fn map_urlpatterninit(pattern_init: URLPatternInit) -> urlpattern::quirks::UrlPatternInit {
203 urlpattern::quirks::UrlPatternInit {
204 protocol: pattern_init.protocol.map(|protocol| protocol.0),
205 username: pattern_init.username.map(|username| username.0),
206 password: pattern_init.password.map(|password| password.0),
207 hostname: pattern_init.hostname.map(|hostname| hostname.0),
208 port: pattern_init.port.map(|hash| hash.0),
209 pathname: pattern_init
210 .pathname
211 .as_ref()
212 .map(|usv_string| usv_string.to_string()),
213 search: pattern_init.search.map(|search| search.0),
214 hash: pattern_init.hash.map(|hash| hash.0),
215 base_url: pattern_init.baseURL.map(|base_url| base_url.0),
216 }
217 }
218
219 pub(super) fn map_urlpattern_input(
220 input: USVStringOrURLPatternInit,
221 ) -> urlpattern::quirks::StringOrInit {
222 match input {
223 USVStringOrURLPatternInit::USVString(usv_string) => {
224 urlpattern::quirks::StringOrInit::String(usv_string.0)
225 },
226 USVStringOrURLPatternInit::URLPatternInit(pattern_init) => {
227 urlpattern::quirks::StringOrInit::Init(map_urlpatterninit(pattern_init))
228 },
229 }
230 }
231}
232
233mod third_party_to_bindings {
234 use script_bindings::codegen::GenericBindings::URLPatternBinding::{
235 URLPatternComponentResult, URLPatternInit, URLPatternResult,
236 };
237 use script_bindings::codegen::GenericUnionTypes::USVStringOrUndefined;
238 use script_bindings::record::Record;
239 use script_bindings::str::USVString;
240
241 use crate::dom::bindings::codegen::UnionTypes::USVStringOrURLPatternInit;
242
243 fn map_component_result(
246 component_result: urlpattern::UrlPatternComponentResult,
247 ) -> URLPatternComponentResult {
248 let mut groups = Record::new();
249 for (key, value) in component_result.groups.iter() {
250 let value = match value {
251 Some(value) => USVStringOrUndefined::USVString(USVString(value.to_owned())),
252 None => USVStringOrUndefined::Undefined(()),
253 };
254
255 groups.insert(USVString(key.to_owned()), value);
256 }
257
258 URLPatternComponentResult {
259 input: Some(component_result.input.into()),
260 groups: Some(groups),
261 }
262 }
263
264 fn map_urlpatterninit(pattern_init: urlpattern::quirks::UrlPatternInit) -> URLPatternInit {
265 URLPatternInit {
266 baseURL: pattern_init.base_url.map(USVString),
267 protocol: pattern_init.protocol.map(USVString),
268 username: pattern_init.username.map(USVString),
269 password: pattern_init.password.map(USVString),
270 hostname: pattern_init.hostname.map(USVString),
271 port: pattern_init.port.map(USVString),
272 pathname: pattern_init.pathname.map(USVString),
273 search: pattern_init.search.map(USVString),
274 hash: pattern_init.hash.map(USVString),
275 }
276 }
277
278 pub(super) fn map_urlpattern_result(
279 result: urlpattern::UrlPatternResult,
280 (string_or_init, base_url): urlpattern::quirks::Inputs,
281 ) -> URLPatternResult {
282 let string_or_init = match string_or_init {
283 urlpattern::quirks::StringOrInit::String(string) => {
284 USVStringOrURLPatternInit::USVString(USVString(string))
285 },
286 urlpattern::quirks::StringOrInit::Init(pattern_init) => {
287 USVStringOrURLPatternInit::URLPatternInit(map_urlpatterninit(pattern_init))
288 },
289 };
290
291 let mut inputs = vec![string_or_init];
292
293 if let Some(base_url) = base_url {
294 inputs.push(USVStringOrURLPatternInit::USVString(USVString(base_url)));
295 }
296
297 URLPatternResult {
298 inputs: Some(inputs),
299 protocol: Some(map_component_result(result.protocol)),
300 username: Some(map_component_result(result.username)),
301 password: Some(map_component_result(result.password)),
302 hostname: Some(map_component_result(result.hostname)),
303 port: Some(map_component_result(result.port)),
304 pathname: Some(map_component_result(result.pathname)),
305 search: Some(map_component_result(result.search)),
306 hash: Some(map_component_result(result.hash)),
307 }
308 }
309}