Comparing version 0.1.6 to 0.1.7
{ | ||
"author" : "Ruslan Kerimov <rus.kerimov@gmail.com>", | ||
"name" : "susanin", | ||
"version" : "0.1.6", | ||
"version" : "0.1.7", | ||
"author" : { | ||
"name" : "Ruslan Kerimov", | ||
"email" : "rus.kerimov@gmail.com" | ||
}, | ||
"description" : "Router system which can be used in any JavaScript environments", | ||
"keywords" : [ "router", "routes", "routing" ], | ||
"repository" : { | ||
@@ -21,5 +26,6 @@ "type" : "git", | ||
"main" : "susanin", | ||
"engines" : { | ||
"node" : "*" | ||
} | ||
"bugs" : { | ||
"url" : "https://github.com/ruslankerimov/susanin/issues" | ||
}, | ||
"license": "MIT" | ||
} |
295
susanin.js
@@ -12,4 +12,4 @@ (function(global) { | ||
/** | ||
* Парсит строку вида "param1=value1¶m2=value2¶m2¶m3=value3" | ||
* и возвращает объект: | ||
* Parse a string "param1=value1¶m2=value2¶m2¶m3=value3" | ||
* and return object: | ||
* { | ||
@@ -20,8 +20,7 @@ * param1 : value1, | ||
* } | ||
* Аналог http://nodejs.org/api/querystring.html#querystring_querystring_parse_str_sep_eq | ||
* @static | ||
* @link http://nodejs.org/api/querystring.html#querystring_querystring_parse_str_sep_eq | ||
* @param {String} query | ||
* @param {String} [sep='&'] | ||
* @param {String} [eq='='] | ||
* @return {Object} | ||
* @returns {Object} | ||
*/ | ||
@@ -51,3 +50,3 @@ parse : function (query, sep, eq) { | ||
if (params.hasOwnProperty(key)) { | ||
if (!Array.isArray(params[key])) { | ||
if ( ! isArray(params[key])) { | ||
params[key] = [params[key], value]; | ||
@@ -66,9 +65,8 @@ } else { | ||
/** | ||
* Метод обратный parse | ||
* Аналог http://nodejs.org/api/querystring.html#querystring_querystring_stringify_obj_sep_eq | ||
* @static | ||
* Build querystring from object | ||
* @link http://nodejs.org/api/querystring.html#querystring_querystring_stringify_obj_sep_eq | ||
* @param {Object} params | ||
* @param {String} [sep='&'] | ||
* @param {String} [eq='='] | ||
* @return {String} | ||
* @returns {String} | ||
*/ | ||
@@ -90,3 +88,3 @@ stringify : function (params, sep, eq) { | ||
for (key in params) { | ||
if (params.hasOwnProperty(key)) { | ||
if (hasOwnProp.call(params, key)) { | ||
tmpArray = [].concat(params[key]); | ||
@@ -142,10 +140,11 @@ for (i = 0, size = tmpArray.length; i < size; ++i) { | ||
/** | ||
* Класс роут | ||
* Creates new Route | ||
* @constructor | ||
* @param {Object} options | ||
* @param {String} options.name имя роута | ||
* @param {String} options.pattern паттерн соответствия | ||
* @param {Object} [options.conditions] условия, накладываемые на параметры | ||
* @param {Object} [options.defaults] умалчиваемые значения параметров | ||
* @param {Array} _options | ||
* @param {Object|String} options If it's a string it means pattern for path match | ||
* @param {String} [options.name] Name of the route | ||
* @param {String} options.pattern Pattern for path match | ||
* @param {Object} [options.conditions] Conditions for params in pattern | ||
* @param {Object} [options.defaults] Defaults values for params in pattern | ||
* @param {Object} [options.data] Data that will be bonded with route | ||
* @param {Array} [_options] If you want to create instance from bundle made of bunle method | ||
*/ | ||
@@ -158,8 +157,7 @@ function Route(options, _options) { | ||
if (_options) { | ||
this._name = _options[0]; | ||
this._defaults = _options[1]; | ||
this._paramsMap = _options[2]; | ||
this._parseRegExpSource = _options[3]; | ||
this._buildFnSource = _options[4]; | ||
this._data = _options[5]; | ||
this._defaults = _options[0]; | ||
this._paramsMap = _options[1]; | ||
this._parseRegExpSource = _options[2]; | ||
this._buildFnSource = _options[3]; | ||
this._data = _options[4]; | ||
@@ -173,2 +171,4 @@ /*jshint evil:true */ | ||
typeof options === 'string' && (options = { pattern : options }); | ||
if ( ! options || typeof options !== 'object') { | ||
@@ -178,7 +178,2 @@ throw new Error('You must specify options'); | ||
if (typeof options.name !== 'string') { | ||
throw new Error('You must specify the name of the route'); | ||
} | ||
this._name = options.name; | ||
if (typeof options.pattern !== 'string') { | ||
@@ -191,5 +186,6 @@ throw new Error('You must specify the pattern of the route'); | ||
this._defaults = options.defaults && typeof options.defaults === 'object' ? options.defaults : {}; | ||
this._data = options.data; | ||
this._data = options.data && typeof options.data === 'object' ? options.data : {}; | ||
typeof options.name === 'string' && (this._data.name = options.name); | ||
/* Добавим query_string */ | ||
/* query_string */ | ||
this._pattern += GROUP_OPENED_CHAR + | ||
@@ -199,3 +195,3 @@ '?' + PARAM_OPENED_CHAR + 'query_string' + PARAM_CLOSED_CHAR + | ||
this._conditions.query_string = '.*'; | ||
/* /Добавим query_string */ | ||
/* /query_string */ | ||
@@ -209,4 +205,5 @@ this._parts = this._parsePattern(this._pattern); | ||
/** | ||
* Парсит паттерн, дробит его на составляющие | ||
* @return {Route} | ||
* @param {String} pattern | ||
* @returns {Array} | ||
* @private | ||
*/ | ||
@@ -270,4 +267,9 @@ Route.prototype._parsePattern = function(pattern) { | ||
return parts; | ||
}, | ||
}; | ||
/** | ||
* @param {String} pattern | ||
* @param {Array} parts | ||
* @private | ||
*/ | ||
Route.prototype._parseParams = function(pattern, parts) { | ||
@@ -295,109 +297,120 @@ var matches = pattern.match(PARSE_PARAMS_REGEXP), | ||
/** | ||
* Строит регэксп для проверки | ||
* @return {Route} | ||
* @returns {Route} | ||
* @private | ||
*/ | ||
Route.prototype._buildParseRegExp = function() { | ||
var route = this; | ||
this._paramsMap = []; | ||
this._parseRegExpSource = '^' + this._buildParseRegExpParts(this._parts) + '$'; | ||
this._parseRegExp = new RegExp(this._parseRegExpSource); | ||
function build(parts) { | ||
var ret = '', | ||
i, size, | ||
part; | ||
return this; | ||
}; | ||
for (i = 0, size = parts.length; i < size; ++i) { | ||
part = parts[i]; | ||
/** | ||
* @param {Array} parts | ||
* @returns {String} | ||
* @private | ||
*/ | ||
Route.prototype._buildParseRegExpParts = function(parts) { | ||
var ret = '', | ||
i, size, | ||
part; | ||
if (typeof part === 'string') { | ||
ret += escape(part); | ||
} else if (part && part.what === 'param') { | ||
route._paramsMap.push(part.name); | ||
ret += '(' + buildParamValueRegExpSource(part.name) + ')'; | ||
} else if (part && part.what === 'optional') { | ||
ret += '(?:' + build(part.parts) + ')?'; | ||
} | ||
for (i = 0, size = parts.length; i < size; ++i) { | ||
part = parts[i]; | ||
if (typeof part === 'string') { | ||
ret += escape(part); | ||
} else if (part && part.what === 'param') { | ||
this._paramsMap.push(part.name); | ||
ret += '(' + this._buildParamValueRegExpSource(part.name) + ')'; | ||
} else if (part && part.what === 'optional') { | ||
ret += '(?:' + this._buildParseRegExpParts(part.parts) + ')?'; | ||
} | ||
return ret; | ||
} | ||
function buildParamValueRegExpSource(paramName) { | ||
var ret = '', | ||
condition = route._conditions && route._conditions[paramName]; | ||
return ret; | ||
}; | ||
if (condition) { | ||
if (isArray(condition)) { | ||
ret = '(?:' + condition.join('|') + ')'; | ||
} else { | ||
ret = condition + ''; | ||
} | ||
/** | ||
* @param {String} paramName | ||
* @returns {String} | ||
* @private | ||
*/ | ||
Route.prototype._buildParamValueRegExpSource = function(paramName) { | ||
var ret, | ||
condition = this._conditions[paramName]; | ||
if (condition) { | ||
if (isArray(condition)) { | ||
ret = '(?:' + condition.join('|') + ')'; | ||
} else { | ||
ret = PARAM_VALUE_REGEXP_SOURCE; | ||
ret = condition + ''; | ||
} | ||
return ret; | ||
} else { | ||
ret = PARAM_VALUE_REGEXP_SOURCE; | ||
} | ||
this._paramsMap = []; | ||
this._parseRegExpSource = '^' + build(this._parts) + '$'; | ||
this._parseRegExp = new RegExp(this._parseRegExpSource); | ||
return this; | ||
return ret; | ||
}; | ||
/** | ||
* Строит функцию для составления пути | ||
* @return {Route} | ||
* @returns {Route} | ||
* @private | ||
*/ | ||
Route.prototype._buildBuildFn = function() { | ||
this._buildFnSource = 'var h=({}).hasOwnProperty;return ' + this._buildBuildFnParts(this._parts) + ';'; | ||
/*jshint evil:true */ | ||
var route = this; | ||
this._buildFn = new Function('p', this._buildFnSource); | ||
function build(parts) { | ||
var ret = '""', | ||
i, sizeI, j, sizeJ, | ||
part, name; | ||
return this; | ||
}; | ||
for (i = 0, sizeI = parts.length; i < sizeI; ++i) { | ||
part = parts[i]; | ||
/** | ||
* @param {Array} parts | ||
* @returns {String} | ||
* @private | ||
*/ | ||
Route.prototype._buildBuildFnParts = function(parts) { | ||
var ret = '""', | ||
i, sizeI, j, sizeJ, | ||
part, name; | ||
if (typeof part === 'string') { | ||
ret += '+"' + escape(part) + '"' ; | ||
} else if (part && part.what === 'param') { | ||
ret += '+(h.call(p,"' + escape(part.name) + '")?' + | ||
'p["' + escape(part.name) + '"]:' + | ||
(route._defaults && hasOwnProp.call(route._defaults, part.name) ? | ||
'"' + escape(route._defaults[part.name]) + '"' : | ||
'""') + | ||
')'; | ||
} else if (part && part.what === 'optional') { | ||
ret += '+((false'; | ||
for (i = 0, sizeI = parts.length; i < sizeI; ++i) { | ||
part = parts[i]; | ||
for (j = 0, sizeJ = part.dependOnParams.length; j < sizeJ; ++j) { | ||
name = part.dependOnParams[j]; | ||
if (typeof part === 'string') { | ||
ret += '+"' + escape(part) + '"' ; | ||
} else if (part && part.what === 'param') { | ||
ret += '+(h.call(p,"' + escape(part.name) + '")?' + | ||
'p["' + escape(part.name) + '"]:' + | ||
(this._defaults && hasOwnProp.call(this._defaults, part.name) ? | ||
'"' + escape(this._defaults[part.name]) + '"' : | ||
'""') + | ||
')'; | ||
} else if (part && part.what === 'optional') { | ||
ret += '+((false'; | ||
ret += '||(h.call(p,"' + escape(name) + '")' + | ||
(route._defaults && hasOwnProp.call(route._defaults, name) ? | ||
'&&p["' + escape(name) + '"]!=="' + | ||
escape(route._defaults[name]) + '"' : | ||
'') + | ||
')'; | ||
} | ||
for (j = 0, sizeJ = part.dependOnParams.length; j < sizeJ; ++j) { | ||
name = part.dependOnParams[j]; | ||
ret += ')?(' + build(part.parts) + '):"")'; | ||
ret += '||(h.call(p,"' + escape(name) + '")' + | ||
(this._defaults && hasOwnProp.call(this._defaults, name) ? | ||
'&&p["' + escape(name) + '"]!=="' + | ||
escape(this._defaults[name]) + '"' : | ||
'') + | ||
')'; | ||
} | ||
ret += ')?(' + this._buildBuildFnParts(part.parts) + '):"")'; | ||
} | ||
return ret; | ||
} | ||
this._buildFnSource = 'var h=({}).hasOwnProperty;return ' + build(this._parts) + ';'; | ||
this._buildFn = new Function('p', this._buildFnSource); | ||
return this; | ||
return ret; | ||
}; | ||
/** | ||
* Парсит переданный путь, возвращает объект с параметрами либо null | ||
* @param {Object} matchObject | ||
* @return {Object} | ||
* Matches object with route | ||
* @param {Object|String} matchObject | ||
* @returns {Object|null} | ||
*/ | ||
@@ -418,4 +431,4 @@ Route.prototype.match = function(matchObject) { | ||
for (key in matchObject) { | ||
if (matchObject.hasOwnProperty(key) && key !== 'path') { | ||
if ( ! this._data || typeof this._data !== 'object' || this._data[key] !== matchObject[key]) { | ||
if (hasOwnProp.call(matchObject, key) && key !== 'path') { | ||
if (this._data[key] !== matchObject[key]) { | ||
return ret; | ||
@@ -464,5 +477,5 @@ } | ||
/** | ||
* Составляет путь по переданным параметрам | ||
* Build path from params | ||
* @param {Object} params | ||
* @return {String} | ||
* @returns {String} | ||
*/ | ||
@@ -505,2 +518,6 @@ Route.prototype.build = function(params) { | ||
/** | ||
* Returns binded with route data | ||
* @returns {*} | ||
*/ | ||
Route.prototype.getData = function() { | ||
@@ -510,9 +527,16 @@ return this._data; | ||
/** | ||
* Returns name of the route | ||
* @returns {*} | ||
*/ | ||
Route.prototype.getName = function() { | ||
return this._name; | ||
return this._data.name; | ||
}; | ||
/** | ||
* Returns bundle | ||
* @returns {Array} | ||
*/ | ||
Route.prototype.bundle = function() { | ||
return [ | ||
this._name, | ||
this._defaults, | ||
@@ -528,3 +552,5 @@ this._paramsMap, | ||
/** | ||
* Creates new Router | ||
* @constructor | ||
* @param {Array} [bundle] | ||
*/ | ||
@@ -539,7 +565,14 @@ function Router(bundle) { | ||
bundle && this.restoreFromBundle(bundle); | ||
bundle && this.addRoutesFromBundle(bundle); | ||
} | ||
/** | ||
* Add route | ||
* @param {Object|String} options | ||
* @param [_options] | ||
* @returns {Route} | ||
*/ | ||
Router.prototype.addRoute = function(options, _options) { | ||
var route; | ||
var route, | ||
name; | ||
@@ -549,3 +582,4 @@ route = new Route(options, _options); | ||
this._routes.push(route); | ||
this._routesByName[route.getName()] = route; | ||
name = route.getName(); | ||
name && (this._routesByName[name] = route); | ||
@@ -555,2 +589,7 @@ return route; | ||
/** | ||
* Returns all successfully matched routes | ||
* @param {Object|String} matchObject | ||
* @returns {Array|null} | ||
*/ | ||
Router.prototype.find = function(matchObject) { | ||
@@ -572,2 +611,7 @@ var ret = [], | ||
/** | ||
* Returns first successfully matched route | ||
* @param {Object|String} matchObject | ||
* @returns {Array|null} | ||
*/ | ||
Router.prototype.findFirst = function(matchObject) { | ||
@@ -589,5 +633,5 @@ var parsed, | ||
/** | ||
* Возвращает роут по имени | ||
* Returns a route by its name | ||
* @param {String} name | ||
* @return {Route} | ||
* @returns {Route} | ||
*/ | ||
@@ -599,4 +643,4 @@ Router.prototype.getRouteByName = function(name) { | ||
/** | ||
* Формирует бандл для прокидывания на клиент | ||
* @return {Array} | ||
* Returns bundle of all routes | ||
* @returns {Array} | ||
*/ | ||
@@ -615,2 +659,7 @@ Router.prototype.bundle = function() { | ||
/** | ||
* Add routes from bunle | ||
* @param bundle | ||
* @returns {Router} | ||
*/ | ||
Router.prototype.addRoutesFromBundle = function(bundle) { | ||
@@ -617,0 +666,0 @@ var i, size; |
@@ -1,1 +0,1 @@ | ||
(function(e){function p(e,t){if(!(this instanceof p))return new p(e,t);if(t){this._name=t[0],this._defaults=t[1],this._paramsMap=t[2],this._parseRegExpSource=t[3],this._buildFnSource=t[4],this._data=t[5],this._buildFn=new Function("p",this._buildFnSource),this._parseRegExp=new RegExp(this._parseRegExpSource);return}if(!e||typeof e!="object")throw new Error("You must specify options");if(typeof e.name!="string")throw new Error("You must specify the name of the route");this._name=e.name;if(typeof e.pattern!="string")throw new Error("You must specify the pattern of the route");this._pattern=e.pattern,this._conditions=e.conditions&&typeof e.conditions=="object"?e.conditions:{},this._defaults=e.defaults&&typeof e.defaults=="object"?e.defaults:{},this._data=e.data,this._pattern+=a+"?"+o+"query_string"+u+f,this._conditions.query_string=".*",this._parts=this._parsePattern(this._pattern),this._buildParseRegExp()._buildBuildFn()}function d(e){if(!(this instanceof d))return new d(e);this._routes=[],this._routesByName={},e&&this.restoreFromBundle(e)}var t=Object.prototype.hasOwnProperty,n=Object.prototype.toString,r=function(e){return n.call(e)==="[object Array]"},i={parse:function(e,t,n){var r={},i,s,o,u,a,f;arguments.length||(e=location.search.substr(1));if(!e)return r;t||(t="&"),n||(n="="),i=e.split(t);for(a=0,f=i.length;a<f;++a)s=i[a].split(n),o=typeof s[1]!="undefined"?decodeURIComponent(s[1].replace(/\+/g,"%20")):"",u=decodeURIComponent(s[0]),r.hasOwnProperty(u)?Array.isArray(r[u])?r[u].push(o):r[u]=[r[u],o]:r[u]=o;return r},stringify:function(e,t,n){var r="",i,s,o,u,a,f;if(!e)return r;t||(t="&"),n||(n="=");for(f in e)if(e.hasOwnProperty(f)){o=[].concat(e[f]);for(u=0,a=o.length;u<a;++u)s=typeof o[u],s==="object"||s==="undefined"?i="":i=encodeURIComponent(o[u]),r+=t+encodeURIComponent(f)+n+i}return r.substr(t.length)}},s=function(){var e=["/",".","*","+","?","|","(",")","[","]","{","}","\\"],t=new RegExp("(\\"+e.join("|\\")+")","g");return function(e){return e.replace(t,"\\$1")}}(),o="<",u=">",a="(",f=")",l="[a-zA-Z_][\\w\\-]*",c="[\\w\\-]+",h=new RegExp("("+s(o)+l+s(u)+"|"+"[^"+s(o)+s(u)+"]+"+"|"+s(o)+"|"+s(u)+")","g");p.prototype._parsePattern=function(e){var t=[],n="",r,i=0,s,o,u=0,l=!1,c=e.length;while(i<c){r=e.charAt(i++);if(r===a)l?(++u,n+=r):(this._parseParams(n,t),n="",u=0,l=!0);else if(r===f)if(l)if(u===0){n={what:"optional",dependOnParams:[],parts:this._parsePattern(n)},t.push(n);for(s=0,o=n.parts.length;s<o;++s)n.parts[s]&&n.parts[s].what==="param"&&n.dependOnParams.push(n.parts[s].name);n="",l=!1}else--u,n+=r;else n+=r;else n+=r}return this._parseParams(n,t),t},p.prototype._parseParams=function(e,t){var n=e.match(h),r,i,s;if(n)for(r=0,i=n.length;r<i;++r)s=n[r],s.charAt(0)===o&&s.charAt(s.length-1)===u?t.push({what:"param",name:s.substr(1,s.length-2)}):t.push(s)},p.prototype._buildParseRegExp=function(){function t(r){var i="",o,u,a;for(o=0,u=r.length;o<u;++o)a=r[o],typeof a=="string"?i+=s(a):a&&a.what==="param"?(e._paramsMap.push(a.name),i+="("+n(a.name)+")"):a&&a.what==="optional"&&(i+="(?:"+t(a.parts)+")?");return i}function n(t){var n="",i=e._conditions&&e._conditions[t];return i?r(i)?n="(?:"+i.join("|")+")":n=i+"":n=c,n}var e=this;return this._paramsMap=[],this._parseRegExpSource="^"+t(this._parts)+"$",this._parseRegExp=new RegExp(this._parseRegExpSource),this},p.prototype._buildBuildFn=function(){function n(r){var i='""',o,u,a,f,l,c;for(o=0,u=r.length;o<u;++o){l=r[o];if(typeof l=="string")i+='+"'+s(l)+'"';else if(l&&l.what==="param")i+='+(h.call(p,"'+s(l.name)+'")?'+'p["'+s(l.name)+'"]:'+(e._defaults&&t.call(e._defaults,l.name)?'"'+s(e._defaults[l.name])+'"':'""')+")";else if(l&&l.what==="optional"){i+="+((false";for(a=0,f=l.dependOnParams.length;a<f;++a)c=l.dependOnParams[a],i+='||(h.call(p,"'+s(c)+'")'+(e._defaults&&t.call(e._defaults,c)?'&&p["'+s(c)+'"]!=="'+s(e._defaults[c])+'"':"")+")";i+=")?("+n(l.parts)+'):"")'}}return i}var e=this;return this._buildFnSource="var h=({}).hasOwnProperty;return "+n(this._parts)+";",this._buildFn=new Function("p",this._buildFnSource),this},p.prototype.match=function(e){var n=null,r,s,o,u,a;typeof e=="string"?e={path:e}:e||(e={});for(u in e)if(e.hasOwnProperty(u)&&u!=="path")if(!this._data||typeof this._data!="object"||this._data[u]!==e[u])return n;if(typeof e.path=="string"){r=e.path.match(this._parseRegExp);if(r){n={};for(s=1,o=r.length;s<o;++s)typeof r[s]!="undefined"&&r[s]!==""&&(n[this._paramsMap[s-1]]=r[s]);for(u in this._defaults)t.call(this._defaults,u)&&!t.call(n,u)&&(n[u]=this._defaults[u]);a=i.parse(n.query_string);for(u in a)t.call(a,u)&&!t.call(n,u)&&(n[u]=a[u]);delete n.query_string}}else n={};return n},p.prototype.build=function(e){var n={},r={},s,o,u,a,f;for(o in e)if(t.call(e,o)&&e[o]!==null&&typeof e[o]!="undefined"){u=!1;for(a=0,f=this._paramsMap.length;a<f;++a)if(this._paramsMap[a]===o){u=!0;break}u?n[o]=e[o]:r[o]=e[o]}return s=i.stringify(r),s&&(n.query_string=s),this._buildFn(n)},p.prototype.getData=function(){return this._data},p.prototype.getName=function(){return this._name},p.prototype.bundle=function(){return[this._name,this._defaults,this._paramsMap,this._parseRegExpSource,this._buildFnSource,this._data]},d.prototype.addRoute=function(e,t){var n;return n=new p(e,t),this._routes.push(n),this._routesByName[n.getName()]=n,n},d.prototype.find=function(e){var t=[],n,r,i,s=this._routes;for(r=0,i=s.length;r<i;++r)n=s[r].match(e),n!==null&&t.push([s[r],n]);return t},d.prototype.findFirst=function(e){var t,n,r,i=this._routes;for(n=0,r=i.length;n<r;++n){t=i[n].match(e);if(t!==null)return[i[n],t]}return null},d.prototype.getRouteByName=function(e){return this._routesByName[e]||null},d.prototype.bundle=function(){var e=[],t,n,r=this._routes;for(t=0,n=r.length;t<n;++t)e.push(r[t].bundle());return e},d.prototype.addRoutesFromBundle=function(e){var t,n;for(t=0,n=e.length;t<n;++t)this.addRoute(null,e[t]);return this},d.Route=p,typeof module!="undefined"&&typeof module.exports=="object"?module.exports=d:e.Susanin=d})(this); | ||
(function(e){function p(e,t){if(!(this instanceof p))return new p(e,t);if(t){this._defaults=t[0],this._paramsMap=t[1],this._parseRegExpSource=t[2],this._buildFnSource=t[3],this._data=t[4],this._buildFn=new Function("p",this._buildFnSource),this._parseRegExp=new RegExp(this._parseRegExpSource);return}typeof e=="string"&&(e={pattern:e});if(!e||typeof e!="object")throw new Error("You must specify options");if(typeof e.pattern!="string")throw new Error("You must specify the pattern of the route");this._pattern=e.pattern,this._conditions=e.conditions&&typeof e.conditions=="object"?e.conditions:{},this._defaults=e.defaults&&typeof e.defaults=="object"?e.defaults:{},this._data=e.data&&typeof e.data=="object"?e.data:{},typeof e.name=="string"&&(this._data.name=e.name),this._pattern+=a+"?"+o+"query_string"+u+f,this._conditions.query_string=".*",this._parts=this._parsePattern(this._pattern),this._buildParseRegExp()._buildBuildFn()}function d(e){if(!(this instanceof d))return new d(e);this._routes=[],this._routesByName={},e&&this.addRoutesFromBundle(e)}var t=Object.prototype.hasOwnProperty,n=Object.prototype.toString,r=function(e){return n.call(e)==="[object Array]"},i={parse:function(e,t,n){var i={},s,o,u,a,f,l;arguments.length||(e=location.search.substr(1));if(!e)return i;t||(t="&"),n||(n="="),s=e.split(t);for(f=0,l=s.length;f<l;++f)o=s[f].split(n),u=typeof o[1]!="undefined"?decodeURIComponent(o[1].replace(/\+/g,"%20")):"",a=decodeURIComponent(o[0]),i.hasOwnProperty(a)?r(i[a])?i[a].push(u):i[a]=[i[a],u]:i[a]=u;return i},stringify:function(e,n,r){var i="",s,o,u,a,f,l;if(!e)return i;n||(n="&"),r||(r="=");for(l in e)if(t.call(e,l)){u=[].concat(e[l]);for(a=0,f=u.length;a<f;++a)o=typeof u[a],o==="object"||o==="undefined"?s="":s=encodeURIComponent(u[a]),i+=n+encodeURIComponent(l)+r+s}return i.substr(n.length)}},s=function(){var e=["/",".","*","+","?","|","(",")","[","]","{","}","\\"],t=new RegExp("(\\"+e.join("|\\")+")","g");return function(e){return e.replace(t,"\\$1")}}(),o="<",u=">",a="(",f=")",l="[a-zA-Z_][\\w\\-]*",c="[\\w\\-]+",h=new RegExp("("+s(o)+l+s(u)+"|"+"[^"+s(o)+s(u)+"]+"+"|"+s(o)+"|"+s(u)+")","g");p.prototype._parsePattern=function(e){var t=[],n="",r,i=0,s,o,u=0,l=!1,c=e.length;while(i<c){r=e.charAt(i++);if(r===a)l?(++u,n+=r):(this._parseParams(n,t),n="",u=0,l=!0);else if(r===f)if(l)if(u===0){n={what:"optional",dependOnParams:[],parts:this._parsePattern(n)},t.push(n);for(s=0,o=n.parts.length;s<o;++s)n.parts[s]&&n.parts[s].what==="param"&&n.dependOnParams.push(n.parts[s].name);n="",l=!1}else--u,n+=r;else n+=r;else n+=r}return this._parseParams(n,t),t},p.prototype._parseParams=function(e,t){var n=e.match(h),r,i,s;if(n)for(r=0,i=n.length;r<i;++r)s=n[r],s.charAt(0)===o&&s.charAt(s.length-1)===u?t.push({what:"param",name:s.substr(1,s.length-2)}):t.push(s)},p.prototype._buildParseRegExp=function(){return this._paramsMap=[],this._parseRegExpSource="^"+this._buildParseRegExpParts(this._parts)+"$",this._parseRegExp=new RegExp(this._parseRegExpSource),this},p.prototype._buildParseRegExpParts=function(e){var t="",n,r,i;for(n=0,r=e.length;n<r;++n)i=e[n],typeof i=="string"?t+=s(i):i&&i.what==="param"?(this._paramsMap.push(i.name),t+="("+this._buildParamValueRegExpSource(i.name)+")"):i&&i.what==="optional"&&(t+="(?:"+this._buildParseRegExpParts(i.parts)+")?");return t},p.prototype._buildParamValueRegExpSource=function(e){var t,n=this._conditions[e];return n?r(n)?t="(?:"+n.join("|")+")":t=n+"":t=c,t},p.prototype._buildBuildFn=function(){return this._buildFnSource="var h=({}).hasOwnProperty;return "+this._buildBuildFnParts(this._parts)+";",this._buildFn=new Function("p",this._buildFnSource),this},p.prototype._buildBuildFnParts=function(e){var n='""',r,i,o,u,a,f;for(r=0,i=e.length;r<i;++r){a=e[r];if(typeof a=="string")n+='+"'+s(a)+'"';else if(a&&a.what==="param")n+='+(h.call(p,"'+s(a.name)+'")?'+'p["'+s(a.name)+'"]:'+(this._defaults&&t.call(this._defaults,a.name)?'"'+s(this._defaults[a.name])+'"':'""')+")";else if(a&&a.what==="optional"){n+="+((false";for(o=0,u=a.dependOnParams.length;o<u;++o)f=a.dependOnParams[o],n+='||(h.call(p,"'+s(f)+'")'+(this._defaults&&t.call(this._defaults,f)?'&&p["'+s(f)+'"]!=="'+s(this._defaults[f])+'"':"")+")";n+=")?("+this._buildBuildFnParts(a.parts)+'):"")'}}return n},p.prototype.match=function(e){var n=null,r,s,o,u,a;typeof e=="string"?e={path:e}:e||(e={});for(u in e)if(t.call(e,u)&&u!=="path"&&this._data[u]!==e[u])return n;if(typeof e.path=="string"){r=e.path.match(this._parseRegExp);if(r){n={};for(s=1,o=r.length;s<o;++s)typeof r[s]!="undefined"&&r[s]!==""&&(n[this._paramsMap[s-1]]=r[s]);for(u in this._defaults)t.call(this._defaults,u)&&!t.call(n,u)&&(n[u]=this._defaults[u]);a=i.parse(n.query_string);for(u in a)t.call(a,u)&&!t.call(n,u)&&(n[u]=a[u]);delete n.query_string}}else n={};return n},p.prototype.build=function(e){var n={},r={},s,o,u,a,f;for(o in e)if(t.call(e,o)&&e[o]!==null&&typeof e[o]!="undefined"){u=!1;for(a=0,f=this._paramsMap.length;a<f;++a)if(this._paramsMap[a]===o){u=!0;break}u?n[o]=e[o]:r[o]=e[o]}return s=i.stringify(r),s&&(n.query_string=s),this._buildFn(n)},p.prototype.getData=function(){return this._data},p.prototype.getName=function(){return this._data.name},p.prototype.bundle=function(){return[this._defaults,this._paramsMap,this._parseRegExpSource,this._buildFnSource,this._data]},d.prototype.addRoute=function(e,t){var n,r;return n=new p(e,t),this._routes.push(n),r=n.getName(),r&&(this._routesByName[r]=n),n},d.prototype.find=function(e){var t=[],n,r,i,s=this._routes;for(r=0,i=s.length;r<i;++r)n=s[r].match(e),n!==null&&t.push([s[r],n]);return t},d.prototype.findFirst=function(e){var t,n,r,i=this._routes;for(n=0,r=i.length;n<r;++n){t=i[n].match(e);if(t!==null)return[i[n],t]}return null},d.prototype.getRouteByName=function(e){return this._routesByName[e]||null},d.prototype.bundle=function(){var e=[],t,n,r=this._routes;for(t=0,n=r.length;t<n;++t)e.push(r[t].bundle());return e},d.prototype.addRoutesFromBundle=function(e){var t,n;for(t=0,n=e.length;t<n;++t)this.addRoute(null,e[t]);return this},d.Route=p,typeof module!="undefined"&&typeof module.exports=="object"?module.exports=d:e.Susanin=d})(this); |
@@ -7,3 +7,3 @@ var Susanin = require('../../'), | ||
'/opa' : function(test) { | ||
var route = Route({ name : 'opa', pattern : '/opa' }); | ||
var route = Route('/opa'); | ||
@@ -25,8 +25,6 @@ test.strictEqual(route.build(), '/opa'); | ||
'/opa/<param>' : function(test) { | ||
var route = Route({ | ||
name : 'opa', | ||
pattern : '/opa/<param>' | ||
}); | ||
var route = Route('/opa/<param>') | ||
; | ||
test.strictEqual(route.build(), '/opa/'); | ||
test.strictEqual(route.build(), '/opa/'); | ||
test.strictEqual(route.build({}), '/opa/'); | ||
@@ -45,6 +43,3 @@ test.strictEqual(route.build({ param : 'bar' }), '/opa/bar'); | ||
'/opa/<param' : function(test) { | ||
var route = Route({ | ||
name : 'opa', | ||
pattern : '/opa/<param' | ||
}); | ||
var route = Route('/opa/<param'); | ||
@@ -61,3 +56,2 @@ test.strictEqual(route.build(), '/opa/<param'); | ||
var route = Route({ | ||
name : 'opa', | ||
pattern : '/opa/<param>', | ||
@@ -78,6 +72,3 @@ defaults : { | ||
'/opa(/opapa/<param>)' : function(test) { | ||
var route = Route({ | ||
name : 'opa', | ||
pattern : '/opa(/opapa/<param>)' | ||
}); | ||
var route = Route('/opa(/opapa/<param>)'); | ||
@@ -94,3 +85,2 @@ test.strictEqual(route.build(), '/opa'); | ||
var route = Route({ | ||
name : 'opa', | ||
pattern : '/opa(/opapa/<param>)', | ||
@@ -111,6 +101,3 @@ defaults : { | ||
'/opa(/opapa/<param1>)(/<param2>)' : function(test) { | ||
var route = Route({ | ||
name : 'opa', | ||
pattern : '/opa(/opapa/<param1>)(/<param2>)' | ||
}); | ||
var route = Route('/opa(/opapa/<param1>)(/<param2>)'); | ||
@@ -129,3 +116,2 @@ test.strictEqual(route.build(), '/opa'); | ||
var route = Route({ | ||
name : 'opa', | ||
pattern : '/opa(/opapa/<param1>)(/<param2>)', | ||
@@ -152,3 +138,3 @@ defaults : { | ||
pattern = '/opa<' + paramName + '>', | ||
route = Route({ name : 'opa', pattern : pattern }), | ||
route = Route(pattern), | ||
obj = {}; | ||
@@ -168,3 +154,3 @@ | ||
pattern = '/opa<' + paramName + '>', | ||
route = Route({ name : 'opa', pattern : pattern }), | ||
route = Route(pattern), | ||
obj = {}; | ||
@@ -171,0 +157,0 @@ |
@@ -12,3 +12,3 @@ var Susanin = require('../../'), | ||
'"Route" must be constructor' : function(test) { | ||
var route = new Route({ name : 'opa', pattern : '/opa' }); | ||
var route = new Route({ pattern : '/opa' }); | ||
@@ -20,3 +20,3 @@ test.ok(route instanceof Route); | ||
'"Route" can be called without "new"' : function(test) { | ||
var route = Route({ name : 'opa', pattern : '/opa' }); | ||
var route = Route({ pattern : '/opa' }); | ||
@@ -38,5 +38,5 @@ test.ok(route instanceof Route); | ||
'"options.name" property is mandatory' : function(test) { | ||
'"options.pattern" property is mandatory' : function(test) { | ||
try { | ||
var route = Route({ pattern : '/opa' }); | ||
var route = Route({ name : 'opa' }); | ||
@@ -50,30 +50,13 @@ test.ok(false); | ||
'"options.pattern" property is mandatory' : function(test) { | ||
'"options" can be string' : function(test) { | ||
try { | ||
var route = Route({ name : 'opa' }); | ||
var route = Route('/opa'); | ||
test.ok(true); | ||
} catch (e) { | ||
test.ok(false); | ||
} catch (e) { | ||
test.ok(true); | ||
} | ||
test.done(); | ||
}, | ||
'route.getData() must return right data' : function(test) { | ||
var data = { | ||
foo : 'bar' | ||
}, | ||
route = Route({ name : 'opa', pattern : '/opa', data : data }); | ||
test.strictEqual(route.getData(), data); | ||
test.done(); | ||
}, | ||
'route.getName() must return the name of the route' : function(test) { | ||
var route = Route({ name : 'opa', pattern : '/opa' }); | ||
test.strictEqual(route.getName(), 'opa'); | ||
test.done(); | ||
} | ||
}; |
@@ -7,8 +7,6 @@ var Susanin = require('../../'), | ||
'/opa' : function(test) { | ||
var route = Route({ | ||
name : 'opa', | ||
pattern : '/opa' | ||
}); | ||
var route = Route('/opa') | ||
; | ||
test.deepEqual(route.match('/opapa'), null); | ||
test.deepEqual(route.match('/opapa'), null); | ||
test.deepEqual(route.match('/opa'), {}); | ||
@@ -26,3 +24,2 @@ test.deepEqual(route.match('/opa?foo'), { foo : '' }); | ||
var route = Route({ | ||
name : 'opa', | ||
pattern : '/opa', | ||
@@ -44,3 +41,2 @@ defaults : { | ||
var route = Route({ | ||
name : 'opa', | ||
pattern : '/opa/<param>' | ||
@@ -61,3 +57,2 @@ }); | ||
var route = Route({ | ||
name : 'opa', | ||
pattern : '/opa/<param>', | ||
@@ -82,3 +77,2 @@ defaults : { | ||
var route = Route({ | ||
name : 'opa', | ||
pattern : '/opa/<param>', | ||
@@ -103,3 +97,2 @@ conditions : { | ||
var route = Route({ | ||
name : 'opa', | ||
pattern : '/opa/<param>', | ||
@@ -126,3 +119,2 @@ conditions : { | ||
var route = Route({ | ||
name : 'opa', | ||
pattern : '/opa(/opapa/<param>)' | ||
@@ -145,3 +137,2 @@ }); | ||
var route = Route({ | ||
name : 'opa', | ||
pattern : '/opa(/opapa/<param>)', | ||
@@ -167,3 +158,2 @@ defaults : { | ||
var route = Route({ | ||
name : 'opa', | ||
pattern : '/opa(/opapa/<param>)', | ||
@@ -195,3 +185,2 @@ conditions : { | ||
var route = Route({ | ||
name : 'opa', | ||
pattern : '/opa/<param1>(/opapa/<param2>(/<param3>))(/)', | ||
@@ -198,0 +187,0 @@ conditions : { |
@@ -22,26 +22,4 @@ var Susanin = require('../../'); | ||
test.done(); | ||
}, | ||
'Instance of "Susanin" must have function "addRoute"' : function(test) { | ||
test.ok(typeof Susanin().addRoute === 'function'); | ||
test.done(); | ||
}, | ||
'"addRoute" must return instance of Susanin.Route' : function(test) { | ||
test.ok(Susanin().addRoute({ name : 'first', pattern : '/opa' }) instanceof Susanin.Route); | ||
test.done(); | ||
}, | ||
'"getRouteByName" must return right instance of "Route"' : function(test) { | ||
var susanin = Susanin(), | ||
routeFoo = susanin.addRoute({ name : 'foo', pattern : '/foo' }), | ||
routeBar = susanin.addRoute({ name : 'bar', pattern : '/bar' }); | ||
test.strictEqual(susanin.getRouteByName('bar'), routeBar); | ||
test.strictEqual(susanin.getRouteByName('foo'), routeFoo); | ||
test.strictEqual(susanin.getRouteByName('opa'), null); | ||
test.done(); | ||
} | ||
}; |
No bug tracker
MaintenancePackage does not have a linked bug tracker in package.json.
Found 1 instance in 1 package
55029
20
1000
1