1
1
/** @module path */ /** for typedoc */
2
2
3
- import { extend , find , pick , omit , tail , mergeR , values , unnestR , Predicate , inArray } from "../common/common" ;
3
+ import {
4
+ extend , find , pick , omit , tail , mergeR , values , unnestR , Predicate , inArray , arrayTuples ,
5
+ } from "../common/common" ;
4
6
import { prop , propEq , not } from "../common/hof" ;
5
7
6
8
import { RawParams } from "../params/interface" ;
@@ -10,13 +12,14 @@ import {_ViewDeclaration} from "../state/interface";
10
12
11
13
import { StateObject } from "../state/stateObject" ;
12
14
import { TargetState } from "../state/targetState" ;
13
- import { PathNode } from "../path/node " ;
15
+ import { GetParamsFn , PathNode } from "./pathNode " ;
14
16
import { ViewService } from "../view/view" ;
17
+ import { Param } from '../params/param' ;
15
18
16
19
/**
17
20
* This class contains functions which convert TargetStates, Nodes and paths from one type to another.
18
21
*/
19
- export class PathFactory {
22
+ export class PathUtils {
20
23
21
24
constructor ( ) { }
22
25
@@ -33,9 +36,9 @@ export class PathFactory {
33
36
34
37
/** Given a fromPath: PathNode[] and a TargetState, builds a toPath: PathNode[] */
35
38
static buildToPath ( fromPath : PathNode [ ] , targetState : TargetState ) : PathNode [ ] {
36
- let toPath : PathNode [ ] = PathFactory . buildPath ( targetState ) ;
39
+ let toPath : PathNode [ ] = PathUtils . buildPath ( targetState ) ;
37
40
if ( targetState . options ( ) . inherit ) {
38
- return PathFactory . inheritParams ( fromPath , toPath , Object . keys ( targetState . params ( ) ) ) ;
41
+ return PathUtils . inheritParams ( fromPath , toPath , Object . keys ( targetState . params ( ) ) ) ;
39
42
}
40
43
return toPath ;
41
44
}
@@ -49,7 +52,7 @@ export class PathFactory {
49
52
// Only apply the viewConfigs to the nodes for the given states
50
53
path . filter ( node => inArray ( states , node . state ) ) . forEach ( node => {
51
54
let viewDecls : _ViewDeclaration [ ] = values ( node . state . views || { } ) ;
52
- let subPath = PathFactory . subPath ( path , n => n === node ) ;
55
+ let subPath = PathUtils . subPath ( path , n => n === node ) ;
53
56
let viewConfigs : ViewConfig [ ] [ ] = viewDecls . map ( view => $view . createViewConfig ( subPath , view ) ) ;
54
57
node . views = viewConfigs . reduce ( unnestR , [ ] ) ;
55
58
} ) ;
@@ -97,15 +100,18 @@ export class PathFactory {
97
100
return < PathNode [ ] > toPath . map ( makeInheritedParamsNode ) ;
98
101
}
99
102
103
+ static nonDynamicParams = ( node : PathNode ) : Param [ ] =>
104
+ node . state . parameters ( { inherit : false } )
105
+ . filter ( param => ! param . dynamic ) ;
106
+
100
107
/**
101
108
* Computes the tree changes (entering, exiting) between a fromPath and toPath.
102
109
*/
103
110
static treeChanges ( fromPath : PathNode [ ] , toPath : PathNode [ ] , reloadState : StateObject ) : TreeChanges {
104
111
let keep = 0 , max = Math . min ( fromPath . length , toPath . length ) ;
105
- const staticParams = ( state : StateObject ) =>
106
- state . parameters ( { inherit : false } ) . filter ( not ( prop ( 'dynamic' ) ) ) . map ( prop ( 'id' ) ) ;
112
+
107
113
const nodesMatch = ( node1 : PathNode , node2 : PathNode ) =>
108
- node1 . equals ( node2 , staticParams ( node1 . state ) ) ;
114
+ node1 . equals ( node2 , PathUtils . nonDynamicParams ) ;
109
115
110
116
while ( keep < max && fromPath [ keep ] . state !== reloadState && nodesMatch ( fromPath [ keep ] , toPath [ keep ] ) ) {
111
117
keep ++ ;
@@ -132,6 +138,43 @@ export class PathFactory {
132
138
return { from, to, retained, exiting, entering } ;
133
139
}
134
140
141
+ /**
142
+ * Returns a new path which is: the subpath of the first path which matches the second path.
143
+ *
144
+ * The new path starts from root and contains any nodes that match the nodes in the second path.
145
+ * It stops before the first non-matching node.
146
+ *
147
+ * Nodes are compared using their state property and their parameter values.
148
+ * If a `paramsFn` is provided, only the [[Param]] returned by the function will be considered when comparing nodes.
149
+ *
150
+ * @param pathA the first path
151
+ * @param pathB the second path
152
+ * @param paramsFn a function which returns the parameters to consider when comparing
153
+ *
154
+ * @returns an array of PathNodes from the first path which match the nodes in the second path
155
+ */
156
+ static matching ( pathA : PathNode [ ] , pathB : PathNode [ ] , paramsFn ?: GetParamsFn ) : PathNode [ ] {
157
+ let done = false ;
158
+ let tuples : PathNode [ ] [ ] = arrayTuples ( pathA , pathB ) ;
159
+ return tuples . reduce ( ( matching , [ nodeA , nodeB ] ) => {
160
+ done = done || ! nodeA . equals ( nodeB , paramsFn ) ;
161
+ return done ? matching : matching . concat ( nodeA ) ;
162
+ } , [ ] ) ;
163
+ }
164
+
165
+ /**
166
+ * Returns true if two paths are identical.
167
+ *
168
+ * @param pathA
169
+ * @param pathB
170
+ * @param paramsFn a function which returns the parameters to consider when comparing
171
+ * @returns true if the the states and parameter values for both paths are identical
172
+ */
173
+ static equals ( pathA : PathNode [ ] , pathB : PathNode [ ] , paramsFn ?: GetParamsFn ) : boolean {
174
+ return pathA . length === pathB . length &&
175
+ PathUtils . matching ( pathA , pathB , paramsFn ) . length === pathA . length ;
176
+ }
177
+
135
178
/**
136
179
* Return a subpath of a path, which stops at the first matching node
137
180
*
@@ -149,5 +192,6 @@ export class PathFactory {
149
192
}
150
193
151
194
/** Gets the raw parameter values from a path */
152
- static paramValues = ( path : PathNode [ ] ) => path . reduce ( ( acc , node ) => extend ( acc , node . paramValues ) , { } ) ;
195
+ static paramValues = ( path : PathNode [ ] ) =>
196
+ path . reduce ( ( acc , node ) => extend ( acc , node . paramValues ) , { } ) ;
153
197
}
0 commit comments