From 6725fa7316d60a5b0902ce3dade6237d5d04b5ce Mon Sep 17 00:00:00 2001 From: Susisu Date: Mon, 20 Aug 2018 16:02:28 +0900 Subject: [PATCH 1/2] fix(ngRoute): extract path params containing hashes and/or question marks correctly The `routeToRegExp` function introduced by 840b5f0 could not extract path params containing hashes and/or question marks from `$location.path()`. Since ngMock and ngRoute deal with different subjects (encoded url for ngMock and decoded path for ngRoute), this commit (re-)introduce separate function for each case. --- angularFiles.js | 2 -- src/ngMock/angular-mocks.js | 43 +++++++++++++++++++++++++++--- src/ngRoute/route.js | 44 ++++++++++++++++++++++++++++--- src/routeToRegExp.js | 46 --------------------------------- test/ngRoute/routeParamsSpec.js | 19 ++++++++++++++ 5 files changed, 99 insertions(+), 55 deletions(-) delete mode 100644 src/routeToRegExp.js diff --git a/angularFiles.js b/angularFiles.js index 6c4bcab00cec..4640f1784650 100644 --- a/angularFiles.js +++ b/angularFiles.js @@ -134,7 +134,6 @@ var angularFiles = { ], 'ngRoute': [ 'src/shallowCopy.js', - 'src/routeToRegExp.js', 'src/ngRoute/route.js', 'src/ngRoute/routeParams.js', 'src/ngRoute/directive/ngView.js' @@ -144,7 +143,6 @@ var angularFiles = { 'src/ngSanitize/filter/linky.js' ], 'ngMock': [ - 'src/routeToRegExp.js', 'src/ngMock/angular-mocks.js', 'src/ngMock/browserTrigger.js' ], diff --git a/src/ngMock/angular-mocks.js b/src/ngMock/angular-mocks.js index f6e5cce71e96..6bc18598acf6 100644 --- a/src/ngMock/angular-mocks.js +++ b/src/ngMock/angular-mocks.js @@ -1,7 +1,5 @@ 'use strict'; -/* global routeToRegExp: false */ - /** * @ngdoc object * @name angular.mock @@ -1771,10 +1769,47 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) { * See {@link ngMock.$httpBackend#when `when`} for more info. */ $httpBackend.whenRoute = function(method, url) { - var pathObj = routeToRegExp(url, {caseInsensitiveMatch: true, ignoreTrailingSlashes: true}); + var pathObj = parseRoute(url); return $httpBackend.when(method, pathObj.regexp, undefined, undefined, pathObj.keys); }; + /** + * @param url {string} url + * @return {?Object} + * + * @description + * Normalizes the given url, returning a regular expression. + * + * Inspired by pathRexp in visionmedia/express/lib/utils.js. + */ + function parseRoute(url) { + var keys = []; + + var pattern = url + .replace(/([().])/g, '\\$1') + .replace(/(\/)?:(\w+)(\*\?|[?*])?/g, function(_, slash, key, option) { + var optional = option === '?' || option === '*?'; + var star = option === '*' || option === '*?'; + keys.push({ name: key, optional: optional }); + slash = slash || ''; + return ( + (optional ? '(?:' + slash : slash + '(?:') + + (star ? '([^?#]+?)' : '([^/?#]+)') + + (optional ? '?)?' : ')') + ); + }) + .replace(/([/$*])/g, '\\$1') + .replace(/\/+$/, '') + '/*'; + + return { + keys: keys, + regexp: new RegExp( + '^' + pattern + '(?:[?#]|$)', + 'i' + ) + }; + } + /** * @ngdoc method * @name $httpBackend#expect @@ -1955,7 +1990,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) { * See {@link ngMock.$httpBackend#expect `expect`} for more info. */ $httpBackend.expectRoute = function(method, url) { - var pathObj = routeToRegExp(url, {caseInsensitiveMatch: true, ignoreTrailingSlashes: true}); + var pathObj = parseRoute(url); return $httpBackend.expect(method, pathObj.regexp, undefined, undefined, pathObj.keys); }; diff --git a/src/ngRoute/route.js b/src/ngRoute/route.js index 706600a5bdeb..91cc1a621dac 100644 --- a/src/ngRoute/route.js +++ b/src/ngRoute/route.js @@ -1,6 +1,5 @@ 'use strict'; -/* global routeToRegExp: false */ /* global shallowCopy: false */ // `isArray` and `isObject` are necessary for `shallowCopy()` (included via `src/shallowCopy.js`). @@ -225,7 +224,7 @@ function $RouteProvider() { } routes[path] = angular.extend( routeCopy, - path && routeToRegExp(path, routeCopy) + path && pathRegExp(path, routeCopy) ); // create redirection for trailing slashes @@ -236,7 +235,7 @@ function $RouteProvider() { routes[redirectPath] = angular.extend( {redirectTo: path}, - routeToRegExp(redirectPath, routeCopy) + pathRegExp(redirectPath, routeCopy) ); } @@ -254,6 +253,45 @@ function $RouteProvider() { */ this.caseInsensitiveMatch = false; + /** + * @param path {string} path + * @param opts {Object} options + * @return {?Object} + * + * @description + * Normalizes the given path, returning a regular expression + * and the original path. + * + * Inspired by pathRexp in visionmedia/express/lib/utils.js. + */ + function pathRegExp(path, opts) { + var keys = []; + + var pattern = path + .replace(/([().])/g, '\\$1') + .replace(/(\/)?:(\w+)(\*\?|[?*])?/g, function(_, slash, key, option) { + var optional = option === '?' || option === '*?'; + var star = option === '*' || option === '*?'; + keys.push({ name: key, optional: optional }); + slash = slash || ''; + return ( + (optional ? '(?:' + slash : slash + '(?:') + + (star ? '(.+?)' : '([^/]+)') + + (optional ? '?)?' : ')') + ); + }) + .replace(/([/$*])/g, '\\$1'); + + return { + originalPath: path, + keys: keys, + regexp: new RegExp( + '^' + pattern + '(?:[?#]|$)', + opts.caseInsensitiveMatch ? 'i' : '' + ) + }; + } + /** * @ngdoc method * @name $routeProvider#otherwise diff --git a/src/routeToRegExp.js b/src/routeToRegExp.js deleted file mode 100644 index ea0b94efe7f3..000000000000 --- a/src/routeToRegExp.js +++ /dev/null @@ -1,46 +0,0 @@ -'use strict'; - -/* global routeToRegExp: true */ - -/** - * @param path {string} path - * @param opts {Object} options - * @return {?Object} - * - * @description - * Normalizes the given path, returning a regular expression - * and the original path. - * - * Inspired by pathRexp in visionmedia/express/lib/utils.js. - */ -function routeToRegExp(path, opts) { - var keys = []; - - var pattern = path - .replace(/([().])/g, '\\$1') - .replace(/(\/)?:(\w+)(\*\?|[?*])?/g, function(_, slash, key, option) { - var optional = option === '?' || option === '*?'; - var star = option === '*' || option === '*?'; - keys.push({ name: key, optional: optional }); - slash = slash || ''; - return ( - (optional ? '(?:' + slash : slash + '(?:') + - (star ? '([^?#]+?)' : '([^/?#]+)') + - (optional ? '?)?' : ')') - ); - }) - .replace(/([/$*])/g, '\\$1'); - - if (opts.ignoreTrailingSlashes) { - pattern = pattern.replace(/\/+$/, '') + '/*'; - } - - return { - originalPath: path, - keys: keys, - regexp: new RegExp( - '^' + pattern + '(?:[?#]|$)', - opts.caseInsensitiveMatch ? 'i' : '' - ) - }; -} diff --git a/test/ngRoute/routeParamsSpec.js b/test/ngRoute/routeParamsSpec.js index e3357fee8152..6d4f416489f2 100644 --- a/test/ngRoute/routeParamsSpec.js +++ b/test/ngRoute/routeParamsSpec.js @@ -77,5 +77,24 @@ describe('$routeParams', function() { }); }); + it('should correctly extract path params containing hashes and/or question marks', function() { + module(function($routeProvider) { + $routeProvider.when('/foo/:bar', {}); + }); + + inject(function($rootScope, $route, $location, $routeParams) { + $location.path('/foo/bar#baz'); + $rootScope.$digest(); + expect($routeParams).toEqual({bar: 'bar#baz'}); + + $location.path('/foo/bar?baz'); + $rootScope.$digest(); + expect($routeParams).toEqual({bar: 'bar?baz'}); + + $location.path('/foo/bar#baz?qux'); + $rootScope.$digest(); + expect($routeParams).toEqual({bar: 'bar#baz?qux'}); + }); + }); }); From b07c80afe563ea96ed0a458a5626793d85ef8f32 Mon Sep 17 00:00:00 2001 From: Susisu Date: Tue, 21 Aug 2018 10:19:45 +0900 Subject: [PATCH 2/2] refactor(ngRoute): add `isUrl` option to routeToRegExp and remove `pathRegExp` and `parseRoute` --- angularFiles.js | 2 ++ src/ngMock/angular-mocks.js | 43 ++++------------------------------ src/ngRoute/route.js | 44 +++-------------------------------- src/routeToRegExp.js | 46 +++++++++++++++++++++++++++++++++++++ 4 files changed, 55 insertions(+), 80 deletions(-) create mode 100644 src/routeToRegExp.js diff --git a/angularFiles.js b/angularFiles.js index 4640f1784650..6c4bcab00cec 100644 --- a/angularFiles.js +++ b/angularFiles.js @@ -134,6 +134,7 @@ var angularFiles = { ], 'ngRoute': [ 'src/shallowCopy.js', + 'src/routeToRegExp.js', 'src/ngRoute/route.js', 'src/ngRoute/routeParams.js', 'src/ngRoute/directive/ngView.js' @@ -143,6 +144,7 @@ var angularFiles = { 'src/ngSanitize/filter/linky.js' ], 'ngMock': [ + 'src/routeToRegExp.js', 'src/ngMock/angular-mocks.js', 'src/ngMock/browserTrigger.js' ], diff --git a/src/ngMock/angular-mocks.js b/src/ngMock/angular-mocks.js index 6bc18598acf6..e7f78fcccdbc 100644 --- a/src/ngMock/angular-mocks.js +++ b/src/ngMock/angular-mocks.js @@ -1,5 +1,7 @@ 'use strict'; +/* global routeToRegExp: false */ + /** * @ngdoc object * @name angular.mock @@ -1769,47 +1771,10 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) { * See {@link ngMock.$httpBackend#when `when`} for more info. */ $httpBackend.whenRoute = function(method, url) { - var pathObj = parseRoute(url); + var pathObj = routeToRegExp(url, {caseInsensitiveMatch: true, ignoreTrailingSlashes: true, isUrl: true}); return $httpBackend.when(method, pathObj.regexp, undefined, undefined, pathObj.keys); }; - /** - * @param url {string} url - * @return {?Object} - * - * @description - * Normalizes the given url, returning a regular expression. - * - * Inspired by pathRexp in visionmedia/express/lib/utils.js. - */ - function parseRoute(url) { - var keys = []; - - var pattern = url - .replace(/([().])/g, '\\$1') - .replace(/(\/)?:(\w+)(\*\?|[?*])?/g, function(_, slash, key, option) { - var optional = option === '?' || option === '*?'; - var star = option === '*' || option === '*?'; - keys.push({ name: key, optional: optional }); - slash = slash || ''; - return ( - (optional ? '(?:' + slash : slash + '(?:') + - (star ? '([^?#]+?)' : '([^/?#]+)') + - (optional ? '?)?' : ')') - ); - }) - .replace(/([/$*])/g, '\\$1') - .replace(/\/+$/, '') + '/*'; - - return { - keys: keys, - regexp: new RegExp( - '^' + pattern + '(?:[?#]|$)', - 'i' - ) - }; - } - /** * @ngdoc method * @name $httpBackend#expect @@ -1990,7 +1955,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) { * See {@link ngMock.$httpBackend#expect `expect`} for more info. */ $httpBackend.expectRoute = function(method, url) { - var pathObj = parseRoute(url); + var pathObj = routeToRegExp(url, {caseInsensitiveMatch: true, ignoreTrailingSlashes: true, isUrl: true}); return $httpBackend.expect(method, pathObj.regexp, undefined, undefined, pathObj.keys); }; diff --git a/src/ngRoute/route.js b/src/ngRoute/route.js index 91cc1a621dac..706600a5bdeb 100644 --- a/src/ngRoute/route.js +++ b/src/ngRoute/route.js @@ -1,5 +1,6 @@ 'use strict'; +/* global routeToRegExp: false */ /* global shallowCopy: false */ // `isArray` and `isObject` are necessary for `shallowCopy()` (included via `src/shallowCopy.js`). @@ -224,7 +225,7 @@ function $RouteProvider() { } routes[path] = angular.extend( routeCopy, - path && pathRegExp(path, routeCopy) + path && routeToRegExp(path, routeCopy) ); // create redirection for trailing slashes @@ -235,7 +236,7 @@ function $RouteProvider() { routes[redirectPath] = angular.extend( {redirectTo: path}, - pathRegExp(redirectPath, routeCopy) + routeToRegExp(redirectPath, routeCopy) ); } @@ -253,45 +254,6 @@ function $RouteProvider() { */ this.caseInsensitiveMatch = false; - /** - * @param path {string} path - * @param opts {Object} options - * @return {?Object} - * - * @description - * Normalizes the given path, returning a regular expression - * and the original path. - * - * Inspired by pathRexp in visionmedia/express/lib/utils.js. - */ - function pathRegExp(path, opts) { - var keys = []; - - var pattern = path - .replace(/([().])/g, '\\$1') - .replace(/(\/)?:(\w+)(\*\?|[?*])?/g, function(_, slash, key, option) { - var optional = option === '?' || option === '*?'; - var star = option === '*' || option === '*?'; - keys.push({ name: key, optional: optional }); - slash = slash || ''; - return ( - (optional ? '(?:' + slash : slash + '(?:') + - (star ? '(.+?)' : '([^/]+)') + - (optional ? '?)?' : ')') - ); - }) - .replace(/([/$*])/g, '\\$1'); - - return { - originalPath: path, - keys: keys, - regexp: new RegExp( - '^' + pattern + '(?:[?#]|$)', - opts.caseInsensitiveMatch ? 'i' : '' - ) - }; - } - /** * @ngdoc method * @name $routeProvider#otherwise diff --git a/src/routeToRegExp.js b/src/routeToRegExp.js new file mode 100644 index 000000000000..d8edd4706359 --- /dev/null +++ b/src/routeToRegExp.js @@ -0,0 +1,46 @@ +'use strict'; + +/* global routeToRegExp: true */ + +/** + * @param pathOrUrl {string} path or url + * @param opts {Object} options + * @return {?Object} + * + * @description + * Normalizes the given path, returning a regular expression + * and the original path. + * + * Inspired by pathRexp in visionmedia/express/lib/utils.js. + */ +function routeToRegExp(pathOrUrl, opts) { + var keys = []; + + var pattern = pathOrUrl + .replace(/([().])/g, '\\$1') + .replace(/(\/)?:(\w+)(\*\?|[?*])?/g, function(_, slash, key, option) { + var optional = option === '?' || option === '*?'; + var star = option === '*' || option === '*?'; + keys.push({ name: key, optional: optional }); + slash = slash || ''; + return ( + (optional ? '(?:' + slash : slash + '(?:') + + (opts.isUrl ? (star ? '([^?#]+?)' : '([^/?#]+)') : (star ? '(.+?)' : '([^/]+)')) + + (optional ? '?)?' : ')') + ); + }) + .replace(/([/$*])/g, '\\$1'); + + if (opts.ignoreTrailingSlashes) { + pattern = pattern.replace(/\/+$/, '') + '/*'; + } + + return { + originalPath: pathOrUrl, + keys: keys, + regexp: new RegExp( + '^' + pattern + '(?:[?#]|$)', + opts.caseInsensitiveMatch ? 'i' : '' + ) + }; +} pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy