Skip to content

Commit

Permalink
feat(UrlMatcher): implement non-strict matching
Browse files Browse the repository at this point in the history
Implements strict (and non-strict) matching, for configuring whether UrlMatchers should treat URLs with and without trailing slashes identically.
  • Loading branch information
nateabele committed Apr 16, 2014
1 parent ad07a8d commit a3e2136
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 8 deletions.
33 changes: 27 additions & 6 deletions src/urlMatcherFactory.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ function UrlMatcher(pattern, config) {
this.sourceSearch = '';
}

compiled += quoteRegExp(segment) + '$';
compiled += quoteRegExp(segment) + (config.strict === false ? '\/?' : '') + '$';
segments.push(segment);

this.regexp = new RegExp(compiled, config.caseInsensitive ? 'i' : undefined);
Expand Down Expand Up @@ -346,7 +346,7 @@ Type.prototype.pattern = /.*/;
*/
function $UrlMatcherFactory() {

var isCaseInsensitive = false;
var isCaseInsensitive = false, isStrictMode = true;

var enqueue = true, typeQueue = [], injector, defaultTypes = {
int: {
Expand Down Expand Up @@ -392,20 +392,41 @@ function $UrlMatcherFactory() {
}
};

function getDefaultConfig() {
return {
strict: isStrictMode,
caseInsensitive: isCaseInsensitive
};
}

/**
* @ngdoc function
* @name ui.router.util.$urlMatcherFactory#caseInsensitive
* @methodOf ui.router.util.$urlMatcherFactory
*
* @description
* Define if url matching should be case sensistive, the default behavior, or not.
*
* @param {bool} value false to match URL in a case sensitive manner; otherwise true;
* Defines whether URL matching should be case sensitive (the default behavior), or not.
*
* @param {bool} value `false` to match URL in a case sensitive manner; otherwise `true`;
*/
this.caseInsensitive = function(value) {
isCaseInsensitive = value;
};

/**
* @ngdoc function
* @name ui.router.util.$urlMatcherFactory#strictMode
* @methodOf ui.router.util.$urlMatcherFactory
*
* @description
* Defines whether URLs should match trailing slashes, or not (the default behavior).
*
* @param {bool} value `false` to match trailing slashes in URLs, otherwise `true`.
*/
this.strictMode = function(value) {
isStrictMode = value;
};

/**
* @ngdoc function
* @name ui.router.util.$urlMatcherFactory#compile
Expand All @@ -419,7 +440,7 @@ function $UrlMatcherFactory() {
* @returns {ui.router.util.type:UrlMatcher} The UrlMatcher.
*/
this.compile = function (pattern, config) {
return new UrlMatcher(pattern, extend({ caseInsensitive: isCaseInsensitive }, config));
return new UrlMatcher(pattern, extend(getDefaultConfig(), config));
};

/**
Expand Down
58 changes: 56 additions & 2 deletions test/urlMatcherFactorySpec.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,37 @@
describe("UrlMatcher", function () {

it("shoudl match static URLs", function () {
describe("provider", function () {

var provider;

beforeEach(function() {
angular.module('ui.router.router.test', function() {}).config(function ($urlMatcherFactoryProvider) {
provider = $urlMatcherFactoryProvider;
});

module('ui.router.router', 'ui.router.router.test');

inject(function($injector) {
$injector.invoke(provider.$get);
});
});

it("should factory matchers with correct configuration", function () {
provider.caseInsensitive(false);
expect(provider.compile('/hello').exec('/HELLO')).toBeNull();

provider.caseInsensitive(true);
expect(provider.compile('/hello').exec('/HELLO')).toEqual({});

provider.strictMode(true);
expect(provider.compile('/hello').exec('/hello/')).toBeNull();

provider.strictMode(false);
expect(provider.compile('/hello').exec('/hello/')).toEqual({});
});
});

it("should match static URLs", function () {
expect(new UrlMatcher('/hello/world').exec('/hello/world')).toEqual({});
});

Expand All @@ -14,7 +45,7 @@ describe("UrlMatcher", function () {
expect(matcher.exec('/hello/world/suffix')).toBeNull();
});

it("shoudl parse parameter placeholders", function () {
it("should parse parameter placeholders", function () {
var matcher = new UrlMatcher('/users/:id/details/{type}/{repeat:[0-9]+}?from&to');
var params = matcher.parameters();
expect(params.length).toBe(5);
Expand Down Expand Up @@ -267,4 +298,27 @@ describe("urlMatcherFactory", function () {
});
});
});

describe("strict matching", function() {
it("should match with or without trailing slash", function() {
var m = new UrlMatcher('/users', { strict: false });
expect(m.exec('/users')).toEqual({});
expect(m.exec('/users/')).toEqual({});
});

it("should not match multiple trailing slashes", function() {
var m = new UrlMatcher('/users', { strict: false });
expect(m.exec('/users//')).toBeNull();
});

it("should match when defined with parameters", function() {
var m = new UrlMatcher('/users/{name}', { strict: false, params: {
name: { value: null }
}});
expect(m.exec('/users/')).toEqual({ name: null });
expect(m.exec('/users/bob')).toEqual({ name: "bob" });
expect(m.exec('/users/bob/')).toEqual({ name: "bob" });
expect(m.exec('/users/bob//')).toBeNull();
});
});
});

0 comments on commit a3e2136

Please sign in to comment.