From 67471bf4ee4fc983d9c4628de5d80fd875c4a925 Mon Sep 17 00:00:00 2001 From: Blake Embrey Date: Sun, 29 Jun 2014 18:30:30 +1000 Subject: [PATCH 1/3] Improve repeated parameter regexp generation --- index.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/index.js b/index.js index 0f3db6b..faadd4b 100644 --- a/index.js +++ b/index.js @@ -90,11 +90,14 @@ function pathtoRegexp (path, keys, options) { return '\\' + escape; } + var repeat = suffix === '+' || suffix === '*'; + var optional = suffix === '?' || suffix === '*'; + keys.push({ name: key || index++, delimiter: prefix || '/', - optional: suffix === '?' || suffix === '*', - repeat: suffix === '+' || suffix === '*' + optional: optional, + repeat: repeat }); // Escape the prefix character. @@ -105,16 +108,13 @@ function pathtoRegexp (path, keys, options) { // prefixed with a period). capture = escapeGroup(capture || group || '[^' + (prefix || '\\/') + ']+?'); - // More complex regexp is required for suffix support. - if (suffix) { - if (suffix === '+') { - return prefix + '(' + capture + '(?:' + prefix + capture + ')*)' - } - - if (suffix === '*') { - return '(?:' + prefix + '(' + capture + '(?:' + prefix + capture + ')*|' + capture + '))?'; - } + // Allow parameters to be repeated more than once. + if (repeat) { + capture = capture + '(?:' + prefix + capture + ')*'; + } + // Allow a parameter to be optional. + if (optional) { return '(?:' + prefix + '(' + capture + '))?'; } From 54b0eced7a772e947db89f01b231d8bee57cb552 Mon Sep 17 00:00:00 2001 From: Blake Embrey Date: Sun, 6 Jul 2014 19:22:33 +1000 Subject: [PATCH 2/3] Improve path matching behaviour of non-end mode * Non-strict mode with a trailing slash will become an optional trailing slash * Only match optional slash at the end of the path (not in the middle) --- index.js | 27 +++++++++++++++------------ test.js | 49 ++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 63 insertions(+), 13 deletions(-) diff --git a/index.js b/index.js index faadd4b..143bffe 100644 --- a/index.js +++ b/index.js @@ -122,19 +122,22 @@ function pathtoRegexp (path, keys, options) { return prefix + '(' + capture + ')'; }); - if (path[path.length - 1] !== '/') { - // If we are doing a non-ending match, we need to prompt the matching groups - // to match as much as possible. To do this, we add a positive lookahead for - // the next path fragment or the end. However, if the regexp already ends - // in a path fragment, we'll run into problems. - if (!end) { - path += '(?=\\/|$)'; - } + // Check whether the path ends in a slash as it alters some match behaviour. + var endsWithSlash = path[path.length - 1] === '/'; + + // In non-strict mode we allow an optional trailing slash in the match. If + // the path to match already ended with a slash, we need to remove it for + // consistency. The slash is only valid at the very end of a path match, not + // anywhere in the middle. This is important for non-ending mode, otherwise + // "/test/" will match "/test//route". + if (!strict) { + path = (endsWithSlash ? path.slice(0, -2) : path) + '(?:\\/(?=$))?'; + } - // Allow trailing slashes to be matched in non-strict, ending mode. - if (end && !strict) { - path += '\\/?'; - } + // In non-ending mode, we need prompt the capturing groups to match as much + // as possible by using a positive lookahead for the end or next path segment. + if (!end) { + path += strict && endsWithSlash ? '' : '(?=\\/|$)'; } return new RegExp('^' + path + (end ? '$' : ''), flags); diff --git a/test.js b/test.js index ecfc833..5a150c8 100644 --- a/test.js +++ b/test.js @@ -32,6 +32,7 @@ var TESTS = [ ['/test', [], '/route', null], ['/test', [], '/test/route', null], ['/test', [], '/test/', ['/test/']], + ['/test/', [], '/test', ['/test']], ['/test/', [], '/test/', ['/test/']], ['/test/', [], '/test//', null], @@ -55,7 +56,25 @@ var TESTS = [ * Non-ending mode. */ ['/test', [], '/test', ['/test'], { end: false }], + ['/test', [], '/test/', ['/test/'], { end: false }], ['/test', [], '/test/route', ['/test'], { end: false }], + ['/test/', [], '/test/route', ['/test'], { end: false }], + ['/test/', [], '/test//', ['/test'], { end: false }], + ['/test/', [], '/test//route', ['/test'], { end: false }], + [ + '/:test', + [{ name: 'test', delimiter: '/', optional: false, repeat: false }], + '/route', + ['/route', 'route'], + { end: false } + ], + [ + '/:test/', + [{ name: 'test', delimiter: '/', optional: false, repeat: false }], + '/route', + ['/route', 'route'], + { end: false } + ], /** * Combine modes. @@ -69,6 +88,34 @@ var TESTS = [ ['/test/', [], '/test/route', ['/test/'], { end: false, strict: true }], ['/test.json', [], '/test.json', ['/test.json'], { end: false, strict: true }], ['/test.json', [], '/test.json.hbs', null, { end: false, strict: true }], + [ + '/:test', + [{ name: 'test', delimiter: '/', optional: false, repeat: false }], + '/route', + ['/route', 'route'], + { end: false, strict: true } + ], + [ + '/:test', + [{ name: 'test', delimiter: '/', optional: false, repeat: false }], + '/route/', + ['/route', 'route'], + { end: false, strict: true } + ], + [ + '/:test/', + [{ name: 'test', delimiter: '/', optional: false, repeat: false }], + '/route/', + ['/route/', 'route'], + { end: false, strict: true } + ], + [ + '/:test/', + [{ name: 'test', delimiter: '/', optional: false, repeat: false }], + '/route', + null, + { end: false, strict: true } + ], /** * Arrays of simple paths. @@ -398,7 +445,7 @@ var TESTS = [ ':test', [{ name: 'test', delimiter: '/', optional: false, repeat: false }], 'route/', - ['route', 'route'], + ['route/', 'route'], { end: false } ], From f787f0bee8d500a1484feb5e358fe93815fb8b0b Mon Sep 17 00:00:00 2001 From: Blake Embrey Date: Sun, 6 Jul 2014 19:25:42 +1000 Subject: [PATCH 3/3] 0.2.2 --- History.md | 6 ++++++ component.json | 2 +- package.json | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/History.md b/History.md index 9cce27b..aa3a949 100644 --- a/History.md +++ b/History.md @@ -1,3 +1,9 @@ +0.2.2 / 2014-07-06 +================== + + * A passed in trailing slash in non-strict mode will become optional + * In non-end mode, the optional trailing slash will only match at the end + 0.2.1 / 2014-06-11 ================== diff --git a/component.json b/component.json index f40e393..44ec822 100644 --- a/component.json +++ b/component.json @@ -1,7 +1,7 @@ { "name": "path-to-regexp", "description": "Express style path to RegExp utility", - "version": "0.2.1", + "version": "0.2.2", "keywords": [ "express", "regexp", diff --git a/package.json b/package.json index cc85474..07b28e4 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "path-to-regexp", "description": "Express style path to RegExp utility", - "version": "0.2.1", + "version": "0.2.2", "scripts": { "test": "istanbul cover node_modules/mocha/bin/_mocha -- -R spec" },