Skip to content

Parameter constraints #52

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions modules/components/Route.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ var RESERVED_PROPS = {
/**
* <Route> components specify components that are rendered to the page when the
* URL matches a given pattern.
*
*
* Routes are arranged in a nested tree structure. When a new URL is requested,
* the tree is searched depth-first to find a route whose path matches the URL.
* When one is found, all routes in the tree that lead to it are considered
Expand Down Expand Up @@ -251,7 +251,9 @@ function Redirect(to, params, query) {
}

function findMatches(path, route) {
var children = route.props.children, matches;
var children = route.props.children,
constraints = route.props.constraints || {},
matches;

// Check the subtree first to find the most deeply-nested match.
if (Array.isArray(children)) {
Expand All @@ -276,7 +278,7 @@ function findMatches(path, route) {
}

// No routes in the subtree matched, so check this route.
var params = Path.extractParams(route.props.path, path);
var params = Path.extractParams(route.props.path, path, constraints);

if (params)
return [ makeMatch(route, params) ];
Expand Down
26 changes: 24 additions & 2 deletions modules/helpers/Path.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ var Path = {
* and returns an object of param name => value pairs. Returns null if the
* pattern does not match the given path.
*/
extractParams: function (pattern, path) {
extractParams: function (pattern, path, constraints) {
if (!isDynamicPattern(pattern)) {
if (pattern === urlDecode(path))
return {}; // No dynamic segments, but the paths match.
Expand All @@ -61,7 +61,29 @@ var Path = {
params[paramName] = match[index + 1];
});

return params;
if (this.testConstraints(params, constraints)) {
return params;
}

return null;
},

testConstraints: function (params, constraints) {
var pass = true;

if (! constraints) {
return true;
}

Object.keys(params).forEach(function(param) {
if (constraints[param]) {
if (! constraints[param].test(params[param])) {
pass = false;
}
}
});

return pass;
},

/**
Expand Down
49 changes: 48 additions & 1 deletion specs/Path.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,23 @@ describe('Path.extractParams', function () {
});
});
});

describe('when a pattern has dynamic segments with constraints', function() {
var pattern = '/comments/:id/edit',
constraints = {
id : /\d+/
};

describe('and the constraints match', function() {
expect(Path.extractParams(pattern, '/comments/123/edit', constraints))
.toEqual({ id : 123 });
});

describe('and the constraints do not match', function() {
expect(Path.extractParams(pattern, '/comments/abc/edit', constraints))
.toBe(null);
});
});
});

describe('Path.extractParamNames', function () {
Expand Down Expand Up @@ -118,7 +135,7 @@ describe('Path.injectParams', function () {
describe('and a param is missing', function () {
it('throws an Error', function () {
expect(function () {
Path.injectParams(pattern, {})
Path.injectParams(pattern, {});
}).toThrow(Error);
});
});
Expand Down Expand Up @@ -186,3 +203,33 @@ describe('Path.normalize', function () {
});
});
});

describe('Path.testConstraints', function () {
it('returns false when one or more constraints fail', function () {
var params = {
id : 123,
name : 'Abc'
};

var constraints = {
id : /^\d+$/,
name : /^[a-z]+$/
};

expect(Path.testConstraints(params, constraints)).toBe(false);
});

it('returns true when constraints pass', function () {
var params = {
id : 123,
name : 'Abc'
};

var constraints = {
id : /^\d+$/,
name : /^[A-Za-z]+$/
};

expect(Path.testConstraints(params, constraints)).toBe(true);
});
});