Skip to content

Commit ef51005

Browse files
authored
Fix context.next() for multiple nested routes (#91)
1 parent a1c9c81 commit ef51005

File tree

7 files changed

+103
-42
lines changed

7 files changed

+103
-42
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ All notable changes to this project will be documented in this file.
44

55
## [Unreleased][unreleased]
66

7+
- Fix `context.next()` for multiple nested routes
8+
([#91](https://github.com/kriasoft/universal-router/pull/91))
79
- Add `pretty` option for `generateUrls(router, options)` to prettier encoding of URI path segments
810
([#88](https://github.com/kriasoft/universal-router/pull/88))
911
- Add source maps for minified builds ([#87](https://github.com/kriasoft/universal-router/pull/87))

dist/universal-router.js

Lines changed: 26 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/universal-router.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/universal-router.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/universal-router.min.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Router.js

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,17 @@ import matchPath from './matchPath';
1212
import matchRoute from './matchRoute';
1313
import resolveRoute from './resolveRoute';
1414

15+
function isChildRoute(parentRoute, childRoute) {
16+
let route = childRoute;
17+
while (route) {
18+
route = route.parent;
19+
if (route === parentRoute) {
20+
return true;
21+
}
22+
}
23+
return false;
24+
}
25+
1526
class Router {
1627
constructor(routes, options = {}) {
1728
if (Object(routes) !== routes) {
@@ -30,12 +41,19 @@ class Router {
3041
typeof pathOrContext === 'string' ? { path: pathOrContext } : pathOrContext);
3142
const match = matchRoute(this.root, this.baseUrl, context.path.substr(this.baseUrl.length));
3243
const resolve = this.resolveRoute;
33-
let matches;
34-
let parent;
44+
let matches = null;
45+
let nextMatches = null;
3546

36-
function next(resume) {
37-
parent = matches ? matches.value.route.parent : null;
38-
matches = match.next();
47+
function next(resume, parent = matches.value.route) {
48+
matches = nextMatches || match.next();
49+
nextMatches = null;
50+
51+
if (!resume) {
52+
if (matches.done || !isChildRoute(parent, matches.value.route)) {
53+
nextMatches = matches;
54+
return Promise.resolve(null);
55+
}
56+
}
3957

4058
if (matches.done) {
4159
return Promise.reject(Object.assign(
@@ -52,18 +70,14 @@ class Router {
5270
return result;
5371
}
5472

55-
if (resume || parent === matches.value.route.parent) {
56-
return next(resume);
57-
}
58-
59-
return result;
73+
return next(resume, parent);
6074
});
6175
}
6276

6377
context.url = context.path;
6478
context.next = next;
6579

66-
return next(true);
80+
return next(true, this.root);
6781
}
6882
}
6983

test/Router.spec.js

Lines changed: 47 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -231,23 +231,52 @@ describe('router.resolve({ path, ...context })', () => {
231231
{
232232
path: '/test',
233233
children: [
234-
{ path: '/', action() { log.push(2); } },
234+
{
235+
path: '/',
236+
action() { log.push(2); },
237+
children: [
238+
{
239+
path: '/',
240+
action({ next }) {
241+
log.push(3);
242+
return next().then(() => { log.push(6); });
243+
},
244+
children: [
245+
{
246+
path: '/',
247+
action({ next }) {
248+
log.push(4);
249+
return next().then(() => { log.push(5); });
250+
},
251+
},
252+
],
253+
},
254+
],
255+
},
256+
{
257+
path: '/',
258+
action() { log.push(7); },
259+
children: [
260+
{ path: '/', action() { log.push(8); } },
261+
{ path: '*', action() { log.push(9); } },
262+
],
263+
},
235264
],
236265
async action({ next }) {
237266
log.push(1);
238267
const result = await next();
239-
log.push(3);
268+
log.push(10);
240269
return result;
241270
},
242271
},
243-
{ path: '/:id', action() { log.push(4); } },
244-
{ path: '/test', action() { return log.push(5); } },
245-
{ path: '/*', action() { log.push(6); } },
272+
{ path: '/:id', action() { log.push(11); } },
273+
{ path: '/test', action() { log.push(12); return 'done'; } },
274+
{ path: '/*', action() { log.push(13); } },
246275
]);
247276

248277
const result = await router.resolve('/test');
249-
expect(log).to.be.deep.equal([1, 2, 3, 4, 5]);
250-
expect(result).to.be.equal(5);
278+
expect(log).to.be.deep.equal([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]);
279+
expect(result).to.be.equal('done');
251280
});
252281

253282
it('should support next(true) across multiple routes', async () => {
@@ -256,45 +285,45 @@ describe('router.resolve({ path, ...context })', () => {
256285
path: '/',
257286
action({ next }) {
258287
log.push(1);
259-
return next().then(() => log.push(8));
288+
return next().then((result) => { log.push(9); return result; });
260289
},
261290
children: [
262291
{
263292
path: '/a/b/c',
264293
action({ next }) {
265294
log.push(2);
266-
return next(true).then(() => log.push(7));
295+
return next(true).then((result) => { log.push(8); return result; });
267296
},
268297
},
269298
{
270299
path: '/a',
271-
action() {
272-
log.push(3);
273-
},
300+
action() { log.push(3); },
274301
children: [
275302
{
276303
path: '/b',
277304
action({ next }) {
278305
log.push(4);
279-
return next().then(() => log.push(6));
306+
return next().then((result) => { log.push(6); return result; });
280307
},
281308
children: [
282309
{
283310
path: '/c',
284-
action() {
285-
log.push(5);
286-
},
311+
action() { log.push(5); },
287312
},
288313
],
289314
},
315+
{
316+
path: '/b/c',
317+
action() { log.push(7); return 'done'; },
318+
},
290319
],
291320
},
292321
],
293322
});
294323

295324
const result = await router.resolve('/a/b/c');
296-
expect(log).to.be.deep.equal([1, 2, 3, 4, 5, 6, 7, 8]);
297-
expect(result).to.be.equal(8);
325+
expect(log).to.be.deep.equal([1, 2, 3, 4, 5, 6, 7, 8, 9]);
326+
expect(result).to.be.equal('done');
298327
});
299328

300329
it('should support parametrized routes 1', async () => {

0 commit comments

Comments
 (0)