Comparing version 0.1.1 to 0.2.0
124
lib/errs.js
@@ -8,3 +8,3 @@ /* | ||
*/ | ||
var events = require('events'), | ||
@@ -27,7 +27,7 @@ util = require('util'); | ||
// | ||
// Creates a new error instance for with the specified `type` | ||
// and `options`. If the `type` is not registered then a new | ||
// Creates a new error instance for with the specified `type` | ||
// and `options`. If the `type` is not registered then a new | ||
// `Error` instance will be created. | ||
// | ||
exports.create = function (type, opts) { | ||
exports.create = function createErr(type, opts) { | ||
if (!arguments[1] && !exports.registered[type]) { | ||
@@ -37,3 +37,3 @@ opts = type; | ||
} | ||
// | ||
@@ -46,7 +46,7 @@ // If the `opts` has a `stack` property assume | ||
} | ||
var message, | ||
errorProto, | ||
ErrorProto, | ||
error; | ||
// | ||
@@ -58,3 +58,3 @@ // Parse arguments liberally for the message | ||
} | ||
if (Array.isArray(opts)) { | ||
@@ -66,7 +66,7 @@ message = opts.join(' '); | ||
switch (typeof opts) { | ||
case 'string': | ||
message = opts || 'Unspecified error'; | ||
case 'string': | ||
message = opts || 'Unspecified error'; | ||
opts = null; | ||
break; | ||
case 'object': | ||
case 'object': | ||
message = (opts && opts.message) || 'Unspecified error'; | ||
@@ -77,18 +77,18 @@ break; | ||
break; | ||
} | ||
} | ||
} | ||
// | ||
// Instantiate a new Error instance or a new | ||
// registered error type (if it exists). | ||
// registered error type (if it exists). | ||
// | ||
errorProto = type && exports.registered[type] || Error; | ||
error = new (errorProto)(message); | ||
ErrorProto = type && exports.registered[type] || Error; | ||
error = new (ErrorProto)(message); | ||
if (!error.name || error.name === 'Error') { | ||
error.name = errorProto.name || 'Error'; | ||
error.name = ErrorProto.name || 'Error'; | ||
} | ||
// | ||
// Capture a stack trace if it does not already exist and | ||
// Capture a stack trace if it does not already exist and | ||
// remote the part of the stack trace referencing `errs.js`. | ||
@@ -98,10 +98,10 @@ // | ||
Error.call(error); | ||
Error.captureStackTrace(error, arguments.callee); | ||
Error.captureStackTrace(error, createErr); | ||
} | ||
else { | ||
error.stack = error.stack.split('\n') | ||
error.stack = error.stack.split('\n'); | ||
error.stack.splice(1, 1); | ||
error.stack = error.stack.join('\n'); | ||
} | ||
} | ||
// | ||
@@ -115,3 +115,3 @@ // Copy all options to the new error instance. | ||
} | ||
return error; | ||
@@ -121,23 +121,63 @@ }; | ||
// | ||
// ### function merge (err, type, opts) | ||
// #### @err {error} The error to merge | ||
// #### @type {string} **Optional** Registered error type to create | ||
// #### @opts {string|object|Array|function} Options for creating the error: | ||
// * `string`: Message for the error | ||
// * `object`: Properties to include on the error | ||
// * `array`: Message for the error (' ' joined). | ||
// * `function`: Function to return error options. | ||
// | ||
// Merges an existing error with a new error instance for with | ||
// the specified `type` and `options`. | ||
// | ||
exports.merge = function (err, type, opts) { | ||
var merged = exports.create(type, opts); | ||
// optional stuff that might be created by module | ||
Object.keys(err).forEach(function (key) { | ||
merged[key] = err[key]; | ||
}); | ||
// merging | ||
merged.name = merged.name || err.name; | ||
merged.message = merged.message || err.message; | ||
// override stack | ||
merged.stack = err.stack; | ||
// add human-readable errors | ||
merged.description = err.message; | ||
merged.stacktrace = err.stack.split("\n"); | ||
return merged; | ||
}; | ||
// | ||
// ### function handle (error, callback) | ||
// #### @error {string|function|Array|object} Error to handle | ||
// #### @callback {function} **Optional** Continuation to pass the error to. | ||
// #### @callback {function|EventEmitter} **Optional** Continuation or stream to pass the error to. | ||
// #### @stream {EventEmitter} **Optional** Explicit EventEmitter to use. | ||
// | ||
// Attempts to instantiate the given `error`. If the `error` is already a properly | ||
// formed `error` object (with a `stack` property) it will not be modified. | ||
// formed `error` object (with a `stack` property) it will not be modified. | ||
// | ||
// * If a `callback` is supplied, it is invoked with the `error`. | ||
// * If no `callback`, return a new `EventEmitter` which emits `error` | ||
// * If `callback` is a function, it is invoked with the `error`. | ||
// * If `callback` is an `EventEmitter`, it emits the `error` event on | ||
// that emitter and returns it. | ||
// * If no `callback`, return a new `EventEmitter` which emits `error` | ||
// on `process.nextTick()`. | ||
// | ||
exports.handle = function (error, callback) { | ||
exports.handle = function (error, callback, stream) { | ||
error = exports.create(error); | ||
if (typeof callback === 'function') { | ||
callback(error); | ||
} | ||
if (callback) { | ||
return callback(error); | ||
} | ||
var emitter = new events.EventEmitter(); | ||
process.nextTick(function () { emitter.emit('error', error); }); | ||
return emitter; | ||
if (typeof callback !== 'function' || stream) { | ||
var emitter = stream || callback || new events.EventEmitter(); | ||
process.nextTick(function () { emitter.emit('error', error); }); | ||
return emitter; | ||
} | ||
}; | ||
@@ -147,3 +187,3 @@ | ||
// ### function register (type, proto) | ||
// #### @type {string} Type of the error to register. | ||
// #### @type {string} **Optional** Type of the error to register. | ||
// #### @proto {function} Constructor function of the error to register. | ||
@@ -155,2 +195,6 @@ // | ||
exports.register = function (type, proto) { | ||
if (arguments.length === 1) { | ||
proto = type; | ||
type = proto.name.toLowerCase(); | ||
} | ||
exports.registered[type] = proto; | ||
@@ -168,2 +212,2 @@ }; | ||
delete exports.registered[type]; | ||
}; | ||
}; |
{ | ||
"name": "errs", | ||
"description": "Simple error creation and passing utilities", | ||
"version": "0.1.1", | ||
"version": "0.2.0", | ||
"author": "Nodejitsu <info@nodejitsu.com>", | ||
@@ -6,0 +6,0 @@ "contributors": [ |
@@ -7,3 +7,5 @@ # errs [![Build Status](https://secure.travis-ci.org/flatiron/errs.png)](http://travis-ci.org/flatiron/errs) | ||
* [Reusing Error Types](#reusing-types) | ||
* [Merging with Existing Errors](#merging-errors) | ||
* [Optional Callback Invocation](#optional-invocation) | ||
* [Piping Error Events](#piping-errors) | ||
@@ -94,2 +96,26 @@ <a name="creating-errors" /> | ||
<a name="merging-errors" /> | ||
## Merging with Existing Errors | ||
When working with errors you catch or are returned in a callback you can extend those errors with properties by using the `errs.merge` method. This will also create a human readable error message and stack-trace: | ||
``` js | ||
process.on('uncaughtException', function(err) { | ||
console.log(errs.merge(err, {namespace: 'uncaughtException'})); | ||
}); | ||
var file = fs.createReadStream('FileDoesNotExist.here'); | ||
``` | ||
``` js | ||
{ [Error: Unspecified error] | ||
name: 'Error', | ||
namespace: 'uncaughtException', | ||
errno: 34, | ||
code: 'ENOENT', | ||
path: 'FileDoesNotExist.here', | ||
description: 'ENOENT, no such file or directory \'FileDoesNotExist.here\'', | ||
stacktrace: [ 'Error: ENOENT, no such file or directory \'FileDoesNotExist.here\'' ] } | ||
``` | ||
<a name="optional-invocation" /> | ||
@@ -114,3 +140,3 @@ ## Optional Callback Invocation | ||
`errs` it presents a common API for both emitting `error` events and invoking continuations (i.e. callbacks) with errors; | ||
`errs` it presents a common API for both emitting `error` events and invoking continuations (i.e. callbacks) with errors. If a `callback` is supplied to `errs.handle()` it will be invoked with the error. It no `callback` is provided then an `EventEmitter` is returned which emits an `error` event on the next tick: | ||
@@ -127,4 +153,71 @@ ``` js | ||
If a `callback` is supplied to `errs.handle()` it will be invoked with the error. It no `callback` is provided then an `EventEmitter` is returned which emits an `error` event on the next tick. | ||
<a name="piping-errors" /> | ||
## Piping Errors | ||
Often when working with streams (especially when buffering for whatever reason), you may have already returned an `EventEmitter` or `Stream` instance by the time an error is handled. | ||
``` js | ||
function pipeSomething(callback) { | ||
// | ||
// You have a stream (e.g. http.ResponseStream) and you | ||
// have an optional `callback`. | ||
// | ||
var stream = new require('stream').Stream; | ||
// | ||
// You need to do something async which may respond with an | ||
// error | ||
// | ||
getAnotherStream(function (err, source) { | ||
if (err) { | ||
if (callback) | ||
callback(err); | ||
} | ||
stream.emit('error', err); | ||
return; | ||
} | ||
source.pipe(stream); | ||
}) | ||
return stream; | ||
} | ||
``` | ||
You may pass either a `function` or `EventEmitter` instance to `errs.handle`. | ||
``` js | ||
function pipeSomething(callback) { | ||
// | ||
// You have a stream (e.g. http.ResponseStream) and you | ||
// have an optional `callback`. | ||
// | ||
var stream = new require('stream').Stream; | ||
// | ||
// You need to do something async which may respond with an | ||
// error | ||
// | ||
getAnotherStream(function (err, source) { | ||
if (err) { | ||
// | ||
// Invoke the callback if it exists otherwise the stream. | ||
// | ||
return errs.handle(err, callback || stream); | ||
} | ||
source.pipe(stream); | ||
}) | ||
return stream; | ||
} | ||
``` | ||
If you wish to invoke both a `callback` function and an `error` event simply pass both: | ||
``` js | ||
errs.handle(err, callback, stream); | ||
``` | ||
## Methods | ||
@@ -137,2 +230,3 @@ The `errs` modules exposes some simple utility methods: | ||
* `.handle(err, callback)`: Attempts to instantiate the given `error`. If the `error` is already a properly formed `error` object (with a `stack` property) it will not be modified. | ||
* `.merge(err, type, opts)`: Merges an existing error with a new error instance for with the specified `type` and `opts`. | ||
@@ -139,0 +233,0 @@ ## Installation |
@@ -10,2 +10,3 @@ /* | ||
var assert = require('assert'), | ||
events = require('events'), | ||
vows = require('vows'), | ||
@@ -29,3 +30,3 @@ errs = require('../lib/errs'), | ||
properties: 'yes' | ||
}] | ||
}]; | ||
@@ -38,2 +39,6 @@ vows.describe('errs').addBatch({ | ||
assert.equal(errs.registered['named'], fixtures.NamedError); | ||
}, | ||
"should register an error without providing its name": function () { | ||
errs.register(fixtures.AnError); | ||
assert.equal(errs.registered['anerror'], fixtures.AnError); | ||
} | ||
@@ -67,2 +72,34 @@ }, | ||
}, | ||
"with an EventEmitter (i.e. stream)": { | ||
topic: function () { | ||
var err = this.err = errs.create('Some emitted error'), | ||
stream = new events.EventEmitter(); | ||
stream.once('error', this.callback.bind(this, null)); | ||
errs.handle(err, stream); | ||
}, | ||
"should emit the `error` event": function (_, err) { | ||
assert.equal(err, this.err); | ||
} | ||
}, | ||
"with a callback and an EventEmitter": { | ||
topic: function () { | ||
var err = this.err = errs.create('Some emitted error'), | ||
stream = new events.EventEmitter(), | ||
invoked = 0, | ||
that = this; | ||
function onError(err) { | ||
if (++invoked === 2) { | ||
that.callback.call(that, null, err); | ||
} | ||
} | ||
stream.once('error', onError); | ||
errs.handle(err, onError, stream); | ||
}, | ||
"should emit the `error` event": function (_, err) { | ||
assert.equal(err, this.err); | ||
} | ||
}, | ||
"with no callback": { | ||
@@ -73,5 +110,5 @@ topic: function () { | ||
emitter.once('error', this.callback.bind(this, null)) | ||
emitter.once('error', this.callback.bind(this, null)); | ||
}, | ||
"should invoke the callback with the error": function (_, err) { | ||
"should emit the `error` event": function (_, err) { | ||
assert.equal(err, this.err); | ||
@@ -91,2 +128,28 @@ } | ||
} | ||
}).export(module); | ||
}).addBatch({ | ||
"Using errs module": { | ||
"the merge() method": { | ||
"should preserve custom properties": function () { | ||
var err = new Error('Msg!'); | ||
err.foo = "bar"; | ||
err = errs.merge(err, {message: "Override!", ns: "test"}); | ||
assert.equal(err.foo, "bar"); | ||
}, | ||
"should have a stack trace": function () { | ||
var err = new Error('Msg!'); | ||
err = errs.merge(err, {message: "Override!", ns: "test"}); | ||
assert.isTrue(Array.isArray(err.stacktrace)); | ||
}, | ||
"should preserve message specified in create": function () { | ||
var err = new Error('Msg!'); | ||
err = errs.merge(err, {message: "Override!", ns: "test"}); | ||
assert.equal(err.message, "Override!"); | ||
}, | ||
"should preserve properties specified": function () { | ||
var err = new Error('Msg!'); | ||
err = errs.merge(err, {message: "Override!", ns: "test"}); | ||
assert.equal(err.ns, "test"); | ||
} | ||
} | ||
} | ||
}).export(module); |
@@ -8,3 +8,3 @@ /* | ||
*/ | ||
var util = require('util'); | ||
@@ -18,2 +18,8 @@ | ||
util.inherits(fixtures.NamedError, Error); | ||
util.inherits(fixtures.NamedError, Error); | ||
fixtures.AnError = function AnError() { | ||
this.named = true; | ||
}; | ||
util.inherits(fixtures.AnError, Error); |
@@ -91,2 +91,2 @@ /* | ||
}; | ||
} | ||
}; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
23572
14
462
257
3