From b61d76d7cc058e750e646b4ef9f2ce8518067c53 Mon Sep 17 00:00:00 2001 From: Ben Youngblood Date: Wed, 25 Jun 2014 15:23:51 -0700 Subject: [PATCH 1/5] ability to specify regex constraints for parameters --- modules/components/Route.js | 8 +++++--- modules/helpers/Path.js | 10 +++++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/modules/components/Route.js b/modules/components/Route.js index 06f99442b8..1c5633fb83 100644 --- a/modules/components/Route.js +++ b/modules/components/Route.js @@ -24,7 +24,7 @@ var RESERVED_PROPS = { /** * 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 @@ -250,7 +250,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)) { @@ -275,7 +277,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) ]; diff --git a/modules/helpers/Path.js b/modules/helpers/Path.js index 469b1b1b08..0587245155 100644 --- a/modules/helpers/Path.js +++ b/modules/helpers/Path.js @@ -39,7 +39,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 === decodeURIComponent(path)) return {}; // No dynamic segments, but the paths match. @@ -53,13 +53,17 @@ var Path = { if (!match) return null; - var params = {}; + var params = {}, + constraintsPassed = true; compiled.paramNames.forEach(function (paramName, index) { + if (constraints[paramName] && ! constraints[paramName].test(match[index + 1])) + constraintsPassed = false; + params[paramName] = match[index + 1]; }); - return params; + return constraintsPassed ? params : null; }, /** From cbbdead3a2216039f20b19521fe219cfad547eed Mon Sep 17 00:00:00 2001 From: Ben Youngblood Date: Thu, 26 Jun 2014 08:23:13 -0700 Subject: [PATCH 2/5] refactor param constraints to be cleaner --- modules/helpers/Path.js | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/modules/helpers/Path.js b/modules/helpers/Path.js index 0587245155..a6311e9596 100644 --- a/modules/helpers/Path.js +++ b/modules/helpers/Path.js @@ -53,17 +53,34 @@ var Path = { if (!match) return null; - var params = {}, - constraintsPassed = true; + var params = {}; compiled.paramNames.forEach(function (paramName, index) { - if (constraints[paramName] && ! constraints[paramName].test(match[index + 1])) - constraintsPassed = false; - params[paramName] = match[index + 1]; }); - return constraintsPassed ? params : null; + if (this.testConstraints(params, constraints)) { + return params; + } + + return null; + }, + + testConstraints: function (params, constraints) { + var pass = true; + + if (! constraints || constraints === {}) + return true; + + Object.keys(params).forEach(function(param) { + if (constraints[param]) { + if (! constraints[param].test(params[param])) { + pass = false; + } + } + }); + + return pass; }, /** From 3d856b6c30734e3cc68c8f2a57784c5b18ecc741 Mon Sep 17 00:00:00 2001 From: Ben Youngblood Date: Thu, 26 Jun 2014 08:23:49 -0700 Subject: [PATCH 3/5] more tests for constraints --- specs/Path.spec.js | 49 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/specs/Path.spec.js b/specs/Path.spec.js index 122ad18d81..173a871591 100644 --- a/specs/Path.spec.js +++ b/specs/Path.spec.js @@ -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 () { @@ -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); }); }); @@ -182,3 +199,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); + }); +}); From 920e14b8a3491e8af06668f6d7ee38952bd6c86b Mon Sep 17 00:00:00 2001 From: Ben Youngblood Date: Fri, 27 Jun 2014 15:31:39 -0700 Subject: [PATCH 4/5] remove unreachable code --- modules/helpers/Path.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/modules/helpers/Path.js b/modules/helpers/Path.js index a6311e9596..0881be734d 100644 --- a/modules/helpers/Path.js +++ b/modules/helpers/Path.js @@ -69,9 +69,6 @@ var Path = { testConstraints: function (params, constraints) { var pass = true; - if (! constraints || constraints === {}) - return true; - Object.keys(params).forEach(function(param) { if (constraints[param]) { if (! constraints[param].test(params[param])) { From 5fa0f989726cca524875143fe3370e87daf034be Mon Sep 17 00:00:00 2001 From: Ben Youngblood Date: Tue, 1 Jul 2014 11:11:49 -0700 Subject: [PATCH 5/5] check constraints are passed in (to fix tests) --- modules/helpers/Path.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/helpers/Path.js b/modules/helpers/Path.js index afd2de730f..93bb7dbd61 100644 --- a/modules/helpers/Path.js +++ b/modules/helpers/Path.js @@ -71,6 +71,10 @@ var Path = { 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])) {