Skip to content

Commit 6719d2e

Browse files
committed
fix: ordering of siblings routes for matching
1 parent 4d5d579 commit 6719d2e

3 files changed

Lines changed: 36 additions & 23 deletions

File tree

modules/RouteNode.js

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -56,29 +56,33 @@ export default class RouteNode {
5656
this.children.push(route);
5757
// Push greedy spats to the bottom of the pile
5858
this.children.sort((left, right) => {
59-
const leftPath = left.path.split('?')[0];
60-
const rightPath = right.path.split('?')[0];
59+
const leftPath = left.path.split('?')[0].replace(/(.+)\/$/, '$1');
60+
const rightPath = right.path.split('?')[0].replace(/(.+)\/$/, '$1');
6161
// '/' last
6262
if (leftPath === '/') return 1;
6363
if (rightPath === '/') return -1;
64-
let leftHasParams = left.parser.hasUrlParams || left.parser.hasSpatParam;
65-
let rightHasParams = right.parser.hasUrlParams || right.parser.hasSpatParam;
66-
// No params first, sort by length descending
67-
if (!leftHasParams && !rightHasParams) {
68-
return leftPath && rightPath ? (leftPath.length < rightPath.length ? 1 : -1) : 0;
69-
}
70-
// Params last
71-
if (leftHasParams && !rightHasParams) return 1;
72-
if (!leftHasParams && rightHasParams) return -1;
7364
// Spat params last
74-
if (!left.parser.hasSpatParam && right.parser.hasSpatParam) return -1;
75-
if (!right.parser.hasSpatParam && left.parser.hasSpatParam) return 1;
76-
// Sort by number of segments descending
77-
let leftSegments = (leftPath.match(/\//g) || []).length;
78-
let rightSegments = (rightPath.match(/\//g) || []).length;
65+
if (left.parser.hasSpatParam) return 1;
66+
if (right.parser.hasSpatParam) return -1;
67+
// No spat, number of segments (less segments last)
68+
const leftSegments = (leftPath.match(/\//g) || []).length;
69+
const rightSegments = (rightPath.match(/\//g) || []).length;
7970
if (leftSegments < rightSegments) return 1;
71+
if (leftSegments > rightSegments) return -1;
72+
// Same number of segments, number of URL params ascending
73+
const leftParamsCount = left.parser.urlParams.length;
74+
const rightParamsCount = right.parser.urlParams.length;
75+
if (leftParamsCount < rightParamsCount) return -1;
76+
if (leftParamsCount > rightParamsCount) return 1;
77+
// Same number of segments and params, last segment length descending
78+
const leftParamLength = (leftPath.split('/').slice(-1)[0] || '').length;
79+
const rightParamLength = (rightPath.split('/').slice(-1)[0] || '').length;
80+
if (leftParamLength < rightParamLength) return 1;
81+
if (leftParamLength > rightParamLength) return -1;
82+
// Same last segment length, preserve definition order
8083
return 0;
8184
});
85+
console.log(this.children.map(c => c.path));
8286
} else {
8387
// Locate parent node
8488
let segments = this.getSegmentsByName(names.slice(0, -1).join('.'));
@@ -176,7 +180,6 @@ export default class RouteNode {
176180

177181
const matched = matchChildren(startingNodes, path, segments);
178182
if (matched && matched.length === 1 && matched[0].name === '') return null;
179-
180183
return matched;
181184
}
182185

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
"yargs": "^3.31.0"
5555
},
5656
"dependencies": {
57-
"path-parser": "~1.0.2"
57+
"path-parser": "~1.0.2",
58+
"search-params": "~1.1.0"
5859
}
5960
}

test/main.js

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
'use strict';
2-
31
import path from 'path';
42
import pkg from '../package.json';
53
import RouteNode from '../modules/RouteNode';
@@ -272,7 +270,7 @@ describe('RouteNode', function () {
272270

273271
withoutMeta(usersNode.matchPath('/users/view/1')).should.eql({name: 'users.view', params: {id: '1'}});
274272
withoutMeta(usersNode.matchPath('/users/list')).should.eql({name: 'users.list', params: {}});
275-
})
273+
});
276274

277275
it('should be able to add deep nodes', function () {
278276
var rootNode = new RouteNode('', '')
@@ -286,17 +284,28 @@ describe('RouteNode', function () {
286284

287285
it('should sort paths by length', function () {
288286
var rootNode = new RouteNode('', '')
287+
.addNode('personList', '/persons/')
288+
.addNode('personDetail', '/persons/:personId')
289289
.addNode('section', '/section/:id?a')
290290
.addNode('index', '/?queryparamOfexceptionalLength')
291291
.addNode('id', '/:id?rrrr')
292292
.addNode('abo', '/abo')
293-
.addNode('about', '/about?hello');
293+
.addNode('about', '/about?hello')
294+
.addNode('users', '/users-tab')
295+
.addNode('user', '/users/:id')
296+
.addNode('postNew', '/blogs/:blogId/posts/new')
297+
.addNode('postDetail', '/blogs/:blogId/posts/:postId');
294298

295299
withoutMeta(rootNode.matchPath('/')).should.eql({name: 'index', params: {}});
296300
withoutMeta(rootNode.matchPath('/abo')).should.eql({name: 'abo', params: {}});
297301
withoutMeta(rootNode.matchPath('/about')).should.eql({name: 'about', params: {}});
298302
withoutMeta(rootNode.matchPath('/abc')).should.eql({name: 'id', params: {id: 'abc'}});
299303
withoutMeta(rootNode.matchPath('/section/abc')).should.eql({name: 'section', params: {id: 'abc'}});
304+
withoutMeta(rootNode.matchPath('/persons/jwoudenberg')).should.eql({name: 'personDetail', params: {personId: 'jwoudenberg'}});
305+
withoutMeta(rootNode.matchPath('/users-tab')).should.eql({name: 'users', params: {}});
306+
withoutMeta(rootNode.matchPath('/users/thomas')).should.eql({name: 'user', params: {id: 'thomas'}});
307+
withoutMeta(rootNode.matchPath('/blogs/123/posts/new')).should.eql({name: 'postNew', params: {blogId: '123'}});
308+
withoutMeta(rootNode.matchPath('/blogs/123/posts/456')).should.eql({name: 'postDetail', params: {blogId: '123', postId: '456'}});
300309
});
301310

302311
it('should match paths with optional trailing slashes', function () {
@@ -317,7 +326,7 @@ describe('RouteNode', function () {
317326
should.not.exists(rootNode.matchPath('/users/list//', { trailingSlash: true }));
318327
});
319328

320-
it.only('should support query parameters with square brackets', function () {
329+
it('should support query parameters with square brackets', function () {
321330
var node = new RouteNode('', '', [
322331
new RouteNode('route', '/route?arr[]', [
323332
new RouteNode('deep', '/deep?arr2[]')

0 commit comments

Comments
 (0)