22 * @coreapi
33 * @module params
44 */ /** 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" ;
88import { RawParams , ParamDeclaration } from "../params/interface" ;
99import { services } from "../common/coreservices" ;
1010import { ParamType } from "./paramType" ;
@@ -17,15 +17,22 @@ import { UrlMatcherFactory } from "../url/urlMatcherFactory";
1717
1818/** @internalapi */
1919export enum DefType {
20- PATH , SEARCH , CONFIG
20+ PATH ,
21+ SEARCH ,
22+ CONFIG ,
2123}
2224
2325/** @hidden */
2426function unwrapShorthand ( cfg : ParamDeclaration ) : ParamDeclaration {
2527 cfg = isShorthand ( cfg ) && { value : cfg } as any || cfg ;
2628
29+ getStaticDefaultValue [ '__cacheable' ] = true ;
30+ function getStaticDefaultValue ( ) {
31+ return cfg . value ;
32+ }
33+
2734 return extend ( cfg , {
28- $$fn : isInjectable ( cfg . value ) ? cfg . value : ( ) => cfg . value
35+ $$fn : isInjectable ( cfg . value ) ? cfg . value : getStaticDefaultValue ,
2936 } ) ;
3037}
3138
@@ -59,7 +66,7 @@ function getSquashPolicy(config: ParamDeclaration, isOptional: boolean, defaultP
5966function getReplace ( config : ParamDeclaration , arrayMode : boolean , isOptional : boolean , squash : ( string | boolean ) ) {
6067 let replace : any , configuredKeys : string [ ] , defaultPolicy = [
6168 { from : "" , to : ( isOptional || arrayMode ? undefined : "" ) } ,
62- { from : null , to : ( isOptional || arrayMode ? undefined : "" ) }
69+ { from : null , to : ( isOptional || arrayMode ? undefined : "" ) } ,
6370 ] ;
6471 replace = isArray ( config . replace ) ? config . replace : [ ] ;
6572 if ( isString ( squash ) ) replace . push ( { from : squash , to : undefined } ) ;
@@ -77,10 +84,14 @@ export class Param {
7784 dynamic : boolean ;
7885 raw : boolean ;
7986 squash : ( boolean | string ) ;
80- replace : any ;
87+ replace : [ { to : any , from : any } ] ;
8188 inherit : boolean ;
8289 array : boolean ;
8390 config : any ;
91+ /** Cache the default value if it is a static value */
92+ _defaultValueCache : {
93+ defaultValue : any ,
94+ } ;
8495
8596 constructor ( id : string , type : ParamType , config : ParamDeclaration , location : DefType , urlMatcherFactory : UrlMatcherFactory ) {
8697 config = unwrapShorthand ( config ) ;
@@ -101,7 +112,7 @@ export class Param {
101112 return extend ( arrayDefaults , arrayParamNomenclature , config ) . array ;
102113 }
103114
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 } ) ;
105116 }
106117
107118 isDefaultValue ( value : any ) : boolean {
@@ -116,21 +127,33 @@ export class Param {
116127 /**
117128 * [Internal] Get the default value of a parameter, which may be an injectable function.
118129 */
119- const $$getDefaultValue = ( ) => {
130+ const getDefaultValue = ( ) => {
131+ if ( this . _defaultValueCache ) return this . _defaultValueCache . defaultValue ;
132+
120133 if ( ! services . $injector ) throw new Error ( "Injectable functions cannot be called at configuration time" ) ;
134+
121135 let defaultValue = services . $injector . invoke ( this . config . $$fn ) ;
136+
122137 if ( defaultValue !== null && defaultValue !== undefined && ! this . type . is ( defaultValue ) )
123138 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+
124144 return defaultValue ;
125145 } ;
126146
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 ;
130152 } ;
131153
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 ) ;
134157 }
135158
136159 isSearch ( ) : boolean {
@@ -139,7 +162,7 @@ export class Param {
139162
140163 validates ( value : any ) : boolean {
141164 // 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 ;
143166
144167 // The value was not of the correct ParamType, and could not be decoded to the correct ParamType
145168 const normalized = this . type . $normalize ( value ) ;
@@ -155,7 +178,11 @@ export class Param {
155178 }
156179
157180 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 ;
159186 }
160187
161188 /**
0 commit comments