diff --git a/lib/utils/create_routes.js b/lib/utils/create_routes.js index 702374a4e..461711229 100644 --- a/lib/utils/create_routes.js +++ b/lib/utils/create_routes.js @@ -1,7 +1,7 @@ const path = require('path'); module.exports = function create_matchers(files) { - return files + const routes = files .map(file => { if (/(^|\/|\\)_/.test(file)) return; @@ -47,9 +47,31 @@ module.exports = function create_matchers(files) { }) .filter(Boolean) .sort((a, b) => { - return ( - (a.dynamic.length - b.dynamic.length) || // match static paths first - (b.parts.length - a.parts.length) // match longer paths first - ); + let same = true; + + for (let i = 0; true; i += 1) { + const a_part = a.parts[i]; + const b_part = b.parts[i]; + + if (!a_part && !b_part) { + if (same) throw new Error(`The ${a.file} and ${b.file} routes clash`); + return 0; + } + + if (!a_part) return 1; + if (!b_part) return -1; + + const a_is_dynamic = a_part[0] === '['; + const b_is_dynamic = b_part[0] === '['; + + if (a_is_dynamic === b_is_dynamic) { + if (!a_is_dynamic) same = false; + continue; + } + + return a_is_dynamic ? 1 : -1; + } }); + + return routes; } \ No newline at end of file diff --git a/test/unit/create_routes.test.js b/test/unit/create_routes.test.js index 07cec2cf0..74b35ad50 100644 --- a/test/unit/create_routes.test.js +++ b/test/unit/create_routes.test.js @@ -5,15 +5,17 @@ const create_routes = require('../../lib/utils/create_routes.js'); describe('create_routes', () => { it('sorts routes correctly', () => { - const routes = create_routes(['index.html', 'about.html', '[wildcard].html', 'post/[id].html']); + const routes = create_routes(['index.html', 'about.html', '[wildcard].html', 'post/foo.html', 'post/[id].html', 'post/bar.html']); assert.deepEqual( routes.map(r => r.file), [ - 'about.html', - 'index.html', + 'post/foo.html', + 'post/bar.html', 'post/[id].html', - '[wildcard].html' + 'about.html', + '[wildcard].html', + 'index.html' ] ); }); @@ -48,4 +50,25 @@ describe('create_routes', () => { ] ); }); + + it('matches /foo/:bar before /:baz/qux', () => { + const a = create_routes(['foo/[bar].html', '[baz]/qux.html']); + const b = create_routes(['[baz]/qux.html', 'foo/[bar].html']); + + assert.deepEqual( + a.map(r => r.file), + ['foo/[bar].html', '[baz]/qux.html'] + ); + + assert.deepEqual( + b.map(r => r.file), + ['foo/[bar].html', '[baz]/qux.html'] + ); + }); + + it('fails if routes are indistinguishable', () => { + assert.throws(() => { + create_routes(['[foo].html', '[bar]/index.html']); + }, /The \[foo\].html and \[bar\]\/index.html routes clash/); + }); }); \ No newline at end of file