diff --git a/index.js b/index.js index 7ad98c6..6bab4ac 100644 --- a/index.js +++ b/index.js @@ -31,6 +31,7 @@ function pathtoRegexp(path, keys, options) { var strict = options.strict; var end = options.end !== false; var flags = options.sensitive ? '' : 'i'; + var lookahead = options.lookahead !== false; var extraOffset = 0; var keysOffset = keys.length; var i = 0; @@ -123,7 +124,11 @@ function pathtoRegexp(path, keys, options) { } // If the path is non-ending, match until the end or a slash. - path += (end ? '$' : (path[path.length - 1] === '/' ? '' : '(?=\\/|$)')); + if (end) { + path += '$'; + } else if (path[path.length - 1] !== '/') { + path += lookahead ? '(?=\\/|$)' : '(?:\/|$)'; + } return new RegExp(path, flags); }; diff --git a/test.js b/test.js index 412cff9..9023fe7 100644 --- a/test.js +++ b/test.js @@ -527,6 +527,19 @@ describe('path-to-regexp', function () { assert.equal(m[1], 'test'); }); + it('should do non-ending matches (no lookahead)', function () { + var params = []; + var m = pathToRegExp('/:test', params, { end: false, lookahead: false }).exec('/test/route'); + + assert.equal(params.length, 1); + assert.equal(params[0].name, 'test'); + assert.equal(params[0].optional, false); + + assert.equal(m.length, 2); + assert.equal(m[0], '/test/'); + assert.equal(m[1], 'test'); + }); + it('should match trailing slashes in non-ending non-strict mode', function () { var params = []; var re = pathToRegExp('/:test', params, { end: false }); @@ -571,6 +584,34 @@ describe('path-to-regexp', function () { assert.equal(m[0], '/route/'); }); + it('should match trailing slashes in non-ending non-strict mode (no lookahead)', function () { + var params = []; + var re = pathToRegExp('/route/', params, { end: false, lookahead: false }); + var m; + + assert.equal(params.length, 0); + + m = re.exec('/route/'); + + assert.equal(m.length, 1); + assert.equal(m[0], '/route/'); + + m = re.exec('/route/test'); + + assert.equal(m.length, 1); + assert.equal(m[0], '/route/'); + + m = re.exec('/route'); + + assert.equal(m.length, 1); + assert.equal(m[0], '/route'); + + m = re.exec('/route//'); + + assert.equal(m.length, 1); + assert.equal(m[0], '/route//'); + }); + it('should match trailing slashing in non-ending strict mode', function () { var params = []; var re = pathToRegExp('/route/', params, { end: false, strict: true }); @@ -616,6 +657,24 @@ describe('path-to-regexp', function () { assert.equal(m[0], '/route'); }); + it('should not match trailing slashes in non-ending strict mode (no lookahead)', function () { + var params = []; + var re = pathToRegExp('/route', params, { end: false, strict: true, lookahead: false }); + var m; + + assert.equal(params.length, 0); + + m = re.exec('/route'); + + assert.equal(m.length, 1); + assert.equal(m[0], '/route'); + + m = re.exec('/route/'); + + assert.ok(m.length, 1); + assert.equal(m[0], '/route/'); + }); + it('should match text after an express param', function () { var params = []; var re = pathToRegExp('/(:test)route', params); @@ -728,6 +787,12 @@ describe('path-to-regexp', function () { }); it('should pull out matching named groups', function () { + const majorVersion = Number(process.version.split('.')[0].replace('v', '')); + if (majorVersion < 10) { + console.log('skipping test: node <10 does not support named capture groups'); + return; + } + var params = []; var re = pathToRegExp(/\/(.*)\/(?.*)\/(.*)/, params); var m;