@@ -94,15 +94,15 @@ function UrlMatcher(pattern, config, parentMatcher) {
94
94
return params [ id ] ;
95
95
}
96
96
97
- function quoteRegExp ( string , pattern , squashPolicy ) {
98
- var flags = [ '' , '' ] , result = string . replace ( / [ \\ \[ \] \^ $ * + ? . ( ) | { } ] / g, "\\$&" ) ;
97
+ function quoteRegExp ( string , pattern , squash ) {
98
+ var surroundPattern = [ '' , '' ] , result = string . replace ( / [ \\ \[ \] \^ $ * + ? . ( ) | { } ] / g, "\\$&" ) ;
99
99
if ( ! pattern ) return result ;
100
- switch ( squashPolicy ) {
101
- case "nosquash" : flags = [ '' , '' ] ; break ;
102
- case "value" : flags = [ '' , '?' ] ; break ;
103
- case "slash" : flags = [ '?' , '?' ] ; break ;
100
+ switch ( squash ) {
101
+ case false : surroundPattern = [ '( ' , ') ' ] ; break ;
102
+ case true : surroundPattern = [ '?( ' , ') ?' ] ; break ;
103
+ default : surroundPattern = [ '(' + squash + "|" , ') ?' ] ; break ;
104
104
}
105
- return result + flags [ 0 ] + '(' + pattern + ')' + flags [ 1 ] ;
105
+ return result + surroundPattern [ 0 ] + pattern + surroundPattern [ 1 ] ;
106
106
}
107
107
108
108
this . source = pattern ;
@@ -231,7 +231,7 @@ UrlMatcher.prototype.exec = function (path, searchParams) {
231
231
232
232
var paramNames = this . parameters ( ) , nTotal = paramNames . length ,
233
233
nPath = this . segments . length - 1 ,
234
- values = { } , i , cfg , paramName ;
234
+ values = { } , i , j , cfg , paramName ;
235
235
236
236
if ( nPath !== m . length - 1 ) throw new Error ( "Unbalanced capture group in route '" + this . source + "'" ) ;
237
237
@@ -244,8 +244,11 @@ UrlMatcher.prototype.exec = function (path, searchParams) {
244
244
for ( i = 0 ; i < nPath ; i ++ ) {
245
245
paramName = paramNames [ i ] ;
246
246
var param = this . params [ paramName ] ;
247
- // if the param is optional, convert an empty string to `undefined`
248
- var paramVal = m [ i + 1 ] === "" ? param . emptyString : m [ i + 1 ] ;
247
+ var paramVal = m [ i + 1 ] ;
248
+ // if the param value matches a pre-replace pair, replace the value before decoding.
249
+ for ( j = 0 ; j < param . replace ; j ++ ) {
250
+ if ( param . replace [ j ] . from === paramVal ) paramVal = param . replace [ j ] . to ;
251
+ }
249
252
if ( paramVal && param . array === true ) paramVal = decodePathArray ( paramVal ) ;
250
253
values [ paramName ] = param . value ( paramVal ) ;
251
254
}
@@ -323,12 +326,12 @@ UrlMatcher.prototype.format = function (values) {
323
326
var isPathParam = i < nPath ;
324
327
var name = params [ i ] , param = paramset [ name ] , value = param . value ( values [ name ] ) ;
325
328
var isDefaultValue = param . isOptional && param . type . equals ( param . value ( ) , value ) ;
326
- var squash = isDefaultValue ? param . squash : "nosquash" ;
329
+ var squash = isDefaultValue ? param . squash : false ;
327
330
var encoded = param . type . encode ( value ) ;
328
331
329
332
if ( isPathParam ) {
330
333
var nextSegment = segments [ i + 1 ] ;
331
- if ( squash === "nosquash" ) {
334
+ if ( squash === false ) {
332
335
if ( encoded != null ) {
333
336
if ( isArray ( encoded ) ) {
334
337
result += encoded . map ( encodeDashes ) . join ( "-" ) ;
@@ -337,14 +340,14 @@ UrlMatcher.prototype.format = function (values) {
337
340
}
338
341
}
339
342
result += nextSegment ;
340
- } else if ( squash === "value" ) {
341
- result += nextSegment ;
342
- } else if ( squash === "slash" ) {
343
+ } else if ( squash === true ) {
343
344
var capture = result . match ( / \/ $ / ) ? / \/ ? ( .* ) / : / ( .* ) / ;
344
345
result += nextSegment . match ( capture ) [ 1 ] ;
346
+ } else if ( isString ( squash ) ) {
347
+ result += squash + nextSegment ;
345
348
}
346
349
} else {
347
- if ( encoded == null || ( isDefaultValue && squash !== "nosquash" ) ) continue ;
350
+ if ( encoded == null || ( isDefaultValue && squash !== false ) ) continue ;
348
351
if ( ! isArray ( encoded ) ) encoded = [ encoded ] ;
349
352
encoded = encoded . map ( encodeURIComponent ) . join ( '&' + name + '=' ) ;
350
353
result += ( search ? '&' : '?' ) + ( name + '=' + encoded ) ;
@@ -525,7 +528,7 @@ Type.prototype.$asArray = function(mode, isSearch) {
525
528
function $UrlMatcherFactory ( ) {
526
529
$$UMFP = this ;
527
530
528
- var isCaseInsensitive = false , isStrictMode = true , defaultSquashPolicy = "nosquash" ;
531
+ var isCaseInsensitive = false , isStrictMode = true , defaultSquashPolicy = false ;
529
532
530
533
function valToString ( val ) { return val != null ? val . toString ( ) . replace ( "/" , "%2F" ) : val ; }
531
534
function valFromString ( val ) { return val != null ? val . toString ( ) . replace ( "%2F" , "/" ) : val ; }
@@ -631,14 +634,15 @@ function $UrlMatcherFactory() {
631
634
*
632
635
* @param {string } value A string that defines the default parameter URL squashing behavior.
633
636
* `nosquash`: When generating an href with a default parameter value, do not squash the parameter value from the URL
634
- * `value`: When generating an href with a default parameter value, squash (remove) the parameter value from the URL
635
637
* `slash`: When generating an href with a default parameter value, squash (remove) the parameter value, and, if the
636
638
* parameter is surrounded by slashes, squash (remove) one slash from the URL
639
+ * any other string, e.g. "~": When generating an href with a default parameter value, squash (remove)
640
+ * the parameter value from the URL and replace it with this string.
637
641
*/
638
642
this . defaultSquashPolicy = function ( value ) {
639
- if ( ! value ) return defaultSquashPolicy ;
640
- if ( value !== "nosquash" && value !== "value" && value !== "slash" )
641
- throw new Error ( "Invalid squash policy: " + value + ". Valid policies: 'nosquash', 'value', 'slash' " ) ;
643
+ if ( ! isDefined ( value ) ) return defaultSquashPolicy ;
644
+ if ( value !== true && value !== false && ! isString ( value ) )
645
+ throw new Error ( "Invalid squash policy: " + value + ". Valid policies: false, true, arbitrary-string " ) ;
642
646
defaultSquashPolicy = value ;
643
647
return value ;
644
648
} ;
@@ -836,7 +840,7 @@ function $UrlMatcherFactory() {
836
840
type = arrayMode ? type . $asArray ( arrayMode , isSearch ) : type ;
837
841
var isOptional = defaultValueConfig . value !== undefined ;
838
842
var squash = getSquashPolicy ( config , isOptional ) ;
839
- var emptyString = getEmptyStringValue ( config , arrayMode , isOptional ) ;
843
+ var replace = getReplace ( config , arrayMode , isOptional , squash ) ;
840
844
841
845
function getDefaultValueConfig ( config ) {
842
846
var keys = isObject ( config ) ? objectKeys ( config ) : [ ] ;
@@ -864,25 +868,26 @@ function $UrlMatcherFactory() {
864
868
}
865
869
866
870
/**
867
- * returns "nosquash", "value", "slash" to indicate the "default parameter url squash policy".
868
- * undefined aliases to urlMatcherFactory default. `false` aliases to "nosquash". `true` aliases to "slash".
871
+ * returns false, true, or the squash value to indicate the "default parameter url squash policy".
869
872
*/
870
873
function getSquashPolicy ( config , isOptional ) {
871
874
var squash = config . squash ;
872
- if ( ! isOptional || squash === false ) return "nosquash" ;
873
- if ( ! isDefined ( squash ) ) return defaultSquashPolicy ;
874
- if ( squash === true ) return "slash" ;
875
- if ( squash === "nosquash" || squash === "value" || squash === "slash" ) return squash ;
876
- throw new Error ( "Invalid squash policy: '" + squash + "'. Valid policies: 'nosquash' (false), 'value', 'slash' (true)" ) ;
875
+ if ( ! isOptional || squash === false ) return false ;
876
+ if ( ! isDefined ( squash ) || squash == null ) return defaultSquashPolicy ;
877
+ if ( squash === true || isString ( squash ) ) return squash ;
878
+ throw new Error ( "Invalid squash policy: '" + squash + "'. Valid policies: false, true, or arbitrary string" ) ;
877
879
}
878
880
879
- /**
880
- * Returns "" or undefined, or whatever is defined in the param's config.emptyString.
881
- * If the parameter was matched in a URL, but was matched as an empty string, this value will be used instead.
882
- */
883
- function getEmptyStringValue ( config , arrayMode , isOptional ) {
884
- var defaultPolicy = { emptyString : ( isOptional || arrayMode ? undefined : "" ) } ;
885
- return extend ( defaultPolicy , config ) . emptyString ;
881
+ function getReplace ( config , arrayMode , isOptional , squash ) {
882
+ var replace , configuredKeys , defaultPolicy = [
883
+ { from : "" , to : ( isOptional || arrayMode ? undefined : "" ) } ,
884
+ { from : null , to : ( isOptional || arrayMode ? undefined : "" ) }
885
+ ] ;
886
+ replace = isArray ( config . replace ) ? config . replace : [ ] ;
887
+ if ( isString ( squash ) )
888
+ replace . push ( { from : squash , to : undefined } ) ;
889
+ configuredKeys = replace . map ( function ( item ) { return item . from ; } ) ;
890
+ return defaultPolicy . filter ( function ( item ) { return configuredKeys . indexOf ( item . from ) === - 1 ; } ) . concat ( replace ) ;
886
891
}
887
892
888
893
/**
@@ -898,19 +903,24 @@ function $UrlMatcherFactory() {
898
903
* default value, which may be the result of an injectable function.
899
904
*/
900
905
function $value ( value ) {
901
- if ( value === "" ) value = self . emptyString ;
906
+ function hasReplaceVal ( val ) { return function ( obj ) { return obj . from === val ; } ; }
907
+ function $replace ( value ) {
908
+ var replacement = self . replace . filter ( hasReplaceVal ( value ) ) . map ( function ( obj ) { return obj . to ; } ) ;
909
+ return replacement . length ? replacement [ 0 ] : value ;
910
+ }
911
+ value = $replace ( value ) ;
902
912
return isDefined ( value ) ? self . type . decode ( value ) : $$getDefaultValue ( ) ;
903
913
}
904
914
905
- function toString ( ) { return "{Param:" + id + " " + type + " squash: " + squash + " optional: " + isOptional + "}" ; }
915
+ function toString ( ) { return "{Param:" + id + " " + type + " squash: ' " + squash + "' optional: " + isOptional + "}" ; }
906
916
907
917
extend ( this , {
908
918
id : id ,
909
919
type : type ,
910
920
array : arrayMode ,
911
921
config : config ,
912
922
squash : squash ,
913
- emptyString : emptyString ,
923
+ replace : replace ,
914
924
isOptional : isOptional ,
915
925
dynamic : undefined ,
916
926
value : $value ,
0 commit comments