5
5
isRouteName ,
6
6
} from '../types'
7
7
import { createRouterError , ErrorTypes , MatcherError } from '../errors'
8
+ import { createMatcherTree , isMatchable } from './matcherTree'
8
9
import { createRouteRecordMatcher , RouteRecordMatcher } from './pathMatcher'
9
10
import { RouteRecordNormalized } from './types'
10
11
@@ -14,8 +15,6 @@ import type {
14
15
_PathParserOptions ,
15
16
} from './pathParserRanker'
16
17
17
- import { comparePathParserScore } from './pathParserRanker'
18
-
19
18
import { warn } from '../warning'
20
19
import { assign , noop } from '../utils'
21
20
import type { RouteRecordNameGeneric , _RouteRecordProps } from '../typed-routes'
@@ -58,8 +57,8 @@ export function createRouterMatcher(
58
57
routes : Readonly < RouteRecordRaw [ ] > ,
59
58
globalOptions : PathParserOptions
60
59
) : RouterMatcher {
61
- // normalized ordered array of matchers
62
- const matchers : RouteRecordMatcher [ ] = [ ]
60
+ // normalized ordered tree of matchers
61
+ const matcherTree = createMatcherTree ( )
63
62
const matcherMap = new Map <
64
63
NonNullable < RouteRecordNameGeneric > ,
65
64
RouteRecordMatcher
@@ -203,28 +202,24 @@ export function createRouterMatcher(
203
202
const matcher = matcherMap . get ( matcherRef )
204
203
if ( matcher ) {
205
204
matcherMap . delete ( matcherRef )
206
- matchers . splice ( matchers . indexOf ( matcher ) , 1 )
205
+ matcherTree . remove ( matcher )
207
206
matcher . children . forEach ( removeRoute )
208
207
matcher . alias . forEach ( removeRoute )
209
208
}
210
209
} else {
211
- const index = matchers . indexOf ( matcherRef )
212
- if ( index > - 1 ) {
213
- matchers . splice ( index , 1 )
214
- if ( matcherRef . record . name ) matcherMap . delete ( matcherRef . record . name )
215
- matcherRef . children . forEach ( removeRoute )
216
- matcherRef . alias . forEach ( removeRoute )
217
- }
210
+ matcherTree . remove ( matcherRef )
211
+ if ( matcherRef . record . name ) matcherMap . delete ( matcherRef . record . name )
212
+ matcherRef . children . forEach ( removeRoute )
213
+ matcherRef . alias . forEach ( removeRoute )
218
214
}
219
215
}
220
216
221
217
function getRoutes ( ) {
222
- return matchers
218
+ return matcherTree . toArray ( )
223
219
}
224
220
225
221
function insertMatcher ( matcher : RouteRecordMatcher ) {
226
- const index = findInsertionIndex ( matcher , matchers )
227
- matchers . splice ( index , 0 , matcher )
222
+ matcherTree . add ( matcher )
228
223
// only add the original record to the name map
229
224
if ( matcher . record . name && ! isAliasRecord ( matcher ) )
230
225
matcherMap . set ( matcher . record . name , matcher )
@@ -297,7 +292,7 @@ export function createRouterMatcher(
297
292
)
298
293
}
299
294
300
- matcher = matchers . find ( m => m . re . test ( path ) )
295
+ matcher = matcherTree . find ( path )
301
296
// matcher should have a value after the loop
302
297
303
298
if ( matcher ) {
@@ -310,7 +305,7 @@ export function createRouterMatcher(
310
305
// match by name or path of current route
311
306
matcher = currentLocation . name
312
307
? matcherMap . get ( currentLocation . name )
313
- : matchers . find ( m => m . re . test ( currentLocation . path ) )
308
+ : matcherTree . find ( currentLocation . path )
314
309
if ( ! matcher )
315
310
throw createRouterError < MatcherError > ( ErrorTypes . MATCHER_NOT_FOUND , {
316
311
location,
@@ -345,7 +340,7 @@ export function createRouterMatcher(
345
340
routes . forEach ( route => addRoute ( route ) )
346
341
347
342
function clearRoutes ( ) {
348
- matchers . length = 0
343
+ matcherTree . clear ( )
349
344
matcherMap . clear ( )
350
345
}
351
346
@@ -528,79 +523,4 @@ function checkMissingParamsInAbsolutePath(
528
523
}
529
524
}
530
525
531
- /**
532
- * Performs a binary search to find the correct insertion index for a new matcher.
533
- *
534
- * Matchers are primarily sorted by their score. If scores are tied then we also consider parent/child relationships,
535
- * with descendants coming before ancestors. If there's still a tie, new routes are inserted after existing routes.
536
- *
537
- * @param matcher - new matcher to be inserted
538
- * @param matchers - existing matchers
539
- */
540
- function findInsertionIndex (
541
- matcher : RouteRecordMatcher ,
542
- matchers : RouteRecordMatcher [ ]
543
- ) {
544
- // First phase: binary search based on score
545
- let lower = 0
546
- let upper = matchers . length
547
-
548
- while ( lower !== upper ) {
549
- const mid = ( lower + upper ) >> 1
550
- const sortOrder = comparePathParserScore ( matcher , matchers [ mid ] )
551
-
552
- if ( sortOrder < 0 ) {
553
- upper = mid
554
- } else {
555
- lower = mid + 1
556
- }
557
- }
558
-
559
- // Second phase: check for an ancestor with the same score
560
- const insertionAncestor = getInsertionAncestor ( matcher )
561
-
562
- if ( insertionAncestor ) {
563
- upper = matchers . lastIndexOf ( insertionAncestor , upper - 1 )
564
-
565
- if ( __DEV__ && upper < 0 ) {
566
- // This should never happen
567
- warn (
568
- `Finding ancestor route "${ insertionAncestor . record . path } " failed for "${ matcher . record . path } "`
569
- )
570
- }
571
- }
572
-
573
- return upper
574
- }
575
-
576
- function getInsertionAncestor ( matcher : RouteRecordMatcher ) {
577
- let ancestor : RouteRecordMatcher | undefined = matcher
578
-
579
- while ( ( ancestor = ancestor . parent ) ) {
580
- if (
581
- isMatchable ( ancestor ) &&
582
- comparePathParserScore ( matcher , ancestor ) === 0
583
- ) {
584
- return ancestor
585
- }
586
- }
587
-
588
- return
589
- }
590
-
591
- /**
592
- * Checks if a matcher can be reachable. This means if it's possible to reach it as a route. For example, routes without
593
- * a component, or name, or redirect, are just used to group other routes.
594
- * @param matcher
595
- * @param matcher.record record of the matcher
596
- * @returns
597
- */
598
- function isMatchable ( { record } : RouteRecordMatcher ) : boolean {
599
- return ! ! (
600
- record . name ||
601
- ( record . components && Object . keys ( record . components ) . length ) ||
602
- record . redirect
603
- )
604
- }
605
-
606
526
export type { PathParserOptions , _PathParserOptions }
0 commit comments