Skip to content

Commit fa36560

Browse files
committed
Added support for catch-all placeholders to keep up with core Angular
1 parent 471a26c commit fa36560

File tree

2 files changed

+23
-12
lines changed

2 files changed

+23
-12
lines changed

src/urlMatcherFactory.js

+17-12
Original file line numberDiff line numberDiff line change
@@ -5,30 +5,34 @@
55
* do not influence whether or not a URL is matched, but their values are passed through into
66
* the matched parameters returned by {@link UrlMatcher#exec exec}.
77
*
8-
* Path parameter placeholders can be specified using simple colon syntax or curly brace syntax,
9-
* which optionally allows a regular expression for the parameter to be specified:
8+
* Path parameter placeholders can be specified using simple colon/catch-all syntax or curly brace
9+
* syntax, which optionally allows a regular expression for the parameter to be specified:
1010
*
1111
* * ':' name - colon placeholder
12+
* * '*' name - catch-all placeholder
1213
* * '{' name '}' - curly placeholder
1314
* * '{' name ':' regexp '}' - curly placeholder with regexp. Should the regexp itself contain
1415
* curly braces, they must be in matched pairs or escaped with a backslash.
1516
*
1617
* Parameter names may contain only word characters (latin letters, digits, and underscore) and
17-
* must be unique within the pattern (across both path and search parameters). In the absence of
18-
* a regular expression, a path parameter matches any number of characters other than '/'.
18+
* must be unique within the pattern (across both path and search parameters). For colon
19+
* placeholders or curly placeholders without an explicit regexp, a path parameter matches any
20+
* number of characters other than '/'. For catch-all placeholders the path parameter matches
21+
* any number of characters.
1922
*
2023
* ### Examples
2124
*
2225
* * '/hello/' - Matches only if the path is exactly '/hello/'. There is no special treatment for
2326
* trailing slashes, and patterns have to match the entire path, not just a prefix.
24-
* * '/user/:id' - Matches '/user/bob' or '/user/1234!!!' or even '/user/' but not '/user'. The
25-
* second path segment will be captured as the parameter 'id'.
27+
* * '/user/:id' - Matches '/user/bob' or '/user/1234!!!' or even '/user/' but not '/user' or
28+
* '/user/bob/details'. The second path segment will be captured as the parameter 'id'.
2629
* * '/user/{id}' - Same as the previous example, but using curly brace syntax.
2730
* * '/user/{id:[^/]*}' - Same as the previous example.
2831
* * '/user/{id:[0-9a-fA-F]{1,8}}' - Similar to the previous example, but only matches if the id
2932
* parameter consists of 1 to 8 hex digits.
3033
* * '/files/{path:.*}' - Matches any URL starting with '/files/' and captures the rest of the
3134
* path into the parameter 'path'.
35+
* * '/files/*path' - ditto.
3236
*
3337
* @constructor
3438
* @param {string} pattern the pattern to compile into a matcher.
@@ -39,19 +43,20 @@
3943
*/
4044
function UrlMatcher(pattern) {
4145

42-
// Find all placeholders and create a compiled pattern, using either colon or curly syntax:
46+
// Find all placeholders and create a compiled pattern, using either classic or curly syntax:
47+
// '*' name
4348
// ':' name
4449
// '{' name '}'
4550
// '{' name ':' regexp '}'
4651
// The regular expression is somewhat complicated due to the need to allow curly braces
4752
// inside the regular expression. The placeholder regexp breaks down as follows:
48-
// :(\w+) colon placeholder ($1)
49-
// \{(\w+)(?:\:( ... ))?\} curly brace placeholder ($2) with optional regexp ... ($3)
53+
// ([:*])(\w+) classic placeholder ($1 / $2)
54+
// \{(\w+)(?:\:( ... ))?\} curly brace placeholder ($3) with optional regexp ... ($4)
5055
// (?: ... | ... | ... )+ the regexp consists of any number of atoms, an atom being either
5156
// [^{}\\]+ - anything other than curly braces or backslash
5257
// \\. - a backslash escape
5358
// \{(?:[^{}\\]+|\\.)*\} - a matched set of curly braces containing other atoms
54-
var placeholder = /:(\w+)|\{(\w+)(?:\:((?:[^{}\\]+|\\.|\{(?:[^{}\\]+|\\.)*\})+))?\}/g,
59+
var placeholder = /([:*])(\w+)|\{(\w+)(?:\:((?:[^{}\\]+|\\.|\{(?:[^{}\\]+|\\.)*\})+))?\}/g,
5560
names = {}, compiled = '^', last = 0, m,
5661
segments = this.segments = [],
5762
params = this.params = [];
@@ -73,8 +78,8 @@ function UrlMatcher(pattern) {
7378
// The number of segments is always 1 more than the number of parameters.
7479
var id, regexp, segment;
7580
while ((m = placeholder.exec(pattern))) {
76-
id = m[1] || m[2]; // IE[78] returns '' for unmatched groups instead of null
77-
regexp = m[3] || '[^/]*';
81+
id = m[2] || m[3]; // IE[78] returns '' for unmatched groups instead of null
82+
regexp = m[4] || (m[1] == '*' ? '.*' : '[^/]*');
7883
segment = pattern.substring(last, m.index);
7984
if (segment.indexOf('?') >= 0) break; // we're into the search part
8085
compiled += quoteRegExp(segment) + '(' + regexp + ')';

test/urlMatcherFactorySpec.js

+6
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@ describe("UrlMatcher", function () {
2727
.toEqual({ id:'123', type:'', repeat:'0' });
2828
});
2929

30+
it(".exec() captures catch-all parameters", function () {
31+
var m = new UrlMatcher('/document/*path');
32+
expect(m.exec('/document/a/b/c', {})).toEqual({ path: 'a/b/c' });
33+
expect(m.exec('/document/', {})).toEqual({ path: '' });
34+
});
35+
3036
it(".exec() uses the optional regexp with curly brace placeholders", function () {
3137
expect(
3238
new UrlMatcher('/users/:id/details/{type}/{repeat:[0-9]+}?from&to')

0 commit comments

Comments
 (0)