Skip to content

Commit a160d1c

Browse files
committed
break: rename wild key to * key;
- Allows named `/:wild` parameter
1 parent 5362fba commit a160d1c

File tree

5 files changed

+66
-37
lines changed

5 files changed

+66
-37
lines changed

index.d.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ export type RouteParams<T extends string> =
2020
: T extends `${string}:${infer P}`
2121
? { [K in P]: string }
2222
: T extends `${string}*`
23-
? { wild: string }
23+
? { "*": string }
2424
: T extends `${string}*?`
25-
? { wild?: string }
25+
? { "*"?: string }
2626
: {};
2727

2828
export function inject<T extends string>(route: T, values: RouteParams<T>): string;

readme.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ exec('/movies/narnia.mp4', bar);
7878
// ---
7979
let baz = parse('users/*');
8080
// baz.pattern => /^\/users\/(.*)\/?$/i
81-
// baz.keys => ['wild']
81+
// baz.keys => ['*']
8282

8383
baz.pattern.test('/users'); //=> false
8484
baz.pattern.test('/users/lukeed'); //=> true
@@ -89,7 +89,7 @@ baz.pattern.test('/users/'); //=> true
8989
// ---
9090
let baz = parse('/users/*?');
9191
// baz.pattern => /^\/users(?:\/(.*))?(?=$|\/)/i
92-
// baz.keys => ['wild']
92+
// baz.keys => ['*']
9393

9494
baz.pattern.test('/users'); //=> true
9595
baz.pattern.test('/users/lukeed'); //=> true
@@ -122,7 +122,7 @@ inject('/posts/:slug/*', {
122122

123123
inject('/posts/:slug/*', {
124124
slug: 'hello',
125-
wild: 'x/y/z',
125+
'*': 'x/y/z',
126126
}); //=> '/posts/hello/x/y/z'
127127

128128
// Missing non-optional value
@@ -218,7 +218,7 @@ Type: `Record<string, string>`
218218

219219
The values to be injected. The keys within `values` must match the `pattern`'s segments in order to be replaced.
220220

221-
> **Note:** To replace a wildcard segment (eg, `/*`), define a `values.wild` key.
221+
> **Note:** To replace a wildcard segment (eg, `/*`), define a `values['*']` key.
222222
223223

224224
## Deno

src/index.js

+9-5
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
1-
export function parse(str, loose) {
2-
if (str instanceof RegExp) return { keys:false, pattern:str };
3-
var c, o, tmp, ext, keys=[], pattern='', arr = str.split('/');
1+
/**
2+
* @param {string|RegExp} input The route pattern
3+
* @param {boolean} [loose] Allow open-ended matching. Ignored with `RegExp` input.
4+
*/
5+
export function parse(input, loose) {
6+
if (input instanceof RegExp) return { keys:false, pattern:input };
7+
var c, o, tmp, ext, keys=[], pattern='', arr = input.split('/');
48
arr[0] || arr.shift();
59

610
while (tmp = arr.shift()) {
711
c = tmp[0];
812
if (c === '*') {
9-
keys.push('wild');
13+
keys.push(c);
1014
pattern += tmp[1] === '?' ? '(?:/(.*))?' : '/(.*)';
1115
} else if (c === ':') {
1216
o = tmp.indexOf('?', 1);
@@ -30,7 +34,7 @@ var RGX = /(\/|^)([:*][^/]*?)(\?)?(?=[/.]|$)/g;
3034
// error if key missing?
3135
export function inject(route, values) {
3236
return route.replace(RGX, (x, lead, key, optional) => {
33-
x = values[key=='*' ? 'wild' : key.substring(1)];
37+
x = values[key=='*' ? key : key.substring(1)];
3438
return x ? '/'+x : (optional || key=='*') ? '' : '/' + key;
3539
});
3640
}

test/inject.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ run('/foo/:id/:a?/:b?/:bar?', '/foo/123/aa/xxx', { id: 123, a: 'aa', bar: 'xxx'
6666
run('/foo/:bar/*', '/foo/123', { bar: '123' });
6767
run('/foo/:bar/*?', '/foo/123', { bar: '123' });
6868

69-
run('/foo/:bar/*', '/foo/123/aa/bb/cc', { bar: '123', wild: 'aa/bb/cc' });
70-
run('/foo/:bar/*?', '/foo/123/aa/bb/cc', { bar: '123', wild: 'aa/bb/cc' });
69+
run('/foo/:bar/*', '/foo/123/aa/bb/cc', { bar: '123', '*': 'aa/bb/cc' });
70+
run('/foo/:bar/*?', '/foo/123/aa/bb/cc', { bar: '123', '*': 'aa/bb/cc' });
7171

7272
// NOTE: Missing non-optional values
7373
// ---

test/parse.js

+49-24
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ test('param :: optional :: multiple', () => {
211211

212212
test('wildcard', () => {
213213
let { keys, pattern } = parse('/books/*');
214-
assert.equal(keys, ['wild'], '~> keys has "wild" value');
214+
assert.equal(keys, ['*'], '~> keys has "*" value');
215215
assert.not.ok(pattern.test('/books'), '~> does not match naked base');
216216
assert.ok(pattern.test('/books/'), '~> does not match naked base w/ trailing slash');
217217
assert.ok(pattern.test('/books/narnia'), '~> matches definition');
@@ -224,7 +224,32 @@ test('wildcard', () => {
224224

225225
test('wildcard :: root', () => {
226226
let { keys, pattern } = parse('*');
227-
assert.equal(keys, ['wild'], '~> keys has "wild" value');
227+
assert.equal(keys, ['*'], '~> keys has "*" value');
228+
assert.ok(pattern.test('/'), '~> matches root path');
229+
assert.ok(pattern.test('/narnia'), '~> matches definition');
230+
assert.ok(pattern.test('/narnia/'), '~> matches definition w/ trailing slash');
231+
assert.ok(pattern.test('/narnia/reviews'), '~> does not match extra bits');
232+
assert.not.ok(pattern.test('narnia'), '~> does not match path without lead slash');
233+
let [_, value] = pattern.exec('/foo/bar/baz');
234+
assert.is(value, 'foo/bar/baz', '~> executing pattern gives ALL values together');
235+
});
236+
237+
test('optional wildcard', () => {
238+
let { keys, pattern } = parse('/books/*?');
239+
assert.equal(keys, ['*'], '~> keys has "*" value');
240+
assert.ok(pattern.test('/books'), '~> matches naked base');
241+
assert.ok(pattern.test('/books/'), '~> matches naked base w/ trailing slash');
242+
assert.ok(pattern.test('/books/narnia'), '~> matches definition');
243+
assert.ok(pattern.test('/books/narnia/'), '~> matches definition w/ trailing slash');
244+
assert.ok(pattern.test('/books/narnia/reviews'), '~> does not match extra bits');
245+
assert.not.ok(pattern.test('books/narnia'), '~> does not match path without lead slash');
246+
let [_, value] = pattern.exec('/books/narnia/reviews');
247+
assert.is(value, 'narnia/reviews', '~> executing pattern gives ALL values after base');
248+
});
249+
250+
test('optional wildcard :: root', () => {
251+
let { keys, pattern } = parse('*?');
252+
assert.equal(keys, ['*'], '~> keys has "*" value');
228253
assert.ok(pattern.test('/'), '~> matches root path');
229254
assert.ok(pattern.test('/narnia'), '~> matches definition');
230255
assert.ok(pattern.test('/narnia/'), '~> matches definition w/ trailing slash');
@@ -283,19 +308,19 @@ test('execs', () => {
283308

284309
// console.log('/books/*');
285310
toExec('/books/*', '/books', false);
286-
toExec('/books/*', '/books/', { wild:null });
287-
toExec('/books/*', '/books/world', { wild:'world' });
288-
toExec('/books/*', '/books/world/', { wild:'world/' });
289-
toExec('/books/*', '/books/world/howdy', { wild:'world/howdy' });
290-
toExec('/books/*', '/books/world/howdy/', { wild:'world/howdy/' });
311+
toExec('/books/*', '/books/', { '*':null });
312+
toExec('/books/*', '/books/world', { '*':'world' });
313+
toExec('/books/*', '/books/world/', { '*':'world/' });
314+
toExec('/books/*', '/books/world/howdy', { '*':'world/howdy' });
315+
toExec('/books/*', '/books/world/howdy/', { '*':'world/howdy/' });
291316

292317
// console.log('/books/*?');
293-
toExec('/books/*?', '/books', { wild:null });
294-
toExec('/books/*?', '/books/', { wild:null });
295-
toExec('/books/*?', '/books/world', { wild:'world' });
296-
toExec('/books/*?', '/books/world/', { wild:'world/' });
297-
toExec('/books/*?', '/books/world/howdy', { wild:'world/howdy' });
298-
toExec('/books/*?', '/books/world/howdy/', { wild:'world/howdy/' });
318+
toExec('/books/*?', '/books', { '*':null });
319+
toExec('/books/*?', '/books/', { '*':null });
320+
toExec('/books/*?', '/books/world', { '*':'world' });
321+
toExec('/books/*?', '/books/world/', { '*':'world/' });
322+
toExec('/books/*?', '/books/world/howdy', { '*':'world/howdy' });
323+
toExec('/books/*?', '/books/world/howdy/', { '*':'world/howdy/' });
299324
});
300325

301326
test('execs :: loose', () => {
@@ -347,19 +372,19 @@ test('execs :: loose', () => {
347372

348373
// console.log('/books/*');
349374
toLooseExec('/books/*', '/books', false);
350-
toLooseExec('/books/*', '/books/', { wild:null });
351-
toLooseExec('/books/*', '/books/world', { wild:'world' });
352-
toLooseExec('/books/*', '/books/world/', { wild:'world/' });
353-
toLooseExec('/books/*', '/books/world/howdy', { wild:'world/howdy' });
354-
toLooseExec('/books/*', '/books/world/howdy/', { wild:'world/howdy/' });
375+
toLooseExec('/books/*', '/books/', { '*':null });
376+
toLooseExec('/books/*', '/books/world', { '*':'world' });
377+
toLooseExec('/books/*', '/books/world/', { '*':'world/' });
378+
toLooseExec('/books/*', '/books/world/howdy', { '*':'world/howdy' });
379+
toLooseExec('/books/*', '/books/world/howdy/', { '*':'world/howdy/' });
355380

356381
// console.log('/books/*?');
357-
toLooseExec('/books/*?', '/books', { wild:null });
358-
toLooseExec('/books/*?', '/books/', { wild:null });
359-
toLooseExec('/books/*?', '/books/world', { wild:'world' });
360-
toLooseExec('/books/*?', '/books/world/', { wild:'world/' });
361-
toLooseExec('/books/*?', '/books/world/howdy', { wild:'world/howdy' });
362-
toLooseExec('/books/*?', '/books/world/howdy/', { wild:'world/howdy/' });
382+
toLooseExec('/books/*?', '/books', { '*':null });
383+
toLooseExec('/books/*?', '/books/', { '*':null });
384+
toLooseExec('/books/*?', '/books/world', { '*':'world' });
385+
toLooseExec('/books/*?', '/books/world/', { '*':'world/' });
386+
toLooseExec('/books/*?', '/books/world/howdy', { '*':'world/howdy' });
387+
toLooseExec('/books/*?', '/books/world/howdy/', { '*':'world/howdy/' });
363388
});
364389

365390
test('(raw) exec', () => {

0 commit comments

Comments
 (0)