2
2
* @coreapi
3
3
* @module params
4
4
*/ /** for typedoc */
5
- import { extend , filter , map , applyPairs , allTrueR } from "../common/common" ;
6
- import { prop , propEq } from "../common/hof" ;
7
- import { isInjectable , isDefined , isString , isArray } from "../common/predicates" ;
5
+ import { extend , filter , map , allTrueR } from "../common/common" ;
6
+ import { prop } from "../common/hof" ;
7
+ import { isInjectable , isDefined , isString , isArray , isUndefined } from "../common/predicates" ;
8
8
import { RawParams , ParamDeclaration } from "../params/interface" ;
9
9
import { services } from "../common/coreservices" ;
10
10
import { ParamType } from "./paramType" ;
@@ -17,15 +17,22 @@ import { UrlMatcherFactory } from "../url/urlMatcherFactory";
17
17
18
18
/** @internalapi */
19
19
export enum DefType {
20
- PATH , SEARCH , CONFIG
20
+ PATH ,
21
+ SEARCH ,
22
+ CONFIG ,
21
23
}
22
24
23
25
/** @hidden */
24
26
function unwrapShorthand ( cfg : ParamDeclaration ) : ParamDeclaration {
25
27
cfg = isShorthand ( cfg ) && { value : cfg } as any || cfg ;
26
28
29
+ getStaticDefaultValue [ '__cacheable' ] = true ;
30
+ function getStaticDefaultValue ( ) {
31
+ return cfg . value ;
32
+ }
33
+
27
34
return extend ( cfg , {
28
- $$fn : isInjectable ( cfg . value ) ? cfg . value : ( ) => cfg . value
35
+ $$fn : isInjectable ( cfg . value ) ? cfg . value : getStaticDefaultValue ,
29
36
} ) ;
30
37
}
31
38
@@ -59,7 +66,7 @@ function getSquashPolicy(config: ParamDeclaration, isOptional: boolean, defaultP
59
66
function getReplace ( config : ParamDeclaration , arrayMode : boolean , isOptional : boolean , squash : ( string | boolean ) ) {
60
67
let replace : any , configuredKeys : string [ ] , defaultPolicy = [
61
68
{ from : "" , to : ( isOptional || arrayMode ? undefined : "" ) } ,
62
- { from : null , to : ( isOptional || arrayMode ? undefined : "" ) }
69
+ { from : null , to : ( isOptional || arrayMode ? undefined : "" ) } ,
63
70
] ;
64
71
replace = isArray ( config . replace ) ? config . replace : [ ] ;
65
72
if ( isString ( squash ) ) replace . push ( { from : squash , to : undefined } ) ;
@@ -77,10 +84,14 @@ export class Param {
77
84
dynamic : boolean ;
78
85
raw : boolean ;
79
86
squash : ( boolean | string ) ;
80
- replace : any ;
87
+ replace : [ { to : any , from : any } ] ;
81
88
inherit : boolean ;
82
89
array : boolean ;
83
90
config : any ;
91
+ /** Cache the default value if it is a static value */
92
+ _defaultValueCache : {
93
+ defaultValue : any ,
94
+ } ;
84
95
85
96
constructor ( id : string , type : ParamType , config : ParamDeclaration , location : DefType , urlMatcherFactory : UrlMatcherFactory ) {
86
97
config = unwrapShorthand ( config ) ;
@@ -101,7 +112,7 @@ export class Param {
101
112
return extend ( arrayDefaults , arrayParamNomenclature , config ) . array ;
102
113
}
103
114
104
- extend ( this , { id, type, location, isOptional, dynamic, raw, squash, replace, inherit, array : arrayMode , config, } ) ;
115
+ extend ( this , { id, type, location, isOptional, dynamic, raw, squash, replace, inherit, array : arrayMode , config } ) ;
105
116
}
106
117
107
118
isDefaultValue ( value : any ) : boolean {
@@ -116,21 +127,33 @@ export class Param {
116
127
/**
117
128
* [Internal] Get the default value of a parameter, which may be an injectable function.
118
129
*/
119
- const $$getDefaultValue = ( ) => {
130
+ const getDefaultValue = ( ) => {
131
+ if ( this . _defaultValueCache ) return this . _defaultValueCache . defaultValue ;
132
+
120
133
if ( ! services . $injector ) throw new Error ( "Injectable functions cannot be called at configuration time" ) ;
134
+
121
135
let defaultValue = services . $injector . invoke ( this . config . $$fn ) ;
136
+
122
137
if ( defaultValue !== null && defaultValue !== undefined && ! this . type . is ( defaultValue ) )
123
138
throw new Error ( `Default value (${ defaultValue } ) for parameter '${ this . id } ' is not an instance of ParamType (${ this . type . name } )` ) ;
139
+
140
+ if ( this . config . $$fn [ '__cacheable' ] ) {
141
+ this . _defaultValueCache = { defaultValue } ;
142
+ }
143
+
124
144
return defaultValue ;
125
145
} ;
126
146
127
- const $replace = ( val : any ) => {
128
- let replacement : any = map ( filter ( this . replace , propEq ( 'from' , val ) ) , prop ( "to" ) ) ;
129
- return replacement . length ? replacement [ 0 ] : val ;
147
+ const replaceSpecialValues = ( val : any ) => {
148
+ for ( let tuple of this . replace ) {
149
+ if ( tuple . from === val ) return tuple . to ;
150
+ }
151
+ return val ;
130
152
} ;
131
153
132
- value = $replace ( value ) ;
133
- return ! isDefined ( value ) ? $$getDefaultValue ( ) : this . type . $normalize ( value ) ;
154
+ value = replaceSpecialValues ( value ) ;
155
+
156
+ return isUndefined ( value ) ? getDefaultValue ( ) : this . type . $normalize ( value ) ;
134
157
}
135
158
136
159
isSearch ( ) : boolean {
@@ -139,7 +162,7 @@ export class Param {
139
162
140
163
validates ( value : any ) : boolean {
141
164
// There was no parameter value, but the param is optional
142
- if ( ( ! isDefined ( value ) || value === null ) && this . isOptional ) return true ;
165
+ if ( ( isUndefined ( value ) || value === null ) && this . isOptional ) return true ;
143
166
144
167
// The value was not of the correct ParamType, and could not be decoded to the correct ParamType
145
168
const normalized = this . type . $normalize ( value ) ;
@@ -155,7 +178,11 @@ export class Param {
155
178
}
156
179
157
180
static values ( params : Param [ ] , values : RawParams = { } ) : RawParams {
158
- return < RawParams > params . map ( param => [ param . id , param . value ( values [ param . id ] ) ] ) . reduce ( applyPairs , { } ) ;
181
+ const paramValues = { } as RawParams ;
182
+ for ( let param of params ) {
183
+ paramValues [ param . id ] = param . value ( values [ param . id ] ) ;
184
+ }
185
+ return paramValues ;
159
186
}
160
187
161
188
/**
0 commit comments