express
Advanced tools
Comparing version 2.4.4 to 2.4.5
2.4.5 / 2011-08-19 | ||
================== | ||
* Added support for routes to handle errors. Closes #809 | ||
* Added `app.routes.all()`. Closes #803 | ||
* Added "basepath" setting to work in conjunction with reverse proxies etc. * Refactored `Route` to use a single array of callbacks | ||
* Added support for multiple callbacks for `app.param()`. Closes #801 | ||
Closes #805 | ||
* Changed: removed .call(self) for route callbacks | ||
* Dependency: `qs >= 0.3.1` | ||
* Fixed `res.redirect()` on windows due to `join()` usage. Closes #808 | ||
2.4.4 / 2011-08-05 | ||
@@ -3,0 +15,0 @@ ================== |
@@ -31,3 +31,3 @@ | ||
exports.version = '2.4.4'; | ||
exports.version = '2.4.5'; | ||
@@ -34,0 +34,0 @@ /** |
@@ -69,3 +69,2 @@ | ||
this.set('home', '/'); | ||
this.set('env', process.env.NODE_ENV || 'development'); | ||
@@ -212,3 +211,3 @@ | ||
app.use = function(route, middleware){ | ||
var app, home, handle; | ||
var app, base, handle; | ||
@@ -239,5 +238,6 @@ if ('string' != typeof route) { | ||
if (app) { | ||
home = app.set('home'); | ||
if ('/' == home) home = ''; | ||
app.set('home', app.route + home); | ||
base = this.set('basepath') || this.route; | ||
if ('/' == base) base = ''; | ||
base = base + (app.set('basepath') || app.route); | ||
app.set('basepath', base); | ||
app.parent = this; | ||
@@ -318,3 +318,3 @@ if (app.__mounted) app.__mounted.call(app, this); | ||
/** | ||
* Map the given param placeholder `name`(s) to the given callback `fn`. | ||
* Map the given param placeholder `name`(s) to the given callback(s). | ||
* | ||
@@ -339,2 +339,34 @@ * Param mapping is used to provide pre-conditions to routes | ||
* | ||
* Passing a single function allows you to map logic | ||
* to the values passed to `app.param()`, for example | ||
* this is useful to provide coercion support in a concise manner. | ||
* | ||
* The following example maps regular expressions to param values | ||
* ensuring that they match, otherwise passing control to the next | ||
* route: | ||
* | ||
* app.param(function(name, regexp){ | ||
* if (regexp instanceof RegExp) { | ||
* return function(req, res, next, val){ | ||
* var captures; | ||
* if (captures = regexp.exec(String(val))) { | ||
* req.params[name] = captures; | ||
* next(); | ||
* } else { | ||
* next('route'); | ||
* } | ||
* } | ||
* } | ||
* }); | ||
* | ||
* We can now use it as shown below, where "/commit/:commit" expects | ||
* that the value for ":commit" is at 5 or more digits. The capture | ||
* groups are then available as `req.params.commit` as we defined | ||
* in the function above. | ||
* | ||
* app.param('commit', /^\d{5,}$/); | ||
* | ||
* For more of this useful functionality take a look | ||
* at [express-params](http://github.com/visionmedia/express-params). | ||
* | ||
* @param {String|Array|Function} name | ||
@@ -347,7 +379,12 @@ * @param {Function} fn | ||
app.param = function(name, fn){ | ||
var self = this | ||
, fns = [].slice.call(arguments, 1); | ||
// array | ||
if (Array.isArray(name)) { | ||
name.forEach(function(name){ | ||
this.param(name, fn); | ||
}, this); | ||
fns.forEach(function(fn){ | ||
self.param(name, fn); | ||
}); | ||
}); | ||
// param logic | ||
@@ -359,3 +396,5 @@ } else if ('function' == typeof name) { | ||
if (':' == name[0]) name = name.substr(1); | ||
this.routes.param(name, fn); | ||
fns.forEach(function(fn){ | ||
self.routes.param(name, fn); | ||
}); | ||
} | ||
@@ -362,0 +401,0 @@ |
@@ -305,3 +305,3 @@ | ||
* - `maxAge` max-age in milliseconds, converted to `expires` | ||
* - `path` defaults to the "home" setting which is typically "/" | ||
* - `path` defaults to the "basepath" setting which is typically "/" | ||
* | ||
@@ -325,3 +325,3 @@ * Examples: | ||
if ('maxAge' in options) options.expires = new Date(Date.now() + options.maxAge); | ||
if (undefined === options.path) options.path = this.app.set('home'); | ||
if (undefined === options.path) options.path = this.app.set('basepath'); | ||
var cookie = utils.serializeCookie(name, val, options); | ||
@@ -338,4 +338,4 @@ this.header('Set-Cookie', cookie); | ||
* to the _Referrer_ or _Referer_ headers or the application's | ||
* "home" setting. Express also supports "home" out of the box, | ||
* which can be set via `app.set('home', '/blog');`, and defaults | ||
* "basepath" setting. Express also supports "basepath" out of the box, | ||
* which can be set via `app.set('basepath', '/blog');`, and defaults | ||
* to '/'. | ||
@@ -380,3 +380,3 @@ * | ||
, req = this.req | ||
, base = app.set('home') || '/' | ||
, base = app.set('basepath') || app.route | ||
, status = status || 302 | ||
@@ -405,3 +405,3 @@ , body; | ||
// Respect mount-point | ||
if (app.route) url = join(app.route, url); | ||
if ('/' != base && 0 != url.indexOf(base)) url = base + url; | ||
@@ -413,3 +413,2 @@ // Absolute | ||
} | ||
@@ -416,0 +415,0 @@ // Support text/{plain,html} by default |
@@ -82,3 +82,3 @@ | ||
this.params[name] = fn; | ||
(this.params[name] = this.params[name] || []).push(fn); | ||
return this; | ||
@@ -88,2 +88,15 @@ }; | ||
/** | ||
* Return a `Collection` of all routes defined. | ||
* | ||
* @return {Collection} | ||
* @api public | ||
*/ | ||
Router.prototype.all = function(){ | ||
return this.find(function(){ | ||
return true; | ||
}); | ||
}; | ||
/** | ||
* Remove the given `route`, returns | ||
@@ -187,10 +200,14 @@ * a bool indicating if the route was present | ||
// route dispatch | ||
(function pass(i){ | ||
var route | ||
(function pass(i, err){ | ||
var paramCallbacks | ||
, paramIndex = 0 | ||
, paramVal | ||
, route | ||
, keys | ||
, key | ||
, ret; | ||
// match next route | ||
function nextRoute() { | ||
pass(req._route_index + 1); | ||
function nextRoute(err) { | ||
pass(req._route_index + 1, err); | ||
} | ||
@@ -205,3 +222,3 @@ | ||
// no route | ||
if (!route) return next(); | ||
if (!route) return next(err); | ||
@@ -214,8 +231,8 @@ // we have a route | ||
(function param(err) { | ||
var key = keys[i++] | ||
, val = key && req.params[key.name] | ||
, fn = key && params[key.name] | ||
, ret; | ||
// param callbacks | ||
function param(err) { | ||
key = keys[i++]; | ||
paramVal = key && req.params[key.name]; | ||
paramCallbacks = key && params[key.name]; | ||
try { | ||
@@ -225,5 +242,6 @@ if ('route' == err) { | ||
} else if (err) { | ||
next(err); | ||
} else if (fn && undefined !== val) { | ||
fn(req, res, param, val); | ||
i = 0; | ||
callbacks(err); | ||
} else if (paramCallbacks && undefined !== paramVal) { | ||
paramCallback(); | ||
} else if (key) { | ||
@@ -233,30 +251,36 @@ param(); | ||
i = 0; | ||
middleware(); | ||
callbacks(); | ||
} | ||
} catch (err) { | ||
next(err); | ||
param(err); | ||
} | ||
})(); | ||
// invoke route middleware | ||
function middleware(err) { | ||
var fn = route.middleware[i++]; | ||
if ('route' == err) { | ||
nextRoute(); | ||
} else if (err) { | ||
next(err); | ||
} else if (fn) { | ||
fn(req, res, middleware); | ||
} else { | ||
done(); | ||
} | ||
}; | ||
// invoke middleware callback | ||
function done() { | ||
route.callback.call(self, req, res, function(err){ | ||
if (err) return next(err); | ||
pass(req._route_index + 1); | ||
}); | ||
param(err); | ||
// single param callbacks | ||
function paramCallback(err) { | ||
var fn = paramCallbacks[paramIndex++]; | ||
if (err || !fn) return param(err); | ||
fn(req, res, paramCallback, paramVal, key.name); | ||
} | ||
// invoke route callbacks | ||
function callbacks(err) { | ||
var fn = route.callbacks[i++]; | ||
try { | ||
if ('route' == err) { | ||
nextRoute(); | ||
} else if (err && fn) { | ||
if (fn.length < 4) return callbacks(err); | ||
fn(err, req, res, callbacks); | ||
} else if (fn) { | ||
fn(req, res, callbacks); | ||
} else { | ||
nextRoute(err); | ||
} | ||
} catch (err) { | ||
callbacks(err); | ||
} | ||
} | ||
})(0); | ||
@@ -354,9 +378,7 @@ }; | ||
/** | ||
* Route `method`, `path`, and optional middleware | ||
* to the callback `fn`. | ||
* Route `method`, `path`, and one or more callbacks. | ||
* | ||
* @param {String} method | ||
* @param {String} path | ||
* @param {Function} ... | ||
* @param {Function} fn | ||
* @param {Function} callback... | ||
* @return {Router} for chaining | ||
@@ -366,22 +388,13 @@ * @api private | ||
Router.prototype._route = function(method, path, fn){ | ||
Router.prototype._route = function(method, path, callbacks){ | ||
var app = this.app | ||
, middleware = []; | ||
, callbacks = utils.flatten(toArray(arguments, 2)); | ||
// slice middleware | ||
if (arguments.length > 3) { | ||
middleware = toArray(arguments, 2); | ||
fn = middleware.pop(); | ||
middleware = utils.flatten(middleware); | ||
} | ||
// ensure path was given | ||
if (!path) throw new Error('app.' + method + '() requires a path'); | ||
// ensure path and callback are given | ||
if (!path) throw new Error(method + 'route requires a path'); | ||
if (!fn) throw new Error(method + ' route ' + path + ' requires a callback'); | ||
// create the route | ||
var route = new Route(method, path, fn, { | ||
var route = new Route(method, path, callbacks, { | ||
sensitive: app.enabled('case sensitive routes') | ||
, strict: app.enabled('strict routing') | ||
, middleware: middleware | ||
}); | ||
@@ -388,0 +401,0 @@ |
@@ -16,3 +16,3 @@ | ||
* Initialize `Route` with the given HTTP `method`, `path`, | ||
* and callback `fn` and `options`. | ||
* and an array of `callbacks` and `options`. | ||
* | ||
@@ -23,7 +23,6 @@ * Options: | ||
* - `strict` enable strict matching for trailing slashes | ||
* - `middleware` array of middleware | ||
* | ||
* @param {String} method | ||
* @param {String} path | ||
* @param {Function} fn | ||
* @param {Array} callbacks | ||
* @param {Object} options. | ||
@@ -33,8 +32,7 @@ * @api private | ||
function Route(method, path, fn, options) { | ||
function Route(method, path, callbacks, options) { | ||
options = options || {}; | ||
this.callback = fn; | ||
this.path = path; | ||
this.method = method; | ||
this.middleware = options.middleware; | ||
this.callbacks = callbacks; | ||
this.regexp = normalize(path | ||
@@ -41,0 +39,0 @@ , this.keys = [] |
@@ -182,4 +182,2 @@ | ||
merge(options, object); | ||
} else { | ||
options.scope = object; | ||
} | ||
@@ -186,0 +184,0 @@ } |
{ | ||
"name": "express", | ||
"description": "Sinatra inspired web development framework", | ||
"version": "2.4.4", | ||
"version": "2.4.5", | ||
"author": "TJ Holowaychuk <tj@vision-media.ca>", | ||
@@ -15,3 +15,3 @@ "contributors": [ | ||
"mime": ">= 0.0.1", | ||
"qs": ">= 0.3.0" | ||
"qs": ">= 0.3.1" | ||
}, | ||
@@ -18,0 +18,0 @@ "devDependencies": { |
Sorry, the diff of this file is not supported yet
2527
109418
21
Updatedqs@>= 0.3.1