@peter.naydenov/url-pattern 1.0.2 → 1.0.3

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/src/main.js CHANGED
@@ -7,7 +7,8 @@
7
7
  * @typedef {Object} UrlPatternOptions
8
8
  * @property {string} [escapeChar='\\'] - Character used for escaping special characters
9
9
  * @property {string} [segmentNameStartChar=':'] - Character that starts a named segment
10
- * @property {string} [segmentNameCharset='a-zA-Z0-9'] - Characters allowed in segment names
10
+ * @property {string} [segmentNameEndChar] - Character that ends a named segment. When set, the segment name stops at the first occurrence of this character (instead of stopping at the first character outside `segmentNameCharset`).
11
+ * @property {string} [segmentNameCharset='a-zA-Z0-9_'] - Characters allowed in segment names
11
12
  * @property {string} [segmentValueCharset='a-zA-Z0-9-_~ %'] - Characters allowed in segment values
12
13
  * @property {string} [optionalSegmentStartChar='('] - Character that starts an optional segment
13
14
  * @property {string} [optionalSegmentEndChar=')'] - Character that ends an optional segment
@@ -19,6 +20,7 @@
19
20
  * @property {string} name - Segment name
20
21
  * @property {string} type - Segment type ('named' | 'wildcard' | 'literal')
21
22
  * @property {boolean} [optional=false] - Whether the segment is optional
23
+ * @property {number} [optionalGroupId] - Identifier of the optional group this segment belongs to; absent for required segments
22
24
  * @property {string} regex - Compiled regex string
23
25
  */
24
26
 
@@ -48,7 +50,8 @@
48
50
  const DEFAULT_OPTIONS = {
49
51
  escapeChar: '\\',
50
52
  segmentNameStartChar: ':',
51
- segmentNameCharset: 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789',
53
+ segmentNameEndChar: undefined,
54
+ segmentNameCharset: 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_',
52
55
  segmentValueCharset: 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_~ %',
53
56
  optionalSegmentStartChar: '(',
54
57
  optionalSegmentEndChar: ')',
@@ -62,6 +65,26 @@ const DEFAULT_OPTIONS = {
62
65
  */
63
66
  const escapeRegex = (str) => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
64
67
 
68
+ /**
69
+ * Builds a safe regex character class body from a charset string.
70
+ *
71
+ * The charset is treated as a list of explicit characters — range notation
72
+ * (`a-z`) is NOT interpreted as a range. To match the same set of chars
73
+ * with range syntax, expand it (e.g. `a-z` → `abcdefghijklmnopqrstuvwxyz`).
74
+ *
75
+ * The following chars are escaped because they are special inside `[...]`:
76
+ * `\`, `]`, `^`, and `-`.
77
+ * @param {string} charset - Character class body
78
+ * @returns {string} Safe char class body
79
+ */
80
+ const escapeCharClass = (charset) => {
81
+ let escaped = charset.replace(/\\/g, '\\\\');
82
+ escaped = escaped.replace(/\]/g, '\\]');
83
+ escaped = escaped.replace(/\^/g, '\\^');
84
+ escaped = escaped.replace(/-/g, '\\-');
85
+ return escaped;
86
+ };
87
+
65
88
  /**
66
89
  * Merges default options with user provided options
67
90
  * @param {UrlPatternOptions} [userOptions={}] - User provided options
@@ -112,29 +135,62 @@ const parsePattern = (pattern, options) => {
112
135
  const segments = [];
113
136
  let i = 0;
114
137
  let inOptional = false;
138
+ let optionalGroupId = 0;
139
+ let parenDepth = 0;
115
140
 
116
141
  while (i < pattern.length) {
117
142
  const char = pattern[i];
118
143
 
119
- if (char === options.escapeChar && i + 1 < pattern.length) {
120
- segments.push({
121
- type: 'literal',
122
- name: pattern[i + 1],
123
- regex: escapeRegex(pattern[i + 1]),
124
- optional: inOptional
125
- });
126
- i += 2;
127
- continue;
144
+ if (char === options.escapeChar) {
145
+ // Throw when the escape char is at the end of the pattern — nothing follows
146
+ // it to escape, and the resulting regex would be broken.
147
+ if (i + 1 >= pattern.length) {
148
+ throw new Error(`Invalid pattern: '\\' at position ${i} has nothing to escape`);
149
+ }
150
+ const nextChar = pattern[i + 1];
151
+ // Only treat \ as an escape when followed by a regex metacharacter.
152
+ // For all other characters the backslash is literal (e.g. '\)' in a URL
153
+ // is just a backslash followed by ')'). This prevents the escape handler
154
+ // from accidentally consuming the optional-group close delimiter ')'.
155
+ const regexMetachars = '^$\.*+?()[]{}|\\';
156
+ if (!regexMetachars.includes(nextChar)) {
157
+ // Not a regex metachar: treat the backslash as a literal character,
158
+ // advance past it so the next character is processed normally.
159
+ segments.push({
160
+ type: 'literal',
161
+ name: '\\',
162
+ regex: '\\\\',
163
+ optional: inOptional,
164
+ optionalGroupId: inOptional ? optionalGroupId : undefined
165
+ });
166
+ i += 1;
167
+ } else {
168
+ segments.push({
169
+ type: 'literal',
170
+ name: nextChar,
171
+ regex: escapeRegex(nextChar),
172
+ optional: inOptional,
173
+ optionalGroupId: inOptional ? optionalGroupId : undefined
174
+ });
175
+ i += 2;
176
+ continue;
177
+ }
128
178
  }
129
179
 
130
180
  if (char === options.optionalSegmentStartChar) {
131
181
  inOptional = true;
182
+ optionalGroupId++;
183
+ parenDepth++;
132
184
  i++;
133
185
  continue;
134
186
  }
135
187
 
136
188
  if (char === options.optionalSegmentEndChar) {
189
+ if (parenDepth === 0) {
190
+ throw new Error(`Invalid pattern: unmatched '${char}' at position ${i}`);
191
+ }
137
192
  inOptional = false;
193
+ parenDepth--;
138
194
  i++;
139
195
  continue;
140
196
  }
@@ -144,7 +200,8 @@ const parsePattern = (pattern, options) => {
144
200
  type: 'wildcard',
145
201
  name: '_',
146
202
  regex: '.*',
147
- optional: inOptional
203
+ optional: inOptional,
204
+ optionalGroupId: inOptional ? optionalGroupId : undefined
148
205
  });
149
206
  i++;
150
207
  continue;
@@ -154,8 +211,12 @@ const parsePattern = (pattern, options) => {
154
211
  const remaining = pattern.slice(i + 1);
155
212
  let nameEnd = 0;
156
213
  const charset = options.segmentNameCharset || '';
157
-
214
+ const endChar = options.segmentNameEndChar;
215
+
158
216
  for (let j = 0; j < remaining.length; j++) {
217
+ if (endChar && remaining[j] === endChar) {
218
+ break;
219
+ }
159
220
  if (!charset.includes(remaining[j])) {
160
221
  break;
161
222
  }
@@ -163,47 +224,68 @@ const parsePattern = (pattern, options) => {
163
224
  }
164
225
 
165
226
  const name = remaining.slice(0, nameEnd);
166
-
227
+ const consumeEndChar = !!(endChar && remaining[nameEnd] === endChar);
228
+
167
229
  if (name.length > 0) {
168
- let valueCharset = options.segmentValueCharset || '';
169
- if (valueCharset.includes('-') && valueCharset.indexOf('-') > 0 && valueCharset.indexOf('-') < valueCharset.length - 1) {
170
- valueCharset = valueCharset.replace(/-/g, '');
171
- valueCharset += '-';
172
- }
173
- const escapedValueCharset = valueCharset.replace(/\]/g, '\\]');
230
+ const valueCharset = options.segmentValueCharset || '';
231
+ const escapedValueCharset = escapeCharClass(valueCharset);
174
232
  const valueRegex = `([${escapedValueCharset}]+)`;
175
-
233
+
176
234
  segments.push({
177
235
  type: 'named',
178
236
  name,
179
237
  regex: valueRegex,
180
- optional: inOptional
238
+ optional: inOptional,
239
+ optionalGroupId: inOptional ? optionalGroupId : undefined
181
240
  });
182
- i += 1 + nameEnd;
241
+ i += 1 + nameEnd + (consumeEndChar ? 1 : 0);
183
242
  continue;
184
243
  }
244
+
245
+ // segmentNameStartChar at end of pattern, or followed by a non-charset
246
+ // character that is also a special char (e.g. ':)').
247
+ throw new Error(`Invalid pattern: '${char}' at position ${i} has no segment name`);
185
248
  }
186
249
 
187
250
  const literalEnd = findNextSpecialChar(pattern, i, options);
188
-
251
+
189
252
  if (literalEnd > i) {
190
253
  const literal = pattern.slice(i, literalEnd);
191
254
  segments.push({
192
255
  type: 'literal',
193
256
  name: literal,
194
257
  regex: escapeRegex(literal),
195
- optional: inOptional
258
+ optional: inOptional,
259
+ optionalGroupId: inOptional ? optionalGroupId : undefined
196
260
  });
197
261
  i = literalEnd;
198
262
  continue;
199
263
  }
200
264
 
201
- i++;
265
+ // literalEnd === i: current char itself is a special char with no
266
+ // name/value following. Throw for clarity.
267
+ throw new Error(`Invalid pattern: '${char}' at position ${i} has no segment name`);
268
+ }
269
+
270
+ if (parenDepth !== 0) {
271
+ throw new Error(`Invalid pattern: unclosed '${options.optionalSegmentStartChar}'`);
202
272
  }
203
273
 
204
274
  return segments;
205
275
  };
206
276
 
277
+ /**
278
+ /**
279
+ * Returns true when a value should be treated as "absent" for an optional segment.
280
+ * @param {*} val - Value to inspect
281
+ * @returns {boolean}
282
+ */
283
+ const isAbsentValue = (val) => {
284
+ if (val === undefined || val === null || val === '') return true;
285
+ if (Array.isArray(val) && val.length === 0) return true;
286
+ return false;
287
+ };
288
+
207
289
  /**
208
290
  * Compiles segments into a regex pattern
209
291
  * @param {Array<ParsedSegment>} segments - Parsed segments
@@ -223,8 +305,9 @@ const compileRegex = (segments, _options) => {
223
305
  if (segment.optional) {
224
306
  let optionalPart = '';
225
307
  let j = i;
226
-
227
- while (j < segments.length && segments[j].optional) {
308
+ const currentGroupId = segment.optionalGroupId;
309
+
310
+ while (j < segments.length && segments[j].optional && segments[j].optionalGroupId === currentGroupId) {
228
311
  const seg = segments[j];
229
312
 
230
313
  if (seg.type === 'wildcard') {
@@ -325,7 +408,11 @@ const match = (compiled, str) => {
325
408
  const result = {};
326
409
  compiled.keys.forEach((key, index) => {
327
410
  const val = matchResult[index + 1];
328
- result[key] = val !== undefined ? val : null;
411
+ // Undefined means the optional group didn't participate — omit the key
412
+ // so this is consistent with string-pattern behaviour.
413
+ if (val !== undefined) {
414
+ result[key] = val;
415
+ }
329
416
  });
330
417
  return result;
331
418
  }
@@ -335,10 +422,22 @@ const match = (compiled, str) => {
335
422
  const result = {};
336
423
  const usedNames = new Set();
337
424
 
425
+ // Track which segment names are wildcards so their empty-string captures survive
426
+ // the cleanup loop. An empty wildcard result (e.g. '/files/*' on '/files/')
427
+ // is a valid match result.
428
+ const wildcardNames = new Set();
429
+ for (const seg of compiled.segmentNames) {
430
+ if (seg.type === 'wildcard') wildcardNames.add(seg.name);
431
+ }
432
+
338
433
  for (let i = 0; i < compiled.segmentNames.length; i++) {
339
434
  const segInfo = compiled.segmentNames[i];
340
- const value = matchResult[segInfo.index + 1] || '';
341
-
435
+ const hasCapture = segInfo.index + 1 in matchResult;
436
+ // When an optional group didn't participate, the regex returns undefined.
437
+ // Normalize to '' so both non-isRegex and isRegex paths behave the same.
438
+ const rawValue = hasCapture ? matchResult[segInfo.index + 1] : '';
439
+ const value = rawValue === undefined ? '' : rawValue;
440
+
342
441
  if (usedNames.has(segInfo.name)) {
343
442
  if (!Array.isArray(result[segInfo.name])) {
344
443
  result[segInfo.name] = [result[segInfo.name]];
@@ -350,8 +449,19 @@ const match = (compiled, str) => {
350
449
  }
351
450
  }
352
451
 
452
+ // Delete empty-string entries, but preserve wildcards — an empty capture is
453
+ // a valid match result for wildcards. Also clean null/undefined from arrays.
353
454
  for (const key in result) {
354
- if (result[key] === '') {
455
+ const val = result[key];
456
+ if (Array.isArray(val)) {
457
+ // Filter out empty-string entries from arrays (but preserve wildcards).
458
+ const filtered = val.filter(v => v !== '' || wildcardNames.has(key));
459
+ if (filtered.length === 0) {
460
+ delete result[key];
461
+ } else {
462
+ result[key] = filtered;
463
+ }
464
+ } else if (val === '' && !wildcardNames.has(key)) {
355
465
  delete result[key];
356
466
  }
357
467
  }
@@ -380,37 +490,38 @@ const stringify = (compiled, values = {}) => {
380
490
  if (segment.optional) {
381
491
  let optionalPart = '';
382
492
  let j = i;
383
-
384
- while (j < compiled.segments.length && compiled.segments[j].optional) {
493
+ const currentGroupId = segment.optionalGroupId;
494
+
495
+ while (j < compiled.segments.length && compiled.segments[j].optional && compiled.segments[j].optionalGroupId === currentGroupId) {
385
496
  const seg = compiled.segments[j];
386
-
497
+
387
498
  if (seg.type === 'literal') {
388
499
  optionalPart += seg.name;
389
500
  } else if (seg.type === 'named') {
390
501
  const val = values[seg.name];
391
- if (val !== undefined && val !== null && val !== '') {
392
- optionalPart += Array.isArray(val) ? val.join('/') : val;
393
- } else {
502
+ if (isAbsentValue(val)) {
394
503
  optionalPart = '';
395
504
  break;
396
505
  }
506
+ optionalPart += Array.isArray(val) ? val.join('/') : val;
397
507
  } else if (seg.type === 'wildcard') {
398
508
  const val = values._;
399
- if (val !== undefined && val !== null && val !== '') {
400
- optionalPart += Array.isArray(val) ? val.join('/') : val;
401
- } else {
509
+ // Original behaviour: wildcards are skipped in optional groups (values._
510
+ // is never used here). If wildcard is absent, wipe the group.
511
+ if (isAbsentValue(val)) {
402
512
  optionalPart = '';
403
513
  break;
404
514
  }
515
+ optionalPart += Array.isArray(val) ? val.join('/') : val;
405
516
  }
406
-
517
+
407
518
  j++;
408
519
  }
409
-
520
+
410
521
  if (optionalPart !== '') {
411
522
  result += optionalPart;
412
523
  }
413
-
524
+
414
525
  if (i === j) {
415
526
  i++;
416
527
  } else {
@@ -423,13 +534,15 @@ const stringify = (compiled, values = {}) => {
423
534
  result += segment.name;
424
535
  } else if (segment.type === 'named') {
425
536
  const value = values[segment.name];
426
- if (value === undefined || value === null || value === '') {
537
+ if (isAbsentValue(value)) {
427
538
  throw new Error(`Missing required value for segment: ${segment.name}`);
428
539
  }
429
540
  result += Array.isArray(value) ? value.join('/') : value;
430
541
  } else if (segment.type === 'wildcard') {
431
542
  const value = values._;
432
- if (value === undefined || value === null || value === '') {
543
+ // Empty string is a valid wildcard match result (e.g. '/files/*' on '/files/')
544
+ // and should be allowed without throwing.
545
+ if (value === undefined || value === null) {
433
546
  throw new Error('Missing required wildcard value');
434
547
  }
435
548
  result += Array.isArray(value) ? value.join('/') : value;
@@ -490,4 +603,4 @@ const urlPattern = (pattern, options = {}) => {
490
603
  };
491
604
 
492
605
  export { UrlPattern, urlPattern, makePattern, makePatternFromRegex, match, stringify, DEFAULT_OPTIONS };
493
- export default UrlPattern;
606
+ export default urlPattern;
package/types/main.d.ts CHANGED
@@ -1,4 +1,7 @@
1
- export default UrlPattern;
1
+ /**
2
+ * @fileoverview URL pattern matching library
3
+ * @module url-pattern
4
+ */
2
5
  export type UrlPatternOptions = {
3
6
  /**
4
7
  * - Character used for escaping special characters
@@ -8,6 +11,10 @@ export type UrlPatternOptions = {
8
11
  * - Character that starts a named segment
9
12
  */
10
13
  segmentNameStartChar?: string;
14
+ /**
15
+ * - Character that ends a named segment. When set, the segment name stops at the first occurrence of this character (instead of stopping at the first character outside `segmentNameCharset`).
16
+ */
17
+ segmentNameEndChar?: string;
11
18
  /**
12
19
  * - Characters allowed in segment names
13
20
  */
@@ -42,6 +49,10 @@ export type ParsedSegment = {
42
49
  * - Whether the segment is optional
43
50
  */
44
51
  optional?: boolean;
52
+ /**
53
+ * - Identifier of the optional group this segment belongs to; absent for required segments
54
+ */
55
+ optionalGroupId?: number;
45
56
  /**
46
57
  * - Compiled regex string
47
58
  */
@@ -95,75 +106,12 @@ export type CompiledPattern = {
95
106
  */
96
107
  keys?: Array<string>;
97
108
  };
98
- /**
99
- * UrlPattern class for matching and generating URLs
100
- */
101
- export class UrlPattern {
102
- /**
103
- * @param {string|RegExp} pattern - Pattern string or regex
104
- * @param {UrlPatternOptions|Array<string>} [options={}] - Options or keys (for regex)
105
- */
106
- constructor(pattern: string | RegExp, options?: UrlPatternOptions | Array<string>);
107
- /** @type {CompiledPattern} */
108
- compiled: CompiledPattern;
109
- /**
110
- * Match a string against the pattern
111
- * @param {string} str - String to match
112
- * @returns {Object|null} Extracted values or null if no match
113
- */
114
- match(str: string): any | null;
115
- /**
116
- * Generate a string from the pattern
117
- * @param {Object} [values={}] - Values to stringify
118
- * @returns {string} Generated string
119
- */
120
- stringify(values?: any): string;
121
- }
122
- /**
123
- * Creates a new UrlPattern instance (functional API)
124
- * @param {string|RegExp} pattern - Pattern string or regex
125
- * @param {UrlPatternOptions|Array<string>} [options={}] - Options or keys
126
- * @returns {UrlPattern} UrlPattern instance
127
- */
128
- export function urlPattern(pattern: string | RegExp, options?: UrlPatternOptions | Array<string>): UrlPattern;
129
- /**
130
- * Creates a compiled pattern from a string
131
- * @param {string} pattern - Pattern string
132
- * @param {UrlPatternOptions} [options={}] - Options
133
- * @returns {CompiledPattern} Compiled pattern
134
- */
135
- export function makePattern(pattern: string, options?: UrlPatternOptions): CompiledPattern;
136
- /**
137
- * Creates a compiled pattern from a regex
138
- * @param {RegExp} regex - Regex pattern
139
- * @param {Array<string>} [keys=[]] - Array of key names for captured groups
140
- * @returns {CompiledPattern} Compiled pattern
141
- */
142
- export function makePatternFromRegex(regex: RegExp, keys?: Array<string>): CompiledPattern;
143
- /**
144
- * Matches a string against a compiled pattern
145
- * @param {CompiledPattern} compiled - Compiled pattern
146
- * @param {string} str - String to match
147
- * @returns {Object|null} Extracted values or null if no match
148
- */
149
- export function match(compiled: CompiledPattern, str: string): any | null;
150
- /**
151
- * Stringifies a pattern with given values
152
- * @param {CompiledPattern} compiled - Compiled pattern
153
- * @param {Object} [values={}] - Values to stringify
154
- * @returns {string} Generated string
155
- * @throws {Error} If required values are missing
156
- */
157
- export function stringify(compiled: CompiledPattern, values?: any): string;
158
- /**
159
- * @fileoverview URL pattern matching library
160
- * @module url-pattern
161
- */
162
109
  /**
163
110
  * @typedef {Object} UrlPatternOptions
164
111
  * @property {string} [escapeChar='\\'] - Character used for escaping special characters
165
112
  * @property {string} [segmentNameStartChar=':'] - Character that starts a named segment
166
- * @property {string} [segmentNameCharset='a-zA-Z0-9'] - Characters allowed in segment names
113
+ * @property {string} [segmentNameEndChar] - Character that ends a named segment. When set, the segment name stops at the first occurrence of this character (instead of stopping at the first character outside `segmentNameCharset`).
114
+ * @property {string} [segmentNameCharset='a-zA-Z0-9_'] - Characters allowed in segment names
167
115
  * @property {string} [segmentValueCharset='a-zA-Z0-9-_~ %'] - Characters allowed in segment values
168
116
  * @property {string} [optionalSegmentStartChar='('] - Character that starts an optional segment
169
117
  * @property {string} [optionalSegmentEndChar=')'] - Character that ends an optional segment
@@ -174,6 +122,7 @@ export function stringify(compiled: CompiledPattern, values?: any): string;
174
122
  * @property {string} name - Segment name
175
123
  * @property {string} type - Segment type ('named' | 'wildcard' | 'literal')
176
124
  * @property {boolean} [optional=false] - Whether the segment is optional
125
+ * @property {number} [optionalGroupId] - Identifier of the optional group this segment belongs to; absent for required segments
177
126
  * @property {string} regex - Compiled regex string
178
127
  */
179
128
  /**
@@ -197,4 +146,66 @@ export function stringify(compiled: CompiledPattern, values?: any): string;
197
146
  * Default options for URL pattern matching
198
147
  * @type {UrlPatternOptions}
199
148
  */
200
- export const DEFAULT_OPTIONS: UrlPatternOptions;
149
+ declare const DEFAULT_OPTIONS: UrlPatternOptions;
150
+ /**
151
+ * Creates a compiled pattern from a string
152
+ * @param {string} pattern - Pattern string
153
+ * @param {UrlPatternOptions} [options={}] - Options
154
+ * @returns {CompiledPattern} Compiled pattern
155
+ */
156
+ declare const makePattern: (pattern: string, options?: UrlPatternOptions) => CompiledPattern;
157
+ /**
158
+ * Creates a compiled pattern from a regex
159
+ * @param {RegExp} regex - Regex pattern
160
+ * @param {Array<string>} [keys=[]] - Array of key names for captured groups
161
+ * @returns {CompiledPattern} Compiled pattern
162
+ */
163
+ declare const makePatternFromRegex: (regex: RegExp, keys?: Array<string>) => CompiledPattern;
164
+ /**
165
+ * Matches a string against a compiled pattern
166
+ * @param {CompiledPattern} compiled - Compiled pattern
167
+ * @param {string} str - String to match
168
+ * @returns {Object|null} Extracted values or null if no match
169
+ */
170
+ declare const match: (compiled: CompiledPattern, str: string) => any | null;
171
+ /**
172
+ * Stringifies a pattern with given values
173
+ * @param {CompiledPattern} compiled - Compiled pattern
174
+ * @param {Object} [values={}] - Values to stringify
175
+ * @returns {string} Generated string
176
+ * @throws {Error} If required values are missing
177
+ */
178
+ declare const stringify: (compiled: CompiledPattern, values?: any) => string;
179
+ /**
180
+ * UrlPattern class for matching and generating URLs
181
+ */
182
+ declare class UrlPattern {
183
+ /** @type {CompiledPattern} */
184
+ compiled: CompiledPattern;
185
+ /**
186
+ * @param {string|RegExp} pattern - Pattern string or regex
187
+ * @param {UrlPatternOptions|Array<string>} [options={}] - Options or keys (for regex)
188
+ */
189
+ constructor(pattern: string | RegExp, options?: UrlPatternOptions | Array<string>);
190
+ /**
191
+ * Match a string against the pattern
192
+ * @param {string} str - String to match
193
+ * @returns {Object|null} Extracted values or null if no match
194
+ */
195
+ match(str: string): any | null;
196
+ /**
197
+ * Generate a string from the pattern
198
+ * @param {Object} [values={}] - Values to stringify
199
+ * @returns {string} Generated string
200
+ */
201
+ stringify(values?: any): string;
202
+ }
203
+ /**
204
+ * Creates a new UrlPattern instance (functional API)
205
+ * @param {string|RegExp} pattern - Pattern string or regex
206
+ * @param {UrlPatternOptions|Array<string>} [options={}] - Options or keys
207
+ * @returns {UrlPattern} UrlPattern instance
208
+ */
209
+ declare const urlPattern: (pattern: string | RegExp, options?: UrlPatternOptions | Array<string>) => UrlPattern;
210
+ export { UrlPattern, urlPattern, makePattern, makePatternFromRegex, match, stringify, DEFAULT_OPTIONS };
211
+ export default urlPattern;