]> git.ipfire.org Git - thirdparty/vuejs/router.git/commitdiff
fix(matcher): handle custom regexp path ranking
authorEduardo San Martin Morote <posva13@gmail.com>
Fri, 12 Jul 2019 10:14:31 +0000 (12:14 +0200)
committerEduardo San Martin Morote <posva13@gmail.com>
Wed, 17 Jul 2019 11:42:36 +0000 (13:42 +0200)
__tests__/matcher-ranking.spec.js
src/matcher.ts

index 5cde0fcfad951cdffb42475c8823ac670c2de94d..30f5799e25165d37dfb400280d73d4000215adc7 100644 (file)
@@ -24,6 +24,10 @@ describe('createRouteMatcher', () => {
    */
   function checkPathOrder(paths, options = {}) {
     const matchers = paths
+      .slice()
+      // Because sorting order is conserved, allows to mismatch order on
+      // routes with the same ranking
+      .reverse()
       .map(path =>
         createRouteMatcher(
           {
@@ -72,20 +76,23 @@ describe('createRouteMatcher', () => {
     checkPathOrder(['/', '/:rest(.*)'])
   })
 
+  it('prioritises custom regex', () => {
+    checkPathOrder(['/:a(\\d+)', '/:a', '/:a(.*)'])
+    checkPathOrder(['/b-:a(\\d+)', '/b-:a', '/b-:a(.*)'])
+  })
+
   it('handles sub segments optional params', () => {
     // TODO: /a/c should be be bigger than /a/c/:b?
-    checkPathOrder(['/a/d/c', '/a/b/c:b', '/a/c/:b?', '/a/c'])
+    checkPathOrder(['/a/d/c', '/a/b/c:b', '/a/c/:b', '/a/c/:b?', '/a/c'])
   })
 
   it('handles optional in sub segments', () => {
     checkPathOrder([
-      '/a/__',
       '/a/_2_',
-      '/a/_:b\\_', // the _ is escaped
       // something like /a/_23_
       '/a/_:b(\\d)?_',
+      '/a/_:b\\_', // the _ is escaped but b can be also letters
       '/a/a_:b',
-      '/a/_:b_', // the _ is part of the identifier
     ])
   })
 
index cfd6d4dbdbda29923e1ff7ab09ce9861a05d5186..442649a68bd092ec1e88967e7a071c9d487ff12a 100644 (file)
@@ -52,6 +52,7 @@ enum PathScore {
   SubSegment = 2, // /multiple-:things-in-one-:segment
   Static = 3, // /static
   Dynamic = 2, // /:someId
+  DynamicCustomRegexp = 2.5, // /:someId(\\d+)
   Wildcard = -1, // /:namedWildcard(.*)
   SubWildcard = 1, // Wildcard as a subsegment
   Repeatable = -0.5, // /:w+ or /:w*
@@ -60,6 +61,9 @@ enum PathScore {
   Root = 1, // just /
 }
 
+// allows to check if the user provided a custom regexp
+const isDefaultPathRegExpRE = /^\[\^[^\]]+\]\+\?$/
+
 export function createRouteMatcher(
   record: Readonly<NormalizedRouteRecord>,
   parent: RouteMatcher | void,
@@ -182,7 +186,12 @@ export function createRouteMatcher(
       if (typeof group === 'string') {
         score += group === '/' ? PathScore.Root : PathScore.Static
       } else {
-        score += group.pattern === '.*' ? PathScore.Wildcard : PathScore.Dynamic
+        score +=
+          group.pattern === '.*'
+            ? PathScore.Wildcard
+            : isDefaultPathRegExpRE.test(group.pattern)
+            ? PathScore.Dynamic
+            : PathScore.DynamicCustomRegexp
         score +=
           +group.optional * PathScore.Optional +
           +group.repeat * PathScore.Repeatable
@@ -201,7 +210,11 @@ export function createRouteMatcher(
         score += PathScore.Static
       } else {
         score +=
-          group.pattern === '.*' ? PathScore.SubWildcard : PathScore.Dynamic
+          group.pattern === '.*'
+            ? PathScore.SubWildcard
+            : isDefaultPathRegExpRE.test(group.pattern)
+            ? PathScore.Dynamic
+            : PathScore.DynamicCustomRegexp
         score += +group.optional * PathScore.SubOptional
         if (typeof group.name === 'number') throw new Error('Name your param')
         // keys.push(group.name)