1
1
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
2
2
3
+ use crate :: matcher:: InnerMatcher ;
4
+ use crate :: matcher:: Matcher ;
3
5
use crate :: parser:: Options ;
4
6
use crate :: parser:: Part ;
5
7
use crate :: parser:: PartModifier ;
@@ -15,6 +17,7 @@ pub(crate) struct Component<R: RegExp> {
15
17
pub pattern_string : String ,
16
18
pub regexp : Result < R , Error > ,
17
19
pub group_name_list : Vec < String > ,
20
+ pub matcher : Matcher < R > ,
18
21
}
19
22
20
23
impl < R : RegExp > Component < R > {
@@ -32,14 +35,17 @@ impl<R: RegExp> Component<R> {
32
35
& options,
33
36
encoding_callback,
34
37
) ?;
38
+ let part_list = part_list. iter ( ) . collect :: < Vec < _ > > ( ) ;
35
39
let ( regexp_string, name_list) =
36
40
generate_regular_expression_and_name_list ( & part_list, & options) ;
37
41
let regexp = R :: parse ( & regexp_string) . map_err ( Error :: RegExp ) ;
38
- let pattern_string = generate_pattern_string ( part_list, & options) ;
42
+ let pattern_string = generate_pattern_string ( & part_list, & options) ;
43
+ let matcher = generate_matcher :: < R > ( & part_list, & options) ;
39
44
Ok ( Component {
40
45
pattern_string,
41
46
regexp,
42
47
group_name_list : name_list,
48
+ matcher,
43
49
} )
44
50
}
45
51
@@ -85,7 +91,7 @@ impl<R: RegExp> Component<R> {
85
91
86
92
// Ref: https://wicg.github.io/urlpattern/#generate-a-regular-expression-and-name-list
87
93
fn generate_regular_expression_and_name_list (
88
- part_list : & [ Part ] ,
94
+ part_list : & [ & Part ] ,
89
95
options : & Options ,
90
96
) -> ( String , Vec < String > ) {
91
97
let mut result = String :: from ( "^" ) ;
@@ -153,12 +159,15 @@ fn generate_regular_expression_and_name_list(
153
159
}
154
160
155
161
// Ref: https://wicg.github.io/urlpattern/#generate-a-pattern-string
156
- fn generate_pattern_string ( part_list : Vec < Part > , options : & Options ) -> String {
162
+ fn generate_pattern_string ( part_list : & [ & Part ] , options : & Options ) -> String {
157
163
let mut result = String :: new ( ) ;
158
164
for ( i, part) in part_list. iter ( ) . enumerate ( ) {
159
- let prev_part: Option < & Part > =
160
- if i == 0 { None } else { part_list. get ( i - 1 ) } ;
161
- let next_part: Option < & Part > = part_list. get ( i + 1 ) ;
165
+ let prev_part: Option < & Part > = if i == 0 {
166
+ None
167
+ } else {
168
+ part_list. get ( i - 1 ) . copied ( )
169
+ } ;
170
+ let next_part: Option < & Part > = part_list. get ( i + 1 ) . copied ( ) ;
162
171
if part. kind == PartType :: FixedText {
163
172
if part. modifier == PartModifier :: None {
164
173
result. push_str ( & escape_pattern_string ( & part. value ) ) ;
@@ -261,3 +270,87 @@ fn escape_pattern_string(input: &str) -> String {
261
270
}
262
271
result
263
272
}
273
+
274
+ /// This function generates a matcher for a given parts list.
275
+ fn generate_matcher < R : RegExp > (
276
+ mut part_list : & [ & Part ] ,
277
+ options : & Options ,
278
+ ) -> Matcher < R > {
279
+ fn is_literal ( part : & Part ) -> bool {
280
+ part. kind == PartType :: FixedText && part. modifier == PartModifier :: None
281
+ }
282
+
283
+ // If the first part is a fixed string, we can use it as a literal prefix.
284
+ let mut prefix = match part_list. first ( ) {
285
+ Some ( part) if is_literal ( part) => {
286
+ part_list = & part_list[ 1 ..] ;
287
+ part. value . clone ( )
288
+ }
289
+ _ => "" . into ( ) ,
290
+ } ;
291
+ // If the last part is a fixed string, we can use it as a literal suffix.
292
+ let mut suffix = match part_list. last ( ) {
293
+ Some ( part) if is_literal ( part) => {
294
+ part_list = & part_list[ ..part_list. len ( ) - 1 ] ;
295
+ part. value . clone ( )
296
+ }
297
+ _ => "" . into ( ) ,
298
+ } ;
299
+
300
+ // If there are no more parts, we must have a prefix and/or a suffix. We can
301
+ // combine these into a single fixed text literal matcher.
302
+ if part_list. is_empty ( ) {
303
+ return Matcher :: literal ( format ! ( "{prefix}{suffix}" ) ) ;
304
+ }
305
+
306
+ let inner = match part_list {
307
+ // If there is only one part, and it is a simple full wildcard with no
308
+ // prefix or suffix, we can use a simple wildcard matcher.
309
+ [ part]
310
+ if part. kind == PartType :: FullWildcard
311
+ && part. modifier == PartModifier :: None =>
312
+ {
313
+ prefix += & part. prefix ;
314
+ if !part. suffix . is_empty ( ) {
315
+ suffix = format ! ( "{}{suffix}" , part. suffix) ;
316
+ }
317
+ InnerMatcher :: SingleCapture {
318
+ filter : None ,
319
+ allow_empty : true ,
320
+ }
321
+ }
322
+ // If there is only one part, and it is a simple segment wildcard with no
323
+ // prefix or suffix, we can use a simple wildcard matcher.
324
+ [ part]
325
+ if part. kind == PartType :: SegmentWildcard
326
+ && part. modifier == PartModifier :: None =>
327
+ {
328
+ prefix += & part. prefix ;
329
+ if !part. suffix . is_empty ( ) {
330
+ suffix = format ! ( "{}{suffix}" , part. suffix) ;
331
+ }
332
+ let filter = if options. delimiter_code_point . is_empty ( ) {
333
+ None
334
+ } else {
335
+ Some ( options. delimiter_code_point . clone ( ) )
336
+ } ;
337
+ InnerMatcher :: SingleCapture {
338
+ filter,
339
+ allow_empty : false ,
340
+ }
341
+ }
342
+ // For all other cases, we fall back to a regexp matcher.
343
+ part_list => {
344
+ let ( regexp_string, _) =
345
+ generate_regular_expression_and_name_list ( part_list, options) ;
346
+ let regexp = R :: parse ( & regexp_string) . map_err ( Error :: RegExp ) ;
347
+ InnerMatcher :: RegExp { regexp }
348
+ }
349
+ } ;
350
+
351
+ Matcher {
352
+ prefix,
353
+ suffix,
354
+ inner,
355
+ }
356
+ }
0 commit comments