Comparing version 0.1.3 to 1.0.0
# Routr API | ||
## Constructor(routes) | ||
## Constructor(routes, options) | ||
Creates a new routr plugin instance with the following parameters: | ||
* `routes` (optional): Route table, which is a name to router config map. | ||
* `routes` (optional): Ordered list of routes used for matching. | ||
** `route.name`: Name of the route (used for path making) | ||
** `route.path`: The matching pattern of the route. Follows rules of [path-to-regexp](https://github | ||
.com/pillarjs/path-to-regexp) | ||
** `route.method=undefined`: The method that the path should match to. Will match all methods if `undefined` and no | ||
methods | ||
if `null`. | ||
* `options` (optional): Options for parsing and generating the urls | ||
** `options.queryLib=require('query-string')`: Library to use to `parse` and `stringify` query strings | ||
@@ -13,3 +21,3 @@ ## Instance Methods | ||
Returns the matched route info if path/method/navigate.params matches to a route; null otherwise. | ||
Returns the matched route info if path/method matches to a route; null otherwise. | ||
@@ -19,7 +27,4 @@ * `url` (required) The url to be used for route matching. Query strings are **not** considered when performing the match. | ||
* `options.method` (optional) The case-insensitive HTTP method string. DEFAULT: 'get' | ||
* `options.navigate` (required) The navigation info. | ||
* `options.navigate.type` (required) The navigation type: 'pageload', 'click', 'popstate'. | ||
* `options.navigate.params` (optional) The navigation params (that are not part of the path). | ||
### makePath(name, params) | ||
### makePath(name, params, query) | ||
@@ -29,2 +34,3 @@ Generates a path string with the route with the given name, using the specified params. | ||
* `name` (required) The route name | ||
* `options` (required) The route parameters to be used to create the path string | ||
* `params` (required) The route parameters to be used to create the path string | ||
* `query` (optional) The query parameters to be used to create the path string |
@@ -10,5 +10,4 @@ /** | ||
var pathToRegexp = require('path-to-regexp'); | ||
var METHODS = { | ||
GET: 'get' | ||
}; | ||
var queryString = require('query-string'); | ||
var DEFAULT_METHOD = 'GET'; | ||
var cachedCompilers = {}; | ||
@@ -21,9 +20,23 @@ | ||
* @param {String} config.path The path of the route. | ||
* @param {Object} [options] Options for parsing and generating the urls | ||
* @param {String} [options.queryLib] Library to use for `parse` and `stringify` methods | ||
* @constructor | ||
*/ | ||
function Route(name, config) { | ||
function Route(name, config, options) { | ||
options = options || {}; | ||
this.name = name; | ||
this.config = config || {}; | ||
var method = config.method; | ||
this.methods = method; | ||
if (method) { | ||
method = Array.isArray(method) ? method : [method]; | ||
this.methods = {}; | ||
for (var i=0; i<method.length; ++i) { | ||
this.methods[method[i].toUpperCase()] = true; | ||
} | ||
} | ||
this.keys = []; | ||
this.regexp = pathToRegexp(this.config.path, this.keys); | ||
this._queryLib = options.queryLib || queryString; | ||
} | ||
@@ -35,8 +48,14 @@ | ||
* @param {String} method The HTTP VERB string. | ||
* @return true if the method is accepted; false otherwise. | ||
* @return {boolean} true if the method is accepted; false otherwise. | ||
* @for Route | ||
*/ | ||
Route.prototype.acceptMethod = function (method) { | ||
//TODO support array for method, ['get', 'post'] | ||
return (method && method.toLowerCase()) === (this.config.method && this.config.method.toLowerCase()); | ||
if (!method || null === this.methods) { | ||
return false; | ||
} | ||
if (!this.methods) { | ||
// If no method is set on route, match all methods | ||
return true; | ||
} | ||
return this.methods[method]; | ||
}; | ||
@@ -52,5 +71,2 @@ | ||
* @param {String} [options.method=get] The case-insensitive HTTP method string. Defaults to 'get'. | ||
* @param {Object} [options.navigate] The navigation info. | ||
* @param {Object} [options.navigate.type] The navigation type: 'pageload', 'click', 'popstate'. | ||
* @param {Object} [options.navigate.params] The navigation params (that are not part of the path). | ||
* @return {Object|null} The matched route params if path/method/navParams matches to this route; null otherwise. | ||
@@ -71,3 +87,6 @@ * @for Route | ||
// 1. check method | ||
var method = options.method || METHODS.GET; | ||
var method = DEFAULT_METHOD; | ||
if (options.method) { | ||
method = options.method.toUpperCase(); | ||
} | ||
if (!self.acceptMethod(method)) { | ||
@@ -101,27 +120,3 @@ return null; | ||
// 3. check navParams, if this route has match requirements defined for navParams | ||
var navParamsConfig = (self.config.navigate && self.config.navigate.params); | ||
if (navParamsConfig) { | ||
var navParamConfigKeys = Object.keys(navParamsConfig); | ||
var navParams = (options.navigate && options.navigate.params) || {}; | ||
var navParamMatched; | ||
for (i = 0, len = navParamConfigKeys.length; i < len; i++) { | ||
// for each navParam defined in the route config, make sure | ||
// the param passed in matches the defined pattern | ||
var configKey = navParamConfigKeys[i]; | ||
var pattern = navParamsConfig[configKey]; | ||
if (pattern instanceof RegExp) { | ||
navParamMatched = navParams[configKey] !== undefined && pattern.test(navParams[configKey]); | ||
} else { | ||
navParamMatched = (navParams[configKey] === pattern); | ||
} | ||
if (!navParamMatched) { | ||
// found a non-matching navParam -> this route does not match | ||
return null; | ||
} | ||
} | ||
} | ||
// 4. method/path/navParams all matched, extract the matched path params | ||
// 3. method/path/navParams all matched, extract the matched path params | ||
var routeParams = {}; | ||
@@ -137,3 +132,13 @@ for (i = 0, len = self.keys.length; i < len; i++) { | ||
return routeParams; | ||
// 4. query params | ||
var queryParams = {}; | ||
if (-1 !== pos) { | ||
queryParams = self._queryLib.parse(url.substring(pos+1)); | ||
} | ||
return { | ||
method: method, | ||
route: routeParams, | ||
query: queryParams | ||
}; | ||
}; | ||
@@ -145,9 +150,11 @@ | ||
* @param {Object} params The route parameters to be used to create the path string | ||
* @param {Object} [query] The query parameters to be used to create the path string | ||
* @return {String} The generated path string. | ||
* @for Route | ||
*/ | ||
Route.prototype.makePath = function (params) { | ||
Route.prototype.makePath = function (params, query) { | ||
var routePath = this.config.path; | ||
var compiler; | ||
var err; | ||
var url; | ||
@@ -163,3 +170,7 @@ if (Array.isArray(routePath)) { | ||
try { | ||
return compiler(params); | ||
url = compiler(params); | ||
if (query) { | ||
url += '?' + this._queryLib.stringify(query); | ||
} | ||
return url; | ||
} catch (e) { | ||
@@ -180,2 +191,4 @@ err = e; | ||
* @param {Object} routes Route table, which is a name to router config map. | ||
* @param {Object} [options] Options for parsing and generating the urls | ||
* @param {String} [options.queryLib] Library to use for `parse` and `stringify` methods | ||
* @constructor | ||
@@ -207,14 +220,32 @@ * @example | ||
*/ | ||
function Router(routes) { | ||
function Router(routes, options) { | ||
var self = this; | ||
self._routes = {}; | ||
self._routeOrder = []; | ||
self._options = options || {}; | ||
debug('new Router, routes = ', routes); | ||
if (routes) { | ||
Object.keys(routes).forEach(function createRoute(name) { | ||
self._routes[name] = new Route(name, routes[name]); | ||
if (!Array.isArray(routes)) { | ||
// Support handling route config object as an ordered map (legacy) | ||
self._routeOrder = Object.keys(routes); | ||
self._routeOrder.forEach(function createRoute(name) { | ||
self._routes[name] = new Route(name, routes[name], self._options); | ||
}); | ||
} else if (routes) { | ||
routes.forEach(function createRouteFromArrayValue(route) { | ||
if (!route.name) { | ||
throw new Error('Undefined route name for route ' + route.path); | ||
} | ||
// Route name already exists | ||
if (self._routes[route.name]) { | ||
throw new Error('Duplicate route with name ' + route.name); | ||
} | ||
self._routeOrder.push(route.name); | ||
self._routes[route.name] = new Route(route.name, route, self._options); | ||
}); | ||
} | ||
if (process.env.NODE_ENV !== 'production') { | ||
if ('function' === typeof Object.freeze) { | ||
Object.keys(self._routes).forEach(function freezeRoute(name) { | ||
self._routeOrder.forEach(function freezeRoute(name) { | ||
var route = self._routes[name]; | ||
@@ -237,9 +268,6 @@ Object.freeze(route.config); | ||
* @param {String} [options.method=get] The case-insensitive HTTP method string. | ||
* @param {Object} [options.navigate] The navigation info. | ||
* @param {Object} [options.navigate.type] The navigation type: 'pageload', 'click', 'popstate'. | ||
* @param {Object} [options.navigate.params] The navigation params (that are not part of the path). | ||
* @return {Object|null} The matched route info if path/method/navigate.params matches to a route; null otherwise. | ||
* @return {Object|null} The matched route info if path/method matches to a route; null otherwise. | ||
*/ | ||
Router.prototype.getRoute = function (url, options) { | ||
var keys = Object.keys(this._routes); | ||
var keys = this._routeOrder; | ||
var route; | ||
@@ -255,5 +283,6 @@ var match; | ||
url: url, | ||
params: match, | ||
method: match.method, | ||
params: match.route, | ||
config: route.config, | ||
navigate: options && options.navigate | ||
query: match.query | ||
}; | ||
@@ -270,8 +299,9 @@ } | ||
* @param {Object} params The route parameters to be used to create the path string | ||
* @param {Object} [query] The query parameters to be used to create the path string | ||
* @return {String} The generated path string, null if there is no route with the given name. | ||
*/ | ||
Router.prototype.makePath = function (name, params) { | ||
return (name && this._routes[name] && this._routes[name].makePath(params)) || null; | ||
Router.prototype.makePath = function (name, params, query) { | ||
return (name && this._routes[name] && this._routes[name].makePath(params, query)) || null; | ||
}; | ||
module.exports = Router; |
{ | ||
"name": "routr", | ||
"version": "0.1.3", | ||
"version": "1.0.0", | ||
"description": "A router for both server and client", | ||
@@ -12,4 +12,4 @@ "main": "index.js", | ||
"cover": "node node_modules/istanbul/lib/cli.js cover --dir artifacts -- ./node_modules/mocha/bin/_mocha tests/unit/ --recursive --reporter spec", | ||
"lint": "./node_modules/.bin/jshint lib tests", | ||
"test": "./node_modules/.bin/mocha tests/unit/ --recursive --reporter spec" | ||
"lint": "eslint .", | ||
"test": "mocha tests/unit/ --recursive --compilers js:babel-register --require babel-polyfill --reporter spec" | ||
}, | ||
@@ -25,15 +25,23 @@ "author": "Lingyan Zhu <lingyan@yahoo-inc.com", | ||
"debug": "^2.0.0", | ||
"path-to-regexp": "^1.1.1" | ||
"path-to-regexp": "^1.1.1", | ||
"query-string": "^3.0.1" | ||
}, | ||
"devDependencies": { | ||
"chai": "^2.0.0", | ||
"babel-eslint": "^5.0.0", | ||
"babel-polyfill": "^6.7.2", | ||
"babel-preset-es2015": "^6.6.0", | ||
"babel-register": "^6.7.2", | ||
"chai": "^3.2.0", | ||
"coveralls": "^2.11.1", | ||
"eslint": "~2.2.0", | ||
"eslint-plugin-babel": "^3.1.0", | ||
"istanbul": "^0.3.2", | ||
"jshint": "^2.5.1", | ||
"mocha": "^2.0.1", | ||
"precommit-hook": "^2.0.1" | ||
"pre-commit": "^1.0.7", | ||
"sinon": "^1.17.3" | ||
}, | ||
"jshintConfig": { | ||
"node": true | ||
}, | ||
"pre-commit": [ | ||
"lint", | ||
"test" | ||
], | ||
"keywords": [ | ||
@@ -40,0 +48,0 @@ "yahoo", |
@@ -19,4 +19,5 @@ # Routr | ||
var router = new Router({ | ||
view_user: { | ||
var router = new Router([ | ||
{ | ||
name: 'view_user', | ||
path: '/user/:id', | ||
@@ -28,10 +29,11 @@ method: 'get', | ||
}, | ||
view_user_post: { | ||
{ | ||
name: 'view_user_post', | ||
path: '/user/:id/post/:post', | ||
method: 'get' | ||
} | ||
}); | ||
]); | ||
// match route | ||
var route = router.getRoute('/user/garfield'); | ||
var route = router.getRoute('/user/garfield?foo=bar'); | ||
if (route) { | ||
@@ -43,2 +45,3 @@ // this will output: | ||
// - {path: "/user/:id", method: "get", foo: { bar: "baz"}} for route.config | ||
// - { foo: 'bar' } for route.query | ||
console.log('[Route found]:', route); | ||
@@ -48,4 +51,4 @@ } | ||
// generate path name (does not include query string) from route | ||
// "path" will be "/user/garfield/post/favoriteFood" | ||
var path = router.makePath('view_user_post', {id: 'garfield', post: 'favoriteFood'}); | ||
// "path" will be "/user/garfield/post/favoriteFood?meal=breakfast" | ||
var path = router.makePath('view_user_post', {id: 'garfield', post: 'favoriteFood'}, { meal: 'breakfast' }); | ||
@@ -52,0 +55,0 @@ ``` |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
43899
22
271
1
102
3
12
+ Addedquery-string@^3.0.1
+ Addedquery-string@3.0.3(transitive)
+ Addedstrict-uri-encode@1.1.0(transitive)