Commit b3f6d49d authored by Leo Iannacone's avatar Leo Iannacone

upgrade express 4.4.1

parent 4b85b75d
../express/bin/express
\ No newline at end of file
.git* .git*
benchmarks/
coverage/
docs/ docs/
examples/ examples/
support/ support/
test/ test/
testing.js testing.js
.DS_Store .DS_Store
coverage.html .travis.yml
lib-cov Contributing.md
language: node_js
node_js:
- "0.8"
- "0.10"
\ No newline at end of file
4.0.0 / 4.4.1 / 2014-06-02
==================
* deps: methods@1.0.1
* deps: send@0.4.1
- Send `max-age` in `Cache-Control` in correct format
* deps: serve-static@1.2.1
- use `escape-html` for escaping
- deps: send@0.4.1
4.4.0 / 2014-05-30
==================
* custom etag control with `app.set('etag', val)`
- `app.set('etag', function(body, encoding){ return '"etag"' })` custom etag generation
- `app.set('etag', 'weak')` weak tag
- `app.set('etag', 'strong')` strong etag
- `app.set('etag', false)` turn off
- `app.set('etag', true)` standard etag
* mark `res.send` ETag as weak and reduce collisions
* update accepts to 1.0.2
- Fix interpretation when header not in request
* update send to 0.4.0
- Calculate ETag with md5 for reduced collisions
- Ignore stream errors after request ends
- deps: debug@0.8.1
* update serve-static to 1.2.0
- Calculate ETag with md5 for reduced collisions
- Ignore stream errors after request ends
- deps: send@0.4.0
4.3.2 / 2014-05-28
==================
* fix handling of errors from `router.param()` callbacks
4.3.1 / 2014-05-23
==================
* revert "fix behavior of multiple `app.VERB` for the same path"
- this caused a regression in the order of route execution
4.3.0 / 2014-05-21
==================
* add `req.baseUrl` to access the path stripped from `req.url` in routes
* fix behavior of multiple `app.VERB` for the same path
* fix issue routing requests among sub routers
* invoke `router.param()` only when necessary instead of every match
* proper proxy trust with `app.set('trust proxy', trust)`
- `app.set('trust proxy', 1)` trust first hop
- `app.set('trust proxy', 'loopback')` trust loopback addresses
- `app.set('trust proxy', '10.0.0.1')` trust single IP
- `app.set('trust proxy', '10.0.0.1/16')` trust subnet
- `app.set('trust proxy', '10.0.0.1, 10.0.0.2')` trust list
- `app.set('trust proxy', false)` turn off
- `app.set('trust proxy', true)` trust everything
* set proper `charset` in `Content-Type` for `res.send`
* update type-is to 1.2.0
- support suffix matching
4.2.0 / 2014-05-11
==================
* deprecate `app.del()` -- use `app.delete()` instead
* deprecate `res.json(obj, status)` -- use `res.json(status, obj)` instead
- the edge-case `res.json(status, num)` requires `res.status(status).json(num)`
* deprecate `res.jsonp(obj, status)` -- use `res.jsonp(status, obj)` instead
- the edge-case `res.jsonp(status, num)` requires `res.status(status).jsonp(num)`
* fix `req.next` when inside router instance
* include `ETag` header in `HEAD` requests
* keep previous `Content-Type` for `res.jsonp`
* support PURGE method
- add `app.purge`
- add `router.purge`
- include PURGE in `app.all`
* update debug to 0.8.0
- add `enable()` method
- change from stderr to stdout
* update methods to 1.0.0
- add PURGE
4.1.2 / 2014-05-08
==================
* fix `req.host` for IPv6 literals
* fix `res.jsonp` error if callback param is object
4.1.1 / 2014-04-27
==================
* fix package.json to reflect supported node version
4.1.0 / 2014-04-24
==================
* pass options from `res.sendfile` to `send`
* preserve casing of headers in `res.header` and `res.set`
* support unicode file names in `res.attachment` and `res.download`
* update accepts to 1.0.1
- deps: negotiator@0.4.0
* update cookie to 0.1.2
- Fix for maxAge == 0
- made compat with expires field
* update send to 0.3.0
- Accept API options in options object
- Coerce option types
- Control whether to generate etags
- Default directory access to 403 when index disabled
- Fix sending files with dots without root set
- Include file path in etag
- Make "Can't set headers after they are sent." catchable
- Send full entity-body for multi range requests
- Set etags to "weak"
- Support "If-Range" header
- Support multiple index paths
- deps: mime@1.2.11
* update serve-static to 1.1.0
- Accept options directly to `send` module
- Resolve relative paths at middleware setup
- Use parseurl to parse the URL from request
- deps: send@0.3.0
* update type-is to 1.1.0
- add non-array values support
- add `multipart` as a shorthand
4.0.0 / 2014-04-09
================== ==================
* remove: * remove:
- node 0.8 support
- connect and connect's patches except for charset handling
- express(1) - moved to [express-generator](https://github.com/expressjs/generator) - express(1) - moved to [express-generator](https://github.com/expressjs/generator)
- `req.accepted*` - use `req.accepts*()` instead - `express.createServer()` - it has been deprecated for a long time. Use `express()`
- `app.configure` - use logic in your own app code - `app.configure` - use logic in your own app code
- `app.router` - is removed
- `req.auth` - use `basic-auth` instead
- `req.accepted*` - use `req.accepts*()` instead
- `res.location` - relative URL resolution is removed
- `res.charset` - include the charset in the content type when using `res.set()`
- all bundled middleware except `static`
* change: * change:
- `app.route` -> `app.mountpath` when mounting an express app in another express app
- `json spaces` no longer enabled by default in development
- `req.accepts*` -> `req.accepts*s` - i.e. `req.acceptsEncoding` -> `req.acceptsEncodings` - `req.accepts*` -> `req.accepts*s` - i.e. `req.acceptsEncoding` -> `req.acceptsEncodings`
- `req.params` is now an object instead of an array - `req.params` is now an object instead of an array
- `json spaces` no longer enabled by default in development - `res.locals` is no longer a function. It is a plain js object. Treat it as such.
- `res.headerSent` -> `res.headersSent` to match node.js ServerResponse object
* refactor: * refactor:
- `req.accepts*` with [accepts](https://github.com/expressjs/accepts) - `req.accepts*` with [accepts](https://github.com/expressjs/accepts)
- `req.is` with [type-is](https://github.com/expressjs/type-is) - `req.is` with [type-is](https://github.com/expressjs/type-is)
- [path-to-regexp](https://github.com/component/path-to-regexp)
* add:
- `app.router()` - returns the app Router instance
- `app.route()` - Proxy to the app's `Router#route()` method to create a new route
- Router & Route - public API
3.9.0 / 2014-05-30
==================
* custom etag control with `app.set('etag', val)`
- `app.set('etag', function(body, encoding){ return '"etag"' })` custom etag generation
- `app.set('etag', 'weak')` weak tag
- `app.set('etag', 'strong')` strong etag
- `app.set('etag', false)` turn off
- `app.set('etag', true)` standard etag
* Include ETag in HEAD requests
* mark `res.send` ETag as weak and reduce collisions
* update connect to 2.18.0
- deps: compression@1.0.3
- deps: serve-index@1.1.0
- deps: serve-static@1.2.0
* update send to 0.4.0
- Calculate ETag with md5 for reduced collisions
- Ignore stream errors after request ends
- deps: debug@0.8.1
3.8.1 / 2014-05-27
==================
* update connect to 2.17.3
- deps: body-parser@1.2.2
- deps: express-session@1.2.1
- deps: method-override@1.0.2
3.8.0 / 2014-05-21
==================
* keep previous `Content-Type` for `res.jsonp`
* set proper `charset` in `Content-Type` for `res.send`
* update connect to 2.17.1
- fix `res.charset` appending charset when `content-type` has one
- deps: express-session@1.2.0
- deps: morgan@1.1.1
- deps: serve-index@1.0.3
3.7.0 / 2014-05-18
==================
* proper proxy trust with `app.set('trust proxy', trust)`
- `app.set('trust proxy', 1)` trust first hop
- `app.set('trust proxy', 'loopback')` trust loopback addresses
- `app.set('trust proxy', '10.0.0.1')` trust single IP
- `app.set('trust proxy', '10.0.0.1/16')` trust subnet
- `app.set('trust proxy', '10.0.0.1, 10.0.0.2')` trust list
- `app.set('trust proxy', false)` turn off
- `app.set('trust proxy', true)` trust everything
* update connect to 2.16.2
- deprecate `res.headerSent` -- use `res.headersSent`
- deprecate `res.on("header")` -- use on-headers module instead
- fix edge-case in `res.appendHeader` that would append in wrong order
- json: use body-parser
- urlencoded: use body-parser
- dep: bytes@1.0.0
- dep: cookie-parser@1.1.0
- dep: csurf@1.2.0
- dep: express-session@1.1.0
- dep: method-override@1.0.1
3.6.0 / 2014-05-09
==================
* deprecate `app.del()` -- use `app.delete()` instead
* deprecate `res.json(obj, status)` -- use `res.json(status, obj)` instead
- the edge-case `res.json(status, num)` requires `res.status(status).json(num)`
* deprecate `res.jsonp(obj, status)` -- use `res.jsonp(status, obj)` instead
- the edge-case `res.jsonp(status, num)` requires `res.status(status).jsonp(num)`
* support PURGE method
- add `app.purge`
- add `router.purge`
- include PURGE in `app.all`
* update connect to 2.15.0
* Add `res.appendHeader`
* Call error stack even when response has been sent
* Patch `res.headerSent` to return Boolean
* Patch `res.headersSent` for node.js 0.8
* Prevent default 404 handler after response sent
* dep: compression@1.0.2
* dep: connect-timeout@1.1.0
* dep: debug@^0.8.0
* dep: errorhandler@1.0.1
* dep: express-session@1.0.4
* dep: morgan@1.0.1
* dep: serve-favicon@2.0.0
* dep: serve-index@1.0.2
* update debug to 0.8.0
* add `enable()` method
* change from stderr to stdout
* update methods to 1.0.0
- add PURGE
* update mkdirp to 0.5.0
3.5.3 / 2014-05-08
==================
* fix `req.host` for IPv6 literals
* fix `res.jsonp` error if callback param is object
3.5.2 / 2014-04-24
==================
* update connect to 2.14.5
* update cookie to 0.1.2
* update mkdirp to 0.4.0
* update send to 0.3.0
3.5.1 / 2014-03-25
==================
* pin less-middleware in generated app
3.5.0 / 2014-03-06 3.5.0 / 2014-03-06
================== ==================
......
(The MIT License) (The MIT License)
Copyright (c) 2009-2013 TJ Holowaychuk <tj@vision-media.ca> Copyright (c) 2009-2014 TJ Holowaychuk <tj@vision-media.ca>
Permission is hereby granted, free of charge, to any person obtaining Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the a copy of this software and associated documentation files (the
......
MOCHA_OPTS= --check-leaks
REPORTER = dot
check: test
test: test-unit test-acceptance
test-unit:
@NODE_ENV=test ./node_modules/.bin/mocha \
--reporter $(REPORTER) \
--globals setImmediate,clearImmediate \
$(MOCHA_OPTS)
test-acceptance:
@NODE_ENV=test ./node_modules/.bin/mocha \
--reporter $(REPORTER) \
--bail \
test/acceptance/*.js
test-cov: lib-cov
@EXPRESS_COV=1 $(MAKE) test REPORTER=html-cov > coverage.html
lib-cov:
@jscoverage lib lib-cov
bench:
@$(MAKE) -C benchmarks
clean:
rm -f coverage.html
rm -fr lib-cov
.PHONY: test test-unit test-acceptance bench clean
[![express logo](http://f.cl.ly/items/0V2S1n0K1i3y1c122g04/Screen%20Shot%202012-04-11%20at%209.59.42%20AM.png)](http://expressjs.com/) [![express logo](https://i.cloudup.com/zfY6lL7eFa-3000x3000.png)](http://expressjs.com/)
Fast, unopinionated, minimalist web framework for [node](http://nodejs.org). Fast, unopinionated, minimalist web framework for [node](http://nodejs.org).
[![Build Status](https://secure.travis-ci.org/visionmedia/express.png)](http://travis-ci.org/visionmedia/express) [![Gittip](http://img.shields.io/gittip/visionmedia.png)](https://www.gittip.com/visionmedia/) [![NPM version](https://badge.fury.io/js/express.svg)](http://badge.fury.io/js/express) [![Build Status](https://travis-ci.org/visionmedia/express.svg?branch=master)](https://travis-ci.org/visionmedia/express) [![Coverage Status](https://img.shields.io/coveralls/visionmedia/express.svg)](https://coveralls.io/r/visionmedia/express) [![Gittip](http://img.shields.io/gittip/visionmedia.svg)](https://www.gittip.com/visionmedia/)
```js ```js
var express = require('express'); var express = require('express');
...@@ -15,17 +15,22 @@ app.get('/', function(req, res){ ...@@ -15,17 +15,22 @@ app.get('/', function(req, res){
app.listen(3000); app.listen(3000);
``` ```
**PROTIP** Be sure to read [Migrating from 3.x to 4.x](https://github.com/visionmedia/express/wiki/Migrating-from-3.x-to-4.x) as well as [New features in 4.x](https://github.com/visionmedia/express/wiki/New-features-in-4.x).
## Installation ## Installation
$ npm install -g express $ npm install express
## Quick Start ## Quick Start
The quickest way to get started with express is to utilize the executable `express(1)` to generate an application as shown below: The quickest way to get started with express is to utilize the executable [`express(1)`](http://github.com/expressjs/generator) to generate an application as shown below:
Install the executable. The executable's major version will match Express's:
$ npm install -g express-generator@3
Create the app: Create the app:
$ npm install -g express
$ express /tmp/foo && cd /tmp/foo $ express /tmp/foo && cd /tmp/foo
Install dependencies: Install dependencies:
...@@ -34,17 +39,15 @@ app.listen(3000); ...@@ -34,17 +39,15 @@ app.listen(3000);
Start the server: Start the server:
$ node app $ npm start
## Features ## Features
* Built on [Connect](http://github.com/senchalabs/connect)
* Robust routing * Robust routing
* HTTP helpers (redirection, caching, etc) * HTTP helpers (redirection, caching, etc)
* View system supporting 14+ template engines * View system supporting 14+ template engines
* Content negotiation * Content negotiation
* Focus on high performance * Focus on high performance
* Environment based configuration
* Executable for generating applications quickly * Executable for generating applications quickly
* High test coverage * High test coverage
...@@ -54,9 +57,7 @@ app.listen(3000); ...@@ -54,9 +57,7 @@ app.listen(3000);
it a great solution for single page applications, web sites, hybrids, or public it a great solution for single page applications, web sites, hybrids, or public
HTTP APIs. HTTP APIs.
Built on Connect, you can use _only_ what you need, and nothing more. Applications Express does not force you to use any specific ORM or template engine. With support for over
can be as big or as small as you like, even a single file. Express does
not force you to use any specific ORM or template engine. With support for over
14 template engines via [Consolidate.js](http://github.com/visionmedia/consolidate.js), 14 template engines via [Consolidate.js](http://github.com/visionmedia/consolidate.js),
you can quickly craft your perfect framework. you can quickly craft your perfect framework.
...@@ -65,7 +66,7 @@ app.listen(3000); ...@@ -65,7 +66,7 @@ app.listen(3000);
* [Website and Documentation](http://expressjs.com/) stored at [visionmedia/expressjs.com](https://github.com/visionmedia/expressjs.com) * [Website and Documentation](http://expressjs.com/) stored at [visionmedia/expressjs.com](https://github.com/visionmedia/expressjs.com)
* Join #express on freenode * Join #express on freenode
* [Google Group](http://groups.google.com/group/express-js) for discussion * [Google Group](http://groups.google.com/group/express-js) for discussion
* Follow [tjholowaychuk](http://twitter.com/tjholowaychuk) on twitter for updates * Follow [tjholowaychuk](http://twitter.com/tjholowaychuk) and [defunctzombie](https://twitter.com/defunctzombie) on twitter for updates
* Visit the [Wiki](http://github.com/visionmedia/express/wiki) * Visit the [Wiki](http://github.com/visionmedia/express/wiki)
* [Русскоязычная документация](http://jsman.ru/express/) * [Русскоязычная документация](http://jsman.ru/express/)
* Run express examples [online](https://runnable.com/express) * Run express examples [online](https://runnable.com/express)
...@@ -94,33 +95,16 @@ To run the test suite, first invoke the following command within the repo, insta ...@@ -94,33 +95,16 @@ To run the test suite, first invoke the following command within the repo, insta
Then run the tests: Then run the tests:
$ make test ```sh
$ npm test
```
## Contributors ## Contributors
https://github.com/visionmedia/express/graphs/contributors Author: [TJ Holowaychuk](http://github.com/visionmedia)
Lead Maintainer: [Roman Shtylman](https://github.com/defunctzombie)
Contributors: https://github.com/visionmedia/express/graphs/contributors
## License ## License
(The MIT License) MIT
Copyright (c) 2009-2012 TJ Holowaychuk &lt;tj@vision-media.ca&gt;
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
all:
@./run 1 middleware
@./run 5 middleware
@./run 10 middleware
@./run 15 middleware
@./run 20 middleware
@./run 30 middleware
@./run 50 middleware
@./run 100 middleware
@echo
.PHONY: all
var http = require('http');
var express = require('..');
var app = express();
// number of middleware
var n = parseInt(process.env.MW || '1', 10);
console.log(' %s middleware', n);
while (n--) {
app.use(function(req, res, next){
next();
});
}
var body = new Buffer('Hello World');
app.use(function(req, res, next){
res.send(body);
});
app.listen(3333);
#!/usr/bin/env bash
echo
MW=$1 node $2 &
pid=$!
sleep 2
wrk 'http://localhost:3333/?foo[bar]=baz' \
-d 3 \
-c 50 \
-t 8 \
| grep 'Requests/sec' \
| awk '{ print " " $2 }'
kill $pid
#!/usr/bin/env node
/**
* Module dependencies.
*/
var program = require('commander')
, mkdirp = require('mkdirp')
, pkg = require('../package.json')
, version = pkg.version
, os = require('os')
, fs = require('fs');
// CLI
program
.version(version)
.usage('[options] [dir]')
.option('-s, --sessions', 'add session support')
.option('-e, --ejs', 'add ejs engine support (defaults to jade)')
.option('-J, --jshtml', 'add jshtml engine support (defaults to jade)')
.option('-H, --hogan', 'add hogan.js engine support')
.option('-c, --css <engine>', 'add stylesheet <engine> support (less|stylus) (defaults to plain css)')
.option('-f, --force', 'force on non-empty directory')
.parse(process.argv);
// Path
var path = program.args.shift() || '.';
// end-of-line code
var eol = os.EOL
// Template engine
program.template = 'jade';
if (program.ejs) program.template = 'ejs';
if (program.jshtml) program.template = 'jshtml';
if (program.hogan) program.template = 'hjs';
/**
* Routes index template.
*/
var index = [
''
, '/*'
, ' * GET home page.'
, ' */'
, ''
, 'exports.index = function(req, res){'
, ' res.render(\'index\', { title: \'Express\' });'
, '};'
].join(eol);
/**
* Routes users template.
*/
var users = [
''
, '/*'
, ' * GET users listing.'
, ' */'
, ''
, 'exports.list = function(req, res){'
, ' res.send("respond with a resource");'
, '};'
].join(eol);
/**
* Jade layout template.
*/
var jadeLayout = [
'doctype html'
, 'html'
, ' head'
, ' title= title'
, ' link(rel=\'stylesheet\', href=\'/stylesheets/style.css\')'
, ' body'
, ' block content'
].join(eol);
/**
* Jade index template.
*/
var jadeIndex = [
'extends layout'
, ''
, 'block content'
, ' h1= title'
, ' p Welcome to #{title}'
].join(eol);
/**
* EJS index template.
*/
var ejsIndex = [
'<!DOCTYPE html>'
, '<html>'
, ' <head>'
, ' <title><%= title %></title>'
, ' <link rel=\'stylesheet\' href=\'/stylesheets/style.css\' />'
, ' </head>'
, ' <body>'
, ' <h1><%= title %></h1>'
, ' <p>Welcome to <%= title %></p>'
, ' </body>'
, '</html>'
].join(eol);
/**
* JSHTML layout template.
*/
var jshtmlLayout = [
'<!DOCTYPE html>'
, '<html>'
, ' <head>'
, ' <title> @write(title) </title>'
, ' <link rel=\'stylesheet\' href=\'/stylesheets/style.css\' />'
, ' </head>'
, ' <body>'
, ' @write(body)'
, ' </body>'
, '</html>'
].join(eol);
/**
* JSHTML index template.
*/
var jshtmlIndex = [
'<h1>@write(title)</h1>'
, '<p>Welcome to @write(title)</p>'
].join(eol);
/**
* Hogan.js index template.
*/
var hoganIndex = [
'<!DOCTYPE html>'
, '<html>'
, ' <head>'
, ' <title>{{ title }}</title>'
, ' <link rel=\'stylesheet\' href=\'/stylesheets/style.css\' />'
, ' </head>'
, ' <body>'
, ' <h1>{{ title }}</h1>'
, ' <p>Welcome to {{ title }}</p>'
, ' </body>'
, '</html>'
].join(eol);
/**
* Default css template.
*/
var css = [
'body {'
, ' padding: 50px;'
, ' font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;'
, '}'
, ''
, 'a {'
, ' color: #00B7FF;'
, '}'
].join(eol);
/**
* Default less template.
*/
var less = [
'body {'
, ' padding: 50px;'
, ' font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;'
, '}'
, ''
, 'a {'
, ' color: #00B7FF;'
, '}'
].join(eol);
/**
* Default stylus template.
*/
var stylus = [
'body'
, ' padding: 50px'
, ' font: 14px "Lucida Grande", Helvetica, Arial, sans-serif'
, 'a'
, ' color: #00B7FF'
].join(eol);
/**
* App template.
*/
var app = [
''
, '/**'
, ' * Module dependencies.'
, ' */'
, ''
, 'var express = require(\'express\');'
, 'var routes = require(\'./routes\');'
, 'var user = require(\'./routes/user\');'
, 'var http = require(\'http\');'
, 'var path = require(\'path\');'
, ''
, 'var app = express();'
, ''
, '// all environments'
, 'app.set(\'port\', process.env.PORT || 3000);'
, 'app.set(\'views\', path.join(__dirname, \'views\'));'
, 'app.set(\'view engine\', \':TEMPLATE\');'
, 'app.use(express.favicon());'
, 'app.use(express.logger(\'dev\'));'
, 'app.use(express.json());'
, 'app.use(express.urlencoded());'
, 'app.use(express.methodOverride());{sess}'
, 'app.use(app.router);{css}'
, 'app.use(express.static(path.join(__dirname, \'public\')));'
, ''
, '// development only'
, 'if (\'development\' == app.get(\'env\')) {'
, ' app.use(express.errorHandler());'
, '}'
, ''
, 'app.get(\'/\', routes.index);'
, 'app.get(\'/users\', user.list);'
, ''
, 'http.createServer(app).listen(app.get(\'port\'), function(){'
, ' console.log(\'Express server listening on port \' + app.get(\'port\'));'
, '});'
, ''
].join(eol);
// Generate application
(function createApplication(path) {
emptyDirectory(path, function(empty){
if (empty || program.force) {
createApplicationAt(path);
} else {
program.confirm('destination is not empty, continue? ', function(ok){
if (ok) {
process.stdin.destroy();
createApplicationAt(path);
} else {
abort('aborting');
}
});
}
});
})(path);
/**
* Create application at the given directory `path`.
*
* @param {String} path
*/
function createApplicationAt(path) {
console.log();
process.on('exit', function(){
console.log();
console.log(' install dependencies:');
console.log(' $ cd %s && npm install', path);
console.log();
console.log(' run the app:');
console.log(' $ node app');
console.log();
});
mkdir(path, function(){
mkdir(path + '/public');
mkdir(path + '/public/javascripts');
mkdir(path + '/public/images');
mkdir(path + '/public/stylesheets', function(){
switch (program.css) {
case 'less':
write(path + '/public/stylesheets/style.less', less);
break;
case 'stylus':
write(path + '/public/stylesheets/style.styl', stylus);
break;
default:
write(path + '/public/stylesheets/style.css', css);
}
});
mkdir(path + '/routes', function(){
write(path + '/routes/index.js', index);
write(path + '/routes/user.js', users);
});
mkdir(path + '/views', function(){
switch (program.template) {
case 'ejs':
write(path + '/views/index.ejs', ejsIndex);
break;
case 'jade':
write(path + '/views/layout.jade', jadeLayout);
write(path + '/views/index.jade', jadeIndex);
break;
case 'jshtml':
write(path + '/views/layout.jshtml', jshtmlLayout);
write(path + '/views/index.jshtml', jshtmlIndex);
break;
case 'hjs':
write(path + '/views/index.hjs', hoganIndex);
break;
}
});
// CSS Engine support
switch (program.css) {
case 'less':
app = app.replace('{css}', eol + 'app.use(require(\'less-middleware\')({ src: path.join(__dirname, \'public\') }));');
break;
case 'stylus':
app = app.replace('{css}', eol + 'app.use(require(\'stylus\').middleware(path.join(__dirname, \'public\')));');
break;
default:
app = app.replace('{css}', '');
}
// Session support
app = app.replace('{sess}', program.sessions
? eol + 'app.use(express.cookieParser(\'your secret here\'));' + eol + 'app.use(express.session());'
: '');
// Template support
app = app.replace(':TEMPLATE', program.template);
// package.json
var pkg = {
name: 'application-name'
, version: '0.0.1'
, private: true
, scripts: { start: 'node app.js' }
, dependencies: {
express: version
}
}
if (program.template) pkg.dependencies[program.template] = '*';
// CSS Engine support
switch (program.css) {
case 'less':
pkg.dependencies['less-middleware'] = '~0.1.15';
break;
default:
if (program.css) {
pkg.dependencies[program.css] = '*';
}
}
write(path + '/package.json', JSON.stringify(pkg, null, 2));
write(path + '/app.js', app);
});
}
/**
* Check if the given directory `path` is empty.
*
* @param {String} path
* @param {Function} fn
*/
function emptyDirectory(path, fn) {
fs.readdir(path, function(err, files){
if (err && 'ENOENT' != err.code) throw err;
fn(!files || !files.length);
});
}
/**
* echo str > path.
*
* @param {String} path
* @param {String} str
*/
function write(path, str) {
fs.writeFile(path, str);
console.log(' \x1b[36mcreate\x1b[0m : ' + path);
}
/**
* Mkdir -p.
*
* @param {String} path
* @param {Function} fn
*/
function mkdir(path, fn) {
mkdirp(path, 0755, function(err){
if (err) throw err;
console.log(' \033[36mcreate\033[0m : ' + path);
fn && fn();
});
}
/**
* Exit with the given `str`.
*
* @param {String} str
*/
function abort(str) {
console.error(str);
process.exit(1);
}
module.exports = process.env.EXPRESS_COV module.exports = require('./lib/express');
? require('./lib-cov/express')
: require('./lib/express');
\ No newline at end of file
...@@ -2,14 +2,13 @@ ...@@ -2,14 +2,13 @@
* Module dependencies. * Module dependencies.
*/ */
var merge = require('merge-descriptors'); var EventEmitter = require('events').EventEmitter;
var connect = require('connect') var mixin = require('utils-merge');
, proto = require('./application') var proto = require('./application');
, Route = require('./router/route') var Route = require('./router/route');
, Router = require('./router') var Router = require('./router');
, req = require('./request') var req = require('./request');
, res = require('./response') var res = require('./response');
, utils = connect.utils;
/** /**
* Expose `createApplication()`. * Expose `createApplication()`.
...@@ -17,12 +16,6 @@ var connect = require('connect') ...@@ -17,12 +16,6 @@ var connect = require('connect')
exports = module.exports = createApplication; exports = module.exports = createApplication;
/**
* Expose mime.
*/
exports.mime = connect.mime;
/** /**
* Create an express application. * Create an express application.
* *
...@@ -31,36 +24,19 @@ exports.mime = connect.mime; ...@@ -31,36 +24,19 @@ exports.mime = connect.mime;
*/ */
function createApplication() { function createApplication() {
var app = connect(); var app = function(req, res, next) {
utils.merge(app, proto); app.handle(req, res, next);
};
mixin(app, proto);
mixin(app, EventEmitter.prototype);
app.request = { __proto__: req, app: app }; app.request = { __proto__: req, app: app };
app.response = { __proto__: res, app: app }; app.response = { __proto__: res, app: app };
app.init(); app.init();
return app; return app;
} }
/**
* Expose connect.middleware as express.*
* for example `express.logger` etc.
*/
merge(exports, connect.middleware);
/**
* Error on createServer().
*/
exports.createServer = function(){
console.warn('Warning: express.createServer() is deprecated, express');
console.warn('applications no longer inherit from http.Server,');
console.warn('please use:');
console.warn('');
console.warn(' var express = require("express");');
console.warn(' var app = express();');
console.warn('');
return createApplication();
};
/** /**
* Expose the prototypes. * Expose the prototypes.
*/ */
...@@ -76,7 +52,42 @@ exports.response = res; ...@@ -76,7 +52,42 @@ exports.response = res;
exports.Route = Route; exports.Route = Route;
exports.Router = Router; exports.Router = Router;
// Error handler title /**
* Expose middleware
*/
exports.query = require('./middleware/query');
exports.static = require('serve-static');
exports.errorHandler.title = 'Express'; /**
* Replace removed middleware with an appropriate error message.
*/
[
'json',
'urlencoded',
'bodyParser',
'compress',
'cookieSession',
'session',
'logger',
'cookieParser',
'favicon',
'responseTime',
'errorHandler',
'timeout',
'methodOverride',
'vhost',
'csrf',
'directory',
'limit',
'multipart',
'staticCache',
].forEach(function (name) {
Object.defineProperty(exports, name, {
get: function () {
throw new Error('Most middleware (like ' + name + ') is no longer bundled with Express and must be installed separately. Please see https://github.com/senchalabs/connect#middleware.');
},
configurable: true
});
});
/**
* Module dependencies.
*/
var utils = require('./utils');
/**
* Initialization middleware, exposing the
* request and response to eachother, as well
* as defaulting the X-Powered-By header field.
*
* @param {Function} app
* @return {Function}
* @api private
*/
exports.init = function(app){
return function expressInit(req, res, next){
if (app.enabled('x-powered-by')) res.setHeader('X-Powered-By', 'Express');
req.res = res;
res.req = req;
req.next = next;
req.__proto__ = app.request;
res.__proto__ = app.response;
res.locals = res.locals || utils.locals(res);
next();
}
};
/** /**
* Module dependencies. * Module dependencies.
*/ */
var http = require('http') var accepts = require('accepts');
, utils = require('./utils') var typeis = require('type-is');
, connect = require('connect') var http = require('http');
, fresh = require('fresh') var fresh = require('fresh');
, parseRange = require('range-parser') var parseRange = require('range-parser');
, parse = connect.utils.parseUrl var parse = require('parseurl');
, mime = connect.mime; var proxyaddr = require('proxy-addr');
/** /**
* Request prototype. * Request prototype.
...@@ -56,6 +55,8 @@ req.header = function(name){ ...@@ -56,6 +55,8 @@ req.header = function(name){
}; };
/** /**
* To do: update docs.
*
* Check if the given `type(s)` is acceptable, returning * Check if the given `type(s)` is acceptable, returning
* the best match when true, otherwise `undefined`, in which * the best match when true, otherwise `undefined`, in which
* case you should respond with 406 "Not Acceptable". * case you should respond with 406 "Not Acceptable".
...@@ -99,9 +100,9 @@ req.header = function(name){ ...@@ -99,9 +100,9 @@ req.header = function(name){
* @api public * @api public
*/ */
req.accepts = function(type){ req.accepts = function(){
var args = arguments.length > 1 ? [].slice.apply(arguments) : type; var accept = accepts(this);
return utils.accepts(args, this.get('Accept')); return accept.types.apply(accept, arguments);
}; };
/** /**
...@@ -112,11 +113,15 @@ req.accepts = function(type){ ...@@ -112,11 +113,15 @@ req.accepts = function(type){
* @api public * @api public
*/ */
req.acceptsEncoding = function(encoding){ req.acceptsEncoding = // backwards compatibility
return !! ~this.acceptedEncodings.indexOf(encoding); req.acceptsEncodings = function(){
var accept = accepts(this);
return accept.encodings.apply(accept, arguments);
}; };
/** /**
* To do: update docs.
*
* Check if the given `charset` is acceptable, * Check if the given `charset` is acceptable,
* otherwise you should respond with 406 "Not Acceptable". * otherwise you should respond with 406 "Not Acceptable".
* *
...@@ -125,14 +130,15 @@ req.acceptsEncoding = function(encoding){ ...@@ -125,14 +130,15 @@ req.acceptsEncoding = function(encoding){
* @api public * @api public
*/ */
req.acceptsCharset = function(charset){ req.acceptsCharset = // backwards compatibility
var accepted = this.acceptedCharsets; req.acceptsCharsets = function(){
return accepted.length var accept = accepts(this);
? !! ~accepted.indexOf(charset) return accept.charsets.apply(accept, arguments);
: true;
}; };
/** /**
* To do: update docs.
*
* Check if the given `lang` is acceptable, * Check if the given `lang` is acceptable,
* otherwise you should respond with 406 "Not Acceptable". * otherwise you should respond with 406 "Not Acceptable".
* *
...@@ -141,11 +147,10 @@ req.acceptsCharset = function(charset){ ...@@ -141,11 +147,10 @@ req.acceptsCharset = function(charset){
* @api public * @api public
*/ */
req.acceptsLanguage = function(lang){ req.acceptsLanguage = // backwards compatibility
var accepted = this.acceptedLanguages; req.acceptsLanguages = function(){
return accepted.length var accept = accepts(this);
? !! ~accepted.indexOf(lang) return accept.languages.apply(accept, arguments);
: true;
}; };
/** /**
...@@ -174,98 +179,6 @@ req.range = function(size){ ...@@ -174,98 +179,6 @@ req.range = function(size){
return parseRange(size, range); return parseRange(size, range);
}; };
/**
* Return an array of encodings.
*
* Examples:
*
* ['gzip', 'deflate']
*
* @return {Array}
* @api public
*/
req.__defineGetter__('acceptedEncodings', function(){
var accept = this.get('Accept-Encoding');
return accept
? accept.trim().split(/ *, */)
: [];
});
/**
* Return an array of Accepted media types
* ordered from highest quality to lowest.
*
* Examples:
*
* [ { value: 'application/json',
* quality: 1,
* type: 'application',
* subtype: 'json' },
* { value: 'text/html',
* quality: 0.5,
* type: 'text',
* subtype: 'html' } ]
*
* @return {Array}
* @api public
*/
req.__defineGetter__('accepted', function(){
var accept = this.get('Accept');
return accept
? utils.parseAccept(accept)
: [];
});
/**
* Return an array of Accepted languages
* ordered from highest quality to lowest.
*
* Examples:
*
* Accept-Language: en;q=.5, en-us
* ['en-us', 'en']
*
* @return {Array}
* @api public
*/
req.__defineGetter__('acceptedLanguages', function(){
var accept = this.get('Accept-Language');
return accept
? utils
.parseParams(accept)
.map(function(obj){
return obj.value;
})
: [];
});
/**
* Return an array of Accepted charsets
* ordered from highest quality to lowest.
*
* Examples:
*
* Accept-Charset: iso-8859-5;q=.2, unicode-1-1;q=0.8
* ['unicode-1-1', 'iso-8859-5']
*
* @return {Array}
* @api public
*/
req.__defineGetter__('acceptedCharsets', function(){
var accept = this.get('Accept-Charset');
return accept
? utils
.parseParams(accept)
.map(function(obj){
return obj.value;
})
: [];
});
/** /**
* Return the value of param `name` when present or `defaultValue`. * Return the value of param `name` when present or `defaultValue`.
* *
...@@ -275,7 +188,7 @@ req.__defineGetter__('acceptedCharsets', function(){ ...@@ -275,7 +188,7 @@ req.__defineGetter__('acceptedCharsets', function(){
* *
* To utilize request bodies, `req.body` * To utilize request bodies, `req.body`
* should be an object. This can be done by using * should be an object. This can be done by using
* the `connect.bodyParser()` middleware. * the `bodyParser()` middleware.
* *
* @param {String} name * @param {String} name
* @param {Mixed} [defaultValue] * @param {Mixed} [defaultValue]
...@@ -319,37 +232,34 @@ req.param = function(name, defaultValue){ ...@@ -319,37 +232,34 @@ req.param = function(name, defaultValue){
* @api public * @api public
*/ */
req.is = function(type){ req.is = function(types){
var ct = this.get('Content-Type'); if (!Array.isArray(types)) types = [].slice.call(arguments);
if (!ct) return false; return typeis(this, types);
ct = ct.split(';')[0];
if (!~type.indexOf('/')) type = mime.lookup(type);
if (~type.indexOf('*')) {
type = type.split('/');
ct = ct.split('/');
if ('*' == type[0] && type[1] == ct[1]) return true;
if ('*' == type[1] && type[0] == ct[0]) return true;
return false;
}
return !! ~ct.indexOf(type);
}; };
/** /**
* Return the protocol string "http" or "https" * Return the protocol string "http" or "https"
* when requested with TLS. When the "trust proxy" * when requested with TLS. When the "trust proxy"
* setting is enabled the "X-Forwarded-Proto" header * setting trusts the socket address, the
* field will be trusted. If you're running behind * "X-Forwarded-Proto" header field will be trusted.
* a reverse proxy that supplies https for you this * If you're running behind a reverse proxy that
* may be enabled. * supplies https for you this may be enabled.
* *
* @return {String} * @return {String}
* @api public * @api public
*/ */
req.__defineGetter__('protocol', function(){ req.__defineGetter__('protocol', function(){
var trustProxy = this.app.get('trust proxy'); var trust = this.app.get('trust proxy fn');
if (this.connection.encrypted) return 'https';
if (!trustProxy) return 'http'; if (!trust(this.connection.remoteAddress)) {
return this.connection.encrypted
? 'https'
: 'http';
}
// Note: X-Forwarded-Proto is normally only ever a
// single value, but this is to be safe.
var proto = this.get('X-Forwarded-Proto') || 'http'; var proto = this.get('X-Forwarded-Proto') || 'http';
return proto.split(/\s*,\s*/)[0]; return proto.split(/\s*,\s*/)[0];
}); });
...@@ -368,66 +278,36 @@ req.__defineGetter__('secure', function(){ ...@@ -368,66 +278,36 @@ req.__defineGetter__('secure', function(){
}); });
/** /**
* Return the remote address, or when * Return the remote address from the trusted proxy.
* "trust proxy" is `true` return *
* the upstream addr. * The is the remote address on the socket unless
* "trust proxy" is set.
* *
* @return {String} * @return {String}
* @api public * @api public
*/ */
req.__defineGetter__('ip', function(){ req.__defineGetter__('ip', function(){
return this.ips[0] || this.connection.remoteAddress; var trust = this.app.get('trust proxy fn');
return proxyaddr(this, trust);
}); });
/** /**
* When "trust proxy" is `true`, parse * When "trust proxy" is set, trusted proxy addresses + client.
* the "X-Forwarded-For" ip address list.
* *
* For example if the value were "client, proxy1, proxy2" * For example if the value were "client, proxy1, proxy2"
* you would receive the array `["client", "proxy1", "proxy2"]` * you would receive the array `["client", "proxy1", "proxy2"]`
* where "proxy2" is the furthest down-stream. * where "proxy2" is the furthest down-stream and "proxy1" and
* "proxy2" were trusted.
* *
* @return {Array} * @return {Array}
* @api public * @api public
*/ */
req.__defineGetter__('ips', function(){ req.__defineGetter__('ips', function(){
var trustProxy = this.app.get('trust proxy'); var trust = this.app.get('trust proxy fn');
var val = this.get('X-Forwarded-For'); var addrs = proxyaddr.all(this, trust);
return trustProxy && val return addrs.slice(1).reverse();
? val.split(/ *, */)
: [];
});
/**
* Return basic auth credentials.
*
* Examples:
*
* // http://tobi:hello@example.com
* req.auth
* // => { username: 'tobi', password: 'hello' }
*
* @return {Object} or undefined
* @api public
*/
req.__defineGetter__('auth', function(){
// missing
var auth = this.get('Authorization');
if (!auth) return;
// malformed
var parts = auth.split(' ');
if ('basic' != parts[0].toLowerCase()) return;
if (!parts[1]) return;
auth = parts[1];
// credentials
auth = new Buffer(auth, 'base64').toString().match(/^([^:]*):(.*)$/);
if (!auth) return;
return { username: auth[1], password: auth[2] };
}); });
/** /**
...@@ -467,16 +347,33 @@ req.__defineGetter__('path', function(){ ...@@ -467,16 +347,33 @@ req.__defineGetter__('path', function(){
/** /**
* Parse the "Host" header field hostname. * Parse the "Host" header field hostname.
* *
* When the "trust proxy" setting trusts the socket
* address, the "X-Forwarded-Host" header field will
* be trusted.
*
* @return {String} * @return {String}
* @api public * @api public
*/ */
req.__defineGetter__('host', function(){ req.__defineGetter__('host', function(){
var trustProxy = this.app.get('trust proxy'); var trust = this.app.get('trust proxy fn');
var host = trustProxy && this.get('X-Forwarded-Host'); var host = this.get('X-Forwarded-Host');
host = host || this.get('Host');
if (!host || !trust(this.connection.remoteAddress)) {
host = this.get('Host');
}
if (!host) return; if (!host) return;
return host.split(':')[0];
// IPv6 literal support
var offset = host[0] === '['
? host.indexOf(']') + 1
: 0;
var index = host.indexOf(':', offset);
return ~index
? host.substring(0, index)
: host;
}); });
/** /**
......
/** /**
* Module dependencies. * Module dependencies.
*/ */
var debug = require('debug')('express:router:route');
var methods = require('methods');
var utils = require('../utils'); var utils = require('../utils');
/** /**
...@@ -12,67 +13,179 @@ var utils = require('../utils'); ...@@ -12,67 +13,179 @@ var utils = require('../utils');
module.exports = Route; module.exports = Route;
/** /**
* Initialize `Route` with the given HTTP `method`, `path`, * Initialize `Route` with the given `path`,
* and an array of `callbacks` and `options`.
*
* Options:
* *
* - `sensitive` enable case-sensitive routes
* - `strict` enable strict matching for trailing slashes
*
* @param {String} method
* @param {String} path * @param {String} path
* @param {Array} callbacks
* @param {Object} options.
* @api private * @api private
*/ */
function Route(method, path, callbacks, options) { function Route(path) {
options = options || {}; debug('new %s', path);
this.path = path; this.path = path;
this.method = method; this.stack = undefined;
this.callbacks = callbacks;
this.regexp = utils.pathRegexp(path // route handlers for various http methods
, this.keys = [] this.methods = {};
, options.sensitive
, options.strict);
} }
/** /**
* Check if this route matches `path`, if so * @return {Array} supported HTTP methods
* populate `.params`. * @api private
*/
Route.prototype._options = function(){
return Object.keys(this.methods).map(function(method) {
return method.toUpperCase();
});
};
/**
* dispatch req, res into this route
* *
* @param {String} path
* @return {Boolean}
* @api private * @api private
*/ */
Route.prototype.match = function(path){ Route.prototype.dispatch = function(req, res, done){
var keys = this.keys var self = this;
, params = this.params = [] var method = req.method.toLowerCase();
, m = this.regexp.exec(path);
if (!m) return false; if (method === 'head' && !this.methods['head']) {
method = 'get';
}
req.route = self;
for (var i = 1, len = m.length; i < len; ++i) { // single middleware route case
var key = keys[i - 1]; if (typeof this.stack === 'function') {
this.stack(req, res, done);
return;
}
var stack = self.stack;
if (!stack) {
return done();
}
var idx = 0;
(function next_layer(err) {
if (err && err === 'route') {
return done();
}
var layer = stack[idx++];
if (!layer) {
return done(err);
}
if (layer.method && layer.method !== method) {
return next_layer(err);
}
var arity = layer.handle.length;
if (err) {
if (arity < 4) {
return next_layer(err);
}
try { try {
var val = 'string' == typeof m[i] layer.handle(err, req, res, next_layer);
? decodeURIComponent(m[i]) } catch (err) {
: m[i]; next_layer(err);
} catch(e) { }
var err = new Error("Failed to decode param '" + m[i] + "'"); return;
err.status = 400;
throw err;
} }
if (key) { if (arity > 3) {
params[key.name] = val; return next_layer();
} else {
params.push(val);
} }
try {
layer.handle(req, res, next_layer);
} catch (err) {
next_layer(err);
} }
})();
};
/**
* Add a handler for all HTTP verbs to this route.
*
* Behaves just like middleware and can respond or call `next`
* to continue processing.
*
* You can use multiple `.all` call to add multiple handlers.
*
* function check_something(req, res, next){
* next();
* };
*
* function validate_user(req, res, next){
* next();
* };
*
* route
* .all(validate_user)
* .all(check_something)
* .get(function(req, res, next){
* res.send('hello world');
* });
*
* @param {function} handler
* @return {Route} for chaining
* @api public
*/
Route.prototype.all = function(){
var self = this;
var callbacks = utils.flatten([].slice.call(arguments));
callbacks.forEach(function(fn) {
if (typeof fn !== 'function') {
var type = {}.toString.call(fn);
var msg = 'Route.all() requires callback functions but got a ' + type;
throw new Error(msg);
}
if (!self.stack) {
self.stack = fn;
}
else if (typeof self.stack === 'function') {
self.stack = [{ handle: self.stack }, { handle: fn }];
}
else {
self.stack.push({ handle: fn });
}
});
return true; return self;
}; };
methods.forEach(function(method){
Route.prototype[method] = function(){
var self = this;
var callbacks = utils.flatten([].slice.call(arguments));
callbacks.forEach(function(fn) {
if (typeof fn !== 'function') {
var type = {}.toString.call(fn);
var msg = 'Route.' + method + '() requires callback functions but got a ' + type;
throw new Error(msg);
}
debug('%s %s', method, self.path);
if (!self.methods[method]) {
self.methods[method] = true;
}
if (!self.stack) {
self.stack = [];
}
else if (typeof self.stack === 'function') {
self.stack = [{ handle: self.stack }];
}
self.stack.push({ method: method, handle: fn });
});
return self;
};
});
/** /**
* Module dependencies. * Module dependencies.
*/ */
var mime = require('connect').mime var mime = require('send').mime;
, crc32 = require('buffer-crc32'); var crc32 = require('buffer-crc32');
var crypto = require('crypto');
var basename = require('path').basename;
var deprecate = require('util').deprecate;
var proxyaddr = require('proxy-addr');
/**
* Simple detection of charset parameter in content-type
*/
var charsetRegExp = /;\s*charset\s*=/;
/** /**
* toString ref. * Deprecate function, like core `util.deprecate`,
* but with NODE_ENV and color support.
*
* @param {Function} fn
* @param {String} msg
* @return {Function}
* @api private
*/ */
var toString = {}.toString; exports.deprecate = function(fn, msg){
if (process.env.NODE_ENV === 'test') return fn;
// prepend module name
msg = 'express: ' + msg;
if (process.stderr.isTTY) {
// colorize
msg = '\x1b[31;1m' + msg + '\x1b[0m';
}
return deprecate(fn, msg);
};
/** /**
* Return ETag for `body`. * Return strong ETag for `body`.
* *
* @param {String|Buffer} body * @param {String|Buffer} body
* @param {String} [encoding]
* @return {String} * @return {String}
* @api private * @api private
*/ */
exports.etag = function(body){ exports.etag = function etag(body, encoding){
return '"' + crc32.signed(body) + '"'; if (body.length === 0) {
// fast-path empty body
return '"1B2M2Y8AsgTpgAmY7PhCfg=="'
}
var hash = crypto
.createHash('md5')
.update(body, encoding)
.digest('base64')
return '"' + hash + '"'
}; };
/** /**
* Make `locals()` bound to the given `obj`. * Return weak ETag for `body`.
*
* This is used for `app.locals` and `res.locals`.
* *
* @param {Object} obj * @param {String|Buffer} body
* @return {Function} * @param {String} [encoding]
* @return {String}
* @api private * @api private
*/ */
exports.locals = function(){ exports.wetag = function wetag(body, encoding){
function locals(obj){ if (body.length === 0) {
for (var key in obj) locals[key] = obj[key]; // fast-path empty body
return obj; return 'W/"0-0"'
}; }
return locals; var buf = Buffer.isBuffer(body)
? body
: new Buffer(body, encoding)
var len = buf.length
return 'W/"' + len.toString(16) + '-' + crc32.unsigned(buf) + '"'
}; };
/** /**
...@@ -66,8 +105,8 @@ exports.isAbsolute = function(path){ ...@@ -66,8 +105,8 @@ exports.isAbsolute = function(path){
*/ */
exports.flatten = function(arr, ret){ exports.flatten = function(arr, ret){
var ret = ret || [] ret = ret || [];
, len = arr.length; var len = arr.length;
for (var i = 0; i < len; ++i) { for (var i = 0; i < len; ++i) {
if (Array.isArray(arr[i])) { if (Array.isArray(arr[i])) {
exports.flatten(arr[i], ret); exports.flatten(arr[i], ret);
...@@ -111,125 +150,25 @@ exports.normalizeTypes = function(types){ ...@@ -111,125 +150,25 @@ exports.normalizeTypes = function(types){
}; };
/** /**
* Return the acceptable type in `types`, if any. * Generate Content-Disposition header appropriate for the filename.
* non-ascii filenames are urlencoded and a filename* parameter is added
* *
* @param {Array} types * @param {String} filename
* @param {String} str
* @return {String} * @return {String}
* @api private * @api private
*/ */
exports.acceptsArray = function(types, str){ exports.contentDisposition = function(filename){
// accept anything when Accept is not present var ret = 'attachment';
if (!str) return types[0]; if (filename) {
filename = basename(filename);
// parse // if filename contains non-ascii characters, add a utf-8 version ala RFC 5987
var accepted = exports.parseAccept(str) ret = /[^\040-\176]/.test(filename)
, normalized = exports.normalizeTypes(types) ? 'attachment; filename=' + encodeURI(filename) + '; filename*=UTF-8\'\'' + encodeURI(filename)
, len = accepted.length; : 'attachment; filename="' + filename + '"';
for (var i = 0; i < len; ++i) {
for (var j = 0, jlen = types.length; j < jlen; ++j) {
if (exports.accept(normalized[j], accepted[i])) {
return types[j];
}
}
} }
};
/**
* Check if `type(s)` are acceptable based on
* the given `str`.
*
* @param {String|Array} type(s)
* @param {String} str
* @return {Boolean|String}
* @api private
*/
exports.accepts = function(type, str){
if ('string' == typeof type) type = type.split(/ *, */);
return exports.acceptsArray(type, str);
};
/**
* Check if `type` array is acceptable for `other`.
*
* @param {Object} type
* @param {Object} other
* @return {Boolean}
* @api private
*/
exports.accept = function(type, other){
var t = type.value.split('/');
return (t[0] == other.type || '*' == other.type)
&& (t[1] == other.subtype || '*' == other.subtype)
&& paramsEqual(type.params, other.params);
};
/** return ret;
* Check if accept params are equal.
*
* @param {Object} a
* @param {Object} b
* @return {Boolean}
* @api private
*/
function paramsEqual(a, b){
return !Object.keys(a).some(function(k) {
return a[k] != b[k];
});
}
/**
* Parse accept `str`, returning
* an array objects containing
* `.type` and `.subtype` along
* with the values provided by
* `parseQuality()`.
*
* @param {Type} name
* @return {Type}
* @api private
*/
exports.parseAccept = function(str){
return exports
.parseParams(str)
.map(function(obj){
var parts = obj.value.split('/');
obj.type = parts[0];
obj.subtype = parts[1];
return obj;
});
};
/**
* Parse quality `str`, returning an
* array of objects with `.value`,
* `.quality` and optional `.params`
*
* @param {String} str
* @return {Array}
* @api private
*/
exports.parseParams = function(str){
return str
.split(/ *, */)
.map(acceptParams)
.filter(function(obj){
return obj.quality;
})
.sort(function(a, b){
if (a.quality === b.quality) {
return a.originalIndex - b.originalIndex;
} else {
return b.quality - a.quality;
}
});
}; };
/** /**
...@@ -259,56 +198,95 @@ function acceptParams(str, index) { ...@@ -259,56 +198,95 @@ function acceptParams(str, index) {
} }
/** /**
* Escape special characters in the given string of html. * Compile "etag" value to function.
* *
* @param {String} html * @param {Boolean|String|Function} val
* @return {String} * @return {Function}
* @api private * @api private
*/ */
exports.escape = function(html) { exports.compileETag = function(val) {
return String(html) var fn;
.replace(/&/g, '&amp;')
.replace(/"/g, '&quot;') if (typeof val === 'function') {
.replace(/</g, '&lt;') return val;
.replace(/>/g, '&gt;'); }
};
switch (val) {
case true:
fn = exports.wetag;
break;
case false:
break;
case 'strong':
fn = exports.etag;
break;
case 'weak':
fn = exports.wetag;
break;
default:
throw new TypeError('unknown value for etag function: ' + val);
}
return fn;
}
/** /**
* Normalize the given path string, * Compile "proxy trust" value to function.
* returning a regular expression.
*
* An empty array should be passed,
* which will contain the placeholder
* key names. For example "/user/:id" will
* then contain ["id"].
* *
* @param {String|RegExp|Array} path * @param {Boolean|String|Number|Array|Function} val
* @param {Array} keys * @return {Function}
* @param {Boolean} sensitive
* @param {Boolean} strict
* @return {RegExp}
* @api private * @api private
*/ */
exports.pathRegexp = function(path, keys, sensitive, strict) { exports.compileTrust = function(val) {
if (toString.call(path) == '[object RegExp]') return path; if (typeof val === 'function') return val;
if (Array.isArray(path)) path = '(' + path.join('|') + ')';
path = path if (val === true) {
.concat(strict ? '' : '/?') // Support plain true/false
.replace(/\/\(/g, '(?:/') return function(){ return true };
.replace(/(\/)?(\.)?:(\w+)(?:(\(.*?\)))?(\?)?(\*)?/g, function(_, slash, format, key, capture, optional, star){ }
keys.push({ name: key, optional: !! optional });
slash = slash || ''; if (typeof val === 'number') {
return '' // Support trusting hop count
+ (optional ? '' : slash) return function(a, i){ return i < val };
+ '(?:' }
+ (optional ? slash : '')
+ (format || '') + (capture || (format && '([^/.]+?)' || '([^/]+?)')) + ')' if (typeof val === 'string') {
+ (optional || '') // Support comma-separated values
+ (star ? '(/*)?' : ''); val = val.split(/ *, */);
}) }
.replace(/([\/.])/g, '\\$1')
.replace(/\*/g, '(.*)'); return proxyaddr.compile(val || []);
return new RegExp('^' + path + '$', sensitive ? '' : 'i');
} }
/**
* Set the charset in a given Content-Type string.
*
* @param {String} type
* @param {String} charset
* @return {String}
* @api private
*/
exports.setCharset = function(type, charset){
if (!type || !charset) return type;
var exists = charsetRegExp.test(type);
// removing existing charset
if (exists) {
var parts = type.split(';');
for (var i = 1; i < parts.length; i++) {
if (charsetRegExp.test(';' + parts[i])) {
parts.splice(i, 1);
break;
}
}
type = parts.join(';');
}
return type + '; charset=' + charset;
};
...@@ -2,14 +2,14 @@ ...@@ -2,14 +2,14 @@
* Module dependencies. * Module dependencies.
*/ */
var path = require('path') var path = require('path');
, fs = require('fs') var fs = require('fs');
, utils = require('./utils') var utils = require('./utils');
, dirname = path.dirname var dirname = path.dirname;
, basename = path.basename var basename = path.basename;
, extname = path.extname var extname = path.extname;
, exists = fs.existsSync || path.existsSync var exists = fs.existsSync || path.existsSync;
, join = path.join; var join = path.join;
/** /**
* Expose `View`. * Expose `View`.
......
1.3.2 / 2013-07-18
==================
* add support for sub-commands to co-exist with the original command
1.3.1 / 2013-07-18
==================
* add quick .runningCommand hack so you can opt-out of other logic when running a sub command
1.3.0 / 2013-07-09
==================
* add EACCES error handling
* fix sub-command --help
1.2.0 / 2013-06-13
==================
* allow "-" hyphen as an option argument
* support for RegExp coercion
1.1.1 / 2012-11-20
==================
* add more sub-command padding
* fix .usage() when args are present. Closes #106
1.1.0 / 2012-11-16
==================
* add git-style executable subcommand support. Closes #94
1.0.5 / 2012-10-09
==================
* fix `--name` clobbering. Closes #92
* fix examples/help. Closes #89
1.0.4 / 2012-09-03
==================
* add `outputHelp()` method.
1.0.3 / 2012-08-30
==================
* remove invalid .version() defaulting
1.0.2 / 2012-08-24
==================
* add `--foo=bar` support [arv]
* fix password on node 0.8.8. Make backward compatible with 0.6 [focusaurus]
1.0.1 / 2012-08-03
==================
* fix issue #56
* fix tty.setRawMode(mode) was moved to tty.ReadStream#setRawMode() (i.e. process.stdin.setRawMode())
1.0.0 / 2012-07-05
==================
* add support for optional option descriptions
* add defaulting of `.version()` to package.json's version
0.6.1 / 2012-06-01
==================
* Added: append (yes or no) on confirmation
* Added: allow node.js v0.7.x
0.6.0 / 2012-04-10
==================
* Added `.prompt(obj, callback)` support. Closes #49
* Added default support to .choose(). Closes #41
* Fixed the choice example
0.5.1 / 2011-12-20
==================
* Fixed `password()` for recent nodes. Closes #36
0.5.0 / 2011-12-04
==================
* Added sub-command option support [itay]
0.4.3 / 2011-12-04
==================
* Fixed custom help ordering. Closes #32
0.4.2 / 2011-11-24
==================
* Added travis support
* Fixed: line-buffered input automatically trimmed. Closes #31
0.4.1 / 2011-11-18
==================
* Removed listening for "close" on --help
0.4.0 / 2011-11-15
==================
* Added support for `--`. Closes #24
0.3.3 / 2011-11-14
==================
* Fixed: wait for close event when writing help info [Jerry Hamlet]
0.3.2 / 2011-11-01
==================
* Fixed long flag definitions with values [felixge]
0.3.1 / 2011-10-31
==================
* Changed `--version` short flag to `-V` from `-v`
* Changed `.version()` so it's configurable [felixge]
0.3.0 / 2011-10-31
==================
* Added support for long flags only. Closes #18
0.2.1 / 2011-10-24
==================
* "node": ">= 0.4.x < 0.7.0". Closes #20
0.2.0 / 2011-09-26
==================
* Allow for defaults that are not just boolean. Default peassignment only occurs for --no-*, optional, and required arguments. [Jim Isaacs]
0.1.0 / 2011-08-24
==================
* Added support for custom `--help` output
0.0.5 / 2011-08-18
==================
* Changed: when the user enters nothing prompt for password again
* Fixed issue with passwords beginning with numbers [NuckChorris]
0.0.4 / 2011-08-15
==================
* Fixed `Commander#args`
0.0.3 / 2011-08-15
==================
* Added default option value support
0.0.2 / 2011-08-15
==================
* Added mask support to `Command#password(str[, mask], fn)`
* Added `Command#password(str, fn)`
0.0.1 / 2010-01-03
==================
* Initial release
# Commander.js
The complete solution for [node.js](http://nodejs.org) command-line interfaces, inspired by Ruby's [commander](https://github.com/visionmedia/commander).
[![Build Status](https://secure.travis-ci.org/visionmedia/commander.js.png)](http://travis-ci.org/visionmedia/commander.js)
## Installation
$ npm install commander
## Option parsing
Options with commander are defined with the `.option()` method, also serving as documentation for the options. The example below parses args and options from `process.argv`, leaving remaining args as the `program.args` array which were not consumed by options.
```js
#!/usr/bin/env node
/**
* Module dependencies.
*/
var program = require('commander');
program
.version('0.0.1')
.option('-p, --peppers', 'Add peppers')
.option('-P, --pineapple', 'Add pineapple')
.option('-b, --bbq', 'Add bbq sauce')
.option('-c, --cheese [type]', 'Add the specified type of cheese [marble]', 'marble')
.parse(process.argv);
console.log('you ordered a pizza with:');
if (program.peppers) console.log(' - peppers');
if (program.pineapple) console.log(' - pineapple');
if (program.bbq) console.log(' - bbq');
console.log(' - %s cheese', program.cheese);
```
Short flags may be passed as a single arg, for example `-abc` is equivalent to `-a -b -c`. Multi-word options such as "--template-engine" are camel-cased, becoming `program.templateEngine` etc.
## Automated --help
The help information is auto-generated based on the information commander already knows about your program, so the following `--help` info is for free:
```
$ ./examples/pizza --help
Usage: pizza [options]
Options:
-V, --version output the version number
-p, --peppers Add peppers
-P, --pineapple Add pineapple
-b, --bbq Add bbq sauce
-c, --cheese <type> Add the specified type of cheese [marble]
-h, --help output usage information
```
## Coercion
```js
function range(val) {
return val.split('..').map(Number);
}
function list(val) {
return val.split(',');
}
program
.version('0.0.1')
.usage('[options] <file ...>')
.option('-i, --integer <n>', 'An integer argument', parseInt)
.option('-f, --float <n>', 'A float argument', parseFloat)
.option('-r, --range <a>..<b>', 'A range', range)
.option('-l, --list <items>', 'A list', list)
.option('-o, --optional [value]', 'An optional value')
.parse(process.argv);
console.log(' int: %j', program.integer);
console.log(' float: %j', program.float);
console.log(' optional: %j', program.optional);
program.range = program.range || [];
console.log(' range: %j..%j', program.range[0], program.range[1]);
console.log(' list: %j', program.list);
console.log(' args: %j', program.args);
```
## Custom help
You can display arbitrary `-h, --help` information
by listening for "--help". Commander will automatically
exit once you are done so that the remainder of your program
does not execute causing undesired behaviours, for example
in the following executable "stuff" will not output when
`--help` is used.
```js
#!/usr/bin/env node
/**
* Module dependencies.
*/
var program = require('../');
function list(val) {
return val.split(',').map(Number);
}
program
.version('0.0.1')
.option('-f, --foo', 'enable some foo')
.option('-b, --bar', 'enable some bar')
.option('-B, --baz', 'enable some baz');
// must be before .parse() since
// node's emit() is immediate
program.on('--help', function(){
console.log(' Examples:');
console.log('');
console.log(' $ custom-help --help');
console.log(' $ custom-help -h');
console.log('');
});
program.parse(process.argv);
console.log('stuff');
```
yielding the following help output:
```
Usage: custom-help [options]
Options:
-h, --help output usage information
-V, --version output the version number
-f, --foo enable some foo
-b, --bar enable some bar
-B, --baz enable some baz
Examples:
$ custom-help --help
$ custom-help -h
```
## .prompt(msg, fn)
Single-line prompt:
```js
program.prompt('name: ', function(name){
console.log('hi %s', name);
});
```
Multi-line prompt:
```js
program.prompt('description:', function(name){
console.log('hi %s', name);
});
```
Coercion:
```js
program.prompt('Age: ', Number, function(age){
console.log('age: %j', age);
});
```
```js
program.prompt('Birthdate: ', Date, function(date){
console.log('date: %s', date);
});
```
```js
program.prompt('Email: ', /^.+@.+\..+$/, function(email){
console.log('email: %j', email);
});
```
## .password(msg[, mask], fn)
Prompt for password without echoing:
```js
program.password('Password: ', function(pass){
console.log('got "%s"', pass);
process.stdin.destroy();
});
```
Prompt for password with mask char "*":
```js
program.password('Password: ', '*', function(pass){
console.log('got "%s"', pass);
process.stdin.destroy();
});
```
## .confirm(msg, fn)
Confirm with the given `msg`:
```js
program.confirm('continue? ', function(ok){
console.log(' got %j', ok);
});
```
## .choose(list, fn)
Let the user choose from a `list`:
```js
var list = ['tobi', 'loki', 'jane', 'manny', 'luna'];
console.log('Choose the coolest pet:');
program.choose(list, function(i){
console.log('you chose %d "%s"', i, list[i]);
});
```
## .outputHelp()
Output help information without exiting.
## .help()
Output help information and exit immediately.
## Links
- [API documentation](http://visionmedia.github.com/commander.js/)
- [ascii tables](https://github.com/LearnBoost/cli-table)
- [progress bars](https://github.com/visionmedia/node-progress)
- [more progress bars](https://github.com/substack/node-multimeter)
- [examples](https://github.com/visionmedia/commander.js/tree/master/examples)
## License
(The MIT License)
Copyright (c) 2011 TJ Holowaychuk &lt;tj@vision-media.ca&gt;
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
keypress
========
### Make any Node ReadableStream emit "keypress" events
Previous to Node `v0.8.x`, there was an undocumented `"keypress"` event that
`process.stdin` would emit when it was a TTY. Some people discovered this hidden
gem, and started using it in their own code.
Now in Node `v0.8.x`, this `"keypress"` event does not get emitted by default,
but rather only when it is being used in conjuction with the `readline` (or by
extension, the `repl`) module.
This module is the exact logic from the node `v0.8.x` releases ripped out into its
own module.
__Bonus:__ Now with mouse support!
Installation
------------
Install with `npm`:
``` bash
$ npm install keypress
```
Or add it to the `"dependencies"` section of your _package.json_ file.
Example
-------
#### Listening for "keypress" events
``` js
var keypress = require('keypress');
// make `process.stdin` begin emitting "keypress" events
keypress(process.stdin);
// listen for the "keypress" event
process.stdin.on('keypress', function (ch, key) {
console.log('got "keypress"', key);
if (key && key.ctrl && key.name == 'c') {
process.stdin.pause();
}
});
process.stdin.setRawMode(true);
process.stdin.resume();
```
#### Listening for "mousepress" events
``` js
var keypress = require('keypress');
// make `process.stdin` begin emitting "mousepress" (and "keypress") events
keypress(process.stdin);
// you must enable the mouse events before they will begin firing
keypress.enableMouse(process.stdout);
process.stdin.on('mousepress', function (info) {
console.log('got "mousepress" event at %d x %d', info.x, info.y);
});
process.on('exit', function () {
// disable mouse on exit, so that the state
// is back to normal for the terminal
keypress.disableMouse(process.stdout);
});
```
License
-------
(The MIT License)
Copyright (c) 2012 Nathan Rajlich &lt;nathan@tootallnate.net&gt;
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
/**
* This module offers the internal "keypress" functionality from node-core's
* `readline` module, for your own programs and modules to use.
*
* Usage:
*
* require('keypress')(process.stdin);
*
* process.stdin.on('keypress', function (ch, key) {
* console.log(ch, key);
* if (key.ctrl && key.name == 'c') {
* process.stdin.pause();
* }
* });
* proces.stdin.resume();
*/
var exports = module.exports = keypress;
exports.enableMouse = function (stream) {
stream.write('\x1b' +'[?1000h')
}
exports.disableMouse = function (stream) {
stream.write('\x1b' +'[?1000l')
}
/**
* accepts a readable Stream instance and makes it emit "keypress" events
*/
function keypress(stream) {
if (isEmittingKeypress(stream)) return;
stream._emitKeypress = true;
function onData(b) {
if (stream.listeners('keypress').length > 0) {
emitKey(stream, b);
} else {
// Nobody's watching anyway
stream.removeListener('data', onData);
stream.on('newListener', onNewListener);
}
}
function onNewListener(event) {
if (event == 'keypress') {
stream.on('data', onData);
stream.removeListener('newListener', onNewListener);
}
}
if (stream.listeners('keypress').length > 0) {
stream.on('data', onData);
} else {
stream.on('newListener', onNewListener);
}
}
/**
* Returns `true` if the stream is already emitting "keypress" events.
* `false` otherwise.
*/
function isEmittingKeypress(stream) {
var rtn = stream._emitKeypress;
if (!rtn) {
// hack: check for the v0.6.x "data" event
stream.listeners('data').forEach(function (l) {
if (l.name == 'onData' && /emitKey/.test(l.toString())) {
rtn = true;
stream._emitKeypress = true;
}
});
}
if (!rtn) {
// hack: check for the v0.6.x "newListener" event
stream.listeners('newListener').forEach(function (l) {
if (l.name == 'onNewListener' && /keypress/.test(l.toString())) {
rtn = true;
stream._emitKeypress = true;
}
});
}
return rtn;
}
/*
Some patterns seen in terminal key escape codes, derived from combos seen
at http://www.midnight-commander.org/browser/lib/tty/key.c
ESC letter
ESC [ letter
ESC [ modifier letter
ESC [ 1 ; modifier letter
ESC [ num char
ESC [ num ; modifier char
ESC O letter
ESC O modifier letter
ESC O 1 ; modifier letter
ESC N letter
ESC [ [ num ; modifier char
ESC [ [ 1 ; modifier letter
ESC ESC [ num char
ESC ESC O letter
- char is usually ~ but $ and ^ also happen with rxvt
- modifier is 1 +
(shift * 1) +
(left_alt * 2) +
(ctrl * 4) +
(right_alt * 8)
- two leading ESCs apparently mean the same as one leading ESC
*/
// Regexes used for ansi escape code splitting
var metaKeyCodeRe = /^(?:\x1b)([a-zA-Z0-9])$/;
var functionKeyCodeRe =
/^(?:\x1b+)(O|N|\[|\[\[)(?:(\d+)(?:;(\d+))?([~^$])|(?:1;)?(\d+)?([a-zA-Z]))/;
function emitKey(stream, s) {
var ch,
key = {
name: undefined,
ctrl: false,
meta: false,
shift: false
},
parts;
if (Buffer.isBuffer(s)) {
if (s[0] > 127 && s[1] === undefined) {
s[0] -= 128;
s = '\x1b' + s.toString(stream.encoding || 'utf-8');
} else {
s = s.toString(stream.encoding || 'utf-8');
}
}
key.sequence = s;
if (s === '\r' || s === '\n') {
// enter
key.name = 'enter';
} else if (s === '\t') {
// tab
key.name = 'tab';
} else if (s === '\b' || s === '\x7f' ||
s === '\x1b\x7f' || s === '\x1b\b') {
// backspace or ctrl+h
key.name = 'backspace';
key.meta = (s.charAt(0) === '\x1b');
} else if (s === '\x1b' || s === '\x1b\x1b') {
// escape key
key.name = 'escape';
key.meta = (s.length === 2);
} else if (s === ' ' || s === '\x1b ') {
key.name = 'space';
key.meta = (s.length === 2);
} else if (s <= '\x1a') {
// ctrl+letter
key.name = String.fromCharCode(s.charCodeAt(0) + 'a'.charCodeAt(0) - 1);
key.ctrl = true;
} else if (s.length === 1 && s >= 'a' && s <= 'z') {
// lowercase letter
key.name = s;
} else if (s.length === 1 && s >= 'A' && s <= 'Z') {
// shift+letter
key.name = s.toLowerCase();
key.shift = true;
} else if (parts = metaKeyCodeRe.exec(s)) {
// meta+character key
key.name = parts[1].toLowerCase();
key.meta = true;
key.shift = /^[A-Z]$/.test(parts[1]);
} else if (parts = functionKeyCodeRe.exec(s)) {
// ansi escape sequence
// reassemble the key code leaving out leading \x1b's,
// the modifier key bitflag and any meaningless "1;" sequence
var code = (parts[1] || '') + (parts[2] || '') +
(parts[4] || '') + (parts[6] || ''),
modifier = (parts[3] || parts[5] || 1) - 1;
// Parse the key modifier
key.ctrl = !!(modifier & 4);
key.meta = !!(modifier & 10);
key.shift = !!(modifier & 1);
key.code = code;
// Parse the key itself
switch (code) {
/* xterm/gnome ESC O letter */
case 'OP': key.name = 'f1'; break;
case 'OQ': key.name = 'f2'; break;
case 'OR': key.name = 'f3'; break;
case 'OS': key.name = 'f4'; break;
/* xterm/rxvt ESC [ number ~ */
case '[11~': key.name = 'f1'; break;
case '[12~': key.name = 'f2'; break;
case '[13~': key.name = 'f3'; break;
case '[14~': key.name = 'f4'; break;
/* from Cygwin and used in libuv */
case '[[A': key.name = 'f1'; break;
case '[[B': key.name = 'f2'; break;
case '[[C': key.name = 'f3'; break;
case '[[D': key.name = 'f4'; break;
case '[[E': key.name = 'f5'; break;
/* common */
case '[15~': key.name = 'f5'; break;
case '[17~': key.name = 'f6'; break;
case '[18~': key.name = 'f7'; break;
case '[19~': key.name = 'f8'; break;
case '[20~': key.name = 'f9'; break;
case '[21~': key.name = 'f10'; break;
case '[23~': key.name = 'f11'; break;
case '[24~': key.name = 'f12'; break;
/* xterm ESC [ letter */
case '[A': key.name = 'up'; break;
case '[B': key.name = 'down'; break;
case '[C': key.name = 'right'; break;
case '[D': key.name = 'left'; break;
case '[E': key.name = 'clear'; break;
case '[F': key.name = 'end'; break;
case '[H': key.name = 'home'; break;
/* xterm/gnome ESC O letter */
case 'OA': key.name = 'up'; break;
case 'OB': key.name = 'down'; break;
case 'OC': key.name = 'right'; break;
case 'OD': key.name = 'left'; break;
case 'OE': key.name = 'clear'; break;
case 'OF': key.name = 'end'; break;
case 'OH': key.name = 'home'; break;
/* xterm/rxvt ESC [ number ~ */
case '[1~': key.name = 'home'; break;
case '[2~': key.name = 'insert'; break;
case '[3~': key.name = 'delete'; break;
case '[4~': key.name = 'end'; break;
case '[5~': key.name = 'pageup'; break;
case '[6~': key.name = 'pagedown'; break;
/* putty */
case '[[5~': key.name = 'pageup'; break;
case '[[6~': key.name = 'pagedown'; break;
/* rxvt */
case '[7~': key.name = 'home'; break;
case '[8~': key.name = 'end'; break;
/* rxvt keys with modifiers */
case '[a': key.name = 'up'; key.shift = true; break;
case '[b': key.name = 'down'; key.shift = true; break;
case '[c': key.name = 'right'; key.shift = true; break;
case '[d': key.name = 'left'; key.shift = true; break;
case '[e': key.name = 'clear'; key.shift = true; break;
case '[2$': key.name = 'insert'; key.shift = true; break;
case '[3$': key.name = 'delete'; key.shift = true; break;
case '[5$': key.name = 'pageup'; key.shift = true; break;
case '[6$': key.name = 'pagedown'; key.shift = true; break;
case '[7$': key.name = 'home'; key.shift = true; break;
case '[8$': key.name = 'end'; key.shift = true; break;
case 'Oa': key.name = 'up'; key.ctrl = true; break;
case 'Ob': key.name = 'down'; key.ctrl = true; break;
case 'Oc': key.name = 'right'; key.ctrl = true; break;
case 'Od': key.name = 'left'; key.ctrl = true; break;
case 'Oe': key.name = 'clear'; key.ctrl = true; break;
case '[2^': key.name = 'insert'; key.ctrl = true; break;
case '[3^': key.name = 'delete'; key.ctrl = true; break;
case '[5^': key.name = 'pageup'; key.ctrl = true; break;
case '[6^': key.name = 'pagedown'; key.ctrl = true; break;
case '[7^': key.name = 'home'; key.ctrl = true; break;
case '[8^': key.name = 'end'; key.ctrl = true; break;
/* misc. */
case '[Z': key.name = 'tab'; key.shift = true; break;
default: key.name = 'undefined'; break;
}
} else if (s.length > 1 && s[0] !== '\x1b') {
// Got a longer-than-one string of characters.
// Probably a paste, since it wasn't a control sequence.
Array.prototype.forEach.call(s, function(c) {
emitKey(stream, c);
});
return;
}
if (key.code == '[M') {
key.name = 'mouse';
var s = key.sequence;
var b = s.charCodeAt(3);
key.x = s.charCodeAt(4) - 040;
key.y = s.charCodeAt(5) - 040;
key.scroll = 0;
key.ctrl = !!(1<<4 & b);
key.meta = !!(1<<3 & b);
key.shift = !!(1<<2 & b);
key.release = (3 & b) === 3;
if (1<<6 & b) { //scroll
key.scroll = 1 & b ? 1 : -1;
}
if (!key.release && !key.scroll) {
key.button = b & 3;
}
}
// Don't emit a key if no name was found
if (key.name === undefined) {
key = undefined;
}
if (s.length === 1) {
ch = s;
}
if (key && key.name == 'mouse') {
stream.emit('mousepress', key)
} else if (key || ch) {
stream.emit('keypress', ch, key);
}
}
{
"name": "keypress",
"version": "0.1.0",
"description": "Make any Node ReadableStream emit \"keypress\" events",
"author": {
"name": "Nathan Rajlich",
"email": "nathan@tootallnate.net",
"url": "http://tootallnate.net"
},
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git://github.com/TooTallNate/keypress.git"
},
"keywords": [
"keypress",
"readline",
"core"
],
"license": "MIT",
"readme": "keypress\n========\n### Make any Node ReadableStream emit \"keypress\" events\n\n\nPrevious to Node `v0.8.x`, there was an undocumented `\"keypress\"` event that\n`process.stdin` would emit when it was a TTY. Some people discovered this hidden\ngem, and started using it in their own code.\n\nNow in Node `v0.8.x`, this `\"keypress\"` event does not get emitted by default,\nbut rather only when it is being used in conjuction with the `readline` (or by\nextension, the `repl`) module.\n\nThis module is the exact logic from the node `v0.8.x` releases ripped out into its\nown module.\n\n__Bonus:__ Now with mouse support!\n\nInstallation\n------------\n\nInstall with `npm`:\n\n``` bash\n$ npm install keypress\n```\n\nOr add it to the `\"dependencies\"` section of your _package.json_ file.\n\n\nExample\n-------\n\n#### Listening for \"keypress\" events\n\n``` js\nvar keypress = require('keypress');\n\n// make `process.stdin` begin emitting \"keypress\" events\nkeypress(process.stdin);\n\n// listen for the \"keypress\" event\nprocess.stdin.on('keypress', function (ch, key) {\n console.log('got \"keypress\"', key);\n if (key && key.ctrl && key.name == 'c') {\n process.stdin.pause();\n }\n});\n\nprocess.stdin.setRawMode(true);\nprocess.stdin.resume();\n```\n\n#### Listening for \"mousepress\" events\n\n``` js\nvar keypress = require('keypress');\n\n// make `process.stdin` begin emitting \"mousepress\" (and \"keypress\") events\nkeypress(process.stdin);\n\n// you must enable the mouse events before they will begin firing\nkeypress.enableMouse(process.stdout);\n\nprocess.stdin.on('mousepress', function (info) {\n console.log('got \"mousepress\" event at %d x %d', info.x, info.y);\n});\n\nprocess.on('exit', function () {\n // disable mouse on exit, so that the state\n // is back to normal for the terminal\n keypress.disableMouse(process.stdout);\n});\n```\n\n\nLicense\n-------\n\n(The MIT License)\n\nCopyright (c) 2012 Nathan Rajlich &lt;nathan@tootallnate.net&gt;\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n",
"readmeFilename": "README.md",
"bugs": {
"url": "https://github.com/TooTallNate/keypress/issues"
},
"_id": "keypress@0.1.0",
"_from": "keypress@0.1.x"
}
var keypress = require('./')
keypress(process.stdin)
if (process.stdin.setRawMode)
process.stdin.setRawMode(true)
else
require('tty').setRawMode(true)
process.stdin.on('keypress', function (c, key) {
console.log(0, c, key)
if (key && key.ctrl && key.name == 'c') {
process.stdin.pause()
}
})
process.stdin.on('mousepress', function (mouse) {
console.log(mouse)
})
keypress.enableMouse(process.stdout)
process.on('exit', function () {
//disable mouse on exit, so that the state is back to normal
//for the terminal.
keypress.disableMouse(process.stdout)
})
process.stdin.resume()
{
"name": "commander",
"version": "1.3.2",
"description": "the complete solution for node.js command-line programs",
"keywords": [
"command",
"option",
"parser",
"prompt",
"stdin"
],
"author": {
"name": "TJ Holowaychuk",
"email": "tj@vision-media.ca"
},
"repository": {
"type": "git",
"url": "https://github.com/visionmedia/commander.js.git"
},
"dependencies": {
"keypress": "0.1.x"
},
"devDependencies": {
"should": ">= 0.0.1"
},
"scripts": {
"test": "make test"
},
"main": "index",
"engines": {
"node": ">= 0.6.x"
},
"readme": "# Commander.js\n\n The complete solution for [node.js](http://nodejs.org) command-line interfaces, inspired by Ruby's [commander](https://github.com/visionmedia/commander).\n\n [![Build Status](https://secure.travis-ci.org/visionmedia/commander.js.png)](http://travis-ci.org/visionmedia/commander.js)\n\n## Installation\n\n $ npm install commander\n\n## Option parsing\n\n Options with commander are defined with the `.option()` method, also serving as documentation for the options. The example below parses args and options from `process.argv`, leaving remaining args as the `program.args` array which were not consumed by options.\n\n```js\n#!/usr/bin/env node\n\n/**\n * Module dependencies.\n */\n\nvar program = require('commander');\n\nprogram\n .version('0.0.1')\n .option('-p, --peppers', 'Add peppers')\n .option('-P, --pineapple', 'Add pineapple')\n .option('-b, --bbq', 'Add bbq sauce')\n .option('-c, --cheese [type]', 'Add the specified type of cheese [marble]', 'marble')\n .parse(process.argv);\n\nconsole.log('you ordered a pizza with:');\nif (program.peppers) console.log(' - peppers');\nif (program.pineapple) console.log(' - pineapple');\nif (program.bbq) console.log(' - bbq');\nconsole.log(' - %s cheese', program.cheese);\n```\n\n Short flags may be passed as a single arg, for example `-abc` is equivalent to `-a -b -c`. Multi-word options such as \"--template-engine\" are camel-cased, becoming `program.templateEngine` etc.\n\n## Automated --help\n\n The help information is auto-generated based on the information commander already knows about your program, so the following `--help` info is for free:\n\n``` \n $ ./examples/pizza --help\n\n Usage: pizza [options]\n\n Options:\n\n -V, --version output the version number\n -p, --peppers Add peppers\n -P, --pineapple Add pineapple\n -b, --bbq Add bbq sauce\n -c, --cheese <type> Add the specified type of cheese [marble]\n -h, --help output usage information\n\n```\n\n## Coercion\n\n```js\nfunction range(val) {\n return val.split('..').map(Number);\n}\n\nfunction list(val) {\n return val.split(',');\n}\n\nprogram\n .version('0.0.1')\n .usage('[options] <file ...>')\n .option('-i, --integer <n>', 'An integer argument', parseInt)\n .option('-f, --float <n>', 'A float argument', parseFloat)\n .option('-r, --range <a>..<b>', 'A range', range)\n .option('-l, --list <items>', 'A list', list)\n .option('-o, --optional [value]', 'An optional value')\n .parse(process.argv);\n\nconsole.log(' int: %j', program.integer);\nconsole.log(' float: %j', program.float);\nconsole.log(' optional: %j', program.optional);\nprogram.range = program.range || [];\nconsole.log(' range: %j..%j', program.range[0], program.range[1]);\nconsole.log(' list: %j', program.list);\nconsole.log(' args: %j', program.args);\n```\n\n## Custom help\n\n You can display arbitrary `-h, --help` information\n by listening for \"--help\". Commander will automatically\n exit once you are done so that the remainder of your program\n does not execute causing undesired behaviours, for example\n in the following executable \"stuff\" will not output when\n `--help` is used.\n\n```js\n#!/usr/bin/env node\n\n/**\n * Module dependencies.\n */\n\nvar program = require('../');\n\nfunction list(val) {\n return val.split(',').map(Number);\n}\n\nprogram\n .version('0.0.1')\n .option('-f, --foo', 'enable some foo')\n .option('-b, --bar', 'enable some bar')\n .option('-B, --baz', 'enable some baz');\n\n// must be before .parse() since\n// node's emit() is immediate\n\nprogram.on('--help', function(){\n console.log(' Examples:');\n console.log('');\n console.log(' $ custom-help --help');\n console.log(' $ custom-help -h');\n console.log('');\n});\n\nprogram.parse(process.argv);\n\nconsole.log('stuff');\n```\n\nyielding the following help output:\n\n```\n\nUsage: custom-help [options]\n\nOptions:\n\n -h, --help output usage information\n -V, --version output the version number\n -f, --foo enable some foo\n -b, --bar enable some bar\n -B, --baz enable some baz\n\nExamples:\n\n $ custom-help --help\n $ custom-help -h\n\n```\n\n## .prompt(msg, fn)\n\n Single-line prompt:\n\n```js\nprogram.prompt('name: ', function(name){\n console.log('hi %s', name);\n});\n```\n\n Multi-line prompt:\n\n```js\nprogram.prompt('description:', function(name){\n console.log('hi %s', name);\n});\n```\n\n Coercion:\n\n```js\nprogram.prompt('Age: ', Number, function(age){\n console.log('age: %j', age);\n});\n```\n\n```js\nprogram.prompt('Birthdate: ', Date, function(date){\n console.log('date: %s', date);\n});\n```\n\n```js\nprogram.prompt('Email: ', /^.+@.+\\..+$/, function(email){\n console.log('email: %j', email);\n});\n```\n\n## .password(msg[, mask], fn)\n\nPrompt for password without echoing:\n\n```js\nprogram.password('Password: ', function(pass){\n console.log('got \"%s\"', pass);\n process.stdin.destroy();\n});\n```\n\nPrompt for password with mask char \"*\":\n\n```js\nprogram.password('Password: ', '*', function(pass){\n console.log('got \"%s\"', pass);\n process.stdin.destroy();\n});\n```\n\n## .confirm(msg, fn)\n\n Confirm with the given `msg`:\n\n```js\nprogram.confirm('continue? ', function(ok){\n console.log(' got %j', ok);\n});\n```\n\n## .choose(list, fn)\n\n Let the user choose from a `list`:\n\n```js\nvar list = ['tobi', 'loki', 'jane', 'manny', 'luna'];\n\nconsole.log('Choose the coolest pet:');\nprogram.choose(list, function(i){\n console.log('you chose %d \"%s\"', i, list[i]);\n});\n```\n\n## .outputHelp()\n\n Output help information without exiting.\n\n## .help()\n\n Output help information and exit immediately.\n\n## Links\n\n - [API documentation](http://visionmedia.github.com/commander.js/)\n - [ascii tables](https://github.com/LearnBoost/cli-table)\n - [progress bars](https://github.com/visionmedia/node-progress)\n - [more progress bars](https://github.com/substack/node-multimeter)\n - [examples](https://github.com/visionmedia/commander.js/tree/master/examples)\n\n## License \n\n(The MIT License)\n\nCopyright (c) 2011 TJ Holowaychuk &lt;tj@vision-media.ca&gt;\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n",
"readmeFilename": "Readme.md",
"bugs": {
"url": "https://github.com/visionmedia/commander.js/issues"
},
"_id": "commander@1.3.2",
"_from": "commander@1.3.2"
}
*.markdown
*.md
.git*
Makefile
benchmarks/
docs/
examples/
install.sh
support/
test/
.DS_Store
coverage.html
language: node_js
node_js:
- "0.8"
- "0.10"
\ No newline at end of file
(The MIT License)
Copyright (c) 2010 Sencha Inc.
Copyright (c) 2011 LearnBoost
Copyright (c) 2011 TJ Holowaychuk
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
# Connect [![build status](https://secure.travis-ci.org/senchalabs/connect.png)](http://travis-ci.org/senchalabs/connect)
Connect is an extensible HTTP server framework for [node](http://nodejs.org), providing high performance "plugins" known as _middleware_.
Connect is bundled with over _20_ commonly used middleware, including
a logger, session support, cookie parser, and [more](http://senchalabs.github.com/connect). Be sure to view the 2.x [documentation](http://www.senchalabs.org/connect/).
```js
var connect = require('connect')
, http = require('http');
var app = connect()
.use(connect.favicon())
.use(connect.logger('dev'))
.use(connect.static('public'))
.use(connect.directory('public'))
.use(connect.cookieParser())
.use(connect.session({ secret: 'my secret here' }))
.use(function(req, res){
res.end('Hello from Connect!\n');
});
http.createServer(app).listen(3000);
```
## Middleware
- [basicAuth](http://www.senchalabs.org/connect/basicAuth.html)
- [bodyParser](http://www.senchalabs.org/connect/bodyParser.html)
- [compress](http://www.senchalabs.org/connect/compress.html)
- [cookieParser](http://www.senchalabs.org/connect/cookieParser.html)
- [cookieSession](http://www.senchalabs.org/connect/cookieSession.html)
- [csrf](http://www.senchalabs.org/connect/csrf.html)
- [directory](http://www.senchalabs.org/connect/directory.html)
- [errorHandler](http://www.senchalabs.org/connect/errorHandler.html)
- [favicon](http://www.senchalabs.org/connect/favicon.html)
- [json](http://www.senchalabs.org/connect/json.html)
- [limit](http://www.senchalabs.org/connect/limit.html)
- [logger](http://www.senchalabs.org/connect/logger.html)
- [methodOverride](http://www.senchalabs.org/connect/methodOverride.html)
- [multipart](http://www.senchalabs.org/connect/multipart.html)
- [urlencoded](http://www.senchalabs.org/connect/urlencoded.html)
- [query](http://www.senchalabs.org/connect/query.html)
- [responseTime](http://www.senchalabs.org/connect/responseTime.html)
- [session](http://www.senchalabs.org/connect/session.html)
- [static](http://www.senchalabs.org/connect/static.html)
- [staticCache](http://www.senchalabs.org/connect/staticCache.html)
- [subdomains](http://www.senchalabs.org/connect/subdomains.html)
- [vhost](http://www.senchalabs.org/connect/vhost.html)
## Running Tests
first:
$ npm install -d
then:
$ make test
## Contributors
https://github.com/senchalabs/connect/graphs/contributors
## Node Compatibility
Connect `< 1.x` is compatible with node 0.2.x
Connect `1.x` is compatible with node 0.4.x
Connect `2.x` is compatible with node 0.6.x
Connect (_master_) is compatible with node 0.8.x
## CLA
[http://sencha.com/cla](http://sencha.com/cla)
## License
View the [LICENSE](https://github.com/senchalabs/connect/blob/master/LICENSE) file. The [Silk](http://www.famfamfam.com/lab/icons/silk/) icons used by the `directory` middleware created by/copyright of [FAMFAMFAM](http://www.famfamfam.com/).
module.exports = process.env.CONNECT_COV
? require('./lib-cov/connect')
: require('./lib/connect');
\ No newline at end of file
/*!
* Connect - Cache
* Copyright(c) 2011 Sencha Inc.
* MIT Licensed
*/
/**
* Expose `Cache`.
*/
module.exports = Cache;
/**
* LRU cache store.
*
* @param {Number} limit
* @api private
*/
function Cache(limit) {
this.store = {};
this.keys = [];
this.limit = limit;
}
/**
* Touch `key`, promoting the object.
*
* @param {String} key
* @param {Number} i
* @api private
*/
Cache.prototype.touch = function(key, i){
this.keys.splice(i,1);
this.keys.push(key);
};
/**
* Remove `key`.
*
* @param {String} key
* @api private
*/
Cache.prototype.remove = function(key){
delete this.store[key];
};
/**
* Get the object stored for `key`.
*
* @param {String} key
* @return {Array}
* @api private
*/
Cache.prototype.get = function(key){
return this.store[key];
};
/**
* Add a cache `key`.
*
* @param {String} key
* @return {Array}
* @api private
*/
Cache.prototype.add = function(key){
// initialize store
var len = this.keys.push(key);
// limit reached, invalidate LRU
if (len > this.limit) this.remove(this.keys.shift());
var arr = this.store[key] = [];
arr.createdAt = new Date;
return arr;
};
/*!
* Connect
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Module dependencies.
*/
var EventEmitter = require('events').EventEmitter
, proto = require('./proto')
, utils = require('./utils')
, path = require('path')
, basename = path.basename
, fs = require('fs');
// node patches
require('./patch');
// expose createServer() as the module
exports = module.exports = createServer;
/**
* Framework version.
*/
exports.version = '2.7.11';
/**
* Expose mime module.
*/
exports.mime = require('./middleware/static').mime;
/**
* Expose the prototype.
*/
exports.proto = proto;
/**
* Auto-load middleware getters.
*/
exports.middleware = {};
/**
* Expose utilities.
*/
exports.utils = utils;
/**
* Create a new connect server.
*
* @return {Function}
* @api public
*/
function createServer() {
function app(req, res, next){ app.handle(req, res, next); }
utils.merge(app, proto);
utils.merge(app, EventEmitter.prototype);
app.route = '/';
app.stack = [];
for (var i = 0; i < arguments.length; ++i) {
app.use(arguments[i]);
}
return app;
};
/**
* Support old `.createServer()` method.
*/
createServer.createServer = createServer;
/**
* Auto-load bundled middleware with getters.
*/
fs.readdirSync(__dirname + '/middleware').forEach(function(filename){
if (!/\.js$/.test(filename)) return;
var name = basename(filename, '.js');
function load(){ return require('./middleware/' + name); }
exports.middleware.__defineGetter__(name, load);
exports.__defineGetter__(name, load);
});
/*!
* Connect - basicAuth
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Basic Auth:
*
* Enfore basic authentication by providing a `callback(user, pass)`,
* which must return `true` in order to gain access. Alternatively an async
* method is provided as well, invoking `callback(user, pass, callback)`. Populates
* `req.user`. The final alternative is simply passing username / password
* strings.
*
* See [basic-auth-connect](https://github.com/expressjs/basic-auth-connect)
*
* @param {Function|String} callback or username
* @param {String} realm
* @api public
*/
module.exports = require('basic-auth-connect');
/*!
* Connect - compress
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Compress:
*
* Compress response data with gzip/deflate.
*
* See [compression](https://github.com/expressjs/compression)
*
* @param {Object} options
* @return {Function}
* @api public
*/
module.exports = require('compression');
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment