@b9g/match-pattern 0.1.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 +180 -0
- package/package.json +33 -0
- package/src/index.d.ts +1 -0
- package/src/index.js +6 -0
- package/src/match-pattern.d.ts +43 -0
- package/src/match-pattern.js +214 -0
package/README.md
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# MatchPattern
|
|
2
|
+
|
|
3
|
+
Extended URLPattern for better routing with enhanced search parameter handling.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
MatchPattern is a subclass of URLPattern that fixes its limitations for web routing while maintaining full backward compatibility. It enhances URLPattern with order-independent search parameters, unified parameter extraction, and convenient string pattern syntax.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @b9g/match-pattern
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Basic Usage
|
|
16
|
+
|
|
17
|
+
```javascript
|
|
18
|
+
import { MatchPattern } from '@b9g/match-pattern';
|
|
19
|
+
|
|
20
|
+
// Create patterns with enhanced string syntax
|
|
21
|
+
const pattern = new MatchPattern('/api/posts/:id&format=:format');
|
|
22
|
+
const url = new URL('http://example.com/api/posts/123?format=json&page=1');
|
|
23
|
+
|
|
24
|
+
if (pattern.test(url)) {
|
|
25
|
+
const result = pattern.exec(url);
|
|
26
|
+
console.log(result.params);
|
|
27
|
+
// { id: '123', format: 'json', page: '1' }
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Key Differences from URLPattern
|
|
32
|
+
|
|
33
|
+
### 1. Order-Independent Search Parameters
|
|
34
|
+
|
|
35
|
+
URLPattern requires exact parameter order. MatchPattern allows any order:
|
|
36
|
+
|
|
37
|
+
```javascript
|
|
38
|
+
const pattern = new MatchPattern({ search: 'type=:type&sort=:sort' });
|
|
39
|
+
|
|
40
|
+
// URLPattern: Only first URL matches
|
|
41
|
+
// MatchPattern: Both URLs match
|
|
42
|
+
pattern.test('/?type=blog&sort=date'); // ✅ Both: true
|
|
43
|
+
pattern.test('/?sort=date&type=blog'); // ✅ MatchPattern: true, URLPattern: false
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### 2. Non-Exhaustive Search Matching
|
|
47
|
+
|
|
48
|
+
URLPattern rejects extra parameters. MatchPattern captures them:
|
|
49
|
+
|
|
50
|
+
```javascript
|
|
51
|
+
const pattern = new MatchPattern({ search: 'q=:query' });
|
|
52
|
+
const result = pattern.exec('/?q=hello&page=1&limit=10');
|
|
53
|
+
|
|
54
|
+
// URLPattern: Fails or captures 'hello&page=1&limit=10' as query value
|
|
55
|
+
// MatchPattern: { q: 'hello', page: '1', limit: '10' }
|
|
56
|
+
console.log(result.params);
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### 3. Unified Parameter Object
|
|
60
|
+
|
|
61
|
+
URLPattern separates pathname and search groups. MatchPattern merges everything:
|
|
62
|
+
|
|
63
|
+
```javascript
|
|
64
|
+
const pattern = new MatchPattern('/api/:version/posts/:id&format=:format');
|
|
65
|
+
const result = pattern.exec('/api/v1/posts/123?format=json&page=1');
|
|
66
|
+
|
|
67
|
+
// URLPattern: result.pathname.groups + result.search.groups (separate)
|
|
68
|
+
// MatchPattern: result.params (unified)
|
|
69
|
+
console.log(result.params); // { version: 'v1', id: '123', format: 'json', page: '1' }
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### 4. Enhanced String Pattern Syntax
|
|
73
|
+
|
|
74
|
+
MatchPattern supports convenient string patterns with `&` separator:
|
|
75
|
+
|
|
76
|
+
```javascript
|
|
77
|
+
// Pathname only
|
|
78
|
+
new MatchPattern('/api/posts/:id')
|
|
79
|
+
|
|
80
|
+
// Pathname with search parameters
|
|
81
|
+
new MatchPattern('/api/posts/:id&format=:format&page=:page')
|
|
82
|
+
|
|
83
|
+
// Search parameters only
|
|
84
|
+
new MatchPattern('&q=:query&sort=:sort')
|
|
85
|
+
|
|
86
|
+
// Full URL patterns
|
|
87
|
+
new MatchPattern('https://api.example.com/v1/posts/:id&format=:format')
|
|
88
|
+
|
|
89
|
+
// Object syntax (same as URLPattern, enhanced behavior)
|
|
90
|
+
new MatchPattern({
|
|
91
|
+
pathname: '/api/posts/:id',
|
|
92
|
+
search: 'format=:format'
|
|
93
|
+
})
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Trailing Slash Normalization
|
|
97
|
+
|
|
98
|
+
URLPattern has inconsistent behavior with trailing slashes that can cause unexpected matches.
|
|
99
|
+
|
|
100
|
+
**Issue:** [kenchris/urlpattern-polyfill#131](https://github.com/kenchris/urlpattern-polyfill/issues/131)
|
|
101
|
+
|
|
102
|
+
**Solution:** ✅ Automatic trailing slash normalization implemented
|
|
103
|
+
|
|
104
|
+
```javascript
|
|
105
|
+
const pattern = new MatchPattern('/api/posts/:id');
|
|
106
|
+
|
|
107
|
+
// Both match consistently
|
|
108
|
+
pattern.test('/api/posts/123'); // ✅ true
|
|
109
|
+
pattern.test('/api/posts/123/'); // ✅ true (normalized)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Known Limitations
|
|
113
|
+
|
|
114
|
+
### Cross-Implementation Differences
|
|
115
|
+
|
|
116
|
+
The polyfill and native browser implementations can return different results for edge cases.
|
|
117
|
+
|
|
118
|
+
**Issue:** [kenchris/urlpattern-polyfill#129](https://github.com/kenchris/urlpattern-polyfill/issues/129)
|
|
119
|
+
|
|
120
|
+
**Impact:** Results may vary between Node.js, browsers, and other runtimes.
|
|
121
|
+
|
|
122
|
+
**Testing:** Use Playwright for cross-browser validation in production applications.
|
|
123
|
+
|
|
124
|
+
### TypeScript Compatibility
|
|
125
|
+
|
|
126
|
+
Node.js and polyfill URLPattern types have slight differences in their TypeScript definitions.
|
|
127
|
+
|
|
128
|
+
**Issue:** [kenchris/urlpattern-polyfill#135](https://github.com/kenchris/urlpattern-polyfill/issues/135)
|
|
129
|
+
|
|
130
|
+
**Solution:** MatchPattern uses canonical WHATWG specification types internally.
|
|
131
|
+
|
|
132
|
+
## API Reference
|
|
133
|
+
|
|
134
|
+
### Constructor
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
new MatchPattern(input: string | URLPatternInit, baseURL?: string)
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Methods
|
|
141
|
+
|
|
142
|
+
```typescript
|
|
143
|
+
// Enhanced methods with unified params
|
|
144
|
+
test(input: string | URL): boolean
|
|
145
|
+
exec(input: string | URL): MatchPatternResult | null
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Types
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
interface MatchPatternResult extends URLPatternResult {
|
|
152
|
+
params: Record<string, string>; // Unified parameters from all sources
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Compatibility
|
|
157
|
+
|
|
158
|
+
- **Node.js**: 18+ (with URLPattern support) or any version with polyfill
|
|
159
|
+
- **Browsers**: Chrome 95+, or any browser with polyfill
|
|
160
|
+
- **Runtimes**: Deno, Bun, Cloudflare Workers, Edge Runtime
|
|
161
|
+
- **TypeScript**: 5.0+ recommended
|
|
162
|
+
|
|
163
|
+
## Contributing
|
|
164
|
+
|
|
165
|
+
MatchPattern follows the [WHATWG URLPattern specification](https://urlpattern.spec.whatwg.org/) while extending it for routing use cases.
|
|
166
|
+
|
|
167
|
+
Report issues related to:
|
|
168
|
+
- URLPattern compatibility problems
|
|
169
|
+
- Performance issues with complex patterns
|
|
170
|
+
- Cross-runtime behavior differences
|
|
171
|
+
|
|
172
|
+
## License
|
|
173
|
+
|
|
174
|
+
MIT - see LICENSE file for details.
|
|
175
|
+
|
|
176
|
+
## Acknowledgments
|
|
177
|
+
|
|
178
|
+
- URLPattern specification by WHATWG
|
|
179
|
+
- [urlpattern-polyfill](https://github.com/kenchris/urlpattern-polyfill) by Ken Christensen
|
|
180
|
+
- Web Platform community
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@b9g/match-pattern",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"devDependencies": {
|
|
5
|
+
"@b9g/libuild": "^0.1.10"
|
|
6
|
+
},
|
|
7
|
+
"type": "module",
|
|
8
|
+
"types": "src/index.d.ts",
|
|
9
|
+
"module": "src/index.js",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./src/index.d.ts",
|
|
13
|
+
"import": "./src/index.js"
|
|
14
|
+
},
|
|
15
|
+
"./index": {
|
|
16
|
+
"types": "./src/index.d.ts",
|
|
17
|
+
"import": "./src/index.js"
|
|
18
|
+
},
|
|
19
|
+
"./index.js": {
|
|
20
|
+
"types": "./src/index.d.ts",
|
|
21
|
+
"import": "./src/index.js"
|
|
22
|
+
},
|
|
23
|
+
"./match-pattern": {
|
|
24
|
+
"types": "./src/match-pattern.d.ts",
|
|
25
|
+
"import": "./src/match-pattern.js"
|
|
26
|
+
},
|
|
27
|
+
"./match-pattern.js": {
|
|
28
|
+
"types": "./src/match-pattern.d.ts",
|
|
29
|
+
"import": "./src/match-pattern.js"
|
|
30
|
+
},
|
|
31
|
+
"./package.json": "./package.json"
|
|
32
|
+
}
|
|
33
|
+
}
|
package/src/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { MatchPattern, type MatchPatternResult } from "./match-pattern.ts";
|
package/src/index.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
declare let URLPattern: any;
|
|
2
|
+
type URLPatternInput = URLPatternInit | string;
|
|
3
|
+
interface URLPatternComponentResult {
|
|
4
|
+
input: string;
|
|
5
|
+
groups: Record<string, string | undefined>;
|
|
6
|
+
}
|
|
7
|
+
interface URLPatternResult {
|
|
8
|
+
inputs: URLPatternInput[];
|
|
9
|
+
protocol: URLPatternComponentResult;
|
|
10
|
+
username: URLPatternComponentResult;
|
|
11
|
+
password: URLPatternComponentResult;
|
|
12
|
+
hostname: URLPatternComponentResult;
|
|
13
|
+
port: URLPatternComponentResult;
|
|
14
|
+
pathname: URLPatternComponentResult;
|
|
15
|
+
search: URLPatternComponentResult;
|
|
16
|
+
hash: URLPatternComponentResult;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Enhanced URLPattern result that includes unified params
|
|
20
|
+
*/
|
|
21
|
+
export interface MatchPatternResult extends URLPatternResult {
|
|
22
|
+
params: Record<string, string>;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* MatchPattern extends URLPattern with enhanced routing capabilities:
|
|
26
|
+
* - Order-independent search parameter matching
|
|
27
|
+
* - Non-exhaustive search matching (extra params allowed)
|
|
28
|
+
* - Unified parameter extraction (pathname + search + extras)
|
|
29
|
+
* - Enhanced string pattern parsing with & syntax
|
|
30
|
+
*/
|
|
31
|
+
export declare class MatchPattern extends URLPattern {
|
|
32
|
+
private _originalInput;
|
|
33
|
+
constructor(input: string | URLPatternInit, baseURL?: string);
|
|
34
|
+
/**
|
|
35
|
+
* Enhanced exec that returns unified params object with trailing slash normalization
|
|
36
|
+
*/
|
|
37
|
+
exec(input: string | URL): MatchPatternResult | null;
|
|
38
|
+
/**
|
|
39
|
+
* Enhanced test with order-independent search parameter matching and trailing slash normalization
|
|
40
|
+
*/
|
|
41
|
+
test(input: string | URL): boolean;
|
|
42
|
+
}
|
|
43
|
+
export {};
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
/// <reference types="./match-pattern.d.ts" />
|
|
2
|
+
// src/match-pattern.ts
|
|
3
|
+
var URLPattern = globalThis.URLPattern;
|
|
4
|
+
if (!URLPattern) {
|
|
5
|
+
await import("urlpattern-polyfill");
|
|
6
|
+
URLPattern = globalThis.URLPattern;
|
|
7
|
+
}
|
|
8
|
+
var MatchPattern = class extends URLPattern {
|
|
9
|
+
_originalInput;
|
|
10
|
+
constructor(input, baseURL) {
|
|
11
|
+
let processedInput = input;
|
|
12
|
+
if (typeof input === "string") {
|
|
13
|
+
processedInput = parseStringPattern(input);
|
|
14
|
+
}
|
|
15
|
+
const normalizedInput = normalizePatternTrailingSlash(processedInput);
|
|
16
|
+
if (baseURL !== void 0) {
|
|
17
|
+
super(normalizedInput, baseURL);
|
|
18
|
+
} else {
|
|
19
|
+
super(normalizedInput);
|
|
20
|
+
}
|
|
21
|
+
this._originalInput = normalizedInput;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Enhanced exec that returns unified params object with trailing slash normalization
|
|
25
|
+
*/
|
|
26
|
+
exec(input) {
|
|
27
|
+
if (!this.test(input)) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
const url = typeof input === "string" ? new URL(input) : input;
|
|
31
|
+
const normalizedUrl = normalizeTrailingSlash(url);
|
|
32
|
+
const result = super.exec(normalizedUrl);
|
|
33
|
+
if (result) {
|
|
34
|
+
const enhancedResult = {
|
|
35
|
+
...result,
|
|
36
|
+
params: extractUnifiedParams(result, input)
|
|
37
|
+
// Use original input for search params
|
|
38
|
+
};
|
|
39
|
+
return enhancedResult;
|
|
40
|
+
}
|
|
41
|
+
return buildCustomResult(this, input);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Enhanced test with order-independent search parameter matching and trailing slash normalization
|
|
45
|
+
*/
|
|
46
|
+
test(input) {
|
|
47
|
+
const url = typeof input === "string" ? new URL(input) : input;
|
|
48
|
+
const normalizedUrl = normalizeTrailingSlash(url);
|
|
49
|
+
if (!this.search || this.search === "*") {
|
|
50
|
+
return super.test(normalizedUrl);
|
|
51
|
+
}
|
|
52
|
+
const pathPatternInit = typeof this._originalInput === "string" ? { pathname: this._originalInput } : { ...this._originalInput, search: void 0 };
|
|
53
|
+
const normalizedPattern = normalizePatternTrailingSlash(pathPatternInit);
|
|
54
|
+
const pathPattern = new URLPattern(normalizedPattern);
|
|
55
|
+
if (!pathPattern.test(normalizedUrl)) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
return testSearchParameters(this.search, url.searchParams);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
function parseStringPattern(pattern) {
|
|
62
|
+
if (pattern.includes("://")) {
|
|
63
|
+
const ampIndex2 = pattern.indexOf("&");
|
|
64
|
+
if (ampIndex2 === -1) {
|
|
65
|
+
return pattern;
|
|
66
|
+
}
|
|
67
|
+
const urlPart = pattern.slice(0, ampIndex2);
|
|
68
|
+
const search2 = pattern.slice(ampIndex2 + 1);
|
|
69
|
+
try {
|
|
70
|
+
const url = new URL(urlPart.replace(/:(\w+)/g, "placeholder"));
|
|
71
|
+
return {
|
|
72
|
+
protocol: urlPart.split("://")[0],
|
|
73
|
+
hostname: url.hostname,
|
|
74
|
+
pathname: url.pathname.replace(/placeholder/g, ":$1"),
|
|
75
|
+
// Restore params
|
|
76
|
+
search: search2
|
|
77
|
+
};
|
|
78
|
+
} catch {
|
|
79
|
+
return pattern;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
const ampIndex = pattern.indexOf("&");
|
|
83
|
+
if (ampIndex === -1) {
|
|
84
|
+
return { pathname: pattern };
|
|
85
|
+
}
|
|
86
|
+
if (ampIndex === 0) {
|
|
87
|
+
return { search: pattern.slice(1) };
|
|
88
|
+
}
|
|
89
|
+
const pathname = pattern.slice(0, ampIndex);
|
|
90
|
+
const search = pattern.slice(ampIndex + 1);
|
|
91
|
+
return { pathname, search };
|
|
92
|
+
}
|
|
93
|
+
function extractUnifiedParams(result, url) {
|
|
94
|
+
const params = {};
|
|
95
|
+
if (result.pathname?.groups) {
|
|
96
|
+
for (const [key, value] of Object.entries(result.pathname.groups)) {
|
|
97
|
+
if (value !== void 0) {
|
|
98
|
+
params[key] = value;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (result.search?.groups) {
|
|
103
|
+
const actualUrl = typeof url === "string" ? new URL(url) : url;
|
|
104
|
+
const searchParams = actualUrl.searchParams;
|
|
105
|
+
for (const [key, value] of searchParams) {
|
|
106
|
+
params[key] = value;
|
|
107
|
+
}
|
|
108
|
+
} else if (typeof url !== "string") {
|
|
109
|
+
const actualUrl = url instanceof URL ? url : new URL(url);
|
|
110
|
+
for (const [key, value] of actualUrl.searchParams) {
|
|
111
|
+
params[key] = value;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return params;
|
|
115
|
+
}
|
|
116
|
+
function normalizeTrailingSlash(url) {
|
|
117
|
+
const normalized = new URL(url.href);
|
|
118
|
+
if (normalized.pathname === "/") {
|
|
119
|
+
return normalized;
|
|
120
|
+
}
|
|
121
|
+
if (normalized.pathname.endsWith("/")) {
|
|
122
|
+
normalized.pathname = normalized.pathname.slice(0, -1);
|
|
123
|
+
}
|
|
124
|
+
return normalized;
|
|
125
|
+
}
|
|
126
|
+
function normalizePatternTrailingSlash(patternInit) {
|
|
127
|
+
if (typeof patternInit === "string") {
|
|
128
|
+
if (patternInit === "/" || patternInit === "") {
|
|
129
|
+
return patternInit;
|
|
130
|
+
}
|
|
131
|
+
return patternInit.endsWith("/") ? patternInit.slice(0, -1) : patternInit;
|
|
132
|
+
}
|
|
133
|
+
const normalized = { ...patternInit };
|
|
134
|
+
if (normalized.pathname && normalized.pathname !== "/") {
|
|
135
|
+
if (normalized.pathname.endsWith("/")) {
|
|
136
|
+
normalized.pathname = normalized.pathname.slice(0, -1);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return normalized;
|
|
140
|
+
}
|
|
141
|
+
function buildCustomResult(pattern, input) {
|
|
142
|
+
const url = typeof input === "string" ? new URL(input) : input;
|
|
143
|
+
const result = {
|
|
144
|
+
inputs: [input],
|
|
145
|
+
pathname: { input: url.pathname, groups: {} },
|
|
146
|
+
search: { input: url.search, groups: {} },
|
|
147
|
+
hash: { input: url.hash, groups: {} },
|
|
148
|
+
protocol: { input: url.protocol, groups: {} },
|
|
149
|
+
hostname: { input: url.hostname, groups: {} },
|
|
150
|
+
port: { input: url.port, groups: {} },
|
|
151
|
+
username: { input: url.username, groups: {} },
|
|
152
|
+
password: { input: url.password, groups: {} },
|
|
153
|
+
params: {}
|
|
154
|
+
};
|
|
155
|
+
if (pattern.pathname && pattern.pathname !== "*") {
|
|
156
|
+
const pathPattern = new URLPattern({ pathname: pattern.pathname });
|
|
157
|
+
const pathResult = pathPattern.exec(url);
|
|
158
|
+
if (pathResult?.pathname?.groups) {
|
|
159
|
+
result.pathname.groups = pathResult.pathname.groups;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
if (pattern.search && pattern.search !== "*") {
|
|
163
|
+
const searchParams = parseSearchPattern(pattern.search);
|
|
164
|
+
const actualParams = url.searchParams;
|
|
165
|
+
for (const [key, paramDef] of searchParams) {
|
|
166
|
+
if (actualParams.has(key)) {
|
|
167
|
+
if (paramDef.type === "named" && paramDef.name) {
|
|
168
|
+
result.search.groups[paramDef.name] = actualParams.get(key);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
result.params = extractUnifiedParams(result, input);
|
|
174
|
+
return result;
|
|
175
|
+
}
|
|
176
|
+
function testSearchParameters(searchPattern, actualParams) {
|
|
177
|
+
const patternParams = parseSearchPattern(searchPattern);
|
|
178
|
+
for (const [key, paramPattern] of patternParams) {
|
|
179
|
+
if (!actualParams.has(key)) {
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
182
|
+
if (paramPattern.type === "literal") {
|
|
183
|
+
if (actualParams.get(key) !== paramPattern.value) {
|
|
184
|
+
return false;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return true;
|
|
189
|
+
}
|
|
190
|
+
function parseSearchPattern(pattern) {
|
|
191
|
+
const params = /* @__PURE__ */ new Map();
|
|
192
|
+
const parts = pattern.split("&");
|
|
193
|
+
for (const part of parts) {
|
|
194
|
+
const [key, value] = part.split("=");
|
|
195
|
+
if (!key || !value)
|
|
196
|
+
continue;
|
|
197
|
+
if (value.startsWith(":")) {
|
|
198
|
+
const isOptional = value.endsWith("?");
|
|
199
|
+
params.set(key, {
|
|
200
|
+
type: "named",
|
|
201
|
+
name: value.slice(1, isOptional ? -1 : void 0),
|
|
202
|
+
optional: isOptional
|
|
203
|
+
});
|
|
204
|
+
} else if (value === "*") {
|
|
205
|
+
params.set(key, { type: "wildcard" });
|
|
206
|
+
} else {
|
|
207
|
+
params.set(key, { type: "literal", value });
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return params;
|
|
211
|
+
}
|
|
212
|
+
export {
|
|
213
|
+
MatchPattern
|
|
214
|
+
};
|