Skip to content

Commit

Permalink
Merge pull request #586 from preactjs/route-params-possibility
Browse files Browse the repository at this point in the history
  • Loading branch information
marvinhagemeister authored Aug 31, 2021
2 parents 9272fa3 + c963fbe commit 44bd683
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 22 deletions.
5 changes: 5 additions & 0 deletions .changeset/light-lamps-design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"preact-iso": minor
---

Pass route paramters as props when no prop exists with that name.
19 changes: 9 additions & 10 deletions packages/preact-iso/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,23 +32,22 @@ const UPDATE = (state, url) => {
export const exec = (url, route, matches) => {
url = url.split('/').filter(Boolean);
route = (route || '').split('/').filter(Boolean);
const params = matches.params || (matches.params = {});
for (let i = 0, val; i < Math.max(url.length, route.length); i++) {
for (let i = 0, val, rest; i < Math.max(url.length, route.length); i++) {
let [, m, param, flag] = (route[i] || '').match(/^(:?)(.*?)([+*?]?)$/);
val = url[i];
// segment match:
if (!m && param == val) continue;
// segment mismatch / missing required field:
if (!m || (!val && flag != '?' && flag != '*')) return;
// field match:
params[param] = val && decodeURIComponent(val);
// normal/optional field:
if (flag >= '?' || flag === '') continue;
rest = flag == '+' || flag == '*';
// rest (+/*) match:
params[param] = url.slice(i).map(decodeURIComponent).join('/');
break;
if (rest) val = url.slice(i).map(decodeURIComponent).join('/');
// normal/optional field:
else if (val) val = decodeURIComponent(val);
matches.params[param] = val;
if (!(param in matches)) matches[param] = val;
if (rest) break;
}

return matches;
};

Expand Down Expand Up @@ -108,7 +107,7 @@ export function Router(props) {

let p, d, m;
toChildArray(props.children).some(vnode => {
const matches = exec(path, vnode.props.path, (m = { path, query }));
const matches = exec(path, vnode.props.path, (m = { path, query, params: {} }));
if (matches) return (p = cloneElement(vnode, m));
if (vnode.props.default) d = cloneElement(vnode, m);
});
Expand Down
31 changes: 20 additions & 11 deletions packages/preact-iso/test/match.test.js
Original file line number Diff line number Diff line change
@@ -1,48 +1,53 @@
import { exec } from '../router.js';

function execPath(path, pattern) {
return exec(path, pattern, { path });
function execPath(path, pattern, opts) {
return exec(path, pattern, { path, query: {}, params: {}, ...(opts || {}) });
}

describe('match', () => {
it('Base route', () => {
const accurateResult = execPath('/', '/');
expect(accurateResult).toEqual({ path: '/', params: {} });
expect(accurateResult).toEqual({ path: '/', params: {}, query: {} });

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

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

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

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

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

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

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

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

const matchedResultWithSlash = execPath('/user/foo/bar', '/user/:id+');
expect(matchedResultWithSlash).toEqual({ path: '/user/foo/bar', params: { id: 'foo/bar' } });
expect(matchedResultWithSlash).toEqual({
path: '/user/foo/bar',
params: { id: 'foo/bar' },
id: 'foo/bar',
query: {}
});

const emptyResult = execPath('/user', '/user/:id+');
expect(emptyResult).toEqual(undefined);
Expand All @@ -58,15 +63,19 @@ describe('match', () => {
params: {
seg1: '_SEGMENT1_',
seg2: '_SEGMENT2_'
}
},
seg1: '_SEGMENT1_',
seg2: '_SEGMENT2_',
query: {}
});
});

it('should not overwrite existing properties', () => {
const result = exec('/foo/bar', '/:path/:query', { path: '/custom-path' });
const result = execPath('/foo/bar', '/:path/:query', { path: '/custom-path' });
expect(result).toEqual({
params: { path: 'foo', query: 'bar' },
path: '/custom-path'
path: '/custom-path',
query: {}
});
});
});
2 changes: 1 addition & 1 deletion packages/preact-iso/test/router.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ describe('Router', () => {
expect(Home).not.toHaveBeenCalled();
expect(Profiles).not.toHaveBeenCalled();
expect(Profile).toHaveBeenCalledWith(
{ path: '/profiles/bob', query: {}, params: { id: 'bob' } },
{ path: '/profiles/bob', query: {}, params: { id: 'bob' }, id: 'bob' },
expect.anything()
);
expect(Fallback).not.toHaveBeenCalled();
Expand Down

0 comments on commit 44bd683

Please sign in to comment.