From 450b1f0e8e03c738174ff967f688b9a6373290f4 Mon Sep 17 00:00:00 2001 From: Nate Abele Date: Wed, 26 Mar 2014 09:59:04 -0400 Subject: [PATCH] feat($urlMatcherFactory): implement type support --- src/urlMatcherFactory.js | 171 +++++++++++++++++++++------- test/urlMatcherFactorySpec.js | 206 ++++++++++++++++++++-------------- 2 files changed, 249 insertions(+), 128 deletions(-) diff --git a/src/urlMatcherFactory.js b/src/urlMatcherFactory.js index 542c75a03..0a272e501 100644 --- a/src/urlMatcherFactory.js +++ b/src/urlMatcherFactory.js @@ -72,15 +72,14 @@ function UrlMatcher(pattern, caseInsensitiveMatch) { // \\. - a backslash escape // \{(?:[^{}\\]+|\\.)*\} - a matched set of curly braces containing other atoms var placeholder = /([:*])(\w+)|\{(\w+)(?:\:((?:[^{}\\]+|\\.|\{(?:[^{}\\]+|\\.)*\})+))?\}/g, - names = {}, compiled = '^', last = 0, m, + compiled = '^', last = 0, m, segments = this.segments = [], - params = this.params = []; + params = this.params = {}; - function addParameter(id) { + function addParameter(id, type) { if (!/^\w+(-+\w+)*$/.test(id)) throw new Error("Invalid parameter name '" + id + "' in pattern '" + pattern + "'"); - if (names[id]) throw new Error("Duplicate parameter name '" + id + "' in pattern '" + pattern + "'"); - names[id] = true; - params.push(id); + if (params[id]) throw new Error("Duplicate parameter name '" + id + "' in pattern '" + pattern + "'"); + params[id] = type; } function quoteRegExp(string) { @@ -91,14 +90,18 @@ function UrlMatcher(pattern, caseInsensitiveMatch) { // Split into static segments separated by path parameter placeholders. // The number of segments is always 1 more than the number of parameters. - var id, regexp, segment; + var id, regexp, segment, type; + while ((m = placeholder.exec(pattern))) { - id = m[2] || m[3]; // IE[78] returns '' for unmatched groups instead of null - regexp = m[4] || (m[1] == '*' ? '.*' : '[^/]*'); + id = m[2] || m[3]; // IE[78] returns '' for unmatched groups instead of null + regexp = m[4] || (m[1] == '*' ? '.*' : '[^/]*'); segment = pattern.substring(last, m.index); + type = this.$types[regexp] || new Type({ pattern: new RegExp(regexp) }); + if (segment.indexOf('?') >= 0) break; // we're into the search part - compiled += quoteRegExp(segment) + '(' + regexp + ')'; - addParameter(id); + + compiled += quoteRegExp(segment) + '(' + type.$subPattern() + ')'; + addParameter(id, type); segments.push(segment); last = placeholder.lastIndex; } @@ -106,10 +109,11 @@ function UrlMatcher(pattern, caseInsensitiveMatch) { // Find any search parameter names and remove them from the last segment var i = segment.indexOf('?'); + if (i >= 0) { var search = this.sourceSearch = segment.substring(i); segment = segment.substring(0, i); - this.sourcePath = pattern.substring(0, last+i); + this.sourcePath = pattern.substring(0, last + i); // Allow parameters to be separated by '?' as well as '&' to make concat() easier forEach(search.substring(1).split(/[&?]/), addParameter); @@ -120,12 +124,8 @@ function UrlMatcher(pattern, caseInsensitiveMatch) { compiled += quoteRegExp(segment) + '$'; segments.push(segment); - if(caseInsensitiveMatch){ - this.regexp = new RegExp(compiled, 'i'); - }else{ - this.regexp = new RegExp(compiled); - } - + + this.regexp = (caseInsensitiveMatch) ? new RegExp(compiled, 'i') : new RegExp(compiled); this.prefix = segments[0]; } @@ -187,14 +187,18 @@ UrlMatcher.prototype.exec = function (path, searchParams) { var m = this.regexp.exec(path); if (!m) return null; - var params = this.params, nTotal = params.length, - nPath = this.segments.length-1, - values = {}, i; + var params = this.parameters(), nTotal = params.length, + nPath = this.segments.length - 1, + values = {}, i, type, param; if (nPath !== m.length - 1) throw new Error("Unbalanced capture group in route '" + this.source + "'"); - for (i=0; i