@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 +69 -30
- package/package.json +2 -11
- package/src/index.d.ts +4 -0
- package/src/index.js +119 -196
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 {
|
|
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 +
|
|
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({
|
|
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({
|
|
82
|
+
const pattern = new MatchPattern({search: 'q=:query'});
|
|
83
83
|
|
|
84
84
|
// URLPattern greedy capture issue
|
|
85
|
-
const urlPattern = new URLPattern({
|
|
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); // {
|
|
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); // {
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
225
|
-
|
|
226
|
-
|
|
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
|
|
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
|
|
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.
|
|
3
|
+
"version": "0.2.0-beta.0",
|
|
4
4
|
"devDependencies": {
|
|
5
|
-
"@b9g/libuild": "^0.1.
|
|
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
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
340
|
-
if (pathname.includes("
|
|
341
|
-
|
|
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
|
-
|
|
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
|
-
|
|
443
|
-
else if (char === "
|
|
444
|
-
|
|
445
|
-
else if (char === "
|
|
446
|
-
|
|
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
|
-
|
|
486
|
-
else if (char === "
|
|
487
|
-
|
|
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
|
-
|
|
542
|
-
else if (char === "
|
|
543
|
-
|
|
544
|
-
else if (char === "
|
|
545
|
-
|
|
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
|
-
|
|
716
|
-
else if (char === "
|
|
717
|
-
|
|
718
|
-
else if (char === "
|
|
719
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 {
|