Uploaded the base of the project the working demo of CH1 Multiplayer Game Development with HTML5
This commit is contained in:
+72
@@ -0,0 +1,72 @@
|
||||
1.3.2 / 2014-09-27
|
||||
==================
|
||||
|
||||
* Fix `req.ip` integration when `immediate: false`
|
||||
|
||||
1.3.1 / 2014-09-14
|
||||
==================
|
||||
|
||||
* Remove un-used `bytes` dependency
|
||||
* deps: depd@0.4.5
|
||||
|
||||
1.3.0 / 2014-09-01
|
||||
==================
|
||||
|
||||
* Assert if `format` is not a function or string
|
||||
|
||||
1.2.3 / 2014-08-16
|
||||
==================
|
||||
|
||||
* deps: on-finished@2.1.0
|
||||
|
||||
1.2.2 / 2014-07-27
|
||||
==================
|
||||
|
||||
* deps: depd@0.4.4
|
||||
- Work-around v8 generating empty stack traces
|
||||
|
||||
1.2.1 / 2014-07-26
|
||||
==================
|
||||
|
||||
* deps: depd@0.4.3
|
||||
- Fix exception when global `Error.stackTraceLimit` is too low
|
||||
|
||||
1.2.0 / 2014-07-19
|
||||
==================
|
||||
|
||||
* Add `:remote-user` token
|
||||
* Add `combined` log format
|
||||
* Add `common` log format
|
||||
* Add `morgan(format, options)` function signature
|
||||
* Deprecate `default` format -- use `combined` format instead
|
||||
* Deprecate not providing a format
|
||||
* Remove non-standard grey color from `dev` format
|
||||
|
||||
1.1.1 / 2014-05-20
|
||||
==================
|
||||
|
||||
* simplify method to get remote address
|
||||
|
||||
1.1.0 / 2014-05-18
|
||||
==================
|
||||
|
||||
* "dev" format will use same tokens as other formats
|
||||
* `:response-time` token is now empty when immediate used
|
||||
* `:response-time` token is now monotonic
|
||||
* `:response-time` token has precision to 1 μs
|
||||
* fix `:status` + immediate output in node.js 0.8
|
||||
* improve `buffer` option to prevent indefinite event loop holding
|
||||
* deps: bytes@1.0.0
|
||||
- add negative support
|
||||
|
||||
1.0.1 / 2014-05-04
|
||||
==================
|
||||
|
||||
* Make buffer unique per morgan instance
|
||||
* deps: bytes@0.3.0
|
||||
* added terabyte support
|
||||
|
||||
1.0.0 / 2014-02-08
|
||||
==================
|
||||
|
||||
* Initial release
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2014 Jonathan Ong <me@jongleberry.com>
|
||||
Copyright (c) 2014 Douglas Christopher Wilson <doug@somethingdoug.com>
|
||||
|
||||
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.
|
||||
+200
@@ -0,0 +1,200 @@
|
||||
# morgan
|
||||
|
||||
[![NPM Version][npm-image]][npm-url]
|
||||
[![NPM Downloads][downloads-image]][downloads-url]
|
||||
[![Build Status][travis-image]][travis-url]
|
||||
[![Test Coverage][coveralls-image]][coveralls-url]
|
||||
[![Gratipay][gratipay-image]][gratipay-url]
|
||||
|
||||
HTTP request logger middleware for node.js
|
||||
|
||||
> Named after [Dexter](http://en.wikipedia.org/wiki/Dexter_Morgan), a show you should not watch until completion.
|
||||
|
||||
## API
|
||||
|
||||
```js
|
||||
var morgan = require('morgan')
|
||||
```
|
||||
|
||||
### morgan(format, options)
|
||||
|
||||
Create a new morgan logger middleware function using the given `format` and `options`.
|
||||
The `format` argument may be a string of a predefined name (see below for the names),
|
||||
a string of a format string, or a function that will produce a log entry.
|
||||
|
||||
#### Options
|
||||
|
||||
Morgan accepts these properties in the options object.
|
||||
|
||||
#### buffer
|
||||
|
||||
Buffer duration before writing logs to the `stream`, defaults to `false`. When
|
||||
set to `true`, defaults to `1000 ms`.
|
||||
|
||||
#### immediate
|
||||
|
||||
Write log line on request instead of response. This means that a requests will
|
||||
be logged even if the server crashes, _but data from the response (like the
|
||||
response code, content length, etc.) cannot be logged_.
|
||||
|
||||
##### skip
|
||||
|
||||
Function to determine if logging is skipped, defaults to `false`. This function
|
||||
will be called as `skip(req, res)`.
|
||||
|
||||
```js
|
||||
// EXAMPLE: only log error responses
|
||||
morgan('combined', {
|
||||
skip: function (req, res) { return res.statusCode < 400 }
|
||||
})
|
||||
```
|
||||
|
||||
##### stream
|
||||
|
||||
Output stream for writing log lines, defaults to `process.stdout`.
|
||||
|
||||
#### Predefined Formats
|
||||
|
||||
There are various pre-defined formats provided:
|
||||
|
||||
##### combined
|
||||
|
||||
Standard Apache combined log output.
|
||||
|
||||
```
|
||||
:remote-addr - :remote-user [:date] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"
|
||||
```
|
||||
|
||||
##### common
|
||||
|
||||
Standard Apache common log output.
|
||||
|
||||
```
|
||||
:remote-addr - :remote-user [:date] ":method :url HTTP/:http-version" :status :res[content-length]
|
||||
```
|
||||
|
||||
##### dev
|
||||
|
||||
Concise output colored by response status for development use. The `:status`
|
||||
token will be colored red for server error codes, yellow for client error
|
||||
codes, cyan for redirection codes, and uncolored for all other codes.
|
||||
|
||||
```
|
||||
:method :url :status :response-time ms - :res[content-length]
|
||||
```
|
||||
|
||||
##### short
|
||||
|
||||
Shorter than default, also including response time.
|
||||
|
||||
```
|
||||
:remote-addr :remote-user :method :url HTTP/:http-version :status :res[content-length] - :response-time ms
|
||||
```
|
||||
|
||||
##### tiny
|
||||
|
||||
The minimal output.
|
||||
|
||||
```
|
||||
:method :url :status :res[content-length] - :response-time ms
|
||||
```
|
||||
|
||||
#### Tokens
|
||||
|
||||
- `:req[header]` ex: `:req[Accept]`
|
||||
- `:res[header]` ex: `:res[Content-Length]`
|
||||
- `:http-version`
|
||||
- `:response-time`
|
||||
- `:remote-addr`
|
||||
- `:remote-user`
|
||||
- `:date`
|
||||
- `:method`
|
||||
- `:url`
|
||||
- `:referrer`
|
||||
- `:user-agent`
|
||||
- `:status`
|
||||
|
||||
To define a token, simply invoke `morgan.token()` with the name and a callback function. The value returned is then available as ":type" in this case:
|
||||
```js
|
||||
morgan.token('type', function(req, res){ return req.headers['content-type']; })
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### express/connect
|
||||
|
||||
Simple app that will log all request in the Apache combined format to STDOUT
|
||||
|
||||
```js
|
||||
var express = require('express')
|
||||
var morgan = require('morgan')
|
||||
|
||||
var app = express()
|
||||
|
||||
app.use(morgan('combined'))
|
||||
|
||||
app.get('/', function (req, res) {
|
||||
res.send('hello, world!')
|
||||
})
|
||||
```
|
||||
|
||||
### vanilla http server
|
||||
|
||||
Simple app that will log all request in the Apache combined format to STDOUT
|
||||
|
||||
```js
|
||||
var finalhandler = require('finalhandler')
|
||||
var http = require('http')
|
||||
var morgan = require('morgan')
|
||||
|
||||
// create "middleware"
|
||||
var logger = morgan('combined')
|
||||
|
||||
http.createServer(function (req, res) {
|
||||
var done = finalhandler(req, res)
|
||||
logger(req, res, function (err) {
|
||||
if (err) return done(err)
|
||||
|
||||
// respond to request
|
||||
res.setHeader('content-type', 'text/plain')
|
||||
res.end('hello, world!')
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
### write logs to a file
|
||||
|
||||
Simple app that will log all request in the Apache combined format to the file "access.log"
|
||||
|
||||
```js
|
||||
var express = require('express')
|
||||
var fs = require('fs')
|
||||
var morgan = require('morgan')
|
||||
|
||||
var app = express()
|
||||
|
||||
// create a write stream (in append mode)
|
||||
var accessLogStream = fs.createWriteStream(__dirname + '/access.log', {flags: 'a'})
|
||||
|
||||
// setup the logger
|
||||
app.use(morgan('combined', {stream: accessLogStream}))
|
||||
|
||||
app.get('/', function (req, res) {
|
||||
res.send('hello, world!')
|
||||
})
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
[MIT](LICENSE)
|
||||
|
||||
[npm-image]: https://img.shields.io/npm/v/morgan.svg?style=flat
|
||||
[npm-url]: https://npmjs.org/package/morgan
|
||||
[travis-image]: https://img.shields.io/travis/expressjs/morgan.svg?style=flat
|
||||
[travis-url]: https://travis-ci.org/expressjs/morgan
|
||||
[coveralls-image]: https://img.shields.io/coveralls/expressjs/morgan.svg?style=flat
|
||||
[coveralls-url]: https://coveralls.io/r/expressjs/morgan?branch=master
|
||||
[downloads-image]: http://img.shields.io/npm/dm/morgan.svg?style=flat
|
||||
[downloads-url]: https://npmjs.org/package/morgan
|
||||
[gratipay-image]: https://img.shields.io/gratipay/dougwilson.svg?style=flat
|
||||
[gratipay-url]: https://www.gratipay.com/dougwilson/
|
||||
+326
@@ -0,0 +1,326 @@
|
||||
/*!
|
||||
* morgan
|
||||
* Copyright(c) 2010 Sencha Inc.
|
||||
* Copyright(c) 2011 TJ Holowaychuk
|
||||
* Copyright(c) 2014 Jonathan Ong
|
||||
* Copyright(c) 2014 Douglas Christopher Wilson
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var auth = require('basic-auth')
|
||||
var deprecate = require('depd')('morgan')
|
||||
var onFinished = require('on-finished')
|
||||
|
||||
/**
|
||||
* Default log buffer duration.
|
||||
*/
|
||||
|
||||
var defaultBufferDuration = 1000;
|
||||
|
||||
/**
|
||||
* Create a logger middleware.
|
||||
*
|
||||
* @param {String|Function} format
|
||||
* @param {Object} [options]
|
||||
* @return {Function} middleware
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports = module.exports = function morgan(format, options) {
|
||||
if (typeof format === 'object') {
|
||||
options = format
|
||||
format = options.format || 'default'
|
||||
|
||||
// smart deprecation message
|
||||
deprecate('morgan(options): use morgan(' + (typeof format === 'string' ? JSON.stringify(format) : 'format') + ', options) instead')
|
||||
}
|
||||
|
||||
if (format === undefined) {
|
||||
deprecate('undefined format: specify a format')
|
||||
}
|
||||
|
||||
options = options || {}
|
||||
|
||||
// output on request instead of response
|
||||
var immediate = options.immediate;
|
||||
|
||||
// check if log entry should be skipped
|
||||
var skip = options.skip || function () { return false; };
|
||||
|
||||
// format function
|
||||
var fmt = compile(exports[format] || format || exports.default)
|
||||
|
||||
// options
|
||||
var stream = options.stream || process.stdout
|
||||
, buffer = options.buffer;
|
||||
|
||||
// buffering support
|
||||
if (buffer) {
|
||||
var realStream = stream
|
||||
var buf = []
|
||||
var timer = null
|
||||
var interval = 'number' == typeof buffer
|
||||
? buffer
|
||||
: defaultBufferDuration
|
||||
|
||||
// flush function
|
||||
var flush = function(){
|
||||
timer = null
|
||||
|
||||
if (buf.length) {
|
||||
realStream.write(buf.join(''));
|
||||
buf.length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// swap the stream
|
||||
stream = {
|
||||
write: function(str){
|
||||
if (timer === null) {
|
||||
timer = setTimeout(flush, interval)
|
||||
}
|
||||
|
||||
buf.push(str);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return function logger(req, res, next) {
|
||||
req._startAt = process.hrtime();
|
||||
req._startTime = new Date;
|
||||
req._remoteAddress = getip(req);
|
||||
|
||||
function logRequest(){
|
||||
if (skip(req, res)) return;
|
||||
var line = fmt(exports, req, res);
|
||||
if (null == line) return;
|
||||
stream.write(line + '\n');
|
||||
};
|
||||
|
||||
// immediate
|
||||
if (immediate) {
|
||||
logRequest();
|
||||
} else {
|
||||
onFinished(res, logRequest)
|
||||
}
|
||||
|
||||
next();
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Compile `format` into a function.
|
||||
*
|
||||
* @param {Function|String} format
|
||||
* @return {Function}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function compile(format) {
|
||||
if (typeof format === 'function') {
|
||||
// already compiled
|
||||
return format
|
||||
}
|
||||
|
||||
if (typeof format !== 'string') {
|
||||
throw new TypeError('argument format must be a function or string')
|
||||
}
|
||||
|
||||
var fmt = format.replace(/"/g, '\\"')
|
||||
var js = ' return "' + fmt.replace(/:([-\w]{2,})(?:\[([^\]]+)\])?/g, function(_, name, arg){
|
||||
return '"\n + (tokens["' + name + '"](req, res, "' + arg + '") || "-") + "';
|
||||
}) + '";'
|
||||
|
||||
return new Function('tokens, req, res', js);
|
||||
};
|
||||
|
||||
/**
|
||||
* Define a token function with the given `name`,
|
||||
* and callback `fn(req, res)`.
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {Function} fn
|
||||
* @return {Object} exports for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.token = function(name, fn) {
|
||||
exports[name] = fn;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Define a `fmt` with the given `name`.
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {String|Function} fmt
|
||||
* @return {Object} exports for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.format = function(name, fmt){
|
||||
exports[name] = fmt;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Apache combined log format.
|
||||
*/
|
||||
|
||||
exports.format('combined', ':remote-addr - :remote-user [:date] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"')
|
||||
|
||||
/**
|
||||
* Apache common log format.
|
||||
*/
|
||||
|
||||
exports.format('common', ':remote-addr - :remote-user [:date] ":method :url HTTP/:http-version" :status :res[content-length]')
|
||||
|
||||
/**
|
||||
* Default format.
|
||||
*/
|
||||
|
||||
exports.format('default', ':remote-addr - :remote-user [:date] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"');
|
||||
deprecate.property(exports, 'default', 'default format: use combined format')
|
||||
|
||||
/**
|
||||
* Short format.
|
||||
*/
|
||||
|
||||
exports.format('short', ':remote-addr :remote-user :method :url HTTP/:http-version :status :res[content-length] - :response-time ms');
|
||||
|
||||
/**
|
||||
* Tiny format.
|
||||
*/
|
||||
|
||||
exports.format('tiny', ':method :url :status :res[content-length] - :response-time ms');
|
||||
|
||||
/**
|
||||
* dev (colored)
|
||||
*/
|
||||
|
||||
exports.format('dev', function(tokens, req, res){
|
||||
var color = 32; // green
|
||||
var status = res.statusCode;
|
||||
|
||||
if (status >= 500) color = 31; // red
|
||||
else if (status >= 400) color = 33; // yellow
|
||||
else if (status >= 300) color = 36; // cyan
|
||||
|
||||
var fn = compile('\x1b[0m:method :url \x1b[' + color + 'm:status \x1b[0m:response-time ms - :res[content-length]\x1b[0m');
|
||||
|
||||
return fn(tokens, req, res);
|
||||
});
|
||||
|
||||
/**
|
||||
* request url
|
||||
*/
|
||||
|
||||
exports.token('url', function(req){
|
||||
return req.originalUrl || req.url;
|
||||
});
|
||||
|
||||
/**
|
||||
* request method
|
||||
*/
|
||||
|
||||
exports.token('method', function(req){
|
||||
return req.method;
|
||||
});
|
||||
|
||||
/**
|
||||
* response time in milliseconds
|
||||
*/
|
||||
|
||||
exports.token('response-time', function(req, res){
|
||||
if (!res._header || !req._startAt) return '';
|
||||
var diff = process.hrtime(req._startAt);
|
||||
var ms = diff[0] * 1e3 + diff[1] * 1e-6;
|
||||
return ms.toFixed(3);
|
||||
});
|
||||
|
||||
/**
|
||||
* UTC date
|
||||
*/
|
||||
|
||||
exports.token('date', function(){
|
||||
return new Date().toUTCString();
|
||||
});
|
||||
|
||||
/**
|
||||
* response status code
|
||||
*/
|
||||
|
||||
exports.token('status', function(req, res){
|
||||
return res._header ? res.statusCode : null;
|
||||
});
|
||||
|
||||
/**
|
||||
* normalized referrer
|
||||
*/
|
||||
|
||||
exports.token('referrer', function(req){
|
||||
return req.headers['referer'] || req.headers['referrer'];
|
||||
});
|
||||
|
||||
/**
|
||||
* remote address
|
||||
*/
|
||||
|
||||
exports.token('remote-addr', getip);
|
||||
|
||||
/**
|
||||
* remote user
|
||||
*/
|
||||
|
||||
exports.token('remote-user', function (req) {
|
||||
var creds = auth(req)
|
||||
var user = (creds && creds.name) || '-'
|
||||
return user;
|
||||
})
|
||||
|
||||
/**
|
||||
* HTTP version
|
||||
*/
|
||||
|
||||
exports.token('http-version', function(req){
|
||||
return req.httpVersionMajor + '.' + req.httpVersionMinor;
|
||||
});
|
||||
|
||||
/**
|
||||
* UA string
|
||||
*/
|
||||
|
||||
exports.token('user-agent', function(req){
|
||||
return req.headers['user-agent'];
|
||||
});
|
||||
|
||||
/**
|
||||
* request header
|
||||
*/
|
||||
|
||||
exports.token('req', function(req, res, field){
|
||||
return req.headers[field.toLowerCase()];
|
||||
});
|
||||
|
||||
/**
|
||||
* response header
|
||||
*/
|
||||
|
||||
exports.token('res', function(req, res, field){
|
||||
return (res._headers || {})[field.toLowerCase()];
|
||||
});
|
||||
|
||||
/**
|
||||
* Get request IP address.
|
||||
*/
|
||||
|
||||
function getip(req) {
|
||||
return req.ip
|
||||
|| req._remoteAddress
|
||||
|| (req.connection && req.connection.remoteAddress)
|
||||
|| undefined;
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
# basic-auth
|
||||
|
||||
Generic basic auth Authorization header field parser for whatever.
|
||||
|
||||
## Installation
|
||||
|
||||
```
|
||||
$ npm install basic-auth
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
Pass a node request or koa Context object to the module exported. If
|
||||
parsing fails `undefined` is returned, otherwise an object with
|
||||
`.name` and `.pass`.
|
||||
|
||||
```js
|
||||
var auth = require('basic-auth');
|
||||
var user = auth(req);
|
||||
// => { name: 'something', pass: 'whatever' }
|
||||
|
||||
```
|
||||
|
||||
# License
|
||||
|
||||
MIT
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
|
||||
/**
|
||||
* Parse the Authorization header field of `req`.
|
||||
*
|
||||
* @param {Request} req
|
||||
* @return {Object} with .name and .pass
|
||||
* @api public
|
||||
*/
|
||||
|
||||
module.exports = function(req){
|
||||
req = req.req || req;
|
||||
|
||||
var auth = req.headers.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();
|
||||
auth = auth.match(/^([^:]*):(.*)$/);
|
||||
if (!auth) return;
|
||||
|
||||
return { name: auth[1], pass: auth[2] };
|
||||
};
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"name": "basic-auth",
|
||||
"version": "1.0.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/visionmedia/node-basic-auth"
|
||||
},
|
||||
"description": "generic basic auth parser",
|
||||
"keywords": [
|
||||
"basic",
|
||||
"auth",
|
||||
"authorization",
|
||||
"basicauth"
|
||||
],
|
||||
"devDependencies": {
|
||||
"mocha": "*",
|
||||
"should": "*"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "make test"
|
||||
},
|
||||
"files": [
|
||||
"index.js"
|
||||
],
|
||||
"license": "MIT",
|
||||
"readme": "# basic-auth\n\n Generic basic auth Authorization header field parser for whatever.\n\n## Installation\n\n```\n$ npm install basic-auth\n```\n\n## Example\n\n Pass a node request or koa Context object to the module exported. If\n parsing fails `undefined` is returned, otherwise an object with\n `.name` and `.pass`.\n\n```js\nvar auth = require('basic-auth');\nvar user = auth(req);\n// => { name: 'something', pass: 'whatever' }\n\n```\n\n# License\n\n MIT\n",
|
||||
"readmeFilename": "Readme.md",
|
||||
"bugs": {
|
||||
"url": "https://github.com/visionmedia/node-basic-auth/issues"
|
||||
},
|
||||
"_id": "basic-auth@1.0.0",
|
||||
"_from": "basic-auth@1.0.0"
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
0.4.5 / 2014-09-09
|
||||
==================
|
||||
|
||||
* Improve call speed to functions using the function wrapper
|
||||
* Support Node.js 0.6
|
||||
|
||||
0.4.4 / 2014-07-27
|
||||
==================
|
||||
|
||||
* Work-around v8 generating empty stack traces
|
||||
|
||||
0.4.3 / 2014-07-26
|
||||
==================
|
||||
|
||||
* Fix exception when global `Error.stackTraceLimit` is too low
|
||||
|
||||
0.4.2 / 2014-07-19
|
||||
==================
|
||||
|
||||
* Correct call site for wrapped functions and properties
|
||||
|
||||
0.4.1 / 2014-07-19
|
||||
==================
|
||||
|
||||
* Improve automatic message generation for function properties
|
||||
|
||||
0.4.0 / 2014-07-19
|
||||
==================
|
||||
|
||||
* Add `TRACE_DEPRECATION` environment variable
|
||||
* Remove non-standard grey color from color output
|
||||
* Support `--no-deprecation` argument
|
||||
* Support `--trace-deprecation` argument
|
||||
* Support `deprecate.property(fn, prop, message)`
|
||||
|
||||
0.3.0 / 2014-06-16
|
||||
==================
|
||||
|
||||
* Add `NO_DEPRECATION` environment variable
|
||||
|
||||
0.2.0 / 2014-06-15
|
||||
==================
|
||||
|
||||
* Add `deprecate.property(obj, prop, message)`
|
||||
* Remove `supports-color` dependency for node.js 0.8
|
||||
|
||||
0.1.0 / 2014-06-15
|
||||
==================
|
||||
|
||||
* Add `deprecate.function(fn, message)`
|
||||
* Add `process.on('deprecation', fn)` emitter
|
||||
* Automatically generate message when omitted from `deprecate()`
|
||||
|
||||
0.0.1 / 2014-06-15
|
||||
==================
|
||||
|
||||
* Fix warning for dynamic calls at singe call site
|
||||
|
||||
0.0.0 / 2014-06-15
|
||||
==================
|
||||
|
||||
* Initial implementation
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2014 Douglas Christopher Wilson
|
||||
|
||||
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.
|
||||
+266
@@ -0,0 +1,266 @@
|
||||
# depd
|
||||
|
||||
[![NPM Version][npm-version-image]][npm-url]
|
||||
[![NPM Downloads][npm-downloads-image]][npm-url]
|
||||
[![Node.js Version][node-image]][node-url]
|
||||
[![Build Status][travis-image]][travis-url]
|
||||
[![Coverage Status][coveralls-image]][coveralls-url]
|
||||
[![Gittip][gittip-image]][gittip-url]
|
||||
|
||||
Deprecate all the things
|
||||
|
||||
> With great modules comes great responsibility; mark things deprecated!
|
||||
|
||||
## Install
|
||||
|
||||
```sh
|
||||
$ npm install depd
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
```js
|
||||
var deprecate = require('depd')('my-module')
|
||||
```
|
||||
|
||||
This library allows you to display deprecation messages to your users.
|
||||
This library goes above and beyond with deprecation warnings by
|
||||
introspecting the call stack (but only the bits that it is interested
|
||||
in).
|
||||
|
||||
Instead of just warning on the first invocation of a deprecated
|
||||
function and never again, this module will warn on the first invocation
|
||||
of a deprecated function per unique call site, making it ideal to alert
|
||||
users of all deprecated uses across the code base, rather than just
|
||||
whatever happens to execute first.
|
||||
|
||||
The deprecation warnings from this module also include the file and line
|
||||
information for the call into the module that the deprecated function was
|
||||
in.
|
||||
|
||||
### depd(namespace)
|
||||
|
||||
Create a new deprecate function that uses the given namespace name in the
|
||||
messages and will display the call site prior to the stack entering the
|
||||
file this function was called from. It is highly suggested you use the
|
||||
name of your module as the namespace.
|
||||
|
||||
### deprecate(message)
|
||||
|
||||
Call this function from deprecated code to display a deprecation message.
|
||||
This message will appear once per unique caller site. Caller site is the
|
||||
first call site in the stack in a different file from the caller of this
|
||||
function.
|
||||
|
||||
If the message is omitted, a message is generated for you based on the site
|
||||
of the `deprecate()` call and will display the name of the function called,
|
||||
similar to the name displayed in a stack trace.
|
||||
|
||||
### deprecate.function(fn, message)
|
||||
|
||||
Call this function to wrap a given function in a deprecation message on any
|
||||
call to the function. An optional message can be supplied to provide a custom
|
||||
message.
|
||||
|
||||
### deprecate.property(obj, prop, message)
|
||||
|
||||
Call this function to wrap a given property on object in a deprecation message
|
||||
on any accessing or setting of the property. An optional message can be supplied
|
||||
to provide a custom message.
|
||||
|
||||
The method must be called on the object where the property belongs (not
|
||||
inherited from the prototype).
|
||||
|
||||
If the property is a data descriptor, it will be converted to an accessor
|
||||
descriptor in order to display the deprecation message.
|
||||
|
||||
### process.on('deprecation', fn)
|
||||
|
||||
This module will allow easy capturing of deprecation errors by emitting the
|
||||
errors as the type "deprecation" on the global `process`. If there are no
|
||||
listeners for this type, the errors are written to STDERR as normal, but if
|
||||
there are any listeners, nothing will be written to STDERR and instead only
|
||||
emitted. From there, you can write the errors in a different format or to a
|
||||
logging source.
|
||||
|
||||
The error represents the deprecation and is emitted only once with the same
|
||||
rules as writing to STDERR. The error has the following properties:
|
||||
|
||||
- `message` - This is the message given by the library
|
||||
- `name` - This is always `'DeprecationError'`
|
||||
- `namespace` - This is the namespace the deprecation came from
|
||||
- `stack` - This is the stack of the call to the deprecated thing
|
||||
|
||||
Example `error.stack` output:
|
||||
|
||||
```
|
||||
DeprecationError: my-cool-module deprecated oldfunction
|
||||
at Object.<anonymous> ([eval]-wrapper:6:22)
|
||||
at Module._compile (module.js:456:26)
|
||||
at evalScript (node.js:532:25)
|
||||
at startup (node.js:80:7)
|
||||
at node.js:902:3
|
||||
```
|
||||
|
||||
### process.env.NO_DEPRECATION
|
||||
|
||||
As a user of modules that are deprecated, the environment variable `NO_DEPRECATION`
|
||||
is provided as a quick solution to silencing deprecation warnings from being
|
||||
output. The format of this is similar to that of `DEBUG`:
|
||||
|
||||
```sh
|
||||
$ NO_DEPRECATION=my-module,othermod node app.js
|
||||
```
|
||||
|
||||
This will suppress deprecations from being output for "my-module" and "othermod".
|
||||
The value is a list of comma-separated namespaces. To suppress every warning
|
||||
across all namespaces, use the value `*` for a namespace.
|
||||
|
||||
Providing the argument `--no-deprecation` to the `node` executable will suppress
|
||||
all deprecations (only available in Node.js 0.8 or higher).
|
||||
|
||||
**NOTE** This will not suppress the deperecations given to any "deprecation"
|
||||
event listeners, just the output to STDERR.
|
||||
|
||||
### process.env.TRACE_DEPRECATION
|
||||
|
||||
As a user of modules that are deprecated, the environment variable `TRACE_DEPRECATION`
|
||||
is provided as a solution to getting more detailed location information in deprecation
|
||||
warnings by including the entire stack trace. The format of this is the same as
|
||||
`NO_DEPRECATION`:
|
||||
|
||||
```sh
|
||||
$ TRACE_DEPRECATION=my-module,othermod node app.js
|
||||
```
|
||||
|
||||
This will include stack traces for deprecations being output for "my-module" and
|
||||
"othermod". The value is a list of comma-separated namespaces. To trace every
|
||||
warning across all namespaces, use the value `*` for a namespace.
|
||||
|
||||
Providing the argument `--trace-deprecation` to the `node` executable will trace
|
||||
all deprecations (only available in Node.js 0.8 or higher).
|
||||
|
||||
**NOTE** This will not trace the deperecations silenced by `NO_DEPRECATION`.
|
||||
|
||||
## Display
|
||||
|
||||

|
||||
|
||||
When a user calls a function in your library that you mark deprecated, they
|
||||
will see the following written to STDERR (in the given colors, similar colors
|
||||
and layout to the `debug` module):
|
||||
|
||||
```
|
||||
bright cyan bright yellow
|
||||
| | reset cyan
|
||||
| | | |
|
||||
▼ ▼ ▼ ▼
|
||||
my-cool-module deprecated oldfunction [eval]-wrapper:6:22
|
||||
▲ ▲ ▲ ▲
|
||||
| | | |
|
||||
namespace | | location of mycoolmod.oldfunction() call
|
||||
| deprecation message
|
||||
the word "deprecated"
|
||||
```
|
||||
|
||||
If the user redirects their STDERR to a file or somewhere that does not support
|
||||
colors, they see (similar layout to the `debug` module):
|
||||
|
||||
```
|
||||
Sun, 15 Jun 2014 05:21:37 GMT my-cool-module deprecated oldfunction at [eval]-wrapper:6:22
|
||||
▲ ▲ ▲ ▲ ▲
|
||||
| | | | |
|
||||
timestamp of message namespace | | location of mycoolmod.oldfunction() call
|
||||
| deprecation message
|
||||
the word "deprecated"
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Deprecating all calls to a function
|
||||
|
||||
This will display a deprecated message about "oldfunction" being deprecated
|
||||
from "my-module" on STDERR.
|
||||
|
||||
```js
|
||||
var deprecate = require('depd')('my-cool-module')
|
||||
|
||||
// message automatically derived from function name
|
||||
// Object.oldfunction
|
||||
exports.oldfunction = deprecate.function(function oldfunction() {
|
||||
// all calls to function are deprecated
|
||||
})
|
||||
|
||||
// specific message
|
||||
exports.oldfunction = deprecate.function(function () {
|
||||
// all calls to function are deprecated
|
||||
}, 'oldfunction')
|
||||
```
|
||||
|
||||
### Conditionally deprecating a function call
|
||||
|
||||
This will display a deprecated message about "weirdfunction" being deprecated
|
||||
from "my-module" on STDERR when called with less than 2 arguments.
|
||||
|
||||
```js
|
||||
var deprecate = require('depd')('my-cool-module')
|
||||
|
||||
exports.weirdfunction = function () {
|
||||
if (arguments.length < 2) {
|
||||
// calls with 0 or 1 args are deprecated
|
||||
deprecate('weirdfunction args < 2')
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
When calling `deprecate` as a function, the warning is counted per call site
|
||||
within your own module, so you can display different deprecations depending
|
||||
on different situations and the users will still get all the warnings:
|
||||
|
||||
```js
|
||||
var deprecate = require('depd')('my-cool-module')
|
||||
|
||||
exports.weirdfunction = function () {
|
||||
if (arguments.length < 2) {
|
||||
// calls with 0 or 1 args are deprecated
|
||||
deprecate('weirdfunction args < 2')
|
||||
} else if (typeof arguments[0] !== 'string') {
|
||||
// calls with non-string first argument are deprecated
|
||||
deprecate('weirdfunction non-string first arg')
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Deprecating property access
|
||||
|
||||
This will display a deprecated message about "oldprop" being deprecated
|
||||
from "my-module" on STDERR when accessed. A deprecation will be displayed
|
||||
when setting the value and when getting the value.
|
||||
|
||||
```js
|
||||
var deprecate = require('depd')('my-cool-module')
|
||||
|
||||
exports.oldprop = 'something'
|
||||
|
||||
// message automatically derives from property name
|
||||
deprecate.property(exports, 'oldprop')
|
||||
|
||||
// explicit message
|
||||
deprecate.property(exports, 'oldprop', 'oldprop >= 0.10')
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
[MIT](LICENSE)
|
||||
|
||||
[npm-version-image]: https://img.shields.io/npm/v/depd.svg?style=flat
|
||||
[npm-downloads-image]: https://img.shields.io/npm/dm/depd.svg?style=flat
|
||||
[npm-url]: https://npmjs.org/package/depd
|
||||
[travis-image]: https://img.shields.io/travis/dougwilson/nodejs-depd.svg?style=flat
|
||||
[travis-url]: https://travis-ci.org/dougwilson/nodejs-depd
|
||||
[coveralls-image]: https://img.shields.io/coveralls/dougwilson/nodejs-depd.svg?style=flat
|
||||
[coveralls-url]: https://coveralls.io/r/dougwilson/nodejs-depd?branch=master
|
||||
[node-image]: https://img.shields.io/node/v/depd.svg?style=flat
|
||||
[node-url]: http://nodejs.org/download/
|
||||
[gittip-image]: https://img.shields.io/gittip/dougwilson.svg?style=flat
|
||||
[gittip-url]: https://www.gittip.com/dougwilson/
|
||||
+522
@@ -0,0 +1,522 @@
|
||||
/*!
|
||||
* depd
|
||||
* Copyright(c) 2014 Douglas Christopher Wilson
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var callSiteToString = require('./lib/compat').callSiteToString
|
||||
var EventEmitter = require('events').EventEmitter
|
||||
var relative = require('path').relative
|
||||
|
||||
/**
|
||||
* Module exports.
|
||||
*/
|
||||
|
||||
module.exports = depd
|
||||
|
||||
/**
|
||||
* Get the path to base files on.
|
||||
*/
|
||||
|
||||
var basePath = process.cwd()
|
||||
|
||||
/**
|
||||
* Get listener count on event emitter.
|
||||
*/
|
||||
|
||||
/*istanbul ignore next*/
|
||||
var eventListenerCount = EventEmitter.listenerCount
|
||||
|| function (emitter, type) { return emitter.listeners(type).length }
|
||||
|
||||
/**
|
||||
* Determine if namespace is contained in the string.
|
||||
*/
|
||||
|
||||
function containsNamespace(str, namespace) {
|
||||
var val = str.split(/[ ,]+/)
|
||||
|
||||
namespace = String(namespace).toLowerCase()
|
||||
|
||||
for (var i = 0 ; i < val.length; i++) {
|
||||
if (!(str = val[i])) continue;
|
||||
|
||||
// namespace contained
|
||||
if (str === '*' || str.toLowerCase() === namespace) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a data descriptor to accessor descriptor.
|
||||
*/
|
||||
|
||||
function convertDataDescriptorToAccessor(obj, prop, message) {
|
||||
var descriptor = Object.getOwnPropertyDescriptor(obj, prop)
|
||||
var value = descriptor.value
|
||||
|
||||
descriptor.get = function getter() { return value }
|
||||
|
||||
if (descriptor.writable) {
|
||||
descriptor.set = function setter(val) { return value = val }
|
||||
}
|
||||
|
||||
delete descriptor.value
|
||||
delete descriptor.writable
|
||||
|
||||
Object.defineProperty(obj, prop, descriptor)
|
||||
|
||||
return descriptor
|
||||
}
|
||||
|
||||
/**
|
||||
* Create arguments string to keep arity.
|
||||
*/
|
||||
|
||||
function createArgumentsString(arity) {
|
||||
var str = ''
|
||||
|
||||
for (var i = 0; i < arity; i++) {
|
||||
str += ', arg' + i
|
||||
}
|
||||
|
||||
return str.substr(2)
|
||||
}
|
||||
|
||||
/**
|
||||
* Create stack string from stack.
|
||||
*/
|
||||
|
||||
function createStackString(stack) {
|
||||
var str = this.name + ': ' + this.namespace
|
||||
|
||||
if (this.message) {
|
||||
str += ' deprecated ' + this.message
|
||||
}
|
||||
|
||||
for (var i = 0; i < stack.length; i++) {
|
||||
str += '\n at ' + callSiteToString(stack[i])
|
||||
}
|
||||
|
||||
return str
|
||||
}
|
||||
|
||||
/**
|
||||
* Create deprecate for namespace in caller.
|
||||
*/
|
||||
|
||||
function depd(namespace) {
|
||||
if (!namespace) {
|
||||
throw new TypeError('argument namespace is required')
|
||||
}
|
||||
|
||||
var stack = getStack()
|
||||
var site = callSiteLocation(stack[1])
|
||||
var file = site[0]
|
||||
|
||||
function deprecate(message) {
|
||||
// call to self as log
|
||||
log.call(deprecate, message)
|
||||
}
|
||||
|
||||
deprecate._file = file
|
||||
deprecate._ignored = isignored(namespace)
|
||||
deprecate._namespace = namespace
|
||||
deprecate._traced = istraced(namespace)
|
||||
deprecate._warned = Object.create(null)
|
||||
|
||||
deprecate.function = wrapfunction
|
||||
deprecate.property = wrapproperty
|
||||
|
||||
return deprecate
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if namespace is ignored.
|
||||
*/
|
||||
|
||||
function isignored(namespace) {
|
||||
/* istanbul ignore next: tested in a child processs */
|
||||
if (process.noDeprecation) {
|
||||
// --no-deprecation support
|
||||
return true
|
||||
}
|
||||
|
||||
var str = process.env.NO_DEPRECATION || ''
|
||||
|
||||
// namespace ignored
|
||||
return containsNamespace(str, namespace)
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if namespace is traced.
|
||||
*/
|
||||
|
||||
function istraced(namespace) {
|
||||
/* istanbul ignore next: tested in a child processs */
|
||||
if (process.traceDeprecation) {
|
||||
// --trace-deprecation support
|
||||
return true
|
||||
}
|
||||
|
||||
var str = process.env.TRACE_DEPRECATION || ''
|
||||
|
||||
// namespace traced
|
||||
return containsNamespace(str, namespace)
|
||||
}
|
||||
|
||||
/**
|
||||
* Display deprecation message.
|
||||
*/
|
||||
|
||||
function log(message, site) {
|
||||
var haslisteners = eventListenerCount(process, 'deprecation') !== 0
|
||||
|
||||
// abort early if no destination
|
||||
if (!haslisteners && this._ignored) {
|
||||
return
|
||||
}
|
||||
|
||||
var caller
|
||||
var callFile
|
||||
var callSite
|
||||
var i = 0
|
||||
var seen = false
|
||||
var stack = getStack()
|
||||
var file = this._file
|
||||
|
||||
if (site) {
|
||||
// provided site
|
||||
callSite = callSiteLocation(stack[1])
|
||||
callSite.name = site.name
|
||||
file = callSite[0]
|
||||
} else {
|
||||
// get call site
|
||||
i = 2
|
||||
site = callSiteLocation(stack[i])
|
||||
callSite = site
|
||||
}
|
||||
|
||||
// get caller of deprecated thing in relation to file
|
||||
for (; i < stack.length; i++) {
|
||||
caller = callSiteLocation(stack[i])
|
||||
callFile = caller[0]
|
||||
|
||||
if (callFile === file) {
|
||||
seen = true
|
||||
} else if (callFile === this._file) {
|
||||
file = this._file
|
||||
} else if (seen) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
var key = caller
|
||||
? site.join(':') + '__' + caller.join(':')
|
||||
: undefined
|
||||
|
||||
if (key !== undefined && key in this._warned) {
|
||||
// already warned
|
||||
return
|
||||
}
|
||||
|
||||
this._warned[key] = true
|
||||
|
||||
// generate automatic message from call site
|
||||
if (!message) {
|
||||
message = callSite === site || !callSite.name
|
||||
? defaultMessage(site)
|
||||
: defaultMessage(callSite)
|
||||
}
|
||||
|
||||
// emit deprecation if listeners exist
|
||||
if (haslisteners) {
|
||||
var err = DeprecationError(this._namespace, message, stack.slice(i))
|
||||
process.emit('deprecation', err)
|
||||
return
|
||||
}
|
||||
|
||||
// format and write message
|
||||
var format = process.stderr.isTTY
|
||||
? formatColor
|
||||
: formatPlain
|
||||
var msg = format.call(this, message, caller, stack.slice(i))
|
||||
process.stderr.write(msg + '\n', 'utf8')
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
/**
|
||||
* Get call site location as array.
|
||||
*/
|
||||
|
||||
function callSiteLocation(callSite) {
|
||||
var file = callSite.getFileName() || '<anonymous>'
|
||||
var line = callSite.getLineNumber()
|
||||
var colm = callSite.getColumnNumber()
|
||||
|
||||
if (callSite.isEval()) {
|
||||
file = callSite.getEvalOrigin() + ', ' + file
|
||||
}
|
||||
|
||||
var site = [file, line, colm]
|
||||
|
||||
site.callSite = callSite
|
||||
site.name = callSite.getFunctionName()
|
||||
|
||||
return site
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a default message from the site.
|
||||
*/
|
||||
|
||||
function defaultMessage(site) {
|
||||
var callSite = site.callSite
|
||||
var funcName = site.name
|
||||
var typeName = callSite.getTypeName()
|
||||
|
||||
// make useful anonymous name
|
||||
if (!funcName) {
|
||||
funcName = '<anonymous@' + formatLocation(site) + '>'
|
||||
}
|
||||
|
||||
// make useful type name
|
||||
if (typeName === 'Function') {
|
||||
typeName = callSite.getThis().name || typeName
|
||||
}
|
||||
|
||||
return callSite.getMethodName()
|
||||
? typeName + '.' + funcName
|
||||
: funcName
|
||||
}
|
||||
|
||||
/**
|
||||
* Format deprecation message without color.
|
||||
*/
|
||||
|
||||
function formatPlain(msg, caller, stack) {
|
||||
var timestamp = new Date().toUTCString()
|
||||
|
||||
var formatted = timestamp
|
||||
+ ' ' + this._namespace
|
||||
+ ' deprecated ' + msg
|
||||
|
||||
// add stack trace
|
||||
if (this._traced) {
|
||||
for (var i = 0; i < stack.length; i++) {
|
||||
formatted += '\n at ' + callSiteToString(stack[i])
|
||||
}
|
||||
|
||||
return formatted
|
||||
}
|
||||
|
||||
if (caller) {
|
||||
formatted += ' at ' + formatLocation(caller)
|
||||
}
|
||||
|
||||
return formatted
|
||||
}
|
||||
|
||||
/**
|
||||
* Format deprecation message with color.
|
||||
*/
|
||||
|
||||
function formatColor(msg, caller, stack) {
|
||||
var formatted = '\x1b[36;1m' + this._namespace + '\x1b[22;39m' // bold cyan
|
||||
+ ' \x1b[33;1mdeprecated\x1b[22;39m' // bold yellow
|
||||
+ ' \x1b[0m' + msg + '\x1b[39m' // reset
|
||||
|
||||
// add stack trace
|
||||
if (this._traced) {
|
||||
for (var i = 0; i < stack.length; i++) {
|
||||
formatted += '\n \x1b[36mat ' + callSiteToString(stack[i]) + '\x1b[39m' // cyan
|
||||
}
|
||||
|
||||
return formatted
|
||||
}
|
||||
|
||||
if (caller) {
|
||||
formatted += ' \x1b[36m' + formatLocation(caller) + '\x1b[39m' // cyan
|
||||
}
|
||||
|
||||
return formatted
|
||||
}
|
||||
|
||||
/**
|
||||
* Format call site location.
|
||||
*/
|
||||
|
||||
function formatLocation(callSite) {
|
||||
return relative(basePath, callSite[0])
|
||||
+ ':' + callSite[1]
|
||||
+ ':' + callSite[2]
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the stack as array of call sites.
|
||||
*/
|
||||
|
||||
function getStack() {
|
||||
var limit = Error.stackTraceLimit
|
||||
var obj = {}
|
||||
var prep = Error.prepareStackTrace
|
||||
|
||||
Error.prepareStackTrace = prepareObjectStackTrace
|
||||
Error.stackTraceLimit = Math.max(10, limit)
|
||||
|
||||
// capture the stack
|
||||
Error.captureStackTrace(obj)
|
||||
|
||||
// slice this function off the top
|
||||
var stack = obj.stack.slice(1)
|
||||
|
||||
Error.prepareStackTrace = prep
|
||||
Error.stackTraceLimit = limit
|
||||
|
||||
return stack
|
||||
}
|
||||
|
||||
/**
|
||||
* Capture call site stack from v8.
|
||||
*/
|
||||
|
||||
function prepareObjectStackTrace(obj, stack) {
|
||||
return stack
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a wrapped function in a deprecation message.
|
||||
*/
|
||||
|
||||
function wrapfunction(fn, message) {
|
||||
if (typeof fn !== 'function') {
|
||||
throw new TypeError('argument fn must be a function')
|
||||
}
|
||||
|
||||
var args = createArgumentsString(fn.length)
|
||||
var deprecate = this
|
||||
var stack = getStack()
|
||||
var site = callSiteLocation(stack[1])
|
||||
|
||||
site.name = fn.name
|
||||
|
||||
var deprecatedfn = eval('(function (' + args + ') {\n'
|
||||
+ '"use strict"\n'
|
||||
+ 'log.call(deprecate, message, site)\n'
|
||||
+ 'return fn.apply(this, arguments)\n'
|
||||
+ '})')
|
||||
|
||||
return deprecatedfn
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap property in a deprecation message.
|
||||
*/
|
||||
|
||||
function wrapproperty(obj, prop, message) {
|
||||
if (!obj || (typeof obj !== 'object' && typeof obj !== 'function')) {
|
||||
throw new TypeError('argument obj must be object')
|
||||
}
|
||||
|
||||
var descriptor = Object.getOwnPropertyDescriptor(obj, prop)
|
||||
|
||||
if (!descriptor) {
|
||||
throw new TypeError('must call property on owner object')
|
||||
}
|
||||
|
||||
if (!descriptor.configurable) {
|
||||
throw new TypeError('property must be configurable')
|
||||
}
|
||||
|
||||
var deprecate = this
|
||||
var stack = getStack()
|
||||
var site = callSiteLocation(stack[1])
|
||||
|
||||
// set site name
|
||||
site.name = prop
|
||||
|
||||
// convert data descriptor
|
||||
if ('value' in descriptor) {
|
||||
descriptor = convertDataDescriptorToAccessor(obj, prop, message)
|
||||
}
|
||||
|
||||
var get = descriptor.get
|
||||
var set = descriptor.set
|
||||
|
||||
// wrap getter
|
||||
if (typeof get === 'function') {
|
||||
descriptor.get = function getter() {
|
||||
log.call(deprecate, message, site)
|
||||
return get.apply(this, arguments)
|
||||
}
|
||||
}
|
||||
|
||||
// wrap setter
|
||||
if (typeof set === 'function') {
|
||||
descriptor.set = function setter() {
|
||||
log.call(deprecate, message, site)
|
||||
return set.apply(this, arguments)
|
||||
}
|
||||
}
|
||||
|
||||
Object.defineProperty(obj, prop, descriptor)
|
||||
}
|
||||
|
||||
/**
|
||||
* Create DeprecationError for deprecation
|
||||
*/
|
||||
|
||||
function DeprecationError(namespace, message, stack) {
|
||||
var error = new Error()
|
||||
var stackString
|
||||
|
||||
Object.defineProperty(error, 'constructor', {
|
||||
value: DeprecationError
|
||||
})
|
||||
|
||||
Object.defineProperty(error, 'message', {
|
||||
configurable: true,
|
||||
enumerable: false,
|
||||
value: message,
|
||||
writable: true
|
||||
})
|
||||
|
||||
Object.defineProperty(error, 'name', {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
value: 'DeprecationError',
|
||||
writable: true
|
||||
})
|
||||
|
||||
Object.defineProperty(error, 'namespace', {
|
||||
configurable: true,
|
||||
enumerable: false,
|
||||
value: namespace,
|
||||
writable: true
|
||||
})
|
||||
|
||||
Object.defineProperty(error, 'stack', {
|
||||
configurable: true,
|
||||
enumerable: false,
|
||||
get: function () {
|
||||
if (stackString !== undefined) {
|
||||
return stackString
|
||||
}
|
||||
|
||||
// prepare stack trace
|
||||
return stackString = createStackString.call(this, stack)
|
||||
},
|
||||
set: function setter(val) {
|
||||
stackString = val
|
||||
}
|
||||
})
|
||||
|
||||
return error
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/*!
|
||||
* depd
|
||||
* Copyright(c) 2014 Douglas Christopher Wilson
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module exports.
|
||||
*/
|
||||
|
||||
module.exports = bufferConcat
|
||||
|
||||
/**
|
||||
* Concatenate an array of Buffers.
|
||||
*/
|
||||
|
||||
function bufferConcat(bufs) {
|
||||
var length = 0
|
||||
|
||||
for (var i = 0, len = bufs.length; i < len; i++) {
|
||||
length += bufs[i].length
|
||||
}
|
||||
|
||||
var buf = new Buffer(length)
|
||||
var pos = 0
|
||||
|
||||
for (var i = 0, len = bufs.length; i < len; i++) {
|
||||
bufs[i].copy(buf, pos)
|
||||
pos += bufs[i].length
|
||||
}
|
||||
|
||||
return buf
|
||||
}
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
/*!
|
||||
* depd
|
||||
* Copyright(c) 2014 Douglas Christopher Wilson
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module exports.
|
||||
*/
|
||||
|
||||
module.exports = callSiteToString
|
||||
|
||||
/**
|
||||
* Format a CallSite file location to a string.
|
||||
*/
|
||||
|
||||
function callSiteFileLocation(callSite) {
|
||||
var fileName
|
||||
var fileLocation = ''
|
||||
|
||||
if (callSite.isNative()) {
|
||||
fileLocation = 'native'
|
||||
} else if (callSite.isEval()) {
|
||||
fileName = callSite.getScriptNameOrSourceURL()
|
||||
if (!fileName) {
|
||||
fileLocation = callSite.getEvalOrigin()
|
||||
}
|
||||
} else {
|
||||
fileName = callSite.getFileName()
|
||||
}
|
||||
|
||||
if (fileName) {
|
||||
fileLocation += fileName
|
||||
|
||||
var lineNumber = callSite.getLineNumber()
|
||||
if (lineNumber != null) {
|
||||
fileLocation += ':' + lineNumber
|
||||
|
||||
var columnNumber = callSite.getColumnNumber()
|
||||
if (columnNumber) {
|
||||
fileLocation += ':' + columnNumber
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fileLocation || 'unknown source'
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a CallSite to a string.
|
||||
*/
|
||||
|
||||
function callSiteToString(callSite) {
|
||||
var addSuffix = true
|
||||
var fileLocation = callSiteFileLocation(callSite)
|
||||
var functionName = callSite.getFunctionName()
|
||||
var isConstructor = callSite.isConstructor()
|
||||
var isMethodCall = !(callSite.isToplevel() || isConstructor)
|
||||
var line = ''
|
||||
|
||||
if (isMethodCall) {
|
||||
var methodName = callSite.getMethodName()
|
||||
var typeName = getConstructorName(callSite)
|
||||
|
||||
if (functionName) {
|
||||
if (typeName && functionName.indexOf(typeName) !== 0) {
|
||||
line += typeName + '.'
|
||||
}
|
||||
|
||||
line += functionName
|
||||
|
||||
if (methodName && functionName.lastIndexOf('.' + methodName) !== functionName.length - methodName.length - 1) {
|
||||
line += ' [as ' + methodName + ']'
|
||||
}
|
||||
} else {
|
||||
line += typeName + '.' + (methodName || '<anonymous>')
|
||||
}
|
||||
} else if (isConstructor) {
|
||||
line += 'new ' + (functionName || '<anonymous>')
|
||||
} else if (functionName) {
|
||||
line += functionName
|
||||
} else {
|
||||
addSuffix = false
|
||||
line += fileLocation
|
||||
}
|
||||
|
||||
if (addSuffix) {
|
||||
line += ' (' + fileLocation + ')'
|
||||
}
|
||||
|
||||
return line
|
||||
}
|
||||
|
||||
/**
|
||||
* Get constructor name of reviver.
|
||||
*/
|
||||
|
||||
function getConstructorName(obj) {
|
||||
var receiver = obj.receiver
|
||||
return (receiver.constructor && receiver.constructor.name) || null
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
/*!
|
||||
* depd
|
||||
* Copyright(c) 2014 Douglas Christopher Wilson
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module exports.
|
||||
*/
|
||||
|
||||
lazyProperty(module.exports, 'bufferConcat', function bufferConcat() {
|
||||
return Buffer.concat || require('./buffer-concat')
|
||||
})
|
||||
|
||||
lazyProperty(module.exports, 'callSiteToString', function callSiteToString() {
|
||||
var limit = Error.stackTraceLimit
|
||||
var obj = {}
|
||||
var prep = Error.prepareStackTrace
|
||||
|
||||
function prepareObjectStackTrace(obj, stack) {
|
||||
return stack
|
||||
}
|
||||
|
||||
Error.prepareStackTrace = prepareObjectStackTrace
|
||||
Error.stackTraceLimit = 2
|
||||
|
||||
// capture the stack
|
||||
Error.captureStackTrace(obj)
|
||||
|
||||
// slice the stack
|
||||
var stack = obj.stack.slice()
|
||||
|
||||
Error.prepareStackTrace = prep
|
||||
Error.stackTraceLimit = limit
|
||||
|
||||
return stack[0].toString ? toString : require('./callsite-tostring')
|
||||
})
|
||||
|
||||
/**
|
||||
* Define a lazy property.
|
||||
*/
|
||||
|
||||
function lazyProperty(obj, prop, getter) {
|
||||
function get() {
|
||||
var val = getter()
|
||||
|
||||
Object.defineProperty(obj, prop, {
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
value: val
|
||||
})
|
||||
|
||||
return val
|
||||
}
|
||||
|
||||
Object.defineProperty(obj, prop, {
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
get: get
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Call toString() on the obj
|
||||
*/
|
||||
|
||||
function toString(obj) {
|
||||
return obj.toString()
|
||||
}
|
||||
+48
File diff suppressed because one or more lines are too long
+66
@@ -0,0 +1,66 @@
|
||||
2.1.0 / 2014-08-16
|
||||
==================
|
||||
|
||||
* Check if `socket` is detached
|
||||
* Return `undefined` for `isFinished` if state unknown
|
||||
|
||||
2.0.0 / 2014-08-16
|
||||
==================
|
||||
|
||||
* Add `isFinished` function
|
||||
* Move to `jshttp` organization
|
||||
* Remove support for plain socket argument
|
||||
* Rename to `on-finished`
|
||||
* Support both `req` and `res` as arguments
|
||||
* deps: ee-first@1.0.5
|
||||
|
||||
1.2.2 / 2014-06-10
|
||||
==================
|
||||
|
||||
* Reduce listeners added to emitters
|
||||
- avoids "event emitter leak" warnings when used multiple times on same request
|
||||
|
||||
1.2.1 / 2014-06-08
|
||||
==================
|
||||
|
||||
* Fix returned value when already finished
|
||||
|
||||
1.2.0 / 2014-06-05
|
||||
==================
|
||||
|
||||
* Call callback when called on already-finished socket
|
||||
|
||||
1.1.4 / 2014-05-27
|
||||
==================
|
||||
|
||||
* Support node.js 0.8
|
||||
|
||||
1.1.3 / 2014-04-30
|
||||
==================
|
||||
|
||||
* Make sure errors passed as instanceof `Error`
|
||||
|
||||
1.1.2 / 2014-04-18
|
||||
==================
|
||||
|
||||
* Default the `socket` to passed-in object
|
||||
|
||||
1.1.1 / 2014-01-16
|
||||
==================
|
||||
|
||||
* Rename module to `finished`
|
||||
|
||||
1.1.0 / 2013-12-25
|
||||
==================
|
||||
|
||||
* Call callback when called on already-errored socket
|
||||
|
||||
1.0.1 / 2013-12-20
|
||||
==================
|
||||
|
||||
* Actually pass the error to the callback
|
||||
|
||||
1.0.0 / 2013-12-20
|
||||
==================
|
||||
|
||||
* Initial release
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2013 Jonathan Ong <me@jongleberry.com>
|
||||
Copyright (c) 2014 Douglas Christopher Wilson <doug@somethingdoug.com>
|
||||
|
||||
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.
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
# on-finished
|
||||
|
||||
[](https://www.npmjs.org/package/on-finished)
|
||||
[](http://nodejs.org/download/)
|
||||
[](https://travis-ci.org/jshttp/on-finished)
|
||||
[](https://coveralls.io/r/jshttp/on-finished)
|
||||
|
||||
Execute a callback when a request closes, finishes, or errors.
|
||||
|
||||
## Install
|
||||
|
||||
```sh
|
||||
$ npm install on-finished
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
```js
|
||||
var onFinished = require('on-finished')
|
||||
```
|
||||
|
||||
### onFinished(res, listener)
|
||||
|
||||
Attach a listener to listen for the response to finish. The listener will
|
||||
be invoked only once when the response finished. If the response finished
|
||||
to to an error, the first argument will contain the error.
|
||||
|
||||
Listening to the end of a response would be used to close things associated
|
||||
with the response, like open files.
|
||||
|
||||
```js
|
||||
onFinished(res, function (err) {
|
||||
// clean up open fds, etc.
|
||||
})
|
||||
```
|
||||
|
||||
### onFinished(req, listener)
|
||||
|
||||
Attach a listener to listen for the request to finish. The listener will
|
||||
be invoked only once when the request finished. If the request finished
|
||||
to to an error, the first argument will contain the error.
|
||||
|
||||
Listening to the end of a request would be used to know when to continue
|
||||
after reading the data.
|
||||
|
||||
```js
|
||||
var data = ''
|
||||
|
||||
req.setEncoding('utf8')
|
||||
res.on('data', function (str) {
|
||||
data += str
|
||||
})
|
||||
|
||||
onFinished(req, function (err) {
|
||||
// data is read unless there is err
|
||||
})
|
||||
```
|
||||
|
||||
### onFinished.isFinished(res)
|
||||
|
||||
Determine if `res` is already finished. This would be useful to check and
|
||||
not even start certain operations if the response has already finished.
|
||||
|
||||
### onFinished.isFinished(req)
|
||||
|
||||
Determine if `req` is already finished. This would be useful to check and
|
||||
not even start certain operations if the request has already finished.
|
||||
|
||||
### Example
|
||||
|
||||
The following code ensures that file descriptors are always closed
|
||||
once the response finishes.
|
||||
|
||||
```js
|
||||
var destroy = require('destroy')
|
||||
var http = require('http')
|
||||
var onFinished = require('finished')
|
||||
|
||||
http.createServer(function onRequest(req, res) {
|
||||
var stream = fs.createReadStream('package.json')
|
||||
stream.pipe(res)
|
||||
onFinished(res, function (err) {
|
||||
destroy(stream)
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
[MIT](LICENSE)
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
/*!
|
||||
* on-finished
|
||||
* Copyright(c) 2013 Jonathan Ong
|
||||
* Copyright(c) 2014 Douglas Christopher Wilson
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module exports.
|
||||
*/
|
||||
|
||||
module.exports = onFinished;
|
||||
module.exports.isFinished = isFinished;
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var first = require('ee-first')
|
||||
|
||||
/**
|
||||
* Variables.
|
||||
*/
|
||||
|
||||
/* istanbul ignore next */
|
||||
var defer = typeof setImmediate === 'function'
|
||||
? setImmediate
|
||||
: function(fn){ process.nextTick(fn.bind.apply(fn, arguments)) }
|
||||
|
||||
/**
|
||||
* Invoke callback when the response has finished, useful for
|
||||
* cleaning up resources afterwards.
|
||||
*
|
||||
* @param {object} msg
|
||||
* @param {function} listener
|
||||
* @return {object}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function onFinished(msg, listener) {
|
||||
if (isFinished(msg) !== false) {
|
||||
defer(listener)
|
||||
return msg
|
||||
}
|
||||
|
||||
// attach the listener to the message
|
||||
attachListener(msg, listener)
|
||||
|
||||
return msg
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine is message is already finished.
|
||||
*
|
||||
* @param {object} msg
|
||||
* @return {boolean}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function isFinished(msg) {
|
||||
var socket = msg.socket
|
||||
|
||||
if (typeof msg.finished === 'boolean') {
|
||||
// OutgoingMessage
|
||||
return Boolean(!socket || msg.finished || !socket.writable)
|
||||
}
|
||||
|
||||
if (typeof msg.complete === 'boolean') {
|
||||
// IncomingMessage
|
||||
return Boolean(!socket || msg.complete || !socket.readable)
|
||||
}
|
||||
|
||||
// don't know
|
||||
return undefined
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach the listener to the message.
|
||||
*
|
||||
* @param {object} msg
|
||||
* @return {function}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function attachListener(msg, listener) {
|
||||
var attached = msg.__onFinished
|
||||
var socket = msg.socket
|
||||
|
||||
// create a private single listener with queue
|
||||
if (!attached || !attached.queue) {
|
||||
attached = msg.__onFinished = createListener(msg)
|
||||
|
||||
// finished on first event
|
||||
first([
|
||||
[socket, 'error', 'close'],
|
||||
[msg, 'end', 'finish'],
|
||||
], attached)
|
||||
}
|
||||
|
||||
attached.queue.push(listener)
|
||||
}
|
||||
|
||||
/**
|
||||
* Create listener on message.
|
||||
*
|
||||
* @param {object} msg
|
||||
* @return {function}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function createListener(msg) {
|
||||
function listener(err) {
|
||||
if (msg.__onFinished === listener) msg.__onFinished = null
|
||||
if (!listener.queue) return
|
||||
|
||||
var queue = listener.queue
|
||||
listener.queue = null
|
||||
|
||||
for (var i = 0; i < queue.length; i++) {
|
||||
queue[i](err)
|
||||
}
|
||||
}
|
||||
|
||||
listener.queue = []
|
||||
|
||||
return listener
|
||||
}
|
||||
Generated
Vendored
+22
@@ -0,0 +1,22 @@
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Jonathan Ong me@jongleberry.com
|
||||
|
||||
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.
|
||||
Generated
Vendored
+63
@@ -0,0 +1,63 @@
|
||||
# EE First
|
||||
|
||||
[![NPM version][npm-image]][npm-url]
|
||||
[![Build status][travis-image]][travis-url]
|
||||
[![Test coverage][coveralls-image]][coveralls-url]
|
||||
[![License][license-image]][license-url]
|
||||
[![Downloads][downloads-image]][downloads-url]
|
||||
[![Gittip][gittip-image]][gittip-url]
|
||||
|
||||
Get the first event in a set of event emitters and event pairs,
|
||||
then clean up after itself.
|
||||
|
||||
## Install
|
||||
|
||||
```sh
|
||||
$ npm install ee-first
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
```js
|
||||
var first = require('ee-first')
|
||||
```
|
||||
|
||||
### first(arr, listener)
|
||||
|
||||
Invoke `listener` on the first event from the list specified in `arr`. `arr` is
|
||||
an array of arrays, with each array in the format `[ee, ...event]`. `listener`
|
||||
will be called only once, the first time any of the given events are emitted. If
|
||||
`error` is one of the listened events, then if that fires first, the `listener`
|
||||
will be given the `err` argument.
|
||||
|
||||
The `listener` is invoked as `listener(err, ee, event, args)`, where `err` is the
|
||||
first argument emitted from an `error` event, if applicable; `ee` is the event
|
||||
emitter that fired; `event` is the string event name that fired; and `args` is an
|
||||
array of the arguments that were emitted on the event.
|
||||
|
||||
```js
|
||||
var ee1 = new EventEmitter()
|
||||
var ee2 = new EventEmitter()
|
||||
|
||||
first([
|
||||
[ee1, 'close', 'end', 'error'],
|
||||
[ee2, 'error']
|
||||
], function (err, ee, event, args) {
|
||||
// listener invoked
|
||||
})
|
||||
```
|
||||
|
||||
[npm-image]: https://img.shields.io/npm/v/ee-first.svg?style=flat-square
|
||||
[npm-url]: https://npmjs.org/package/ee-first
|
||||
[github-tag]: http://img.shields.io/github/tag/jonathanong/ee-first.svg?style=flat-square
|
||||
[github-url]: https://github.com/jonathanong/ee-first/tags
|
||||
[travis-image]: https://img.shields.io/travis/jonathanong/ee-first.svg?style=flat-square
|
||||
[travis-url]: https://travis-ci.org/jonathanong/ee-first
|
||||
[coveralls-image]: https://img.shields.io/coveralls/jonathanong/ee-first.svg?style=flat-square
|
||||
[coveralls-url]: https://coveralls.io/r/jonathanong/ee-first?branch=master
|
||||
[license-image]: http://img.shields.io/npm/l/ee-first.svg?style=flat-square
|
||||
[license-url]: LICENSE.md
|
||||
[downloads-image]: http://img.shields.io/npm/dm/ee-first.svg?style=flat-square
|
||||
[downloads-url]: https://npmjs.org/package/ee-first
|
||||
[gittip-image]: https://img.shields.io/gittip/jonathanong.svg?style=flat-square
|
||||
[gittip-url]: https://www.gittip.com/jonathanong/
|
||||
Generated
Vendored
+60
@@ -0,0 +1,60 @@
|
||||
|
||||
module.exports = function first(stuff, done) {
|
||||
if (!Array.isArray(stuff))
|
||||
throw new TypeError('arg must be an array of [ee, events...] arrays')
|
||||
|
||||
var cleanups = []
|
||||
|
||||
for (var i = 0; i < stuff.length; i++) {
|
||||
var arr = stuff[i]
|
||||
|
||||
if (!Array.isArray(arr) || arr.length < 2)
|
||||
throw new TypeError('each array member must be [ee, events...]')
|
||||
|
||||
var ee = arr[0]
|
||||
|
||||
for (var j = 1; j < arr.length; j++) {
|
||||
var event = arr[j]
|
||||
var fn = listener(event, cleanup)
|
||||
|
||||
// listen to the event
|
||||
ee.on(event, fn)
|
||||
// push this listener to the list of cleanups
|
||||
cleanups.push({
|
||||
ee: ee,
|
||||
event: event,
|
||||
fn: fn,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return function (fn) {
|
||||
done = fn
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
var x
|
||||
for (var i = 0; i < cleanups.length; i++) {
|
||||
x = cleanups[i]
|
||||
x.ee.removeListener(x.event, x.fn)
|
||||
}
|
||||
done.apply(null, arguments)
|
||||
}
|
||||
}
|
||||
|
||||
function listener(event, done) {
|
||||
return function onevent(arg1) {
|
||||
var args = new Array(arguments.length)
|
||||
var ee = this
|
||||
var err = event === 'error'
|
||||
? arg1
|
||||
: null
|
||||
|
||||
// copy args to prevent arguments escaping scope
|
||||
for (var i = 0; i < args.length; i++) {
|
||||
args[i] = arguments[i]
|
||||
}
|
||||
|
||||
done(err, ee, event, args)
|
||||
}
|
||||
}
|
||||
Generated
Vendored
+41
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"name": "ee-first",
|
||||
"description": "return the first event in a set of ee/event pairs",
|
||||
"version": "1.0.5",
|
||||
"author": {
|
||||
"name": "Jonathan Ong",
|
||||
"email": "me@jongleberry.com",
|
||||
"url": "http://jongleberry.com"
|
||||
},
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Douglas Christopher Wilson",
|
||||
"email": "doug@somethingdoug.com"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/jonathanong/ee-first"
|
||||
},
|
||||
"devDependencies": {
|
||||
"istanbul": "0.3.0",
|
||||
"mocha": "1"
|
||||
},
|
||||
"files": [
|
||||
"index.js",
|
||||
"LICENSE"
|
||||
],
|
||||
"scripts": {
|
||||
"test": "mocha --reporter spec --bail --check-leaks test/",
|
||||
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/",
|
||||
"test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/"
|
||||
},
|
||||
"readme": "# EE First\n\n[![NPM version][npm-image]][npm-url]\n[![Build status][travis-image]][travis-url]\n[![Test coverage][coveralls-image]][coveralls-url]\n[![License][license-image]][license-url]\n[![Downloads][downloads-image]][downloads-url]\n[![Gittip][gittip-image]][gittip-url]\n\nGet the first event in a set of event emitters and event pairs,\nthen clean up after itself.\n\n## Install\n\n```sh\n$ npm install ee-first\n```\n\n## API\n\n```js\nvar first = require('ee-first')\n```\n\n### first(arr, listener)\n\nInvoke `listener` on the first event from the list specified in `arr`. `arr` is\nan array of arrays, with each array in the format `[ee, ...event]`. `listener`\nwill be called only once, the first time any of the given events are emitted. If\n`error` is one of the listened events, then if that fires first, the `listener`\nwill be given the `err` argument.\n\nThe `listener` is invoked as `listener(err, ee, event, args)`, where `err` is the\nfirst argument emitted from an `error` event, if applicable; `ee` is the event\nemitter that fired; `event` is the string event name that fired; and `args` is an\narray of the arguments that were emitted on the event.\n\n```js\nvar ee1 = new EventEmitter()\nvar ee2 = new EventEmitter()\n\nfirst([\n [ee1, 'close', 'end', 'error'],\n [ee2, 'error']\n], function (err, ee, event, args) {\n // listener invoked\n})\n```\n\n[npm-image]: https://img.shields.io/npm/v/ee-first.svg?style=flat-square\n[npm-url]: https://npmjs.org/package/ee-first\n[github-tag]: http://img.shields.io/github/tag/jonathanong/ee-first.svg?style=flat-square\n[github-url]: https://github.com/jonathanong/ee-first/tags\n[travis-image]: https://img.shields.io/travis/jonathanong/ee-first.svg?style=flat-square\n[travis-url]: https://travis-ci.org/jonathanong/ee-first\n[coveralls-image]: https://img.shields.io/coveralls/jonathanong/ee-first.svg?style=flat-square\n[coveralls-url]: https://coveralls.io/r/jonathanong/ee-first?branch=master\n[license-image]: http://img.shields.io/npm/l/ee-first.svg?style=flat-square\n[license-url]: LICENSE.md\n[downloads-image]: http://img.shields.io/npm/dm/ee-first.svg?style=flat-square\n[downloads-url]: https://npmjs.org/package/ee-first\n[gittip-image]: https://img.shields.io/gittip/jonathanong.svg?style=flat-square\n[gittip-url]: https://www.gittip.com/jonathanong/\n",
|
||||
"readmeFilename": "README.md",
|
||||
"bugs": {
|
||||
"url": "https://github.com/jonathanong/ee-first/issues"
|
||||
},
|
||||
"_id": "ee-first@1.0.5",
|
||||
"_from": "ee-first@1.0.5"
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"name": "on-finished",
|
||||
"description": "Execute a callback when a request closes, finishes, or errors",
|
||||
"version": "2.1.0",
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Douglas Christopher Wilson",
|
||||
"email": "doug@somethingdoug.com"
|
||||
},
|
||||
{
|
||||
"name": "Jonathan Ong",
|
||||
"email": "me@jongleberry.com",
|
||||
"url": "http://jongleberry.com"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/jshttp/on-finished"
|
||||
},
|
||||
"dependencies": {
|
||||
"ee-first": "1.0.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"istanbul": "0.3.0",
|
||||
"mocha": "~1.21.4"
|
||||
},
|
||||
"engine": {
|
||||
"node": ">= 0.8.0"
|
||||
},
|
||||
"files": [
|
||||
"HISTORY.md",
|
||||
"LICENSE",
|
||||
"index.js"
|
||||
],
|
||||
"scripts": {
|
||||
"test": "mocha --reporter spec --bail --check-leaks test/",
|
||||
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/",
|
||||
"test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/"
|
||||
},
|
||||
"readme": "# on-finished\n\n[](https://www.npmjs.org/package/on-finished)\n[](http://nodejs.org/download/)\n[](https://travis-ci.org/jshttp/on-finished)\n[](https://coveralls.io/r/jshttp/on-finished)\n\nExecute a callback when a request closes, finishes, or errors.\n\n## Install\n\n```sh\n$ npm install on-finished\n```\n\n## API\n\n```js\nvar onFinished = require('on-finished')\n```\n\n### onFinished(res, listener)\n\nAttach a listener to listen for the response to finish. The listener will\nbe invoked only once when the response finished. If the response finished\nto to an error, the first argument will contain the error.\n\nListening to the end of a response would be used to close things associated\nwith the response, like open files.\n\n```js\nonFinished(res, function (err) {\n // clean up open fds, etc.\n})\n```\n\n### onFinished(req, listener)\n\nAttach a listener to listen for the request to finish. The listener will\nbe invoked only once when the request finished. If the request finished\nto to an error, the first argument will contain the error.\n\nListening to the end of a request would be used to know when to continue\nafter reading the data.\n\n```js\nvar data = ''\n\nreq.setEncoding('utf8')\nres.on('data', function (str) {\n data += str\n})\n\nonFinished(req, function (err) {\n // data is read unless there is err\n})\n```\n\n### onFinished.isFinished(res)\n\nDetermine if `res` is already finished. This would be useful to check and\nnot even start certain operations if the response has already finished.\n\n### onFinished.isFinished(req)\n\nDetermine if `req` is already finished. This would be useful to check and\nnot even start certain operations if the request has already finished.\n\n### Example\n\nThe following code ensures that file descriptors are always closed\nonce the response finishes.\n\n```js\nvar destroy = require('destroy')\nvar http = require('http')\nvar onFinished = require('finished')\n\nhttp.createServer(function onRequest(req, res) {\n var stream = fs.createReadStream('package.json')\n stream.pipe(res)\n onFinished(res, function (err) {\n destroy(stream)\n })\n})\n```\n\n## License\n\n[MIT](LICENSE)\n",
|
||||
"readmeFilename": "README.md",
|
||||
"bugs": {
|
||||
"url": "https://github.com/jshttp/on-finished/issues"
|
||||
},
|
||||
"_id": "on-finished@2.1.0",
|
||||
"_from": "on-finished@2.1.0"
|
||||
}
|
||||
+52
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user