Skip to content
This repository
Browse code

Removed `router()` middleware. Closes #262

  • Loading branch information...
commit 2ca7ec3ff64cb7600bfd029233228236bf048671 1 parent 7d96c75
TJ Holowaychuk visionmedia authored

Showing 2 changed files with 0 additions and 802 deletions. Show diff stats Hide diff stats

  1. +0 379 lib/middleware/router.js
  2. +0 423 test/router.test.js
379 lib/middleware/router.js
... ... @@ -1,379 +0,0 @@
1   -
2   -/*!
3   - * Connect - router
4   - * Copyright(c) 2010 Sencha Inc.
5   - * Copyright(c) 2011 TJ Holowaychuk
6   - * MIT Licensed
7   - */
8   -
9   -/**
10   - * Module dependencies.
11   - */
12   -
13   -var utils = require('../utils')
14   - , parse = require('url').parse;
15   -
16   -/**
17   - * Expose router.
18   - */
19   -
20   -exports = module.exports = router;
21   -
22   -/**
23   - * Supported HTTP / WebDAV methods.
24   - */
25   -
26   -var _methods = exports.methods = [
27   - 'get'
28   - , 'post'
29   - , 'put'
30   - , 'delete'
31   - , 'connect'
32   - , 'options'
33   - , 'trace'
34   - , 'copy'
35   - , 'lock'
36   - , 'mkcol'
37   - , 'move'
38   - , 'propfind'
39   - , 'proppatch'
40   - , 'unlock'
41   - , 'report'
42   - , 'mkactivity'
43   - , 'checkout'
44   - , 'merge'
45   -];
46   -
47   -/**
48   - * Provides Sinatra and Express-like routing capabilities.
49   - *
50   - * Examples:
51   - *
52   - * connect.router(function(app){
53   - * app.get('/user/:id', function(req, res, next){
54   - * // populates req.params.id
55   - * });
56   - * app.put('/user/:id', function(req, res, next){
57   - * // populates req.params.id
58   - * });
59   - * })
60   - *
61   - * @param {Function} fn
62   - * @return {Function}
63   - * @api public
64   - */
65   -
66   -function router(fn){
67   - var self = this
68   - , methods = {}
69   - , routes = {}
70   - , params = {};
71   -
72   - if (!fn) throw new Error('router provider requires a callback function');
73   -
74   - // Generate method functions
75   - _methods.forEach(function(method){
76   - methods[method] = generateMethodFunction(method.toUpperCase());
77   - });
78   -
79   - // Alias del -> delete
80   - methods.del = methods.delete;
81   -
82   - // Apply callback to all methods
83   - methods.all = function(){
84   - var args = arguments;
85   - _methods.forEach(function(name){
86   - methods[name].apply(this, args);
87   - });
88   - return self;
89   - };
90   -
91   - // Register param callback
92   - methods.param = function(name, fn){
93   - params[name] = fn;
94   - };
95   -
96   - fn.call(this, methods);
97   -
98   - function generateMethodFunction(name) {
99   - var localRoutes = routes[name] = routes[name] || [];
100   - return function(path, fn){
101   - var keys = []
102   - , middleware = [];
103   -
104   - // slice middleware
105   - if (arguments.length > 2) {
106   - middleware = Array.prototype.slice.call(arguments, 1, arguments.length);
107   - fn = middleware.pop();
108   - middleware = utils.flatten(middleware);
109   - }
110   -
111   - fn.middleware = middleware;
112   -
113   - if (!path) throw new Error(name + ' route requires a path');
114   - if (!fn) throw new Error(name + ' route ' + path + ' requires a callback');
115   - var regexp = path instanceof RegExp
116   - ? path
117   - : normalizePath(path, keys);
118   - localRoutes.push({
119   - fn: fn
120   - , path: regexp
121   - , keys: keys
122   - , orig: path
123   - , method: name
124   - });
125   - return self;
126   - };
127   - }
128   -
129   - function router(req, res, next){
130   - var route
131   - , self = this;
132   -
133   - (function pass(i){
134   - if (route = match(req, routes, i)) {
135   - var i = 0
136   - , keys = route.keys;
137   -
138   - req.params = route.params;
139   -
140   - // Param preconditions
141   - (function param(err) {
142   - try {
143   - var key = keys[i++]
144   - , val = req.params[key]
145   - , fn = params[key];
146   -
147   - if ('route' == err) {
148   - pass(req._route_index + 1);
149   - // Error
150   - } else if (err) {
151   - next(err);
152   - // Param has callback
153   - } else if (fn) {
154   - // Return style
155   - if (1 == fn.length) {
156   - req.params[key] = fn(val);
157   - param();
158   - // Middleware style
159   - } else {
160   - fn(req, res, param, val);
161   - }
162   - // Finished processing params
163   - } else if (!key) {
164   - // route middleware
165   - i = 0;
166   - (function nextMiddleware(err){
167   - var fn = route.middleware[i++];
168   - if ('route' == err) {
169   - pass(req._route_index + 1);
170   - } else if (err) {
171   - next(err);
172   - } else if (fn) {
173   - fn(req, res, nextMiddleware);
174   - } else {
175   - route.call(self, req, res, function(err){
176   - if (err) {
177   - next(err);
178   - } else {
179   - pass(req._route_index + 1);
180   - }
181   - });
182   - }
183   - })();
184   - // More params
185   - } else {
186   - param();
187   - }
188   - } catch (err) {
189   - next(err);
190   - }
191   - })();
192   - } else if ('OPTIONS' == req.method) {
193   - options(req, res, routes);
194   - } else {
195   - next();
196   - }
197   - })();
198   - };
199   -
200   - router.remove = function(path, method){
201   - var fns = router.lookup(path, method);
202   - fns.forEach(function(fn){
203   - routes[fn.method].splice(fn.index, 1);
204   - });
205   - };
206   -
207   - router.lookup = function(path, method, ret){
208   - ret = ret || [];
209   -
210   - // method specific lookup
211   - if (method) {
212   - method = method.toUpperCase();
213   - if (routes[method]) {
214   - routes[method].forEach(function(route, i){
215   - if (path == route.orig) {
216   - var fn = route.fn;
217   - fn.regexp = route.path;
218   - fn.keys = route.keys;
219   - fn.path = route.orig;
220   - fn.method = route.method;
221   - fn.index = i;
222   - ret.push(fn);
223   - }
224   - });
225   - }
226   - // global lookup
227   - } else {
228   - _methods.forEach(function(method){
229   - router.lookup(path, method, ret);
230   - });
231   - }
232   -
233   - return ret;
234   - };
235   -
236   - router.match = function(url, method, ret){
237   - var ret = ret || []
238   - , i = 0
239   - , fn
240   - , req;
241   -
242   - // method specific matches
243   - if (method) {
244   - method = method.toUpperCase();
245   - req = { url: url, method: method };
246   - while (fn = match(req, routes, i)) {
247   - i = req._route_index + 1;
248   - ret.push(fn);
249   - }
250   - // global matches
251   - } else {
252   - _methods.forEach(function(method){
253   - router.match(url, method, ret);
254   - });
255   - }
256   -
257   - return ret;
258   - };
259   -
260   - return router;
261   -}
262   -
263   -/**
264   - * Respond to OPTIONS.
265   - *
266   - * @param {ServerRequest} req
267   - * @param {ServerResponse} req
268   - * @param {Array} routes
269   - * @api private
270   - */
271   -
272   -function options(req, res, routes) {
273   - var pathname = parse(req.url).pathname
274   - , body = optionsFor(pathname, routes).join(',');
275   - res.writeHead(200, {
276   - 'Content-Length': body.length
277   - , 'Allow': body
278   - });
279   - res.end(body);
280   -}
281   -
282   -/**
283   - * Return OPTIONS array for the given `path`, matching `routes`.
284   - *
285   - * @param {String} path
286   - * @param {Array} routes
287   - * @return {Array}
288   - * @api private
289   - */
290   -
291   -function optionsFor(path, routes) {
292   - return _methods.filter(function(method){
293   - var arr = routes[method.toUpperCase()];
294   - for (var i = 0, len = arr.length; i < len; ++i) {
295   - if (arr[i].path.test(path)) return true;
296   - }
297   - }).map(function(method){
298   - return method.toUpperCase();
299   - });
300   -}
301   -
302   -/**
303   - * Normalize the given path string,
304   - * returning a regular expression.
305   - *
306   - * An empty array should be passed,
307   - * which will contain the placeholder
308   - * key names. For example "/user/:id" will
309   - * then contain ["id"].
310   - *
311   - * @param {String} path
312   - * @param {Array} keys
313   - * @return {RegExp}
314   - * @api private
315   - */
316   -
317   -function normalizePath(path, keys) {
318   - path = path
319   - .concat('/?')
320   - .replace(/\/\(/g, '(?:/')
321   - .replace(/(\/)?(\.)?:(\w+)(?:(\(.*?\)))?(\?)?/g, function(_, slash, format, key, capture, optional){
322   - keys.push(key);
323   - slash = slash || '';
324   - return ''
325   - + (optional ? '' : slash)
326   - + '(?:'
327   - + (optional ? slash : '')
328   - + (format || '') + (capture || '([^/]+?)') + ')'
329   - + (optional || '');
330   - })
331   - .replace(/([\/.])/g, '\\$1')
332   - .replace(/\*/g, '(.+)');
333   - return new RegExp('^' + path + '$', 'i');
334   -}
335   -
336   -/**
337   - * Attempt to match the given request to
338   - * one of the routes. When successful
339   - * a route function is returned.
340   - *
341   - * @param {ServerRequest} req
342   - * @param {Object} routes
343   - * @return {Function}
344   - * @api private
345   - */
346   -
347   -function match(req, routes, i) {
348   - var captures
349   - , method = req.method
350   - , i = i || 0;
351   - if ('HEAD' == method) method = 'GET';
352   - if (routes = routes[method]) {
353   - var url = parse(req.url)
354   - , pathname = url.pathname;
355   - for (var len = routes.length; i < len; ++i) {
356   - var route = routes[i]
357   - , fn = route.fn
358   - , path = route.path
359   - , keys = fn.keys = route.keys;
360   - if (captures = path.exec(pathname)) {
361   - fn.method = method;
362   - fn.params = [];
363   - for (var j = 1, len = captures.length; j < len; ++j) {
364   - var key = keys[j-1],
365   - val = typeof captures[j] === 'string'
366   - ? decodeURIComponent(captures[j])
367   - : captures[j];
368   - if (key) {
369   - fn.params[key] = val;
370   - } else {
371   - fn.params.push(val);
372   - }
373   - }
374   - req._route_index = i;
375   - return fn;
376   - }
377   - }
378   - }
379   -}
423 test/router.test.js
... ... @@ -1,423 +0,0 @@
1   -
2   -/**
3   - * Module dependencies.
4   - */
5   -
6   -var connect = require('connect')
7   - , assert = require('assert')
8   - , should = require('should')
9   - , http = require('http')
10   - , create = require('./common').create;
11   -
12   -module.exports = {
13   - 'test methods': function(){
14   - var app = create(
15   - connect.router(function(app){
16   - app.get('/', function(req, res){
17   - res.end('GET /');
18   - });
19   -
20   - app.post('/', function(req, res){
21   - res.end('POST /');
22   - });
23   -
24   - app.put('/', function(req, res){
25   - res.end('PUT /');
26   - });
27   - })
28   - );
29   -
30   - assert.response(app,
31   - { url: '/' },
32   - { body: 'GET /' });
33   -
34   - assert.response(app,
35   - { url: '/', method: 'POST' },
36   - { body: 'POST /' });
37   -
38   - assert.response(app,
39   - { url: '/', method: 'PUT' },
40   - { body: 'PUT /' });
41   - },
42   -
43   - 'test params': function(){
44   - var app = create(
45   - connect.router(function(app){
46   - app.get('/user/:id', function(req, res){
47   - res.end('user ' + req.params.id);
48   - });
49   -
50   - app.get('/user/:id/:op', function(req, res){
51   - res.end(req.params.op + 'ing user ' + req.params.id);
52   - });
53   - })
54   - );
55   -
56   - assert.response(app,
57   - { url: '/user/12/' },
58   - { body: 'user 12' });
59   -
60   - assert.response(app,
61   - { url: '/user/12' },
62   - { body: 'user 12' });
63   -
64   - assert.response(app,
65   - { url: '/user/tj.holowaychuk' },
66   - { body: 'user tj.holowaychuk' });
67   -
68   - assert.response(app,
69   - { url: '/user/12/edit' },
70   - { body: 'editing user 12' });
71   - },
72   -
73   - 'test optional params': function(){
74   - var app = create(
75   - connect.router(function(app){
76   - app.get('/user/:id?', function(req, res){
77   - res.end('user ' + (req.params.id || 'account'));
78   - });
79   -
80   - app.get('/account/:id?/:op', function(req, res){
81   - res.end(req.params.op + 'ing user ' + (req.params.id || 'account'));
82   - });
83   - })
84   - );
85   -
86   - assert.response(app,
87   - { url: '/user/12' },
88   - { body: 'user 12' });
89   -
90   - assert.response(app,
91   - { url: '/account/edit' },
92   - { body: 'editing user account' });
93   -
94   - assert.response(app,
95   - { url: '/account/12/edit' },
96   - { body: 'editing user 12' });
97   - },
98   -
99   - 'test splat': function(){
100   - var app = create(
101   - connect.router(function(app){
102   - app.get('/file/*', function(req, res){
103   - res.end('file ' + req.params[0]);
104   - });
105   - })
106   - );
107   -
108   - assert.response(app,
109   - { url: '/file' },
110   - { status: 404 });
111   -
112   - assert.response(app,
113   - { url: '/file/jquery.js' },
114   - { body: 'file jquery.js' });
115   -
116   - assert.response(app,
117   - { url: '/file/public/javascripts/jquery.js' },
118   - { body: 'file public/javascripts/jquery.js' });
119   - },
120   -
121   - 'test several splats': function(){
122   - var app = create(
123   - connect.router(function(app){
124   - app.get('/file/*.*', function(req, res){
125   - res.end('file ' + req.params[0] + ' ext ' + req.params[1]);
126   - });
127   -
128   - app.get('/move/*/to/*', function(req, res){
129   - res.end('moved ' + req.params[0] + ' to ' + req.params[1]);
130   - });
131   - })
132   - );
133   -
134   - assert.response(app,
135   - { url: '/file/jquery.js' },
136   - { body: 'file jquery ext js' });
137   -
138   - assert.response(app,
139   - { url: '/file/public/javascripts/jquery.js' },
140   - { body: 'file public/javascripts/jquery ext js' });
141   -
142   - assert.response(app,
143   - { url: '/move/jquery/to/jquery.js' },
144   - { body: 'moved jquery to jquery.js' });
145   - },
146   -
147   - 'test named captures': function(){
148   - var app = create(
149   - connect.router(function(app){
150   - app.get('/page/:from(\\d+)-:to(\\d+)', function(req, res){
151   - res.end('viewing ' + req.params.from + ' to ' + req.params.to);
152   - });
153   - })
154   - );
155   -
156   - assert.response(app,
157   - { url: '/page/1-9' },
158   - { body: 'viewing 1 to 9' });
159   -
160   - assert.response(app,
161   - { url: '/page/3-b' },
162   - { status: 404 });
163   - },
164   -
165   - 'test format': function(){
166   - var app = create(
167   - connect.router(function(app){
168   - app.get('/users.:format', function(req, res){
169   - res.end('format ' + req.params.format);
170   - });
171   -
172   - app.get('/users', function(req, res){
173   - res.end('users');
174   - });
175   - })
176   - );
177   -
178   - assert.response(app,
179   - { url: '/users' },
180   - { body: 'users' });
181   -
182   - assert.response(app,
183   - { url: '/users.json' },
184   - { body: 'format json' });
185   - },
186   -
187   - 'test optional format': function(){
188   - var app = create(
189   - connect.router(function(app){
190   - app.get('/users.:format?', function(req, res){
191   - res.end('format ' + (req.params.format || 'html'));
192   - });
193   - })
194   - );
195   -
196   - assert.response(app,
197   - { url: '/users' },
198   - { body: 'format html' });
199   -
200   - assert.response(app,
201   - { url: '/users.json' },
202   - { body: 'format json' });
203   - },
204   -
205   - 'test regular expressions': function(){
206   - var app = create(
207   - connect.router(function(app){
208   - app.get(/\/commits\/(\w+)\.\.(\w+)\/?/i, function(req, res){
209   - res.end(
210   - 'from ' + req.params[0]
211   - + ' to ' + req.params[1]);
212   - });
213   - })
214   - );
215   -
216   - assert.response(app,
217   - { url: '/commits/abc..def' },
218   - { body: 'from abc to def' });
219   - },
220   -
221   - 'test next()': function(){
222   - var hits = [];
223   -
224   - var app = create(
225   - connect.router(function(app){
226   - app.get('/:user', function(req, res, next){
227   - hits.push('a');
228   - next();
229   - });
230   -
231   - app.get('/:user', function(req, res, next){
232   - hits.push('b');
233   - next();
234   - });
235   -
236   - app.get('/:user', function(req, res, next){
237   - hits.push('c');
238   - res.end(req.params.user);
239   - });
240   - })
241   - );
242   -
243   - assert.response(app,
244   - { url: '/tj' },
245   - { body: 'tj' },
246   - function(){
247   - hits.should.eql(['a', 'b', 'c']);
248   - });
249   - },
250   -
251   - 'test next(err)': function(){
252   - var hits = [];
253   -
254   - var app = create(
255   - connect.router(function(app){
256   - app.get('/:user', function(req, res, next){
257   - hits.push('a');
258   - next();
259   - });
260   -
261   - app.get('/:user', function(req, res, next){
262   - hits.push('b');
263   - next(new Error('keyboard cat'));
264   - });
265   -
266   - app.get('/:user', function(req, res, next){
267   - hits.push('c');
268   - res.end(req.params.user);
269   - });
270   - }),
271   - function(err, req, res, next) {
272   - res.end(err.toString());
273   - }
274   - );
275   -
276   - assert.response(app,
277   - { url: '/tj' },
278   - { body: 'Error: keyboard cat' },
279   - function(){
280   - hits.should.eql(['a', 'b']);
281   - });
282   - },
283   -
284   - 'test HEAD': function(){
285   - var app = create(
286   - connect.router(function(app){
287   - app.get('/items', function(req, res){
288   - res.end('HEAD' == req.method
289   - ? ''
290   - : 'foo, bar, baz');
291   - });
292   - })
293   - );
294   -
295   - assert.response(app,
296   - { url: '/items', method: 'HEAD' },
297   - { body: '' });
298   - },
299   -
300   - 'test OPTIONS': function(){
301   - var app = create(
302   - connect.router(function(app){
303   - app.get('/items', function(){});
304   - app.post('/items', function(){});
305   - app.get('/users', function(){});
306   - app.options('/accounts', function(req, res){
307   - res.writeHead(204, { Allow: 'GET' });
308   - res.end();
309   - });
310   - })
311   - );
312   -
313   - assert.response(app,
314   - { url: '/items', method: 'OPTIONS' },
315   - { body: 'GET,POST', headers: { Allow: 'GET,POST' }});
316   -
317   - assert.response(app,
318   - { url: '/users', method: 'OPTIONS' },
319   - { body: 'GET', headers: { Allow: 'GET' }});
320   -
321   - assert.response(app,
322   - { url: '/accounts', method: 'OPTIONS' },
323   - { headers: { Allow: 'GET' }});
324   - },
325   -
326   - 'test immutable params': function(){
327   - var app = create(
328   - connect.router(function(app){
329   - app.get('/user/:id', function(req, res, next){
330   - req.params.id = parseInt(req.params.id, 10);
331   - next();
332   - });
333   -
334   - app.get('/user/:id', function(req, res){
335   - res.end(typeof req.params.id);
336   - });
337   - })
338   - );
339   -
340   - assert.response(app,
341   - { url: '/user/12' },
342   - { body: 'string' });
343   - },
344   -
345   - 'test .lookup()': function(){
346   - var router = connect.router(function(app){
347   - app.get('/user/:id', function(req, res, next){
348   - req.params.id = parseInt(req.params.id, 10);
349   - next();
350   - });
351   -
352   - app.get('/user/:id', function(req, res){
353   - res.end(typeof req.params.id);
354   - });
355   -
356   - app.put('/user/:id', function(){});
357   - app.get('/user/:id/edit', function(){});
358   - app.post('/user', function(){});
359   - });
360   -
361   - var fn = router.lookup('/user/:id')[0];
362   - fn.regexp.should.be.an.instanceof(RegExp);
363   - fn.path.should.equal('/user/:id');
364   - fn.method.should.equal('GET');
365   - fn.keys.should.eql(['id']);
366   -
367   - router.lookup('/user/:id')[0].should.be.a('function');
368   - router.lookup('/user/:id').should.have.length(3);
369   - router.lookup('/user/:id', 'GET').should.have.length(2);
370   - router.lookup('/user/:id', 'get').should.have.length(2);
371   - router.lookup('/user/:id/edit', 'GET').should.have.length(1);
372   - router.lookup('/user/:id', 'PUT').should.have.length(1);
373   - router.lookup('/user/:id', 'FOO').should.be.empty;
374   - },
375   -
376   - 'test .match()': function(){
377   - var router = connect.router(function(app){
378   - app.get('/user/:id', function(req, res, next){
379   - req.params.id = parseInt(req.params.id, 10);
380   - next();
381   - });
382   -
383   - app.get('/user/:id', function(req, res){
384   - res.end(typeof req.params.id);
385   - });
386   -
387   - app.put('/user/:id', function(){});
388   - app.get('/user/:id/edit', function(){});
389   - app.post('/user', function(){});
390   - });
391   -
392   - var fn = router.match('/user/12')[0];
393   - fn.keys.should.eql(['id']);
394   - fn.params.id.should.equal('12');
395   -
396   - router.match('/').should.be.empty;
397   - router.match('/', 'GET').should.be.empty;
398   - router.match('/user/12', 'GET')[0].should.be.a('function');
399   - router.match('/user/12/edit', 'GET').should.have.length(1);
400   - router.match('/user/12', 'GET').should.have.length(2);
401   - router.match('/user/12', 'PUT').should.have.length(1);
402   - router.match('/user', 'POST').should.have.length(1);
403   - router.match('/user').should.have.length(1);
404   - },
405   -
406   - 'test .remove()': function(){
407   - var router = connect.router(function(app){
408   - app.get('/', function(req, res){});
409   - app.get('/foo/bar', function(req, res){});
410   - app.get('/bar', function(req, res){});
411   - app.put('/bar', function(req, res){});
412   - app.post('/bar', function(req, res){});
413   - });
414   -
415   - router.remove('/', 'GET');
416   - router.remove('/bar');
417   - router.lookup('/', 'GET').should.be.empty;
418   - router.lookup('/bar', 'GET').should.be.empty;
419   - router.lookup('/bar', 'PUT').should.be.empty;
420   - router.lookup('/bar', 'POST').should.be.empty;
421   - router.lookup('/foo/bar', 'GET').should.not.be.empty;
422   - }
423   -};

0 comments on commit 2ca7ec3

Please sign in to comment.
Something went wrong with that request. Please try again.