@b9g/match-pattern 0.1.7 → 0.2.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -6,7 +6,7 @@ High-performance URLPattern-compatible implementation for web routing with enhan
6
6
 
7
7
  This package provides two classes:
8
8
 
9
- - **URLPattern**: A 100% WPT-compliant implementation that's ~60x faster than the polyfill/native
9
+ - **URLPattern**: A 100% WPT-compliant implementation that's ~40-60x faster than the polyfill/native
10
10
  - **MatchPattern**: Same performance with routing enhancements (order-independent search params, unified `params` object)
11
11
 
12
12
  Both compile patterns directly to RegExp in a single pass, bypassing the multi-stage pipeline used by polyfill/native implementations.
@@ -20,12 +20,12 @@ npm install @b9g/match-pattern
20
20
  ## Basic Usage
21
21
 
22
22
  ```javascript
23
- import { MatchPattern, URLPattern } from '@b9g/match-pattern';
23
+ import {MatchPattern, URLPattern} from '@b9g/match-pattern';
24
24
 
25
25
  // URLPattern: 100% WPT-compliant, ~60x faster than polyfill/native
26
26
  const strict = new URLPattern({ pathname: '/api/posts/:id' });
27
27
 
28
- // MatchPattern: Same performance + order-independent search params
28
+ // MatchPattern: Same performance + DX improvements
29
29
  const pattern = new MatchPattern('/api/posts/:id&format=:format');
30
30
  const url = new URL('http://example.com/api/posts/123?format=json&page=1');
31
31
 
@@ -66,7 +66,7 @@ All URLPattern syntax is fully supported including:
66
66
  URLPattern requires exact parameter order. MatchPattern allows any order:
67
67
 
68
68
  ```javascript
69
- const pattern = new MatchPattern({ search: 'type=:type&sort=:sort' });
69
+ const pattern = new MatchPattern({search: 'type=:type&sort=:sort'});
70
70
 
71
71
  // URLPattern: Only first URL matches
72
72
  // MatchPattern: Both URLs match
@@ -79,15 +79,15 @@ pattern.test('/?sort=date&type=blog'); // MatchPattern: true, URLPattern: false
79
79
  URLPattern uses greedy capture that lumps extra params into the last parameter value. MatchPattern properly parses them:
80
80
 
81
81
  ```javascript
82
- const pattern = new MatchPattern({ search: 'q=:query' });
82
+ const pattern = new MatchPattern({search: 'q=:query'});
83
83
 
84
84
  // URLPattern greedy capture issue
85
- const urlPattern = new URLPattern({ search: 'q=:query' });
85
+ const urlPattern = new URLPattern({search: 'q=:query'});
86
86
  urlPattern.exec('?q=hello&page=1').search.groups; // { query: "hello&page=1" }
87
87
 
88
88
  // MatchPattern proper parsing
89
89
  const result = pattern.exec('/?q=hello&page=1&limit=10');
90
- console.log(result.params); // { q: 'hello', page: '1', limit: '10' }
90
+ console.log(result.params); // {q: 'hello', page: '1', limit: '10'}
91
91
  ```
92
92
 
93
93
  Required parameters must be present, but extra parameters are allowed:
@@ -108,15 +108,15 @@ const result = pattern.exec('/api/v1/posts/123?format=json&page=1');
108
108
 
109
109
  // URLPattern: result.pathname.groups + result.search.groups (separate)
110
110
  // MatchPattern: result.params (unified)
111
- console.log(result.params); // { version: 'v1', id: '123', format: 'json', page: '1' }
111
+ console.log(result.params); // {version: 'v1', id: '123', format: 'json', page: '1'}
112
112
  ```
113
113
 
114
114
  ### 4. Enhanced String Pattern Syntax
115
115
 
116
- MatchPattern supports convenient string patterns with `&` separator:
116
+ It's not possible to separate pathname from search with `?` because the syntax is used to indicate optionality, so MatchPattern supports convenient string patterns with `&` separator:
117
117
 
118
118
  ```javascript
119
- // Pathname only
119
+ // Pathname only (URLPattern throws a TypeError when passing a relative path without a baseURL)
120
120
  new MatchPattern('/api/posts/:id')
121
121
 
122
122
  // Pathname with search parameters
@@ -135,8 +135,6 @@ new MatchPattern({
135
135
  })
136
136
  ```
137
137
 
138
- It's not possible to separate pathname from search with `?` because the syntax is used to indicate optionality.
139
-
140
138
  ## Trailing Slash Handling
141
139
 
142
140
  MatchPattern does not automatically normalize trailing slashes. Use explicit patterns:
@@ -193,12 +191,14 @@ The `URLPattern` class passes 100% of the Web Platform Tests (755 tests). It imp
193
191
 
194
192
  - `MatchPatternResult` - Result type for MatchPattern.exec()
195
193
  - `URLPatternOptions` - Options for URLPattern constructor (ignoreCase, etc.)
196
- - `CompiledPattern` - Internal compiled pattern representation
197
194
  - `ParsedPattern` - Parsed pattern structure
198
195
  - `PatternSegment` - Individual segment of a parsed pattern
196
+ - `CompiledPattern` - Internal compiled pattern representation
199
197
 
200
198
  ### Utility Functions
201
199
 
200
+ Advanced functions for pattern inspection and compilation for optimized routers
201
+
202
202
  - `isSimplePattern(pathname: string): boolean` - Check if pathname is a simple pattern (no regex features)
203
203
  - `parseSimplePattern(pathname: string): ParsedPattern | null` - Parse a simple pattern into segments
204
204
  - `compilePathname(pathname: string, options?: object): CompiledPattern` - Compile a pathname pattern to RegExp
@@ -208,33 +208,78 @@ The `URLPattern` class passes 100% of the Web Platform Tests (755 tests). It imp
208
208
  ### URLPattern
209
209
 
210
210
  ```typescript
211
- new URLPattern(input?: string | URLPatternInit, baseURL?: string, options?: URLPatternOptions)
211
+ class URLPattern {
212
+ constructor(input?: string | URLPatternInit, baseURL?: string, options?: URLPatternOptions)
213
+
214
+ test(input: string | URL | URLPatternInit, baseURL?: string): boolean
215
+ exec(input: string | URL | URLPatternInit, baseURL?: string): URLPatternResult | null
216
+
217
+ readonly protocol: string
218
+ readonly username: string
219
+ readonly password: string
220
+ readonly hostname: string
221
+ readonly port: string
222
+ readonly pathname: string
223
+ readonly search: string
224
+ readonly hash: string
225
+ }
212
226
  ```
213
227
 
214
- Methods:
215
- - `test(input: string | URL | URLPatternInit, baseURL?: string): boolean`
216
- - `exec(input: string | URL | URLPatternInit, baseURL?: string): URLPatternResult | null`
217
-
218
228
  ### MatchPattern
219
229
 
220
230
  ```typescript
221
- new MatchPattern(input: string | URLPatternInit, baseURL?: string)
231
+ class MatchPattern {
232
+ constructor(input: string | URLPatternInit, baseURL?: string)
233
+
234
+ test(input: string | URL): boolean
235
+ exec(input: string | URL): MatchPatternResult | null
236
+ }
222
237
  ```
223
238
 
224
- Methods:
225
- - `test(input: string | URL): boolean`
226
- - `exec(input: string | URL): MatchPatternResult | null`
239
+ ### Utility Functions
240
+
241
+ Advanced functions for pattern inspection and compilation (used by router optimizations):
242
+
243
+ ```typescript
244
+ // Check if a pathname pattern contains only literal segments and named parameters
245
+ function isSimplePattern(pathname: string): boolean
246
+
247
+ // Parse a simple pattern into its component segments
248
+ function parseSimplePattern(pathname: string): ParsedPattern | null
249
+
250
+ // Compile a pathname pattern to optimized RegExp
251
+ function compilePathname(
252
+ pathname: string,
253
+ options?: { ignoreCase?: boolean }
254
+ ): CompiledPattern
255
+ ```
227
256
 
228
257
  ### Types
229
258
 
230
259
  ```typescript
231
260
  interface MatchPatternResult extends URLPatternResult {
232
- params: Record<string, string>; // Unified parameters from all sources
261
+ params: Record<string, string>; // Unified parameters from pathname and search
233
262
  }
234
263
 
235
264
  interface URLPatternOptions {
236
265
  ignoreCase?: boolean; // Case-insensitive matching
237
266
  }
267
+
268
+ interface ParsedPattern {
269
+ segments: PatternSegment[];
270
+ paramNames: string[];
271
+ }
272
+
273
+ type PatternSegment =
274
+ | { type: 'literal'; value: string }
275
+ | { type: 'param'; name: string; pattern?: string }
276
+ | { type: 'wildcard' }
277
+ | { type: 'group'; segments: PatternSegment[] }
278
+
279
+ interface CompiledPattern {
280
+ regexp: RegExp;
281
+ paramNames: string[];
282
+ }
238
283
  ```
239
284
 
240
285
  ## Compatibility
@@ -254,10 +299,4 @@ Report issues related to:
254
299
 
255
300
  ## License
256
301
 
257
- MIT - see LICENSE file for details.
258
-
259
- ## Acknowledgments
260
-
261
- - [URLPattern specification](https://urlpattern.spec.whatwg.org/) by WHATWG
262
- - Inspired by [path-to-regexp](https://github.com/pillarjs/path-to-regexp) and the URLPattern spec
263
- - Web Platform community
302
+ MIT
package/package.json CHANGED
@@ -1,17 +1,8 @@
1
1
  {
2
2
  "name": "@b9g/match-pattern",
3
- "version": "0.1.7",
3
+ "version": "0.2.0-beta.0",
4
4
  "devDependencies": {
5
- "@b9g/libuild": "^0.1.11",
6
- "bun-types": "latest"
7
- },
8
- "peerDependencies": {
9
- "urlpattern-polyfill": "^10.0.0"
10
- },
11
- "peerDependenciesMeta": {
12
- "urlpattern-polyfill": {
13
- "optional": true
14
- }
5
+ "@b9g/libuild": "^0.1.18"
15
6
  },
16
7
  "type": "module",
17
8
  "types": "src/index.d.ts",
package/src/index.d.ts CHANGED
@@ -1,3 +1,7 @@
1
+ /**
2
+ * High-performance URLPattern-compatible implementation for web routing with
3
+ * enhanced search parameter handling.
4
+ */
1
5
  /**
2
6
  * Result of pattern matching
3
7
  */
package/src/index.js CHANGED
@@ -1,10 +1,8 @@
1
1
  /// <reference types="./index.d.ts" />
2
2
  // src/index.ts
3
3
  function isValidProtocol(protocol) {
4
- if (!protocol)
5
- return false;
6
- if (!/^[a-zA-Z]/.test(protocol))
7
- return false;
4
+ if (!protocol) return false;
5
+ if (!/^[a-zA-Z]/.test(protocol)) return false;
8
6
  return /^[a-zA-Z][a-zA-Z0-9+\-.]*$/.test(protocol);
9
7
  }
10
8
  function isSpecialScheme(protocol) {
@@ -12,8 +10,7 @@ function isSpecialScheme(protocol) {
12
10
  return special.includes(protocol.toLowerCase());
13
11
  }
14
12
  function isDefinitelyNonSpecialScheme(protocolPattern) {
15
- if (!protocolPattern)
16
- return false;
13
+ if (!protocolPattern) return false;
17
14
  if (protocolPattern.includes("*") || protocolPattern.includes("+")) {
18
15
  return false;
19
16
  }
@@ -27,20 +24,21 @@ function isDefinitelyNonSpecialScheme(protocolPattern) {
27
24
  }
28
25
  return !isSpecialScheme(protocolPattern);
29
26
  }
27
+ var DEFAULT_PORTS = {
28
+ http: "80",
29
+ https: "443",
30
+ ws: "80",
31
+ wss: "443",
32
+ ftp: "21"
33
+ };
30
34
  function getDefaultPort(protocol) {
31
- const defaults = {
32
- http: "80",
33
- https: "443",
34
- ws: "80",
35
- wss: "443",
36
- ftp: "21"
37
- };
38
- return defaults[protocol.toLowerCase()];
35
+ return DEFAULT_PORTS[protocol.toLowerCase()];
39
36
  }
40
37
  function toASCII(hostname) {
41
38
  try {
42
39
  return new URL("http://" + hostname).hostname;
43
- } catch {
40
+ } catch (err) {
41
+ if (!(err instanceof TypeError)) throw err;
44
42
  return hostname;
45
43
  }
46
44
  }
@@ -153,10 +151,8 @@ function validateHostnamePattern(hostname) {
153
151
  j += 2;
154
152
  continue;
155
153
  }
156
- if (hostname[j] === "(")
157
- depth++;
158
- if (hostname[j] === ")")
159
- depth--;
154
+ if (hostname[j] === "(") depth++;
155
+ if (hostname[j] === ")") depth--;
160
156
  j++;
161
157
  }
162
158
  i = j;
@@ -225,12 +221,10 @@ function normalizeHostnamePattern(hostname) {
225
221
  return hostname;
226
222
  }
227
223
  function canonicalizePort(port, throwOnInvalid = false) {
228
- if (port === "")
229
- return "";
224
+ if (port === "") return "";
230
225
  const stripped = port.replace(/[\t\n\r]/g, "");
231
226
  const match = stripped.match(/^(\d+)/);
232
- if (!match)
233
- return void 0;
227
+ if (!match) return void 0;
234
228
  const numericPort = parseInt(match[1], 10);
235
229
  if (numericPort > 65535) {
236
230
  if (throwOnInvalid) {
@@ -241,8 +235,7 @@ function canonicalizePort(port, throwOnInvalid = false) {
241
235
  return numericPort.toString();
242
236
  }
243
237
  function isValidPatternPort(port) {
244
- if (port === "")
245
- return true;
238
+ if (port === "") return true;
246
239
  const stripped = port.replace(/[\t\n\r]/g, "");
247
240
  return /^\d+$/.test(stripped);
248
241
  }
@@ -297,7 +290,10 @@ function encodeSearch(search) {
297
290
  function encodeHash(hash) {
298
291
  try {
299
292
  return encodeURIComponent(decodeURIComponent(hash));
300
- } catch {
293
+ } catch (err) {
294
+ if (!(err instanceof URIError) || !String(err.message).includes("URI malformed")) {
295
+ throw err;
296
+ }
301
297
  return encodeURIComponent(hash);
302
298
  }
303
299
  }
@@ -335,22 +331,15 @@ function normalizePathname(pathname) {
335
331
  return result;
336
332
  }
337
333
  function isSimplePattern(pathname) {
338
- if (pathname.includes("\\"))
339
- return false;
340
- if (pathname.includes("{"))
341
- return false;
342
- if (pathname.includes("("))
343
- return false;
344
- if (pathname.includes("+"))
345
- return false;
346
- if (pathname.includes("?"))
347
- return false;
334
+ if (pathname.includes("\\")) return false;
335
+ if (pathname.includes("{")) return false;
336
+ if (pathname.includes("(")) return false;
337
+ if (pathname.includes("+")) return false;
338
+ if (pathname.includes("?")) return false;
348
339
  const wildcardIndex = pathname.indexOf("*");
349
340
  if (wildcardIndex !== -1) {
350
- if (wildcardIndex !== pathname.length - 1)
351
- return false;
352
- if (pathname[wildcardIndex - 1] !== "/")
353
- return false;
341
+ if (wildcardIndex !== pathname.length - 1) return false;
342
+ if (pathname[wildcardIndex - 1] !== "/") return false;
354
343
  }
355
344
  const paramMatches = pathname.matchAll(new RegExp(":(\\p{ID_Continue}+)", "gu"));
356
345
  for (const match of paramMatches) {
@@ -438,18 +427,12 @@ function findSearchDelimiter(pattern) {
438
427
  i++;
439
428
  continue;
440
429
  }
441
- if (char === "(")
442
- parenDepth++;
443
- else if (char === ")")
444
- parenDepth--;
445
- else if (char === "[")
446
- bracketDepth++;
447
- else if (char === "]")
448
- bracketDepth--;
449
- else if (char === "{")
450
- braceDepth++;
451
- else if (char === "}")
452
- braceDepth--;
430
+ if (char === "(") parenDepth++;
431
+ else if (char === ")") parenDepth--;
432
+ else if (char === "[") bracketDepth++;
433
+ else if (char === "]") bracketDepth--;
434
+ else if (char === "{") braceDepth++;
435
+ else if (char === "}") braceDepth--;
453
436
  if (char === "?" && parenDepth === 0 && bracketDepth === 0 && braceDepth === 0) {
454
437
  const prev = i > 0 ? pattern[i - 1] : "";
455
438
  if ("*+)}".includes(prev)) {
@@ -481,22 +464,16 @@ function findPathnameStart(afterScheme) {
481
464
  i++;
482
465
  continue;
483
466
  }
484
- if (char === "(")
485
- parenDepth++;
486
- else if (char === ")")
487
- parenDepth--;
488
- else if (char === "[")
489
- bracketDepth++;
490
- else if (char === "]")
491
- bracketDepth--;
467
+ if (char === "(") parenDepth++;
468
+ else if (char === ")") parenDepth--;
469
+ else if (char === "[") bracketDepth++;
470
+ else if (char === "]") bracketDepth--;
492
471
  else if (char === "{") {
493
472
  braceDepth++;
494
- if (braceDepth === 1)
495
- braceStart = i;
473
+ if (braceDepth === 1) braceStart = i;
496
474
  } else if (char === "}") {
497
475
  braceDepth--;
498
- if (braceDepth === 0)
499
- braceStart = -1;
476
+ if (braceDepth === 0) braceStart = -1;
500
477
  } else if (char === "/" && parenDepth === 0 && bracketDepth === 0) {
501
478
  if (braceDepth > 0 && braceStart !== -1) {
502
479
  return { index: i, truncateHostname: i, useWildcardPathname: true };
@@ -537,18 +514,12 @@ function validatePatternStructure(pattern) {
537
514
  i++;
538
515
  continue;
539
516
  }
540
- if (char === "(")
541
- parenDepth++;
542
- else if (char === ")")
543
- parenDepth--;
544
- else if (char === "[")
545
- bracketDepth++;
546
- else if (char === "]")
547
- bracketDepth--;
548
- else if (char === "{")
549
- braceDepth++;
550
- else if (char === "}")
551
- braceDepth--;
517
+ if (char === "(") parenDepth++;
518
+ else if (char === ")") parenDepth--;
519
+ else if (char === "[") bracketDepth++;
520
+ else if (char === "]") bracketDepth--;
521
+ else if (char === "{") braceDepth++;
522
+ else if (char === "}") braceDepth--;
552
523
  }
553
524
  if (parenDepth > 0 || bracketDepth > 0 || braceDepth > 0) {
554
525
  throw new TypeError(
@@ -617,12 +588,10 @@ function parseStringPattern(pattern) {
617
588
  const hashIdx = afterAt.indexOf("#");
618
589
  const searchDelim2 = findSearchDelimiter(afterAt);
619
590
  let hostEnd = afterAt.length;
620
- if (slashIdx !== -1 && slashIdx < hostEnd)
621
- hostEnd = slashIdx;
591
+ if (slashIdx !== -1 && slashIdx < hostEnd) hostEnd = slashIdx;
622
592
  if (searchDelim2.index !== -1 && searchDelim2.index < hostEnd)
623
593
  hostEnd = searchDelim2.index;
624
- if (hashIdx !== -1 && hashIdx < hostEnd)
625
- hostEnd = hashIdx;
594
+ if (hashIdx !== -1 && hashIdx < hostEnd) hostEnd = hashIdx;
626
595
  const hostPart = afterAt.slice(0, hostEnd);
627
596
  let hostname;
628
597
  let port;
@@ -641,14 +610,12 @@ function parseStringPattern(pattern) {
641
610
  let pathEnd = afterAt.length;
642
611
  if (searchDelim2.index !== -1 && searchDelim2.index > slashIdx)
643
612
  pathEnd = Math.min(pathEnd, searchDelim2.index);
644
- if (hashIdx !== -1)
645
- pathEnd = Math.min(pathEnd, hashIdx);
613
+ if (hashIdx !== -1) pathEnd = Math.min(pathEnd, hashIdx);
646
614
  pathname2 = afterAt.slice(pathStart, pathEnd);
647
615
  }
648
616
  if (searchDelim2.index !== -1) {
649
617
  let searchEnd = afterAt.length;
650
- if (hashIdx !== -1 && hashIdx > searchDelim2.index)
651
- searchEnd = hashIdx;
618
+ if (hashIdx !== -1 && hashIdx > searchDelim2.index) searchEnd = hashIdx;
652
619
  search2 = afterAt.slice(
653
620
  searchDelim2.index + searchDelim2.offset,
654
621
  searchEnd
@@ -711,18 +678,12 @@ function parseStringPattern(pattern) {
711
678
  i++;
712
679
  continue;
713
680
  }
714
- if (char === "[")
715
- bracketDepth++;
716
- else if (char === "]")
717
- bracketDepth--;
718
- else if (char === "{")
719
- braceDepth++;
720
- else if (char === "}")
721
- braceDepth--;
722
- else if (char === "(")
723
- parenDepth++;
724
- else if (char === ")")
725
- parenDepth--;
681
+ if (char === "[") bracketDepth++;
682
+ else if (char === "]") bracketDepth--;
683
+ else if (char === "{") braceDepth++;
684
+ else if (char === "}") braceDepth--;
685
+ else if (char === "(") parenDepth++;
686
+ else if (char === ")") parenDepth--;
726
687
  else if (char === "@" && bracketDepth === 0 && braceDepth === 0 && parenDepth === 0) {
727
688
  atIndex = i;
728
689
  break;
@@ -745,10 +706,8 @@ function parseStringPattern(pattern) {
745
706
  i++;
746
707
  continue;
747
708
  }
748
- if (char === "{")
749
- braceDepth2++;
750
- else if (char === "}")
751
- braceDepth2--;
709
+ if (char === "{") braceDepth2++;
710
+ else if (char === "}") braceDepth2--;
752
711
  else if (char === ":" && braceDepth2 === 0) {
753
712
  const afterColon = userinfo.slice(i + 1);
754
713
  const paramMatch = afterColon.match(
@@ -906,12 +865,9 @@ function compileComponentPattern(component, ignoreCase = false) {
906
865
  j += 2;
907
866
  continue;
908
867
  }
909
- if (component[j] === "(")
910
- depth++;
911
- if (component[j] === ")")
912
- depth--;
913
- if (depth > 0)
914
- regexContent += component[j];
868
+ if (component[j] === "(") depth++;
869
+ if (component[j] === ")") depth--;
870
+ if (depth > 0) regexContent += component[j];
915
871
  j++;
916
872
  }
917
873
  validateRegexGroupContent(regexContent);
@@ -944,8 +900,7 @@ function compileComponentPattern(component, ignoreCase = false) {
944
900
  }
945
901
  paramNames.push(...compiled.paramNames);
946
902
  i = closeIndex + 1;
947
- if (isModifier)
948
- i++;
903
+ if (isModifier) i++;
949
904
  continue;
950
905
  }
951
906
  }
@@ -985,10 +940,8 @@ function compileComponentPattern(component, ignoreCase = false) {
985
940
  }
986
941
  const needsVFlag = requiresVFlag(pattern);
987
942
  let flags = "";
988
- if (ignoreCase)
989
- flags += "i";
990
- if (needsVFlag)
991
- flags += "v";
943
+ if (ignoreCase) flags += "i";
944
+ if (needsVFlag) flags += "v";
992
945
  const regex = new RegExp(`^${pattern}$`, flags || void 0);
993
946
  return { regex, paramNames, hasWildcard };
994
947
  }
@@ -1096,12 +1049,9 @@ function compilePathname(pathname, encodeChars = true, ignoreCase = false) {
1096
1049
  j += 2;
1097
1050
  continue;
1098
1051
  }
1099
- if (pathname[j] === "(")
1100
- depth++;
1101
- if (pathname[j] === ")")
1102
- depth--;
1103
- if (depth > 0)
1104
- regexContent += pathname[j];
1052
+ if (pathname[j] === "(") depth++;
1053
+ if (pathname[j] === ")") depth--;
1054
+ if (depth > 0) regexContent += pathname[j];
1105
1055
  j++;
1106
1056
  }
1107
1057
  validateRegexGroupContent(regexContent);
@@ -1158,8 +1108,7 @@ function compilePathname(pathname, encodeChars = true, ignoreCase = false) {
1158
1108
  }
1159
1109
  paramNames.push(...compiled.paramNames);
1160
1110
  i = closeIndex + 1;
1161
- if (isModifier)
1162
- i++;
1111
+ if (isModifier) i++;
1163
1112
  continue;
1164
1113
  }
1165
1114
  }
@@ -1231,10 +1180,8 @@ function compilePathname(pathname, encodeChars = true, ignoreCase = false) {
1231
1180
  }
1232
1181
  const needsVFlag = requiresVFlag(pattern);
1233
1182
  let flags = "";
1234
- if (ignoreCase)
1235
- flags += "i";
1236
- if (needsVFlag)
1237
- flags += "v";
1183
+ if (ignoreCase) flags += "i";
1184
+ if (needsVFlag) flags += "v";
1238
1185
  const regex = new RegExp(`^${pattern}$`, flags || void 0);
1239
1186
  return { regex, paramNames, hasWildcard };
1240
1187
  }
@@ -1255,8 +1202,7 @@ function testSearchParameters(searchPattern, actualSearch) {
1255
1202
  }
1256
1203
  function parseRawSearchParams(search) {
1257
1204
  const params = /* @__PURE__ */ new Map();
1258
- if (!search)
1259
- return params;
1205
+ if (!search) return params;
1260
1206
  const parts = search.split("&");
1261
1207
  for (const part of parts) {
1262
1208
  const eqIdx = part.indexOf("=");
@@ -1291,8 +1237,7 @@ function parseSearchPattern(pattern) {
1291
1237
  const parts = pattern.split("&");
1292
1238
  for (const part of parts) {
1293
1239
  const [key, value] = part.split("=");
1294
- if (!key)
1295
- continue;
1240
+ if (!key) continue;
1296
1241
  if (value === void 0) {
1297
1242
  params.set(key, { type: "wildcard" });
1298
1243
  continue;
@@ -1317,7 +1262,8 @@ function compileURLPatternInit(init, baseURL, options) {
1317
1262
  if (base) {
1318
1263
  try {
1319
1264
  baseURLParsed = new URL(base);
1320
- } catch {
1265
+ } catch (err) {
1266
+ if (!(err instanceof TypeError)) throw err;
1321
1267
  }
1322
1268
  }
1323
1269
  const result = {};
@@ -1549,7 +1495,8 @@ var URLPattern = class {
1549
1495
  if (typeof input === "string") {
1550
1496
  try {
1551
1497
  url = baseURL ? new URL(input, baseURL) : new URL(input);
1552
- } catch {
1498
+ } catch (err) {
1499
+ if (!(err instanceof TypeError)) throw err;
1553
1500
  return false;
1554
1501
  }
1555
1502
  } else {
@@ -1566,34 +1513,30 @@ var URLPattern = class {
1566
1513
  if (base) {
1567
1514
  try {
1568
1515
  baseURLObj = new URL(base);
1569
- } catch {
1516
+ } catch (err) {
1517
+ if (!(err instanceof TypeError)) throw err;
1570
1518
  }
1571
1519
  }
1572
1520
  const protocol = input.protocol ?? baseURLObj?.protocol.replace(":", "") ?? void 0;
1573
- if (protocol !== void 0 && !isValidProtocol(protocol))
1574
- return false;
1521
+ if (protocol !== void 0 && !isValidProtocol(protocol)) return false;
1575
1522
  if (this.#compiled.protocol) {
1576
1523
  if (protocol === void 0 || !this.#compiled.protocol.regex.test(protocol))
1577
1524
  return false;
1578
1525
  }
1579
1526
  if (this.#compiled.hostname) {
1580
1527
  let hostname = input.hostname ?? baseURLObj?.hostname;
1581
- if (hostname === void 0)
1582
- return false;
1528
+ if (hostname === void 0) return false;
1583
1529
  hostname = toASCII(hostname);
1584
- if (!this.#compiled.hostname.regex.test(hostname))
1585
- return false;
1530
+ if (!this.#compiled.hostname.regex.test(hostname)) return false;
1586
1531
  }
1587
1532
  let port = input.port ?? baseURLObj?.port;
1588
1533
  if (port !== void 0) {
1589
1534
  const canonical = canonicalizePort(port);
1590
- if (canonical === void 0)
1591
- return false;
1535
+ if (canonical === void 0) return false;
1592
1536
  port = canonical;
1593
1537
  if (protocol) {
1594
1538
  const defaultPort = getDefaultPort(protocol);
1595
- if (defaultPort && port === defaultPort)
1596
- port = "";
1539
+ if (defaultPort && port === defaultPort) port = "";
1597
1540
  }
1598
1541
  }
1599
1542
  if (this.#compiled.port) {
@@ -1619,36 +1562,27 @@ var URLPattern = class {
1619
1562
  pathname = basePath.slice(0, basePath.lastIndexOf("/") + 1) + pathname;
1620
1563
  }
1621
1564
  }
1622
- if (pathname.startsWith("/"))
1623
- pathname = normalizePathname(pathname);
1565
+ if (pathname.startsWith("/")) pathname = normalizePathname(pathname);
1624
1566
  const shouldEncode = !protocol || isSpecialScheme(protocol);
1625
- if (shouldEncode)
1626
- pathname = encodePathname(pathname);
1627
- if (!this.#compiled.pathname.regex.test(pathname))
1628
- return false;
1567
+ if (shouldEncode) pathname = encodePathname(pathname);
1568
+ if (!this.#compiled.pathname.regex.test(pathname)) return false;
1629
1569
  if (this.#compiled.hash) {
1630
1570
  let hash = input.hash ?? baseURLObj?.hash.replace("#", "") ?? void 0;
1631
- if (hash === void 0)
1632
- return false;
1633
- if (hash.startsWith("#"))
1634
- hash = hash.slice(1);
1571
+ if (hash === void 0) return false;
1572
+ if (hash.startsWith("#")) hash = hash.slice(1);
1635
1573
  hash = encodeHash(hash);
1636
- if (!this.#compiled.hash.regex.test(hash))
1637
- return false;
1574
+ if (!this.#compiled.hash.regex.test(hash)) return false;
1638
1575
  }
1639
1576
  if (this.#compiled.search) {
1640
1577
  let search = input.search ?? baseURLObj?.search?.replace("?", "") ?? "";
1641
- if (search.startsWith("?"))
1642
- search = search.slice(1);
1578
+ if (search.startsWith("?")) search = search.slice(1);
1643
1579
  search = encodeSearch(search);
1644
- if (!this.#compiled.search.regex.test(search))
1645
- return false;
1580
+ if (!this.#compiled.search.regex.test(search)) return false;
1646
1581
  }
1647
1582
  return true;
1648
1583
  }
1649
1584
  exec(input, baseURL) {
1650
- if (!this.test(input, baseURL))
1651
- return null;
1585
+ if (!this.test(input, baseURL)) return null;
1652
1586
  if (typeof input === "object" && !(input instanceof URL)) {
1653
1587
  return this.#execInit(input, baseURL);
1654
1588
  }
@@ -1705,7 +1639,8 @@ var URLPattern = class {
1705
1639
  if (base) {
1706
1640
  try {
1707
1641
  baseURLObj = new URL(base);
1708
- } catch {
1642
+ } catch (err) {
1643
+ if (!(err instanceof TypeError)) throw err;
1709
1644
  }
1710
1645
  }
1711
1646
  let pathname = input.pathname ?? baseURLObj?.pathname ?? "/";
@@ -1726,8 +1661,7 @@ var URLPattern = class {
1726
1661
  }
1727
1662
  if (this.#compiled.search) {
1728
1663
  let search2 = input.search ?? baseURLObj?.search?.replace("?", "") ?? "";
1729
- if (search2.startsWith("?"))
1730
- search2 = search2.slice(1);
1664
+ if (search2.startsWith("?")) search2 = search2.slice(1);
1731
1665
  const searchMatch = this.#compiled.search.regex.exec(search2);
1732
1666
  if (searchMatch) {
1733
1667
  for (let i = 0; i < this.#compiled.search.paramNames.length; i++) {
@@ -1743,8 +1677,7 @@ var URLPattern = class {
1743
1677
  const protocol = input.protocol ?? baseURLObj?.protocol.replace(":", "") ?? "";
1744
1678
  const hostname = input.hostname ?? baseURLObj?.hostname ?? "";
1745
1679
  let port = input.port ?? baseURLObj?.port ?? "";
1746
- if (port)
1747
- port = canonicalizePort(port) || "";
1680
+ if (port) port = canonicalizePort(port) || "";
1748
1681
  const hash = input.hash ?? baseURLObj?.hash?.replace("#", "") ?? "";
1749
1682
  const search = input.search ?? baseURLObj?.search?.replace("?", "") ?? "";
1750
1683
  return {
@@ -1812,7 +1745,8 @@ var MatchPattern = class {
1812
1745
  if (typeof input === "string") {
1813
1746
  try {
1814
1747
  url = baseURL ? new URL(input, baseURL) : new URL(input);
1815
- } catch {
1748
+ } catch (err) {
1749
+ if (!(err instanceof TypeError)) throw err;
1816
1750
  return false;
1817
1751
  }
1818
1752
  } else {
@@ -1833,34 +1767,30 @@ var MatchPattern = class {
1833
1767
  if (base) {
1834
1768
  try {
1835
1769
  baseURLObj = new URL(base);
1836
- } catch {
1770
+ } catch (err) {
1771
+ if (!(err instanceof TypeError)) throw err;
1837
1772
  }
1838
1773
  }
1839
1774
  const protocol = input.protocol ?? baseURLObj?.protocol.replace(":", "") ?? void 0;
1840
- if (protocol !== void 0 && !isValidProtocol(protocol))
1841
- return false;
1775
+ if (protocol !== void 0 && !isValidProtocol(protocol)) return false;
1842
1776
  if (this.#compiled.protocol) {
1843
1777
  if (protocol === void 0 || !this.#compiled.protocol.regex.test(protocol))
1844
1778
  return false;
1845
1779
  }
1846
1780
  if (this.#compiled.hostname) {
1847
1781
  let hostname = input.hostname ?? baseURLObj?.hostname;
1848
- if (hostname === void 0)
1849
- return false;
1782
+ if (hostname === void 0) return false;
1850
1783
  hostname = toASCII(hostname);
1851
- if (!this.#compiled.hostname.regex.test(hostname))
1852
- return false;
1784
+ if (!this.#compiled.hostname.regex.test(hostname)) return false;
1853
1785
  }
1854
1786
  let port = input.port ?? baseURLObj?.port;
1855
1787
  if (port !== void 0) {
1856
1788
  const canonical = canonicalizePort(port);
1857
- if (canonical === void 0)
1858
- return false;
1789
+ if (canonical === void 0) return false;
1859
1790
  port = canonical;
1860
1791
  if (protocol) {
1861
1792
  const defaultPort = getDefaultPort(protocol);
1862
- if (defaultPort && port === defaultPort)
1863
- port = "";
1793
+ if (defaultPort && port === defaultPort) port = "";
1864
1794
  }
1865
1795
  }
1866
1796
  if (this.#compiled.port) {
@@ -1882,7 +1812,8 @@ var MatchPattern = class {
1882
1812
  try {
1883
1813
  const resolved = new URL(pathname, baseURLObj.href);
1884
1814
  pathname = resolved.pathname;
1885
- } catch {
1815
+ } catch (err) {
1816
+ if (!(err instanceof TypeError)) throw err;
1886
1817
  const basePath = baseURLObj.pathname;
1887
1818
  if (basePath.endsWith("/")) {
1888
1819
  pathname = basePath + pathname;
@@ -1891,27 +1822,20 @@ var MatchPattern = class {
1891
1822
  }
1892
1823
  }
1893
1824
  }
1894
- if (pathname.startsWith("/"))
1895
- pathname = normalizePathname(pathname);
1825
+ if (pathname.startsWith("/")) pathname = normalizePathname(pathname);
1896
1826
  const shouldEncode = !protocol || isSpecialScheme(protocol);
1897
- if (shouldEncode)
1898
- pathname = encodePathname(pathname);
1899
- if (!this.#compiled.pathname.regex.test(pathname))
1900
- return false;
1827
+ if (shouldEncode) pathname = encodePathname(pathname);
1828
+ if (!this.#compiled.pathname.regex.test(pathname)) return false;
1901
1829
  if (this.#compiled.hash) {
1902
1830
  let hash = input.hash ?? baseURLObj?.hash.replace("#", "") ?? void 0;
1903
- if (hash === void 0)
1904
- return false;
1905
- if (hash.startsWith("#"))
1906
- hash = hash.slice(1);
1831
+ if (hash === void 0) return false;
1832
+ if (hash.startsWith("#")) hash = hash.slice(1);
1907
1833
  hash = encodeHash(hash);
1908
- if (!this.#compiled.hash.regex.test(hash))
1909
- return false;
1834
+ if (!this.#compiled.hash.regex.test(hash)) return false;
1910
1835
  }
1911
1836
  if (this.#searchPattern) {
1912
1837
  let search = input.search ?? baseURLObj?.search?.replace("?", "") ?? "";
1913
- if (search.startsWith("?"))
1914
- search = search.slice(1);
1838
+ if (search.startsWith("?")) search = search.slice(1);
1915
1839
  search = encodeSearch(search);
1916
1840
  if (!this.#searchPattern.includes("=")) {
1917
1841
  if (this.#compiled.search) {
@@ -1924,8 +1848,7 @@ var MatchPattern = class {
1924
1848
  return true;
1925
1849
  }
1926
1850
  exec(input, baseURL) {
1927
- if (!this.test(input, baseURL))
1928
- return null;
1851
+ if (!this.test(input, baseURL)) return null;
1929
1852
  if (typeof input === "object" && !(input instanceof URL)) {
1930
1853
  return this.#execInit(input, baseURL);
1931
1854
  }
@@ -1981,7 +1904,8 @@ var MatchPattern = class {
1981
1904
  if (base) {
1982
1905
  try {
1983
1906
  baseURLObj = new URL(base);
1984
- } catch {
1907
+ } catch (err) {
1908
+ if (!(err instanceof TypeError)) throw err;
1985
1909
  }
1986
1910
  }
1987
1911
  let pathname = input.pathname ?? baseURLObj?.pathname ?? "/";
@@ -2012,8 +1936,7 @@ var MatchPattern = class {
2012
1936
  const protocol = input.protocol ?? baseURLObj?.protocol.replace(":", "") ?? "";
2013
1937
  const hostname = input.hostname ?? baseURLObj?.hostname ?? "";
2014
1938
  let port = input.port ?? baseURLObj?.port ?? "";
2015
- if (port)
2016
- port = canonicalizePort(port) || "";
1939
+ if (port) port = canonicalizePort(port) || "";
2017
1940
  const hash = input.hash ?? baseURLObj?.hash?.replace("#", "") ?? "";
2018
1941
  const search = input.search ?? baseURLObj?.search?.replace("?", "") ?? "";
2019
1942
  return {