Skip to content

Commit f29e3f4

Browse files
committed
feat(router): adds parameters
1 parent cc365f8 commit f29e3f4

File tree

10 files changed

+204
-130
lines changed

10 files changed

+204
-130
lines changed

packages/core/src/components.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2600,8 +2600,8 @@ declare global {
26002600
namespace JSXElements {
26012601
export interface IonRouteAttributes extends HTMLAttributes {
26022602
component?: string;
2603+
params?: undefined;
26032604
path?: string;
2604-
props?: any;
26052605
}
26062606
}
26072607
}

packages/core/src/components/nav/nav.tsx

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -223,11 +223,6 @@ export class NavControllerBase implements NavOutlet {
223223
return null;
224224
}
225225

226-
@Method()
227-
markVisible() {
228-
return Promise.resolve();
229-
}
230-
231226
@Method()
232227
getContentElement(): HTMLElement {
233228
const active = this.getActive();

packages/core/src/components/nav/readme.md

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,6 @@ Return a view controller
7171
#### insertPages()
7272

7373

74-
#### markVisible()
75-
76-
7774
#### pop()
7875

7976

packages/core/src/components/route/readme.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@
1212
string
1313

1414

15-
#### path
15+
#### params
1616

17-
string
1817

1918

20-
#### props
2119

22-
any
20+
#### path
21+
22+
string
2323

2424

2525
## Attributes
@@ -29,14 +29,14 @@ any
2929
string
3030

3131

32-
#### path
32+
#### params
3333

34-
string
3534

3635

37-
#### props
3836

39-
any
37+
#### path
38+
39+
string
4040

4141

4242

packages/core/src/components/route/route.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,5 @@ import { Component, Prop } from '@stencil/core';
77
export class Route {
88
@Prop() path = '';
99
@Prop() component: string;
10-
@Prop() props: any = {};
10+
@Prop() params: undefined;
1111
}

packages/core/src/components/router/test/matching.spec.tsx

Lines changed: 130 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,30 @@
11
import { RouteChain } from '../utils/interfaces';
2-
import { matchesIDs, matchesPath, routerPathToChain } from '../utils/matching';
3-
import { mockRouteElement } from './parser.spec';
4-
import { mockElement } from '@stencil/core/dist/testing';
2+
import { matchesIDs, matchesPath, mergeParams, routerPathToChain } from '../utils/matching';
3+
import { parsePath } from '../utils/path';
54

65
const CHAIN_1: RouteChain = [
7-
{ id: '2', path: ['to'], props: undefined },
8-
{ id: '1', path: ['path'], props: undefined },
9-
{ id: '3', path: ['segment'], props: undefined },
10-
{ id: '4', path: [''], props: undefined },
6+
{ id: '2', path: ['to'], params: undefined },
7+
{ id: '1', path: ['path'], params: undefined },
8+
{ id: '3', path: ['segment'], params: undefined },
9+
{ id: '4', path: [''], params: undefined },
1110
];
1211

1312
const CHAIN_2: RouteChain = [
14-
{ id: '2', path: [''], props: undefined },
15-
{ id: '1', path: [''], props: undefined },
16-
{ id: '3', path: ['segment', 'to'], props: undefined },
17-
{ id: '4', path: [''], props: undefined },
18-
{ id: '5', path: ['hola'], props: undefined },
19-
{ id: '6', path: [''], props: undefined },
20-
{ id: '7', path: [''], props: undefined },
21-
{ id: '8', path: ['adios', 'que', 'tal'], props: undefined },
13+
{ id: '2', path: [''], params: undefined },
14+
{ id: '1', path: [''], params: undefined },
15+
{ id: '3', path: ['segment', 'to'], params: undefined },
16+
{ id: '4', path: [''], params: undefined },
17+
{ id: '5', path: ['hola'], params: undefined },
18+
{ id: '6', path: [''], params: undefined },
19+
{ id: '7', path: [''], params: undefined },
20+
{ id: '8', path: ['adios', 'que', 'tal'], params: undefined },
2221
];
2322

2423
const CHAIN_3: RouteChain = [
25-
{ id: '2', path: ['this', 'to'], props: undefined },
26-
{ id: '1', path: ['path'], props: undefined },
27-
{ id: '3', path: ['segment', 'to', 'element'], props: undefined },
28-
{ id: '4', path: [''], props: undefined },
24+
{ id: '2', path: ['this', 'to'], params: undefined },
25+
{ id: '1', path: ['path'], params: undefined },
26+
{ id: '3', path: ['segment', 'to', 'element'], params: undefined },
27+
{ id: '4', path: [''], params: undefined },
2928
];
3029

3130

@@ -47,67 +46,85 @@ describe('matchesIDs', () => {
4746
describe('matchesPath', () => {
4847
it('should match simple path', () => {
4948
const chain: RouteChain = CHAIN_3;
50-
expect(matchesPath(['this'], chain)).toBe(false);
51-
expect(matchesPath(['this', 'to'], chain)).toBe(false);
52-
expect(matchesPath(['this', 'to', 'path'], chain)).toBe(false);
53-
expect(matchesPath(['this', 'to', 'path', 'segment'], chain)).toBe(false);
54-
expect(matchesPath(['this', 'to', 'path', 'segment', 'to'], chain)).toBe(false);
55-
expect(matchesPath(['this', 'to', 'path', 'segment', 'to', 'element'], chain)).toBe(true);
56-
expect(matchesPath(['this', 'to', 'path', 'segment', 'to', 'element', 'more'], chain)).toBe(false);
57-
58-
expect(matchesPath([], chain)).toBe(false);
59-
expect(matchesPath([''], chain)).toBe(false);
60-
expect(matchesPath(['path'], chain)).toBe(false);
49+
expect(matchesPath(['this'], chain)).toEqual(null);
50+
expect(matchesPath(['this', 'to'], chain)).toEqual(null);
51+
expect(matchesPath(['this', 'to', 'path'], chain)).toEqual(null);
52+
expect(matchesPath(['this', 'to', 'path', 'segment'], chain)).toEqual(null);
53+
expect(matchesPath(['this', 'to', 'path', 'segment', 'to'], chain)).toEqual(null);
54+
expect(matchesPath(['this', 'to', 'path', 'segment', 'to', 'element'], chain)).toEqual(chain);
55+
expect(matchesPath(['this', 'to', 'path', 'segment', 'to', 'element', 'more'], chain)).toEqual(null);
56+
57+
expect(matchesPath([], chain)).toEqual(null);
58+
expect(matchesPath([''], chain)).toEqual(null);
59+
expect(matchesPath(['path'], chain)).toEqual(null);
6160
});
6261

6362
it('should match simple default route', () => {
6463
const chain: RouteChain = CHAIN_2;
65-
expect(matchesPath([''], chain)).toBe(false);
66-
expect(matchesPath(['segment'], chain)).toBe(false);
67-
expect(matchesPath(['segment', 'to'], chain)).toBe(false);
68-
expect(matchesPath(['segment', 'to', 'hola'], chain)).toBe(false);
69-
expect(matchesPath(['segment', 'to', 'hola', 'adios'], chain)).toBe(false);
70-
expect(matchesPath(['segment', 'to', 'hola', 'adios', 'que'], chain)).toBe(false);
71-
expect(matchesPath(['segment', 'to', 'hola', 'adios', 'que', 'tal'], chain)).toBe(true);
72-
73-
expect(matchesPath(['to'], chain)).toBe(false);
74-
expect(matchesPath(['path', 'to'], chain)).toBe(false);
64+
expect(matchesPath([''], chain)).toEqual(null);
65+
expect(matchesPath(['segment'], chain)).toEqual(null);
66+
expect(matchesPath(['segment', 'to'], chain)).toEqual(null);
67+
expect(matchesPath(['segment', 'to', 'hola'], chain)).toEqual(null);
68+
expect(matchesPath(['segment', 'to', 'hola', 'adios'], chain)).toEqual(null);
69+
expect(matchesPath(['segment', 'to', 'hola', 'adios', 'que'], chain)).toEqual(null);
70+
expect(matchesPath(['segment', 'to', 'hola', 'adios', 'que', 'tal'], chain)).toEqual(chain);
71+
expect(matchesPath(['segment', 'to', 'hola', 'adios', 'que', 'tal', 'more'], chain)).toEqual(chain);
72+
73+
expect(matchesPath(['to'], chain)).toEqual(null);
74+
expect(matchesPath(['path', 'to'], chain)).toEqual(null);
7575
});
7676

7777
it('should match simple route 2', () => {
78-
const chain: RouteChain = [{ id: '5', path: ['hola'], props: undefined }];
79-
expect(matchesPath([''], chain)).toBe(false);
80-
expect(matchesPath(['hola'], chain)).toBe(true);
81-
expect(matchesPath(['hola', 'hola'], chain)).toBe(true);
82-
expect(matchesPath(['hola', 'adios'], chain)).toBe(true);
78+
const chain: RouteChain = [{ id: '5', path: ['hola'], params: undefined }];
79+
expect(matchesPath([''], chain)).toEqual(null);
80+
expect(matchesPath(['hola'], chain)).toEqual(chain);
81+
expect(matchesPath(['hola', 'hola'], chain)).toEqual(chain);
82+
expect(matchesPath(['hola', 'adios'], chain)).toEqual(chain);
8383
});
8484

8585
it('should match simple route 3', () => {
86-
const chain: RouteChain = [{ id: '5', path: ['hola', 'adios'], props: undefined }];
87-
expect(matchesPath([''], chain)).toBe(false);
88-
expect(matchesPath(['hola'], chain)).toBe(false);
89-
expect(matchesPath(['hola', 'hola'], chain)).toBe(false);
90-
expect(matchesPath(['hola', 'adios'], chain)).toBe(true);
86+
const chain: RouteChain = [{ id: '5', path: ['hola', 'adios'], params: undefined }];
87+
expect(matchesPath([''], chain)).toEqual(null);
88+
expect(matchesPath(['hola'], chain)).toEqual(null);
89+
expect(matchesPath(['hola', 'hola'], chain)).toEqual(null);
90+
expect(matchesPath(['hola', 'adios'], chain)).toEqual(chain);
91+
expect(matchesPath(['hola', 'adios', 'bye'], chain)).toEqual(chain);
9192
});
9293

9394
it('should match simple route 4', () => {
9495
const chain: RouteChain = [
95-
{ id: '5', path: ['hola'], props: undefined },
96-
{ id: '5', path: ['adios'], props: undefined }];
96+
{ id: '5', path: ['hola'], params: undefined },
97+
{ id: '5', path: ['adios'], params: undefined }];
9798

98-
expect(matchesPath([''], chain)).toBe(false);
99-
expect(matchesPath(['hola'], chain)).toBe(false);
100-
expect(matchesPath(['hola', 'hola'], chain)).toBe(false);
101-
expect(matchesPath(['hola', 'adios'], chain)).toBe(true);
99+
expect(matchesPath([''], chain)).toEqual(null);
100+
expect(matchesPath(['hola'], chain)).toEqual(null);
101+
expect(matchesPath(['hola', 'hola'], chain)).toEqual(null);
102+
expect(matchesPath(['hola', 'adios'], chain)).toEqual(chain);
103+
});
104+
105+
it('should match with parameters', () => {
106+
const chain: RouteChain = [
107+
{ id: '5', path: ['profile', ':name'], params: undefined },
108+
{ id: '5', path: [''], params: undefined },
109+
{ id: '5', path: ['image'], params: {size: 'lg'} },
110+
{ id: '5', path: ['image', ':size', ':type'], params: {size: 'mg'} },
111+
];
112+
const matched = matchesPath(parsePath('/profile/manu/image/image/large/retina'), chain);
113+
expect(matched).toEqual([
114+
{ id: '5', path: ['profile', ':name'], params: {name: 'manu'} },
115+
{ id: '5', path: [''], params: undefined },
116+
{ id: '5', path: ['image'], params: {size: 'lg'} },
117+
{ id: '5', path: ['image', ':size', ':type'], params: {size: 'large', type: 'retina'} },
118+
]);
102119
});
103120
});
104121

105122
describe('routerPathToChain', () => {
106123
it('should match the route with higher priority', () => {
107-
const chain3: RouteChain = [{ id: '5', path: ['hola'], props: undefined }];
124+
const chain3: RouteChain = [{ id: '5', path: ['hola'], params: undefined }];
108125
const chain4: RouteChain = [
109-
{ id: '5', path: ['hola'], props: undefined },
110-
{ id: '5', path: ['adios'], props: undefined }];
126+
{ id: '5', path: ['hola'], params: undefined },
127+
{ id: '5', path: ['adios'], params: undefined }];
111128

112129
const routes: RouteChain[] = [
113130
CHAIN_1,
@@ -147,35 +164,62 @@ describe('routerPathToChain', () => {
147164

148165
it('should match the default route', () => {
149166
const chain1: RouteChain = [
150-
{ id: 'tabs', path: [''], props: undefined },
151-
{ id: 'tab1', path: [''], props: undefined },
152-
{ id: 'schedule', path: [''], props: undefined }
167+
{ id: 'tabs', path: [''], params: undefined },
168+
{ id: 'tab1', path: [''], params: undefined },
169+
{ id: 'schedule', path: [''], params: undefined }
153170
];
154171
const chain2: RouteChain = [
155-
{ id: 'tabs', path: [''], props: undefined },
156-
{ id: 'tab2', path: ['tab2'], props: undefined },
157-
{ id: 'page2', path: [''], props: undefined }
172+
{ id: 'tabs', path: [''], params: undefined },
173+
{ id: 'tab2', path: ['tab2'], params: undefined },
174+
{ id: 'page2', path: [''], params: undefined }
158175
];
159176

160177
expect(routerPathToChain([''], [chain1])).toEqual({chain: chain1, matches: 3});
161178
expect(routerPathToChain(['tab2'], [chain1])).toEqual({chain: null, matches: 0});
162179

163180
expect(routerPathToChain([''], [chain2])).toEqual({chain: null, matches: 0});
164181
expect(routerPathToChain(['tab2'], [chain2])).toEqual({chain: chain2, matches: 3});
182+
});
183+
});
184+
185+
describe('mergeParams', () => {
186+
it('should merge undefined', () => {
187+
expect(mergeParams(undefined, undefined)).toBeUndefined();
188+
expect(mergeParams(null, undefined)).toBeUndefined();
189+
expect(mergeParams(undefined, null)).toBeUndefined();
190+
expect(mergeParams(null, null)).toBeUndefined();
191+
});
165192

193+
it('should merge undefined with params', () => {
194+
const params = {data: '1'};
195+
expect(mergeParams(undefined, params)).toEqual(params);
196+
expect(mergeParams(null, params)).toEqual(params);
197+
expect(mergeParams(params, undefined)).toEqual(params);
198+
expect(mergeParams(params, null)).toEqual(params);
166199
});
167200

201+
it('should merge params with params', () => {
202+
const params1 = {data: '1', data3: 'hello'};
203+
const params2 = {data: '2', data2: 'hola'};
168204

205+
expect(mergeParams(params1, params2)).toEqual({
206+
data: '2',
207+
data2: 'hola',
208+
data3: 'hello'
209+
});
210+
expect(params1).toEqual({data: '1', data3: 'hello'});
211+
expect(params2).toEqual({data: '2', data2: 'hola'});
212+
});
169213
});
170214

171215
// describe('matchRoute', () => {
172216
// it('should match simple route', () => {
173217
// const path = ['path', 'to', 'component'];
174218
// const routes: RouteChain[] = [
175-
// [{ id: 2, path: ['to'], props: undefined }],
176-
// [{ id: 1, path: ['path'], props: undefined }],
177-
// [{ id: 3, path: ['segment'], props: undefined }],
178-
// [{ id: 4, path: [''], props: undefined }],
219+
// [{ id: 2, path: ['to'], params: undefined }],
220+
// [{ id: 1, path: ['path'], params: undefined }],
221+
// [{ id: 3, path: ['segment'], params: undefined }],
222+
// [{ id: 4, path: [''], params: undefined }],
179223
// ];
180224
// const match = routerPathToChain(path, routes);
181225
// expect(match).toEqual({ id: 1, path: ['path'], children: [] });
@@ -184,10 +228,10 @@ describe('routerPathToChain', () => {
184228

185229
// it('should match default route', () => {
186230
// const routes: RouteTree = [
187-
// { id: 2, path: ['to'], children: [], props: undefined },
188-
// { id: 1, path: ['path'], children: [], props: undefined },
189-
// { id: 3, path: ['segment'], children: [], props: undefined },
190-
// { id: 4, path: [''], children: [], props: undefined },
231+
// { id: 2, path: ['to'], children: [], params: undefined },
232+
// { id: 1, path: ['path'], children: [], params: undefined },
233+
// { id: 3, path: ['segment'], children: [], params: undefined },
234+
// { id: 4, path: [''], children: [], params: undefined },
191235
// ];
192236
// const seg = new RouterSegments(['hola', 'path']);
193237
// let match = matchRoute(seg, routes);
@@ -204,10 +248,10 @@ describe('routerPathToChain', () => {
204248

205249
// it('should not match any route', () => {
206250
// const routes: RouteTree = [
207-
// { id: 2, path: ['to', 'to', 'to'], children: [], props: undefined },
208-
// { id: 1, path: ['adam', 'manu'], children: [], props: undefined },
209-
// { id: 3, path: ['hola', 'adam'], children: [], props: undefined },
210-
// { id: 4, path: [''], children: [], props: undefined },
251+
// { id: 2, path: ['to', 'to', 'to'], children: [], params: undefined },
252+
// { id: 1, path: ['adam', 'manu'], children: [], params: undefined },
253+
// { id: 3, path: ['hola', 'adam'], children: [], params: undefined },
254+
// { id: 4, path: [''], children: [], params: undefined },
211255
// ];
212256
// const seg = new RouterSegments(['hola', 'manu', 'adam']);
213257
// const match = matchRoute(seg, routes);
@@ -224,8 +268,8 @@ describe('routerPathToChain', () => {
224268

225269
// it('should not match any route (2)', () => {
226270
// const routes: RouteTree = [
227-
// { id: 1, path: ['adam', 'manu'], children: [], props: undefined },
228-
// { id: 3, path: ['hola', 'adam'], children: [], props: undefined },
271+
// { id: 1, path: ['adam', 'manu'], children: [], params: undefined },
272+
// { id: 3, path: ['hola', 'adam'], children: [], params: undefined },
229273
// ];
230274
// const seg = new RouterSegments(['adam']);
231275
// expect(matchRoute(seg, routes)).toBeNull();
@@ -235,10 +279,10 @@ describe('routerPathToChain', () => {
235279

236280
// it ('should match multiple segments', () => {
237281
// const routes: RouteTree = [
238-
// { id: 1, path: ['adam', 'manu'], children: [], props: undefined },
239-
// { id: 2, path: ['manu', 'hello'], children: [], props: undefined },
240-
// { id: 3, path: ['hello'], children: [], props: undefined },
241-
// { id: 4, path: [''], children: [], props: undefined },
282+
// { id: 1, path: ['adam', 'manu'], children: [], params: undefined },
283+
// { id: 2, path: ['manu', 'hello'], children: [], params: undefined },
284+
// { id: 3, path: ['hello'], children: [], params: undefined },
285+
// { id: 4, path: [''], children: [], params: undefined },
242286
// ];
243287
// const seg = new RouterSegments(['adam', 'manu', 'hello', 'manu', 'hello']);
244288
// let match = matchRoute(seg, routes);
@@ -259,9 +303,9 @@ describe('routerPathToChain', () => {
259303

260304
// it('should match long multi segments', () => {
261305
// const routes: RouteTree = [
262-
// { id: 1, path: ['adam', 'manu', 'hello', 'menu', 'hello'], children: [], props: undefined },
263-
// { id: 2, path: ['adam', 'manu', 'hello', 'menu'], children: [], props: undefined },
264-
// { id: 3, path: ['adam', 'manu'], children: [], props: undefined },
306+
// { id: 1, path: ['adam', 'manu', 'hello', 'menu', 'hello'], children: [], params: undefined },
307+
// { id: 2, path: ['adam', 'manu', 'hello', 'menu'], children: [], params: undefined },
308+
// { id: 3, path: ['adam', 'manu'], children: [], params: undefined },
265309
// ];
266310
// const seg = new RouterSegments(['adam', 'manu', 'hello', 'menu', 'hello']);
267311
// const match = matchRoute(seg, routes);

0 commit comments

Comments
 (0)