@@ -13,65 +13,149 @@ export function createEmptyUrlTree() {
1313 return new UrlTree ( new UrlSegmentGroup ( [ ] , { } ) , { } , null ) ;
1414}
1515
16- export function containsTree ( container : UrlTree , containee : UrlTree , exact : boolean ) : boolean {
17- if ( exact ) {
18- return equalQueryParams ( container . queryParams , containee . queryParams ) &&
19- equalSegmentGroups ( container . root , containee . root ) ;
20- }
16+ /**
17+ * A set of options which specify how to determine if a `UrlTree` is active, given the `UrlTree`
18+ * for the current router state.
19+ *
20+ * @publicApi
21+ * @see Router.isActive
22+ */
23+ export interface IsActiveMatchOptions {
24+ /**
25+ * Defines the strategy for comparing the matrix parameters of two `UrlTree`s.
26+ *
27+ * The matrix parameter matching is dependent on the strategy for matching the
28+ * segments. That is, if the `paths` option is set to `'subset'`, only
29+ * the matrix parameters of the matching segments will be compared.
30+ *
31+ * - `'exact'`: Requires that matching segments also have exact matrix parameter
32+ * matches.
33+ * - `'subset'`: The matching segments in the router's active `UrlTree` may contain
34+ * extra matrix parameters, but those that exist in the `UrlTree` in question must match.
35+ * - `'ignored'`: When comparing `UrlTree`s, matrix params will be ignored.
36+ */
37+ matrixParams : 'exact' | 'subset' | 'ignored' ;
38+ /**
39+ * Defines the strategy for comparing the query parameters of two `UrlTree`s.
40+ *
41+ * - `'exact'`: the query parameters must match exactly.
42+ * - `'subset'`: the active `UrlTree` may contain extra parameters,
43+ * but must match the key and value of any that exist in the `UrlTree` in question.
44+ * - `'ignored'`: When comparing `UrlTree`s, query params will be ignored.
45+ */
46+ queryParams : 'exact' | 'subset' | 'ignored' ;
47+ /**
48+ * Defines the strategy for comparing the `UrlSegment`s of the `UrlTree`s.
49+ *
50+ * - `'exact'`: all segments in each `UrlTree` must match.
51+ * - `'subset'`: a `UrlTree` will be determined to be active if it
52+ * is a subtree of the active route. That is, the active route may contain extra
53+ * segments, but must at least have all the segements of the `UrlTree` in question.
54+ */
55+ paths : 'exact' | 'subset' ;
56+ /**
57+ * - 'exact'`: indicates that the `UrlTree` fragments must be equal.
58+ * - `'ignored'`: the fragments will not be compared when determining if a
59+ * `UrlTree` is active.
60+ */
61+ fragment : 'exact' | 'ignored' ;
62+ }
2163
22- return containsQueryParams ( container . queryParams , containee . queryParams ) &&
23- containsSegmentGroup ( container . root , containee . root ) ;
64+ type ParamMatchOptions = 'exact' | 'subset' | 'ignored' ;
65+
66+ type PathCompareFn =
67+ ( container : UrlSegmentGroup , containee : UrlSegmentGroup , matrixParams : ParamMatchOptions ) =>
68+ boolean ;
69+ type ParamCompareFn = ( container : Params , containee : Params ) => boolean ;
70+
71+ const pathCompareMap : Record < IsActiveMatchOptions [ 'paths' ] , PathCompareFn > = {
72+ 'exact' : equalSegmentGroups ,
73+ 'subset' : containsSegmentGroup ,
74+ } ;
75+ const paramCompareMap : Record < ParamMatchOptions , ParamCompareFn > = {
76+ 'exact' : equalParams ,
77+ 'subset' : containsParams ,
78+ 'ignored' : ( ) => true ,
79+ } ;
80+
81+ export function containsTree (
82+ container : UrlTree , containee : UrlTree , options : IsActiveMatchOptions ) : boolean {
83+ return pathCompareMap [ options . paths ] ( container . root , containee . root , options . matrixParams ) &&
84+ paramCompareMap [ options . queryParams ] ( container . queryParams , containee . queryParams ) &&
85+ ! ( options . fragment === 'exact' && container . fragment !== containee . fragment ) ;
2486}
2587
26- function equalQueryParams ( container : Params , containee : Params ) : boolean {
88+ function equalParams ( container : Params , containee : Params ) : boolean {
2789 // TODO: This does not handle array params correctly.
2890 return shallowEqual ( container , containee ) ;
2991}
3092
31- function equalSegmentGroups ( container : UrlSegmentGroup , containee : UrlSegmentGroup ) : boolean {
93+ function equalSegmentGroups (
94+ container : UrlSegmentGroup , containee : UrlSegmentGroup ,
95+ matrixParams : ParamMatchOptions ) : boolean {
3296 if ( ! equalPath ( container . segments , containee . segments ) ) return false ;
97+ if ( ! matrixParamsMatch ( container . segments , containee . segments , matrixParams ) ) {
98+ return false ;
99+ }
33100 if ( container . numberOfChildren !== containee . numberOfChildren ) return false ;
34101 for ( const c in containee . children ) {
35102 if ( ! container . children [ c ] ) return false ;
36- if ( ! equalSegmentGroups ( container . children [ c ] , containee . children [ c ] ) ) return false ;
103+ if ( ! equalSegmentGroups ( container . children [ c ] , containee . children [ c ] , matrixParams ) )
104+ return false ;
37105 }
38106 return true ;
39107}
40108
41- function containsQueryParams ( container : Params , containee : Params ) : boolean {
109+ function containsParams ( container : Params , containee : Params ) : boolean {
42110 return Object . keys ( containee ) . length <= Object . keys ( container ) . length &&
43111 Object . keys ( containee ) . every ( key => equalArraysOrString ( container [ key ] , containee [ key ] ) ) ;
44112}
45113
46- function containsSegmentGroup ( container : UrlSegmentGroup , containee : UrlSegmentGroup ) : boolean {
47- return containsSegmentGroupHelper ( container , containee , containee . segments ) ;
114+ function containsSegmentGroup (
115+ container : UrlSegmentGroup , containee : UrlSegmentGroup ,
116+ matrixParams : ParamMatchOptions ) : boolean {
117+ return containsSegmentGroupHelper ( container , containee , containee . segments , matrixParams ) ;
48118}
49119
50120function containsSegmentGroupHelper (
51- container : UrlSegmentGroup , containee : UrlSegmentGroup , containeePaths : UrlSegment [ ] ) : boolean {
121+ container : UrlSegmentGroup , containee : UrlSegmentGroup , containeePaths : UrlSegment [ ] ,
122+ matrixParams : ParamMatchOptions ) : boolean {
52123 if ( container . segments . length > containeePaths . length ) {
53124 const current = container . segments . slice ( 0 , containeePaths . length ) ;
54125 if ( ! equalPath ( current , containeePaths ) ) return false ;
55126 if ( containee . hasChildren ( ) ) return false ;
127+ if ( ! matrixParamsMatch ( current , containeePaths , matrixParams ) ) return false ;
56128 return true ;
57129
58130 } else if ( container . segments . length === containeePaths . length ) {
59131 if ( ! equalPath ( container . segments , containeePaths ) ) return false ;
132+ if ( ! matrixParamsMatch ( container . segments , containeePaths , matrixParams ) ) return false ;
60133 for ( const c in containee . children ) {
61134 if ( ! container . children [ c ] ) return false ;
62- if ( ! containsSegmentGroup ( container . children [ c ] , containee . children [ c ] ) ) return false ;
135+ if ( ! containsSegmentGroup ( container . children [ c ] , containee . children [ c ] , matrixParams ) ) {
136+ return false ;
137+ }
63138 }
64139 return true ;
65140
66141 } else {
67142 const current = containeePaths . slice ( 0 , container . segments . length ) ;
68143 const next = containeePaths . slice ( container . segments . length ) ;
69144 if ( ! equalPath ( container . segments , current ) ) return false ;
145+ if ( ! matrixParamsMatch ( container . segments , current , matrixParams ) ) return false ;
70146 if ( ! container . children [ PRIMARY_OUTLET ] ) return false ;
71- return containsSegmentGroupHelper ( container . children [ PRIMARY_OUTLET ] , containee , next ) ;
147+ return containsSegmentGroupHelper (
148+ container . children [ PRIMARY_OUTLET ] , containee , next , matrixParams ) ;
72149 }
73150}
74151
152+ function matrixParamsMatch (
153+ containerPaths : UrlSegment [ ] , containeePaths : UrlSegment [ ] , options : ParamMatchOptions ) {
154+ return containeePaths . every ( ( containeeSegment , i ) => {
155+ return paramCompareMap [ options ] ( containerPaths [ i ] . parameters , containeeSegment . parameters ) ;
156+ } ) ;
157+ }
158+
75159/**
76160 * @description
77161 *
0 commit comments