1
- /* jshint -W084 */
2
1
var invariant = require ( 'react/lib/invariant' ) ;
3
2
var assign = require ( 'object-assign' ) ;
4
3
var qs = require ( 'qs' ) ;
5
4
5
+ var paramCompileMatcher = / : ( [ a - z A - Z _ $ ] [ a - z A - Z 0 - 9 _ $ ] * ) | [ * . ( ) \[ \] \\ + | { } ^ $ ] / g;
6
+ var paramInjectMatcher = / : ( [ a - z A - Z _ $ ] [ a - z A - Z 0 - 9 _ $ ? ] * [ ? ] ? ) | [ * ] / g;
7
+ var paramInjectTrailingSlashMatcher = / \/ \/ \? | \/ \? \/ | \/ \? / g;
6
8
var queryMatcher = / \? ( .* ) $ / ;
7
9
8
- function escapeRegExp ( string ) {
9
- return string . replace ( / [ . * + ? ^ $ { } ( ) | [ \] \\ ] / g, "\\$&" ) ;
10
- }
11
-
12
- function _compilePattern ( pattern ) {
13
- var escapedSource = '' ;
14
- var paramNames = [ ] ;
15
- var tokens = [ ] ;
16
-
17
- var match , lastIndex = 0 , matcher = / : ( [ a - z A - Z _ $ ] [ a - z A - Z 0 - 9 _ $ ] * ) | \* | \( | \) / g;
18
- while ( match = matcher . exec ( pattern ) ) {
19
- if ( match . index !== lastIndex ) {
20
- tokens . push ( pattern . slice ( lastIndex , match . index ) ) ;
21
- escapedSource += escapeRegExp ( pattern . slice ( lastIndex , match . index ) ) ;
22
- }
23
-
24
- if ( match [ 1 ] ) {
25
- escapedSource += '([^/?#]+)' ;
26
- paramNames . push ( match [ 1 ] ) ;
27
- } else if ( match [ 0 ] === '*' ) {
28
- escapedSource += '(.*?)' ;
29
- paramNames . push ( 'splat' ) ;
30
- } else if ( match [ 0 ] === '(' ) {
31
- escapedSource += '(?:' ;
32
- } else if ( match [ 0 ] === ')' ) {
33
- escapedSource += ')?' ;
34
- }
35
-
36
- tokens . push ( match [ 0 ] ) ;
37
-
38
- lastIndex = matcher . lastIndex ;
39
- }
40
-
41
- if ( lastIndex !== pattern . length ) {
42
- tokens . push ( pattern . slice ( lastIndex , pattern . length ) ) ;
43
- escapedSource += escapeRegExp ( pattern . slice ( lastIndex , pattern . length ) ) ;
44
- }
45
-
46
- return {
47
- pattern,
48
- escapedSource,
49
- paramNames,
50
- tokens
51
- } ;
52
- }
53
-
54
10
var _compiledPatterns = { } ;
55
11
56
12
function compilePattern ( pattern ) {
57
- if ( ! ( pattern in _compiledPatterns ) )
58
- _compiledPatterns [ pattern ] = _compilePattern ( pattern ) ;
13
+ if ( ! ( pattern in _compiledPatterns ) ) {
14
+ var paramNames = [ ] ;
15
+ var source = pattern . replace ( paramCompileMatcher , function ( match , paramName ) {
16
+ if ( paramName ) {
17
+ paramNames . push ( paramName ) ;
18
+ return '([^/?#]+)' ;
19
+ } else if ( match === '*' ) {
20
+ paramNames . push ( 'splat' ) ;
21
+ return '(.*?)' ;
22
+ } else {
23
+ return '\\' + match ;
24
+ }
25
+ } ) ;
26
+
27
+ _compiledPatterns [ pattern ] = {
28
+ matcher : new RegExp ( '^' + source + '$' , 'i' ) ,
29
+ paramNames : paramNames
30
+ } ;
31
+ }
59
32
60
33
return _compiledPatterns [ pattern ] ;
61
34
}
@@ -89,8 +62,7 @@ var PathUtils = {
89
62
* pattern does not match the given path.
90
63
*/
91
64
extractParams : function ( pattern , path ) {
92
- var { escapedSource, paramNames } = compilePattern ( pattern ) ;
93
- var matcher = new RegExp ( '^' + escapedSource + '$' , 'i' ) ;
65
+ var { matcher, paramNames } = compilePattern ( pattern ) ;
94
66
var match = path . match ( matcher ) ;
95
67
96
68
if ( ! match )
@@ -112,46 +84,40 @@ var PathUtils = {
112
84
injectParams : function ( pattern , params ) {
113
85
params = params || { } ;
114
86
115
- var { tokens } = compilePattern ( pattern ) ;
116
- var parenCount = 0 , pathname = '' , splatIndex = 0 ;
87
+ var splatIndex = 0 ;
117
88
118
- var token , paramName , paramValue ;
119
- for ( var i = 0 , len = tokens . length ; i < len ; ++ i ) {
120
- token = tokens [ i ] ;
89
+ return pattern . replace ( paramInjectMatcher , function ( match , paramName ) {
90
+ paramName = paramName || 'splat' ;
121
91
122
- if ( token === '*' ) {
123
- paramValue = Array . isArray ( params . splat ) ? params . splat [ splatIndex ++ ] : params . splat ;
92
+ // If param is optional don't check for existence
93
+ if ( paramName . slice ( - 1 ) === '?' ) {
94
+ paramName = paramName . slice ( 0 , - 1 ) ;
124
95
96
+ if ( params [ paramName ] == null )
97
+ return '' ;
98
+ } else {
125
99
invariant (
126
- paramValue != null || parenCount > 0 ,
127
- 'Missing splat #%s for path "%s"' ,
128
- splatIndex , pattern
100
+ params [ paramName ] != null ,
101
+ 'Missing "%s" parameter for path "%s"' ,
102
+ paramName , pattern
129
103
) ;
104
+ }
130
105
131
- if ( paramValue != null )
132
- pathname += paramValue ;
133
- } else if ( token === '(' ) {
134
- parenCount += 1 ;
135
- } else if ( token === ')' ) {
136
- parenCount -= 1 ;
137
- } else if ( token . charAt ( 0 ) === ':' ) {
138
- paramName = token . substring ( 1 ) ;
139
- paramValue = params [ paramName ] ;
106
+ var segment ;
107
+ if ( paramName === 'splat' && Array . isArray ( params [ paramName ] ) ) {
108
+ segment = params [ paramName ] [ splatIndex ++ ] ;
140
109
141
110
invariant (
142
- paramValue != null || parenCount > 0 ,
143
- 'Missing "%s" parameter for path "%s"' ,
144
- paramName , pattern
111
+ segment != null ,
112
+ 'Missing splat # %s for path "%s"' ,
113
+ splatIndex , pattern
145
114
) ;
146
-
147
- if ( paramValue != null )
148
- pathname += paramValue ;
149
115
} else {
150
- pathname += token ;
116
+ segment = params [ paramName ] ;
151
117
}
152
- }
153
118
154
- return pathname . replace ( / \/ + / g, '/' ) ;
119
+ return segment ;
120
+ } ) . replace ( paramInjectTrailingSlashMatcher , '/' ) ;
155
121
} ,
156
122
157
123
/**
0 commit comments