Skip to content

Commit de17a7a

Browse files
Merge pull request #586 from preactjs/route-params-possibility
2 parents df3e39c + 9f03c25 commit de17a7a

File tree

3 files changed

+30
-22
lines changed

3 files changed

+30
-22
lines changed

router.js

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,23 +32,22 @@ const UPDATE = (state, url) => {
3232
export const exec = (url, route, matches) => {
3333
url = url.split('/').filter(Boolean);
3434
route = (route || '').split('/').filter(Boolean);
35-
const params = matches.params || (matches.params = {});
36-
for (let i = 0, val; i < Math.max(url.length, route.length); i++) {
35+
for (let i = 0, val, rest; i < Math.max(url.length, route.length); i++) {
3736
let [, m, param, flag] = (route[i] || '').match(/^(:?)(.*?)([+*?]?)$/);
3837
val = url[i];
3938
// segment match:
4039
if (!m && param == val) continue;
4140
// segment mismatch / missing required field:
4241
if (!m || (!val && flag != '?' && flag != '*')) return;
43-
// field match:
44-
params[param] = val && decodeURIComponent(val);
45-
// normal/optional field:
46-
if (flag >= '?' || flag === '') continue;
42+
rest = flag == '+' || flag == '*';
4743
// rest (+/*) match:
48-
params[param] = url.slice(i).map(decodeURIComponent).join('/');
49-
break;
44+
if (rest) val = url.slice(i).map(decodeURIComponent).join('/');
45+
// normal/optional field:
46+
else if (val) val = decodeURIComponent(val);
47+
matches.params[param] = val;
48+
if (!(param in matches)) matches[param] = val;
49+
if (rest) break;
5050
}
51-
5251
return matches;
5352
};
5453

@@ -108,7 +107,7 @@ export function Router(props) {
108107

109108
let p, d, m;
110109
toChildArray(props.children).some(vnode => {
111-
const matches = exec(path, vnode.props.path, (m = { path, query }));
110+
const matches = exec(path, vnode.props.path, (m = { path, query, params: {} }));
112111
if (matches) return (p = cloneElement(vnode, m));
113112
if (vnode.props.default) d = cloneElement(vnode, m);
114113
});

test/match.test.js

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,53 @@
11
import { exec } from '../router.js';
22

3-
function execPath(path, pattern) {
4-
return exec(path, pattern, { path });
3+
function execPath(path, pattern, opts) {
4+
return exec(path, pattern, { path, query: {}, params: {}, ...(opts || {}) });
55
}
66

77
describe('match', () => {
88
it('Base route', () => {
99
const accurateResult = execPath('/', '/');
10-
expect(accurateResult).toEqual({ path: '/', params: {} });
10+
expect(accurateResult).toEqual({ path: '/', params: {}, query: {} });
1111

1212
const inaccurateResult = execPath('/user/1', '/');
1313
expect(inaccurateResult).toEqual(undefined);
1414
});
1515

1616
it('Param route', () => {
1717
const accurateResult = execPath('/user/2', '/user/:id');
18-
expect(accurateResult).toEqual({ path: '/user/2', params: { id: '2' } });
18+
expect(accurateResult).toEqual({ path: '/user/2', params: { id: '2' }, id: '2', query: {} });
1919

2020
const inaccurateResult = execPath('/', '/user/:id');
2121
expect(inaccurateResult).toEqual(undefined);
2222
});
2323

2424
it('Optional param route', () => {
2525
const accurateResult = execPath('/user', '/user/:id?');
26-
expect(accurateResult).toEqual({ path: '/user', params: { id: undefined } });
26+
expect(accurateResult).toEqual({ path: '/user', params: { id: undefined }, id: undefined, query: {} });
2727

2828
const inaccurateResult = execPath('/', '/user/:id?');
2929
expect(inaccurateResult).toEqual(undefined);
3030
});
3131

3232
it('Optional rest param route "/:x*"', () => {
3333
const accurateResult = execPath('/user', '/user/:id?');
34-
expect(accurateResult).toEqual({ path: '/user', params: { id: undefined } });
34+
expect(accurateResult).toEqual({ path: '/user', params: { id: undefined }, id: undefined, query: {} });
3535

3636
const inaccurateResult = execPath('/', '/user/:id?');
3737
expect(inaccurateResult).toEqual(undefined);
3838
});
3939

4040
it('Rest param route "/:x+"', () => {
4141
const matchedResult = execPath('/user/foo', '/user/:id+');
42-
expect(matchedResult).toEqual({ path: '/user/foo', params: { id: 'foo' } });
42+
expect(matchedResult).toEqual({ path: '/user/foo', params: { id: 'foo' }, id: 'foo', query: {} });
4343

4444
const matchedResultWithSlash = execPath('/user/foo/bar', '/user/:id+');
45-
expect(matchedResultWithSlash).toEqual({ path: '/user/foo/bar', params: { id: 'foo/bar' } });
45+
expect(matchedResultWithSlash).toEqual({
46+
path: '/user/foo/bar',
47+
params: { id: 'foo/bar' },
48+
id: 'foo/bar',
49+
query: {}
50+
});
4651

4752
const emptyResult = execPath('/user', '/user/:id+');
4853
expect(emptyResult).toEqual(undefined);
@@ -58,15 +63,19 @@ describe('match', () => {
5863
params: {
5964
seg1: '_SEGMENT1_',
6065
seg2: '_SEGMENT2_'
61-
}
66+
},
67+
seg1: '_SEGMENT1_',
68+
seg2: '_SEGMENT2_',
69+
query: {}
6270
});
6371
});
6472

6573
it('should not overwrite existing properties', () => {
66-
const result = exec('/foo/bar', '/:path/:query', { path: '/custom-path' });
74+
const result = execPath('/foo/bar', '/:path/:query', { path: '/custom-path' });
6775
expect(result).toEqual({
6876
params: { path: 'foo', query: 'bar' },
69-
path: '/custom-path'
77+
path: '/custom-path',
78+
query: {}
7079
});
7180
});
7281
});

test/router.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ describe('Router', () => {
8282
expect(Home).not.toHaveBeenCalled();
8383
expect(Profiles).not.toHaveBeenCalled();
8484
expect(Profile).toHaveBeenCalledWith(
85-
{ path: '/profiles/bob', query: {}, params: { id: 'bob' } },
85+
{ path: '/profiles/bob', query: {}, params: { id: 'bob' }, id: 'bob' },
8686
expect.anything()
8787
);
8888
expect(Fallback).not.toHaveBeenCalled();

0 commit comments

Comments
 (0)